switchroom 0.19.43 → 0.19.45
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 +4 -1
- package/dist/auth-broker/index.js +254 -119
- package/dist/cli/notion-write-pretool.mjs +4 -1
- package/dist/cli/switchroom.js +3995 -3196
- package/dist/host-control/main.js +270 -130
- package/dist/vault/approvals/kernel-server.js +201 -66
- package/dist/vault/broker/server.js +263 -128
- package/package.json +1 -1
- package/profiles/_base/start.sh.hbs +11 -4
- package/telegram-plugin/dist/gateway/gateway.js +945 -638
- package/telegram-plugin/flushed-turn-supersede.ts +190 -16
- package/telegram-plugin/gateway/cron-session.ts +31 -0
- package/telegram-plugin/gateway/gateway.ts +66 -65
- package/telegram-plugin/gateway/outbound-send-path.ts +60 -8
- package/telegram-plugin/gateway/reply-owner-wiring.ts +128 -0
- package/telegram-plugin/gateway/stream-render.ts +91 -1
- package/telegram-plugin/gateway/subagent-handback-marker.ts +49 -9
- package/telegram-plugin/gateway/subagent-reply-authority.ts +147 -0
- package/telegram-plugin/gateway/turn-end.ts +9 -1
- package/telegram-plugin/reply-owner-resolve.ts +102 -26
- package/telegram-plugin/tests/flushed-turn-supersede.test.ts +110 -8
- package/telegram-plugin/tests/narrative-lane-golden.test.ts +2 -0
- package/telegram-plugin/tests/reply-owner-resolve.test.ts +297 -27
- package/telegram-plugin/tests/reply-quote-wire.test.ts +2 -0
- package/telegram-plugin/tests/send-reply-golden.test.ts +567 -5
- package/telegram-plugin/tests/stream-render-golden.test.ts +204 -1
- package/vendor/hindsight-memory/scripts/lib/config.py +15 -0
- package/vendor/hindsight-memory/scripts/tests/test_retain_provenance_tag.py +135 -0
- package/vendor/hindsight-memory/settings.json +1 -1
|
@@ -21547,7 +21547,7 @@ var init_observation_scopes = __esm(() => {
|
|
|
21547
21547
|
});
|
|
21548
21548
|
|
|
21549
21549
|
// ../src/config/schema.ts
|
|
21550
|
-
var CodeRepoEntrySchema, AgentBindMountSchema, HttpDiffPollSchema, PollSpecSchema, TelegramMessageActionSchema, WebhookActionSchema, ActionSpecSchema, ScheduleEntrySchema, AgentSoulSchema, AgentToolsSchema, ObservationScopesSchema, ObservationScopeStrategySchema, AgentMemorySchema, HookEntrySchema, AgentHooksSchema, SubagentSchema, SessionSchema, SessionContinuitySchema, webhookDispatchRule, TelegramChannelSchema, ChannelsSchema, TIMEZONE_REGEX, ApproverIdSchema, GoogleWorkspaceTierSchema, GoogleWorkspaceConfigSchema, LiteLLMConfigSchema, HindsightPerOpLlmSchema, HindsightConfigSchema, MicrosoftWorkspaceConfigSchema, NotionWorkspaceConfigSchema, AgentGoogleWorkspaceConfigSchema, MicrosoftAccountEmailSchema, MicrosoftToolTokenSchema, MicrosoftAccountBindingSchema, AgentMicrosoftWorkspaceConfigSchema, AgentNotionWorkspaceConfigSchema, ReactionsSchema, ReactionDispatchSchema, releaseBlockFields, ReleaseBlock, RootReleaseBlock, NetworkIsolationSchema, servesField, knowsField, profileFields, ProfileSchema, _omitExtends, defaultsFields, AgentDefaultsSchema, AgentSchema, TelegramConfigSchema, MemoryBackendConfigSchema, VaultConfigSchema, QuotaConfigSchema, AutoReleaseCheckSchema, HostControlConfigSchema, WebServiceConfigSchema, FleetHealthConfigSchema, HostdConfigSchema, CronEgressSchema, CronConfigSchema, UserSchema, SwitchroomConfigSchema;
|
|
21550
|
+
var CodeRepoEntrySchema, AgentBindMountSchema, HttpDiffPollSchema, PollSpecSchema, TelegramMessageActionSchema, WebhookActionSchema, ActionSpecSchema, ScheduleEntrySchema, AgentSoulSchema, AgentToolsSchema, ObservationScopesSchema, ObservationScopeStrategySchema, AntiConfabulationDirectiveSchema, AgentMemorySchema, HookEntrySchema, AgentHooksSchema, SubagentSchema, SessionSchema, SessionContinuitySchema, webhookDispatchRule, TelegramChannelSchema, ChannelsSchema, TIMEZONE_REGEX, ApproverIdSchema, GoogleWorkspaceTierSchema, GoogleWorkspaceConfigSchema, LiteLLMConfigSchema, HindsightPerOpLlmSchema, HindsightConfigSchema, MicrosoftWorkspaceConfigSchema, NotionWorkspaceConfigSchema, AgentGoogleWorkspaceConfigSchema, MicrosoftAccountEmailSchema, MicrosoftToolTokenSchema, MicrosoftAccountBindingSchema, AgentMicrosoftWorkspaceConfigSchema, AgentNotionWorkspaceConfigSchema, ReactionsSchema, ReactionDispatchSchema, releaseBlockFields, ReleaseBlock, RootReleaseBlock, NetworkIsolationSchema, servesField, knowsField, profileFields, ProfileSchema, _omitExtends, defaultsFields, AgentDefaultsSchema, AgentSchema, TelegramConfigSchema, MemoryBackendConfigSchema, VaultConfigSchema, QuotaConfigSchema, AutoReleaseCheckSchema, HostControlConfigSchema, WebServiceConfigSchema, FleetHealthConfigSchema, HostdConfigSchema, CronEgressSchema, CronConfigSchema, UserSchema, SwitchroomConfigSchema;
|
|
21551
21551
|
var init_schema = __esm(() => {
|
|
21552
21552
|
init_zod();
|
|
21553
21553
|
init_observation_scopes();
|
|
@@ -21664,6 +21664,7 @@ var init_schema = __esm(() => {
|
|
|
21664
21664
|
}).optional();
|
|
21665
21665
|
ObservationScopesSchema = exports_external.enum(OBSERVATION_SCOPES).optional().describe("Operator PIN for the per-row observation scope, overriding the " + 'default `curated` strategy (see docs/configuration.md). "shared" ' + "forces Hindsight's consolidation to write EVERY observation into ONE " + "global untagged scope \u2014 what several agents pooling one bank want so " + "their observations merge rather than sitting in parallel silos. " + '"combined" is the pin form of opting out (restores the pre-#4035 ' + "engine default). UNSET does NOT mean 'nothing on the wire': the " + "`curated` strategy still computes a scope per retain. Applies to " + "every retain path (Stop hook, " + "sidechain, boot reconcile, queue drain, backfill, session-handoff " + "mirror) and is carried on the queued payload, so a retain that fails " + "now and drains later still lands in this scope. Accepted values: " + `${OBSERVATION_SCOPES.join(", ")}. ` + "Cascade: override (per-agent wins over default).");
|
|
21666
21666
|
ObservationScopeStrategySchema = exports_external.enum(OBSERVATION_SCOPE_STRATEGIES).optional().describe("Per-retain strategy that decides how the observation scope is " + 'computed when no `observation_scopes` pin is set. "curated" ' + "(the default since #4035) strips volatile per-session provenance " + "tags from each retain's consolidation scope \u2014 keeping the stable " + "semantic ones on the source fact \u2014 so an agent's observations dedup " + "and merge across sessions instead of pocketing one-per-session. " + '"shared" sends every retain to the one global untagged scope. ' + '"combined" / "off" opt OUT: no per-row scope goes on the wire, ' + "restoring the pre-feature engine default (byte-identical to an " + "unconfigured client). OMITTED BY DEFAULT: unset leaves the plugin's " + "own default (`curated`) in force. A manual `observation_scopes` pin " + "wins over this strategy. Accepted values: " + `${OBSERVATION_SCOPE_STRATEGIES.join(", ")}. ` + "Cascade: override (per-agent wins over default).");
|
|
21667
|
+
AntiConfabulationDirectiveSchema = exports_external.union([exports_external.boolean(), exports_external.string().min(1)]).optional().describe("The seeded anti-confabulation directive: reflect has no relevance " + "floor (`min_scores` is a /recall-only parameter), so a bank holding " + "nothing relevant still yields a confident answer, and a question that " + "presupposes a decision reliably produces one. Directives ARE applied " + "during reflect, so this is the lever. Unset or true (the default) " + "seeds and maintains switchroom's own text; false disables seeding and " + "leaves any existing directive untouched; a string is operator-authored " + "text that wins outright. Switchroom only ever upgrades directive text " + "byte-equal to a default it shipped, so editing the directive in the " + "bank is also a permanent override. " + "Cascade: override (per-agent wins over default).");
|
|
21667
21668
|
AgentMemorySchema = exports_external.object({
|
|
21668
21669
|
collection: exports_external.string().describe("Hindsight collection name for this agent"),
|
|
21669
21670
|
auto_recall: exports_external.boolean().default(true).describe("Auto-search memories before each response"),
|
|
@@ -21699,6 +21700,7 @@ var init_schema = __esm(() => {
|
|
|
21699
21700
|
empathy: exports_external.number().int().min(1).max(5).optional().describe("How much the bank weights emotional/relational context (1-5; engine default 3).")
|
|
21700
21701
|
}).optional().describe("Personality traits (1-5 each) steering how this bank frames recall, " + "reflect, and observation synthesis \u2014 a coach leans empathy-high, a " + "lawyer/analyst leans skepticism/literalism-high. Maps to the engine's " + "flat `disposition_skepticism`/`_literalism`/`_empathy` fields. " + "Cascade: per-key merge (an agent overrides individual traits and " + "inherits the rest, matching `recall`)."),
|
|
21701
21702
|
directive_capture_nudge: exports_external.boolean().optional().describe("Deterministic directive-capture nudge (issue #2848 Stage B). When " + "on (switchroom default true \u2014 Stage A measured a ~55% miss rate on " + "durable corrections), the auto-recall hook regex-detects correction " + '/ standing-rule-shaped inbound ("always/never \u2026", "from now on \u2026", ' + `"stop doing \u2026", a stated preference, "that's wrong, it's \u2026") and ` + "appends a terse advisory to the turn's context telling the model to " + "persist the rule with mcp__hindsight__create_directive if it IS " + "durable. Detection is pure regex \u2014 the model does the judgment " + "in-session and calls create_directive itself (no model callsite, no " + "silent hook-side write). Set false to disable per-agent. " + "Cascade: override (per-agent wins over default)."),
|
|
21703
|
+
anti_confabulation_directive: AntiConfabulationDirectiveSchema,
|
|
21702
21704
|
observation_scopes: ObservationScopesSchema,
|
|
21703
21705
|
observation_scope_strategy: ObservationScopeStrategySchema,
|
|
21704
21706
|
recall: exports_external.object({
|
|
@@ -21969,7 +21971,7 @@ var init_schema = __esm(() => {
|
|
|
21969
21971
|
reflect: HindsightPerOpLlmSchema.optional().describe("Per-op override for the `reflect` LLM op (synthesis / mental-model " + "refresh). Emits `HINDSIGHT_API_REFLECT_LLM_*`. Absent \u2192 uses global."),
|
|
21970
21972
|
consolidation: HindsightPerOpLlmSchema.optional().describe("Per-op override for the `consolidation` LLM op (background memory " + "merge). Emits `HINDSIGHT_API_CONSOLIDATION_LLM_*`. Absent \u2192 global.")
|
|
21971
21973
|
}).optional().describe("LLM knob for the hindsight container. The flat `provider`/`model` set " + "the global default (backward-compatible); optional `retain`/`reflect`/" + "`consolidation` blocks override individual ops. All fields optional; " + "unset fields fall back to the hard-coded defaults."),
|
|
21972
|
-
env: exports_external.record(exports_external.union([exports_external.string(), exports_external.number(), exports_external.boolean()])).optional().describe("Operator overrides for switchroom's capability-gated Hindsight " + "performance defaults. Only the keys switchroom actually manages are " + "honoured (`HINDSIGHT_PERF_ENV_KEYS` in " + "src/setup/hindsight-perf-defaults.ts: RERANKER_LOCAL_FP16, " + "RERANKER_LOCAL_BATCH_SIZE, LLM_MAX_CONCURRENT, " + "RETAIN/CONSOLIDATION_LLM_MAX_CONCURRENT, LLM_STRICT_SCHEMA, " + "LLM_MAX_RETRIES, CONSOLIDATION_LLM_PARALLELISM, " + "MAX_OBSERVATIONS_PER_SCOPE, " + "RECALL_MAX_CANDIDATES_PER_SOURCE, LINK_EXPANSION_PER_ENTITY_LIMIT, " + "LINK_EXPANSION_TIMEOUT, LLM_REASONING_EFFORT, " + "RERANKER_LOCAL_BUCKET_BATCHING, RERANKER_MAX_CANDIDATES, " + "RERANKER_LOCAL_MAX_CONCURRENT, RECALL_MAX_CONCURRENT, " + "REFLECT_WALL_TIMEOUT, WORKER_CONSOLIDATION_RESERVED_SLOTS, " + "WORKER_CONSOLIDATION_SLOT_LIMIT, " + "CONSOLIDATION_MAX_MEMORIES_PER_ROUND, GRAPH_SEED_MIN_SIMILARITY, " + "LLM_SUPPORTS_MAX_ITEMS, RECENCY_DECAY_FUNCTION, " + "RECENCY_DECAY_HALFLIFE_DAYS \u2014 switchroom defaults recall's recency " + "curve to `exponential` with a 30-day half-life so a fact retained " + "today outranks a stale one, instead of upstream's near-flat " + "linear/365-day window), the override-only keys " + "switchroom manages but ships NO default for " + "(`HINDSIGHT_PERF_OVERRIDE_ONLY_KEYS`: " + "HINDSIGHT_API_WORKER_CONSOLIDATION_BANK_PRIORITY \u2014 a per-deployment " + "`bank-pattern:priority,...` map; unset means upstream's flat " + "created_at FIFO across banks; and " + "HINDSIGHT_CE_DECISIVE_RELATIVE_GAP \u2014 the rollback knob for " + "switchroom's CE-saturation damping patch, a float; >= ~0.65 backs the " + "damping out entirely, unset means the patch's own derived gap; and " + "HINDSIGHT_API_RECENCY_DECAY_LINEAR_WINDOW_DAYS \u2014 only read when the " + "decay function is `linear`, so switchroom ships no default for it but " + "still honours an operator who flips the function back; and " + "HINDSIGHT_API_WORKER_MAX_SLOTS \u2014 the worker poller's TOTAL in-flight " + "task budget, the pool WORKER_CONSOLIDATION_RESERVED_SLOTS reserves out of; " + "unset means upstream's own default; and " + "HINDSIGHT_API_WORKER_RETAIN_RESERVED_SLOTS \u2014 the reserved slot FLOOR for the " + "retain (memory write) lane, carved from that same total; unset means " + "upstream's own 0, i.e. no floor and retain competes for the shared " + "pool; and " + "the pre-0.8.6 name HINDSIGHT_API_WORKER_<TYPE>_MAX_SLOTS is still " + "accepted for every operation type and normalised to " + "..._RESERVED_SLOTS on the way in, because setting both names for " + "one type is a hard boot failure in the engine and switchroom " + "therefore emits only the canonical name; and " + "HINDSIGHT_API_SEMANTIC_MIN_SIMILARITY \u2014 the cosine-similarity floor a " + "candidate must reach to be returned by the semantic retrieval arm at " + "all (0..1); unset means upstream's own 0.3, and where it should sit " + "depends on the bank's embedding model and phrasing diversity, so " + "switchroom ships no opinion; and " + "HINDSIGHT_MCP_RECALL_BUDGET_MODE \u2014 the rollback knob for switchroom's " + "mcp-recall-token-budget image patch; `legacy` restores upstream's " + "exact pre-patch recall returns, anything else or unset is the " + "honest-envelope mode; and " + "HINDSIGHT_API_LLM_TEMPERATURE_REFLECT \u2014 upstream's own per-op reflect " + "temperature knob, made live by switchroom's reflect-temperature image " + "patch; a float, or `none` to omit the kwarg (provider default, " + "upstream's accidental pre-patch behaviour); unset means the image's " + "baked default 0.1), plus the " + "embedded-PostgreSQL (pg0) sizing keys switchroom manages in " + "src/setup/hindsight-pg-defaults.ts (`HINDSIGHT_PG_ENV_KEYS`: " + "SWITCHROOM_HINDSIGHT_PG_EFFECTIVE_CACHE_SIZE, " + "SWITCHROOM_HINDSIGHT_PG_SHARED_BUFFERS \u2014 a postgres size string such " + "as `4GB`, or the sentinel `off` to leave pg0's own default for that " + "one knob). A value set here " + "REPLACES switchroom's default and is emitted even when the gating " + "capability is absent, so an operator can always force a knob. Other " + "`HINDSIGHT_API_*` keys are deliberately IGNORED \u2014 a blanket " + "passthrough would collide with the vars startHindsight() derives " + "itself (HINDSIGHT_API_PORT, the retain token/deadline budget).")
|
|
21974
|
+
env: exports_external.record(exports_external.union([exports_external.string(), exports_external.number(), exports_external.boolean()])).optional().describe("Operator overrides for switchroom's capability-gated Hindsight " + "performance defaults. Only the keys switchroom actually manages are " + "honoured (`HINDSIGHT_PERF_ENV_KEYS` in " + "src/setup/hindsight-perf-defaults.ts: RERANKER_LOCAL_FP16, " + "RERANKER_LOCAL_BATCH_SIZE, LLM_MAX_CONCURRENT, " + "RETAIN/CONSOLIDATION_LLM_MAX_CONCURRENT, LLM_STRICT_SCHEMA, " + "LLM_MAX_RETRIES, CONSOLIDATION_LLM_PARALLELISM, " + "MAX_OBSERVATIONS_PER_SCOPE, " + "RECALL_MAX_CANDIDATES_PER_SOURCE, LINK_EXPANSION_PER_ENTITY_LIMIT, " + "LINK_EXPANSION_TIMEOUT, LLM_REASONING_EFFORT, " + "RERANKER_LOCAL_BUCKET_BATCHING, RERANKER_MAX_CANDIDATES, " + "RERANKER_LOCAL_MAX_CONCURRENT, RECALL_MAX_CONCURRENT, " + "REFLECT_WALL_TIMEOUT, WORKER_CONSOLIDATION_RESERVED_SLOTS, " + "WORKER_CONSOLIDATION_SLOT_LIMIT, " + "CONSOLIDATION_MAX_MEMORIES_PER_ROUND, GRAPH_SEED_MIN_SIMILARITY, " + "LLM_SUPPORTS_MAX_ITEMS, RECENCY_DECAY_FUNCTION, " + "RECENCY_DECAY_HALFLIFE_DAYS \u2014 switchroom defaults recall's recency " + "curve to `exponential` with a 30-day half-life so a fact retained " + "today outranks a stale one, instead of upstream's near-flat " + "linear/365-day window), the override-only keys " + "switchroom manages but ships NO default for " + "(`HINDSIGHT_PERF_OVERRIDE_ONLY_KEYS`: " + "HINDSIGHT_API_WORKER_CONSOLIDATION_BANK_PRIORITY \u2014 a per-deployment " + "`bank-pattern:priority,...` map; unset means upstream's flat " + "created_at FIFO across banks; and " + "HINDSIGHT_CE_DECISIVE_RELATIVE_GAP \u2014 the rollback knob for " + "switchroom's CE-saturation damping patch, a float; >= ~0.65 backs the " + "damping out entirely, unset means the patch's own derived gap; and " + "HINDSIGHT_API_RECENCY_DECAY_LINEAR_WINDOW_DAYS \u2014 only read when the " + "decay function is `linear`, so switchroom ships no default for it but " + "still honours an operator who flips the function back; and " + "HINDSIGHT_API_WORKER_MAX_SLOTS \u2014 the worker poller's TOTAL in-flight " + "task budget, the pool WORKER_CONSOLIDATION_RESERVED_SLOTS reserves out of; " + "unset means upstream's own default; and " + "HINDSIGHT_API_WORKER_RETAIN_RESERVED_SLOTS \u2014 the reserved slot FLOOR for the " + "retain (memory write) lane, carved from that same total; unset means " + "upstream's own 0, i.e. no floor and retain competes for the shared " + "pool; and " + "the pre-0.8.6 name HINDSIGHT_API_WORKER_<TYPE>_MAX_SLOTS is still " + "accepted for every operation type and normalised to " + "..._RESERVED_SLOTS on the way in, because setting both names for " + "one type is a hard boot failure in the engine and switchroom " + "therefore emits only the canonical name; and " + "HINDSIGHT_API_SEMANTIC_MIN_SIMILARITY \u2014 the cosine-similarity floor a " + "candidate must reach to be returned by the semantic retrieval arm at " + "all (0..1); unset means upstream's own 0.3, and where it should sit " + "depends on the bank's embedding model and phrasing diversity, so " + "switchroom ships no opinion; and " + "HINDSIGHT_MCP_RECALL_BUDGET_MODE \u2014 the rollback knob for switchroom's " + "mcp-recall-token-budget image patch; `legacy` restores upstream's " + "exact pre-patch recall returns, anything else or unset is the " + "honest-envelope mode; and " + "HINDSIGHT_API_LLM_TEMPERATURE_REFLECT \u2014 upstream's own per-op reflect " + "temperature knob, made live by switchroom's reflect-temperature image " + "patch; a float, or `none` to omit the kwarg (provider default, " + "upstream's accidental pre-patch behaviour); unset means the image's " + "baked default 0.1; and " + "HINDSIGHT_API_CONSOLIDATION_RECALL_MAX_CONCURRENT \u2014 the background " + "half of switchroom's recall-admission split (#3660): of the " + "RECALL_MAX_CONCURRENT admission slots, at most this many may be held " + "by background consolidation recalls at once, so foreground per-turn " + "recall always keeps the remainder; must be >= 1 and strictly less " + "than RECALL_MAX_CONCURRENT or the engine refuses to boot; unset " + "means the image's derived default min(2, RECALL_MAX_CONCURRENT - 1); " + "1 biases hard toward the interactive lane while a consolidation " + "backlog drains), plus the " + "embedded-PostgreSQL (pg0) sizing keys switchroom manages in " + "src/setup/hindsight-pg-defaults.ts (`HINDSIGHT_PG_ENV_KEYS`: " + "SWITCHROOM_HINDSIGHT_PG_EFFECTIVE_CACHE_SIZE, " + "SWITCHROOM_HINDSIGHT_PG_SHARED_BUFFERS \u2014 a postgres size string such " + "as `4GB`, or the sentinel `off` to leave pg0's own default for that " + "one knob). A value set here " + "REPLACES switchroom's default and is emitted even when the gating " + "capability is absent, so an operator can always force a knob. Other " + "`HINDSIGHT_API_*` keys are deliberately IGNORED \u2014 a blanket " + "passthrough would collide with the vars startHindsight() derives " + "itself (HINDSIGHT_API_PORT, the retain token/deadline budget).")
|
|
21973
21975
|
});
|
|
21974
21976
|
MicrosoftWorkspaceConfigSchema = exports_external.object({
|
|
21975
21977
|
microsoft_client_id: exports_external.string().min(1).optional().describe("Microsoft OAuth application (client) ID from Entra portal " + "(literal string or vault reference e.g. " + "'vault:microsoft-oauth-client-id'). OPTIONAL \u2014 omit it to use " + "switchroom's shipped default Microsoft app (zero-config). " + "Set it only to bring your own Entra app (BYO)."),
|
|
@@ -22103,6 +22105,7 @@ var init_schema = __esm(() => {
|
|
|
22103
22105
|
isolation: exports_external.enum(["default", "strict"]).optional(),
|
|
22104
22106
|
profile: exports_external.string().optional(),
|
|
22105
22107
|
directive_capture_nudge: exports_external.boolean().optional(),
|
|
22108
|
+
anti_confabulation_directive: AntiConfabulationDirectiveSchema,
|
|
22106
22109
|
observation_scopes: ObservationScopesSchema,
|
|
22107
22110
|
observation_scope_strategy: ObservationScopeStrategySchema,
|
|
22108
22111
|
recall: exports_external.object({
|
|
@@ -30147,7 +30150,7 @@ var init_turn_flush_suppression = () => {};
|
|
|
30147
30150
|
|
|
30148
30151
|
// ../src/agents/generation-stamp.ts
|
|
30149
30152
|
import { createHash as createHash6 } from "node:crypto";
|
|
30150
|
-
import { existsSync as
|
|
30153
|
+
import { existsSync as existsSync33, readFileSync as readFileSync32, writeFileSync as writeFileSync28 } from "node:fs";
|
|
30151
30154
|
import { join as join41 } from "node:path";
|
|
30152
30155
|
function sha256Text(s) {
|
|
30153
30156
|
return createHash6("sha256").update(s, "utf-8").digest("hex");
|
|
@@ -30159,11 +30162,11 @@ function hashManagedClaudeMd(content3) {
|
|
|
30159
30162
|
}
|
|
30160
30163
|
function hashStampedFileOnDisk(agentDir, rel) {
|
|
30161
30164
|
const p = join41(agentDir, rel);
|
|
30162
|
-
if (!
|
|
30165
|
+
if (!existsSync33(p))
|
|
30163
30166
|
return null;
|
|
30164
30167
|
let content3;
|
|
30165
30168
|
try {
|
|
30166
|
-
content3 =
|
|
30169
|
+
content3 = readFileSync32(p, "utf-8");
|
|
30167
30170
|
} catch {
|
|
30168
30171
|
return null;
|
|
30169
30172
|
}
|
|
@@ -30171,10 +30174,10 @@ function hashStampedFileOnDisk(agentDir, rel) {
|
|
|
30171
30174
|
}
|
|
30172
30175
|
function readGenerationStamp(agentDir) {
|
|
30173
30176
|
const p = join41(agentDir, GENERATION_STAMP_FILE);
|
|
30174
|
-
if (!
|
|
30177
|
+
if (!existsSync33(p))
|
|
30175
30178
|
return null;
|
|
30176
30179
|
try {
|
|
30177
|
-
const parsed = JSON.parse(
|
|
30180
|
+
const parsed = JSON.parse(readFileSync32(p, "utf-8"));
|
|
30178
30181
|
if (parsed?.version !== 1 || typeof parsed.files !== "object" || parsed.files === null || Array.isArray(parsed.files)) {
|
|
30179
30182
|
return null;
|
|
30180
30183
|
}
|
|
@@ -35984,19 +35987,19 @@ function renderAuthLine(state7, agentName3, now = Date.now()) {
|
|
|
35984
35987
|
}
|
|
35985
35988
|
|
|
35986
35989
|
// gateway/quota-cache.ts
|
|
35987
|
-
import { existsSync as
|
|
35988
|
-
import { join as
|
|
35990
|
+
import { existsSync as existsSync45, readFileSync as readFileSync45, writeFileSync as writeFileSync37, mkdirSync as mkdirSync39 } from "fs";
|
|
35991
|
+
import { join as join53, dirname as dirname22 } from "path";
|
|
35989
35992
|
function defaultCachePath() {
|
|
35990
|
-
return process.env.SWITCHROOM_QUOTA_CACHE_PATH ??
|
|
35993
|
+
return process.env.SWITCHROOM_QUOTA_CACHE_PATH ?? join53(process.env.HOME ?? "/tmp", ".switchroom", "quota-cache.json");
|
|
35991
35994
|
}
|
|
35992
35995
|
function readQuotaCache(opts = {}) {
|
|
35993
35996
|
const path3 = opts.path ?? defaultCachePath();
|
|
35994
35997
|
const now = opts.now ?? Date.now();
|
|
35995
|
-
if (!
|
|
35998
|
+
if (!existsSync45(path3))
|
|
35996
35999
|
return null;
|
|
35997
36000
|
let entry;
|
|
35998
36001
|
try {
|
|
35999
|
-
entry = JSON.parse(
|
|
36002
|
+
entry = JSON.parse(readFileSync45(path3, "utf8"));
|
|
36000
36003
|
} catch {
|
|
36001
36004
|
return null;
|
|
36002
36005
|
}
|
|
@@ -36033,8 +36036,8 @@ var init_quota_cache = __esm(() => {
|
|
|
36033
36036
|
});
|
|
36034
36037
|
|
|
36035
36038
|
// gateway/boot-probes.ts
|
|
36036
|
-
import { readFileSync as
|
|
36037
|
-
import { join as
|
|
36039
|
+
import { readFileSync as readFileSync46, readdirSync as readdirSync12, existsSync as existsSync46 } from "fs";
|
|
36040
|
+
import { join as join54 } from "path";
|
|
36038
36041
|
import { execFile as execFileCb } from "child_process";
|
|
36039
36042
|
import { promisify } from "util";
|
|
36040
36043
|
async function withTimeout(label, p, timeoutMs = PROBE_TIMEOUT_MS) {
|
|
@@ -36076,11 +36079,11 @@ function mapPlan(billingType, hasExtra) {
|
|
|
36076
36079
|
}
|
|
36077
36080
|
async function probeAccount(agentDir) {
|
|
36078
36081
|
return withTimeout("Account", (async () => {
|
|
36079
|
-
const claudeDir =
|
|
36080
|
-
const claudeJsonPath =
|
|
36082
|
+
const claudeDir = join54(agentDir, ".claude");
|
|
36083
|
+
const claudeJsonPath = join54(claudeDir, ".claude.json");
|
|
36081
36084
|
let cfg = {};
|
|
36082
36085
|
try {
|
|
36083
|
-
const raw =
|
|
36086
|
+
const raw = readFileSync46(claudeJsonPath, "utf8");
|
|
36084
36087
|
cfg = JSON.parse(raw);
|
|
36085
36088
|
} catch {
|
|
36086
36089
|
return { status: "fail", label: "Account", detail: "no .claude.json" };
|
|
@@ -36098,12 +36101,12 @@ async function probeAccount(agentDir) {
|
|
|
36098
36101
|
let tokenStr = "";
|
|
36099
36102
|
let status = "ok";
|
|
36100
36103
|
for (const candidate of [
|
|
36101
|
-
|
|
36102
|
-
|
|
36104
|
+
join54(claudeDir, ".oauth-token.meta.json"),
|
|
36105
|
+
join54(claudeDir, "accounts", "default", ".oauth-token.meta.json")
|
|
36103
36106
|
]) {
|
|
36104
|
-
if (
|
|
36107
|
+
if (existsSync46(candidate)) {
|
|
36105
36108
|
try {
|
|
36106
|
-
const meta = JSON.parse(
|
|
36109
|
+
const meta = JSON.parse(readFileSync46(candidate, "utf8"));
|
|
36107
36110
|
if (meta.expiresAt) {
|
|
36108
36111
|
tokenStr = " \u00b7 " + formatDaysFromNow(meta.expiresAt);
|
|
36109
36112
|
const daysLeft = Math.round((meta.expiresAt - Date.now()) / 86400000);
|
|
@@ -36278,9 +36281,9 @@ async function resolveTmuxSupervisorPid(agentName3, execFileImpl) {
|
|
|
36278
36281
|
if (!cgroup)
|
|
36279
36282
|
return null;
|
|
36280
36283
|
const procsPath = `/sys/fs/cgroup${cgroup}/cgroup.procs`;
|
|
36281
|
-
if (!
|
|
36284
|
+
if (!existsSync46(procsPath))
|
|
36282
36285
|
return null;
|
|
36283
|
-
const pidsRaw =
|
|
36286
|
+
const pidsRaw = readFileSync46(procsPath, "utf-8");
|
|
36284
36287
|
const pids = pidsRaw.split(`
|
|
36285
36288
|
`).map((s) => s.trim()).filter(Boolean);
|
|
36286
36289
|
if (pids.length === 0)
|
|
@@ -36293,7 +36296,7 @@ async function resolveTmuxSupervisorPid(agentName3, execFileImpl) {
|
|
|
36293
36296
|
let rss = 0;
|
|
36294
36297
|
let comm = "";
|
|
36295
36298
|
try {
|
|
36296
|
-
const status =
|
|
36299
|
+
const status = readFileSync46(`/proc/${pid}/status`, "utf-8");
|
|
36297
36300
|
const rssLine = status.split(`
|
|
36298
36301
|
`).find((l) => l.startsWith("VmRSS:"));
|
|
36299
36302
|
if (rssLine) {
|
|
@@ -36305,7 +36308,7 @@ async function resolveTmuxSupervisorPid(agentName3, execFileImpl) {
|
|
|
36305
36308
|
continue;
|
|
36306
36309
|
}
|
|
36307
36310
|
try {
|
|
36308
|
-
comm =
|
|
36311
|
+
comm = readFileSync46(`/proc/${pid}/comm`, "utf-8").trim();
|
|
36309
36312
|
} catch {}
|
|
36310
36313
|
candidates.push({ pid, rss, comm });
|
|
36311
36314
|
}
|
|
@@ -36485,9 +36488,9 @@ async function probeQuota(claudeConfigDir, _agentDir, fetchImpl = fetch, opts =
|
|
|
36485
36488
|
let claudeDirForProbe = null;
|
|
36486
36489
|
for (const candidate of [
|
|
36487
36490
|
claudeConfigDir,
|
|
36488
|
-
|
|
36491
|
+
join54(claudeConfigDir, "accounts", "default")
|
|
36489
36492
|
]) {
|
|
36490
|
-
if (
|
|
36493
|
+
if (existsSync46(join54(candidate, ".oauth-token"))) {
|
|
36491
36494
|
claudeDirForProbe = candidate;
|
|
36492
36495
|
break;
|
|
36493
36496
|
}
|
|
@@ -36552,7 +36555,7 @@ async function probeHindsight(bankName, fetchImpl = fetch) {
|
|
|
36552
36555
|
}
|
|
36553
36556
|
function readContainerBootTimeMsForProbe() {
|
|
36554
36557
|
try {
|
|
36555
|
-
const stat1 =
|
|
36558
|
+
const stat1 = readFileSync46("/proc/1/stat", "utf8");
|
|
36556
36559
|
const lastParen = stat1.lastIndexOf(")");
|
|
36557
36560
|
if (lastParen < 0)
|
|
36558
36561
|
return null;
|
|
@@ -36560,7 +36563,7 @@ function readContainerBootTimeMsForProbe() {
|
|
|
36560
36563
|
const starttimeTicks = Number(after[19]);
|
|
36561
36564
|
if (!Number.isFinite(starttimeTicks))
|
|
36562
36565
|
return null;
|
|
36563
|
-
const procStat =
|
|
36566
|
+
const procStat = readFileSync46("/proc/stat", "utf8");
|
|
36564
36567
|
const btimeLine = procStat.split(`
|
|
36565
36568
|
`).find((l) => l.startsWith("btime "));
|
|
36566
36569
|
if (!btimeLine)
|
|
@@ -36658,7 +36661,7 @@ async function probeUds(label, socketPath, opts = {}) {
|
|
|
36658
36661
|
}
|
|
36659
36662
|
return withTimeout(label, (async () => {
|
|
36660
36663
|
if (!opts.connectImpl) {
|
|
36661
|
-
if (!
|
|
36664
|
+
if (!existsSync46(socketPath)) {
|
|
36662
36665
|
return {
|
|
36663
36666
|
status: "fail",
|
|
36664
36667
|
label,
|
|
@@ -36722,7 +36725,7 @@ async function probeSkills(agentDir, opts = {}) {
|
|
|
36722
36725
|
return withTimeout("Skills", (async () => {
|
|
36723
36726
|
const fs3 = opts.fs ?? realSkillsFs;
|
|
36724
36727
|
const max = opts.maxNamesShown ?? 3;
|
|
36725
|
-
const skillsDir =
|
|
36728
|
+
const skillsDir = join54(agentDir, ".claude", "skills");
|
|
36726
36729
|
if (!fs3.exists(skillsDir)) {
|
|
36727
36730
|
return { status: "ok", label: "Skills", detail: "no skills dir" };
|
|
36728
36731
|
}
|
|
@@ -36737,17 +36740,17 @@ async function probeSkills(agentDir, opts = {}) {
|
|
|
36737
36740
|
}
|
|
36738
36741
|
const dangling = [];
|
|
36739
36742
|
for (const name of entries) {
|
|
36740
|
-
const skillPath =
|
|
36743
|
+
const skillPath = join54(skillsDir, name);
|
|
36741
36744
|
if (!fs3.exists(skillPath)) {
|
|
36742
36745
|
dangling.push(name);
|
|
36743
36746
|
continue;
|
|
36744
36747
|
}
|
|
36745
|
-
const skillMd =
|
|
36748
|
+
const skillMd = join54(skillPath, "SKILL.md");
|
|
36746
36749
|
if (!fs3.exists(skillMd) && !fs3.exists(skillPath + ".md")) {
|
|
36747
36750
|
continue;
|
|
36748
36751
|
}
|
|
36749
36752
|
}
|
|
36750
|
-
const overlayDir = opts.overlaySkillsDir ??
|
|
36753
|
+
const overlayDir = opts.overlaySkillsDir ?? join54(agentDir, "skills.d");
|
|
36751
36754
|
const overlaySlugs = new Set;
|
|
36752
36755
|
if (fs3.exists(overlayDir)) {
|
|
36753
36756
|
let overlayEntries = [];
|
|
@@ -36789,8 +36792,8 @@ function renderBucketedSkills(switchroom, agent) {
|
|
|
36789
36792
|
}
|
|
36790
36793
|
async function probeConnections(agentDir, opts = {}) {
|
|
36791
36794
|
return withTimeout("Connections", (async () => {
|
|
36792
|
-
const path3 =
|
|
36793
|
-
const read = opts.readFileImpl ?? ((p) =>
|
|
36795
|
+
const path3 = join54(agentDir, ".claude", "connection-health.json");
|
|
36796
|
+
const read = opts.readFileImpl ?? ((p) => readFileSync46(p, "utf8"));
|
|
36794
36797
|
let issues = [];
|
|
36795
36798
|
try {
|
|
36796
36799
|
const parsed = JSON.parse(read(path3));
|
|
@@ -36830,7 +36833,7 @@ async function probeDrift(agentDir, opts = {}) {
|
|
|
36830
36833
|
}
|
|
36831
36834
|
} catch {}
|
|
36832
36835
|
try {
|
|
36833
|
-
const raw =
|
|
36836
|
+
const raw = readFileSync46(join54(agentDir, ".switchroom-drift.json"), "utf8");
|
|
36834
36837
|
const report = JSON.parse(raw);
|
|
36835
36838
|
if (report?.version === 1 && Array.isArray(report.findings)) {
|
|
36836
36839
|
const gen = report.generatedAt ? Date.parse(report.generatedAt) : NaN;
|
|
@@ -36877,24 +36880,24 @@ var init_boot_probes = __esm(() => {
|
|
|
36877
36880
|
execFile = promisify(execFileCb);
|
|
36878
36881
|
realProcFs = {
|
|
36879
36882
|
readdir: (p) => readdirSync12(p),
|
|
36880
|
-
readFile: (p) =>
|
|
36883
|
+
readFile: (p) => readFileSync46(p, "utf-8")
|
|
36881
36884
|
};
|
|
36882
36885
|
realSchedulerFs = {
|
|
36883
|
-
readFile: (p) =>
|
|
36886
|
+
readFile: (p) => readFileSync46(p, "utf-8"),
|
|
36884
36887
|
mtimeMs: (p) => {
|
|
36885
36888
|
const { statSync: statSync17 } = __require("fs");
|
|
36886
36889
|
return statSync17(p).mtimeMs;
|
|
36887
36890
|
},
|
|
36888
|
-
exists: (p) =>
|
|
36891
|
+
exists: (p) => existsSync46(p)
|
|
36889
36892
|
};
|
|
36890
36893
|
realSkillsFs = {
|
|
36891
36894
|
readdir: (p) => readdirSync12(p),
|
|
36892
|
-
exists: (p) =>
|
|
36895
|
+
exists: (p) => existsSync46(p)
|
|
36893
36896
|
};
|
|
36894
36897
|
});
|
|
36895
36898
|
|
|
36896
36899
|
// gateway/boot-issue-cache.ts
|
|
36897
|
-
import { existsSync as
|
|
36900
|
+
import { existsSync as existsSync47, readFileSync as readFileSync47, writeFileSync as writeFileSync38, mkdirSync as mkdirSync40, renameSync as renameSync22 } from "fs";
|
|
36898
36901
|
import { dirname as dirname23 } from "path";
|
|
36899
36902
|
function fingerprintProbe(key, r) {
|
|
36900
36903
|
if (r.status === "ok")
|
|
@@ -36974,11 +36977,11 @@ function diffProbes(probes, cache, opts = {}) {
|
|
|
36974
36977
|
return out;
|
|
36975
36978
|
}
|
|
36976
36979
|
function loadCache(path3, now = Date.now) {
|
|
36977
|
-
if (!
|
|
36980
|
+
if (!existsSync47(path3))
|
|
36978
36981
|
return { ...EMPTY_CACHE, probes: {} };
|
|
36979
36982
|
let raw;
|
|
36980
36983
|
try {
|
|
36981
|
-
raw =
|
|
36984
|
+
raw = readFileSync47(path3, "utf-8");
|
|
36982
36985
|
} catch {
|
|
36983
36986
|
return { ...EMPTY_CACHE, probes: {} };
|
|
36984
36987
|
}
|
|
@@ -37037,7 +37040,7 @@ var init_boot_issue_cache = __esm(() => {
|
|
|
37037
37040
|
|
|
37038
37041
|
// gateway/config-snapshot.ts
|
|
37039
37042
|
import { createHash as createHash7 } from "crypto";
|
|
37040
|
-
import { existsSync as
|
|
37043
|
+
import { existsSync as existsSync48, readFileSync as readFileSync48, writeFileSync as writeFileSync39, mkdirSync as mkdirSync41, renameSync as renameSync23 } from "fs";
|
|
37041
37044
|
import { dirname as dirname24 } from "path";
|
|
37042
37045
|
function hashStringArray(items) {
|
|
37043
37046
|
if (!items || items.length === 0)
|
|
@@ -37102,11 +37105,11 @@ function renderConfigChangeDim(dim) {
|
|
|
37102
37105
|
}
|
|
37103
37106
|
}
|
|
37104
37107
|
function loadSnapshot(path3, now = Date.now) {
|
|
37105
|
-
if (!
|
|
37108
|
+
if (!existsSync48(path3))
|
|
37106
37109
|
return null;
|
|
37107
37110
|
let raw;
|
|
37108
37111
|
try {
|
|
37109
|
-
raw =
|
|
37112
|
+
raw = readFileSync48(path3, "utf-8");
|
|
37110
37113
|
} catch {
|
|
37111
37114
|
return null;
|
|
37112
37115
|
}
|
|
@@ -37147,13 +37150,13 @@ var init_config_snapshot = __esm(() => {
|
|
|
37147
37150
|
});
|
|
37148
37151
|
|
|
37149
37152
|
// gateway/boot-card-msgid.ts
|
|
37150
|
-
import { readFileSync as
|
|
37153
|
+
import { readFileSync as readFileSync49, writeFileSync as writeFileSync40 } from "node:fs";
|
|
37151
37154
|
function bootCardChatKey(chatId, threadId) {
|
|
37152
37155
|
return `${chatId}:${threadId ?? ""}`;
|
|
37153
37156
|
}
|
|
37154
37157
|
function readStore(path3) {
|
|
37155
37158
|
try {
|
|
37156
|
-
const parsed = JSON.parse(
|
|
37159
|
+
const parsed = JSON.parse(readFileSync49(path3, "utf8"));
|
|
37157
37160
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
37158
37161
|
return parsed;
|
|
37159
37162
|
}
|
|
@@ -37190,8 +37193,8 @@ __export(exports_boot_card, {
|
|
|
37190
37193
|
readRoutingMode: () => readRoutingMode,
|
|
37191
37194
|
containerBootStartMs: () => containerBootStartMs
|
|
37192
37195
|
});
|
|
37193
|
-
import { join as
|
|
37194
|
-
import { readFileSync as
|
|
37196
|
+
import { join as join55 } from "path";
|
|
37197
|
+
import { readFileSync as readFileSync50, statSync as statSync17 } from "fs";
|
|
37195
37198
|
function resolvePersonaName(slug, loadConfig3) {
|
|
37196
37199
|
try {
|
|
37197
37200
|
const config = loadConfig3 ? loadConfig3() : loadConfig();
|
|
@@ -37213,7 +37216,7 @@ function shouldSkipDuplicateBootCard(gate, site) {
|
|
|
37213
37216
|
}
|
|
37214
37217
|
return { skip: false };
|
|
37215
37218
|
}
|
|
37216
|
-
function containerBootStartMs(fsImpl = { readFileSync:
|
|
37219
|
+
function containerBootStartMs(fsImpl = { readFileSync: readFileSync50 }) {
|
|
37217
37220
|
try {
|
|
37218
37221
|
const btimeLine = fsImpl.readFileSync("/proc/stat", "utf-8").split(`
|
|
37219
37222
|
`).find((l) => l.startsWith("btime "));
|
|
@@ -37234,8 +37237,8 @@ function containerBootStartMs(fsImpl = { readFileSync: readFileSync49 }) {
|
|
|
37234
37237
|
return null;
|
|
37235
37238
|
}
|
|
37236
37239
|
}
|
|
37237
|
-
function readRoutingMode(agentDir, bootStartMs, fsImpl = { readFileSync:
|
|
37238
|
-
const path3 =
|
|
37240
|
+
function readRoutingMode(agentDir, bootStartMs, fsImpl = { readFileSync: readFileSync50, statSync: statSync17 }) {
|
|
37241
|
+
const path3 = join55(agentDir, ".routing-mode");
|
|
37239
37242
|
try {
|
|
37240
37243
|
const raw = fsImpl.readFileSync(path3, "utf-8");
|
|
37241
37244
|
const line = raw.split(`
|
|
@@ -37342,7 +37345,7 @@ function renderBootCard(opts) {
|
|
|
37342
37345
|
return stackCardLines(flatLines);
|
|
37343
37346
|
}
|
|
37344
37347
|
async function runAllProbes(opts) {
|
|
37345
|
-
const claudeDir =
|
|
37348
|
+
const claudeDir = join55(opts.agentDir, ".claude");
|
|
37346
37349
|
const probes = {};
|
|
37347
37350
|
const slug = opts.agentSlug ?? opts.agentName;
|
|
37348
37351
|
await Promise.allSettled([
|
|
@@ -39140,7 +39143,7 @@ __export(exports_materialize_bot_token, {
|
|
|
39140
39143
|
materializeBotToken: () => materializeBotToken,
|
|
39141
39144
|
BotTokenMaterializeError: () => BotTokenMaterializeError
|
|
39142
39145
|
});
|
|
39143
|
-
import { existsSync as
|
|
39146
|
+
import { existsSync as existsSync57 } from "node:fs";
|
|
39144
39147
|
function pickConfiguredToken(config, agentName3) {
|
|
39145
39148
|
if (agentName3) {
|
|
39146
39149
|
const agent = config.agents?.[agentName3];
|
|
@@ -39154,7 +39157,7 @@ function tryDirectVaultRead4(ref, config, passphrase) {
|
|
|
39154
39157
|
if (!passphrase)
|
|
39155
39158
|
return null;
|
|
39156
39159
|
const vaultPath = resolvePath(config.vault?.path ?? "~/.switchroom/vault.enc");
|
|
39157
|
-
if (!
|
|
39160
|
+
if (!existsSync57(vaultPath))
|
|
39158
39161
|
return null;
|
|
39159
39162
|
try {
|
|
39160
39163
|
const secrets = openVault(passphrase, vaultPath);
|
|
@@ -39309,18 +39312,18 @@ var import_runner3 = __toESM(require_mod3(), 1);
|
|
|
39309
39312
|
import { randomBytes as randomBytes13, createHash as createHash8 } from "crypto";
|
|
39310
39313
|
import { execFileSync as execFileSync9, execSync as execSync2, spawn as spawn2 } from "child_process";
|
|
39311
39314
|
import {
|
|
39312
|
-
readFileSync as
|
|
39315
|
+
readFileSync as readFileSync61,
|
|
39313
39316
|
writeFileSync as writeFileSync50,
|
|
39314
39317
|
mkdirSync as mkdirSync51,
|
|
39315
39318
|
readdirSync as readdirSync16,
|
|
39316
39319
|
rmSync as rmSync8,
|
|
39317
39320
|
statSync as statSync23,
|
|
39318
39321
|
renameSync as renameSync27,
|
|
39319
|
-
realpathSync as
|
|
39322
|
+
realpathSync as realpathSync5,
|
|
39320
39323
|
chmodSync as chmodSync14,
|
|
39321
39324
|
openSync as openSync15,
|
|
39322
39325
|
closeSync as closeSync15,
|
|
39323
|
-
existsSync as
|
|
39326
|
+
existsSync as existsSync58,
|
|
39324
39327
|
unlinkSync as unlinkSync31,
|
|
39325
39328
|
appendFileSync as appendFileSync9
|
|
39326
39329
|
} from "fs";
|
|
@@ -39376,7 +39379,7 @@ function fsyncPathSync(path) {
|
|
|
39376
39379
|
|
|
39377
39380
|
// gateway/gateway.ts
|
|
39378
39381
|
import { homedir as homedir20 } from "os";
|
|
39379
|
-
import { join as
|
|
39382
|
+
import { join as join68, sep as sep4, basename as basename17 } from "path";
|
|
39380
39383
|
|
|
39381
39384
|
// plugin-logger.ts
|
|
39382
39385
|
import { appendFileSync, mkdirSync, renameSync as renameSync2, statSync, existsSync } from "fs";
|
|
@@ -41866,7 +41869,8 @@ function normalizeForDedup(text) {
|
|
|
41866
41869
|
}
|
|
41867
41870
|
|
|
41868
41871
|
// flushed-turn-supersede.ts
|
|
41869
|
-
var
|
|
41872
|
+
var SUPERSEDE_OPEN_WINDOW_CAP_MS = 30 * 60000;
|
|
41873
|
+
var SUPERSEDE_COMPLETED_GRACE_MS = 60000;
|
|
41870
41874
|
var SUPERSEDE_MATCH_MIN_CONTAINMENT_CHARS = 32;
|
|
41871
41875
|
function normalizeForMatch(text) {
|
|
41872
41876
|
return text.replace(/\s+/g, " ").trim();
|
|
@@ -41885,10 +41889,12 @@ function flushedAnswerMatchesReply(flushedText, replyText) {
|
|
|
41885
41889
|
return false;
|
|
41886
41890
|
}
|
|
41887
41891
|
function decideSupersede(record, args) {
|
|
41888
|
-
const
|
|
41892
|
+
const openCapMs = args.openCapMs ?? SUPERSEDE_OPEN_WINDOW_CAP_MS;
|
|
41893
|
+
const completedGraceMs = args.completedGraceMs ?? SUPERSEDE_COMPLETED_GRACE_MS;
|
|
41889
41894
|
if (record == null)
|
|
41890
41895
|
return { supersede: false, deleteMessageIds: [], reason: "no-record" };
|
|
41891
|
-
|
|
41896
|
+
const expired = record.completedAt == null ? args.now - record.ts > openCapMs : args.now - record.completedAt > completedGraceMs;
|
|
41897
|
+
if (expired) {
|
|
41892
41898
|
return { supersede: false, deleteMessageIds: [], reason: "expired" };
|
|
41893
41899
|
}
|
|
41894
41900
|
const sameTurn = record.turnId != null ? record.turnId === args.liveTurnId : args.liveTurnId == null;
|
|
@@ -41912,9 +41918,11 @@ function turnKey(turnId) {
|
|
|
41912
41918
|
|
|
41913
41919
|
class FlushedTurnSupersedeRegistry {
|
|
41914
41920
|
entries = new Map;
|
|
41915
|
-
|
|
41921
|
+
openCapMs;
|
|
41922
|
+
completedGraceMs;
|
|
41916
41923
|
constructor(opts = {}) {
|
|
41917
|
-
this.
|
|
41924
|
+
this.openCapMs = opts.openCapMs ?? SUPERSEDE_OPEN_WINDOW_CAP_MS;
|
|
41925
|
+
this.completedGraceMs = opts.completedGraceMs ?? SUPERSEDE_COMPLETED_GRACE_MS;
|
|
41918
41926
|
}
|
|
41919
41927
|
record(chatId, threadId, rec, now) {
|
|
41920
41928
|
if (rec.messageIds.length === 0)
|
|
@@ -41930,9 +41938,18 @@ class FlushedTurnSupersedeRegistry {
|
|
|
41930
41938
|
turnId: rec.turnId,
|
|
41931
41939
|
messageIds: [...rec.messageIds],
|
|
41932
41940
|
text: rec.text,
|
|
41933
|
-
ts: now
|
|
41941
|
+
ts: now,
|
|
41942
|
+
completedAt: rec.completedAt ?? null
|
|
41934
41943
|
});
|
|
41935
41944
|
}
|
|
41945
|
+
completeAll(now) {
|
|
41946
|
+
for (const laneMap of this.entries.values()) {
|
|
41947
|
+
for (const rec of laneMap.values()) {
|
|
41948
|
+
if (rec.completedAt == null)
|
|
41949
|
+
rec.completedAt = now;
|
|
41950
|
+
}
|
|
41951
|
+
}
|
|
41952
|
+
}
|
|
41936
41953
|
peek(chatId, threadId, args) {
|
|
41937
41954
|
const rec = this.entries.get(makeKey2(chatId, threadId))?.get(turnKey(args.liveTurnId));
|
|
41938
41955
|
return decideSupersede(rec, {
|
|
@@ -41940,7 +41957,8 @@ class FlushedTurnSupersedeRegistry {
|
|
|
41940
41957
|
replyText: args.replyText,
|
|
41941
41958
|
positiveAttribution: args.positiveAttribution,
|
|
41942
41959
|
now: args.now,
|
|
41943
|
-
|
|
41960
|
+
openCapMs: this.openCapMs,
|
|
41961
|
+
completedGraceMs: this.completedGraceMs
|
|
41944
41962
|
});
|
|
41945
41963
|
}
|
|
41946
41964
|
take(chatId, threadId, args) {
|
|
@@ -41963,7 +41981,8 @@ class FlushedTurnSupersedeRegistry {
|
|
|
41963
41981
|
sweep(now) {
|
|
41964
41982
|
for (const [lane, laneMap] of this.entries) {
|
|
41965
41983
|
for (const [tk, rec] of laneMap) {
|
|
41966
|
-
|
|
41984
|
+
const expired = rec.completedAt == null ? now - rec.ts > this.openCapMs : now - rec.completedAt > this.completedGraceMs;
|
|
41985
|
+
if (expired)
|
|
41967
41986
|
laneMap.delete(tk);
|
|
41968
41987
|
}
|
|
41969
41988
|
if (laneMap.size === 0)
|
|
@@ -41982,6 +42001,302 @@ function makeKey2(chatId, threadId) {
|
|
|
41982
42001
|
return threadId == null ? chatId : `${chatId}|${threadId}`;
|
|
41983
42002
|
}
|
|
41984
42003
|
|
|
42004
|
+
// flushed-turn-supersede.ts
|
|
42005
|
+
var SUPERSEDE_OPEN_WINDOW_CAP_MS2 = 30 * 60000;
|
|
42006
|
+
var SUPERSEDE_COMPLETED_GRACE_MS2 = 60000;
|
|
42007
|
+
var SUPERSEDE_MATCH_MIN_CONTAINMENT_CHARS2 = 32;
|
|
42008
|
+
function normalizeForMatch2(text) {
|
|
42009
|
+
return text.replace(/\s+/g, " ").trim();
|
|
42010
|
+
}
|
|
42011
|
+
function flushedAnswerMatchesReply2(flushedText, replyText) {
|
|
42012
|
+
const flushed = normalizeForMatch2(flushedText);
|
|
42013
|
+
const reply = normalizeForMatch2(replyText);
|
|
42014
|
+
if (flushed.length === 0 || reply.length === 0)
|
|
42015
|
+
return false;
|
|
42016
|
+
if (flushed === reply)
|
|
42017
|
+
return true;
|
|
42018
|
+
if (reply.length >= SUPERSEDE_MATCH_MIN_CONTAINMENT_CHARS2 && flushed.includes(reply))
|
|
42019
|
+
return true;
|
|
42020
|
+
if (flushed.length >= SUPERSEDE_MATCH_MIN_CONTAINMENT_CHARS2 && reply.includes(flushed))
|
|
42021
|
+
return true;
|
|
42022
|
+
return false;
|
|
42023
|
+
}
|
|
42024
|
+
function decideSupersede2(record, args) {
|
|
42025
|
+
const openCapMs = args.openCapMs ?? SUPERSEDE_OPEN_WINDOW_CAP_MS2;
|
|
42026
|
+
const completedGraceMs = args.completedGraceMs ?? SUPERSEDE_COMPLETED_GRACE_MS2;
|
|
42027
|
+
if (record == null)
|
|
42028
|
+
return { supersede: false, deleteMessageIds: [], reason: "no-record" };
|
|
42029
|
+
const expired = record.completedAt == null ? args.now - record.ts > openCapMs : args.now - record.completedAt > completedGraceMs;
|
|
42030
|
+
if (expired) {
|
|
42031
|
+
return { supersede: false, deleteMessageIds: [], reason: "expired" };
|
|
42032
|
+
}
|
|
42033
|
+
const sameTurn = record.turnId != null ? record.turnId === args.liveTurnId : args.liveTurnId == null;
|
|
42034
|
+
if (!sameTurn) {
|
|
42035
|
+
return { supersede: false, deleteMessageIds: [], reason: "different-turn" };
|
|
42036
|
+
}
|
|
42037
|
+
if (!args.positiveAttribution && args.replyText != null && !flushedAnswerMatchesReply2(record.text, args.replyText)) {
|
|
42038
|
+
return { supersede: false, deleteMessageIds: [], reason: "new-content", recordText: record.text };
|
|
42039
|
+
}
|
|
42040
|
+
return {
|
|
42041
|
+
supersede: true,
|
|
42042
|
+
deleteMessageIds: [...record.messageIds],
|
|
42043
|
+
reason: "supersede",
|
|
42044
|
+
recordText: record.text
|
|
42045
|
+
};
|
|
42046
|
+
}
|
|
42047
|
+
function decideSupersedeCorrection(input) {
|
|
42048
|
+
const eligible = input.flushMessageIds.length === 1 && input.chunkCount === 1 && !input.hasFiles && !input.suppressText && !input.hasOpenPreview;
|
|
42049
|
+
if (eligible) {
|
|
42050
|
+
return { mode: "edit-in-place", editMessageId: input.flushMessageIds[0], deleteMessageIds: [] };
|
|
42051
|
+
}
|
|
42052
|
+
return { mode: "delete-resend", deleteMessageIds: [...input.flushMessageIds] };
|
|
42053
|
+
}
|
|
42054
|
+
var NULL_TURN_KEY2 = "<<null-turn>>";
|
|
42055
|
+
function turnKey2(turnId) {
|
|
42056
|
+
return turnId == null ? NULL_TURN_KEY2 : turnId;
|
|
42057
|
+
}
|
|
42058
|
+
|
|
42059
|
+
class FlushedTurnSupersedeRegistry2 {
|
|
42060
|
+
entries = new Map;
|
|
42061
|
+
openCapMs;
|
|
42062
|
+
completedGraceMs;
|
|
42063
|
+
constructor(opts = {}) {
|
|
42064
|
+
this.openCapMs = opts.openCapMs ?? SUPERSEDE_OPEN_WINDOW_CAP_MS2;
|
|
42065
|
+
this.completedGraceMs = opts.completedGraceMs ?? SUPERSEDE_COMPLETED_GRACE_MS2;
|
|
42066
|
+
}
|
|
42067
|
+
record(chatId, threadId, rec, now) {
|
|
42068
|
+
if (rec.messageIds.length === 0)
|
|
42069
|
+
return;
|
|
42070
|
+
this.sweep(now);
|
|
42071
|
+
const lane = makeKey3(chatId, threadId);
|
|
42072
|
+
let laneMap = this.entries.get(lane);
|
|
42073
|
+
if (laneMap == null) {
|
|
42074
|
+
laneMap = new Map;
|
|
42075
|
+
this.entries.set(lane, laneMap);
|
|
42076
|
+
}
|
|
42077
|
+
laneMap.set(turnKey2(rec.turnId), {
|
|
42078
|
+
turnId: rec.turnId,
|
|
42079
|
+
messageIds: [...rec.messageIds],
|
|
42080
|
+
text: rec.text,
|
|
42081
|
+
ts: now,
|
|
42082
|
+
completedAt: rec.completedAt ?? null
|
|
42083
|
+
});
|
|
42084
|
+
}
|
|
42085
|
+
completeAll(now) {
|
|
42086
|
+
for (const laneMap of this.entries.values()) {
|
|
42087
|
+
for (const rec of laneMap.values()) {
|
|
42088
|
+
if (rec.completedAt == null)
|
|
42089
|
+
rec.completedAt = now;
|
|
42090
|
+
}
|
|
42091
|
+
}
|
|
42092
|
+
}
|
|
42093
|
+
peek(chatId, threadId, args) {
|
|
42094
|
+
const rec = this.entries.get(makeKey3(chatId, threadId))?.get(turnKey2(args.liveTurnId));
|
|
42095
|
+
return decideSupersede2(rec, {
|
|
42096
|
+
liveTurnId: args.liveTurnId,
|
|
42097
|
+
replyText: args.replyText,
|
|
42098
|
+
positiveAttribution: args.positiveAttribution,
|
|
42099
|
+
now: args.now,
|
|
42100
|
+
openCapMs: this.openCapMs,
|
|
42101
|
+
completedGraceMs: this.completedGraceMs
|
|
42102
|
+
});
|
|
42103
|
+
}
|
|
42104
|
+
take(chatId, threadId, args) {
|
|
42105
|
+
const lane = makeKey3(chatId, threadId);
|
|
42106
|
+
const decision = this.peek(chatId, threadId, args);
|
|
42107
|
+
if (decision.supersede) {
|
|
42108
|
+
const laneMap = this.entries.get(lane);
|
|
42109
|
+
laneMap?.delete(turnKey2(args.liveTurnId));
|
|
42110
|
+
if (laneMap != null && laneMap.size === 0)
|
|
42111
|
+
this.entries.delete(lane);
|
|
42112
|
+
}
|
|
42113
|
+
return decision;
|
|
42114
|
+
}
|
|
42115
|
+
forget(chatId, threadId) {
|
|
42116
|
+
this.entries.delete(makeKey3(chatId, threadId));
|
|
42117
|
+
}
|
|
42118
|
+
clear() {
|
|
42119
|
+
this.entries.clear();
|
|
42120
|
+
}
|
|
42121
|
+
sweep(now) {
|
|
42122
|
+
for (const [lane, laneMap] of this.entries) {
|
|
42123
|
+
for (const [tk, rec] of laneMap) {
|
|
42124
|
+
const expired = rec.completedAt == null ? now - rec.ts > this.openCapMs : now - rec.completedAt > this.completedGraceMs;
|
|
42125
|
+
if (expired)
|
|
42126
|
+
laneMap.delete(tk);
|
|
42127
|
+
}
|
|
42128
|
+
if (laneMap.size === 0)
|
|
42129
|
+
this.entries.delete(lane);
|
|
42130
|
+
}
|
|
42131
|
+
}
|
|
42132
|
+
size(now) {
|
|
42133
|
+
this.sweep(now);
|
|
42134
|
+
let total = 0;
|
|
42135
|
+
for (const laneMap of this.entries.values())
|
|
42136
|
+
total += laneMap.size;
|
|
42137
|
+
return total;
|
|
42138
|
+
}
|
|
42139
|
+
}
|
|
42140
|
+
function makeKey3(chatId, threadId) {
|
|
42141
|
+
return threadId == null ? chatId : `${chatId}|${threadId}`;
|
|
42142
|
+
}
|
|
42143
|
+
|
|
42144
|
+
class FlushCompletionTracker {
|
|
42145
|
+
pending = [];
|
|
42146
|
+
open(turn) {
|
|
42147
|
+
turn.realEndObservedAt = null;
|
|
42148
|
+
if (!this.pending.includes(turn))
|
|
42149
|
+
this.pending.push(turn);
|
|
42150
|
+
}
|
|
42151
|
+
closeAll(now) {
|
|
42152
|
+
let closed = 0;
|
|
42153
|
+
for (const turn of this.pending) {
|
|
42154
|
+
if (turn.realEndObservedAt == null) {
|
|
42155
|
+
turn.realEndObservedAt = now;
|
|
42156
|
+
closed++;
|
|
42157
|
+
}
|
|
42158
|
+
}
|
|
42159
|
+
this.pending = [];
|
|
42160
|
+
return closed;
|
|
42161
|
+
}
|
|
42162
|
+
pendingCount() {
|
|
42163
|
+
return this.pending.length;
|
|
42164
|
+
}
|
|
42165
|
+
}
|
|
42166
|
+
|
|
42167
|
+
// reply-owner-resolve.ts
|
|
42168
|
+
function latestEndedAccepted(candidates) {
|
|
42169
|
+
if (candidates.latestEndedTurnId == null)
|
|
42170
|
+
return false;
|
|
42171
|
+
const age = candidates.latestEndedAgeMs;
|
|
42172
|
+
const ttl = candidates.latestEndedTtlMs;
|
|
42173
|
+
if (age == null || ttl == null)
|
|
42174
|
+
return false;
|
|
42175
|
+
const realEndAge = candidates.latestEndedRealEndAgeMs;
|
|
42176
|
+
if (realEndAge === undefined || realEndAge === null) {
|
|
42177
|
+
return age <= ttl;
|
|
42178
|
+
}
|
|
42179
|
+
const grace = candidates.latestEndedCompletedGraceMs ?? SUPERSEDE_COMPLETED_GRACE_MS2;
|
|
42180
|
+
return realEndAge <= grace;
|
|
42181
|
+
}
|
|
42182
|
+
function resolveReplyOwnerTier(candidates) {
|
|
42183
|
+
if (candidates.liveTurnId != null)
|
|
42184
|
+
return "live";
|
|
42185
|
+
if (candidates.originTurnId != null)
|
|
42186
|
+
return "origin";
|
|
42187
|
+
if (candidates.quotedTurnId != null)
|
|
42188
|
+
return "quoted";
|
|
42189
|
+
if (latestEndedAccepted(candidates))
|
|
42190
|
+
return "latest-ended";
|
|
42191
|
+
return "none";
|
|
42192
|
+
}
|
|
42193
|
+
function resolveReplyOwnerTurnId(candidates) {
|
|
42194
|
+
switch (resolveReplyOwnerTier(candidates)) {
|
|
42195
|
+
case "live":
|
|
42196
|
+
return candidates.liveTurnId;
|
|
42197
|
+
case "origin":
|
|
42198
|
+
return candidates.originTurnId;
|
|
42199
|
+
case "quoted":
|
|
42200
|
+
return candidates.quotedTurnId;
|
|
42201
|
+
case "latest-ended":
|
|
42202
|
+
return candidates.latestEndedTurnId;
|
|
42203
|
+
case "none":
|
|
42204
|
+
return null;
|
|
42205
|
+
}
|
|
42206
|
+
}
|
|
42207
|
+
function decideContentGateBypass(input) {
|
|
42208
|
+
if (input.tier === "live")
|
|
42209
|
+
return true;
|
|
42210
|
+
if (input.tier === "none")
|
|
42211
|
+
return false;
|
|
42212
|
+
if (input.handbackCouldOwnReply)
|
|
42213
|
+
return false;
|
|
42214
|
+
if (input.subagentCouldOwnReply !== false)
|
|
42215
|
+
return false;
|
|
42216
|
+
if (input.candidates == null)
|
|
42217
|
+
return false;
|
|
42218
|
+
if (!latestEndedAccepted(input.candidates))
|
|
42219
|
+
return false;
|
|
42220
|
+
return input.resolvedTurnId != null && input.resolvedTurnId === input.candidates.latestEndedTurnId;
|
|
42221
|
+
}
|
|
42222
|
+
function decideAnswerLatchSuppression(input) {
|
|
42223
|
+
if (input.superseded)
|
|
42224
|
+
return false;
|
|
42225
|
+
if (!input.replySubstantive)
|
|
42226
|
+
return false;
|
|
42227
|
+
if (!input.isLateReply)
|
|
42228
|
+
return false;
|
|
42229
|
+
if (input.replyMatchesFlushedAnswer === false)
|
|
42230
|
+
return false;
|
|
42231
|
+
return input.ownerAnswerDelivered === "flush";
|
|
42232
|
+
}
|
|
42233
|
+
|
|
42234
|
+
// gateway/reply-owner-wiring.ts
|
|
42235
|
+
var SUPERSEDE_OPEN_CAP_MS = (() => {
|
|
42236
|
+
const raw = Number(process.env.SWITCHROOM_SUPERSEDE_OPEN_CAP_MS);
|
|
42237
|
+
return Number.isFinite(raw) && raw > 0 ? raw : SUPERSEDE_OPEN_WINDOW_CAP_MS2;
|
|
42238
|
+
})();
|
|
42239
|
+
var SUPERSEDE_GRACE_MS = (() => {
|
|
42240
|
+
const raw = Number(process.env.SWITCHROOM_SUPERSEDE_GRACE_MS);
|
|
42241
|
+
return Number.isFinite(raw) && raw > 0 ? raw : SUPERSEDE_COMPLETED_GRACE_MS2;
|
|
42242
|
+
})();
|
|
42243
|
+
function resolveReplyOwnerTurnWith(lookups, liveTurn, chatId, args) {
|
|
42244
|
+
const origin = lookups.findTurnByOriginId(args.origin_turn_id);
|
|
42245
|
+
const quoted = lookups.findTurnByQuotedMessageId(chatId, args.reply_to);
|
|
42246
|
+
const latestEnded = lookups.findLatestTurnForChat(chatId, { endedOnly: true });
|
|
42247
|
+
const byId = new Map;
|
|
42248
|
+
for (const t of [latestEnded, quoted, origin, liveTurn]) {
|
|
42249
|
+
if (t != null)
|
|
42250
|
+
byId.set(t.turnId, t);
|
|
42251
|
+
}
|
|
42252
|
+
const latestEndedAgeMs = latestEnded?.endedAt != null ? lookups.now() - latestEnded.endedAt : null;
|
|
42253
|
+
const latestEndedRealEndAgeMs = latestEnded == null ? null : latestEnded.realEndObservedAt != null ? lookups.now() - latestEnded.realEndObservedAt : null;
|
|
42254
|
+
const candidates = {
|
|
42255
|
+
liveTurnId: liveTurn?.turnId ?? null,
|
|
42256
|
+
originTurnId: origin?.turnId ?? null,
|
|
42257
|
+
quotedTurnId: quoted?.turnId ?? null,
|
|
42258
|
+
latestEndedTurnId: latestEnded?.turnId ?? null,
|
|
42259
|
+
latestEndedAgeMs,
|
|
42260
|
+
latestEndedTtlMs: SUPERSEDE_OPEN_CAP_MS,
|
|
42261
|
+
latestEndedRealEndAgeMs,
|
|
42262
|
+
latestEndedCompletedGraceMs: SUPERSEDE_GRACE_MS
|
|
42263
|
+
};
|
|
42264
|
+
const tier = resolveReplyOwnerTier(candidates);
|
|
42265
|
+
const winnerId = resolveReplyOwnerTurnId(candidates);
|
|
42266
|
+
return { turn: winnerId != null ? byId.get(winnerId) ?? null : null, tier, candidates };
|
|
42267
|
+
}
|
|
42268
|
+
|
|
42269
|
+
// gateway/subagent-reply-authority.ts
|
|
42270
|
+
var SUB_AGENT_KIND_PREFIX = "sub_agent_";
|
|
42271
|
+
|
|
42272
|
+
class SubagentReplyAuthority {
|
|
42273
|
+
live = new Set;
|
|
42274
|
+
noteSessionEvent(ev) {
|
|
42275
|
+
if (ev == null)
|
|
42276
|
+
return;
|
|
42277
|
+
const kind = ev.kind;
|
|
42278
|
+
if (typeof kind !== "string" || !kind.startsWith(SUB_AGENT_KIND_PREFIX))
|
|
42279
|
+
return;
|
|
42280
|
+
const agentId = ev.agentId;
|
|
42281
|
+
if (typeof agentId !== "string" || agentId === "")
|
|
42282
|
+
return;
|
|
42283
|
+
if (kind === `${SUB_AGENT_KIND_PREFIX}turn_end`)
|
|
42284
|
+
this.live.delete(agentId);
|
|
42285
|
+
else
|
|
42286
|
+
this.live.add(agentId);
|
|
42287
|
+
}
|
|
42288
|
+
subagentCouldOwnReply() {
|
|
42289
|
+
return this.live.size > 0;
|
|
42290
|
+
}
|
|
42291
|
+
reset() {
|
|
42292
|
+
this.live.clear();
|
|
42293
|
+
}
|
|
42294
|
+
liveCount() {
|
|
42295
|
+
return this.live.size;
|
|
42296
|
+
}
|
|
42297
|
+
}
|
|
42298
|
+
var subagentReplyAuthority = new SubagentReplyAuthority;
|
|
42299
|
+
|
|
41985
42300
|
// gateway/inbound-coalesce.ts
|
|
41986
42301
|
function createInboundCoalescer(opts) {
|
|
41987
42302
|
const buffer = new Map;
|
|
@@ -53951,11 +54266,11 @@ function createHandbackPreturnSignal(deps) {
|
|
|
53951
54266
|
}
|
|
53952
54267
|
return false;
|
|
53953
54268
|
},
|
|
53954
|
-
isPreTurnRecord(
|
|
53955
|
-
return
|
|
54269
|
+
isPreTurnRecord(turnKey3) {
|
|
54270
|
+
return turnKey3.startsWith(PRETURN_TURNKEY_PREFIX);
|
|
53956
54271
|
},
|
|
53957
|
-
handleReaped(
|
|
53958
|
-
const statusKey = bySyntheticKey.get(
|
|
54272
|
+
handleReaped(turnKey3) {
|
|
54273
|
+
const statusKey = bySyntheticKey.get(turnKey3);
|
|
53959
54274
|
if (statusKey == null)
|
|
53960
54275
|
return;
|
|
53961
54276
|
const entry = byKey.get(statusKey);
|
|
@@ -71285,16 +71600,16 @@ function writeSilentEndState(args, deps) {
|
|
|
71285
71600
|
`);
|
|
71286
71601
|
}
|
|
71287
71602
|
}
|
|
71288
|
-
function clearSilentEndState(
|
|
71603
|
+
function clearSilentEndState(turnKey3, deps) {
|
|
71289
71604
|
const statePath = resolveStatePath2(deps);
|
|
71290
71605
|
if (!existsSync16(statePath))
|
|
71291
71606
|
return;
|
|
71292
71607
|
try {
|
|
71293
71608
|
const prev = JSON.parse(readFileSync18(statePath, "utf8"));
|
|
71294
|
-
if (prev.turnKey != null && prev.turnKey !==
|
|
71609
|
+
if (prev.turnKey != null && prev.turnKey !== turnKey3)
|
|
71295
71610
|
return;
|
|
71296
71611
|
unlinkSync12(statePath);
|
|
71297
|
-
emitLog(deps, `silent-end: cleared state file turnKey=${
|
|
71612
|
+
emitLog(deps, `silent-end: cleared state file turnKey=${turnKey3}
|
|
71298
71613
|
`);
|
|
71299
71614
|
} catch {}
|
|
71300
71615
|
}
|
|
@@ -75369,12 +75684,12 @@ class PendingUserNoticeGate {
|
|
|
75369
75684
|
this.pending = this.pending.filter((p) => !(p.agent === notice.agent && p.key === notice.key));
|
|
75370
75685
|
this.pending.push(notice);
|
|
75371
75686
|
}
|
|
75372
|
-
resolveTurnEnd(
|
|
75687
|
+
resolveTurnEnd(turnKey3, turnDeliveredReply, now = Date.now()) {
|
|
75373
75688
|
this.prune(now);
|
|
75374
75689
|
const resolved = [];
|
|
75375
75690
|
const remaining = [];
|
|
75376
75691
|
for (const p of this.pending) {
|
|
75377
|
-
if (p.key ===
|
|
75692
|
+
if (p.key === turnKey3 || p.key === undefined)
|
|
75378
75693
|
resolved.push(p);
|
|
75379
75694
|
else
|
|
75380
75695
|
remaining.push(p);
|
|
@@ -78002,166 +78317,76 @@ ${input.newReplyText}`;
|
|
|
78002
78317
|
};
|
|
78003
78318
|
}
|
|
78004
78319
|
|
|
78005
|
-
//
|
|
78006
|
-
var
|
|
78007
|
-
|
|
78008
|
-
|
|
78009
|
-
|
|
78010
|
-
}
|
|
78011
|
-
|
|
78012
|
-
|
|
78013
|
-
|
|
78014
|
-
|
|
78320
|
+
// gateway/subagent-handback-marker.ts
|
|
78321
|
+
var INBOUND_SOURCE_CLASSIFICATION = {
|
|
78322
|
+
subagent_handback: { decoupledCompletion: true },
|
|
78323
|
+
cron: { decoupledCompletion: false },
|
|
78324
|
+
reaction: { decoupledCompletion: false },
|
|
78325
|
+
subagent_progress: { decoupledCompletion: false },
|
|
78326
|
+
resume_interrupted: { decoupledCompletion: false },
|
|
78327
|
+
resume_deferred: { decoupledCompletion: false },
|
|
78328
|
+
resume_watchdog_timeout: { decoupledCompletion: false },
|
|
78329
|
+
vault_grant_approved: { decoupledCompletion: false },
|
|
78330
|
+
vault_grant_denied: { decoupledCompletion: false },
|
|
78331
|
+
vault_grant_timeout: { decoupledCompletion: false },
|
|
78332
|
+
vault_save_completed: { decoupledCompletion: false },
|
|
78333
|
+
vault_save_discarded: { decoupledCompletion: false },
|
|
78334
|
+
vault_save_failed: { decoupledCompletion: false },
|
|
78335
|
+
vault_save_timeout: { decoupledCompletion: false },
|
|
78336
|
+
secret_provided: { decoupledCompletion: false },
|
|
78337
|
+
secret_declined: { decoupledCompletion: false },
|
|
78338
|
+
secret_provide_failed: { decoupledCompletion: false },
|
|
78339
|
+
secret_request_timeout: { decoupledCompletion: false },
|
|
78340
|
+
mental_model_propose_timeout: { decoupledCompletion: false },
|
|
78341
|
+
bridge_dead_restart: { decoupledCompletion: false },
|
|
78342
|
+
obligation_represent: { decoupledCompletion: false },
|
|
78343
|
+
missed_approval_retry: { decoupledCompletion: false },
|
|
78344
|
+
skill_proposal_apply: { decoupledCompletion: false },
|
|
78345
|
+
warmup: { decoupledCompletion: false },
|
|
78346
|
+
mental_model_proposal_applied: { decoupledCompletion: false },
|
|
78347
|
+
mental_model_proposal_denied: { decoupledCompletion: false },
|
|
78348
|
+
mental_model_proposal_failed: { decoupledCompletion: false },
|
|
78349
|
+
webhook: { decoupledCompletion: false },
|
|
78350
|
+
linear: { decoupledCompletion: false }
|
|
78351
|
+
};
|
|
78352
|
+
function stampsHandbackMarker(source) {
|
|
78353
|
+
if (source == null)
|
|
78015
78354
|
return false;
|
|
78016
|
-
|
|
78017
|
-
|
|
78018
|
-
if (reply.length >= SUPERSEDE_MATCH_MIN_CONTAINMENT_CHARS2 && flushed.includes(reply))
|
|
78019
|
-
return true;
|
|
78020
|
-
if (flushed.length >= SUPERSEDE_MATCH_MIN_CONTAINMENT_CHARS2 && reply.includes(flushed))
|
|
78355
|
+
const known = INBOUND_SOURCE_CLASSIFICATION[source];
|
|
78356
|
+
if (known == null)
|
|
78021
78357
|
return true;
|
|
78022
|
-
return
|
|
78023
|
-
}
|
|
78024
|
-
function decideSupersede2(record, args) {
|
|
78025
|
-
const ttlMs = args.ttlMs ?? DEFAULT_SUPERSEDE_TTL_MS2;
|
|
78026
|
-
if (record == null)
|
|
78027
|
-
return { supersede: false, deleteMessageIds: [], reason: "no-record" };
|
|
78028
|
-
if (args.now - record.ts > ttlMs) {
|
|
78029
|
-
return { supersede: false, deleteMessageIds: [], reason: "expired" };
|
|
78030
|
-
}
|
|
78031
|
-
const sameTurn = record.turnId != null ? record.turnId === args.liveTurnId : args.liveTurnId == null;
|
|
78032
|
-
if (!sameTurn) {
|
|
78033
|
-
return { supersede: false, deleteMessageIds: [], reason: "different-turn" };
|
|
78034
|
-
}
|
|
78035
|
-
if (!args.positiveAttribution && args.replyText != null && !flushedAnswerMatchesReply2(record.text, args.replyText)) {
|
|
78036
|
-
return { supersede: false, deleteMessageIds: [], reason: "new-content", recordText: record.text };
|
|
78037
|
-
}
|
|
78038
|
-
return {
|
|
78039
|
-
supersede: true,
|
|
78040
|
-
deleteMessageIds: [...record.messageIds],
|
|
78041
|
-
reason: "supersede",
|
|
78042
|
-
recordText: record.text
|
|
78043
|
-
};
|
|
78044
|
-
}
|
|
78045
|
-
function decideSupersedeCorrection(input) {
|
|
78046
|
-
const eligible = input.flushMessageIds.length === 1 && input.chunkCount === 1 && !input.hasFiles && !input.suppressText && !input.hasOpenPreview;
|
|
78047
|
-
if (eligible) {
|
|
78048
|
-
return { mode: "edit-in-place", editMessageId: input.flushMessageIds[0], deleteMessageIds: [] };
|
|
78049
|
-
}
|
|
78050
|
-
return { mode: "delete-resend", deleteMessageIds: [...input.flushMessageIds] };
|
|
78051
|
-
}
|
|
78052
|
-
var NULL_TURN_KEY2 = "<<null-turn>>";
|
|
78053
|
-
function turnKey2(turnId) {
|
|
78054
|
-
return turnId == null ? NULL_TURN_KEY2 : turnId;
|
|
78358
|
+
return known.decoupledCompletion;
|
|
78055
78359
|
}
|
|
78360
|
+
var HANDBACK_RECENCY_WINDOW_MS = 60000;
|
|
78361
|
+
var MAIN_THREAD_KEY = "<main>";
|
|
78056
78362
|
|
|
78057
|
-
class
|
|
78058
|
-
|
|
78059
|
-
|
|
78060
|
-
|
|
78061
|
-
this.ttlMs = opts.ttlMs ?? DEFAULT_SUPERSEDE_TTL_MS2;
|
|
78062
|
-
}
|
|
78063
|
-
record(chatId, threadId, rec, now) {
|
|
78064
|
-
if (rec.messageIds.length === 0)
|
|
78065
|
-
return;
|
|
78066
|
-
this.sweep(now);
|
|
78067
|
-
const lane = makeKey3(chatId, threadId);
|
|
78068
|
-
let laneMap = this.entries.get(lane);
|
|
78069
|
-
if (laneMap == null) {
|
|
78070
|
-
laneMap = new Map;
|
|
78071
|
-
this.entries.set(lane, laneMap);
|
|
78072
|
-
}
|
|
78073
|
-
laneMap.set(turnKey2(rec.turnId), {
|
|
78074
|
-
turnId: rec.turnId,
|
|
78075
|
-
messageIds: [...rec.messageIds],
|
|
78076
|
-
text: rec.text,
|
|
78077
|
-
ts: now
|
|
78078
|
-
});
|
|
78079
|
-
}
|
|
78080
|
-
peek(chatId, threadId, args) {
|
|
78081
|
-
const rec = this.entries.get(makeKey3(chatId, threadId))?.get(turnKey2(args.liveTurnId));
|
|
78082
|
-
return decideSupersede2(rec, {
|
|
78083
|
-
liveTurnId: args.liveTurnId,
|
|
78084
|
-
replyText: args.replyText,
|
|
78085
|
-
positiveAttribution: args.positiveAttribution,
|
|
78086
|
-
now: args.now,
|
|
78087
|
-
ttlMs: this.ttlMs
|
|
78088
|
-
});
|
|
78363
|
+
class SubagentHandbackMarker {
|
|
78364
|
+
byChat = new Map;
|
|
78365
|
+
threadKey(threadId) {
|
|
78366
|
+
return threadId == null ? MAIN_THREAD_KEY : String(threadId);
|
|
78089
78367
|
}
|
|
78090
|
-
|
|
78091
|
-
|
|
78092
|
-
|
|
78093
|
-
|
|
78094
|
-
|
|
78095
|
-
laneMap?.delete(turnKey2(args.liveTurnId));
|
|
78096
|
-
if (laneMap != null && laneMap.size === 0)
|
|
78097
|
-
this.entries.delete(lane);
|
|
78368
|
+
record(chatId, threadId, now) {
|
|
78369
|
+
let inner = this.byChat.get(chatId);
|
|
78370
|
+
if (inner == null) {
|
|
78371
|
+
inner = new Map;
|
|
78372
|
+
this.byChat.set(chatId, inner);
|
|
78098
78373
|
}
|
|
78099
|
-
|
|
78100
|
-
}
|
|
78101
|
-
forget(chatId, threadId) {
|
|
78102
|
-
this.entries.delete(makeKey3(chatId, threadId));
|
|
78103
|
-
}
|
|
78104
|
-
clear() {
|
|
78105
|
-
this.entries.clear();
|
|
78374
|
+
inner.set(this.threadKey(threadId), now);
|
|
78106
78375
|
}
|
|
78107
|
-
|
|
78108
|
-
|
|
78109
|
-
for (const [tk, rec] of laneMap) {
|
|
78110
|
-
if (now - rec.ts > this.ttlMs)
|
|
78111
|
-
laneMap.delete(tk);
|
|
78112
|
-
}
|
|
78113
|
-
if (laneMap.size === 0)
|
|
78114
|
-
this.entries.delete(lane);
|
|
78115
|
-
}
|
|
78376
|
+
lastAt(chatId, threadId) {
|
|
78377
|
+
return this.byChat.get(chatId)?.get(this.threadKey(threadId)) ?? null;
|
|
78116
78378
|
}
|
|
78117
|
-
|
|
78118
|
-
this.
|
|
78119
|
-
|
|
78120
|
-
|
|
78121
|
-
|
|
78122
|
-
|
|
78379
|
+
lastAtInChat(chatId) {
|
|
78380
|
+
const inner = this.byChat.get(chatId);
|
|
78381
|
+
if (inner == null || inner.size === 0)
|
|
78382
|
+
return null;
|
|
78383
|
+
let max = -Infinity;
|
|
78384
|
+
for (const ts of inner.values())
|
|
78385
|
+
if (ts > max)
|
|
78386
|
+
max = ts;
|
|
78387
|
+
return max === -Infinity ? null : max;
|
|
78123
78388
|
}
|
|
78124
78389
|
}
|
|
78125
|
-
function makeKey3(chatId, threadId) {
|
|
78126
|
-
return threadId == null ? chatId : `${chatId}|${threadId}`;
|
|
78127
|
-
}
|
|
78128
|
-
|
|
78129
|
-
// reply-owner-resolve.ts
|
|
78130
|
-
function latestEndedAccepted(candidates) {
|
|
78131
|
-
if (candidates.latestEndedTurnId == null)
|
|
78132
|
-
return false;
|
|
78133
|
-
const age = candidates.latestEndedAgeMs;
|
|
78134
|
-
const ttl = candidates.latestEndedTtlMs;
|
|
78135
|
-
if (age === null)
|
|
78136
|
-
return false;
|
|
78137
|
-
if (age === undefined || ttl == null)
|
|
78138
|
-
return true;
|
|
78139
|
-
return age <= ttl;
|
|
78140
|
-
}
|
|
78141
|
-
function decideContentGateBypass(input) {
|
|
78142
|
-
if (input.tier === "live")
|
|
78143
|
-
return true;
|
|
78144
|
-
if (input.tier === "none")
|
|
78145
|
-
return false;
|
|
78146
|
-
if (input.handbackCouldOwnReply)
|
|
78147
|
-
return false;
|
|
78148
|
-
if (input.candidates == null)
|
|
78149
|
-
return false;
|
|
78150
|
-
if (!latestEndedAccepted(input.candidates))
|
|
78151
|
-
return false;
|
|
78152
|
-
return input.resolvedTurnId != null && input.resolvedTurnId === input.candidates.latestEndedTurnId;
|
|
78153
|
-
}
|
|
78154
|
-
function decideAnswerLatchSuppression(input) {
|
|
78155
|
-
if (input.superseded)
|
|
78156
|
-
return false;
|
|
78157
|
-
if (!input.replySubstantive)
|
|
78158
|
-
return false;
|
|
78159
|
-
if (!input.isLateReply)
|
|
78160
|
-
return false;
|
|
78161
|
-
if (input.replyMatchesFlushedAnswer === false)
|
|
78162
|
-
return false;
|
|
78163
|
-
return input.ownerAnswerDelivered === "flush";
|
|
78164
|
-
}
|
|
78165
78390
|
|
|
78166
78391
|
// telegraph.ts
|
|
78167
78392
|
function deriveTelegraphTitle2(text4) {
|
|
@@ -78736,6 +78961,7 @@ async function sendReply(deps, req) {
|
|
|
78736
78961
|
resolveThreadId,
|
|
78737
78962
|
getLatestInboundMessageId: getLatestInboundMessageId2,
|
|
78738
78963
|
getLastSubagentHandbackAt,
|
|
78964
|
+
subagentReplyAuthority: subagentReplyAuthority2,
|
|
78739
78965
|
recordOutbound: recordOutbound2,
|
|
78740
78966
|
emissionAuthorityFor,
|
|
78741
78967
|
clearActivitySummary,
|
|
@@ -78810,7 +79036,10 @@ async function sendReply(deps, req) {
|
|
|
78810
79036
|
}
|
|
78811
79037
|
}
|
|
78812
79038
|
let supersedeFlushIds = [];
|
|
78813
|
-
{
|
|
79039
|
+
if (req.callerIsForeignSession === true) {
|
|
79040
|
+
process.stderr.write(`telegram gateway: reply: foreign-session caller \u2014 supersede/latch skipped (#4172) ` + `chatId=${chat_id}
|
|
79041
|
+
`);
|
|
79042
|
+
} else {
|
|
78814
79043
|
const replyThreadId = args.message_thread_id != null ? Number(args.message_thread_id) : undefined;
|
|
78815
79044
|
const {
|
|
78816
79045
|
turn: ownerTurn,
|
|
@@ -78822,12 +79051,14 @@ async function sendReply(deps, req) {
|
|
|
78822
79051
|
const gateThreadId = ownerTurn?.sessionThreadId ?? replyThreadId;
|
|
78823
79052
|
const handbackAt = getLastSubagentHandbackAt(chat_id);
|
|
78824
79053
|
const now = Date.now();
|
|
78825
|
-
const handbackCouldOwnReply = handbackAt != null && ownerEndedAt != null && handbackAt > ownerEndedAt && now - handbackAt <=
|
|
79054
|
+
const handbackCouldOwnReply = handbackAt != null && ownerEndedAt != null && handbackAt > ownerEndedAt && now - handbackAt <= HANDBACK_RECENCY_WINDOW_MS;
|
|
79055
|
+
const subagentCouldOwnReply = subagentReplyAuthority2.subagentCouldOwnReply();
|
|
78826
79056
|
const replyIsOwnAnswer = decideContentGateBypass({
|
|
78827
79057
|
tier: ownerTier,
|
|
78828
79058
|
resolvedTurnId,
|
|
78829
79059
|
candidates: ownerCandidates,
|
|
78830
|
-
handbackCouldOwnReply
|
|
79060
|
+
handbackCouldOwnReply,
|
|
79061
|
+
subagentCouldOwnReply
|
|
78831
79062
|
});
|
|
78832
79063
|
const decision = flushedTurnSupersede.take(chat_id, gateThreadId, { liveTurnId: resolvedTurnId, replyText: text4, positiveAttribution: replyIsOwnAnswer, now });
|
|
78833
79064
|
if (decision.supersede) {
|
|
@@ -78853,7 +79084,7 @@ async function sendReply(deps, req) {
|
|
|
78853
79084
|
replyMatchesFlushedAnswer
|
|
78854
79085
|
});
|
|
78855
79086
|
if (decision.reason === "new-content") {
|
|
78856
|
-
process.stderr.write(`telegram gateway: reply: flush supersede declined \u2014 new content (#3429) ` + `chatId=${chat_id} ownerTurnId=${JSON.stringify(resolvedTurnId)} ` + `tier=${ownerTier} latestEnded=${JSON.stringify(ownerCandidates.latestEndedTurnId)} ` + `handbackInWindow=${handbackCouldOwnReply}; sending fresh
|
|
79087
|
+
process.stderr.write(`telegram gateway: reply: flush supersede declined \u2014 new content (#3429) ` + `chatId=${chat_id} ownerTurnId=${JSON.stringify(resolvedTurnId)} ` + `tier=${ownerTier} latestEnded=${JSON.stringify(ownerCandidates.latestEndedTurnId)} ` + `handbackInWindow=${handbackCouldOwnReply} subagentLive=${subagentCouldOwnReply}; sending fresh
|
|
78857
79088
|
`);
|
|
78858
79089
|
}
|
|
78859
79090
|
if (suppressByLatch) {
|
|
@@ -80107,6 +80338,37 @@ function emitRuntimeMetric2(event) {
|
|
|
80107
80338
|
captureEvent(event.kind, { ...event, ts: wrapped.ts });
|
|
80108
80339
|
}
|
|
80109
80340
|
|
|
80341
|
+
// gateway/subagent-reply-authority.ts
|
|
80342
|
+
var SUB_AGENT_KIND_PREFIX2 = "sub_agent_";
|
|
80343
|
+
|
|
80344
|
+
class SubagentReplyAuthority2 {
|
|
80345
|
+
live = new Set;
|
|
80346
|
+
noteSessionEvent(ev) {
|
|
80347
|
+
if (ev == null)
|
|
80348
|
+
return;
|
|
80349
|
+
const kind = ev.kind;
|
|
80350
|
+
if (typeof kind !== "string" || !kind.startsWith(SUB_AGENT_KIND_PREFIX2))
|
|
80351
|
+
return;
|
|
80352
|
+
const agentId = ev.agentId;
|
|
80353
|
+
if (typeof agentId !== "string" || agentId === "")
|
|
80354
|
+
return;
|
|
80355
|
+
if (kind === `${SUB_AGENT_KIND_PREFIX2}turn_end`)
|
|
80356
|
+
this.live.delete(agentId);
|
|
80357
|
+
else
|
|
80358
|
+
this.live.add(agentId);
|
|
80359
|
+
}
|
|
80360
|
+
subagentCouldOwnReply() {
|
|
80361
|
+
return this.live.size > 0;
|
|
80362
|
+
}
|
|
80363
|
+
reset() {
|
|
80364
|
+
this.live.clear();
|
|
80365
|
+
}
|
|
80366
|
+
liveCount() {
|
|
80367
|
+
return this.live.size;
|
|
80368
|
+
}
|
|
80369
|
+
}
|
|
80370
|
+
var subagentReplyAuthority2 = new SubagentReplyAuthority2;
|
|
80371
|
+
|
|
80110
80372
|
// gateway/feed-open-gate.ts
|
|
80111
80373
|
function shouldEarlyOpenLiveness(input) {
|
|
80112
80374
|
if (!input.enabled)
|
|
@@ -80835,6 +81097,12 @@ function discardParkedTurnStart(rawContent) {
|
|
|
80835
81097
|
}
|
|
80836
81098
|
return null;
|
|
80837
81099
|
}
|
|
81100
|
+
var flushCompletionTracker = new FlushCompletionTracker;
|
|
81101
|
+
function closeFlushCompletionWindows(registry, now) {
|
|
81102
|
+
const closed = flushCompletionTracker.closeAll(now);
|
|
81103
|
+
registry?.completeAll?.(now);
|
|
81104
|
+
return closed;
|
|
81105
|
+
}
|
|
80838
81106
|
function drainParkedTurnStartsForChat(deps, chatId, threadId) {
|
|
80839
81107
|
const wantThread = envThreadIdNum(threadId);
|
|
80840
81108
|
const drained = [];
|
|
@@ -80967,6 +81235,7 @@ function beginTurn(deps, ev) {
|
|
|
80967
81235
|
answerDelivered: false,
|
|
80968
81236
|
flushedAnswerText: null,
|
|
80969
81237
|
endedAt: null,
|
|
81238
|
+
realEndObservedAt: null,
|
|
80970
81239
|
firstPingAt: null,
|
|
80971
81240
|
firstPingWasSubstantive: false,
|
|
80972
81241
|
silentAnchorMessageId: null,
|
|
@@ -81022,6 +81291,7 @@ function beginTurn(deps, ev) {
|
|
|
81022
81291
|
`);
|
|
81023
81292
|
}
|
|
81024
81293
|
startTurnTypingLoop(ev.chatId, enqThreadIdNum ?? null);
|
|
81294
|
+
closeFlushCompletionWindows(deps.flushedTurnSupersede, Date.now());
|
|
81025
81295
|
setCurrentTurn(next, statusKey(ev.chatId, enqThreadIdNum));
|
|
81026
81296
|
scheduleEarlyLivenessOpen(next);
|
|
81027
81297
|
process.stderr.write(`telegram gateway: ${formatTurnLifecycle("set", "enqueue", next, startedAt)}
|
|
@@ -81160,6 +81430,7 @@ function handleSessionEvent(deps, ev) {
|
|
|
81160
81430
|
const durationMs = ev.kind === "turn_end" ? ev.durationMs : undefined;
|
|
81161
81431
|
idleTracker.noteEvent(ev.kind, Date.now(), durationMs);
|
|
81162
81432
|
}
|
|
81433
|
+
subagentReplyAuthority2.noteSessionEvent(ev);
|
|
81163
81434
|
switch (ev.kind) {
|
|
81164
81435
|
case "enqueue": {
|
|
81165
81436
|
const enqThreadIdNum = ev.threadId != null ? Number(ev.threadId) : undefined;
|
|
@@ -81472,6 +81743,7 @@ function handleSessionEvent(deps, ev) {
|
|
|
81472
81743
|
return;
|
|
81473
81744
|
}
|
|
81474
81745
|
}
|
|
81746
|
+
closeFlushCompletionWindows(flushedTurnSupersede, Date.now());
|
|
81475
81747
|
const turnEndBackstopTurn = getCurrentTurn();
|
|
81476
81748
|
const turnEndBackstopKey = turnEndBackstopTurn != null ? statusKey(turnEndBackstopTurn.sessionChatId, turnEndBackstopTurn.sessionThreadId) : null;
|
|
81477
81749
|
withTurnEndGateBackstop(turnEndBackstopKey, turnEndBackstopTurn, () => {
|
|
@@ -81645,6 +81917,9 @@ function handleSessionEvent(deps, ev) {
|
|
|
81645
81917
|
const backstopCardMessageId = cardTakeover.wasEmitted && cardTakeover.turnKey != null ? getPinnedProgressCardMessageId?.(cardTakeover.turnKey) ?? null : null;
|
|
81646
81918
|
const backstopCardTurnKey = cardTakeover.turnKey;
|
|
81647
81919
|
const backstopTurnEndedAt = endCurrentTurnAtomic(turn, { deferRecord: true, deferObligationClose: true });
|
|
81920
|
+
if (ev.durationMs === -1) {
|
|
81921
|
+
flushCompletionTracker.open(turn);
|
|
81922
|
+
}
|
|
81648
81923
|
preambleSuppressor.dropNow();
|
|
81649
81924
|
{
|
|
81650
81925
|
const tKey = statusKey(chatId, threadId);
|
|
@@ -81722,7 +81997,12 @@ function handleSessionEvent(deps, ev) {
|
|
|
81722
81997
|
turn.landedUnconfirmed = delivery.landedUnconfirmed;
|
|
81723
81998
|
outboundDedup.record(backstopChatId, backstopThreadId, capturedText, Date.now(), getCurrentTurn()?.registryKey ?? null);
|
|
81724
81999
|
if (sentIds.length > 0) {
|
|
81725
|
-
flushedTurnSupersede.record(backstopChatId, backstopThreadId, {
|
|
82000
|
+
flushedTurnSupersede.record(backstopChatId, backstopThreadId, {
|
|
82001
|
+
turnId: turn.turnId,
|
|
82002
|
+
messageIds: sentIds,
|
|
82003
|
+
text: capturedText,
|
|
82004
|
+
completedAt: turn.realEndObservedAt
|
|
82005
|
+
}, Date.now());
|
|
81726
82006
|
}
|
|
81727
82007
|
if (!delivered) {
|
|
81728
82008
|
if (backstopCtrl)
|
|
@@ -82695,51 +82975,13 @@ function isTurnFlushSafetyEnabled(env = process.env) {
|
|
|
82695
82975
|
return true;
|
|
82696
82976
|
}
|
|
82697
82977
|
|
|
82698
|
-
// reply-owner-resolve.ts
|
|
82699
|
-
function latestEndedAccepted2(candidates) {
|
|
82700
|
-
if (candidates.latestEndedTurnId == null)
|
|
82701
|
-
return false;
|
|
82702
|
-
const age = candidates.latestEndedAgeMs;
|
|
82703
|
-
const ttl = candidates.latestEndedTtlMs;
|
|
82704
|
-
if (age === null)
|
|
82705
|
-
return false;
|
|
82706
|
-
if (age === undefined || ttl == null)
|
|
82707
|
-
return true;
|
|
82708
|
-
return age <= ttl;
|
|
82709
|
-
}
|
|
82710
|
-
function resolveReplyOwnerTier(candidates) {
|
|
82711
|
-
if (candidates.liveTurnId != null)
|
|
82712
|
-
return "live";
|
|
82713
|
-
if (candidates.originTurnId != null)
|
|
82714
|
-
return "origin";
|
|
82715
|
-
if (candidates.quotedTurnId != null)
|
|
82716
|
-
return "quoted";
|
|
82717
|
-
if (latestEndedAccepted2(candidates))
|
|
82718
|
-
return "latest-ended";
|
|
82719
|
-
return "none";
|
|
82720
|
-
}
|
|
82721
|
-
function resolveReplyOwnerTurnId(candidates) {
|
|
82722
|
-
switch (resolveReplyOwnerTier(candidates)) {
|
|
82723
|
-
case "live":
|
|
82724
|
-
return candidates.liveTurnId;
|
|
82725
|
-
case "origin":
|
|
82726
|
-
return candidates.originTurnId;
|
|
82727
|
-
case "quoted":
|
|
82728
|
-
return candidates.quotedTurnId;
|
|
82729
|
-
case "latest-ended":
|
|
82730
|
-
return candidates.latestEndedTurnId;
|
|
82731
|
-
case "none":
|
|
82732
|
-
return null;
|
|
82733
|
-
}
|
|
82734
|
-
}
|
|
82735
|
-
|
|
82736
82978
|
// gateway/subagent-handback-marker.ts
|
|
82737
|
-
var
|
|
82979
|
+
var MAIN_THREAD_KEY2 = "<main>";
|
|
82738
82980
|
|
|
82739
|
-
class
|
|
82981
|
+
class SubagentHandbackMarker2 {
|
|
82740
82982
|
byChat = new Map;
|
|
82741
82983
|
threadKey(threadId) {
|
|
82742
|
-
return threadId == null ?
|
|
82984
|
+
return threadId == null ? MAIN_THREAD_KEY2 : String(threadId);
|
|
82743
82985
|
}
|
|
82744
82986
|
record(chatId, threadId, now) {
|
|
82745
82987
|
let inner = this.byChat.get(chatId);
|
|
@@ -85592,9 +85834,66 @@ async function discoverModels(agentName3, opts = {}) {
|
|
|
85592
85834
|
}
|
|
85593
85835
|
|
|
85594
85836
|
// ../src/agents/scaffold.ts
|
|
85595
|
-
import { dirname as dirname18, isAbsolute, join as join44, relative, resolve as resolve8 } from "node:path";
|
|
85596
85837
|
init_atomic();
|
|
85597
85838
|
|
|
85839
|
+
// ../src/util/shipped-assets.ts
|
|
85840
|
+
import { existsSync as existsSync32, readFileSync as readFileSync31, realpathSync as realpathSync2 } from "node:fs";
|
|
85841
|
+
import { dirname as dirname18, resolve as resolve7 } from "node:path";
|
|
85842
|
+
var FHS_SHARE_ROOTS = [
|
|
85843
|
+
"/usr/local/share/switchroom",
|
|
85844
|
+
"/usr/share/switchroom"
|
|
85845
|
+
];
|
|
85846
|
+
var PROFILES_ASSET = {
|
|
85847
|
+
asset: "profiles",
|
|
85848
|
+
envVar: "SWITCHROOM_PROFILES_ROOT"
|
|
85849
|
+
};
|
|
85850
|
+
function orderedCandidates(spec, probe) {
|
|
85851
|
+
const out = [];
|
|
85852
|
+
const push2 = (path2, source) => {
|
|
85853
|
+
if (!out.some((c) => c.path === path2))
|
|
85854
|
+
out.push({ path: path2, source });
|
|
85855
|
+
};
|
|
85856
|
+
if (probe.bundleDir) {
|
|
85857
|
+
push2(resolve7(probe.bundleDir, "../..", spec.asset), "npm");
|
|
85858
|
+
push2(resolve7(probe.bundleDir, spec.asset), "image");
|
|
85859
|
+
}
|
|
85860
|
+
if (probe.execPath) {
|
|
85861
|
+
push2(resolve7(dirname18(probe.execPath), "../share/switchroom", spec.asset), "sea-sibling");
|
|
85862
|
+
}
|
|
85863
|
+
for (const root of FHS_SHARE_ROOTS) {
|
|
85864
|
+
push2(resolve7(root, spec.asset), "fhs");
|
|
85865
|
+
}
|
|
85866
|
+
return out;
|
|
85867
|
+
}
|
|
85868
|
+
function resolveShippedAsset(spec, probe) {
|
|
85869
|
+
const env = probe.env ?? process.env;
|
|
85870
|
+
const override = env[spec.envVar]?.trim();
|
|
85871
|
+
if (override) {
|
|
85872
|
+
const path2 = canonicalise(resolve7(override), probe);
|
|
85873
|
+
return { path: path2, candidates: [path2], source: "env" };
|
|
85874
|
+
}
|
|
85875
|
+
const exists = probe.exists ?? existsSync32;
|
|
85876
|
+
const candidates = orderedCandidates(spec, probe);
|
|
85877
|
+
for (const c of candidates) {
|
|
85878
|
+
if (exists(c.path)) {
|
|
85879
|
+
return {
|
|
85880
|
+
path: canonicalise(c.path, probe),
|
|
85881
|
+
candidates: candidates.map((x) => x.path),
|
|
85882
|
+
source: c.source
|
|
85883
|
+
};
|
|
85884
|
+
}
|
|
85885
|
+
}
|
|
85886
|
+
return { path: null, candidates: candidates.map((x) => x.path), source: "none" };
|
|
85887
|
+
}
|
|
85888
|
+
function canonicalise(path2, probe) {
|
|
85889
|
+
const realpath = probe.realpath ?? realpathSync2;
|
|
85890
|
+
try {
|
|
85891
|
+
return realpath(path2);
|
|
85892
|
+
} catch {
|
|
85893
|
+
return path2;
|
|
85894
|
+
}
|
|
85895
|
+
}
|
|
85896
|
+
|
|
85598
85897
|
// ../src/agents/agent-uid.ts
|
|
85599
85898
|
init_peercred();
|
|
85600
85899
|
|
|
@@ -85641,37 +85940,29 @@ var AUDIT_ROOT = join42(homedir11(), ".switchroom", "audit");
|
|
|
85641
85940
|
|
|
85642
85941
|
// ../src/agents/profiles.ts
|
|
85643
85942
|
var import_handlebars = __toESM(require_lib(), 1);
|
|
85644
|
-
import { readFileSync as
|
|
85645
|
-
import { resolve as
|
|
85646
|
-
function
|
|
85647
|
-
|
|
85648
|
-
|
|
85649
|
-
|
|
85650
|
-
}
|
|
85651
|
-
const candidates = [
|
|
85652
|
-
resolve7(import.meta.dirname, "../../profiles"),
|
|
85653
|
-
resolve7(import.meta.dirname, "profiles")
|
|
85654
|
-
];
|
|
85655
|
-
for (const candidate of candidates) {
|
|
85656
|
-
if (existsSync33(candidate)) {
|
|
85657
|
-
return candidate;
|
|
85658
|
-
}
|
|
85659
|
-
}
|
|
85660
|
-
return candidates[0];
|
|
85943
|
+
import { readFileSync as readFileSync33, writeFileSync as writeFileSync29, existsSync as existsSync34, readdirSync as readdirSync8, statSync as statSync13, copyFileSync, mkdirSync as mkdirSync32, realpathSync as realpathSync3 } from "node:fs";
|
|
85944
|
+
import { resolve as resolve8, join as join43, sep as pathSep } from "node:path";
|
|
85945
|
+
function resolveProfilesRootDetailed() {
|
|
85946
|
+
return resolveShippedAsset(PROFILES_ASSET, {
|
|
85947
|
+
bundleDir: import.meta.dirname,
|
|
85948
|
+
execPath: process.execPath
|
|
85949
|
+
});
|
|
85661
85950
|
}
|
|
85662
|
-
var
|
|
85951
|
+
var PROFILES_RESOLUTION = resolveProfilesRootDetailed();
|
|
85952
|
+
var PROFILES_ROOT = PROFILES_RESOLUTION.path ?? PROFILES_RESOLUTION.candidates[0];
|
|
85953
|
+
var PROFILES_ROOT_SEARCH = PROFILES_RESOLUTION.candidates;
|
|
85663
85954
|
import_handlebars.default.registerHelper("json", (value) => {
|
|
85664
85955
|
return new import_handlebars.default.SafeString(JSON.stringify(value, null, 2));
|
|
85665
85956
|
});
|
|
85666
85957
|
import_handlebars.default.registerHelper("isNumber", (value) => {
|
|
85667
85958
|
return typeof value === "number" && Number.isFinite(value);
|
|
85668
85959
|
});
|
|
85669
|
-
var SHARED_FRAGMENTS_DIR =
|
|
85960
|
+
var SHARED_FRAGMENTS_DIR = resolve8(PROFILES_ROOT, "_shared");
|
|
85670
85961
|
var SHARED_FRAGMENTS = ["vault-protocol", "agent-self-service", "execution-discipline", "reply-discipline", "dev-protocol"];
|
|
85671
85962
|
for (const name of SHARED_FRAGMENTS) {
|
|
85672
85963
|
const fragPath = join43(SHARED_FRAGMENTS_DIR, `${name}.md.hbs`);
|
|
85673
|
-
if (
|
|
85674
|
-
import_handlebars.default.registerPartial(name,
|
|
85964
|
+
if (existsSync34(fragPath)) {
|
|
85965
|
+
import_handlebars.default.registerPartial(name, readFileSync33(fragPath, "utf-8"));
|
|
85675
85966
|
}
|
|
85676
85967
|
}
|
|
85677
85968
|
|
|
@@ -85874,7 +86165,8 @@ var HINDSIGHT_PERF_OVERRIDE_ONLY_KEYS = new Set([
|
|
|
85874
86165
|
"HINDSIGHT_API_SEMANTIC_MIN_SIMILARITY",
|
|
85875
86166
|
"HINDSIGHT_MCP_RECALL_BUDGET_MODE",
|
|
85876
86167
|
"HINDSIGHT_API_LLM_TEMPERATURE_REFLECT",
|
|
85877
|
-
"HINDSIGHT_API_RETAIN_WALL_TIMEOUT"
|
|
86168
|
+
"HINDSIGHT_API_RETAIN_WALL_TIMEOUT",
|
|
86169
|
+
"HINDSIGHT_API_CONSOLIDATION_RECALL_MAX_CONCURRENT"
|
|
85878
86170
|
]);
|
|
85879
86171
|
var HINDSIGHT_WORKER_SLOT_TYPES = [
|
|
85880
86172
|
"consolidation",
|
|
@@ -85969,6 +86261,15 @@ var DEFAULT_RETAIN_MISSION = `Extract durable facts that will still be true and
|
|
|
85969
86261
|
` + `- Hindsight's own errors, retries, backlogs, or internal state \u2014 the memory
|
|
85970
86262
|
` + ` system's self-reports are not memories.
|
|
85971
86263
|
` + `- Restatements of the user's current request or the task in progress.
|
|
86264
|
+
` + `- The assistant's own answers, summaries, recaps, or reflect output. Before
|
|
86265
|
+
` + ` extracting, ask: does anything in this transcript support this claim OTHER
|
|
86266
|
+
` + ` than the assistant having asserted it? If not, drop it \u2014 a model's own
|
|
86267
|
+
` + ` synthesis re-extracted as a fact is how a guess becomes permanent.
|
|
86268
|
+
` + ` Concretely, never produce a fact whose only support is the assistant
|
|
86269
|
+
` + ` stating a date, a version, an attribution, a total, or a decision that the
|
|
86270
|
+
` + ` user never confirmed and no tool output shows. An unverified claim recalls
|
|
86271
|
+
` + ` later as though it had been established, which is worse than not
|
|
86272
|
+
` + ` remembering it at all.
|
|
85972
86273
|
` + `- Volatile state written as a timeless assertion. A version, count, size,
|
|
85973
86274
|
` + ` backlog, status, or any "X is running Y" / "X is at Y" / "X is currently Y"
|
|
85974
86275
|
` + ` claim is true only at the instant it was said. Concretely, never produce a
|
|
@@ -86124,6 +86425,64 @@ var SUPERSEDED_RETAIN_MISSIONS = [
|
|
|
86124
86425
|
` + `
|
|
86125
86426
|
` + `If a candidate fact matches an exclusion, drop it rather than rewording it. If
|
|
86126
86427
|
` + `nothing durable remains, return an empty facts list.
|
|
86428
|
+
`,
|
|
86429
|
+
`Extract durable facts that will still be true and useful weeks from now, once this session is forgotten.
|
|
86430
|
+
` + `
|
|
86431
|
+
` + `DURABILITY GATE. Emit a candidate ONLY if it is one of these five classes:
|
|
86432
|
+
` + `- PREFERENCE \u2014 what the user likes, wants, or always does; a standing rule or correction.
|
|
86433
|
+
` + `- DECISION \u2014 a settled choice that changes how future work is done, including a choice NOT to do something. A decision about the mechanics of the CURRENT task (which worker to dispatch, which branch to rebase, which PR to merge now, what to do next) is process narration, not a durable decision \u2014 drop it unless it establishes a standing rule or permanently changes a system.
|
|
86434
|
+
` + `- FINDING \u2014 a root cause, a measurement, or verified behaviour of a system. Include the number.
|
|
86435
|
+
` + `- OUTCOME \u2014 a completed result that changed the world: what shipped, what a thing turned out to be. Not the act of shipping it.
|
|
86436
|
+
` + `- RELATIONSHIP \u2014 who a person is, what a project or tool is, and how they connect.
|
|
86437
|
+
` + `If a candidate fits none of the five, it is not a memory. Drop it; do not reword it into one.
|
|
86438
|
+
` + `
|
|
86439
|
+
` + `A preference revealed by a request is durable \u2014 record the preference (what the user likes, wants, or always does), not the request itself.
|
|
86440
|
+
` + `
|
|
86441
|
+
` + `A TOOL RESULT IS NOT A FACT. Before extracting, ask: is the subject of this
|
|
86442
|
+
` + `candidate a file path, a command/process/agent/session id, a temp directory, or
|
|
86443
|
+
` + `the location where some output was written? If yes, drop it \u2014 it is transcript
|
|
86444
|
+
` + `exhaust, not memory.
|
|
86445
|
+
` + `
|
|
86446
|
+
` + `NEVER extract:
|
|
86447
|
+
` + `- Tool results verbatim or paraphrased. Concretely, never produce a fact whose
|
|
86448
|
+
` + ` text resembles any of these: "File created successfully at /path/to/file",
|
|
86449
|
+
` + ` "A background command with ID bctz4yskm is running, and its output will be
|
|
86450
|
+
` + ` written to /tmp/...", "Async agent a745598ba84e71df1 was launched successfully
|
|
86451
|
+
` + ` and is running in the background", "User executed a Bash command to sleep for
|
|
86452
|
+
` + ` 200 seconds", "The assistant used grep to locate 'truncateSync' in src/foo.ts".
|
|
86453
|
+
` + `- Anything mentioning a path under /tmp, a scratchpad directory, or a .tmp file.
|
|
86454
|
+
` + `- Agent tool-use traces or narration of what the assistant did (e.g. "the
|
|
86455
|
+
` + ` assistant used X to query Y", "ran a search", "sent the message").
|
|
86456
|
+
` + `- The act of delegating, dispatching, spawning, launching, steering or merging
|
|
86457
|
+
` + ` work \u2014 including when it succeeded. "X was dispatched and completed" is the
|
|
86458
|
+
` + ` session describing itself. Record only what the work LEARNED or CHANGED.
|
|
86459
|
+
` + `- In-flight workflow/process narration (a sub-task started, paused, or is still
|
|
86460
|
+
` + ` running) \u2014 retain the outcome only once the task completes or a decision is made.
|
|
86461
|
+
` + `- Operation, request, batch, agent, command or session IDs, UUIDs, hashes, or error codes.
|
|
86462
|
+
` + `- Slash commands the user typed and their effects (e.g. "User issued /clear to
|
|
86463
|
+
` + ` reset assistant state").
|
|
86464
|
+
` + `- Hindsight's own errors, retries, backlogs, or internal state \u2014 the memory
|
|
86465
|
+
` + ` system's self-reports are not memories.
|
|
86466
|
+
` + `- Restatements of the user's current request or the task in progress.
|
|
86467
|
+
` + `- Volatile state written as a timeless assertion. A version, count, size,
|
|
86468
|
+
` + ` backlog, status, or any "X is running Y" / "X is at Y" / "X is currently Y"
|
|
86469
|
+
` + ` claim is true only at the instant it was said. Concretely, never produce a
|
|
86470
|
+
` + ` fact whose text resembles any of these: "Switchroom fleet is running image
|
|
86471
|
+
` + ` version v0.18.19", "The switchroom repo is at /path/to/fleet, version
|
|
86472
|
+
` + ` v0.19.5", "Bank overlord has 43155 pending consolidations", "The build is
|
|
86473
|
+
` + ` currently green". If the claim is worth keeping, put the date INSIDE the
|
|
86474
|
+
` + ` fact text ("As of 2026-07-19 the fleet was running v0.18.19"); if you
|
|
86475
|
+
` + ` cannot date it, drop it. An undated one is recalled forever as though it
|
|
86476
|
+
` + ` were still true, which is worse than not remembering it at all.
|
|
86477
|
+
` + `- Transient state (unread counts, build status, what is running right now) unless
|
|
86478
|
+
` + ` the fact is explicitly dated, in which case record it as a dated observation.
|
|
86479
|
+
` + `- Greetings, acknowledgements, and routine operational chatter.
|
|
86480
|
+
` + `
|
|
86481
|
+
` + `Write each fact so it stands alone: name the thing, the number, and the date. A
|
|
86482
|
+
` + `sentence that only makes sense while reading this transcript is not durable.
|
|
86483
|
+
` + `
|
|
86484
|
+
` + `If a candidate fact matches an exclusion, drop it rather than rewording it. If
|
|
86485
|
+
` + `nothing durable remains, return an empty facts list.
|
|
86127
86486
|
`
|
|
86128
86487
|
];
|
|
86129
86488
|
var DEFAULT_OBSERVATIONS_MISSION = `Synthesise durable, standing knowledge about the people, projects, and systems this agent works with: preferences and standing rules, roles and relationships, skills and recurring patterns, technical and operational decisions with their rationale, and the state of long-running work once it lands.
|
|
@@ -86201,6 +86560,22 @@ var PROFILE_MEMORY_DEFAULTS = {
|
|
|
86201
86560
|
var warnedMissingPool = new Set;
|
|
86202
86561
|
var warnedMissingDefault = new Set;
|
|
86203
86562
|
|
|
86563
|
+
// ../src/memory/hindsight-retain-provenance.ts
|
|
86564
|
+
var RETAIN_PROVENANCE_TAG = "source:transcript";
|
|
86565
|
+
var RETAIN_TAGS_DEFAULT = Object.freeze([
|
|
86566
|
+
"{session_id}",
|
|
86567
|
+
RETAIN_PROVENANCE_TAG
|
|
86568
|
+
]);
|
|
86569
|
+
|
|
86570
|
+
// ../src/memory/hindsight-seed-directives.ts
|
|
86571
|
+
var ANTI_CONFABULATION_DIRECTIVE = `When the retrieved memories do not support an answer, say so instead of composing one.
|
|
86572
|
+
` + `
|
|
86573
|
+
` + `- If nothing retrieved scores meaningfully above zero, or what came back is off-topic, the honest answer is that the bank does not know. Say that plainly, and say what would settle it.
|
|
86574
|
+
` + `- Never assert a date, a version, a number, an attribution, a decision, or an outcome that no retrieved memory states. A question that presupposes something is not evidence for it: asked when a decision was made, when the bank records no such decision, answer that none is recorded \u2014 do not supply one.
|
|
86575
|
+
` + `- Keep what the bank RECORDED separate from what you INFER. State inferences as inferences, and say which memory a recorded fact came from.
|
|
86576
|
+
` + `- Treat a memory that was extracted from a conversation transcript as an unverified claim, not an established fact \u2014 it may be an assistant's own earlier guess. If it is the only support for an answer, say that it is.
|
|
86577
|
+
` + "- Partial knowledge with its gaps named is more useful than a fluent answer that fills them in.";
|
|
86578
|
+
|
|
86204
86579
|
// ../src/telegram/state.ts
|
|
86205
86580
|
init_paths();
|
|
86206
86581
|
|
|
@@ -86238,7 +86613,6 @@ var RECALL_PASSTHROUGH_DEFAULTS = Object.freeze({
|
|
|
86238
86613
|
init_paths();
|
|
86239
86614
|
|
|
86240
86615
|
// ../src/agents/scaffold.ts
|
|
86241
|
-
var REPO_ROOT = resolve8(import.meta.dirname, "../..");
|
|
86242
86616
|
var SWITCHROOM_DEFAULT_MAIN_MODEL = "claude-sonnet-5";
|
|
86243
86617
|
var SWITCHROOM_DEFAULT_THINKING_EFFORT = "low";
|
|
86244
86618
|
function resolveMainModel(model) {
|
|
@@ -86798,7 +87172,7 @@ init_overlay_loader();
|
|
|
86798
87172
|
init_merge();
|
|
86799
87173
|
init_timezone();
|
|
86800
87174
|
var import_yaml4 = __toESM(require_dist(), 1);
|
|
86801
|
-
import { readFileSync as
|
|
87175
|
+
import { readFileSync as readFileSync34, existsSync as existsSync35 } from "node:fs";
|
|
86802
87176
|
import { homedir as homedir12 } from "node:os";
|
|
86803
87177
|
import { resolve as resolve9 } from "node:path";
|
|
86804
87178
|
|
|
@@ -86874,7 +87248,7 @@ function findConfigFile2(startDir) {
|
|
|
86874
87248
|
resolve9(userDir, "clerk.yml")
|
|
86875
87249
|
].filter(Boolean);
|
|
86876
87250
|
for (const path2 of searchPaths) {
|
|
86877
|
-
if (
|
|
87251
|
+
if (existsSync35(path2)) {
|
|
86878
87252
|
return path2;
|
|
86879
87253
|
}
|
|
86880
87254
|
}
|
|
@@ -86882,12 +87256,12 @@ function findConfigFile2(startDir) {
|
|
|
86882
87256
|
}
|
|
86883
87257
|
function loadConfig2(configPath) {
|
|
86884
87258
|
const filePath = configPath ?? findConfigFile2();
|
|
86885
|
-
if (!
|
|
87259
|
+
if (!existsSync35(filePath)) {
|
|
86886
87260
|
throw new ConfigError2(`Config file not found: ${filePath}`);
|
|
86887
87261
|
}
|
|
86888
87262
|
let raw;
|
|
86889
87263
|
try {
|
|
86890
|
-
raw =
|
|
87264
|
+
raw = readFileSync34(filePath, "utf-8");
|
|
86891
87265
|
} catch (err) {
|
|
86892
87266
|
throw new ConfigError2(`Failed to read config file: ${filePath}`, [
|
|
86893
87267
|
` ${err.message}`
|
|
@@ -87417,15 +87791,15 @@ function topicForRecipient(args) {
|
|
|
87417
87791
|
}
|
|
87418
87792
|
|
|
87419
87793
|
// ../src/agents/perf.ts
|
|
87420
|
-
import { existsSync as
|
|
87794
|
+
import { existsSync as existsSync36, readFileSync as readFileSync35 } from "node:fs";
|
|
87421
87795
|
function readTurnUsages(jsonlPath, lastN) {
|
|
87422
|
-
if (!
|
|
87796
|
+
if (!existsSync36(jsonlPath))
|
|
87423
87797
|
return [];
|
|
87424
87798
|
if (lastN <= 0)
|
|
87425
87799
|
return [];
|
|
87426
87800
|
let raw;
|
|
87427
87801
|
try {
|
|
87428
|
-
raw =
|
|
87802
|
+
raw = readFileSync35(jsonlPath, "utf-8");
|
|
87429
87803
|
} catch {
|
|
87430
87804
|
return [];
|
|
87431
87805
|
}
|
|
@@ -87517,7 +87891,7 @@ function numField(obj, key) {
|
|
|
87517
87891
|
|
|
87518
87892
|
// gateway/context-occupancy.ts
|
|
87519
87893
|
import { mkdirSync as mkdirSync33, writeFileSync as writeFileSync30 } from "node:fs";
|
|
87520
|
-
import { join as
|
|
87894
|
+
import { join as join44 } from "node:path";
|
|
87521
87895
|
var CONTEXT_OCCUPANCY_FILENAME = "context-occupancy.json";
|
|
87522
87896
|
var TIGHT_FRACTION = 0.8;
|
|
87523
87897
|
function buildContextOccupancy(occupancy, cap, now) {
|
|
@@ -87540,7 +87914,7 @@ function buildContextOccupancy(occupancy, cap, now) {
|
|
|
87540
87914
|
}
|
|
87541
87915
|
function writeContextOccupancySnapshot(stateDir, snapshot, deps) {
|
|
87542
87916
|
try {
|
|
87543
|
-
const path2 =
|
|
87917
|
+
const path2 = join44(stateDir, CONTEXT_OCCUPANCY_FILENAME);
|
|
87544
87918
|
(deps?.mkdir ?? ((p, o) => mkdirSync33(p, o)))(stateDir, { recursive: true });
|
|
87545
87919
|
(deps?.writeFile ?? ((p, d) => writeFileSync30(p, d)))(path2, JSON.stringify(snapshot, null, 2) + `
|
|
87546
87920
|
`);
|
|
@@ -87696,7 +88070,7 @@ function nextCompactNotify(state6, ev) {
|
|
|
87696
88070
|
}
|
|
87697
88071
|
|
|
87698
88072
|
// gateway/hostd-dispatch.ts
|
|
87699
|
-
import { existsSync as
|
|
88073
|
+
import { existsSync as existsSync37 } from "node:fs";
|
|
87700
88074
|
import { randomBytes as randomBytes10 } from "node:crypto";
|
|
87701
88075
|
init_loader();
|
|
87702
88076
|
var _hostdEnabled2;
|
|
@@ -87720,13 +88094,13 @@ function hostdSocketPath2(agentName3) {
|
|
|
87720
88094
|
function hostdWillBeUsed2(agentName3) {
|
|
87721
88095
|
if (!isHostdEnabled2())
|
|
87722
88096
|
return false;
|
|
87723
|
-
return
|
|
88097
|
+
return existsSync37(hostdSocketPath2(agentName3));
|
|
87724
88098
|
}
|
|
87725
88099
|
async function tryHostdDispatch2(agentName3, req, timeoutMs = 5000) {
|
|
87726
88100
|
if (!isHostdEnabled2())
|
|
87727
88101
|
return "not-configured";
|
|
87728
88102
|
const sockPath = hostdSocketPath2(agentName3);
|
|
87729
|
-
if (!
|
|
88103
|
+
if (!existsSync37(sockPath))
|
|
87730
88104
|
return "not-configured";
|
|
87731
88105
|
try {
|
|
87732
88106
|
return await hostdRequest({ socketPath: sockPath, timeoutMs }, req);
|
|
@@ -87755,7 +88129,7 @@ async function pollHostdStatus(agentName3, targetRequestId, opts) {
|
|
|
87755
88129
|
if (!isHostdEnabled2())
|
|
87756
88130
|
return "not-configured";
|
|
87757
88131
|
const sockPath = hostdSocketPath2(agentName3);
|
|
87758
|
-
if (!
|
|
88132
|
+
if (!existsSync37(sockPath))
|
|
87759
88133
|
return "not-configured";
|
|
87760
88134
|
const now = opts.now ?? Date.now;
|
|
87761
88135
|
const sleep2 = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
@@ -88721,7 +89095,7 @@ function createGatewayStalePinSweeper(w) {
|
|
|
88721
89095
|
|
|
88722
89096
|
// gateway/webhook-ingest-server.ts
|
|
88723
89097
|
import net4 from "node:net";
|
|
88724
|
-
import { chmodSync as chmodSync10, existsSync as
|
|
89098
|
+
import { chmodSync as chmodSync10, existsSync as existsSync38, unlinkSync as unlinkSync18 } from "node:fs";
|
|
88725
89099
|
var MAX_REQUEST_BYTES = 1024 * 1024;
|
|
88726
89100
|
function fdOf(conn) {
|
|
88727
89101
|
const handle = conn._handle;
|
|
@@ -88733,7 +89107,7 @@ function startWebhookIngestServer(opts) {
|
|
|
88733
89107
|
const log = opts.log ?? ((s) => process.stderr.write(s));
|
|
88734
89108
|
const allowed = new Set(opts.allowedUids);
|
|
88735
89109
|
try {
|
|
88736
|
-
if (
|
|
89110
|
+
if (existsSync38(opts.socketPath))
|
|
88737
89111
|
unlinkSync18(opts.socketPath);
|
|
88738
89112
|
} catch (err) {
|
|
88739
89113
|
log(`webhook-ingest-server: could not unlink stale socket: ${err.message}
|
|
@@ -88826,7 +89200,7 @@ function startWebhookIngestServer(opts) {
|
|
|
88826
89200
|
server.close();
|
|
88827
89201
|
} catch {}
|
|
88828
89202
|
try {
|
|
88829
|
-
if (
|
|
89203
|
+
if (existsSync38(opts.socketPath))
|
|
88830
89204
|
unlinkSync18(opts.socketPath);
|
|
88831
89205
|
} catch {}
|
|
88832
89206
|
}
|
|
@@ -88835,12 +89209,12 @@ function startWebhookIngestServer(opts) {
|
|
|
88835
89209
|
|
|
88836
89210
|
// ../src/web/webhook-gateway-record.ts
|
|
88837
89211
|
import { appendFileSync as appendFileSync8, mkdirSync as mkdirSync36 } from "fs";
|
|
88838
|
-
import { join as
|
|
89212
|
+
import { join as join48 } from "path";
|
|
88839
89213
|
import { homedir as homedir14 } from "os";
|
|
88840
89214
|
|
|
88841
89215
|
// ../src/web/webhook-handler.ts
|
|
88842
|
-
import { appendFileSync as appendFileSync7, existsSync as
|
|
88843
|
-
import { join as
|
|
89216
|
+
import { appendFileSync as appendFileSync7, existsSync as existsSync40, mkdirSync as mkdirSync34, readFileSync as readFileSync36, writeFileSync as writeFileSync31 } from "fs";
|
|
89217
|
+
import { join as join46 } from "path";
|
|
88844
89218
|
|
|
88845
89219
|
// ../src/util/log-rotation.ts
|
|
88846
89220
|
import * as fs2 from "node:fs";
|
|
@@ -89178,9 +89552,9 @@ var DEDUP_MAX = 1000;
|
|
|
89178
89552
|
var DEDUP_TTL_MS = 24 * 60 * 60 * 1000;
|
|
89179
89553
|
function loadDedupFile(path3) {
|
|
89180
89554
|
try {
|
|
89181
|
-
if (!
|
|
89555
|
+
if (!existsSync40(path3))
|
|
89182
89556
|
return {};
|
|
89183
|
-
const raw = JSON.parse(
|
|
89557
|
+
const raw = JSON.parse(readFileSync36(path3, "utf-8"));
|
|
89184
89558
|
return typeof raw.deliveries === "object" && raw.deliveries !== null ? raw.deliveries : {};
|
|
89185
89559
|
} catch {
|
|
89186
89560
|
return {};
|
|
@@ -89202,8 +89576,8 @@ var agentDedupCache = new Map;
|
|
|
89202
89576
|
function createFileDedupStore(resolveAgentDir) {
|
|
89203
89577
|
return {
|
|
89204
89578
|
check(agent, deliveryId, now) {
|
|
89205
|
-
const telegramDir =
|
|
89206
|
-
const filePath =
|
|
89579
|
+
const telegramDir = join46(resolveAgentDir(agent), "telegram");
|
|
89580
|
+
const filePath = join46(telegramDir, "webhook-dedup.json");
|
|
89207
89581
|
if (!agentDedupCache.has(agent)) {
|
|
89208
89582
|
agentDedupCache.set(agent, loadDedupFile(filePath));
|
|
89209
89583
|
}
|
|
@@ -89224,8 +89598,8 @@ var tokenBuckets = new Map;
|
|
|
89224
89598
|
var throttleIssueWindow = new Map;
|
|
89225
89599
|
|
|
89226
89600
|
// ../src/web/webhook-dispatch.ts
|
|
89227
|
-
import { existsSync as
|
|
89228
|
-
import { join as
|
|
89601
|
+
import { existsSync as existsSync41, mkdirSync as mkdirSync35, readFileSync as readFileSync37, writeFileSync as writeFileSync32 } from "fs";
|
|
89602
|
+
import { join as join47 } from "path";
|
|
89229
89603
|
import { homedir as homedir13 } from "os";
|
|
89230
89604
|
|
|
89231
89605
|
// ../src/agent-scheduler/ipc-client.ts
|
|
@@ -89524,9 +89898,9 @@ function cooldownKey(source, eventType, repo, number, ruleIndex) {
|
|
|
89524
89898
|
}
|
|
89525
89899
|
function loadCooldownFile(path3) {
|
|
89526
89900
|
try {
|
|
89527
|
-
if (!
|
|
89901
|
+
if (!existsSync41(path3))
|
|
89528
89902
|
return {};
|
|
89529
|
-
const raw = JSON.parse(
|
|
89903
|
+
const raw = JSON.parse(readFileSync37(path3, "utf-8"));
|
|
89530
89904
|
return typeof raw.dispatches === "object" && raw.dispatches !== null ? raw.dispatches : {};
|
|
89531
89905
|
} catch {
|
|
89532
89906
|
return {};
|
|
@@ -89545,8 +89919,8 @@ function createFileCooldownStore(resolveAgentDir) {
|
|
|
89545
89919
|
isCoolingDown(agent, key, cooldownMs, now) {
|
|
89546
89920
|
if (cooldownMs <= 0)
|
|
89547
89921
|
return false;
|
|
89548
|
-
const telegramDir =
|
|
89549
|
-
const filePath =
|
|
89922
|
+
const telegramDir = join47(resolveAgentDir(agent), "telegram");
|
|
89923
|
+
const filePath = join47(telegramDir, "webhook-cooldown.json");
|
|
89550
89924
|
if (!cache.has(agent)) {
|
|
89551
89925
|
cache.set(agent, loadCooldownFile(filePath));
|
|
89552
89926
|
}
|
|
@@ -89603,9 +89977,9 @@ async function defaultInject(socketPath, agentName3, inbound) {
|
|
|
89603
89977
|
}
|
|
89604
89978
|
function injectWebhookInbound(agent, prompt, ctx, deps = {}) {
|
|
89605
89979
|
const log = deps.log ?? ((s) => process.stderr.write(s));
|
|
89606
|
-
const resolveAgentDir = deps.resolveAgentDir ?? ((a) =>
|
|
89980
|
+
const resolveAgentDir = deps.resolveAgentDir ?? ((a) => join47(homedir13(), ".switchroom", "agents", a));
|
|
89607
89981
|
const now = (deps.now ?? Date.now)();
|
|
89608
|
-
const socketPath =
|
|
89982
|
+
const socketPath = join47(resolveAgentDir(agent), "telegram", "gateway.sock");
|
|
89609
89983
|
const inbound = {
|
|
89610
89984
|
type: "inbound",
|
|
89611
89985
|
chatId: ctx.chatId,
|
|
@@ -89677,7 +90051,7 @@ function evaluateDispatch(args, deps = {}) {
|
|
|
89677
90051
|
const log = deps.log ?? ((s) => process.stderr.write(s));
|
|
89678
90052
|
const now = (deps.now ?? Date.now)();
|
|
89679
90053
|
const nowDate = deps.nowDate ?? (() => new Date(now));
|
|
89680
|
-
const resolveAgentDir = deps.resolveAgentDir ?? ((a) =>
|
|
90054
|
+
const resolveAgentDir = deps.resolveAgentDir ?? ((a) => join47(homedir13(), ".switchroom", "agents", a));
|
|
89681
90055
|
const cooldownStore = deps.cooldownStore ?? createFileCooldownStore(resolveAgentDir);
|
|
89682
90056
|
if (!DISPATCH_SOURCES.includes(args.source))
|
|
89683
90057
|
return 0;
|
|
@@ -89755,10 +90129,10 @@ var CONSOLIDATION_COMPLETED_EVENT = "consolidation.completed";
|
|
|
89755
90129
|
function recordWebhookEvent(rec, deps = {}) {
|
|
89756
90130
|
const log = deps.log ?? ((s) => process.stderr.write(s));
|
|
89757
90131
|
const now = rec.ts || (deps.now ?? Date.now)();
|
|
89758
|
-
const resolveAgentDir = deps.resolveAgentDir ?? ((a) =>
|
|
90132
|
+
const resolveAgentDir = deps.resolveAgentDir ?? ((a) => join48(homedir14(), ".switchroom", "agents", a));
|
|
89759
90133
|
const dedupStore = deps.dedupStore ?? createFileDedupStore(resolveAgentDir);
|
|
89760
90134
|
const agent = rec.agent;
|
|
89761
|
-
const telegramDir =
|
|
90135
|
+
const telegramDir = join48(resolveAgentDir(agent), "telegram");
|
|
89762
90136
|
if (rec.source === "github" && rec.delivery_id) {
|
|
89763
90137
|
const originalTs = dedupStore.check(agent, rec.delivery_id, now);
|
|
89764
90138
|
if (originalTs !== undefined) {
|
|
@@ -89767,7 +90141,7 @@ function recordWebhookEvent(rec, deps = {}) {
|
|
|
89767
90141
|
return { status: "deduped", ts: originalTs };
|
|
89768
90142
|
}
|
|
89769
90143
|
}
|
|
89770
|
-
const logPath =
|
|
90144
|
+
const logPath = join48(telegramDir, "webhook-events.jsonl");
|
|
89771
90145
|
try {
|
|
89772
90146
|
mkdirSync36(telegramDir, { recursive: true });
|
|
89773
90147
|
rotateWebhookLogIfNeeded(logPath);
|
|
@@ -91047,76 +91421,6 @@ function buildDiffPreviewCard(input) {
|
|
|
91047
91421
|
return { text: text4, reply_markup: kb };
|
|
91048
91422
|
}
|
|
91049
91423
|
|
|
91050
|
-
// gateway/subagent-handback-marker.ts
|
|
91051
|
-
var INBOUND_SOURCE_CLASSIFICATION = {
|
|
91052
|
-
subagent_handback: { decoupledCompletion: true },
|
|
91053
|
-
cron: { decoupledCompletion: false },
|
|
91054
|
-
reaction: { decoupledCompletion: false },
|
|
91055
|
-
subagent_progress: { decoupledCompletion: false },
|
|
91056
|
-
resume_interrupted: { decoupledCompletion: false },
|
|
91057
|
-
resume_deferred: { decoupledCompletion: false },
|
|
91058
|
-
resume_watchdog_timeout: { decoupledCompletion: false },
|
|
91059
|
-
vault_grant_approved: { decoupledCompletion: false },
|
|
91060
|
-
vault_grant_denied: { decoupledCompletion: false },
|
|
91061
|
-
vault_grant_timeout: { decoupledCompletion: false },
|
|
91062
|
-
vault_save_completed: { decoupledCompletion: false },
|
|
91063
|
-
vault_save_discarded: { decoupledCompletion: false },
|
|
91064
|
-
vault_save_failed: { decoupledCompletion: false },
|
|
91065
|
-
vault_save_timeout: { decoupledCompletion: false },
|
|
91066
|
-
secret_provided: { decoupledCompletion: false },
|
|
91067
|
-
secret_declined: { decoupledCompletion: false },
|
|
91068
|
-
secret_provide_failed: { decoupledCompletion: false },
|
|
91069
|
-
secret_request_timeout: { decoupledCompletion: false },
|
|
91070
|
-
mental_model_propose_timeout: { decoupledCompletion: false },
|
|
91071
|
-
bridge_dead_restart: { decoupledCompletion: false },
|
|
91072
|
-
obligation_represent: { decoupledCompletion: false },
|
|
91073
|
-
missed_approval_retry: { decoupledCompletion: false },
|
|
91074
|
-
skill_proposal_apply: { decoupledCompletion: false },
|
|
91075
|
-
warmup: { decoupledCompletion: false },
|
|
91076
|
-
mental_model_proposal_applied: { decoupledCompletion: false },
|
|
91077
|
-
mental_model_proposal_denied: { decoupledCompletion: false },
|
|
91078
|
-
mental_model_proposal_failed: { decoupledCompletion: false },
|
|
91079
|
-
webhook: { decoupledCompletion: false },
|
|
91080
|
-
linear: { decoupledCompletion: false }
|
|
91081
|
-
};
|
|
91082
|
-
function stampsHandbackMarker(source) {
|
|
91083
|
-
if (source == null)
|
|
91084
|
-
return false;
|
|
91085
|
-
const known = INBOUND_SOURCE_CLASSIFICATION[source];
|
|
91086
|
-
if (known == null)
|
|
91087
|
-
return true;
|
|
91088
|
-
return known.decoupledCompletion;
|
|
91089
|
-
}
|
|
91090
|
-
var MAIN_THREAD_KEY2 = "<main>";
|
|
91091
|
-
|
|
91092
|
-
class SubagentHandbackMarker2 {
|
|
91093
|
-
byChat = new Map;
|
|
91094
|
-
threadKey(threadId) {
|
|
91095
|
-
return threadId == null ? MAIN_THREAD_KEY2 : String(threadId);
|
|
91096
|
-
}
|
|
91097
|
-
record(chatId, threadId, now) {
|
|
91098
|
-
let inner = this.byChat.get(chatId);
|
|
91099
|
-
if (inner == null) {
|
|
91100
|
-
inner = new Map;
|
|
91101
|
-
this.byChat.set(chatId, inner);
|
|
91102
|
-
}
|
|
91103
|
-
inner.set(this.threadKey(threadId), now);
|
|
91104
|
-
}
|
|
91105
|
-
lastAt(chatId, threadId) {
|
|
91106
|
-
return this.byChat.get(chatId)?.get(this.threadKey(threadId)) ?? null;
|
|
91107
|
-
}
|
|
91108
|
-
lastAtInChat(chatId) {
|
|
91109
|
-
const inner = this.byChat.get(chatId);
|
|
91110
|
-
if (inner == null || inner.size === 0)
|
|
91111
|
-
return null;
|
|
91112
|
-
let max = -Infinity;
|
|
91113
|
-
for (const ts of inner.values())
|
|
91114
|
-
if (ts > max)
|
|
91115
|
-
max = ts;
|
|
91116
|
-
return max === -Infinity ? null : max;
|
|
91117
|
-
}
|
|
91118
|
-
}
|
|
91119
|
-
|
|
91120
91424
|
// gateway/pending-inbound-buffer.ts
|
|
91121
91425
|
var DEFAULT_PENDING_INBOUND_CAP = 32;
|
|
91122
91426
|
function redeliverBufferedInbound(buffer, agent, send, spool, onDelivered) {
|
|
@@ -91270,6 +91574,11 @@ function cronIdentity(agent) {
|
|
|
91270
91574
|
function isCronIdentity(name) {
|
|
91271
91575
|
return typeof name === "string" && name.endsWith(CRON_IDENTITY_SUFFIX);
|
|
91272
91576
|
}
|
|
91577
|
+
function replyCallerIsForeignSession(name) {
|
|
91578
|
+
if (name == null || name === "")
|
|
91579
|
+
return true;
|
|
91580
|
+
return isCronIdentity(name);
|
|
91581
|
+
}
|
|
91273
91582
|
function isCronInjectFire(meta) {
|
|
91274
91583
|
return meta?.source === "cron" || meta?.session === "cron";
|
|
91275
91584
|
}
|
|
@@ -93069,6 +93378,7 @@ function createTurnEndFunnel(deps) {
|
|
|
93069
93378
|
endCurrentTurnForKey(turn, key);
|
|
93070
93379
|
const turnEndedAt = Date.now();
|
|
93071
93380
|
turn.endedAt = turnEndedAt;
|
|
93381
|
+
turn.realEndObservedAt = turnEndedAt;
|
|
93072
93382
|
process.stderr.write(`telegram gateway: ${formatTurnLifecycle("clear", "turn_end", turn, turnEndedAt)}
|
|
93073
93383
|
`);
|
|
93074
93384
|
if (opts?.deferRecord !== true) {
|
|
@@ -94030,14 +94340,14 @@ function purgeStaleTurnsForChat(chatId, keys, purger, isStale = () => true) {
|
|
|
94030
94340
|
// gateway/compaction-marker.ts
|
|
94031
94341
|
import { statSync as statSync15, unlinkSync as unlinkSync21 } from "node:fs";
|
|
94032
94342
|
import { homedir as homedir15 } from "node:os";
|
|
94033
|
-
import { join as
|
|
94343
|
+
import { join as join49 } from "node:path";
|
|
94034
94344
|
var COMPACTION_MARKER_FILE = "compaction-in-flight.json";
|
|
94035
94345
|
function resolveTelegramStateDir() {
|
|
94036
|
-
return process.env.TELEGRAM_STATE_DIR ??
|
|
94346
|
+
return process.env.TELEGRAM_STATE_DIR ?? join49(homedir15(), ".claude", "channels", "telegram");
|
|
94037
94347
|
}
|
|
94038
94348
|
function readCompactionMarkerAgeMs(stateDir, now) {
|
|
94039
94349
|
try {
|
|
94040
|
-
const st = statSync15(
|
|
94350
|
+
const st = statSync15(join49(stateDir, COMPACTION_MARKER_FILE));
|
|
94041
94351
|
return (now ?? Date.now()) - st.mtimeMs;
|
|
94042
94352
|
} catch {
|
|
94043
94353
|
return null;
|
|
@@ -94045,7 +94355,7 @@ function readCompactionMarkerAgeMs(stateDir, now) {
|
|
|
94045
94355
|
}
|
|
94046
94356
|
function removeCompactionMarker(stateDir) {
|
|
94047
94357
|
try {
|
|
94048
|
-
unlinkSync21(
|
|
94358
|
+
unlinkSync21(join49(stateDir, COMPACTION_MARKER_FILE));
|
|
94049
94359
|
} catch {}
|
|
94050
94360
|
}
|
|
94051
94361
|
|
|
@@ -94867,26 +95177,26 @@ function skillProposalKeyboard(id) {
|
|
|
94867
95177
|
// ../src/self-improve/skill-proposals.ts
|
|
94868
95178
|
import {
|
|
94869
95179
|
closeSync as closeSync9,
|
|
94870
|
-
existsSync as
|
|
95180
|
+
existsSync as existsSync42,
|
|
94871
95181
|
mkdirSync as mkdirSync37,
|
|
94872
95182
|
openSync as openSync9,
|
|
94873
|
-
readFileSync as
|
|
95183
|
+
readFileSync as readFileSync38,
|
|
94874
95184
|
writeSync as writeSync6
|
|
94875
95185
|
} from "node:fs";
|
|
94876
|
-
import { join as
|
|
95186
|
+
import { join as join50 } from "node:path";
|
|
94877
95187
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
94878
95188
|
var PROPOSALS_FILE2 = "skill-proposals.jsonl";
|
|
94879
95189
|
var REJECTED_FILE2 = "skill-proposals-rejected.jsonl";
|
|
94880
95190
|
var REJECTION_TTL_MS2 = 90 * 24 * 60 * 60 * 1000;
|
|
94881
95191
|
var PROPOSAL_SIM_THRESHOLD = 0.5;
|
|
94882
95192
|
function proposalsPath2(stateDir) {
|
|
94883
|
-
return
|
|
95193
|
+
return join50(stateDir, PROPOSALS_FILE2);
|
|
94884
95194
|
}
|
|
94885
95195
|
function rejectedPath2(stateDir) {
|
|
94886
|
-
return
|
|
95196
|
+
return join50(stateDir, REJECTED_FILE2);
|
|
94887
95197
|
}
|
|
94888
95198
|
function ensureDir3(stateDir) {
|
|
94889
|
-
if (!
|
|
95199
|
+
if (!existsSync42(stateDir)) {
|
|
94890
95200
|
mkdirSync37(stateDir, { recursive: true, mode: 493 });
|
|
94891
95201
|
}
|
|
94892
95202
|
}
|
|
@@ -94900,11 +95210,11 @@ function appendLine2(path3, obj) {
|
|
|
94900
95210
|
}
|
|
94901
95211
|
}
|
|
94902
95212
|
function readLines2(path3, isValid2) {
|
|
94903
|
-
if (!
|
|
95213
|
+
if (!existsSync42(path3))
|
|
94904
95214
|
return [];
|
|
94905
95215
|
let raw;
|
|
94906
95216
|
try {
|
|
94907
|
-
raw =
|
|
95217
|
+
raw = readFileSync38(path3, "utf-8");
|
|
94908
95218
|
} catch {
|
|
94909
95219
|
return [];
|
|
94910
95220
|
}
|
|
@@ -95501,7 +95811,7 @@ function escapeBody2(s) {
|
|
|
95501
95811
|
}
|
|
95502
95812
|
|
|
95503
95813
|
// gateway/pid-file.ts
|
|
95504
|
-
import { writeFileSync as writeFileSync33, readFileSync as
|
|
95814
|
+
import { writeFileSync as writeFileSync33, readFileSync as readFileSync39, unlinkSync as unlinkSync22, renameSync as renameSync18 } from "node:fs";
|
|
95505
95815
|
function writePidFile(path3, record) {
|
|
95506
95816
|
const tmp = `${path3}.tmp-${process.pid}-${Date.now()}`;
|
|
95507
95817
|
writeFileSync33(tmp, JSON.stringify(record), "utf-8");
|
|
@@ -95520,10 +95830,10 @@ import {
|
|
|
95520
95830
|
writeFile as writeFileAsync,
|
|
95521
95831
|
readFile as readFileAsync
|
|
95522
95832
|
} from "node:fs/promises";
|
|
95523
|
-
import { readFileSync as
|
|
95833
|
+
import { readFileSync as readFileSync40 } from "node:fs";
|
|
95524
95834
|
function readCurrentBootId() {
|
|
95525
95835
|
try {
|
|
95526
|
-
const stat =
|
|
95836
|
+
const stat = readFileSync40("/proc/1/stat", "utf-8");
|
|
95527
95837
|
const lastParen = stat.lastIndexOf(")");
|
|
95528
95838
|
if (lastParen < 0)
|
|
95529
95839
|
return null;
|
|
@@ -95726,7 +96036,7 @@ function safeCount(fn) {
|
|
|
95726
96036
|
}
|
|
95727
96037
|
|
|
95728
96038
|
// gateway/session-marker.ts
|
|
95729
|
-
import { writeFileSync as writeFileSync34, readFileSync as
|
|
96039
|
+
import { writeFileSync as writeFileSync34, readFileSync as readFileSync41, renameSync as renameSync19, unlinkSync as unlinkSync23 } from "node:fs";
|
|
95730
96040
|
function writeSessionMarker(path3, marker) {
|
|
95731
96041
|
const tmp = `${path3}.tmp-${process.pid}-${Date.now()}`;
|
|
95732
96042
|
writeFileSync34(tmp, JSON.stringify(marker), "utf-8");
|
|
@@ -95734,7 +96044,7 @@ function writeSessionMarker(path3, marker) {
|
|
|
95734
96044
|
}
|
|
95735
96045
|
function readSessionMarker(path3) {
|
|
95736
96046
|
try {
|
|
95737
|
-
const raw =
|
|
96047
|
+
const raw = readFileSync41(path3, "utf-8");
|
|
95738
96048
|
const parsed = JSON.parse(raw);
|
|
95739
96049
|
if (typeof parsed.pid === "number" && typeof parsed.startedAtMs === "number" && Number.isFinite(parsed.pid) && Number.isFinite(parsed.startedAtMs)) {
|
|
95740
96050
|
return { pid: parsed.pid, startedAtMs: parsed.startedAtMs };
|
|
@@ -95756,7 +96066,7 @@ function shouldFireRestartBanner(input) {
|
|
|
95756
96066
|
}
|
|
95757
96067
|
|
|
95758
96068
|
// gateway/clean-shutdown-marker.ts
|
|
95759
|
-
import { writeFileSync as writeFileSync35, readFileSync as
|
|
96069
|
+
import { writeFileSync as writeFileSync35, readFileSync as readFileSync42, renameSync as renameSync20, unlinkSync as unlinkSync24 } from "node:fs";
|
|
95760
96070
|
var DEFAULT_MAX_AGE_MS = 60000;
|
|
95761
96071
|
function writeCleanShutdownMarker(path3, marker) {
|
|
95762
96072
|
const tmp = `${path3}.tmp-${process.pid}-${Date.now()}`;
|
|
@@ -95765,7 +96075,7 @@ function writeCleanShutdownMarker(path3, marker) {
|
|
|
95765
96075
|
}
|
|
95766
96076
|
function readCleanShutdownMarker(path3) {
|
|
95767
96077
|
try {
|
|
95768
|
-
const raw =
|
|
96078
|
+
const raw = readFileSync42(path3, "utf-8");
|
|
95769
96079
|
const parsed = JSON.parse(raw);
|
|
95770
96080
|
if (typeof parsed.ts === "number" && Number.isFinite(parsed.ts) && typeof parsed.signal === "string" && parsed.signal.length > 0) {
|
|
95771
96081
|
const out = { ts: parsed.ts, signal: parsed.signal };
|
|
@@ -96137,16 +96447,16 @@ function classifyAdminGate(text4, myAgentName) {
|
|
|
96137
96447
|
|
|
96138
96448
|
// subagent-watcher.ts
|
|
96139
96449
|
import {
|
|
96140
|
-
existsSync as
|
|
96450
|
+
existsSync as existsSync43,
|
|
96141
96451
|
openSync as openSync10,
|
|
96142
96452
|
readSync as readSync2,
|
|
96143
96453
|
statSync as statSync16,
|
|
96144
96454
|
closeSync as closeSync10,
|
|
96145
96455
|
watch,
|
|
96146
96456
|
readdirSync as readdirSync10,
|
|
96147
|
-
readFileSync as
|
|
96457
|
+
readFileSync as readFileSync43
|
|
96148
96458
|
} from "fs";
|
|
96149
|
-
import { join as
|
|
96459
|
+
import { join as join51 } from "path";
|
|
96150
96460
|
|
|
96151
96461
|
// session-tail.ts
|
|
96152
96462
|
function sanitizeCwdToProjectName2(cwd) {
|
|
@@ -96496,7 +96806,7 @@ function backfillJsonlAgentId(db3, jsonlPath, agentId, log) {
|
|
|
96496
96806
|
const metaPath = jsonlPath.replace(/\.jsonl$/, ".meta.json");
|
|
96497
96807
|
let meta;
|
|
96498
96808
|
try {
|
|
96499
|
-
const raw =
|
|
96809
|
+
const raw = readFileSync43(metaPath, "utf8");
|
|
96500
96810
|
meta = JSON.parse(raw);
|
|
96501
96811
|
} catch {
|
|
96502
96812
|
log?.(`subagent-watcher: backfill skip ${agentId} \u2014 meta.json not readable at ${metaPath}`);
|
|
@@ -96951,7 +97261,7 @@ function startSubagentWatcher(config) {
|
|
|
96951
97261
|
clearTimeout(ref.ref);
|
|
96952
97262
|
});
|
|
96953
97263
|
const fs3 = config.fs ?? {
|
|
96954
|
-
existsSync:
|
|
97264
|
+
existsSync: existsSync43,
|
|
96955
97265
|
readdirSync: readdirSync10,
|
|
96956
97266
|
statSync: statSync16,
|
|
96957
97267
|
openSync: openSync10,
|
|
@@ -97469,8 +97779,8 @@ function startSubagentWatcher(config) {
|
|
|
97469
97779
|
if (stopped)
|
|
97470
97780
|
return;
|
|
97471
97781
|
pruneVanishedDirWatchers();
|
|
97472
|
-
const claudeHome =
|
|
97473
|
-
const projectsRoot =
|
|
97782
|
+
const claudeHome = join51(agentDir, ".claude");
|
|
97783
|
+
const projectsRoot = join51(claudeHome, "projects");
|
|
97474
97784
|
if (!fs3.existsSync(projectsRoot))
|
|
97475
97785
|
return;
|
|
97476
97786
|
let projectDirs;
|
|
@@ -97504,7 +97814,7 @@ function startSubagentWatcher(config) {
|
|
|
97504
97814
|
continue;
|
|
97505
97815
|
}
|
|
97506
97816
|
warnedForeignSlugs.delete(pDir);
|
|
97507
|
-
const projectPath =
|
|
97817
|
+
const projectPath = join51(projectsRoot, pDir);
|
|
97508
97818
|
let sessionDirs;
|
|
97509
97819
|
try {
|
|
97510
97820
|
sessionDirs = fs3.readdirSync(projectPath);
|
|
@@ -97514,7 +97824,7 @@ function startSubagentWatcher(config) {
|
|
|
97514
97824
|
for (const sDir of sessionDirs) {
|
|
97515
97825
|
if (sDir.endsWith(".jsonl"))
|
|
97516
97826
|
continue;
|
|
97517
|
-
const subagentsPath =
|
|
97827
|
+
const subagentsPath = join51(projectPath, sDir, "subagents");
|
|
97518
97828
|
if (!fs3.existsSync(subagentsPath))
|
|
97519
97829
|
continue;
|
|
97520
97830
|
const watchAndScan = (dirPath) => {
|
|
@@ -97523,7 +97833,7 @@ function startSubagentWatcher(config) {
|
|
|
97523
97833
|
const w = fs3.watch(dirPath, (_event, filename) => {
|
|
97524
97834
|
if (!filename || !filename.toString().startsWith("agent-") || !filename.toString().endsWith(".jsonl"))
|
|
97525
97835
|
return;
|
|
97526
|
-
const filePath =
|
|
97836
|
+
const filePath = join51(dirPath, filename.toString());
|
|
97527
97837
|
if (!knownFiles.has(filePath)) {
|
|
97528
97838
|
scanSubagentsDir(dirPath);
|
|
97529
97839
|
}
|
|
@@ -97537,7 +97847,7 @@ function startSubagentWatcher(config) {
|
|
|
97537
97847
|
scanSubagentsDir(dirPath);
|
|
97538
97848
|
};
|
|
97539
97849
|
watchAndScan(subagentsPath);
|
|
97540
|
-
const workflowsPath =
|
|
97850
|
+
const workflowsPath = join51(subagentsPath, "workflows");
|
|
97541
97851
|
if (fs3.existsSync(workflowsPath)) {
|
|
97542
97852
|
let wfDirs;
|
|
97543
97853
|
try {
|
|
@@ -97547,7 +97857,7 @@ function startSubagentWatcher(config) {
|
|
|
97547
97857
|
}
|
|
97548
97858
|
for (const wfDir of wfDirs) {
|
|
97549
97859
|
try {
|
|
97550
|
-
const wfPath =
|
|
97860
|
+
const wfPath = join51(workflowsPath, wfDir);
|
|
97551
97861
|
if (!fs3.statSync(wfPath).isDirectory())
|
|
97552
97862
|
continue;
|
|
97553
97863
|
watchAndScan(wfPath);
|
|
@@ -97567,7 +97877,7 @@ function startSubagentWatcher(config) {
|
|
|
97567
97877
|
for (const e of entries) {
|
|
97568
97878
|
if (!e.startsWith("agent-") || !e.endsWith(".jsonl"))
|
|
97569
97879
|
continue;
|
|
97570
|
-
const filePath =
|
|
97880
|
+
const filePath = join51(subagentsPath, e);
|
|
97571
97881
|
if (knownFiles.has(filePath))
|
|
97572
97882
|
continue;
|
|
97573
97883
|
const agentId = e.slice("agent-".length, -".jsonl".length);
|
|
@@ -97697,19 +98007,19 @@ function startSubagentWatcher(config) {
|
|
|
97697
98007
|
import {
|
|
97698
98008
|
mkdirSync as mkdirSync38,
|
|
97699
98009
|
writeFileSync as writeFileSync36,
|
|
97700
|
-
readFileSync as
|
|
98010
|
+
readFileSync as readFileSync44,
|
|
97701
98011
|
readdirSync as readdirSync11,
|
|
97702
98012
|
unlinkSync as unlinkSync25,
|
|
97703
|
-
existsSync as
|
|
98013
|
+
existsSync as existsSync44,
|
|
97704
98014
|
renameSync as renameSync21
|
|
97705
98015
|
} from "node:fs";
|
|
97706
|
-
import { join as
|
|
98016
|
+
import { join as join52, resolve as resolve10 } from "node:path";
|
|
97707
98017
|
import { homedir as homedir16 } from "node:os";
|
|
97708
98018
|
function registryDir() {
|
|
97709
|
-
return resolve10(process.env.SWITCHROOM_WORKTREE_DIR ??
|
|
98019
|
+
return resolve10(process.env.SWITCHROOM_WORKTREE_DIR ?? join52(homedir16(), ".switchroom", "worktrees"));
|
|
97710
98020
|
}
|
|
97711
98021
|
function recordPath(id) {
|
|
97712
|
-
return
|
|
98022
|
+
return join52(registryDir(), `${id}.json`);
|
|
97713
98023
|
}
|
|
97714
98024
|
function ensureDir4() {
|
|
97715
98025
|
mkdirSync38(registryDir(), { recursive: true });
|
|
@@ -97725,7 +98035,7 @@ function writeRecord(record) {
|
|
|
97725
98035
|
function readRecord(id) {
|
|
97726
98036
|
const path3 = recordPath(id);
|
|
97727
98037
|
try {
|
|
97728
|
-
const raw =
|
|
98038
|
+
const raw = readFileSync44(path3, "utf8");
|
|
97729
98039
|
return JSON.parse(raw);
|
|
97730
98040
|
} catch {
|
|
97731
98041
|
return null;
|
|
@@ -97755,11 +98065,11 @@ function touchHeartbeat(id, onAfterRead) {
|
|
|
97755
98065
|
writeRecord({ ...rec, heartbeatAt: new Date().toISOString() });
|
|
97756
98066
|
}
|
|
97757
98067
|
function recordExists(id) {
|
|
97758
|
-
return
|
|
98068
|
+
return existsSync44(recordPath(id));
|
|
97759
98069
|
}
|
|
97760
98070
|
|
|
97761
98071
|
// worktree-watch-cwds.ts
|
|
97762
|
-
import { realpathSync as
|
|
98072
|
+
import { realpathSync as realpathSync4 } from "node:fs";
|
|
97763
98073
|
import { basename as basename13 } from "node:path";
|
|
97764
98074
|
var identityEscalated = false;
|
|
97765
98075
|
function defaultDeriveName(agentDir) {
|
|
@@ -97785,7 +98095,7 @@ function ownedWorktreeCwds(opts) {
|
|
|
97785
98095
|
}
|
|
97786
98096
|
return [];
|
|
97787
98097
|
}
|
|
97788
|
-
const rp = opts.realpath ??
|
|
98098
|
+
const rp = opts.realpath ?? realpathSync4;
|
|
97789
98099
|
try {
|
|
97790
98100
|
return opts.listRecords().filter((r) => r.ownerAgent === resolved).map((r) => {
|
|
97791
98101
|
try {
|
|
@@ -97884,20 +98194,20 @@ function determineRestartReason(opts) {
|
|
|
97884
98194
|
}
|
|
97885
98195
|
|
|
97886
98196
|
// gateway/update-announce.ts
|
|
97887
|
-
import { existsSync as
|
|
97888
|
-
import { join as
|
|
98197
|
+
import { existsSync as existsSync49, mkdirSync as mkdirSync42, openSync as openSync11, closeSync as closeSync11, readFileSync as readFileSync51 } from "node:fs";
|
|
98198
|
+
import { join as join57 } from "node:path";
|
|
97889
98199
|
import { homedir as homedir18 } from "node:os";
|
|
97890
98200
|
|
|
97891
98201
|
// ../src/host-control/audit-reader.ts
|
|
97892
98202
|
import { homedir as homedir17 } from "node:os";
|
|
97893
|
-
import { join as
|
|
98203
|
+
import { join as join56 } from "node:path";
|
|
97894
98204
|
|
|
97895
98205
|
// ../src/host-control/audit-rotation-config.ts
|
|
97896
98206
|
var DEFAULT_HOSTD_AUDIT_MAX_BYTES = 32 * 1024 * 1024;
|
|
97897
98207
|
|
|
97898
98208
|
// ../src/host-control/audit-reader.ts
|
|
97899
98209
|
function defaultAuditLogPath(home2 = homedir17()) {
|
|
97900
|
-
return
|
|
98210
|
+
return join56(home2, ".switchroom", "host-control-audit.log");
|
|
97901
98211
|
}
|
|
97902
98212
|
var AUDIT_READ_WINDOW_BYTES = 4 * 1024 * 1024;
|
|
97903
98213
|
function parseAuditLine(line) {
|
|
@@ -98031,8 +98341,8 @@ init_status_no_truncate();
|
|
|
98031
98341
|
var DEFAULT_LOOKBACK_MS = 10 * 60 * 1000;
|
|
98032
98342
|
function readLastTerminalUpdateAudit(opts = {}) {
|
|
98033
98343
|
const path3 = opts.auditLogPath ?? defaultAuditLogPath();
|
|
98034
|
-
const exists = opts.exists ??
|
|
98035
|
-
const readFile = opts.readFile ?? ((p) =>
|
|
98344
|
+
const exists = opts.exists ?? existsSync49;
|
|
98345
|
+
const readFile = opts.readFile ?? ((p) => readFileSync51(p, "utf-8"));
|
|
98036
98346
|
if (!exists(path3))
|
|
98037
98347
|
return null;
|
|
98038
98348
|
let raw;
|
|
@@ -98096,15 +98406,15 @@ function renderUpdateOutcomeLine(entry) {
|
|
|
98096
98406
|
`);
|
|
98097
98407
|
}
|
|
98098
98408
|
function claimUpdateAnnouncement(requestId, opts = {}) {
|
|
98099
|
-
const stateDir = opts.stateDir ?? process.env.TELEGRAM_STATE_DIR ??
|
|
98100
|
-
const dir =
|
|
98409
|
+
const stateDir = opts.stateDir ?? process.env.TELEGRAM_STATE_DIR ?? join57(homedir18(), ".switchroom");
|
|
98410
|
+
const dir = join57(stateDir, "update-announced");
|
|
98101
98411
|
try {
|
|
98102
98412
|
mkdirSync42(dir, { recursive: true });
|
|
98103
98413
|
} catch {
|
|
98104
98414
|
return false;
|
|
98105
98415
|
}
|
|
98106
98416
|
const safeId = requestId.replace(/[^A-Za-z0-9_.-]/g, "_").slice(0, 200);
|
|
98107
|
-
const path3 =
|
|
98417
|
+
const path3 = join57(dir, safeId);
|
|
98108
98418
|
try {
|
|
98109
98419
|
const fd = openSync11(path3, "wx");
|
|
98110
98420
|
closeSync11(fd);
|
|
@@ -98124,7 +98434,7 @@ function maybeRenderUpdateAnnouncement(opts = {}) {
|
|
|
98124
98434
|
|
|
98125
98435
|
// issues-card.ts
|
|
98126
98436
|
init_card_format();
|
|
98127
|
-
import { readFileSync as
|
|
98437
|
+
import { readFileSync as readFileSync52, writeFileSync as writeFileSync41 } from "node:fs";
|
|
98128
98438
|
var SEVERITY_EMOJI = {
|
|
98129
98439
|
info: "\u2139\ufe0f",
|
|
98130
98440
|
warn: "\u26a0\ufe0f",
|
|
@@ -98216,7 +98526,7 @@ function extractRetryAfterSecs2(err) {
|
|
|
98216
98526
|
var COOLDOWN_JITTER_MS2 = 500;
|
|
98217
98527
|
function readPersistedMessageId(path3, log) {
|
|
98218
98528
|
try {
|
|
98219
|
-
const raw =
|
|
98529
|
+
const raw = readFileSync52(path3, "utf8");
|
|
98220
98530
|
const parsed = JSON.parse(raw);
|
|
98221
98531
|
const v = parsed.messageId;
|
|
98222
98532
|
if (typeof v === "number" && Number.isInteger(v) && v > 0)
|
|
@@ -98325,24 +98635,24 @@ function createIssuesCardHandle(opts) {
|
|
|
98325
98635
|
}
|
|
98326
98636
|
|
|
98327
98637
|
// issues-watcher.ts
|
|
98328
|
-
import { existsSync as
|
|
98329
|
-
import { join as
|
|
98638
|
+
import { existsSync as existsSync51, statSync as statSync19 } from "node:fs";
|
|
98639
|
+
import { join as join59 } from "node:path";
|
|
98330
98640
|
|
|
98331
98641
|
// ../src/issues/store.ts
|
|
98332
98642
|
import {
|
|
98333
98643
|
closeSync as closeSync12,
|
|
98334
|
-
existsSync as
|
|
98644
|
+
existsSync as existsSync50,
|
|
98335
98645
|
mkdirSync as mkdirSync43,
|
|
98336
98646
|
openSync as openSync12,
|
|
98337
98647
|
readdirSync as readdirSync13,
|
|
98338
|
-
readFileSync as
|
|
98648
|
+
readFileSync as readFileSync53,
|
|
98339
98649
|
renameSync as renameSync24,
|
|
98340
98650
|
statSync as statSync18,
|
|
98341
98651
|
unlinkSync as unlinkSync26,
|
|
98342
98652
|
writeFileSync as writeFileSync42,
|
|
98343
98653
|
writeSync as writeSync7
|
|
98344
98654
|
} from "node:fs";
|
|
98345
|
-
import { join as
|
|
98655
|
+
import { join as join58 } from "node:path";
|
|
98346
98656
|
import { randomBytes as randomBytes11 } from "node:crypto";
|
|
98347
98657
|
import { execSync } from "node:child_process";
|
|
98348
98658
|
|
|
@@ -98361,12 +98671,12 @@ init_redact();
|
|
|
98361
98671
|
var ISSUES_FILE = "issues.jsonl";
|
|
98362
98672
|
var ISSUES_LOCK = "issues.lock";
|
|
98363
98673
|
function readAll(stateDir) {
|
|
98364
|
-
const path3 =
|
|
98365
|
-
if (!
|
|
98674
|
+
const path3 = join58(stateDir, ISSUES_FILE);
|
|
98675
|
+
if (!existsSync50(path3))
|
|
98366
98676
|
return [];
|
|
98367
98677
|
let raw;
|
|
98368
98678
|
try {
|
|
98369
|
-
raw =
|
|
98679
|
+
raw = readFileSync53(path3, "utf-8");
|
|
98370
98680
|
} catch {
|
|
98371
98681
|
return [];
|
|
98372
98682
|
}
|
|
@@ -98398,7 +98708,7 @@ function list2(stateDir, opts = {}) {
|
|
|
98398
98708
|
});
|
|
98399
98709
|
}
|
|
98400
98710
|
function resolve11(stateDir, fingerprint, nowFn = Date.now) {
|
|
98401
|
-
if (!
|
|
98711
|
+
if (!existsSync50(join58(stateDir, ISSUES_FILE)))
|
|
98402
98712
|
return 0;
|
|
98403
98713
|
return withLock(stateDir, () => {
|
|
98404
98714
|
const all2 = readAll(stateDir);
|
|
@@ -98416,7 +98726,7 @@ function resolve11(stateDir, fingerprint, nowFn = Date.now) {
|
|
|
98416
98726
|
});
|
|
98417
98727
|
}
|
|
98418
98728
|
function writeAll(stateDir, events) {
|
|
98419
|
-
const path3 =
|
|
98729
|
+
const path3 = join58(stateDir, ISSUES_FILE);
|
|
98420
98730
|
sweepOrphanTmpFiles(stateDir);
|
|
98421
98731
|
const tmp = `${path3}.tmp-${process.pid}-${randomBytes11(4).toString("hex")}`;
|
|
98422
98732
|
const body = events.length === 0 ? "" : events.map((e) => JSON.stringify(e)).join(`
|
|
@@ -98438,7 +98748,7 @@ function sweepOrphanTmpFiles(stateDir) {
|
|
|
98438
98748
|
for (const entry of entries) {
|
|
98439
98749
|
if (!entry.startsWith(TMP_PREFIX))
|
|
98440
98750
|
continue;
|
|
98441
|
-
const tmpPath2 =
|
|
98751
|
+
const tmpPath2 = join58(stateDir, entry);
|
|
98442
98752
|
try {
|
|
98443
98753
|
const stat = statSync18(tmpPath2);
|
|
98444
98754
|
if (stat.mtimeMs < cutoff) {
|
|
@@ -98450,7 +98760,7 @@ function sweepOrphanTmpFiles(stateDir) {
|
|
|
98450
98760
|
var LOCK_RETRY_MS = 25;
|
|
98451
98761
|
var LOCK_TIMEOUT_MS = 1e4;
|
|
98452
98762
|
function withLock(stateDir, fn) {
|
|
98453
|
-
const lockPath =
|
|
98763
|
+
const lockPath = join58(stateDir, ISSUES_LOCK);
|
|
98454
98764
|
const startedAt = Date.now();
|
|
98455
98765
|
let fd = null;
|
|
98456
98766
|
while (fd === null) {
|
|
@@ -98485,7 +98795,7 @@ function withLock(stateDir, fn) {
|
|
|
98485
98795
|
function tryStealStaleLock(lockPath) {
|
|
98486
98796
|
let pidStr;
|
|
98487
98797
|
try {
|
|
98488
|
-
pidStr =
|
|
98798
|
+
pidStr = readFileSync53(lockPath, "utf-8").trim();
|
|
98489
98799
|
} catch {
|
|
98490
98800
|
return true;
|
|
98491
98801
|
}
|
|
@@ -98535,7 +98845,7 @@ function isIssueEvent(v) {
|
|
|
98535
98845
|
// issues-watcher.ts
|
|
98536
98846
|
var DEFAULT_POLL_INTERVAL_MS2 = 2000;
|
|
98537
98847
|
function startIssuesWatcher(opts) {
|
|
98538
|
-
const path3 =
|
|
98848
|
+
const path3 = join59(opts.stateDir, ISSUES_FILE);
|
|
98539
98849
|
const log = opts.log ?? (() => {});
|
|
98540
98850
|
const intervalMs = opts.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS2;
|
|
98541
98851
|
const setIntervalFn = opts.setInterval ?? setInterval;
|
|
@@ -98583,7 +98893,7 @@ function startIssuesWatcher(opts) {
|
|
|
98583
98893
|
};
|
|
98584
98894
|
}
|
|
98585
98895
|
function defaultSignatureProvider(path3) {
|
|
98586
|
-
if (!
|
|
98896
|
+
if (!existsSync51(path3))
|
|
98587
98897
|
return null;
|
|
98588
98898
|
try {
|
|
98589
98899
|
const stat = statSync19(path3);
|
|
@@ -99295,7 +99605,7 @@ function readBashCommand(inputPreview) {
|
|
|
99295
99605
|
|
|
99296
99606
|
// gateway/scoped-grant-store.ts
|
|
99297
99607
|
init_atomic();
|
|
99298
|
-
import { join as
|
|
99608
|
+
import { join as join60 } from "node:path";
|
|
99299
99609
|
|
|
99300
99610
|
// scoped-approval.ts
|
|
99301
99611
|
var SCOPED_APPROVAL_DEFAULT_TTL_MS2 = 30 * 60 * 1000;
|
|
@@ -99337,7 +99647,7 @@ function scopedGrantPersistEnabled(env = process.env) {
|
|
|
99337
99647
|
return env.SWITCHROOM_SCOPED_GRANT_PERSIST !== "0";
|
|
99338
99648
|
}
|
|
99339
99649
|
function createScopedGrantStore(stateDir, env = process.env, log = (l) => process.stderr.write(l)) {
|
|
99340
|
-
const filePath =
|
|
99650
|
+
const filePath = join60(stateDir, "scoped-grants.json");
|
|
99341
99651
|
const enabled7 = scopedGrantPersistEnabled(env);
|
|
99342
99652
|
let unreadable = false;
|
|
99343
99653
|
function read() {
|
|
@@ -99715,8 +100025,8 @@ function isDiffPreApproved(agentName3, unifiedDiff, deps) {
|
|
|
99715
100025
|
|
|
99716
100026
|
// credits-watch.ts
|
|
99717
100027
|
init_card_format();
|
|
99718
|
-
import { readFileSync as
|
|
99719
|
-
import { join as
|
|
100028
|
+
import { readFileSync as readFileSync54, writeFileSync as writeFileSync43, existsSync as existsSync52, mkdirSync as mkdirSync44 } from "fs";
|
|
100029
|
+
import { join as join61 } from "path";
|
|
99720
100030
|
var STATE_FILE = "credits-watch.json";
|
|
99721
100031
|
var DEFAULT_CREDIT_FATAL_REASONS = new Set;
|
|
99722
100032
|
var KNOWN_CREDIT_REASONS = [
|
|
@@ -99738,12 +100048,12 @@ function emptyCreditState() {
|
|
|
99738
100048
|
return { lastNotifiedReason: null, lastNotifiedAt: 0 };
|
|
99739
100049
|
}
|
|
99740
100050
|
function readClaudeJsonOverage(claudeConfigDir) {
|
|
99741
|
-
const path3 =
|
|
99742
|
-
if (!
|
|
100051
|
+
const path3 = join61(claudeConfigDir, ".claude.json");
|
|
100052
|
+
if (!existsSync52(path3))
|
|
99743
100053
|
return null;
|
|
99744
100054
|
let raw;
|
|
99745
100055
|
try {
|
|
99746
|
-
raw =
|
|
100056
|
+
raw = readFileSync54(path3, "utf-8");
|
|
99747
100057
|
} catch {
|
|
99748
100058
|
return null;
|
|
99749
100059
|
}
|
|
@@ -99821,11 +100131,11 @@ function humanizeReason(reason) {
|
|
|
99821
100131
|
}
|
|
99822
100132
|
}
|
|
99823
100133
|
function loadCreditState(stateDir) {
|
|
99824
|
-
const path3 =
|
|
99825
|
-
if (!
|
|
100134
|
+
const path3 = join61(stateDir, STATE_FILE);
|
|
100135
|
+
if (!existsSync52(path3))
|
|
99826
100136
|
return emptyCreditState();
|
|
99827
100137
|
try {
|
|
99828
|
-
const raw =
|
|
100138
|
+
const raw = readFileSync54(path3, "utf-8");
|
|
99829
100139
|
const parsed = JSON.parse(raw);
|
|
99830
100140
|
if (parsed && typeof parsed === "object" && (parsed.lastNotifiedReason === null || typeof parsed.lastNotifiedReason === "string") && typeof parsed.lastNotifiedAt === "number" && Number.isFinite(parsed.lastNotifiedAt)) {
|
|
99831
100141
|
return {
|
|
@@ -99838,7 +100148,7 @@ function loadCreditState(stateDir) {
|
|
|
99838
100148
|
}
|
|
99839
100149
|
function saveCreditState(stateDir, state7) {
|
|
99840
100150
|
mkdirSync44(stateDir, { recursive: true });
|
|
99841
|
-
const path3 =
|
|
100151
|
+
const path3 = join61(stateDir, STATE_FILE);
|
|
99842
100152
|
writeFileSync43(path3, JSON.stringify(state7, null, 2) + `
|
|
99843
100153
|
`, { mode: 384 });
|
|
99844
100154
|
}
|
|
@@ -99846,8 +100156,8 @@ function saveCreditState(stateDir, state7) {
|
|
|
99846
100156
|
// quota-watch.ts
|
|
99847
100157
|
init_auth_snapshot_format();
|
|
99848
100158
|
init_card_format();
|
|
99849
|
-
import { readFileSync as
|
|
99850
|
-
import { join as
|
|
100159
|
+
import { readFileSync as readFileSync55, writeFileSync as writeFileSync44, existsSync as existsSync53, mkdirSync as mkdirSync45 } from "fs";
|
|
100160
|
+
import { join as join62 } from "path";
|
|
99851
100161
|
var STATE_FILE2 = "quota-watch.json";
|
|
99852
100162
|
function emptyQuotaWatchState() {
|
|
99853
100163
|
return {};
|
|
@@ -100085,11 +100395,11 @@ function buildRecoveryMessage(agentName3, snap) {
|
|
|
100085
100395
|
`);
|
|
100086
100396
|
}
|
|
100087
100397
|
function loadQuotaWatchState(stateDir) {
|
|
100088
|
-
const path3 =
|
|
100089
|
-
if (!
|
|
100398
|
+
const path3 = join62(stateDir, STATE_FILE2);
|
|
100399
|
+
if (!existsSync53(path3))
|
|
100090
100400
|
return emptyQuotaWatchState();
|
|
100091
100401
|
try {
|
|
100092
|
-
const raw =
|
|
100402
|
+
const raw = readFileSync55(path3, "utf-8");
|
|
100093
100403
|
const parsed = JSON.parse(raw);
|
|
100094
100404
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
100095
100405
|
return emptyQuotaWatchState();
|
|
@@ -100107,7 +100417,7 @@ function loadQuotaWatchState(stateDir) {
|
|
|
100107
100417
|
}
|
|
100108
100418
|
function saveQuotaWatchState(stateDir, state7) {
|
|
100109
100419
|
mkdirSync45(stateDir, { recursive: true });
|
|
100110
|
-
const path3 =
|
|
100420
|
+
const path3 = join62(stateDir, STATE_FILE2);
|
|
100111
100421
|
writeFileSync44(path3, JSON.stringify(state7, null, 2) + `
|
|
100112
100422
|
`, { mode: 384 });
|
|
100113
100423
|
}
|
|
@@ -100156,27 +100466,27 @@ init_auth_snapshot_format2();
|
|
|
100156
100466
|
// gateway/turn-active-marker.ts
|
|
100157
100467
|
import {
|
|
100158
100468
|
closeSync as closeSync13,
|
|
100159
|
-
existsSync as
|
|
100469
|
+
existsSync as existsSync54,
|
|
100160
100470
|
mkdirSync as mkdirSync46,
|
|
100161
100471
|
openSync as openSync13,
|
|
100162
|
-
readFileSync as
|
|
100472
|
+
readFileSync as readFileSync56,
|
|
100163
100473
|
statSync as statSync20,
|
|
100164
100474
|
unlinkSync as unlinkSync27,
|
|
100165
100475
|
utimesSync as utimesSync2,
|
|
100166
100476
|
writeFileSync as writeFileSync45
|
|
100167
100477
|
} from "node:fs";
|
|
100168
|
-
import { join as
|
|
100478
|
+
import { join as join63 } from "node:path";
|
|
100169
100479
|
var TURN_ACTIVE_MARKER_FILE2 = "turn-active.json";
|
|
100170
100480
|
var TURN_ACTIVE_HARD_TTL_MS2 = 10 * 60000;
|
|
100171
100481
|
var TURN_ACTIVE_IDLE_SWEEP_MS = 60000;
|
|
100172
100482
|
function removeTurnActiveMarker2(stateDir) {
|
|
100173
100483
|
try {
|
|
100174
|
-
unlinkSync27(
|
|
100484
|
+
unlinkSync27(join63(stateDir, TURN_ACTIVE_MARKER_FILE2));
|
|
100175
100485
|
} catch {}
|
|
100176
100486
|
}
|
|
100177
100487
|
function sweepStaleTurnActiveMarker(stateDir, opts) {
|
|
100178
|
-
const path3 =
|
|
100179
|
-
if (!
|
|
100488
|
+
const path3 = join63(stateDir, TURN_ACTIVE_MARKER_FILE2);
|
|
100489
|
+
if (!existsSync54(path3))
|
|
100180
100490
|
return false;
|
|
100181
100491
|
const now = opts.now ?? Date.now();
|
|
100182
100492
|
try {
|
|
@@ -100188,7 +100498,7 @@ function sweepStaleTurnActiveMarker(stateDir, opts) {
|
|
|
100188
100498
|
return false;
|
|
100189
100499
|
let payload = null;
|
|
100190
100500
|
try {
|
|
100191
|
-
payload =
|
|
100501
|
+
payload = readFileSync56(path3, "utf8");
|
|
100192
100502
|
} catch {}
|
|
100193
100503
|
unlinkSync27(path3);
|
|
100194
100504
|
if (opts.onRemove) {
|
|
@@ -100206,7 +100516,7 @@ function sweepStaleTurnActiveMarker(stateDir, opts) {
|
|
|
100206
100516
|
}
|
|
100207
100517
|
}
|
|
100208
100518
|
function readTurnActiveMarkerAgeMs2(stateDir, now) {
|
|
100209
|
-
const path3 =
|
|
100519
|
+
const path3 = join63(stateDir, TURN_ACTIVE_MARKER_FILE2);
|
|
100210
100520
|
try {
|
|
100211
100521
|
const st = statSync20(path3);
|
|
100212
100522
|
return (now ?? Date.now()) - st.mtimeMs;
|
|
@@ -100220,11 +100530,11 @@ function effectiveTurnAgeMs(markerAgeMs, turnStartedAt, now) {
|
|
|
100220
100530
|
|
|
100221
100531
|
// gateway/gateway-heartbeat.ts
|
|
100222
100532
|
import { mkdirSync as mkdirSync47, utimesSync as utimesSync3, writeFileSync as writeFileSync46 } from "node:fs";
|
|
100223
|
-
import { join as
|
|
100533
|
+
import { join as join64 } from "node:path";
|
|
100224
100534
|
var GATEWAY_HEARTBEAT_FILE = "gateway-heartbeat";
|
|
100225
100535
|
var GATEWAY_HEARTBEAT_INTERVAL_MS = 15000;
|
|
100226
100536
|
function touchGatewayHeartbeat(stateDir) {
|
|
100227
|
-
const path3 =
|
|
100537
|
+
const path3 = join64(stateDir, GATEWAY_HEARTBEAT_FILE);
|
|
100228
100538
|
const now = new Date;
|
|
100229
100539
|
try {
|
|
100230
100540
|
utimesSync3(path3, now, now);
|
|
@@ -100250,12 +100560,12 @@ import {
|
|
|
100250
100560
|
fsyncSync as fsyncSync5,
|
|
100251
100561
|
mkdirSync as mkdirSync48,
|
|
100252
100562
|
openSync as openSync14,
|
|
100253
|
-
readFileSync as
|
|
100563
|
+
readFileSync as readFileSync57,
|
|
100254
100564
|
renameSync as renameSync25,
|
|
100255
100565
|
unlinkSync as unlinkSync28,
|
|
100256
100566
|
writeFileSync as writeFileSync47
|
|
100257
100567
|
} from "node:fs";
|
|
100258
|
-
import { join as
|
|
100568
|
+
import { join as join65 } from "node:path";
|
|
100259
100569
|
var BOOT_BEACON_FILE = "gateway-beacon.json";
|
|
100260
100570
|
var HOST_BOOT_ID_PATH = "/proc/sys/kernel/random/boot_id";
|
|
100261
100571
|
var CGROUP_MEMORY_EVENTS_PATH = "/sys/fs/cgroup/memory.events";
|
|
@@ -100332,7 +100642,7 @@ function serializeBootBeacon(beacon) {
|
|
|
100332
100642
|
}
|
|
100333
100643
|
function readTextOrNull(path3) {
|
|
100334
100644
|
try {
|
|
100335
|
-
return
|
|
100645
|
+
return readFileSync57(path3, "utf-8");
|
|
100336
100646
|
} catch {
|
|
100337
100647
|
return null;
|
|
100338
100648
|
}
|
|
@@ -100354,7 +100664,7 @@ function sampleBeaconHost(paths = {}) {
|
|
|
100354
100664
|
return sample3;
|
|
100355
100665
|
}
|
|
100356
100666
|
function writeBootBeaconFile(stateDir, beacon) {
|
|
100357
|
-
const path3 =
|
|
100667
|
+
const path3 = join65(stateDir, BOOT_BEACON_FILE);
|
|
100358
100668
|
const tmp = `${path3}.tmp-${process.pid}`;
|
|
100359
100669
|
let fd;
|
|
100360
100670
|
try {
|
|
@@ -100731,10 +101041,10 @@ function startOutboxSweep(deps) {
|
|
|
100731
101041
|
}
|
|
100732
101042
|
|
|
100733
101043
|
// ../src/build-info.ts
|
|
100734
|
-
var VERSION2 = "0.19.
|
|
100735
|
-
var COMMIT_SHA = "
|
|
100736
|
-
var COMMIT_DATE = "2026-08-
|
|
100737
|
-
var LATEST_PR =
|
|
101044
|
+
var VERSION2 = "0.19.45";
|
|
101045
|
+
var COMMIT_SHA = "2ad33d5d";
|
|
101046
|
+
var COMMIT_DATE = "2026-08-01T23:47:32Z";
|
|
101047
|
+
var LATEST_PR = 4192;
|
|
100738
101048
|
var COMMITS_AHEAD_OF_TAG = 0;
|
|
100739
101049
|
|
|
100740
101050
|
// gateway/boot-version.ts
|
|
@@ -100812,11 +101122,11 @@ init_peercred();
|
|
|
100812
101122
|
import * as net5 from "node:net";
|
|
100813
101123
|
import * as fs3 from "node:fs";
|
|
100814
101124
|
import { homedir as homedir19 } from "node:os";
|
|
100815
|
-
import { join as
|
|
101125
|
+
import { join as join66 } from "node:path";
|
|
100816
101126
|
var DEFAULT_TIMEOUT_MS4 = 2000;
|
|
100817
101127
|
var UNLOCK_TIMEOUT_MS = 30000;
|
|
100818
|
-
var LEGACY_SOCKET_PATH2 =
|
|
100819
|
-
var OPERATOR_SOCKET_PATH2 =
|
|
101128
|
+
var LEGACY_SOCKET_PATH2 = join66(homedir19(), ".switchroom", "vault-broker.sock");
|
|
101129
|
+
var OPERATOR_SOCKET_PATH2 = join66(homedir19(), ".switchroom", "broker-operator", "sock");
|
|
100820
101130
|
function defaultBrokerSocketPath2() {
|
|
100821
101131
|
if (fs3.existsSync(OPERATOR_SOCKET_PATH2))
|
|
100822
101132
|
return OPERATOR_SOCKET_PATH2;
|
|
@@ -101699,7 +102009,7 @@ function resolveVaultApprovalPosture(broker) {
|
|
|
101699
102009
|
|
|
101700
102010
|
// registry/turns-schema.ts
|
|
101701
102011
|
import { chmodSync as chmodSync12, mkdirSync as mkdirSync49 } from "fs";
|
|
101702
|
-
import { join as
|
|
102012
|
+
import { join as join67 } from "path";
|
|
101703
102013
|
var DatabaseClass3 = null;
|
|
101704
102014
|
function loadDatabaseClass3() {
|
|
101705
102015
|
if (DatabaseClass3 != null)
|
|
@@ -101771,9 +102081,9 @@ function applySchema(db3) {
|
|
|
101771
102081
|
}
|
|
101772
102082
|
function openTurnsDb(agentDir) {
|
|
101773
102083
|
const Database = loadDatabaseClass3();
|
|
101774
|
-
const dir =
|
|
102084
|
+
const dir = join67(agentDir, "telegram");
|
|
101775
102085
|
mkdirSync49(dir, { recursive: true, mode: 448 });
|
|
101776
|
-
const path3 =
|
|
102086
|
+
const path3 = join67(dir, "registry.db");
|
|
101777
102087
|
const db3 = new Database(path3, { create: true });
|
|
101778
102088
|
applySchema(db3);
|
|
101779
102089
|
try {
|
|
@@ -102118,7 +102428,7 @@ function selectResumeBuilder(endedVia, opts) {
|
|
|
102118
102428
|
}
|
|
102119
102429
|
|
|
102120
102430
|
// gateway/bridge-dead-watchdog.ts
|
|
102121
|
-
import { readFileSync as
|
|
102431
|
+
import { readFileSync as readFileSync59, writeFileSync as writeFileSync48, renameSync as renameSync26, unlinkSync as unlinkSync29 } from "node:fs";
|
|
102122
102432
|
|
|
102123
102433
|
// gateway/cron-session.ts
|
|
102124
102434
|
var CRON_IDENTITY_SUFFIX2 = "-cron";
|
|
@@ -102151,7 +102461,7 @@ function readFreshCrashLogTail(path3, opts = {}) {
|
|
|
102151
102461
|
const nowMs3 = opts.nowMs ?? Date.now();
|
|
102152
102462
|
const freshWindowMs = opts.freshWindowMs ?? CRASH_LOG_FRESH_WINDOW_MS;
|
|
102153
102463
|
const maxLines = opts.maxLines ?? CRASH_LOG_TAIL_LINES;
|
|
102154
|
-
const readFile = opts.readFile ?? ((p) =>
|
|
102464
|
+
const readFile = opts.readFile ?? ((p) => readFileSync59(p, "utf8"));
|
|
102155
102465
|
let raw;
|
|
102156
102466
|
try {
|
|
102157
102467
|
raw = readFile(path3);
|
|
@@ -102178,7 +102488,7 @@ function writeBridgeDeadEscalationMarker(path3, marker) {
|
|
|
102178
102488
|
function consumeBridgeDeadEscalationMarker(path3, nowMs3 = Date.now(), maxAgeMs = ESCALATION_MARKER_MAX_AGE_MS) {
|
|
102179
102489
|
let marker = null;
|
|
102180
102490
|
try {
|
|
102181
|
-
const parsed = JSON.parse(
|
|
102491
|
+
const parsed = JSON.parse(readFileSync59(path3, "utf8"));
|
|
102182
102492
|
if (typeof parsed.ts === "number" && Number.isFinite(parsed.ts) && typeof parsed.reason === "string") {
|
|
102183
102493
|
const age = nowMs3 - parsed.ts;
|
|
102184
102494
|
if (age >= 0 && age < maxAgeMs) {
|
|
@@ -102331,7 +102641,7 @@ function createBridgeDeadWatchdog(opts) {
|
|
|
102331
102641
|
}
|
|
102332
102642
|
|
|
102333
102643
|
// gateway/boot-probes.ts
|
|
102334
|
-
import { readFileSync as
|
|
102644
|
+
import { readFileSync as readFileSync60, readdirSync as readdirSync14, existsSync as existsSync56 } from "fs";
|
|
102335
102645
|
init_quota_cache();
|
|
102336
102646
|
init_generation_stamp();
|
|
102337
102647
|
init_quota_check();
|
|
@@ -102340,7 +102650,7 @@ import { promisify as promisify2 } from "util";
|
|
|
102340
102650
|
var execFile2 = promisify2(execFileCb2);
|
|
102341
102651
|
var realProcFs2 = {
|
|
102342
102652
|
readdir: (p) => readdirSync14(p),
|
|
102343
|
-
readFile: (p) =>
|
|
102653
|
+
readFile: (p) => readFileSync60(p, "utf-8")
|
|
102344
102654
|
};
|
|
102345
102655
|
function findAgentProcessInContainer2(fs4 = realProcFs2) {
|
|
102346
102656
|
let entries;
|
|
@@ -102590,7 +102900,7 @@ if (isGatewayMain) {
|
|
|
102590
102900
|
shutdownAnalytics();
|
|
102591
102901
|
});
|
|
102592
102902
|
}
|
|
102593
|
-
var STATE_DIR = process.env.TELEGRAM_STATE_DIR ??
|
|
102903
|
+
var STATE_DIR = process.env.TELEGRAM_STATE_DIR ?? join68(homedir20(), ".claude", "channels", "telegram");
|
|
102594
102904
|
var permCardStore = createPermissionCardStore(STATE_DIR);
|
|
102595
102905
|
var BLOCKED_APPROVALS_DIR = process.env.SWITCHROOM_BLOCKED_APPROVALS_DIR ?? "/state/blocked-approvals";
|
|
102596
102906
|
var AGENT_NAME = process.env.SWITCHROOM_AGENT_NAME ?? "agent";
|
|
@@ -102629,7 +102939,7 @@ function alwaysAllowDrainDeps() {
|
|
|
102629
102939
|
return {
|
|
102630
102940
|
readConfigText: () => {
|
|
102631
102941
|
const cfgPath = process.env.SWITCHROOM_CONFIG ?? SWITCHROOM_CONFIG ?? findConfigFile2();
|
|
102632
|
-
return
|
|
102942
|
+
return readFileSync61(cfgPath, "utf8");
|
|
102633
102943
|
},
|
|
102634
102944
|
resolveAllowList: (_configText, agentName3) => {
|
|
102635
102945
|
const cfg = loadConfig2();
|
|
@@ -102690,11 +103000,11 @@ function scheduleAlwaysAllowPersistDrain() {
|
|
|
102690
103000
|
}, ALWAYS_ALLOW_DRAIN_INTERVAL_MS);
|
|
102691
103001
|
timer3.unref?.();
|
|
102692
103002
|
}
|
|
102693
|
-
var ACCESS_FILE =
|
|
102694
|
-
var APPROVED_DIR =
|
|
102695
|
-
var ENV_FILE =
|
|
102696
|
-
var INBOX_DIR =
|
|
102697
|
-
var PEOPLE_FILE =
|
|
103003
|
+
var ACCESS_FILE = join68(STATE_DIR, "access.json");
|
|
103004
|
+
var APPROVED_DIR = join68(STATE_DIR, "approved");
|
|
103005
|
+
var ENV_FILE = join68(STATE_DIR, ".env");
|
|
103006
|
+
var INBOX_DIR = join68(STATE_DIR, "inbox");
|
|
103007
|
+
var PEOPLE_FILE = join68(STATE_DIR, "people.json");
|
|
102698
103008
|
function triggerSelfRestart(targetAgent, reason, delayMs = 300) {
|
|
102699
103009
|
const isDocker = process.env.SWITCHROOM_RUNTIME === "docker";
|
|
102700
103010
|
const selfAgent = process.env.SWITCHROOM_AGENT_NAME;
|
|
@@ -102759,7 +103069,7 @@ function formatBootVersion() {
|
|
|
102759
103069
|
}
|
|
102760
103070
|
try {
|
|
102761
103071
|
chmodSync14(ENV_FILE, 384);
|
|
102762
|
-
for (const line of
|
|
103072
|
+
for (const line of readFileSync61(ENV_FILE, "utf8").split(`
|
|
102763
103073
|
`)) {
|
|
102764
103074
|
const m = line.match(/^(\w+)=(.*)$/);
|
|
102765
103075
|
if (m && process.env[m[1]] === undefined)
|
|
@@ -102780,7 +103090,7 @@ var bot;
|
|
|
102780
103090
|
var lastGetUpdatesHeartbeatMs = Date.now();
|
|
102781
103091
|
var GRAMMY_VERSION = (() => {
|
|
102782
103092
|
try {
|
|
102783
|
-
const raw =
|
|
103093
|
+
const raw = readFileSync61(new URL("../../node_modules/grammy/package.json", import.meta.url), "utf8");
|
|
102784
103094
|
return JSON.parse(raw).version ?? "unknown";
|
|
102785
103095
|
} catch {
|
|
102786
103096
|
return "unknown";
|
|
@@ -102819,12 +103129,12 @@ function assertSendable(f) {
|
|
|
102819
103129
|
}
|
|
102820
103130
|
let real, stateReal;
|
|
102821
103131
|
try {
|
|
102822
|
-
real =
|
|
102823
|
-
stateReal =
|
|
103132
|
+
real = realpathSync5(f);
|
|
103133
|
+
stateReal = realpathSync5(STATE_DIR);
|
|
102824
103134
|
} catch {
|
|
102825
103135
|
throw new Error(`refusing to send file \u2014 cannot resolve real path: ${f}`);
|
|
102826
103136
|
}
|
|
102827
|
-
const inbox =
|
|
103137
|
+
const inbox = join68(stateReal, "inbox");
|
|
102828
103138
|
if (real.startsWith(stateReal + sep4) && !real.startsWith(inbox + sep4)) {
|
|
102829
103139
|
throw new Error(`refusing to send channel state: ${f}`);
|
|
102830
103140
|
}
|
|
@@ -102843,7 +103153,7 @@ function assertSendable(f) {
|
|
|
102843
103153
|
}
|
|
102844
103154
|
function readAccessFile() {
|
|
102845
103155
|
try {
|
|
102846
|
-
const raw =
|
|
103156
|
+
const raw = readFileSync61(ACCESS_FILE, "utf8");
|
|
102847
103157
|
const parsed = JSON.parse(raw);
|
|
102848
103158
|
const allowFrom = validateStringArray("allowFrom", parsed.allowFrom ?? []);
|
|
102849
103159
|
const groups = {};
|
|
@@ -102905,7 +103215,7 @@ function loadAccess() {
|
|
|
102905
103215
|
}
|
|
102906
103216
|
function readPeopleFile() {
|
|
102907
103217
|
try {
|
|
102908
|
-
const raw =
|
|
103218
|
+
const raw = readFileSync61(PEOPLE_FILE, "utf8");
|
|
102909
103219
|
const parsed = JSON.parse(raw);
|
|
102910
103220
|
if (!Array.isArray(parsed.entries))
|
|
102911
103221
|
return [];
|
|
@@ -102949,7 +103259,7 @@ var HISTORY_ENABLED = HISTORY_ACCESS.historyEnabled !== false;
|
|
|
102949
103259
|
if (isGatewayMain && HISTORY_ENABLED) {
|
|
102950
103260
|
try {
|
|
102951
103261
|
initHistory(STATE_DIR, HISTORY_ACCESS.historyRetentionDays ?? 30);
|
|
102952
|
-
process.stderr.write(`telegram gateway: history capture enabled at ${
|
|
103262
|
+
process.stderr.write(`telegram gateway: history capture enabled at ${join68(STATE_DIR, "history.db")}
|
|
102953
103263
|
`);
|
|
102954
103264
|
} catch (err) {
|
|
102955
103265
|
process.stderr.write(`telegram gateway: history init failed (${err.message}) \u2014 capture disabled
|
|
@@ -102968,12 +103278,12 @@ if (isGatewayMain)
|
|
|
102968
103278
|
let markerTurnKey = null;
|
|
102969
103279
|
let markerAgeMs = null;
|
|
102970
103280
|
try {
|
|
102971
|
-
const markerPath =
|
|
102972
|
-
if (
|
|
103281
|
+
const markerPath = join68(STATE_DIR, TURN_ACTIVE_MARKER_FILE2);
|
|
103282
|
+
if (existsSync58(markerPath)) {
|
|
102973
103283
|
const st = statSync23(markerPath);
|
|
102974
103284
|
markerAgeMs = Date.now() - st.mtimeMs;
|
|
102975
103285
|
try {
|
|
102976
|
-
const payload = JSON.parse(
|
|
103286
|
+
const payload = JSON.parse(readFileSync61(markerPath, "utf8"));
|
|
102977
103287
|
if (typeof payload.turnKey === "string" && payload.turnKey.length > 0) {
|
|
102978
103288
|
markerTurnKey = payload.turnKey;
|
|
102979
103289
|
}
|
|
@@ -102993,10 +103303,10 @@ if (isGatewayMain)
|
|
|
102993
103303
|
process.stderr.write(`telegram gateway: turn-registry boot-reaper stamped ${reaped} orphaned turn(s)` + `${timeoutTurnKey ? ` (turnKey=${timeoutTurnKey} as 'timeout', markerAgeMs=${markerAgeMs})` : " as 'restart'"}
|
|
102994
103304
|
`);
|
|
102995
103305
|
} else {
|
|
102996
|
-
process.stderr.write(`telegram gateway: turn-registry initialized at ${
|
|
103306
|
+
process.stderr.write(`telegram gateway: turn-registry initialized at ${join68(agentDir, "telegram", "registry.db")}
|
|
102997
103307
|
`);
|
|
102998
103308
|
}
|
|
102999
|
-
const bridgeDeadMarker = consumeBridgeDeadEscalationMarker(
|
|
103309
|
+
const bridgeDeadMarker = consumeBridgeDeadEscalationMarker(join68(STATE_DIR, "bridge-dead-escalation.json"));
|
|
103000
103310
|
if (bridgeDeadMarker != null) {
|
|
103001
103311
|
bridgeDeadPriorStreak = bridgeDeadMarker.count ?? 1;
|
|
103002
103312
|
process.stderr.write(`telegram gateway: boot: prior restart was a bridge-dead escalation (reason=${bridgeDeadMarker.reason}` + `, consecutive=${bridgeDeadPriorStreak}` + `${bridgeDeadMarker.crashTail ? `, crashTail=${bridgeDeadMarker.crashTail}` : ""})
|
|
@@ -103009,7 +103319,7 @@ if (isGatewayMain)
|
|
|
103009
103319
|
const pending2 = findLatestTurnIfInterrupted(turnsDb);
|
|
103010
103320
|
const selfAgent = process.env.SWITCHROOM_AGENT_NAME ?? "";
|
|
103011
103321
|
if (pending2 != null && selfAgent) {
|
|
103012
|
-
const bootResumeMarkerPath = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ??
|
|
103322
|
+
const bootResumeMarkerPath = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ?? join68(STATE_DIR, "clean-shutdown.json");
|
|
103013
103323
|
const bootResumeCleanMarker = readCleanShutdownMarker(bootResumeMarkerPath);
|
|
103014
103324
|
const bootResumeForceAlways = process.env.SWITCHROOM_BOOT_RESUME_ALWAYS === "1";
|
|
103015
103325
|
const bootResumeMode = parseBootResumeMode(process.env.SWITCHROOM_BOOT_RESUME);
|
|
@@ -103122,7 +103432,7 @@ if (isGatewayMain)
|
|
|
103122
103432
|
`);
|
|
103123
103433
|
}
|
|
103124
103434
|
}
|
|
103125
|
-
const pendingEnvPath =
|
|
103435
|
+
const pendingEnvPath = join68(agentDir, ".pending-turn.env");
|
|
103126
103436
|
try {
|
|
103127
103437
|
if (pending2 != null) {
|
|
103128
103438
|
const lines = [
|
|
@@ -103142,7 +103452,7 @@ if (isGatewayMain)
|
|
|
103142
103452
|
renameSync27(pendingEnvTmp, pendingEnvPath);
|
|
103143
103453
|
process.stderr.write(`telegram gateway: pending-turn env written to ${pendingEnvPath} turnKey=${pending2.turn_key} endedVia=${pending2.ended_via ?? "open"}
|
|
103144
103454
|
`);
|
|
103145
|
-
} else if (
|
|
103455
|
+
} else if (existsSync58(pendingEnvPath)) {
|
|
103146
103456
|
rmSync8(pendingEnvPath, { force: true });
|
|
103147
103457
|
process.stderr.write(`telegram gateway: pending-turn env cleared (clean previous shutdown)
|
|
103148
103458
|
`);
|
|
@@ -103250,7 +103560,7 @@ function checkApprovals() {
|
|
|
103250
103560
|
return;
|
|
103251
103561
|
}
|
|
103252
103562
|
for (const senderId of files) {
|
|
103253
|
-
const file =
|
|
103563
|
+
const file = join68(APPROVED_DIR, senderId);
|
|
103254
103564
|
bot.api.sendMessage(senderId, "Paired! Say hi to Claude.").then(() => rmSync8(file, { force: true }), (err) => {
|
|
103255
103565
|
process.stderr.write(`telegram gateway: failed to send approval confirm: ${err}
|
|
103256
103566
|
`);
|
|
@@ -103277,7 +103587,10 @@ var deferredDoneReactions = new DeferredDoneReactions({
|
|
|
103277
103587
|
purge: (key) => purgeReactionTracking(key)
|
|
103278
103588
|
});
|
|
103279
103589
|
var outboundDedup = new OutboundDedupCache;
|
|
103280
|
-
var flushedTurnSupersede = new FlushedTurnSupersedeRegistry
|
|
103590
|
+
var flushedTurnSupersede = new FlushedTurnSupersedeRegistry({
|
|
103591
|
+
openCapMs: SUPERSEDE_OPEN_CAP_MS,
|
|
103592
|
+
completedGraceMs: SUPERSEDE_GRACE_MS
|
|
103593
|
+
});
|
|
103281
103594
|
var backstopDeliveryLedger = new BackstopDeliveryLedger2;
|
|
103282
103595
|
var BACKSTOP_DELIVERY_MAX_ATTEMPTS = (() => {
|
|
103283
103596
|
const raw = Number(process.env.SWITCHROOM_BACKSTOP_DELIVERY_MAX_ATTEMPTS);
|
|
@@ -103425,12 +103738,12 @@ function noteAgentOutputAt(key, ts) {
|
|
|
103425
103738
|
lastAgentOutputAt.delete(oldest);
|
|
103426
103739
|
}
|
|
103427
103740
|
}
|
|
103428
|
-
var OBLIGATION_STORE_PATH =
|
|
103741
|
+
var OBLIGATION_STORE_PATH = join68(STATE_DIR, "obligations.json");
|
|
103429
103742
|
var obligationStoreFs = {
|
|
103430
|
-
readFileSync: (p) =>
|
|
103743
|
+
readFileSync: (p) => readFileSync61(p, "utf8"),
|
|
103431
103744
|
writeFileSync: (p, d) => writeFileSync50(p, d),
|
|
103432
103745
|
renameSync: (a, b) => renameSync27(a, b),
|
|
103433
|
-
existsSync: (p) =>
|
|
103746
|
+
existsSync: (p) => existsSync58(p),
|
|
103434
103747
|
fsyncFileSync: fsyncPathSync,
|
|
103435
103748
|
fsyncDirSync: fsyncPathSync,
|
|
103436
103749
|
unlinkSync: unlinkSync31
|
|
@@ -103641,7 +103954,7 @@ function cardDrainGate(turn, ea, run4) {
|
|
|
103641
103954
|
var RECENT_TURNS_MAX = 32;
|
|
103642
103955
|
var recentTurnsById = new Map;
|
|
103643
103956
|
var recentTurnIdBySourceMessageId = new Map;
|
|
103644
|
-
var subagentHandbackMarker = new
|
|
103957
|
+
var subagentHandbackMarker = new SubagentHandbackMarker2;
|
|
103645
103958
|
var getLastSubagentHandbackAt = (chatId) => subagentHandbackMarker.lastAtInChat(chatId);
|
|
103646
103959
|
function rememberRecentTurn(turn) {
|
|
103647
103960
|
recentTurnsById.set(turn.turnId, turn);
|
|
@@ -103695,26 +104008,7 @@ function findLatestTurnForChat(chatId, opts) {
|
|
|
103695
104008
|
return latestTurnForChat(recentTurnsById.values(), chatId, opts);
|
|
103696
104009
|
}
|
|
103697
104010
|
function resolveReplyOwnerTurn(liveTurn, chatId, args) {
|
|
103698
|
-
|
|
103699
|
-
const quoted = findTurnByQuotedMessageId(chatId, args.reply_to);
|
|
103700
|
-
const latestEnded = findLatestTurnForChat(chatId, { endedOnly: true });
|
|
103701
|
-
const byId = new Map;
|
|
103702
|
-
for (const t of [latestEnded, quoted, origin, liveTurn]) {
|
|
103703
|
-
if (t != null)
|
|
103704
|
-
byId.set(t.turnId, t);
|
|
103705
|
-
}
|
|
103706
|
-
const latestEndedAgeMs = latestEnded?.endedAt != null ? Date.now() - latestEnded.endedAt : null;
|
|
103707
|
-
const candidates = {
|
|
103708
|
-
liveTurnId: liveTurn?.turnId ?? null,
|
|
103709
|
-
originTurnId: origin?.turnId ?? null,
|
|
103710
|
-
quotedTurnId: quoted?.turnId ?? null,
|
|
103711
|
-
latestEndedTurnId: latestEnded?.turnId ?? null,
|
|
103712
|
-
latestEndedAgeMs,
|
|
103713
|
-
latestEndedTtlMs: DEFAULT_SUPERSEDE_TTL_MS
|
|
103714
|
-
};
|
|
103715
|
-
const tier = resolveReplyOwnerTier(candidates);
|
|
103716
|
-
const winnerId = resolveReplyOwnerTurnId(candidates);
|
|
103717
|
-
return { turn: winnerId != null ? byId.get(winnerId) ?? null : null, tier, candidates };
|
|
104011
|
+
return resolveReplyOwnerTurnWith({ findTurnByOriginId, findTurnByQuotedMessageId, findLatestTurnForChat, now: Date.now }, liveTurn, chatId, args);
|
|
103718
104012
|
}
|
|
103719
104013
|
function resolveAnswerThreadWithLog(chatId, explicitThreadId, originTurn, originVia, liveTurn, surface) {
|
|
103720
104014
|
const recovered = LATE_REPLY_TOPIC_RECOVERY_ENABLED && explicitThreadId == null && originTurn == null && liveTurn == null ? findLatestTurnForChat(chatId, { endedOnly: false }) : null;
|
|
@@ -105773,28 +106067,28 @@ var PIN_STATUS_WHILE_WORKING = (() => {
|
|
|
105773
106067
|
})();
|
|
105774
106068
|
var statusPinClaims = new Map;
|
|
105775
106069
|
var statusPinRightsCache = new PinRightsCache2;
|
|
105776
|
-
var STATUS_PIN_STORE_PATH =
|
|
106070
|
+
var STATUS_PIN_STORE_PATH = join68(STATE_DIR, "status-pins.json");
|
|
105777
106071
|
var statusPinStoreFs = {
|
|
105778
|
-
readFileSync: (p) =>
|
|
106072
|
+
readFileSync: (p) => readFileSync61(p, "utf8"),
|
|
105779
106073
|
writeFileSync: (p, d) => writeFileSync50(p, d),
|
|
105780
106074
|
renameSync: (a, b) => renameSync27(a, b),
|
|
105781
|
-
existsSync: (p) =>
|
|
106075
|
+
existsSync: (p) => existsSync58(p)
|
|
105782
106076
|
};
|
|
105783
106077
|
var statusPinPersistEnabled = !STATIC && PIN_STATUS_WHILE_WORKING;
|
|
105784
|
-
var ACTIVITY_CARD_STORE_PATH =
|
|
106078
|
+
var ACTIVITY_CARD_STORE_PATH = join68(STATE_DIR, "activity-cards-pending.json");
|
|
105785
106079
|
var activityCardStoreFs = {
|
|
105786
|
-
readFileSync: (p) =>
|
|
106080
|
+
readFileSync: (p) => readFileSync61(p, "utf8"),
|
|
105787
106081
|
writeFileSync: (p, d) => writeFileSync50(p, d),
|
|
105788
106082
|
renameSync: (a, b) => renameSync27(a, b),
|
|
105789
|
-
existsSync: (p) =>
|
|
106083
|
+
existsSync: (p) => existsSync58(p)
|
|
105790
106084
|
};
|
|
105791
106085
|
var activityCardPersistEnabled = !STATIC;
|
|
105792
|
-
var QUEUED_CARD_STORE_PATH =
|
|
106086
|
+
var QUEUED_CARD_STORE_PATH = join68(STATE_DIR, "queued-cards-pending.json");
|
|
105793
106087
|
var queuedCardStoreFs = {
|
|
105794
|
-
readFileSync: (p) =>
|
|
106088
|
+
readFileSync: (p) => readFileSync61(p, "utf8"),
|
|
105795
106089
|
writeFileSync: (p, d) => writeFileSync50(p, d),
|
|
105796
106090
|
renameSync: (a, b) => renameSync27(a, b),
|
|
105797
|
-
existsSync: (p) =>
|
|
106091
|
+
existsSync: (p) => existsSync58(p)
|
|
105798
106092
|
};
|
|
105799
106093
|
var queuedCardPersistEnabled = !STATIC;
|
|
105800
106094
|
function persistQueuedCard(key, chatId, threadId, messageId) {
|
|
@@ -106081,7 +106375,7 @@ async function unpinAllStatusPins() {
|
|
|
106081
106375
|
}
|
|
106082
106376
|
}
|
|
106083
106377
|
var stalePinSweepEligible = false;
|
|
106084
|
-
var STALE_PIN_SWEEP_STORE_PATH =
|
|
106378
|
+
var STALE_PIN_SWEEP_STORE_PATH = join68(STATE_DIR, "stale-pin-sweep.json");
|
|
106085
106379
|
var stalePinSweeper = createGatewayStalePinSweeper({
|
|
106086
106380
|
telegram: { handle: () => lockedBot, call: robustApiCall },
|
|
106087
106381
|
claims: () => statusPinClaims.values(),
|
|
@@ -106090,9 +106384,9 @@ var stalePinSweeper = createGatewayStalePinSweeper({
|
|
|
106090
106384
|
store: {
|
|
106091
106385
|
path: STALE_PIN_SWEEP_STORE_PATH,
|
|
106092
106386
|
fs: {
|
|
106093
|
-
readFileSync: (p) =>
|
|
106387
|
+
readFileSync: (p) => readFileSync61(p, "utf-8"),
|
|
106094
106388
|
writeFileSync: (p, data) => atomicWriteFileSync(p, data, 384),
|
|
106095
|
-
existsSync: (p) =>
|
|
106389
|
+
existsSync: (p) => existsSync58(p)
|
|
106096
106390
|
}
|
|
106097
106391
|
},
|
|
106098
106392
|
allowUnpinAllForumTopic: process.env.SWITCHROOM_PIN_SWEEP_UNPIN_ALL_TOPIC == null ? undefined : process.env.SWITCHROOM_PIN_SWEEP_UNPIN_ALL_TOPIC === "1"
|
|
@@ -106122,12 +106416,12 @@ var getPinnedProgressCardMessageId = null;
|
|
|
106122
106416
|
var completeProgressCardTurn = null;
|
|
106123
106417
|
var subagentWatcher = null;
|
|
106124
106418
|
var workerActivityFeed = null;
|
|
106125
|
-
var SOCKET_PATH = process.env.SWITCHROOM_GATEWAY_SOCKET ??
|
|
106419
|
+
var SOCKET_PATH = process.env.SWITCHROOM_GATEWAY_SOCKET ?? join68(STATE_DIR, "gateway.sock");
|
|
106126
106420
|
if (isGatewayMain)
|
|
106127
106421
|
mkdirSync51(STATE_DIR, { recursive: true, mode: 448 });
|
|
106128
|
-
var GATEWAY_PID_PATH = process.env.SWITCHROOM_GATEWAY_PID_FILE ??
|
|
106129
|
-
var GATEWAY_SESSION_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_SESSION_MARKER ??
|
|
106130
|
-
var GATEWAY_CLEAN_SHUTDOWN_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ??
|
|
106422
|
+
var GATEWAY_PID_PATH = process.env.SWITCHROOM_GATEWAY_PID_FILE ?? join68(STATE_DIR, "gateway.pid.json");
|
|
106423
|
+
var GATEWAY_SESSION_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_SESSION_MARKER ?? join68(STATE_DIR, "gateway-session.json");
|
|
106424
|
+
var GATEWAY_CLEAN_SHUTDOWN_MARKER_PATH = process.env.SWITCHROOM_GATEWAY_CLEAN_SHUTDOWN_MARKER ?? join68(STATE_DIR, "clean-shutdown.json");
|
|
106131
106425
|
var GATEWAY_STARTED_AT_MS = Date.now();
|
|
106132
106426
|
var BOOT_CARD_ENABLED = process.env.SWITCHROOM_BOOT_CARD !== "false";
|
|
106133
106427
|
var activeBootCard = null;
|
|
@@ -106156,7 +106450,7 @@ function ensureIssuesCard(chatId, threadId) {
|
|
|
106156
106450
|
bot: botApi,
|
|
106157
106451
|
log: (msg) => process.stderr.write(`telegram gateway: ${msg}
|
|
106158
106452
|
`),
|
|
106159
|
-
persistPath:
|
|
106453
|
+
persistPath: join68(stateDir, "issues-card.json")
|
|
106160
106454
|
});
|
|
106161
106455
|
activeIssuesWatcher = startIssuesWatcher({
|
|
106162
106456
|
stateDir,
|
|
@@ -106361,13 +106655,13 @@ if (isGatewayMain)
|
|
|
106361
106655
|
var inboundSpool;
|
|
106362
106656
|
if (isGatewayMain)
|
|
106363
106657
|
inboundSpool = STATIC ? undefined : createInboundSpool({
|
|
106364
|
-
path:
|
|
106658
|
+
path: join68(STATE_DIR, "inbound-spool.jsonl"),
|
|
106365
106659
|
fs: {
|
|
106366
106660
|
appendFileSync: (p, d) => appendFileSync9(p, d),
|
|
106367
|
-
readFileSync: (p) =>
|
|
106661
|
+
readFileSync: (p) => readFileSync61(p, "utf8"),
|
|
106368
106662
|
writeFileSync: (p, d) => writeFileSync50(p, d),
|
|
106369
106663
|
renameSync: (a, b) => renameSync27(a, b),
|
|
106370
|
-
existsSync: (p) =>
|
|
106664
|
+
existsSync: (p) => existsSync58(p),
|
|
106371
106665
|
statSizeSync: (p) => statSync23(p).size,
|
|
106372
106666
|
fsyncFileSync: fsyncPathSync,
|
|
106373
106667
|
fsyncDirSync: fsyncPathSync
|
|
@@ -106431,13 +106725,13 @@ async function maybeRedeliverUndeliveredAnswer() {
|
|
|
106431
106725
|
let transcriptText;
|
|
106432
106726
|
try {
|
|
106433
106727
|
const projectsDir = getProjectsDirForCwd();
|
|
106434
|
-
const path3 =
|
|
106435
|
-
if (!
|
|
106728
|
+
const path3 = join68(projectsDir, `${sessionId}.jsonl`);
|
|
106729
|
+
if (!existsSync58(path3)) {
|
|
106436
106730
|
process.stderr.write(`telegram gateway: crash-redelivery \u2014 transcript not found for turnKey=${turn.turn_key} session=${sessionId} (${path3}); skipping
|
|
106437
106731
|
`);
|
|
106438
106732
|
return;
|
|
106439
106733
|
}
|
|
106440
|
-
transcriptText =
|
|
106734
|
+
transcriptText = readFileSync61(path3, "utf8");
|
|
106441
106735
|
} catch (err) {
|
|
106442
106736
|
process.stderr.write(`telegram gateway: crash-redelivery \u2014 transcript read failed turnKey=${turn.turn_key}: ${err.message}
|
|
106443
106737
|
`);
|
|
@@ -106596,8 +106890,8 @@ var bridgeDeadWatchdog = createBridgeDeadWatchdog({
|
|
|
106596
106890
|
isSessionAlive: () => findAgentProcessInContainer2()?.comm === "claude",
|
|
106597
106891
|
isShuttingDown: () => shuttingDown,
|
|
106598
106892
|
escalate: (reason) => triggerSelfRestart(process.env.SWITCHROOM_AGENT_NAME ?? "", reason, 1500),
|
|
106599
|
-
crashLogPath:
|
|
106600
|
-
markerPath:
|
|
106893
|
+
crashLogPath: join68(STATE_DIR, "bridge-crash.log"),
|
|
106894
|
+
markerPath: join68(STATE_DIR, "bridge-dead-escalation.json"),
|
|
106601
106895
|
log: (line) => process.stderr.write(`${line}
|
|
106602
106896
|
`),
|
|
106603
106897
|
priorStreak: bridgeDeadPriorStreak,
|
|
@@ -106703,8 +106997,8 @@ if (isGatewayMain)
|
|
|
106703
106997
|
probeQuotaViaBroker: (t) => probeQuotaForBootCard(agentSlug, t),
|
|
106704
106998
|
tmuxSupervisor: process.env.SWITCHROOM_TMUX_SUPERVISOR === "1",
|
|
106705
106999
|
dockerMode: process.env.SWITCHROOM_RUNTIME === "docker",
|
|
106706
|
-
configSnapshotPath:
|
|
106707
|
-
bootCardStatePath:
|
|
107000
|
+
configSnapshotPath: join68(resolvedAgentDirForCard, ".config-snapshot.json"),
|
|
107001
|
+
bootCardStatePath: join68(resolvedAgentDirForCard, ".boot-card-msgid.json"),
|
|
106708
107002
|
floodStatePath: FLOOD_STATE_PATH,
|
|
106709
107003
|
...updateOutcomeLine ? { updateOutcomeLine } : {}
|
|
106710
107004
|
}, ackMsgId).then((handle) => {
|
|
@@ -106770,12 +107064,20 @@ if (isGatewayMain)
|
|
|
106770
107064
|
log: (msg) => process.stderr.write(`${msg}
|
|
106771
107065
|
`)
|
|
106772
107066
|
});
|
|
107067
|
+
if (client3.agentName != null && !isCronIdentity(client3.agentName)) {
|
|
107068
|
+
subagentReplyAuthority.reset();
|
|
107069
|
+
const closedWindows = closeFlushCompletionWindows(flushedTurnSupersede, Date.now());
|
|
107070
|
+
if (closedWindows > 0) {
|
|
107071
|
+
process.stderr.write(`telegram gateway: bridge disconnect closed ${closedWindows} open flush-completion window(s) (#4173)
|
|
107072
|
+
`);
|
|
107073
|
+
}
|
|
107074
|
+
}
|
|
106773
107075
|
},
|
|
106774
107076
|
async onToolCall(client3, msg) {
|
|
106775
107077
|
process.stderr.write(`telegram gateway: ipc: tool_call tool=${msg.tool} agent=${client3.agentName ?? "-"} clientId=${client3.id ?? "-"} callId=${msg.id}
|
|
106776
107078
|
`);
|
|
106777
107079
|
try {
|
|
106778
|
-
const result = await executeToolCall(msg.tool, msg.args);
|
|
107080
|
+
const result = await executeToolCall(msg.tool, msg.args, client3.agentName);
|
|
106779
107081
|
return { type: "tool_call_result", id: msg.id, success: true, result };
|
|
106780
107082
|
} catch (err) {
|
|
106781
107083
|
return {
|
|
@@ -107371,7 +107673,7 @@ if (isGatewayMain)
|
|
|
107371
107673
|
const receiverUid = receiverUidRaw ? Number(receiverUidRaw) : NaN;
|
|
107372
107674
|
if (Number.isInteger(receiverUid))
|
|
107373
107675
|
allowedUids.push(receiverUid);
|
|
107374
|
-
const socketPath =
|
|
107676
|
+
const socketPath = join68(STATE_DIR, "webhook.sock");
|
|
107375
107677
|
const webhookInject = (agentName3, inbound) => {
|
|
107376
107678
|
const msg = inbound;
|
|
107377
107679
|
const delivered = ipcServer.sendToAgent(agentName3, msg);
|
|
@@ -107453,13 +107755,13 @@ var ALLOWED_TOOLS = new Set([
|
|
|
107453
107755
|
"linear_create_issue",
|
|
107454
107756
|
"linear_agent_setup"
|
|
107455
107757
|
]);
|
|
107456
|
-
async function executeToolCall(tool, args) {
|
|
107758
|
+
async function executeToolCall(tool, args, callerAgentName = null) {
|
|
107457
107759
|
if (!ALLOWED_TOOLS.has(tool)) {
|
|
107458
107760
|
throw new Error(`tool not allowed: ${tool}`);
|
|
107459
107761
|
}
|
|
107460
107762
|
switch (tool) {
|
|
107461
107763
|
case "reply":
|
|
107462
|
-
return executeReply(args);
|
|
107764
|
+
return executeReply(args, callerAgentName);
|
|
107463
107765
|
case "progress_update":
|
|
107464
107766
|
return executeProgressUpdate(args);
|
|
107465
107767
|
case "react":
|
|
@@ -107622,9 +107924,9 @@ function redactOutboundText(text5, site) {
|
|
|
107622
107924
|
var VOICE_OUT_DEFAULT_CHUNK_CHARS = 600;
|
|
107623
107925
|
var VOICE_OUT_HARD_CHUNK_CAP = 4096;
|
|
107624
107926
|
var voiceOnDemandCache = new VoiceOnDemandCache({
|
|
107625
|
-
persistPath:
|
|
107927
|
+
persistPath: join68(STATE_DIR, "voice-ondemand.json")
|
|
107626
107928
|
});
|
|
107627
|
-
var VOICE_CACHE_DIR =
|
|
107929
|
+
var VOICE_CACHE_DIR = join68(STATE_DIR, "voice-cache");
|
|
107628
107930
|
var voicePreSynthQueue = new PreSynthQueue({
|
|
107629
107931
|
runJob: async (job) => {
|
|
107630
107932
|
const sidecarToken = await materializeSidecarToken2();
|
|
@@ -107740,8 +108042,12 @@ async function synthesizeVoiceOut(plan) {
|
|
|
107740
108042
|
return null;
|
|
107741
108043
|
}
|
|
107742
108044
|
}
|
|
107743
|
-
async function executeReply(args) {
|
|
107744
|
-
return sendReply(gatewaySendReplyDeps(), {
|
|
108045
|
+
async function executeReply(args, callerAgentName = null) {
|
|
108046
|
+
return sendReply(gatewaySendReplyDeps(), {
|
|
108047
|
+
args,
|
|
108048
|
+
turn: currentTurn,
|
|
108049
|
+
callerIsForeignSession: replyCallerIsForeignSession(callerAgentName)
|
|
108050
|
+
});
|
|
107745
108051
|
}
|
|
107746
108052
|
function gatewaySendReplyDeps() {
|
|
107747
108053
|
return {
|
|
@@ -107780,6 +108086,7 @@ function gatewaySendReplyDeps() {
|
|
|
107780
108086
|
resolveThreadId,
|
|
107781
108087
|
getLatestInboundMessageId,
|
|
107782
108088
|
getLastSubagentHandbackAt,
|
|
108089
|
+
subagentReplyAuthority,
|
|
107783
108090
|
recordOutbound,
|
|
107784
108091
|
emissionAuthorityFor,
|
|
107785
108092
|
clearActivitySummary,
|
|
@@ -108026,11 +108333,11 @@ async function executeSendGif(rawArgs) {
|
|
|
108026
108333
|
};
|
|
108027
108334
|
}
|
|
108028
108335
|
async function publishToTelegraph(text5, shortName, authorName) {
|
|
108029
|
-
const accountPath =
|
|
108336
|
+
const accountPath = join68(STATE_DIR, "telegraph-account.json");
|
|
108030
108337
|
let account = null;
|
|
108031
108338
|
try {
|
|
108032
|
-
if (
|
|
108033
|
-
const raw =
|
|
108339
|
+
if (existsSync58(accountPath)) {
|
|
108340
|
+
const raw = readFileSync61(accountPath, "utf-8");
|
|
108034
108341
|
const parsed = JSON.parse(raw);
|
|
108035
108342
|
if (parsed.shortName && parsed.accessToken) {
|
|
108036
108343
|
account = parsed;
|
|
@@ -108166,7 +108473,7 @@ _The secret was NOT saved. The agent can re-request with \`request_secret\`._`,
|
|
|
108166
108473
|
}
|
|
108167
108474
|
function readLiveSwitchroomConfigText() {
|
|
108168
108475
|
const cfgPath = process.env.SWITCHROOM_CONFIG ?? findConfigFile2();
|
|
108169
|
-
return
|
|
108476
|
+
return readFileSync61(cfgPath, "utf8");
|
|
108170
108477
|
}
|
|
108171
108478
|
async function executeReact(args) {
|
|
108172
108479
|
if (!args.chat_id)
|
|
@@ -109579,7 +109886,7 @@ function restartMarkerPath() {
|
|
|
109579
109886
|
const agentDir = resolveAgentDirFromEnv();
|
|
109580
109887
|
if (!agentDir)
|
|
109581
109888
|
return null;
|
|
109582
|
-
return
|
|
109889
|
+
return join68(agentDir, "restart-pending.json");
|
|
109583
109890
|
}
|
|
109584
109891
|
function writeRestartMarker(marker) {
|
|
109585
109892
|
const p = restartMarkerPath();
|
|
@@ -109605,7 +109912,7 @@ function readRestartMarker() {
|
|
|
109605
109912
|
if (!p)
|
|
109606
109913
|
return null;
|
|
109607
109914
|
try {
|
|
109608
|
-
return JSON.parse(
|
|
109915
|
+
return JSON.parse(readFileSync61(p, "utf8"));
|
|
109609
109916
|
} catch {
|
|
109610
109917
|
return null;
|
|
109611
109918
|
}
|
|
@@ -109754,7 +110061,7 @@ var _dockerReachable;
|
|
|
109754
110061
|
function isDockerReachable() {
|
|
109755
110062
|
if (_dockerReachable !== undefined)
|
|
109756
110063
|
return _dockerReachable;
|
|
109757
|
-
if (!
|
|
110064
|
+
if (!existsSync58("/var/run/docker.sock")) {
|
|
109758
110065
|
_dockerReachable = false;
|
|
109759
110066
|
return _dockerReachable;
|
|
109760
110067
|
}
|
|
@@ -109771,7 +110078,7 @@ function _resetDockerReachableCache() {
|
|
|
109771
110078
|
}
|
|
109772
110079
|
function spawnSwitchroomDetached(args, onFailure) {
|
|
109773
110080
|
const fullArgs = SWITCHROOM_CONFIG ? ["--config", SWITCHROOM_CONFIG, ...args] : args;
|
|
109774
|
-
const logPath =
|
|
110081
|
+
const logPath = join68(STATE_DIR, "detached-spawn.log");
|
|
109775
110082
|
let outFd = null;
|
|
109776
110083
|
try {
|
|
109777
110084
|
mkdirSync51(STATE_DIR, { recursive: true });
|
|
@@ -109802,7 +110109,7 @@ function spawnSwitchroomDetached(args, onFailure) {
|
|
|
109802
110109
|
return;
|
|
109803
110110
|
let tail = "";
|
|
109804
110111
|
try {
|
|
109805
|
-
const full =
|
|
110112
|
+
const full = readFileSync61(logPath, "utf8");
|
|
109806
110113
|
tail = full.split(`
|
|
109807
110114
|
`).slice(-30).join(`
|
|
109808
110115
|
`).trim();
|
|
@@ -110064,10 +110371,10 @@ ${preBlock(formatSwitchroomOutput(detail))}`, { html: true });
|
|
|
110064
110371
|
}
|
|
110065
110372
|
function readRecentDenialsForAgent(agentName3, windowMs, limit) {
|
|
110066
110373
|
try {
|
|
110067
|
-
const auditPath =
|
|
110068
|
-
if (!
|
|
110374
|
+
const auditPath = join68(homedir20(), ".switchroom", "vault-audit.log");
|
|
110375
|
+
if (!existsSync58(auditPath))
|
|
110069
110376
|
return [];
|
|
110070
|
-
const raw =
|
|
110377
|
+
const raw = readFileSync61(auditPath, "utf8");
|
|
110071
110378
|
return recentDenialsFromAuditLog(raw, { agentName: agentName3, windowMs, limit });
|
|
110072
110379
|
} catch {
|
|
110073
110380
|
return [];
|
|
@@ -110118,7 +110425,7 @@ async function buildAgentMetadata(agentName3) {
|
|
|
110118
110425
|
try {
|
|
110119
110426
|
const agentDir = resolveAgentDirFromEnv();
|
|
110120
110427
|
if (agentDir) {
|
|
110121
|
-
const raw =
|
|
110428
|
+
const raw = readFileSync61(join68(agentDir, ".claude", ".claude.json"), "utf8");
|
|
110122
110429
|
claudeJson = JSON.parse(raw);
|
|
110123
110430
|
}
|
|
110124
110431
|
} catch {}
|
|
@@ -110247,7 +110554,7 @@ function buildModelDeps(restartCtx) {
|
|
|
110247
110554
|
try {
|
|
110248
110555
|
const agentDir = resolveAgentDirFromEnv();
|
|
110249
110556
|
if (agentDir) {
|
|
110250
|
-
const local = await fetchQuota2({ claudeConfigDir:
|
|
110557
|
+
const local = await fetchQuota2({ claudeConfigDir: join68(agentDir, ".claude") });
|
|
110251
110558
|
if (local.ok)
|
|
110252
110559
|
return formatQuotaLine2(local.data);
|
|
110253
110560
|
}
|
|
@@ -110494,9 +110801,9 @@ function effortMenuReplyMarkup(reply) {
|
|
|
110494
110801
|
function flushAgentHandoff(agentDir) {
|
|
110495
110802
|
let removed = 0;
|
|
110496
110803
|
for (const fname of [".handoff.md", ".handoff-topic"]) {
|
|
110497
|
-
const p =
|
|
110804
|
+
const p = join68(agentDir, fname);
|
|
110498
110805
|
try {
|
|
110499
|
-
if (
|
|
110806
|
+
if (existsSync58(p)) {
|
|
110500
110807
|
unlinkSync31(p);
|
|
110501
110808
|
removed++;
|
|
110502
110809
|
}
|
|
@@ -110552,7 +110859,7 @@ async function handleNewCommand(ctx) {
|
|
|
110552
110859
|
writeRestartMarker({ chat_id: chatId, thread_id: threadId ?? null, ack_message_id: ackId, ts: Date.now() });
|
|
110553
110860
|
if (agentDir != null) {
|
|
110554
110861
|
try {
|
|
110555
|
-
writeFileSync50(
|
|
110862
|
+
writeFileSync50(join68(agentDir, ".force-fresh-session"), `${kind} at ${new Date().toISOString()}
|
|
110556
110863
|
`, "utf8");
|
|
110557
110864
|
} catch (err) {
|
|
110558
110865
|
process.stderr.write(`telegram gateway: failed to write force-fresh marker: ${err}
|
|
@@ -110665,16 +110972,16 @@ function buildFolderPickerDeps() {
|
|
|
110665
110972
|
};
|
|
110666
110973
|
}
|
|
110667
110974
|
var lockoutOps = {
|
|
110668
|
-
readFileSync: (p, enc) =>
|
|
110975
|
+
readFileSync: (p, enc) => readFileSync61(p, enc),
|
|
110669
110976
|
writeFileSync: (p, data, opts) => writeFileSync50(p, data, opts),
|
|
110670
|
-
existsSync: (p) =>
|
|
110977
|
+
existsSync: (p) => existsSync58(p),
|
|
110671
110978
|
mkdirSync: (p, opts) => mkdirSync51(p, opts),
|
|
110672
|
-
joinPath: (...parts) =>
|
|
110979
|
+
joinPath: (...parts) => join68(...parts)
|
|
110673
110980
|
};
|
|
110674
110981
|
var FLEET_FALLBACK_DEDUP_MS = 30000;
|
|
110675
110982
|
function isAuthBrokerSocketReachable() {
|
|
110676
110983
|
try {
|
|
110677
|
-
return
|
|
110984
|
+
return existsSync58(resolveAuthBrokerSocketPath2());
|
|
110678
110985
|
} catch {
|
|
110679
110986
|
return false;
|
|
110680
110987
|
}
|
|
@@ -110929,7 +111236,7 @@ async function runCreditWatch() {
|
|
|
110929
111236
|
if (!agentDir)
|
|
110930
111237
|
return;
|
|
110931
111238
|
const agentName3 = getMyAgentName();
|
|
110932
|
-
const claudeConfigDir =
|
|
111239
|
+
const claudeConfigDir = join68(agentDir, ".claude");
|
|
110933
111240
|
const stateDir = STATE_DIR;
|
|
110934
111241
|
const reason = readClaudeJsonOverage(claudeConfigDir);
|
|
110935
111242
|
const prev = loadCreditState(stateDir);
|
|
@@ -112685,7 +112992,7 @@ Send \`/auth ${parsed.provider} cancel\` to abort.`, { html: true });
|
|
|
112685
112992
|
await switchroomReply(ctx, "**/usage:** cannot resolve agent dir.", { html: true });
|
|
112686
112993
|
return;
|
|
112687
112994
|
}
|
|
112688
|
-
const result = await fetchQuota2({ claudeConfigDir:
|
|
112995
|
+
const result = await fetchQuota2({ claudeConfigDir: join68(agentDir, ".claude") });
|
|
112689
112996
|
if (!result.ok) {
|
|
112690
112997
|
await switchroomReply(ctx, `**/usage:** ${escapeHtmlForTg2(result.reason)}`, { html: true });
|
|
112691
112998
|
return;
|
|
@@ -113072,7 +113379,7 @@ ${interimLabel}` : interimLabel
|
|
|
113072
113379
|
const unifiedDiff = (() => {
|
|
113073
113380
|
try {
|
|
113074
113381
|
const cfgPath = process.env.SWITCHROOM_CONFIG ?? SWITCHROOM_CONFIG ?? findConfigFile2();
|
|
113075
|
-
const raw =
|
|
113382
|
+
const raw = readFileSync61(cfgPath, "utf8");
|
|
113076
113383
|
return synthesizeAllowRuleDiff({ agentName: agentName3, rule: chosen.rule, configText: raw });
|
|
113077
113384
|
} catch (err) {
|
|
113078
113385
|
process.stderr.write(`telegram gateway: always-allow diff synth failed: ${err.message}
|
|
@@ -113941,7 +114248,7 @@ async function startGateway() {
|
|
|
113941
114248
|
return;
|
|
113942
114249
|
}
|
|
113943
114250
|
})();
|
|
113944
|
-
const resolvedAgentDirForBootCard = agentDir ??
|
|
114251
|
+
const resolvedAgentDirForBootCard = agentDir ?? join68(homedir20(), ".switchroom", "agents", agentSlug);
|
|
113945
114252
|
const handle = await startBootCard(chatId, threadId, botApiForCard, {
|
|
113946
114253
|
agentName: agentDisplayName,
|
|
113947
114254
|
agentSlug,
|
|
@@ -113955,8 +114262,8 @@ async function startGateway() {
|
|
|
113955
114262
|
probeQuotaViaBroker: (t) => probeQuotaForBootCard(agentSlug, t),
|
|
113956
114263
|
tmuxSupervisor: process.env.SWITCHROOM_TMUX_SUPERVISOR === "1",
|
|
113957
114264
|
dockerMode: process.env.SWITCHROOM_RUNTIME === "docker",
|
|
113958
|
-
configSnapshotPath:
|
|
113959
|
-
bootCardStatePath:
|
|
114265
|
+
configSnapshotPath: join68(resolvedAgentDirForBootCard, ".config-snapshot.json"),
|
|
114266
|
+
bootCardStatePath: join68(resolvedAgentDirForBootCard, ".boot-card-msgid.json"),
|
|
113960
114267
|
floodStatePath: FLOOD_STATE_PATH,
|
|
113961
114268
|
...updateOutcomeLine ? { updateOutcomeLine } : {}
|
|
113962
114269
|
}, ackMsgId);
|
|
@@ -113989,7 +114296,7 @@ async function startGateway() {
|
|
|
113989
114296
|
if (smAgentDir) {
|
|
113990
114297
|
const resolutionTimeoutMs = resolveSessionModelResolutionTimeoutMs(process.env.SWITCHROOM_SESSION_MODEL_RESOLUTION_TIMEOUT_MS);
|
|
113991
114298
|
const resolved = await waitForSessionModelResolution({
|
|
113992
|
-
barrierExists: () =>
|
|
114299
|
+
barrierExists: () => existsSync58(join68(smAgentDir, ".session-model-resolved")),
|
|
113993
114300
|
timeoutMs: resolutionTimeoutMs
|
|
113994
114301
|
});
|
|
113995
114302
|
if (!resolved) {
|
|
@@ -113997,10 +114304,10 @@ async function startGateway() {
|
|
|
113997
114304
|
process.stderr.write(`telegram gateway: gw /model relaunch UNRESOLVED agent=${getMyAgentName()} target=${target} (barrier timeout after ${resolutionTimeoutMs}ms)
|
|
113998
114305
|
`);
|
|
113999
114306
|
} else {
|
|
114000
|
-
const activePath =
|
|
114001
|
-
if (
|
|
114307
|
+
const activePath = join68(smAgentDir, ".active-session-model");
|
|
114308
|
+
if (existsSync58(activePath)) {
|
|
114002
114309
|
try {
|
|
114003
|
-
const launched =
|
|
114310
|
+
const launched = readFileSync61(activePath, "utf8").trim();
|
|
114004
114311
|
const configured = (() => {
|
|
114005
114312
|
const d = switchroomExecJson(["agent", "list"]);
|
|
114006
114313
|
const raw = d?.agents?.find((a) => a.name === getMyAgentName())?.model ?? null;
|
|
@@ -114033,24 +114340,24 @@ async function startGateway() {
|
|
|
114033
114340
|
deliverModelSwitchBootNotice({
|
|
114034
114341
|
...modelBootCardDeps,
|
|
114035
114342
|
confirmation,
|
|
114036
|
-
hasSessionModelAlert:
|
|
114343
|
+
hasSessionModelAlert: existsSync58(join68(smAgentDir, ".session-model-alert"))
|
|
114037
114344
|
});
|
|
114038
114345
|
}
|
|
114039
114346
|
} catch {}
|
|
114040
114347
|
}
|
|
114041
|
-
const activeEffortPath =
|
|
114042
|
-
if (
|
|
114348
|
+
const activeEffortPath = join68(smAgentDir, ".active-session-effort");
|
|
114349
|
+
if (existsSync58(activeEffortPath)) {
|
|
114043
114350
|
try {
|
|
114044
|
-
const launchedEffort =
|
|
114351
|
+
const launchedEffort = readFileSync61(activeEffortPath, "utf8").trim();
|
|
114045
114352
|
const configuredEffort = getConfiguredEffortForPersist();
|
|
114046
114353
|
sessionEffortOverride = launchedEffort.length > 0 && launchedEffort !== configuredEffort ? launchedEffort : null;
|
|
114047
114354
|
} catch {}
|
|
114048
114355
|
}
|
|
114049
|
-
const alertPath =
|
|
114050
|
-
if (
|
|
114356
|
+
const alertPath = join68(smAgentDir, ".session-model-alert");
|
|
114357
|
+
if (existsSync58(alertPath)) {
|
|
114051
114358
|
let alertText = null;
|
|
114052
114359
|
try {
|
|
114053
|
-
alertText =
|
|
114360
|
+
alertText = readFileSync61(alertPath, "utf8").trim();
|
|
114054
114361
|
} catch {
|
|
114055
114362
|
alertText = null;
|
|
114056
114363
|
}
|