switchroom 0.15.3 → 0.15.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/turn-pacing-hook.sh +112 -0
- package/bin/workspace-dynamic-hook.sh +105 -15
- package/bin/workspace-stable-hook.sh +2 -2
- package/dist/agent-scheduler/index.js +2 -1
- package/dist/auth-broker/index.js +2 -1
- package/dist/cli/notion-write-pretool.mjs +2 -1
- package/dist/cli/switchroom.js +442 -394
- package/dist/host-control/main.js +2 -1
- package/dist/vault/approvals/kernel-server.js +2 -1
- package/dist/vault/broker/server.js +2 -1
- package/package.json +1 -1
- package/profiles/_base/start.sh.hbs +2 -2
- package/telegram-plugin/dist/gateway/gateway.js +100 -39
- package/telegram-plugin/gateway/gateway.ts +45 -9
- package/telegram-plugin/gateway/inbound-spool.ts +107 -16
- package/telegram-plugin/gateway/model-command.ts +89 -21
- package/telegram-plugin/tests/inbound-spool.test.ts +101 -0
- package/telegram-plugin/tests/model-command.test.ts +41 -6
- package/telegram-plugin/tests/welcome-text.test.ts +11 -0
- package/telegram-plugin/welcome-text.ts +16 -1
- package/profiles/default/workspace/HEARTBEAT.md.hbs +0 -40
package/dist/cli/switchroom.js
CHANGED
|
@@ -13654,7 +13654,8 @@ var init_schema = __esm(() => {
|
|
|
13654
13654
|
stream_mode: exports_external.enum(["pty", "checklist"]).optional().describe("How live progress is streamed to Telegram during a turn. " + "'pty' (default) surfaces text snapshots of Claude Code's TUI \u2014 " + "compatible but can flicker as Ink re-renders. 'checklist' drives " + "a structured progress card from session-tail events \u2014 stable " + "order, per-tool status emojis, fires only on semantic transitions."),
|
|
13655
13655
|
stream_throttle_ms: exports_external.number().int().nonnegative().optional().describe("Throttle window in ms between successive stream edits (or " + "sendMessageDraft tics) during a turn. Lower = more responsive " + "stream, higher = fewer API calls. Floored at 250 by draft-stream " + "itself. Default 300 for draft transport (DMs) and 1000 for " + "message transport (groups/forums). Override per-agent if a " + "particular agent needs snappier or quieter streaming."),
|
|
13656
13656
|
clear_status_on_completion: exports_external.boolean().optional().describe("When true, the live activity/status feed (the in-place 'what it's " + "doing' message \u2014 Reading X, Searching the web for Y, \u2026) is DELETED " + "when the turn's final answer lands, so only the reply remains. " + "Default false: the status message is left in the chat as a record " + "(its last step marked done) \u2014 no post-then-delete. Per-agent " + "override; cascades defaults \u2192 profile \u2192 agent (per-key)."),
|
|
13657
|
-
hotReloadStable: exports_external.boolean().optional().describe("If true, the stable workspace prefix (AGENTS.md, SOUL.md, USER.md, " + "IDENTITY.md, TOOLS.md
|
|
13657
|
+
hotReloadStable: exports_external.boolean().optional().describe("If true, the stable workspace prefix (AGENTS.md, SOUL.md, USER.md, " + "IDENTITY.md, TOOLS.md) is re-injected on every turn via " + "the UserPromptSubmit hook instead of baked into --append-system-prompt " + "at session start. Lets workspace edits propagate without a restart. " + "Costs ~5-10% per-turn latency/spend since the stable prefix is no " + "longer prompt-cached."),
|
|
13658
|
+
inject_on_change: exports_external.boolean().optional().describe("Context-efficiency gate for per-turn hook injection (default true). " + "When true (the default), the turn-pacing directive and dynamic " + "workspace content are only re-emitted when their content changes or " + "the session_id changes \u2014 suppressing redundant injection that " + "otherwise triples compaction frequency. Set to false to revert to " + "the legacy always-emit behaviour (every turn injects the full " + "content regardless of whether it changed)."),
|
|
13658
13659
|
orphan_promotion_ms: exports_external.number().int().nonnegative().optional().describe("How long (ms) a parent turn waits for a sub-agent JSONL watcher " + "to deliver sub_agent_started before the heartbeat promotes the spawn " + "to a synthesised 'running' row. Default 5000. Set to 0 to disable " + "orphan promotion entirely."),
|
|
13659
13660
|
cold_sub_agent_threshold_ms: exports_external.number().int().nonnegative().optional().describe("JSONL-cold threshold (ms). When a running sub-agent emits no events " + "for this long, the heartbeat synthesises a turn_end for it so the " + "deferred-completion path can proceed. Default 30000. Set to 0 to " + "disable the synthetic close."),
|
|
13660
13661
|
deferred_completion_timeout_ms: exports_external.number().int().nonnegative().optional().describe("Force-close timeout (ms) for deferred sub-agent completion. After " + "the parent turn_end arrives while sub-agents are still running, the " + "card is force-closed after this many ms even if sub-agents never " + "finish. Watcher-disconnect safety net. Default 180000 (3 min)."),
|
|
@@ -23264,6 +23265,14 @@ function normalizeBindMountPath(p) {
|
|
|
23264
23265
|
out = out.slice(0, -1);
|
|
23265
23266
|
return out;
|
|
23266
23267
|
}
|
|
23268
|
+
function resolveConfigMountSource(switchroomConfigPath, homePrefix) {
|
|
23269
|
+
if (!switchroomConfigPath)
|
|
23270
|
+
return;
|
|
23271
|
+
if (switchroomConfigPath === CONTAINER_CONFIG_PATH || switchroomConfigPath.startsWith("/state/")) {
|
|
23272
|
+
return `${homePrefix}/.switchroom/switchroom.yaml`;
|
|
23273
|
+
}
|
|
23274
|
+
return switchroomConfigPath;
|
|
23275
|
+
}
|
|
23267
23276
|
function resolveBindMount(agentName, entry) {
|
|
23268
23277
|
const rawSource = entry.source;
|
|
23269
23278
|
if (typeof rawSource !== "string" || rawSource.length === 0) {
|
|
@@ -23320,10 +23329,15 @@ function generateCompose(opts) {
|
|
|
23320
23329
|
const buildMode = opts.buildMode ?? "pull";
|
|
23321
23330
|
const buildContext = opts.buildContext;
|
|
23322
23331
|
const homePrefix = opts.homeDir ?? "${HOME}";
|
|
23332
|
+
if (homePrefix === "/host-home" || homePrefix.startsWith("/host-home/")) {
|
|
23333
|
+
throw new Error(`compose: refusing to generate \u2014 the host-home prefix resolved to "${homePrefix}", ` + `which is the IN-CONTAINER mount point, not a host path. Emitting it as a bind-mount ` + `source would make docker create empty dirs on the host and crash the fleet (start.sh ` + `missing \u2192 exec 127; broker EISDIR).
|
|
23334
|
+
|
|
23335
|
+
` + `Cause: \`apply\` ran inside a container without SWITCHROOM_HOST_HOME set to the real ` + `host home. Recovery: run \`switchroom apply\` once from the HOST shell (not via an ` + `agent / hostd), which regenerates the compose with correct host paths and re-bakes a ` + `correct SWITCHROOM_HOST_HOME into the fleet.`);
|
|
23336
|
+
}
|
|
23323
23337
|
const containerNamePrefix = opts.containerNamePrefix ?? "switchroom";
|
|
23324
23338
|
const hostControlEnabled = config.host_control?.enabled !== false;
|
|
23325
23339
|
const hostHomeForChecks = opts.homeDir ?? process.env.HOME ?? "";
|
|
23326
|
-
const switchroomConfigPath = opts.switchroomConfigPath;
|
|
23340
|
+
const switchroomConfigPath = resolveConfigMountSource(opts.switchroomConfigPath, homePrefix);
|
|
23327
23341
|
const bundledSkillsPoolDir = opts.bundledSkillsPoolDir ?? getBundledSkillsPoolDir();
|
|
23328
23342
|
let resolvedAnalyticsId = null;
|
|
23329
23343
|
if (hostHomeForChecks !== "") {
|
|
@@ -23608,6 +23622,9 @@ function emitAgentService(lines, a, imageTag, buildMode, buildContext, homePrefi
|
|
|
23608
23622
|
SWITCHROOM_TIMEZONE: a.timezone,
|
|
23609
23623
|
TZ: a.timezone
|
|
23610
23624
|
};
|
|
23625
|
+
if (hostHomeForChecks) {
|
|
23626
|
+
env2.SWITCHROOM_HOST_HOME = hostHomeForChecks;
|
|
23627
|
+
}
|
|
23611
23628
|
if (posthog.analyticsId != null) {
|
|
23612
23629
|
env2.SWITCHROOM_ANALYTICS_ID = posthog.analyticsId;
|
|
23613
23630
|
}
|
|
@@ -23717,7 +23734,7 @@ function emitAgentService(lines, a, imageTag, buildMode, buildContext, homePrefi
|
|
|
23717
23734
|
lines.push(` - ${homePrefix}/.switchroom/logs/${a.name}:${homePrefix}/.switchroom/logs/${a.name}`);
|
|
23718
23735
|
lines.push(``);
|
|
23719
23736
|
}
|
|
23720
|
-
var AGENT_UID_MIN = 10001, AGENT_UID_MAX = 10999, RESOURCE_BY_PROFILE, CRON_SESSION_MEM_BUMP_MIB = 512, CRON_SESSION_PIDS_BUMP = 128, BIND_MOUNT_SOURCE_DENYLIST, BIND_MOUNT_TARGET_DENYLIST, BIND_MOUNT_EXACT_SOURCE_DENY;
|
|
23737
|
+
var AGENT_UID_MIN = 10001, AGENT_UID_MAX = 10999, RESOURCE_BY_PROFILE, CRON_SESSION_MEM_BUMP_MIB = 512, CRON_SESSION_PIDS_BUMP = 128, BIND_MOUNT_SOURCE_DENYLIST, BIND_MOUNT_TARGET_DENYLIST, BIND_MOUNT_EXACT_SOURCE_DENY, CONTAINER_CONFIG_PATH = "/state/config/switchroom.yaml";
|
|
23721
23738
|
var init_compose = __esm(() => {
|
|
23722
23739
|
init_cron_routing();
|
|
23723
23740
|
init_merge();
|
|
@@ -23969,16 +23986,16 @@ var init_singleton_reconcile = __esm(() => {
|
|
|
23969
23986
|
// src/agents/lifecycle.ts
|
|
23970
23987
|
import { execFileSync as execFileSync8, spawn, spawnSync } from "node:child_process";
|
|
23971
23988
|
import { existsSync as existsSync17, mkdirSync as mkdirSync13, writeFileSync as writeFileSync7, renameSync as renameSync4, readFileSync as readFileSync15 } from "node:fs";
|
|
23972
|
-
import { resolve as resolve13, join as
|
|
23989
|
+
import { resolve as resolve13, join as join13 } from "node:path";
|
|
23973
23990
|
import { connect } from "node:net";
|
|
23974
23991
|
function cleanShutdownMarkerPathForAgent(name) {
|
|
23975
23992
|
const agentsDir = process.env.SWITCHROOM_AGENTS_DIR ?? resolveStatePath("agents");
|
|
23976
|
-
return
|
|
23993
|
+
return join13(agentsDir, name, "telegram", "clean-shutdown.json");
|
|
23977
23994
|
}
|
|
23978
23995
|
function writeRestartReasonMarker(name, reason, opts = {}) {
|
|
23979
23996
|
const path = cleanShutdownMarkerPathForAgent(name);
|
|
23980
23997
|
try {
|
|
23981
|
-
mkdirSync13(
|
|
23998
|
+
mkdirSync13(join13(path, ".."), { recursive: true });
|
|
23982
23999
|
if (opts.preserveExisting && existsSync17(path)) {
|
|
23983
24000
|
try {
|
|
23984
24001
|
const prev = JSON.parse(readFileSync15(path, "utf-8"));
|
|
@@ -24082,7 +24099,7 @@ function gracefulRestartAgent(name) {
|
|
|
24082
24099
|
return new Promise((resolvePromise, reject) => {
|
|
24083
24100
|
const agentsDir = process.env.SWITCHROOM_AGENTS_DIR ?? resolveStatePath("agents");
|
|
24084
24101
|
const agentDir = resolve13(agentsDir, name);
|
|
24085
|
-
const socketPath = process.env.SWITCHROOM_GATEWAY_SOCKET ??
|
|
24102
|
+
const socketPath = process.env.SWITCHROOM_GATEWAY_SOCKET ?? join13(agentDir, "telegram", "gateway.sock");
|
|
24086
24103
|
if (!existsSync17(socketPath)) {
|
|
24087
24104
|
reject(new Error("Gateway socket not found. Is the gateway running?"));
|
|
24088
24105
|
return;
|
|
@@ -24478,30 +24495,30 @@ import {
|
|
|
24478
24495
|
writeFileSync as writeFileSync9
|
|
24479
24496
|
} from "node:fs";
|
|
24480
24497
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
24481
|
-
import { join as
|
|
24498
|
+
import { join as join16 } from "node:path";
|
|
24482
24499
|
function claudeDir(agentDir) {
|
|
24483
|
-
return
|
|
24500
|
+
return join16(agentDir, ".claude");
|
|
24484
24501
|
}
|
|
24485
24502
|
function accountsDir(agentDir) {
|
|
24486
|
-
return
|
|
24503
|
+
return join16(claudeDir(agentDir), "accounts");
|
|
24487
24504
|
}
|
|
24488
24505
|
function slotDir(agentDir, slot) {
|
|
24489
|
-
return
|
|
24506
|
+
return join16(accountsDir(agentDir), slot);
|
|
24490
24507
|
}
|
|
24491
24508
|
function slotTokenPath(agentDir, slot) {
|
|
24492
|
-
return
|
|
24509
|
+
return join16(slotDir(agentDir, slot), ".oauth-token");
|
|
24493
24510
|
}
|
|
24494
24511
|
function slotMetaPath(agentDir, slot) {
|
|
24495
|
-
return
|
|
24512
|
+
return join16(slotDir(agentDir, slot), ".oauth-token.meta.json");
|
|
24496
24513
|
}
|
|
24497
24514
|
function activeMarkerPath(agentDir) {
|
|
24498
|
-
return
|
|
24515
|
+
return join16(claudeDir(agentDir), "active");
|
|
24499
24516
|
}
|
|
24500
24517
|
function legacyTokenPath(agentDir) {
|
|
24501
|
-
return
|
|
24518
|
+
return join16(claudeDir(agentDir), ".oauth-token");
|
|
24502
24519
|
}
|
|
24503
24520
|
function legacyMetaPath(agentDir) {
|
|
24504
|
-
return
|
|
24521
|
+
return join16(claudeDir(agentDir), ".oauth-token.meta.json");
|
|
24505
24522
|
}
|
|
24506
24523
|
function validateSlotName(slot) {
|
|
24507
24524
|
if (typeof slot !== "string" || slot.length === 0) {
|
|
@@ -24544,7 +24561,7 @@ function listSlots(agentDir) {
|
|
|
24544
24561
|
try {
|
|
24545
24562
|
return readdirSync10(dir).filter((name) => {
|
|
24546
24563
|
try {
|
|
24547
|
-
return statSync12(
|
|
24564
|
+
return statSync12(join16(dir, name)).isDirectory();
|
|
24548
24565
|
} catch {
|
|
24549
24566
|
return false;
|
|
24550
24567
|
}
|
|
@@ -24723,7 +24740,7 @@ import {
|
|
|
24723
24740
|
chmodSync as chmodSync3,
|
|
24724
24741
|
statSync as statSync13
|
|
24725
24742
|
} from "node:fs";
|
|
24726
|
-
import { join as
|
|
24743
|
+
import { join as join17, resolve as resolve15 } from "node:path";
|
|
24727
24744
|
function extractCodeChallenge(url) {
|
|
24728
24745
|
const match = url.match(/[?&]code_challenge=([A-Za-z0-9_-]+)/);
|
|
24729
24746
|
return match ? match[1] : null;
|
|
@@ -24738,22 +24755,22 @@ function stripAnsi(text) {
|
|
|
24738
24755
|
return text.replace(/\x1B\[[0-9;?]*[ -/]*[@-~]/g, "").replace(/\x1B[@-_]/g, "").replace(/\r/g, "");
|
|
24739
24756
|
}
|
|
24740
24757
|
function claudeDir2(agentDir) {
|
|
24741
|
-
return
|
|
24758
|
+
return join17(agentDir, ".claude");
|
|
24742
24759
|
}
|
|
24743
24760
|
function credentialsPath(agentDir) {
|
|
24744
|
-
return
|
|
24761
|
+
return join17(claudeDir2(agentDir), ".credentials.json");
|
|
24745
24762
|
}
|
|
24746
24763
|
function oauthTokenPath(agentDir) {
|
|
24747
|
-
return
|
|
24764
|
+
return join17(claudeDir2(agentDir), ".oauth-token");
|
|
24748
24765
|
}
|
|
24749
24766
|
function oauthTokenMetaPath(agentDir) {
|
|
24750
|
-
return
|
|
24767
|
+
return join17(claudeDir2(agentDir), ".oauth-token.meta.json");
|
|
24751
24768
|
}
|
|
24752
24769
|
function authLogPath(agentDir) {
|
|
24753
|
-
return
|
|
24770
|
+
return join17(claudeDir2(agentDir), ".setup-token.log");
|
|
24754
24771
|
}
|
|
24755
24772
|
function authSessionMetaPath(agentDir) {
|
|
24756
|
-
return
|
|
24773
|
+
return join17(claudeDir2(agentDir), ".setup-token.session.json");
|
|
24757
24774
|
}
|
|
24758
24775
|
function authSessionName(name, slot) {
|
|
24759
24776
|
const base = `switchroom-auth-${name.replace(/[^a-zA-Z0-9_.-]/g, "-")}`;
|
|
@@ -24873,7 +24890,7 @@ function cleanupAuthTempDirs(agentDir) {
|
|
|
24873
24890
|
try {
|
|
24874
24891
|
for (const entry of readdirSync11(dir)) {
|
|
24875
24892
|
if (entry.startsWith(".setup-token-tmp-")) {
|
|
24876
|
-
rmSync5(
|
|
24893
|
+
rmSync5(join17(dir, entry), { recursive: true, force: true });
|
|
24877
24894
|
}
|
|
24878
24895
|
}
|
|
24879
24896
|
} catch {}
|
|
@@ -25034,14 +25051,14 @@ function startAuthSession(name, agentDir, opts = {}) {
|
|
|
25034
25051
|
rmSync5(logPath, { force: true });
|
|
25035
25052
|
let configDir;
|
|
25036
25053
|
if (opts.force) {
|
|
25037
|
-
configDir = mkdtempSync2(
|
|
25054
|
+
configDir = mkdtempSync2(join17(claudeDir2(agentDir), ".setup-token-tmp-"));
|
|
25038
25055
|
try {
|
|
25039
25056
|
chmodSync3(configDir, 448);
|
|
25040
25057
|
} catch {}
|
|
25041
25058
|
} else {
|
|
25042
25059
|
configDir = claudeDir2(agentDir);
|
|
25043
25060
|
}
|
|
25044
|
-
const credentialsMtimeAtStart = fileMtimeMs(
|
|
25061
|
+
const credentialsMtimeAtStart = fileMtimeMs(join17(configDir, ".credentials.json"));
|
|
25045
25062
|
const commandParts = [];
|
|
25046
25063
|
commandParts.push(`CLAUDE_CONFIG_DIR=${shellQuote(configDir)}`);
|
|
25047
25064
|
commandParts.push(`LOG_PATH=${shellQuote(logPath)}`);
|
|
@@ -25129,7 +25146,7 @@ function submitAuthCode(name, agentDir, code, slot, _opts = {}) {
|
|
|
25129
25146
|
tmux(["send-keys", "-l", "-t", sessionName, code.trim()]);
|
|
25130
25147
|
tmux(["send-keys", "-t", sessionName, "Enter"]);
|
|
25131
25148
|
const meta = readJsonFile(authSessionMetaPath(agentDir));
|
|
25132
|
-
const credFileToWatch = meta?.configDir ?
|
|
25149
|
+
const credFileToWatch = meta?.configDir ? join17(meta.configDir, ".credentials.json") : credentialsPath(agentDir);
|
|
25133
25150
|
const credsMtimeSnapshot = meta?.credentialsMtimeAtStart ?? 0;
|
|
25134
25151
|
const logPath = authLogPath(agentDir);
|
|
25135
25152
|
let token = null;
|
|
@@ -25235,9 +25252,9 @@ import {
|
|
|
25235
25252
|
unlinkSync as unlinkSync6,
|
|
25236
25253
|
writeFileSync as writeFileSync12
|
|
25237
25254
|
} from "node:fs";
|
|
25238
|
-
import { join as
|
|
25255
|
+
import { join as join19 } from "node:path";
|
|
25239
25256
|
function quarantineMarkerPath(telegramStateDir) {
|
|
25240
|
-
return
|
|
25257
|
+
return join19(telegramStateDir, QUARANTINE_FILENAME);
|
|
25241
25258
|
}
|
|
25242
25259
|
function readQuarantineMarker(telegramStateDir) {
|
|
25243
25260
|
const path = quarantineMarkerPath(telegramStateDir);
|
|
@@ -25277,7 +25294,7 @@ function clearQuarantineMarker(telegramStateDir) {
|
|
|
25277
25294
|
}
|
|
25278
25295
|
}
|
|
25279
25296
|
function hostTelegramStateDir(agentsDir, name) {
|
|
25280
|
-
return
|
|
25297
|
+
return join19(agentsDir, name, "telegram");
|
|
25281
25298
|
}
|
|
25282
25299
|
function readQuarantineMarkerForAgent(agentsDir, name) {
|
|
25283
25300
|
return readQuarantineMarker(hostTelegramStateDir(agentsDir, name));
|
|
@@ -25855,7 +25872,7 @@ import * as net2 from "node:net";
|
|
|
25855
25872
|
import { existsSync as existsSync29 } from "node:fs";
|
|
25856
25873
|
import { homedir as homedir9 } from "node:os";
|
|
25857
25874
|
import { randomUUID } from "node:crypto";
|
|
25858
|
-
import { join as
|
|
25875
|
+
import { join as join21 } from "node:path";
|
|
25859
25876
|
function reviveDate(v) {
|
|
25860
25877
|
if (v == null)
|
|
25861
25878
|
return null;
|
|
@@ -25865,7 +25882,7 @@ function reviveDate(v) {
|
|
|
25865
25882
|
return Number.isNaN(d.getTime()) ? null : d;
|
|
25866
25883
|
}
|
|
25867
25884
|
function operatorSocketPath(home2 = homedir9()) {
|
|
25868
|
-
return
|
|
25885
|
+
return join21(home2, ".switchroom", "state", "auth-broker-operator", "sock");
|
|
25869
25886
|
}
|
|
25870
25887
|
function resolveAuthBrokerSocketPath(opts) {
|
|
25871
25888
|
if (opts?.socket)
|
|
@@ -26223,7 +26240,7 @@ import {
|
|
|
26223
26240
|
writeFileSync as writeFileSync14
|
|
26224
26241
|
} from "node:fs";
|
|
26225
26242
|
import { homedir as homedir11 } from "node:os";
|
|
26226
|
-
import { join as
|
|
26243
|
+
import { join as join23, resolve as resolve22 } from "node:path";
|
|
26227
26244
|
function accountsRootOverride() {
|
|
26228
26245
|
const v = process.env.SWITCHROOM_ACCOUNTS_DIR;
|
|
26229
26246
|
if (v && v.length > 0 && v.startsWith("/"))
|
|
@@ -26234,13 +26251,13 @@ function accountsRoot(home2 = homedir11()) {
|
|
|
26234
26251
|
return accountsRootOverride() ?? resolve22(home2, ".switchroom", "accounts");
|
|
26235
26252
|
}
|
|
26236
26253
|
function accountDir(label, home2 = homedir11()) {
|
|
26237
|
-
return
|
|
26254
|
+
return join23(accountsRoot(home2), label);
|
|
26238
26255
|
}
|
|
26239
26256
|
function accountCredentialsPath(label, home2 = homedir11()) {
|
|
26240
|
-
return
|
|
26257
|
+
return join23(accountDir(label, home2), "credentials.json");
|
|
26241
26258
|
}
|
|
26242
26259
|
function accountMetaPath(label, home2 = homedir11()) {
|
|
26243
|
-
return
|
|
26260
|
+
return join23(accountDir(label, home2), "meta.json");
|
|
26244
26261
|
}
|
|
26245
26262
|
function listAccounts(home2 = homedir11()) {
|
|
26246
26263
|
const root = accountsRoot(home2);
|
|
@@ -26249,7 +26266,7 @@ function listAccounts(home2 = homedir11()) {
|
|
|
26249
26266
|
try {
|
|
26250
26267
|
return readdirSync15(root).filter((name) => {
|
|
26251
26268
|
try {
|
|
26252
|
-
return statSync16(
|
|
26269
|
+
return statSync16(join23(root, name)).isDirectory();
|
|
26253
26270
|
} catch {
|
|
26254
26271
|
return false;
|
|
26255
26272
|
}
|
|
@@ -26965,9 +26982,9 @@ var init_disconnect = __esm(() => {
|
|
|
26965
26982
|
// src/vault/approvals/client.ts
|
|
26966
26983
|
import { existsSync as existsSync31 } from "node:fs";
|
|
26967
26984
|
import { homedir as homedir12 } from "node:os";
|
|
26968
|
-
import { join as
|
|
26985
|
+
import { join as join24 } from "node:path";
|
|
26969
26986
|
function kernelOperatorSocketPath(home2 = homedir12()) {
|
|
26970
|
-
return
|
|
26987
|
+
return join24(home2, ".switchroom", "state", "kernel-operator", "sock");
|
|
26971
26988
|
}
|
|
26972
26989
|
function resolveKernelOperatorSocket(home2 = homedir12()) {
|
|
26973
26990
|
const p = kernelOperatorSocketPath(home2);
|
|
@@ -28051,7 +28068,7 @@ __export(exports_via_claude, {
|
|
|
28051
28068
|
});
|
|
28052
28069
|
import { execFileSync as execFileSync14, spawnSync as spawnSync2 } from "node:child_process";
|
|
28053
28070
|
import { existsSync as existsSync32, mkdirSync as mkdirSync19, readFileSync as readFileSync27 } from "node:fs";
|
|
28054
|
-
import { join as
|
|
28071
|
+
import { join as join25, resolve as resolve23 } from "node:path";
|
|
28055
28072
|
function tmuxHasSession(session) {
|
|
28056
28073
|
const r = spawnSync2("tmux", ["has-session", "-t", session], {
|
|
28057
28074
|
stdio: ["ignore", "ignore", "ignore"]
|
|
@@ -28097,7 +28114,7 @@ async function runViaClaude(opts) {
|
|
|
28097
28114
|
const poll = opts.pollMs ?? VIA_CLAUDE_DEFAULTS.pollMs;
|
|
28098
28115
|
const configDir = resolve23(opts.configDir);
|
|
28099
28116
|
mkdirSync19(configDir, { recursive: true });
|
|
28100
|
-
const credentialsPath2 =
|
|
28117
|
+
const credentialsPath2 = join25(configDir, ".credentials.json");
|
|
28101
28118
|
const capture = opts.capturePane ?? (() => tmuxCapturePane(SESSION));
|
|
28102
28119
|
const send = opts.sendKeys ?? ((keys, literal) => tmuxSendKeys(SESSION, keys, literal === true));
|
|
28103
28120
|
if (!opts.spawnClaude) {
|
|
@@ -28852,9 +28869,9 @@ var DOCUMENTS_PAGE_LIMIT = 500;
|
|
|
28852
28869
|
|
|
28853
28870
|
// src/host-control/audit-reader.ts
|
|
28854
28871
|
import { homedir as homedir21 } from "node:os";
|
|
28855
|
-
import { join as
|
|
28872
|
+
import { join as join40 } from "node:path";
|
|
28856
28873
|
function defaultAuditLogPath2(home2 = homedir21()) {
|
|
28857
|
-
return
|
|
28874
|
+
return join40(home2, ".switchroom", "host-control-audit.log");
|
|
28858
28875
|
}
|
|
28859
28876
|
function parseAuditLine2(line) {
|
|
28860
28877
|
const trimmed = line.trim();
|
|
@@ -29117,12 +29134,12 @@ import {
|
|
|
29117
29134
|
readFileSync as readFileSync47,
|
|
29118
29135
|
readdirSync as readdirSync19
|
|
29119
29136
|
} from "node:fs";
|
|
29120
|
-
import { dirname as dirname12, join as
|
|
29137
|
+
import { dirname as dirname12, join as join47 } from "node:path";
|
|
29121
29138
|
import { execSync as execSync2 } from "node:child_process";
|
|
29122
29139
|
function locateManifestPath() {
|
|
29123
29140
|
let dir = import.meta.dirname;
|
|
29124
29141
|
for (let i = 0;i < 10 && dir && dir !== "/"; i++) {
|
|
29125
|
-
const candidate =
|
|
29142
|
+
const candidate = join47(dir, "dependencies.json");
|
|
29126
29143
|
if (existsSync52(candidate))
|
|
29127
29144
|
return candidate;
|
|
29128
29145
|
dir = dirname12(dir);
|
|
@@ -29192,13 +29209,13 @@ function probeClaudeVersion() {
|
|
|
29192
29209
|
}
|
|
29193
29210
|
function probePlaywrightMcpVersion() {
|
|
29194
29211
|
const home2 = process.env.HOME ?? "";
|
|
29195
|
-
const npxCache =
|
|
29212
|
+
const npxCache = join47(home2, ".npm/_npx");
|
|
29196
29213
|
if (!existsSync52(npxCache))
|
|
29197
29214
|
return null;
|
|
29198
29215
|
try {
|
|
29199
29216
|
const entries = readdirSync19(npxCache);
|
|
29200
29217
|
for (const entry of entries) {
|
|
29201
|
-
const pkgPath =
|
|
29218
|
+
const pkgPath = join47(npxCache, entry, "node_modules/@playwright/mcp/package.json");
|
|
29202
29219
|
if (existsSync52(pkgPath)) {
|
|
29203
29220
|
try {
|
|
29204
29221
|
const pkg = JSON.parse(readFileSync47(pkgPath, "utf-8"));
|
|
@@ -29644,7 +29661,7 @@ import { existsSync as existsSync53, readFileSync as readFileSync49 } from "node
|
|
|
29644
29661
|
import { createHash as createHash10 } from "node:crypto";
|
|
29645
29662
|
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
29646
29663
|
import { homedir as homedir26 } from "node:os";
|
|
29647
|
-
import { join as
|
|
29664
|
+
import { join as join48 } from "node:path";
|
|
29648
29665
|
function defaultDockerInspect(container, format) {
|
|
29649
29666
|
try {
|
|
29650
29667
|
const r = spawnSync6("docker", ["inspect", "-f", format, container], { encoding: "utf-8", timeout: 5000 });
|
|
@@ -29744,7 +29761,7 @@ function checkAuthBrokerPerAgentSockets(config, deps = {}) {
|
|
|
29744
29761
|
}
|
|
29745
29762
|
function checkAuthBrokerDrift(deps = {}) {
|
|
29746
29763
|
const stateDir = resolveStateDir(deps);
|
|
29747
|
-
const indexPath =
|
|
29764
|
+
const indexPath = join48(stateDir, "sha-index.json");
|
|
29748
29765
|
if (!existsSync53(indexPath)) {
|
|
29749
29766
|
return {
|
|
29750
29767
|
name: "auth-broker: drift",
|
|
@@ -29805,7 +29822,7 @@ function checkAuthBrokerDrift(deps = {}) {
|
|
|
29805
29822
|
}
|
|
29806
29823
|
function checkAuthBrokerThresholdViolations(deps = {}) {
|
|
29807
29824
|
const stateDir = resolveStateDir(deps);
|
|
29808
|
-
const path4 =
|
|
29825
|
+
const path4 = join48(stateDir, "threshold-violations.json");
|
|
29809
29826
|
if (!existsSync53(path4)) {
|
|
29810
29827
|
return {
|
|
29811
29828
|
name: "auth-broker: threshold violations",
|
|
@@ -30002,7 +30019,7 @@ import {
|
|
|
30002
30019
|
statSync as statSync23
|
|
30003
30020
|
} from "node:fs";
|
|
30004
30021
|
import { userInfo, homedir as homedir27 } from "node:os";
|
|
30005
|
-
import { join as
|
|
30022
|
+
import { join as join49 } from "node:path";
|
|
30006
30023
|
function resolveVaultPath2(config) {
|
|
30007
30024
|
return config.vault?.path ? config.vault.path.replace(/^~/, process.env.HOME ?? "") : resolveStatePath("vault.enc");
|
|
30008
30025
|
}
|
|
@@ -30140,7 +30157,7 @@ async function runSecretAccessChecks(config, deps = {}) {
|
|
|
30140
30157
|
};
|
|
30141
30158
|
const passphrase = deps.passphrase ?? process.env.SWITCHROOM_VAULT_PASSPHRASE;
|
|
30142
30159
|
if (!passphrase) {
|
|
30143
|
-
const sock = deps.brokerOperatorSocket ??
|
|
30160
|
+
const sock = deps.brokerOperatorSocket ?? join49(homedir27(), ".switchroom", "broker-operator", "sock");
|
|
30144
30161
|
const preflight = deps.preflight ?? ((a, k) => defaultPreflight(sock, a, k));
|
|
30145
30162
|
for (const name of Object.keys(config.agents ?? {})) {
|
|
30146
30163
|
const resolved = resolveAgentConfig(config.defaults, config.profiles, config.agents[name]);
|
|
@@ -30225,7 +30242,7 @@ import {
|
|
|
30225
30242
|
existsSync as realExistsSync,
|
|
30226
30243
|
readFileSync as realReadFileSync
|
|
30227
30244
|
} from "node:fs";
|
|
30228
|
-
import { join as
|
|
30245
|
+
import { join as join50, resolve as resolve30 } from "node:path";
|
|
30229
30246
|
import { homedir as homedir28 } from "node:os";
|
|
30230
30247
|
function resolveDeps(config, deps) {
|
|
30231
30248
|
let agentsDir = deps.agentsDir;
|
|
@@ -30349,8 +30366,8 @@ function checkScaffoldWiring(config, driveAgents, d) {
|
|
|
30349
30366
|
});
|
|
30350
30367
|
continue;
|
|
30351
30368
|
}
|
|
30352
|
-
const mcpPath =
|
|
30353
|
-
const claudeJsonPath =
|
|
30369
|
+
const mcpPath = join50(agentDir, ".mcp.json");
|
|
30370
|
+
const claudeJsonPath = join50(agentDir, ".claude", ".claude.json");
|
|
30354
30371
|
const mcpRead = readJson(d, mcpPath);
|
|
30355
30372
|
const trustRead = readJson(d, claudeJsonPath);
|
|
30356
30373
|
if (mcpRead.kind === "unreadable" || trustRead.kind === "unreadable") {
|
|
@@ -30463,7 +30480,7 @@ async function runDriveBrokerReachabilityChecks(config, deps = {}) {
|
|
|
30463
30480
|
}
|
|
30464
30481
|
];
|
|
30465
30482
|
}
|
|
30466
|
-
const sock = deps.brokerOperatorSocket ??
|
|
30483
|
+
const sock = deps.brokerOperatorSocket ?? join50(homedir28(), ".switchroom", "broker-operator", "sock");
|
|
30467
30484
|
const preflight = deps.preflight ?? ((a, k) => defaultPreflight(sock, a, k));
|
|
30468
30485
|
const results = [];
|
|
30469
30486
|
for (const agent of driveAgents) {
|
|
@@ -30517,7 +30534,7 @@ import {
|
|
|
30517
30534
|
readSync as realReadSync,
|
|
30518
30535
|
closeSync as realCloseSync
|
|
30519
30536
|
} from "node:fs";
|
|
30520
|
-
import { join as
|
|
30537
|
+
import { join as join51 } from "node:path";
|
|
30521
30538
|
import { homedir as homedir29 } from "node:os";
|
|
30522
30539
|
function defaultReadHead(p, n) {
|
|
30523
30540
|
let fd;
|
|
@@ -30575,7 +30592,7 @@ function runWebkiteChecks(config, deps = {}) {
|
|
|
30575
30592
|
return [];
|
|
30576
30593
|
const d = resolveDeps2(config, deps);
|
|
30577
30594
|
const results = [];
|
|
30578
|
-
const binPath =
|
|
30595
|
+
const binPath = join51(d.homeDir, ".switchroom", "bin", "webkite");
|
|
30579
30596
|
if (!d.existsSync(binPath)) {
|
|
30580
30597
|
results.push({
|
|
30581
30598
|
name: "webkite: binary",
|
|
@@ -30605,12 +30622,12 @@ function runWebkiteChecks(config, deps = {}) {
|
|
|
30605
30622
|
});
|
|
30606
30623
|
}
|
|
30607
30624
|
}
|
|
30608
|
-
const cloakDir =
|
|
30625
|
+
const cloakDir = join51(d.homeDir, ".cloakbrowser");
|
|
30609
30626
|
let chromeFound = false;
|
|
30610
30627
|
if (d.existsSync(cloakDir)) {
|
|
30611
30628
|
try {
|
|
30612
30629
|
for (const entry of d.readdirSync(cloakDir)) {
|
|
30613
|
-
if (entry.startsWith("chromium-") && d.existsSync(
|
|
30630
|
+
if (entry.startsWith("chromium-") && d.existsSync(join51(cloakDir, entry, "chrome"))) {
|
|
30614
30631
|
chromeFound = true;
|
|
30615
30632
|
break;
|
|
30616
30633
|
}
|
|
@@ -30636,9 +30653,9 @@ function runWebkiteChecks(config, deps = {}) {
|
|
|
30636
30653
|
return results;
|
|
30637
30654
|
}
|
|
30638
30655
|
for (const agent of enabledAgents) {
|
|
30639
|
-
const agentDir =
|
|
30640
|
-
const settingsPath =
|
|
30641
|
-
const mcpPath =
|
|
30656
|
+
const agentDir = join51(d.agentsDir, agent);
|
|
30657
|
+
const settingsPath = join51(agentDir, ".claude", "settings.json");
|
|
30658
|
+
const mcpPath = join51(agentDir, ".mcp.json");
|
|
30642
30659
|
if (!d.existsSync(settingsPath) && !d.existsSync(mcpPath)) {
|
|
30643
30660
|
continue;
|
|
30644
30661
|
}
|
|
@@ -30702,7 +30719,7 @@ var init_doctor_webkite = __esm(() => {
|
|
|
30702
30719
|
});
|
|
30703
30720
|
|
|
30704
30721
|
// src/cli/doctor-scaffold-wiring.ts
|
|
30705
|
-
import { join as
|
|
30722
|
+
import { join as join52, resolve as resolve31 } from "node:path";
|
|
30706
30723
|
function readJson2(d, path4) {
|
|
30707
30724
|
if (!d.existsSync(path4))
|
|
30708
30725
|
return { kind: "absent" };
|
|
@@ -30745,8 +30762,8 @@ function checkIntegrationScaffoldWiring(args) {
|
|
|
30745
30762
|
});
|
|
30746
30763
|
continue;
|
|
30747
30764
|
}
|
|
30748
|
-
const mcpPath =
|
|
30749
|
-
const claudeJsonPath =
|
|
30765
|
+
const mcpPath = join52(agentDir, ".mcp.json");
|
|
30766
|
+
const claudeJsonPath = join52(agentDir, ".claude", ".claude.json");
|
|
30750
30767
|
const mcpRead = readJson2(deps, mcpPath);
|
|
30751
30768
|
const trustRead = readJson2(deps, claudeJsonPath);
|
|
30752
30769
|
if (mcpRead.kind === "unreadable" || trustRead.kind === "unreadable") {
|
|
@@ -30810,14 +30827,14 @@ import {
|
|
|
30810
30827
|
existsSync as realExistsSync3,
|
|
30811
30828
|
readFileSync as realReadFileSync3
|
|
30812
30829
|
} from "node:fs";
|
|
30813
|
-
import { join as
|
|
30830
|
+
import { join as join53 } from "node:path";
|
|
30814
30831
|
import { homedir as homedir30 } from "node:os";
|
|
30815
30832
|
function resolveDeps3(deps) {
|
|
30816
30833
|
const home2 = deps.homeDir?.() ?? homedir30();
|
|
30817
30834
|
return {
|
|
30818
30835
|
existsSync: deps.existsSync ?? realExistsSync3,
|
|
30819
30836
|
readFileSync: deps.readFileSync ?? realReadFileSync3,
|
|
30820
|
-
agentsDir:
|
|
30837
|
+
agentsDir: join53(home2, ".switchroom", "agents"),
|
|
30821
30838
|
now: deps.now ?? Date.now
|
|
30822
30839
|
};
|
|
30823
30840
|
}
|
|
@@ -30900,7 +30917,7 @@ function checkOAuthClient2(config, anyAgentEnabled) {
|
|
|
30900
30917
|
];
|
|
30901
30918
|
}
|
|
30902
30919
|
function readHeartbeat(d, agentName) {
|
|
30903
|
-
const path4 =
|
|
30920
|
+
const path4 = join53(d.agentsDir, agentName, "m365-launcher.heartbeat.json");
|
|
30904
30921
|
if (!d.existsSync(path4)) {
|
|
30905
30922
|
return { error: "heartbeat file missing \u2014 launcher has not yet started" };
|
|
30906
30923
|
}
|
|
@@ -30997,7 +31014,7 @@ import {
|
|
|
30997
31014
|
readFileSync as realReadFileSync4,
|
|
30998
31015
|
statSync as realStatSync
|
|
30999
31016
|
} from "node:fs";
|
|
31000
|
-
import { join as
|
|
31017
|
+
import { join as join54 } from "node:path";
|
|
31001
31018
|
import { homedir as homedir31 } from "node:os";
|
|
31002
31019
|
function resolveDeps4(deps) {
|
|
31003
31020
|
const home2 = deps.homeDir?.() ?? homedir31();
|
|
@@ -31005,7 +31022,7 @@ function resolveDeps4(deps) {
|
|
|
31005
31022
|
existsSync: deps.existsSync ?? realExistsSync4,
|
|
31006
31023
|
readFileSync: deps.readFileSync ?? realReadFileSync4,
|
|
31007
31024
|
statSync: deps.statSync ?? realStatSync,
|
|
31008
|
-
agentsDir:
|
|
31025
|
+
agentsDir: join54(home2, ".switchroom", "agents"),
|
|
31009
31026
|
now: deps.now ?? Date.now,
|
|
31010
31027
|
vaultAclReader: deps.vaultAclReader ?? (async () => ({ kind: "unreachable", msg: "no default reader wired" }))
|
|
31011
31028
|
};
|
|
@@ -31130,7 +31147,7 @@ function checkLauncherHeartbeat2(notionAgents, d) {
|
|
|
31130
31147
|
return [];
|
|
31131
31148
|
const results = [];
|
|
31132
31149
|
for (const name of notionAgents) {
|
|
31133
|
-
const heartbeatPath =
|
|
31150
|
+
const heartbeatPath = join54(d.agentsDir, name, "notion-launcher.heartbeat.json");
|
|
31134
31151
|
if (!d.existsSync(heartbeatPath)) {
|
|
31135
31152
|
results.push({
|
|
31136
31153
|
name: `notion:launcher-heartbeat:${name}`,
|
|
@@ -31206,9 +31223,9 @@ import {
|
|
|
31206
31223
|
statSync as realStatSync2
|
|
31207
31224
|
} from "node:fs";
|
|
31208
31225
|
import { homedir as homedir32 } from "node:os";
|
|
31209
|
-
import { join as
|
|
31226
|
+
import { join as join55 } from "node:path";
|
|
31210
31227
|
function runCredentialsMigrationChecks(config, deps = {}) {
|
|
31211
|
-
const credDir = deps.credentialsDir ??
|
|
31228
|
+
const credDir = deps.credentialsDir ?? join55(homedir32(), ".switchroom", "credentials");
|
|
31212
31229
|
const existsSync55 = deps.existsSync ?? ((p) => realExistsSync5(p));
|
|
31213
31230
|
const readdirSync21 = deps.readdirSync ?? ((p) => realReaddirSync2(p));
|
|
31214
31231
|
const isDirectory = deps.isDirectory ?? ((p) => {
|
|
@@ -31236,7 +31253,7 @@ function runCredentialsMigrationChecks(config, deps = {}) {
|
|
|
31236
31253
|
const flat = [];
|
|
31237
31254
|
const perAgentDirs = [];
|
|
31238
31255
|
for (const e of entries) {
|
|
31239
|
-
const full =
|
|
31256
|
+
const full = join55(credDir, e);
|
|
31240
31257
|
if (isDirectory(full) && agentNames.has(e)) {
|
|
31241
31258
|
perAgentDirs.push(e);
|
|
31242
31259
|
} else {
|
|
@@ -31360,13 +31377,13 @@ var init_doctor_inlined_secrets = __esm(() => {
|
|
|
31360
31377
|
// src/cli/doctor-audit-integrity.ts
|
|
31361
31378
|
import { readFileSync as fsReadFileSync2 } from "node:fs";
|
|
31362
31379
|
import { homedir as homedir33 } from "node:os";
|
|
31363
|
-
import { join as
|
|
31380
|
+
import { join as join56 } from "node:path";
|
|
31364
31381
|
function rootWrittenLogs(home2) {
|
|
31365
31382
|
return [
|
|
31366
|
-
{ label: "vault-broker", path:
|
|
31383
|
+
{ label: "vault-broker", path: join56(home2, ".switchroom", "vault-audit.log") },
|
|
31367
31384
|
{
|
|
31368
31385
|
label: "hostd",
|
|
31369
|
-
path:
|
|
31386
|
+
path: join56(home2, ".switchroom", "host-control-audit.log")
|
|
31370
31387
|
}
|
|
31371
31388
|
];
|
|
31372
31389
|
}
|
|
@@ -31430,13 +31447,13 @@ var init_doctor_audit_integrity = __esm(() => {
|
|
|
31430
31447
|
// src/cli/doctor-agent-smoke.ts
|
|
31431
31448
|
import { existsSync as existsSync55 } from "node:fs";
|
|
31432
31449
|
import { homedir as homedir34 } from "node:os";
|
|
31433
|
-
import { join as
|
|
31450
|
+
import { join as join57 } from "node:path";
|
|
31434
31451
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
31435
31452
|
async function runAgentSmokeChecks(config, deps = {}) {
|
|
31436
31453
|
if (deps.fast)
|
|
31437
31454
|
return [];
|
|
31438
31455
|
const home2 = deps.homeDir ?? homedir34();
|
|
31439
|
-
const sock = deps.operatorSockPath ??
|
|
31456
|
+
const sock = deps.operatorSockPath ?? join57(home2, ".switchroom", "hostd", "operator", "sock");
|
|
31440
31457
|
if (!deps.hostdRequestImpl && !existsSync55(sock)) {
|
|
31441
31458
|
return [
|
|
31442
31459
|
{
|
|
@@ -31517,7 +31534,7 @@ var init_doctor_agent_smoke = __esm(() => {
|
|
|
31517
31534
|
import { execFileSync as execFileSync18 } from "node:child_process";
|
|
31518
31535
|
import { existsSync as existsSync56, statSync as statSync24 } from "node:fs";
|
|
31519
31536
|
import { homedir as homedir35 } from "node:os";
|
|
31520
|
-
import { join as
|
|
31537
|
+
import { join as join58 } from "node:path";
|
|
31521
31538
|
function probeBindMountInode(hostPath, brokerContainerPath, opts) {
|
|
31522
31539
|
const statHost = opts?.statHost ?? defaultStatHost;
|
|
31523
31540
|
const statBroker = opts?.statBroker ?? defaultStatBroker;
|
|
@@ -31666,16 +31683,16 @@ function runVaultBrokerDurabilityChecks(_config, opts) {
|
|
|
31666
31683
|
probeBrokerUnlocked(opts?.statusProbe),
|
|
31667
31684
|
probeAutoUnlockBlob(home2),
|
|
31668
31685
|
probeMachineIdMount(),
|
|
31669
|
-
formatBindMountResult("vault-broker: vault.enc bind mount",
|
|
31670
|
-
formatBindMountResult("vault-broker: vault-grants.db bind mount (#1737)",
|
|
31671
|
-
formatBindMountResult("vault-broker: vault-audit.log bind mount (#1025)",
|
|
31686
|
+
formatBindMountResult("vault-broker: vault.enc bind mount", join58(home2, ".switchroom", "vault", "vault.enc"), "/state/vault/vault.enc", probe2(join58(home2, ".switchroom", "vault", "vault.enc"), "/state/vault/vault.enc")),
|
|
31687
|
+
formatBindMountResult("vault-broker: vault-grants.db bind mount (#1737)", join58(home2, ".switchroom", "vault-grants.db"), "/root/.switchroom/vault-grants.db", probe2(join58(home2, ".switchroom", "vault-grants.db"), "/root/.switchroom/vault-grants.db")),
|
|
31688
|
+
formatBindMountResult("vault-broker: vault-audit.log bind mount (#1025)", join58(home2, ".switchroom", "vault-audit.log"), "/root/.switchroom/vault-audit.log", probe2(join58(home2, ".switchroom", "vault-audit.log"), "/root/.switchroom/vault-audit.log")),
|
|
31672
31689
|
probeKernelDbDurability(home2, {
|
|
31673
31690
|
statBroker: opts?.kernelStatBroker
|
|
31674
31691
|
})
|
|
31675
31692
|
];
|
|
31676
31693
|
}
|
|
31677
31694
|
function probeKernelDbDurability(home2, opts) {
|
|
31678
|
-
const hostDir =
|
|
31695
|
+
const hostDir = join58(home2, ".switchroom", "approvals");
|
|
31679
31696
|
const containerDir = "/state/approvals";
|
|
31680
31697
|
const name = "approval-kernel: approvals bind mount (allow_always durability)";
|
|
31681
31698
|
const kernelStat = opts?.statBroker ?? defaultKernelStatBroker;
|
|
@@ -31743,7 +31760,7 @@ function defaultKernelStatBroker(p) {
|
|
|
31743
31760
|
return { kind: "ok-with-stat", ino: inoStr, size };
|
|
31744
31761
|
}
|
|
31745
31762
|
function probeAutoUnlockBlob(home2) {
|
|
31746
|
-
const blobPath =
|
|
31763
|
+
const blobPath = join58(home2, ".switchroom", "vault-auto-unlock");
|
|
31747
31764
|
if (!existsSync56(blobPath)) {
|
|
31748
31765
|
return {
|
|
31749
31766
|
name: "vault-broker: auto-unlock blob",
|
|
@@ -31855,16 +31872,16 @@ import {
|
|
|
31855
31872
|
readdirSync as readdirSync21,
|
|
31856
31873
|
statSync as statSync25
|
|
31857
31874
|
} from "node:fs";
|
|
31858
|
-
import { dirname as dirname13, join as
|
|
31875
|
+
import { dirname as dirname13, join as join59, resolve as resolve32 } from "node:path";
|
|
31859
31876
|
import { createPublicKey, createPrivateKey } from "node:crypto";
|
|
31860
31877
|
function findInNvm(bin) {
|
|
31861
|
-
const nvmRoot =
|
|
31878
|
+
const nvmRoot = join59(process.env.HOME ?? "", ".nvm", "versions", "node");
|
|
31862
31879
|
if (!existsSync57(nvmRoot))
|
|
31863
31880
|
return null;
|
|
31864
31881
|
try {
|
|
31865
31882
|
const versions = readdirSync21(nvmRoot).sort().reverse();
|
|
31866
31883
|
for (const v of versions) {
|
|
31867
|
-
const candidate =
|
|
31884
|
+
const candidate = join59(nvmRoot, v, "bin", bin);
|
|
31868
31885
|
try {
|
|
31869
31886
|
const s = statSync25(candidate);
|
|
31870
31887
|
if (s.isFile() || s.isSymbolicLink()) {
|
|
@@ -32029,7 +32046,7 @@ function findChromium(homeDir = process.env.HOME ?? "", envBrowsersPath = proces
|
|
|
32029
32046
|
if (envBrowsersPath && envBrowsersPath.length > 0) {
|
|
32030
32047
|
cacheLocations.push(envBrowsersPath);
|
|
32031
32048
|
}
|
|
32032
|
-
cacheLocations.push(
|
|
32049
|
+
cacheLocations.push(join59(homeDir, ".cache", "ms-playwright"));
|
|
32033
32050
|
for (const cacheDir of cacheLocations) {
|
|
32034
32051
|
if (!existsSync57(cacheDir))
|
|
32035
32052
|
continue;
|
|
@@ -32037,10 +32054,10 @@ function findChromium(homeDir = process.env.HOME ?? "", envBrowsersPath = proces
|
|
|
32037
32054
|
const entries = readdirSync21(cacheDir).filter((e) => e.startsWith("chromium"));
|
|
32038
32055
|
for (const entry of entries) {
|
|
32039
32056
|
const candidates2 = [
|
|
32040
|
-
|
|
32041
|
-
|
|
32042
|
-
|
|
32043
|
-
|
|
32057
|
+
join59(cacheDir, entry, "chrome-linux64", "chrome"),
|
|
32058
|
+
join59(cacheDir, entry, "chrome-linux", "chrome"),
|
|
32059
|
+
join59(cacheDir, entry, "chrome-linux64", "headless_shell"),
|
|
32060
|
+
join59(cacheDir, entry, "chrome-linux", "headless_shell")
|
|
32044
32061
|
];
|
|
32045
32062
|
for (const path4 of candidates2) {
|
|
32046
32063
|
if (existsSync57(path4))
|
|
@@ -32163,7 +32180,7 @@ function checkUserDeclaredMcps(name, agentConfig, config, renderedMcpServers) {
|
|
|
32163
32180
|
function checkLegacyState() {
|
|
32164
32181
|
const results = [];
|
|
32165
32182
|
const h = process.env.HOME ?? "/root";
|
|
32166
|
-
const clerkDir =
|
|
32183
|
+
const clerkDir = join59(h, LEGACY_STATE_DIR);
|
|
32167
32184
|
const clerkPresent = existsSync57(clerkDir);
|
|
32168
32185
|
results.push({
|
|
32169
32186
|
name: "legacy ~/.clerk state",
|
|
@@ -32173,7 +32190,7 @@ function checkLegacyState() {
|
|
|
32173
32190
|
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."
|
|
32174
32191
|
} : {}
|
|
32175
32192
|
});
|
|
32176
|
-
const legacySock =
|
|
32193
|
+
const legacySock = join59(h, ".switchroom", "vault-broker.sock");
|
|
32177
32194
|
let sockStat = null;
|
|
32178
32195
|
try {
|
|
32179
32196
|
sockStat = lstatSync6(legacySock);
|
|
@@ -32551,7 +32568,7 @@ async function checkHindsight(config) {
|
|
|
32551
32568
|
}
|
|
32552
32569
|
function checkPendingRetainsQueue(dir) {
|
|
32553
32570
|
const home2 = process.env.HOME ?? "";
|
|
32554
|
-
const pendingDir = dir ?? process.env.HINDSIGHT_PENDING_DIR ??
|
|
32571
|
+
const pendingDir = dir ?? process.env.HINDSIGHT_PENDING_DIR ?? join59(home2, ".hindsight", "pending-retains");
|
|
32555
32572
|
if (!existsSync57(pendingDir)) {
|
|
32556
32573
|
return {
|
|
32557
32574
|
name: "pending-retains queue",
|
|
@@ -32682,7 +32699,7 @@ async function checkTelegram(config) {
|
|
|
32682
32699
|
const plugin = agentConfig.channels?.telegram?.plugin ?? "switchroom";
|
|
32683
32700
|
if (plugin !== "switchroom")
|
|
32684
32701
|
continue;
|
|
32685
|
-
const envPath =
|
|
32702
|
+
const envPath = join59(agentsDir, name, "telegram", ".env");
|
|
32686
32703
|
const read = tryReadHostFile(envPath);
|
|
32687
32704
|
if (read.kind === "eacces") {
|
|
32688
32705
|
results.push({
|
|
@@ -32765,7 +32782,7 @@ function checkStartShStale(agentName, startShPath) {
|
|
|
32765
32782
|
}
|
|
32766
32783
|
function checkLeakedHomeSwitchroom(agentName, agentDir) {
|
|
32767
32784
|
const label = `${agentName}: $HOME/.switchroom symlink (#910)`;
|
|
32768
|
-
const path4 =
|
|
32785
|
+
const path4 = join59(agentDir, "home", ".switchroom");
|
|
32769
32786
|
let stats;
|
|
32770
32787
|
try {
|
|
32771
32788
|
stats = lstatSync6(path4);
|
|
@@ -32802,7 +32819,7 @@ function checkLeakedHomeSwitchroom(agentName, agentDir) {
|
|
|
32802
32819
|
}
|
|
32803
32820
|
function checkRepoHygiene(repoRoot) {
|
|
32804
32821
|
const results = [];
|
|
32805
|
-
const exportDir =
|
|
32822
|
+
const exportDir = join59(repoRoot, "clerk-export");
|
|
32806
32823
|
if (existsSync57(exportDir)) {
|
|
32807
32824
|
results.push({
|
|
32808
32825
|
name: "repo hygiene: clerk-export/ on disk (#1072)",
|
|
@@ -32811,7 +32828,7 @@ function checkRepoHygiene(repoRoot) {
|
|
|
32811
32828
|
fix: `Run scripts/migrate-clerk-export-to-vault.sh to move the bundle ` + `into the vault, then delete the on-disk copy.`
|
|
32812
32829
|
});
|
|
32813
32830
|
}
|
|
32814
|
-
const knownTarball =
|
|
32831
|
+
const knownTarball = join59(repoRoot, "clerk-export-with-secrets.tar.gz");
|
|
32815
32832
|
if (existsSync57(knownTarball)) {
|
|
32816
32833
|
results.push({
|
|
32817
32834
|
name: "repo hygiene: clerk-export-with-secrets.tar.gz on disk (#1072)",
|
|
@@ -32829,7 +32846,7 @@ function checkRepoHygiene(repoRoot) {
|
|
|
32829
32846
|
results.push({
|
|
32830
32847
|
name: `repo hygiene: ${name} on disk (#1072)`,
|
|
32831
32848
|
status: "warn",
|
|
32832
|
-
detail: `${
|
|
32849
|
+
detail: `${join59(repoRoot, name)} matches the *-with-secrets*.tar.gz ` + `pattern. Likely contains real credentials.`,
|
|
32833
32850
|
fix: `Inspect, migrate any secrets into the vault, then delete the ` + `archive.`
|
|
32834
32851
|
});
|
|
32835
32852
|
}
|
|
@@ -32852,9 +32869,9 @@ function checkRepoHygiene(repoRoot) {
|
|
|
32852
32869
|
}
|
|
32853
32870
|
function isSwitchroomCheckout(dir) {
|
|
32854
32871
|
try {
|
|
32855
|
-
if (!existsSync57(
|
|
32872
|
+
if (!existsSync57(join59(dir, ".git")))
|
|
32856
32873
|
return false;
|
|
32857
|
-
const pkgPath =
|
|
32874
|
+
const pkgPath = join59(dir, "package.json");
|
|
32858
32875
|
if (!existsSync57(pkgPath))
|
|
32859
32876
|
return false;
|
|
32860
32877
|
const pkg = JSON.parse(readFileSync50(pkgPath, "utf-8"));
|
|
@@ -32891,7 +32908,7 @@ function checkAgents(config, configPath) {
|
|
|
32891
32908
|
fix: `Rotate the bot token (e.g. via \`switchroom vault\`), then run ` + `\`switchroom agent unquarantine ${name}\` and \`switchroom agent restart ${name}\``
|
|
32892
32909
|
});
|
|
32893
32910
|
}
|
|
32894
|
-
results.push(checkStartShStale(name,
|
|
32911
|
+
results.push(checkStartShStale(name, join59(agentDir, "start.sh")));
|
|
32895
32912
|
results.push(checkLeakedHomeSwitchroom(name, agentDir));
|
|
32896
32913
|
const status = statuses[name];
|
|
32897
32914
|
const active = status?.active ?? "unknown";
|
|
@@ -32968,7 +32985,7 @@ function checkAgents(config, configPath) {
|
|
|
32968
32985
|
}
|
|
32969
32986
|
}
|
|
32970
32987
|
if (agentConfig.channels?.telegram?.plugin === "switchroom") {
|
|
32971
|
-
const mcpJsonPath =
|
|
32988
|
+
const mcpJsonPath = join59(agentDir, ".mcp.json");
|
|
32972
32989
|
if (!existsSync57(mcpJsonPath)) {
|
|
32973
32990
|
results.push({
|
|
32974
32991
|
name: `${name}: .mcp.json`,
|
|
@@ -33270,7 +33287,7 @@ async function checkMffAuthFlow(envPath = mffEnvPath(), timeoutMs = 8000) {
|
|
|
33270
33287
|
};
|
|
33271
33288
|
}
|
|
33272
33289
|
const credDir = dirname13(envPath);
|
|
33273
|
-
const authScript =
|
|
33290
|
+
const authScript = join59(credDir, "claude-auth.py");
|
|
33274
33291
|
if (!existsSync57(authScript)) {
|
|
33275
33292
|
return {
|
|
33276
33293
|
name: "mff: auth flow",
|
|
@@ -50182,12 +50199,12 @@ var {
|
|
|
50182
50199
|
} = import__.default;
|
|
50183
50200
|
|
|
50184
50201
|
// src/build-info.ts
|
|
50185
|
-
var VERSION = "0.15.
|
|
50186
|
-
var COMMIT_SHA = "
|
|
50202
|
+
var VERSION = "0.15.5";
|
|
50203
|
+
var COMMIT_SHA = "fcc9d7b7";
|
|
50187
50204
|
|
|
50188
50205
|
// src/cli/agent.ts
|
|
50189
50206
|
init_source();
|
|
50190
|
-
import { join as
|
|
50207
|
+
import { join as join20, resolve as resolve21 } from "node:path";
|
|
50191
50208
|
import { rmSync as rmSync9, existsSync as existsSync28, readFileSync as readFileSync23, writeFileSync as writeFileSync13 } from "node:fs";
|
|
50192
50209
|
import { homedir as homedir8 } from "node:os";
|
|
50193
50210
|
|
|
@@ -52922,8 +52939,6 @@ function classifyChange(path, agentDir, useHotReloadStable) {
|
|
|
52922
52939
|
return "hot";
|
|
52923
52940
|
if (relPath.startsWith("workspace/memory/") && relPath.endsWith(".md"))
|
|
52924
52941
|
return "hot";
|
|
52925
|
-
if (relPath === "workspace/HEARTBEAT.md")
|
|
52926
|
-
return "hot";
|
|
52927
52942
|
if (relPath === "workspace/SOUL.md" || relPath === "workspace/SOUL.custom.md") {
|
|
52928
52943
|
return useHotReloadStable ? "hot" : "restart-required";
|
|
52929
52944
|
}
|
|
@@ -53116,6 +53131,7 @@ function buildSettingsHooksBlock(p) {
|
|
|
53116
53131
|
}
|
|
53117
53132
|
] : [];
|
|
53118
53133
|
const useHotReloadStable = agentConfig.channels?.telegram?.hotReloadStable === true;
|
|
53134
|
+
const useInjectOnChange = agentConfig.channels?.telegram?.inject_on_change !== false;
|
|
53119
53135
|
const turnPacingDirective = "<turn-pacing>You are messaging a human via Telegram. The framework " + "automatically shows the user a live preview in their compose area as " + 'you work \u2014 they see "Read a file", "Ran 2 commands", etc. as your ' + `tool_use events stream. You do NOT need to ack manually.
|
|
53120
53136
|
|
|
53121
53137
|
` + "ALWAYS reply to a message the user sends you. A direct message " + 'expects a response: a greeting ("hi", "hey", "you there?") gets a ' + "greeting back; a thanks gets a brief acknowledgement; a question " + "gets an answer. NEVER end a turn with NO_REPLY when the user has " + "just sent you something \u2014 NO_REPLY is only for genuine non-prompts " + `(a system-synthesized event you have already fully handled).
|
|
@@ -53150,7 +53166,7 @@ function buildSettingsHooksBlock(p) {
|
|
|
53150
53166
|
hooks: [
|
|
53151
53167
|
{
|
|
53152
53168
|
type: "command",
|
|
53153
|
-
command: wrap("hook:workspace-dynamic", `bash "${join9(DOCKER_BIN_PATH, "workspace-dynamic-hook.sh")}"`),
|
|
53169
|
+
command: wrap("hook:workspace-dynamic", `${useInjectOnChange ? `env SWITCHROOM_INJECT_ON_CHANGE=1 ` : ""}bash "${join9(DOCKER_BIN_PATH, "workspace-dynamic-hook.sh")}"`),
|
|
53154
53170
|
timeout: 5
|
|
53155
53171
|
}
|
|
53156
53172
|
]
|
|
@@ -53168,7 +53184,10 @@ function buildSettingsHooksBlock(p) {
|
|
|
53168
53184
|
hooks: [
|
|
53169
53185
|
{
|
|
53170
53186
|
type: "command",
|
|
53171
|
-
command:
|
|
53187
|
+
command: useInjectOnChange ? (() => {
|
|
53188
|
+
const directiveHash = createHash2("sha256").update(turnPacingDirective).digest("hex");
|
|
53189
|
+
return wrap("hook:turn-pacing", `env TURN_PACING_DIRECTIVE=${shellSingleQuote(turnPacingDirective)} TURN_PACING_HASH=${shellSingleQuote(directiveHash)} bash "${join9(DOCKER_BIN_PATH, "turn-pacing-hook.sh")}"`);
|
|
53190
|
+
})() : wrap("hook:turn-pacing", `printf '%s\\n' ${shellSingleQuote(turnPacingDirective)}`),
|
|
53172
53191
|
timeout: 3
|
|
53173
53192
|
}
|
|
53174
53193
|
]
|
|
@@ -53984,7 +54003,7 @@ init_compose();
|
|
|
53984
54003
|
import { chownSync as chownSync2 } from "node:fs";
|
|
53985
54004
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
53986
54005
|
import { homedir as homedir6 } from "node:os";
|
|
53987
|
-
import { dirname as dirname3 } from "node:path";
|
|
54006
|
+
import { basename as basename3, dirname as dirname3, join as join12 } from "node:path";
|
|
53988
54007
|
|
|
53989
54008
|
// src/config/release-resolve.ts
|
|
53990
54009
|
function resolveImageTag(release) {
|
|
@@ -54005,7 +54024,6 @@ function resolveRelease(opts) {
|
|
|
54005
54024
|
return opts.root;
|
|
54006
54025
|
return;
|
|
54007
54026
|
}
|
|
54008
|
-
|
|
54009
54027
|
// src/cli/operator-uid.ts
|
|
54010
54028
|
import {
|
|
54011
54029
|
chownSync,
|
|
@@ -54098,17 +54116,36 @@ function restoreOperatorOwnership(home2, operatorUid, deps = {}) {
|
|
|
54098
54116
|
|
|
54099
54117
|
// src/cli/write-compose.ts
|
|
54100
54118
|
var AGENT_IMAGE_TAG_RE = /image:\s*\S*switchroom-agent:(\S+)/;
|
|
54119
|
+
var CONTAINER_CONFIG_PREFIX = "/state/config/";
|
|
54120
|
+
function resolveHostSwitchroomConfigPath(rawPath) {
|
|
54121
|
+
if (!isDockerRuntime()) {
|
|
54122
|
+
return rawPath;
|
|
54123
|
+
}
|
|
54124
|
+
if (!rawPath.startsWith(CONTAINER_CONFIG_PREFIX)) {
|
|
54125
|
+
return rawPath;
|
|
54126
|
+
}
|
|
54127
|
+
const hostHome = process.env.SWITCHROOM_HOST_HOME;
|
|
54128
|
+
if (!hostHome || hostHome.length === 0) {
|
|
54129
|
+
throw new Error(`switchroom apply: running inside a container but SWITCHROOM_HOST_HOME is not set.
|
|
54130
|
+
` + `The config path "${rawPath}" is a container-internal path \u2014 emitting it as a ` + `Docker bind-mount source would cause Docker to create an empty directory at that ` + `path on the host, crashing the vault-broker and auth-broker with EISDIR.
|
|
54131
|
+
|
|
54132
|
+
` + `Recovery: run \`switchroom apply\` once from the HOST (not from inside the container). ` + `That will regenerate the compose file with SWITCHROOM_HOST_HOME set, after which ` + `in-container apply will work correctly.`);
|
|
54133
|
+
}
|
|
54134
|
+
const filename = basename3(rawPath);
|
|
54135
|
+
return join12(hostHome, ".switchroom", filename);
|
|
54136
|
+
}
|
|
54101
54137
|
async function writeComposeFile(opts) {
|
|
54102
54138
|
const release = resolveRelease({ override: opts.releaseOverride, root: opts.config.release });
|
|
54103
54139
|
const imageTag = resolveImageTag(release);
|
|
54104
54140
|
const operatorUid = resolveOperatorUid();
|
|
54141
|
+
const resolvedConfigPath = opts.switchroomConfigPath !== undefined ? resolveHostSwitchroomConfigPath(opts.switchroomConfigPath) : undefined;
|
|
54105
54142
|
const content = generateCompose({
|
|
54106
54143
|
config: opts.config,
|
|
54107
54144
|
imageTag,
|
|
54108
54145
|
buildMode: opts.buildMode ?? "pull",
|
|
54109
54146
|
buildContext: opts.buildContext,
|
|
54110
|
-
homeDir: homedir6(),
|
|
54111
|
-
switchroomConfigPath:
|
|
54147
|
+
homeDir: process.env.SWITCHROOM_HOST_HOME || homedir6(),
|
|
54148
|
+
switchroomConfigPath: resolvedConfigPath,
|
|
54112
54149
|
operatorUid
|
|
54113
54150
|
});
|
|
54114
54151
|
let previous = null;
|
|
@@ -54360,12 +54397,12 @@ function spinner(message) {
|
|
|
54360
54397
|
|
|
54361
54398
|
// src/agents/status.ts
|
|
54362
54399
|
import { existsSync as existsSync20, readFileSync as readFileSync18, statSync as statSync11 } from "node:fs";
|
|
54363
|
-
import { join as
|
|
54400
|
+
import { join as join15 } from "node:path";
|
|
54364
54401
|
import { execFileSync as execFileSync9 } from "node:child_process";
|
|
54365
54402
|
|
|
54366
54403
|
// src/agents/handoff-summarizer.ts
|
|
54367
54404
|
import { readFileSync as readFileSync16, writeFileSync as writeFileSync8, renameSync as renameSync5, mkdirSync as mkdirSync14, existsSync as existsSync18, statSync as statSync10, readdirSync as readdirSync9 } from "node:fs";
|
|
54368
|
-
import { join as
|
|
54405
|
+
import { join as join14 } from "node:path";
|
|
54369
54406
|
var DEFAULT_MAX_TURNS = 50;
|
|
54370
54407
|
var TOPIC_MAX_CHARS = 117;
|
|
54371
54408
|
var TURN_TEXT_MAX_CHARS = 1200;
|
|
@@ -54500,8 +54537,8 @@ function clampTopic(s) {
|
|
|
54500
54537
|
}
|
|
54501
54538
|
function writeSidecarsAtomic(agentDir, briefing, topic) {
|
|
54502
54539
|
mkdirSync14(agentDir, { recursive: true });
|
|
54503
|
-
const handoffPath =
|
|
54504
|
-
const topicPath =
|
|
54540
|
+
const handoffPath = join14(agentDir, ".handoff.md");
|
|
54541
|
+
const topicPath = join14(agentDir, ".handoff-topic");
|
|
54505
54542
|
const handoffTmp = handoffPath + ".tmp";
|
|
54506
54543
|
const topicTmp = topicPath + ".tmp";
|
|
54507
54544
|
writeFileSync8(handoffTmp, briefing, "utf-8");
|
|
@@ -54562,7 +54599,7 @@ async function mirrorToHindsight(briefing, opts) {
|
|
|
54562
54599
|
}
|
|
54563
54600
|
}
|
|
54564
54601
|
function findLatestSessionJsonl(claudeConfigDir) {
|
|
54565
|
-
const projects =
|
|
54602
|
+
const projects = join14(claudeConfigDir, "projects");
|
|
54566
54603
|
if (!existsSync18(projects))
|
|
54567
54604
|
return null;
|
|
54568
54605
|
let latest = null;
|
|
@@ -54574,7 +54611,7 @@ function findLatestSessionJsonl(claudeConfigDir) {
|
|
|
54574
54611
|
return;
|
|
54575
54612
|
}
|
|
54576
54613
|
for (const name of entries) {
|
|
54577
|
-
const full =
|
|
54614
|
+
const full = join14(dir, name);
|
|
54578
54615
|
let st;
|
|
54579
54616
|
try {
|
|
54580
54617
|
st = statSync10(full);
|
|
@@ -54910,10 +54947,10 @@ async function buildAgentStatusReport(inputs) {
|
|
|
54910
54947
|
};
|
|
54911
54948
|
}
|
|
54912
54949
|
}
|
|
54913
|
-
const logPath =
|
|
54950
|
+
const logPath = join15(inputs.agentDir, "telegram", "gateway.log");
|
|
54914
54951
|
const logContent = inputs.readGatewayLog(logPath);
|
|
54915
54952
|
const polling = buildPollingStatus(logContent);
|
|
54916
|
-
const historyDbPath =
|
|
54953
|
+
const historyDbPath = join15(inputs.agentDir, "telegram", "history.db");
|
|
54917
54954
|
const messagesResult = inputs.getLastMessages(historyDbPath);
|
|
54918
54955
|
const messages = buildMessageStatus(messagesResult);
|
|
54919
54956
|
const checks = [
|
|
@@ -55191,7 +55228,7 @@ function defaultStatusInputs(params) {
|
|
|
55191
55228
|
}
|
|
55192
55229
|
function readCacheTelemetry(agentDir) {
|
|
55193
55230
|
try {
|
|
55194
|
-
const claudeConfigDir =
|
|
55231
|
+
const claudeConfigDir = join15(agentDir, ".claude");
|
|
55195
55232
|
const jsonl = findLatestSessionJsonl(claudeConfigDir);
|
|
55196
55233
|
if (!jsonl)
|
|
55197
55234
|
return null;
|
|
@@ -55431,7 +55468,7 @@ async function completeCreation(name, code, opts = {}) {
|
|
|
55431
55468
|
}
|
|
55432
55469
|
|
|
55433
55470
|
// src/agents/add-orchestrator.ts
|
|
55434
|
-
import { resolve as resolve18, join as
|
|
55471
|
+
import { resolve as resolve18, join as join18 } from "node:path";
|
|
55435
55472
|
import { existsSync as existsSync25, rmSync as rmSync7, statSync as statSync15 } from "node:fs";
|
|
55436
55473
|
import { execFileSync as execFileSync12 } from "node:child_process";
|
|
55437
55474
|
|
|
@@ -55985,7 +56022,7 @@ function pruneBundledSkills(agentDir, keep, scope) {
|
|
|
55985
56022
|
for (const entry of scopeSet) {
|
|
55986
56023
|
if (keepSet.has(entry))
|
|
55987
56024
|
continue;
|
|
55988
|
-
const entryPath =
|
|
56025
|
+
const entryPath = join18(skillsDir, entry);
|
|
55989
56026
|
if (!existsSync25(entryPath))
|
|
55990
56027
|
continue;
|
|
55991
56028
|
let isDir = false;
|
|
@@ -56706,7 +56743,7 @@ function registerAgentCommand(program3) {
|
|
|
56706
56743
|
}
|
|
56707
56744
|
return;
|
|
56708
56745
|
}
|
|
56709
|
-
const logsDir =
|
|
56746
|
+
const logsDir = join20(homedir8(), ".switchroom", "logs");
|
|
56710
56747
|
const schedulerStates = Object.fromEntries(agentNames.map((n) => [n, getSchedulerState(n, logsDir)]));
|
|
56711
56748
|
if (opts.json) {
|
|
56712
56749
|
const data = agentNames.map((name) => {
|
|
@@ -57746,7 +57783,7 @@ init_lifecycle();
|
|
|
57746
57783
|
import { execFile as execFile2 } from "node:child_process";
|
|
57747
57784
|
import { promisify as promisify2 } from "node:util";
|
|
57748
57785
|
import { homedir as homedir10 } from "node:os";
|
|
57749
|
-
import { join as
|
|
57786
|
+
import { join as join22 } from "node:path";
|
|
57750
57787
|
init_helpers();
|
|
57751
57788
|
init_broker_call();
|
|
57752
57789
|
var execFileP = promisify2(execFile2);
|
|
@@ -57818,7 +57855,7 @@ function registerStatusCommand(program3) {
|
|
|
57818
57855
|
const config = getConfig(program3);
|
|
57819
57856
|
const agentNames = Object.keys(config.agents ?? {}).sort();
|
|
57820
57857
|
const statuses = getAllAgentStatuses(config);
|
|
57821
|
-
const logsDir =
|
|
57858
|
+
const logsDir = join22(homedir10(), ".switchroom", "logs");
|
|
57822
57859
|
const schedulerStates = Object.fromEntries(agentNames.map((n) => [n, getSchedulerState(n, logsDir)]));
|
|
57823
57860
|
const accountsP = fetchAccounts();
|
|
57824
57861
|
const mcpEnabled = opts.mcp !== false;
|
|
@@ -58228,7 +58265,7 @@ init_loader();
|
|
|
58228
58265
|
init_manager();
|
|
58229
58266
|
init_helpers();
|
|
58230
58267
|
import { existsSync as existsSync33, readFileSync as readFileSync28 } from "node:fs";
|
|
58231
|
-
import { join as
|
|
58268
|
+
import { join as join26, resolve as resolve24 } from "node:path";
|
|
58232
58269
|
|
|
58233
58270
|
// src/cli/auth-google.ts
|
|
58234
58271
|
init_source();
|
|
@@ -59753,8 +59790,8 @@ var SEVERITY_RANK = {
|
|
|
59753
59790
|
};
|
|
59754
59791
|
function diagnoseAuthState(claudeConfigDir) {
|
|
59755
59792
|
const findings = [];
|
|
59756
|
-
const credsPath =
|
|
59757
|
-
const oauthTokenPath2 =
|
|
59793
|
+
const credsPath = join26(claudeConfigDir, ".credentials.json");
|
|
59794
|
+
const oauthTokenPath2 = join26(claudeConfigDir, ".oauth-token");
|
|
59758
59795
|
const hasCreds = existsSync33(credsPath);
|
|
59759
59796
|
const hasOauthToken = existsSync33(oauthTokenPath2);
|
|
59760
59797
|
if (!hasCreds && !hasOauthToken) {
|
|
@@ -59939,7 +59976,7 @@ function loadCredentialsFromAgent(agentName) {
|
|
|
59939
59976
|
const config = getConfigSafe();
|
|
59940
59977
|
const agentsDir = resolveAgentsDir(config);
|
|
59941
59978
|
const agentDir = resolve24(agentsDir, agentName);
|
|
59942
|
-
const credsPath =
|
|
59979
|
+
const credsPath = join26(agentDir, ".claude", ".credentials.json");
|
|
59943
59980
|
if (!existsSync33(credsPath)) {
|
|
59944
59981
|
console.error(source_default.red(` Agent "${agentName}" has no .claude/.credentials.json \u2014 log it in first.`));
|
|
59945
59982
|
process.exit(1);
|
|
@@ -60002,7 +60039,7 @@ async function loadCredentialsViaClaude(label) {
|
|
|
60002
60039
|
import("node:os"),
|
|
60003
60040
|
import("node:readline")
|
|
60004
60041
|
]);
|
|
60005
|
-
const configDir =
|
|
60042
|
+
const configDir = join26(homedir13(), ".switchroom", "accounts", label);
|
|
60006
60043
|
const result = await runViaClaude2({
|
|
60007
60044
|
configDir,
|
|
60008
60045
|
promptForCode: async (_url) => {
|
|
@@ -60044,7 +60081,7 @@ function registerAuthCommand(program3) {
|
|
|
60044
60081
|
await withConfigError(async () => {
|
|
60045
60082
|
const config = getConfig(program3);
|
|
60046
60083
|
const agentsDir = resolveAgentsDir(config);
|
|
60047
|
-
configDir =
|
|
60084
|
+
configDir = join26(agentsDir, agent, ".claude");
|
|
60048
60085
|
})();
|
|
60049
60086
|
}
|
|
60050
60087
|
const diag = diagnoseAuthState(configDir);
|
|
@@ -60203,7 +60240,7 @@ function registerAuthCommand(program3) {
|
|
|
60203
60240
|
}));
|
|
60204
60241
|
auth.command("reauth <agent>").description("Start/resume an OAuth re-auth session for an agent; prints the login URL").option("--slot <label>", "Target a specific account slot/label instead of the agent's active one").option("--force", "Kill any existing session and force a fresh login (use to switch accounts)").action(withConfigError(async (agent, opts) => {
|
|
60205
60242
|
const config = getConfig(program3);
|
|
60206
|
-
const agentDir =
|
|
60243
|
+
const agentDir = join26(resolveAgentsDir(config), agent);
|
|
60207
60244
|
const r = startAuthSession(agent, agentDir, {
|
|
60208
60245
|
force: opts.force,
|
|
60209
60246
|
slot: opts.slot
|
|
@@ -60216,7 +60253,7 @@ function registerAuthCommand(program3) {
|
|
|
60216
60253
|
}));
|
|
60217
60254
|
auth.command("code <agent> <code>").description("Submit the browser OAuth code to complete a pending `auth reauth`").option("--slot <label>", "Target a specific account slot/label").option("--json", "Emit the structured AuthCodeResult as JSON (consumed by the Telegram gateway)").action(withConfigError(async (agent, code, opts) => {
|
|
60218
60255
|
const config = getConfig(program3);
|
|
60219
|
-
const agentDir =
|
|
60256
|
+
const agentDir = join26(resolveAgentsDir(config), agent);
|
|
60220
60257
|
const r = submitAuthCode(agent, agentDir, code, opts.slot);
|
|
60221
60258
|
if (opts.json) {
|
|
60222
60259
|
console.log(JSON.stringify({
|
|
@@ -60233,7 +60270,7 @@ function registerAuthCommand(program3) {
|
|
|
60233
60270
|
}));
|
|
60234
60271
|
auth.command("cancel <agent>").description("Cancel a pending `auth reauth` session for an agent").option("--slot <label>", "Target a specific account slot/label").action(withConfigError(async (agent, opts) => {
|
|
60235
60272
|
const config = getConfig(program3);
|
|
60236
|
-
const agentDir =
|
|
60273
|
+
const agentDir = join26(resolveAgentsDir(config), agent);
|
|
60237
60274
|
const r = cancelAuthSession(agent, agentDir, opts.slot);
|
|
60238
60275
|
for (const line of r.instructions)
|
|
60239
60276
|
console.log(line);
|
|
@@ -60255,7 +60292,7 @@ init_vault();
|
|
|
60255
60292
|
init_hindsight();
|
|
60256
60293
|
import { readFileSync as readFileSync29, writeFileSync as writeFileSync17, copyFileSync as copyFileSync6, existsSync as existsSync34, readdirSync as readdirSync16, statSync as statSync18 } from "node:fs";
|
|
60257
60294
|
import { execFileSync as execFileSync15 } from "node:child_process";
|
|
60258
|
-
import { join as
|
|
60295
|
+
import { join as join27 } from "node:path";
|
|
60259
60296
|
import { homedir as homedir13 } from "node:os";
|
|
60260
60297
|
function getVaultPath2(configPath) {
|
|
60261
60298
|
try {
|
|
@@ -60271,7 +60308,7 @@ function maskToken(s) {
|
|
|
60271
60308
|
return "***";
|
|
60272
60309
|
}
|
|
60273
60310
|
function findClaudeTranscripts() {
|
|
60274
|
-
const root =
|
|
60311
|
+
const root = join27(homedir13(), ".claude", "projects");
|
|
60275
60312
|
if (!existsSync34(root))
|
|
60276
60313
|
return [];
|
|
60277
60314
|
const out = [];
|
|
@@ -60283,7 +60320,7 @@ function findClaudeTranscripts() {
|
|
|
60283
60320
|
return;
|
|
60284
60321
|
}
|
|
60285
60322
|
for (const e of entries) {
|
|
60286
|
-
const p =
|
|
60323
|
+
const p = join27(dir, e);
|
|
60287
60324
|
let st;
|
|
60288
60325
|
try {
|
|
60289
60326
|
st = statSync18(p);
|
|
@@ -60302,8 +60339,8 @@ function findClaudeTranscripts() {
|
|
|
60302
60339
|
}
|
|
60303
60340
|
function findTelegramHistoryDb() {
|
|
60304
60341
|
const candidates = [
|
|
60305
|
-
process.env.TELEGRAM_STATE_DIR ?
|
|
60306
|
-
|
|
60342
|
+
process.env.TELEGRAM_STATE_DIR ? join27(process.env.TELEGRAM_STATE_DIR, "history.db") : null,
|
|
60343
|
+
join27(homedir13(), ".claude", "channels", "telegram", "history.db")
|
|
60307
60344
|
].filter(Boolean);
|
|
60308
60345
|
for (const c of candidates) {
|
|
60309
60346
|
if (existsSync34(c))
|
|
@@ -60670,7 +60707,7 @@ init_compose();
|
|
|
60670
60707
|
init_vault();
|
|
60671
60708
|
import * as net3 from "node:net";
|
|
60672
60709
|
import { mkdirSync as mkdirSync23, chmodSync as chmodSync7, chownSync as chownSync4, existsSync as existsSync37, readFileSync as readFileSync32, readdirSync as readdirSync17, statSync as statSync20, unlinkSync as unlinkSync8, writeFileSync as writeFileSync19, renameSync as renameSync10 } from "node:fs";
|
|
60673
|
-
import { dirname as dirname7, resolve as resolve26, basename as
|
|
60710
|
+
import { dirname as dirname7, resolve as resolve26, basename as basename5 } from "node:path";
|
|
60674
60711
|
import * as os4 from "node:os";
|
|
60675
60712
|
import * as path3 from "node:path";
|
|
60676
60713
|
|
|
@@ -60692,13 +60729,13 @@ import {
|
|
|
60692
60729
|
unlinkSync as unlinkSync7
|
|
60693
60730
|
} from "node:fs";
|
|
60694
60731
|
import { createHash as createHash5 } from "node:crypto";
|
|
60695
|
-
import { basename as
|
|
60732
|
+
import { basename as basename4, dirname as dirname4, join as join28 } from "node:path";
|
|
60696
60733
|
function vaultLayoutPaths(home2) {
|
|
60697
|
-
const switchroomRoot =
|
|
60734
|
+
const switchroomRoot = join28(home2, ".switchroom");
|
|
60698
60735
|
return {
|
|
60699
|
-
oldPath:
|
|
60700
|
-
newPath:
|
|
60701
|
-
parent:
|
|
60736
|
+
oldPath: join28(switchroomRoot, "vault.enc"),
|
|
60737
|
+
newPath: join28(switchroomRoot, "vault", "vault.enc"),
|
|
60738
|
+
parent: join28(switchroomRoot, "vault"),
|
|
60702
60739
|
switchroomRoot
|
|
60703
60740
|
};
|
|
60704
60741
|
}
|
|
@@ -60845,7 +60882,7 @@ function sha256File(path) {
|
|
|
60845
60882
|
return createHash5("sha256").update(data).digest("hex");
|
|
60846
60883
|
}
|
|
60847
60884
|
function atomicReplaceWithSymlink(target, linkTarget) {
|
|
60848
|
-
const tmp =
|
|
60885
|
+
const tmp = join28(dirname4(target), `.${basename4(target)}.symlink-tmp`);
|
|
60849
60886
|
if (existsSync35(tmp)) {
|
|
60850
60887
|
try {
|
|
60851
60888
|
unlinkSync7(tmp);
|
|
@@ -60998,7 +61035,7 @@ import * as path from "node:path";
|
|
|
60998
61035
|
// src/vault/broker/test-isolation-guard.ts
|
|
60999
61036
|
import { mkdtempSync as mkdtempSync4 } from "node:fs";
|
|
61000
61037
|
import { homedir as homedir14, tmpdir as tmpdir3 } from "node:os";
|
|
61001
|
-
import { join as
|
|
61038
|
+
import { join as join29, resolve as resolve25, sep } from "node:path";
|
|
61002
61039
|
function isTestRuntime() {
|
|
61003
61040
|
return process.env.VITEST !== undefined;
|
|
61004
61041
|
}
|
|
@@ -61019,7 +61056,7 @@ function safeVaultPath(requestedPath) {
|
|
|
61019
61056
|
return requestedPath;
|
|
61020
61057
|
if (!isUnderRealSwitchroomHome(requestedPath))
|
|
61021
61058
|
return requestedPath;
|
|
61022
|
-
const redirected =
|
|
61059
|
+
const redirected = join29(mkdtempSync4(join29(tmpdir3(), "sw-test-vault-")), "vault.enc");
|
|
61023
61060
|
if (!warnedVault) {
|
|
61024
61061
|
warnedVault = true;
|
|
61025
61062
|
process.stderr.write(`[test-isolation guard] vault path redirected away from the ` + `production tree to an isolated tmpdir \u2014 a vault/broker test ` + `resolved its vault path inside ~/.switchroom. See CLAUDE.md ` + `"Vault & shared-state test discipline".
|
|
@@ -61035,7 +61072,7 @@ function safeAuditLogPath(requestedPath) {
|
|
|
61035
61072
|
if (!isUnderRealSwitchroomHome(requestedPath))
|
|
61036
61073
|
return requestedPath;
|
|
61037
61074
|
if (!cachedTmpAuditLog) {
|
|
61038
|
-
cachedTmpAuditLog =
|
|
61075
|
+
cachedTmpAuditLog = join29(mkdtempSync4(join29(tmpdir3(), "sw-test-audit-")), "vault-audit.log");
|
|
61039
61076
|
}
|
|
61040
61077
|
if (!warnedAudit) {
|
|
61041
61078
|
warnedAudit = true;
|
|
@@ -64872,12 +64909,12 @@ class VaultBroker {
|
|
|
64872
64909
|
}
|
|
64873
64910
|
function detectVaultLayoutDrift(vaultPath) {
|
|
64874
64911
|
const dir = dirname7(vaultPath);
|
|
64875
|
-
if (
|
|
64912
|
+
if (basename5(dir) !== "vault")
|
|
64876
64913
|
return;
|
|
64877
|
-
if (
|
|
64914
|
+
if (basename5(vaultPath) !== "vault.enc")
|
|
64878
64915
|
return;
|
|
64879
64916
|
const switchroomDir = dirname7(dir);
|
|
64880
|
-
if (
|
|
64917
|
+
if (basename5(switchroomDir) !== ".switchroom")
|
|
64881
64918
|
return;
|
|
64882
64919
|
const home2 = dirname7(switchroomDir);
|
|
64883
64920
|
const result = inspectVaultLayout(home2);
|
|
@@ -64988,7 +65025,7 @@ var import_yaml10 = __toESM(require_dist(), 1);
|
|
|
64988
65025
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
64989
65026
|
import { readFileSync as readFileSync33, writeFileSync as writeFileSync20 } from "node:fs";
|
|
64990
65027
|
import { homedir as homedir18 } from "node:os";
|
|
64991
|
-
import { join as
|
|
65028
|
+
import { join as join34 } from "node:path";
|
|
64992
65029
|
class EncryptFailedError extends Error {
|
|
64993
65030
|
detail;
|
|
64994
65031
|
constructor(detail) {
|
|
@@ -65021,7 +65058,7 @@ function setVaultBrokerAutoUnlock(configPath, value) {
|
|
|
65021
65058
|
doc.setIn(["vault", "broker", "autoUnlock"], value);
|
|
65022
65059
|
writeFileSync20(configPath, doc.toString(), "utf-8");
|
|
65023
65060
|
}
|
|
65024
|
-
var DEFAULT_COMPOSE_FILE =
|
|
65061
|
+
var DEFAULT_COMPOSE_FILE = join34(homedir18(), ".switchroom", "compose", "docker-compose.yml");
|
|
65025
65062
|
async function applyAutoUnlock(opts = {}) {
|
|
65026
65063
|
const log = opts.log ?? ((s) => console.log(s));
|
|
65027
65064
|
const err = opts.err ?? ((s) => console.error(s));
|
|
@@ -65740,7 +65777,7 @@ init_source();
|
|
|
65740
65777
|
init_loader();
|
|
65741
65778
|
init_loader();
|
|
65742
65779
|
init_client();
|
|
65743
|
-
import { join as
|
|
65780
|
+
import { join as join35 } from "node:path";
|
|
65744
65781
|
import { homedir as homedir19 } from "node:os";
|
|
65745
65782
|
function parseDuration(raw) {
|
|
65746
65783
|
const lower = raw.toLowerCase().trim();
|
|
@@ -65833,7 +65870,7 @@ function registerVaultGrantCommands(vault, program3) {
|
|
|
65833
65870
|
console.error(source_default.red(`Failed to mint grant: ${result.msg}`));
|
|
65834
65871
|
process.exit(1);
|
|
65835
65872
|
}
|
|
65836
|
-
const tokenPath =
|
|
65873
|
+
const tokenPath = join35(homedir19(), ".switchroom", "agents", agent, ".vault-token");
|
|
65837
65874
|
console.log(source_default.green(`\u2713 Grant minted`));
|
|
65838
65875
|
if (process.stdout.isTTY) {
|
|
65839
65876
|
console.log(source_default.bold("Token: ") + result.token);
|
|
@@ -65885,7 +65922,7 @@ The token file was written to the agent directory (mode 0600).`));
|
|
|
65885
65922
|
init_source();
|
|
65886
65923
|
init_loader();
|
|
65887
65924
|
import { existsSync as existsSync42 } from "node:fs";
|
|
65888
|
-
import { join as
|
|
65925
|
+
import { join as join37 } from "node:path";
|
|
65889
65926
|
|
|
65890
65927
|
// src/vault/backup.ts
|
|
65891
65928
|
import {
|
|
@@ -65908,7 +65945,7 @@ import {
|
|
|
65908
65945
|
writeSync as writeSync5
|
|
65909
65946
|
} from "node:fs";
|
|
65910
65947
|
import { homedir as homedir20 } from "node:os";
|
|
65911
|
-
import { join as
|
|
65948
|
+
import { join as join36, resolve as resolvePath2 } from "node:path";
|
|
65912
65949
|
var LATEST_SYMLINK = "vault.enc.latest.bak";
|
|
65913
65950
|
var MANIFEST_FILE = "manifest.jsonl";
|
|
65914
65951
|
var DEFAULT_RETAIN = 30;
|
|
@@ -65983,9 +66020,9 @@ function resolveBackupDestination(input) {
|
|
|
65983
66020
|
if (input.configDestination)
|
|
65984
66021
|
return resolvePath2(input.configDestination);
|
|
65985
66022
|
if (input.hasSwitchroomConfigRepo) {
|
|
65986
|
-
return
|
|
66023
|
+
return join36(input.home, ".switchroom-config", "vault-backups");
|
|
65987
66024
|
}
|
|
65988
|
-
return
|
|
66025
|
+
return join36(input.home, ".switchroom", "vault-backups");
|
|
65989
66026
|
}
|
|
65990
66027
|
function findAutoUnlockSibling(entries) {
|
|
65991
66028
|
for (const name of entries) {
|
|
@@ -66036,9 +66073,9 @@ function backupVault(opts) {
|
|
|
66036
66073
|
throw new Error(`vault backup refused: destination '${opts.destDir}' contains a file ` + `that looks like an auto-unlock credential ('${offender}'). The ` + `machine-bound auto-unlock blob MUST NOT be co-located with the ` + `encrypted vault \u2014 if they're together in version control, the ` + `passphrase gate is bypassed. Move/remove that file and retry.`);
|
|
66037
66074
|
}
|
|
66038
66075
|
const filename = computeBackupFilename(now);
|
|
66039
|
-
const fullPath =
|
|
66076
|
+
const fullPath = join36(opts.destDir, filename);
|
|
66040
66077
|
const tmpName = `.tmp.${process.pid}.${randomBytes10(4).toString("hex")}`;
|
|
66041
|
-
const tmpPath =
|
|
66078
|
+
const tmpPath = join36(opts.destDir, tmpName);
|
|
66042
66079
|
const src = readFileSync36(opts.vaultPath);
|
|
66043
66080
|
const fd = openSync9(tmpPath, "wx", 384);
|
|
66044
66081
|
try {
|
|
@@ -66062,9 +66099,9 @@ function backupVault(opts) {
|
|
|
66062
66099
|
size_bytes: stat.size,
|
|
66063
66100
|
sha256
|
|
66064
66101
|
};
|
|
66065
|
-
appendFileSync3(
|
|
66102
|
+
appendFileSync3(join36(opts.destDir, MANIFEST_FILE), JSON.stringify(row) + `
|
|
66066
66103
|
`, { mode: 384 });
|
|
66067
|
-
const latestPath =
|
|
66104
|
+
const latestPath = join36(opts.destDir, LATEST_SYMLINK);
|
|
66068
66105
|
try {
|
|
66069
66106
|
unlinkSync10(latestPath);
|
|
66070
66107
|
} catch {}
|
|
@@ -66083,7 +66120,7 @@ function backupVault(opts) {
|
|
|
66083
66120
|
const pruneNames = selectBackupsToPrune(sorted, retain);
|
|
66084
66121
|
for (const old of pruneNames) {
|
|
66085
66122
|
try {
|
|
66086
|
-
unlinkSync10(
|
|
66123
|
+
unlinkSync10(join36(opts.destDir, old));
|
|
66087
66124
|
} catch {}
|
|
66088
66125
|
}
|
|
66089
66126
|
if (pruneNames.length > 0) {
|
|
@@ -66132,7 +66169,7 @@ function registerVaultBackupCommand(vault, program3) {
|
|
|
66132
66169
|
}
|
|
66133
66170
|
} catch {}
|
|
66134
66171
|
const home2 = defaultHome();
|
|
66135
|
-
const hasSwitchroomConfigRepo = existsSync42(
|
|
66172
|
+
const hasSwitchroomConfigRepo = existsSync42(join37(home2, ".switchroom-config"));
|
|
66136
66173
|
const destDir = resolveBackupDestination({
|
|
66137
66174
|
cliToFlag: opts.to ? resolvePath(opts.to) : undefined,
|
|
66138
66175
|
configDestination,
|
|
@@ -66759,7 +66796,7 @@ Push passphrase to broker for future requests? [Y/n]: `);
|
|
|
66759
66796
|
// src/cli/telegram.ts
|
|
66760
66797
|
init_source();
|
|
66761
66798
|
import { existsSync as existsSync43, readFileSync as readFileSync38, writeFileSync as writeFileSync21 } from "node:fs";
|
|
66762
|
-
import { join as
|
|
66799
|
+
import { join as join38 } from "node:path";
|
|
66763
66800
|
|
|
66764
66801
|
// src/web/webhook-dispatch.ts
|
|
66765
66802
|
function renderTemplate2(template, ctx) {
|
|
@@ -67021,7 +67058,7 @@ async function runTopicsDiscover(program3, chatId, opts) {
|
|
|
67021
67058
|
fail(`Unknown agent '${agentName}'. Check switchroom.yaml.`);
|
|
67022
67059
|
}
|
|
67023
67060
|
const agentsDir = process.env.SWITCHROOM_AGENTS_DIR ?? resolveStatePath("agents");
|
|
67024
|
-
const dbPath =
|
|
67061
|
+
const dbPath = join38(agentsDir, agentName, "telegram", "history.db");
|
|
67025
67062
|
if (!existsSync43(dbPath)) {
|
|
67026
67063
|
fail(`No history DB at ${dbPath}.
|
|
67027
67064
|
` + ` The agent may not have received any Telegram messages yet, or it may be offline.
|
|
@@ -67687,9 +67724,9 @@ async function ensureHindsightConsumer(configPath, account, uid = HINDSIGHT_DEFA
|
|
|
67687
67724
|
init_loader();
|
|
67688
67725
|
var import_yaml12 = __toESM(require_dist(), 1);
|
|
67689
67726
|
import { existsSync as existsSync44, readFileSync as readFileSync39, writeFileSync as writeFileSync22 } from "node:fs";
|
|
67690
|
-
import { join as
|
|
67727
|
+
import { join as join39 } from "node:path";
|
|
67691
67728
|
function readRecallLog(agentDir, limit) {
|
|
67692
|
-
const path4 =
|
|
67729
|
+
const path4 = join39(agentDir, ".claude", "plugins", "data", "hindsight-memory-inline", "state", "recall_log.jsonl");
|
|
67693
67730
|
if (!existsSync44(path4))
|
|
67694
67731
|
return [];
|
|
67695
67732
|
let raw;
|
|
@@ -67930,7 +67967,7 @@ Cross-agent reflection plan
|
|
|
67930
67967
|
process.exit(1);
|
|
67931
67968
|
})() : Object.keys(config.agents);
|
|
67932
67969
|
for (const name of targets) {
|
|
67933
|
-
const agentDir =
|
|
67970
|
+
const agentDir = join39(agentsDir, name);
|
|
67934
67971
|
const entries = readRecallLog(agentDir, limit);
|
|
67935
67972
|
if (opts.json) {
|
|
67936
67973
|
for (const e of entries) {
|
|
@@ -68006,7 +68043,7 @@ import {
|
|
|
68006
68043
|
writeSync as writeSync6,
|
|
68007
68044
|
constants as fsConstants3
|
|
68008
68045
|
} from "node:fs";
|
|
68009
|
-
import { resolve as resolve28, extname, join as
|
|
68046
|
+
import { resolve as resolve28, extname, join as join46, relative, dirname as dirname10 } from "node:path";
|
|
68010
68047
|
import { homedir as homedir25 } from "node:os";
|
|
68011
68048
|
import { spawn as spawn5 } from "node:child_process";
|
|
68012
68049
|
import { timingSafeEqual as timingSafeEqual3, randomBytes as randomBytes11 } from "node:crypto";
|
|
@@ -72726,19 +72763,19 @@ import {
|
|
|
72726
72763
|
} from "node:fs";
|
|
72727
72764
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
72728
72765
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
72729
|
-
import { join as
|
|
72766
|
+
import { join as join41 } from "node:path";
|
|
72730
72767
|
|
|
72731
72768
|
class ConfigDiffError extends Error {
|
|
72732
72769
|
}
|
|
72733
72770
|
function generateUnifiedDiff(before, after, name = "switchroom.yaml", gitBin = "git") {
|
|
72734
72771
|
if (before === after)
|
|
72735
72772
|
return "";
|
|
72736
|
-
const dir = mkdtemp(
|
|
72773
|
+
const dir = mkdtemp(join41(tmpdir4(), "switchroom-config-diff-"));
|
|
72737
72774
|
try {
|
|
72738
|
-
mkdirSync26(
|
|
72739
|
-
mkdirSync26(
|
|
72740
|
-
writeFileSync24(
|
|
72741
|
-
writeFileSync24(
|
|
72775
|
+
mkdirSync26(join41(dir, "cur"), { recursive: true });
|
|
72776
|
+
mkdirSync26(join41(dir, "new"), { recursive: true });
|
|
72777
|
+
writeFileSync24(join41(dir, "cur", name), before);
|
|
72778
|
+
writeFileSync24(join41(dir, "new", name), after);
|
|
72742
72779
|
const r = spawnSync4(gitBin, ["diff", "--no-index", "--no-color", "--", `cur/${name}`, `new/${name}`], { cwd: dir, encoding: "utf-8", timeout: 1e4 });
|
|
72743
72780
|
if (r.status === 0)
|
|
72744
72781
|
return "";
|
|
@@ -72772,7 +72809,7 @@ function generateUnifiedDiff(before, after, name = "switchroom.yaml", gitBin = "
|
|
|
72772
72809
|
init_client4();
|
|
72773
72810
|
import { existsSync as existsSync46 } from "node:fs";
|
|
72774
72811
|
import { homedir as homedir22 } from "node:os";
|
|
72775
|
-
import { join as
|
|
72812
|
+
import { join as join42 } from "node:path";
|
|
72776
72813
|
var PROPOSE_TIMEOUT_MS = 11 * 60 * 1000;
|
|
72777
72814
|
function resolveHostdOperatorSocket(env2 = process.env) {
|
|
72778
72815
|
const override = env2.SWITCHROOM_HOSTD_OPERATOR_SOCKET;
|
|
@@ -72780,7 +72817,7 @@ function resolveHostdOperatorSocket(env2 = process.env) {
|
|
|
72780
72817
|
return override;
|
|
72781
72818
|
const candidates = [
|
|
72782
72819
|
"/host-home/.switchroom/hostd/operator/sock",
|
|
72783
|
-
|
|
72820
|
+
join42(homedir22(), ".switchroom", "hostd", "operator", "sock")
|
|
72784
72821
|
];
|
|
72785
72822
|
for (const c of candidates) {
|
|
72786
72823
|
if (existsSync46(c))
|
|
@@ -72876,7 +72913,7 @@ init_client2();
|
|
|
72876
72913
|
|
|
72877
72914
|
// telegram-plugin/registry/turns-schema.ts
|
|
72878
72915
|
import { chmodSync as chmodSync8, mkdirSync as mkdirSync27 } from "fs";
|
|
72879
|
-
import { join as
|
|
72916
|
+
import { join as join43 } from "path";
|
|
72880
72917
|
var DatabaseClass = null;
|
|
72881
72918
|
function loadDatabaseClass() {
|
|
72882
72919
|
if (DatabaseClass != null)
|
|
@@ -72939,9 +72976,9 @@ function applySchema(db) {
|
|
|
72939
72976
|
}
|
|
72940
72977
|
function openTurnsDb(agentDir) {
|
|
72941
72978
|
const Database2 = loadDatabaseClass();
|
|
72942
|
-
const dir =
|
|
72979
|
+
const dir = join43(agentDir, "telegram");
|
|
72943
72980
|
mkdirSync27(dir, { recursive: true, mode: 448 });
|
|
72944
|
-
const path4 =
|
|
72981
|
+
const path4 = join43(dir, "registry.db");
|
|
72945
72982
|
const db = new Database2(path4, { create: true });
|
|
72946
72983
|
applySchema(db);
|
|
72947
72984
|
try {
|
|
@@ -73736,7 +73773,7 @@ async function handleGetMemoryHealth(config, opts) {
|
|
|
73736
73773
|
|
|
73737
73774
|
// src/web/webhook-handler.ts
|
|
73738
73775
|
import { appendFileSync as appendFileSync4, existsSync as existsSync49, mkdirSync as mkdirSync28, readFileSync as readFileSync44, writeFileSync as writeFileSync25 } from "fs";
|
|
73739
|
-
import { join as
|
|
73776
|
+
import { join as join45 } from "path";
|
|
73740
73777
|
import { homedir as homedir24 } from "os";
|
|
73741
73778
|
|
|
73742
73779
|
// src/web/webhook-verify.ts
|
|
@@ -73888,12 +73925,12 @@ function forwardToGateway(socketPath, req, opts = {}) {
|
|
|
73888
73925
|
|
|
73889
73926
|
// src/web/webhook-edge.ts
|
|
73890
73927
|
import { existsSync as existsSync48, readFileSync as readFileSync43 } from "fs";
|
|
73891
|
-
import { join as
|
|
73928
|
+
import { join as join44 } from "path";
|
|
73892
73929
|
import { homedir as homedir23 } from "os";
|
|
73893
73930
|
import { timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
73894
73931
|
var EDGE_HEADER = "x-switchroom-edge";
|
|
73895
73932
|
function edgeSecretPath() {
|
|
73896
|
-
return
|
|
73933
|
+
return join44(homedir23(), ".switchroom", "webhook-edge-secret");
|
|
73897
73934
|
}
|
|
73898
73935
|
function loadEdgeSecret(path4) {
|
|
73899
73936
|
const p = path4 ?? edgeSecretPath();
|
|
@@ -73956,8 +73993,8 @@ var agentDedupCache = new Map;
|
|
|
73956
73993
|
function createFileDedupStore(resolveAgentDir) {
|
|
73957
73994
|
return {
|
|
73958
73995
|
check(agent, deliveryId, now) {
|
|
73959
|
-
const telegramDir =
|
|
73960
|
-
const filePath =
|
|
73996
|
+
const telegramDir = join45(resolveAgentDir(agent), "telegram");
|
|
73997
|
+
const filePath = join45(telegramDir, "webhook-dedup.json");
|
|
73961
73998
|
if (!agentDedupCache.has(agent)) {
|
|
73962
73999
|
agentDedupCache.set(agent, loadDedupFile(filePath));
|
|
73963
74000
|
}
|
|
@@ -74009,7 +74046,7 @@ function shouldWriteThrottleIssue(agent, source, now, windowMap) {
|
|
|
74009
74046
|
return true;
|
|
74010
74047
|
}
|
|
74011
74048
|
function writeThrottleIssue(agent, source, now, telegramDir, log) {
|
|
74012
|
-
const issuesPath =
|
|
74049
|
+
const issuesPath = join45(telegramDir, "issues.jsonl");
|
|
74013
74050
|
try {
|
|
74014
74051
|
mkdirSync28(telegramDir, { recursive: true });
|
|
74015
74052
|
const record = {
|
|
@@ -74034,7 +74071,7 @@ function writeThrottleIssue(agent, source, now, telegramDir, log) {
|
|
|
74034
74071
|
async function handleWebhookIngest(args, deps = {}) {
|
|
74035
74072
|
const log = deps.log ?? ((s) => process.stderr.write(s));
|
|
74036
74073
|
const now = (deps.now ?? Date.now)();
|
|
74037
|
-
const resolveAgentDir = deps.resolveAgentDir ?? ((a) =>
|
|
74074
|
+
const resolveAgentDir = deps.resolveAgentDir ?? ((a) => join45(homedir24(), ".switchroom", "agents", a));
|
|
74038
74075
|
const rateLimiter = deps.rateLimiter ?? defaultRateLimiter;
|
|
74039
74076
|
const dedupStore = deps.dedupStore ?? createFileDedupStore(resolveAgentDir);
|
|
74040
74077
|
if (!args.agentExists) {
|
|
@@ -74098,7 +74135,7 @@ async function handleWebhookIngest(args, deps = {}) {
|
|
|
74098
74135
|
if (retryAfter !== null) {
|
|
74099
74136
|
if (!args.viaGateway) {
|
|
74100
74137
|
const agentDir2 = resolveAgentDir(args.agent);
|
|
74101
|
-
const telegramDir2 =
|
|
74138
|
+
const telegramDir2 = join45(agentDir2, "telegram");
|
|
74102
74139
|
if (shouldWriteThrottleIssue(args.agent, source, now)) {
|
|
74103
74140
|
writeThrottleIssue(args.agent, source, now, telegramDir2, log);
|
|
74104
74141
|
}
|
|
@@ -74118,7 +74155,7 @@ async function handleWebhookIngest(args, deps = {}) {
|
|
|
74118
74155
|
const eventType = source === "github" ? args.headers.get("x-github-event") ?? "unknown" : args.source;
|
|
74119
74156
|
const rendered = source === "github" ? renderGithubEvent(eventType, payload) : renderGenericEvent(args.source, payload);
|
|
74120
74157
|
if (args.viaGateway) {
|
|
74121
|
-
const socketPath =
|
|
74158
|
+
const socketPath = join45(resolveAgentDir(args.agent), "telegram", "webhook.sock");
|
|
74122
74159
|
const forward = deps.forwardFn ?? forwardToGateway;
|
|
74123
74160
|
const deliveryId = source === "github" ? args.headers.get("x-github-delivery") ?? undefined : undefined;
|
|
74124
74161
|
let resp;
|
|
@@ -74157,8 +74194,8 @@ async function handleWebhookIngest(args, deps = {}) {
|
|
|
74157
74194
|
return jsonReply(202, { ok: true, recorded: true, ts: resp.ts });
|
|
74158
74195
|
}
|
|
74159
74196
|
const agentDir = resolveAgentDir(args.agent);
|
|
74160
|
-
const telegramDir =
|
|
74161
|
-
const logPath =
|
|
74197
|
+
const telegramDir = join45(agentDir, "telegram");
|
|
74198
|
+
const logPath = join45(telegramDir, "webhook-events.jsonl");
|
|
74162
74199
|
try {
|
|
74163
74200
|
mkdirSync28(telegramDir, { recursive: true });
|
|
74164
74201
|
const record = {
|
|
@@ -74212,7 +74249,7 @@ function resolveWebToken() {
|
|
|
74212
74249
|
if (fromEnv && fromEnv.length > 0)
|
|
74213
74250
|
return fromEnv;
|
|
74214
74251
|
const home2 = process.env.HOME ?? homedir25();
|
|
74215
|
-
const tokenPath =
|
|
74252
|
+
const tokenPath = join46(home2, ".switchroom", "web-token");
|
|
74216
74253
|
if (existsSync50(tokenPath)) {
|
|
74217
74254
|
const existing = readFileSync45(tokenPath, "utf8").trim();
|
|
74218
74255
|
if (existing.length > 0)
|
|
@@ -74297,7 +74334,7 @@ function checkWsAuth(req, token, server) {
|
|
|
74297
74334
|
return presented !== null && constantTimeEqual(presented, token);
|
|
74298
74335
|
}
|
|
74299
74336
|
function loadWebhookSecrets() {
|
|
74300
|
-
const path4 =
|
|
74337
|
+
const path4 = join46(homedir25(), ".switchroom", "webhook-secrets.json");
|
|
74301
74338
|
if (!existsSync50(path4))
|
|
74302
74339
|
return {};
|
|
74303
74340
|
try {
|
|
@@ -74633,7 +74670,7 @@ function startWebServer(config, port, hostname = "127.0.0.1", configPath) {
|
|
|
74633
74670
|
}
|
|
74634
74671
|
}
|
|
74635
74672
|
let filePath = pathname === "/" ? "/index.html" : pathname;
|
|
74636
|
-
const fullPath =
|
|
74673
|
+
const fullPath = join46(uiDir, filePath);
|
|
74637
74674
|
if (!existsSync50(fullPath)) {
|
|
74638
74675
|
return new Response("Not Found", { status: 404 });
|
|
74639
74676
|
}
|
|
@@ -75678,15 +75715,15 @@ init_loader();
|
|
|
75678
75715
|
init_lifecycle();
|
|
75679
75716
|
import { cpSync as cpSync2, existsSync as existsSync58, mkdirSync as mkdirSync32, readFileSync as readFileSync51, realpathSync as realpathSync6, rmSync as rmSync12, statSync as statSync26 } from "node:fs";
|
|
75680
75717
|
import { spawnSync as spawnSync9 } from "node:child_process";
|
|
75681
|
-
import { join as
|
|
75718
|
+
import { join as join60, dirname as dirname14, resolve as resolve33 } from "node:path";
|
|
75682
75719
|
import { homedir as homedir36 } from "node:os";
|
|
75683
|
-
var DEFAULT_COMPOSE_PATH =
|
|
75720
|
+
var DEFAULT_COMPOSE_PATH = join60(homedir36(), ".switchroom", "compose", "docker-compose.yml");
|
|
75684
75721
|
function runningFromSwitchroomCheckout(scriptPath) {
|
|
75685
75722
|
let dir = dirname14(scriptPath);
|
|
75686
75723
|
for (let i = 0;i < 12; i++) {
|
|
75687
|
-
if (existsSync58(
|
|
75724
|
+
if (existsSync58(join60(dir, ".git"))) {
|
|
75688
75725
|
try {
|
|
75689
|
-
const pkg = JSON.parse(readFileSync51(
|
|
75726
|
+
const pkg = JSON.parse(readFileSync51(join60(dir, "package.json"), "utf-8"));
|
|
75690
75727
|
if (pkg.name === "switchroom")
|
|
75691
75728
|
return true;
|
|
75692
75729
|
} catch {}
|
|
@@ -75837,7 +75874,7 @@ function planUpdate(opts) {
|
|
|
75837
75874
|
return;
|
|
75838
75875
|
}
|
|
75839
75876
|
const source = resolve33(import.meta.dirname, "../../skills");
|
|
75840
|
-
const dest =
|
|
75877
|
+
const dest = join60(homedir36(), ".switchroom", "skills", "_bundled");
|
|
75841
75878
|
if (!existsSync58(source)) {
|
|
75842
75879
|
process.stderr.write(`switchroom update: sync-bundled-skills \u2014 CLI bundle has no adjacent skills/ at ${source}; skipping.
|
|
75843
75880
|
`);
|
|
@@ -75951,7 +75988,7 @@ function defaultStatusProbe(composePath) {
|
|
|
75951
75988
|
} catch {}
|
|
75952
75989
|
let dir = dirname14(scriptPath);
|
|
75953
75990
|
for (let i = 0;i < 8; i++) {
|
|
75954
|
-
const pkgPath =
|
|
75991
|
+
const pkgPath = join60(dir, "package.json");
|
|
75955
75992
|
if (existsSync58(pkgPath)) {
|
|
75956
75993
|
try {
|
|
75957
75994
|
const pkg = JSON.parse(readFileSync51(pkgPath, "utf-8"));
|
|
@@ -76171,7 +76208,7 @@ init_helpers();
|
|
|
76171
76208
|
init_lifecycle();
|
|
76172
76209
|
import { execSync as execSync4 } from "node:child_process";
|
|
76173
76210
|
import { existsSync as existsSync59, readFileSync as readFileSync52 } from "node:fs";
|
|
76174
|
-
import { dirname as dirname15, join as
|
|
76211
|
+
import { dirname as dirname15, join as join61 } from "node:path";
|
|
76175
76212
|
function getClaudeCodeVersion() {
|
|
76176
76213
|
try {
|
|
76177
76214
|
const out = execSync4("claude --version 2>/dev/null", {
|
|
@@ -76221,11 +76258,11 @@ function formatUptime3(timestamp) {
|
|
|
76221
76258
|
function locateSwitchroomInstallDir() {
|
|
76222
76259
|
let dir = import.meta.dirname;
|
|
76223
76260
|
for (let i = 0;i < 10 && dir && dir !== "/"; i++) {
|
|
76224
|
-
const pkgPath =
|
|
76261
|
+
const pkgPath = join61(dir, "package.json");
|
|
76225
76262
|
if (existsSync59(pkgPath)) {
|
|
76226
76263
|
try {
|
|
76227
76264
|
const pkg = JSON.parse(readFileSync52(pkgPath, "utf-8"));
|
|
76228
|
-
if (pkg.name === "switchroom" && existsSync59(
|
|
76265
|
+
if (pkg.name === "switchroom" && existsSync59(join61(dir, ".git"))) {
|
|
76229
76266
|
return dir;
|
|
76230
76267
|
}
|
|
76231
76268
|
} catch {}
|
|
@@ -76462,7 +76499,7 @@ import {
|
|
|
76462
76499
|
writeFileSync as writeFileSync27,
|
|
76463
76500
|
writeSync as writeSync7
|
|
76464
76501
|
} from "node:fs";
|
|
76465
|
-
import { join as
|
|
76502
|
+
import { join as join62 } from "node:path";
|
|
76466
76503
|
import { randomBytes as randomBytes12 } from "node:crypto";
|
|
76467
76504
|
import { execSync as execSync5 } from "node:child_process";
|
|
76468
76505
|
|
|
@@ -76860,7 +76897,7 @@ function redactedMarker(ruleId) {
|
|
|
76860
76897
|
var ISSUES_FILE = "issues.jsonl";
|
|
76861
76898
|
var ISSUES_LOCK = "issues.lock";
|
|
76862
76899
|
function readAll(stateDir) {
|
|
76863
|
-
const path4 =
|
|
76900
|
+
const path4 = join62(stateDir, ISSUES_FILE);
|
|
76864
76901
|
if (!existsSync60(path4))
|
|
76865
76902
|
return [];
|
|
76866
76903
|
let raw;
|
|
@@ -76938,7 +76975,7 @@ function record(stateDir, input, nowFn = Date.now) {
|
|
|
76938
76975
|
});
|
|
76939
76976
|
}
|
|
76940
76977
|
function resolve36(stateDir, fingerprint, nowFn = Date.now) {
|
|
76941
|
-
if (!existsSync60(
|
|
76978
|
+
if (!existsSync60(join62(stateDir, ISSUES_FILE)))
|
|
76942
76979
|
return 0;
|
|
76943
76980
|
return withLock(stateDir, () => {
|
|
76944
76981
|
const all = readAll(stateDir);
|
|
@@ -76956,7 +76993,7 @@ function resolve36(stateDir, fingerprint, nowFn = Date.now) {
|
|
|
76956
76993
|
});
|
|
76957
76994
|
}
|
|
76958
76995
|
function resolveAllBySource(stateDir, source, nowFn = Date.now) {
|
|
76959
|
-
if (!existsSync60(
|
|
76996
|
+
if (!existsSync60(join62(stateDir, ISSUES_FILE)))
|
|
76960
76997
|
return 0;
|
|
76961
76998
|
return withLock(stateDir, () => {
|
|
76962
76999
|
const all = readAll(stateDir);
|
|
@@ -76974,7 +77011,7 @@ function resolveAllBySource(stateDir, source, nowFn = Date.now) {
|
|
|
76974
77011
|
});
|
|
76975
77012
|
}
|
|
76976
77013
|
function prune(stateDir, opts = {}) {
|
|
76977
|
-
if (!existsSync60(
|
|
77014
|
+
if (!existsSync60(join62(stateDir, ISSUES_FILE)))
|
|
76978
77015
|
return 0;
|
|
76979
77016
|
return withLock(stateDir, () => {
|
|
76980
77017
|
const all = readAll(stateDir);
|
|
@@ -77007,7 +77044,7 @@ function ensureDir(stateDir) {
|
|
|
77007
77044
|
mkdirSync33(stateDir, { recursive: true });
|
|
77008
77045
|
}
|
|
77009
77046
|
function writeAll(stateDir, events) {
|
|
77010
|
-
const path4 =
|
|
77047
|
+
const path4 = join62(stateDir, ISSUES_FILE);
|
|
77011
77048
|
sweepOrphanTmpFiles(stateDir);
|
|
77012
77049
|
const tmp = `${path4}.tmp-${process.pid}-${randomBytes12(4).toString("hex")}`;
|
|
77013
77050
|
const body = events.length === 0 ? "" : events.map((e) => JSON.stringify(e)).join(`
|
|
@@ -77029,7 +77066,7 @@ function sweepOrphanTmpFiles(stateDir) {
|
|
|
77029
77066
|
for (const entry of entries) {
|
|
77030
77067
|
if (!entry.startsWith(TMP_PREFIX))
|
|
77031
77068
|
continue;
|
|
77032
|
-
const tmpPath =
|
|
77069
|
+
const tmpPath = join62(stateDir, entry);
|
|
77033
77070
|
try {
|
|
77034
77071
|
const stat = statSync27(tmpPath);
|
|
77035
77072
|
if (stat.mtimeMs < cutoff) {
|
|
@@ -77041,7 +77078,7 @@ function sweepOrphanTmpFiles(stateDir) {
|
|
|
77041
77078
|
var LOCK_RETRY_MS = 25;
|
|
77042
77079
|
var LOCK_TIMEOUT_MS = 1e4;
|
|
77043
77080
|
function withLock(stateDir, fn) {
|
|
77044
|
-
const lockPath =
|
|
77081
|
+
const lockPath = join62(stateDir, ISSUES_LOCK);
|
|
77045
77082
|
const startedAt = Date.now();
|
|
77046
77083
|
let fd = null;
|
|
77047
77084
|
while (fd === null) {
|
|
@@ -77326,7 +77363,7 @@ function relTime(deltaMs) {
|
|
|
77326
77363
|
init_source();
|
|
77327
77364
|
import { existsSync as existsSync63 } from "node:fs";
|
|
77328
77365
|
import { homedir as homedir39 } from "node:os";
|
|
77329
|
-
import { join as
|
|
77366
|
+
import { join as join65, resolve as resolve37 } from "node:path";
|
|
77330
77367
|
|
|
77331
77368
|
// src/deps/python.ts
|
|
77332
77369
|
import { createHash as createHash11 } from "node:crypto";
|
|
@@ -77337,7 +77374,7 @@ import {
|
|
|
77337
77374
|
rmSync as rmSync13,
|
|
77338
77375
|
writeFileSync as writeFileSync28
|
|
77339
77376
|
} from "node:fs";
|
|
77340
|
-
import { dirname as dirname16, join as
|
|
77377
|
+
import { dirname as dirname16, join as join63 } from "node:path";
|
|
77341
77378
|
import { homedir as homedir37 } from "node:os";
|
|
77342
77379
|
import { execFileSync as execFileSync19 } from "node:child_process";
|
|
77343
77380
|
|
|
@@ -77350,7 +77387,7 @@ class PythonEnvError extends Error {
|
|
|
77350
77387
|
}
|
|
77351
77388
|
}
|
|
77352
77389
|
function defaultPythonCacheRoot() {
|
|
77353
|
-
return
|
|
77390
|
+
return join63(homedir37(), ".switchroom", "deps", "python");
|
|
77354
77391
|
}
|
|
77355
77392
|
function hashFile(path4) {
|
|
77356
77393
|
return createHash11("sha256").update(readFileSync54(path4)).digest("hex");
|
|
@@ -77362,11 +77399,11 @@ function ensurePythonEnv(opts) {
|
|
|
77362
77399
|
if (!existsSync61(requirementsPath)) {
|
|
77363
77400
|
throw new PythonEnvError(`requirements file not found: ${requirementsPath}`);
|
|
77364
77401
|
}
|
|
77365
|
-
const venvDir =
|
|
77366
|
-
const stampPath =
|
|
77367
|
-
const binDir =
|
|
77368
|
-
const pythonBin =
|
|
77369
|
-
const pipBin =
|
|
77402
|
+
const venvDir = join63(cacheRoot, skillName);
|
|
77403
|
+
const stampPath = join63(venvDir, ".requirements.sha256");
|
|
77404
|
+
const binDir = join63(venvDir, "bin");
|
|
77405
|
+
const pythonBin = join63(binDir, "python");
|
|
77406
|
+
const pipBin = join63(binDir, "pip");
|
|
77370
77407
|
const targetHash = hashFile(requirementsPath);
|
|
77371
77408
|
if (!force && existsSync61(stampPath) && existsSync61(pythonBin)) {
|
|
77372
77409
|
const existingHash = readFileSync54(stampPath, "utf8").trim();
|
|
@@ -77425,7 +77462,7 @@ import {
|
|
|
77425
77462
|
rmSync as rmSync14,
|
|
77426
77463
|
writeFileSync as writeFileSync29
|
|
77427
77464
|
} from "node:fs";
|
|
77428
|
-
import { dirname as dirname17, join as
|
|
77465
|
+
import { dirname as dirname17, join as join64 } from "node:path";
|
|
77429
77466
|
import { homedir as homedir38 } from "node:os";
|
|
77430
77467
|
import { execFileSync as execFileSync20 } from "node:child_process";
|
|
77431
77468
|
|
|
@@ -77449,7 +77486,7 @@ var LOCKFILES_FOR = {
|
|
|
77449
77486
|
npm: ["package-lock.json"]
|
|
77450
77487
|
};
|
|
77451
77488
|
function defaultNodeCacheRoot() {
|
|
77452
|
-
return
|
|
77489
|
+
return join64(homedir38(), ".switchroom", "deps", "node");
|
|
77453
77490
|
}
|
|
77454
77491
|
function hashDepInputs(packageJsonPath) {
|
|
77455
77492
|
const sourceDir = dirname17(packageJsonPath);
|
|
@@ -77458,7 +77495,7 @@ function hashDepInputs(packageJsonPath) {
|
|
|
77458
77495
|
`);
|
|
77459
77496
|
hasher.update(readFileSync55(packageJsonPath));
|
|
77460
77497
|
for (const lockName of ALL_LOCKFILES) {
|
|
77461
|
-
const lockPath =
|
|
77498
|
+
const lockPath = join64(sourceDir, lockName);
|
|
77462
77499
|
if (existsSync62(lockPath)) {
|
|
77463
77500
|
hasher.update(`
|
|
77464
77501
|
`);
|
|
@@ -77478,10 +77515,10 @@ function ensureNodeEnv(opts) {
|
|
|
77478
77515
|
throw new NodeEnvError(`package.json not found: ${packageJsonPath}`);
|
|
77479
77516
|
}
|
|
77480
77517
|
const sourceDir = dirname17(packageJsonPath);
|
|
77481
|
-
const envDir =
|
|
77482
|
-
const stampPath =
|
|
77483
|
-
const nodeModulesDir =
|
|
77484
|
-
const binDir =
|
|
77518
|
+
const envDir = join64(cacheRoot, skillName);
|
|
77519
|
+
const stampPath = join64(envDir, ".package.sha256");
|
|
77520
|
+
const nodeModulesDir = join64(envDir, "node_modules");
|
|
77521
|
+
const binDir = join64(nodeModulesDir, ".bin");
|
|
77485
77522
|
const targetHash = hashDepInputs(packageJsonPath);
|
|
77486
77523
|
if (!force && existsSync62(stampPath) && existsSync62(nodeModulesDir)) {
|
|
77487
77524
|
const existingHash = readFileSync55(stampPath, "utf8").trim();
|
|
@@ -77499,12 +77536,12 @@ function ensureNodeEnv(opts) {
|
|
|
77499
77536
|
rmSync14(envDir, { recursive: true, force: true });
|
|
77500
77537
|
}
|
|
77501
77538
|
mkdirSync35(envDir, { recursive: true });
|
|
77502
|
-
copyFileSync9(packageJsonPath,
|
|
77539
|
+
copyFileSync9(packageJsonPath, join64(envDir, "package.json"));
|
|
77503
77540
|
let copiedLockfile = false;
|
|
77504
77541
|
for (const lockName of LOCKFILES_FOR[installer]) {
|
|
77505
|
-
const lockPath =
|
|
77542
|
+
const lockPath = join64(sourceDir, lockName);
|
|
77506
77543
|
if (existsSync62(lockPath)) {
|
|
77507
|
-
copyFileSync9(lockPath,
|
|
77544
|
+
copyFileSync9(lockPath, join64(envDir, lockName));
|
|
77508
77545
|
copiedLockfile = true;
|
|
77509
77546
|
}
|
|
77510
77547
|
}
|
|
@@ -77543,13 +77580,13 @@ function registerDepsCommand(program3) {
|
|
|
77543
77580
|
console.error(source_default.red(`Bundled skills pool dir not found at ${skillsRoot} \u2014 run \`switchroom update\` to install it.`));
|
|
77544
77581
|
process.exit(1);
|
|
77545
77582
|
}
|
|
77546
|
-
const skillDir =
|
|
77583
|
+
const skillDir = join65(skillsRoot, skill);
|
|
77547
77584
|
if (!existsSync63(skillDir)) {
|
|
77548
77585
|
console.error(source_default.red(`Unknown skill: ${skill} (no dir at ${skillDir})`));
|
|
77549
77586
|
process.exit(1);
|
|
77550
77587
|
}
|
|
77551
|
-
const requirementsPath =
|
|
77552
|
-
const packageJsonPath =
|
|
77588
|
+
const requirementsPath = join65(skillDir, "requirements.txt");
|
|
77589
|
+
const packageJsonPath = join65(skillDir, "package.json");
|
|
77553
77590
|
const wantPython = opts.python ?? (!opts.python && !opts.node && existsSync63(requirementsPath));
|
|
77554
77591
|
const wantNode = opts.node ?? (!opts.python && !opts.node && existsSync63(packageJsonPath));
|
|
77555
77592
|
let did = 0;
|
|
@@ -77826,7 +77863,6 @@ var DEFAULT_SOUL_FILENAME = "SOUL.md";
|
|
|
77826
77863
|
var DEFAULT_TOOLS_FILENAME = "TOOLS.md";
|
|
77827
77864
|
var DEFAULT_IDENTITY_FILENAME = "IDENTITY.md";
|
|
77828
77865
|
var DEFAULT_USER_FILENAME = "USER.md";
|
|
77829
|
-
var DEFAULT_HEARTBEAT_FILENAME = "HEARTBEAT.md";
|
|
77830
77866
|
var DEFAULT_BOOTSTRAP_FILENAME = "BOOTSTRAP.md";
|
|
77831
77867
|
var DEFAULT_MEMORY_FILENAME = "MEMORY.md";
|
|
77832
77868
|
|
|
@@ -77843,8 +77879,7 @@ var STABLE_BOOTSTRAP_FILENAMES = [
|
|
|
77843
77879
|
DEFAULT_BOOTSTRAP_FILENAME
|
|
77844
77880
|
];
|
|
77845
77881
|
var DYNAMIC_BOOTSTRAP_FILENAMES = [
|
|
77846
|
-
DEFAULT_MEMORY_FILENAME
|
|
77847
|
-
DEFAULT_HEARTBEAT_FILENAME
|
|
77882
|
+
DEFAULT_MEMORY_FILENAME
|
|
77848
77883
|
];
|
|
77849
77884
|
var DEFAULT_BOOTSTRAP_MAX_CHARS = 12000;
|
|
77850
77885
|
var DEFAULT_BOOTSTRAP_TOTAL_MAX_CHARS = 64000;
|
|
@@ -78258,7 +78293,7 @@ function registerWorkspaceCommand(program3) {
|
|
|
78258
78293
|
process.stdout.write(`${dir}
|
|
78259
78294
|
`);
|
|
78260
78295
|
}));
|
|
78261
|
-
cmd.command("render <agent>").description("Render the agent's workspace bootstrap block to stdout " + "(used by start.sh and the UserPromptSubmit hook)").option("--stable", "Render only stable files (AGENTS/SOUL/USER/IDENTITY/TOOLS/BOOTSTRAP)").option("--dynamic", "Render only dynamic files (MEMORY + today/yesterday daily
|
|
78296
|
+
cmd.command("render <agent>").description("Render the agent's workspace bootstrap block to stdout " + "(used by start.sh and the UserPromptSubmit hook)").option("--stable", "Render only stable files (AGENTS/SOUL/USER/IDENTITY/TOOLS/BOOTSTRAP)").option("--dynamic", "Render only dynamic files (MEMORY + today/yesterday daily)").option("--warning-mode <mode>", "Truncation warning mode: off | once | always | error (default: off for start.sh use)", "off").option("--max-per-file <n>", "Per-file char cap", String(DEFAULT_BOOTSTRAP_MAX_CHARS)).option("--max-total <n>", "Total char cap (defaults differ for stable vs dynamic)").action(withConfigError(async (agentName, opts) => {
|
|
78262
78297
|
const dir = resolveAgentWorkspaceDirOrExit(program3, agentName);
|
|
78263
78298
|
if (!dir)
|
|
78264
78299
|
return;
|
|
@@ -78506,7 +78541,7 @@ init_helpers();
|
|
|
78506
78541
|
init_loader();
|
|
78507
78542
|
init_merge();
|
|
78508
78543
|
import { copyFileSync as copyFileSync10, existsSync as existsSync65, readFileSync as readFileSync56, writeFileSync as writeFileSync30 } from "node:fs";
|
|
78509
|
-
import { join as
|
|
78544
|
+
import { join as join66, resolve as resolve39 } from "node:path";
|
|
78510
78545
|
init_schema();
|
|
78511
78546
|
function resolveSoulTargetOrExit(program3, agentName) {
|
|
78512
78547
|
const config = getConfig(program3);
|
|
@@ -78530,7 +78565,7 @@ function resolveSoulTargetOrExit(program3, agentName) {
|
|
|
78530
78565
|
profileName,
|
|
78531
78566
|
profilePath,
|
|
78532
78567
|
workspaceDir,
|
|
78533
|
-
soulPath:
|
|
78568
|
+
soulPath: join66(workspaceDir, "SOUL.md"),
|
|
78534
78569
|
soul: merged.soul
|
|
78535
78570
|
};
|
|
78536
78571
|
}
|
|
@@ -78597,7 +78632,7 @@ function registerSoulCommand(program3) {
|
|
|
78597
78632
|
init_helpers();
|
|
78598
78633
|
init_loader();
|
|
78599
78634
|
import { existsSync as existsSync66, readFileSync as readFileSync57, readdirSync as readdirSync23, statSync as statSync28 } from "node:fs";
|
|
78600
|
-
import { resolve as resolve40, join as
|
|
78635
|
+
import { resolve as resolve40, join as join67 } from "node:path";
|
|
78601
78636
|
import { createHash as createHash13 } from "node:crypto";
|
|
78602
78637
|
init_merge();
|
|
78603
78638
|
init_hindsight();
|
|
@@ -78608,7 +78643,7 @@ function estimateTokens(bytes) {
|
|
|
78608
78643
|
return Math.round(bytes / 3.7);
|
|
78609
78644
|
}
|
|
78610
78645
|
function readMcpServerNames(agentDir) {
|
|
78611
|
-
const mcpPath =
|
|
78646
|
+
const mcpPath = join67(agentDir, ".mcp.json");
|
|
78612
78647
|
if (!existsSync66(mcpPath))
|
|
78613
78648
|
return [];
|
|
78614
78649
|
try {
|
|
@@ -78622,7 +78657,7 @@ function sha256(content) {
|
|
|
78622
78657
|
return createHash13("sha256").update(content).digest("hex").slice(0, 16);
|
|
78623
78658
|
}
|
|
78624
78659
|
function findLatestTranscriptJsonl(claudeConfigDir) {
|
|
78625
|
-
const projectsDir =
|
|
78660
|
+
const projectsDir = join67(claudeConfigDir, "projects");
|
|
78626
78661
|
if (!existsSync66(projectsDir))
|
|
78627
78662
|
return;
|
|
78628
78663
|
try {
|
|
@@ -78631,8 +78666,8 @@ function findLatestTranscriptJsonl(claudeConfigDir) {
|
|
|
78631
78666
|
for (const entry of entries) {
|
|
78632
78667
|
if (!entry.isDirectory())
|
|
78633
78668
|
continue;
|
|
78634
|
-
const projectPath =
|
|
78635
|
-
const transcriptPath =
|
|
78669
|
+
const projectPath = join67(projectsDir, entry.name);
|
|
78670
|
+
const transcriptPath = join67(projectPath, "transcript.jsonl");
|
|
78636
78671
|
if (!existsSync66(transcriptPath))
|
|
78637
78672
|
continue;
|
|
78638
78673
|
const stat3 = statSync28(transcriptPath);
|
|
@@ -78701,11 +78736,11 @@ function registerDebugCommand(program3) {
|
|
|
78701
78736
|
process.exit(1);
|
|
78702
78737
|
}
|
|
78703
78738
|
const workspaceDir = resolveAgentWorkspaceDir(agentDir);
|
|
78704
|
-
const claudeConfigDir =
|
|
78705
|
-
const claudeMdPath =
|
|
78706
|
-
const soulMdPath =
|
|
78707
|
-
const workspaceSoulMdPath =
|
|
78708
|
-
const handoffPath =
|
|
78739
|
+
const claudeConfigDir = join67(agentDir, ".claude");
|
|
78740
|
+
const claudeMdPath = join67(agentDir, "CLAUDE.md");
|
|
78741
|
+
const soulMdPath = join67(agentDir, "SOUL.md");
|
|
78742
|
+
const workspaceSoulMdPath = join67(workspaceDir, "SOUL.md");
|
|
78743
|
+
const handoffPath = join67(agentDir, ".handoff.md");
|
|
78709
78744
|
const lastN = parseInt(opts.last, 10);
|
|
78710
78745
|
if (isNaN(lastN) || lastN < 1) {
|
|
78711
78746
|
console.error("--last must be a positive integer");
|
|
@@ -78834,9 +78869,9 @@ function registerDebugCommand(program3) {
|
|
|
78834
78869
|
const soulMdBytes = soulMdContent.length;
|
|
78835
78870
|
const perTurnBytes = dynamicResult.concatenated.length;
|
|
78836
78871
|
const userBytes = userMessage?.text.length ?? 0;
|
|
78837
|
-
const fleetDir =
|
|
78838
|
-
const fleetInvPath =
|
|
78839
|
-
const fleetClaudePath =
|
|
78872
|
+
const fleetDir = join67(agentsDir, "..", "fleet");
|
|
78873
|
+
const fleetInvPath = join67(fleetDir, "switchroom-invariants.md");
|
|
78874
|
+
const fleetClaudePath = join67(fleetDir, "CLAUDE.md");
|
|
78840
78875
|
const fleetInvBytes = existsSync66(fleetInvPath) ? readFileSync57(fleetInvPath, "utf-8").length : 0;
|
|
78841
78876
|
const fleetClaudeBytes = existsSync66(fleetClaudePath) ? readFileSync57(fleetClaudePath, "utf-8").length : 0;
|
|
78842
78877
|
const fleetBytes = fleetInvBytes + fleetClaudeBytes;
|
|
@@ -78872,7 +78907,7 @@ init_source();
|
|
|
78872
78907
|
// src/worktree/claim.ts
|
|
78873
78908
|
import { execFileSync as execFileSync21 } from "node:child_process";
|
|
78874
78909
|
import { closeSync as closeSync12, mkdirSync as mkdirSync37, openSync as openSync12, existsSync as existsSync68, unlinkSync as unlinkSync13 } from "node:fs";
|
|
78875
|
-
import { join as
|
|
78910
|
+
import { join as join69, resolve as resolve42 } from "node:path";
|
|
78876
78911
|
import { homedir as homedir41 } from "node:os";
|
|
78877
78912
|
import { randomBytes as randomBytes13 } from "node:crypto";
|
|
78878
78913
|
|
|
@@ -78886,13 +78921,13 @@ import {
|
|
|
78886
78921
|
existsSync as existsSync67,
|
|
78887
78922
|
renameSync as renameSync13
|
|
78888
78923
|
} from "node:fs";
|
|
78889
|
-
import { join as
|
|
78924
|
+
import { join as join68, resolve as resolve41 } from "node:path";
|
|
78890
78925
|
import { homedir as homedir40 } from "node:os";
|
|
78891
78926
|
function registryDir() {
|
|
78892
|
-
return resolve41(process.env.SWITCHROOM_WORKTREE_DIR ??
|
|
78927
|
+
return resolve41(process.env.SWITCHROOM_WORKTREE_DIR ?? join68(homedir40(), ".switchroom", "worktrees"));
|
|
78893
78928
|
}
|
|
78894
78929
|
function recordPath(id) {
|
|
78895
|
-
return
|
|
78930
|
+
return join68(registryDir(), `${id}.json`);
|
|
78896
78931
|
}
|
|
78897
78932
|
function ensureDir2() {
|
|
78898
78933
|
mkdirSync36(registryDir(), { recursive: true });
|
|
@@ -78943,7 +78978,7 @@ function acquireRepoLock(repoPath) {
|
|
|
78943
78978
|
const lockDir = registryDir();
|
|
78944
78979
|
mkdirSync37(lockDir, { recursive: true });
|
|
78945
78980
|
const lockName = repoPath.replace(/[^A-Za-z0-9]/g, "_");
|
|
78946
|
-
const lockPath =
|
|
78981
|
+
const lockPath = join69(lockDir, `.lock-${lockName}`);
|
|
78947
78982
|
const deadline = Date.now() + 5000;
|
|
78948
78983
|
let fd = null;
|
|
78949
78984
|
while (fd === null) {
|
|
@@ -78970,7 +79005,7 @@ function acquireRepoLock(repoPath) {
|
|
|
78970
79005
|
}
|
|
78971
79006
|
var DEFAULT_CONCURRENCY = 5;
|
|
78972
79007
|
function worktreesBaseDir() {
|
|
78973
|
-
return resolve42(process.env.SWITCHROOM_WORKTREE_BASE ??
|
|
79008
|
+
return resolve42(process.env.SWITCHROOM_WORKTREE_BASE ?? join69(homedir41(), ".switchroom", "worktree-checkouts"));
|
|
78974
79009
|
}
|
|
78975
79010
|
function shortId() {
|
|
78976
79011
|
return randomBytes13(4).toString("hex");
|
|
@@ -78992,7 +79027,7 @@ function resolveRepoPath(repo, codeRepos) {
|
|
|
78992
79027
|
}
|
|
78993
79028
|
function expandHome(p) {
|
|
78994
79029
|
if (p.startsWith("~/"))
|
|
78995
|
-
return
|
|
79030
|
+
return join69(homedir41(), p.slice(2));
|
|
78996
79031
|
return p;
|
|
78997
79032
|
}
|
|
78998
79033
|
async function claimWorktree(input, codeRepos) {
|
|
@@ -79020,7 +79055,7 @@ async function claimWorktree(input, codeRepos) {
|
|
|
79020
79055
|
branch = `task/${taskSuffix}-${id}`;
|
|
79021
79056
|
const baseDir = worktreesBaseDir();
|
|
79022
79057
|
mkdirSync37(baseDir, { recursive: true });
|
|
79023
|
-
worktreePath =
|
|
79058
|
+
worktreePath = join69(baseDir, `${id}-${taskSuffix}`);
|
|
79024
79059
|
const now = new Date().toISOString();
|
|
79025
79060
|
const record2 = {
|
|
79026
79061
|
id,
|
|
@@ -79275,7 +79310,7 @@ import {
|
|
|
79275
79310
|
rmSync as rmSync15,
|
|
79276
79311
|
writeFileSync as writeFileSync32
|
|
79277
79312
|
} from "node:fs";
|
|
79278
|
-
import { join as
|
|
79313
|
+
import { join as join70 } from "node:path";
|
|
79279
79314
|
function encodeCredentialsFilename(email) {
|
|
79280
79315
|
const SAFE = new Set([
|
|
79281
79316
|
..."ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
|
|
@@ -79465,16 +79500,16 @@ function resolveCredentialsDir(env2) {
|
|
|
79465
79500
|
if (explicit && explicit.length > 0)
|
|
79466
79501
|
return explicit;
|
|
79467
79502
|
const stateBase = env2.SWITCHROOM_CONTAINER === "1" ? "/state/agent" : env2.HOME ?? ".";
|
|
79468
|
-
return
|
|
79503
|
+
return join70(stateBase, "google-workspace-mcp", "credentials");
|
|
79469
79504
|
}
|
|
79470
79505
|
function writeSeedFile(dir, email, seed) {
|
|
79471
79506
|
mkdirSync38(dir, { recursive: true, mode: 448 });
|
|
79472
79507
|
chmodSync9(dir, 448);
|
|
79473
79508
|
for (const name of readdirSync25(dir)) {
|
|
79474
|
-
rmSync15(
|
|
79509
|
+
rmSync15(join70(dir, name), { force: true, recursive: true });
|
|
79475
79510
|
}
|
|
79476
79511
|
const filename = encodeCredentialsFilename(email);
|
|
79477
|
-
const filePath =
|
|
79512
|
+
const filePath = join70(dir, filename);
|
|
79478
79513
|
writeFileSync32(filePath, JSON.stringify(seed), { mode: 384 });
|
|
79479
79514
|
chmodSync9(filePath, 384);
|
|
79480
79515
|
return filePath;
|
|
@@ -79634,7 +79669,7 @@ function registerDriveMcpLauncherCommand(program3) {
|
|
|
79634
79669
|
init_scaffold_integration();
|
|
79635
79670
|
import { spawn as spawn6 } from "node:child_process";
|
|
79636
79671
|
import { writeFileSync as writeFileSync33, mkdirSync as mkdirSync39 } from "node:fs";
|
|
79637
|
-
import { dirname as dirname18, join as
|
|
79672
|
+
import { dirname as dirname18, join as join71 } from "node:path";
|
|
79638
79673
|
var SOFTERIA_TOKEN_ENV = "MS365_MCP_OAUTH_TOKEN";
|
|
79639
79674
|
var DEFAULT_REFRESH_LEAD_MS = 5 * 60 * 1000;
|
|
79640
79675
|
var MAX_REFRESH_INTERVAL_MS = 60 * 60 * 1000;
|
|
@@ -79666,7 +79701,7 @@ function writeRefreshHeartbeat(agentName, data) {
|
|
|
79666
79701
|
function heartbeatPath(agentName) {
|
|
79667
79702
|
const override = process.env.SWITCHROOM_M365_HEARTBEAT_DIR;
|
|
79668
79703
|
if (override) {
|
|
79669
|
-
return
|
|
79704
|
+
return join71(override, `m365-launcher-${agentName}.heartbeat.json`);
|
|
79670
79705
|
}
|
|
79671
79706
|
return "/state/agent/m365-launcher.heartbeat.json";
|
|
79672
79707
|
}
|
|
@@ -79976,10 +80011,10 @@ function registerNotionMcpLauncherCommand(program3) {
|
|
|
79976
80011
|
// src/cli/deliver-file.ts
|
|
79977
80012
|
init_client2();
|
|
79978
80013
|
import { readFileSync as readFileSync59, statSync as statSync29 } from "node:fs";
|
|
79979
|
-
import { basename as
|
|
80014
|
+
import { basename as basename8 } from "node:path";
|
|
79980
80015
|
|
|
79981
80016
|
// src/delivery/onedrive.ts
|
|
79982
|
-
import { basename as
|
|
80017
|
+
import { basename as basename6 } from "node:path";
|
|
79983
80018
|
var GRAPH = "https://graph.microsoft.com/v1.0";
|
|
79984
80019
|
var ONEDRIVE_INLINE_MAX_BYTES = 4 * 1024 * 1024;
|
|
79985
80020
|
function authHeaders(token) {
|
|
@@ -80102,14 +80137,14 @@ async function createShareLink(deps, item, scopes = ["anonymous", "organization"
|
|
|
80102
80137
|
async function deliverToOneDrive(args) {
|
|
80103
80138
|
const deps = { accessToken: args.accessToken, fetchImpl: args.fetchImpl };
|
|
80104
80139
|
const folder = await ensureSwitchroomFolder(deps, args.agentName);
|
|
80105
|
-
const filename =
|
|
80140
|
+
const filename = basename6(args.localPath);
|
|
80106
80141
|
const item = await uploadFile(deps, folder.id, filename, args.bytes);
|
|
80107
80142
|
const link = await createShareLink(deps, item, args.linkScopes);
|
|
80108
80143
|
return { itemId: item.id, link, folderPath: `Switchroom/${args.agentName}` };
|
|
80109
80144
|
}
|
|
80110
80145
|
|
|
80111
80146
|
// src/delivery/gdrive.ts
|
|
80112
|
-
import { basename as
|
|
80147
|
+
import { basename as basename7 } from "node:path";
|
|
80113
80148
|
var DRIVE = "https://www.googleapis.com/drive/v3";
|
|
80114
80149
|
var UPLOAD = "https://www.googleapis.com/upload/drive/v3";
|
|
80115
80150
|
var FOLDER_MIME = "application/vnd.google-apps.folder";
|
|
@@ -80257,7 +80292,7 @@ async function createShareLink2(deps, file, scopes = ["anyone"]) {
|
|
|
80257
80292
|
async function deliverToGoogleDrive(args) {
|
|
80258
80293
|
const deps = { accessToken: args.accessToken, fetchImpl: args.fetchImpl };
|
|
80259
80294
|
const folder = await ensureSwitchroomFolder2(deps, args.agentName);
|
|
80260
|
-
const filename =
|
|
80295
|
+
const filename = basename7(args.localPath);
|
|
80261
80296
|
const file = await uploadFile2(deps, folder.id, filename, args.bytes);
|
|
80262
80297
|
const link = await createShareLink2(deps, file, args.linkScopes);
|
|
80263
80298
|
return { itemId: file.id, link, folderPath: `Switchroom/${args.agentName}` };
|
|
@@ -80336,7 +80371,7 @@ async function runDeliverFile(localPath, deps = {}) {
|
|
|
80336
80371
|
try {
|
|
80337
80372
|
const bytes = read(localPath);
|
|
80338
80373
|
const out = await provider.deliver({ agentName, localPath, bytes });
|
|
80339
|
-
return { ok: true, provider: provider.name, link: out.link, folderPath: out.folderPath, filename:
|
|
80374
|
+
return { ok: true, provider: provider.name, link: out.link, folderPath: out.folderPath, filename: basename8(localPath) };
|
|
80340
80375
|
} catch (err) {
|
|
80341
80376
|
return { ok: false, provider: provider.name, error: `upload failed: ${err.message}` };
|
|
80342
80377
|
}
|
|
@@ -80994,7 +81029,7 @@ agents:
|
|
|
80994
81029
|
|
|
80995
81030
|
// src/cli/apply.ts
|
|
80996
81031
|
init_resolver();
|
|
80997
|
-
import { dirname as dirname22, join as
|
|
81032
|
+
import { dirname as dirname22, join as join74, resolve as resolve44 } from "node:path";
|
|
80998
81033
|
import { homedir as homedir43 } from "node:os";
|
|
80999
81034
|
import { execFileSync as execFileSync24 } from "node:child_process";
|
|
81000
81035
|
init_vault();
|
|
@@ -81003,7 +81038,7 @@ init_loader();
|
|
|
81003
81038
|
|
|
81004
81039
|
// src/cli/update-prompt-hook.ts
|
|
81005
81040
|
import { existsSync as existsSync72, readFileSync as readFileSync60, writeFileSync as writeFileSync35, chmodSync as chmodSync10, mkdirSync as mkdirSync41 } from "node:fs";
|
|
81006
|
-
import { join as
|
|
81041
|
+
import { join as join72 } from "node:path";
|
|
81007
81042
|
var HOOK_FILENAME = "update-card-on-prompt.sh";
|
|
81008
81043
|
function updatePromptHookScript() {
|
|
81009
81044
|
return `#!/bin/bash
|
|
@@ -81069,9 +81104,9 @@ exit 0
|
|
|
81069
81104
|
`;
|
|
81070
81105
|
}
|
|
81071
81106
|
function installUpdatePromptHook(agentDir) {
|
|
81072
|
-
const hooksDir =
|
|
81107
|
+
const hooksDir = join72(agentDir, ".claude", "hooks");
|
|
81073
81108
|
mkdirSync41(hooksDir, { recursive: true });
|
|
81074
|
-
const scriptPath =
|
|
81109
|
+
const scriptPath = join72(hooksDir, HOOK_FILENAME);
|
|
81075
81110
|
const desired = updatePromptHookScript();
|
|
81076
81111
|
let installed = false;
|
|
81077
81112
|
const existing = existsSync72(scriptPath) ? readFileSync60(scriptPath, "utf-8") : "";
|
|
@@ -81084,7 +81119,7 @@ function installUpdatePromptHook(agentDir) {
|
|
|
81084
81119
|
chmodSync10(scriptPath, 493);
|
|
81085
81120
|
} catch {}
|
|
81086
81121
|
}
|
|
81087
|
-
const settingsPath =
|
|
81122
|
+
const settingsPath = join72(agentDir, ".claude", "settings.json");
|
|
81088
81123
|
if (!existsSync72(settingsPath)) {
|
|
81089
81124
|
return { scriptPath, settingsPath, installed };
|
|
81090
81125
|
}
|
|
@@ -81186,14 +81221,14 @@ var EMBEDDED_EXAMPLES = {
|
|
|
81186
81221
|
switchroom: switchroom_default,
|
|
81187
81222
|
minimal: minimal_default
|
|
81188
81223
|
};
|
|
81189
|
-
var DEFAULT_COMPOSE_PATH2 =
|
|
81224
|
+
var DEFAULT_COMPOSE_PATH2 = join74(homedir43(), ".switchroom", "compose", "docker-compose.yml");
|
|
81190
81225
|
var COMPOSE_PROJECT2 = "switchroom";
|
|
81191
81226
|
function resolveVaultBindMountDir(homeDir, ctx) {
|
|
81192
81227
|
const isCustomPath = ctx.migrationKind === "custom-path-skipped";
|
|
81193
81228
|
if (isCustomPath && ctx.customVaultPath) {
|
|
81194
81229
|
return dirname22(ctx.customVaultPath);
|
|
81195
81230
|
}
|
|
81196
|
-
return
|
|
81231
|
+
return join74(homeDir, ".switchroom", "vault");
|
|
81197
81232
|
}
|
|
81198
81233
|
function inspectVaultBindMountDir(vaultDir) {
|
|
81199
81234
|
if (!existsSync74(vaultDir))
|
|
@@ -81224,42 +81259,42 @@ function hasVaultRefs(value) {
|
|
|
81224
81259
|
async function ensureHostMountSources(config) {
|
|
81225
81260
|
const home2 = homedir43();
|
|
81226
81261
|
const dirs = [
|
|
81227
|
-
|
|
81228
|
-
|
|
81229
|
-
|
|
81230
|
-
|
|
81231
|
-
|
|
81262
|
+
join74(home2, ".switchroom", "approvals"),
|
|
81263
|
+
join74(home2, ".switchroom", "scheduler"),
|
|
81264
|
+
join74(home2, ".switchroom", "logs"),
|
|
81265
|
+
join74(home2, ".switchroom", "compose"),
|
|
81266
|
+
join74(home2, ".switchroom", "broker-operator")
|
|
81232
81267
|
];
|
|
81233
81268
|
for (const name of Object.keys(config.agents)) {
|
|
81234
|
-
dirs.push(
|
|
81235
|
-
dirs.push(
|
|
81236
|
-
dirs.push(
|
|
81237
|
-
dirs.push(
|
|
81238
|
-
if (existsSync74(
|
|
81239
|
-
dirs.push(
|
|
81269
|
+
dirs.push(join74(home2, ".switchroom", "agents", name));
|
|
81270
|
+
dirs.push(join74(home2, ".switchroom", "logs", name));
|
|
81271
|
+
dirs.push(join74(home2, ".claude", "projects", name));
|
|
81272
|
+
dirs.push(join74(home2, ".switchroom", "audit", name));
|
|
81273
|
+
if (existsSync74(join74(home2, ".switchroom-config"))) {
|
|
81274
|
+
dirs.push(join74(home2, ".switchroom-config", "agents", name, "personal-skills"));
|
|
81240
81275
|
}
|
|
81241
81276
|
}
|
|
81242
81277
|
for (const dir of dirs) {
|
|
81243
81278
|
await mkdir2(dir, { recursive: true });
|
|
81244
81279
|
}
|
|
81245
|
-
const autoUnlockPath =
|
|
81280
|
+
const autoUnlockPath = join74(home2, ".switchroom", "vault-auto-unlock");
|
|
81246
81281
|
if (!existsSync74(autoUnlockPath)) {
|
|
81247
81282
|
writeFileSync36(autoUnlockPath, "", { mode: 384 });
|
|
81248
81283
|
}
|
|
81249
|
-
const auditLogPath =
|
|
81284
|
+
const auditLogPath = join74(home2, ".switchroom", "vault-audit.log");
|
|
81250
81285
|
if (!existsSync74(auditLogPath)) {
|
|
81251
81286
|
writeFileSync36(auditLogPath, "", { mode: 420 });
|
|
81252
81287
|
}
|
|
81253
|
-
const grantsDbPath =
|
|
81288
|
+
const grantsDbPath = join74(home2, ".switchroom", "vault-grants.db");
|
|
81254
81289
|
if (!existsSync74(grantsDbPath)) {
|
|
81255
81290
|
writeFileSync36(grantsDbPath, "", { mode: 384 });
|
|
81256
81291
|
}
|
|
81257
|
-
const hostdAuditLogPath =
|
|
81292
|
+
const hostdAuditLogPath = join74(home2, ".switchroom", "host-control-audit.log");
|
|
81258
81293
|
if (!existsSync74(hostdAuditLogPath)) {
|
|
81259
81294
|
writeFileSync36(hostdAuditLogPath, "", { mode: 420 });
|
|
81260
81295
|
}
|
|
81261
81296
|
for (const name of Object.keys(config.agents)) {
|
|
81262
|
-
const tokenPath =
|
|
81297
|
+
const tokenPath = join74(home2, ".switchroom", "agents", name, ".vault-token");
|
|
81263
81298
|
if (!existsSync74(tokenPath)) {
|
|
81264
81299
|
writeFileSync36(tokenPath, "", { mode: 384 });
|
|
81265
81300
|
}
|
|
@@ -81268,15 +81303,15 @@ async function ensureHostMountSources(config) {
|
|
|
81268
81303
|
chownSync5(tokenPath, uid, uid);
|
|
81269
81304
|
} catch {}
|
|
81270
81305
|
}
|
|
81271
|
-
const fleetDir =
|
|
81306
|
+
const fleetDir = join74(home2, ".switchroom", "fleet");
|
|
81272
81307
|
await mkdir2(fleetDir, { recursive: true });
|
|
81273
|
-
const invariantsPath =
|
|
81308
|
+
const invariantsPath = join74(fleetDir, "switchroom-invariants.md");
|
|
81274
81309
|
const invariantsCanonical = renderFleetInvariants();
|
|
81275
81310
|
const invariantsCurrent = existsSync74(invariantsPath) ? readFileSync61(invariantsPath, "utf-8") : null;
|
|
81276
81311
|
if (invariantsCurrent !== invariantsCanonical) {
|
|
81277
81312
|
writeFileSync36(invariantsPath, invariantsCanonical, { mode: 420 });
|
|
81278
81313
|
}
|
|
81279
|
-
const fleetClaudePath =
|
|
81314
|
+
const fleetClaudePath = join74(fleetDir, "CLAUDE.md");
|
|
81280
81315
|
if (!existsSync74(fleetClaudePath)) {
|
|
81281
81316
|
writeFileSync36(fleetClaudePath, [
|
|
81282
81317
|
"# Switchroom fleet defaults",
|
|
@@ -81361,8 +81396,8 @@ function detectAndReportLegacyGdriveSlots(vaultPath) {
|
|
|
81361
81396
|
}
|
|
81362
81397
|
function writeInstallTypeCache(homeDir = homedir43()) {
|
|
81363
81398
|
const ctx = detectInstallType();
|
|
81364
|
-
const dir =
|
|
81365
|
-
const out =
|
|
81399
|
+
const dir = join74(homeDir, ".switchroom");
|
|
81400
|
+
const out = join74(dir, "install-type.json");
|
|
81366
81401
|
const tmp = `${out}.tmp`;
|
|
81367
81402
|
mkdirSync42(dir, { recursive: true });
|
|
81368
81403
|
const payload = {
|
|
@@ -81411,14 +81446,14 @@ Applying switchroom config...
|
|
|
81411
81446
|
writeOut(source_default.green(` + ${name}`) + source_default.gray(` (${agentConfig.extends ?? "default"}) \u2014 ${detail}
|
|
81412
81447
|
`));
|
|
81413
81448
|
try {
|
|
81414
|
-
installUpdatePromptHook(
|
|
81449
|
+
installUpdatePromptHook(join74(agentsDir, name));
|
|
81415
81450
|
} catch (hookErr) {
|
|
81416
81451
|
writeOut(source_default.gray(` (update-prompt hook install failed for ${name}: ${hookErr.message})
|
|
81417
81452
|
`));
|
|
81418
81453
|
}
|
|
81419
81454
|
try {
|
|
81420
81455
|
const uid = allocateAgentUid(name);
|
|
81421
|
-
alignAgentUid(name,
|
|
81456
|
+
alignAgentUid(name, join74(agentsDir, name), uid, {
|
|
81422
81457
|
confirm: !options.nonInteractive,
|
|
81423
81458
|
writeOut
|
|
81424
81459
|
});
|
|
@@ -81455,7 +81490,7 @@ Applying switchroom config...
|
|
|
81455
81490
|
for (const name of agentNames) {
|
|
81456
81491
|
try {
|
|
81457
81492
|
const uid = allocateAgentUid(name);
|
|
81458
|
-
alignAgentUid(name,
|
|
81493
|
+
alignAgentUid(name, join74(agentsDir, name), uid, {
|
|
81459
81494
|
confirm: !options.nonInteractive,
|
|
81460
81495
|
writeOut
|
|
81461
81496
|
});
|
|
@@ -81618,7 +81653,7 @@ function findUnwritableAgentDirs(config, opts) {
|
|
|
81618
81653
|
const targets = opts.only ? [opts.only] : Object.keys(config.agents ?? {});
|
|
81619
81654
|
const unwritable = [];
|
|
81620
81655
|
for (const name of targets) {
|
|
81621
|
-
const startSh =
|
|
81656
|
+
const startSh = join74(agentsDir, name, "start.sh");
|
|
81622
81657
|
if (!existsSync74(startSh))
|
|
81623
81658
|
continue;
|
|
81624
81659
|
try {
|
|
@@ -81685,7 +81720,7 @@ function registerApplyCommand(program3) {
|
|
|
81685
81720
|
}
|
|
81686
81721
|
const parentOpts = program3.opts();
|
|
81687
81722
|
const config = loadConfig(parentOpts.config);
|
|
81688
|
-
const switchroomConfigPath = parentOpts.config ?? findConfigFile();
|
|
81723
|
+
const switchroomConfigPath = resolveHostSwitchroomConfigPath(parentOpts.config ?? findConfigFile());
|
|
81689
81724
|
if (opts.printSudoCmd) {
|
|
81690
81725
|
const argv = ["sudo", ...buildSelfElevateArgv()];
|
|
81691
81726
|
process.stdout.write(argv.join(" ") + `
|
|
@@ -81798,7 +81833,7 @@ function runRedactStdin() {
|
|
|
81798
81833
|
|
|
81799
81834
|
// src/cli/status-ask.ts
|
|
81800
81835
|
import { readFileSync as readFileSync62, existsSync as existsSync75, readdirSync as readdirSync27 } from "node:fs";
|
|
81801
|
-
import { join as
|
|
81836
|
+
import { join as join75 } from "node:path";
|
|
81802
81837
|
import { homedir as homedir44 } from "node:os";
|
|
81803
81838
|
|
|
81804
81839
|
// src/status-ask/report.ts
|
|
@@ -82134,7 +82169,7 @@ function resolveSources(explicitPath) {
|
|
|
82134
82169
|
const config = loadConfig();
|
|
82135
82170
|
agentsDir = resolveAgentsDir(config);
|
|
82136
82171
|
} catch {
|
|
82137
|
-
agentsDir =
|
|
82172
|
+
agentsDir = join75(homedir44(), ".switchroom", "agents");
|
|
82138
82173
|
}
|
|
82139
82174
|
if (!existsSync75(agentsDir))
|
|
82140
82175
|
return [];
|
|
@@ -82146,7 +82181,7 @@ function resolveSources(explicitPath) {
|
|
|
82146
82181
|
return [];
|
|
82147
82182
|
}
|
|
82148
82183
|
for (const name of entries) {
|
|
82149
|
-
const path8 =
|
|
82184
|
+
const path8 = join75(agentsDir, name, "runtime-metrics.jsonl");
|
|
82150
82185
|
if (existsSync75(path8)) {
|
|
82151
82186
|
sources.push({ path: path8, agent: name });
|
|
82152
82187
|
}
|
|
@@ -82184,21 +82219,21 @@ import {
|
|
|
82184
82219
|
unlinkSync as unlinkSync14,
|
|
82185
82220
|
writeSync as writeSync8
|
|
82186
82221
|
} from "node:fs";
|
|
82187
|
-
import { join as
|
|
82222
|
+
import { join as join76, resolve as resolve45 } from "node:path";
|
|
82188
82223
|
var STAGING_SUBDIR = ".staging";
|
|
82189
82224
|
function overlayPathsFor(agent, opts = {}) {
|
|
82190
82225
|
const base = opts.root ? resolve45(opts.root, agent) : resolve45(resolveDualPath(`~/.switchroom/agents/${agent}`));
|
|
82191
|
-
const scheduleDir =
|
|
82192
|
-
const scheduleStagingDir =
|
|
82193
|
-
const skillsDir =
|
|
82194
|
-
const skillsStagingDir =
|
|
82226
|
+
const scheduleDir = join76(base, "schedule.d");
|
|
82227
|
+
const scheduleStagingDir = join76(scheduleDir, STAGING_SUBDIR);
|
|
82228
|
+
const skillsDir = join76(base, "skills.d");
|
|
82229
|
+
const skillsStagingDir = join76(skillsDir, STAGING_SUBDIR);
|
|
82195
82230
|
return {
|
|
82196
82231
|
agentRoot: base,
|
|
82197
82232
|
scheduleDir,
|
|
82198
82233
|
scheduleStagingDir,
|
|
82199
82234
|
skillsDir,
|
|
82200
82235
|
skillsStagingDir,
|
|
82201
|
-
lockPath:
|
|
82236
|
+
lockPath: join76(base, ".lock"),
|
|
82202
82237
|
stagingDir: scheduleStagingDir
|
|
82203
82238
|
};
|
|
82204
82239
|
}
|
|
@@ -82252,8 +82287,8 @@ function writeOverlayEntry(agent, slug, yamlText, opts = {}) {
|
|
|
82252
82287
|
const paths = overlayPathsFor(agent, opts);
|
|
82253
82288
|
return withAgentLock(paths, () => {
|
|
82254
82289
|
ensureDirs(paths);
|
|
82255
|
-
const stagingPath =
|
|
82256
|
-
const finalPath =
|
|
82290
|
+
const stagingPath = join76(paths.scheduleStagingDir, `${slug}.yaml`);
|
|
82291
|
+
const finalPath = join76(paths.scheduleDir, `${slug}.yaml`);
|
|
82257
82292
|
const fd = openSync13(stagingPath, "w", 384);
|
|
82258
82293
|
try {
|
|
82259
82294
|
writeSync8(fd, yamlText);
|
|
@@ -82269,8 +82304,8 @@ function writeSkillsOverlayEntry(agent, slug, yamlText, opts = {}) {
|
|
|
82269
82304
|
const paths = overlayPathsFor(agent, opts);
|
|
82270
82305
|
return withAgentLock(paths, () => {
|
|
82271
82306
|
ensureSkillsDirs(paths);
|
|
82272
|
-
const stagingPath =
|
|
82273
|
-
const finalPath =
|
|
82307
|
+
const stagingPath = join76(paths.skillsStagingDir, `${slug}.yaml`);
|
|
82308
|
+
const finalPath = join76(paths.skillsDir, `${slug}.yaml`);
|
|
82274
82309
|
const fd = openSync13(stagingPath, "w", 384);
|
|
82275
82310
|
try {
|
|
82276
82311
|
writeSync8(fd, yamlText);
|
|
@@ -82285,7 +82320,7 @@ function writeSkillsOverlayEntry(agent, slug, yamlText, opts = {}) {
|
|
|
82285
82320
|
function deleteSkillsOverlayEntry(agent, slug, opts = {}) {
|
|
82286
82321
|
const paths = overlayPathsFor(agent, opts);
|
|
82287
82322
|
return withAgentLock(paths, () => {
|
|
82288
|
-
const finalPath =
|
|
82323
|
+
const finalPath = join76(paths.skillsDir, `${slug}.yaml`);
|
|
82289
82324
|
if (!existsSync76(finalPath))
|
|
82290
82325
|
return false;
|
|
82291
82326
|
unlinkSync14(finalPath);
|
|
@@ -82300,7 +82335,7 @@ function listSkillsOverlayEntries(agent, opts = {}) {
|
|
|
82300
82335
|
for (const name of readdirSync28(paths.skillsDir)) {
|
|
82301
82336
|
if (!/\.ya?ml$/i.test(name))
|
|
82302
82337
|
continue;
|
|
82303
|
-
const full =
|
|
82338
|
+
const full = join76(paths.skillsDir, name);
|
|
82304
82339
|
try {
|
|
82305
82340
|
const raw = readFileSync63(full, "utf-8");
|
|
82306
82341
|
const slug = name.replace(/\.ya?ml$/i, "");
|
|
@@ -82312,7 +82347,7 @@ function listSkillsOverlayEntries(agent, opts = {}) {
|
|
|
82312
82347
|
function deleteOverlayEntry(agent, slug, opts = {}) {
|
|
82313
82348
|
const paths = overlayPathsFor(agent, opts);
|
|
82314
82349
|
return withAgentLock(paths, () => {
|
|
82315
|
-
const finalPath =
|
|
82350
|
+
const finalPath = join76(paths.scheduleDir, `${slug}.yaml`);
|
|
82316
82351
|
if (!existsSync76(finalPath))
|
|
82317
82352
|
return false;
|
|
82318
82353
|
unlinkSync14(finalPath);
|
|
@@ -82327,7 +82362,7 @@ function listOverlayEntries(agent, opts = {}) {
|
|
|
82327
82362
|
for (const name of readdirSync28(paths.scheduleDir)) {
|
|
82328
82363
|
if (!/\.ya?ml$/i.test(name))
|
|
82329
82364
|
continue;
|
|
82330
|
-
const full =
|
|
82365
|
+
const full = join76(paths.scheduleDir, name);
|
|
82331
82366
|
try {
|
|
82332
82367
|
const raw = readFileSync63(full, "utf-8");
|
|
82333
82368
|
const slug = name.replace(/\.ya?ml$/i, "");
|
|
@@ -82483,12 +82518,12 @@ import {
|
|
|
82483
82518
|
writeFileSync as writeFileSync37,
|
|
82484
82519
|
writeSync as writeSync9
|
|
82485
82520
|
} from "node:fs";
|
|
82486
|
-
import { join as
|
|
82521
|
+
import { join as join77 } from "node:path";
|
|
82487
82522
|
import { randomBytes as randomBytes14 } from "node:crypto";
|
|
82488
82523
|
var STAGE_ID_PREFIX = "cap_";
|
|
82489
82524
|
function pendingDir(agent, opts = {}) {
|
|
82490
82525
|
const paths = overlayPathsFor(agent, opts);
|
|
82491
|
-
return
|
|
82526
|
+
return join77(paths.scheduleDir, ".pending");
|
|
82492
82527
|
}
|
|
82493
82528
|
function ensurePendingDir(agent, opts = {}) {
|
|
82494
82529
|
const dir = pendingDir(agent, opts);
|
|
@@ -82501,8 +82536,8 @@ function newStageId() {
|
|
|
82501
82536
|
function stagePendingScheduleEntry(opts) {
|
|
82502
82537
|
const dir = ensurePendingDir(opts.agent, { root: opts.root });
|
|
82503
82538
|
const stageId = opts.stageId ?? newStageId();
|
|
82504
|
-
const yamlPath =
|
|
82505
|
-
const metaPath =
|
|
82539
|
+
const yamlPath = join77(dir, `${stageId}.yaml`);
|
|
82540
|
+
const metaPath = join77(dir, `${stageId}.meta.json`);
|
|
82506
82541
|
const meta = {
|
|
82507
82542
|
v: 1,
|
|
82508
82543
|
stage_id: stageId,
|
|
@@ -82536,8 +82571,8 @@ function listPendingScheduleEntries(agent, opts = {}) {
|
|
|
82536
82571
|
if (!name.endsWith(".meta.json"))
|
|
82537
82572
|
continue;
|
|
82538
82573
|
const stageId = name.slice(0, -".meta.json".length);
|
|
82539
|
-
const metaPath =
|
|
82540
|
-
const yamlPath =
|
|
82574
|
+
const metaPath = join77(dir, name);
|
|
82575
|
+
const yamlPath = join77(dir, `${stageId}.yaml`);
|
|
82541
82576
|
if (!existsSync77(yamlPath))
|
|
82542
82577
|
continue;
|
|
82543
82578
|
try {
|
|
@@ -82556,7 +82591,7 @@ function commitPendingScheduleEntry(opts) {
|
|
|
82556
82591
|
return { committed: false, reason: "not_found" };
|
|
82557
82592
|
const slug = match.meta.entry.name ?? match.stageId;
|
|
82558
82593
|
const paths = overlayPathsFor(opts.agent, { root: opts.root });
|
|
82559
|
-
const finalPath =
|
|
82594
|
+
const finalPath = join77(paths.scheduleDir, `${slug}.yaml`);
|
|
82560
82595
|
if (existsSync77(finalPath)) {
|
|
82561
82596
|
return { committed: false, reason: "slug_collision" };
|
|
82562
82597
|
}
|
|
@@ -83171,7 +83206,7 @@ var import_yaml20 = __toESM(require_dist(), 1);
|
|
|
83171
83206
|
import { existsSync as existsSync79 } from "node:fs";
|
|
83172
83207
|
init_reconcile_default_skills();
|
|
83173
83208
|
var import_yaml21 = __toESM(require_dist(), 1);
|
|
83174
|
-
import { join as
|
|
83209
|
+
import { join as join78 } from "node:path";
|
|
83175
83210
|
var MAX_SKILLS_PER_AGENT = 20;
|
|
83176
83211
|
var V1_ALLOWED_SOURCE_PREFIX = "bundled:";
|
|
83177
83212
|
function exitCodeFor2(code) {
|
|
@@ -83246,7 +83281,7 @@ function skillInstall(opts) {
|
|
|
83246
83281
|
return err("E_SKILL_QUOTA_EXCEEDED", `agent ${agent} already has ${used} overlay-installed skills (cap ${MAX_SKILLS_PER_AGENT})`);
|
|
83247
83282
|
}
|
|
83248
83283
|
const poolDir = opts.bundledSkillsPoolDir ?? getBundledSkillsPoolDir();
|
|
83249
|
-
const skillPath =
|
|
83284
|
+
const skillPath = join78(poolDir, skillName);
|
|
83250
83285
|
if (!existsSync79(skillPath)) {
|
|
83251
83286
|
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.`);
|
|
83252
83287
|
}
|
|
@@ -83425,7 +83460,7 @@ import {
|
|
|
83425
83460
|
writeFileSync as writeFileSync38
|
|
83426
83461
|
} from "node:fs";
|
|
83427
83462
|
import { tmpdir as tmpdir5, homedir as homedir45 } from "node:os";
|
|
83428
|
-
import { dirname as dirname23, join as
|
|
83463
|
+
import { dirname as dirname23, join as join79, relative as relative2, resolve as resolve46 } from "node:path";
|
|
83429
83464
|
import { spawnSync as spawnSync11 } from "node:child_process";
|
|
83430
83465
|
|
|
83431
83466
|
// src/cli/skill-common.ts
|
|
@@ -83619,7 +83654,7 @@ function scanForClaudeP2(content) {
|
|
|
83619
83654
|
function resolveSkillsPoolDir2(override) {
|
|
83620
83655
|
const raw = override ?? "~/.switchroom/skills";
|
|
83621
83656
|
if (raw.startsWith("~/")) {
|
|
83622
|
-
return
|
|
83657
|
+
return join79(homedir45(), raw.slice(2));
|
|
83623
83658
|
}
|
|
83624
83659
|
if (raw === "~")
|
|
83625
83660
|
return homedir45();
|
|
@@ -83658,7 +83693,7 @@ function loadFromDir(dir) {
|
|
|
83658
83693
|
const walk2 = (sub) => {
|
|
83659
83694
|
const entries = readdirSync30(sub, { withFileTypes: true });
|
|
83660
83695
|
for (const ent of entries) {
|
|
83661
|
-
const full =
|
|
83696
|
+
const full = join79(sub, ent.name);
|
|
83662
83697
|
const rel = relative2(abs, full);
|
|
83663
83698
|
if (ent.isSymbolicLink()) {
|
|
83664
83699
|
fail2(`refusing to read symlink inside --from dir: ${rel}`);
|
|
@@ -83693,7 +83728,7 @@ function loadFromTarball(tarPath) {
|
|
|
83693
83728
|
fail2(`tarball contains disallowed path: ${JSON.stringify(entry)} \u2014 ` + `refusing to extract before any file is written`);
|
|
83694
83729
|
}
|
|
83695
83730
|
}
|
|
83696
|
-
const staging = mkdtempSync5(
|
|
83731
|
+
const staging = mkdtempSync5(join79(tmpdir5(), "skill-apply-extract-"));
|
|
83697
83732
|
try {
|
|
83698
83733
|
const flags = isGz ? ["-xzf"] : ["-xf"];
|
|
83699
83734
|
const r = spawnSync11("tar", [
|
|
@@ -83779,8 +83814,8 @@ function validatePayload(name, files) {
|
|
|
83779
83814
|
errors2.push(`${path8} fails \`bash -n\` syntax check: ${(r.stderr ?? "").trim()}`);
|
|
83780
83815
|
}
|
|
83781
83816
|
} else if (PY_SCRIPT_RE2.test(path8)) {
|
|
83782
|
-
const tmp = mkdtempSync5(
|
|
83783
|
-
const tmpPy =
|
|
83817
|
+
const tmp = mkdtempSync5(join79(tmpdir5(), "skill-apply-py-"));
|
|
83818
|
+
const tmpPy = join79(tmp, "check.py");
|
|
83784
83819
|
try {
|
|
83785
83820
|
writeFileSync38(tmpPy, content);
|
|
83786
83821
|
const r = spawnSync11("python3", ["-m", "py_compile", tmpPy], {
|
|
@@ -83803,7 +83838,7 @@ function diffSummary(currentDir, files) {
|
|
|
83803
83838
|
if (existsSync80(currentDir)) {
|
|
83804
83839
|
const walk2 = (sub) => {
|
|
83805
83840
|
for (const ent of readdirSync30(sub, { withFileTypes: true })) {
|
|
83806
|
-
const full =
|
|
83841
|
+
const full = join79(sub, ent.name);
|
|
83807
83842
|
const rel = relative2(currentDir, full);
|
|
83808
83843
|
if (ent.isDirectory()) {
|
|
83809
83844
|
walk2(full);
|
|
@@ -83839,7 +83874,7 @@ function writePayload(poolDir, name, files) {
|
|
|
83839
83874
|
if (!existsSync80(poolDir)) {
|
|
83840
83875
|
mkdirSync45(poolDir, { recursive: true, mode: 493 });
|
|
83841
83876
|
}
|
|
83842
|
-
const target =
|
|
83877
|
+
const target = join79(poolDir, name);
|
|
83843
83878
|
let targetIsSymlink = false;
|
|
83844
83879
|
try {
|
|
83845
83880
|
const st = lstatSync8(target);
|
|
@@ -83850,11 +83885,11 @@ function writePayload(poolDir, name, files) {
|
|
|
83850
83885
|
if (targetIsSymlink) {
|
|
83851
83886
|
fail2(`refusing to overwrite symlink at ${target}; investigate manually`);
|
|
83852
83887
|
}
|
|
83853
|
-
const staging = mkdtempSync5(
|
|
83888
|
+
const staging = mkdtempSync5(join79(poolDir, `.skill-apply-stage-${name}-`));
|
|
83854
83889
|
let oldRename = null;
|
|
83855
83890
|
try {
|
|
83856
83891
|
for (const [path8, content] of Object.entries(files)) {
|
|
83857
|
-
const full =
|
|
83892
|
+
const full = join79(staging, path8);
|
|
83858
83893
|
mkdirSync45(dirname23(full), { recursive: true, mode: 493 });
|
|
83859
83894
|
const fd = openSync15(full, "wx");
|
|
83860
83895
|
try {
|
|
@@ -83932,7 +83967,7 @@ function registerSkillCommand(program3) {
|
|
|
83932
83967
|
}
|
|
83933
83968
|
const config = loadConfig();
|
|
83934
83969
|
const poolDir = resolveSkillsPoolDir2(config.switchroom?.skills_dir);
|
|
83935
|
-
const currentDir =
|
|
83970
|
+
const currentDir = join79(poolDir, name);
|
|
83936
83971
|
console.log(source_default.bold(`Skill: ${name}`) + source_default.gray(` (${Object.keys(files).length} files, ${sumBytes(files)} bytes)`));
|
|
83937
83972
|
console.log(source_default.bold("Diff vs current pool content:"));
|
|
83938
83973
|
console.log(diffSummary(currentDir, files));
|
|
@@ -83976,7 +84011,7 @@ import {
|
|
|
83976
84011
|
utimesSync,
|
|
83977
84012
|
writeFileSync as writeFileSync39
|
|
83978
84013
|
} from "node:fs";
|
|
83979
|
-
import { dirname as dirname24, join as
|
|
84014
|
+
import { dirname as dirname24, join as join80, relative as relative3, resolve as resolve47 } from "node:path";
|
|
83980
84015
|
import { homedir as homedir46, tmpdir as tmpdir6 } from "node:os";
|
|
83981
84016
|
import { spawnSync as spawnSync12 } from "node:child_process";
|
|
83982
84017
|
init_helpers();
|
|
@@ -83987,10 +84022,10 @@ var TRASH_TTL_MS = 24 * 60 * 60 * 1000;
|
|
|
83987
84022
|
var PERSONAL_SKILLS_SUBPATH = "personal-skills";
|
|
83988
84023
|
function resolveConfigSkillsDir(agent) {
|
|
83989
84024
|
const override = process.env.SWITCHROOM_CONFIG_DIR;
|
|
83990
|
-
const candidate = override ? resolve47(override) :
|
|
84025
|
+
const candidate = override ? resolve47(override) : join80(homedir46(), ".switchroom-config");
|
|
83991
84026
|
if (!existsSync81(candidate))
|
|
83992
84027
|
return null;
|
|
83993
|
-
return
|
|
84028
|
+
return join80(candidate, "agents", agent, PERSONAL_SKILLS_SUBPATH);
|
|
83994
84029
|
}
|
|
83995
84030
|
var MIRROR_PRIOR_TTL_MS = 24 * 60 * 60 * 1000;
|
|
83996
84031
|
function sweepMirrorPriors(configSkillsRoot) {
|
|
@@ -84008,7 +84043,7 @@ function sweepMirrorPriors(configSkillsRoot) {
|
|
|
84008
84043
|
if (now - ts < MIRROR_PRIOR_TTL_MS)
|
|
84009
84044
|
continue;
|
|
84010
84045
|
try {
|
|
84011
|
-
rmSync17(
|
|
84046
|
+
rmSync17(join80(configSkillsRoot, ent), { recursive: true, force: true });
|
|
84012
84047
|
} catch {}
|
|
84013
84048
|
}
|
|
84014
84049
|
} catch {}
|
|
@@ -84017,7 +84052,7 @@ function mirrorToConfigRepo(agent, name, liveSkillDir) {
|
|
|
84017
84052
|
const configSkillsRoot = resolveConfigSkillsDir(agent);
|
|
84018
84053
|
if (!configSkillsRoot)
|
|
84019
84054
|
return;
|
|
84020
|
-
const dest =
|
|
84055
|
+
const dest = join80(configSkillsRoot, name);
|
|
84021
84056
|
try {
|
|
84022
84057
|
if (liveSkillDir !== null) {
|
|
84023
84058
|
try {
|
|
@@ -84032,19 +84067,19 @@ function mirrorToConfigRepo(agent, name, liveSkillDir) {
|
|
|
84032
84067
|
if (liveSkillDir === null) {
|
|
84033
84068
|
sweepMirrorPriors(configSkillsRoot);
|
|
84034
84069
|
if (existsSync81(dest)) {
|
|
84035
|
-
const trash =
|
|
84070
|
+
const trash = join80(configSkillsRoot, `.${name}-trash-${Date.now()}`);
|
|
84036
84071
|
renameSync18(dest, trash);
|
|
84037
84072
|
}
|
|
84038
84073
|
return;
|
|
84039
84074
|
}
|
|
84040
84075
|
mkdirSync46(configSkillsRoot, { recursive: true, mode: 493 });
|
|
84041
84076
|
sweepMirrorPriors(configSkillsRoot);
|
|
84042
|
-
const staging = mkdtempSync6(
|
|
84077
|
+
const staging = mkdtempSync6(join80(configSkillsRoot, `.${name}-staging-`));
|
|
84043
84078
|
const walk2 = (src, dst) => {
|
|
84044
84079
|
mkdirSync46(dst, { recursive: true, mode: 493 });
|
|
84045
84080
|
for (const ent of readdirSync31(src, { withFileTypes: true })) {
|
|
84046
|
-
const s =
|
|
84047
|
-
const d =
|
|
84081
|
+
const s = join80(src, ent.name);
|
|
84082
|
+
const d = join80(dst, ent.name);
|
|
84048
84083
|
if (ent.isSymbolicLink())
|
|
84049
84084
|
continue;
|
|
84050
84085
|
if (ent.isDirectory())
|
|
@@ -84056,7 +84091,7 @@ function mirrorToConfigRepo(agent, name, liveSkillDir) {
|
|
|
84056
84091
|
};
|
|
84057
84092
|
walk2(liveSkillDir, staging);
|
|
84058
84093
|
if (existsSync81(dest)) {
|
|
84059
|
-
const prior =
|
|
84094
|
+
const prior = join80(configSkillsRoot, `.${name}-prior-${Date.now()}`);
|
|
84060
84095
|
renameSync18(dest, prior);
|
|
84061
84096
|
}
|
|
84062
84097
|
renameSync18(staging, dest);
|
|
@@ -84083,13 +84118,13 @@ function resolveAgent(opts) {
|
|
|
84083
84118
|
function resolveAgentsRoot(opts) {
|
|
84084
84119
|
if (opts.root)
|
|
84085
84120
|
return resolve47(opts.root);
|
|
84086
|
-
return
|
|
84121
|
+
return join80(homedir46(), ".switchroom", "agents");
|
|
84087
84122
|
}
|
|
84088
84123
|
function personalSkillDir(agentsRoot, agent, name) {
|
|
84089
|
-
return
|
|
84124
|
+
return join80(agentsRoot, agent, ".claude", "skills", PERSONAL_PREFIX + name);
|
|
84090
84125
|
}
|
|
84091
84126
|
function trashDir(agentsRoot, agent) {
|
|
84092
|
-
return
|
|
84127
|
+
return join80(agentsRoot, agent, ".claude", TRASH_DIRNAME);
|
|
84093
84128
|
}
|
|
84094
84129
|
function readStdinSync2() {
|
|
84095
84130
|
const chunks = [];
|
|
@@ -84119,7 +84154,7 @@ function loadFromDir2(dir) {
|
|
|
84119
84154
|
const files = {};
|
|
84120
84155
|
const walk2 = (sub) => {
|
|
84121
84156
|
for (const ent of readdirSync31(sub, { withFileTypes: true })) {
|
|
84122
|
-
const full =
|
|
84157
|
+
const full = join80(sub, ent.name);
|
|
84123
84158
|
if (ent.isSymbolicLink()) {
|
|
84124
84159
|
fail3(`refusing to read symlink in --from dir: ${relative3(abs, full)}`);
|
|
84125
84160
|
}
|
|
@@ -84172,8 +84207,8 @@ function behavioralValidate(files) {
|
|
|
84172
84207
|
errors2.push(`${path8} fails \`bash -n\`: ${(r.stderr ?? "").trim()}`);
|
|
84173
84208
|
}
|
|
84174
84209
|
} else if (PY_SCRIPT_RE.test(path8)) {
|
|
84175
|
-
const tmp = mkdtempSync6(
|
|
84176
|
-
const tmpPy =
|
|
84210
|
+
const tmp = mkdtempSync6(join80(tmpdir6(), "skill-personal-py-"));
|
|
84211
|
+
const tmpPy = join80(tmp, "check.py");
|
|
84177
84212
|
try {
|
|
84178
84213
|
writeFileSync39(tmpPy, content);
|
|
84179
84214
|
const r = spawnSync12("python3", ["-m", "py_compile", tmpPy], {
|
|
@@ -84197,7 +84232,7 @@ function sweepTrash(agentsRoot, agent) {
|
|
|
84197
84232
|
for (const ent of readdirSync31(trash, { withFileTypes: true })) {
|
|
84198
84233
|
if (!ent.isDirectory())
|
|
84199
84234
|
continue;
|
|
84200
|
-
const entPath =
|
|
84235
|
+
const entPath = join80(trash, ent.name);
|
|
84201
84236
|
try {
|
|
84202
84237
|
const st = statSync32(entPath);
|
|
84203
84238
|
if (now - st.mtimeMs > TRASH_TTL_MS) {
|
|
@@ -84218,11 +84253,11 @@ function writePersonalSkill(targetDir, files) {
|
|
|
84218
84253
|
fail3(`refusing to overwrite symlink at ${targetDir}; investigate manually`);
|
|
84219
84254
|
}
|
|
84220
84255
|
mkdirSync46(dirname24(targetDir), { recursive: true, mode: 493 });
|
|
84221
|
-
const staging = mkdtempSync6(
|
|
84256
|
+
const staging = mkdtempSync6(join80(dirname24(targetDir), `.skill-personal-stage-`));
|
|
84222
84257
|
let oldRename = null;
|
|
84223
84258
|
try {
|
|
84224
84259
|
for (const [path8, content] of Object.entries(files)) {
|
|
84225
|
-
const full =
|
|
84260
|
+
const full = join80(staging, path8);
|
|
84226
84261
|
mkdirSync46(dirname24(full), { recursive: true, mode: 493 });
|
|
84227
84262
|
const fd = openSync16(full, "wx");
|
|
84228
84263
|
try {
|
|
@@ -84355,10 +84390,10 @@ function editPersonalAction(name, opts) {
|
|
|
84355
84390
|
}
|
|
84356
84391
|
var CLONE_SOURCE_RE = /^(shared|bundled):([a-z0-9][a-z0-9_-]{0,62})$/;
|
|
84357
84392
|
function defaultSharedRoot() {
|
|
84358
|
-
return
|
|
84393
|
+
return join80(homedir46(), ".switchroom", "skills");
|
|
84359
84394
|
}
|
|
84360
84395
|
function defaultBundledRoot() {
|
|
84361
|
-
return
|
|
84396
|
+
return join80(homedir46(), ".switchroom", "skills", "_bundled");
|
|
84362
84397
|
}
|
|
84363
84398
|
function resolveCloneSource(source, opts) {
|
|
84364
84399
|
const m = CLONE_SOURCE_RE.exec(source);
|
|
@@ -84368,7 +84403,7 @@ function resolveCloneSource(source, opts) {
|
|
|
84368
84403
|
const tier = m[1];
|
|
84369
84404
|
const slug = m[2];
|
|
84370
84405
|
const root = tier === "bundled" ? opts.bundledRoot ?? defaultBundledRoot() : opts.sharedRoot ?? defaultSharedRoot();
|
|
84371
|
-
const dir =
|
|
84406
|
+
const dir = join80(root, slug);
|
|
84372
84407
|
if (!existsSync81(dir)) {
|
|
84373
84408
|
fail3(`clone source ${JSON.stringify(source)} not found at ${dir}; ` + `check \`switchroom skill search --tier ${tier}\``, 1);
|
|
84374
84409
|
}
|
|
@@ -84384,7 +84419,7 @@ function readSourceFiles(dir) {
|
|
|
84384
84419
|
const skipped = [];
|
|
84385
84420
|
const walk2 = (sub) => {
|
|
84386
84421
|
for (const ent of readdirSync31(sub, { withFileTypes: true })) {
|
|
84387
|
-
const full =
|
|
84422
|
+
const full = join80(sub, ent.name);
|
|
84388
84423
|
if (ent.isSymbolicLink()) {
|
|
84389
84424
|
continue;
|
|
84390
84425
|
}
|
|
@@ -84495,7 +84530,7 @@ function removePersonalAction(name, opts) {
|
|
|
84495
84530
|
const trashRoot = trashDir(agentsRoot, agent);
|
|
84496
84531
|
mkdirSync46(trashRoot, { recursive: true, mode: 493 });
|
|
84497
84532
|
const ts = Date.now();
|
|
84498
|
-
const trashTarget =
|
|
84533
|
+
const trashTarget = join80(trashRoot, `${name}-${ts}`);
|
|
84499
84534
|
renameSync18(target, trashTarget);
|
|
84500
84535
|
const now = new Date(ts);
|
|
84501
84536
|
utimesSync(trashTarget, now, now);
|
|
@@ -84514,7 +84549,7 @@ function listPersonalAction(opts) {
|
|
|
84514
84549
|
const agent = resolveAgent(opts);
|
|
84515
84550
|
const agentsRoot = resolveAgentsRoot(opts);
|
|
84516
84551
|
sweepTrash(agentsRoot, agent);
|
|
84517
|
-
const skillsDir =
|
|
84552
|
+
const skillsDir = join80(agentsRoot, agent, ".claude", "skills");
|
|
84518
84553
|
const personal = [];
|
|
84519
84554
|
if (existsSync81(skillsDir)) {
|
|
84520
84555
|
for (const ent of readdirSync31(skillsDir, { withFileTypes: true })) {
|
|
@@ -84523,7 +84558,7 @@ function listPersonalAction(opts) {
|
|
|
84523
84558
|
if (!ent.name.startsWith(PERSONAL_PREFIX))
|
|
84524
84559
|
continue;
|
|
84525
84560
|
const skillName = ent.name.slice(PERSONAL_PREFIX.length);
|
|
84526
|
-
const skillPath =
|
|
84561
|
+
const skillPath = join80(skillsDir, ent.name);
|
|
84527
84562
|
let fileCount = 0;
|
|
84528
84563
|
let totalBytes = 0;
|
|
84529
84564
|
const walk2 = (sub) => {
|
|
@@ -84531,10 +84566,10 @@ function listPersonalAction(opts) {
|
|
|
84531
84566
|
if (e.isFile()) {
|
|
84532
84567
|
fileCount += 1;
|
|
84533
84568
|
try {
|
|
84534
|
-
totalBytes += statSync32(
|
|
84569
|
+
totalBytes += statSync32(join80(sub, e.name)).size;
|
|
84535
84570
|
} catch {}
|
|
84536
84571
|
} else if (e.isDirectory()) {
|
|
84537
|
-
walk2(
|
|
84572
|
+
walk2(join80(sub, e.name));
|
|
84538
84573
|
}
|
|
84539
84574
|
}
|
|
84540
84575
|
};
|
|
@@ -84575,7 +84610,7 @@ init_helpers();
|
|
|
84575
84610
|
var import_yaml23 = __toESM(require_dist(), 1);
|
|
84576
84611
|
import { existsSync as existsSync82, readdirSync as readdirSync32, readFileSync as readFileSync68, statSync as statSync33 } from "node:fs";
|
|
84577
84612
|
import { homedir as homedir47 } from "node:os";
|
|
84578
|
-
import { join as
|
|
84613
|
+
import { join as join81, resolve as resolve48 } from "node:path";
|
|
84579
84614
|
var PERSONAL_PREFIX2 = "personal-";
|
|
84580
84615
|
var BUNDLED_SUBDIR = "_bundled";
|
|
84581
84616
|
var AGENT_NAME_RE3 = /^[a-z][a-z0-9_-]{0,62}$/;
|
|
@@ -84589,7 +84624,7 @@ function defaultBundledRoot2() {
|
|
|
84589
84624
|
return resolve48(homedir47(), ".switchroom/skills/_bundled");
|
|
84590
84625
|
}
|
|
84591
84626
|
function readSkillFrontmatter(skillDir) {
|
|
84592
|
-
const mdPath =
|
|
84627
|
+
const mdPath = join81(skillDir, "SKILL.md");
|
|
84593
84628
|
if (!existsSync82(mdPath))
|
|
84594
84629
|
return null;
|
|
84595
84630
|
let content;
|
|
@@ -84622,7 +84657,7 @@ function readSkillFrontmatter(skillDir) {
|
|
|
84622
84657
|
return { fm: parsed };
|
|
84623
84658
|
}
|
|
84624
84659
|
function statSkillMd(skillDir) {
|
|
84625
|
-
const mdPath =
|
|
84660
|
+
const mdPath = join81(skillDir, "SKILL.md");
|
|
84626
84661
|
try {
|
|
84627
84662
|
const st = statSync33(mdPath);
|
|
84628
84663
|
return { size: st.size, mtime: st.mtime.toISOString() };
|
|
@@ -84633,7 +84668,7 @@ function statSkillMd(skillDir) {
|
|
|
84633
84668
|
function listPersonalSkills(agent, agentsRoot = defaultAgentsRoot()) {
|
|
84634
84669
|
if (!AGENT_NAME_RE3.test(agent))
|
|
84635
84670
|
return [];
|
|
84636
|
-
const skillsDir =
|
|
84671
|
+
const skillsDir = join81(agentsRoot, agent, ".claude/skills");
|
|
84637
84672
|
if (!existsSync82(skillsDir))
|
|
84638
84673
|
return [];
|
|
84639
84674
|
const out = [];
|
|
@@ -84646,7 +84681,7 @@ function listPersonalSkills(agent, agentsRoot = defaultAgentsRoot()) {
|
|
|
84646
84681
|
for (const ent of entries) {
|
|
84647
84682
|
if (!ent.startsWith(PERSONAL_PREFIX2))
|
|
84648
84683
|
continue;
|
|
84649
|
-
const dirPath =
|
|
84684
|
+
const dirPath = join81(skillsDir, ent);
|
|
84650
84685
|
try {
|
|
84651
84686
|
if (!statSync33(dirPath).isDirectory())
|
|
84652
84687
|
continue;
|
|
@@ -84686,7 +84721,7 @@ function listSharedSkills(sharedRoot = defaultSharedRoot2()) {
|
|
|
84686
84721
|
continue;
|
|
84687
84722
|
if (ent.startsWith("."))
|
|
84688
84723
|
continue;
|
|
84689
|
-
const dirPath =
|
|
84724
|
+
const dirPath = join81(sharedRoot, ent);
|
|
84690
84725
|
try {
|
|
84691
84726
|
if (!statSync33(dirPath).isDirectory())
|
|
84692
84727
|
continue;
|
|
@@ -84722,7 +84757,7 @@ function listBundledSkills(bundledRoot = defaultBundledRoot2()) {
|
|
|
84722
84757
|
for (const ent of entries) {
|
|
84723
84758
|
if (ent.startsWith("."))
|
|
84724
84759
|
continue;
|
|
84725
|
-
const dirPath =
|
|
84760
|
+
const dirPath = join81(bundledRoot, ent);
|
|
84726
84761
|
try {
|
|
84727
84762
|
if (!statSync33(dirPath).isDirectory())
|
|
84728
84763
|
continue;
|
|
@@ -84868,7 +84903,7 @@ init_source();
|
|
|
84868
84903
|
init_helpers();
|
|
84869
84904
|
import { existsSync as existsSync84, mkdirSync as mkdirSync47, readdirSync as readdirSync33, readFileSync as readFileSync70, writeFileSync as writeFileSync40, statSync as statSync34, copyFileSync as copyFileSync12 } from "node:fs";
|
|
84870
84905
|
import { homedir as homedir48 } from "node:os";
|
|
84871
|
-
import { join as
|
|
84906
|
+
import { join as join82 } from "node:path";
|
|
84872
84907
|
import { spawnSync as spawnSync14 } from "node:child_process";
|
|
84873
84908
|
init_audit_reader();
|
|
84874
84909
|
var DEFAULT_IMAGE_TAG = "latest";
|
|
@@ -84937,6 +84972,19 @@ services:
|
|
|
84937
84972
|
# operator's home), so the socket paths the agent fleet sees
|
|
84938
84973
|
# (~/.switchroom/hostd/<agent>/sock) match the paths hostd binds.
|
|
84939
84974
|
HOME: /host-home
|
|
84975
|
+
# The REAL host home path. HOME above is pinned to /host-home (the
|
|
84976
|
+
# in-container mount point) for the socket-path convention, but that
|
|
84977
|
+
# is NOT a host filesystem path. When hostd shells out \`switchroom
|
|
84978
|
+
# apply\` / \`agent restart\`, the compose generator must emit HOST
|
|
84979
|
+
# paths as bind-mount SOURCES \u2014 homedir() inside here returns
|
|
84980
|
+
# /host-home, which docker would auto-create as empty dirs on the
|
|
84981
|
+
# host (start.sh missing \u2192 every agent exec-fails 127; broker EISDIR
|
|
84982
|
+
# \u2014 the 2026-06-11/12 fleet outages). SWITCHROOM_HOST_HOME is the
|
|
84983
|
+
# generator's authoritative host home (write-compose.ts prefers it
|
|
84984
|
+
# over homedir(); compose.ts bakes it into each agent). Without it,
|
|
84985
|
+
# an in-container apply poisons every bind source with /host-home AND
|
|
84986
|
+
# re-bakes /host-home into the fleet, self-perpetuating.
|
|
84987
|
+
SWITCHROOM_HOST_HOME: ${hostHome}
|
|
84940
84988
|
# Hostd's CLI shellouts (\`switchroom <verb>\`) need to pick up the
|
|
84941
84989
|
# same config the agent fleet's compose generator did. Point at
|
|
84942
84990
|
# the resolved /state/config bind so the agent fleet's config-path
|
|
@@ -84959,10 +85007,10 @@ networks:
|
|
|
84959
85007
|
`;
|
|
84960
85008
|
}
|
|
84961
85009
|
function hostdDir() {
|
|
84962
|
-
return
|
|
85010
|
+
return join82(homedir48(), ".switchroom", "hostd");
|
|
84963
85011
|
}
|
|
84964
85012
|
function hostdComposePath() {
|
|
84965
|
-
return
|
|
85013
|
+
return join82(hostdDir(), "docker-compose.yml");
|
|
84966
85014
|
}
|
|
84967
85015
|
function backupExistingCompose() {
|
|
84968
85016
|
const p = hostdComposePath();
|
|
@@ -85072,7 +85120,7 @@ function doStatus() {
|
|
|
85072
85120
|
for (const name of readdirSync33(dir)) {
|
|
85073
85121
|
if (name === "docker-compose.yml" || name.startsWith("docker-compose.yml."))
|
|
85074
85122
|
continue;
|
|
85075
|
-
const sockPath =
|
|
85123
|
+
const sockPath = join82(dir, name, "sock");
|
|
85076
85124
|
if (existsSync84(sockPath)) {
|
|
85077
85125
|
const st = statSync34(sockPath);
|
|
85078
85126
|
if ((st.mode & 61440) === 49152) {
|
|
@@ -85165,7 +85213,7 @@ init_source();
|
|
|
85165
85213
|
init_helpers();
|
|
85166
85214
|
import { existsSync as existsSync85, mkdirSync as mkdirSync48, writeFileSync as writeFileSync41, copyFileSync as copyFileSync13 } from "node:fs";
|
|
85167
85215
|
import { homedir as homedir49 } from "node:os";
|
|
85168
|
-
import { join as
|
|
85216
|
+
import { join as join83 } from "node:path";
|
|
85169
85217
|
import { spawnSync as spawnSync15 } from "node:child_process";
|
|
85170
85218
|
var DEFAULT_IMAGE_TAG2 = "latest";
|
|
85171
85219
|
var WEB_COMPOSE_PROJECT = "switchroom-web";
|
|
@@ -85246,10 +85294,10 @@ services:
|
|
|
85246
85294
|
`;
|
|
85247
85295
|
}
|
|
85248
85296
|
function webdDir() {
|
|
85249
|
-
return
|
|
85297
|
+
return join83(homedir49(), ".switchroom", "web");
|
|
85250
85298
|
}
|
|
85251
85299
|
function webdComposePath() {
|
|
85252
|
-
return
|
|
85300
|
+
return join83(webdDir(), "docker-compose.yml");
|
|
85253
85301
|
}
|
|
85254
85302
|
function backupExistingCompose2() {
|
|
85255
85303
|
const p = webdComposePath();
|