switchroom 0.21.14 → 0.21.15

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.
@@ -2120,7 +2120,7 @@ var init_esm = __esm(() => {
2120
2120
  });
2121
2121
 
2122
2122
  // src/build-info.ts
2123
- var VERSION = "0.21.14", COMMIT_SHA = "2d43063c", COMMIT_DATE = "2026-08-16T08:34:12Z";
2123
+ var VERSION = "0.21.15", COMMIT_SHA = "efa77e51", COMMIT_DATE = "2026-08-17T00:42:23Z";
2124
2124
 
2125
2125
  // src/cli/resolve-version.ts
2126
2126
  import { existsSync, readFileSync } from "node:fs";
@@ -13750,6 +13750,7 @@ var init_schema = __esm(() => {
13750
13750
  empathy: exports_external.number().int().min(1).max(5).optional().describe("How much the bank weights emotional/relational context (1-5; engine default 3).")
13751
13751
  }).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`)."),
13752
13752
  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)."),
13753
+ profile_capture_nudge: exports_external.boolean().optional().describe("Deterministic operator-profile capture nudge (RFC phase4 P3, serves " + 'the "save memories about him" want). When on (switchroom default ' + "true), the auto-recall hook regex-detects a first-person durable " + 'self-statement by the operator ("I prefer \u2026", "my \u2026 is \u2026", "I ' + 'always \u2026", "remind me that I \u2026") and appends a terse advisory to ' + "the turn's context telling the model to persist it with an explicit " + "mcp__hindsight__retain tagged `profile:ken` into the agent's OWN bank " + "(not a shared/cross-agent person bank). Detection is pure regex \u2014 the " + "model does the judgment in-session and calls retain itself (no model " + "callsite, no silent hook-side write). Set false to disable per-agent. " + "Cascade: override (per-agent wins over default)."),
13753
13754
  anti_confabulation_directive: AntiConfabulationDirectiveSchema,
13754
13755
  observation_scopes: ObservationScopesSchema,
13755
13756
  observation_scope_strategy: ObservationScopeStrategySchema,
@@ -13798,7 +13799,8 @@ var init_schema = __esm(() => {
13798
13799
  }).optional().describe("Auto-recall tuning knobs"),
13799
13800
  retain: exports_external.object({
13800
13801
  every_n_turns: exports_external.number().int().min(1).optional().describe("How often the Stop hook fires auto-retention, in turns. The " + "vendor plugin default is 10 (a short session can end before " + "retention ever fires); switchroom's scaffold default is 3. " + "Lower = more frequent, smaller retains + tighter crash " + "durability (at 1, every turn is retained before a restart can " + "lose it); higher = fewer, larger retains + less LLM churn. " + "Raised from the historical 1 to 3 because the local reasoning " + "consolidation model (Ollama gpt-oss-20b) ran away on the large " + "overlapping every-turn payloads. Set to 1 for the old " + "every-turn crash-durability guarantee. Min 1. Cascade: " + "per-field merge (agent wins over default)."),
13801
- overlap_turns: exports_external.number().int().min(0).optional().describe("Extra recent turns included in each chunked retain window on " + "top of `every_n_turns`, so window = overlap_turns + " + "every_n_turns recent turns. Vendor default is 2; switchroom's " + "scaffold default is 1 (smaller payloads for the local " + "reasoning consolidation model). Higher = more redundant " + "context re-sent per fire. Min 0. Cascade: per-field merge.")
13802
+ overlap_turns: exports_external.number().int().min(0).optional().describe("Extra recent turns included in each chunked retain window on " + "top of `every_n_turns`, so window = overlap_turns + " + "every_n_turns recent turns. Vendor default is 2; switchroom's " + "scaffold default is 1 (smaller payloads for the local " + "reasoning consolidation model). Higher = more redundant " + "context re-sent per fire. Min 0. Cascade: per-field merge."),
13803
+ tool_calls: exports_external.boolean().optional().describe("Whether auto-retain stores assistant tool_use blocks (with their " + "entire input dict) and tool_result content (up to 2000 chars) " + "alongside the human/assistant turns. Vendor + switchroom default " + "is true \u2014 the fleet behaves byte-identically until an operator " + "sets this false. Tool inputs/results are a large fraction of " + "retained volume (RFC memory-redesign P4) but also where evidence " + "lives (a commit SHA, a failing test's output, the diff that " + "fixed something), so the tradeoff is real and per-agent. false is " + "not a new mode: sidechains already force it off " + "(subagent_retain.py). Set false to drop tool exhaust from an " + "agent's retains. Cascade: per-field merge (agent wins over " + "default).")
13802
13804
  }).optional().describe("Auto-retain (Stop-hook consolidation) cadence knobs")
13803
13805
  }).optional();
13804
13806
  HookEntrySchema = exports_external.object({
@@ -14186,6 +14188,7 @@ var init_schema = __esm(() => {
14186
14188
  isolation: exports_external.enum(["default", "strict"]).optional(),
14187
14189
  profile: exports_external.string().optional(),
14188
14190
  directive_capture_nudge: exports_external.boolean().optional(),
14191
+ profile_capture_nudge: exports_external.boolean().optional(),
14189
14192
  anti_confabulation_directive: AntiConfabulationDirectiveSchema,
14190
14193
  observation_scopes: ObservationScopesSchema,
14191
14194
  observation_scope_strategy: ObservationScopeStrategySchema,
@@ -14234,7 +14237,8 @@ var init_schema = __esm(() => {
14234
14237
  }).optional(),
14235
14238
  retain: exports_external.object({
14236
14239
  every_n_turns: exports_external.number().int().min(1).optional(),
14237
- overlap_turns: exports_external.number().int().min(0).optional()
14240
+ overlap_turns: exports_external.number().int().min(0).optional(),
14241
+ tool_calls: exports_external.boolean().optional()
14238
14242
  }).optional(),
14239
14243
  bank_mission: exports_external.string().optional(),
14240
14244
  reflect_mission: exports_external.string().optional(),
@@ -30444,7 +30448,8 @@ function resolveHindsightRetainConfig(switchroomConfig, agentName, resolvedAgent
30444
30448
  const retain = resolvedAgentConfig ? resolvedAgentConfig.memory?.retain : switchroomConfig ? resolveAgentConfig(switchroomConfig.defaults, switchroomConfig.profiles, switchroomConfig.agents[agentName] ?? {})?.memory?.retain : undefined;
30445
30449
  return {
30446
30450
  everyNTurns: retain?.every_n_turns ?? HINDSIGHT_DEFAULT_RETAIN_EVERY_N_TURNS,
30447
- overlapTurns: retain?.overlap_turns ?? HINDSIGHT_DEFAULT_RETAIN_OVERLAP_TURNS
30451
+ overlapTurns: retain?.overlap_turns ?? HINDSIGHT_DEFAULT_RETAIN_OVERLAP_TURNS,
30452
+ toolCalls: retain?.tool_calls ?? HINDSIGHT_DEFAULT_RETAIN_TOOL_CALLS
30448
30453
  };
30449
30454
  }
30450
30455
  function resolveHindsightAutoRecall(switchroomConfig, agentName, resolvedAgentConfig) {
@@ -30520,6 +30525,7 @@ function renderHindsightSettingsOverrides(raw, additionalBanks, retainConfig, re
30520
30525
  settings.retainEveryNTurns = retainConfig.everyNTurns;
30521
30526
  settings.retainMode = "chunked";
30522
30527
  settings.retainOverlapTurns = retainConfig.overlapTurns;
30528
+ settings.retainToolCalls = retainConfig.toolCalls;
30523
30529
  settings.retainTags = [...RETAIN_TAGS_DEFAULT];
30524
30530
  settings.recallMaxMemories = recallCaps.maxMemories;
30525
30531
  settings.recallMaxTokens = recallCaps.maxTokens;
@@ -30530,6 +30536,7 @@ function renderHindsightSettingsOverrides(raw, additionalBanks, retainConfig, re
30530
30536
  settings.recallAdditionalBankMinSlots = defaultRecallAdditionalBankMinSlots(recallCaps.maxMemories);
30531
30537
  settings.recallSkipTrivial = true;
30532
30538
  settings.directiveCaptureNudge = true;
30539
+ settings.profileCaptureNudge = true;
30533
30540
  settings.recallTagWeights = { ...HINDSIGHT_RECALL_TAG_WEIGHT_SEED };
30534
30541
  if (additionalBanks.length > 0) {
30535
30542
  settings.recallAdditionalBanks = [...additionalBanks];
@@ -30583,6 +30590,7 @@ function buildWorkspaceContext(args) {
30583
30590
  hindsightRecallTypes,
30584
30591
  hindsightRecallSkipTrivial,
30585
30592
  hindsightDirectiveCaptureNudge,
30593
+ hindsightProfileCaptureNudge,
30586
30594
  hindsightObservationScopes,
30587
30595
  hindsightObservationScopeStrategy,
30588
30596
  hindsightTopicAliasesJson,
@@ -30637,6 +30645,7 @@ function buildWorkspaceContext(args) {
30637
30645
  hindsightRecallTypes,
30638
30646
  hindsightRecallSkipTrivial,
30639
30647
  hindsightDirectiveCaptureNudge,
30648
+ hindsightProfileCaptureNudge,
30640
30649
  hindsightObservationScopesQ: hindsightObservationScopes ? shellSingleQuote(hindsightObservationScopes) : undefined,
30641
30650
  hindsightObservationScopeStrategyQ: hindsightObservationScopeStrategy ? shellSingleQuote(hindsightObservationScopeStrategy) : undefined,
30642
30651
  hindsightTopicAliasesJsonQ: hindsightTopicAliasesJson ? shellSingleQuote(hindsightTopicAliasesJson) : undefined,
@@ -30912,6 +30921,7 @@ function scaffoldAgent(name, agentConfigRaw, agentsDir, telegramConfig, switchro
30912
30921
  const hindsightRecallTypes = agentConfig.memory?.recall?.types?.length ? agentConfig.memory.recall.types.join(",") : undefined;
30913
30922
  const hindsightRecallSkipTrivial = agentConfig.memory?.recall?.skip_trivial === undefined ? undefined : String(agentConfig.memory.recall.skip_trivial);
30914
30923
  const hindsightDirectiveCaptureNudge = agentConfig.memory?.directive_capture_nudge === undefined ? undefined : String(agentConfig.memory.directive_capture_nudge);
30924
+ const hindsightProfileCaptureNudge = agentConfig.memory?.profile_capture_nudge === undefined ? undefined : String(agentConfig.memory.profile_capture_nudge);
30915
30925
  const hindsightObservationScopes = agentConfig.memory?.observation_scopes;
30916
30926
  const hindsightObservationScopeStrategy = agentConfig.memory?.observation_scope_strategy;
30917
30927
  const topicAliases = agentConfig.channels?.telegram?.topic_aliases;
@@ -30949,6 +30959,7 @@ function scaffoldAgent(name, agentConfigRaw, agentsDir, telegramConfig, switchro
30949
30959
  hindsightRecallTypes,
30950
30960
  hindsightRecallSkipTrivial,
30951
30961
  hindsightDirectiveCaptureNudge,
30962
+ hindsightProfileCaptureNudge,
30952
30963
  hindsightObservationScopes,
30953
30964
  hindsightObservationScopeStrategy,
30954
30965
  hindsightTopicAliasesJson,
@@ -31925,6 +31936,7 @@ function reconcileAgentInner(name, agentConfigRaw, agentsDir, telegramConfig, sw
31925
31936
  const hindsightRecallTypes = agentConfig.memory?.recall?.types?.length ? agentConfig.memory.recall.types.join(",") : undefined;
31926
31937
  const hindsightRecallSkipTrivial = agentConfig.memory?.recall?.skip_trivial === undefined ? undefined : String(agentConfig.memory.recall.skip_trivial);
31927
31938
  const hindsightDirectiveCaptureNudge = agentConfig.memory?.directive_capture_nudge === undefined ? undefined : String(agentConfig.memory.directive_capture_nudge);
31939
+ const hindsightProfileCaptureNudge = agentConfig.memory?.profile_capture_nudge === undefined ? undefined : String(agentConfig.memory.profile_capture_nudge);
31928
31940
  const hindsightObservationScopes = agentConfig.memory?.observation_scopes;
31929
31941
  const hindsightObservationScopeStrategy = agentConfig.memory?.observation_scope_strategy;
31930
31942
  const topicAliases = agentConfig.channels?.telegram?.topic_aliases;
@@ -31974,6 +31986,7 @@ function reconcileAgentInner(name, agentConfigRaw, agentsDir, telegramConfig, sw
31974
31986
  hindsightRecallTypes,
31975
31987
  hindsightRecallSkipTrivial,
31976
31988
  hindsightDirectiveCaptureNudge,
31989
+ hindsightProfileCaptureNudge,
31977
31990
  hindsightObservationScopesQ: hindsightObservationScopes ? shellSingleQuote(hindsightObservationScopes) : undefined,
31978
31991
  hindsightObservationScopeStrategyQ: hindsightObservationScopeStrategy ? shellSingleQuote(hindsightObservationScopeStrategy) : undefined,
31979
31992
  hindsightTopicAliasesJsonQ: hindsightTopicAliasesJson ? shellSingleQuote(hindsightTopicAliasesJson) : undefined,
@@ -32411,6 +32424,7 @@ ${body}
32411
32424
  hindsightRecallTypes,
32412
32425
  hindsightRecallSkipTrivial,
32413
32426
  hindsightDirectiveCaptureNudge,
32427
+ hindsightProfileCaptureNudge,
32414
32428
  hindsightObservationScopes,
32415
32429
  hindsightObservationScopeStrategy,
32416
32430
  hindsightTopicAliasesJson,
@@ -32955,6 +32969,13 @@ When the user asks you to forget something ("forget that", "delete X", "drop wha
32955
32969
  ### Inspect proactively
32956
32970
  When the user asks "what do you know about X / me", "what do you remember about Y", or any memory audit, use \`reflect\` to synthesize an answer across the bank. Return it as honest prose, not a raw dump. If the bank has little on the topic, say so.
32957
32971
 
32972
+ ### Route repo knowledge to the shared repo bank
32973
+ Auto-retain always writes your OWN bank, and that stays true for everything above \u2014 don't fight it. The one place you reach past it, by hand, is durable knowledge about a REPOSITORY: a build invariant, a migration gotcha, a house-style rule, a "this suite only passes single-threaded" trap. That kind of fact is worth having for every agent that touches the repo, not just you \u2014 so persist it to the shared repo bank with an explicit \`retain\` that names the bank, in the same turn you learn it:
32974
+
32975
+ \`mcp__hindsight__retain(content="switchroom's vitest config must set assetsInclude to ['**/*.yaml'], or a .yaml imported with { type: 'text' } fails to resolve under vitest", bank_id="switchroom-dev", tags=["repo:switchroom", "build"])\`
32976
+
32977
+ Passing \`bank_id\` is what makes this the exception: auto-retain can't reach a shared bank (it always resolves your own), so if you don't make the call by hand the knowledge stays trapped in your bank. Two rules keep the shared bank clean: route only durable, repo-scoped facts there \u2014 never conversation, user preferences, or anything about a person (those stay in your own bank via ordinary retain) \u2014 and tag every one \`repo:<name>\` so it is findable. Writes are always durable and readable by the configured agents; on the read side, ordinary \`recall\` / \`reflect\` reach the shared repo bank only for agents that list it in \`memory.recall.additional_banks\` (a handful of dev agents) \u2014 for everyone else the shared write is write-only from their own recall.
32978
+
32958
32979
  Don't wait for a slash command. Don't ask permission. Memory work is table stakes, like a colleague who takes notes and remembers.`, WEB_FETCH_GUIDANCE = `## Fetching from the web
32959
32980
 
32960
32981
  The native \`WebFetch\` tool is disabled in this fleet \u2014 fetch pages
@@ -33121,7 +33142,7 @@ plainer wins.
33121
33142
  Every turn that answers a user message ends with a user-visible \`reply\`
33122
33143
  \u2014 Telegram is all the user sees; your terminal output
33123
33144
  never reaches them.`, TELEGRAM_ENV_PLACEHOLDER = `# Set your bot token: TELEGRAM_BOT_TOKEN=your-token-here
33124
- `, SWITCHROOM_TELEGRAM_MCP_TOOLS, HINDSIGHT_MCP_TOOLS, AGENT_CONFIG_MCP_TOOLS, HOSTD_MCP_TOOLS, WEBKITE_MCP_TOOLS, CONTEXT7_MCP_TOOLS, CONTEXT7_BLANKET_TOKENS, LEGACY_SWITCHROOM_MCP_TOKENS, LEGACY_HOSTD_BLANKET_TOKENS, DEFAULT_READ_ONLY_PREAPPROVED_TOOLS, NATIVE_WEBSEARCH_PREAPPROVED_TOOLS, WEBKITE_FLEET_DENY_TOOLS, INTERACTIVE_TUI_FLEET_DENY_TOOLS, WEBKITE_BINARY_CONTAINER_PATH = "/usr/local/bin/webkite", SWITCHROOM_DEFAULT_MAIN_MODEL = "claude-sonnet-5", SWITCHROOM_DEFAULT_THINKING_EFFORT = "low", CLAUDE_MD_YOURS_PLACEHOLDER, pendingBankOps, SWITCHROOM_OWNED_SETTINGS_KEYS, ALL_BUILTIN_TOOLS, HINDSIGHT_DEFAULT_RETAIN_EVERY_N_TURNS = 3, HINDSIGHT_DEFAULT_RETAIN_OVERLAP_TURNS = 1, RECALL_OWN_BANK_SLOT_DIVISOR = 3, RECALL_ADDITIONAL_BANK_SLOT_DIVISOR = 6, HINDSIGHT_RECALL_MIN_SCORE_DEFAULT = 0, HINDSIGHT_RECALL_MIN_SCORE_SCOPE_DEFAULT = "degraded", VALID_SETTINGS_DEFAULT_MODES, SWITCHROOM_DEFAULT_PERMISSION_MODE = "acceptEdits", DOCKER_TELEGRAM_PLUGIN_PATH = "/opt/switchroom/telegram-plugin", DOCKER_HOOKS_PATH, DOCKER_BUNDLED_HOOKS_PATH = "/opt/switchroom/hooks", DOCKER_BIN_PATH = "/opt/switchroom/bin", DOCKER_SECURITY_PLUGIN_PATH = "/opt/switchroom/security-plugin", DOCKER_CONFIG_PATH = "/state/config/switchroom.yaml", DOCKER_SWITCHROOM_CLI_PATH = "/usr/local/bin/switchroom", DOCKER_AUTH_BROKER_SOCKET = "/run/switchroom/auth-broker/sock", DOCKER_VAULT_BROKER_SOCKET = "/run/switchroom/broker/sock", DOCKER_AGENT_HOME = "/state/agent/home", CONTEXT7_MCP_URL = "https://mcp.context7.com/mcp", INTEGRATION_MCP_RESOLVERS;
33145
+ `, SWITCHROOM_TELEGRAM_MCP_TOOLS, HINDSIGHT_MCP_TOOLS, AGENT_CONFIG_MCP_TOOLS, HOSTD_MCP_TOOLS, WEBKITE_MCP_TOOLS, CONTEXT7_MCP_TOOLS, CONTEXT7_BLANKET_TOKENS, LEGACY_SWITCHROOM_MCP_TOKENS, LEGACY_HOSTD_BLANKET_TOKENS, DEFAULT_READ_ONLY_PREAPPROVED_TOOLS, NATIVE_WEBSEARCH_PREAPPROVED_TOOLS, WEBKITE_FLEET_DENY_TOOLS, INTERACTIVE_TUI_FLEET_DENY_TOOLS, WEBKITE_BINARY_CONTAINER_PATH = "/usr/local/bin/webkite", SWITCHROOM_DEFAULT_MAIN_MODEL = "claude-sonnet-5", SWITCHROOM_DEFAULT_THINKING_EFFORT = "low", CLAUDE_MD_YOURS_PLACEHOLDER, pendingBankOps, SWITCHROOM_OWNED_SETTINGS_KEYS, ALL_BUILTIN_TOOLS, HINDSIGHT_DEFAULT_RETAIN_EVERY_N_TURNS = 3, HINDSIGHT_DEFAULT_RETAIN_OVERLAP_TURNS = 1, HINDSIGHT_DEFAULT_RETAIN_TOOL_CALLS = true, RECALL_OWN_BANK_SLOT_DIVISOR = 3, RECALL_ADDITIONAL_BANK_SLOT_DIVISOR = 6, HINDSIGHT_RECALL_MIN_SCORE_DEFAULT = 0, HINDSIGHT_RECALL_MIN_SCORE_SCOPE_DEFAULT = "degraded", VALID_SETTINGS_DEFAULT_MODES, SWITCHROOM_DEFAULT_PERMISSION_MODE = "acceptEdits", DOCKER_TELEGRAM_PLUGIN_PATH = "/opt/switchroom/telegram-plugin", DOCKER_HOOKS_PATH, DOCKER_BUNDLED_HOOKS_PATH = "/opt/switchroom/hooks", DOCKER_BIN_PATH = "/opt/switchroom/bin", DOCKER_SECURITY_PLUGIN_PATH = "/opt/switchroom/security-plugin", DOCKER_CONFIG_PATH = "/state/config/switchroom.yaml", DOCKER_SWITCHROOM_CLI_PATH = "/usr/local/bin/switchroom", DOCKER_AUTH_BROKER_SOCKET = "/run/switchroom/auth-broker/sock", DOCKER_VAULT_BROKER_SOCKET = "/run/switchroom/broker/sock", DOCKER_AGENT_HOME = "/state/agent/home", CONTEXT7_MCP_URL = "https://mcp.context7.com/mcp", INTEGRATION_MCP_RESOLVERS;
33125
33146
  var init_scaffold = __esm(() => {
33126
33147
  init_source();
33127
33148
  init_cron_unit_name();
@@ -84741,7 +84762,7 @@ __export(exports_server2, {
84741
84762
  TOOLS: () => TOOLS2
84742
84763
  });
84743
84764
  import { randomBytes as randomBytes18 } from "node:crypto";
84744
- import { existsSync as existsSync123 } from "node:fs";
84765
+ import { existsSync as existsSync124 } from "node:fs";
84745
84766
  function selfSocketPath() {
84746
84767
  return `/run/switchroom/hostd/${SELF_AGENT}/sock`;
84747
84768
  }
@@ -84768,7 +84789,7 @@ async function dispatchTool2(name, args) {
84768
84789
  return errorText2("hostd MCP: SWITCHROOM_AGENT_NAME env var is not set \u2014 cannot " + "determine which per-agent socket to talk to.");
84769
84790
  }
84770
84791
  const sockPath = selfSocketPath();
84771
- if (!existsSync123(sockPath)) {
84792
+ if (!existsSync124(sockPath)) {
84772
84793
  return errorText2(`hostd MCP: socket not bound at ${sockPath}. The host-control ` + `daemon is either not installed (run \`switchroom hostd install\`) ` + `or this agent isn't admin-flagged in switchroom.yaml. RFC C ` + `bind-mounts the per-agent socket only when host_control.enabled ` + `is true AND the agent has admin: true.`);
84773
84794
  }
84774
84795
  let req;
@@ -85019,13 +85040,13 @@ function resolveAuditLogPath() {
85019
85040
  if (process.env.HOSTD_AUDIT_LOG_PATH)
85020
85041
  return process.env.HOSTD_AUDIT_LOG_PATH;
85021
85042
  const bindMounted = "/host-home/.switchroom/host-control-audit.log";
85022
- if (existsSync123(bindMounted))
85043
+ if (existsSync124(bindMounted))
85023
85044
  return bindMounted;
85024
85045
  return defaultAuditLogPath2();
85025
85046
  }
