switchroom 0.19.2 → 0.19.3

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.
Files changed (60) hide show
  1. package/dist/agent-scheduler/index.js +2 -0
  2. package/dist/auth-broker/index.js +13 -0
  3. package/dist/cli/autoaccept-poll.js +2 -0
  4. package/dist/cli/drive-write-pretool.mjs +2 -0
  5. package/dist/cli/ms-365-write-pretool.mjs +2 -0
  6. package/dist/cli/switchroom.js +404 -245
  7. package/dist/host-control/main.js +1 -1
  8. package/package.json +1 -1
  9. package/profiles/default/CLAUDE.md.hbs +8 -0
  10. package/skills/mental-model-curator/SKILL.md +68 -2
  11. package/telegram-plugin/auth-snapshot-format.ts +104 -12
  12. package/telegram-plugin/dist/bridge/bridge.js +8 -2
  13. package/telegram-plugin/dist/gateway/gateway.js +1194 -794
  14. package/telegram-plugin/dist/server.js +8 -2
  15. package/telegram-plugin/flushed-turn-supersede.ts +117 -13
  16. package/telegram-plugin/gateway/auth-add-flow.ts +215 -6
  17. package/telegram-plugin/gateway/auth-command.ts +138 -5
  18. package/telegram-plugin/gateway/gateway.ts +68 -101
  19. package/telegram-plugin/gateway/inbound-interceptors.ts +13 -3
  20. package/telegram-plugin/gateway/model-command.ts +203 -1
  21. package/telegram-plugin/gateway/outbound-send-path.ts +68 -15
  22. package/telegram-plugin/gateway/session-model-source.ts +90 -10
  23. package/telegram-plugin/gateway/stream-render.ts +22 -5
  24. package/telegram-plugin/quota-bar-format.ts +60 -12
  25. package/telegram-plugin/reply-owner-resolve.ts +76 -11
  26. package/telegram-plugin/session-tail.ts +27 -3
  27. package/telegram-plugin/tests/auth-add-flow.test.ts +367 -5
  28. package/telegram-plugin/tests/auth-snapshot-format.test.ts +41 -0
  29. package/telegram-plugin/tests/flushed-turn-supersede.test.ts +117 -0
  30. package/telegram-plugin/tests/gateway-session-model-relaunch.test.ts +185 -29
  31. package/telegram-plugin/tests/model-command.test.ts +220 -0
  32. package/telegram-plugin/tests/reply-owner-resolve.test.ts +257 -13
  33. package/telegram-plugin/tests/send-reply-golden.test.ts +154 -0
  34. package/telegram-plugin/tests/session-model-source.test.ts +142 -0
  35. package/telegram-plugin/tests/session-tail-first-attach.test.ts +115 -2
  36. package/vendor/hindsight-memory/CHANGELOG.md +102 -0
  37. package/vendor/hindsight-memory/README.md +2 -1
  38. package/vendor/hindsight-memory/hooks/hooks.json +12 -0
  39. package/vendor/hindsight-memory/scripts/directive_verify.py +100 -3
  40. package/vendor/hindsight-memory/scripts/lib/config.py +150 -1
  41. package/vendor/hindsight-memory/scripts/lib/content.py +55 -5
  42. package/vendor/hindsight-memory/scripts/lib/directives.py +152 -15
  43. package/vendor/hindsight-memory/scripts/lib/parallel_recall.py +142 -0
  44. package/vendor/hindsight-memory/scripts/lib/state.py +31 -0
  45. package/vendor/hindsight-memory/scripts/recall.py +789 -143
  46. package/vendor/hindsight-memory/scripts/reconcile_tail.py +22 -1
  47. package/vendor/hindsight-memory/scripts/retain.py +71 -2
  48. package/vendor/hindsight-memory/scripts/subagent_retain.py +501 -0
  49. package/vendor/hindsight-memory/scripts/tests/test_directive_verify.py +169 -0
  50. package/vendor/hindsight-memory/scripts/tests/test_directives.py +177 -0
  51. package/vendor/hindsight-memory/scripts/tests/test_lesson_tagging.py +200 -0
  52. package/vendor/hindsight-memory/scripts/tests/test_recall_context_turns_default.py +200 -0
  53. package/vendor/hindsight-memory/scripts/tests/test_recall_envelope_strip_telemetry.py +477 -0
  54. package/vendor/hindsight-memory/scripts/tests/test_recall_integration.py +51 -0
  55. package/vendor/hindsight-memory/scripts/tests/test_recall_parallel_deadline.py +409 -0
  56. package/vendor/hindsight-memory/scripts/tests/test_recall_tag_weights.py +96 -0
  57. package/vendor/hindsight-memory/scripts/tests/test_recall_transcript_fallback.py +413 -0
  58. package/vendor/hindsight-memory/scripts/tests/test_reconcile_durability.py +49 -0
  59. package/vendor/hindsight-memory/scripts/tests/test_subagent_retain.py +439 -0
  60. package/vendor/hindsight-memory/settings.json +3 -1
@@ -2120,7 +2120,7 @@ var init_esm = __esm(() => {
2120
2120
  });
2121
2121
 
2122
2122
  // src/build-info.ts
2123
- var VERSION = "0.19.2", COMMIT_SHA = "1fa69736";
2123
+ var VERSION = "0.19.3", COMMIT_SHA = "41896be4";
2124
2124
 
2125
2125
  // src/cli/resolve-version.ts
2126
2126
  import { existsSync, readFileSync } from "node:fs";