85026
85047
  function getLastUpdateApplyStatus() {
85027
85048
  const path10 = resolveAuditLogPath();
85028
- if (!existsSync123(path10)) {
85049
+ if (!existsSync124(path10)) {
85029
85050
  return errorText2(`get_status: audit log not found at ${path10}. No update_apply has run yet?`);
85030
85051
  }
85031
85052
  let raw;
@@ -85993,11 +86014,11 @@ var init_test_agents = __esm(() => {
85993
86014
  });
85994
86015
 
85995
86016
  // src/litellm/header-passthrough-guard.ts
85996
- import { existsSync as existsSync126, readdirSync as readdirSync49 } from "node:fs";
86017
+ import { existsSync as existsSync127, readdirSync as readdirSync49 } from "node:fs";
85997
86018
  function discoverLiveLitellmConfigPath(opts) {
85998
86019
  const servicesDir = opts?.servicesDir ?? COOLIFY_SERVICES_DIR;
85999
86020
  const readdir2 = opts?.readdirFn ?? ((p) => readdirSync49(p));
86000
- const exists = opts?.existsFn ?? existsSync126;
86021
+ const exists = opts?.existsFn ?? existsSync127;
86001
86022
  let entries;
86002
86023
  try {
86003
86024
  entries = readdir2(servicesDir);
@@ -86215,12 +86236,12 @@ var init_passthrough_mount_guard = __esm(() => {
86215
86236
  });
86216
86237
 
86217
86238
  // src/fleet-health/litellm-config-sensor.ts
86218
- import { execFileSync as execFileSync37 } from "node:child_process";
86219
- import { readFileSync as readFileSync113, existsSync as existsSync127 } from "node:fs";
86220
- import { dirname as dirname54, join as join131 } from "node:path";
86239
+ import { execFileSync as execFileSync38 } from "node:child_process";
86240
+ import { readFileSync as readFileSync114, existsSync as existsSync128 } from "node:fs";
86241
+ import { dirname as dirname55, join as join131 } from "node:path";
86221
86242
  function resolveLiveLitellmPythonVersion() {
86222
86243
  try {
86223
- const ps = execFileSync37("docker", ["ps", "--format", "{{.Names}}\t{{.Image}}"], {
86244
+ const ps = execFileSync38("docker", ["ps", "--format", "{{.Names}}\t{{.Image}}"], {
86224
86245
  encoding: "utf-8",
86225
86246
  timeout: 5000,
86226
86247
  stdio: ["ignore", "pipe", "ignore"]
@@ -86232,7 +86253,7 @@ function resolveLiveLitellmPythonVersion() {
86232
86253
  const name = line.split("\t")[0]?.trim();
86233
86254
  if (!name)
86234
86255
  return null;
86235
- const lsOut = execFileSync37("docker", ["exec", name, "sh", "-c", "ls -d /app/.venv/lib/python*/ 2>/dev/null"], { encoding: "utf-8", timeout: 5000, stdio: ["ignore", "pipe", "ignore"] });
86256
+ const lsOut = execFileSync38("docker", ["exec", name, "sh", "-c", "ls -d /app/.venv/lib/python*/ 2>/dev/null"], { encoding: "utf-8", timeout: 5000, stdio: ["ignore", "pipe", "ignore"] });
86236
86257
  const m = lsOut.match(/python(\d+\.\d+)/);
86237
86258
  return m ? m[1] : null;
86238
86259
  } catch {
@@ -86249,8 +86270,8 @@ function resolveLitellmConfigPath(explicit, discoverFn = () => discoverLiveLitel
86249
86270
  }
86250
86271
  function scanLitellmConfig(opts = {}) {
86251
86272
  const path10 = resolveLitellmConfigPath(opts.path, opts.discoverFn);
86252
- const exists = opts.existsFn ?? existsSync127;
86253
- const read = opts.readFn ?? ((p) => readFileSync113(p, "utf-8"));
86273
+ const exists = opts.existsFn ?? existsSync128;
86274
+ const read = opts.readFn ?? ((p) => readFileSync114(p, "utf-8"));
86254
86275
  const log = opts.log ?? (() => {});
86255
86276
  const nowIso = opts.nowIso ?? new Date().toISOString();
86256
86277
  if (path10 === null) {
@@ -86301,7 +86322,7 @@ function scanLitellmConfig(opts = {}) {
86301
86322
  ts: nowIso
86302
86323
  });
86303
86324
  }
86304
- const composePath = join131(dirname54(path10), LIVE_COMPOSE_BASENAME);
86325
+ const composePath = join131(dirname55(path10), LIVE_COMPOSE_BASENAME);
86305
86326
  let composeText = null;
86306
86327
  if (exists(composePath)) {
86307
86328
  try {
@@ -86404,20 +86425,20 @@ __export(exports_scan, {
86404
86425
  ledgerPathForBase: () => ledgerPathForBase
86405
86426
  });
86406
86427
  import {
86407
- readFileSync as readFileSync114,
86428
+ readFileSync as readFileSync115,
86408
86429
  readdirSync as readdirSync50,
86409
- existsSync as existsSync128,
86410
- mkdirSync as mkdirSync73,
86411
- writeFileSync as writeFileSync55
86430
+ existsSync as existsSync129,
86431
+ mkdirSync as mkdirSync74,
86432
+ writeFileSync as writeFileSync56
86412
86433
  } from "node:fs";
86413
- import { resolve as resolve65, dirname as dirname55 } from "node:path";
86434
+ import { resolve as resolve65, dirname as dirname56 } from "node:path";
86414
86435
  import { homedir as homedir69 } from "node:os";
86415
86436
  function resolveSwitchroomBase(home2 = process.env.SWITCHROOM_HOME ?? process.env.HOME ?? homedir69()) {
86416
86437
  return resolve65(home2, ".switchroom");
86417
86438
  }
86418
86439
  function listAgents(base) {
86419
86440
  const dir = resolve65(base, "agents");
86420
- if (!existsSync128(dir))
86441
+ if (!existsSync129(dir))
86421
86442
  return [];
86422
86443
  try {
86423
86444
  return readdirSync50(dir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).sort();
@@ -86446,16 +86467,16 @@ function runScan(opts = {}) {
86446
86467
  let gwText = "";
86447
86468
  let sawArtifact = false;
86448
86469
  try {
86449
- if (existsSync128(turnsPath)) {
86450
- turnsText = readFileSync114(turnsPath, "utf-8");
86470
+ if (existsSync129(turnsPath)) {
86471
+ turnsText = readFileSync115(turnsPath, "utf-8");
86451
86472
  sawArtifact = true;
86452
86473
  }
86453
86474
  } catch (e) {
86454
86475
  log(`fleet-health: WARN skipping ${agent} turns.jsonl unreadable: ${String(e)}`);
86455
86476
  }
86456
86477
  try {
86457
- if (existsSync128(gwPath)) {
86458
- gwText = readFileSync114(gwPath, "utf-8");
86478
+ if (existsSync129(gwPath)) {
86479
+ gwText = readFileSync115(gwPath, "utf-8");
86459
86480
  sawArtifact = true;
86460
86481
  }
86461
86482
  } catch (e) {
@@ -86499,20 +86520,20 @@ function runScan(opts = {}) {
86499
86520
  function readLedgerIfPresent(base) {
86500
86521
  const path10 = ledgerPathForBase(base);
86501
86522
  try {
86502
- if (!existsSync128(path10))
86523
+ if (!existsSync129(path10))
86503
86524
  return null;
86504
- return JSON.parse(readFileSync114(path10, "utf-8"));
86525
+ return JSON.parse(readFileSync115(path10, "utf-8"));
86505
86526
  } catch {
86506
86527
  return null;
86507
86528
  }
86508
86529
  }
86509
86530
  function ledgerPathForBase(base) {
86510
- return fleetHealthLedgerPath(dirname55(base));
86531
+ return fleetHealthLedgerPath(dirname56(base));
86511
86532
  }
86512
86533
  function writeLedger(base, ledger) {
86513
86534
  const path10 = ledgerPathForBase(base);
86514
- mkdirSync73(dirname55(path10), { recursive: true });
86515
- writeFileSync55(path10, JSON.stringify(ledger, null, 2) + `
86535
+ mkdirSync74(dirname56(path10), { recursive: true });
86536
+ writeFileSync56(path10, JSON.stringify(ledger, null, 2) + `
86516
86537
  `, "utf-8");
86517
86538
  return path10;
86518
86539
  }
@@ -116745,9 +116766,9 @@ init_source();
116745
116766
  init_loader();
116746
116767
  init_lifecycle();
116747
116768
  init_compose_env();
116748
- import { existsSync as existsSync94, mkdirSync as mkdirSync54, readFileSync as readFileSync85, realpathSync as realpathSync8, statSync as statSync55, chownSync as chownSync12 } from "node:fs";
116769
+ import { existsSync as existsSync95, mkdirSync as mkdirSync55, readFileSync as readFileSync86, realpathSync as realpathSync8, statSync as statSync56, chownSync as chownSync13 } from "node:fs";
116749
116770
  import { spawnSync as spawnSync20 } from "node:child_process";
116750
- import { join as join98, dirname as dirname41 } from "node:path";
116771
+ import { join as join98, dirname as dirname42 } from "node:path";
116751
116772
  import { homedir as homedir51 } from "node:os";
116752
116773
 
116753
116774
  // src/cli/release-yaml.ts
@@ -117049,12 +117070,141 @@ function defaultSelfUpdateIO() {
117049
117070
  init_self_invoke();
117050
117071
  init_component_versions();
117051
117072
  init_install_cron();
117073
+
117074
+ // src/memory/mm-refresh-cron.ts
117075
+ import { execFileSync as execFileSync30 } from "node:child_process";
117076
+ import { chownSync as chownSync12, existsSync as existsSync93, mkdirSync as mkdirSync53, readFileSync as readFileSync84, renameSync as renameSync24, statSync as statSync55, writeFileSync as writeFileSync37 } from "node:fs";
117077
+ import { dirname as dirname40 } from "node:path";
117078
+ var CRON_PATH3 = "/etc/cron.d/mental-model-refresh";
117079
+ var CRON_SCHEDULE2 = "27 4 * * *";
117080
+ var CRON_LOG_PATH3 = "/var/log/mental-model-refresh.log";
117081
+ var LOGROTATE_PATH3 = "/etc/logrotate.d/mental-model-refresh";
117082
+ var CRON_LOCK_PATH3 = "/run/lock/mental-model-refresh.lock";
117083
+ function renderCron3(opts) {
117084
+ return `# switchroom mental-model-refresh \u2014 model-free stale-model refresh sweep (RFC P10).
117085
+ ` + `# Managed by \`switchroom mental-model-refresh --install-cron\`; edits are overwritten.
117086
+ ` + `# Exit 0 = swept (some refreshes may have failed; see log), 1 = the sweep could not complete.
117087
+ ` + `SHELL=/bin/sh
117088
+ ` + `PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
117089
+ ` + `${CRON_SCHEDULE2} ${opts.user} /usr/bin/flock -n ${CRON_LOCK_PATH3} ` + `${opts.binary} mental-model-refresh >> ${CRON_LOG_PATH3} 2>&1
117090
+ `;
117091
+ }
117092
+ function installCron3(opts) {
117093
+ const path7 = opts.path ?? CRON_PATH3;
117094
+ const content = renderCron3(opts);
117095
+ if (existsSync93(path7)) {
117096
+ try {
117097
+ if (readFileSync84(path7, "utf8") === content) {
117098
+ return { status: "unchanged", path: path7, content };
117099
+ }
117100
+ } catch {}
117101
+ }
117102
+ mkdirSync53(dirname40(path7), { recursive: true });
117103
+ const tmp = `${path7}.${process.pid}.tmp`;
117104
+ writeFileSync37(tmp, content, { mode: 420 });
117105
+ renameSync24(tmp, path7);
117106
+ return { status: "installed", path: path7, content };
117107
+ }
117108
+ var defaultIdResolver3 = (user) => {
117109
+ const uid = Number(execFileSync30("id", ["-u", user], { encoding: "utf8" }).trim());
117110
+ const gid = Number(execFileSync30("id", ["-g", user], { encoding: "utf8" }).trim());
117111
+ if (!Number.isInteger(uid) || !Number.isInteger(gid)) {
117112
+ throw new Error(`could not resolve uid/gid for user ${JSON.stringify(user)}`);
117113
+ }
117114
+ return { uid, gid };
117115
+ };
117116
+ function ensureLogFile3(opts) {
117117
+ const path7 = opts.path ?? CRON_LOG_PATH3;
117118
+ if (existsSync93(path7))
117119
+ return { status: "unchanged", path: path7 };
117120
+ const { uid, gid } = (opts.resolveIds ?? defaultIdResolver3)(opts.user);
117121
+ mkdirSync53(dirname40(path7), { recursive: true });
117122
+ writeFileSync37(path7, "", { mode: 420, flag: "a" });
117123
+ const isRoot = process.getuid?.() === 0;
117124
+ let alreadyOwned = false;
117125
+ try {
117126
+ const st = statSync55(path7);
117127
+ alreadyOwned = st.uid === uid && st.gid === gid;
117128
+ } catch {}
117129
+ if (isRoot && !alreadyOwned) {
117130
+ try {
117131
+ chownSync12(path7, uid, gid);
117132
+ } catch (e) {
117133
+ if (e.code !== "EPERM")
117134
+ throw e;
117135
+ }
117136
+ }
117137
+ return { status: "created", path: path7 };
117138
+ }
117139
+ function renderLogrotate3(opts) {
117140
+ return `${opts.logPath} {
117141
+ ` + ` weekly
117142
+ ` + ` rotate 8
117143
+ ` + ` compress
117144
+ ` + ` delaycompress
117145
+ ` + ` missingok
117146
+ ` + ` notifempty
117147
+ ` + ` copytruncate
117148
+ ` + ` su ${opts.user} ${opts.user}
117149
+ ` + `}
117150
+ `;
117151
+ }
117152
+ function installLogrotate3(opts) {
117153
+ const path7 = opts.path ?? LOGROTATE_PATH3;
117154
+ const content = renderLogrotate3({ logPath: opts.logPath ?? CRON_LOG_PATH3, user: opts.user });
117155
+ if (existsSync93(path7)) {
117156
+ try {
117157
+ if (readFileSync84(path7, "utf8") === content) {
117158
+ return { status: "unchanged", path: path7, content };
117159
+ }
117160
+ } catch {}
117161
+ }
117162
+ mkdirSync53(dirname40(path7), { recursive: true });
117163
+ const tmp = `${path7}.${process.pid}.tmp`;
117164
+ writeFileSync37(tmp, content, { mode: 420 });
117165
+ renameSync24(tmp, path7);
117166
+ return { status: "installed", path: path7, content };
117167
+ }
117168
+ function parseCronUser3(content) {
117169
+ for (const line of content.split(`
117170
+ `)) {
117171
+ const trimmed = line.trim();
117172
+ if (!trimmed || trimmed.startsWith("#"))
117173
+ continue;
117174
+ if (!trimmed.includes("mental-model-refresh"))
117175
+ continue;
117176
+ const fields = trimmed.split(/\s+/);
117177
+ if (fields.length >= 7)
117178
+ return fields[5];
117179
+ }
117180
+ return null;
117181
+ }
117182
+ function reconcileCron3(opts) {
117183
+ const path7 = opts.path ?? CRON_PATH3;
117184
+ if (!existsSync93(path7))
117185
+ return { status: "absent", path: path7 };
117186
+ let user = opts.fallbackUser;
117187
+ try {
117188
+ user = parseCronUser3(readFileSync84(path7, "utf8")) ?? opts.fallbackUser;
117189
+ } catch {}
117190
+ if (!user) {
117191
+ throw new Error(`cannot reconcile ${path7}: no cron-user parseable from the existing fragment and no fallback user available`);
117192
+ }
117193
+ const r = installCron3({ user, binary: opts.binary, path: path7 });
117194
+ return {
117195
+ status: r.status === "installed" ? "reconciled" : "unchanged",
117196
+ path: path7,
117197
+ content: r.content
117198
+ };
117199
+ }
117200
+
117201
+ // src/cli/update.ts
117052
117202
  init_install_cron2();
117053
117203
 
117054
117204
  // src/host-cli-self-heal/install-timer.ts
117055
117205
  import { spawnSync as spawnSync19 } from "node:child_process";
117056
- import { existsSync as existsSync93, mkdirSync as mkdirSync53, readFileSync as readFileSync84, renameSync as renameSync24, writeFileSync as writeFileSync37 } from "node:fs";
117057
- import { dirname as dirname40 } from "node:path";
117206
+ import { existsSync as existsSync94, mkdirSync as mkdirSync54, readFileSync as readFileSync85, renameSync as renameSync25, writeFileSync as writeFileSync38 } from "node:fs";
117207
+ import { dirname as dirname41 } from "node:path";
117058
117208
  var SERVICE_PATH = "/etc/systemd/system/switchroom-self-heal.service";
117059
117209
  var TIMER_PATH = "/etc/systemd/system/switchroom-self-heal.timer";
117060
117210
  var TIMER_UNIT = "switchroom-self-heal.timer";
@@ -117100,21 +117250,21 @@ function renderTimer() {
117100
117250
  `;
117101
117251
  }
117102
117252
  function writeUnitIdempotent(path7, content) {
117103
- if (existsSync93(path7)) {
117253
+ if (existsSync94(path7)) {
117104
117254
  try {
117105
- if (readFileSync84(path7, "utf8") === content)
117255
+ if (readFileSync85(path7, "utf8") === content)
117106
117256
  return "unchanged";
117107
117257
  } catch {}
117108
117258
  }
117109
- mkdirSync53(dirname40(path7), { recursive: true });
117259
+ mkdirSync54(dirname41(path7), { recursive: true });
117110
117260
  const tmp = `${path7}.${process.pid}.tmp`;
117111
- writeFileSync37(tmp, content, { mode: 420 });
117112
- renameSync24(tmp, path7);
117261
+ writeFileSync38(tmp, content, { mode: 420 });
117262
+ renameSync25(tmp, path7);
117113
117263
  return "written";
117114
117264
  }
117115
117265
  function homeFromPasswd2(user) {
117116
117266
  try {
117117
- for (const line of readFileSync84("/etc/passwd", "utf8").split(`
117267
+ for (const line of readFileSync85("/etc/passwd", "utf8").split(`
117118
117268
  `)) {
117119
117269
  const f = line.split(":");
117120
117270
  if (f[0] === user && f[5])
@@ -117131,7 +117281,7 @@ function resolveOperatorUser(env2) {
117131
117281
  }
117132
117282
  function installSelfHealTimer(deps = {}) {
117133
117283
  const env2 = deps.env ?? process.env;
117134
- const systemdBooted = deps.systemdBooted ?? (() => existsSync93(SYSTEMD_MARKER));
117284
+ const systemdBooted = deps.systemdBooted ?? (() => existsSync94(SYSTEMD_MARKER));
117135
117285
  const geteuid = deps.geteuid ?? (() => typeof process.geteuid === "function" ? process.geteuid() : undefined);
117136
117286
  const homeForUser = deps.homeForUser ?? homeFromPasswd2;
117137
117287
  const servicePath = deps.servicePath ?? SERVICE_PATH;
@@ -117193,16 +117343,16 @@ function installSelfHealTimer(deps = {}) {
117193
117343
  function defaultPersistPin(configPath) {
117194
117344
  return (pin) => {
117195
117345
  const path7 = configPath ?? findConfigFile();
117196
- const before = readFileSync85(path7, "utf8");
117346
+ const before = readFileSync86(path7, "utf8");
117197
117347
  const after = setReleasePinInConfig(before, pin);
117198
117348
  if (after === before)
117199
117349
  return;
117200
- writeConfigFileSync(path7, after, statSync55(path7).mode & 511);
117350
+ writeConfigFileSync(path7, after, statSync56(path7).mode & 511);
117201
117351
  try {
117202
117352
  if (typeof process.geteuid === "function" && process.geteuid() === 0) {
117203
117353
  const uid = resolveOperatorUid();
117204
117354
  if (uid !== undefined)
117205
- chownSync12(path7, uid, uid);
117355
+ chownSync13(path7, uid, uid);
117206
117356
  }
117207
117357
  } catch {}
117208
117358
  };
@@ -117214,16 +117364,16 @@ var PACKAGED_INSTALL_KINDS = new Set([
117214
117364
  "container"
117215
117365
  ]);
117216
117366
  function runningFromSwitchroomCheckout(scriptPath) {
117217
- let dir = dirname41(scriptPath);
117367
+ let dir = dirname42(scriptPath);
117218
117368
  for (let i2 = 0;i2 < 12; i2++) {
117219
- if (existsSync94(join98(dir, ".git"))) {
117369
+ if (existsSync95(join98(dir, ".git"))) {
117220
117370
  try {
117221
- const pkg = JSON.parse(readFileSync85(join98(dir, "package.json"), "utf-8"));
117371
+ const pkg = JSON.parse(readFileSync86(join98(dir, "package.json"), "utf-8"));
117222
117372
  if (pkg.name === "switchroom")
117223
117373
  return true;
117224
117374
  } catch {}
117225
117375
  }
117226
- const parent = dirname41(dir);
117376
+ const parent = dirname42(dir);
117227
117377
  if (parent === dir)
117228
117378
  break;
117229
117379
  dir = parent;
@@ -117285,7 +117435,7 @@ function planUpdate(opts) {
117285
117435
  bundleDir: import.meta.dirname,
117286
117436
  execPath: process.execPath,
117287
117437
  scriptPath,
117288
- inContainer: process.env.SWITCHROOM_HOSTD_CONTEXT === "1" || existsSync94("/.dockerenv")
117438
+ inContainer: process.env.SWITCHROOM_HOSTD_CONTEXT === "1" || existsSync95("/.dockerenv")
117289
117439
  });
117290
117440
  if (detection.kind !== "static-binary") {
117291
117441
  say(source_default.gray(` host CLI not self-updated: ${detection.reason}
@@ -117368,7 +117518,7 @@ function planUpdate(opts) {
117368
117518
  steps.push({
117369
117519
  name: "pull-images",
117370
117520
  description: "Pull broker / kernel / agent images from GHCR",
117371
- skipReason: opts.skipImages ? "--skip-images flag set" : !existsSync94(composePath) ? `compose file not found at ${composePath} (run \`switchroom apply --compose-only\` first)` : undefined,
117521
+ skipReason: opts.skipImages ? "--skip-images flag set" : !existsSync95(composePath) ? `compose file not found at ${composePath} (run \`switchroom apply --compose-only\` first)` : undefined,
117372
117522
  run: () => {
117373
117523
  const r = runner("docker", [
117374
117524
  "compose",
@@ -117441,6 +117591,34 @@ function planUpdate(opts) {
117441
117591
  `));
117442
117592
  } else {
117443
117593
  say(source_default.gray(` hindsight-watch cron already current at ${res.path}
117594
+ `));
117595
+ }
117596
+ }
117597
+ });
117598
+ steps.push({
117599
+ name: "reconcile-mental-model-refresh-cron",
117600
+ description: "Reconcile /etc/cron.d/mental-model-refresh (binary path / schedule / flags) on already-armed hosts \u2014 idempotent; no-op when unarmed or already current",
117601
+ skipReason: hostdContext ? "deferred (hostd-context): /etc/cron.d is on the host, not in the hostd container \u2014 finish host-side with `switchroom mental-model-refresh --install-cron`" : undefined,
117602
+ isHostdDeferred: hostdContext,
117603
+ run: () => {
117604
+ const say = opts.stdout ?? ((t) => process.stdout.write(t));
117605
+ const binary = process.env.SWITCHROOM_BINARY ?? "/usr/local/bin/switchroom";
117606
+ const fallbackUser = process.env.SUDO_USER ?? process.env.USER ?? process.env.LOGNAME;
117607
+ let res;
117608
+ try {
117609
+ res = reconcileCron3({ binary, fallbackUser });
117610
+ } catch (e) {
117611
+ say(source_default.yellow(` mental-model-refresh cron not reconciled: ${e.message}
117612
+ `));
117613
+ return;
117614
+ }
117615
+ if (res.status === "absent") {
117616
+ say(source_default.gray(" mental-model-refresh cron not armed \u2014 skipping reconcile " + "(arm with `switchroom mental-model-refresh --install-cron`)\n"));
117617
+ } else if (res.status === "reconciled") {
117618
+ say(source_default.green(` mental-model-refresh cron reconciled at ${res.path}
117619
+ `));
117620
+ } else {
117621
+ say(source_default.gray(` mental-model-refresh cron already current at ${res.path}
117444
117622
  `));
117445
117623
  }
117446
117624
  }
@@ -117603,7 +117781,7 @@ function planUpdate(opts) {
117603
117781
  bundleDir: import.meta.dirname,
117604
117782
  execPath: process.execPath,
117605
117783
  scriptPath,
117606
- inContainer: process.env.SWITCHROOM_HOSTD_CONTEXT === "1" || existsSync94("/.dockerenv")
117784
+ inContainer: process.env.SWITCHROOM_HOSTD_CONTEXT === "1" || existsSync95("/.dockerenv")
117607
117785
  });
117608
117786
  const detail = `no shipped skills/ payload found for this install ` + `(${detection.kind}; ${describeShippedAssetSearch(resolution)})`;
117609
117787
  if (PACKAGED_INSTALL_KINDS.has(detection.kind)) {
@@ -117617,7 +117795,7 @@ function planUpdate(opts) {
117617
117795
  }
117618
117796
  const source = resolution.path;
117619
117797
  try {
117620
- mkdirSync54(dirname41(dest), { recursive: true });
117798
+ mkdirSync55(dirname42(dest), { recursive: true });
117621
117799
  const r = syncBundledSkills({
117622
117800
  source,
117623
117801
  dest,
@@ -117643,10 +117821,10 @@ function planUpdate(opts) {
117643
117821
  if (opts.syncBundledSkillsFn)
117644
117822
  return;
117645
117823
  const dest = join98(homedir51(), ".switchroom", "skills", "_bundled");
117646
- if (!existsSync94(dest)) {
117824
+ if (!existsSync95(dest)) {
117647
117825
  return;
117648
117826
  }
117649
- const missing = getBuiltinDefaultSkillEntries().map((e) => e.key).filter((key) => !existsSync94(join98(dest, key)));
117827
+ const missing = getBuiltinDefaultSkillEntries().map((e) => e.key).filter((key) => !existsSync95(join98(dest, key)));
117650
117828
  if (missing.length > 0) {
117651
117829
  throw new Error(`verify-bundled-skills: builtin default skill(s) missing from the pool after sync: ` + `${missing.join(", ")}. These ship in the CLI package and must exist in ${dest}. ` + `This is a broken sync or a packaging regression \u2014 the pool is not converged.`);
117652
117830
  }
@@ -117681,7 +117859,7 @@ function planUpdate(opts) {
117681
117859
  description: "docker compose up -d --remove-orphans (recreates services with new images / compose)",
117682
117860
  run: () => {
117683
117861
  try {
117684
- const composeText = readFileSync85(composePath, "utf8");
117862
+ const composeText = readFileSync86(composePath, "utf8");
117685
117863
  const pf = validateBindSources(composeText);
117686
117864
  if (!pf.ok)
117687
117865
  throw new Error(formatPreflightError(pf));
@@ -117756,14 +117934,14 @@ function defaultStatusProbe(composePath) {
117756
117934
  } catch {}
117757
117935
  if (scriptPath) {
117758
117936
  try {
117759
- cliBuiltAt = new Date(statSync55(scriptPath).mtimeMs).toISOString();
117937
+ cliBuiltAt = new Date(statSync56(scriptPath).mtimeMs).toISOString();
117760
117938
  } catch {}
117761
- let dir = dirname41(scriptPath);
117939
+ let dir = dirname42(scriptPath);
117762
117940
  for (let i2 = 0;i2 < 8; i2++) {
117763
117941
  const pkgPath = join98(dir, "package.json");
117764
- if (existsSync94(pkgPath)) {
117942
+ if (existsSync95(pkgPath)) {
117765
117943
  try {
117766
- const pkg = JSON.parse(readFileSync85(pkgPath, "utf-8"));
117944
+ const pkg = JSON.parse(readFileSync86(pkgPath, "utf-8"));
117767
117945
  if (typeof pkg.version === "string")
117768
117946
  cliVersion = pkg.version;
117769
117947
  } catch (err) {
@@ -117771,7 +117949,7 @@ function defaultStatusProbe(composePath) {
117771
117949
  }
117772
117950
  break;
117773
117951
  }
117774
- const parent = dirname41(dir);
117952
+ const parent = dirname42(dir);
117775
117953
  if (parent === dir)
117776
117954
  break;
117777
117955
  dir = parent;
@@ -117784,7 +117962,7 @@ function defaultStatusProbe(composePath) {
117784
117962
  warnings.push("could not resolve CLI version (no package.json found above the resolved script path)");
117785
117963
  }
117786
117964
  const services = [];
117787
- if (!existsSync94(composePath)) {
117965
+ if (!existsSync95(composePath)) {
117788
117966
  warnings.push(`compose file not found at ${composePath}; service status unknown`);
117789
117967
  return { cliVersion, cliBuiltAt, services, warnings };
117790
117968
  }
@@ -118047,22 +118225,22 @@ function registerUpdateCommand(program3) {
118047
118225
  // src/cli/rollout.ts
118048
118226
  init_helpers();
118049
118227
  import { spawnSync as spawnSync22 } from "node:child_process";
118050
- import { readFileSync as readFileSync87, chownSync as chownSync13, statSync as statSync58 } from "node:fs";
118228
+ import { readFileSync as readFileSync88, chownSync as chownSync14, statSync as statSync59 } from "node:fs";
118051
118229
  import { homedir as homedir53 } from "node:os";
118052
118230
 
118053
118231
  // src/cli/rollout-pin-journal.ts
118054
118232
  import {
118055
- existsSync as existsSync95,
118056
- readFileSync as readFileSync86,
118057
- writeFileSync as writeFileSync38,
118058
- renameSync as renameSync25,
118233
+ existsSync as existsSync96,
118234
+ readFileSync as readFileSync87,
118235
+ writeFileSync as writeFileSync39,
118236
+ renameSync as renameSync26,
118059
118237
  unlinkSync as unlinkSync19,
118060
- statSync as statSync56,
118061
- mkdirSync as mkdirSync55
118238
+ statSync as statSync57,
118239
+ mkdirSync as mkdirSync56
118062
118240
  } from "node:fs";
118063
118241
  import { homedir as homedir52 } from "node:os";
118064
118242
  import { createHash as createHash17 } from "node:crypto";
118065
- import { join as join99, basename as basename9, resolve as resolve50, dirname as dirname42 } from "node:path";
118243
+ import { join as join99, basename as basename9, resolve as resolve50, dirname as dirname43 } from "node:path";
118066
118244
  init_flock();
118067
118245
  var PIN_JOURNAL_MAX_AGE_MS = 15 * 60 * 1000;
118068
118246
  var STATE_DIR_NAME = ".switchroom";
@@ -118071,7 +118249,7 @@ function pinJournalDir(configPath) {
118071
118249
  if (override && override.trim().length > 0)
118072
118250
  return override.trim();
118073
118251
  if (configPath) {
118074
- const dir = dirname42(resolve50(configPath));
118252
+ const dir = dirname43(resolve50(configPath));
118075
118253
  if (basename9(dir) === STATE_DIR_NAME)
118076
118254
  return dir;
118077
118255
  }
@@ -118114,9 +118292,9 @@ function readPinJournal(configPath, warn = (m) => process.stderr.write(m)) {
118114
118292
  const p = pinJournalPath(configPath);
118115
118293
  let raw;
118116
118294
  try {
118117
- raw = readFileSync86(p, "utf8");
118295
+ raw = readFileSync87(p, "utf8");
118118
118296
  } catch (e) {
118119
- if (existsSync95(p)) {
118297
+ if (existsSync96(p)) {
118120
118298
  warn(`\u26a0\ufe0f rollout pin journal: ${p} exists but could not be read ` + `(${e.message}). A provisional \`release.pin\` may be ` + `uncommitted \u2014 verify it host-side before the next reconcile.
118121
118299
  `);
118122
118300
  }
@@ -118167,7 +118345,7 @@ function beginPinPersist(configPath, pin, opts = {}) {
118167
118345
  warn(`\u26a0\ufe0f rollout pin journal: overwriting an ABANDONED journal at ${p} ` + `(pid ${existing.pid} recorded ${existing.at}, provisional pin ` + `${existing.pin}). Its roll never committed or reverted; \`release.pin\` ` + `in ${configPath} may still name that unproven build \u2014 verify it.
118168
118346
  `);
118169
118347
  }
118170
- const priorPin = getReleasePinFromConfig(readFileSync86(configPath, "utf8"));
118348
+ const priorPin = getReleasePinFromConfig(readFileSync87(configPath, "utf8"));
118171
118349
  const journal = {
118172
118350
  v: 1,
118173
118351
  configPath,
@@ -118176,10 +118354,10 @@ function beginPinPersist(configPath, pin, opts = {}) {
118176
118354
  pid: process.pid,
118177
118355
  at: new Date().toISOString()
118178
118356
  };
118179
- mkdirSync55(dirname42(p), { recursive: true });
118357
+ mkdirSync56(dirname43(p), { recursive: true });
118180
118358
  const tmp = `${p}.${process.pid}.tmp`;
118181
- writeFileSync38(tmp, JSON.stringify(journal), { encoding: "utf8", mode: 384 });
118182
- renameSync25(tmp, p);
118359
+ writeFileSync39(tmp, JSON.stringify(journal), { encoding: "utf8", mode: 384 });
118360
+ renameSync26(tmp, p);
118183
118361
  return journal;
118184
118362
  }
118185
118363
  function commitPinPersist(configPath) {
@@ -118188,7 +118366,7 @@ function commitPinPersist(configPath) {
118188
118366
  unlinkSync19(p);
118189
118367
  return null;
118190
118368
  } catch (e) {
118191
- if (!existsSync95(p))
118369
+ if (!existsSync96(p))
118192
118370
  return null;
118193
118371
  return `rollout pin journal: FAILED to clear ${p} after a SUCCESSFUL roll ` + `(${e.message}). Delete it host-side \u2014 while it exists, ` + `recovery may revert a proven \`release.pin\`.`;
118194
118372
  }
@@ -118210,16 +118388,16 @@ function rollbackPinPersist(configPath, opts = {}) {
118210
118388
  }
118211
118389
  }
118212
118390
  try {
118213
- const current = readFileSync86(configPath, "utf8");
118391
+ const current = readFileSync87(configPath, "utf8");
118214
118392
  const next = journal.priorPin ? setReleasePinInConfig(current, journal.priorPin) : deleteReleasePinInConfig(current);
118215
118393
  let mode = 384;
118216
118394
  try {
118217
- mode = statSync56(configPath).mode & 511;
118395
+ mode = statSync57(configPath).mode & 511;
118218
118396
  } catch {}
118219
118397
  if (opts.writeConfig) {
118220
118398
  opts.writeConfig(configPath, next, mode);
118221
118399
  } else {
118222
- writeFileSync38(configPath, next, { encoding: "utf8", mode });
118400
+ writeFileSync39(configPath, next, { encoding: "utf8", mode });
118223
118401
  }
118224
118402
  } catch (e) {
118225
118403
  return {
@@ -118264,8 +118442,8 @@ init_host_cli_stamp();
118264
118442
 
118265
118443
  // src/cli/host-cli-upgrade.ts
118266
118444
  init_self_update();
118267
- import { lchownSync, lstatSync as lstatSync14, readdirSync as readdirSync33, statSync as statSync57 } from "node:fs";
118268
- import { basename as basename10, dirname as dirname43, join as join100 } from "node:path";
118445
+ import { lchownSync, lstatSync as lstatSync14, readdirSync as readdirSync33, statSync as statSync58 } from "node:fs";
118446
+ import { basename as basename10, dirname as dirname44, join as join100 } from "node:path";
118269
118447
  init_shipped_assets();
118270
118448
  var HOST_CLI_UPGRADE_SENTINEL = "SWITCHROOM_HOST_CLI_UPGRADE:";
118271
118449
  function encodeHostCliUpgradeResult(r) {
@@ -118301,7 +118479,7 @@ function defaultIo() {
118301
118479
  return {
118302
118480
  isFile: (p) => {
118303
118481
  try {
118304
- return statSync57(p).isFile();
118482
+ return statSync58(p).isFile();
118305
118483
  } catch {
118306
118484
  return false;
118307
118485
  }
@@ -118401,8 +118579,8 @@ async function runHostCliUpgrade(opts, io = defaultIo(), log = () => {}) {
118401
118579
  const installRoot = payloadInstallRoot(binary);
118402
118580
  const failures = handBackOwnership([
118403
118581
  binary,
118404
- join100(dirname43(binary), ".switchroom-versions"),
118405
- dirname43(installRoot),
118582
+ join100(dirname44(binary), ".switchroom-versions"),
118583
+ dirname44(installRoot),
118406
118584
  installRoot,
118407
118585
  payloadVersionDir(installRoot, pin)
118408
118586
  ], priorOwner, io);
@@ -119202,7 +119380,7 @@ function createRolloutDeps(params) {
119202
119380
  if (typeof process.geteuid === "function" && process.geteuid() === 0) {
119203
119381
  const uid = resolveOperatorUid();
119204
119382
  if (uid !== undefined) {
119205
- chownSync13(path7, uid, uid);
119383
+ chownSync14(path7, uid, uid);
119206
119384
  } else if (hostdCtx) {
119207
119385
  warn("\u26a0\ufe0f rollout (hostd path): could not resolve operator uid; " + "skipping config chown-back to avoid leaving switchroom.yaml " + "root-owned. Verify ownership host-side if other yaml verbs " + `EACCES.
119208
119386
  `);
@@ -119261,12 +119439,12 @@ function createRolloutDeps(params) {
119261
119439
  return stamp ? { hostCli: stamp } : {};
119262
119440
  })(),
119263
119441
  persistPin: (pin) => {
119264
- const before = readFileSync87(configPath, "utf8");
119442
+ const before = readFileSync88(configPath, "utf8");
119265
119443
  const after = setReleasePinInConfig(before, pin);
119266
119444
  if (after === before)
119267
119445
  return false;
119268
119446
  beginPinPersist(configPath, pin);
119269
- writeConfigPreservingOwnership(configPath, after, statSync58(configPath).mode & 511);
119447
+ writeConfigPreservingOwnership(configPath, after, statSync59(configPath).mode & 511);
119270
119448
  return true;
119271
119449
  },
119272
119450
  commitPin: () => {
@@ -119550,8 +119728,8 @@ init_helpers();
119550
119728
  init_lifecycle();
119551
119729
  init_resolve_version();
119552
119730
  import { execSync as execSync3 } from "node:child_process";
119553
- import { existsSync as existsSync96, readFileSync as readFileSync88 } from "node:fs";
119554
- import { dirname as dirname44, join as join101 } from "node:path";
119731
+ import { existsSync as existsSync97, readFileSync as readFileSync89 } from "node:fs";
119732
+ import { dirname as dirname45, join as join101 } from "node:path";
119555
119733
  function getClaudeCodeVersion() {
119556
119734
  try {
119557
119735
  const out = execSync3("claude --version 2>/dev/null", {
@@ -119602,15 +119780,15 @@ function locateSwitchroomInstallDir() {
119602
119780
  let dir = import.meta.dirname;
119603
119781
  for (let i2 = 0;i2 < 10 && dir && dir !== "/"; i2++) {
119604
119782
  const pkgPath = join101(dir, "package.json");
119605
- if (existsSync96(pkgPath)) {
119783
+ if (existsSync97(pkgPath)) {
119606
119784
  try {
119607
- const pkg = JSON.parse(readFileSync88(pkgPath, "utf-8"));
119608
- if (pkg.name === "switchroom" && existsSync96(join101(dir, ".git"))) {
119785
+ const pkg = JSON.parse(readFileSync89(pkgPath, "utf-8"));
119786
+ if (pkg.name === "switchroom" && existsSync97(join101(dir, ".git"))) {
119609
119787
  return dir;
119610
119788
  }
119611
119789
  } catch {}
119612
119790
  }
119613
- dir = dirname44(dir);
119791
+ dir = dirname45(dir);
119614
119792
  }
119615
119793
  return null;
119616
119794
  }
@@ -119786,9 +119964,9 @@ init_merge();
119786
119964
 
119787
119965
  // src/agents/session-retention.ts
119788
119966
  import {
119789
- existsSync as existsSync97,
119967
+ existsSync as existsSync98,
119790
119968
  readdirSync as readdirSync34,
119791
- statSync as statSync59,
119969
+ statSync as statSync60,
119792
119970
  unlinkSync as unlinkSync20
119793
119971
  } from "node:fs";
119794
119972
  import { join as join102 } from "node:path";
@@ -119797,7 +119975,7 @@ var DEFAULT_SESSION_RETENTION_MAX_AGE_DAYS = 30;
119797
119975
  var MIN_KEEP = 2;
119798
119976
  function collectSessionJsonl(claudeConfigDir) {
119799
119977
  const projects = join102(claudeConfigDir, "projects");
119800
- if (!existsSync97(projects))
119978
+ if (!existsSync98(projects))
119801
119979
  return [];
119802
119980
  const found = [];
119803
119981
  const walk2 = (dir) => {
@@ -119811,7 +119989,7 @@ function collectSessionJsonl(claudeConfigDir) {
119811
119989
  const full = join102(dir, name);
119812
119990
  let st;
119813
119991
  try {
119814
- st = statSync59(full);
119992
+ st = statSync60(full);
119815
119993
  } catch {
119816
119994
  continue;
119817
119995
  }
@@ -119929,15 +120107,15 @@ function registerHandoffCommand(program3) {
119929
120107
  // src/issues/store.ts
119930
120108
  import {
119931
120109
  closeSync as closeSync19,
119932
- existsSync as existsSync98,
119933
- mkdirSync as mkdirSync56,
120110
+ existsSync as existsSync99,
120111
+ mkdirSync as mkdirSync57,
119934
120112
  openSync as openSync19,
119935
120113
  readdirSync as readdirSync35,
119936
- readFileSync as readFileSync89,
119937
- renameSync as renameSync26,
119938
- statSync as statSync60,
120114
+ readFileSync as readFileSync90,
120115
+ renameSync as renameSync27,
120116
+ statSync as statSync61,
119939
120117
  unlinkSync as unlinkSync21,
119940
- writeFileSync as writeFileSync39,
120118
+ writeFileSync as writeFileSync40,
119941
120119
  writeSync as writeSync9
119942
120120
  } from "node:fs";
119943
120121
  import { join as join103 } from "node:path";
@@ -119968,11 +120146,11 @@ var ISSUES_FILE = "issues.jsonl";
119968
120146
  var ISSUES_LOCK = "issues.lock";
119969
120147
  function readAll(stateDir) {
119970
120148
  const path7 = join103(stateDir, ISSUES_FILE);
119971
- if (!existsSync98(path7))
120149
+ if (!existsSync99(path7))
119972
120150
  return [];
119973
120151
  let raw;
119974
120152
  try {
119975
- raw = readFileSync89(path7, "utf-8");
120153
+ raw = readFileSync90(path7, "utf-8");
119976
120154
  } catch {
119977
120155
  return [];
119978
120156
  }
@@ -120045,7 +120223,7 @@ function record(stateDir, input, nowFn = Date.now) {
120045
120223
  });
120046
120224
  }
120047
120225
  function resolve53(stateDir, fingerprint, nowFn = Date.now) {
120048
- if (!existsSync98(join103(stateDir, ISSUES_FILE)))
120226
+ if (!existsSync99(join103(stateDir, ISSUES_FILE)))
120049
120227
  return 0;
120050
120228
  return withLock(stateDir, () => {
120051
120229
  const all = readAll(stateDir);
@@ -120063,7 +120241,7 @@ function resolve53(stateDir, fingerprint, nowFn = Date.now) {
120063
120241
  });
120064
120242
  }
120065
120243
  function resolveAllBySource(stateDir, source, nowFn = Date.now) {
120066
- if (!existsSync98(join103(stateDir, ISSUES_FILE)))
120244
+ if (!existsSync99(join103(stateDir, ISSUES_FILE)))
120067
120245
  return 0;
120068
120246
  return withLock(stateDir, () => {
120069
120247
  const all = readAll(stateDir);
@@ -120081,7 +120259,7 @@ function resolveAllBySource(stateDir, source, nowFn = Date.now) {
120081
120259
  });
120082
120260
  }
120083
120261
  function prune(stateDir, opts = {}) {
120084
- if (!existsSync98(join103(stateDir, ISSUES_FILE)))
120262
+ if (!existsSync99(join103(stateDir, ISSUES_FILE)))
120085
120263
  return 0;
120086
120264
  return withLock(stateDir, () => {
120087
120265
  const all = readAll(stateDir);
@@ -120111,7 +120289,7 @@ function prune(stateDir, opts = {}) {
120111
120289
  });
120112
120290
  }
120113
120291
  function ensureDir2(stateDir) {
120114
- mkdirSync56(stateDir, { recursive: true });
120292
+ mkdirSync57(stateDir, { recursive: true });
120115
120293
  }
120116
120294
  function writeAll(stateDir, events) {
120117
120295
  const path7 = join103(stateDir, ISSUES_FILE);
@@ -120120,8 +120298,8 @@ function writeAll(stateDir, events) {
120120
120298
  const body = events.length === 0 ? "" : events.map((e) => JSON.stringify(e)).join(`
120121
120299
  `) + `
120122
120300
  `;
120123
- writeFileSync39(tmp, body, "utf-8");
120124
- renameSync26(tmp, path7);
120301
+ writeFileSync40(tmp, body, "utf-8");
120302
+ renameSync27(tmp, path7);
120125
120303
  }
120126
120304
  var ORPHAN_TMP_TTL_MS = 60000;
120127
120305
  var TMP_PREFIX = `${ISSUES_FILE}.tmp-`;
@@ -120138,7 +120316,7 @@ function sweepOrphanTmpFiles(stateDir) {
120138
120316
  continue;
120139
120317
  const tmpPath = join103(stateDir, entry);
120140
120318
  try {
120141
- const stat = statSync60(tmpPath);
120319
+ const stat = statSync61(tmpPath);
120142
120320
  if (stat.mtimeMs < cutoff) {
120143
120321
  unlinkSync21(tmpPath);
120144
120322
  }
@@ -120183,7 +120361,7 @@ function withLock(stateDir, fn) {
120183
120361
  function tryStealStaleLock(lockPath) {
120184
120362
  let pidStr;
120185
120363
  try {
120186
- pidStr = readFileSync89(lockPath, "utf-8").trim();
120364
+ pidStr = readFileSync90(lockPath, "utf-8").trim();
120187
120365
  } catch {
120188
120366
  return true;
120189
120367
  }
@@ -120431,22 +120609,22 @@ function relTime(deltaMs) {
120431
120609
 
120432
120610
  // src/cli/deps.ts
120433
120611
  init_source();
120434
- import { existsSync as existsSync101 } from "node:fs";
120612
+ import { existsSync as existsSync102 } from "node:fs";
120435
120613
  import { homedir as homedir56 } from "node:os";
120436
120614
  import { join as join106, resolve as resolve54 } from "node:path";
120437
120615
 
120438
120616
  // src/deps/python.ts
120439
120617
  import { createHash as createHash18 } from "node:crypto";
120440
120618
  import {
120441
- existsSync as existsSync99,
120442
- mkdirSync as mkdirSync57,
120443
- readFileSync as readFileSync90,
120619
+ existsSync as existsSync100,
120620
+ mkdirSync as mkdirSync58,
120621
+ readFileSync as readFileSync91,
120444
120622
  rmSync as rmSync19,
120445
- writeFileSync as writeFileSync40
120623
+ writeFileSync as writeFileSync41
120446
120624
  } from "node:fs";
120447
- import { dirname as dirname45, join as join104 } from "node:path";
120625
+ import { dirname as dirname46, join as join104 } from "node:path";
120448
120626
  import { homedir as homedir54 } from "node:os";
120449
- import { execFileSync as execFileSync30 } from "node:child_process";
120627
+ import { execFileSync as execFileSync31 } from "node:child_process";
120450
120628
 
120451
120629
  class PythonEnvError extends Error {
120452
120630
  stderr;
@@ -120460,13 +120638,13 @@ function defaultPythonCacheRoot() {
120460
120638
  return join104(homedir54(), ".switchroom", "deps", "python");
120461
120639
  }
120462
120640
  function hashFile(path7) {
120463
- return createHash18("sha256").update(readFileSync90(path7)).digest("hex");
120641
+ return createHash18("sha256").update(readFileSync91(path7)).digest("hex");
120464
120642
  }
120465
120643
  function ensurePythonEnv(opts) {
120466
120644
  const { skillName, requirementsPath, force = false } = opts;
120467
120645
  const cacheRoot = opts.cacheRoot ?? defaultPythonCacheRoot();
120468
120646
  const hostPython = opts.pythonBin ?? "python3";
120469
- if (!existsSync99(requirementsPath)) {
120647
+ if (!existsSync100(requirementsPath)) {
120470
120648
  throw new PythonEnvError(`requirements file not found: ${requirementsPath}`);
120471
120649
  }
120472
120650
  const venvDir = join104(cacheRoot, skillName);
@@ -120475,8 +120653,8 @@ function ensurePythonEnv(opts) {
120475
120653
  const pythonBin = join104(binDir, "python");
120476
120654
  const pipBin = join104(binDir, "pip");
120477
120655
  const targetHash = hashFile(requirementsPath);
120478
- if (!force && existsSync99(stampPath) && existsSync99(pythonBin)) {
120479
- const existingHash = readFileSync90(stampPath, "utf8").trim();
120656
+ if (!force && existsSync100(stampPath) && existsSync100(pythonBin)) {
120657
+ const existingHash = readFileSync91(stampPath, "utf8").trim();
120480
120658
  if (existingHash === targetHash) {
120481
120659
  return {
120482
120660
  skillName,
@@ -120488,12 +120666,12 @@ function ensurePythonEnv(opts) {
120488
120666
  };
120489
120667
  }
120490
120668
  }
120491
- if (existsSync99(venvDir)) {
120669
+ if (existsSync100(venvDir)) {
120492
120670
  rmSync19(venvDir, { recursive: true, force: true });
120493
120671
  }
120494
- mkdirSync57(dirname45(venvDir), { recursive: true });
120672
+ mkdirSync58(dirname46(venvDir), { recursive: true });
120495
120673
  try {
120496
- execFileSync30(hostPython, ["-m", "venv", venvDir], { stdio: "pipe" });
120674
+ execFileSync31(hostPython, ["-m", "venv", venvDir], { stdio: "pipe" });
120497
120675
  } catch (err) {
120498
120676
  const e = err;
120499
120677
  throw new PythonEnvError(`Failed to create venv for skill "${skillName}" with ${hostPython}: ${e.message}`, e.stderr?.toString());
@@ -120505,12 +120683,12 @@ function ensurePythonEnv(opts) {
120505
120683
  delete childEnv.PIP_TARGET;
120506
120684
  delete childEnv.PIP_PREFIX;
120507
120685
  delete childEnv.PYTHONUSERBASE;
120508
- execFileSync30(pipBin, ["install", "--disable-pip-version-check", "-r", requirementsPath], { stdio: "pipe", env: childEnv });
120686
+ execFileSync31(pipBin, ["install", "--disable-pip-version-check", "-r", requirementsPath], { stdio: "pipe", env: childEnv });
120509
120687
  } catch (err) {
120510
120688
  const e = err;
120511
120689
  throw new PythonEnvError(`Failed to install requirements for skill "${skillName}": ${e.message}`, e.stderr?.toString());
120512
120690
  }
120513
- writeFileSync40(stampPath, targetHash + `
120691
+ writeFileSync41(stampPath, targetHash + `
120514
120692
  `);
120515
120693
  return {
120516
120694
  skillName,
@@ -120526,15 +120704,15 @@ function ensurePythonEnv(opts) {
120526
120704
  import { createHash as createHash19 } from "node:crypto";
120527
120705
  import {
120528
120706
  copyFileSync as copyFileSync13,
120529
- existsSync as existsSync100,
120530
- mkdirSync as mkdirSync58,
120531
- readFileSync as readFileSync91,
120707
+ existsSync as existsSync101,
120708
+ mkdirSync as mkdirSync59,
120709
+ readFileSync as readFileSync92,
120532
120710
  rmSync as rmSync20,
120533
- writeFileSync as writeFileSync41
120711
+ writeFileSync as writeFileSync42
120534
120712
  } from "node:fs";
120535
- import { dirname as dirname46, join as join105 } from "node:path";
120713
+ import { dirname as dirname47, join as join105 } from "node:path";
120536
120714
  import { homedir as homedir55 } from "node:os";
120537
- import { execFileSync as execFileSync31 } from "node:child_process";
120715
+ import { execFileSync as execFileSync32 } from "node:child_process";
120538
120716
 
120539
120717
  class NodeEnvError extends Error {
120540
120718
  stderr;
@@ -120559,20 +120737,20 @@ function defaultNodeCacheRoot() {
120559
120737
  return join105(homedir55(), ".switchroom", "deps", "node");
120560
120738
  }
120561
120739
  function hashDepInputs(packageJsonPath) {
120562
- const sourceDir = dirname46(packageJsonPath);
120740
+ const sourceDir = dirname47(packageJsonPath);
120563
120741
  const hasher = createHash19("sha256");
120564
120742
  hasher.update(`package.json
120565
120743
  `);
120566
- hasher.update(readFileSync91(packageJsonPath));
120744
+ hasher.update(readFileSync92(packageJsonPath));
120567
120745
  for (const lockName of ALL_LOCKFILES) {
120568
120746
  const lockPath = join105(sourceDir, lockName);
120569
- if (existsSync100(lockPath)) {
120747
+ if (existsSync101(lockPath)) {
120570
120748
  hasher.update(`
120571
120749
  `);
120572
120750
  hasher.update(lockName);
120573
120751
  hasher.update(`
120574
120752
  `);
120575
- hasher.update(readFileSync91(lockPath));
120753
+ hasher.update(readFileSync92(lockPath));
120576
120754
  }
120577
120755
  }
120578
120756
  return hasher.digest("hex");
@@ -120581,17 +120759,17 @@ function ensureNodeEnv(opts) {
120581
120759
  const { skillName, packageJsonPath, force = false } = opts;
120582
120760
  const cacheRoot = opts.cacheRoot ?? defaultNodeCacheRoot();
120583
120761
  const installer = opts.installer ?? "bun";
120584
- if (!existsSync100(packageJsonPath)) {
120762
+ if (!existsSync101(packageJsonPath)) {
120585
120763
  throw new NodeEnvError(`package.json not found: ${packageJsonPath}`);
120586
120764
  }
120587
- const sourceDir = dirname46(packageJsonPath);
120765
+ const sourceDir = dirname47(packageJsonPath);
120588
120766
  const envDir = join105(cacheRoot, skillName);
120589
120767
  const stampPath = join105(envDir, ".package.sha256");
120590
120768
  const nodeModulesDir = join105(envDir, "node_modules");
120591
120769
  const binDir = join105(nodeModulesDir, ".bin");
120592
120770
  const targetHash = hashDepInputs(packageJsonPath);
120593
- if (!force && existsSync100(stampPath) && existsSync100(nodeModulesDir)) {
120594
- const existingHash = readFileSync91(stampPath, "utf8").trim();
120771
+ if (!force && existsSync101(stampPath) && existsSync101(nodeModulesDir)) {
120772
+ const existingHash = readFileSync92(stampPath, "utf8").trim();
120595
120773
  if (existingHash === targetHash) {
120596
120774
  return {
120597
120775
  skillName,
@@ -120602,15 +120780,15 @@ function ensureNodeEnv(opts) {
120602
120780
  };
120603
120781
  }
120604
120782
  }
120605
- if (existsSync100(envDir)) {
120783
+ if (existsSync101(envDir)) {
120606
120784
  rmSync20(envDir, { recursive: true, force: true });
120607
120785
  }
120608
- mkdirSync58(envDir, { recursive: true });
120786
+ mkdirSync59(envDir, { recursive: true });
120609
120787
  copyFileSync13(packageJsonPath, join105(envDir, "package.json"));
120610
120788
  let copiedLockfile = false;
120611
120789
  for (const lockName of LOCKFILES_FOR[installer]) {
120612
120790
  const lockPath = join105(sourceDir, lockName);
120613
- if (existsSync100(lockPath)) {
120791
+ if (existsSync101(lockPath)) {
120614
120792
  copyFileSync13(lockPath, join105(envDir, lockName));
120615
120793
  copiedLockfile = true;
120616
120794
  }
@@ -120618,16 +120796,16 @@ function ensureNodeEnv(opts) {
120618
120796
  try {
120619
120797
  if (installer === "bun") {
120620
120798
  const args = copiedLockfile ? ["install", "--frozen-lockfile"] : ["install"];
120621
- execFileSync31("bun", args, { cwd: envDir, stdio: "pipe" });
120799
+ execFileSync32("bun", args, { cwd: envDir, stdio: "pipe" });
120622
120800
  } else {
120623
120801
  const args = copiedLockfile ? ["ci"] : ["install"];
120624
- execFileSync31("npm", args, { cwd: envDir, stdio: "pipe" });
120802
+ execFileSync32("npm", args, { cwd: envDir, stdio: "pipe" });
120625
120803
  }
120626
120804
  } catch (err) {
120627
120805
  const e = err;
120628
120806
  throw new NodeEnvError(`Failed to install node deps for skill "${skillName}" with ${installer}: ${e.message}`, e.stderr?.toString());
120629
120807
  }
120630
- writeFileSync41(stampPath, targetHash + `
120808
+ writeFileSync42(stampPath, targetHash + `
120631
120809
  `);
120632
120810
  return {
120633
120811
  skillName,
@@ -120646,22 +120824,22 @@ function registerDepsCommand(program3) {
120646
120824
  const deps = program3.command("deps").description("Manage cached per-skill dependency environments");
120647
120825
  deps.command("rebuild <skill>").description("Rebuild the Python venv and/or Node node_modules cache for a skill").option("-p, --python", "Rebuild only the Python env").option("-n, --node", "Rebuild only the Node env").action(async (skill, opts) => {
120648
120826
  const skillsRoot = builtinSkillsRoot();
120649
- if (!existsSync101(skillsRoot)) {
120827
+ if (!existsSync102(skillsRoot)) {
120650
120828
  console.error(source_default.red(`Bundled skills pool dir not found at ${skillsRoot} \u2014 run \`switchroom update\` to install it.`));
120651
120829
  process.exit(1);
120652
120830
  }
120653
120831
  const skillDir = join106(skillsRoot, skill);
120654
- if (!existsSync101(skillDir)) {
120832
+ if (!existsSync102(skillDir)) {
120655
120833
  console.error(source_default.red(`Unknown skill: ${skill} (no dir at ${skillDir})`));
120656
120834
  process.exit(1);
120657
120835
  }
120658
120836
  const requirementsPath = join106(skillDir, "requirements.txt");
120659
120837
  const packageJsonPath = join106(skillDir, "package.json");
120660
- const wantPython = opts.python ?? (!opts.python && !opts.node && existsSync101(requirementsPath));
120661
- const wantNode = opts.node ?? (!opts.python && !opts.node && existsSync101(packageJsonPath));
120838
+ const wantPython = opts.python ?? (!opts.python && !opts.node && existsSync102(requirementsPath));
120839
+ const wantNode = opts.node ?? (!opts.python && !opts.node && existsSync102(packageJsonPath));
120662
120840
  let did = 0;
120663
120841
  if (wantPython) {
120664
- if (!existsSync101(requirementsPath)) {
120842
+ if (!existsSync102(requirementsPath)) {
120665
120843
  console.error(source_default.red(`Skill "${skill}" has no requirements.txt at ${requirementsPath}`));
120666
120844
  process.exit(1);
120667
120845
  }
@@ -120685,7 +120863,7 @@ function registerDepsCommand(program3) {
120685
120863
  }
120686
120864
  }
120687
120865
  if (wantNode) {
120688
- if (!existsSync101(packageJsonPath)) {
120866
+ if (!existsSync102(packageJsonPath)) {
120689
120867
  console.error(source_default.red(`Skill "${skill}" has no package.json at ${packageJsonPath}`));
120690
120868
  process.exit(1);
120691
120869
  }
@@ -120718,7 +120896,7 @@ function registerDepsCommand(program3) {
120718
120896
  // src/cli/workspace.ts
120719
120897
  init_helpers();
120720
120898
  init_loader();
120721
- import { existsSync as existsSync102 } from "node:fs";
120899
+ import { existsSync as existsSync103 } from "node:fs";
120722
120900
  import { resolve as resolve55, sep as sep7 } from "node:path";
120723
120901
  import { spawnSync as spawnSync23 } from "node:child_process";
120724
120902
 
@@ -121495,7 +121673,7 @@ function registerWorkspaceCommand(program3) {
121495
121673
  if (!dir)
121496
121674
  return;
121497
121675
  const gitDir = resolve55(dir, ".git");
121498
- if (!existsSync102(gitDir)) {
121676
+ if (!existsSync103(gitDir)) {
121499
121677
  process.stdout.write(`Workspace is not a git repository. Re-run \`switchroom agent create ${agentName}\` ` + `or manually \`git init\` in ${dir} to enable versioning.
121500
121678
  `);
121501
121679
  return;
@@ -121549,7 +121727,7 @@ function registerWorkspaceCommand(program3) {
121549
121727
  if (!dir)
121550
121728
  return;
121551
121729
  const gitDir = resolve55(dir, ".git");
121552
- if (!existsSync102(gitDir)) {
121730
+ if (!existsSync103(gitDir)) {
121553
121731
  process.stdout.write(`Workspace is not a git repository.
121554
121732
  `);
121555
121733
  return;
@@ -121574,7 +121752,7 @@ function resolveAgentWorkspaceDirOrExit(program3, agentName) {
121574
121752
  const agentsDir = resolveAgentsDir(config);
121575
121753
  const agentDir = resolve55(agentsDir, agentName);
121576
121754
  const dir = resolveAgentWorkspaceDir(agentDir);
121577
- if (!existsSync102(dir)) {
121755
+ if (!existsSync103(dir)) {
121578
121756
  process.stderr.write(`workspace: ${dir} does not exist yet. Run \`switchroom setup\` or \`switchroom agent scaffold ${agentName}\` to seed it.
121579
121757
  `);
121580
121758
  return;
@@ -121610,7 +121788,7 @@ function safeParseInt(value, fallback) {
121610
121788
  init_helpers();
121611
121789
  init_loader();
121612
121790
  init_merge();
121613
- import { copyFileSync as copyFileSync14, existsSync as existsSync103, readFileSync as readFileSync92, writeFileSync as writeFileSync42 } from "node:fs";
121791
+ import { copyFileSync as copyFileSync14, existsSync as existsSync104, readFileSync as readFileSync93, writeFileSync as writeFileSync43 } from "node:fs";
121614
121792
  import { join as join107, resolve as resolve56 } from "node:path";
121615
121793
  init_scaffold();
121616
121794
  init_profiles();
@@ -121628,7 +121806,7 @@ function resolveSoulTargetOrExit(program3, agentName) {
121628
121806
  const agentsDir = resolveAgentsDir(config);
121629
121807
  const agentDir = resolve56(agentsDir, agentName);
121630
121808
  const workspaceDir = resolveAgentWorkspaceDir(agentDir);
121631
- if (!existsSync103(workspaceDir)) {
121809
+ if (!existsSync104(workspaceDir)) {
121632
121810
  console.error(`soul: ${workspaceDir} does not exist yet. Run \`switchroom setup\` ` + `or \`switchroom agent scaffold ${agentName}\` to seed it.`);
121633
121811
  process.exit(1);
121634
121812
  }
@@ -121654,11 +121832,11 @@ function registerSoulCommand(program3) {
121654
121832
  const t = resolveSoulTargetOrExit(program3, agentName);
121655
121833
  if (!t)
121656
121834
  return;
121657
- if (!existsSync103(t.soulPath)) {
121835
+ if (!existsSync104(t.soulPath)) {
121658
121836
  console.error(`soul: ${t.soulPath} does not exist yet \u2014 run ` + `\`switchroom soul reset ${agentName}\` to seed it.`);
121659
121837
  process.exit(1);
121660
121838
  }
121661
- process.stdout.write(readFileSync92(t.soulPath, "utf-8"));
121839
+ process.stdout.write(readFileSync93(t.soulPath, "utf-8"));
121662
121840
  }));
121663
121841
  cmd.command("reset <agent>").description("Re-seed SOUL.md from the agent's current profile " + "(backs the existing file up to SOUL.md.bak first)").option("-y, --yes", "Skip the confirmation prompt").action(withConfigError(async (agentName, opts) => {
121664
121842
  const t = resolveSoulTargetOrExit(program3, agentName);
@@ -121669,7 +121847,7 @@ function registerSoulCommand(program3) {
121669
121847
  console.error(`soul: profile "${t.profileName}" ships no SOUL.md.hbs \u2014 ` + `nothing to re-seed from.`);
121670
121848
  process.exit(1);
121671
121849
  }
121672
- const exists = existsSync103(t.soulPath);
121850
+ const exists = existsSync104(t.soulPath);
121673
121851
  if (exists && !opts.yes) {
121674
121852
  if (!isInteractive()) {
121675
121853
  console.error(`soul: ${t.soulPath} already exists. Re-run with --yes to ` + `replace it (the current file is backed up to SOUL.md.bak).`);
@@ -121684,12 +121862,12 @@ function registerSoulCommand(program3) {
121684
121862
  let backupPath;
121685
121863
  if (exists) {
121686
121864
  backupPath = `${t.soulPath}.bak`;
121687
- if (existsSync103(backupPath)) {
121865
+ if (existsSync104(backupPath)) {
121688
121866
  backupPath = `${t.soulPath}.bak.${Date.now()}`;
121689
121867
  }
121690
121868
  copyFileSync14(t.soulPath, backupPath);
121691
121869
  }
121692
- writeFileSync42(t.soulPath, content, "utf-8");
121870
+ writeFileSync43(t.soulPath, content, "utf-8");
121693
121871
  if (backupPath) {
121694
121872
  console.log(`soul: re-seeded ${agentName}'s SOUL.md from profile ` + `"${t.profileName}".
121695
121873
  ` + ` Previous version saved to ${backupPath}`);
@@ -121703,7 +121881,7 @@ function registerSoulCommand(program3) {
121703
121881
  // src/cli/debug.ts
121704
121882
  init_helpers();
121705
121883
  init_loader();
121706
- import { existsSync as existsSync104, readFileSync as readFileSync93, readdirSync as readdirSync36, statSync as statSync61 } from "node:fs";
121884
+ import { existsSync as existsSync105, readFileSync as readFileSync94, readdirSync as readdirSync36, statSync as statSync62 } from "node:fs";
121707
121885
  import { resolve as resolve57, join as join108 } from "node:path";
121708
121886
  import { createHash as createHash20 } from "node:crypto";
121709
121887
  init_merge();
@@ -121716,10 +121894,10 @@ function estimateTokens(bytes) {
121716
121894
  }
121717
121895
  function readMcpServerNames(agentDir) {
121718
121896
  const mcpPath = join108(agentDir, ".mcp.json");
121719
- if (!existsSync104(mcpPath))
121897
+ if (!existsSync105(mcpPath))
121720
121898
  return [];
121721
121899
  try {
121722
- const parsed = JSON.parse(readFileSync93(mcpPath, "utf-8"));
121900
+ const parsed = JSON.parse(readFileSync94(mcpPath, "utf-8"));
121723
121901
  return Object.keys(parsed.mcpServers ?? {});
121724
121902
  } catch {
121725
121903
  return null;
@@ -121730,7 +121908,7 @@ function sha2562(content) {
121730
121908
  }
121731
121909
  function findLatestTranscriptJsonl(claudeConfigDir) {
121732
121910
  const projectsDir = join108(claudeConfigDir, "projects");
121733
- if (!existsSync104(projectsDir))
121911
+ if (!existsSync105(projectsDir))
121734
121912
  return;
121735
121913
  try {
121736
121914
  const entries = readdirSync36(projectsDir, { withFileTypes: true });
@@ -121740,9 +121918,9 @@ function findLatestTranscriptJsonl(claudeConfigDir) {
121740
121918
  continue;
121741
121919
  const projectPath = join108(projectsDir, entry.name);
121742
121920
  const transcriptPath = join108(projectPath, "transcript.jsonl");
121743
- if (!existsSync104(transcriptPath))
121921
+ if (!existsSync105(transcriptPath))
121744
121922
  continue;
121745
- const stat3 = statSync61(transcriptPath);
121923
+ const stat3 = statSync62(transcriptPath);
121746
121924
  if (!latest || stat3.mtimeMs > latest.mtime) {
121747
121925
  latest = { path: transcriptPath, mtime: stat3.mtimeMs };
121748
121926
  }
@@ -121754,7 +121932,7 @@ function findLatestTranscriptJsonl(claudeConfigDir) {
121754
121932
  }
121755
121933
  function extractLatestUserMessage(transcriptPath) {
121756
121934
  try {
121757
- const content = readFileSync93(transcriptPath, "utf-8");
121935
+ const content = readFileSync94(transcriptPath, "utf-8");
121758
121936
  const lines = content.trim().split(`
121759
121937
  `).filter(Boolean);
121760
121938
  for (let i2 = lines.length - 1;i2 >= 0; i2--) {
@@ -121803,7 +121981,7 @@ function registerDebugCommand(program3) {
121803
121981
  }
121804
121982
  const agentsDir = resolveAgentsDir(config);
121805
121983
  const agentDir = resolve57(agentsDir, agentName);
121806
- if (!existsSync104(agentDir)) {
121984
+ if (!existsSync105(agentDir)) {
121807
121985
  console.error(`Agent directory not found: ${agentDir}`);
121808
121986
  process.exit(1);
121809
121987
  }
@@ -121858,7 +122036,7 @@ function registerDebugCommand(program3) {
121858
122036
  }
121859
122037
  console.log(`=== Append System Prompt (per-session) ===
121860
122038
  `);
121861
- const handoffContent = existsSync104(handoffPath) ? readFileSync93(handoffPath, "utf-8") : "";
122039
+ const handoffContent = existsSync105(handoffPath) ? readFileSync94(handoffPath, "utf-8") : "";
121862
122040
  if (handoffContent.trim().length > 0) {
121863
122041
  console.log(`-- Handoff Briefing (${formatBytes(handoffContent.length)}) --`);
121864
122042
  console.log(handoffContent);
@@ -121869,7 +122047,7 @@ function registerDebugCommand(program3) {
121869
122047
  }
121870
122048
  console.log(`=== CLAUDE.md (auto-loaded by Claude Code) ===
121871
122049
  `);
121872
- const claudeMdContent = existsSync104(claudeMdPath) ? readFileSync93(claudeMdPath, "utf-8") : "";
122050
+ const claudeMdContent = existsSync105(claudeMdPath) ? readFileSync94(claudeMdPath, "utf-8") : "";
121873
122051
  if (claudeMdContent.trim().length > 0) {
121874
122052
  console.log(`(${formatBytes(claudeMdContent.length)})`);
121875
122053
  console.log(claudeMdContent);
@@ -121880,7 +122058,7 @@ function registerDebugCommand(program3) {
121880
122058
  }
121881
122059
  console.log(`=== Persona (SOUL.md) ===
121882
122060
  `);
121883
- const soulMdContent = existsSync104(soulMdPath) ? readFileSync93(soulMdPath, "utf-8") : existsSync104(workspaceSoulMdPath) ? readFileSync93(workspaceSoulMdPath, "utf-8") : "";
122061
+ const soulMdContent = existsSync105(soulMdPath) ? readFileSync94(soulMdPath, "utf-8") : existsSync105(workspaceSoulMdPath) ? readFileSync94(workspaceSoulMdPath, "utf-8") : "";
121884
122062
  if (soulMdContent.trim().length > 0) {
121885
122063
  console.log(`(${formatBytes(soulMdContent.length)})`);
121886
122064
  console.log(soulMdContent);
@@ -121944,8 +122122,8 @@ function registerDebugCommand(program3) {
121944
122122
  const fleetDir = join108(agentsDir, "..", "fleet");
121945
122123
  const fleetInvPath = join108(fleetDir, "switchroom-invariants.md");
121946
122124
  const fleetClaudePath = join108(fleetDir, "CLAUDE.md");
121947
- const fleetInvBytes = existsSync104(fleetInvPath) ? readFileSync93(fleetInvPath, "utf-8").length : 0;
121948
- const fleetClaudeBytes = existsSync104(fleetClaudePath) ? readFileSync93(fleetClaudePath, "utf-8").length : 0;
122125
+ const fleetInvBytes = existsSync105(fleetInvPath) ? readFileSync94(fleetInvPath, "utf-8").length : 0;
122126
+ const fleetClaudeBytes = existsSync105(fleetClaudePath) ? readFileSync94(fleetClaudePath, "utf-8").length : 0;
121949
122127
  const fleetBytes = fleetInvBytes + fleetClaudeBytes;
121950
122128
  const totalBytes = stableBytes + perSessionBytes + claudeMdBytes + fleetBytes + perTurnBytes + userBytes;
121951
122129
  console.log(`Stable prefix: ${formatBytes(stableBytes).padEnd(20)} (cache-hot; includes SOUL.md ${soulMdBytes.toLocaleString()}B)`);
@@ -121981,7 +122159,7 @@ import { appendFileSync as appendFileSync6 } from "node:fs";
121981
122159
  // src/worktree/release.ts
121982
122160
  init_registry();
121983
122161
  init_remove_checkout();
121984
- import { existsSync as existsSync105 } from "node:fs";
122162
+ import { existsSync as existsSync106 } from "node:fs";
121985
122163
  function releaseWorktree(input) {
121986
122164
  const { id } = input;
121987
122165
  const record2 = readRecord(id);
@@ -121989,7 +122167,7 @@ function releaseWorktree(input) {
121989
122167
  return { released: true };
121990
122168
  }
121991
122169
  let gitSuccess = true;
121992
- if (existsSync105(record2.path)) {
122170
+ if (existsSync106(record2.path)) {
121993
122171
  try {
121994
122172
  removeCheckout(record2.repo, record2.path);
121995
122173
  } catch {
@@ -122025,11 +122203,11 @@ function listWorktrees() {
122025
122203
  }
122026
122204
 
122027
122205
  // src/worktree/reaper.ts
122028
- import { execFileSync as execFileSync32 } from "node:child_process";
122029
- import { existsSync as existsSync106 } from "node:fs";
122206
+ import { execFileSync as execFileSync33 } from "node:child_process";
122207
+ import { existsSync as existsSync107 } from "node:fs";
122030
122208
 
122031
122209
  // src/worktree/proc-liveness.ts
122032
- import { readdirSync as readdirSync37, readlinkSync as readlinkSync8, realpathSync as realpathSync9, statSync as statSync62, readFileSync as readFileSync94 } from "node:fs";
122210
+ import { readdirSync as readdirSync37, readlinkSync as readlinkSync8, realpathSync as realpathSync9, statSync as statSync63, readFileSync as readFileSync95 } from "node:fs";
122033
122211
  import { join as join109, sep as sep8 } from "node:path";
122034
122212
  function isPidDir(name) {
122035
122213
  return /^\d+$/.test(name);
@@ -122045,7 +122223,7 @@ function errno(e) {
122045
122223
  }
122046
122224
  function isKernelThread(procRoot, pid) {
122047
122225
  try {
122048
- return readFileSync94(join109(procRoot, pid, "cmdline")).length === 0;
122226
+ return readFileSync95(join109(procRoot, pid, "cmdline")).length === 0;
122049
122227
  } catch {
122050
122228
  return false;
122051
122229
  }
@@ -122057,7 +122235,7 @@ function cwdIsUnderRootByInode(linkPath, rootId, maxDepth) {
122057
122235
  for (let hop = 0;hop <= maxDepth; hop++) {
122058
122236
  let st;
122059
122237
  try {
122060
- st = statSync62(linkPath + suffix);
122238
+ st = statSync63(linkPath + suffix);
122061
122239
  } catch {
122062
122240
  return false;
122063
122241
  }
@@ -122078,7 +122256,7 @@ function scanProcForHolders(path10, opts = {}) {
122078
122256
  let rootId;
122079
122257
  try {
122080
122258
  root = realpathSync9(path10);
122081
- const st = statSync62(root);
122259
+ const st = statSync63(root);
122082
122260
  rootId = { dev: st.dev, ino: st.ino };
122083
122261
  } catch {
122084
122262
  return { state: "unavailable", inaccessible: 0 };
@@ -122163,11 +122341,11 @@ function reapSkipReasonText(action) {
122163
122341
  function probePathInUseWithTools(path10) {
122164
122342
  let probeRan = false;
122165
122343
  try {
122166
- execFileSync32("fuser", [path10], { stdio: "pipe" });
122344
+ execFileSync33("fuser", [path10], { stdio: "pipe" });
122167
122345
  return "in-use";
122168
122346
  } catch {}
122169
122347
  try {
122170
- const out = execFileSync32("lsof", ["-t", "+D", path10], {
122348
+ const out = execFileSync33("lsof", ["-t", "+D", path10], {
122171
122349
  stdio: ["ignore", "pipe", "ignore"]
122172
122350
  }).toString().trim();
122173
122351
  probeRan = true;
@@ -122197,7 +122375,7 @@ function probePathInUse(path10, deps = {}) {
122197
122375
  }
122198
122376
  function hasUncommittedChanges(_repoPath, worktreePath) {
122199
122377
  try {
122200
- const out = execFileSync32("git", ["-C", worktreePath, "status", "--porcelain"], { stdio: "pipe" }).toString();
122378
+ const out = execFileSync33("git", ["-C", worktreePath, "status", "--porcelain"], { stdio: "pipe" }).toString();
122201
122379
  return out.trim().length > 0;
122202
122380
  } catch {
122203
122381
  return true;
@@ -122215,7 +122393,7 @@ function planReaper(nowMs, deps = {}) {
122215
122393
  const plan = [];
122216
122394
  for (const record2 of listRecords()) {
122217
122395
  const heartbeatAge = now2 - new Date(record2.heartbeatAt).getTime();
122218
- const worktreeExists = existsSync106(record2.path);
122396
+ const worktreeExists = existsSync107(record2.path);
122219
122397
  if (!worktreeExists) {
122220
122398
  plan.push({
122221
122399
  record: record2,
@@ -122295,15 +122473,15 @@ function runReaper(nowMs, deps = {}) {
122295
122473
 
122296
122474
  // src/worktree/gc.ts
122297
122475
  init_registry();
122298
- import { execFileSync as execFileSync33 } from "node:child_process";
122476
+ import { execFileSync as execFileSync34 } from "node:child_process";
122299
122477
  import { createHash as createHash21 } from "node:crypto";
122300
122478
  import {
122301
- existsSync as existsSync107,
122302
- readFileSync as readFileSync95,
122479
+ existsSync as existsSync108,
122480
+ readFileSync as readFileSync96,
122303
122481
  readdirSync as readdirSync38,
122304
- statSync as statSync63,
122305
- renameSync as renameSync27,
122306
- mkdirSync as mkdirSync59,
122482
+ statSync as statSync64,
122483
+ renameSync as renameSync28,
122484
+ mkdirSync as mkdirSync60,
122307
122485
  rmSync as rmSync21
122308
122486
  } from "node:fs";
122309
122487
  import { homedir as homedir57 } from "node:os";
@@ -122453,7 +122631,7 @@ function describeExecFailure(e) {
122453
122631
  }
122454
122632
  var execCapture = (file, args, cwd) => {
122455
122633
  try {
122456
- return execFileSync33(file, args, {
122634
+ return execFileSync34(file, args, {
122457
122635
  cwd,
122458
122636
  encoding: "utf8",
122459
122637
  stdio: ["ignore", "pipe", "pipe"],
@@ -122509,7 +122687,7 @@ function defaultNewestTrackedMtimeMs(dir, exec) {
122509
122687
  let newest = 0;
122510
122688
  for (const f of files) {
122511
122689
  try {
122512
- const m = statSync63(join110(dir, f)).mtimeMs;
122690
+ const m = statSync64(join110(dir, f)).mtimeMs;
122513
122691
  if (m > newest)
122514
122692
  newest = m;
122515
122693
  } catch {}
@@ -122531,10 +122709,10 @@ function trashRoot() {
122531
122709
  return resolve58(process.env.SWITCHROOM_WORKTREE_TRASH ?? join110(homedir57(), ".switchroom", "worktree-gc-trash"));
122532
122710
  }
122533
122711
  function planGc(roots, deps = {}, taskTreeRoots = [], taskTreeDirs = []) {
122534
- const exists = deps.existsSync ?? existsSync107;
122712
+ const exists = deps.existsSync ?? existsSync108;
122535
122713
  const readDir = deps.readDir ?? ((p) => readdirSync38(p));
122536
- const readFile4 = deps.readFile ?? ((p) => readFileSync95(p, "utf8"));
122537
- const stat3 = deps.stat ?? ((p) => statSync63(p));
122714
+ const readFile4 = deps.readFile ?? ((p) => readFileSync96(p, "utf8"));
122715
+ const stat3 = deps.stat ?? ((p) => statSync64(p));
122538
122716
  const exec = deps.exec ?? execCapture;
122539
122717
  const prSignal = deps.prSignal ?? ((repo, branch) => defaultPrSignal(repo, branch, exec));
122540
122718
  const stamp = deps.dateStamp ?? "undated";
@@ -122830,10 +123008,10 @@ function planGc(roots, deps = {}, taskTreeRoots = [], taskTreeDirs = []) {
122830
123008
  }
122831
123009
  function applyGc(plan, deps = {}) {
122832
123010
  const exec = deps.exec ?? execCapture;
122833
- const mkdirp = deps.mkdirp ?? ((p) => void mkdirSync59(p, { recursive: true }));
123011
+ const mkdirp = deps.mkdirp ?? ((p) => void mkdirSync60(p, { recursive: true }));
122834
123012
  const move = deps.move ?? ((src, dest) => {
122835
123013
  try {
122836
- renameSync27(src, dest);
123014
+ renameSync28(src, dest);
122837
123015
  } catch {
122838
123016
  exec("mv", [src, dest]);
122839
123017
  }
@@ -122893,7 +123071,7 @@ function selectPurgeTargets(entries, olderThanDays) {
122893
123071
  return entries.filter((e) => e.ageDays >= olderThanDays).map((e) => e.path);
122894
123072
  }
122895
123073
  function listTrashEntries(nowMs, deps = {}) {
122896
- const exists = deps.existsSync ?? existsSync107;
123074
+ const exists = deps.existsSync ?? existsSync108;
122897
123075
  const readDir = deps.readDir ?? ((p) => readdirSync38(p));
122898
123076
  const root = trashRoot();
122899
123077
  if (!exists(root))
@@ -122911,7 +123089,7 @@ function listTrashEntries(nowMs, deps = {}) {
122911
123089
  const p = join110(stampDir, name);
122912
123090
  let mtimeMs = nowMs;
122913
123091
  try {
122914
- mtimeMs = statSync63(p).mtimeMs;
123092
+ mtimeMs = statSync64(p).mtimeMs;
122915
123093
  } catch {}
122916
123094
  out.push({ path: p, ageDays: (nowMs - mtimeMs) / 86400000 });
122917
123095
  }
@@ -122946,7 +123124,7 @@ function defaultTaskTreeRoots() {
122946
123124
  for (const name of names.sort()) {
122947
123125
  for (const sub of ["home/work", "home/workspace"]) {
122948
123126
  const r = join110(agentsDir, name, sub);
122949
- if (existsSync107(r))
123127
+ if (existsSync108(r))
122950
123128
  roots.push(r);
122951
123129
  }
122952
123130
  }
@@ -122994,7 +123172,7 @@ function reservedAgentPath(relParts) {
122994
123172
  }
122995
123173
  function discoverAgentCheckouts(agentsDir, deps = {}) {
122996
123174
  const readDir = deps.readDir ?? ((p) => readdirSync38(p, { withFileTypes: true }));
122997
- const exists = deps.existsSync ?? existsSync107;
123175
+ const exists = deps.existsSync ?? existsSync108;
122998
123176
  const maxDepth = deps.maxDepth ?? 4;
122999
123177
  const maxVisits = deps.maxVisits ?? 50000;
123000
123178
  let agents;
@@ -123046,7 +123224,7 @@ function defaultTaskTreeDirs(deps = {}) {
123046
123224
  }
123047
123225
 
123048
123226
  // src/worktree/reap-report.ts
123049
- import { execFileSync as execFileSync34 } from "node:child_process";
123227
+ import { execFileSync as execFileSync35 } from "node:child_process";
123050
123228
  import { sep as sep9 } from "node:path";
123051
123229
  var DEFAULT_AGENT_TREE_BUDGET_BYTES = 5 * 1024 * 1024 * 1024;
123052
123230
  var UNATTRIBUTED_AGENT = "(unattributed)";
@@ -123068,7 +123246,7 @@ function agentFromPath(path10) {
123068
123246
  return name && name !== "" ? name : null;
123069
123247
  }
123070
123248
  function defaultDirSizeBytes(path10) {
123071
- const out = execFileSync34("du", ["-sk", path10], {
123249
+ const out = execFileSync35("du", ["-sk", path10], {
123072
123250
  stdio: ["ignore", "pipe", "pipe"],
123073
123251
  maxBuffer: 8 * 1024 * 1024
123074
123252
  }).toString();
@@ -123258,17 +123436,17 @@ function formatReapReport(report) {
123258
123436
  }
123259
123437
 
123260
123438
  // src/worktree/capture.ts
123261
- import { execFileSync as execFileSync35 } from "node:child_process";
123439
+ import { execFileSync as execFileSync36 } from "node:child_process";
123262
123440
  import {
123263
- existsSync as existsSync108,
123264
- mkdirSync as mkdirSync60,
123441
+ existsSync as existsSync109,
123442
+ mkdirSync as mkdirSync61,
123265
123443
  mkdtempSync as mkdtempSync5,
123266
123444
  rmSync as rmSync22,
123267
- statSync as statSync64,
123268
- writeFileSync as writeFileSync43
123445
+ statSync as statSync65,
123446
+ writeFileSync as writeFileSync44
123269
123447
  } from "node:fs";
123270
123448
  import { homedir as homedir58 } from "node:os";
123271
- import { basename as basename12, dirname as dirname47, join as join111, resolve as resolve59 } from "node:path";
123449
+ import { basename as basename12, dirname as dirname48, join as join111, resolve as resolve59 } from "node:path";
123272
123450
  init_remove_checkout();
123273
123451
  init_scratch();
123274
123452
  init_loader();
@@ -123354,7 +123532,7 @@ function rescueRootIsFallback(destRoot) {
123354
123532
  }
123355
123533
  function run(args, input, cwd, env2) {
123356
123534
  try {
123357
- const stdout = execFileSync35("git", args, {
123535
+ const stdout = execFileSync36("git", args, {
123358
123536
  encoding: "utf-8",
123359
123537
  stdio: input === undefined ? ["ignore", "pipe", "pipe"] : ["pipe", "pipe", "pipe"],
123360
123538
  maxBuffer: MAX_BUFFER,
@@ -123421,7 +123599,7 @@ function captureCheckout(opts) {
123421
123599
  };
123422
123600
  let st;
123423
123601
  try {
123424
- st = statSync64(source);
123602
+ st = statSync65(source);
123425
123603
  } catch {
123426
123604
  return { ...base, failure: "missing", error: `No such directory: ${source}` };
123427
123605
  }
@@ -123435,7 +123613,7 @@ function captureCheckout(opts) {
123435
123613
  failure: "not-a-git-repo",
123436
123614
  error: `${source} is not a usable git repository (${commonDirProbe.stderr}).
123437
123615
  ` + `A bundle cannot represent it. Capture it as a tarball instead:
123438
- ` + ` tar -C ${dirname47(source)} -czf <dest>/${basename12(source)}.tar.gz ${basename12(source)}
123616
+ ` + ` tar -C ${dirname48(source)} -czf <dest>/${basename12(source)}.tar.gz ${basename12(source)}
123439
123617
  ` + "then verify with `tar -tzf <file> >/dev/null` before deleting anything."
123440
123618
  };
123441
123619
  }
@@ -123444,7 +123622,7 @@ function captureCheckout(opts) {
123444
123622
  const headSha = run(gitArgs(source, "rev-parse", "--verify", "--quiet", "HEAD")).stdout.trim();
123445
123623
  const headBranch = run(gitArgs(source, "symbolic-ref", "--quiet", "HEAD")).stdout.trim();
123446
123624
  const head = headBranch ? headBranch.replace(/^refs\/heads\//, "") : headSha ? `detached@${headSha.slice(0, 12)}` : null;
123447
- const destRoot = opts.out ? dirname47(resolve59(opts.out)) : opts.dest ? resolve59(opts.dest) : rescueDestRoot();
123625
+ const destRoot = opts.out ? dirname48(resolve59(opts.out)) : opts.dest ? resolve59(opts.dest) : rescueDestRoot();
123448
123626
  const bundlePath = opts.out ? resolve59(opts.out) : join111(destRoot, bundleFileName(source, now2));
123449
123627
  if (bundlePath === source || bundlePath.startsWith(source + "/")) {
123450
123628
  return {
@@ -123455,7 +123633,7 @@ function captureCheckout(opts) {
123455
123633
  };
123456
123634
  }
123457
123635
  try {
123458
- mkdirSync60(destRoot, { recursive: true });
123636
+ mkdirSync61(destRoot, { recursive: true });
123459
123637
  } catch (e) {
123460
123638
  return {
123461
123639
  ...base,
@@ -123478,8 +123656,8 @@ function captureCheckout(opts) {
123478
123656
  if (!init.ok) {
123479
123657
  return { ...base, failure: "bundle-failed", error: `staging init failed: ${init.stderr}` };
123480
123658
  }
123481
- mkdirSync60(join111(stageDir, "objects", "info"), { recursive: true });
123482
- writeFileSync43(join111(stageDir, "objects", "info", "alternates"), objectsDir + `
123659
+ mkdirSync61(join111(stageDir, "objects", "info"), { recursive: true });
123660
+ writeFileSync44(join111(stageDir, "objects", "info", "alternates"), objectsDir + `
123483
123661
  `);
123484
123662
  const sourceRefs = parseForEachRef(run(gitArgs(source, "for-each-ref", "--format=%(objectname) %(refname)")).stdout);
123485
123663
  const sourceRefNames = new Set(sourceRefs.map((r) => r.ref));
@@ -123502,7 +123680,7 @@ function captureCheckout(opts) {
123502
123680
  const nStash = createRefs(stageDir, stashRefs, warnings);
123503
123681
  let wip = false;
123504
123682
  let wipCommit = null;
123505
- if (!bare && existsSync108(source)) {
123683
+ if (!bare && existsSync109(source)) {
123506
123684
  const add2 = run(stageArgs(stageDir, "--work-tree", source, "add", "-A"), undefined, source);
123507
123685
  if (!add2.ok) {
123508
123686
  return {
@@ -123537,7 +123715,7 @@ function captureCheckout(opts) {
123537
123715
  } else {
123538
123716
  warnings.push("could not write a tree for the working-tree snapshot");
123539
123717
  }
123540
- if (existsSync108(join111(source, ".gitmodules"))) {
123718
+ if (existsSync109(join111(source, ".gitmodules"))) {
123541
123719
  warnings.push("this checkout has submodules: they are captured as gitlinks only, " + "so submodule CONTENT is not in this bundle \u2014 capture each submodule " + "separately if it holds unpushed work");
123542
123720
  }
123543
123721
  }
@@ -123569,7 +123747,7 @@ function captureCheckout(opts) {
123569
123747
  };
123570
123748
  }
123571
123749
  const created = run(stageArgs(stageDir, "bundle", "create", bundlePath, "--all"));
123572
- if (!created.ok || !existsSync108(bundlePath)) {
123750
+ if (!created.ok || !existsSync109(bundlePath)) {
123573
123751
  return {
123574
123752
  ...base,
123575
123753
  head,
@@ -123579,7 +123757,7 @@ function captureCheckout(opts) {
123579
123757
  };
123580
123758
  }
123581
123759
  opts.onBundleWritten?.(bundlePath);
123582
- const bytes = statSync64(bundlePath).size;
123760
+ const bytes = statSync65(bundlePath).size;
123583
123761
  if (bytes === 0) {
123584
123762
  return {
123585
123763
  ...base,
@@ -123658,7 +123836,7 @@ function captureCheckout(opts) {
123658
123836
  };
123659
123837
  const writeManifest = (r) => {
123660
123838
  try {
123661
- writeFileSync43(`${bundlePath}.json`, JSON.stringify(r, null, 2) + `
123839
+ writeFileSync44(`${bundlePath}.json`, JSON.stringify(r, null, 2) + `
123662
123840
  `);
123663
123841
  } catch (e) {
123664
123842
  warnings.push(`could not write the manifest sidecar: ${e.message}`);
@@ -123676,7 +123854,7 @@ function captureCheckout(opts) {
123676
123854
  return failed;
123677
123855
  }
123678
123856
  if (kind === "worktree") {
123679
- const repoRoot = dirname47(resolve59(source, commonDirProbe.stdout.trim()));
123857
+ const repoRoot = dirname48(resolve59(source, commonDirProbe.stdout.trim()));
123680
123858
  const pruned = run(gitArgs(repoRoot, "worktree", "prune"));
123681
123859
  if (!pruned.ok)
123682
123860
  warnings.push(`git worktree prune failed in ${repoRoot}: ${pruned.stderr}`);
@@ -124042,10 +124220,10 @@ init_drive();
124042
124220
  init_scaffold_integration();
124043
124221
  import {
124044
124222
  chmodSync as chmodSync17,
124045
- mkdirSync as mkdirSync61,
124223
+ mkdirSync as mkdirSync62,
124046
124224
  readdirSync as readdirSync39,
124047
124225
  rmSync as rmSync23,
124048
- writeFileSync as writeFileSync44
124226
+ writeFileSync as writeFileSync45
124049
124227
  } from "node:fs";
124050
124228
  import { join as join112 } from "node:path";
124051
124229
  function encodeCredentialsFilename(email) {
@@ -124314,14 +124492,14 @@ function resolveCredentialsDir(env2) {
124314
124492
  return join112(stateBase, "google-workspace-mcp", "credentials");
124315
124493
  }
124316
124494
  function writeSeedFile(dir, email, seed) {
124317
- mkdirSync61(dir, { recursive: true, mode: 448 });
124495
+ mkdirSync62(dir, { recursive: true, mode: 448 });
124318
124496
  chmodSync17(dir, 448);
124319
124497
  for (const name of readdirSync39(dir)) {
124320
124498
  rmSync23(join112(dir, name), { force: true, recursive: true });
124321
124499
  }
124322
124500
  const filename = encodeCredentialsFilename(email);
124323
124501
  const filePath = join112(dir, filename);
124324
- writeFileSync44(filePath, JSON.stringify(seed), { mode: 384 });
124502
+ writeFileSync45(filePath, JSON.stringify(seed), { mode: 384 });
124325
124503
  chmodSync17(filePath, 384);
124326
124504
  return filePath;
124327
124505
  }
@@ -124516,8 +124694,8 @@ function registerDriveMcpLauncherCommand(program3) {
124516
124694
  // src/cli/m365-mcp-launcher.ts
124517
124695
  init_scaffold_integration();
124518
124696
  import { spawn as spawn6 } from "node:child_process";
124519
- import { writeFileSync as writeFileSync45, mkdirSync as mkdirSync62 } from "node:fs";
124520
- import { dirname as dirname48, join as join113 } from "node:path";
124697
+ import { writeFileSync as writeFileSync46, mkdirSync as mkdirSync63 } from "node:fs";
124698
+ import { dirname as dirname49, join as join113 } from "node:path";
124521
124699
  var SOFTERIA_TOKEN_ENV = "MS365_MCP_OAUTH_TOKEN";
124522
124700
  var DEFAULT_REFRESH_LEAD_MS = 5 * 60 * 1000;
124523
124701
  var MAX_REFRESH_INTERVAL_MS = 60 * 60 * 1000;
@@ -124553,8 +124731,8 @@ function computeRefreshDelayMs(expiresAt, now2, leadMs = DEFAULT_REFRESH_LEAD_MS
124553
124731
  function writeRefreshHeartbeat(agentName, data, account) {
124554
124732
  const path10 = heartbeatPath(agentName, account);
124555
124733
  try {
124556
- mkdirSync62(dirname48(path10), { recursive: true });
124557
- writeFileSync45(path10, JSON.stringify(data, null, 2), { mode: 420 });
124734
+ mkdirSync63(dirname49(path10), { recursive: true });
124735
+ writeFileSync46(path10, JSON.stringify(data, null, 2), { mode: 420 });
124558
124736
  } catch {}
124559
124737
  }
124560
124738
  function heartbeatPath(agentName, account) {
@@ -124794,8 +124972,8 @@ function registerM365McpLauncherCommand(program3) {
124794
124972
  // src/cli/notion-mcp-launcher.ts
124795
124973
  init_scaffold_integration();
124796
124974
  import { spawn as spawn7 } from "node:child_process";
124797
- import { existsSync as existsSync109, mkdirSync as mkdirSync63, writeFileSync as writeFileSync46 } from "node:fs";
124798
- import { dirname as dirname49 } from "node:path";
124975
+ import { existsSync as existsSync110, mkdirSync as mkdirSync64, writeFileSync as writeFileSync47 } from "node:fs";
124976
+ import { dirname as dirname50 } from "node:path";
124799
124977
  var HEARTBEAT_WRITE_INTERVAL_MS = 30 * 1000;
124800
124978
  var DEFAULT_HEARTBEAT_PATH = "/state/agent/notion-launcher.heartbeat.json";
124801
124979
  var DEFAULT_VAULT_KEY = "notion/integration-token";
@@ -124805,10 +124983,10 @@ function buildNotionMcpArgs(opts) {
124805
124983
  }
124806
124984
  function defaultWriteHeartbeat(path10, contents) {
124807
124985
  try {
124808
- const dir = dirname49(path10);
124809
- if (!existsSync109(dir))
124810
- mkdirSync63(dir, { recursive: true });
124811
- writeFileSync46(path10, contents);
124986
+ const dir = dirname50(path10);
124987
+ if (!existsSync110(dir))
124988
+ mkdirSync64(dir, { recursive: true });
124989
+ writeFileSync47(path10, contents);
124812
124990
  } catch {}
124813
124991
  }
124814
124992
  async function runNotionMcpLauncher(opts, runtime) {
@@ -124918,7 +125096,7 @@ function registerNotionMcpLauncherCommand(program3) {
124918
125096
 
124919
125097
  // src/cli/hindsight-mcp-shim.ts
124920
125098
  init_hindsight_directive_admin();
124921
- import { mkdirSync as mkdirSync64, readFileSync as readFileSync96, renameSync as renameSync28, writeFileSync as writeFileSync47 } from "node:fs";
125099
+ import { mkdirSync as mkdirSync65, readFileSync as readFileSync97, renameSync as renameSync29, writeFileSync as writeFileSync48 } from "node:fs";
124922
125100
  import { tmpdir as tmpdir6 } from "node:os";
124923
125101
  import { join as join114 } from "node:path";
124924
125102
  import { createInterface as createInterface7 } from "node:readline";
@@ -125200,6 +125378,63 @@ function isReflectToolCallFailure(toolName, res) {
125200
125378
  }
125201
125379
  return texts.some((t) => t.includes(REFLECT_NO_TOOL_CALL_SIGNATURE));
125202
125380
  }
125381
+ var REFLECT_EMPTY_EVIDENCE_TEXT = "No relevant memories: reflect retrieved ZERO evidence from your memory " + "bank for this query \u2014 no memories, mental models, or directives matched. " + "This is not an error and not a synthesized answer: the bank has nothing " + "recorded on this topic. Treat it as an explicit absence, not a fact, and " + "do not present the (suppressed) synthesized prose as if it were recalled.";
125382
+ function reflectEvidenceCardinality(basedOn) {
125383
+ if (!basedOn || typeof basedOn !== "object" || Array.isArray(basedOn)) {
125384
+ return null;
125385
+ }
125386
+ let total = 0;
125387
+ for (const v of Object.values(basedOn)) {
125388
+ if (!Array.isArray(v))
125389
+ return null;
125390
+ total += v.length;
125391
+ }
125392
+ return total;
125393
+ }
125394
+ function applyReflectCardinalityGuard(result, callerWantedBasedOn) {
125395
+ const abstain = {
125396
+ content: [{ type: "text", text: REFLECT_EMPTY_EVIDENCE_TEXT }],
125397
+ isError: false
125398
+ };
125399
+ if (!result || typeof result !== "object")
125400
+ return result;
125401
+ const res = result;
125402
+ if (res.isError)
125403
+ return result;
125404
+ const content = res.content;
125405
+ if (!Array.isArray(content) || content.length === 0)
125406
+ return result;
125407
+ const first = content[0];
125408
+ if (!first || typeof first.text !== "string")
125409
+ return result;
125410
+ let payload;
125411
+ try {
125412
+ payload = JSON.parse(first.text);
125413
+ } catch {
125414
+ return result;
125415
+ }
125416
+ if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
125417
+ return result;
125418
+ }
125419
+ const obj = payload;
125420
+ if (!("based_on" in obj))
125421
+ return result;
125422
+ const cardinality = reflectEvidenceCardinality(obj.based_on);
125423
+ if (cardinality === null)
125424
+ return result;
125425
+ if (cardinality === 0)
125426
+ return abstain;
125427
+ if (callerWantedBasedOn)
125428
+ return result;
125429
+ delete obj.based_on;
125430
+ return {
125431
+ ...res,
125432
+ content: [
125433
+ { ...first, text: JSON.stringify(obj, null, 2) },
125434
+ ...content.slice(1)
125435
+ ]
125436
+ };
125437
+ }
125203
125438
  function redactToolArguments(value) {
125204
125439
  if (typeof value === "string")
125205
125440
  return redact(value);
@@ -125324,6 +125559,9 @@ function guardAndClampToolCall(params, env2) {
125324
125559
  if (injected.budget === undefined) {
125325
125560
  injected.budget = name === "recall" ? resolveClampBudget(env2.HINDSIGHT_SHIM_RECALL_BUDGET, DEFAULT_RECALL_BUDGET) : resolveClampBudget(env2.HINDSIGHT_SHIM_REFLECT_BUDGET, DEFAULT_REFLECT_BUDGET);
125326
125561
  }
125562
+ if (name === "reflect" && injected.include_based_on === undefined) {
125563
+ injected.include_based_on = true;
125564
+ }
125327
125565
  return { ok: true, params: { ...called, arguments: injected } };
125328
125566
  }
125329
125567
  return { ok: true, params };
@@ -125513,18 +125751,18 @@ class HindsightShim {
125513
125751
  }
125514
125752
  writeCache(result) {
125515
125753
  try {
125516
- mkdirSync64(this.opts.cacheDir, { recursive: true });
125754
+ mkdirSync65(this.opts.cacheDir, { recursive: true });
125517
125755
  const tmp = join114(this.opts.cacheDir, `.${TOOLS_CACHE_FILENAME}.${process.pid}.tmp`);
125518
- writeFileSync47(tmp, JSON.stringify(result, null, 2) + `
125756
+ writeFileSync48(tmp, JSON.stringify(result, null, 2) + `
125519
125757
  `);
125520
- renameSync28(tmp, this.cachePath);
125758
+ renameSync29(tmp, this.cachePath);
125521
125759
  } catch (err) {
125522
125760
  this.log(`[hindsight-shim] cache write failed: ${String(err)}`);
125523
125761
  }
125524
125762
  }
125525
125763
  readCache() {
125526
125764
  try {
125527
- const parsed = JSON.parse(readFileSync96(this.cachePath, "utf-8"));
125765
+ const parsed = JSON.parse(readFileSync97(this.cachePath, "utf-8"));
125528
125766
  if (Array.isArray(parsed.tools))
125529
125767
  return parsed;
125530
125768
  return null;
@@ -125718,6 +125956,7 @@ class HindsightShim {
125718
125956
  }
125719
125957
  const forwarded = redactToolCallParams(guarded.params);
125720
125958
  const toolName = guarded.params?.name;
125959
+ const callerWantedBasedOn = toolName === "reflect" && Boolean(called?.arguments?.include_based_on);
125721
125960
  const timeoutMs = this.opts.toolsCallTimeoutMs ?? TOOLS_CALL_TIMEOUT_MS;
125722
125961
  try {
125723
125962
  let res = await this.upstream.request("tools/call", forwarded, timeoutMs);
@@ -125734,6 +125973,9 @@ class HindsightShim {
125734
125973
  isError: true
125735
125974
  };
125736
125975
  }
125976
+ if (toolName === "reflect") {
125977
+ return applyReflectCardinalityGuard(res.result, callerWantedBasedOn);
125978
+ }
125737
125979
  return res.result;
125738
125980
  } catch (err) {
125739
125981
  const name = params?.name ?? "unknown";
@@ -125825,7 +126067,7 @@ function registerHindsightMcpShimCommand(program3) {
125825
126067
 
125826
126068
  // src/cli/deliver-file.ts
125827
126069
  init_client2();
125828
- import { readFileSync as readFileSync97, statSync as statSync65 } from "node:fs";
126070
+ import { readFileSync as readFileSync98, statSync as statSync66 } from "node:fs";
125829
126071
  import { basename as basename15 } from "node:path";
125830
126072
 
125831
126073
  // src/delivery/onedrive.ts
@@ -126164,8 +126406,8 @@ async function defaultResolveProvider() {
126164
126406
  }
126165
126407
  async function runDeliverFile(localPath, deps = {}) {
126166
126408
  const agentName = safeAgentName(deps.agentName ?? process.env.SWITCHROOM_AGENT_NAME);
126167
- const sizeOf = deps.fileSize ?? ((p) => statSync65(p).size);
126168
- const read = deps.readFile ?? ((p) => new Uint8Array(readFileSync97(p)));
126409
+ const sizeOf = deps.fileSize ?? ((p) => statSync66(p).size);
126410
+ const read = deps.readFile ?? ((p) => new Uint8Array(readFileSync98(p)));
126169
126411
  const resolveProvider = deps.resolveProvider ?? defaultResolveProvider;
126170
126412
  let size;
126171
126413
  try {
@@ -126486,7 +126728,7 @@ function runRedactStdin() {
126486
126728
  }
126487
126729
 
126488
126730
  // src/cli/status-ask.ts
126489
- import { readFileSync as readFileSync98, existsSync as existsSync110, readdirSync as readdirSync40 } from "node:fs";
126731
+ import { readFileSync as readFileSync99, existsSync as existsSync111, readdirSync as readdirSync40 } from "node:fs";
126490
126732
  import { join as join115 } from "node:path";
126491
126733
  import { homedir as homedir59 } from "node:os";
126492
126734
 
@@ -126762,7 +127004,7 @@ function runReport(opts) {
126762
127004
  for (const src of sources) {
126763
127005
  let content;
126764
127006
  try {
126765
- content = readFileSync98(src.path, "utf-8");
127007
+ content = readFileSync99(src.path, "utf-8");
126766
127008
  } catch (err) {
126767
127009
  process.stderr.write(`status-ask report: cannot read ${src.path}: ${err instanceof Error ? err.message : String(err)}
126768
127010
  `);
@@ -126809,7 +127051,7 @@ function runReport(opts) {
126809
127051
  function resolveSources(explicitPath) {
126810
127052
  if (explicitPath != null && explicitPath.trim() !== "") {
126811
127053
  const trimmed = explicitPath.trim();
126812
- if (!existsSync110(trimmed)) {
127054
+ if (!existsSync111(trimmed)) {
126813
127055
  process.stderr.write(`status-ask report: ${trimmed}: file not found
126814
127056
  `);
126815
127057
  process.exit(1);
@@ -126825,7 +127067,7 @@ function resolveSources(explicitPath) {
126825
127067
  } catch {
126826
127068
  agentsDir = join115(homedir59(), ".switchroom", "agents");
126827
127069
  }
126828
- if (!existsSync110(agentsDir))
127070
+ if (!existsSync111(agentsDir))
126829
127071
  return [];
126830
127072
  const sources = [];
126831
127073
  let entries;
@@ -126836,7 +127078,7 @@ function resolveSources(explicitPath) {
126836
127078
  }
126837
127079
  for (const name of entries) {
126838
127080
  const path10 = join115(agentsDir, name, "runtime-metrics.jsonl");
126839
- if (existsSync110(path10)) {
127081
+ if (existsSync111(path10)) {
126840
127082
  sources.push({ path: path10, agent: name });
126841
127083
  }
126842
127084
  }
@@ -126865,16 +127107,16 @@ var import_yaml23 = __toESM(require_dist(), 1);
126865
127107
  // src/config/overlay-writer.ts
126866
127108
  init_paths();
126867
127109
  import {
126868
- chownSync as chownSync14,
127110
+ chownSync as chownSync15,
126869
127111
  closeSync as closeSync20,
126870
- existsSync as existsSync111,
127112
+ existsSync as existsSync112,
126871
127113
  fsyncSync as fsyncSync8,
126872
- mkdirSync as mkdirSync65,
127114
+ mkdirSync as mkdirSync66,
126873
127115
  openSync as openSync20,
126874
127116
  readdirSync as readdirSync41,
126875
- readFileSync as readFileSync99,
126876
- renameSync as renameSync29,
126877
- statSync as statSync66,
127117
+ readFileSync as readFileSync100,
127118
+ renameSync as renameSync30,
127119
+ statSync as statSync67,
126878
127120
  unlinkSync as unlinkSync22,
126879
127121
  writeSync as writeSync10
126880
127122
  } from "node:fs";
@@ -126897,15 +127139,15 @@ function overlayPathsFor(agent, opts = {}) {
126897
127139
  };
126898
127140
  }
126899
127141
  function ensureDirs(paths) {
126900
- mkdirSync65(paths.scheduleDir, { recursive: true });
126901
- mkdirSync65(paths.scheduleStagingDir, { recursive: true });
127142
+ mkdirSync66(paths.scheduleDir, { recursive: true });
127143
+ mkdirSync66(paths.scheduleStagingDir, { recursive: true });
126902
127144
  }
126903
127145
  function ensureSkillsDirs(paths) {
126904
- mkdirSync65(paths.skillsDir, { recursive: true });
126905
- mkdirSync65(paths.skillsStagingDir, { recursive: true });
127146
+ mkdirSync66(paths.skillsDir, { recursive: true });
127147
+ mkdirSync66(paths.skillsStagingDir, { recursive: true });
126906
127148
  }
126907
127149
  function withAgentLock(paths, fn) {
126908
- mkdirSync65(paths.agentRoot, { recursive: true });
127150
+ mkdirSync66(paths.agentRoot, { recursive: true });
126909
127151
  const start = Date.now();
126910
127152
  const TIMEOUT_MS = 5000;
126911
127153
  let fd = null;
@@ -126918,7 +127160,7 @@ function withAgentLock(paths, fn) {
126918
127160
  if (e.code !== "EEXIST")
126919
127161
  throw err;
126920
127162
  try {
126921
- const age = Date.now() - statSync66(paths.lockPath).mtimeMs;
127163
+ const age = Date.now() - statSync67(paths.lockPath).mtimeMs;
126922
127164
  if (age > 30000) {
126923
127165
  unlinkSync22(paths.lockPath);
126924
127166
  continue;
@@ -126944,14 +127186,14 @@ function withAgentLock(paths, fn) {
126944
127186
  }
126945
127187
  var overlayWriterRuntime = {
126946
127188
  geteuid: () => process.geteuid?.(),
126947
- chown: (path10, uid, gid) => chownSync14(path10, uid, gid)
127189
+ chown: (path10, uid, gid) => chownSync15(path10, uid, gid)
126948
127190
  };
126949
127191
  function alignStagedOwnerToDir(stagingPath, targetDir) {
126950
127192
  try {
126951
127193
  const euid = overlayWriterRuntime.geteuid();
126952
127194
  if (euid === undefined)
126953
127195
  return;
126954
- const dirStat = statSync66(targetDir);
127196
+ const dirStat = statSync67(targetDir);
126955
127197
  if (dirStat.uid === euid)
126956
127198
  return;
126957
127199
  overlayWriterRuntime.chown(stagingPath, dirStat.uid, dirStat.gid);
@@ -126971,7 +127213,7 @@ function writeOverlayEntry(agent, slug, yamlText, opts = {}) {
126971
127213
  closeSync20(fd);
126972
127214
  }
126973
127215
  alignStagedOwnerToDir(stagingPath, paths.scheduleDir);
126974
- renameSync29(stagingPath, finalPath);
127216
+ renameSync30(stagingPath, finalPath);
126975
127217
  return finalPath;
126976
127218
  });
126977
127219
  }
@@ -126989,7 +127231,7 @@ function writeSkillsOverlayEntry(agent, slug, yamlText, opts = {}) {
126989
127231
  closeSync20(fd);
126990
127232
  }
126991
127233
  alignStagedOwnerToDir(stagingPath, paths.skillsDir);
126992
- renameSync29(stagingPath, finalPath);
127234
+ renameSync30(stagingPath, finalPath);
126993
127235
  return finalPath;
126994
127236
  });
126995
127237
  }
@@ -126997,7 +127239,7 @@ function deleteSkillsOverlayEntry(agent, slug, opts = {}) {
126997
127239
  const paths = overlayPathsFor(agent, opts);
126998
127240
  return withAgentLock(paths, () => {
126999
127241
  const finalPath = join116(paths.skillsDir, `${slug}.yaml`);
127000
- if (!existsSync111(finalPath))
127242
+ if (!existsSync112(finalPath))
127001
127243
  return false;
127002
127244
  unlinkSync22(finalPath);
127003
127245
  return true;
@@ -127005,7 +127247,7 @@ function deleteSkillsOverlayEntry(agent, slug, opts = {}) {
127005
127247
  }
127006
127248
  function listSkillsOverlayEntries(agent, opts = {}) {
127007
127249
  const paths = overlayPathsFor(agent, opts);
127008
- if (!existsSync111(paths.skillsDir))
127250
+ if (!existsSync112(paths.skillsDir))
127009
127251
  return [];
127010
127252
  const out = [];
127011
127253
  for (const name of readdirSync41(paths.skillsDir)) {
@@ -127013,7 +127255,7 @@ function listSkillsOverlayEntries(agent, opts = {}) {
127013
127255
  continue;
127014
127256
  const full = join116(paths.skillsDir, name);
127015
127257
  try {
127016
- const raw = readFileSync99(full, "utf-8");
127258
+ const raw = readFileSync100(full, "utf-8");
127017
127259
  const slug = name.replace(/\.ya?ml$/i, "");
127018
127260
  out.push({ slug, path: full, raw });
127019
127261
  } catch {}
@@ -127024,7 +127266,7 @@ function deleteOverlayEntry(agent, slug, opts = {}) {
127024
127266
  const paths = overlayPathsFor(agent, opts);
127025
127267
  return withAgentLock(paths, () => {
127026
127268
  const finalPath = join116(paths.scheduleDir, `${slug}.yaml`);
127027
- if (!existsSync111(finalPath))
127269
+ if (!existsSync112(finalPath))
127028
127270
  return false;
127029
127271
  unlinkSync22(finalPath);
127030
127272
  return true;
@@ -127032,7 +127274,7 @@ function deleteOverlayEntry(agent, slug, opts = {}) {
127032
127274
  }
127033
127275
  function listOverlayEntries(agent, opts = {}) {
127034
127276
  const paths = overlayPathsFor(agent, opts);
127035
- if (!existsSync111(paths.scheduleDir))
127277
+ if (!existsSync112(paths.scheduleDir))
127036
127278
  return [];
127037
127279
  const out = [];
127038
127280
  for (const name of readdirSync41(paths.scheduleDir)) {
@@ -127040,7 +127282,7 @@ function listOverlayEntries(agent, opts = {}) {
127040
127282
  continue;
127041
127283
  const full = join116(paths.scheduleDir, name);
127042
127284
  try {
127043
- const raw = readFileSync99(full, "utf-8");
127285
+ const raw = readFileSync100(full, "utf-8");
127044
127286
  const slug = name.replace(/\.ya?ml$/i, "");
127045
127287
  out.push({ slug, path: full, raw });
127046
127288
  } catch {}
@@ -127260,15 +127502,15 @@ function reconcileAgentCronOnly(agent) {
127260
127502
  // src/cli/agent-config-pending.ts
127261
127503
  import {
127262
127504
  closeSync as closeSync21,
127263
- existsSync as existsSync112,
127505
+ existsSync as existsSync113,
127264
127506
  fsyncSync as fsyncSync9,
127265
- mkdirSync as mkdirSync66,
127507
+ mkdirSync as mkdirSync67,
127266
127508
  openSync as openSync21,
127267
127509
  readdirSync as readdirSync42,
127268
- readFileSync as readFileSync100,
127269
- renameSync as renameSync30,
127510
+ readFileSync as readFileSync101,
127511
+ renameSync as renameSync31,
127270
127512
  unlinkSync as unlinkSync23,
127271
- writeFileSync as writeFileSync48,
127513
+ writeFileSync as writeFileSync49,
127272
127514
  writeSync as writeSync11
127273
127515
  } from "node:fs";
127274
127516
  import { join as join117 } from "node:path";
@@ -127280,7 +127522,7 @@ function pendingDir(agent, opts = {}) {
127280
127522
  }
127281
127523
  function ensurePendingDir(agent, opts = {}) {
127282
127524
  const dir = pendingDir(agent, opts);
127283
- mkdirSync66(dir, { recursive: true });
127525
+ mkdirSync67(dir, { recursive: true });
127284
127526
  return dir;
127285
127527
  }
127286
127528
  function newStageId() {
@@ -127309,15 +127551,15 @@ function stagePendingScheduleEntry(opts) {
127309
127551
  } finally {
127310
127552
  closeSync21(fd);
127311
127553
  }
127312
- renameSync30(yamlTmp, yamlPath);
127554
+ renameSync31(yamlTmp, yamlPath);
127313
127555
  }
127314
- writeFileSync48(metaPath, JSON.stringify(meta, null, 2) + `
127556
+ writeFileSync49(metaPath, JSON.stringify(meta, null, 2) + `
127315
127557
  `, { mode: 384 });
127316
127558
  return { stageId, yamlPath, metaPath };
127317
127559
  }
127318
127560
  function listPendingScheduleEntries(agent, opts = {}) {
127319
127561
  const dir = pendingDir(agent, opts);
127320
- if (!existsSync112(dir))
127562
+ if (!existsSync113(dir))
127321
127563
  return [];
127322
127564
  const out = [];
127323
127565
  for (const name of readdirSync42(dir).sort()) {
@@ -127326,10 +127568,10 @@ function listPendingScheduleEntries(agent, opts = {}) {
127326
127568
  const stageId = name.slice(0, -".meta.json".length);
127327
127569
  const metaPath = join117(dir, name);
127328
127570
  const yamlPath = join117(dir, `${stageId}.yaml`);
127329
- if (!existsSync112(yamlPath))
127571
+ if (!existsSync113(yamlPath))
127330
127572
  continue;
127331
127573
  try {
127332
- const meta = JSON.parse(readFileSync100(metaPath, "utf-8"));
127574
+ const meta = JSON.parse(readFileSync101(metaPath, "utf-8"));
127333
127575
  if (meta?.v !== 1 || typeof meta.stage_id !== "string")
127334
127576
  continue;
127335
127577
  out.push({ stageId: meta.stage_id, agent: meta.agent, yamlPath, metaPath, meta });
@@ -127345,10 +127587,10 @@ function commitPendingScheduleEntry(opts) {
127345
127587
  const slug = match.meta.entry.name ?? match.stageId;
127346
127588
  const paths = overlayPathsFor(opts.agent, { root: opts.root });
127347
127589
  const finalPath = join117(paths.scheduleDir, `${slug}.yaml`);
127348
- if (existsSync112(finalPath)) {
127590
+ if (existsSync113(finalPath)) {
127349
127591
  return { committed: false, reason: "slug_collision" };
127350
127592
  }
127351
- renameSync30(match.yamlPath, finalPath);
127593
+ renameSync31(match.yamlPath, finalPath);
127352
127594
  unlinkSync23(match.metaPath);
127353
127595
  return { committed: true, path: finalPath, slug };
127354
127596
  }
@@ -127367,8 +127609,8 @@ function denyPendingScheduleEntry(opts) {
127367
127609
  }
127368
127610
 
127369
127611
  // src/cli/agent-config-write.ts
127370
- import { existsSync as existsSync113, readFileSync as readFileSync101 } from "node:fs";
127371
- import { execFileSync as execFileSync36 } from "node:child_process";
127612
+ import { existsSync as existsSync114, readFileSync as readFileSync102 } from "node:fs";
127613
+ import { execFileSync as execFileSync37 } from "node:child_process";
127372
127614
 
127373
127615
  // src/scheduler/schedule-report.ts
127374
127616
  var TIER_WEIGHT = { poll: 0, action: 0, cheap: 1, main: 5 };
@@ -127757,8 +127999,8 @@ function scheduleRemove(opts) {
127757
127999
  }
127758
128000
  let priorContent = null;
127759
128001
  try {
127760
- if (existsSync113(match.path))
127761
- priorContent = readFileSync101(match.path, "utf-8");
128002
+ if (existsSync114(match.path))
128003
+ priorContent = readFileSync102(match.path, "utf-8");
127762
128004
  } catch {}
127763
128005
  deleteOverlayEntry(agent, match.slug, { root: opts.root });
127764
128006
  const reconcileFn = opts.reconcile === undefined ? opts.root ? null : reconcileAgentCronOnly : opts.reconcile;
@@ -127961,10 +128203,10 @@ function registerAgentConfigWriteCommands(program3) {
127961
128203
  }
127962
128204
  let blob;
127963
128205
  if (opts.jsonl) {
127964
- blob = existsSync113(opts.jsonl) ? readFileSync101(opts.jsonl, "utf-8") : "";
128206
+ blob = existsSync114(opts.jsonl) ? readFileSync102(opts.jsonl, "utf-8") : "";
127965
128207
  } else {
127966
128208
  try {
127967
- blob = execFileSync36("docker", ["exec", `switchroom-${agent}`, "cat", "/state/agent/scheduler.jsonl"], {
128209
+ blob = execFileSync37("docker", ["exec", `switchroom-${agent}`, "cat", "/state/agent/scheduler.jsonl"], {
127968
128210
  encoding: "utf-8",
127969
128211
  stdio: ["ignore", "pipe", "ignore"]
127970
128212
  });
@@ -127993,7 +128235,7 @@ function registerAgentConfigWriteCommands(program3) {
127993
128235
 
127994
128236
  // src/cli/agent-config-skill-write.ts
127995
128237
  var import_yaml24 = __toESM(require_dist(), 1);
127996
- import { existsSync as existsSync114 } from "node:fs";
128238
+ import { existsSync as existsSync115 } from "node:fs";
127997
128239
  init_reconcile_default_skills();
127998
128240
  init_agent_config();
127999
128241
  var import_yaml25 = __toESM(require_dist(), 1);
@@ -128073,7 +128315,7 @@ function skillInstall(opts) {
128073
128315
  }
128074
128316
  const poolDir = opts.bundledSkillsPoolDir ?? getBundledSkillsPoolDir();
128075
128317
  const skillPath = join118(poolDir, skillName);
128076
- if (!existsSync114(skillPath)) {
128318
+ if (!existsSync115(skillPath)) {
128077
128319
  return err("E_SKILL_NOT_FOUND", `bundled skill not found at ${skillPath}. The operator needs to ` + `place the skill at this path before the agent can opt in.`);
128078
128320
  }
128079
128321
  const yamlText = import_yaml24.stringify({ skills: [skillName] });
@@ -128243,21 +128485,21 @@ init_source();
128243
128485
  import {
128244
128486
  chmodSync as chmodSync18,
128245
128487
  closeSync as closeSync22,
128246
- existsSync as existsSync115,
128488
+ existsSync as existsSync116,
128247
128489
  lstatSync as lstatSync15,
128248
- mkdirSync as mkdirSync67,
128490
+ mkdirSync as mkdirSync68,
128249
128491
  mkdtempSync as mkdtempSync6,
128250
128492
  openSync as openSync22,
128251
- readFileSync as readFileSync102,
128493
+ readFileSync as readFileSync103,
128252
128494
  readdirSync as readdirSync43,
128253
128495
  realpathSync as realpathSync10,
128254
- renameSync as renameSync31,
128496
+ renameSync as renameSync32,
128255
128497
  rmSync as rmSync24,
128256
- statSync as statSync67,
128257
- writeFileSync as writeFileSync49
128498
+ statSync as statSync68,
128499
+ writeFileSync as writeFileSync50
128258
128500
  } from "node:fs";
128259
128501
  import { tmpdir as tmpdir7, homedir as homedir60 } from "node:os";
128260
- import { dirname as dirname50, join as join119, relative as relative6, resolve as resolve61 } from "node:path";
128502
+ import { dirname as dirname51, join as join119, relative as relative6, resolve as resolve61 } from "node:path";
128261
128503
  import { spawnSync as spawnSync24 } from "node:child_process";
128262
128504
  var SKILL_NAME_RE = /^[a-z0-9][a-z0-9_-]{0,62}$/;
128263
128505
  var SH_SCRIPT_RE2 = /^scripts\/[A-Za-z0-9_.-]+\.sh$/;
@@ -128303,7 +128545,7 @@ function isTarballPath(p) {
128303
128545
  }
128304
128546
  function loadFromDir(dir) {
128305
128547
  const abs = realpathSync10(dir);
128306
- if (!statSync67(abs).isDirectory()) {
128548
+ if (!statSync68(abs).isDirectory()) {
128307
128549
  fail4(`--from path is not a directory: ${dir}`);
128308
128550
  }
128309
128551
  const files = {};
@@ -128320,7 +128562,7 @@ function loadFromDir(dir) {
128320
128562
  continue;
128321
128563
  }
128322
128564
  if (ent.isFile()) {
128323
- const buf = readFileSync102(full);
128565
+ const buf = readFileSync103(full);
128324
128566
  files[rel.replace(/\\/g, "/")] = buf.toString("utf-8");
128325
128567
  }
128326
128568
  }
@@ -128369,7 +128611,7 @@ function loadFromTarball(tarPath) {
128369
128611
  }
128370
128612
  }
128371
128613
  function loadSingleFile(filePath) {
128372
- const content = readFileSync102(filePath, "utf-8");
128614
+ const content = readFileSync103(filePath, "utf-8");
128373
128615
  return { "SKILL.md": content };
128374
128616
  }
128375
128617
  function loadFromStdin() {
@@ -128434,7 +128676,7 @@ function validatePayload(name, files) {
128434
128676
  const tmp = mkdtempSync6(join119(tmpdir7(), "skill-apply-py-"));
128435
128677
  const tmpPy = join119(tmp, "check.py");
128436
128678
  try {
128437
- writeFileSync49(tmpPy, content);
128679
+ writeFileSync50(tmpPy, content);
128438
128680
  const r = spawnSync24("python3", ["-m", "py_compile", tmpPy], {
128439
128681
  encoding: "utf-8"
128440
128682
  });
@@ -128452,7 +128694,7 @@ function validatePayload(name, files) {
128452
128694
  function diffSummary(currentDir, files) {
128453
128695
  const lines = [];
128454
128696
  const currentFiles = {};
128455
- if (existsSync115(currentDir)) {
128697
+ if (existsSync116(currentDir)) {
128456
128698
  const walk2 = (sub) => {
128457
128699
  for (const ent of readdirSync43(sub, { withFileTypes: true })) {
128458
128700
  const full = join119(sub, ent.name);
@@ -128460,7 +128702,7 @@ function diffSummary(currentDir, files) {
128460
128702
  if (ent.isDirectory()) {
128461
128703
  walk2(full);
128462
128704
  } else if (ent.isFile()) {
128463
- currentFiles[rel.replace(/\\/g, "/")] = readFileSync102(full, "utf-8");
128705
+ currentFiles[rel.replace(/\\/g, "/")] = readFileSync103(full, "utf-8");
128464
128706
  }
128465
128707
  }
128466
128708
  };
@@ -128488,8 +128730,8 @@ function diffSummary(currentDir, files) {
128488
128730
  `);
128489
128731
  }
128490
128732
  function writePayload(poolDir, name, files) {
128491
- if (!existsSync115(poolDir)) {
128492
- mkdirSync67(poolDir, { recursive: true, mode: 493 });
128733
+ if (!existsSync116(poolDir)) {
128734
+ mkdirSync68(poolDir, { recursive: true, mode: 493 });
128493
128735
  }
128494
128736
  const target = join119(poolDir, name);
128495
128737
  let targetIsSymlink = false;
@@ -128508,10 +128750,10 @@ function writePayload(poolDir, name, files) {
128508
128750
  try {
128509
128751
  for (const [path10, content] of Object.entries(files)) {
128510
128752
  const full = join119(staging, path10);
128511
- mkdirSync67(dirname50(full), { recursive: true, mode: 493 });
128753
+ mkdirSync68(dirname51(full), { recursive: true, mode: 493 });
128512
128754
  const fd = openSync22(full, "wx");
128513
128755
  try {
128514
- writeFileSync49(fd, content);
128756
+ writeFileSync50(fd, content);
128515
128757
  } finally {
128516
128758
  closeSync22(fd);
128517
128759
  }
@@ -128527,9 +128769,9 @@ function writePayload(poolDir, name, files) {
128527
128769
  } catch {}
128528
128770
  if (targetExists) {
128529
128771
  oldRename = `${target}.skill-apply-old-${Date.now()}`;
128530
- renameSync31(target, oldRename);
128772
+ renameSync32(target, oldRename);
128531
128773
  }
128532
- renameSync31(staging, target);
128774
+ renameSync32(staging, target);
128533
128775
  if (oldRename) {
128534
128776
  rmSync24(oldRename, { recursive: true, force: true });
128535
128777
  oldRename = null;
@@ -128538,12 +128780,12 @@ function writePayload(poolDir, name, files) {
128538
128780
  try {
128539
128781
  rmSync24(staging, { recursive: true, force: true });
128540
128782
  } catch {}
128541
- if (oldRename && existsSync115(oldRename)) {
128783
+ if (oldRename && existsSync116(oldRename)) {
128542
128784
  try {
128543
- if (existsSync115(target)) {
128785
+ if (existsSync116(target)) {
128544
128786
  rmSync24(target, { recursive: true, force: true });
128545
128787
  }
128546
- renameSync31(oldRename, target);
128788
+ renameSync32(oldRename, target);
128547
128789
  } catch {}
128548
128790
  }
128549
128791
  throw err2;
@@ -128561,10 +128803,10 @@ function registerSkillCommand(program3) {
128561
128803
  files = loadFromStdin();
128562
128804
  } else {
128563
128805
  const fromPath = resolve61(opts.from);
128564
- if (!existsSync115(fromPath)) {
128806
+ if (!existsSync116(fromPath)) {
128565
128807
  fail4(`--from path does not exist: ${opts.from}`);
128566
128808
  }
128567
- const st = statSync67(fromPath);
128809
+ const st = statSync68(fromPath);
128568
128810
  if (st.isDirectory()) {
128569
128811
  files = loadFromDir(fromPath);
128570
128812
  } else if (isTarballPath(fromPath)) {
@@ -128622,20 +128864,20 @@ init_source();
128622
128864
  import {
128623
128865
  chmodSync as chmodSync19,
128624
128866
  closeSync as closeSync23,
128625
- existsSync as existsSync116,
128867
+ existsSync as existsSync117,
128626
128868
  lstatSync as lstatSync16,
128627
- mkdirSync as mkdirSync68,
128869
+ mkdirSync as mkdirSync69,
128628
128870
  mkdtempSync as mkdtempSync7,
128629
128871
  openSync as openSync23,
128630
- readFileSync as readFileSync103,
128872
+ readFileSync as readFileSync104,
128631
128873
  readdirSync as readdirSync44,
128632
- renameSync as renameSync32,
128874
+ renameSync as renameSync33,
128633
128875
  rmSync as rmSync25,
128634
- statSync as statSync68,
128876
+ statSync as statSync69,
128635
128877
  utimesSync,
128636
- writeFileSync as writeFileSync50
128878
+ writeFileSync as writeFileSync51
128637
128879
  } from "node:fs";
128638
- import { dirname as dirname51, join as join120, relative as relative7, resolve as resolve62 } from "node:path";
128880
+ import { dirname as dirname52, join as join120, relative as relative7, resolve as resolve62 } from "node:path";
128639
128881
  import { homedir as homedir61, tmpdir as tmpdir8 } from "node:os";
128640
128882
  import { spawnSync as spawnSync25 } from "node:child_process";
128641
128883
  var PERSONAL_PREFIX = "personal-";
@@ -128645,14 +128887,14 @@ var PERSONAL_SKILLS_SUBPATH2 = "personal-skills";
128645
128887
  function resolveConfigSkillsDir(agent) {
128646
128888
  const override = process.env.SWITCHROOM_CONFIG_DIR;
128647
128889
  const candidate = override ? resolve62(override) : join120(homedir61(), ".switchroom-config");
128648
- if (!existsSync116(candidate))
128890
+ if (!existsSync117(candidate))
128649
128891
  return null;
128650
128892
  return join120(candidate, "agents", agent, PERSONAL_SKILLS_SUBPATH2);
128651
128893
  }
128652
128894
  var MIRROR_PRIOR_TTL_MS = 24 * 60 * 60 * 1000;
128653
128895
  function sweepMirrorPriors(configSkillsRoot) {
128654
128896
  try {
128655
- if (!existsSync116(configSkillsRoot))
128897
+ if (!existsSync117(configSkillsRoot))
128656
128898
  return;
128657
128899
  const now2 = Date.now();
128658
128900
  for (const ent of readdirSync44(configSkillsRoot)) {
@@ -128688,17 +128930,17 @@ function mirrorToConfigRepo(agent, name, liveSkillDir) {
128688
128930
  }
128689
128931
  if (liveSkillDir === null) {
128690
128932
  sweepMirrorPriors(configSkillsRoot);
128691
- if (existsSync116(dest)) {
128933
+ if (existsSync117(dest)) {
128692
128934
  const trash = join120(configSkillsRoot, `.${name}-trash-${Date.now()}`);
128693
- renameSync32(dest, trash);
128935
+ renameSync33(dest, trash);
128694
128936
  }
128695
128937
  return;
128696
128938
  }
128697
- mkdirSync68(configSkillsRoot, { recursive: true, mode: 493 });
128939
+ mkdirSync69(configSkillsRoot, { recursive: true, mode: 493 });
128698
128940
  sweepMirrorPriors(configSkillsRoot);
128699
128941
  const staging = mkdtempSync7(join120(configSkillsRoot, `.${name}-staging-`));
128700
128942
  const walk2 = (src, dst) => {
128701
- mkdirSync68(dst, { recursive: true, mode: 493 });
128943
+ mkdirSync69(dst, { recursive: true, mode: 493 });
128702
128944
  for (const ent of readdirSync44(src, { withFileTypes: true })) {
128703
128945
  const s = join120(src, ent.name);
128704
128946
  const d = join120(dst, ent.name);
@@ -128707,17 +128949,17 @@ function mirrorToConfigRepo(agent, name, liveSkillDir) {
128707
128949
  if (ent.isDirectory())
128708
128950
  walk2(s, d);
128709
128951
  else if (ent.isFile()) {
128710
- writeFileSync50(d, readFileSync103(s));
128952
+ writeFileSync51(d, readFileSync104(s));
128711
128953
  }
128712
128954
  }
128713
128955
  };
128714
128956
  walk2(liveSkillDir, staging);
128715
128957
  chmodSync19(staging, 493);
128716
- if (existsSync116(dest)) {
128958
+ if (existsSync117(dest)) {
128717
128959
  const prior = join120(configSkillsRoot, `.${name}-prior-${Date.now()}`);
128718
- renameSync32(dest, prior);
128960
+ renameSync33(dest, prior);
128719
128961
  }
128720
- renameSync32(staging, dest);
128962
+ renameSync33(staging, dest);
128721
128963
  } catch (err2) {
128722
128964
  process.stderr.write(source_default.yellow(`warning: mirror to ${dest} failed (${err2.message ?? err2}); ` + `live copy still works, but this skill is not version-controlled until next successful sync.
128723
128965
  `));
@@ -128754,7 +128996,7 @@ function trashDir(agentsRoot, agent) {
128754
128996
  }
128755
128997
  function countPersonalSkills(agentsRoot, agent) {
128756
128998
  const skillsDir = join120(agentsRoot, agent, ".claude", "skills");
128757
- if (!existsSync116(skillsDir))
128999
+ if (!existsSync117(skillsDir))
128758
129000
  return 0;
128759
129001
  let n = 0;
128760
129002
  for (const ent of readdirSync44(skillsDir, { withFileTypes: true })) {
@@ -128785,7 +129027,7 @@ function readStdinSync2() {
128785
129027
  }
128786
129028
  function loadFromDir2(dir) {
128787
129029
  const abs = resolve62(dir);
128788
- if (!statSync68(abs).isDirectory()) {
129030
+ if (!statSync69(abs).isDirectory()) {
128789
129031
  fail5(`--from path is not a directory: ${dir}`);
128790
129032
  }
128791
129033
  const files = {};
@@ -128801,7 +129043,7 @@ function loadFromDir2(dir) {
128801
129043
  }
128802
129044
  if (ent.isFile()) {
128803
129045
  const rel = relative7(abs, full).replace(/\\/g, "/");
128804
- files[rel] = readFileSync103(full, "utf-8");
129046
+ files[rel] = readFileSync104(full, "utf-8");
128805
129047
  }
128806
129048
  }
128807
129049
  };
@@ -128847,7 +129089,7 @@ function behavioralValidate(files) {
128847
129089
  const tmp = mkdtempSync7(join120(tmpdir8(), "skill-personal-py-"));
128848
129090
  const tmpPy = join120(tmp, "check.py");
128849
129091
  try {
128850
- writeFileSync50(tmpPy, content);
129092
+ writeFileSync51(tmpPy, content);
128851
129093
  const r = spawnSync25("python3", ["-m", "py_compile", tmpPy], {
128852
129094
  encoding: "utf-8"
128853
129095
  });
@@ -128863,7 +129105,7 @@ function behavioralValidate(files) {
128863
129105
  }
128864
129106
  function sweepTrash(agentsRoot, agent) {
128865
129107
  const trash = trashDir(agentsRoot, agent);
128866
- if (!existsSync116(trash))
129108
+ if (!existsSync117(trash))
128867
129109
  return;
128868
129110
  const now2 = Date.now();
128869
129111
  for (const ent of readdirSync44(trash, { withFileTypes: true })) {
@@ -128871,7 +129113,7 @@ function sweepTrash(agentsRoot, agent) {
128871
129113
  continue;
128872
129114
  const entPath = join120(trash, ent.name);
128873
129115
  try {
128874
- const st = statSync68(entPath);
129116
+ const st = statSync69(entPath);
128875
129117
  if (now2 - st.mtimeMs > TRASH_TTL_MS) {
128876
129118
  rmSync25(entPath, { recursive: true, force: true });
128877
129119
  }
@@ -128889,17 +129131,17 @@ function writePersonalSkill(targetDir, files) {
128889
129131
  if (targetIsSymlink) {
128890
129132
  fail5(`refusing to overwrite symlink at ${targetDir}; investigate manually`);
128891
129133
  }
128892
- mkdirSync68(dirname51(targetDir), { recursive: true, mode: 493 });
128893
- const staging = mkdtempSync7(join120(dirname51(targetDir), `.skill-personal-stage-`));
129134
+ mkdirSync69(dirname52(targetDir), { recursive: true, mode: 493 });
129135
+ const staging = mkdtempSync7(join120(dirname52(targetDir), `.skill-personal-stage-`));
128894
129136
  chmodSync19(staging, 493);
128895
129137
  let oldRename = null;
128896
129138
  try {
128897
129139
  for (const [path10, content] of Object.entries(files)) {
128898
129140
  const full = join120(staging, path10);
128899
- mkdirSync68(dirname51(full), { recursive: true, mode: 493 });
129141
+ mkdirSync69(dirname52(full), { recursive: true, mode: 493 });
128900
129142
  const fd = openSync23(full, "wx");
128901
129143
  try {
128902
- writeFileSync50(fd, content);
129144
+ writeFileSync51(fd, content);
128903
129145
  } finally {
128904
129146
  closeSync23(fd);
128905
129147
  }
@@ -128915,9 +129157,9 @@ function writePersonalSkill(targetDir, files) {
128915
129157
  } catch {}
128916
129158
  if (targetExists) {
128917
129159
  oldRename = `${targetDir}.personal-old-${Date.now()}`;
128918
- renameSync32(targetDir, oldRename);
129160
+ renameSync33(targetDir, oldRename);
128919
129161
  }
128920
- renameSync32(staging, targetDir);
129162
+ renameSync33(staging, targetDir);
128921
129163
  if (oldRename) {
128922
129164
  rmSync25(oldRename, { recursive: true, force: true });
128923
129165
  oldRename = null;
@@ -128926,12 +129168,12 @@ function writePersonalSkill(targetDir, files) {
128926
129168
  try {
128927
129169
  rmSync25(staging, { recursive: true, force: true });
128928
129170
  } catch {}
128929
- if (oldRename && existsSync116(oldRename)) {
129171
+ if (oldRename && existsSync117(oldRename)) {
128930
129172
  try {
128931
- if (existsSync116(targetDir)) {
129173
+ if (existsSync117(targetDir)) {
128932
129174
  rmSync25(targetDir, { recursive: true, force: true });
128933
129175
  }
128934
- renameSync32(oldRename, targetDir);
129176
+ renameSync33(oldRename, targetDir);
128935
129177
  } catch {}
128936
129178
  }
128937
129179
  throw err2;
@@ -128994,15 +129236,15 @@ function loadFiles(opts) {
128994
129236
  return loadFromStdin2();
128995
129237
  }
128996
129238
  const p = resolve62(opts.from);
128997
- if (!existsSync116(p)) {
129239
+ if (!existsSync117(p)) {
128998
129240
  fail5(`--from path does not exist: ${opts.from}`);
128999
129241
  }
129000
- const st = statSync68(p);
129242
+ const st = statSync69(p);
129001
129243
  if (st.isDirectory()) {
129002
129244
  return loadFromDir2(p);
129003
129245
  }
129004
129246
  if (p.endsWith(".md")) {
129005
- return { "SKILL.md": readFileSync103(p, "utf-8") };
129247
+ return { "SKILL.md": readFileSync104(p, "utf-8") };
129006
129248
  }
129007
129249
  fail5(`--from must be a directory or a .md file. Got: ${opts.from}`);
129008
129250
  }
@@ -129056,7 +129298,7 @@ function resolveCloneSource(source, opts) {
129056
129298
  const slug = m[2];
129057
129299
  const root = tier === "bundled" ? opts.bundledRoot ?? defaultBundledRoot() : opts.sharedRoot ?? defaultSharedRoot();
129058
129300
  const dir = join120(root, slug);
129059
- if (!existsSync116(dir)) {
129301
+ if (!existsSync117(dir)) {
129060
129302
  fail5(`clone source ${JSON.stringify(source)} not found at ${dir}; ` + `check \`switchroom skill search --tier ${tier}\``, 1);
129061
129303
  }
129062
129304
  const st = lstatSync16(dir);
@@ -129091,7 +129333,7 @@ function readSourceFiles(dir) {
129091
129333
  fail5(`clone source has oversized file ${rel} (${st.size} bytes > ${CLONE_MAX_FILE_BYTES}); ` + `refuse to read`, 3);
129092
129334
  }
129093
129335
  } catch {}
129094
- files[rel] = readFileSync103(full, "utf-8");
129336
+ files[rel] = readFileSync104(full, "utf-8");
129095
129337
  }
129096
129338
  }
129097
129339
  };
@@ -129180,10 +129422,10 @@ function removePersonalAction(name, opts) {
129180
129422
  throw err2;
129181
129423
  }
129182
129424
  const trashRoot2 = trashDir(agentsRoot, agent);
129183
- mkdirSync68(trashRoot2, { recursive: true, mode: 493 });
129425
+ mkdirSync69(trashRoot2, { recursive: true, mode: 493 });
129184
129426
  const ts = Date.now();
129185
129427
  const trashTarget = join120(trashRoot2, `${name}-${ts}`);
129186
- renameSync32(target, trashTarget);
129428
+ renameSync33(target, trashTarget);
129187
129429
  const now2 = new Date(ts);
129188
129430
  utimesSync(trashTarget, now2, now2);
129189
129431
  mirrorToConfigRepo(agent, name, null);
@@ -129203,7 +129445,7 @@ function listPersonalAction(opts) {
129203
129445
  sweepTrash(agentsRoot, agent);
129204
129446
  const skillsDir = join120(agentsRoot, agent, ".claude", "skills");
129205
129447
  const personal = [];
129206
- if (existsSync116(skillsDir)) {
129448
+ if (existsSync117(skillsDir)) {
129207
129449
  for (const ent of readdirSync44(skillsDir, { withFileTypes: true })) {
129208
129450
  if (!ent.isDirectory())
129209
129451
  continue;
@@ -129218,7 +129460,7 @@ function listPersonalAction(opts) {
129218
129460
  if (e.isFile()) {
129219
129461
  fileCount += 1;
129220
129462
  try {
129221
- totalBytes += statSync68(join120(sub, e.name)).size;
129463
+ totalBytes += statSync69(join120(sub, e.name)).size;
129222
129464
  } catch {}
129223
129465
  } else if (e.isDirectory()) {
129224
129466
  walk2(join120(sub, e.name));
@@ -129261,7 +129503,7 @@ function registerSkillPersonalCommands(program3) {
129261
129503
  import { createConnection as createConnection4 } from "node:net";
129262
129504
  import { homedir as homedir62 } from "node:os";
129263
129505
  import { join as join121 } from "node:path";
129264
- import { readFileSync as readFileSync104 } from "node:fs";
129506
+ import { readFileSync as readFileSync105 } from "node:fs";
129265
129507
 
129266
129508
  // src/self-improve/skill-proposals.ts
129267
129509
  var REJECTION_TTL_MS = 90 * 24 * 60 * 60 * 1000;
@@ -129350,7 +129592,7 @@ function registerSelfImproveProposeSkillCommand(program3) {
129350
129592
  }
129351
129593
  let draft;
129352
129594
  try {
129353
- draft = JSON.parse(readFileSync104(opts.draft, "utf-8"));
129595
+ draft = JSON.parse(readFileSync105(opts.draft, "utf-8"));
129354
129596
  } catch (e) {
129355
129597
  fail6(`failed to read/parse --draft: ${e.message}`);
129356
129598
  }
@@ -129389,10 +129631,10 @@ function registerSelfImproveProposeSkillCommand(program3) {
129389
129631
  import { createConnection as createConnection5 } from "node:net";
129390
129632
  import { homedir as homedir63 } from "node:os";
129391
129633
  import { join as join125, resolve as resolve63, sep as sep10 } from "node:path";
129392
- import { existsSync as existsSync121, readFileSync as readFileSync109, realpathSync as realpathSync11 } from "node:fs";
129634
+ import { existsSync as existsSync122, readFileSync as readFileSync110, realpathSync as realpathSync11 } from "node:fs";
129393
129635
 
129394
129636
  // src/self-improve/apply-guard.ts
129395
- import { existsSync as existsSync119, lstatSync as lstatSync17, readFileSync as readFileSync107, statSync as statSync70 } from "node:fs";
129637
+ import { existsSync as existsSync120, lstatSync as lstatSync17, readFileSync as readFileSync108, statSync as statSync71 } from "node:fs";
129396
129638
 
129397
129639
  // src/self-improve/config.ts
129398
129640
  function intEnv(name, def) {
@@ -129413,7 +129655,7 @@ function resolveSelfImproveConfig() {
129413
129655
  }
129414
129656
 
129415
129657
  // src/self-improve/eval-gate.ts
129416
- import { existsSync as existsSync117, readFileSync as readFileSync105, readdirSync as readdirSync45, statSync as statSync69 } from "node:fs";
129658
+ import { existsSync as existsSync118, readFileSync as readFileSync106, readdirSync as readdirSync45, statSync as statSync70 } from "node:fs";
129417
129659
  import { join as join122 } from "node:path";
129418
129660
  import { spawnSync as spawnSync26 } from "node:child_process";
129419
129661
  function evalsJsonPath(skillDir) {
@@ -129421,10 +129663,10 @@ function evalsJsonPath(skillDir) {
129421
129663
  }
129422
129664
  function skillHasEvals(skillDir) {
129423
129665
  const p = evalsJsonPath(skillDir);
129424
- if (!existsSync117(p))
129666
+ if (!existsSync118(p))
129425
129667
  return false;
129426
129668
  try {
129427
- const parsed = JSON.parse(readFileSync105(p, "utf-8"));
129669
+ const parsed = JSON.parse(readFileSync106(p, "utf-8"));
129428
129670
  return Array.isArray(parsed.evals) && parsed.evals.length > 0;
129429
129671
  } catch {
129430
129672
  return false;
@@ -129432,7 +129674,7 @@ function skillHasEvals(skillDir) {
129432
129674
  }
129433
129675
  function aggregateBenchmark(benchmarkDir, repoRoot, pythonBin = process.env.SWITCHROOM_PYTHON ?? "python3") {
129434
129676
  const script = join122(repoRoot, "skills", "skill-creator", "scripts", "aggregate_benchmark.py");
129435
- if (!existsSync117(script)) {
129677
+ if (!existsSync118(script)) {
129436
129678
  return { ok: false, error: `aggregate_benchmark.py not found at ${script}` };
129437
129679
  }
129438
129680
  const r = spawnSync26(pythonBin, [script, benchmarkDir], {
@@ -129449,7 +129691,7 @@ function aggregateBenchmark(benchmarkDir, repoRoot, pythonBin = process.env.SWIT
129449
129691
  }
129450
129692
  function isBenchmarkDir(dir) {
129451
129693
  try {
129452
- if (!statSync69(dir).isDirectory())
129694
+ if (!statSync70(dir).isDirectory())
129453
129695
  return false;
129454
129696
  } catch {
129455
129697
  return false;
@@ -129464,7 +129706,7 @@ function isBenchmarkDir(dir) {
129464
129706
  if (hasEvalDirs(dir))
129465
129707
  return true;
129466
129708
  const runs = join122(dir, "runs");
129467
- return existsSync117(runs) && hasEvalDirs(runs);
129709
+ return existsSync118(runs) && hasEvalDirs(runs);
129468
129710
  }
129469
129711
  function resolveBenchmarkDir(baseDir, explicit) {
129470
129712
  if (explicit != null && explicit.length > 0) {
@@ -129480,7 +129722,7 @@ function resolveBenchmarkDir(baseDir, explicit) {
129480
129722
  }
129481
129723
  if (entries.length === 0)
129482
129724
  return null;
129483
- entries.sort((a, b) => statSync69(b).mtimeMs - statSync69(a).mtimeMs);
129725
+ entries.sort((a, b) => statSync70(b).mtimeMs - statSync70(a).mtimeMs);
129484
129726
  return entries[0];
129485
129727
  }
129486
129728
  var CANDIDATE_CONFIGS = ["with_skill", "candidate", "new_skill", "after"];
@@ -129497,7 +129739,7 @@ function pickPassRate(summary, names) {
129497
129739
  function evalVerdict(benchmarkJson, _cfg = resolveSelfImproveConfig()) {
129498
129740
  let bench;
129499
129741
  try {
129500
- bench = JSON.parse(readFileSync105(benchmarkJson, "utf-8"));
129742
+ bench = JSON.parse(readFileSync106(benchmarkJson, "utf-8"));
129501
129743
  } catch (err2) {
129502
129744
  return { pass: false, reason: `unreadable benchmark.json: ${err2.message}` };
129503
129745
  }
@@ -129543,16 +129785,16 @@ function floatEnv(name, def) {
129543
129785
  import {
129544
129786
  closeSync as closeSync24,
129545
129787
  copyFileSync as copyFileSync15,
129546
- existsSync as existsSync118,
129547
- mkdirSync as mkdirSync69,
129788
+ existsSync as existsSync119,
129789
+ mkdirSync as mkdirSync70,
129548
129790
  openSync as openSync24,
129549
- readFileSync as readFileSync106,
129791
+ readFileSync as readFileSync107,
129550
129792
  readdirSync as readdirSync46,
129551
- renameSync as renameSync33,
129552
- writeFileSync as writeFileSync51,
129793
+ renameSync as renameSync34,
129794
+ writeFileSync as writeFileSync52,
129553
129795
  writeSync as writeSync12
129554
129796
  } from "node:fs";
129555
- import { dirname as dirname52, join as join123 } from "node:path";
129797
+ import { dirname as dirname53, join as join123 } from "node:path";
129556
129798
  import { createHash as createHash22 } from "node:crypto";
129557
129799
 
129558
129800
  // src/self-improve/pii-scan.ts
@@ -129690,10 +129932,10 @@ function caseFingerprint(prompt) {
129690
129932
  }
129691
129933
  function readEvalsDoc(skillDir) {
129692
129934
  const p = evalsJsonPath(skillDir);
129693
- if (!existsSync118(p))
129935
+ if (!existsSync119(p))
129694
129936
  return null;
129695
129937
  try {
129696
- const parsed = JSON.parse(readFileSync106(p, "utf-8"));
129938
+ const parsed = JSON.parse(readFileSync107(p, "utf-8"));
129697
129939
  if (!parsed || typeof parsed !== "object" || !Array.isArray(parsed.evals)) {
129698
129940
  return null;
129699
129941
  }
@@ -129703,10 +129945,10 @@ function readEvalsDoc(skillDir) {
129703
129945
  }
129704
129946
  }
129705
129947
  function writeAtomic(path10, content) {
129706
- mkdirSync69(dirname52(path10), { recursive: true });
129948
+ mkdirSync70(dirname53(path10), { recursive: true });
129707
129949
  const tmp = `${path10}.tmp-${process.pid}-${Date.now()}`;
129708
- writeFileSync51(tmp, content, { encoding: "utf-8", mode: 420 });
129709
- renameSync33(tmp, path10);
129950
+ writeFileSync52(tmp, content, { encoding: "utf-8", mode: 420 });
129951
+ renameSync34(tmp, path10);
129710
129952
  }
129711
129953
  function appendEvalCase(skillDir, slug, input) {
129712
129954
  const parsed = parseEvalCase(input);
@@ -129714,7 +129956,7 @@ function appendEvalCase(skillDir, slug, input) {
129714
129956
  return { ok: false, reason: parsed.error };
129715
129957
  const ec = parsed.case;
129716
129958
  const existingDoc = readEvalsDoc(skillDir);
129717
- if (existingDoc === null && existsSync118(evalsJsonPath(skillDir))) {
129959
+ if (existingDoc === null && existsSync119(evalsJsonPath(skillDir))) {
129718
129960
  return {
129719
129961
  ok: false,
129720
129962
  reason: "evals.json exists but is unparseable or malformed \u2014 refusing to " + "overwrite it (fix or remove the file first)"
@@ -129746,11 +129988,11 @@ function heldOutPath(stateDir) {
129746
129988
  }
129747
129989
  function heldOutHasFingerprint(stateDir, slug, fp) {
129748
129990
  const path10 = heldOutPath(stateDir);
129749
- if (!existsSync118(path10))
129991
+ if (!existsSync119(path10))
129750
129992
  return false;
129751
129993
  let text;
129752
129994
  try {
129753
- text = readFileSync106(path10, "utf-8");
129995
+ text = readFileSync107(path10, "utf-8");
129754
129996
  } catch {
129755
129997
  return false;
129756
129998
  }
@@ -129778,7 +130020,7 @@ function appendHeldOutCase(stateDir, slug, ec, opts = {}) {
129778
130020
  };
129779
130021
  }
129780
130022
  const now2 = opts.now ?? Date.now;
129781
- mkdirSync69(stateDir, { recursive: true });
130023
+ mkdirSync70(stateDir, { recursive: true });
129782
130024
  const fd = openSync24(heldOutPath(stateDir), "a");
129783
130025
  try {
129784
130026
  writeSync12(fd, JSON.stringify({ at: new Date(now2()).toISOString(), slug, case: ec }) + `
@@ -129798,20 +130040,20 @@ function baselineEvalsPath(stateDir, slug) {
129798
130040
  }
129799
130041
  function evalsSha256(skillDir) {
129800
130042
  const p = evalsJsonPath(skillDir);
129801
- if (!existsSync118(p))
130043
+ if (!existsSync119(p))
129802
130044
  return null;
129803
130045
  try {
129804
- return createHash22("sha256").update(readFileSync106(p)).digest("hex");
130046
+ return createHash22("sha256").update(readFileSync107(p)).digest("hex");
129805
130047
  } catch {
129806
130048
  return null;
129807
130049
  }
129808
130050
  }
129809
130051
  function readManifest(stateDir) {
129810
130052
  const p = manifestPath(stateDir);
129811
- if (!existsSync118(p))
130053
+ if (!existsSync119(p))
129812
130054
  return {};
129813
130055
  try {
129814
- const parsed = JSON.parse(readFileSync106(p, "utf-8"));
130056
+ const parsed = JSON.parse(readFileSync107(p, "utf-8"));
129815
130057
  return parsed && typeof parsed === "object" ? parsed : {};
129816
130058
  } catch {
129817
130059
  return {};
@@ -129830,7 +130072,7 @@ function recordEvalBaseline(stateDir, slug, skillDir, opts = {}) {
129830
130072
  m[slug] = { sha256: sha, updated_at: new Date(now2()).toISOString(), skill_dir: skillDir };
129831
130073
  writeManifest(stateDir, m);
129832
130074
  const snap = baselineEvalsPath(stateDir, slug);
129833
- mkdirSync69(dirname52(snap), { recursive: true });
130075
+ mkdirSync70(dirname53(snap), { recursive: true });
129834
130076
  copyFileSync15(evalsJsonPath(skillDir), snap);
129835
130077
  }
129836
130078
 
@@ -129850,13 +130092,13 @@ function ownsSkill(skillDir) {
129850
130092
  // src/self-improve/eval-case-proposals.ts
129851
130093
  import {
129852
130094
  closeSync as closeSync25,
129853
- existsSync as existsSync120,
129854
- mkdirSync as mkdirSync70,
130095
+ existsSync as existsSync121,
130096
+ mkdirSync as mkdirSync71,
129855
130097
  openSync as openSync25,
129856
- readFileSync as readFileSync108,
129857
- renameSync as renameSync34,
130098
+ readFileSync as readFileSync109,
130099
+ renameSync as renameSync35,
129858
130100
  unlinkSync as unlinkSync24,
129859
- writeFileSync as writeFileSync52,
130101
+ writeFileSync as writeFileSync53,
129860
130102
  writeSync as writeSync13
129861
130103
  } from "node:fs";
129862
130104
  import { join as join124 } from "node:path";
@@ -129869,11 +130111,11 @@ function isRecord2(v) {
129869
130111
  }
129870
130112
  function readEvalCaseProposals(stateDir) {
129871
130113
  const p = proposalsPath(stateDir);
129872
- if (!existsSync120(p))
130114
+ if (!existsSync121(p))
129873
130115
  return [];
129874
130116
  let raw;
129875
130117
  try {
129876
- raw = readFileSync108(p, "utf-8");
130118
+ raw = readFileSync109(p, "utf-8");
129877
130119
  } catch {
129878
130120
  return [];
129879
130121
  }
@@ -129972,7 +130214,7 @@ function buildCaseFromOpts(opts) {
129972
130214
  let raw;
129973
130215
  if (opts.case) {
129974
130216
  try {
129975
- raw = JSON.parse(readFileSync109(opts.case, "utf-8"));
130217
+ raw = JSON.parse(readFileSync110(opts.case, "utf-8"));
129976
130218
  } catch (e) {
129977
130219
  fail7(`failed to read/parse --case: ${e.message}`);
129978
130220
  }
@@ -130066,7 +130308,7 @@ function registerApply(parent) {
130066
130308
  }));
130067
130309
  process.exit(0);
130068
130310
  }
130069
- if (!existsSync121(proposal.skill_dir)) {
130311
+ if (!existsSync122(proposal.skill_dir)) {
130070
130312
  fail7(`skill dir gone: ${proposal.skill_dir}`);
130071
130313
  }
130072
130314
  const { dir, resolvedDir } = authorizeApplyTarget(proposal.skill_dir, proposal.skill_slug);
@@ -130104,7 +130346,7 @@ function registerSelfImproveEvalCaseCommands(program3) {
130104
130346
 
130105
130347
  // src/cli/self-improve-bench.ts
130106
130348
  import { homedir as homedir64 } from "node:os";
130107
- import { dirname as dirname53, join as join126 } from "node:path";
130349
+ import { dirname as dirname54, join as join126 } from "node:path";
130108
130350
  init_shipped_assets();
130109
130351
  function fail8(msg, code = 1) {
130110
130352
  console.error(msg);
@@ -130129,7 +130371,7 @@ function resolveAggregatorRepoRoot() {
130129
130371
  `);
130130
130372
  return null;
130131
130373
  }
130132
- return dirname53(res.path);
130374
+ return dirname54(res.path);
130133
130375
  }
130134
130376
  function registerSelfImproveBenchCommand(program3) {
130135
130377
  const parent = program3.commands.find((c) => c.name() === "self-improve") ?? program3.command("self-improve").description("Agent self-improvement ops");
@@ -130179,7 +130421,7 @@ function registerSelfImproveBenchCommand(program3) {
130179
130421
  init_esm();
130180
130422
  init_helpers();
130181
130423
  var import_yaml26 = __toESM(require_dist(), 1);
130182
- import { existsSync as existsSync122, readdirSync as readdirSync47, readFileSync as readFileSync110, statSync as statSync71 } from "node:fs";
130424
+ import { existsSync as existsSync123, readdirSync as readdirSync47, readFileSync as readFileSync111, statSync as statSync72 } from "node:fs";
130183
130425
  import { homedir as homedir65 } from "node:os";
130184
130426
  import { join as join127, resolve as resolve64 } from "node:path";
130185
130427
  var PERSONAL_PREFIX2 = "personal-";
@@ -130196,11 +130438,11 @@ function defaultBundledRoot2() {
130196
130438
  }
130197
130439
  function readSkillFrontmatter(skillDir) {
130198
130440
  const mdPath = join127(skillDir, "SKILL.md");
130199
- if (!existsSync122(mdPath))
130441
+ if (!existsSync123(mdPath))
130200
130442
  return null;
130201
130443
  let content;
130202
130444
  try {
130203
- content = readFileSync110(mdPath, "utf-8");
130445
+ content = readFileSync111(mdPath, "utf-8");
130204
130446
  } catch {
130205
130447
  return null;
130206
130448
  }
@@ -130230,7 +130472,7 @@ function readSkillFrontmatter(skillDir) {
130230
130472
  function statSkillMd(skillDir) {
130231
130473
  const mdPath = join127(skillDir, "SKILL.md");
130232
130474
  try {
130233
- const st = statSync71(mdPath);
130475
+ const st = statSync72(mdPath);
130234
130476
  return { size: st.size, mtime: st.mtime.toISOString() };
130235
130477
  } catch {
130236
130478
  return null;
@@ -130240,7 +130482,7 @@ function listPersonalSkills(agent, agentsRoot = defaultAgentsRoot()) {
130240
130482
  if (!AGENT_NAME_RE3.test(agent))
130241
130483
  return [];
130242
130484
  const skillsDir = join127(agentsRoot, agent, ".claude/skills");
130243
- if (!existsSync122(skillsDir))
130485
+ if (!existsSync123(skillsDir))
130244
130486
  return [];
130245
130487
  const out = [];
130246
130488
  let entries;
@@ -130254,7 +130496,7 @@ function listPersonalSkills(agent, agentsRoot = defaultAgentsRoot()) {
130254
130496
  continue;
130255
130497
  const dirPath = join127(skillsDir, ent);
130256
130498
  try {
130257
- if (!statSync71(dirPath).isDirectory())
130499
+ if (!statSync72(dirPath).isDirectory())
130258
130500
  continue;
130259
130501
  } catch {
130260
130502
  continue;
@@ -130278,7 +130520,7 @@ function listPersonalSkills(agent, agentsRoot = defaultAgentsRoot()) {
130278
130520
  return out;
130279
130521
  }
130280
130522
  function listSharedSkills(sharedRoot = defaultSharedRoot2()) {
130281
- if (!existsSync122(sharedRoot))
130523
+ if (!existsSync123(sharedRoot))
130282
130524
  return [];
130283
130525
  const out = [];
130284
130526
  let entries;
@@ -130294,7 +130536,7 @@ function listSharedSkills(sharedRoot = defaultSharedRoot2()) {
130294
130536
  continue;
130295
130537
  const dirPath = join127(sharedRoot, ent);
130296
130538
  try {
130297
- if (!statSync71(dirPath).isDirectory())
130539
+ if (!statSync72(dirPath).isDirectory())
130298
130540
  continue;
130299
130541
  } catch {
130300
130542
  continue;
@@ -130316,7 +130558,7 @@ function listSharedSkills(sharedRoot = defaultSharedRoot2()) {
130316
130558
  return out;
130317
130559
  }
130318
130560
  function listBundledSkills(bundledRoot = defaultBundledRoot2()) {
130319
- if (!existsSync122(bundledRoot))
130561
+ if (!existsSync123(bundledRoot))
130320
130562
  return [];
130321
130563
  const out = [];
130322
130564
  let entries;
@@ -130330,7 +130572,7 @@ function listBundledSkills(bundledRoot = defaultBundledRoot2()) {
130330
130572
  continue;
130331
130573
  const dirPath = join127(bundledRoot, ent);
130332
130574
  try {
130333
- if (!statSync71(dirPath).isDirectory())
130575
+ if (!statSync72(dirPath).isDirectory())
130334
130576
  continue;
130335
130577
  } catch {
130336
130578
  continue;
@@ -130475,11 +130717,11 @@ init_helpers();
130475
130717
  init_docker_socket();
130476
130718
  init_operator_uid();
130477
130719
  import {
130478
- existsSync as existsSync124,
130479
- mkdirSync as mkdirSync71,
130720
+ existsSync as existsSync125,
130721
+ mkdirSync as mkdirSync72,
130480
130722
  readdirSync as readdirSync48,
130481
- writeFileSync as writeFileSync53,
130482
- statSync as statSync72,
130723
+ writeFileSync as writeFileSync54,
130724
+ statSync as statSync73,
130483
130725
  lstatSync as lstatSync18,
130484
130726
  realpathSync as realpathSync12,
130485
130727
  copyFileSync as copyFileSync16
@@ -130858,7 +131100,7 @@ function resolveHostdSkillsTarget(hostHome) {
130858
131100
  console.warn(`switchroom hostd install: ~/.switchroom/skills is a symlink whose target ` + `does not resolve (dangling) \u2014 skipping the skills bind mount. Bundled ` + `skills will be unavailable to rollout/update until the symlink is fixed.`);
130859
131101
  return;
130860
131102
  }
130861
- if (!existsSync124(target)) {
131103
+ if (!existsSync125(target)) {
130862
131104
  console.warn(`switchroom hostd install: ~/.switchroom/skills resolves to "${target}", ` + `which does not exist \u2014 skipping the skills bind mount. Bundled skills ` + `will be unavailable to rollout/update until the symlink target exists.`);
130863
131105
  return;
130864
131106
  }
@@ -130872,7 +131114,7 @@ function hostdComposePath() {
130872
131114
  }
130873
131115
  function backupExistingCompose() {
130874
131116
  const p = hostdComposePath();
130875
- if (!existsSync124(p))
131117
+ if (!existsSync125(p))
130876
131118
  return null;
130877
131119
  const ts = new Date().toISOString().replace(/[:.]/g, "-");
130878
131120
  const bak = `${p}.bak-${ts}`;
@@ -130905,7 +131147,7 @@ async function doInstall(opts, program3) {
130905
131147
  }
130906
131148
  const dir = hostdDir();
130907
131149
  const composePath = hostdComposePath();
130908
- mkdirSync71(dir, { recursive: true });
131150
+ mkdirSync72(dir, { recursive: true });
130909
131151
  const imageTag = resolveHostdImageTag(opts.tag, cfg.release);
130910
131152
  const guard = checkDowngrade({
130911
131153
  container: "switchroom-hostd",
@@ -130939,7 +131181,7 @@ async function doInstall(opts, program3) {
130939
131181
  const bak = backupExistingCompose();
130940
131182
  if (bak)
130941
131183
  console.log(source_default.dim(` Backed up existing compose to ${bak}`));
130942
- writeFileSync53(composePath, yaml, "utf8");
131184
+ writeFileSync54(composePath, yaml, "utf8");
130943
131185
  console.log(source_default.green(` \u2713 Wrote ${composePath}`));
130944
131186
  const adminAgents = Object.entries(cfg.agents ?? {}).filter(([, a]) => a?.admin === true).map(([name]) => name);
130945
131187
  console.log(source_default.dim(` agents served (one socket each): ${allAgents.length === 0 ? "(none)" : allAgents.join(", ")}`));
@@ -130971,7 +131213,7 @@ function doStatus() {
130971
131213
  const composeYml = hostdComposePath();
130972
131214
  console.log(source_default.bold("switchroom-hostd"));
130973
131215
  console.log("");
130974
- if (!existsSync124(composeYml)) {
131216
+ if (!existsSync125(composeYml)) {
130975
131217
  console.log(source_default.yellow(" compose: not installed"));
130976
131218
  console.log(source_default.dim(" run `switchroom hostd install` to set up."));
130977
131219
  return;
@@ -130992,15 +131234,15 @@ function doStatus() {
130992
131234
  } else {
130993
131235
  console.log(source_default.green(` container: ${ps.stdout.trim()}`));
130994
131236
  }
130995
- if (existsSync124(dir)) {
131237
+ if (existsSync125(dir)) {
130996
131238
  const entries = [];
130997
131239
  try {
130998
131240
  for (const name of readdirSync48(dir)) {
130999
131241
  if (name === "docker-compose.yml" || name.startsWith("docker-compose.yml."))
131000
131242
  continue;
131001
131243
  const sockPath = join128(dir, name, "sock");
131002
- if (existsSync124(sockPath)) {
131003
- const st = statSync72(sockPath);
131244
+ if (existsSync125(sockPath)) {
131245
+ const st = statSync73(sockPath);
131004
131246
  if ((st.mode & 61440) === 49152) {
131005
131247
  entries.push(`${name} \u2192 ${sockPath}`);
131006
131248
  }
@@ -131018,7 +131260,7 @@ function doStatus() {
131018
131260
  }
131019
131261
  function doUninstall() {
131020
131262
  const composeYml = hostdComposePath();
131021
- if (!existsSync124(composeYml)) {
131263
+ if (!existsSync125(composeYml)) {
131022
131264
  console.log(source_default.yellow(" No hostd install detected (no compose file at this path)."));
131023
131265
  return;
131024
131266
  }
@@ -131042,7 +131284,7 @@ function registerHostdCommand(program3) {
131042
131284
  hostd.command("uninstall").description("Stop the hostd container. Leaves the compose file in place for re-install.").action(() => doUninstall());
131043
131285
  hostd.command("audit").description("Tail and filter the hostd audit log (privileged-verb call history)").option("--tail <n>", "Number of matching entries to show (default: 50)", "50").option("--agent <name>", "Filter to a specific caller agent").option("--op <verb>", "Filter to a specific hostd verb (e.g. update_apply, agent_restart)").option("--error", "Show only failed (error/denied) entries").option("--verbose", "Show the captured stderr / error tail under each failed row").option("--path <file>", "Override audit log path (for debugging)").action((opts) => {
131044
131286
  const logPath = opts.path ?? defaultAuditLogPath2();
131045
- if (!existsSync124(logPath)) {
131287
+ if (!existsSync125(logPath)) {
131046
131288
  console.error(source_default.yellow(`Audit log not found at ${logPath}.`) + source_default.gray(`
131047
131289
  The log is created when hostd handles its first privileged-verb request.`));
131048
131290
  return;
@@ -131091,7 +131333,7 @@ init_source();
131091
131333
  init_helpers();
131092
131334
  init_operator_uid();
131093
131335
  init_compose();
131094
- import { chownSync as chownSync15, existsSync as existsSync125, mkdirSync as mkdirSync72, writeFileSync as writeFileSync54, copyFileSync as copyFileSync17 } from "node:fs";
131336
+ import { chownSync as chownSync16, existsSync as existsSync126, mkdirSync as mkdirSync73, writeFileSync as writeFileSync55, copyFileSync as copyFileSync17 } from "node:fs";
131095
131337
  import { homedir as homedir67 } from "node:os";
131096
131338
  import { join as join129 } from "node:path";
131097
131339
  import { spawnSync as spawnSync30 } from "node:child_process";
@@ -131202,7 +131444,7 @@ function webdComposePath() {
131202
131444
  }
131203
131445
  function backupExistingCompose2() {
131204
131446
  const p = webdComposePath();
131205
- if (!existsSync125(p))
131447
+ if (!existsSync126(p))
131206
131448
  return null;
131207
131449
  const ts = new Date().toISOString().replace(/[:.]/g, "-");
131208
131450
  const bak = `${p}.bak-${ts}`;
@@ -131233,7 +131475,7 @@ async function doInstall2(opts, program3) {
131233
131475
  }
131234
131476
  const dir = webdDir();
131235
131477
  const composePath = webdComposePath();
131236
- mkdirSync72(dir, { recursive: true });
131478
+ mkdirSync73(dir, { recursive: true });
131237
131479
  const cfg = getConfig(program3);
131238
131480
  const imageTag = resolveWebImageTag(opts.tag, cfg.release);
131239
131481
  const port = cfg.web_service?.port ?? 8080;
@@ -131268,13 +131510,13 @@ async function doInstall2(opts, program3) {
131268
131510
  const bak = backupExistingCompose2();
131269
131511
  if (bak)
131270
131512
  console.log(source_default.dim(` Backed up existing compose to ${bak}`));
131271
- writeFileSync54(composePath, yaml, "utf8");
131513
+ writeFileSync55(composePath, yaml, "utf8");
131272
131514
  try {
131273
131515
  if (typeof process.geteuid === "function" && process.geteuid() === 0) {
131274
- chownSync15(dir, operatorUid, operatorUid);
131275
- chownSync15(composePath, operatorUid, operatorUid);
131516
+ chownSync16(dir, operatorUid, operatorUid);
131517
+ chownSync16(composePath, operatorUid, operatorUid);
131276
131518
  if (bak)
131277
- chownSync15(bak, operatorUid, operatorUid);
131519
+ chownSync16(bak, operatorUid, operatorUid);
131278
131520
  }
131279
131521
  } catch {}
131280
131522
  console.log(source_default.green(` \u2713 Wrote ${composePath}`));
@@ -131310,7 +131552,7 @@ function doStatus2() {
131310
131552
  const composeYml = webdComposePath();
131311
131553
  console.log(source_default.bold("switchroom-web"));
131312
131554
  console.log("");
131313
- if (!existsSync125(composeYml)) {
131555
+ if (!existsSync126(composeYml)) {
131314
131556
  console.log(source_default.yellow(" compose: not installed"));
131315
131557
  console.log(source_default.dim(" run `switchroom webd install` to set up."));
131316
131558
  return;
@@ -131334,7 +131576,7 @@ function doStatus2() {
131334
131576
  }
131335
131577
  function doUninstall2() {
131336
131578
  const composeYml = webdComposePath();
131337
- if (!existsSync125(composeYml)) {
131579
+ if (!existsSync126(composeYml)) {
131338
131580
  console.log(source_default.yellow(" No web-service install detected (no compose file at this path)."));
131339
131581
  return;
131340
131582
  }
@@ -131830,7 +132072,7 @@ function printDeepDiveBrief(targets) {
131830
132072
 
131831
132073
  // src/cli/hindsight-watch.ts
131832
132074
  init_source();
131833
- import { existsSync as existsSync130, readdirSync as readdirSync53 } from "node:fs";
132075
+ import { existsSync as existsSync131, readdirSync as readdirSync53 } from "node:fs";
131834
132076
  import { homedir as homedir71 } from "node:os";
131835
132077
  import { join as join133, resolve as resolve67 } from "node:path";
131836
132078
 
@@ -131901,7 +132143,7 @@ init_install_cron();
131901
132143
 
131902
132144
  // src/hindsight-watch/probe.ts
131903
132145
  import { spawnSync as spawnSync32 } from "node:child_process";
131904
- import { readFileSync as readFileSync115, readdirSync as readdirSync52, statSync as statSync74 } from "node:fs";
132146
+ import { readFileSync as readFileSync116, readdirSync as readdirSync52, statSync as statSync75 } from "node:fs";
131905
132147
  import { homedir as homedir70 } from "node:os";
131906
132148
  import { resolve as resolve66 } from "node:path";
131907
132149
 
@@ -132029,7 +132271,7 @@ function readLlmSignals(series) {
132029
132271
  }
132030
132272
 
132031
132273
  // src/hindsight-watch/recall-log.ts
132032
- import { closeSync as closeSync26, existsSync as existsSync129, openSync as openSync26, readdirSync as readdirSync51, readSync as readSync7, statSync as statSync73 } from "node:fs";
132274
+ import { closeSync as closeSync26, existsSync as existsSync130, openSync as openSync26, readdirSync as readdirSync51, readSync as readSync7, statSync as statSync74 } from "node:fs";
132033
132275
  import { join as join132 } from "node:path";
132034
132276
  var RECALL_WINDOW_ROWS = 200;
132035
132277
  var RECALL_MAX_TAIL_BYTES = 1024 * 1024;
@@ -132038,13 +132280,13 @@ function recallLogPath2(agentDir) {
132038
132280
  return join132(agentDir, ".claude", "plugins", "data", "hindsight-memory-inline", "state", "recall_log.jsonl");
132039
132281
  }
132040
132282
  function readRecallLogTail2(path10, windowRows = RECALL_WINDOW_ROWS) {
132041
- if (!existsSync129(path10))
132283
+ if (!existsSync130(path10))
132042
132284
  return [];
132043
132285
  let text;
132044
132286
  let truncatedHead = false;
132045
132287
  let fd;
132046
132288
  try {
132047
- const size = statSync73(path10).size;
132289
+ const size = statSync74(path10).size;
132048
132290
  const start = Math.max(0, size - RECALL_MAX_TAIL_BYTES);
132049
132291
  truncatedHead = start > 0;
132050
132292
  const length = size - start;
@@ -132292,9 +132534,9 @@ function readDropCount(hindsightDir) {
132292
132534
  const path10 = resolve66(hindsightDir, "pending-drops.json");
132293
132535
  let parsed;
132294
132536
  try {
132295
- if (statSync74(path10).size > DROPS_LEDGER_MAX_BYTES)
132537
+ if (statSync75(path10).size > DROPS_LEDGER_MAX_BYTES)
132296
132538
  return 0;
132297
- parsed = JSON.parse(readFileSync115(path10, "utf8"));
132539
+ parsed = JSON.parse(readFileSync116(path10, "utf8"));
132298
132540
  } catch {
132299
132541
  return 0;
132300
132542
  }
@@ -133598,7 +133840,7 @@ function collectRelayCandidates(agentsDir) {
133598
133840
  const candidates = [];
133599
133841
  for (const name of readdirSync53(agentsDir).sort()) {
133600
133842
  const sock = resolve67(agentsDir, name, "telegram", "gateway.sock");
133601
- if (existsSync130(sock))
133843
+ if (existsSync131(sock))
133602
133844
  candidates.push({ agent: name, sock });
133603
133845
  }
133604
133846
  return orderRelayCandidates(candidates);
@@ -133618,10 +133860,276 @@ async function notifyOperator(agentsDir, text, log) {
133618
133860
  return agent !== null;
133619
133861
  }
133620
133862
 
133863
+ // src/cli/mental-model-refresh.ts
133864
+ init_source();
133865
+ init_helpers();
133866
+ init_hindsight2();
133867
+ init_hindsight();
133868
+
133869
+ // src/memory/mental-model-refresh.ts
133870
+ init_hindsight2();
133871
+ var DEFAULT_STALE_DAYS = 7;
133872
+ var DEFAULT_REFRESH_TIMEOUT_MS = 30000;
133873
+ var INIT_TIMEOUT_MS = 3000;
133874
+ function parseMcpBody(text) {
133875
+ const dataLine = text.split(`
133876
+ `).find((line) => line.startsWith("data: "));
133877
+ const payload = dataLine ? dataLine.slice("data: ".length) : text;
133878
+ return JSON.parse(payload);
133879
+ }
133880
+ async function refreshMentalModel2(mcpUrl, bankId, modelId, opts) {
133881
+ const fetchImpl = opts?.fetchImpl ?? fetch;
133882
+ const timeoutMs = opts?.timeoutMs ?? DEFAULT_REFRESH_TIMEOUT_MS;
133883
+ const headers = {
133884
+ "Content-Type": "application/json",
133885
+ Accept: "application/json, text/event-stream",
133886
+ "X-Bank-Id": bankId
133887
+ };
133888
+ try {
133889
+ await fetchImpl(mcpUrl, {
133890
+ method: "POST",
133891
+ headers,
133892
+ body: JSON.stringify({
133893
+ jsonrpc: "2.0",
133894
+ id: 1,
133895
+ method: "initialize",
133896
+ params: {
133897
+ protocolVersion: "2024-11-05",
133898
+ capabilities: {},
133899
+ clientInfo: { name: "mm-refresh", version: "0.1" }
133900
+ }
133901
+ }),
133902
+ signal: AbortSignal.timeout(INIT_TIMEOUT_MS)
133903
+ });
133904
+ } catch {}
133905
+ const controller = new AbortController;
133906
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
133907
+ try {
133908
+ const resp = await fetchImpl(mcpUrl, {
133909
+ method: "POST",
133910
+ headers,
133911
+ body: JSON.stringify({
133912
+ jsonrpc: "2.0",
133913
+ id: 2,
133914
+ method: "tools/call",
133915
+ params: {
133916
+ name: "refresh_mental_model",
133917
+ arguments: { mental_model_id: modelId }
133918
+ }
133919
+ }),
133920
+ signal: controller.signal
133921
+ });
133922
+ if (!resp.ok)
133923
+ return { ok: false, reason: `HTTP ${resp.status}` };
133924
+ const parsed = parseMcpBody(await resp.text());
133925
+ if (parsed.result?.isError === true) {
133926
+ return {
133927
+ ok: false,
133928
+ reason: parsed.result.content?.[0]?.text ?? "refresh returned isError"
133929
+ };
133930
+ }
133931
+ return { ok: true };
133932
+ } catch (err2) {
133933
+ if (err2.name === "AbortError")
133934
+ return { ok: false, reason: "Timeout" };
133935
+ return { ok: false, reason: String(err2.message ?? err2) };
133936
+ } finally {
133937
+ clearTimeout(timeout);
133938
+ }
133939
+ }
133940
+ async function refreshStaleModelsInBank(mcpUrl, bankId, opts) {
133941
+ const staleDays = opts?.staleDays ?? DEFAULT_STALE_DAYS;
133942
+ const now2 = opts?.now ?? new Date;
133943
+ const dryRun = opts?.dryRun ?? false;
133944
+ const health = await inspectBankHealth(mcpUrl, bankId, {
133945
+ fetchImpl: opts?.fetchImpl,
133946
+ timeoutMs: opts?.timeoutMs
133947
+ });
133948
+ if (!health.ok) {
133949
+ return {
133950
+ bankId,
133951
+ ok: false,
133952
+ reason: health.reason,
133953
+ totalModels: 0,
133954
+ staleModels: 0,
133955
+ refreshed: 0,
133956
+ failed: 0,
133957
+ dryRun,
133958
+ models: []
133959
+ };
133960
+ }
133961
+ const stale = staleMentalModels(health.mentalModels, staleDays, now2);
133962
+ const models = [];
133963
+ let refreshed = 0;
133964
+ let failed = 0;
133965
+ for (const m of stale) {
133966
+ const age = ageDays(m.lastRefreshedAt ?? m.createdAt, now2);
133967
+ if (dryRun) {
133968
+ models.push({ id: m.id, name: m.name, ageDays: age, refreshed: false });
133969
+ continue;
133970
+ }
133971
+ const res = await refreshMentalModel2(mcpUrl, bankId, m.id, {
133972
+ fetchImpl: opts?.fetchImpl,
133973
+ timeoutMs: opts?.timeoutMs
133974
+ });
133975
+ if (res.ok) {
133976
+ refreshed++;
133977
+ models.push({ id: m.id, name: m.name, ageDays: age, refreshed: true });
133978
+ } else {
133979
+ failed++;
133980
+ models.push({ id: m.id, name: m.name, ageDays: age, refreshed: false, reason: res.reason });
133981
+ }
133982
+ }
133983
+ return {
133984
+ bankId,
133985
+ ok: true,
133986
+ totalModels: health.mentalModels.length,
133987
+ staleModels: stale.length,
133988
+ refreshed,
133989
+ failed,
133990
+ dryRun,
133991
+ models
133992
+ };
133993
+ }
133994
+ function collectRefreshBanks(config2) {
133995
+ const banks = new Set;
133996
+ for (const [agentName, agentConfig] of Object.entries(config2.agents)) {
133997
+ banks.add(agentConfig.memory?.collection ?? agentName);
133998
+ }
133999
+ for (const bank of collectProfileBanks(config2))
134000
+ banks.add(bank);
134001
+ return [...banks].sort();
134002
+ }
134003
+ async function runMentalModelRefresh(opts) {
134004
+ const banks = [];
134005
+ let totalRefreshed = 0;
134006
+ let totalFailed = 0;
134007
+ for (const bankId of opts.bankIds) {
134008
+ const r = await refreshStaleModelsInBank(opts.mcpUrl, bankId, {
134009
+ staleDays: opts.staleDays,
134010
+ now: opts.now,
134011
+ dryRun: opts.dryRun,
134012
+ fetchImpl: opts.fetchImpl,
134013
+ timeoutMs: opts.timeoutMs
134014
+ });
134015
+ banks.push(r);
134016
+ totalRefreshed += r.refreshed;
134017
+ totalFailed += r.failed;
134018
+ if (opts.log) {
134019
+ opts.log(r.ok ? `${r.bankId}: ${r.staleModels}/${r.totalModels} stale, ` + `${r.dryRun ? "would refresh" : "refreshed"} ${r.dryRun ? r.staleModels : r.refreshed}` + (r.failed > 0 ? `, ${r.failed} failed` : "") : `${r.bankId}: could not inspect (${r.reason})`);
134020
+ }
134021
+ }
134022
+ const couldNotComplete = banks.length > 0 && banks.every((b) => !b.ok);
134023
+ return { banks, totalRefreshed, totalFailed, couldNotComplete };
134024
+ }
134025
+
134026
+ // src/cli/mental-model-refresh.ts
134027
+ function registerMentalModelRefreshCommand(program3) {
134028
+ program3.command("mental-model-refresh").description("Model-free refresh of stale mental models: list each bank's models, " + "select those past the staleness interval, refresh via the hindsight MCP tool.").option("--install-cron", `arm the sweep: write ${CRON_PATH3} (${CRON_SCHEDULE2}, flock-guarded) and exit`, false).option("--cron-user <user>", "unix user the cron sweep runs as (default: current user)").option("--stale-days <n>", `refresh models whose last refresh is older than N days (default: ${DEFAULT_STALE_DAYS})`, String(DEFAULT_STALE_DAYS)).option("--bank <id>", "restrict the sweep to a single bank (default: every fleet bank)").option("--mcp-url <url>", "hindsight MCP endpoint (default: config or built-in)").option("--dry-run", "select and print stale models but issue no refreshes", false).option("--json", "emit machine-readable JSON", false).action(async (opts) => {
134029
+ if (opts.installCron) {
134030
+ process.exitCode = runInstallCron2(opts.cronUser);
134031
+ return;
134032
+ }
134033
+ const staleDays = Number(opts.staleDays);
134034
+ if (!Number.isFinite(staleDays) || staleDays < 0) {
134035
+ process.stderr.write(source_default.red(`mental-model-refresh: --stale-days must be a non-negative number (got ${opts.staleDays})
134036
+ `));
134037
+ process.exitCode = 1;
134038
+ return;
134039
+ }
134040
+ const config2 = getConfig(program3);
134041
+ if (!isHindsightEnabled(config2)) {
134042
+ process.stderr.write(source_default.red(`mental-model-refresh: hindsight memory backend is not enabled \u2014 nothing to refresh.
134043
+ `));
134044
+ process.exitCode = 1;
134045
+ return;
134046
+ }
134047
+ const mcpUrl = opts.mcpUrl ?? config2.memory?.config?.url ?? HINDSIGHT_DEFAULT_MCP_URL;
134048
+ const bankIds = opts.bank ? [String(opts.bank)] : collectRefreshBanks(config2);
134049
+ if (bankIds.length === 0) {
134050
+ process.stderr.write(source_default.yellow(`mental-model-refresh: no banks to sweep.
134051
+ `));
134052
+ process.exitCode = 0;
134053
+ return;
134054
+ }
134055
+ const log = opts.json ? undefined : (m) => {
134056
+ process.stderr.write(`${m}
134057
+ `);
134058
+ };
134059
+ const result = await runMentalModelRefresh({
134060
+ mcpUrl,
134061
+ bankIds,
134062
+ staleDays,
134063
+ dryRun: Boolean(opts.dryRun),
134064
+ log
134065
+ });
134066
+ if (opts.json) {
134067
+ process.stdout.write(JSON.stringify({ staleDays, dryRun: Boolean(opts.dryRun), ...result }, null, 2) + `
134068
+ `);
134069
+ } else {
134070
+ const verb = opts.dryRun ? "would refresh" : "refreshed";
134071
+ process.stdout.write(`
134072
+ ${source_default.bold(`${verb} ${result.totalRefreshed} model(s)`)}` + (result.totalFailed > 0 ? source_default.yellow(` \u2014 ${result.totalFailed} refresh failure(s)`) : "") + ` across ${result.banks.length} bank(s).
134073
+ `);
134074
+ if (result.couldNotComplete) {
134075
+ process.stdout.write(source_default.red(` every bank failed inspection \u2014 hindsight unreachable?
134076
+ `));
134077
+ }
134078
+ }
134079
+ process.exitCode = result.couldNotComplete ? 1 : 0;
134080
+ });
134081
+ }
134082
+ function runInstallCron2(cronUser) {
134083
+ const user = cronUser ?? process.env.SUDO_USER ?? process.env.USER ?? process.env.LOGNAME;
134084
+ if (!user || user === "root") {
134085
+ process.stderr.write(source_default.red("mental-model-refresh: refusing to install a cron for `root`.\n") + " The config the sweep reads lives under the OPERATOR's ~/.switchroom, " + `so a root tick would read the wrong config.
134086
+ ` + " Re-run with `--cron-user <operator>`.\n");
134087
+ return 1;
134088
+ }
134089
+ const binary = process.env.SWITCHROOM_BINARY ?? "/usr/local/bin/switchroom";
134090
+ if (!binary.startsWith("/")) {
134091
+ process.stderr.write(source_default.red(`mental-model-refresh: SWITCHROOM_BINARY must be an absolute path (got ${binary})
134092
+ `));
134093
+ return 1;
134094
+ }
134095
+ let res;
134096
+ try {
134097
+ res = installCron3({ user, binary });
134098
+ } catch (e) {
134099
+ process.stderr.write(source_default.red(`mental-model-refresh: could not write ${CRON_PATH3}: ${e.message}
134100
+ `) + " This path needs root; re-run under sudo with `--cron-user <operator>`.\n");
134101
+ return 1;
134102
+ }
134103
+ let logStatus;
134104
+ try {
134105
+ const logRes = ensureLogFile3({ user });
134106
+ logStatus = logRes.status === "created" ? `created ${logRes.path} (owned by ${user})` : `${logRes.path} already present`;
134107
+ } catch (e) {
134108
+ process.stderr.write(source_default.red(`mental-model-refresh: could not provision the log file: ${e.message}
134109
+ `) + ` The cron redirects into ${CRON_LOG_PATH3} and would die at the redirection every tick.
134110
+ ` + " This path needs root; re-run under sudo with `--cron-user <operator>`.\n");
134111
+ return 1;
134112
+ }
134113
+ let rotateStatus;
134114
+ try {
134115
+ const rotateRes = installLogrotate3({ user });
134116
+ rotateStatus = rotateRes.status === "installed" ? `installed ${rotateRes.path}` : `${rotateRes.path} already up to date`;
134117
+ } catch (e) {
134118
+ rotateStatus = source_default.yellow(`logrotate drop-in NOT written (${e.message}) \u2014 log growth is unbounded`);
134119
+ }
134120
+ const verb = res.status === "installed" ? "installed" : "already up to date";
134121
+ process.stdout.write(`${source_default.green("\u2713")} mental-model-refresh cron ${verb} at ${res.path} ` + `(${CRON_SCHEDULE2}, as ${user})
134122
+ ` + ` log: ${logStatus}
134123
+ ` + ` logrotate: ${rotateStatus}
134124
+ ` + ` Verify with: switchroom mental-model-refresh --dry-run
134125
+ `);
134126
+ return 0;
134127
+ }
134128
+
133621
134129
  // src/cli/hindsight-bench.ts
133622
134130
  init_source();
133623
- import { mkdirSync as mkdirSync74, readFileSync as readFileSync116, writeFileSync as writeFileSync56 } from "node:fs";
133624
- import { dirname as dirname56, resolve as resolve68 } from "node:path";
134131
+ import { mkdirSync as mkdirSync75, readFileSync as readFileSync117, writeFileSync as writeFileSync57 } from "node:fs";
134132
+ import { dirname as dirname57, resolve as resolve68 } from "node:path";
133625
134133
 
133626
134134
  // src/hindsight-bench/anonymise.ts
133627
134135
  function pseudonym(n, width) {
@@ -134731,7 +135239,7 @@ function fail9(msg) {
134731
135239
  function readResult(path10) {
134732
135240
  let parsed;
134733
135241
  try {
134734
- parsed = JSON.parse(readFileSync116(path10, "utf8"));
135242
+ parsed = JSON.parse(readFileSync117(path10, "utf8"));
134735
135243
  } catch (e) {
134736
135244
  fail9(`cannot read ${path10}: ${e.message}`);
134737
135245
  }
@@ -134749,8 +135257,8 @@ function readResult(path10) {
134749
135257
  }
134750
135258
  function writeOut(path10, body) {
134751
135259
  const abs = resolve68(path10);
134752
- mkdirSync74(dirname56(abs), { recursive: true });
134753
- writeFileSync56(abs, body);
135260
+ mkdirSync75(dirname57(abs), { recursive: true });
135261
+ writeFileSync57(abs, body);
134754
135262
  process.stderr.write(`${source_default.green("\u2713")} wrote ${abs}
134755
135263
  `);
134756
135264
  }
@@ -134954,53 +135462,53 @@ async function runMeasureMode(opts) {
134954
135462
 
134955
135463
  // src/cli/openrouter-watch.ts
134956
135464
  init_source();
134957
- import { existsSync as existsSync132, readdirSync as readdirSync54 } from "node:fs";
135465
+ import { existsSync as existsSync133, readdirSync as readdirSync54 } from "node:fs";
134958
135466
  import { homedir as homedir73 } from "node:os";
134959
135467
  import { join as join134, resolve as resolve70 } from "node:path";
134960
135468
 
134961
135469
  // src/openrouter/install-cron.ts
134962
- import { existsSync as existsSync131, mkdirSync as mkdirSync75, readFileSync as readFileSync117, renameSync as renameSync35, writeFileSync as writeFileSync57 } from "node:fs";
134963
- import { dirname as dirname57 } from "node:path";
134964
- var CRON_PATH3 = "/etc/cron.d/openrouter-watch";
134965
- var CRON_SCHEDULE2 = "17 * * * *";
134966
- var CRON_LOG_PATH3 = "/var/log/openrouter-watch.log";
134967
- var CRON_LOCK_PATH3 = "/run/lock/openrouter-watch.lock";
134968
- function renderCron3(opts) {
135470
+ import { existsSync as existsSync132, mkdirSync as mkdirSync76, readFileSync as readFileSync118, renameSync as renameSync36, writeFileSync as writeFileSync58 } from "node:fs";
135471
+ import { dirname as dirname58 } from "node:path";
135472
+ var CRON_PATH4 = "/etc/cron.d/openrouter-watch";
135473
+ var CRON_SCHEDULE3 = "17 * * * *";
135474
+ var CRON_LOG_PATH4 = "/var/log/openrouter-watch.log";
135475
+ var CRON_LOCK_PATH4 = "/run/lock/openrouter-watch.lock";
135476
+ function renderCron4(opts) {
134969
135477
  return `# switchroom openrouter-watch \u2014 model-free OpenRouter credit watchdog.
134970
135478
  ` + `# Managed by \`switchroom openrouter-watch --install-cron\`; edits are overwritten.
134971
135479
  ` + `# Exit 0 = clean, 10 = credit signal firing (DM sent), 1 = the check could not complete.
134972
135480
  ` + `SHELL=/bin/sh
134973
135481
  ` + `PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
134974
- ` + `${CRON_SCHEDULE2} ${opts.user} /usr/bin/flock -n ${CRON_LOCK_PATH3} ` + `${opts.binary} openrouter-watch >> ${CRON_LOG_PATH3} 2>&1
135482
+ ` + `${CRON_SCHEDULE3} ${opts.user} /usr/bin/flock -n ${CRON_LOCK_PATH4} ` + `${opts.binary} openrouter-watch >> ${CRON_LOG_PATH4} 2>&1
134975
135483
  `;
134976
135484
  }
134977
- function installCron3(opts) {
134978
- const path10 = opts.path ?? CRON_PATH3;
134979
- const content = renderCron3(opts);
134980
- if (existsSync131(path10)) {
135485
+ function installCron4(opts) {
135486
+ const path10 = opts.path ?? CRON_PATH4;
135487
+ const content = renderCron4(opts);
135488
+ if (existsSync132(path10)) {
134981
135489
  try {
134982
- if (readFileSync117(path10, "utf8") === content) {
135490
+ if (readFileSync118(path10, "utf8") === content) {
134983
135491
  return { status: "unchanged", path: path10, content };
134984
135492
  }
134985
135493
  } catch {}
134986
135494
  }
134987
- mkdirSync75(dirname57(path10), { recursive: true });
135495
+ mkdirSync76(dirname58(path10), { recursive: true });
134988
135496
  const tmp = `${path10}.${process.pid}.tmp`;
134989
- writeFileSync57(tmp, content, { mode: 420 });
134990
- renameSync35(tmp, path10);
135497
+ writeFileSync58(tmp, content, { mode: 420 });
135498
+ renameSync36(tmp, path10);
134991
135499
  return { status: "installed", path: path10, content };
134992
135500
  }
134993
135501
  // src/openrouter/state.ts
134994
- import { mkdirSync as mkdirSync76, readFileSync as readFileSync118, renameSync as renameSync36, writeFileSync as writeFileSync58 } from "node:fs";
135502
+ import { mkdirSync as mkdirSync77, readFileSync as readFileSync119, renameSync as renameSync37, writeFileSync as writeFileSync59 } from "node:fs";
134995
135503
  import { homedir as homedir72 } from "node:os";
134996
- import { dirname as dirname58, resolve as resolve69 } from "node:path";
135504
+ import { dirname as dirname59, resolve as resolve69 } from "node:path";
134997
135505
  function defaultStatePath3(home2 = process.env.SWITCHROOM_HOME ?? process.env.HOME ?? homedir72()) {
134998
135506
  return resolve69(home2, ".switchroom", "openrouter-watch", "state.json");
134999
135507
  }
135000
135508
  function loadState2(path10) {
135001
135509
  let parsed;
135002
135510
  try {
135003
- parsed = JSON.parse(readFileSync118(path10, "utf8"));
135511
+ parsed = JSON.parse(readFileSync119(path10, "utf8"));
135004
135512
  } catch {
135005
135513
  return {};
135006
135514
  }
@@ -135020,12 +135528,12 @@ function loadState2(path10) {
135020
135528
  return out;
135021
135529
  }
135022
135530
  function saveState2(path10, state) {
135023
- mkdirSync76(dirname58(path10), { recursive: true, mode: 448 });
135531
+ mkdirSync77(dirname59(path10), { recursive: true, mode: 448 });
135024
135532
  const tmp = `${path10}.${process.pid}.tmp`;
135025
135533
  const payload = { v: 1, ...state };
135026
- writeFileSync58(tmp, JSON.stringify(payload, null, 2) + `
135534
+ writeFileSync59(tmp, JSON.stringify(payload, null, 2) + `
135027
135535
  `, { mode: 384 });
135028
- renameSync36(tmp, path10);
135536
+ renameSync37(tmp, path10);
135029
135537
  }
135030
135538
 
135031
135539
  // src/openrouter/watch.ts
@@ -135106,9 +135614,9 @@ async function tick2(deps) {
135106
135614
  }
135107
135615
  // src/cli/openrouter-watch.ts
135108
135616
  function registerOpenRouterWatchCommand(program3) {
135109
- program3.command("openrouter-watch").description("Model-free OpenRouter credit watchdog: warns before the key's credit runs out. " + "Alerts at most once per 6h, and escalates immediately.").option("--install-cron", `arm the watchdog: write ${CRON_PATH3} (${CRON_SCHEDULE2}, flock-guarded) and exit`, false).option("--cron-user <user>", "unix user the cron tick runs as (default: current user)").option("--dry-run", "evaluate and print; send no DM and write no state", false).option("--json", "emit machine-readable JSON", false).option("--state <path>", "state file path (default ~/.switchroom/openrouter-watch/state.json)").option("--agents-dir <path>", "agents scaffold dir (default ~/.switchroom/agents)").action(async (opts) => {
135617
+ program3.command("openrouter-watch").description("Model-free OpenRouter credit watchdog: warns before the key's credit runs out. " + "Alerts at most once per 6h, and escalates immediately.").option("--install-cron", `arm the watchdog: write ${CRON_PATH4} (${CRON_SCHEDULE3}, flock-guarded) and exit`, false).option("--cron-user <user>", "unix user the cron tick runs as (default: current user)").option("--dry-run", "evaluate and print; send no DM and write no state", false).option("--json", "emit machine-readable JSON", false).option("--state <path>", "state file path (default ~/.switchroom/openrouter-watch/state.json)").option("--agents-dir <path>", "agents scaffold dir (default ~/.switchroom/agents)").action(async (opts) => {
135110
135618
  if (opts.installCron) {
135111
- process.exitCode = runInstallCron2(opts.cronUser);
135619
+ process.exitCode = runInstallCron3(opts.cronUser);
135112
135620
  return;
135113
135621
  }
135114
135622
  const agentsDir = opts.agentsDir ?? process.env.SWITCHROOM_AGENTS_DIR ?? join134(process.env.SWITCHROOM_HOME ?? process.env.HOME ?? homedir73(), ".switchroom", "agents");
@@ -135178,7 +135686,7 @@ ${source_default.bold(`operator DM ${header}:`)}
135178
135686
  process.exitCode = result.exitCode;
135179
135687
  });
135180
135688
  }
135181
- function runInstallCron2(cronUser) {
135689
+ function runInstallCron3(cronUser) {
135182
135690
  const user = cronUser ?? process.env.SUDO_USER ?? process.env.USER ?? process.env.LOGNAME;
135183
135691
  if (!user || user === "root") {
135184
135692
  process.stderr.write(source_default.red("openrouter-watch: refusing to install a cron for `root`.\n") + " The state file and the agents scaffold live under the OPERATOR's " + "~/.switchroom, so a root tick would keep its re-notify ledger somewhere " + `nothing else reads.
@@ -135193,14 +135701,14 @@ function runInstallCron2(cronUser) {
135193
135701
  }
135194
135702
  let res;
135195
135703
  try {
135196
- res = installCron3({ user, binary });
135704
+ res = installCron4({ user, binary });
135197
135705
  } catch (e) {
135198
- process.stderr.write(source_default.red(`openrouter-watch: could not write ${CRON_PATH3}: ${e.message}
135706
+ process.stderr.write(source_default.red(`openrouter-watch: could not write ${CRON_PATH4}: ${e.message}
135199
135707
  `) + " This path needs root; re-run under sudo with `--cron-user <operator>`.\n");
135200
135708
  return 1;
135201
135709
  }
135202
135710
  const verb = res.status === "installed" ? "installed" : "already up to date";
135203
- process.stdout.write(`${source_default.green("\u2713")} openrouter-watch cron ${verb} at ${res.path} ` + `(${CRON_SCHEDULE2}, as ${user})
135711
+ process.stdout.write(`${source_default.green("\u2713")} openrouter-watch cron ${verb} at ${res.path} ` + `(${CRON_SCHEDULE3}, as ${user})
135204
135712
  ` + ` Verify with: switchroom openrouter-watch --dry-run
135205
135713
  `);
135206
135714
  return 0;
@@ -135210,7 +135718,7 @@ async function notifyOperator2(agentsDir, text, log) {
135210
135718
  try {
135211
135719
  for (const name of readdirSync54(agentsDir).sort()) {
135212
135720
  const sock = resolve70(agentsDir, name, "telegram", "gateway.sock");
135213
- if (existsSync132(sock))
135721
+ if (existsSync133(sock))
135214
135722
  candidates.push({ agent: name, sock });
135215
135723
  }
135216
135724
  } catch (e) {
@@ -135311,13 +135819,13 @@ function registerConfigRepoCommand(program3) {
135311
135819
  });
135312
135820
  configRepo.command("install-cron").description("Arm the scheduled auto-backup: write /etc/cron.d/switchroom-config-sync " + "(30-min `config-repo sync` tick + a daily `vault backup && sync` leg), " + "provision its log, and install a logrotate drop-in. Gated on " + "config_repo.enabled; refuses to run as root.").option("--cron-user <user>", "unix user the cron tick runs as (default: current user)").action((opts) => {
135313
135821
  const parentOpts = program3.opts();
135314
- process.exitCode = runInstallCron3(parentOpts.config, opts.cronUser);
135822
+ process.exitCode = runInstallCron4(parentOpts.config, opts.cronUser);
135315
135823
  });
135316
135824
  configRepo.command("uninstall-cron").description("Disarm the scheduled auto-backup: remove /etc/cron.d/switchroom-config-sync " + "and its logrotate drop-in (the sync verb still works on demand). Idempotent.").action(() => {
135317
135825
  process.exitCode = runUninstallCron();
135318
135826
  });
135319
135827
  }
135320
- function runInstallCron3(configPath, cronUser) {
135828
+ function runInstallCron4(configPath, cronUser) {
135321
135829
  let intervalMinutes = DEFAULT_INTERVAL_MINUTES;
135322
135830
  let includeVaultBackup = "daily";
135323
135831
  let enabled = false;
@@ -135476,6 +135984,7 @@ registerWebdCommand(program3);
135476
135984
  registerHostCommand(program3);
135477
135985
  registerFleetHealthCommand(program3);
135478
135986
  registerHindsightWatchCommand(program3);
135987
+ registerMentalModelRefreshCommand(program3);
135479
135988
  registerHindsightBenchCommand(program3);
135480
135989
  registerOpenRouterWatchCommand(program3);
135481
135990
  registerConfigRepoCommand(program3);