@@ -27107,6 +27107,7 @@ function renderHindsightSettingsOverrides(raw, additionalBanks, retainConfig) {
27107
27107
  settings.recallTypes = ["world", "experience", "observation"];
27108
27108
  settings.recallSkipTrivial = true;
27109
27109
  settings.directiveCaptureNudge = true;
27110
+ settings.recallTagWeights = { sidechain: 0.8 };
27110
27111
  if (additionalBanks.length > 0) {
27111
27112
  settings.recallAdditionalBanks = [...additionalBanks];
27112
27113
  }
@@ -29881,6 +29882,7 @@ function describeAgents(config, litellmConfirmedAgents) {
29881
29882
  smallFastModel: resolved.litellm?.small_fast_model ?? config.litellm?.small_fast_model ?? "claude-haiku-4-5-20251001"
29882
29883
  },
29883
29884
  model: resolveMainModel(resolved.model),
29885
+ tmuxSupervisor: resolved.experimental?.legacy_pty !== true,
29884
29886
  timezone: resolveTimezone(config, resolved, {
29885
29887
  onUtcFallback: () => {
29886
29888
  console.warn(` \u26a0 timezone: no explicit timezone set and server detection resolved to UTC ` + `for agent "${name}" \u2014 cron schedules and the per-turn time hint will ` + `run in UTC. Add \`switchroom.timezone: "Region/City"\` (e.g. ` + `"Australia/Melbourne") to switchroom.yaml to silence this warning.`);
@@ -30343,6 +30345,7 @@ function emitAgentService(lines, a, imageTag, buildMode, buildContext, homePrefi
30343
30345
  env2.ANTHROPIC_SMALL_FAST_MODEL = a.litellm.smallFastModel;
30344
30346
  }
30345
30347
  env2.SWITCHROOM_VOICE_ENGINE = voiceEngine;
30348
+ env2.SWITCHROOM_TMUX_SUPERVISOR = a.tmuxSupervisor ? "1" : "0";
30346
30349
  for (const [k, v] of Object.entries(a.userEnv)) {
30347
30350
  if (env2[k] === undefined)
30348
30351
  env2[k] = v;
@@ -32986,6 +32989,8 @@ var init_protocol2 = __esm(() => {
32986
32989
  label: exports_external.string(),
32987
32990
  expiresAt: exports_external.number().optional(),
32988
32991
  exhausted: exports_external.boolean(),
32992
+ in_service: exports_external.boolean().optional(),
32993
+ entitlement_blocked: exports_external.boolean().optional(),
32989
32994
  exhausted_until: exports_external.number().optional(),
32990
32995
  throttled_until: exports_external.number().optional(),
32991
32996
  threshold_violations: exports_external.number().int().nonnegative().optional(),
@@ -36657,7 +36662,8 @@ async function inspectBankHealth(mcpUrl, bankId, opts) {
36657
36662
  pendingOperations: 0,
36658
36663
  newestDocumentAt: null,
36659
36664
  unextractedDocuments: [],
36660
- mentalModels: []
36665
+ mentalModels: [],
36666
+ activeDirectiveCount: null
36661
36667
  };
36662
36668
  const stats = await getJson(`${base}/v1/default/banks/${bank}/stats`, opts);
36663
36669
  if (!stats.ok)
@@ -36668,6 +36674,8 @@ async function inspectBankHealth(mcpUrl, bankId, opts) {
36668
36674
  const models = await getJson(`${base}/v1/default/banks/${bank}/mental-models`, opts);
36669
36675
  if (!models.ok)
36670
36676
  return { ...empty, reason: models.reason };
36677
+ const directives = await getJson(`${base}/v1/default/banks/${bank}/directives?active_only=true`, opts);
36678
+ const activeDirectiveCount = directives.ok && Array.isArray(directives.data.items) ? directives.data.items.length : null;
36671
36679
  const docItems = docs.data.items ?? [];
36672
36680
  let newestDocumentAt = null;
36673
36681
  const unextracted = [];
@@ -36694,6 +36702,7 @@ async function inspectBankHealth(mcpUrl, bankId, opts) {
36694
36702
  pendingOperations: stats.data.pending_operations ?? 0,
36695
36703
  newestDocumentAt,
36696
36704
  unextractedDocuments: unextracted,
36705
+ activeDirectiveCount,
36697
36706
  mentalModels: (models.data.items ?? []).filter((m) => typeof m?.id === "string" && typeof m?.name === "string").map((m) => {
36698
36707
  const { basedOnCounts, totalSourceFacts, derivedFromModelIds } = summarizeBasedOn(m.reflect_response);
36699
36708
  return {
@@ -42022,6 +42031,29 @@ var init_hindsight_tools = __esm(() => {
42022
42031
 
42023
42032
  // src/cli/doctor-memory.ts
42024
42033
  import { execFileSync as execFileSync18 } from "node:child_process";
42034
+ function classifyDirectiveCount(count, bankLabel) {
42035
+ if (count === null)
42036
+ return null;
42037
+ const name = `${bankLabel} directives`;
42038
+ if (count > MAX_DIRECTIVES) {
42039
+ const truncated = count - MAX_DIRECTIVES;
42040
+ return {
42041
+ name,
42042
+ status: "fail",
42043
+ detail: `${count} active directives \u2014 exceeds MAX_DIRECTIVES=${MAX_DIRECTIVES}, so the ` + `${truncated} lowest-priority directive(s) are SILENTLY truncated from the ` + `<active_directives> recall block and never reach the agent`,
42044
+ fix: "Retire or merge stale directives so the active count is at or below " + `${MAX_DIRECTIVES} (deletes stay operator-approved). The mental-model-curator ` + "skill's directive merge/retire pass is the durable path."
42045
+ };
42046
+ }
42047
+ if (count > DIRECTIVE_WARN_THRESHOLD) {
42048
+ return {
42049
+ name,
42050
+ status: "warn",
42051
+ detail: `${count} active directives \u2014 approaching the MAX_DIRECTIVES=${MAX_DIRECTIVES} cap ` + `above which the recall block silently truncates the overflow`,
42052
+ fix: "Prune or merge low-value directives before the count crosses " + `${MAX_DIRECTIVES}. Review with \`switchroom memory --directives <bank>\`.`
42053
+ };
42054
+ }
42055
+ return null;
42056
+ }
42025
42057
  function classifyShmSize(bytes) {
42026
42058
  const mib = Math.round(bytes / 1024 / 1024);
42027
42059
  if (bytes < MIN_HINDSIGHT_SHM_BYTES) {
@@ -42434,7 +42466,7 @@ function classifyToolContract(advertised) {
42434
42466
  }
42435
42467
  return results;
42436
42468
  }
42437
- var MIN_HINDSIGHT_SHM_BYTES, CONSOLIDATION_BACKLOG_WARN = 25, CONSOLIDATION_BACKLOG_FAIL = 200;
42469
+ var MIN_HINDSIGHT_SHM_BYTES, MAX_DIRECTIVES = 15, DIRECTIVE_WARN_THRESHOLD = 12, CONSOLIDATION_BACKLOG_WARN = 25, CONSOLIDATION_BACKLOG_FAIL = 200;
42438
42470
  var init_doctor_memory = __esm(() => {
42439
42471
  init_hindsight_tools();
42440
42472
  init_hindsight();
@@ -45758,6 +45790,69 @@ var init_doctor_timezone = __esm(() => {
45758
45790
  init_timezone();
45759
45791
  });
45760
45792
 
45793
+ // src/cli/doctor-fix-session-model.ts
45794
+ import { join as join67 } from "node:path";
45795
+ function describeReconcileChanges(changes) {
45796
+ if (changes.length === 0)
45797
+ return "Reconcile rewrote no other files.";
45798
+ const MAX_LISTED = 6;
45799
+ const listed = changes.slice(0, MAX_LISTED).join(", ");
45800
+ const more = changes.length > MAX_LISTED ? ` (+${changes.length - MAX_LISTED} more)` : "";
45801
+ return `Full per-agent reconcile applied \u2014 rewrote ${changes.length} managed file(s): ` + listed + more;
45802
+ }
45803
+ function fixSessionModelCarrierDrift(config, deps) {
45804
+ const agentsDir = resolveAgentsDir(config);
45805
+ const results = [];
45806
+ for (const name of Object.keys(config.agents ?? {})) {
45807
+ const startShPath = join67(agentsDir, name, "start.sh");
45808
+ const label = `${name}: start.sh /model session carrier (--fix)`;
45809
+ const pre = deps.check(name, startShPath);
45810
+ if (pre.status === "ok") {
45811
+ results.push({
45812
+ name: label,
45813
+ status: "ok",
45814
+ detail: "rev5 carrier already present \u2014 nothing to fix"
45815
+ });
45816
+ continue;
45817
+ }
45818
+ if (pre.status === "skip") {
45819
+ results.push({ ...pre, name: label });
45820
+ continue;
45821
+ }
45822
+ let reconcileChanges;
45823
+ try {
45824
+ reconcileChanges = deps.reconcile(name).changes;
45825
+ } catch (err) {
45826
+ results.push({
45827
+ name: label,
45828
+ status: "fail",
45829
+ detail: `drift detected (${pre.detail ?? "carrier check failed"}) but reconcile failed: ${err.message}`,
45830
+ fix: "Fix the reconcile error, or run `switchroom apply` manually."
45831
+ });
45832
+ continue;
45833
+ }
45834
+ const post = deps.check(name, startShPath);
45835
+ if (post.status === "ok") {
45836
+ results.push({
45837
+ name: label,
45838
+ status: "ok",
45839
+ detail: "healed: start.sh regenerated with the rev5 `.session-model` carrier \u2014 takes effect on the agent's next restart. " + describeReconcileChanges(reconcileChanges)
45840
+ });
45841
+ } else {
45842
+ results.push({
45843
+ name: label,
45844
+ status: "fail",
45845
+ detail: `regenerated start.sh still fails the carrier check: ${post.detail ?? post.status} \u2014 the installed template may be stale`,
45846
+ fix: "Update switchroom (the bundled profiles/_base/start.sh.hbs must carry the rev5 carrier), then re-run `switchroom doctor --fix`."
45847
+ });
45848
+ }
45849
+ }
45850
+ return results;
45851
+ }
45852
+ var init_doctor_fix_session_model = __esm(() => {
45853
+ init_loader();
45854
+ });
45855
+
45761
45856
  // src/cli/doctor.ts
45762
45857
  var exports_doctor = {};
45763
45858
  __export(exports_doctor, {
@@ -45817,16 +45912,16 @@ import {
45817
45912
  readdirSync as readdirSync23,
45818
45913
  statSync as statSync38
45819
45914
  } from "node:fs";
45820
- import { dirname as dirname20, join as join67, resolve as resolve39 } from "node:path";
45915
+ import { dirname as dirname20, join as join68, resolve as resolve39 } from "node:path";
45821
45916
  import { createPublicKey, createPrivateKey } from "node:crypto";
45822
45917
  function findInNvm(bin) {
45823
- const nvmRoot = join67(process.env.HOME ?? "", ".nvm", "versions", "node");
45918
+ const nvmRoot = join68(process.env.HOME ?? "", ".nvm", "versions", "node");
45824
45919
  if (!existsSync66(nvmRoot))
45825
45920
  return null;
45826
45921
  try {
45827
45922
  const versions = readdirSync23(nvmRoot).sort().reverse();
45828
45923
  for (const v of versions) {
45829
- const candidate = join67(nvmRoot, v, "bin", bin);
45924
+ const candidate = join68(nvmRoot, v, "bin", bin);
45830
45925
  try {
45831
45926
  const s = statSync38(candidate);
45832
45927
  if (s.isFile() || s.isSymbolicLink()) {
@@ -45853,7 +45948,7 @@ function whichOnPath(bin) {
45853
45948
  for (const dir of pathEnv.split(":")) {
45854
45949
  if (!dir)
45855
45950
  continue;
45856
- const candidate = join67(dir, bin);
45951
+ const candidate = join68(dir, bin);
45857
45952
  if (isX(candidate))
45858
45953
  return candidate;
45859
45954
  }
@@ -46019,7 +46114,7 @@ function findChromium(homeDir = process.env.HOME ?? "", envBrowsersPath = proces
46019
46114
  if (envBrowsersPath && envBrowsersPath.length > 0) {
46020
46115
  cacheLocations.push(envBrowsersPath);
46021
46116
  }
46022
- cacheLocations.push(join67(homeDir, ".cache", "ms-playwright"));
46117
+ cacheLocations.push(join68(homeDir, ".cache", "ms-playwright"));
46023
46118
  for (const cacheDir of cacheLocations) {
46024
46119
  if (!existsSync66(cacheDir))
46025
46120
  continue;
@@ -46027,10 +46122,10 @@ function findChromium(homeDir = process.env.HOME ?? "", envBrowsersPath = proces
46027
46122
  const entries = readdirSync23(cacheDir).filter((e) => e.startsWith("chromium"));
46028
46123
  for (const entry of entries) {
46029
46124
  const candidates2 = [
46030
- join67(cacheDir, entry, "chrome-linux64", "chrome"),
46031
- join67(cacheDir, entry, "chrome-linux", "chrome"),
46032
- join67(cacheDir, entry, "chrome-linux64", "headless_shell"),
46033
- join67(cacheDir, entry, "chrome-linux", "headless_shell")
46125
+ join68(cacheDir, entry, "chrome-linux64", "chrome"),
46126
+ join68(cacheDir, entry, "chrome-linux", "chrome"),
46127
+ join68(cacheDir, entry, "chrome-linux64", "headless_shell"),
46128
+ join68(cacheDir, entry, "chrome-linux", "headless_shell")
46034
46129
  ];
46035
46130
  for (const path5 of candidates2) {
46036
46131
  if (existsSync66(path5))
@@ -46162,7 +46257,7 @@ function checkDeployMounts(opts) {
46162
46257
  const home2 = opts?.home ?? process.env.HOME ?? "/root";
46163
46258
  const { pathKind } = opts?.deps ?? DEFAULT_DEPLOY_MOUNTS_DEPS;
46164
46259
  const results = [];
46165
- const dockerComposePlugin = join67(home2, ".docker", "cli-plugins", "docker-compose");
46260
+ const dockerComposePlugin = join68(home2, ".docker", "cli-plugins", "docker-compose");
46166
46261
  const pluginKind = pathKind(dockerComposePlugin);
46167
46262
  if (pluginKind === "dir") {
46168
46263
  results.push({
@@ -46200,7 +46295,7 @@ function checkDeployMounts(opts) {
46200
46295
  function checkLegacyState() {
46201
46296
  const results = [];
46202
46297
  const h = process.env.HOME ?? "/root";
46203
- const clerkDir = join67(h, LEGACY_STATE_DIR);
46298
+ const clerkDir = join68(h, LEGACY_STATE_DIR);
46204
46299
  const clerkPresent = existsSync66(clerkDir);
46205
46300
  results.push({
46206
46301
  name: "legacy ~/.clerk state",
@@ -46210,7 +46305,7 @@ function checkLegacyState() {
46210
46305
  fix: "Legacy state detected. Run `mv ~/.clerk ~/.switchroom` and rename " + "any top-level `clerk:` key in switchroom.yaml to `switchroom:`. " + "This back-compat shim is REMOVED in v0.13.0 \u2014 no automatic " + "migration exists."
46211
46306
  } : {}
46212
46307
  });
46213
- const legacySock = join67(h, ".switchroom", "vault-broker.sock");
46308
+ const legacySock = join68(h, ".switchroom", "vault-broker.sock");
46214
46309
  let sockStat = null;
46215
46310
  try {
46216
46311
  sockStat = lstatSync9(legacySock);
@@ -46474,6 +46569,9 @@ async function checkBankIngestHealth(config, url, opts) {
46474
46569
  });
46475
46570
  continue;
46476
46571
  }
46572
+ const directiveRow = classifyDirectiveCount(h.activeDirectiveCount, label);
46573
+ if (directiveRow)
46574
+ results.push(directiveRow);
46477
46575
  if (h.totalDocuments === 0) {
46478
46576
  results.push({
46479
46577
  name: label,
@@ -46776,7 +46874,7 @@ async function checkTelegram(config) {
46776
46874
  const plugin = agentConfig.channels?.telegram?.plugin ?? "switchroom";
46777
46875
  if (plugin !== "switchroom")
46778
46876
  continue;
46779
- const envPath = join67(agentsDir, name, "telegram", ".env");
46877
+ const envPath = join68(agentsDir, name, "telegram", ".env");
46780
46878
  const read = tryReadHostFile(envPath);
46781
46879
  if (read.kind === "eacces") {
46782
46880
  results.push({
@@ -46864,7 +46962,7 @@ function checkStartShSessionModelCarrier(agentName, startShPath) {
46864
46962
  name: label,
46865
46963
  status: "warn",
46866
46964
  detail: `${startShPath} not found`,
46867
- fix: `Run \`switchroom apply\` to scaffold start.sh (rev5 \`.session-model\` carrier).`
46965
+ fix: `Run \`switchroom doctor --fix\` (or \`switchroom apply\`) to scaffold start.sh (rev5 \`.session-model\` carrier).`
46868
46966
  };
46869
46967
  }
46870
46968
  let content;
@@ -46893,7 +46991,7 @@ function checkStartShSessionModelCarrier(agentName, startShPath) {
46893
46991
  name: label,
46894
46992
  status: "fail",
46895
46993
  detail: "start.sh tests `.session-model` but lacks rev5 JSON apply (`configuredDefaultAtWrite` / boot-attempts) \u2014 /model switches may not stick",
46896
- fix: "Run `switchroom apply` to regenerate start.sh from profiles/_base/start.sh.hbs (rev5 carrier). Takes effect on the next agent restart (no need to bounce until release)."
46994
+ fix: "Run `switchroom doctor --fix` (or `switchroom apply`) to regenerate start.sh from profiles/_base/start.sh.hbs (rev5 carrier). Takes effect on the next agent restart (no need to bounce until release)."
46897
46995
  };
46898
46996
  }
46899
46997
  const legacyOnly = /\.session-model-override/.test(content) && !hasBareSessionModelTest;
@@ -46901,12 +46999,12 @@ function checkStartShSessionModelCarrier(agentName, startShPath) {
46901
46999
  name: label,
46902
47000
  status: "fail",
46903
47001
  detail: legacyOnly ? "start.sh only reads legacy `.session-model-override`; gateway writes rev5 `.session-model` \u2014 Telegram /model relaunches boot the yaml pin (silent miss)" : "start.sh missing rev5 `.session-model` carrier file test \u2014 Telegram /model cannot apply session overrides across relaunch",
46904
- fix: "Run `switchroom apply` to regenerate start.sh from the latest template (rev5 `.session-model` carrier). The rewrite is on disk immediately; session switches apply on the next agent restart/release bounce."
47002
+ fix: "Run `switchroom doctor --fix` (or `switchroom apply`) to regenerate start.sh from the latest template (rev5 `.session-model` carrier). The rewrite is on disk immediately; session switches apply on the next agent restart/release bounce."
46905
47003
  };
46906
47004
  }
46907
47005
  function checkLeakedHomeSwitchroom(agentName, agentDir) {
46908
47006
  const label = `${agentName}: $HOME/.switchroom symlink (#910)`;
46909
- const path5 = join67(agentDir, "home", ".switchroom");
47007
+ const path5 = join68(agentDir, "home", ".switchroom");
46910
47008
  let stats;
46911
47009
  try {
46912
47010
  stats = lstatSync9(path5);
@@ -46943,7 +47041,7 @@ function checkLeakedHomeSwitchroom(agentName, agentDir) {
46943
47041
  }
46944
47042
  function checkRepoHygiene(repoRoot) {
46945
47043
  const results = [];
46946
- const exportDir = join67(repoRoot, "clerk-export");
47044
+ const exportDir = join68(repoRoot, "clerk-export");
46947
47045
  if (existsSync66(exportDir)) {
46948
47046
  results.push({
46949
47047
  name: "repo hygiene: clerk-export/ on disk (#1072)",
@@ -46952,7 +47050,7 @@ function checkRepoHygiene(repoRoot) {
46952
47050
  fix: `Run scripts/migrate-clerk-export-to-vault.sh to move the bundle ` + `into the vault, then delete the on-disk copy.`
46953
47051
  });
46954
47052
  }
46955
- const knownTarball = join67(repoRoot, "clerk-export-with-secrets.tar.gz");
47053
+ const knownTarball = join68(repoRoot, "clerk-export-with-secrets.tar.gz");
46956
47054
  if (existsSync66(knownTarball)) {
46957
47055
  results.push({
46958
47056
  name: "repo hygiene: clerk-export-with-secrets.tar.gz on disk (#1072)",
@@ -46970,7 +47068,7 @@ function checkRepoHygiene(repoRoot) {
46970
47068
  results.push({
46971
47069
  name: `repo hygiene: ${name} on disk (#1072)`,
46972
47070
  status: "warn",
46973
- detail: `${join67(repoRoot, name)} matches the *-with-secrets*.tar.gz ` + `pattern. Likely contains real credentials.`,
47071
+ detail: `${join68(repoRoot, name)} matches the *-with-secrets*.tar.gz ` + `pattern. Likely contains real credentials.`,
46974
47072
  fix: `Inspect, migrate any secrets into the vault, then delete the ` + `archive.`
46975
47073
  });
46976
47074
  }
@@ -46993,9 +47091,9 @@ function checkRepoHygiene(repoRoot) {
46993
47091
  }
46994
47092
  function isSwitchroomCheckout(dir) {
46995
47093
  try {
46996
- if (!existsSync66(join67(dir, ".git")))
47094
+ if (!existsSync66(join68(dir, ".git")))
46997
47095
  return false;
46998
- const pkgPath = join67(dir, "package.json");
47096
+ const pkgPath = join68(dir, "package.json");
46999
47097
  if (!existsSync66(pkgPath))
47000
47098
  return false;
47001
47099
  const pkg = JSON.parse(readFileSync59(pkgPath, "utf-8"));
@@ -47032,8 +47130,8 @@ function checkAgents(config, configPath) {
47032
47130
  fix: `Rotate the bot token (e.g. via \`switchroom vault\`), then run ` + `\`switchroom agent unquarantine ${name}\` and \`switchroom agent restart ${name}\``
47033
47131
  });
47034
47132
  }
47035
- results.push(checkStartShStale(name, join67(agentDir, "start.sh")));
47036
- results.push(checkStartShSessionModelCarrier(name, join67(agentDir, "start.sh")));
47133
+ results.push(checkStartShStale(name, join68(agentDir, "start.sh")));
47134
+ results.push(checkStartShSessionModelCarrier(name, join68(agentDir, "start.sh")));
47037
47135
  results.push(checkLeakedHomeSwitchroom(name, agentDir));
47038
47136
  const status = statuses[name];
47039
47137
  const active = status?.active ?? "unknown";
@@ -47110,7 +47208,7 @@ function checkAgents(config, configPath) {
47110
47208
  }
47111
47209
  }
47112
47210
  if (agentConfig.channels?.telegram?.plugin === "switchroom") {
47113
- const mcpJsonPath = join67(agentDir, ".mcp.json");
47211
+ const mcpJsonPath = join68(agentDir, ".mcp.json");
47114
47212
  if (!existsSync66(mcpJsonPath)) {
47115
47213
  results.push({
47116
47214
  name: `${name}: .mcp.json`,
@@ -47412,7 +47510,7 @@ async function checkMffAuthFlow(envPath = mffEnvPath(), timeoutMs = 8000) {
47412
47510
  };
47413
47511
  }
47414
47512
  const credDir = dirname20(envPath);
47415
- const authScript = join67(credDir, "claude-auth.py");
47513
+ const authScript = join68(credDir, "claude-auth.py");
47416
47514
  if (!existsSync66(authScript)) {
47417
47515
  return {
47418
47516
  name: "mff: auth flow",
@@ -47629,7 +47727,7 @@ function runDockerSection(config) {
47629
47727
  });
47630
47728
  }
47631
47729
  function registerDoctorCommand(program3) {
47632
- program3.command("doctor").description("Diagnose Switchroom's setup: deps, vault, memory, agents, MCP wireup").option("--json", "Output as JSON").option("--skill <name>", "Run probes for a specific skill only (e.g. mff)").option("--fast", "Skip in-agent (hostd) liveness probes \u2014 offline/quick; the host-unverifiable rows stay `skip`").action(withConfigError(async (opts) => {
47730
+ program3.command("doctor").description("Diagnose Switchroom's setup: deps, vault, memory, agents, MCP wireup").option("--json", "Output as JSON").option("--skill <name>", "Run probes for a specific skill only (e.g. mff)").option("--fast", "Skip in-agent (hostd) liveness probes \u2014 offline/quick; the host-unverifiable rows stay `skip`").option("--fix", "Auto-remediate rev5 /model `.session-model` carrier drift by running the FULL per-agent reconcile for each drifted agent (start.sh + all switchroom-managed files, same as `switchroom apply` for that agent; staged switchroom.yaml edits land too \u2014 files rewritten are listed in the result row). Takes effect on the agent's next restart").action(withConfigError(async (opts) => {
47633
47731
  try {
47634
47732
  getConfigPath(program3);
47635
47733
  } catch (_e) {
@@ -47698,7 +47796,23 @@ function registerDoctorCommand(program3) {
47698
47796
  return { kind: "unreachable", msg: err.message };
47699
47797
  }
47700
47798
  };
47799
+ const fixSections = opts.fix ? [
47800
+ {
47801
+ title: "Auto-remediation (--fix)",
47802
+ results: fixSessionModelCarrierDrift(config, {
47803
+ check: checkStartShSessionModelCarrier,
47804
+ reconcile: (name) => {
47805
+ const agentConfig = config.agents?.[name];
47806
+ if (!agentConfig)
47807
+ throw new Error(`agent ${name} not in config`);
47808
+ const result = reconcileAgent(name, agentConfig, resolveAgentsDir(config), config.telegram, config, configPath, { preserveClaudeMd: true });
47809
+ return { changes: result.changes };
47810
+ }
47811
+ })
47812
+ }
47813
+ ] : [];
47701
47814
  const sections = [
47815
+ ...fixSections,
47702
47816
  { title: "Dependencies", results: checkDependencies() },
47703
47817
  { title: "Skills Prerequisites", results: checkSkillsPrerequisites() },
47704
47818
  { title: "Manifest Drift", results: await checkManifestDrift() },
@@ -47845,6 +47959,7 @@ var init_doctor = __esm(() => {
47845
47959
  init_helpers();
47846
47960
  init_lifecycle();
47847
47961
  init_quarantine();
47962
+ init_scaffold();
47848
47963
  init_manager();
47849
47964
  init_accounts();
47850
47965
  init_manifest();
@@ -47869,6 +47984,7 @@ var init_doctor = __esm(() => {
47869
47984
  init_doctor_agent_smoke();
47870
47985
  init_doctor_vault_broker_durability();
47871
47986
  init_doctor_timezone();
47987
+ init_doctor_fix_session_model();
47872
47988
  DEFAULT_DEPLOY_MOUNTS_DEPS = { pathKind: defaultPathKind };
47873
47989
  MANIFEST_WARN_ONLY = new Set([
47874
47990
  "@playwright/mcp",
@@ -48454,7 +48570,7 @@ var init_fleet_defaults = __esm(() => {
48454
48570
 
48455
48571
  // src/agents/connection-health.ts
48456
48572
  import { mkdirSync as mkdirSync46, writeFileSync as writeFileSync28 } from "node:fs";
48457
- import { join as join83 } from "node:path";
48573
+ import { join as join84 } from "node:path";
48458
48574
  async function computeAgentConnectionIssues(config, agentName, vaultAclReader) {
48459
48575
  const reqs = computeMcpSecretRequirements(config).filter((r) => r.agent === agentName);
48460
48576
  if (reqs.length === 0)
@@ -48511,8 +48627,8 @@ async function computeAgentConnectionIssues(config, agentName, vaultAclReader) {
48511
48627
  return issues;
48512
48628
  }
48513
48629
  function writeConnectionHealthFile(agentDir, health, deps) {
48514
- const dir = join83(agentDir, ".claude");
48515
- const path8 = join83(dir, CONNECTION_HEALTH_FILENAME);
48630
+ const dir = join84(agentDir, ".claude");
48631
+ const path8 = join84(dir, CONNECTION_HEALTH_FILENAME);
48516
48632
  (deps?.mkdir ?? ((p, o) => mkdirSync46(p, o)))(dir, { recursive: true });
48517
48633
  (deps?.writeFile ?? ((p, d) => writeFileSync28(p, d)))(path8, JSON.stringify(health, null, 2) + `
48518
48634
  `);
@@ -48536,9 +48652,9 @@ var init_connection_health = () => {};
48536
48652
 
48537
48653
  // src/cli/update-prompt-hook.ts
48538
48654
  import { existsSync as existsSync83, readFileSync as readFileSync72, writeFileSync as writeFileSync29, chmodSync as chmodSync12, mkdirSync as mkdirSync47 } from "node:fs";
48539
- import { join as join84 } from "node:path";
48655
+ import { join as join85 } from "node:path";
48540
48656
  function containerHookCommand() {
48541
- return join84(CONTAINER_AGENT_DIR, ".claude", "hooks", HOOK_FILENAME);
48657
+ return join85(CONTAINER_AGENT_DIR, ".claude", "hooks", HOOK_FILENAME);
48542
48658
  }
48543
48659
  function updatePromptHookScript() {
48544
48660
  return `#!/bin/bash
@@ -48604,9 +48720,9 @@ exit 0
48604
48720
  `;
48605
48721
  }
48606
48722
  function installUpdatePromptHook(agentDir) {
48607
- const hooksDir = join84(agentDir, ".claude", "hooks");
48723
+ const hooksDir = join85(agentDir, ".claude", "hooks");
48608
48724
  mkdirSync47(hooksDir, { recursive: true });
48609
- const scriptPath = join84(hooksDir, HOOK_FILENAME);
48725
+ const scriptPath = join85(hooksDir, HOOK_FILENAME);
48610
48726
  const desired = updatePromptHookScript();
48611
48727
  let installed = false;
48612
48728
  const existing = existsSync83(scriptPath) ? readFileSync72(scriptPath, "utf-8") : "";
@@ -48619,7 +48735,7 @@ function installUpdatePromptHook(agentDir) {
48619
48735
  chmodSync12(scriptPath, 493);
48620
48736
  } catch {}
48621
48737
  }
48622
- const settingsPath = join84(agentDir, ".claude", "settings.json");
48738
+ const settingsPath = join85(agentDir, ".claude", "settings.json");
48623
48739
  if (!existsSync83(settingsPath)) {
48624
48740
  return { scriptPath, settingsPath, installed };
48625
48741
  }
@@ -49175,7 +49291,7 @@ import { accessSync as accessSync3, chmodSync as chmodSync14, chownSync as chown
49175
49291
  import { mkdir as mkdir2 } from "node:fs/promises";
49176
49292
  import { spawnSync as childSpawnSync } from "node:child_process";
49177
49293
  import readline from "node:readline";
49178
- import { dirname as dirname30, join as join86, resolve as resolve52 } from "node:path";
49294
+ import { dirname as dirname30, join as join87, resolve as resolve52 } from "node:path";
49179
49295
  import { homedir as homedir49 } from "node:os";
49180
49296
  import { execFileSync as execFileSync27 } from "node:child_process";
49181
49297
  function effectiveLiteLLMEnabled(config, agentResolvedLitellm) {
@@ -49187,7 +49303,7 @@ async function resolveOperatorVaultPassphrase(home2) {
49187
49303
  return envPass;
49188
49304
  try {
49189
49305
  const { readAutoUnlockFile: readAutoUnlockFile2 } = await Promise.resolve().then(() => (init_auto_unlock(), exports_auto_unlock));
49190
- const blobPath = join86(home2, ".switchroom", "vault-auto-unlock");
49306
+ const blobPath = join87(home2, ".switchroom", "vault-auto-unlock");
49191
49307
  const pass = readAutoUnlockFile2(blobPath);
49192
49308
  return pass && pass.length > 0 ? pass : null;
49193
49309
  } catch {
@@ -49196,9 +49312,9 @@ async function resolveOperatorVaultPassphrase(home2) {
49196
49312
  }
49197
49313
  function materializeLitellmMasterKeyForBroker(masterKey, home2 = process.env.HOME ?? "/root") {
49198
49314
  try {
49199
- const stateDir = join86(home2, ".switchroom", "state", "auth-broker");
49315
+ const stateDir = join87(home2, ".switchroom", "state", "auth-broker");
49200
49316
  mkdirSync49(stateDir, { recursive: true, mode: 448 });
49201
- const path9 = join86(stateDir, LITELLM_MASTER_KEY_STATE_BASENAME);
49317
+ const path9 = join87(stateDir, LITELLM_MASTER_KEY_STATE_BASENAME);
49202
49318
  writeFileSync31(path9, masterKey.trim() + `
49203
49319
  `, { mode: 384 });
49204
49320
  try {
@@ -49524,7 +49640,7 @@ function resolveVaultBindMountDir(homeDir, ctx) {
49524
49640
  if (isCustomPath && ctx.customVaultPath) {
49525
49641
  return dirname30(ctx.customVaultPath);
49526
49642
  }
49527
- return join86(homeDir, ".switchroom", "vault");
49643
+ return join87(homeDir, ".switchroom", "vault");
49528
49644
  }
49529
49645
  function inspectVaultBindMountDir(vaultDir) {
49530
49646
  if (!existsSync86(vaultDir))
@@ -49555,41 +49671,41 @@ function hasVaultRefs(value) {
49555
49671
  async function ensureHostMountSources(config) {
49556
49672
  const home2 = resolveHostHomeForCompose();
49557
49673
  const dirs = [
49558
- join86(home2, ".switchroom", "approvals"),
49559
- join86(home2, ".switchroom", "scheduler"),
49560
- join86(home2, ".switchroom", "logs"),
49561
- join86(home2, ".switchroom", "compose"),
49562
- join86(home2, ".switchroom", "broker-operator")
49674
+ join87(home2, ".switchroom", "approvals"),
49675
+ join87(home2, ".switchroom", "scheduler"),
49676
+ join87(home2, ".switchroom", "logs"),
49677
+ join87(home2, ".switchroom", "compose"),
49678
+ join87(home2, ".switchroom", "broker-operator")
49563
49679
  ];
49564
49680
  for (const name of Object.keys(config.agents)) {
49565
- dirs.push(join86(home2, ".switchroom", "agents", name));
49566
- dirs.push(join86(home2, ".switchroom", "logs", name));
49567
- dirs.push(join86(home2, ".claude", "projects", name));
49568
- dirs.push(join86(home2, ".switchroom", "audit", name));
49569
- if (existsSync86(join86(home2, ".switchroom-config"))) {
49570
- dirs.push(join86(home2, ".switchroom-config", "agents", name, "personal-skills"));
49681
+ dirs.push(join87(home2, ".switchroom", "agents", name));
49682
+ dirs.push(join87(home2, ".switchroom", "logs", name));
49683
+ dirs.push(join87(home2, ".claude", "projects", name));
49684
+ dirs.push(join87(home2, ".switchroom", "audit", name));
49685
+ if (existsSync86(join87(home2, ".switchroom-config"))) {
49686
+ dirs.push(join87(home2, ".switchroom-config", "agents", name, "personal-skills"));
49571
49687
  }
49572
49688
  }
49573
49689
  for (const dir of dirs) {
49574
49690
  await mkdir2(dir, { recursive: true });
49575
49691
  }
49576
- const autoUnlockPath = join86(home2, ".switchroom", "vault-auto-unlock");
49692
+ const autoUnlockPath = join87(home2, ".switchroom", "vault-auto-unlock");
49577
49693
  if (!existsSync86(autoUnlockPath)) {
49578
49694
  writeFileSync31(autoUnlockPath, "", { mode: 384 });
49579
49695
  }
49580
- const auditLogPath = join86(home2, ".switchroom", "vault-audit.log");
49696
+ const auditLogPath = join87(home2, ".switchroom", "vault-audit.log");
49581
49697
  if (!existsSync86(auditLogPath)) {
49582
49698
  writeFileSync31(auditLogPath, "", { mode: 420 });
49583
49699
  }
49584
49700
  const grantsDbDir = getGrantsDbDir(home2);
49585
49701
  mkdirSync49(grantsDbDir, { recursive: true, mode: 448 });
49586
49702
  migrateLegacyGrantsDbLocation(getGrantsDbPath(home2));
49587
- const hostdAuditLogPath = join86(home2, ".switchroom", "host-control-audit.log");
49703
+ const hostdAuditLogPath = join87(home2, ".switchroom", "host-control-audit.log");
49588
49704
  if (!existsSync86(hostdAuditLogPath)) {
49589
49705
  writeFileSync31(hostdAuditLogPath, "", { mode: 420 });
49590
49706
  }
49591
49707
  for (const name of Object.keys(config.agents)) {
49592
- const tokenPath = join86(home2, ".switchroom", "agents", name, ".vault-token");
49708
+ const tokenPath = join87(home2, ".switchroom", "agents", name, ".vault-token");
49593
49709
  if (!existsSync86(tokenPath)) {
49594
49710
  writeFileSync31(tokenPath, "", { mode: 384 });
49595
49711
  }
@@ -49598,15 +49714,15 @@ async function ensureHostMountSources(config) {
49598
49714
  chownSync8(tokenPath, uid, uid);
49599
49715
  } catch {}
49600
49716
  }
49601
- const fleetDir = join86(home2, ".switchroom", "fleet");
49717
+ const fleetDir = join87(home2, ".switchroom", "fleet");
49602
49718
  await mkdir2(fleetDir, { recursive: true });
49603
- const invariantsPath = join86(fleetDir, "switchroom-invariants.md");
49719
+ const invariantsPath = join87(fleetDir, "switchroom-invariants.md");
49604
49720
  const invariantsCanonical = renderFleetInvariants();
49605
49721
  const invariantsCurrent = existsSync86(invariantsPath) ? readFileSync74(invariantsPath, "utf-8") : null;
49606
49722
  if (invariantsCurrent !== invariantsCanonical) {
49607
49723
  writeFileSync31(invariantsPath, invariantsCanonical, { mode: 420 });
49608
49724
  }
49609
- const fleetClaudePath = join86(fleetDir, "CLAUDE.md");
49725
+ const fleetClaudePath = join87(fleetDir, "CLAUDE.md");
49610
49726
  if (!existsSync86(fleetClaudePath)) {
49611
49727
  writeFileSync31(fleetClaudePath, renderFleetDefaultsClaudeMd(), {
49612
49728
  mode: 420
@@ -49692,8 +49808,8 @@ function detectAndReportLegacyGdriveSlots(vaultPath) {
49692
49808
  }
49693
49809
  function writeInstallTypeCache(homeDir = homedir49()) {
49694
49810
  const ctx = detectInstallType();
49695
- const dir = join86(homeDir, ".switchroom");
49696
- const out = join86(dir, "install-type.json");
49811
+ const dir = join87(homeDir, ".switchroom");
49812
+ const out = join87(dir, "install-type.json");
49697
49813
  const tmp = `${out}.tmp`;
49698
49814
  mkdirSync49(dir, { recursive: true });
49699
49815
  const payload = {
@@ -49760,17 +49876,17 @@ Applying switchroom config...
49760
49876
  writeOut(source_default.green(` + ${name}`) + source_default.gray(` (${agentConfig.extends ?? "default"}) \u2014 ${detail}
49761
49877
  `));
49762
49878
  try {
49763
- installUpdatePromptHook(join86(agentsDir, name));
49879
+ installUpdatePromptHook(join87(agentsDir, name));
49764
49880
  } catch (hookErr) {
49765
49881
  writeOut(source_default.gray(` (update-prompt hook install failed for ${name}: ${hookErr.message})
49766
49882
  `));
49767
49883
  }
49768
- await refreshAgentConnectionHealth(config, name, join86(agentsDir, name), {
49884
+ await refreshAgentConnectionHealth(config, name, join87(agentsDir, name), {
49769
49885
  vaultAclReader: connHealthVaultAclReader
49770
49886
  });
49771
49887
  try {
49772
49888
  const uid = allocateAgentUid(name);
49773
- alignAgentUid(name, join86(agentsDir, name), uid, {
49889
+ alignAgentUid(name, join87(agentsDir, name), uid, {
49774
49890
  confirm: !options.nonInteractive,
49775
49891
  writeOut
49776
49892
  });
@@ -49815,7 +49931,7 @@ Applying switchroom config...
49815
49931
  for (const name of agentNames) {
49816
49932
  try {
49817
49933
  const uid = allocateAgentUid(name);
49818
- alignAgentUid(name, join86(agentsDir, name), uid, {
49934
+ alignAgentUid(name, join87(agentsDir, name), uid, {
49819
49935
  confirm: !options.nonInteractive,
49820
49936
  writeOut
49821
49937
  });
@@ -50175,7 +50291,7 @@ function findUnwritableAgentDirs(config, opts) {
50175
50291
  const targets = opts.only ? [opts.only] : Object.keys(config.agents ?? {});
50176
50292
  const unwritable = [];
50177
50293
  for (const name of targets) {
50178
- const startSh = join86(agentsDir, name, "start.sh");
50294
+ const startSh = join87(agentsDir, name, "start.sh");
50179
50295
  if (!existsSync86(startSh))
50180
50296
  continue;
50181
50297
  try {
@@ -50381,7 +50497,7 @@ var init_apply = __esm(() => {
50381
50497
  switchroom: switchroom_default,
50382
50498
  minimal: minimal_default
50383
50499
  };
50384
- DEFAULT_COMPOSE_PATH2 = join86(homedir49(), ".switchroom", "compose", "docker-compose.yml");
50500
+ DEFAULT_COMPOSE_PATH2 = join87(homedir49(), ".switchroom", "compose", "docker-compose.yml");
50385
50501
  IN_AGENT_CONTAINER_APPLY_MSG = "`switchroom apply`'s full per-agent scaffold cannot run from inside an " + "agent container \u2014 this is a host/hostd operation by construction " + "(no vault at the container HOME, and no `docker compose` v2 plugin here).\nTo roll the fleet to a new version, drive the hostd rollout (`mcp__hostd__rollout`): it runs a `--compose-only` apply plus a per-agent restart-reconcile, and each agent refreshes its own templates " + `on restart \u2014 the roll completes without any agent running a full apply.
50386
50502
  ` + "A full host-side `sudo switchroom apply` is only needed for structural changes (compose regeneration / new-agent scaffolding), and is run by the operator on the host, never from inside an agent.";
50387
50503
  SELF_ELEVATE_PRESERVED_ENV = [
@@ -70801,6 +70917,10 @@ function isThin(d) {
70801
70917
  }
70802
70918
  function classifyState(args) {
70803
70919
  const { exhausted, exhaustedUntil, window, now } = args;
70920
+ if (args.entitlementBlocked === true)
70921
+ return "org-disabled";
70922
+ if (args.inService === false)
70923
+ return "retired";
70804
70924
  if (window.probeThin)
70805
70925
  return "unprobed";
70806
70926
  const norm = refillNormalizedUtils({
@@ -70845,17 +70965,30 @@ function buildScheduleRows(state, probe, now) {
70845
70965
  const exhaustedUntil = typeof a.exhausted_until === "number" ? new Date(a.exhausted_until) : null;
70846
70966
  const exhausted = a.exhausted && (exhaustedUntil?.getTime() ?? 0) > now.getTime();
70847
70967
  const rank = state.fallback_order.indexOf(a.label);
70968
+ const isActive = a.label === state.active;
70969
+ const inService = isActive ? true : a.in_service !== false;
70970
+ const entitlementBlocked = isActive ? false : a.entitlement_blocked === true;
70848
70971
  return {
70849
70972
  label: a.label,
70850
- isActive: a.label === state.active,
70973
+ isActive,
70851
70974
  fallbackRank: rank === -1 ? null : rank + 1,
70975
+ inService,
70976
+ entitlementBlocked,
70852
70977
  window,
70853
70978
  exhausted,
70854
70979
  exhaustedUntil,
70855
- state: classifyState({ exhausted, exhaustedUntil, window, now })
70980
+ state: classifyState({
70981
+ exhausted,
70982
+ exhaustedUntil,
70983
+ window,
70984
+ now,
70985
+ inService,
70986
+ entitlementBlocked
70987
+ })
70856
70988
  };
70857
70989
  });
70858
- const key = (r) => r.isActive ? -1 : r.fallbackRank ?? 9999;
70990
+ const outOfService = (r) => !r.inService || r.entitlementBlocked;
70991
+ const key = (r) => outOfService(r) ? 1e5 : r.isActive ? -1 : r.fallbackRank ?? 9999;
70859
70992
  return rows.sort((a, b) => key(a) - key(b) || a.label.localeCompare(b.label));
70860
70993
  }
70861
70994
  var EM_DASH = "\u2014";
@@ -70908,6 +71041,10 @@ function formatWeeklyCell(w, now, tz) {
70908
71041
  return `${pct} \u00b7 ${formatResetDay(w.weeklyResetAt, tz)} (${rel})`;
70909
71042
  }
70910
71043
  function poolLabel(row) {
71044
+ if (row.entitlementBlocked)
71045
+ return "disabled";
71046
+ if (!row.inService)
71047
+ return "retired";
70911
71048
  if (row.isActive)
70912
71049
  return row.fallbackRank ? `active #${row.fallbackRank}` : "active";
70913
71050
  if (row.fallbackRank)
@@ -70919,6 +71056,10 @@ function formatStateCell(row, now) {
70919
71056
  const rel = horizon ? ` \u00b7 ${formatDuration(horizon.getTime() - now.getTime())}` : "";
70920
71057
  const overageNote = row.window.overageServeBlocking && row.window.overageReason ? ` (overage off: ${row.window.overageReason})` : row.window.overageServeBlocking ? " (overage off)" : "";
70921
71058
  switch (row.state) {
71059
+ case "org-disabled":
71060
+ return "DISABLED (org)";
71061
+ case "retired":
71062
+ return "retired";
70922
71063
  case "quota-exhausted":
70923
71064
  return `quota-exhausted${rel}`;
70924
71065
  case "healthy":
@@ -70940,10 +71081,16 @@ function pad3(s, n) {
70940
71081
  return s.padEnd(n);
70941
71082
  }
70942
71083
  function glyphFor(row, color) {
70943
- const g = row.isActive ? "\u25cf" : row.exhausted ? "!" : row.state === "unprobed" ? "\u00b7" : "\u2713";
71084
+ const g = row.isActive ? "\u25cf" : row.state === "org-disabled" ? "\u2298" : row.state === "retired" ? "\u2205" : row.exhausted ? "!" : row.state === "unprobed" ? "\u00b7" : "\u2713";
70944
71085
  if (!color)
70945
71086
  return g;
70946
- return row.isActive ? source_default.green(g) : row.exhausted ? source_default.red(g) : source_default.gray(g);
71087
+ if (row.isActive)
71088
+ return source_default.green(g);
71089
+ if (row.state === "org-disabled")
71090
+ return source_default.red(g);
71091
+ if (row.state === "retired")
71092
+ return source_default.gray(g);
71093
+ return row.exhausted ? source_default.red(g) : source_default.gray(g);
70947
71094
  }
70948
71095
  function colorState(text, state, color) {
70949
71096
  if (!color)
@@ -70951,6 +71098,7 @@ function colorState(text, state, color) {
70951
71098
  switch (state) {
70952
71099
  case "healthy":
70953
71100
  return source_default.green(text);
71101
+ case "org-disabled":
70954
71102
  case "weekly-walled":
70955
71103
  return source_default.red(text);
70956
71104
  case "quota-exhausted":
@@ -71164,8 +71312,11 @@ function formatQuotaUtilCell(a, now = Date.now()) {
71164
71312
  function printAccountsTable(state) {
71165
71313
  console.log(source_default.bold(" ACCOUNT STATUS EXPIRES QUOTA 5h\u00b77d QUOTA-RESET"));
71166
71314
  for (const a of state.accounts) {
71167
- const marker = a.label === state.active ? source_default.green("\u25cf") : a.exhausted ? source_default.red("!") : source_default.gray("\u2713");
71168
- const status = a.label === state.active ? source_default.green("active ") : a.exhausted ? source_default.red("exhausted") : "available";
71315
+ const isActive = a.label === state.active;
71316
+ const orgBlocked = a.entitlement_blocked === true;
71317
+ const retired = a.in_service === false;
71318
+ const marker = isActive ? source_default.green("\u25cf") : orgBlocked ? source_default.red("\u2298") : retired ? source_default.gray("\u2205") : a.exhausted ? source_default.red("!") : source_default.gray("\u2713");
71319
+ const status = isActive ? source_default.green("active ") : orgBlocked ? source_default.red("DISABLED ") : retired ? source_default.gray("retired ") : a.exhausted ? source_default.red("exhausted") : "available";
71169
71320
  const label = a.label.padEnd(32);
71170
71321
  const exp = formatExpiry2(a.expiresAt).padEnd(10);
71171
71322
  const util3 = formatQuotaUtilCell(a).padEnd(20);
@@ -71214,8 +71365,16 @@ function printUsageTable(state) {
71214
71365
  console.log(source_default.bold(" ACCOUNT PREMIUM (Fable) HEADROOM STANDARD HEADROOM"));
71215
71366
  const WIDTH = 44;
71216
71367
  for (const a of state.accounts) {
71217
- const marker = a.label === state.active ? source_default.green("*") : " ";
71368
+ const isActive = a.label === state.active;
71369
+ const orgBlocked = a.entitlement_blocked === true;
71370
+ const retired = a.in_service === false;
71371
+ const marker = isActive ? source_default.green("*") : orgBlocked ? source_default.red("\u2298") : retired ? source_default.gray("\u2205") : " ";
71218
71372
  const label = a.label.padEnd(32);
71373
+ if (orgBlocked || retired) {
71374
+ const note = orgBlocked ? source_default.red("DISABLED (org) \u2014 no fleet routing") : source_default.gray("retired \u2014 removed from fleet rotation");
71375
+ console.log(` ${marker} ${label} ${note}`);
71376
+ continue;
71377
+ }
71219
71378
  const premium = usageHeadroomCell(a.usage_ledger?.premium ?? null);
71220
71379
  const standard = usageHeadroomCell(a.usage_ledger?.standard ?? null);
71221
71380
  const premiumCol = premium.color(premium.plain.padEnd(WIDTH));
@@ -84825,7 +84984,7 @@ init_lifecycle();
84825
84984
  init_compose_env();
84826
84985
  import { cpSync as cpSync2, existsSync as existsSync67, mkdirSync as mkdirSync35, readFileSync as readFileSync60, realpathSync as realpathSync6, rmSync as rmSync12, statSync as statSync40, chownSync as chownSync5 } from "node:fs";
84827
84986
  import { spawnSync as spawnSync12 } from "node:child_process";
84828
- import { join as join68, dirname as dirname21, resolve as resolve40 } from "node:path";
84987
+ import { join as join69, dirname as dirname21, resolve as resolve40 } from "node:path";
84829
84988
  import { homedir as homedir40 } from "node:os";
84830
84989
 
84831
84990
  // src/cli/release-yaml.ts
@@ -84933,13 +85092,13 @@ function defaultPersistPin(configPath) {
84933
85092
  } catch {}
84934
85093
  };
84935
85094
  }
84936
- var DEFAULT_COMPOSE_PATH = join68(homedir40(), ".switchroom", "compose", "docker-compose.yml");
85095
+ var DEFAULT_COMPOSE_PATH = join69(homedir40(), ".switchroom", "compose", "docker-compose.yml");
84937
85096
  function runningFromSwitchroomCheckout(scriptPath) {
84938
85097
  let dir = dirname21(scriptPath);
84939
85098
  for (let i = 0;i < 12; i++) {
84940
- if (existsSync67(join68(dir, ".git"))) {
85099
+ if (existsSync67(join69(dir, ".git"))) {
84941
85100
  try {
84942
- const pkg = JSON.parse(readFileSync60(join68(dir, "package.json"), "utf-8"));
85101
+ const pkg = JSON.parse(readFileSync60(join69(dir, "package.json"), "utf-8"));
84943
85102
  if (pkg.name === "switchroom")
84944
85103
  return true;
84945
85104
  } catch {}
@@ -85150,7 +85309,7 @@ function planUpdate(opts) {
85150
85309
  return;
85151
85310
  }
85152
85311
  const source = resolve40(import.meta.dirname, "../../skills");
85153
- const dest = join68(homedir40(), ".switchroom", "skills", "_bundled");
85312
+ const dest = join69(homedir40(), ".switchroom", "skills", "_bundled");
85154
85313
  if (!existsSync67(source)) {
85155
85314
  process.stderr.write(`switchroom update: sync-bundled-skills \u2014 CLI bundle has no adjacent skills/ at ${source}; skipping.
85156
85315
  `);
@@ -85275,7 +85434,7 @@ function defaultStatusProbe(composePath) {
85275
85434
  } catch {}
85276
85435
  let dir = dirname21(scriptPath);
85277
85436
  for (let i = 0;i < 8; i++) {
85278
- const pkgPath = join68(dir, "package.json");
85437
+ const pkgPath = join69(dir, "package.json");
85279
85438
  if (existsSync67(pkgPath)) {
85280
85439
  try {
85281
85440
  const pkg = JSON.parse(readFileSync60(pkgPath, "utf-8"));
@@ -85978,7 +86137,7 @@ init_lifecycle();
85978
86137
  init_resolve_version();
85979
86138
  import { execSync as execSync3 } from "node:child_process";
85980
86139
  import { existsSync as existsSync68, readFileSync as readFileSync62 } from "node:fs";
85981
- import { dirname as dirname22, join as join69 } from "node:path";
86140
+ import { dirname as dirname22, join as join70 } from "node:path";
85982
86141
  function getClaudeCodeVersion() {
85983
86142
  try {
85984
86143
  const out = execSync3("claude --version 2>/dev/null", {
@@ -86028,11 +86187,11 @@ function formatUptime3(timestamp) {
86028
86187
  function locateSwitchroomInstallDir() {
86029
86188
  let dir = import.meta.dirname;
86030
86189
  for (let i = 0;i < 10 && dir && dir !== "/"; i++) {
86031
- const pkgPath = join69(dir, "package.json");
86190
+ const pkgPath = join70(dir, "package.json");
86032
86191
  if (existsSync68(pkgPath)) {
86033
86192
  try {
86034
86193
  const pkg = JSON.parse(readFileSync62(pkgPath, "utf-8"));
86035
- if (pkg.name === "switchroom" && existsSync68(join69(dir, ".git"))) {
86194
+ if (pkg.name === "switchroom" && existsSync68(join70(dir, ".git"))) {
86036
86195
  return dir;
86037
86196
  }
86038
86197
  } catch {}
@@ -86215,12 +86374,12 @@ import {
86215
86374
  statSync as statSync42,
86216
86375
  unlinkSync as unlinkSync14
86217
86376
  } from "node:fs";
86218
- import { join as join70 } from "node:path";
86377
+ import { join as join71 } from "node:path";
86219
86378
  var DEFAULT_SESSION_RETENTION_MAX_COUNT = 20;
86220
86379
  var DEFAULT_SESSION_RETENTION_MAX_AGE_DAYS = 30;
86221
86380
  var MIN_KEEP = 2;
86222
86381
  function collectSessionJsonl(claudeConfigDir) {
86223
- const projects = join70(claudeConfigDir, "projects");
86382
+ const projects = join71(claudeConfigDir, "projects");
86224
86383
  if (!existsSync69(projects))
86225
86384
  return [];
86226
86385
  const found = [];
@@ -86232,7 +86391,7 @@ function collectSessionJsonl(claudeConfigDir) {
86232
86391
  return;
86233
86392
  }
86234
86393
  for (const name of entries) {
86235
- const full = join70(dir, name);
86394
+ const full = join71(dir, name);
86236
86395
  let st;
86237
86396
  try {
86238
86397
  st = statSync42(full);
@@ -86363,7 +86522,7 @@ import {
86363
86522
  writeFileSync as writeFileSync19,
86364
86523
  writeSync as writeSync9
86365
86524
  } from "node:fs";
86366
- import { join as join71 } from "node:path";
86525
+ import { join as join72 } from "node:path";
86367
86526
  import { randomBytes as randomBytes12 } from "node:crypto";
86368
86527
  import { execSync as execSync4 } from "node:child_process";
86369
86528
 
@@ -86794,7 +86953,7 @@ function redactedMarker(ruleId) {
86794
86953
  var ISSUES_FILE = "issues.jsonl";
86795
86954
  var ISSUES_LOCK = "issues.lock";
86796
86955
  function readAll(stateDir) {
86797
- const path5 = join71(stateDir, ISSUES_FILE);
86956
+ const path5 = join72(stateDir, ISSUES_FILE);
86798
86957
  if (!existsSync70(path5))
86799
86958
  return [];
86800
86959
  let raw;
@@ -86872,7 +87031,7 @@ function record(stateDir, input, nowFn = Date.now) {
86872
87031
  });
86873
87032
  }
86874
87033
  function resolve43(stateDir, fingerprint, nowFn = Date.now) {
86875
- if (!existsSync70(join71(stateDir, ISSUES_FILE)))
87034
+ if (!existsSync70(join72(stateDir, ISSUES_FILE)))
86876
87035
  return 0;
86877
87036
  return withLock(stateDir, () => {
86878
87037
  const all = readAll(stateDir);
@@ -86890,7 +87049,7 @@ function resolve43(stateDir, fingerprint, nowFn = Date.now) {
86890
87049
  });
86891
87050
  }
86892
87051
  function resolveAllBySource(stateDir, source, nowFn = Date.now) {
86893
- if (!existsSync70(join71(stateDir, ISSUES_FILE)))
87052
+ if (!existsSync70(join72(stateDir, ISSUES_FILE)))
86894
87053
  return 0;
86895
87054
  return withLock(stateDir, () => {
86896
87055
  const all = readAll(stateDir);
@@ -86908,7 +87067,7 @@ function resolveAllBySource(stateDir, source, nowFn = Date.now) {
86908
87067
  });
86909
87068
  }
86910
87069
  function prune(stateDir, opts = {}) {
86911
- if (!existsSync70(join71(stateDir, ISSUES_FILE)))
87070
+ if (!existsSync70(join72(stateDir, ISSUES_FILE)))
86912
87071
  return 0;
86913
87072
  return withLock(stateDir, () => {
86914
87073
  const all = readAll(stateDir);
@@ -86941,7 +87100,7 @@ function ensureDir(stateDir) {
86941
87100
  mkdirSync36(stateDir, { recursive: true });
86942
87101
  }
86943
87102
  function writeAll(stateDir, events) {
86944
- const path5 = join71(stateDir, ISSUES_FILE);
87103
+ const path5 = join72(stateDir, ISSUES_FILE);
86945
87104
  sweepOrphanTmpFiles(stateDir);
86946
87105
  const tmp = `${path5}.tmp-${process.pid}-${randomBytes12(4).toString("hex")}`;
86947
87106
  const body = events.length === 0 ? "" : events.map((e) => JSON.stringify(e)).join(`
@@ -86963,7 +87122,7 @@ function sweepOrphanTmpFiles(stateDir) {
86963
87122
  for (const entry of entries) {
86964
87123
  if (!entry.startsWith(TMP_PREFIX))
86965
87124
  continue;
86966
- const tmpPath = join71(stateDir, entry);
87125
+ const tmpPath = join72(stateDir, entry);
86967
87126
  try {
86968
87127
  const stat = statSync43(tmpPath);
86969
87128
  if (stat.mtimeMs < cutoff) {
@@ -86975,7 +87134,7 @@ function sweepOrphanTmpFiles(stateDir) {
86975
87134
  var LOCK_RETRY_MS = 25;
86976
87135
  var LOCK_TIMEOUT_MS = 1e4;
86977
87136
  function withLock(stateDir, fn) {
86978
- const lockPath = join71(stateDir, ISSUES_LOCK);
87137
+ const lockPath = join72(stateDir, ISSUES_LOCK);
86979
87138
  const startedAt = Date.now();
86980
87139
  let fd = null;
86981
87140
  while (fd === null) {
@@ -87260,7 +87419,7 @@ function relTime(deltaMs) {
87260
87419
  init_source();
87261
87420
  import { existsSync as existsSync73 } from "node:fs";
87262
87421
  import { homedir as homedir44 } from "node:os";
87263
- import { join as join74, resolve as resolve44 } from "node:path";
87422
+ import { join as join75, resolve as resolve44 } from "node:path";
87264
87423
 
87265
87424
  // src/deps/python.ts
87266
87425
  import { createHash as createHash13 } from "node:crypto";
@@ -87271,7 +87430,7 @@ import {
87271
87430
  rmSync as rmSync13,
87272
87431
  writeFileSync as writeFileSync20
87273
87432
  } from "node:fs";
87274
- import { dirname as dirname23, join as join72 } from "node:path";
87433
+ import { dirname as dirname23, join as join73 } from "node:path";
87275
87434
  import { homedir as homedir42 } from "node:os";
87276
87435
  import { execFileSync as execFileSync21 } from "node:child_process";
87277
87436
 
@@ -87284,7 +87443,7 @@ class PythonEnvError extends Error {
87284
87443
  }
87285
87444
  }
87286
87445
  function defaultPythonCacheRoot() {
87287
- return join72(homedir42(), ".switchroom", "deps", "python");
87446
+ return join73(homedir42(), ".switchroom", "deps", "python");
87288
87447
  }
87289
87448
  function hashFile(path5) {
87290
87449
  return createHash13("sha256").update(readFileSync64(path5)).digest("hex");
@@ -87296,11 +87455,11 @@ function ensurePythonEnv(opts) {
87296
87455
  if (!existsSync71(requirementsPath)) {
87297
87456
  throw new PythonEnvError(`requirements file not found: ${requirementsPath}`);
87298
87457
  }
87299
- const venvDir = join72(cacheRoot, skillName);
87300
- const stampPath = join72(venvDir, ".requirements.sha256");
87301
- const binDir = join72(venvDir, "bin");
87302
- const pythonBin = join72(binDir, "python");
87303
- const pipBin = join72(binDir, "pip");
87458
+ const venvDir = join73(cacheRoot, skillName);
87459
+ const stampPath = join73(venvDir, ".requirements.sha256");
87460
+ const binDir = join73(venvDir, "bin");
87461
+ const pythonBin = join73(binDir, "python");
87462
+ const pipBin = join73(binDir, "pip");
87304
87463
  const targetHash = hashFile(requirementsPath);
87305
87464
  if (!force && existsSync71(stampPath) && existsSync71(pythonBin)) {
87306
87465
  const existingHash = readFileSync64(stampPath, "utf8").trim();
@@ -87359,7 +87518,7 @@ import {
87359
87518
  rmSync as rmSync14,
87360
87519
  writeFileSync as writeFileSync21
87361
87520
  } from "node:fs";
87362
- import { dirname as dirname24, join as join73 } from "node:path";
87521
+ import { dirname as dirname24, join as join74 } from "node:path";
87363
87522
  import { homedir as homedir43 } from "node:os";
87364
87523
  import { execFileSync as execFileSync22 } from "node:child_process";
87365
87524
 
@@ -87383,7 +87542,7 @@ var LOCKFILES_FOR = {
87383
87542
  npm: ["package-lock.json"]
87384
87543
  };
87385
87544
  function defaultNodeCacheRoot() {
87386
- return join73(homedir43(), ".switchroom", "deps", "node");
87545
+ return join74(homedir43(), ".switchroom", "deps", "node");
87387
87546
  }
87388
87547
  function hashDepInputs(packageJsonPath) {
87389
87548
  const sourceDir = dirname24(packageJsonPath);
@@ -87392,7 +87551,7 @@ function hashDepInputs(packageJsonPath) {
87392
87551
  `);
87393
87552
  hasher.update(readFileSync65(packageJsonPath));
87394
87553
  for (const lockName of ALL_LOCKFILES) {
87395
- const lockPath = join73(sourceDir, lockName);
87554
+ const lockPath = join74(sourceDir, lockName);
87396
87555
  if (existsSync72(lockPath)) {
87397
87556
  hasher.update(`
87398
87557
  `);
@@ -87412,10 +87571,10 @@ function ensureNodeEnv(opts) {
87412
87571
  throw new NodeEnvError(`package.json not found: ${packageJsonPath}`);
87413
87572
  }
87414
87573
  const sourceDir = dirname24(packageJsonPath);
87415
- const envDir = join73(cacheRoot, skillName);
87416
- const stampPath = join73(envDir, ".package.sha256");
87417
- const nodeModulesDir = join73(envDir, "node_modules");
87418
- const binDir = join73(nodeModulesDir, ".bin");
87574
+ const envDir = join74(cacheRoot, skillName);
87575
+ const stampPath = join74(envDir, ".package.sha256");
87576
+ const nodeModulesDir = join74(envDir, "node_modules");
87577
+ const binDir = join74(nodeModulesDir, ".bin");
87419
87578
  const targetHash = hashDepInputs(packageJsonPath);
87420
87579
  if (!force && existsSync72(stampPath) && existsSync72(nodeModulesDir)) {
87421
87580
  const existingHash = readFileSync65(stampPath, "utf8").trim();
@@ -87433,12 +87592,12 @@ function ensureNodeEnv(opts) {
87433
87592
  rmSync14(envDir, { recursive: true, force: true });
87434
87593
  }
87435
87594
  mkdirSync38(envDir, { recursive: true });
87436
- copyFileSync10(packageJsonPath, join73(envDir, "package.json"));
87595
+ copyFileSync10(packageJsonPath, join74(envDir, "package.json"));
87437
87596
  let copiedLockfile = false;
87438
87597
  for (const lockName of LOCKFILES_FOR[installer]) {
87439
- const lockPath = join73(sourceDir, lockName);
87598
+ const lockPath = join74(sourceDir, lockName);
87440
87599
  if (existsSync72(lockPath)) {
87441
- copyFileSync10(lockPath, join73(envDir, lockName));
87600
+ copyFileSync10(lockPath, join74(envDir, lockName));
87442
87601
  copiedLockfile = true;
87443
87602
  }
87444
87603
  }
@@ -87477,13 +87636,13 @@ function registerDepsCommand(program3) {
87477
87636
  console.error(source_default.red(`Bundled skills pool dir not found at ${skillsRoot} \u2014 run \`switchroom update\` to install it.`));
87478
87637
  process.exit(1);
87479
87638
  }
87480
- const skillDir = join74(skillsRoot, skill);
87639
+ const skillDir = join75(skillsRoot, skill);
87481
87640
  if (!existsSync73(skillDir)) {
87482
87641
  console.error(source_default.red(`Unknown skill: ${skill} (no dir at ${skillDir})`));
87483
87642
  process.exit(1);
87484
87643
  }
87485
- const requirementsPath = join74(skillDir, "requirements.txt");
87486
- const packageJsonPath = join74(skillDir, "package.json");
87644
+ const requirementsPath = join75(skillDir, "requirements.txt");
87645
+ const packageJsonPath = join75(skillDir, "package.json");
87487
87646
  const wantPython = opts.python ?? (!opts.python && !opts.node && existsSync73(requirementsPath));
87488
87647
  const wantNode = opts.node ?? (!opts.python && !opts.node && existsSync73(packageJsonPath));
87489
87648
  let did = 0;
@@ -88438,7 +88597,7 @@ init_helpers();
88438
88597
  init_loader();
88439
88598
  init_merge();
88440
88599
  import { copyFileSync as copyFileSync11, existsSync as existsSync75, readFileSync as readFileSync66, writeFileSync as writeFileSync22 } from "node:fs";
88441
- import { join as join75, resolve as resolve46 } from "node:path";
88600
+ import { join as join76, resolve as resolve46 } from "node:path";
88442
88601
  init_scaffold();
88443
88602
  init_profiles();
88444
88603
  init_schema();
@@ -88464,7 +88623,7 @@ function resolveSoulTargetOrExit(program3, agentName) {
88464
88623
  profileName,
88465
88624
  profilePath,
88466
88625
  workspaceDir,
88467
- soulPath: join75(workspaceDir, "SOUL.md"),
88626
+ soulPath: join76(workspaceDir, "SOUL.md"),
88468
88627
  soul: merged.soul
88469
88628
  };
88470
88629
  }
@@ -88531,7 +88690,7 @@ function registerSoulCommand(program3) {
88531
88690
  init_helpers();
88532
88691
  init_loader();
88533
88692
  import { existsSync as existsSync76, readFileSync as readFileSync67, readdirSync as readdirSync26, statSync as statSync44 } from "node:fs";
88534
- import { resolve as resolve47, join as join76 } from "node:path";
88693
+ import { resolve as resolve47, join as join77 } from "node:path";
88535
88694
  import { createHash as createHash15 } from "node:crypto";
88536
88695
  init_merge();
88537
88696
  init_hindsight2();
@@ -88542,7 +88701,7 @@ function estimateTokens(bytes) {
88542
88701
  return Math.round(bytes / 3.7);
88543
88702
  }
88544
88703
  function readMcpServerNames(agentDir) {
88545
- const mcpPath = join76(agentDir, ".mcp.json");
88704
+ const mcpPath = join77(agentDir, ".mcp.json");
88546
88705
  if (!existsSync76(mcpPath))
88547
88706
  return [];
88548
88707
  try {
@@ -88556,7 +88715,7 @@ function sha256(content) {
88556
88715
  return createHash15("sha256").update(content).digest("hex").slice(0, 16);
88557
88716
  }
88558
88717
  function findLatestTranscriptJsonl(claudeConfigDir) {
88559
- const projectsDir = join76(claudeConfigDir, "projects");
88718
+ const projectsDir = join77(claudeConfigDir, "projects");
88560
88719
  if (!existsSync76(projectsDir))
88561
88720
  return;
88562
88721
  try {
@@ -88565,8 +88724,8 @@ function findLatestTranscriptJsonl(claudeConfigDir) {
88565
88724
  for (const entry of entries) {
88566
88725
  if (!entry.isDirectory())
88567
88726
  continue;
88568
- const projectPath = join76(projectsDir, entry.name);
88569
- const transcriptPath = join76(projectPath, "transcript.jsonl");
88727
+ const projectPath = join77(projectsDir, entry.name);
88728
+ const transcriptPath = join77(projectPath, "transcript.jsonl");
88570
88729
  if (!existsSync76(transcriptPath))
88571
88730
  continue;
88572
88731
  const stat3 = statSync44(transcriptPath);
@@ -88635,11 +88794,11 @@ function registerDebugCommand(program3) {
88635
88794
  process.exit(1);
88636
88795
  }
88637
88796
  const workspaceDir = resolveAgentWorkspaceDir(agentDir);
88638
- const claudeConfigDir = join76(agentDir, ".claude");
88639
- const claudeMdPath = join76(agentDir, "CLAUDE.md");
88640
- const soulMdPath = join76(agentDir, "SOUL.md");
88641
- const workspaceSoulMdPath = join76(workspaceDir, "SOUL.md");
88642
- const handoffPath = join76(agentDir, ".handoff.md");
88797
+ const claudeConfigDir = join77(agentDir, ".claude");
88798
+ const claudeMdPath = join77(agentDir, "CLAUDE.md");
88799
+ const soulMdPath = join77(agentDir, "SOUL.md");
88800
+ const workspaceSoulMdPath = join77(workspaceDir, "SOUL.md");
88801
+ const handoffPath = join77(agentDir, ".handoff.md");
88643
88802
  const lastN = parseInt(opts.last, 10);
88644
88803
  if (isNaN(lastN) || lastN < 1) {
88645
88804
  console.error("--last must be a positive integer");
@@ -88768,9 +88927,9 @@ function registerDebugCommand(program3) {
88768
88927
  const soulMdBytes = soulMdContent.length;
88769
88928
  const perTurnBytes = dynamicResult.concatenated.length;
88770
88929
  const userBytes = userMessage?.text.length ?? 0;
88771
- const fleetDir = join76(agentsDir, "..", "fleet");
88772
- const fleetInvPath = join76(fleetDir, "switchroom-invariants.md");
88773
- const fleetClaudePath = join76(fleetDir, "CLAUDE.md");
88930
+ const fleetDir = join77(agentsDir, "..", "fleet");
88931
+ const fleetInvPath = join77(fleetDir, "switchroom-invariants.md");
88932
+ const fleetClaudePath = join77(fleetDir, "CLAUDE.md");
88774
88933
  const fleetInvBytes = existsSync76(fleetInvPath) ? readFileSync67(fleetInvPath, "utf-8").length : 0;
88775
88934
  const fleetClaudeBytes = existsSync76(fleetClaudePath) ? readFileSync67(fleetClaudePath, "utf-8").length : 0;
88776
88935
  const fleetBytes = fleetInvBytes + fleetClaudeBytes;
@@ -88806,7 +88965,7 @@ init_source();
88806
88965
  // src/worktree/claim.ts
88807
88966
  import { execFileSync as execFileSync23 } from "node:child_process";
88808
88967
  import { closeSync as closeSync13, mkdirSync as mkdirSync40, openSync as openSync13, existsSync as existsSync78, unlinkSync as unlinkSync17 } from "node:fs";
88809
- import { join as join78, resolve as resolve49 } from "node:path";
88968
+ import { join as join79, resolve as resolve49 } from "node:path";
88810
88969
  import { homedir as homedir46 } from "node:os";
88811
88970
  import { randomBytes as randomBytes13 } from "node:crypto";
88812
88971
 
@@ -88820,13 +88979,13 @@ import {
88820
88979
  existsSync as existsSync77,
88821
88980
  renameSync as renameSync17
88822
88981
  } from "node:fs";
88823
- import { join as join77, resolve as resolve48 } from "node:path";
88982
+ import { join as join78, resolve as resolve48 } from "node:path";
88824
88983
  import { homedir as homedir45 } from "node:os";
88825
88984
  function registryDir() {
88826
- return resolve48(process.env.SWITCHROOM_WORKTREE_DIR ?? join77(homedir45(), ".switchroom", "worktrees"));
88985
+ return resolve48(process.env.SWITCHROOM_WORKTREE_DIR ?? join78(homedir45(), ".switchroom", "worktrees"));
88827
88986
  }
88828
88987
  function recordPath(id) {
88829
- return join77(registryDir(), `${id}.json`);
88988
+ return join78(registryDir(), `${id}.json`);
88830
88989
  }
88831
88990
  function ensureDir2() {
88832
88991
  mkdirSync39(registryDir(), { recursive: true });
@@ -88877,7 +89036,7 @@ function acquireRepoLock(repoPath) {
88877
89036
  const lockDir = registryDir();
88878
89037
  mkdirSync40(lockDir, { recursive: true });
88879
89038
  const lockName = repoPath.replace(/[^A-Za-z0-9]/g, "_");
88880
- const lockPath = join78(lockDir, `.lock-${lockName}`);
89039
+ const lockPath = join79(lockDir, `.lock-${lockName}`);
88881
89040
  const deadline = Date.now() + 5000;
88882
89041
  let fd = null;
88883
89042
  while (fd === null) {
@@ -88904,7 +89063,7 @@ function acquireRepoLock(repoPath) {
88904
89063
  }
88905
89064
  var DEFAULT_CONCURRENCY = 5;
88906
89065
  function worktreesBaseDir() {
88907
- return resolve49(process.env.SWITCHROOM_WORKTREE_BASE ?? join78(homedir46(), ".switchroom", "worktree-checkouts"));
89066
+ return resolve49(process.env.SWITCHROOM_WORKTREE_BASE ?? join79(homedir46(), ".switchroom", "worktree-checkouts"));
88908
89067
  }
88909
89068
  function shortId() {
88910
89069
  return randomBytes13(4).toString("hex");
@@ -88926,7 +89085,7 @@ function resolveRepoPath(repo, codeRepos) {
88926
89085
  }
88927
89086
  function expandHome(p) {
88928
89087
  if (p.startsWith("~/"))
88929
- return join78(homedir46(), p.slice(2));
89088
+ return join79(homedir46(), p.slice(2));
88930
89089
  return p;
88931
89090
  }
88932
89091
  async function claimWorktree(input, codeRepos) {
@@ -88954,7 +89113,7 @@ async function claimWorktree(input, codeRepos) {
88954
89113
  branch = `task/${taskSuffix}-${id}`;
88955
89114
  const baseDir = worktreesBaseDir();
88956
89115
  mkdirSync40(baseDir, { recursive: true });
88957
- worktreePath = join78(baseDir, `${id}-${taskSuffix}`);
89116
+ worktreePath = join79(baseDir, `${id}-${taskSuffix}`);
88958
89117
  const ambientOwner = process.env.SWITCHROOM_AGENT_NAME;
88959
89118
  const ownerAgent = input.ownerAgent ?? (ambientOwner != null && ambientOwner !== "" ? ambientOwner : undefined);
88960
89119
  const now = new Date().toISOString();
@@ -89185,7 +89344,7 @@ import {
89185
89344
  rmSync as rmSync15
89186
89345
  } from "node:fs";
89187
89346
  import { homedir as homedir47 } from "node:os";
89188
- import { join as join79, resolve as resolve50 } from "node:path";
89347
+ import { join as join80, resolve as resolve50 } from "node:path";
89189
89348
  function parseGitdirPointer(dotGitFileContents) {
89190
89349
  const m = /^gitdir:\s*(.+?)\s*$/m.exec(dotGitFileContents);
89191
89350
  return m ? m[1] : null;
@@ -89300,7 +89459,7 @@ function defaultPrSignal(repo, branch, exec) {
89300
89459
  }
89301
89460
  }
89302
89461
  function trashRoot() {
89303
- return resolve50(process.env.SWITCHROOM_WORKTREE_TRASH ?? join79(homedir47(), ".switchroom", "worktree-gc-trash"));
89462
+ return resolve50(process.env.SWITCHROOM_WORKTREE_TRASH ?? join80(homedir47(), ".switchroom", "worktree-gc-trash"));
89304
89463
  }
89305
89464
  function planGc(roots, deps = {}) {
89306
89465
  const exists = deps.existsSync ?? existsSync81;
@@ -89310,7 +89469,7 @@ function planGc(roots, deps = {}) {
89310
89469
  const exec = deps.exec ?? defaultExec;
89311
89470
  const prSignal = deps.prSignal ?? ((repo, branch) => defaultPrSignal(repo, branch, exec));
89312
89471
  const stamp = deps.dateStamp ?? "undated";
89313
- const trash = join79(trashRoot(), stamp);
89472
+ const trash = join80(trashRoot(), stamp);
89314
89473
  let claimed;
89315
89474
  try {
89316
89475
  claimed = new Set(listRecords().map((r) => resolve50(r.path)));
@@ -89346,10 +89505,10 @@ function planGc(roots, deps = {}) {
89346
89505
  continue;
89347
89506
  }
89348
89507
  for (const name of entries) {
89349
- const dir = join79(root, name);
89508
+ const dir = join80(root, name);
89350
89509
  if (isEphemeralPath(dir))
89351
89510
  continue;
89352
- const dotGit = join79(dir, ".git");
89511
+ const dotGit = join80(dir, ".git");
89353
89512
  if (!exists(dotGit))
89354
89513
  continue;
89355
89514
  let st;
@@ -89378,7 +89537,7 @@ function planGc(roots, deps = {}) {
89378
89537
  ownerRepos.add(repoRoot);
89379
89538
  if (exists(ptr))
89380
89539
  continue;
89381
- orphans.push({ dir, owner: repoRoot, dest: join79(trash, name) });
89540
+ orphans.push({ dir, owner: repoRoot, dest: join80(trash, name) });
89382
89541
  }
89383
89542
  }
89384
89543
  const registered = [];
@@ -89489,7 +89648,7 @@ function listTrashEntries(nowMs, deps = {}) {
89489
89648
  return [];
89490
89649
  const out = [];
89491
89650
  for (const stamp of readDir(root)) {
89492
- const stampDir = join79(root, stamp);
89651
+ const stampDir = join80(root, stamp);
89493
89652
  let names;
89494
89653
  try {
89495
89654
  names = readDir(stampDir);
@@ -89497,7 +89656,7 @@ function listTrashEntries(nowMs, deps = {}) {
89497
89656
  continue;
89498
89657
  }
89499
89658
  for (const name of names) {
89500
- const p = join79(stampDir, name);
89659
+ const p = join80(stampDir, name);
89501
89660
  let mtimeMs = nowMs;
89502
89661
  try {
89503
89662
  mtimeMs = statSync45(p).mtimeMs;
@@ -89521,7 +89680,7 @@ function purgeTrash(paths) {
89521
89680
  return { deleted, errors: errors2 };
89522
89681
  }
89523
89682
  function defaultRoots() {
89524
- return [join79(homedir47(), "code")];
89683
+ return [join80(homedir47(), "code")];
89525
89684
  }
89526
89685
 
89527
89686
  // src/cli/worktree.ts
@@ -89749,7 +89908,7 @@ import {
89749
89908
  rmSync as rmSync16,
89750
89909
  writeFileSync as writeFileSync24
89751
89910
  } from "node:fs";
89752
- import { join as join80 } from "node:path";
89911
+ import { join as join81 } from "node:path";
89753
89912
  function encodeCredentialsFilename(email) {
89754
89913
  const SAFE = new Set([
89755
89914
  ..."ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
@@ -89939,16 +90098,16 @@ function resolveCredentialsDir(env2) {
89939
90098
  if (explicit && explicit.length > 0)
89940
90099
  return explicit;
89941
90100
  const stateBase = env2.SWITCHROOM_CONTAINER === "1" ? "/state/agent" : env2.HOME ?? ".";
89942
- return join80(stateBase, "google-workspace-mcp", "credentials");
90101
+ return join81(stateBase, "google-workspace-mcp", "credentials");
89943
90102
  }
89944
90103
  function writeSeedFile(dir, email, seed) {
89945
90104
  mkdirSync42(dir, { recursive: true, mode: 448 });
89946
90105
  chmodSync11(dir, 448);
89947
90106
  for (const name of readdirSync29(dir)) {
89948
- rmSync16(join80(dir, name), { force: true, recursive: true });
90107
+ rmSync16(join81(dir, name), { force: true, recursive: true });
89949
90108
  }
89950
90109
  const filename = encodeCredentialsFilename(email);
89951
- const filePath = join80(dir, filename);
90110
+ const filePath = join81(dir, filename);
89952
90111
  writeFileSync24(filePath, JSON.stringify(seed), { mode: 384 });
89953
90112
  chmodSync11(filePath, 384);
89954
90113
  return filePath;
@@ -90108,7 +90267,7 @@ function registerDriveMcpLauncherCommand(program3) {
90108
90267
  init_scaffold_integration();
90109
90268
  import { spawn as spawn5 } from "node:child_process";
90110
90269
  import { writeFileSync as writeFileSync25, mkdirSync as mkdirSync43 } from "node:fs";
90111
- import { dirname as dirname25, join as join81 } from "node:path";
90270
+ import { dirname as dirname25, join as join82 } from "node:path";
90112
90271
  var SOFTERIA_TOKEN_ENV = "MS365_MCP_OAUTH_TOKEN";
90113
90272
  var DEFAULT_REFRESH_LEAD_MS = 5 * 60 * 1000;
90114
90273
  var MAX_REFRESH_INTERVAL_MS = 60 * 60 * 1000;
@@ -90153,7 +90312,7 @@ function heartbeatPath(agentName, account) {
90153
90312
  const override = process.env.SWITCHROOM_M365_HEARTBEAT_DIR;
90154
90313
  if (override) {
90155
90314
  const base = slug ? `m365-launcher-${agentName}-${slug}` : `m365-launcher-${agentName}`;
90156
- return join81(override, `${base}.heartbeat.json`);
90315
+ return join82(override, `${base}.heartbeat.json`);
90157
90316
  }
90158
90317
  return slug ? `/state/agent/m365-launcher-${slug}.heartbeat.json` : "/state/agent/m365-launcher.heartbeat.json";
90159
90318
  }
@@ -90511,7 +90670,7 @@ function registerNotionMcpLauncherCommand(program3) {
90511
90670
  init_hindsight();
90512
90671
  import { mkdirSync as mkdirSync45, readFileSync as readFileSync70, renameSync as renameSync19, writeFileSync as writeFileSync27 } from "node:fs";
90513
90672
  import { tmpdir as tmpdir5 } from "node:os";
90514
- import { join as join82 } from "node:path";
90673
+ import { join as join83 } from "node:path";
90515
90674
  import { createInterface as createInterface6 } from "node:readline";
90516
90675
  var SHIM_SUPPORTED_PROTOCOL_VERSIONS = [
90517
90676
  "2025-06-18",
@@ -90734,12 +90893,12 @@ class HindsightShim {
90734
90893
  `));
90735
90894
  }
90736
90895
  get cachePath() {
90737
- return join82(this.opts.cacheDir, TOOLS_CACHE_FILENAME);
90896
+ return join83(this.opts.cacheDir, TOOLS_CACHE_FILENAME);
90738
90897
  }
90739
90898
  writeCache(result) {
90740
90899
  try {
90741
90900
  mkdirSync45(this.opts.cacheDir, { recursive: true });
90742
- const tmp = join82(this.opts.cacheDir, `.${TOOLS_CACHE_FILENAME}.${process.pid}.tmp`);
90901
+ const tmp = join83(this.opts.cacheDir, `.${TOOLS_CACHE_FILENAME}.${process.pid}.tmp`);
90743
90902
  writeFileSync27(tmp, JSON.stringify(result, null, 2) + `
90744
90903
  `);
90745
90904
  renameSync19(tmp, this.cachePath);
@@ -90912,7 +91071,7 @@ function resolveShimOptionsFromEnv(env2) {
90912
91071
  return {
90913
91072
  url: env2.HINDSIGHT_MCP_URL || HINDSIGHT_DEFAULT_MCP_URL,
90914
91073
  bankId: env2.HINDSIGHT_BANK_ID || "",
90915
- cacheDir: env2.HINDSIGHT_SHIM_CACHE_DIR || join82(home2, ".hindsight-shim")
91074
+ cacheDir: env2.HINDSIGHT_SHIM_CACHE_DIR || join83(home2, ".hindsight-shim")
90916
91075
  };
90917
91076
  }
90918
91077
  function registerHindsightMcpShimCommand(program3) {
@@ -91587,7 +91746,7 @@ function runRedactStdin() {
91587
91746
 
91588
91747
  // src/cli/status-ask.ts
91589
91748
  import { readFileSync as readFileSync75, existsSync as existsSync87, readdirSync as readdirSync31 } from "node:fs";
91590
- import { join as join87 } from "node:path";
91749
+ import { join as join88 } from "node:path";
91591
91750
  import { homedir as homedir50 } from "node:os";
91592
91751
 
91593
91752
  // src/status-ask/report.ts
@@ -91923,7 +92082,7 @@ function resolveSources(explicitPath) {
91923
92082
  const config = loadConfig();
91924
92083
  agentsDir = resolveAgentsDir(config);
91925
92084
  } catch {
91926
- agentsDir = join87(homedir50(), ".switchroom", "agents");
92085
+ agentsDir = join88(homedir50(), ".switchroom", "agents");
91927
92086
  }
91928
92087
  if (!existsSync87(agentsDir))
91929
92088
  return [];
@@ -91935,7 +92094,7 @@ function resolveSources(explicitPath) {
91935
92094
  return [];
91936
92095
  }
91937
92096
  for (const name of entries) {
91938
- const path9 = join87(agentsDir, name, "runtime-metrics.jsonl");
92097
+ const path9 = join88(agentsDir, name, "runtime-metrics.jsonl");
91939
92098
  if (existsSync87(path9)) {
91940
92099
  sources.push({ path: path9, agent: name });
91941
92100
  }
@@ -91977,21 +92136,21 @@ import {
91977
92136
  unlinkSync as unlinkSync18,
91978
92137
  writeSync as writeSync10
91979
92138
  } from "node:fs";
91980
- import { join as join88, resolve as resolve53 } from "node:path";
92139
+ import { join as join89, resolve as resolve53 } from "node:path";
91981
92140
  var STAGING_SUBDIR = ".staging";
91982
92141
  function overlayPathsFor(agent, opts = {}) {
91983
92142
  const base = opts.root ? resolve53(opts.root, agent) : resolve53(resolveDualPath(`~/.switchroom/agents/${agent}`));
91984
- const scheduleDir = join88(base, "schedule.d");
91985
- const scheduleStagingDir = join88(scheduleDir, STAGING_SUBDIR);
91986
- const skillsDir = join88(base, "skills.d");
91987
- const skillsStagingDir = join88(skillsDir, STAGING_SUBDIR);
92143
+ const scheduleDir = join89(base, "schedule.d");
92144
+ const scheduleStagingDir = join89(scheduleDir, STAGING_SUBDIR);
92145
+ const skillsDir = join89(base, "skills.d");
92146
+ const skillsStagingDir = join89(skillsDir, STAGING_SUBDIR);
91988
92147
  return {
91989
92148
  agentRoot: base,
91990
92149
  scheduleDir,
91991
92150
  scheduleStagingDir,
91992
92151
  skillsDir,
91993
92152
  skillsStagingDir,
91994
- lockPath: join88(base, ".lock"),
92153
+ lockPath: join89(base, ".lock"),
91995
92154
  stagingDir: scheduleStagingDir
91996
92155
  };
91997
92156
  }
@@ -92045,8 +92204,8 @@ function writeOverlayEntry(agent, slug, yamlText, opts = {}) {
92045
92204
  const paths = overlayPathsFor(agent, opts);
92046
92205
  return withAgentLock(paths, () => {
92047
92206
  ensureDirs(paths);
92048
- const stagingPath = join88(paths.scheduleStagingDir, `${slug}.yaml`);
92049
- const finalPath = join88(paths.scheduleDir, `${slug}.yaml`);
92207
+ const stagingPath = join89(paths.scheduleStagingDir, `${slug}.yaml`);
92208
+ const finalPath = join89(paths.scheduleDir, `${slug}.yaml`);
92050
92209
  const fd = openSync14(stagingPath, "w", 384);
92051
92210
  try {
92052
92211
  writeSync10(fd, yamlText);
@@ -92062,8 +92221,8 @@ function writeSkillsOverlayEntry(agent, slug, yamlText, opts = {}) {
92062
92221
  const paths = overlayPathsFor(agent, opts);
92063
92222
  return withAgentLock(paths, () => {
92064
92223
  ensureSkillsDirs(paths);
92065
- const stagingPath = join88(paths.skillsStagingDir, `${slug}.yaml`);
92066
- const finalPath = join88(paths.skillsDir, `${slug}.yaml`);
92224
+ const stagingPath = join89(paths.skillsStagingDir, `${slug}.yaml`);
92225
+ const finalPath = join89(paths.skillsDir, `${slug}.yaml`);
92067
92226
  const fd = openSync14(stagingPath, "w", 384);
92068
92227
  try {
92069
92228
  writeSync10(fd, yamlText);
@@ -92078,7 +92237,7 @@ function writeSkillsOverlayEntry(agent, slug, yamlText, opts = {}) {
92078
92237
  function deleteSkillsOverlayEntry(agent, slug, opts = {}) {
92079
92238
  const paths = overlayPathsFor(agent, opts);
92080
92239
  return withAgentLock(paths, () => {
92081
- const finalPath = join88(paths.skillsDir, `${slug}.yaml`);
92240
+ const finalPath = join89(paths.skillsDir, `${slug}.yaml`);
92082
92241
  if (!existsSync88(finalPath))
92083
92242
  return false;
92084
92243
  unlinkSync18(finalPath);
@@ -92093,7 +92252,7 @@ function listSkillsOverlayEntries(agent, opts = {}) {
92093
92252
  for (const name of readdirSync32(paths.skillsDir)) {
92094
92253
  if (!/\.ya?ml$/i.test(name))
92095
92254
  continue;
92096
- const full = join88(paths.skillsDir, name);
92255
+ const full = join89(paths.skillsDir, name);
92097
92256
  try {
92098
92257
  const raw = readFileSync76(full, "utf-8");
92099
92258
  const slug = name.replace(/\.ya?ml$/i, "");
@@ -92105,7 +92264,7 @@ function listSkillsOverlayEntries(agent, opts = {}) {
92105
92264
  function deleteOverlayEntry(agent, slug, opts = {}) {
92106
92265
  const paths = overlayPathsFor(agent, opts);
92107
92266
  return withAgentLock(paths, () => {
92108
- const finalPath = join88(paths.scheduleDir, `${slug}.yaml`);
92267
+ const finalPath = join89(paths.scheduleDir, `${slug}.yaml`);
92109
92268
  if (!existsSync88(finalPath))
92110
92269
  return false;
92111
92270
  unlinkSync18(finalPath);
@@ -92120,7 +92279,7 @@ function listOverlayEntries(agent, opts = {}) {
92120
92279
  for (const name of readdirSync32(paths.scheduleDir)) {
92121
92280
  if (!/\.ya?ml$/i.test(name))
92122
92281
  continue;
92123
- const full = join88(paths.scheduleDir, name);
92282
+ const full = join89(paths.scheduleDir, name);
92124
92283
  try {
92125
92284
  const raw = readFileSync76(full, "utf-8");
92126
92285
  const slug = name.replace(/\.ya?ml$/i, "");
@@ -92353,12 +92512,12 @@ import {
92353
92512
  writeFileSync as writeFileSync32,
92354
92513
  writeSync as writeSync11
92355
92514
  } from "node:fs";
92356
- import { join as join89 } from "node:path";
92515
+ import { join as join90 } from "node:path";
92357
92516
  import { randomBytes as randomBytes15 } from "node:crypto";
92358
92517
  var STAGE_ID_PREFIX = "cap_";
92359
92518
  function pendingDir(agent, opts = {}) {
92360
92519
  const paths = overlayPathsFor(agent, opts);
92361
- return join89(paths.scheduleDir, ".pending");
92520
+ return join90(paths.scheduleDir, ".pending");
92362
92521
  }
92363
92522
  function ensurePendingDir(agent, opts = {}) {
92364
92523
  const dir = pendingDir(agent, opts);
@@ -92371,8 +92530,8 @@ function newStageId() {
92371
92530
  function stagePendingScheduleEntry(opts) {
92372
92531
  const dir = ensurePendingDir(opts.agent, { root: opts.root });
92373
92532
  const stageId = opts.stageId ?? newStageId();
92374
- const yamlPath = join89(dir, `${stageId}.yaml`);
92375
- const metaPath = join89(dir, `${stageId}.meta.json`);
92533
+ const yamlPath = join90(dir, `${stageId}.yaml`);
92534
+ const metaPath = join90(dir, `${stageId}.meta.json`);
92376
92535
  const meta = {
92377
92536
  v: 1,
92378
92537
  stage_id: stageId,
@@ -92406,8 +92565,8 @@ function listPendingScheduleEntries(agent, opts = {}) {
92406
92565
  if (!name.endsWith(".meta.json"))
92407
92566
  continue;
92408
92567
  const stageId = name.slice(0, -".meta.json".length);
92409
- const metaPath = join89(dir, name);
92410
- const yamlPath = join89(dir, `${stageId}.yaml`);
92568
+ const metaPath = join90(dir, name);
92569
+ const yamlPath = join90(dir, `${stageId}.yaml`);
92411
92570
  if (!existsSync89(yamlPath))
92412
92571
  continue;
92413
92572
  try {
@@ -92426,7 +92585,7 @@ function commitPendingScheduleEntry(opts) {
92426
92585
  return { committed: false, reason: "not_found" };
92427
92586
  const slug = match.meta.entry.name ?? match.stageId;
92428
92587
  const paths = overlayPathsFor(opts.agent, { root: opts.root });
92429
- const finalPath = join89(paths.scheduleDir, `${slug}.yaml`);
92588
+ const finalPath = join90(paths.scheduleDir, `${slug}.yaml`);
92430
92589
  if (existsSync89(finalPath)) {
92431
92590
  return { committed: false, reason: "slug_collision" };
92432
92591
  }
@@ -93079,7 +93238,7 @@ import { existsSync as existsSync91 } from "node:fs";
93079
93238
  init_reconcile_default_skills();
93080
93239
  init_agent_config();
93081
93240
  var import_yaml23 = __toESM(require_dist(), 1);
93082
- import { join as join90 } from "node:path";
93241
+ import { join as join91 } from "node:path";
93083
93242
  var MAX_SKILLS_PER_AGENT = 20;
93084
93243
  var V1_ALLOWED_SOURCE_PREFIX = "bundled:";
93085
93244
  function exitCodeFor2(code) {
@@ -93154,7 +93313,7 @@ function skillInstall(opts) {
93154
93313
  return err("E_SKILL_QUOTA_EXCEEDED", `agent ${agent} already has ${used} overlay-installed skills (cap ${MAX_SKILLS_PER_AGENT})`);
93155
93314
  }
93156
93315
  const poolDir = opts.bundledSkillsPoolDir ?? getBundledSkillsPoolDir();
93157
- const skillPath = join90(poolDir, skillName);
93316
+ const skillPath = join91(poolDir, skillName);
93158
93317
  if (!existsSync91(skillPath)) {
93159
93318
  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.`);
93160
93319
  }
@@ -93333,7 +93492,7 @@ import {
93333
93492
  writeFileSync as writeFileSync33
93334
93493
  } from "node:fs";
93335
93494
  import { tmpdir as tmpdir6, homedir as homedir51 } from "node:os";
93336
- import { dirname as dirname31, join as join91, relative as relative2, resolve as resolve54 } from "node:path";
93495
+ import { dirname as dirname31, join as join92, relative as relative2, resolve as resolve54 } from "node:path";
93337
93496
  import { spawnSync as spawnSync16 } from "node:child_process";
93338
93497
 
93339
93498
  // src/cli/skill-common.ts
@@ -93567,7 +93726,7 @@ function scanForClaudeP2(content) {
93567
93726
  function resolveSkillsPoolDir2(override) {
93568
93727
  const raw = override ?? "~/.switchroom/skills";
93569
93728
  if (raw.startsWith("~/")) {
93570
- return join91(homedir51(), raw.slice(2));
93729
+ return join92(homedir51(), raw.slice(2));
93571
93730
  }
93572
93731
  if (raw === "~")
93573
93732
  return homedir51();
@@ -93606,7 +93765,7 @@ function loadFromDir(dir) {
93606
93765
  const walk2 = (sub) => {
93607
93766
  const entries = readdirSync34(sub, { withFileTypes: true });
93608
93767
  for (const ent of entries) {
93609
- const full = join91(sub, ent.name);
93768
+ const full = join92(sub, ent.name);
93610
93769
  const rel = relative2(abs, full);
93611
93770
  if (ent.isSymbolicLink()) {
93612
93771
  fail3(`refusing to read symlink inside --from dir: ${rel}`);
@@ -93641,7 +93800,7 @@ function loadFromTarball(tarPath) {
93641
93800
  fail3(`tarball contains disallowed path: ${JSON.stringify(entry)} \u2014 ` + `refusing to extract before any file is written`);
93642
93801
  }
93643
93802
  }
93644
- const staging = mkdtempSync5(join91(tmpdir6(), "skill-apply-extract-"));
93803
+ const staging = mkdtempSync5(join92(tmpdir6(), "skill-apply-extract-"));
93645
93804
  try {
93646
93805
  const flags = isGz ? ["-xzf"] : ["-xf"];
93647
93806
  const r = spawnSync16("tar", [
@@ -93727,8 +93886,8 @@ function validatePayload(name, files) {
93727
93886
  errors2.push(`${path9} fails \`bash -n\` syntax check: ${(r.stderr ?? "").trim()}`);
93728
93887
  }
93729
93888
  } else if (PY_SCRIPT_RE2.test(path9)) {
93730
- const tmp = mkdtempSync5(join91(tmpdir6(), "skill-apply-py-"));
93731
- const tmpPy = join91(tmp, "check.py");
93889
+ const tmp = mkdtempSync5(join92(tmpdir6(), "skill-apply-py-"));
93890
+ const tmpPy = join92(tmp, "check.py");
93732
93891
  try {
93733
93892
  writeFileSync33(tmpPy, content);
93734
93893
  const r = spawnSync16("python3", ["-m", "py_compile", tmpPy], {
@@ -93751,7 +93910,7 @@ function diffSummary(currentDir, files) {
93751
93910
  if (existsSync92(currentDir)) {
93752
93911
  const walk2 = (sub) => {
93753
93912
  for (const ent of readdirSync34(sub, { withFileTypes: true })) {
93754
- const full = join91(sub, ent.name);
93913
+ const full = join92(sub, ent.name);
93755
93914
  const rel = relative2(currentDir, full);
93756
93915
  if (ent.isDirectory()) {
93757
93916
  walk2(full);
@@ -93787,7 +93946,7 @@ function writePayload(poolDir, name, files) {
93787
93946
  if (!existsSync92(poolDir)) {
93788
93947
  mkdirSync52(poolDir, { recursive: true, mode: 493 });
93789
93948
  }
93790
- const target = join91(poolDir, name);
93949
+ const target = join92(poolDir, name);
93791
93950
  let targetIsSymlink = false;
93792
93951
  try {
93793
93952
  const st = lstatSync11(target);
@@ -93798,11 +93957,11 @@ function writePayload(poolDir, name, files) {
93798
93957
  if (targetIsSymlink) {
93799
93958
  fail3(`refusing to overwrite symlink at ${target}; investigate manually`);
93800
93959
  }
93801
- const staging = mkdtempSync5(join91(poolDir, `.skill-apply-stage-${name}-`));
93960
+ const staging = mkdtempSync5(join92(poolDir, `.skill-apply-stage-${name}-`));
93802
93961
  let oldRename = null;
93803
93962
  try {
93804
93963
  for (const [path9, content] of Object.entries(files)) {
93805
- const full = join91(staging, path9);
93964
+ const full = join92(staging, path9);
93806
93965
  mkdirSync52(dirname31(full), { recursive: true, mode: 493 });
93807
93966
  const fd = openSync16(full, "wx");
93808
93967
  try {
@@ -93880,7 +94039,7 @@ function registerSkillCommand(program3) {
93880
94039
  }
93881
94040
  const config = loadConfig();
93882
94041
  const poolDir = resolveSkillsPoolDir2(config.switchroom?.skills_dir);
93883
- const currentDir = join91(poolDir, name);
94042
+ const currentDir = join92(poolDir, name);
93884
94043
  console.log(source_default.bold(`Skill: ${name}`) + source_default.gray(` (${Object.keys(files).length} files, ${sumBytes(files)} bytes)`));
93885
94044
  console.log(source_default.bold("Diff vs current pool content:"));
93886
94045
  console.log(diffSummary(currentDir, files));
@@ -93925,7 +94084,7 @@ import {
93925
94084
  utimesSync,
93926
94085
  writeFileSync as writeFileSync34
93927
94086
  } from "node:fs";
93928
- import { dirname as dirname32, join as join92, relative as relative3, resolve as resolve55 } from "node:path";
94087
+ import { dirname as dirname32, join as join93, relative as relative3, resolve as resolve55 } from "node:path";
93929
94088
  import { homedir as homedir52, tmpdir as tmpdir7 } from "node:os";
93930
94089
  import { spawnSync as spawnSync17 } from "node:child_process";
93931
94090
  init_helpers();
@@ -93937,10 +94096,10 @@ var TRASH_TTL_MS = 24 * 60 * 60 * 1000;
93937
94096
  var PERSONAL_SKILLS_SUBPATH = "personal-skills";
93938
94097
  function resolveConfigSkillsDir(agent) {
93939
94098
  const override = process.env.SWITCHROOM_CONFIG_DIR;
93940
- const candidate = override ? resolve55(override) : join92(homedir52(), ".switchroom-config");
94099
+ const candidate = override ? resolve55(override) : join93(homedir52(), ".switchroom-config");
93941
94100
  if (!existsSync93(candidate))
93942
94101
  return null;
93943
- return join92(candidate, "agents", agent, PERSONAL_SKILLS_SUBPATH);
94102
+ return join93(candidate, "agents", agent, PERSONAL_SKILLS_SUBPATH);
93944
94103
  }
93945
94104
  var MIRROR_PRIOR_TTL_MS = 24 * 60 * 60 * 1000;
93946
94105
  function sweepMirrorPriors(configSkillsRoot) {
@@ -93958,7 +94117,7 @@ function sweepMirrorPriors(configSkillsRoot) {
93958
94117
  if (now - ts < MIRROR_PRIOR_TTL_MS)
93959
94118
  continue;
93960
94119
  try {
93961
- rmSync19(join92(configSkillsRoot, ent), { recursive: true, force: true });
94120
+ rmSync19(join93(configSkillsRoot, ent), { recursive: true, force: true });
93962
94121
  } catch {}
93963
94122
  }
93964
94123
  } catch {}
@@ -93967,7 +94126,7 @@ function mirrorToConfigRepo(agent, name, liveSkillDir) {
93967
94126
  const configSkillsRoot = resolveConfigSkillsDir(agent);
93968
94127
  if (!configSkillsRoot)
93969
94128
  return;
93970
- const dest = join92(configSkillsRoot, name);
94129
+ const dest = join93(configSkillsRoot, name);
93971
94130
  try {
93972
94131
  if (liveSkillDir !== null) {
93973
94132
  try {
@@ -93982,19 +94141,19 @@ function mirrorToConfigRepo(agent, name, liveSkillDir) {
93982
94141
  if (liveSkillDir === null) {
93983
94142
  sweepMirrorPriors(configSkillsRoot);
93984
94143
  if (existsSync93(dest)) {
93985
- const trash = join92(configSkillsRoot, `.${name}-trash-${Date.now()}`);
94144
+ const trash = join93(configSkillsRoot, `.${name}-trash-${Date.now()}`);
93986
94145
  renameSync24(dest, trash);
93987
94146
  }
93988
94147
  return;
93989
94148
  }
93990
94149
  mkdirSync53(configSkillsRoot, { recursive: true, mode: 493 });
93991
94150
  sweepMirrorPriors(configSkillsRoot);
93992
- const staging = mkdtempSync6(join92(configSkillsRoot, `.${name}-staging-`));
94151
+ const staging = mkdtempSync6(join93(configSkillsRoot, `.${name}-staging-`));
93993
94152
  const walk2 = (src, dst) => {
93994
94153
  mkdirSync53(dst, { recursive: true, mode: 493 });
93995
94154
  for (const ent of readdirSync35(src, { withFileTypes: true })) {
93996
- const s = join92(src, ent.name);
93997
- const d = join92(dst, ent.name);
94155
+ const s = join93(src, ent.name);
94156
+ const d = join93(dst, ent.name);
93998
94157
  if (ent.isSymbolicLink())
93999
94158
  continue;
94000
94159
  if (ent.isDirectory())
@@ -94006,7 +94165,7 @@ function mirrorToConfigRepo(agent, name, liveSkillDir) {
94006
94165
  };
94007
94166
  walk2(liveSkillDir, staging);
94008
94167
  if (existsSync93(dest)) {
94009
- const prior = join92(configSkillsRoot, `.${name}-prior-${Date.now()}`);
94168
+ const prior = join93(configSkillsRoot, `.${name}-prior-${Date.now()}`);
94010
94169
  renameSync24(dest, prior);
94011
94170
  }
94012
94171
  renameSync24(staging, dest);
@@ -94036,16 +94195,16 @@ function resolveAgent(opts) {
94036
94195
  function resolveAgentsRoot(opts) {
94037
94196
  if (opts.root)
94038
94197
  return resolve55(opts.root);
94039
- return join92(homedir52(), ".switchroom", "agents");
94198
+ return join93(homedir52(), ".switchroom", "agents");
94040
94199
  }
94041
94200
  function personalSkillDir(agentsRoot, agent, name) {
94042
- return join92(agentsRoot, agent, ".claude", "skills", PERSONAL_PREFIX + name);
94201
+ return join93(agentsRoot, agent, ".claude", "skills", PERSONAL_PREFIX + name);
94043
94202
  }
94044
94203
  function trashDir(agentsRoot, agent) {
94045
- return join92(agentsRoot, agent, ".claude", TRASH_DIRNAME);
94204
+ return join93(agentsRoot, agent, ".claude", TRASH_DIRNAME);
94046
94205
  }
94047
94206
  function countPersonalSkills(agentsRoot, agent) {
94048
- const skillsDir = join92(agentsRoot, agent, ".claude", "skills");
94207
+ const skillsDir = join93(agentsRoot, agent, ".claude", "skills");
94049
94208
  if (!existsSync93(skillsDir))
94050
94209
  return 0;
94051
94210
  let n = 0;
@@ -94083,7 +94242,7 @@ function loadFromDir2(dir) {
94083
94242
  const files = {};
94084
94243
  const walk2 = (sub) => {
94085
94244
  for (const ent of readdirSync35(sub, { withFileTypes: true })) {
94086
- const full = join92(sub, ent.name);
94245
+ const full = join93(sub, ent.name);
94087
94246
  if (ent.isSymbolicLink()) {
94088
94247
  fail4(`refusing to read symlink in --from dir: ${relative3(abs, full)}`);
94089
94248
  }
@@ -94136,8 +94295,8 @@ function behavioralValidate(files) {
94136
94295
  errors2.push(`${path9} fails \`bash -n\`: ${(r.stderr ?? "").trim()}`);
94137
94296
  }
94138
94297
  } else if (PY_SCRIPT_RE.test(path9)) {
94139
- const tmp = mkdtempSync6(join92(tmpdir7(), "skill-personal-py-"));
94140
- const tmpPy = join92(tmp, "check.py");
94298
+ const tmp = mkdtempSync6(join93(tmpdir7(), "skill-personal-py-"));
94299
+ const tmpPy = join93(tmp, "check.py");
94141
94300
  try {
94142
94301
  writeFileSync34(tmpPy, content);
94143
94302
  const r = spawnSync17("python3", ["-m", "py_compile", tmpPy], {
@@ -94161,7 +94320,7 @@ function sweepTrash(agentsRoot, agent) {
94161
94320
  for (const ent of readdirSync35(trash, { withFileTypes: true })) {
94162
94321
  if (!ent.isDirectory())
94163
94322
  continue;
94164
- const entPath = join92(trash, ent.name);
94323
+ const entPath = join93(trash, ent.name);
94165
94324
  try {
94166
94325
  const st = statSync50(entPath);
94167
94326
  if (now - st.mtimeMs > TRASH_TTL_MS) {
@@ -94182,11 +94341,11 @@ function writePersonalSkill(targetDir, files) {
94182
94341
  fail4(`refusing to overwrite symlink at ${targetDir}; investigate manually`);
94183
94342
  }
94184
94343
  mkdirSync53(dirname32(targetDir), { recursive: true, mode: 493 });
94185
- const staging = mkdtempSync6(join92(dirname32(targetDir), `.skill-personal-stage-`));
94344
+ const staging = mkdtempSync6(join93(dirname32(targetDir), `.skill-personal-stage-`));
94186
94345
  let oldRename = null;
94187
94346
  try {
94188
94347
  for (const [path9, content] of Object.entries(files)) {
94189
- const full = join92(staging, path9);
94348
+ const full = join93(staging, path9);
94190
94349
  mkdirSync53(dirname32(full), { recursive: true, mode: 493 });
94191
94350
  const fd = openSync17(full, "wx");
94192
94351
  try {
@@ -94333,10 +94492,10 @@ function editPersonalAction(name, opts) {
94333
94492
  }
94334
94493
  var CLONE_SOURCE_RE = /^(shared|bundled):([a-z0-9][a-z0-9_-]{0,62})$/;
94335
94494
  function defaultSharedRoot() {
94336
- return join92(homedir52(), ".switchroom", "skills");
94495
+ return join93(homedir52(), ".switchroom", "skills");
94337
94496
  }
94338
94497
  function defaultBundledRoot() {
94339
- return join92(homedir52(), ".switchroom", "skills", "_bundled");
94498
+ return join93(homedir52(), ".switchroom", "skills", "_bundled");
94340
94499
  }
94341
94500
  function resolveCloneSource(source, opts) {
94342
94501
  const m = CLONE_SOURCE_RE.exec(source);
@@ -94346,7 +94505,7 @@ function resolveCloneSource(source, opts) {
94346
94505
  const tier = m[1];
94347
94506
  const slug = m[2];
94348
94507
  const root = tier === "bundled" ? opts.bundledRoot ?? defaultBundledRoot() : opts.sharedRoot ?? defaultSharedRoot();
94349
- const dir = join92(root, slug);
94508
+ const dir = join93(root, slug);
94350
94509
  if (!existsSync93(dir)) {
94351
94510
  fail4(`clone source ${JSON.stringify(source)} not found at ${dir}; ` + `check \`switchroom skill search --tier ${tier}\``, 1);
94352
94511
  }
@@ -94362,7 +94521,7 @@ function readSourceFiles(dir) {
94362
94521
  const skipped = [];
94363
94522
  const walk2 = (sub) => {
94364
94523
  for (const ent of readdirSync35(sub, { withFileTypes: true })) {
94365
- const full = join92(sub, ent.name);
94524
+ const full = join93(sub, ent.name);
94366
94525
  if (ent.isSymbolicLink()) {
94367
94526
  continue;
94368
94527
  }
@@ -94473,7 +94632,7 @@ function removePersonalAction(name, opts) {
94473
94632
  const trashRoot2 = trashDir(agentsRoot, agent);
94474
94633
  mkdirSync53(trashRoot2, { recursive: true, mode: 493 });
94475
94634
  const ts = Date.now();
94476
- const trashTarget = join92(trashRoot2, `${name}-${ts}`);
94635
+ const trashTarget = join93(trashRoot2, `${name}-${ts}`);
94477
94636
  renameSync24(target, trashTarget);
94478
94637
  const now = new Date(ts);
94479
94638
  utimesSync(trashTarget, now, now);
@@ -94492,7 +94651,7 @@ function listPersonalAction(opts) {
94492
94651
  const agent = resolveAgent(opts);
94493
94652
  const agentsRoot = resolveAgentsRoot(opts);
94494
94653
  sweepTrash(agentsRoot, agent);
94495
- const skillsDir = join92(agentsRoot, agent, ".claude", "skills");
94654
+ const skillsDir = join93(agentsRoot, agent, ".claude", "skills");
94496
94655
  const personal = [];
94497
94656
  if (existsSync93(skillsDir)) {
94498
94657
  for (const ent of readdirSync35(skillsDir, { withFileTypes: true })) {
@@ -94501,7 +94660,7 @@ function listPersonalAction(opts) {
94501
94660
  if (!ent.name.startsWith(PERSONAL_PREFIX))
94502
94661
  continue;
94503
94662
  const skillName = ent.name.slice(PERSONAL_PREFIX.length);
94504
- const skillPath = join92(skillsDir, ent.name);
94663
+ const skillPath = join93(skillsDir, ent.name);
94505
94664
  let fileCount = 0;
94506
94665
  let totalBytes = 0;
94507
94666
  const walk2 = (sub) => {
@@ -94509,10 +94668,10 @@ function listPersonalAction(opts) {
94509
94668
  if (e.isFile()) {
94510
94669
  fileCount += 1;
94511
94670
  try {
94512
- totalBytes += statSync50(join92(sub, e.name)).size;
94671
+ totalBytes += statSync50(join93(sub, e.name)).size;
94513
94672
  } catch {}
94514
94673
  } else if (e.isDirectory()) {
94515
- walk2(join92(sub, e.name));
94674
+ walk2(join93(sub, e.name));
94516
94675
  }
94517
94676
  }
94518
94677
  };
@@ -94551,11 +94710,11 @@ function registerSkillPersonalCommands(program3) {
94551
94710
  // src/cli/self-improve-propose-skill.ts
94552
94711
  import { createConnection as createConnection4 } from "node:net";
94553
94712
  import { homedir as homedir53 } from "node:os";
94554
- import { join as join93 } from "node:path";
94713
+ import { join as join94 } from "node:path";
94555
94714
  import { readFileSync as readFileSync81 } from "node:fs";
94556
94715
  var IPC_CONNECT_TIMEOUT_MS = 5000;
94557
94716
  function gatewaySocketPath() {
94558
- return process.env.SWITCHROOM_GATEWAY_SOCKET ?? (process.env.TELEGRAM_STATE_DIR ? join93(process.env.TELEGRAM_STATE_DIR, "gateway.sock") : join93(homedir53(), ".claude", "channels", "telegram", "gateway.sock"));
94717
+ return process.env.SWITCHROOM_GATEWAY_SOCKET ?? (process.env.TELEGRAM_STATE_DIR ? join94(process.env.TELEGRAM_STATE_DIR, "gateway.sock") : join94(homedir53(), ".claude", "channels", "telegram", "gateway.sock"));
94559
94718
  }
94560
94719
  function fail5(msg, code = 1) {
94561
94720
  console.error(msg);
@@ -94629,7 +94788,7 @@ init_helpers();
94629
94788
  var import_yaml25 = __toESM(require_dist(), 1);
94630
94789
  import { existsSync as existsSync94, readdirSync as readdirSync36, readFileSync as readFileSync82, statSync as statSync51 } from "node:fs";
94631
94790
  import { homedir as homedir54 } from "node:os";
94632
- import { join as join94, resolve as resolve56 } from "node:path";
94791
+ import { join as join95, resolve as resolve56 } from "node:path";
94633
94792
  var PERSONAL_PREFIX2 = "personal-";
94634
94793
  var BUNDLED_SUBDIR = "_bundled";
94635
94794
  var AGENT_NAME_RE3 = /^[a-z][a-z0-9_-]{0,62}$/;
@@ -94643,7 +94802,7 @@ function defaultBundledRoot2() {
94643
94802
  return resolve56(homedir54(), ".switchroom/skills/_bundled");
94644
94803
  }
94645
94804
  function readSkillFrontmatter(skillDir) {
94646
- const mdPath = join94(skillDir, "SKILL.md");
94805
+ const mdPath = join95(skillDir, "SKILL.md");
94647
94806
  if (!existsSync94(mdPath))
94648
94807
  return null;
94649
94808
  let content;
@@ -94676,7 +94835,7 @@ function readSkillFrontmatter(skillDir) {
94676
94835
  return { fm: parsed };
94677
94836
  }
94678
94837
  function statSkillMd(skillDir) {
94679
- const mdPath = join94(skillDir, "SKILL.md");
94838
+ const mdPath = join95(skillDir, "SKILL.md");
94680
94839
  try {
94681
94840
  const st = statSync51(mdPath);
94682
94841
  return { size: st.size, mtime: st.mtime.toISOString() };
@@ -94687,7 +94846,7 @@ function statSkillMd(skillDir) {
94687
94846
  function listPersonalSkills(agent, agentsRoot = defaultAgentsRoot()) {
94688
94847
  if (!AGENT_NAME_RE3.test(agent))
94689
94848
  return [];
94690
- const skillsDir = join94(agentsRoot, agent, ".claude/skills");
94849
+ const skillsDir = join95(agentsRoot, agent, ".claude/skills");
94691
94850
  if (!existsSync94(skillsDir))
94692
94851
  return [];
94693
94852
  const out = [];
@@ -94700,7 +94859,7 @@ function listPersonalSkills(agent, agentsRoot = defaultAgentsRoot()) {
94700
94859
  for (const ent of entries) {
94701
94860
  if (!ent.startsWith(PERSONAL_PREFIX2))
94702
94861
  continue;
94703
- const dirPath = join94(skillsDir, ent);
94862
+ const dirPath = join95(skillsDir, ent);
94704
94863
  try {
94705
94864
  if (!statSync51(dirPath).isDirectory())
94706
94865
  continue;
@@ -94740,7 +94899,7 @@ function listSharedSkills(sharedRoot = defaultSharedRoot2()) {
94740
94899
  continue;
94741
94900
  if (ent.startsWith("."))
94742
94901
  continue;
94743
- const dirPath = join94(sharedRoot, ent);
94902
+ const dirPath = join95(sharedRoot, ent);
94744
94903
  try {
94745
94904
  if (!statSync51(dirPath).isDirectory())
94746
94905
  continue;
@@ -94776,7 +94935,7 @@ function listBundledSkills(bundledRoot = defaultBundledRoot2()) {
94776
94935
  for (const ent of entries) {
94777
94936
  if (ent.startsWith("."))
94778
94937
  continue;
94779
- const dirPath = join94(bundledRoot, ent);
94938
+ const dirPath = join95(bundledRoot, ent);
94780
94939
  try {
94781
94940
  if (!statSync51(dirPath).isDirectory())
94782
94941
  continue;
@@ -94933,7 +95092,7 @@ import {
94933
95092
  copyFileSync as copyFileSync13
94934
95093
  } from "node:fs";
94935
95094
  import { homedir as homedir55 } from "node:os";
94936
- import { join as join95 } from "node:path";
95095
+ import { join as join96 } from "node:path";
94937
95096
  import { spawnSync as spawnSync20 } from "node:child_process";
94938
95097
 
94939
95098
  // src/cli/singleton-stale-cleanup.ts
@@ -95282,7 +95441,7 @@ function resolveHostdHostHome(env2 = process.env, home2 = homedir55()) {
95282
95441
  return resolved;
95283
95442
  }
95284
95443
  function resolveHostdSkillsTarget(hostHome) {
95285
- const skillsPath = join95(hostHome, ".switchroom", "skills");
95444
+ const skillsPath = join96(hostHome, ".switchroom", "skills");
95286
95445
  let st;
95287
95446
  try {
95288
95447
  st = lstatSync13(skillsPath);
@@ -95306,10 +95465,10 @@ function resolveHostdSkillsTarget(hostHome) {
95306
95465
  return target;
95307
95466
  }
95308
95467
  function hostdDir() {
95309
- return join95(homedir55(), ".switchroom", "hostd");
95468
+ return join96(homedir55(), ".switchroom", "hostd");
95310
95469
  }
95311
95470
  function hostdComposePath() {
95312
- return join95(hostdDir(), "docker-compose.yml");
95471
+ return join96(hostdDir(), "docker-compose.yml");
95313
95472
  }
95314
95473
  function backupExistingCompose() {
95315
95474
  const p = hostdComposePath();
@@ -95438,7 +95597,7 @@ function doStatus() {
95438
95597
  for (const name of readdirSync37(dir)) {
95439
95598
  if (name === "docker-compose.yml" || name.startsWith("docker-compose.yml."))
95440
95599
  continue;
95441
- const sockPath = join95(dir, name, "sock");
95600
+ const sockPath = join96(dir, name, "sock");
95442
95601
  if (existsSync96(sockPath)) {
95443
95602
  const st = statSync52(sockPath);
95444
95603
  if ((st.mode & 61440) === 49152) {
@@ -95532,7 +95691,7 @@ init_helpers();
95532
95691
  init_operator_uid();
95533
95692
  import { chownSync as chownSync9, existsSync as existsSync97, mkdirSync as mkdirSync55, writeFileSync as writeFileSync36, copyFileSync as copyFileSync14 } from "node:fs";
95534
95693
  import { homedir as homedir56 } from "node:os";
95535
- import { join as join96 } from "node:path";
95694
+ import { join as join97 } from "node:path";
95536
95695
  import { spawnSync as spawnSync21 } from "node:child_process";
95537
95696
  function resolveWebImageTag(explicitTag, release) {
95538
95697
  if (explicitTag)
@@ -95632,10 +95791,10 @@ services:
95632
95791
  `;
95633
95792
  }
95634
95793
  function webdDir() {
95635
- return join96(homedir56(), ".switchroom", "web");
95794
+ return join97(homedir56(), ".switchroom", "web");
95636
95795
  }
95637
95796
  function webdComposePath() {
95638
- return join96(webdDir(), "docker-compose.yml");
95797
+ return join97(webdDir(), "docker-compose.yml");
95639
95798
  }
95640
95799
  function backupExistingCompose2() {
95641
95800
  const p = webdComposePath();
@@ -95795,9 +95954,9 @@ function registerWebdCommand(program3) {
95795
95954
  // src/cli/host-repair.ts
95796
95955
  init_source();
95797
95956
  import { homedir as homedir57 } from "node:os";
95798
- import { join as join97 } from "node:path";
95957
+ import { join as join98 } from "node:path";
95799
95958
  var ARTIFACT_ALLOWLIST = {
95800
- dockerComposePluginDir: (home2) => join97(home2, ".docker", "cli-plugins", "docker-compose"),
95959
+ dockerComposePluginDir: (home2) => join98(home2, ".docker", "cli-plugins", "docker-compose"),
95801
95960
  stateSentinel: "/state"
95802
95961
  };
95803
95962
  function isStateBogusAutoDir(probe2) {