switchroom 0.14.92 → 0.14.93
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/switchroom.js +935 -887
- package/package.json +1 -1
- package/telegram-plugin/dist/gateway/gateway.js +48 -8
- package/telegram-plugin/gateway/gateway.ts +81 -4
- package/telegram-plugin/gateway/obligation-ledger.ts +47 -8
- package/telegram-plugin/gateway/turn-active-marker.ts +22 -0
- package/telegram-plugin/tests/obligation-determinism.test.ts +63 -3
- package/telegram-plugin/tests/obligation-ledger.test.ts +85 -0
- package/telegram-plugin/tests/turn-active-marker.test.ts +28 -0
package/dist/cli/switchroom.js
CHANGED
|
@@ -23137,42 +23137,6 @@ var init_resolver = __esm(() => {
|
|
|
23137
23137
|
materializedDirs = new Set;
|
|
23138
23138
|
});
|
|
23139
23139
|
|
|
23140
|
-
// src/agents/tmux.ts
|
|
23141
|
-
import { execFileSync as execFileSync5 } from "node:child_process";
|
|
23142
|
-
function sendAgentInterrupt(opts) {
|
|
23143
|
-
const { agentName } = opts;
|
|
23144
|
-
const attempts = typeof opts.attempts === "number" && opts.attempts > 0 ? opts.attempts : 1;
|
|
23145
|
-
const retryDelayMs = typeof opts.retryDelayMs === "number" && opts.retryDelayMs >= 0 ? opts.retryDelayMs : 100;
|
|
23146
|
-
const socket = `switchroom-${agentName}`;
|
|
23147
|
-
const args = ["-L", socket, "send-keys", "-t", agentName, "C-c"];
|
|
23148
|
-
let lastError = null;
|
|
23149
|
-
for (let i = 0;i < attempts; i++) {
|
|
23150
|
-
try {
|
|
23151
|
-
execFileSync5("tmux", args, {
|
|
23152
|
-
timeout: 3000,
|
|
23153
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
23154
|
-
});
|
|
23155
|
-
return { ok: true };
|
|
23156
|
-
} catch (err) {
|
|
23157
|
-
lastError = `tmux send-keys C-c failed: ${err.message}`;
|
|
23158
|
-
console.error(`[tmux-interrupt] ${agentName}: ${lastError}`);
|
|
23159
|
-
}
|
|
23160
|
-
if (i < attempts - 1 && retryDelayMs > 0) {
|
|
23161
|
-
sleepSync(retryDelayMs);
|
|
23162
|
-
}
|
|
23163
|
-
}
|
|
23164
|
-
return { error: lastError ?? "tmux send-keys C-c failed" };
|
|
23165
|
-
}
|
|
23166
|
-
function sleepSync(ms) {
|
|
23167
|
-
const sab = new SharedArrayBuffer(4);
|
|
23168
|
-
const view = new Int32Array(sab);
|
|
23169
|
-
Atomics.wait(view, 0, 0, ms);
|
|
23170
|
-
}
|
|
23171
|
-
var MAX_BYTES;
|
|
23172
|
-
var init_tmux = __esm(() => {
|
|
23173
|
-
MAX_BYTES = 10 * 1024 * 1024;
|
|
23174
|
-
});
|
|
23175
|
-
|
|
23176
23140
|
// src/agents/compose.ts
|
|
23177
23141
|
import { createHash as createHash3 } from "node:crypto";
|
|
23178
23142
|
import { existsSync as existsSync14, mkdirSync as mkdirSync10, readFileSync as readFileSync12 } from "node:fs";
|
|
@@ -23804,10 +23768,46 @@ var init_compose = __esm(() => {
|
|
|
23804
23768
|
BIND_MOUNT_EXACT_SOURCE_DENY = new Set(["/var/run/docker.sock"]);
|
|
23805
23769
|
});
|
|
23806
23770
|
|
|
23771
|
+
// src/agents/tmux.ts
|
|
23772
|
+
import { execFileSync as execFileSync5 } from "node:child_process";
|
|
23773
|
+
function sendAgentInterrupt(opts) {
|
|
23774
|
+
const { agentName } = opts;
|
|
23775
|
+
const attempts = typeof opts.attempts === "number" && opts.attempts > 0 ? opts.attempts : 1;
|
|
23776
|
+
const retryDelayMs = typeof opts.retryDelayMs === "number" && opts.retryDelayMs >= 0 ? opts.retryDelayMs : 100;
|
|
23777
|
+
const socket = `switchroom-${agentName}`;
|
|
23778
|
+
const args = ["-L", socket, "send-keys", "-t", agentName, "C-c"];
|
|
23779
|
+
let lastError = null;
|
|
23780
|
+
for (let i = 0;i < attempts; i++) {
|
|
23781
|
+
try {
|
|
23782
|
+
execFileSync5("tmux", args, {
|
|
23783
|
+
timeout: 3000,
|
|
23784
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
23785
|
+
});
|
|
23786
|
+
return { ok: true };
|
|
23787
|
+
} catch (err) {
|
|
23788
|
+
lastError = `tmux send-keys C-c failed: ${err.message}`;
|
|
23789
|
+
console.error(`[tmux-interrupt] ${agentName}: ${lastError}`);
|
|
23790
|
+
}
|
|
23791
|
+
if (i < attempts - 1 && retryDelayMs > 0) {
|
|
23792
|
+
sleepSync(retryDelayMs);
|
|
23793
|
+
}
|
|
23794
|
+
}
|
|
23795
|
+
return { error: lastError ?? "tmux send-keys C-c failed" };
|
|
23796
|
+
}
|
|
23797
|
+
function sleepSync(ms) {
|
|
23798
|
+
const sab = new SharedArrayBuffer(4);
|
|
23799
|
+
const view = new Int32Array(sab);
|
|
23800
|
+
Atomics.wait(view, 0, 0, ms);
|
|
23801
|
+
}
|
|
23802
|
+
var MAX_BYTES;
|
|
23803
|
+
var init_tmux = __esm(() => {
|
|
23804
|
+
MAX_BYTES = 10 * 1024 * 1024;
|
|
23805
|
+
});
|
|
23806
|
+
|
|
23807
23807
|
// src/agents/docker-fleet.ts
|
|
23808
23808
|
import { resolve as resolve12 } from "node:path";
|
|
23809
23809
|
import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync6 } from "node:fs";
|
|
23810
|
-
import { homedir as
|
|
23810
|
+
import { homedir as homedir6 } from "node:os";
|
|
23811
23811
|
import { execFileSync as execFileSync6 } from "node:child_process";
|
|
23812
23812
|
function resolveSwitchroomHome(explicit) {
|
|
23813
23813
|
if (explicit && explicit.length > 0)
|
|
@@ -23831,7 +23831,7 @@ function bringUpAgentService(opts) {
|
|
|
23831
23831
|
}
|
|
23832
23832
|
const compose = opts.generateComposeContent?.() ?? generateCompose({
|
|
23833
23833
|
config: opts.config,
|
|
23834
|
-
homeDir:
|
|
23834
|
+
homeDir: homedir6(),
|
|
23835
23835
|
switchroomConfigPath
|
|
23836
23836
|
});
|
|
23837
23837
|
const composePath = resolve12(composeDir, "docker-compose.yml");
|
|
@@ -23952,18 +23952,18 @@ var init_singleton_reconcile = __esm(() => {
|
|
|
23952
23952
|
|
|
23953
23953
|
// src/agents/lifecycle.ts
|
|
23954
23954
|
import { execFileSync as execFileSync8, spawn, spawnSync } from "node:child_process";
|
|
23955
|
-
import { existsSync as
|
|
23956
|
-
import { resolve as resolve13, join as
|
|
23955
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync12, writeFileSync as writeFileSync7, renameSync as renameSync4, readFileSync as readFileSync14 } from "node:fs";
|
|
23956
|
+
import { resolve as resolve13, join as join11 } from "node:path";
|
|
23957
23957
|
import { connect } from "node:net";
|
|
23958
23958
|
function cleanShutdownMarkerPathForAgent(name) {
|
|
23959
23959
|
const agentsDir = process.env.SWITCHROOM_AGENTS_DIR ?? resolveStatePath("agents");
|
|
23960
|
-
return
|
|
23960
|
+
return join11(agentsDir, name, "telegram", "clean-shutdown.json");
|
|
23961
23961
|
}
|
|
23962
23962
|
function writeRestartReasonMarker(name, reason, opts = {}) {
|
|
23963
23963
|
const path = cleanShutdownMarkerPathForAgent(name);
|
|
23964
23964
|
try {
|
|
23965
|
-
mkdirSync12(
|
|
23966
|
-
if (opts.preserveExisting &&
|
|
23965
|
+
mkdirSync12(join11(path, ".."), { recursive: true });
|
|
23966
|
+
if (opts.preserveExisting && existsSync16(path)) {
|
|
23967
23967
|
try {
|
|
23968
23968
|
const prev = JSON.parse(readFileSync14(path, "utf-8"));
|
|
23969
23969
|
if (prev && typeof prev.ts === "number" && Date.now() - prev.ts < 30000 && prev.reason) {
|
|
@@ -24066,8 +24066,8 @@ function gracefulRestartAgent(name) {
|
|
|
24066
24066
|
return new Promise((resolvePromise, reject) => {
|
|
24067
24067
|
const agentsDir = process.env.SWITCHROOM_AGENTS_DIR ?? resolveStatePath("agents");
|
|
24068
24068
|
const agentDir = resolve13(agentsDir, name);
|
|
24069
|
-
const socketPath = process.env.SWITCHROOM_GATEWAY_SOCKET ??
|
|
24070
|
-
if (!
|
|
24069
|
+
const socketPath = process.env.SWITCHROOM_GATEWAY_SOCKET ?? join11(agentDir, "telegram", "gateway.sock");
|
|
24070
|
+
if (!existsSync16(socketPath)) {
|
|
24071
24071
|
reject(new Error("Gateway socket not found. Is the gateway running?"));
|
|
24072
24072
|
return;
|
|
24073
24073
|
}
|
|
@@ -24452,40 +24452,40 @@ var init_pane_ready_probe = () => {};
|
|
|
24452
24452
|
// src/auth/accounts.ts
|
|
24453
24453
|
import {
|
|
24454
24454
|
copyFileSync as copyFileSync5,
|
|
24455
|
-
existsSync as
|
|
24455
|
+
existsSync as existsSync20,
|
|
24456
24456
|
mkdirSync as mkdirSync14,
|
|
24457
24457
|
readFileSync as readFileSync18,
|
|
24458
|
-
readdirSync as
|
|
24458
|
+
readdirSync as readdirSync10,
|
|
24459
24459
|
renameSync as renameSync6,
|
|
24460
24460
|
rmSync as rmSync4,
|
|
24461
|
-
statSync as
|
|
24461
|
+
statSync as statSync12,
|
|
24462
24462
|
writeFileSync as writeFileSync9
|
|
24463
24463
|
} from "node:fs";
|
|
24464
24464
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
24465
|
-
import { join as
|
|
24465
|
+
import { join as join14 } from "node:path";
|
|
24466
24466
|
function claudeDir(agentDir) {
|
|
24467
|
-
return
|
|
24467
|
+
return join14(agentDir, ".claude");
|
|
24468
24468
|
}
|
|
24469
24469
|
function accountsDir(agentDir) {
|
|
24470
|
-
return
|
|
24470
|
+
return join14(claudeDir(agentDir), "accounts");
|
|
24471
24471
|
}
|
|
24472
24472
|
function slotDir(agentDir, slot) {
|
|
24473
|
-
return
|
|
24473
|
+
return join14(accountsDir(agentDir), slot);
|
|
24474
24474
|
}
|
|
24475
24475
|
function slotTokenPath(agentDir, slot) {
|
|
24476
|
-
return
|
|
24476
|
+
return join14(slotDir(agentDir, slot), ".oauth-token");
|
|
24477
24477
|
}
|
|
24478
24478
|
function slotMetaPath(agentDir, slot) {
|
|
24479
|
-
return
|
|
24479
|
+
return join14(slotDir(agentDir, slot), ".oauth-token.meta.json");
|
|
24480
24480
|
}
|
|
24481
24481
|
function activeMarkerPath(agentDir) {
|
|
24482
|
-
return
|
|
24482
|
+
return join14(claudeDir(agentDir), "active");
|
|
24483
24483
|
}
|
|
24484
24484
|
function legacyTokenPath(agentDir) {
|
|
24485
|
-
return
|
|
24485
|
+
return join14(claudeDir(agentDir), ".oauth-token");
|
|
24486
24486
|
}
|
|
24487
24487
|
function legacyMetaPath(agentDir) {
|
|
24488
|
-
return
|
|
24488
|
+
return join14(claudeDir(agentDir), ".oauth-token.meta.json");
|
|
24489
24489
|
}
|
|
24490
24490
|
function validateSlotName(slot) {
|
|
24491
24491
|
if (typeof slot !== "string" || slot.length === 0) {
|
|
@@ -24506,7 +24506,7 @@ function validateSlotName(slot) {
|
|
|
24506
24506
|
}
|
|
24507
24507
|
function readActiveSlot(agentDir) {
|
|
24508
24508
|
const p = activeMarkerPath(agentDir);
|
|
24509
|
-
if (!
|
|
24509
|
+
if (!existsSync20(p))
|
|
24510
24510
|
return null;
|
|
24511
24511
|
try {
|
|
24512
24512
|
const val = readFileSync18(p, "utf-8").trim();
|
|
@@ -24523,12 +24523,12 @@ function writeActiveSlot(agentDir, slot) {
|
|
|
24523
24523
|
}
|
|
24524
24524
|
function listSlots(agentDir) {
|
|
24525
24525
|
const dir = accountsDir(agentDir);
|
|
24526
|
-
if (!
|
|
24526
|
+
if (!existsSync20(dir))
|
|
24527
24527
|
return [];
|
|
24528
24528
|
try {
|
|
24529
|
-
return
|
|
24529
|
+
return readdirSync10(dir).filter((name) => {
|
|
24530
24530
|
try {
|
|
24531
|
-
return
|
|
24531
|
+
return statSync12(join14(dir, name)).isDirectory();
|
|
24532
24532
|
} catch {
|
|
24533
24533
|
return false;
|
|
24534
24534
|
}
|
|
@@ -24538,11 +24538,11 @@ function listSlots(agentDir) {
|
|
|
24538
24538
|
}
|
|
24539
24539
|
}
|
|
24540
24540
|
function slotExists(agentDir, slot) {
|
|
24541
|
-
return
|
|
24541
|
+
return existsSync20(slotTokenPath(agentDir, slot));
|
|
24542
24542
|
}
|
|
24543
24543
|
function readSlotMeta(agentDir, slot) {
|
|
24544
24544
|
const p = slotMetaPath(agentDir, slot);
|
|
24545
|
-
if (!
|
|
24545
|
+
if (!existsSync20(p))
|
|
24546
24546
|
return null;
|
|
24547
24547
|
try {
|
|
24548
24548
|
return JSON.parse(readFileSync18(p, "utf-8"));
|
|
@@ -24585,11 +24585,11 @@ function syncLegacyFromActive(agentDir) {
|
|
|
24585
24585
|
return;
|
|
24586
24586
|
const srcToken = slotTokenPath(agentDir, active);
|
|
24587
24587
|
const srcMeta = slotMetaPath(agentDir, active);
|
|
24588
|
-
if (!
|
|
24588
|
+
if (!existsSync20(srcToken))
|
|
24589
24589
|
return;
|
|
24590
24590
|
mkdirSync14(claudeDir(agentDir), { recursive: true });
|
|
24591
24591
|
atomicCopy(srcToken, legacyTokenPath(agentDir), 384);
|
|
24592
|
-
if (
|
|
24592
|
+
if (existsSync20(srcMeta)) {
|
|
24593
24593
|
atomicCopy(srcMeta, legacyMetaPath(agentDir), 384);
|
|
24594
24594
|
}
|
|
24595
24595
|
}
|
|
@@ -24613,7 +24613,7 @@ function migrateLegacyIfNeeded(agentDir) {
|
|
|
24613
24613
|
return { migrated: false };
|
|
24614
24614
|
}
|
|
24615
24615
|
const legacyToken = legacyTokenPath(agentDir);
|
|
24616
|
-
if (!
|
|
24616
|
+
if (!existsSync20(legacyToken)) {
|
|
24617
24617
|
if (slots.length === 1 && slotExists(agentDir, slots[0])) {
|
|
24618
24618
|
writeActiveSlot(agentDir, slots[0]);
|
|
24619
24619
|
syncLegacyFromActive(agentDir);
|
|
@@ -24635,7 +24635,7 @@ function migrateLegacyIfNeeded(agentDir) {
|
|
|
24635
24635
|
writeFileSync9(slotTokenPath(agentDir, slot), token + `
|
|
24636
24636
|
`, { mode: 384 });
|
|
24637
24637
|
const legacyMeta = legacyMetaPath(agentDir);
|
|
24638
|
-
if (
|
|
24638
|
+
if (existsSync20(legacyMeta)) {
|
|
24639
24639
|
try {
|
|
24640
24640
|
copyFileSync5(legacyMeta, slotMetaPath(agentDir, slot));
|
|
24641
24641
|
} catch {
|
|
@@ -24698,16 +24698,16 @@ var init_accounts = __esm(() => {
|
|
|
24698
24698
|
import { execFileSync as execFileSync11 } from "node:child_process";
|
|
24699
24699
|
import {
|
|
24700
24700
|
readFileSync as readFileSync19,
|
|
24701
|
-
readdirSync as
|
|
24702
|
-
existsSync as
|
|
24701
|
+
readdirSync as readdirSync11,
|
|
24702
|
+
existsSync as existsSync21,
|
|
24703
24703
|
writeFileSync as writeFileSync10,
|
|
24704
24704
|
mkdirSync as mkdirSync15,
|
|
24705
24705
|
mkdtempSync as mkdtempSync2,
|
|
24706
24706
|
rmSync as rmSync5,
|
|
24707
24707
|
chmodSync as chmodSync3,
|
|
24708
|
-
statSync as
|
|
24708
|
+
statSync as statSync13
|
|
24709
24709
|
} from "node:fs";
|
|
24710
|
-
import { join as
|
|
24710
|
+
import { join as join15, resolve as resolve15 } from "node:path";
|
|
24711
24711
|
function extractCodeChallenge(url) {
|
|
24712
24712
|
const match = url.match(/[?&]code_challenge=([A-Za-z0-9_-]+)/);
|
|
24713
24713
|
return match ? match[1] : null;
|
|
@@ -24722,22 +24722,22 @@ function stripAnsi(text) {
|
|
|
24722
24722
|
return text.replace(/\x1B\[[0-9;?]*[ -/]*[@-~]/g, "").replace(/\x1B[@-_]/g, "").replace(/\r/g, "");
|
|
24723
24723
|
}
|
|
24724
24724
|
function claudeDir2(agentDir) {
|
|
24725
|
-
return
|
|
24725
|
+
return join15(agentDir, ".claude");
|
|
24726
24726
|
}
|
|
24727
24727
|
function credentialsPath(agentDir) {
|
|
24728
|
-
return
|
|
24728
|
+
return join15(claudeDir2(agentDir), ".credentials.json");
|
|
24729
24729
|
}
|
|
24730
24730
|
function oauthTokenPath(agentDir) {
|
|
24731
|
-
return
|
|
24731
|
+
return join15(claudeDir2(agentDir), ".oauth-token");
|
|
24732
24732
|
}
|
|
24733
24733
|
function oauthTokenMetaPath(agentDir) {
|
|
24734
|
-
return
|
|
24734
|
+
return join15(claudeDir2(agentDir), ".oauth-token.meta.json");
|
|
24735
24735
|
}
|
|
24736
24736
|
function authLogPath(agentDir) {
|
|
24737
|
-
return
|
|
24737
|
+
return join15(claudeDir2(agentDir), ".setup-token.log");
|
|
24738
24738
|
}
|
|
24739
24739
|
function authSessionMetaPath(agentDir) {
|
|
24740
|
-
return
|
|
24740
|
+
return join15(claudeDir2(agentDir), ".setup-token.session.json");
|
|
24741
24741
|
}
|
|
24742
24742
|
function authSessionName(name, slot) {
|
|
24743
24743
|
const base = `switchroom-auth-${name.replace(/[^a-zA-Z0-9_.-]/g, "-")}`;
|
|
@@ -24765,7 +24765,7 @@ function captureTmuxPane(sessionName) {
|
|
|
24765
24765
|
return tmux(["capture-pane", "-p", "-t", sessionName, "-S", "-200"]);
|
|
24766
24766
|
}
|
|
24767
24767
|
function readJsonFile(path) {
|
|
24768
|
-
if (!
|
|
24768
|
+
if (!existsSync21(path))
|
|
24769
24769
|
return null;
|
|
24770
24770
|
try {
|
|
24771
24771
|
return JSON.parse(readFileSync19(path, "utf-8"));
|
|
@@ -24775,7 +24775,7 @@ function readJsonFile(path) {
|
|
|
24775
24775
|
}
|
|
24776
24776
|
function readOAuthToken(agentDir) {
|
|
24777
24777
|
const path = oauthTokenPath(agentDir);
|
|
24778
|
-
if (!
|
|
24778
|
+
if (!existsSync21(path))
|
|
24779
24779
|
return null;
|
|
24780
24780
|
try {
|
|
24781
24781
|
const token = readFileSync19(path, "utf-8").trim();
|
|
@@ -24787,7 +24787,7 @@ function readOAuthToken(agentDir) {
|
|
|
24787
24787
|
function authFilesAreInaccessible(agentDir) {
|
|
24788
24788
|
const probes = [credentialsPath(agentDir), oauthTokenPath(agentDir)];
|
|
24789
24789
|
for (const p of probes) {
|
|
24790
|
-
if (!
|
|
24790
|
+
if (!existsSync21(p))
|
|
24791
24791
|
continue;
|
|
24792
24792
|
try {
|
|
24793
24793
|
readFileSync19(p, "utf-8");
|
|
@@ -24818,7 +24818,7 @@ function writeOAuthToken(agentDir, token, slot) {
|
|
|
24818
24818
|
}
|
|
24819
24819
|
function fileMtimeMs(filePath) {
|
|
24820
24820
|
try {
|
|
24821
|
-
return
|
|
24821
|
+
return statSync13(filePath).mtimeMs;
|
|
24822
24822
|
} catch {
|
|
24823
24823
|
return 0;
|
|
24824
24824
|
}
|
|
@@ -24852,12 +24852,12 @@ function isSessionStale(agentDir, sessionName) {
|
|
|
24852
24852
|
}
|
|
24853
24853
|
function cleanupAuthTempDirs(agentDir) {
|
|
24854
24854
|
const dir = claudeDir2(agentDir);
|
|
24855
|
-
if (!
|
|
24855
|
+
if (!existsSync21(dir))
|
|
24856
24856
|
return;
|
|
24857
24857
|
try {
|
|
24858
|
-
for (const entry of
|
|
24858
|
+
for (const entry of readdirSync11(dir)) {
|
|
24859
24859
|
if (entry.startsWith(".setup-token-tmp-")) {
|
|
24860
|
-
rmSync5(
|
|
24860
|
+
rmSync5(join15(dir, entry), { recursive: true, force: true });
|
|
24861
24861
|
}
|
|
24862
24862
|
}
|
|
24863
24863
|
} catch {}
|
|
@@ -24887,7 +24887,7 @@ function parseSetupTokenValue(output) {
|
|
|
24887
24887
|
}
|
|
24888
24888
|
function readTokenFromCredentialsFile(credentialsFilePath) {
|
|
24889
24889
|
try {
|
|
24890
|
-
if (!
|
|
24890
|
+
if (!existsSync21(credentialsFilePath))
|
|
24891
24891
|
return null;
|
|
24892
24892
|
const raw = readFileSync19(credentialsFilePath, "utf-8");
|
|
24893
24893
|
const parsed = JSON.parse(raw);
|
|
@@ -24910,7 +24910,7 @@ function hasPendingAuthSession(name, agentDir) {
|
|
|
24910
24910
|
}
|
|
24911
24911
|
function readCredentials(agentDir) {
|
|
24912
24912
|
const credPath = credentialsPath(agentDir);
|
|
24913
|
-
if (!
|
|
24913
|
+
if (!existsSync21(credPath))
|
|
24914
24914
|
return null;
|
|
24915
24915
|
try {
|
|
24916
24916
|
const parsed = JSON.parse(readFileSync19(credPath, "utf-8"));
|
|
@@ -24922,9 +24922,9 @@ function readCredentials(agentDir) {
|
|
|
24922
24922
|
function getAuthStatus(name, agentDir) {
|
|
24923
24923
|
const pendingAuth = hasPendingAuthSession(name, agentDir);
|
|
24924
24924
|
const creds = readCredentials(agentDir);
|
|
24925
|
-
if (!
|
|
24925
|
+
if (!existsSync21(oauthTokenPath(agentDir))) {
|
|
24926
24926
|
const activeSlot = readActiveSlot(agentDir);
|
|
24927
|
-
if (activeSlot &&
|
|
24927
|
+
if (activeSlot && existsSync21(slotTokenPath(agentDir, activeSlot))) {
|
|
24928
24928
|
try {
|
|
24929
24929
|
syncLegacyFromActive(agentDir);
|
|
24930
24930
|
} catch {}
|
|
@@ -25018,14 +25018,14 @@ function startAuthSession(name, agentDir, opts = {}) {
|
|
|
25018
25018
|
rmSync5(logPath, { force: true });
|
|
25019
25019
|
let configDir;
|
|
25020
25020
|
if (opts.force) {
|
|
25021
|
-
configDir = mkdtempSync2(
|
|
25021
|
+
configDir = mkdtempSync2(join15(claudeDir2(agentDir), ".setup-token-tmp-"));
|
|
25022
25022
|
try {
|
|
25023
25023
|
chmodSync3(configDir, 448);
|
|
25024
25024
|
} catch {}
|
|
25025
25025
|
} else {
|
|
25026
25026
|
configDir = claudeDir2(agentDir);
|
|
25027
25027
|
}
|
|
25028
|
-
const credentialsMtimeAtStart = fileMtimeMs(
|
|
25028
|
+
const credentialsMtimeAtStart = fileMtimeMs(join15(configDir, ".credentials.json"));
|
|
25029
25029
|
const commandParts = [];
|
|
25030
25030
|
commandParts.push(`CLAUDE_CONFIG_DIR=${shellQuote(configDir)}`);
|
|
25031
25031
|
commandParts.push(`LOG_PATH=${shellQuote(logPath)}`);
|
|
@@ -25066,7 +25066,7 @@ function startAuthSession(name, agentDir, opts = {}) {
|
|
|
25066
25066
|
};
|
|
25067
25067
|
}
|
|
25068
25068
|
function readTokenFromLogFile(logPath) {
|
|
25069
|
-
if (!
|
|
25069
|
+
if (!existsSync21(logPath))
|
|
25070
25070
|
return null;
|
|
25071
25071
|
try {
|
|
25072
25072
|
const content = readFileSync19(logPath, "utf-8");
|
|
@@ -25113,7 +25113,7 @@ function submitAuthCode(name, agentDir, code, slot, _opts = {}) {
|
|
|
25113
25113
|
tmux(["send-keys", "-l", "-t", sessionName, code.trim()]);
|
|
25114
25114
|
tmux(["send-keys", "-t", sessionName, "Enter"]);
|
|
25115
25115
|
const meta = readJsonFile(authSessionMetaPath(agentDir));
|
|
25116
|
-
const credFileToWatch = meta?.configDir ?
|
|
25116
|
+
const credFileToWatch = meta?.configDir ? join15(meta.configDir, ".credentials.json") : credentialsPath(agentDir);
|
|
25117
25117
|
const credsMtimeSnapshot = meta?.credentialsMtimeAtStart ?? 0;
|
|
25118
25118
|
const logPath = authLogPath(agentDir);
|
|
25119
25119
|
let token = null;
|
|
@@ -25213,19 +25213,19 @@ var init_manager = __esm(() => {
|
|
|
25213
25213
|
|
|
25214
25214
|
// src/agents/quarantine.ts
|
|
25215
25215
|
import {
|
|
25216
|
-
existsSync as
|
|
25216
|
+
existsSync as existsSync26,
|
|
25217
25217
|
mkdirSync as mkdirSync16,
|
|
25218
25218
|
readFileSync as readFileSync21,
|
|
25219
25219
|
unlinkSync as unlinkSync6,
|
|
25220
25220
|
writeFileSync as writeFileSync12
|
|
25221
25221
|
} from "node:fs";
|
|
25222
|
-
import { join as
|
|
25222
|
+
import { join as join17 } from "node:path";
|
|
25223
25223
|
function quarantineMarkerPath(telegramStateDir) {
|
|
25224
|
-
return
|
|
25224
|
+
return join17(telegramStateDir, QUARANTINE_FILENAME);
|
|
25225
25225
|
}
|
|
25226
25226
|
function readQuarantineMarker(telegramStateDir) {
|
|
25227
25227
|
const path = quarantineMarkerPath(telegramStateDir);
|
|
25228
|
-
if (!
|
|
25228
|
+
if (!existsSync26(path))
|
|
25229
25229
|
return null;
|
|
25230
25230
|
try {
|
|
25231
25231
|
const raw = readFileSync21(path, "utf-8");
|
|
@@ -25251,7 +25251,7 @@ function readQuarantineMarker(telegramStateDir) {
|
|
|
25251
25251
|
}
|
|
25252
25252
|
function clearQuarantineMarker(telegramStateDir) {
|
|
25253
25253
|
const path = quarantineMarkerPath(telegramStateDir);
|
|
25254
|
-
if (!
|
|
25254
|
+
if (!existsSync26(path))
|
|
25255
25255
|
return false;
|
|
25256
25256
|
try {
|
|
25257
25257
|
unlinkSync6(path);
|
|
@@ -25261,7 +25261,7 @@ function clearQuarantineMarker(telegramStateDir) {
|
|
|
25261
25261
|
}
|
|
25262
25262
|
}
|
|
25263
25263
|
function hostTelegramStateDir(agentsDir, name) {
|
|
25264
|
-
return
|
|
25264
|
+
return join17(agentsDir, name, "telegram");
|
|
25265
25265
|
}
|
|
25266
25266
|
function readQuarantineMarkerForAgent(agentsDir, name) {
|
|
25267
25267
|
return readQuarantineMarker(hostTelegramStateDir(agentsDir, name));
|
|
@@ -25807,10 +25807,10 @@ __export(exports_client2, {
|
|
|
25807
25807
|
AuthBrokerClient: () => AuthBrokerClient
|
|
25808
25808
|
});
|
|
25809
25809
|
import * as net2 from "node:net";
|
|
25810
|
-
import { existsSync as
|
|
25811
|
-
import { homedir as
|
|
25810
|
+
import { existsSync as existsSync28 } from "node:fs";
|
|
25811
|
+
import { homedir as homedir8 } from "node:os";
|
|
25812
25812
|
import { randomUUID } from "node:crypto";
|
|
25813
|
-
import { join as
|
|
25813
|
+
import { join as join19 } from "node:path";
|
|
25814
25814
|
function reviveDate(v) {
|
|
25815
25815
|
if (v == null)
|
|
25816
25816
|
return null;
|
|
@@ -25819,8 +25819,8 @@ function reviveDate(v) {
|
|
|
25819
25819
|
const d = new Date(v);
|
|
25820
25820
|
return Number.isNaN(d.getTime()) ? null : d;
|
|
25821
25821
|
}
|
|
25822
|
-
function operatorSocketPath(home2 =
|
|
25823
|
-
return
|
|
25822
|
+
function operatorSocketPath(home2 = homedir8()) {
|
|
25823
|
+
return join19(home2, ".switchroom", "state", "auth-broker-operator", "sock");
|
|
25824
25824
|
}
|
|
25825
25825
|
function resolveAuthBrokerSocketPath(opts) {
|
|
25826
25826
|
if (opts?.socket)
|
|
@@ -26098,7 +26098,7 @@ async function withAuthBrokerClient(fn, opts) {
|
|
|
26098
26098
|
}
|
|
26099
26099
|
}
|
|
26100
26100
|
function authBrokerSocketExists(opts) {
|
|
26101
|
-
return
|
|
26101
|
+
return existsSync28(resolveAuthBrokerSocketPath(opts));
|
|
26102
26102
|
}
|
|
26103
26103
|
var DEFAULT_TIMEOUT_MS2 = 5000, AuthBrokerError, AuthBrokerUnreachableError;
|
|
26104
26104
|
var init_client2 = __esm(() => {
|
|
@@ -26157,44 +26157,44 @@ var init_broker_call = __esm(() => {
|
|
|
26157
26157
|
|
|
26158
26158
|
// src/auth/account-store.ts
|
|
26159
26159
|
import {
|
|
26160
|
-
chownSync,
|
|
26161
|
-
existsSync as
|
|
26160
|
+
chownSync as chownSync3,
|
|
26161
|
+
existsSync as existsSync29,
|
|
26162
26162
|
mkdirSync as mkdirSync17,
|
|
26163
26163
|
readFileSync as readFileSync23,
|
|
26164
|
-
readdirSync as
|
|
26164
|
+
readdirSync as readdirSync15,
|
|
26165
26165
|
renameSync as renameSync7,
|
|
26166
26166
|
rmSync as rmSync10,
|
|
26167
|
-
statSync as
|
|
26167
|
+
statSync as statSync16,
|
|
26168
26168
|
writeFileSync as writeFileSync14
|
|
26169
26169
|
} from "node:fs";
|
|
26170
|
-
import { homedir as
|
|
26171
|
-
import { join as
|
|
26170
|
+
import { homedir as homedir10 } from "node:os";
|
|
26171
|
+
import { join as join21, resolve as resolve22 } from "node:path";
|
|
26172
26172
|
function accountsRootOverride() {
|
|
26173
26173
|
const v = process.env.SWITCHROOM_ACCOUNTS_DIR;
|
|
26174
26174
|
if (v && v.length > 0 && v.startsWith("/"))
|
|
26175
26175
|
return v;
|
|
26176
26176
|
return;
|
|
26177
26177
|
}
|
|
26178
|
-
function accountsRoot(home2 =
|
|
26178
|
+
function accountsRoot(home2 = homedir10()) {
|
|
26179
26179
|
return accountsRootOverride() ?? resolve22(home2, ".switchroom", "accounts");
|
|
26180
26180
|
}
|
|
26181
|
-
function accountDir(label, home2 =
|
|
26182
|
-
return
|
|
26181
|
+
function accountDir(label, home2 = homedir10()) {
|
|
26182
|
+
return join21(accountsRoot(home2), label);
|
|
26183
26183
|
}
|
|
26184
|
-
function accountCredentialsPath(label, home2 =
|
|
26185
|
-
return
|
|
26184
|
+
function accountCredentialsPath(label, home2 = homedir10()) {
|
|
26185
|
+
return join21(accountDir(label, home2), "credentials.json");
|
|
26186
26186
|
}
|
|
26187
|
-
function accountMetaPath(label, home2 =
|
|
26188
|
-
return
|
|
26187
|
+
function accountMetaPath(label, home2 = homedir10()) {
|
|
26188
|
+
return join21(accountDir(label, home2), "meta.json");
|
|
26189
26189
|
}
|
|
26190
|
-
function listAccounts(home2 =
|
|
26190
|
+
function listAccounts(home2 = homedir10()) {
|
|
26191
26191
|
const root = accountsRoot(home2);
|
|
26192
|
-
if (!
|
|
26192
|
+
if (!existsSync29(root))
|
|
26193
26193
|
return [];
|
|
26194
26194
|
try {
|
|
26195
|
-
return
|
|
26195
|
+
return readdirSync15(root).filter((name) => {
|
|
26196
26196
|
try {
|
|
26197
|
-
return
|
|
26197
|
+
return statSync16(join21(root, name)).isDirectory();
|
|
26198
26198
|
} catch {
|
|
26199
26199
|
return false;
|
|
26200
26200
|
}
|
|
@@ -26203,9 +26203,9 @@ function listAccounts(home2 = homedir9()) {
|
|
|
26203
26203
|
return [];
|
|
26204
26204
|
}
|
|
26205
26205
|
}
|
|
26206
|
-
function readAccountCredentials(label, home2 =
|
|
26206
|
+
function readAccountCredentials(label, home2 = homedir10()) {
|
|
26207
26207
|
const p = accountCredentialsPath(label, home2);
|
|
26208
|
-
if (!
|
|
26208
|
+
if (!existsSync29(p))
|
|
26209
26209
|
return null;
|
|
26210
26210
|
try {
|
|
26211
26211
|
return JSON.parse(readFileSync23(p, "utf-8"));
|
|
@@ -26213,9 +26213,9 @@ function readAccountCredentials(label, home2 = homedir9()) {
|
|
|
26213
26213
|
return null;
|
|
26214
26214
|
}
|
|
26215
26215
|
}
|
|
26216
|
-
function readAccountMeta(label, home2 =
|
|
26216
|
+
function readAccountMeta(label, home2 = homedir10()) {
|
|
26217
26217
|
const p = accountMetaPath(label, home2);
|
|
26218
|
-
if (!
|
|
26218
|
+
if (!existsSync29(p))
|
|
26219
26219
|
return null;
|
|
26220
26220
|
try {
|
|
26221
26221
|
return JSON.parse(readFileSync23(p, "utf-8"));
|
|
@@ -26223,7 +26223,7 @@ function readAccountMeta(label, home2 = homedir9()) {
|
|
|
26223
26223
|
return null;
|
|
26224
26224
|
}
|
|
26225
26225
|
}
|
|
26226
|
-
function accountHealth(label, now = Date.now(), home2 =
|
|
26226
|
+
function accountHealth(label, now = Date.now(), home2 = homedir10()) {
|
|
26227
26227
|
const creds = readAccountCredentials(label, home2);
|
|
26228
26228
|
if (!creds?.claudeAiOauth?.accessToken)
|
|
26229
26229
|
return "missing-credentials";
|
|
@@ -26239,7 +26239,7 @@ function accountHealth(label, now = Date.now(), home2 = homedir9()) {
|
|
|
26239
26239
|
}
|
|
26240
26240
|
return "healthy";
|
|
26241
26241
|
}
|
|
26242
|
-
function getAccountInfos(now = Date.now(), home2 =
|
|
26242
|
+
function getAccountInfos(now = Date.now(), home2 = homedir10()) {
|
|
26243
26243
|
return listAccounts(home2).map((label) => {
|
|
26244
26244
|
const creds = readAccountCredentials(label, home2);
|
|
26245
26245
|
const meta = readAccountMeta(label, home2);
|
|
@@ -26908,15 +26908,15 @@ var init_disconnect = __esm(() => {
|
|
|
26908
26908
|
});
|
|
26909
26909
|
|
|
26910
26910
|
// src/vault/approvals/client.ts
|
|
26911
|
-
import { existsSync as
|
|
26912
|
-
import { homedir as
|
|
26913
|
-
import { join as
|
|
26914
|
-
function kernelOperatorSocketPath(home2 =
|
|
26915
|
-
return
|
|
26911
|
+
import { existsSync as existsSync30 } from "node:fs";
|
|
26912
|
+
import { homedir as homedir11 } from "node:os";
|
|
26913
|
+
import { join as join22 } from "node:path";
|
|
26914
|
+
function kernelOperatorSocketPath(home2 = homedir11()) {
|
|
26915
|
+
return join22(home2, ".switchroom", "state", "kernel-operator", "sock");
|
|
26916
26916
|
}
|
|
26917
|
-
function resolveKernelOperatorSocket(home2 =
|
|
26917
|
+
function resolveKernelOperatorSocket(home2 = homedir11()) {
|
|
26918
26918
|
const p = kernelOperatorSocketPath(home2);
|
|
26919
|
-
return
|
|
26919
|
+
return existsSync30(p) ? p : null;
|
|
26920
26920
|
}
|
|
26921
26921
|
function resolveKernelSocketPath(opts) {
|
|
26922
26922
|
if (opts?.socket)
|
|
@@ -27995,8 +27995,8 @@ __export(exports_via_claude, {
|
|
|
27995
27995
|
POST_PASTE_RULES: () => POST_PASTE_RULES
|
|
27996
27996
|
});
|
|
27997
27997
|
import { execFileSync as execFileSync14, spawnSync as spawnSync2 } from "node:child_process";
|
|
27998
|
-
import { existsSync as
|
|
27999
|
-
import { join as
|
|
27998
|
+
import { existsSync as existsSync31, mkdirSync as mkdirSync18, readFileSync as readFileSync26 } from "node:fs";
|
|
27999
|
+
import { join as join23, resolve as resolve23 } from "node:path";
|
|
28000
28000
|
function tmuxHasSession(session) {
|
|
28001
28001
|
const r = spawnSync2("tmux", ["has-session", "-t", session], {
|
|
28002
28002
|
stdio: ["ignore", "ignore", "ignore"]
|
|
@@ -28042,7 +28042,7 @@ async function runViaClaude(opts) {
|
|
|
28042
28042
|
const poll = opts.pollMs ?? VIA_CLAUDE_DEFAULTS.pollMs;
|
|
28043
28043
|
const configDir = resolve23(opts.configDir);
|
|
28044
28044
|
mkdirSync18(configDir, { recursive: true });
|
|
28045
|
-
const credentialsPath2 =
|
|
28045
|
+
const credentialsPath2 = join23(configDir, ".credentials.json");
|
|
28046
28046
|
const capture = opts.capturePane ?? (() => tmuxCapturePane(SESSION));
|
|
28047
28047
|
const send = opts.sendKeys ?? ((keys, literal) => tmuxSendKeys(SESSION, keys, literal === true));
|
|
28048
28048
|
if (!opts.spawnClaude) {
|
|
@@ -28103,7 +28103,7 @@ async function runViaClaude(opts) {
|
|
|
28103
28103
|
log(" Waiting for credentials to land\u2026");
|
|
28104
28104
|
while (Date.now() < phase2Deadline) {
|
|
28105
28105
|
await sleep3(poll);
|
|
28106
|
-
if (
|
|
28106
|
+
if (existsSync31(credentialsPath2)) {
|
|
28107
28107
|
await sleep3(200);
|
|
28108
28108
|
const raw = readFileSync26(credentialsPath2, "utf-8");
|
|
28109
28109
|
let parsed;
|
|
@@ -28684,10 +28684,10 @@ var init_protocol3 = __esm(() => {
|
|
|
28684
28684
|
});
|
|
28685
28685
|
|
|
28686
28686
|
// src/host-control/audit-reader.ts
|
|
28687
|
-
import { homedir as
|
|
28688
|
-
import { join as
|
|
28689
|
-
function defaultAuditLogPath2(home2 =
|
|
28690
|
-
return
|
|
28687
|
+
import { homedir as homedir20 } from "node:os";
|
|
28688
|
+
import { join as join38 } from "node:path";
|
|
28689
|
+
function defaultAuditLogPath2(home2 = homedir20()) {
|
|
28690
|
+
return join38(home2, ".switchroom", "host-control-audit.log");
|
|
28691
28691
|
}
|
|
28692
28692
|
function parseAuditLine2(line) {
|
|
28693
28693
|
const trimmed = line.trim();
|
|
@@ -28946,19 +28946,19 @@ var init_thinking_effort_risk = __esm(() => {
|
|
|
28946
28946
|
|
|
28947
28947
|
// src/manifest.ts
|
|
28948
28948
|
import {
|
|
28949
|
-
existsSync as
|
|
28949
|
+
existsSync as existsSync51,
|
|
28950
28950
|
readFileSync as readFileSync46,
|
|
28951
|
-
readdirSync as
|
|
28951
|
+
readdirSync as readdirSync19
|
|
28952
28952
|
} from "node:fs";
|
|
28953
|
-
import { dirname as
|
|
28953
|
+
import { dirname as dirname12, join as join45 } from "node:path";
|
|
28954
28954
|
import { execSync as execSync2 } from "node:child_process";
|
|
28955
28955
|
function locateManifestPath() {
|
|
28956
28956
|
let dir = import.meta.dirname;
|
|
28957
28957
|
for (let i = 0;i < 10 && dir && dir !== "/"; i++) {
|
|
28958
|
-
const candidate =
|
|
28959
|
-
if (
|
|
28958
|
+
const candidate = join45(dir, "dependencies.json");
|
|
28959
|
+
if (existsSync51(candidate))
|
|
28960
28960
|
return candidate;
|
|
28961
|
-
dir =
|
|
28961
|
+
dir = dirname12(dir);
|
|
28962
28962
|
}
|
|
28963
28963
|
return null;
|
|
28964
28964
|
}
|
|
@@ -29025,14 +29025,14 @@ function probeClaudeVersion() {
|
|
|
29025
29025
|
}
|
|
29026
29026
|
function probePlaywrightMcpVersion() {
|
|
29027
29027
|
const home2 = process.env.HOME ?? "";
|
|
29028
|
-
const npxCache =
|
|
29029
|
-
if (!
|
|
29028
|
+
const npxCache = join45(home2, ".npm/_npx");
|
|
29029
|
+
if (!existsSync51(npxCache))
|
|
29030
29030
|
return null;
|
|
29031
29031
|
try {
|
|
29032
|
-
const entries =
|
|
29032
|
+
const entries = readdirSync19(npxCache);
|
|
29033
29033
|
for (const entry of entries) {
|
|
29034
|
-
const pkgPath =
|
|
29035
|
-
if (
|
|
29034
|
+
const pkgPath = join45(npxCache, entry, "node_modules/@playwright/mcp/package.json");
|
|
29035
|
+
if (existsSync51(pkgPath)) {
|
|
29036
29036
|
try {
|
|
29037
29037
|
const pkg = JSON.parse(readFileSync46(pkgPath, "utf-8"));
|
|
29038
29038
|
if (pkg.version)
|
|
@@ -29473,11 +29473,11 @@ var init_doctor_docker = __esm(() => {
|
|
|
29473
29473
|
});
|
|
29474
29474
|
|
|
29475
29475
|
// src/cli/doctor-auth-broker.ts
|
|
29476
|
-
import { existsSync as
|
|
29476
|
+
import { existsSync as existsSync52, readFileSync as readFileSync48 } from "node:fs";
|
|
29477
29477
|
import { createHash as createHash10 } from "node:crypto";
|
|
29478
29478
|
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
29479
|
-
import { homedir as
|
|
29480
|
-
import { join as
|
|
29479
|
+
import { homedir as homedir25 } from "node:os";
|
|
29480
|
+
import { join as join46 } from "node:path";
|
|
29481
29481
|
function defaultDockerInspect(container, format) {
|
|
29482
29482
|
try {
|
|
29483
29483
|
const r = spawnSync6("docker", ["inspect", "-f", format, container], { encoding: "utf-8", timeout: 5000 });
|
|
@@ -29577,8 +29577,8 @@ function checkAuthBrokerPerAgentSockets(config, deps = {}) {
|
|
|
29577
29577
|
}
|
|
29578
29578
|
function checkAuthBrokerDrift(deps = {}) {
|
|
29579
29579
|
const stateDir = resolveStateDir(deps);
|
|
29580
|
-
const indexPath =
|
|
29581
|
-
if (!
|
|
29580
|
+
const indexPath = join46(stateDir, "sha-index.json");
|
|
29581
|
+
if (!existsSync52(indexPath)) {
|
|
29582
29582
|
return {
|
|
29583
29583
|
name: "auth-broker: drift",
|
|
29584
29584
|
status: "ok",
|
|
@@ -29596,12 +29596,12 @@ function checkAuthBrokerDrift(deps = {}) {
|
|
|
29596
29596
|
fix: "Inspect `~/.switchroom/state/auth-broker/sha-index.json` for corruption."
|
|
29597
29597
|
};
|
|
29598
29598
|
}
|
|
29599
|
-
const home2 = deps.home ??
|
|
29599
|
+
const home2 = deps.home ?? homedir25();
|
|
29600
29600
|
const divergent = [];
|
|
29601
29601
|
const missingOnDisk = [];
|
|
29602
29602
|
for (const [label, expected] of Object.entries(index)) {
|
|
29603
29603
|
const credsPath = accountCredentialsPath(label, home2);
|
|
29604
|
-
if (!
|
|
29604
|
+
if (!existsSync52(credsPath)) {
|
|
29605
29605
|
missingOnDisk.push(label);
|
|
29606
29606
|
continue;
|
|
29607
29607
|
}
|
|
@@ -29638,8 +29638,8 @@ function checkAuthBrokerDrift(deps = {}) {
|
|
|
29638
29638
|
}
|
|
29639
29639
|
function checkAuthBrokerThresholdViolations(deps = {}) {
|
|
29640
29640
|
const stateDir = resolveStateDir(deps);
|
|
29641
|
-
const path4 =
|
|
29642
|
-
if (!
|
|
29641
|
+
const path4 = join46(stateDir, "threshold-violations.json");
|
|
29642
|
+
if (!existsSync52(path4)) {
|
|
29643
29643
|
return {
|
|
29644
29644
|
name: "auth-broker: threshold violations",
|
|
29645
29645
|
status: "ok",
|
|
@@ -29682,9 +29682,9 @@ function checkAuthBrokerActiveAccount(config, deps = {}) {
|
|
|
29682
29682
|
fix: "Run `switchroom auth use <label>` to pin a fleet-wide account, then `switchroom apply`. Without an active account every agent boot fails."
|
|
29683
29683
|
};
|
|
29684
29684
|
}
|
|
29685
|
-
const home2 = deps.home ??
|
|
29685
|
+
const home2 = deps.home ?? homedir25();
|
|
29686
29686
|
const dir = accountDir(active, home2);
|
|
29687
|
-
if (!
|
|
29687
|
+
if (!existsSync52(dir)) {
|
|
29688
29688
|
return {
|
|
29689
29689
|
name: "auth-broker: fleet active account",
|
|
29690
29690
|
status: "fail",
|
|
@@ -29693,7 +29693,7 @@ function checkAuthBrokerActiveAccount(config, deps = {}) {
|
|
|
29693
29693
|
};
|
|
29694
29694
|
}
|
|
29695
29695
|
const creds = accountCredentialsPath(active, home2);
|
|
29696
|
-
if (!
|
|
29696
|
+
if (!existsSync52(creds)) {
|
|
29697
29697
|
return {
|
|
29698
29698
|
name: "auth-broker: fleet active account",
|
|
29699
29699
|
status: "fail",
|
|
@@ -29830,27 +29830,27 @@ var init_doctor_hostd = () => {};
|
|
|
29830
29830
|
import {
|
|
29831
29831
|
accessSync,
|
|
29832
29832
|
constants as fsConstants4,
|
|
29833
|
-
existsSync as
|
|
29834
|
-
realpathSync as
|
|
29835
|
-
statSync as
|
|
29833
|
+
existsSync as existsSync53,
|
|
29834
|
+
realpathSync as realpathSync5,
|
|
29835
|
+
statSync as statSync23
|
|
29836
29836
|
} from "node:fs";
|
|
29837
|
-
import { userInfo, homedir as
|
|
29838
|
-
import { join as
|
|
29837
|
+
import { userInfo, homedir as homedir26 } from "node:os";
|
|
29838
|
+
import { join as join47 } from "node:path";
|
|
29839
29839
|
function resolveVaultPath2(config) {
|
|
29840
29840
|
return config.vault?.path ? config.vault.path.replace(/^~/, process.env.HOME ?? "") : resolveStatePath("vault.enc");
|
|
29841
29841
|
}
|
|
29842
29842
|
function defaultStatVault(path4) {
|
|
29843
|
-
if (!
|
|
29843
|
+
if (!existsSync53(path4)) {
|
|
29844
29844
|
return { exists: false, readable: false, uid: -1, mode: 0, realPath: path4 };
|
|
29845
29845
|
}
|
|
29846
29846
|
let real = path4;
|
|
29847
29847
|
try {
|
|
29848
|
-
real =
|
|
29848
|
+
real = realpathSync5(path4);
|
|
29849
29849
|
} catch {}
|
|
29850
29850
|
let uid = -1;
|
|
29851
29851
|
let mode = 0;
|
|
29852
29852
|
try {
|
|
29853
|
-
const s =
|
|
29853
|
+
const s = statSync23(real);
|
|
29854
29854
|
uid = s.uid;
|
|
29855
29855
|
mode = s.mode & 511;
|
|
29856
29856
|
} catch {
|
|
@@ -29973,7 +29973,7 @@ async function runSecretAccessChecks(config, deps = {}) {
|
|
|
29973
29973
|
};
|
|
29974
29974
|
const passphrase = deps.passphrase ?? process.env.SWITCHROOM_VAULT_PASSPHRASE;
|
|
29975
29975
|
if (!passphrase) {
|
|
29976
|
-
const sock = deps.brokerOperatorSocket ??
|
|
29976
|
+
const sock = deps.brokerOperatorSocket ?? join47(homedir26(), ".switchroom", "broker-operator", "sock");
|
|
29977
29977
|
const preflight = deps.preflight ?? ((a, k) => defaultPreflight(sock, a, k));
|
|
29978
29978
|
for (const name of Object.keys(config.agents ?? {})) {
|
|
29979
29979
|
const resolved = resolveAgentConfig(config.defaults, config.profiles, config.agents[name]);
|
|
@@ -30058,8 +30058,8 @@ import {
|
|
|
30058
30058
|
existsSync as realExistsSync,
|
|
30059
30059
|
readFileSync as realReadFileSync
|
|
30060
30060
|
} from "node:fs";
|
|
30061
|
-
import { join as
|
|
30062
|
-
import { homedir as
|
|
30061
|
+
import { join as join48, resolve as resolve30 } from "node:path";
|
|
30062
|
+
import { homedir as homedir27 } from "node:os";
|
|
30063
30063
|
function resolveDeps(config, deps) {
|
|
30064
30064
|
let agentsDir = deps.agentsDir;
|
|
30065
30065
|
if (agentsDir === undefined) {
|
|
@@ -30182,8 +30182,8 @@ function checkScaffoldWiring(config, driveAgents, d) {
|
|
|
30182
30182
|
});
|
|
30183
30183
|
continue;
|
|
30184
30184
|
}
|
|
30185
|
-
const mcpPath =
|
|
30186
|
-
const claudeJsonPath =
|
|
30185
|
+
const mcpPath = join48(agentDir, ".mcp.json");
|
|
30186
|
+
const claudeJsonPath = join48(agentDir, ".claude", ".claude.json");
|
|
30187
30187
|
const mcpRead = readJson(d, mcpPath);
|
|
30188
30188
|
const trustRead = readJson(d, claudeJsonPath);
|
|
30189
30189
|
if (mcpRead.kind === "unreadable" || trustRead.kind === "unreadable") {
|
|
@@ -30296,7 +30296,7 @@ async function runDriveBrokerReachabilityChecks(config, deps = {}) {
|
|
|
30296
30296
|
}
|
|
30297
30297
|
];
|
|
30298
30298
|
}
|
|
30299
|
-
const sock = deps.brokerOperatorSocket ??
|
|
30299
|
+
const sock = deps.brokerOperatorSocket ?? join48(homedir27(), ".switchroom", "broker-operator", "sock");
|
|
30300
30300
|
const preflight = deps.preflight ?? ((a, k) => defaultPreflight(sock, a, k));
|
|
30301
30301
|
const results = [];
|
|
30302
30302
|
for (const agent of driveAgents) {
|
|
@@ -30350,8 +30350,8 @@ import {
|
|
|
30350
30350
|
readSync as realReadSync,
|
|
30351
30351
|
closeSync as realCloseSync
|
|
30352
30352
|
} from "node:fs";
|
|
30353
|
-
import { join as
|
|
30354
|
-
import { homedir as
|
|
30353
|
+
import { join as join49 } from "node:path";
|
|
30354
|
+
import { homedir as homedir28 } from "node:os";
|
|
30355
30355
|
function defaultReadHead(p, n) {
|
|
30356
30356
|
let fd;
|
|
30357
30357
|
try {
|
|
@@ -30379,7 +30379,7 @@ function resolveDeps2(config, deps) {
|
|
|
30379
30379
|
}
|
|
30380
30380
|
}
|
|
30381
30381
|
return {
|
|
30382
|
-
homeDir: deps.homeDir ??
|
|
30382
|
+
homeDir: deps.homeDir ?? homedir28(),
|
|
30383
30383
|
agentsDir,
|
|
30384
30384
|
existsSync: deps.existsSync ?? ((p) => realExistsSync2(p)),
|
|
30385
30385
|
readFileSync: deps.readFileSync ?? ((p) => realReadFileSync2(p, "utf-8")),
|
|
@@ -30408,7 +30408,7 @@ function runWebkiteChecks(config, deps = {}) {
|
|
|
30408
30408
|
return [];
|
|
30409
30409
|
const d = resolveDeps2(config, deps);
|
|
30410
30410
|
const results = [];
|
|
30411
|
-
const binPath =
|
|
30411
|
+
const binPath = join49(d.homeDir, ".switchroom", "bin", "webkite");
|
|
30412
30412
|
if (!d.existsSync(binPath)) {
|
|
30413
30413
|
results.push({
|
|
30414
30414
|
name: "webkite: binary",
|
|
@@ -30438,12 +30438,12 @@ function runWebkiteChecks(config, deps = {}) {
|
|
|
30438
30438
|
});
|
|
30439
30439
|
}
|
|
30440
30440
|
}
|
|
30441
|
-
const cloakDir =
|
|
30441
|
+
const cloakDir = join49(d.homeDir, ".cloakbrowser");
|
|
30442
30442
|
let chromeFound = false;
|
|
30443
30443
|
if (d.existsSync(cloakDir)) {
|
|
30444
30444
|
try {
|
|
30445
30445
|
for (const entry of d.readdirSync(cloakDir)) {
|
|
30446
|
-
if (entry.startsWith("chromium-") && d.existsSync(
|
|
30446
|
+
if (entry.startsWith("chromium-") && d.existsSync(join49(cloakDir, entry, "chrome"))) {
|
|
30447
30447
|
chromeFound = true;
|
|
30448
30448
|
break;
|
|
30449
30449
|
}
|
|
@@ -30469,9 +30469,9 @@ function runWebkiteChecks(config, deps = {}) {
|
|
|
30469
30469
|
return results;
|
|
30470
30470
|
}
|
|
30471
30471
|
for (const agent of enabledAgents) {
|
|
30472
|
-
const agentDir =
|
|
30473
|
-
const settingsPath =
|
|
30474
|
-
const mcpPath =
|
|
30472
|
+
const agentDir = join49(d.agentsDir, agent);
|
|
30473
|
+
const settingsPath = join49(agentDir, ".claude", "settings.json");
|
|
30474
|
+
const mcpPath = join49(agentDir, ".mcp.json");
|
|
30475
30475
|
if (!d.existsSync(settingsPath) && !d.existsSync(mcpPath)) {
|
|
30476
30476
|
continue;
|
|
30477
30477
|
}
|
|
@@ -30535,7 +30535,7 @@ var init_doctor_webkite = __esm(() => {
|
|
|
30535
30535
|
});
|
|
30536
30536
|
|
|
30537
30537
|
// src/cli/doctor-scaffold-wiring.ts
|
|
30538
|
-
import { join as
|
|
30538
|
+
import { join as join50, resolve as resolve31 } from "node:path";
|
|
30539
30539
|
function readJson2(d, path4) {
|
|
30540
30540
|
if (!d.existsSync(path4))
|
|
30541
30541
|
return { kind: "absent" };
|
|
@@ -30578,8 +30578,8 @@ function checkIntegrationScaffoldWiring(args) {
|
|
|
30578
30578
|
});
|
|
30579
30579
|
continue;
|
|
30580
30580
|
}
|
|
30581
|
-
const mcpPath =
|
|
30582
|
-
const claudeJsonPath =
|
|
30581
|
+
const mcpPath = join50(agentDir, ".mcp.json");
|
|
30582
|
+
const claudeJsonPath = join50(agentDir, ".claude", ".claude.json");
|
|
30583
30583
|
const mcpRead = readJson2(deps, mcpPath);
|
|
30584
30584
|
const trustRead = readJson2(deps, claudeJsonPath);
|
|
30585
30585
|
if (mcpRead.kind === "unreadable" || trustRead.kind === "unreadable") {
|
|
@@ -30643,14 +30643,14 @@ import {
|
|
|
30643
30643
|
existsSync as realExistsSync3,
|
|
30644
30644
|
readFileSync as realReadFileSync3
|
|
30645
30645
|
} from "node:fs";
|
|
30646
|
-
import { join as
|
|
30647
|
-
import { homedir as
|
|
30646
|
+
import { join as join51 } from "node:path";
|
|
30647
|
+
import { homedir as homedir29 } from "node:os";
|
|
30648
30648
|
function resolveDeps3(deps) {
|
|
30649
|
-
const home2 = deps.homeDir?.() ??
|
|
30649
|
+
const home2 = deps.homeDir?.() ?? homedir29();
|
|
30650
30650
|
return {
|
|
30651
30651
|
existsSync: deps.existsSync ?? realExistsSync3,
|
|
30652
30652
|
readFileSync: deps.readFileSync ?? realReadFileSync3,
|
|
30653
|
-
agentsDir:
|
|
30653
|
+
agentsDir: join51(home2, ".switchroom", "agents"),
|
|
30654
30654
|
now: deps.now ?? Date.now
|
|
30655
30655
|
};
|
|
30656
30656
|
}
|
|
@@ -30733,7 +30733,7 @@ function checkOAuthClient2(config, anyAgentEnabled) {
|
|
|
30733
30733
|
];
|
|
30734
30734
|
}
|
|
30735
30735
|
function readHeartbeat(d, agentName) {
|
|
30736
|
-
const path4 =
|
|
30736
|
+
const path4 = join51(d.agentsDir, agentName, "m365-launcher.heartbeat.json");
|
|
30737
30737
|
if (!d.existsSync(path4)) {
|
|
30738
30738
|
return { error: "heartbeat file missing \u2014 launcher has not yet started" };
|
|
30739
30739
|
}
|
|
@@ -30830,15 +30830,15 @@ import {
|
|
|
30830
30830
|
readFileSync as realReadFileSync4,
|
|
30831
30831
|
statSync as realStatSync
|
|
30832
30832
|
} from "node:fs";
|
|
30833
|
-
import { join as
|
|
30834
|
-
import { homedir as
|
|
30833
|
+
import { join as join52 } from "node:path";
|
|
30834
|
+
import { homedir as homedir30 } from "node:os";
|
|
30835
30835
|
function resolveDeps4(deps) {
|
|
30836
|
-
const home2 = deps.homeDir?.() ??
|
|
30836
|
+
const home2 = deps.homeDir?.() ?? homedir30();
|
|
30837
30837
|
return {
|
|
30838
30838
|
existsSync: deps.existsSync ?? realExistsSync4,
|
|
30839
30839
|
readFileSync: deps.readFileSync ?? realReadFileSync4,
|
|
30840
30840
|
statSync: deps.statSync ?? realStatSync,
|
|
30841
|
-
agentsDir:
|
|
30841
|
+
agentsDir: join52(home2, ".switchroom", "agents"),
|
|
30842
30842
|
now: deps.now ?? Date.now,
|
|
30843
30843
|
vaultAclReader: deps.vaultAclReader ?? (async () => ({ kind: "unreachable", msg: "no default reader wired" }))
|
|
30844
30844
|
};
|
|
@@ -30963,7 +30963,7 @@ function checkLauncherHeartbeat2(notionAgents, d) {
|
|
|
30963
30963
|
return [];
|
|
30964
30964
|
const results = [];
|
|
30965
30965
|
for (const name of notionAgents) {
|
|
30966
|
-
const heartbeatPath =
|
|
30966
|
+
const heartbeatPath = join52(d.agentsDir, name, "notion-launcher.heartbeat.json");
|
|
30967
30967
|
if (!d.existsSync(heartbeatPath)) {
|
|
30968
30968
|
results.push({
|
|
30969
30969
|
name: `notion:launcher-heartbeat:${name}`,
|
|
@@ -31038,12 +31038,12 @@ import {
|
|
|
31038
31038
|
readdirSync as realReaddirSync2,
|
|
31039
31039
|
statSync as realStatSync2
|
|
31040
31040
|
} from "node:fs";
|
|
31041
|
-
import { homedir as
|
|
31042
|
-
import { join as
|
|
31041
|
+
import { homedir as homedir31 } from "node:os";
|
|
31042
|
+
import { join as join53 } from "node:path";
|
|
31043
31043
|
function runCredentialsMigrationChecks(config, deps = {}) {
|
|
31044
|
-
const credDir = deps.credentialsDir ??
|
|
31045
|
-
const
|
|
31046
|
-
const
|
|
31044
|
+
const credDir = deps.credentialsDir ?? join53(homedir31(), ".switchroom", "credentials");
|
|
31045
|
+
const existsSync54 = deps.existsSync ?? ((p) => realExistsSync5(p));
|
|
31046
|
+
const readdirSync21 = deps.readdirSync ?? ((p) => realReaddirSync2(p));
|
|
31047
31047
|
const isDirectory = deps.isDirectory ?? ((p) => {
|
|
31048
31048
|
try {
|
|
31049
31049
|
return realStatSync2(p).isDirectory();
|
|
@@ -31051,12 +31051,12 @@ function runCredentialsMigrationChecks(config, deps = {}) {
|
|
|
31051
31051
|
return false;
|
|
31052
31052
|
}
|
|
31053
31053
|
});
|
|
31054
|
-
if (!
|
|
31054
|
+
if (!existsSync54(credDir))
|
|
31055
31055
|
return [];
|
|
31056
31056
|
const agentNames = new Set(Object.keys(config.agents ?? {}));
|
|
31057
31057
|
let entries;
|
|
31058
31058
|
try {
|
|
31059
|
-
entries =
|
|
31059
|
+
entries = readdirSync21(credDir);
|
|
31060
31060
|
} catch {
|
|
31061
31061
|
return [
|
|
31062
31062
|
{
|
|
@@ -31069,7 +31069,7 @@ function runCredentialsMigrationChecks(config, deps = {}) {
|
|
|
31069
31069
|
const flat = [];
|
|
31070
31070
|
const perAgentDirs = [];
|
|
31071
31071
|
for (const e of entries) {
|
|
31072
|
-
const full =
|
|
31072
|
+
const full = join53(credDir, e);
|
|
31073
31073
|
if (isDirectory(full) && agentNames.has(e)) {
|
|
31074
31074
|
perAgentDirs.push(e);
|
|
31075
31075
|
} else {
|
|
@@ -31192,19 +31192,19 @@ var init_doctor_inlined_secrets = __esm(() => {
|
|
|
31192
31192
|
|
|
31193
31193
|
// src/cli/doctor-audit-integrity.ts
|
|
31194
31194
|
import { readFileSync as fsReadFileSync2 } from "node:fs";
|
|
31195
|
-
import { homedir as
|
|
31196
|
-
import { join as
|
|
31195
|
+
import { homedir as homedir32 } from "node:os";
|
|
31196
|
+
import { join as join54 } from "node:path";
|
|
31197
31197
|
function rootWrittenLogs(home2) {
|
|
31198
31198
|
return [
|
|
31199
|
-
{ label: "vault-broker", path:
|
|
31199
|
+
{ label: "vault-broker", path: join54(home2, ".switchroom", "vault-audit.log") },
|
|
31200
31200
|
{
|
|
31201
31201
|
label: "hostd",
|
|
31202
|
-
path:
|
|
31202
|
+
path: join54(home2, ".switchroom", "host-control-audit.log")
|
|
31203
31203
|
}
|
|
31204
31204
|
];
|
|
31205
31205
|
}
|
|
31206
31206
|
function runAuditIntegrityChecks(deps = {}) {
|
|
31207
|
-
const home2 = deps.homeDir ??
|
|
31207
|
+
const home2 = deps.homeDir ?? homedir32();
|
|
31208
31208
|
const read = deps.readFileSync ?? ((p) => fsReadFileSync2(p, "utf8"));
|
|
31209
31209
|
const results = [];
|
|
31210
31210
|
for (const { label, path: path4 } of rootWrittenLogs(home2)) {
|
|
@@ -31261,16 +31261,16 @@ var init_doctor_audit_integrity = __esm(() => {
|
|
|
31261
31261
|
});
|
|
31262
31262
|
|
|
31263
31263
|
// src/cli/doctor-agent-smoke.ts
|
|
31264
|
-
import { existsSync as
|
|
31265
|
-
import { homedir as
|
|
31266
|
-
import { join as
|
|
31264
|
+
import { existsSync as existsSync54 } from "node:fs";
|
|
31265
|
+
import { homedir as homedir33 } from "node:os";
|
|
31266
|
+
import { join as join55 } from "node:path";
|
|
31267
31267
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
31268
31268
|
async function runAgentSmokeChecks(config, deps = {}) {
|
|
31269
31269
|
if (deps.fast)
|
|
31270
31270
|
return [];
|
|
31271
|
-
const home2 = deps.homeDir ??
|
|
31272
|
-
const sock = deps.operatorSockPath ??
|
|
31273
|
-
if (!deps.hostdRequestImpl && !
|
|
31271
|
+
const home2 = deps.homeDir ?? homedir33();
|
|
31272
|
+
const sock = deps.operatorSockPath ?? join55(home2, ".switchroom", "hostd", "operator", "sock");
|
|
31273
|
+
if (!deps.hostdRequestImpl && !existsSync54(sock)) {
|
|
31274
31274
|
return [
|
|
31275
31275
|
{
|
|
31276
31276
|
name: "agent liveness",
|
|
@@ -31348,9 +31348,9 @@ var init_doctor_agent_smoke = __esm(() => {
|
|
|
31348
31348
|
|
|
31349
31349
|
// src/cli/doctor-vault-broker-durability.ts
|
|
31350
31350
|
import { execFileSync as execFileSync18 } from "node:child_process";
|
|
31351
|
-
import { existsSync as
|
|
31352
|
-
import { homedir as
|
|
31353
|
-
import { join as
|
|
31351
|
+
import { existsSync as existsSync55, statSync as statSync24 } from "node:fs";
|
|
31352
|
+
import { homedir as homedir34 } from "node:os";
|
|
31353
|
+
import { join as join56 } from "node:path";
|
|
31354
31354
|
function probeBindMountInode(hostPath, brokerContainerPath, opts) {
|
|
31355
31355
|
const statHost = opts?.statHost ?? defaultStatHost;
|
|
31356
31356
|
const statBroker = opts?.statBroker ?? defaultStatBroker;
|
|
@@ -31372,10 +31372,10 @@ function probeBindMountInode(hostPath, brokerContainerPath, opts) {
|
|
|
31372
31372
|
};
|
|
31373
31373
|
}
|
|
31374
31374
|
function defaultStatHost(p) {
|
|
31375
|
-
if (!
|
|
31375
|
+
if (!existsSync55(p))
|
|
31376
31376
|
return null;
|
|
31377
31377
|
try {
|
|
31378
|
-
const s =
|
|
31378
|
+
const s = statSync24(p, { bigint: true });
|
|
31379
31379
|
return { ino: s.ino, size: Number(s.size) };
|
|
31380
31380
|
} catch {
|
|
31381
31381
|
return null;
|
|
@@ -31493,22 +31493,22 @@ function defaultBrokerStatusProbe() {
|
|
|
31493
31493
|
}
|
|
31494
31494
|
}
|
|
31495
31495
|
function runVaultBrokerDurabilityChecks(_config, opts) {
|
|
31496
|
-
const home2 =
|
|
31496
|
+
const home2 = homedir34();
|
|
31497
31497
|
const probe2 = opts?.inodeProbe ?? probeBindMountInode;
|
|
31498
31498
|
return [
|
|
31499
31499
|
probeBrokerUnlocked(opts?.statusProbe),
|
|
31500
31500
|
probeAutoUnlockBlob(home2),
|
|
31501
31501
|
probeMachineIdMount(),
|
|
31502
|
-
formatBindMountResult("vault-broker: vault.enc bind mount",
|
|
31503
|
-
formatBindMountResult("vault-broker: vault-grants.db bind mount (#1737)",
|
|
31504
|
-
formatBindMountResult("vault-broker: vault-audit.log bind mount (#1025)",
|
|
31502
|
+
formatBindMountResult("vault-broker: vault.enc bind mount", join56(home2, ".switchroom", "vault", "vault.enc"), "/state/vault/vault.enc", probe2(join56(home2, ".switchroom", "vault", "vault.enc"), "/state/vault/vault.enc")),
|
|
31503
|
+
formatBindMountResult("vault-broker: vault-grants.db bind mount (#1737)", join56(home2, ".switchroom", "vault-grants.db"), "/root/.switchroom/vault-grants.db", probe2(join56(home2, ".switchroom", "vault-grants.db"), "/root/.switchroom/vault-grants.db")),
|
|
31504
|
+
formatBindMountResult("vault-broker: vault-audit.log bind mount (#1025)", join56(home2, ".switchroom", "vault-audit.log"), "/root/.switchroom/vault-audit.log", probe2(join56(home2, ".switchroom", "vault-audit.log"), "/root/.switchroom/vault-audit.log")),
|
|
31505
31505
|
probeKernelDbDurability(home2, {
|
|
31506
31506
|
statBroker: opts?.kernelStatBroker
|
|
31507
31507
|
})
|
|
31508
31508
|
];
|
|
31509
31509
|
}
|
|
31510
31510
|
function probeKernelDbDurability(home2, opts) {
|
|
31511
|
-
const hostDir =
|
|
31511
|
+
const hostDir = join56(home2, ".switchroom", "approvals");
|
|
31512
31512
|
const containerDir = "/state/approvals";
|
|
31513
31513
|
const name = "approval-kernel: approvals bind mount (allow_always durability)";
|
|
31514
31514
|
const kernelStat = opts?.statBroker ?? defaultKernelStatBroker;
|
|
@@ -31576,8 +31576,8 @@ function defaultKernelStatBroker(p) {
|
|
|
31576
31576
|
return { kind: "ok-with-stat", ino: inoStr, size };
|
|
31577
31577
|
}
|
|
31578
31578
|
function probeAutoUnlockBlob(home2) {
|
|
31579
|
-
const blobPath =
|
|
31580
|
-
if (!
|
|
31579
|
+
const blobPath = join56(home2, ".switchroom", "vault-auto-unlock");
|
|
31580
|
+
if (!existsSync55(blobPath)) {
|
|
31581
31581
|
return {
|
|
31582
31582
|
name: "vault-broker: auto-unlock blob",
|
|
31583
31583
|
status: "warn",
|
|
@@ -31585,7 +31585,7 @@ function probeAutoUnlockBlob(home2) {
|
|
|
31585
31585
|
fix: "Run `switchroom vault broker enable-auto-unlock` to seal the blob with the current passphrase + machine-id"
|
|
31586
31586
|
};
|
|
31587
31587
|
}
|
|
31588
|
-
const sz =
|
|
31588
|
+
const sz = statSync24(blobPath).size;
|
|
31589
31589
|
if (sz === 0) {
|
|
31590
31590
|
return {
|
|
31591
31591
|
name: "vault-broker: auto-unlock blob",
|
|
@@ -31601,7 +31601,7 @@ function probeAutoUnlockBlob(home2) {
|
|
|
31601
31601
|
};
|
|
31602
31602
|
}
|
|
31603
31603
|
function probeMachineIdMount() {
|
|
31604
|
-
const hostExists =
|
|
31604
|
+
const hostExists = existsSync55("/etc/machine-id");
|
|
31605
31605
|
if (!hostExists) {
|
|
31606
31606
|
return {
|
|
31607
31607
|
name: "vault-broker: machine-id passthrough",
|
|
@@ -31680,25 +31680,25 @@ import { execSync as execSync3, spawnSync as spawnSync8 } from "node:child_proce
|
|
|
31680
31680
|
import {
|
|
31681
31681
|
accessSync as accessSync2,
|
|
31682
31682
|
constants as fsConstants5,
|
|
31683
|
-
existsSync as
|
|
31684
|
-
lstatSync as
|
|
31683
|
+
existsSync as existsSync56,
|
|
31684
|
+
lstatSync as lstatSync6,
|
|
31685
31685
|
mkdirSync as mkdirSync30,
|
|
31686
31686
|
readFileSync as readFileSync49,
|
|
31687
|
-
readdirSync as
|
|
31688
|
-
statSync as
|
|
31687
|
+
readdirSync as readdirSync21,
|
|
31688
|
+
statSync as statSync25
|
|
31689
31689
|
} from "node:fs";
|
|
31690
|
-
import { dirname as
|
|
31690
|
+
import { dirname as dirname13, join as join57, resolve as resolve32 } from "node:path";
|
|
31691
31691
|
import { createPublicKey, createPrivateKey } from "node:crypto";
|
|
31692
31692
|
function findInNvm(bin) {
|
|
31693
|
-
const nvmRoot =
|
|
31694
|
-
if (!
|
|
31693
|
+
const nvmRoot = join57(process.env.HOME ?? "", ".nvm", "versions", "node");
|
|
31694
|
+
if (!existsSync56(nvmRoot))
|
|
31695
31695
|
return null;
|
|
31696
31696
|
try {
|
|
31697
|
-
const versions =
|
|
31697
|
+
const versions = readdirSync21(nvmRoot).sort().reverse();
|
|
31698
31698
|
for (const v of versions) {
|
|
31699
|
-
const candidate =
|
|
31699
|
+
const candidate = join57(nvmRoot, v, "bin", bin);
|
|
31700
31700
|
try {
|
|
31701
|
-
const s =
|
|
31701
|
+
const s = statSync25(candidate);
|
|
31702
31702
|
if (s.isFile() || s.isSymbolicLink()) {
|
|
31703
31703
|
return candidate;
|
|
31704
31704
|
}
|
|
@@ -31861,21 +31861,21 @@ function findChromium(homeDir = process.env.HOME ?? "", envBrowsersPath = proces
|
|
|
31861
31861
|
if (envBrowsersPath && envBrowsersPath.length > 0) {
|
|
31862
31862
|
cacheLocations.push(envBrowsersPath);
|
|
31863
31863
|
}
|
|
31864
|
-
cacheLocations.push(
|
|
31864
|
+
cacheLocations.push(join57(homeDir, ".cache", "ms-playwright"));
|
|
31865
31865
|
for (const cacheDir of cacheLocations) {
|
|
31866
|
-
if (!
|
|
31866
|
+
if (!existsSync56(cacheDir))
|
|
31867
31867
|
continue;
|
|
31868
31868
|
try {
|
|
31869
|
-
const entries =
|
|
31869
|
+
const entries = readdirSync21(cacheDir).filter((e) => e.startsWith("chromium"));
|
|
31870
31870
|
for (const entry of entries) {
|
|
31871
31871
|
const candidates2 = [
|
|
31872
|
-
|
|
31873
|
-
|
|
31874
|
-
|
|
31875
|
-
|
|
31872
|
+
join57(cacheDir, entry, "chrome-linux64", "chrome"),
|
|
31873
|
+
join57(cacheDir, entry, "chrome-linux", "chrome"),
|
|
31874
|
+
join57(cacheDir, entry, "chrome-linux64", "headless_shell"),
|
|
31875
|
+
join57(cacheDir, entry, "chrome-linux", "headless_shell")
|
|
31876
31876
|
];
|
|
31877
31877
|
for (const path4 of candidates2) {
|
|
31878
|
-
if (
|
|
31878
|
+
if (existsSync56(path4))
|
|
31879
31879
|
return path4;
|
|
31880
31880
|
}
|
|
31881
31881
|
}
|
|
@@ -31995,8 +31995,8 @@ function checkUserDeclaredMcps(name, agentConfig, config, renderedMcpServers) {
|
|
|
31995
31995
|
function checkLegacyState() {
|
|
31996
31996
|
const results = [];
|
|
31997
31997
|
const h = process.env.HOME ?? "/root";
|
|
31998
|
-
const clerkDir =
|
|
31999
|
-
const clerkPresent =
|
|
31998
|
+
const clerkDir = join57(h, LEGACY_STATE_DIR);
|
|
31999
|
+
const clerkPresent = existsSync56(clerkDir);
|
|
32000
32000
|
results.push({
|
|
32001
32001
|
name: "legacy ~/.clerk state",
|
|
32002
32002
|
status: clerkPresent ? "warn" : "ok",
|
|
@@ -32005,10 +32005,10 @@ function checkLegacyState() {
|
|
|
32005
32005
|
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."
|
|
32006
32006
|
} : {}
|
|
32007
32007
|
});
|
|
32008
|
-
const legacySock =
|
|
32008
|
+
const legacySock = join57(h, ".switchroom", "vault-broker.sock");
|
|
32009
32009
|
let sockStat = null;
|
|
32010
32010
|
try {
|
|
32011
|
-
sockStat =
|
|
32011
|
+
sockStat = lstatSync6(legacySock);
|
|
32012
32012
|
} catch {}
|
|
32013
32013
|
if (sockStat) {
|
|
32014
32014
|
results.push({
|
|
@@ -32126,7 +32126,7 @@ function checkVault(config) {
|
|
|
32126
32126
|
detail: "Approval auth: passphrase (two-factor)"
|
|
32127
32127
|
};
|
|
32128
32128
|
const pairsResult = checkVaultBrokerSocketPairs(config);
|
|
32129
|
-
if (!
|
|
32129
|
+
if (!existsSync56(vaultPath)) {
|
|
32130
32130
|
return [
|
|
32131
32131
|
postureResult,
|
|
32132
32132
|
{
|
|
@@ -32306,8 +32306,8 @@ async function checkHindsight(config) {
|
|
|
32306
32306
|
}
|
|
32307
32307
|
function checkPendingRetainsQueue(dir) {
|
|
32308
32308
|
const home2 = process.env.HOME ?? "";
|
|
32309
|
-
const pendingDir = dir ?? process.env.HINDSIGHT_PENDING_DIR ??
|
|
32310
|
-
if (!
|
|
32309
|
+
const pendingDir = dir ?? process.env.HINDSIGHT_PENDING_DIR ?? join57(home2, ".hindsight", "pending-retains");
|
|
32310
|
+
if (!existsSync56(pendingDir)) {
|
|
32311
32311
|
return {
|
|
32312
32312
|
name: "pending-retains queue",
|
|
32313
32313
|
status: "ok",
|
|
@@ -32316,7 +32316,7 @@ function checkPendingRetainsQueue(dir) {
|
|
|
32316
32316
|
}
|
|
32317
32317
|
let names;
|
|
32318
32318
|
try {
|
|
32319
|
-
names =
|
|
32319
|
+
names = readdirSync21(pendingDir);
|
|
32320
32320
|
} catch (err) {
|
|
32321
32321
|
return {
|
|
32322
32322
|
name: "pending-retains queue",
|
|
@@ -32378,7 +32378,7 @@ function tryReadHostFile(path4) {
|
|
|
32378
32378
|
}
|
|
32379
32379
|
}
|
|
32380
32380
|
function parseEnvFile(path4) {
|
|
32381
|
-
if (!
|
|
32381
|
+
if (!existsSync56(path4))
|
|
32382
32382
|
return {};
|
|
32383
32383
|
let content;
|
|
32384
32384
|
try {
|
|
@@ -32437,7 +32437,7 @@ async function checkTelegram(config) {
|
|
|
32437
32437
|
const plugin = agentConfig.channels?.telegram?.plugin ?? "switchroom";
|
|
32438
32438
|
if (plugin !== "switchroom")
|
|
32439
32439
|
continue;
|
|
32440
|
-
const envPath =
|
|
32440
|
+
const envPath = join57(agentsDir, name, "telegram", ".env");
|
|
32441
32441
|
const read = tryReadHostFile(envPath);
|
|
32442
32442
|
if (read.kind === "eacces") {
|
|
32443
32443
|
results.push({
|
|
@@ -32489,7 +32489,7 @@ async function checkTelegram(config) {
|
|
|
32489
32489
|
}
|
|
32490
32490
|
function checkStartShStale(agentName, startShPath) {
|
|
32491
32491
|
const label = `${agentName}: start.sh scheduler block`;
|
|
32492
|
-
if (!
|
|
32492
|
+
if (!existsSync56(startShPath)) {
|
|
32493
32493
|
return {
|
|
32494
32494
|
name: label,
|
|
32495
32495
|
status: "warn",
|
|
@@ -32520,10 +32520,10 @@ function checkStartShStale(agentName, startShPath) {
|
|
|
32520
32520
|
}
|
|
32521
32521
|
function checkLeakedHomeSwitchroom(agentName, agentDir) {
|
|
32522
32522
|
const label = `${agentName}: $HOME/.switchroom symlink (#910)`;
|
|
32523
|
-
const path4 =
|
|
32523
|
+
const path4 = join57(agentDir, "home", ".switchroom");
|
|
32524
32524
|
let stats;
|
|
32525
32525
|
try {
|
|
32526
|
-
stats =
|
|
32526
|
+
stats = lstatSync6(path4);
|
|
32527
32527
|
} catch (err) {
|
|
32528
32528
|
if (err.code === "ENOENT") {
|
|
32529
32529
|
return {
|
|
@@ -32557,8 +32557,8 @@ function checkLeakedHomeSwitchroom(agentName, agentDir) {
|
|
|
32557
32557
|
}
|
|
32558
32558
|
function checkRepoHygiene(repoRoot) {
|
|
32559
32559
|
const results = [];
|
|
32560
|
-
const exportDir =
|
|
32561
|
-
if (
|
|
32560
|
+
const exportDir = join57(repoRoot, "clerk-export");
|
|
32561
|
+
if (existsSync56(exportDir)) {
|
|
32562
32562
|
results.push({
|
|
32563
32563
|
name: "repo hygiene: clerk-export/ on disk (#1072)",
|
|
32564
32564
|
status: "warn",
|
|
@@ -32566,8 +32566,8 @@ function checkRepoHygiene(repoRoot) {
|
|
|
32566
32566
|
fix: `Run scripts/migrate-clerk-export-to-vault.sh to move the bundle ` + `into the vault, then delete the on-disk copy.`
|
|
32567
32567
|
});
|
|
32568
32568
|
}
|
|
32569
|
-
const knownTarball =
|
|
32570
|
-
if (
|
|
32569
|
+
const knownTarball = join57(repoRoot, "clerk-export-with-secrets.tar.gz");
|
|
32570
|
+
if (existsSync56(knownTarball)) {
|
|
32571
32571
|
results.push({
|
|
32572
32572
|
name: "repo hygiene: clerk-export-with-secrets.tar.gz on disk (#1072)",
|
|
32573
32573
|
status: "warn",
|
|
@@ -32576,7 +32576,7 @@ function checkRepoHygiene(repoRoot) {
|
|
|
32576
32576
|
});
|
|
32577
32577
|
}
|
|
32578
32578
|
try {
|
|
32579
|
-
const entries =
|
|
32579
|
+
const entries = readdirSync21(repoRoot);
|
|
32580
32580
|
for (const name of entries) {
|
|
32581
32581
|
if (name === "clerk-export-with-secrets.tar.gz")
|
|
32582
32582
|
continue;
|
|
@@ -32584,7 +32584,7 @@ function checkRepoHygiene(repoRoot) {
|
|
|
32584
32584
|
results.push({
|
|
32585
32585
|
name: `repo hygiene: ${name} on disk (#1072)`,
|
|
32586
32586
|
status: "warn",
|
|
32587
|
-
detail: `${
|
|
32587
|
+
detail: `${join57(repoRoot, name)} matches the *-with-secrets*.tar.gz ` + `pattern. Likely contains real credentials.`,
|
|
32588
32588
|
fix: `Inspect, migrate any secrets into the vault, then delete the ` + `archive.`
|
|
32589
32589
|
});
|
|
32590
32590
|
}
|
|
@@ -32607,10 +32607,10 @@ function checkRepoHygiene(repoRoot) {
|
|
|
32607
32607
|
}
|
|
32608
32608
|
function isSwitchroomCheckout(dir) {
|
|
32609
32609
|
try {
|
|
32610
|
-
if (!
|
|
32610
|
+
if (!existsSync56(join57(dir, ".git")))
|
|
32611
32611
|
return false;
|
|
32612
|
-
const pkgPath =
|
|
32613
|
-
if (!
|
|
32612
|
+
const pkgPath = join57(dir, "package.json");
|
|
32613
|
+
if (!existsSync56(pkgPath))
|
|
32614
32614
|
return false;
|
|
32615
32615
|
const pkg = JSON.parse(readFileSync49(pkgPath, "utf-8"));
|
|
32616
32616
|
return pkg.name === "switchroom";
|
|
@@ -32625,7 +32625,7 @@ function checkAgents(config, configPath) {
|
|
|
32625
32625
|
const authStatuses = getAllAuthStatuses(config);
|
|
32626
32626
|
for (const [name, agentConfig] of Object.entries(config.agents)) {
|
|
32627
32627
|
const agentDir = resolve32(agentsDir, name);
|
|
32628
|
-
if (!
|
|
32628
|
+
if (!existsSync56(agentDir)) {
|
|
32629
32629
|
results.push({
|
|
32630
32630
|
name: `${name}: scaffold`,
|
|
32631
32631
|
status: "fail",
|
|
@@ -32646,7 +32646,7 @@ function checkAgents(config, configPath) {
|
|
|
32646
32646
|
fix: `Rotate the bot token (e.g. via \`switchroom vault\`), then run ` + `\`switchroom agent unquarantine ${name}\` and \`switchroom agent restart ${name}\``
|
|
32647
32647
|
});
|
|
32648
32648
|
}
|
|
32649
|
-
results.push(checkStartShStale(name,
|
|
32649
|
+
results.push(checkStartShStale(name, join57(agentDir, "start.sh")));
|
|
32650
32650
|
results.push(checkLeakedHomeSwitchroom(name, agentDir));
|
|
32651
32651
|
const status = statuses[name];
|
|
32652
32652
|
const active = status?.active ?? "unknown";
|
|
@@ -32723,8 +32723,8 @@ function checkAgents(config, configPath) {
|
|
|
32723
32723
|
}
|
|
32724
32724
|
}
|
|
32725
32725
|
if (agentConfig.channels?.telegram?.plugin === "switchroom") {
|
|
32726
|
-
const mcpJsonPath =
|
|
32727
|
-
if (!
|
|
32726
|
+
const mcpJsonPath = join57(agentDir, ".mcp.json");
|
|
32727
|
+
if (!existsSync56(mcpJsonPath)) {
|
|
32728
32728
|
results.push({
|
|
32729
32729
|
name: `${name}: .mcp.json`,
|
|
32730
32730
|
status: "fail",
|
|
@@ -32810,7 +32810,7 @@ function mffEnvPath(config) {
|
|
|
32810
32810
|
return agent ? resolve32(home2, ".switchroom/credentials", agent, "my-family-finance/.env") : resolve32(home2, ".switchroom/credentials/my-family-finance/.env");
|
|
32811
32811
|
}
|
|
32812
32812
|
function mffEnvState(envPath) {
|
|
32813
|
-
if (!
|
|
32813
|
+
if (!existsSync56(envPath))
|
|
32814
32814
|
return "absent";
|
|
32815
32815
|
try {
|
|
32816
32816
|
accessSync2(envPath, fsConstants5.R_OK);
|
|
@@ -32828,7 +32828,7 @@ function checkMffVaultKeyPresent(passphrase, vaultPath) {
|
|
|
32828
32828
|
fix: "Export SWITCHROOM_VAULT_PASSPHRASE to enable MFF vault probes"
|
|
32829
32829
|
};
|
|
32830
32830
|
}
|
|
32831
|
-
if (!
|
|
32831
|
+
if (!existsSync56(vaultPath)) {
|
|
32832
32832
|
return {
|
|
32833
32833
|
name: "mff: vault key present",
|
|
32834
32834
|
status: "fail",
|
|
@@ -32881,7 +32881,7 @@ function deriveEd25519PublicKeyBytes(keyMaterial) {
|
|
|
32881
32881
|
}
|
|
32882
32882
|
}
|
|
32883
32883
|
function checkMffVaultKeyFormat(passphrase, vaultPath) {
|
|
32884
|
-
if (!passphrase || !
|
|
32884
|
+
if (!passphrase || !existsSync56(vaultPath)) {
|
|
32885
32885
|
return {
|
|
32886
32886
|
name: "mff: vault key format",
|
|
32887
32887
|
status: "warn",
|
|
@@ -33024,9 +33024,9 @@ async function checkMffAuthFlow(envPath = mffEnvPath(), timeoutMs = 8000) {
|
|
|
33024
33024
|
detail: "skipped (MFF_API_URL not set)"
|
|
33025
33025
|
};
|
|
33026
33026
|
}
|
|
33027
|
-
const credDir =
|
|
33028
|
-
const authScript =
|
|
33029
|
-
if (!
|
|
33027
|
+
const credDir = dirname13(envPath);
|
|
33028
|
+
const authScript = join57(credDir, "claude-auth.py");
|
|
33029
|
+
if (!existsSync56(authScript)) {
|
|
33030
33030
|
return {
|
|
33031
33031
|
name: "mff: auth flow",
|
|
33032
33032
|
status: "warn",
|
|
@@ -49937,14 +49937,14 @@ var {
|
|
|
49937
49937
|
} = import__.default;
|
|
49938
49938
|
|
|
49939
49939
|
// src/build-info.ts
|
|
49940
|
-
var VERSION = "0.14.
|
|
49941
|
-
var COMMIT_SHA = "
|
|
49940
|
+
var VERSION = "0.14.93";
|
|
49941
|
+
var COMMIT_SHA = "87b62902";
|
|
49942
49942
|
|
|
49943
49943
|
// src/cli/agent.ts
|
|
49944
49944
|
init_source();
|
|
49945
|
-
import { join as
|
|
49946
|
-
import { rmSync as rmSync9, existsSync as
|
|
49947
|
-
import { homedir as
|
|
49945
|
+
import { join as join18, resolve as resolve21 } from "node:path";
|
|
49946
|
+
import { rmSync as rmSync9, existsSync as existsSync27, readFileSync as readFileSync22, writeFileSync as writeFileSync13 } from "node:fs";
|
|
49947
|
+
import { homedir as homedir7 } from "node:os";
|
|
49948
49948
|
|
|
49949
49949
|
// src/agents/scheduler-state.ts
|
|
49950
49950
|
import { closeSync, openSync, readSync, statSync } from "node:fs";
|
|
@@ -53465,24 +53465,179 @@ function buildAccessJson2(agentConfig, telegramConfig, resolvedTopicId, userId)
|
|
|
53465
53465
|
`;
|
|
53466
53466
|
}
|
|
53467
53467
|
|
|
53468
|
+
// src/cli/write-compose.ts
|
|
53469
|
+
init_compose();
|
|
53470
|
+
import { chownSync as chownSync2 } from "node:fs";
|
|
53471
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
53472
|
+
import { homedir as homedir5 } from "node:os";
|
|
53473
|
+
import { dirname as dirname3 } from "node:path";
|
|
53474
|
+
|
|
53475
|
+
// src/config/release-resolve.ts
|
|
53476
|
+
function resolveImageTag(release) {
|
|
53477
|
+
if (!release)
|
|
53478
|
+
return "latest";
|
|
53479
|
+
if (release.pin)
|
|
53480
|
+
return release.pin;
|
|
53481
|
+
if (release.channel)
|
|
53482
|
+
return release.channel;
|
|
53483
|
+
return "latest";
|
|
53484
|
+
}
|
|
53485
|
+
function resolveRelease(opts) {
|
|
53486
|
+
if (opts.override)
|
|
53487
|
+
return opts.override;
|
|
53488
|
+
if (opts.perAgent)
|
|
53489
|
+
return opts.perAgent;
|
|
53490
|
+
if (opts.root)
|
|
53491
|
+
return opts.root;
|
|
53492
|
+
return;
|
|
53493
|
+
}
|
|
53494
|
+
|
|
53495
|
+
// src/cli/operator-uid.ts
|
|
53496
|
+
import {
|
|
53497
|
+
chownSync,
|
|
53498
|
+
existsSync as existsSync15,
|
|
53499
|
+
lstatSync as lstatSync4,
|
|
53500
|
+
readdirSync as readdirSync7,
|
|
53501
|
+
realpathSync as realpathSync3,
|
|
53502
|
+
statSync as statSync8
|
|
53503
|
+
} from "node:fs";
|
|
53504
|
+
import { join as join10 } from "node:path";
|
|
53505
|
+
function resolveOperatorUid() {
|
|
53506
|
+
const sudoUid = process.env.SUDO_UID;
|
|
53507
|
+
if (sudoUid !== undefined) {
|
|
53508
|
+
const parsed = parseInt(sudoUid, 10);
|
|
53509
|
+
if (Number.isFinite(parsed) && parsed > 0)
|
|
53510
|
+
return parsed;
|
|
53511
|
+
}
|
|
53512
|
+
if (typeof process.getuid === "function") {
|
|
53513
|
+
const uid = process.getuid();
|
|
53514
|
+
if (uid > 0)
|
|
53515
|
+
return uid;
|
|
53516
|
+
}
|
|
53517
|
+
return;
|
|
53518
|
+
}
|
|
53519
|
+
function operatorOwnedPaths(home2) {
|
|
53520
|
+
const root = join10(home2, ".switchroom");
|
|
53521
|
+
return [
|
|
53522
|
+
join10(root, "vault"),
|
|
53523
|
+
join10(root, "vault-auto-unlock"),
|
|
53524
|
+
join10(root, "vault-audit.log"),
|
|
53525
|
+
join10(root, "host-control-audit.log"),
|
|
53526
|
+
join10(root, "accounts"),
|
|
53527
|
+
join10(root, "compose")
|
|
53528
|
+
];
|
|
53529
|
+
}
|
|
53530
|
+
function restoreOperatorOwnership(home2, operatorUid, deps = {}) {
|
|
53531
|
+
const chown = deps.chown ?? ((p, u, g) => chownSync(p, u, g));
|
|
53532
|
+
const exists = deps.exists ?? ((p) => existsSync15(p));
|
|
53533
|
+
const isSymlink = deps.isSymlink ?? ((p) => {
|
|
53534
|
+
try {
|
|
53535
|
+
return lstatSync4(p).isSymbolicLink();
|
|
53536
|
+
} catch {
|
|
53537
|
+
return false;
|
|
53538
|
+
}
|
|
53539
|
+
});
|
|
53540
|
+
const isDir = deps.isDir ?? ((p) => {
|
|
53541
|
+
try {
|
|
53542
|
+
return statSync8(p).isDirectory();
|
|
53543
|
+
} catch {
|
|
53544
|
+
return false;
|
|
53545
|
+
}
|
|
53546
|
+
});
|
|
53547
|
+
const realpath = deps.realpath ?? ((p) => {
|
|
53548
|
+
try {
|
|
53549
|
+
return realpathSync3(p);
|
|
53550
|
+
} catch {
|
|
53551
|
+
return p;
|
|
53552
|
+
}
|
|
53553
|
+
});
|
|
53554
|
+
const readdir = deps.readdir ?? ((p) => {
|
|
53555
|
+
try {
|
|
53556
|
+
return readdirSync7(p);
|
|
53557
|
+
} catch {
|
|
53558
|
+
return [];
|
|
53559
|
+
}
|
|
53560
|
+
});
|
|
53561
|
+
const chowned = [];
|
|
53562
|
+
const seen = new Set;
|
|
53563
|
+
const visit = (path) => {
|
|
53564
|
+
if (!exists(path))
|
|
53565
|
+
return;
|
|
53566
|
+
const target = isSymlink(path) ? realpath(path) : path;
|
|
53567
|
+
if (seen.has(target))
|
|
53568
|
+
return;
|
|
53569
|
+
seen.add(target);
|
|
53570
|
+
try {
|
|
53571
|
+
chown(target, operatorUid, operatorUid);
|
|
53572
|
+
chowned.push(target);
|
|
53573
|
+
} catch {}
|
|
53574
|
+
if (isDir(target)) {
|
|
53575
|
+
for (const entry of readdir(target)) {
|
|
53576
|
+
visit(join10(target, entry));
|
|
53577
|
+
}
|
|
53578
|
+
}
|
|
53579
|
+
};
|
|
53580
|
+
for (const p of operatorOwnedPaths(home2))
|
|
53581
|
+
visit(p);
|
|
53582
|
+
return chowned;
|
|
53583
|
+
}
|
|
53584
|
+
|
|
53585
|
+
// src/cli/write-compose.ts
|
|
53586
|
+
var AGENT_IMAGE_TAG_RE = /image:\s*\S*switchroom-agent:(\S+)/;
|
|
53587
|
+
async function writeComposeFile(opts) {
|
|
53588
|
+
const release = resolveRelease({ override: opts.releaseOverride, root: opts.config.release });
|
|
53589
|
+
const imageTag = resolveImageTag(release);
|
|
53590
|
+
const operatorUid = resolveOperatorUid();
|
|
53591
|
+
const content = generateCompose({
|
|
53592
|
+
config: opts.config,
|
|
53593
|
+
imageTag,
|
|
53594
|
+
buildMode: opts.buildMode ?? "pull",
|
|
53595
|
+
buildContext: opts.buildContext,
|
|
53596
|
+
homeDir: homedir5(),
|
|
53597
|
+
switchroomConfigPath: opts.switchroomConfigPath,
|
|
53598
|
+
operatorUid
|
|
53599
|
+
});
|
|
53600
|
+
let previous = null;
|
|
53601
|
+
try {
|
|
53602
|
+
previous = await readFile(opts.composePath, "utf8");
|
|
53603
|
+
} catch {
|
|
53604
|
+
previous = null;
|
|
53605
|
+
}
|
|
53606
|
+
const previousImageTag = previous ? AGENT_IMAGE_TAG_RE.exec(previous)?.[1] ?? null : null;
|
|
53607
|
+
await mkdir(dirname3(opts.composePath), { recursive: true });
|
|
53608
|
+
await writeFile(opts.composePath, content, { encoding: "utf8", mode: 384 });
|
|
53609
|
+
if (operatorUid !== undefined && process.geteuid?.() === 0) {
|
|
53610
|
+
try {
|
|
53611
|
+
chownSync2(opts.composePath, operatorUid, operatorUid);
|
|
53612
|
+
} catch {}
|
|
53613
|
+
}
|
|
53614
|
+
return {
|
|
53615
|
+
composePath: opts.composePath,
|
|
53616
|
+
imageTag,
|
|
53617
|
+
bytes: Buffer.byteLength(content, "utf8"),
|
|
53618
|
+
changed: previous !== content,
|
|
53619
|
+
previousImageTag
|
|
53620
|
+
};
|
|
53621
|
+
}
|
|
53622
|
+
|
|
53468
53623
|
// src/cli/agent.ts
|
|
53469
53624
|
init_lifecycle();
|
|
53470
53625
|
init_merge();
|
|
53471
53626
|
|
|
53472
53627
|
// src/agents/in-flight.ts
|
|
53473
|
-
import { readdirSync as
|
|
53628
|
+
import { readdirSync as readdirSync8, statSync as statSync9 } from "node:fs";
|
|
53474
53629
|
import { resolve as resolve14 } from "node:path";
|
|
53475
53630
|
var DEFAULT_RECENCY_MS = 30000;
|
|
53476
53631
|
function safeReaddir(path) {
|
|
53477
53632
|
try {
|
|
53478
|
-
return
|
|
53633
|
+
return readdirSync8(path);
|
|
53479
53634
|
} catch {
|
|
53480
53635
|
return [];
|
|
53481
53636
|
}
|
|
53482
53637
|
}
|
|
53483
53638
|
function safeMtimeMs(path) {
|
|
53484
53639
|
try {
|
|
53485
|
-
return
|
|
53640
|
+
return statSync9(path).mtimeMs;
|
|
53486
53641
|
} catch {
|
|
53487
53642
|
return 0;
|
|
53488
53643
|
}
|
|
@@ -53501,7 +53656,7 @@ function collectJsonl(root, maxDepth = 4) {
|
|
|
53501
53656
|
const full = resolve14(dir, entry);
|
|
53502
53657
|
let isDir = false;
|
|
53503
53658
|
try {
|
|
53504
|
-
isDir =
|
|
53659
|
+
isDir = statSync9(full).isDirectory();
|
|
53505
53660
|
} catch {
|
|
53506
53661
|
continue;
|
|
53507
53662
|
}
|
|
@@ -53690,13 +53845,13 @@ function spinner(message) {
|
|
|
53690
53845
|
}
|
|
53691
53846
|
|
|
53692
53847
|
// src/agents/status.ts
|
|
53693
|
-
import { existsSync as
|
|
53694
|
-
import { join as
|
|
53848
|
+
import { existsSync as existsSync19, readFileSync as readFileSync17, statSync as statSync11 } from "node:fs";
|
|
53849
|
+
import { join as join13 } from "node:path";
|
|
53695
53850
|
import { execFileSync as execFileSync9 } from "node:child_process";
|
|
53696
53851
|
|
|
53697
53852
|
// src/agents/handoff-summarizer.ts
|
|
53698
|
-
import { readFileSync as readFileSync15, writeFileSync as writeFileSync8, renameSync as renameSync5, mkdirSync as mkdirSync13, existsSync as
|
|
53699
|
-
import { join as
|
|
53853
|
+
import { readFileSync as readFileSync15, writeFileSync as writeFileSync8, renameSync as renameSync5, mkdirSync as mkdirSync13, existsSync as existsSync17, statSync as statSync10, readdirSync as readdirSync9 } from "node:fs";
|
|
53854
|
+
import { join as join12 } from "node:path";
|
|
53700
53855
|
var DEFAULT_MAX_TURNS = 50;
|
|
53701
53856
|
var TOPIC_MAX_CHARS = 117;
|
|
53702
53857
|
var TURN_TEXT_MAX_CHARS = 1200;
|
|
@@ -53831,8 +53986,8 @@ function clampTopic(s) {
|
|
|
53831
53986
|
}
|
|
53832
53987
|
function writeSidecarsAtomic(agentDir, briefing, topic) {
|
|
53833
53988
|
mkdirSync13(agentDir, { recursive: true });
|
|
53834
|
-
const handoffPath =
|
|
53835
|
-
const topicPath =
|
|
53989
|
+
const handoffPath = join12(agentDir, ".handoff.md");
|
|
53990
|
+
const topicPath = join12(agentDir, ".handoff-topic");
|
|
53836
53991
|
const handoffTmp = handoffPath + ".tmp";
|
|
53837
53992
|
const topicTmp = topicPath + ".tmp";
|
|
53838
53993
|
writeFileSync8(handoffTmp, briefing, "utf-8");
|
|
@@ -53893,22 +54048,22 @@ async function mirrorToHindsight(briefing, opts) {
|
|
|
53893
54048
|
}
|
|
53894
54049
|
}
|
|
53895
54050
|
function findLatestSessionJsonl(claudeConfigDir) {
|
|
53896
|
-
const projects =
|
|
53897
|
-
if (!
|
|
54051
|
+
const projects = join12(claudeConfigDir, "projects");
|
|
54052
|
+
if (!existsSync17(projects))
|
|
53898
54053
|
return null;
|
|
53899
54054
|
let latest = null;
|
|
53900
54055
|
const walk = (dir) => {
|
|
53901
54056
|
let entries;
|
|
53902
54057
|
try {
|
|
53903
|
-
entries =
|
|
54058
|
+
entries = readdirSync9(dir);
|
|
53904
54059
|
} catch {
|
|
53905
54060
|
return;
|
|
53906
54061
|
}
|
|
53907
54062
|
for (const name of entries) {
|
|
53908
|
-
const full =
|
|
54063
|
+
const full = join12(dir, name);
|
|
53909
54064
|
let st;
|
|
53910
54065
|
try {
|
|
53911
|
-
st =
|
|
54066
|
+
st = statSync10(full);
|
|
53912
54067
|
} catch {
|
|
53913
54068
|
continue;
|
|
53914
54069
|
}
|
|
@@ -53928,9 +54083,9 @@ function findLatestSessionJsonl(claudeConfigDir) {
|
|
|
53928
54083
|
}
|
|
53929
54084
|
|
|
53930
54085
|
// src/agents/perf.ts
|
|
53931
|
-
import { existsSync as
|
|
54086
|
+
import { existsSync as existsSync18, readFileSync as readFileSync16 } from "node:fs";
|
|
53932
54087
|
function readTurnUsages(jsonlPath, lastN) {
|
|
53933
|
-
if (!
|
|
54088
|
+
if (!existsSync18(jsonlPath))
|
|
53934
54089
|
return [];
|
|
53935
54090
|
if (lastN <= 0)
|
|
53936
54091
|
return [];
|
|
@@ -54241,10 +54396,10 @@ async function buildAgentStatusReport(inputs) {
|
|
|
54241
54396
|
};
|
|
54242
54397
|
}
|
|
54243
54398
|
}
|
|
54244
|
-
const logPath =
|
|
54399
|
+
const logPath = join13(inputs.agentDir, "telegram", "gateway.log");
|
|
54245
54400
|
const logContent = inputs.readGatewayLog(logPath);
|
|
54246
54401
|
const polling = buildPollingStatus(logContent);
|
|
54247
|
-
const historyDbPath =
|
|
54402
|
+
const historyDbPath = join13(inputs.agentDir, "telegram", "history.db");
|
|
54248
54403
|
const messagesResult = inputs.getLastMessages(historyDbPath);
|
|
54249
54404
|
const messages = buildMessageStatus(messagesResult);
|
|
54250
54405
|
const checks = [
|
|
@@ -54339,10 +54494,10 @@ function formatWindowFromIso(first, last) {
|
|
|
54339
54494
|
return `${f} .. ${l}`;
|
|
54340
54495
|
}
|
|
54341
54496
|
function readLogFile(logPath) {
|
|
54342
|
-
if (!
|
|
54497
|
+
if (!existsSync19(logPath))
|
|
54343
54498
|
return null;
|
|
54344
54499
|
try {
|
|
54345
|
-
const stat =
|
|
54500
|
+
const stat = statSync11(logPath);
|
|
54346
54501
|
const cap = 256 * 1024;
|
|
54347
54502
|
if (stat.size <= cap) {
|
|
54348
54503
|
return readFileSync17(logPath, "utf-8");
|
|
@@ -54361,7 +54516,7 @@ function readLogFile(logPath) {
|
|
|
54361
54516
|
}
|
|
54362
54517
|
}
|
|
54363
54518
|
function readLastMessages(historyDbPath) {
|
|
54364
|
-
if (!
|
|
54519
|
+
if (!existsSync19(historyDbPath)) {
|
|
54365
54520
|
return {
|
|
54366
54521
|
lastInboundTs: null,
|
|
54367
54522
|
lastOutboundTs: null,
|
|
@@ -54522,7 +54677,7 @@ function defaultStatusInputs(params) {
|
|
|
54522
54677
|
}
|
|
54523
54678
|
function readCacheTelemetry(agentDir) {
|
|
54524
54679
|
try {
|
|
54525
|
-
const claudeConfigDir =
|
|
54680
|
+
const claudeConfigDir = join13(agentDir, ".claude");
|
|
54526
54681
|
const jsonl = findLatestSessionJsonl(claudeConfigDir);
|
|
54527
54682
|
if (!jsonl)
|
|
54528
54683
|
return null;
|
|
@@ -54546,7 +54701,7 @@ function readCacheTelemetry(agentDir) {
|
|
|
54546
54701
|
// src/agents/create-orchestrator.ts
|
|
54547
54702
|
init_loader();
|
|
54548
54703
|
import { resolve as resolve16 } from "node:path";
|
|
54549
|
-
import { existsSync as
|
|
54704
|
+
import { existsSync as existsSync22, rmSync as rmSync6 } from "node:fs";
|
|
54550
54705
|
init_lifecycle();
|
|
54551
54706
|
init_manager();
|
|
54552
54707
|
|
|
@@ -54653,7 +54808,7 @@ async function createAgent(opts) {
|
|
|
54653
54808
|
resolve16(cwd, "switchroom.yml")
|
|
54654
54809
|
];
|
|
54655
54810
|
for (const c of candidates) {
|
|
54656
|
-
if (
|
|
54811
|
+
if (existsSync22(c))
|
|
54657
54812
|
return c;
|
|
54658
54813
|
}
|
|
54659
54814
|
throw new Error("switchroom.yaml not found. Pass configPath or run from the project root.");
|
|
@@ -54716,14 +54871,14 @@ async function completeCreation(name, code, opts = {}) {
|
|
|
54716
54871
|
const cwd = process.cwd();
|
|
54717
54872
|
const candidates = [resolve16(cwd, "switchroom.yaml"), resolve16(cwd, "switchroom.yml")];
|
|
54718
54873
|
for (const c of candidates)
|
|
54719
|
-
if (
|
|
54874
|
+
if (existsSync22(c))
|
|
54720
54875
|
return c;
|
|
54721
54876
|
throw new Error("switchroom.yaml not found. Pass configPath option.");
|
|
54722
54877
|
})();
|
|
54723
54878
|
const config = loadConfig(configPath);
|
|
54724
54879
|
const agentsDir = resolveAgentsDir(config);
|
|
54725
54880
|
const agentDir = resolve16(agentsDir, name);
|
|
54726
|
-
if (!
|
|
54881
|
+
if (!existsSync22(agentDir)) {
|
|
54727
54882
|
throw new Error(`Agent dir not found: ${agentDir}. Run createAgent first.`);
|
|
54728
54883
|
}
|
|
54729
54884
|
const authCodeResult = submitAuthCode(name, agentDir, code, undefined, opts.pollTimeoutMs ? { pollTimeoutMs: opts.pollTimeoutMs } : {});
|
|
@@ -54762,8 +54917,8 @@ async function completeCreation(name, code, opts = {}) {
|
|
|
54762
54917
|
}
|
|
54763
54918
|
|
|
54764
54919
|
// src/agents/add-orchestrator.ts
|
|
54765
|
-
import { resolve as resolve18, join as
|
|
54766
|
-
import { existsSync as
|
|
54920
|
+
import { resolve as resolve18, join as join16 } from "node:path";
|
|
54921
|
+
import { existsSync as existsSync24, rmSync as rmSync7, statSync as statSync15 } from "node:fs";
|
|
54767
54922
|
import { execFileSync as execFileSync12 } from "node:child_process";
|
|
54768
54923
|
|
|
54769
54924
|
// src/setup/botfather-walkthrough.ts
|
|
@@ -54854,7 +55009,7 @@ function enforceUsername(username, agentSlug, expectedUsername, loose, warn) {
|
|
|
54854
55009
|
}
|
|
54855
55010
|
|
|
54856
55011
|
// src/setup/profile-picker.ts
|
|
54857
|
-
import { existsSync as
|
|
55012
|
+
import { existsSync as existsSync23, readdirSync as readdirSync12, statSync as statSync14 } from "node:fs";
|
|
54858
55013
|
import { resolve as resolve17 } from "node:path";
|
|
54859
55014
|
var PROFILE_GLOSSES = {
|
|
54860
55015
|
default: "minimal baseline \u2014 generic chat helper, no opinion.",
|
|
@@ -54866,13 +55021,13 @@ var DEFAULT_MAX_ATTEMPTS2 = 3;
|
|
|
54866
55021
|
var PROFILES_ROOT2 = resolve17(import.meta.dirname, "../../profiles");
|
|
54867
55022
|
function defaultListProfileSkills(profileName) {
|
|
54868
55023
|
const skillsDir = resolve17(PROFILES_ROOT2, profileName, "skills");
|
|
54869
|
-
if (!
|
|
55024
|
+
if (!existsSync23(skillsDir)) {
|
|
54870
55025
|
return [];
|
|
54871
55026
|
}
|
|
54872
55027
|
try {
|
|
54873
|
-
return
|
|
55028
|
+
return readdirSync12(skillsDir).filter((entry) => {
|
|
54874
55029
|
try {
|
|
54875
|
-
return
|
|
55030
|
+
return statSync14(resolve17(skillsDir, entry)).isDirectory();
|
|
54876
55031
|
} catch {
|
|
54877
55032
|
return false;
|
|
54878
55033
|
}
|
|
@@ -55153,7 +55308,7 @@ function runFinalPreflight(inputs) {
|
|
|
55153
55308
|
const { name, agentDir, expectedUserId, isUnitActive, configPath } = inputs;
|
|
55154
55309
|
const unitPath = resolve18(process.env.HOME ?? "/root", ".config/systemd/user", `switchroom-${name}.service`);
|
|
55155
55310
|
let autoaccept = { ok: false, detail: `unit not found at ${unitPath}` };
|
|
55156
|
-
if (
|
|
55311
|
+
if (existsSync24(unitPath)) {
|
|
55157
55312
|
const fs2 = __require("node:fs");
|
|
55158
55313
|
const content = fs2.readFileSync(unitPath, "utf-8");
|
|
55159
55314
|
if (content.includes("expect") || content.includes("autoaccept")) {
|
|
@@ -55172,7 +55327,7 @@ function runFinalPreflight(inputs) {
|
|
|
55172
55327
|
}
|
|
55173
55328
|
const envPath = resolve18(agentDir, "telegram", ".env");
|
|
55174
55329
|
let token = { ok: false, detail: `telegram/.env missing at ${envPath}` };
|
|
55175
|
-
if (
|
|
55330
|
+
if (existsSync24(envPath)) {
|
|
55176
55331
|
const fs2 = __require("node:fs");
|
|
55177
55332
|
const content = fs2.readFileSync(envPath, "utf-8");
|
|
55178
55333
|
if (/TELEGRAM_BOT_TOKEN=\S+/.test(content)) {
|
|
@@ -55200,7 +55355,7 @@ function runFinalPreflight(inputs) {
|
|
|
55200
55355
|
}
|
|
55201
55356
|
const accessPath = resolve18(agentDir, "telegram", "access.json");
|
|
55202
55357
|
let access;
|
|
55203
|
-
if (!
|
|
55358
|
+
if (!existsSync24(accessPath)) {
|
|
55204
55359
|
access = {
|
|
55205
55360
|
ok: false,
|
|
55206
55361
|
detail: `access.json missing at ${accessPath}`
|
|
@@ -55227,7 +55382,7 @@ function runFinalPreflight(inputs) {
|
|
|
55227
55382
|
}
|
|
55228
55383
|
const settingsPath = resolve18(agentDir, ".claude", "settings.json");
|
|
55229
55384
|
let mcp;
|
|
55230
|
-
if (!
|
|
55385
|
+
if (!existsSync24(settingsPath)) {
|
|
55231
55386
|
mcp = {
|
|
55232
55387
|
ok: false,
|
|
55233
55388
|
detail: `.claude/settings.json missing at ${settingsPath}. ` + `Fix: switchroom agent reconcile ${name}`
|
|
@@ -55261,7 +55416,7 @@ function runFinalPreflight(inputs) {
|
|
|
55261
55416
|
ok: true,
|
|
55262
55417
|
detail: "skipped (no switchroom.yaml path supplied)"
|
|
55263
55418
|
};
|
|
55264
|
-
} else if (!
|
|
55419
|
+
} else if (!existsSync24(configPath)) {
|
|
55265
55420
|
vaultMgd = {
|
|
55266
55421
|
ok: false,
|
|
55267
55422
|
detail: `switchroom.yaml not found at ${configPath}`
|
|
@@ -55307,7 +55462,7 @@ function runFinalPreflight(inputs) {
|
|
|
55307
55462
|
}
|
|
55308
55463
|
function pruneBundledSkills(agentDir, keep, scope) {
|
|
55309
55464
|
const skillsDir = resolve18(agentDir, ".claude", "skills");
|
|
55310
|
-
if (!
|
|
55465
|
+
if (!existsSync24(skillsDir)) {
|
|
55311
55466
|
return [];
|
|
55312
55467
|
}
|
|
55313
55468
|
const keepSet = new Set(keep);
|
|
@@ -55316,12 +55471,12 @@ function pruneBundledSkills(agentDir, keep, scope) {
|
|
|
55316
55471
|
for (const entry of scopeSet) {
|
|
55317
55472
|
if (keepSet.has(entry))
|
|
55318
55473
|
continue;
|
|
55319
|
-
const entryPath =
|
|
55320
|
-
if (!
|
|
55474
|
+
const entryPath = join16(skillsDir, entry);
|
|
55475
|
+
if (!existsSync24(entryPath))
|
|
55321
55476
|
continue;
|
|
55322
55477
|
let isDir = false;
|
|
55323
55478
|
try {
|
|
55324
|
-
isDir =
|
|
55479
|
+
isDir = statSync15(entryPath).isDirectory();
|
|
55325
55480
|
} catch {
|
|
55326
55481
|
continue;
|
|
55327
55482
|
}
|
|
@@ -55356,7 +55511,7 @@ init_vault();
|
|
|
55356
55511
|
init_lifecycle();
|
|
55357
55512
|
import { resolve as resolve19 } from "node:path";
|
|
55358
55513
|
import {
|
|
55359
|
-
existsSync as
|
|
55514
|
+
existsSync as existsSync25,
|
|
55360
55515
|
mkdtempSync as mkdtempSync3,
|
|
55361
55516
|
rmSync as rmSync8,
|
|
55362
55517
|
cpSync
|
|
@@ -55388,7 +55543,7 @@ function defaultDeps() {
|
|
|
55388
55543
|
},
|
|
55389
55544
|
copyDir: (src, dst) => cpSync(src, dst, { recursive: true }),
|
|
55390
55545
|
removeDir: (p) => rmSync8(p, { recursive: true, force: true }),
|
|
55391
|
-
existsSync:
|
|
55546
|
+
existsSync: existsSync25,
|
|
55392
55547
|
readFileSync: (p, enc) => readFileSync20(p, enc)
|
|
55393
55548
|
};
|
|
55394
55549
|
}
|
|
@@ -55805,11 +55960,11 @@ function checkQuarantineRefusal(agentsDir, name) {
|
|
|
55805
55960
|
function preflightCheck(name, agentDir, _usesDevChannels) {
|
|
55806
55961
|
const errors2 = [];
|
|
55807
55962
|
const startSh = resolve21(agentDir, "start.sh");
|
|
55808
|
-
if (!
|
|
55963
|
+
if (!existsSync27(startSh)) {
|
|
55809
55964
|
errors2.push(`start.sh not found at ${startSh}`);
|
|
55810
55965
|
}
|
|
55811
55966
|
const envPath = resolve21(agentDir, "telegram", ".env");
|
|
55812
|
-
if (
|
|
55967
|
+
if (existsSync27(envPath)) {
|
|
55813
55968
|
const envContent = readFileSync22(envPath, "utf-8");
|
|
55814
55969
|
if (!envContent.includes("TELEGRAM_BOT_TOKEN=") || envContent.includes("# Set your bot token")) {
|
|
55815
55970
|
errors2.push(`telegram/.env is missing TELEGRAM_BOT_TOKEN. ` + `Set it or run: switchroom setup`);
|
|
@@ -55817,7 +55972,7 @@ function preflightCheck(name, agentDir, _usesDevChannels) {
|
|
|
55817
55972
|
} else {
|
|
55818
55973
|
errors2.push(`telegram/.env not found at ${envPath}`);
|
|
55819
55974
|
}
|
|
55820
|
-
if (!
|
|
55975
|
+
if (!existsSync27(resolve21(agentDir, ".claude", "settings.json"))) {
|
|
55821
55976
|
errors2.push(`.claude/settings.json not found. Run: switchroom agent reconcile ${name}`);
|
|
55822
55977
|
}
|
|
55823
55978
|
return errors2;
|
|
@@ -55894,7 +56049,7 @@ function synthesizeTopicName2(name) {
|
|
|
55894
56049
|
return name.split(/[-_]+/).filter((s) => s.length > 0).map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(" ");
|
|
55895
56050
|
}
|
|
55896
56051
|
function writeAgentEntryToConfig(configPath, name, profile) {
|
|
55897
|
-
if (!
|
|
56052
|
+
if (!existsSync27(configPath)) {
|
|
55898
56053
|
throw new Error(`switchroom.yaml not found at ${configPath}`);
|
|
55899
56054
|
}
|
|
55900
56055
|
const raw = readFileSync22(configPath, "utf-8");
|
|
@@ -55925,7 +56080,7 @@ function updateAgentExtendsInConfig(configPath, name, profile) {
|
|
|
55925
56080
|
writeFileSync13(configPath, doc.toString(), "utf-8");
|
|
55926
56081
|
}
|
|
55927
56082
|
function removeAgentFromConfig(configPath, name) {
|
|
55928
|
-
if (!
|
|
56083
|
+
if (!existsSync27(configPath))
|
|
55929
56084
|
return;
|
|
55930
56085
|
const raw = readFileSync22(configPath, "utf-8");
|
|
55931
56086
|
const doc = import_yaml5.default.parseDocument(raw);
|
|
@@ -55939,7 +56094,8 @@ async function reconcileAndRestartAgent(name, config, agentsDir, configPath, opt
|
|
|
55939
56094
|
reconcileAgent,
|
|
55940
56095
|
restartAgent,
|
|
55941
56096
|
gracefulRestartAgent,
|
|
55942
|
-
applyCronChangesHot
|
|
56097
|
+
applyCronChangesHot,
|
|
56098
|
+
writeComposeFile
|
|
55943
56099
|
}) {
|
|
55944
56100
|
const log = opts.silent ? () => {} : (msg) => console.log(msg);
|
|
55945
56101
|
const agentConfig = config.agents[name];
|
|
@@ -55972,7 +56128,7 @@ async function reconcileAndRestartAgent(name, config, agentsDir, configPath, opt
|
|
|
55972
56128
|
}
|
|
55973
56129
|
if (!opts.force) {
|
|
55974
56130
|
const envPath = resolve21(agentsDir, name, "telegram", ".env");
|
|
55975
|
-
if (
|
|
56131
|
+
if (existsSync27(envPath)) {
|
|
55976
56132
|
const envContent = readFileSync22(envPath, "utf-8");
|
|
55977
56133
|
const match = envContent.match(/^TELEGRAM_BOT_TOKEN=(.+)$/m);
|
|
55978
56134
|
if (match) {
|
|
@@ -55988,6 +56144,20 @@ async function reconcileAndRestartAgent(name, config, agentsDir, configPath, opt
|
|
|
55988
56144
|
}
|
|
55989
56145
|
}
|
|
55990
56146
|
}
|
|
56147
|
+
try {
|
|
56148
|
+
const r = await deps.writeComposeFile({
|
|
56149
|
+
config,
|
|
56150
|
+
composePath: opts.composePath ?? composeFilePath(),
|
|
56151
|
+
switchroomConfigPath: configPath
|
|
56152
|
+
});
|
|
56153
|
+
if (r.changed) {
|
|
56154
|
+
const tagNote = r.previousImageTag && r.previousImageTag !== r.imageTag ? ` (image ${r.previousImageTag} \u2192 ${r.imageTag})` : ` (image ${r.imageTag})`;
|
|
56155
|
+
log(source_default.green(` ${name}: compose regenerated${tagNote}`));
|
|
56156
|
+
}
|
|
56157
|
+
} catch (err) {
|
|
56158
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
56159
|
+
log(source_default.yellow(` ${name}: could not regenerate compose (${msg}) \u2014 image/pin changes may not apply; run \`switchroom apply\``));
|
|
56160
|
+
}
|
|
55991
56161
|
if (opts.graceful) {
|
|
55992
56162
|
try {
|
|
55993
56163
|
const r = await deps.gracefulRestartAgent(name);
|
|
@@ -56022,7 +56192,7 @@ function registerAgentCommand(program3) {
|
|
|
56022
56192
|
}
|
|
56023
56193
|
return;
|
|
56024
56194
|
}
|
|
56025
|
-
const logsDir =
|
|
56195
|
+
const logsDir = join18(homedir7(), ".switchroom", "logs");
|
|
56026
56196
|
const schedulerStates = Object.fromEntries(agentNames.map((n) => [n, getSchedulerState(n, logsDir)]));
|
|
56027
56197
|
if (opts.json) {
|
|
56028
56198
|
const data = agentNames.map((name) => {
|
|
@@ -56453,7 +56623,7 @@ Scaffolding agent: ${name}
|
|
|
56453
56623
|
});
|
|
56454
56624
|
const settingsPath = resolve21(agentsDir, n, ".claude", "settings.json");
|
|
56455
56625
|
let actual = {};
|
|
56456
|
-
if (
|
|
56626
|
+
if (existsSync27(settingsPath)) {
|
|
56457
56627
|
try {
|
|
56458
56628
|
const raw = JSON.parse(readFileSync22(settingsPath, "utf-8"));
|
|
56459
56629
|
actual = raw.hooks ?? {};
|
|
@@ -56593,7 +56763,7 @@ Reconciled ${agentsTouched} agent(s), ${totalChanges} file(s) changed.`));
|
|
|
56593
56763
|
}));
|
|
56594
56764
|
agent.command("grant <name> <tool>").description("Add a tool name (or 'all') to an agent's tools.allow in switchroom.yaml, then reconcile").option("--no-restart", "Skip restarting the agent after granting").action(withConfigError(async (name, tool, opts) => {
|
|
56595
56765
|
const configPath = getConfigPath(program3);
|
|
56596
|
-
if (!
|
|
56766
|
+
if (!existsSync27(configPath)) {
|
|
56597
56767
|
console.error(source_default.red(`switchroom.yaml not found at ${configPath}`));
|
|
56598
56768
|
process.exit(1);
|
|
56599
56769
|
}
|
|
@@ -56642,7 +56812,7 @@ Reconciled ${agentsTouched} agent(s), ${totalChanges} file(s) changed.`));
|
|
|
56642
56812
|
}));
|
|
56643
56813
|
agent.command("dangerous <name>").description("Enable full tool access for an agent (sets tools.allow: [all] in switchroom.yaml). Reconciles + restarts.").option("--off", "Disable: clear tools.allow").option("--no-restart", "Skip restarting the agent").action(withConfigError(async (name, opts) => {
|
|
56644
56814
|
const configPath = getConfigPath(program3);
|
|
56645
|
-
if (!
|
|
56815
|
+
if (!existsSync27(configPath)) {
|
|
56646
56816
|
console.error(source_default.red(`switchroom.yaml not found at ${configPath}`));
|
|
56647
56817
|
process.exit(1);
|
|
56648
56818
|
}
|
|
@@ -56697,7 +56867,7 @@ Reconciled ${agentsTouched} agent(s), ${totalChanges} file(s) changed.`));
|
|
|
56697
56867
|
const config = getConfig(program3);
|
|
56698
56868
|
const agentsDir = resolveAgentsDir(config);
|
|
56699
56869
|
const settingsPath = resolve21(agentsDir, name, ".claude", "settings.json");
|
|
56700
|
-
if (!
|
|
56870
|
+
if (!existsSync27(settingsPath)) {
|
|
56701
56871
|
console.error(source_default.red(`Agent "${name}" not found at ${settingsPath}`));
|
|
56702
56872
|
process.exit(1);
|
|
56703
56873
|
}
|
|
@@ -56756,7 +56926,7 @@ Permissions for ${name}
|
|
|
56756
56926
|
}
|
|
56757
56927
|
}
|
|
56758
56928
|
}
|
|
56759
|
-
if (
|
|
56929
|
+
if (existsSync27(agentDir)) {
|
|
56760
56930
|
rmSync9(agentDir, { recursive: true, force: true });
|
|
56761
56931
|
console.log(source_default.green(` Removed directory: ${agentDir}`));
|
|
56762
56932
|
} else {
|
|
@@ -56960,7 +57130,7 @@ switchroom agent add: ${name}
|
|
|
56960
57130
|
} catch {}
|
|
56961
57131
|
const agentsDirRollback = resolveAgentsDir(cfg);
|
|
56962
57132
|
const agentDirRollback = resolve21(agentsDirRollback, name);
|
|
56963
|
-
if (
|
|
57133
|
+
if (existsSync27(agentDirRollback)) {
|
|
56964
57134
|
rmSync9(agentDirRollback, { recursive: true, force: true });
|
|
56965
57135
|
console.log(source_default.gray(` Rolled back: removed ${agentDirRollback}`));
|
|
56966
57136
|
}
|
|
@@ -57059,8 +57229,8 @@ init_source();
|
|
|
57059
57229
|
init_lifecycle();
|
|
57060
57230
|
import { execFile as execFile2 } from "node:child_process";
|
|
57061
57231
|
import { promisify as promisify2 } from "node:util";
|
|
57062
|
-
import { homedir as
|
|
57063
|
-
import { join as
|
|
57232
|
+
import { homedir as homedir9 } from "node:os";
|
|
57233
|
+
import { join as join20 } from "node:path";
|
|
57064
57234
|
init_helpers();
|
|
57065
57235
|
init_broker_call();
|
|
57066
57236
|
var execFileP = promisify2(execFile2);
|
|
@@ -57132,7 +57302,7 @@ function registerStatusCommand(program3) {
|
|
|
57132
57302
|
const config = getConfig(program3);
|
|
57133
57303
|
const agentNames = Object.keys(config.agents ?? {}).sort();
|
|
57134
57304
|
const statuses = getAllAgentStatuses(config);
|
|
57135
|
-
const logsDir =
|
|
57305
|
+
const logsDir = join20(homedir9(), ".switchroom", "logs");
|
|
57136
57306
|
const schedulerStates = Object.fromEntries(agentNames.map((n) => [n, getSchedulerState(n, logsDir)]));
|
|
57137
57307
|
const accountsP = fetchAccounts();
|
|
57138
57308
|
const mcpEnabled = opts.mcp !== false;
|
|
@@ -57541,8 +57711,8 @@ init_account_store();
|
|
|
57541
57711
|
init_loader();
|
|
57542
57712
|
init_manager();
|
|
57543
57713
|
init_helpers();
|
|
57544
|
-
import { existsSync as
|
|
57545
|
-
import { join as
|
|
57714
|
+
import { existsSync as existsSync32, readFileSync as readFileSync27 } from "node:fs";
|
|
57715
|
+
import { join as join24, resolve as resolve24 } from "node:path";
|
|
57546
57716
|
|
|
57547
57717
|
// src/cli/auth-google.ts
|
|
57548
57718
|
init_source();
|
|
@@ -57759,8 +57929,8 @@ function registerConnect(googleParent, program3) {
|
|
|
57759
57929
|
}
|
|
57760
57930
|
let mode = 420;
|
|
57761
57931
|
try {
|
|
57762
|
-
const { statSync:
|
|
57763
|
-
mode =
|
|
57932
|
+
const { statSync: statSync17 } = await import("node:fs");
|
|
57933
|
+
mode = statSync17(configPath).mode & 511;
|
|
57764
57934
|
} catch {}
|
|
57765
57935
|
atomicWriteFileSync3(configPath, patched, mode);
|
|
57766
57936
|
try {
|
|
@@ -59058,7 +59228,7 @@ function registerAuthScheduleSubcommands(_program, authParent) {
|
|
|
59058
59228
|
// src/cli/auth.ts
|
|
59059
59229
|
init_auth_active_yaml();
|
|
59060
59230
|
init_atomic();
|
|
59061
|
-
import { statSync as
|
|
59231
|
+
import { statSync as statSync17 } from "node:fs";
|
|
59062
59232
|
var SEVERITY_RANK = {
|
|
59063
59233
|
ok: 0,
|
|
59064
59234
|
warn: 1,
|
|
@@ -59067,10 +59237,10 @@ var SEVERITY_RANK = {
|
|
|
59067
59237
|
};
|
|
59068
59238
|
function diagnoseAuthState(claudeConfigDir) {
|
|
59069
59239
|
const findings = [];
|
|
59070
|
-
const credsPath =
|
|
59071
|
-
const oauthTokenPath2 =
|
|
59072
|
-
const hasCreds =
|
|
59073
|
-
const hasOauthToken =
|
|
59240
|
+
const credsPath = join24(claudeConfigDir, ".credentials.json");
|
|
59241
|
+
const oauthTokenPath2 = join24(claudeConfigDir, ".oauth-token");
|
|
59242
|
+
const hasCreds = existsSync32(credsPath);
|
|
59243
|
+
const hasOauthToken = existsSync32(oauthTokenPath2);
|
|
59074
59244
|
if (!hasCreds && !hasOauthToken) {
|
|
59075
59245
|
findings.push({
|
|
59076
59246
|
code: "credentials_missing",
|
|
@@ -59241,8 +59411,8 @@ function loadCredentialsFromAgent(agentName) {
|
|
|
59241
59411
|
const config = getConfigSafe();
|
|
59242
59412
|
const agentsDir = resolveAgentsDir(config);
|
|
59243
59413
|
const agentDir = resolve24(agentsDir, agentName);
|
|
59244
|
-
const credsPath =
|
|
59245
|
-
if (!
|
|
59414
|
+
const credsPath = join24(agentDir, ".claude", ".credentials.json");
|
|
59415
|
+
if (!existsSync32(credsPath)) {
|
|
59246
59416
|
console.error(source_default.red(` Agent "${agentName}" has no .claude/.credentials.json \u2014 log it in first.`));
|
|
59247
59417
|
process.exit(1);
|
|
59248
59418
|
}
|
|
@@ -59260,7 +59430,7 @@ function loadCredentialsFromAgent(agentName) {
|
|
|
59260
59430
|
return parsed;
|
|
59261
59431
|
}
|
|
59262
59432
|
function loadCredentialsFromFile(path) {
|
|
59263
|
-
if (!
|
|
59433
|
+
if (!existsSync32(path)) {
|
|
59264
59434
|
console.error(source_default.red(` No file at ${path}`));
|
|
59265
59435
|
process.exit(1);
|
|
59266
59436
|
}
|
|
@@ -59299,12 +59469,12 @@ function loadCredentialsFromGlobalAccount(label) {
|
|
|
59299
59469
|
};
|
|
59300
59470
|
}
|
|
59301
59471
|
async function loadCredentialsViaClaude(label) {
|
|
59302
|
-
const [{ runViaClaude: runViaClaude2 }, { homedir:
|
|
59472
|
+
const [{ runViaClaude: runViaClaude2 }, { homedir: homedir12 }, { default: readline }] = await Promise.all([
|
|
59303
59473
|
Promise.resolve().then(() => (init_via_claude(), exports_via_claude)),
|
|
59304
59474
|
import("node:os"),
|
|
59305
59475
|
import("node:readline")
|
|
59306
59476
|
]);
|
|
59307
|
-
const configDir =
|
|
59477
|
+
const configDir = join24(homedir12(), ".switchroom", "accounts", label);
|
|
59308
59478
|
const result = await runViaClaude2({
|
|
59309
59479
|
configDir,
|
|
59310
59480
|
promptForCode: async (_url) => {
|
|
@@ -59346,7 +59516,7 @@ function registerAuthCommand(program3) {
|
|
|
59346
59516
|
await withConfigError(async () => {
|
|
59347
59517
|
const config = getConfig(program3);
|
|
59348
59518
|
const agentsDir = resolveAgentsDir(config);
|
|
59349
|
-
configDir =
|
|
59519
|
+
configDir = join24(agentsDir, agent, ".claude");
|
|
59350
59520
|
})();
|
|
59351
59521
|
}
|
|
59352
59522
|
const diag = diagnoseAuthState(configDir);
|
|
@@ -59405,7 +59575,7 @@ function registerAuthCommand(program3) {
|
|
|
59405
59575
|
if (after !== before) {
|
|
59406
59576
|
let mode = 420;
|
|
59407
59577
|
try {
|
|
59408
|
-
mode =
|
|
59578
|
+
mode = statSync17(yamlPath).mode & 511;
|
|
59409
59579
|
} catch {}
|
|
59410
59580
|
atomicWriteFileSync2(yamlPath, after, mode);
|
|
59411
59581
|
if (!quiet) {
|
|
@@ -59505,7 +59675,7 @@ function registerAuthCommand(program3) {
|
|
|
59505
59675
|
}));
|
|
59506
59676
|
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) => {
|
|
59507
59677
|
const config = getConfig(program3);
|
|
59508
|
-
const agentDir =
|
|
59678
|
+
const agentDir = join24(resolveAgentsDir(config), agent);
|
|
59509
59679
|
const r = startAuthSession(agent, agentDir, {
|
|
59510
59680
|
force: opts.force,
|
|
59511
59681
|
slot: opts.slot
|
|
@@ -59518,7 +59688,7 @@ function registerAuthCommand(program3) {
|
|
|
59518
59688
|
}));
|
|
59519
59689
|
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) => {
|
|
59520
59690
|
const config = getConfig(program3);
|
|
59521
|
-
const agentDir =
|
|
59691
|
+
const agentDir = join24(resolveAgentsDir(config), agent);
|
|
59522
59692
|
const r = submitAuthCode(agent, agentDir, code, opts.slot);
|
|
59523
59693
|
if (opts.json) {
|
|
59524
59694
|
console.log(JSON.stringify({
|
|
@@ -59535,7 +59705,7 @@ function registerAuthCommand(program3) {
|
|
|
59535
59705
|
}));
|
|
59536
59706
|
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) => {
|
|
59537
59707
|
const config = getConfig(program3);
|
|
59538
|
-
const agentDir =
|
|
59708
|
+
const agentDir = join24(resolveAgentsDir(config), agent);
|
|
59539
59709
|
const r = cancelAuthSession(agent, agentDir, opts.slot);
|
|
59540
59710
|
for (const line of r.instructions)
|
|
59541
59711
|
console.log(line);
|
|
@@ -59555,10 +59725,10 @@ init_source();
|
|
|
59555
59725
|
init_loader();
|
|
59556
59726
|
init_vault();
|
|
59557
59727
|
init_hindsight();
|
|
59558
|
-
import { readFileSync as readFileSync28, writeFileSync as writeFileSync17, copyFileSync as copyFileSync6, existsSync as
|
|
59728
|
+
import { readFileSync as readFileSync28, writeFileSync as writeFileSync17, copyFileSync as copyFileSync6, existsSync as existsSync33, readdirSync as readdirSync16, statSync as statSync18 } from "node:fs";
|
|
59559
59729
|
import { execFileSync as execFileSync15 } from "node:child_process";
|
|
59560
|
-
import { join as
|
|
59561
|
-
import { homedir as
|
|
59730
|
+
import { join as join25 } from "node:path";
|
|
59731
|
+
import { homedir as homedir12 } from "node:os";
|
|
59562
59732
|
function getVaultPath2(configPath) {
|
|
59563
59733
|
try {
|
|
59564
59734
|
const config = loadConfig(configPath);
|
|
@@ -59573,22 +59743,22 @@ function maskToken(s) {
|
|
|
59573
59743
|
return "***";
|
|
59574
59744
|
}
|
|
59575
59745
|
function findClaudeTranscripts() {
|
|
59576
|
-
const root =
|
|
59577
|
-
if (!
|
|
59746
|
+
const root = join25(homedir12(), ".claude", "projects");
|
|
59747
|
+
if (!existsSync33(root))
|
|
59578
59748
|
return [];
|
|
59579
59749
|
const out = [];
|
|
59580
59750
|
const walk = (dir) => {
|
|
59581
59751
|
let entries;
|
|
59582
59752
|
try {
|
|
59583
|
-
entries =
|
|
59753
|
+
entries = readdirSync16(dir);
|
|
59584
59754
|
} catch {
|
|
59585
59755
|
return;
|
|
59586
59756
|
}
|
|
59587
59757
|
for (const e of entries) {
|
|
59588
|
-
const p =
|
|
59758
|
+
const p = join25(dir, e);
|
|
59589
59759
|
let st;
|
|
59590
59760
|
try {
|
|
59591
|
-
st =
|
|
59761
|
+
st = statSync18(p);
|
|
59592
59762
|
} catch {
|
|
59593
59763
|
continue;
|
|
59594
59764
|
}
|
|
@@ -59604,11 +59774,11 @@ function findClaudeTranscripts() {
|
|
|
59604
59774
|
}
|
|
59605
59775
|
function findTelegramHistoryDb() {
|
|
59606
59776
|
const candidates = [
|
|
59607
|
-
process.env.TELEGRAM_STATE_DIR ?
|
|
59608
|
-
|
|
59777
|
+
process.env.TELEGRAM_STATE_DIR ? join25(process.env.TELEGRAM_STATE_DIR, "history.db") : null,
|
|
59778
|
+
join25(homedir12(), ".claude", "channels", "telegram", "history.db")
|
|
59609
59779
|
].filter(Boolean);
|
|
59610
59780
|
for (const c of candidates) {
|
|
59611
|
-
if (
|
|
59781
|
+
if (existsSync33(c))
|
|
59612
59782
|
return c;
|
|
59613
59783
|
}
|
|
59614
59784
|
return null;
|
|
@@ -59964,15 +60134,15 @@ function suggestVaultKeys(requested, available, max = 3) {
|
|
|
59964
60134
|
init_loader();
|
|
59965
60135
|
init_loader();
|
|
59966
60136
|
init_client();
|
|
59967
|
-
import { readFileSync as readFileSync33, existsSync as
|
|
60137
|
+
import { readFileSync as readFileSync33, existsSync as existsSync37, unlinkSync as unlinkSync9 } from "node:fs";
|
|
59968
60138
|
import { spawn as spawn4 } from "node:child_process";
|
|
59969
60139
|
|
|
59970
60140
|
// src/vault/broker/server.ts
|
|
59971
60141
|
init_compose();
|
|
59972
60142
|
init_vault();
|
|
59973
60143
|
import * as net3 from "node:net";
|
|
59974
|
-
import { mkdirSync as mkdirSync22, chmodSync as chmodSync7, chownSync as
|
|
59975
|
-
import { dirname as
|
|
60144
|
+
import { mkdirSync as mkdirSync22, chmodSync as chmodSync7, chownSync as chownSync4, existsSync as existsSync36, readFileSync as readFileSync31, readdirSync as readdirSync17, statSync as statSync20, unlinkSync as unlinkSync8, writeFileSync as writeFileSync19, renameSync as renameSync10 } from "node:fs";
|
|
60145
|
+
import { dirname as dirname7, resolve as resolve26, basename as basename4 } from "node:path";
|
|
59976
60146
|
import * as os4 from "node:os";
|
|
59977
60147
|
import * as path3 from "node:path";
|
|
59978
60148
|
|
|
@@ -59981,26 +60151,26 @@ init_vault();
|
|
|
59981
60151
|
import {
|
|
59982
60152
|
copyFileSync as copyFileSync7,
|
|
59983
60153
|
chmodSync as chmodSync4,
|
|
59984
|
-
existsSync as
|
|
60154
|
+
existsSync as existsSync34,
|
|
59985
60155
|
fsyncSync as fsyncSync4,
|
|
59986
|
-
lstatSync as
|
|
60156
|
+
lstatSync as lstatSync5,
|
|
59987
60157
|
mkdirSync as mkdirSync19,
|
|
59988
60158
|
openSync as openSync6,
|
|
59989
60159
|
closeSync as closeSync6,
|
|
59990
60160
|
readFileSync as readFileSync29,
|
|
59991
60161
|
renameSync as renameSync9,
|
|
59992
|
-
statSync as
|
|
60162
|
+
statSync as statSync19,
|
|
59993
60163
|
symlinkSync as symlinkSync3,
|
|
59994
60164
|
unlinkSync as unlinkSync7
|
|
59995
60165
|
} from "node:fs";
|
|
59996
60166
|
import { createHash as createHash5 } from "node:crypto";
|
|
59997
|
-
import { basename as basename3, dirname as
|
|
60167
|
+
import { basename as basename3, dirname as dirname4, join as join26 } from "node:path";
|
|
59998
60168
|
function vaultLayoutPaths(home2) {
|
|
59999
|
-
const switchroomRoot =
|
|
60169
|
+
const switchroomRoot = join26(home2, ".switchroom");
|
|
60000
60170
|
return {
|
|
60001
|
-
oldPath:
|
|
60002
|
-
newPath:
|
|
60003
|
-
parent:
|
|
60171
|
+
oldPath: join26(switchroomRoot, "vault.enc"),
|
|
60172
|
+
newPath: join26(switchroomRoot, "vault", "vault.enc"),
|
|
60173
|
+
parent: join26(switchroomRoot, "vault"),
|
|
60004
60174
|
switchroomRoot
|
|
60005
60175
|
};
|
|
60006
60176
|
}
|
|
@@ -60020,11 +60190,11 @@ function migrateVaultLayout(home2, opts = {}) {
|
|
|
60020
60190
|
}
|
|
60021
60191
|
function runMigration(home2, opts) {
|
|
60022
60192
|
const { oldPath, newPath, parent, switchroomRoot } = vaultLayoutPaths(home2);
|
|
60023
|
-
const lockTarget =
|
|
60193
|
+
const lockTarget = existsSync34(newPath) ? newPath : existsSync34(oldPath) ? oldPath : null;
|
|
60024
60194
|
const release = !opts.dryRun && lockTarget !== null ? acquireVaultLock(lockTarget) : null;
|
|
60025
60195
|
try {
|
|
60026
60196
|
const oldStat = lstatSyncOrNull(oldPath);
|
|
60027
|
-
const newExists =
|
|
60197
|
+
const newExists = existsSync34(newPath);
|
|
60028
60198
|
if (oldStat === null && !newExists) {
|
|
60029
60199
|
return { kind: "no-vault" };
|
|
60030
60200
|
}
|
|
@@ -60041,8 +60211,8 @@ function runMigration(home2, opts) {
|
|
|
60041
60211
|
fsyncDir(switchroomRoot);
|
|
60042
60212
|
return { kind: "completed-partial" };
|
|
60043
60213
|
}
|
|
60044
|
-
const oldRealStat =
|
|
60045
|
-
const newRealStat =
|
|
60214
|
+
const oldRealStat = statSync19(oldPath);
|
|
60215
|
+
const newRealStat = statSync19(newPath);
|
|
60046
60216
|
return {
|
|
60047
60217
|
kind: "divergent",
|
|
60048
60218
|
details: {
|
|
@@ -60137,7 +60307,7 @@ your fleet works after \`switchroom apply\`, then delete it.
|
|
|
60137
60307
|
}
|
|
60138
60308
|
function lstatSyncOrNull(path) {
|
|
60139
60309
|
try {
|
|
60140
|
-
return
|
|
60310
|
+
return lstatSync5(path);
|
|
60141
60311
|
} catch {
|
|
60142
60312
|
return null;
|
|
60143
60313
|
}
|
|
@@ -60147,8 +60317,8 @@ function sha256File(path) {
|
|
|
60147
60317
|
return createHash5("sha256").update(data).digest("hex");
|
|
60148
60318
|
}
|
|
60149
60319
|
function atomicReplaceWithSymlink(target, linkTarget) {
|
|
60150
|
-
const tmp =
|
|
60151
|
-
if (
|
|
60320
|
+
const tmp = join26(dirname4(target), `.${basename3(target)}.symlink-tmp`);
|
|
60321
|
+
if (existsSync34(tmp)) {
|
|
60152
60322
|
try {
|
|
60153
60323
|
unlinkSync7(tmp);
|
|
60154
60324
|
} catch {}
|
|
@@ -60178,8 +60348,8 @@ init_loader();
|
|
|
60178
60348
|
|
|
60179
60349
|
// src/vault/auto-unlock.ts
|
|
60180
60350
|
import { createHmac, randomBytes as randomBytes6, createCipheriv as createCipheriv2, createDecipheriv as createDecipheriv2 } from "node:crypto";
|
|
60181
|
-
import { chmodSync as chmodSync5, existsSync as
|
|
60182
|
-
import { dirname as
|
|
60351
|
+
import { chmodSync as chmodSync5, existsSync as existsSync35, mkdirSync as mkdirSync20, readFileSync as readFileSync30, writeFileSync as writeFileSync18 } from "node:fs";
|
|
60352
|
+
import { dirname as dirname5 } from "node:path";
|
|
60183
60353
|
var FORMAT_VERSION = 1;
|
|
60184
60354
|
var SALT_LEN = 16;
|
|
60185
60355
|
var NONCE_LEN = 12;
|
|
@@ -60268,12 +60438,12 @@ function decryptAutoUnlock(blob, machineId) {
|
|
|
60268
60438
|
}
|
|
60269
60439
|
function writeAutoUnlockFile(passphrase, filePath) {
|
|
60270
60440
|
const blob = encryptAutoUnlock(passphrase);
|
|
60271
|
-
mkdirSync20(
|
|
60441
|
+
mkdirSync20(dirname5(filePath), { recursive: true, mode: 448 });
|
|
60272
60442
|
writeFileSync18(filePath, blob, { mode: 384 });
|
|
60273
60443
|
chmodSync5(filePath, 384);
|
|
60274
60444
|
}
|
|
60275
60445
|
function readAutoUnlockFile(filePath) {
|
|
60276
|
-
if (!
|
|
60446
|
+
if (!existsSync35(filePath)) {
|
|
60277
60447
|
throw new AutoUnlockDecryptError("io");
|
|
60278
60448
|
}
|
|
60279
60449
|
let blob;
|
|
@@ -60299,8 +60469,8 @@ import * as path from "node:path";
|
|
|
60299
60469
|
|
|
60300
60470
|
// src/vault/broker/test-isolation-guard.ts
|
|
60301
60471
|
import { mkdtempSync as mkdtempSync4 } from "node:fs";
|
|
60302
|
-
import { homedir as
|
|
60303
|
-
import { join as
|
|
60472
|
+
import { homedir as homedir13, tmpdir as tmpdir3 } from "node:os";
|
|
60473
|
+
import { join as join27, resolve as resolve25, sep } from "node:path";
|
|
60304
60474
|
function isTestRuntime() {
|
|
60305
60475
|
return process.env.VITEST !== undefined;
|
|
60306
60476
|
}
|
|
@@ -60308,7 +60478,7 @@ function escapeHatchSet() {
|
|
|
60308
60478
|
return process.env.SWITCHROOM_ALLOW_PROD_VAULT_IN_TEST === "1";
|
|
60309
60479
|
}
|
|
60310
60480
|
function realSwitchroomHome() {
|
|
60311
|
-
return resolve25(
|
|
60481
|
+
return resolve25(homedir13(), ".switchroom");
|
|
60312
60482
|
}
|
|
60313
60483
|
function isUnderRealSwitchroomHome(p) {
|
|
60314
60484
|
const home2 = realSwitchroomHome();
|
|
@@ -60321,7 +60491,7 @@ function safeVaultPath(requestedPath) {
|
|
|
60321
60491
|
return requestedPath;
|
|
60322
60492
|
if (!isUnderRealSwitchroomHome(requestedPath))
|
|
60323
60493
|
return requestedPath;
|
|
60324
|
-
const redirected =
|
|
60494
|
+
const redirected = join27(mkdtempSync4(join27(tmpdir3(), "sw-test-vault-")), "vault.enc");
|
|
60325
60495
|
if (!warnedVault) {
|
|
60326
60496
|
warnedVault = true;
|
|
60327
60497
|
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".
|
|
@@ -60337,7 +60507,7 @@ function safeAuditLogPath(requestedPath) {
|
|
|
60337
60507
|
if (!isUnderRealSwitchroomHome(requestedPath))
|
|
60338
60508
|
return requestedPath;
|
|
60339
60509
|
if (!cachedTmpAuditLog) {
|
|
60340
|
-
cachedTmpAuditLog =
|
|
60510
|
+
cachedTmpAuditLog = join27(mkdtempSync4(join27(tmpdir3(), "sw-test-audit-")), "vault-audit.log");
|
|
60341
60511
|
}
|
|
60342
60512
|
if (!warnedAudit) {
|
|
60343
60513
|
warnedAudit = true;
|
|
@@ -62700,13 +62870,13 @@ class VaultBroker {
|
|
|
62700
62870
|
this.passphrase = this.testOpts._testPassphrase;
|
|
62701
62871
|
}
|
|
62702
62872
|
process.umask(63);
|
|
62703
|
-
const parentDir =
|
|
62873
|
+
const parentDir = dirname7(this.socketPath);
|
|
62704
62874
|
mkdirSync22(parentDir, { recursive: true, mode: 448 });
|
|
62705
62875
|
try {
|
|
62706
62876
|
chmodSync7(parentDir, 448);
|
|
62707
62877
|
} catch {}
|
|
62708
62878
|
for (const p of [this.socketPath, this.unlockSocketPath]) {
|
|
62709
|
-
if (
|
|
62879
|
+
if (existsSync36(p)) {
|
|
62710
62880
|
try {
|
|
62711
62881
|
unlinkSync8(p);
|
|
62712
62882
|
} catch {}
|
|
@@ -62739,7 +62909,7 @@ class VaultBroker {
|
|
|
62739
62909
|
try {
|
|
62740
62910
|
if (ready) {
|
|
62741
62911
|
writeFileSync19(p, "", { mode: 384 });
|
|
62742
|
-
} else if (
|
|
62912
|
+
} else if (existsSync36(p)) {
|
|
62743
62913
|
unlinkSync8(p);
|
|
62744
62914
|
}
|
|
62745
62915
|
} catch {}
|
|
@@ -62772,7 +62942,7 @@ class VaultBroker {
|
|
|
62772
62942
|
try {
|
|
62773
62943
|
entry.server.close();
|
|
62774
62944
|
} catch {}
|
|
62775
|
-
if (
|
|
62945
|
+
if (existsSync36(sockPath)) {
|
|
62776
62946
|
try {
|
|
62777
62947
|
unlinkSync8(sockPath);
|
|
62778
62948
|
} catch {}
|
|
@@ -62780,7 +62950,7 @@ class VaultBroker {
|
|
|
62780
62950
|
}
|
|
62781
62951
|
this.agentServers.clear();
|
|
62782
62952
|
for (const p of [this.socketPath, this.unlockSocketPath]) {
|
|
62783
|
-
if (p &&
|
|
62953
|
+
if (p && existsSync36(p)) {
|
|
62784
62954
|
try {
|
|
62785
62955
|
unlinkSync8(p);
|
|
62786
62956
|
} catch {}
|
|
@@ -62788,7 +62958,7 @@ class VaultBroker {
|
|
|
62788
62958
|
}
|
|
62789
62959
|
try {
|
|
62790
62960
|
const pidPath = resolvePath(PID_FILE_DEFAULT);
|
|
62791
|
-
if (
|
|
62961
|
+
if (existsSync36(pidPath))
|
|
62792
62962
|
unlinkSync8(pidPath);
|
|
62793
62963
|
} catch {}
|
|
62794
62964
|
}
|
|
@@ -62811,16 +62981,16 @@ class VaultBroker {
|
|
|
62811
62981
|
return new Promise((resolveP, rejectP) => {
|
|
62812
62982
|
if (abs.endsWith("/sock")) {
|
|
62813
62983
|
const dir = abs.slice(0, -"/sock".length);
|
|
62814
|
-
if (
|
|
62984
|
+
if (existsSync36(dir)) {
|
|
62815
62985
|
try {
|
|
62816
|
-
|
|
62986
|
+
chownSync4(dir, 0, 0);
|
|
62817
62987
|
} catch {}
|
|
62818
62988
|
try {
|
|
62819
62989
|
chmodSync7(dir, 448);
|
|
62820
62990
|
} catch {}
|
|
62821
62991
|
}
|
|
62822
62992
|
}
|
|
62823
|
-
if (
|
|
62993
|
+
if (existsSync36(abs)) {
|
|
62824
62994
|
try {
|
|
62825
62995
|
unlinkSync8(abs);
|
|
62826
62996
|
} catch (err) {
|
|
@@ -62841,18 +63011,18 @@ class VaultBroker {
|
|
|
62841
63011
|
try {
|
|
62842
63012
|
agentUid = allocateAgentUid(agentName);
|
|
62843
63013
|
try {
|
|
62844
|
-
|
|
63014
|
+
chownSync4(abs, agentUid, agentUid);
|
|
62845
63015
|
} catch {}
|
|
62846
63016
|
if (abs.endsWith("/sock")) {
|
|
62847
63017
|
const dir = abs.slice(0, -"/sock".length);
|
|
62848
63018
|
try {
|
|
62849
|
-
|
|
63019
|
+
chownSync4(dir, agentUid, agentUid);
|
|
62850
63020
|
} catch {}
|
|
62851
63021
|
}
|
|
62852
63022
|
} catch {}
|
|
62853
63023
|
this.agentServers.set(abs, { server, agentName });
|
|
62854
63024
|
const unlockAbs = unlockSocketFor(abs);
|
|
62855
|
-
if (
|
|
63025
|
+
if (existsSync36(unlockAbs)) {
|
|
62856
63026
|
try {
|
|
62857
63027
|
unlinkSync8(unlockAbs);
|
|
62858
63028
|
} catch {}
|
|
@@ -62873,7 +63043,7 @@ class VaultBroker {
|
|
|
62873
63043
|
} catch {}
|
|
62874
63044
|
if (agentUid !== null) {
|
|
62875
63045
|
try {
|
|
62876
|
-
|
|
63046
|
+
chownSync4(unlockAbs, agentUid, agentUid);
|
|
62877
63047
|
} catch {}
|
|
62878
63048
|
}
|
|
62879
63049
|
this.agentServers.set(unlockAbs, { server: unlockServer, agentName });
|
|
@@ -62907,8 +63077,8 @@ class VaultBroker {
|
|
|
62907
63077
|
if (!Number.isFinite(uid) || uid <= 0)
|
|
62908
63078
|
return;
|
|
62909
63079
|
try {
|
|
62910
|
-
if (
|
|
62911
|
-
|
|
63080
|
+
if (existsSync36(this.vaultPath))
|
|
63081
|
+
chownSync4(this.vaultPath, uid, uid);
|
|
62912
63082
|
} catch {}
|
|
62913
63083
|
}
|
|
62914
63084
|
bindOperatorListener(socketPath, operatorUid) {
|
|
@@ -62920,9 +63090,9 @@ class VaultBroker {
|
|
|
62920
63090
|
const unlockAbs = unlockSocketFor(abs);
|
|
62921
63091
|
if (abs.endsWith("/sock")) {
|
|
62922
63092
|
const dir = abs.slice(0, -"/sock".length);
|
|
62923
|
-
if (
|
|
63093
|
+
if (existsSync36(dir)) {
|
|
62924
63094
|
try {
|
|
62925
|
-
|
|
63095
|
+
chownSync4(dir, 0, 0);
|
|
62926
63096
|
} catch {}
|
|
62927
63097
|
try {
|
|
62928
63098
|
chmodSync7(dir, 448);
|
|
@@ -62930,7 +63100,7 @@ class VaultBroker {
|
|
|
62930
63100
|
}
|
|
62931
63101
|
}
|
|
62932
63102
|
for (const p of [abs, unlockAbs]) {
|
|
62933
|
-
if (
|
|
63103
|
+
if (existsSync36(p)) {
|
|
62934
63104
|
try {
|
|
62935
63105
|
unlinkSync8(p);
|
|
62936
63106
|
} catch {}
|
|
@@ -62946,7 +63116,7 @@ class VaultBroker {
|
|
|
62946
63116
|
chmodSync7(abs, 384);
|
|
62947
63117
|
} catch {}
|
|
62948
63118
|
try {
|
|
62949
|
-
|
|
63119
|
+
chownSync4(abs, operatorUid, operatorUid);
|
|
62950
63120
|
} catch {}
|
|
62951
63121
|
const unlockServer = net3.createServer((sock) => {
|
|
62952
63122
|
this._handleUnlockConnection(sock, true);
|
|
@@ -62957,12 +63127,12 @@ class VaultBroker {
|
|
|
62957
63127
|
chmodSync7(unlockAbs, 384);
|
|
62958
63128
|
} catch {}
|
|
62959
63129
|
try {
|
|
62960
|
-
|
|
63130
|
+
chownSync4(unlockAbs, operatorUid, operatorUid);
|
|
62961
63131
|
} catch {}
|
|
62962
63132
|
if (abs.endsWith("/sock")) {
|
|
62963
63133
|
const dir = abs.slice(0, -"/sock".length);
|
|
62964
63134
|
try {
|
|
62965
|
-
|
|
63135
|
+
chownSync4(dir, operatorUid, operatorUid);
|
|
62966
63136
|
} catch {}
|
|
62967
63137
|
try {
|
|
62968
63138
|
chmodSync7(dir, 448);
|
|
@@ -63797,7 +63967,7 @@ class VaultBroker {
|
|
|
63797
63967
|
renameSync10(tmpPath, tokenPath);
|
|
63798
63968
|
try {
|
|
63799
63969
|
const uid = allocateAgentUid(agent);
|
|
63800
|
-
|
|
63970
|
+
chownSync4(tokenPath, uid, uid);
|
|
63801
63971
|
} catch (chownErr) {
|
|
63802
63972
|
process.stderr.write(`[vault-broker] mint_grant: token written but chown failed for agent ${agent}: ${chownErr.message} (CAP_CHOWN missing?)
|
|
63803
63973
|
`);
|
|
@@ -63854,7 +64024,7 @@ class VaultBroker {
|
|
|
63854
64024
|
const row = this.grantsDb.query("SELECT agent_slug FROM vault_grants WHERE id = ?").get(id);
|
|
63855
64025
|
if (row && AgentNameSchema.safeParse(row.agent_slug).success) {
|
|
63856
64026
|
const tokenPath = path3.join(os4.homedir(), ".switchroom", "agents", row.agent_slug, ".vault-token");
|
|
63857
|
-
if (
|
|
64027
|
+
if (existsSync36(tokenPath)) {
|
|
63858
64028
|
try {
|
|
63859
64029
|
unlinkSync8(tokenPath);
|
|
63860
64030
|
} catch {}
|
|
@@ -64092,10 +64262,10 @@ class VaultBroker {
|
|
|
64092
64262
|
const envPath = process.env.SWITCHROOM_VAULT_BROKER_AUTO_UNLOCK_PATH;
|
|
64093
64263
|
const configuredPath = (envPath && envPath.length > 0 ? envPath : undefined) ?? this.config?.vault?.broker?.autoUnlockCredentialPath ?? DEFAULT_AUTO_UNLOCK_PATH;
|
|
64094
64264
|
const filePath = resolvePath(configuredPath);
|
|
64095
|
-
if (!
|
|
64265
|
+
if (!existsSync36(filePath))
|
|
64096
64266
|
return false;
|
|
64097
64267
|
try {
|
|
64098
|
-
if (
|
|
64268
|
+
if (statSync20(filePath).size === 0)
|
|
64099
64269
|
return false;
|
|
64100
64270
|
} catch {
|
|
64101
64271
|
return false;
|
|
@@ -64173,15 +64343,15 @@ class VaultBroker {
|
|
|
64173
64343
|
}
|
|
64174
64344
|
}
|
|
64175
64345
|
function detectVaultLayoutDrift(vaultPath) {
|
|
64176
|
-
const dir =
|
|
64346
|
+
const dir = dirname7(vaultPath);
|
|
64177
64347
|
if (basename4(dir) !== "vault")
|
|
64178
64348
|
return;
|
|
64179
64349
|
if (basename4(vaultPath) !== "vault.enc")
|
|
64180
64350
|
return;
|
|
64181
|
-
const switchroomDir =
|
|
64351
|
+
const switchroomDir = dirname7(dir);
|
|
64182
64352
|
if (basename4(switchroomDir) !== ".switchroom")
|
|
64183
64353
|
return;
|
|
64184
|
-
const home2 =
|
|
64354
|
+
const home2 = dirname7(switchroomDir);
|
|
64185
64355
|
const result = inspectVaultLayout(home2);
|
|
64186
64356
|
if (result.kind === "divergent") {
|
|
64187
64357
|
throw new VaultError(`Vault layout divergence detected at boot: ${result.details.oldPath} and ${result.details.newPath} are both regular files with different content. An older switchroom CLI may have written to the legacy path after migration ran. Run \`switchroom apply\` from the host to surface the recovery recipe (state E refusal with literal \`mv\` commands). See docs/operators/state-e-recovery.md.`);
|
|
@@ -64207,8 +64377,8 @@ async function main() {
|
|
|
64207
64377
|
const vaultPath = process.env.SWITCHROOM_VAULT_PATH;
|
|
64208
64378
|
let perAgentTargets = [];
|
|
64209
64379
|
try {
|
|
64210
|
-
if (
|
|
64211
|
-
const entries =
|
|
64380
|
+
if (existsSync36(perAgentDir)) {
|
|
64381
|
+
const entries = readdirSync17(perAgentDir, { withFileTypes: true });
|
|
64212
64382
|
const flat = [];
|
|
64213
64383
|
const subdirs = [];
|
|
64214
64384
|
for (const e of entries) {
|
|
@@ -64249,7 +64419,7 @@ async function main() {
|
|
|
64249
64419
|
}
|
|
64250
64420
|
const operatorUidStr = process.env.SWITCHROOM_BROKER_OPERATOR_UID;
|
|
64251
64421
|
const operatorDir = "/run/switchroom/broker/operator";
|
|
64252
|
-
if (operatorUidStr !== undefined &&
|
|
64422
|
+
if (operatorUidStr !== undefined && existsSync36(operatorDir)) {
|
|
64253
64423
|
const operatorUid = parseInt(operatorUidStr, 10);
|
|
64254
64424
|
if (!Number.isFinite(operatorUid) || operatorUid <= 0) {
|
|
64255
64425
|
process.stderr.write(`[vault-broker] SWITCHROOM_BROKER_OPERATOR_UID='${operatorUidStr}' is not a positive integer; skipping operator listener
|
|
@@ -64289,8 +64459,8 @@ init_client();
|
|
|
64289
64459
|
var import_yaml10 = __toESM(require_dist(), 1);
|
|
64290
64460
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
64291
64461
|
import { readFileSync as readFileSync32, writeFileSync as writeFileSync20 } from "node:fs";
|
|
64292
|
-
import { homedir as
|
|
64293
|
-
import { join as
|
|
64462
|
+
import { homedir as homedir17 } from "node:os";
|
|
64463
|
+
import { join as join32 } from "node:path";
|
|
64294
64464
|
class EncryptFailedError extends Error {
|
|
64295
64465
|
detail;
|
|
64296
64466
|
constructor(detail) {
|
|
@@ -64323,7 +64493,7 @@ function setVaultBrokerAutoUnlock(configPath, value) {
|
|
|
64323
64493
|
doc.setIn(["vault", "broker", "autoUnlock"], value);
|
|
64324
64494
|
writeFileSync20(configPath, doc.toString(), "utf-8");
|
|
64325
64495
|
}
|
|
64326
|
-
var DEFAULT_COMPOSE_FILE =
|
|
64496
|
+
var DEFAULT_COMPOSE_FILE = join32(homedir17(), ".switchroom", "compose", "docker-compose.yml");
|
|
64327
64497
|
async function applyAutoUnlock(opts = {}) {
|
|
64328
64498
|
const log = opts.log ?? ((s) => console.log(s));
|
|
64329
64499
|
const err = opts.err ?? ((s) => console.error(s));
|
|
@@ -64509,7 +64679,7 @@ function registerVaultBrokerCommand(vaultCmd, program3) {
|
|
|
64509
64679
|
process.exit(0);
|
|
64510
64680
|
}
|
|
64511
64681
|
const pidPath = resolvePath(DEFAULT_PID_FILE);
|
|
64512
|
-
if (!
|
|
64682
|
+
if (!existsSync37(pidPath)) {
|
|
64513
64683
|
console.error("vault-broker PID file not found \u2014 is the daemon running?");
|
|
64514
64684
|
process.exit(1);
|
|
64515
64685
|
}
|
|
@@ -64636,7 +64806,7 @@ function registerVaultBrokerCommand(vaultCmd, program3) {
|
|
|
64636
64806
|
broker.command("disable-auto-unlock").description("Remove the auto-unlock credential file. Reconcile + restart broker after.").action(() => {
|
|
64637
64807
|
const parentOpts = program3.opts();
|
|
64638
64808
|
const credPath = getAutoUnlockCredPath(parentOpts.config);
|
|
64639
|
-
if (!
|
|
64809
|
+
if (!existsSync37(credPath)) {
|
|
64640
64810
|
console.log(`No credential file at ${credPath} \u2014 nothing to do.`);
|
|
64641
64811
|
return;
|
|
64642
64812
|
}
|
|
@@ -64657,7 +64827,7 @@ function registerVaultBrokerCommand(vaultCmd, program3) {
|
|
|
64657
64827
|
|
|
64658
64828
|
// src/cli/vault-doctor.ts
|
|
64659
64829
|
init_source();
|
|
64660
|
-
import { existsSync as
|
|
64830
|
+
import { existsSync as existsSync38 } from "node:fs";
|
|
64661
64831
|
|
|
64662
64832
|
// src/vault/doctor.ts
|
|
64663
64833
|
var SENSITIVE_KEY_RE = /oauth(?![a-zA-Z])|token(?![a-zA-Z])|secret(?![a-zA-Z])|api[-_]?key(?![a-zA-Z])|password(?![a-zA-Z])/i;
|
|
@@ -64827,7 +64997,7 @@ function registerVaultDoctorCommand(vault, program3) {
|
|
|
64827
64997
|
const vaultPath = resolvePath(config.vault?.path ?? "~/.switchroom/vault.enc");
|
|
64828
64998
|
const passphrase = process.env.SWITCHROOM_VAULT_PASSPHRASE;
|
|
64829
64999
|
let vaultKeys = undefined;
|
|
64830
|
-
if (passphrase &&
|
|
65000
|
+
if (passphrase && existsSync38(vaultPath)) {
|
|
64831
65001
|
try {
|
|
64832
65002
|
const entries = openVault(passphrase, vaultPath);
|
|
64833
65003
|
vaultKeys = {};
|
|
@@ -64913,7 +65083,7 @@ Vault Doctor`));
|
|
|
64913
65083
|
|
|
64914
65084
|
// src/cli/vault-audit.ts
|
|
64915
65085
|
init_source();
|
|
64916
|
-
import { existsSync as
|
|
65086
|
+
import { existsSync as existsSync39, readFileSync as readFileSync34 } from "node:fs";
|
|
64917
65087
|
|
|
64918
65088
|
// src/vault/audit-reader.ts
|
|
64919
65089
|
function parseAuditLine(line) {
|
|
@@ -64987,7 +65157,7 @@ function formatAuditLines(rawLines, filters, limit = 50) {
|
|
|
64987
65157
|
function registerVaultAuditCommand(vault, _program) {
|
|
64988
65158
|
vault.command("audit").description("Tail and filter the vault audit log (~/.switchroom/vault-audit.log)").option("--who <caller>", "Filter by caller substring (unit name or pid)").option("--key <pattern>", "Filter by key name (regex or substring)").option("--denied", "Show only denied access attempts").option("--tail <n>", "Number of matching entries to show (default: 50)", "50").option("--path <file>", "Override audit log path (for debugging)").action((opts) => {
|
|
64989
65159
|
const logPath = opts.path ?? defaultAuditLogPath();
|
|
64990
|
-
if (!
|
|
65160
|
+
if (!existsSync39(logPath)) {
|
|
64991
65161
|
console.error(source_default.yellow(`Audit log not found at ${logPath}.`) + source_default.gray(`
|
|
64992
65162
|
The log is created when the vault broker handles its first request.`));
|
|
64993
65163
|
process.exit(0);
|
|
@@ -65042,8 +65212,8 @@ init_source();
|
|
|
65042
65212
|
init_loader();
|
|
65043
65213
|
init_loader();
|
|
65044
65214
|
init_client();
|
|
65045
|
-
import { join as
|
|
65046
|
-
import { homedir as
|
|
65215
|
+
import { join as join33 } from "node:path";
|
|
65216
|
+
import { homedir as homedir18 } from "node:os";
|
|
65047
65217
|
function parseDuration(raw) {
|
|
65048
65218
|
const lower = raw.toLowerCase().trim();
|
|
65049
65219
|
if (lower === "0" || lower === "never" || lower === "none")
|
|
@@ -65135,7 +65305,7 @@ function registerVaultGrantCommands(vault, program3) {
|
|
|
65135
65305
|
console.error(source_default.red(`Failed to mint grant: ${result.msg}`));
|
|
65136
65306
|
process.exit(1);
|
|
65137
65307
|
}
|
|
65138
|
-
const tokenPath =
|
|
65308
|
+
const tokenPath = join33(homedir18(), ".switchroom", "agents", agent, ".vault-token");
|
|
65139
65309
|
console.log(source_default.green(`\u2713 Grant minted`));
|
|
65140
65310
|
if (process.stdout.isTTY) {
|
|
65141
65311
|
console.log(source_default.bold("Token: ") + result.token);
|
|
@@ -65186,8 +65356,8 @@ The token file was written to the agent directory (mode 0600).`));
|
|
|
65186
65356
|
// src/cli/vault-backup.ts
|
|
65187
65357
|
init_source();
|
|
65188
65358
|
init_loader();
|
|
65189
|
-
import { existsSync as
|
|
65190
|
-
import { join as
|
|
65359
|
+
import { existsSync as existsSync41 } from "node:fs";
|
|
65360
|
+
import { join as join35 } from "node:path";
|
|
65191
65361
|
|
|
65192
65362
|
// src/vault/backup.ts
|
|
65193
65363
|
import {
|
|
@@ -65197,20 +65367,20 @@ import {
|
|
|
65197
65367
|
import {
|
|
65198
65368
|
appendFileSync as appendFileSync2,
|
|
65199
65369
|
closeSync as closeSync9,
|
|
65200
|
-
existsSync as
|
|
65370
|
+
existsSync as existsSync40,
|
|
65201
65371
|
fsyncSync as fsyncSync5,
|
|
65202
65372
|
mkdirSync as mkdirSync23,
|
|
65203
65373
|
openSync as openSync9,
|
|
65204
|
-
readdirSync as
|
|
65374
|
+
readdirSync as readdirSync18,
|
|
65205
65375
|
readFileSync as readFileSync35,
|
|
65206
65376
|
renameSync as renameSync11,
|
|
65207
|
-
statSync as
|
|
65377
|
+
statSync as statSync21,
|
|
65208
65378
|
symlinkSync as symlinkSync4,
|
|
65209
65379
|
unlinkSync as unlinkSync10,
|
|
65210
65380
|
writeSync as writeSync5
|
|
65211
65381
|
} from "node:fs";
|
|
65212
|
-
import { homedir as
|
|
65213
|
-
import { join as
|
|
65382
|
+
import { homedir as homedir19 } from "node:os";
|
|
65383
|
+
import { join as join34, resolve as resolvePath2 } from "node:path";
|
|
65214
65384
|
var LATEST_SYMLINK = "vault.enc.latest.bak";
|
|
65215
65385
|
var MANIFEST_FILE = "manifest.jsonl";
|
|
65216
65386
|
var DEFAULT_RETAIN = 30;
|
|
@@ -65285,9 +65455,9 @@ function resolveBackupDestination(input) {
|
|
|
65285
65455
|
if (input.configDestination)
|
|
65286
65456
|
return resolvePath2(input.configDestination);
|
|
65287
65457
|
if (input.hasSwitchroomConfigRepo) {
|
|
65288
|
-
return
|
|
65458
|
+
return join34(input.home, ".switchroom-config", "vault-backups");
|
|
65289
65459
|
}
|
|
65290
|
-
return
|
|
65460
|
+
return join34(input.home, ".switchroom", "vault-backups");
|
|
65291
65461
|
}
|
|
65292
65462
|
function findAutoUnlockSibling(entries) {
|
|
65293
65463
|
for (const name of entries) {
|
|
@@ -65305,11 +65475,11 @@ function selectBackupsToPrune(sortedNewestFirst, retain) {
|
|
|
65305
65475
|
return sortedNewestFirst.slice(retain);
|
|
65306
65476
|
}
|
|
65307
65477
|
function listBackupFiles(dir) {
|
|
65308
|
-
if (!
|
|
65478
|
+
if (!existsSync40(dir))
|
|
65309
65479
|
return [];
|
|
65310
65480
|
let entries;
|
|
65311
65481
|
try {
|
|
65312
|
-
entries =
|
|
65482
|
+
entries = readdirSync18(dir);
|
|
65313
65483
|
} catch {
|
|
65314
65484
|
return [];
|
|
65315
65485
|
}
|
|
@@ -65332,15 +65502,15 @@ function backupVault(opts) {
|
|
|
65332
65502
|
throw new Error(`vault backup refused: source is not a valid vault envelope: ${validationError}`);
|
|
65333
65503
|
}
|
|
65334
65504
|
mkdirSync23(opts.destDir, { recursive: true, mode: 448 });
|
|
65335
|
-
const dirEntries =
|
|
65505
|
+
const dirEntries = readdirSync18(opts.destDir);
|
|
65336
65506
|
const offender = findAutoUnlockSibling(dirEntries);
|
|
65337
65507
|
if (offender) {
|
|
65338
65508
|
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.`);
|
|
65339
65509
|
}
|
|
65340
65510
|
const filename = computeBackupFilename(now);
|
|
65341
|
-
const fullPath =
|
|
65511
|
+
const fullPath = join34(opts.destDir, filename);
|
|
65342
65512
|
const tmpName = `.tmp.${process.pid}.${randomBytes10(4).toString("hex")}`;
|
|
65343
|
-
const tmpPath =
|
|
65513
|
+
const tmpPath = join34(opts.destDir, tmpName);
|
|
65344
65514
|
const src = readFileSync35(opts.vaultPath);
|
|
65345
65515
|
const fd = openSync9(tmpPath, "wx", 384);
|
|
65346
65516
|
try {
|
|
@@ -65349,14 +65519,14 @@ function backupVault(opts) {
|
|
|
65349
65519
|
} finally {
|
|
65350
65520
|
closeSync9(fd);
|
|
65351
65521
|
}
|
|
65352
|
-
if (
|
|
65522
|
+
if (existsSync40(fullPath)) {
|
|
65353
65523
|
try {
|
|
65354
65524
|
unlinkSync10(tmpPath);
|
|
65355
65525
|
} catch {}
|
|
65356
65526
|
throw new Error(`vault backup refused: '${fullPath}' already exists ` + `(sub-second collision with another backup). Retry in 1 second, ` + `or check for a concurrent backup process.`);
|
|
65357
65527
|
}
|
|
65358
65528
|
renameSync11(tmpPath, fullPath);
|
|
65359
|
-
const stat =
|
|
65529
|
+
const stat = statSync21(fullPath);
|
|
65360
65530
|
const sha256 = sha256OfFile(fullPath);
|
|
65361
65531
|
const row = {
|
|
65362
65532
|
ts: now.toISOString(),
|
|
@@ -65364,9 +65534,9 @@ function backupVault(opts) {
|
|
|
65364
65534
|
size_bytes: stat.size,
|
|
65365
65535
|
sha256
|
|
65366
65536
|
};
|
|
65367
|
-
appendFileSync2(
|
|
65537
|
+
appendFileSync2(join34(opts.destDir, MANIFEST_FILE), JSON.stringify(row) + `
|
|
65368
65538
|
`, { mode: 384 });
|
|
65369
|
-
const latestPath =
|
|
65539
|
+
const latestPath = join34(opts.destDir, LATEST_SYMLINK);
|
|
65370
65540
|
try {
|
|
65371
65541
|
unlinkSync10(latestPath);
|
|
65372
65542
|
} catch {}
|
|
@@ -65385,7 +65555,7 @@ function backupVault(opts) {
|
|
|
65385
65555
|
const pruneNames = selectBackupsToPrune(sorted, retain);
|
|
65386
65556
|
for (const old of pruneNames) {
|
|
65387
65557
|
try {
|
|
65388
|
-
unlinkSync10(
|
|
65558
|
+
unlinkSync10(join34(opts.destDir, old));
|
|
65389
65559
|
} catch {}
|
|
65390
65560
|
}
|
|
65391
65561
|
if (pruneNames.length > 0) {
|
|
@@ -65408,7 +65578,7 @@ function backupVault(opts) {
|
|
|
65408
65578
|
};
|
|
65409
65579
|
}
|
|
65410
65580
|
function defaultHome() {
|
|
65411
|
-
return process.env.HOME ??
|
|
65581
|
+
return process.env.HOME ?? homedir19();
|
|
65412
65582
|
}
|
|
65413
65583
|
|
|
65414
65584
|
// src/cli/vault-backup.ts
|
|
@@ -65434,7 +65604,7 @@ function registerVaultBackupCommand(vault, program3) {
|
|
|
65434
65604
|
}
|
|
65435
65605
|
} catch {}
|
|
65436
65606
|
const home2 = defaultHome();
|
|
65437
|
-
const hasSwitchroomConfigRepo =
|
|
65607
|
+
const hasSwitchroomConfigRepo = existsSync41(join35(home2, ".switchroom-config"));
|
|
65438
65608
|
const destDir = resolveBackupDestination({
|
|
65439
65609
|
cliToFlag: opts.to ? resolvePath(opts.to) : undefined,
|
|
65440
65610
|
configDestination,
|
|
@@ -66060,8 +66230,8 @@ Push passphrase to broker for future requests? [Y/n]: `);
|
|
|
66060
66230
|
|
|
66061
66231
|
// src/cli/telegram.ts
|
|
66062
66232
|
init_source();
|
|
66063
|
-
import { existsSync as
|
|
66064
|
-
import { join as
|
|
66233
|
+
import { existsSync as existsSync42, readFileSync as readFileSync37, writeFileSync as writeFileSync21 } from "node:fs";
|
|
66234
|
+
import { join as join36 } from "node:path";
|
|
66065
66235
|
|
|
66066
66236
|
// src/web/webhook-dispatch.ts
|
|
66067
66237
|
function renderTemplate2(template, ctx) {
|
|
@@ -66323,8 +66493,8 @@ async function runTopicsDiscover(program3, chatId, opts) {
|
|
|
66323
66493
|
fail(`Unknown agent '${agentName}'. Check switchroom.yaml.`);
|
|
66324
66494
|
}
|
|
66325
66495
|
const agentsDir = process.env.SWITCHROOM_AGENTS_DIR ?? resolveStatePath("agents");
|
|
66326
|
-
const dbPath =
|
|
66327
|
-
if (!
|
|
66496
|
+
const dbPath = join36(agentsDir, agentName, "telegram", "history.db");
|
|
66497
|
+
if (!existsSync42(dbPath)) {
|
|
66328
66498
|
fail(`No history DB at ${dbPath}.
|
|
66329
66499
|
` + ` The agent may not have received any Telegram messages yet, or it may be offline.
|
|
66330
66500
|
` + ` Tip: send one message in each topic of the supergroup, then re-run this command.`);
|
|
@@ -66592,7 +66762,7 @@ async function vaultPut(program3, key, value) {
|
|
|
66592
66762
|
const configPath = program3.optsWithGlobals().config ?? undefined;
|
|
66593
66763
|
const vaultPath = resolveVaultPath(configPath);
|
|
66594
66764
|
const passphrase = await getVaultPassphrase();
|
|
66595
|
-
if (!
|
|
66765
|
+
if (!existsSync42(vaultPath)) {
|
|
66596
66766
|
createVault(passphrase, vaultPath);
|
|
66597
66767
|
console.log(source_default.gray(` Created new vault at ${vaultPath}`));
|
|
66598
66768
|
}
|
|
@@ -66988,11 +67158,11 @@ async function ensureHindsightConsumer(configPath, account, uid = HINDSIGHT_DEFA
|
|
|
66988
67158
|
// src/cli/memory.ts
|
|
66989
67159
|
init_loader();
|
|
66990
67160
|
var import_yaml12 = __toESM(require_dist(), 1);
|
|
66991
|
-
import { existsSync as
|
|
66992
|
-
import { join as
|
|
67161
|
+
import { existsSync as existsSync43, readFileSync as readFileSync38, writeFileSync as writeFileSync22 } from "node:fs";
|
|
67162
|
+
import { join as join37 } from "node:path";
|
|
66993
67163
|
function readRecallLog(agentDir, limit) {
|
|
66994
|
-
const path4 =
|
|
66995
|
-
if (!
|
|
67164
|
+
const path4 = join37(agentDir, ".claude", "plugins", "data", "hindsight-memory-inline", "state", "recall_log.jsonl");
|
|
67165
|
+
if (!existsSync43(path4))
|
|
66996
67166
|
return [];
|
|
66997
67167
|
let raw;
|
|
66998
67168
|
try {
|
|
@@ -67190,7 +67360,7 @@ Cross-agent reflection plan
|
|
|
67190
67360
|
const url = `http://127.0.0.1:${ports.apiPort}/mcp/`;
|
|
67191
67361
|
const configPath = getConfigPath(program3);
|
|
67192
67362
|
try {
|
|
67193
|
-
if (
|
|
67363
|
+
if (existsSync43(configPath)) {
|
|
67194
67364
|
const raw = readFileSync38(configPath, "utf-8");
|
|
67195
67365
|
const doc = import_yaml12.default.parseDocument(raw);
|
|
67196
67366
|
if (!doc.has("memory")) {
|
|
@@ -67232,7 +67402,7 @@ Cross-agent reflection plan
|
|
|
67232
67402
|
process.exit(1);
|
|
67233
67403
|
})() : Object.keys(config.agents);
|
|
67234
67404
|
for (const name of targets) {
|
|
67235
|
-
const agentDir =
|
|
67405
|
+
const agentDir = join37(agentsDir, name);
|
|
67236
67406
|
const entries = readRecallLog(agentDir, limit);
|
|
67237
67407
|
if (opts.json) {
|
|
67238
67408
|
for (const e of entries) {
|
|
@@ -67300,16 +67470,16 @@ init_loader();
|
|
|
67300
67470
|
init_lifecycle();
|
|
67301
67471
|
import {
|
|
67302
67472
|
readFileSync as readFileSync44,
|
|
67303
|
-
existsSync as
|
|
67304
|
-
realpathSync as
|
|
67473
|
+
existsSync as existsSync49,
|
|
67474
|
+
realpathSync as realpathSync4,
|
|
67305
67475
|
mkdirSync as mkdirSync28,
|
|
67306
67476
|
openSync as openSync10,
|
|
67307
67477
|
closeSync as closeSync10,
|
|
67308
67478
|
writeSync as writeSync6,
|
|
67309
67479
|
constants as fsConstants3
|
|
67310
67480
|
} from "node:fs";
|
|
67311
|
-
import { resolve as resolve28, extname, join as
|
|
67312
|
-
import { homedir as
|
|
67481
|
+
import { resolve as resolve28, extname, join as join44, relative, dirname as dirname10 } from "node:path";
|
|
67482
|
+
import { homedir as homedir24 } from "node:os";
|
|
67313
67483
|
import { spawn as spawn5 } from "node:child_process";
|
|
67314
67484
|
import { timingSafeEqual as timingSafeEqual3, randomBytes as randomBytes11 } from "node:crypto";
|
|
67315
67485
|
|
|
@@ -67318,7 +67488,7 @@ init_lifecycle();
|
|
|
67318
67488
|
init_manager();
|
|
67319
67489
|
init_hindsight();
|
|
67320
67490
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
67321
|
-
import { existsSync as
|
|
67491
|
+
import { existsSync as existsSync46, readFileSync as readFileSync41, statSync as statSync22 } from "node:fs";
|
|
67322
67492
|
import { resolve as resolve27 } from "node:path";
|
|
67323
67493
|
init_audit_reader();
|
|
67324
67494
|
|
|
@@ -67382,7 +67552,7 @@ function readRecentFires(jsonlPath) {
|
|
|
67382
67552
|
init_client3();
|
|
67383
67553
|
|
|
67384
67554
|
// node_modules/.bun/posthog-node@5.29.2/node_modules/posthog-node/dist/extensions/error-tracking/modifiers/module.node.mjs
|
|
67385
|
-
import { dirname as
|
|
67555
|
+
import { dirname as dirname8, posix, sep as sep2 } from "path";
|
|
67386
67556
|
function createModulerModifier() {
|
|
67387
67557
|
const getModuleFromFileName = createGetModuleFromFilename();
|
|
67388
67558
|
return async (frames) => {
|
|
@@ -67391,7 +67561,7 @@ function createModulerModifier() {
|
|
|
67391
67561
|
return frames;
|
|
67392
67562
|
};
|
|
67393
67563
|
}
|
|
67394
|
-
function createGetModuleFromFilename(basePath = process.argv[1] ?
|
|
67564
|
+
function createGetModuleFromFilename(basePath = process.argv[1] ? dirname8(process.argv[1]) : process.cwd(), isWindows = sep2 === "\\") {
|
|
67395
67565
|
const normalizedBase = isWindows ? normalizeWindowsPath(basePath) : basePath;
|
|
67396
67566
|
return (filename) => {
|
|
67397
67567
|
if (!filename)
|
|
@@ -71824,12 +71994,12 @@ class PostHog extends PostHogBackendClient {
|
|
|
71824
71994
|
// src/analytics/posthog.ts
|
|
71825
71995
|
init_paths();
|
|
71826
71996
|
import {
|
|
71827
|
-
existsSync as
|
|
71997
|
+
existsSync as existsSync44,
|
|
71828
71998
|
mkdirSync as mkdirSync24,
|
|
71829
71999
|
readFileSync as readFileSync39,
|
|
71830
72000
|
writeFileSync as writeFileSync23
|
|
71831
72001
|
} from "node:fs";
|
|
71832
|
-
import { dirname as
|
|
72002
|
+
import { dirname as dirname9 } from "node:path";
|
|
71833
72003
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
71834
72004
|
var DEFAULT_KEY = "phc_qKY87cKWZm6ZyCtk7LcRd2cU8Sg42u7Ywhui5stYCegd";
|
|
71835
72005
|
var DEFAULT_HOST = "https://us.i.posthog.com";
|
|
@@ -71846,7 +72016,7 @@ function getDistinctId() {
|
|
|
71846
72016
|
return cachedDistinctId;
|
|
71847
72017
|
const path4 = resolveStatePath("analytics-id");
|
|
71848
72018
|
try {
|
|
71849
|
-
if (
|
|
72019
|
+
if (existsSync44(path4)) {
|
|
71850
72020
|
const existing = readFileSync39(path4, "utf-8").trim();
|
|
71851
72021
|
if (existing) {
|
|
71852
72022
|
cachedDistinctId = existing;
|
|
@@ -71857,7 +72027,7 @@ function getDistinctId() {
|
|
|
71857
72027
|
const id = randomUUID3();
|
|
71858
72028
|
cachedDistinctId = id;
|
|
71859
72029
|
try {
|
|
71860
|
-
mkdirSync24(
|
|
72030
|
+
mkdirSync24(dirname9(path4), { recursive: true });
|
|
71861
72031
|
writeFileSync23(path4, id, "utf-8");
|
|
71862
72032
|
} catch {}
|
|
71863
72033
|
return id;
|
|
@@ -72028,19 +72198,19 @@ import {
|
|
|
72028
72198
|
} from "node:fs";
|
|
72029
72199
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
72030
72200
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
72031
|
-
import { join as
|
|
72201
|
+
import { join as join39 } from "node:path";
|
|
72032
72202
|
|
|
72033
72203
|
class ConfigDiffError extends Error {
|
|
72034
72204
|
}
|
|
72035
72205
|
function generateUnifiedDiff(before, after, name = "switchroom.yaml", gitBin = "git") {
|
|
72036
72206
|
if (before === after)
|
|
72037
72207
|
return "";
|
|
72038
|
-
const dir = mkdtemp(
|
|
72208
|
+
const dir = mkdtemp(join39(tmpdir4(), "switchroom-config-diff-"));
|
|
72039
72209
|
try {
|
|
72040
|
-
mkdirSync25(
|
|
72041
|
-
mkdirSync25(
|
|
72042
|
-
writeFileSync24(
|
|
72043
|
-
writeFileSync24(
|
|
72210
|
+
mkdirSync25(join39(dir, "cur"), { recursive: true });
|
|
72211
|
+
mkdirSync25(join39(dir, "new"), { recursive: true });
|
|
72212
|
+
writeFileSync24(join39(dir, "cur", name), before);
|
|
72213
|
+
writeFileSync24(join39(dir, "new", name), after);
|
|
72044
72214
|
const r = spawnSync4(gitBin, ["diff", "--no-index", "--no-color", "--", `cur/${name}`, `new/${name}`], { cwd: dir, encoding: "utf-8", timeout: 1e4 });
|
|
72045
72215
|
if (r.status === 0)
|
|
72046
72216
|
return "";
|
|
@@ -72072,9 +72242,9 @@ function generateUnifiedDiff(before, after, name = "switchroom.yaml", gitBin = "
|
|
|
72072
72242
|
|
|
72073
72243
|
// src/web/hostd-config-propose.ts
|
|
72074
72244
|
init_client4();
|
|
72075
|
-
import { existsSync as
|
|
72076
|
-
import { homedir as
|
|
72077
|
-
import { join as
|
|
72245
|
+
import { existsSync as existsSync45 } from "node:fs";
|
|
72246
|
+
import { homedir as homedir21 } from "node:os";
|
|
72247
|
+
import { join as join40 } from "node:path";
|
|
72078
72248
|
var PROPOSE_TIMEOUT_MS = 11 * 60 * 1000;
|
|
72079
72249
|
function resolveHostdOperatorSocket(env2 = process.env) {
|
|
72080
72250
|
const override = env2.SWITCHROOM_HOSTD_OPERATOR_SOCKET;
|
|
@@ -72082,10 +72252,10 @@ function resolveHostdOperatorSocket(env2 = process.env) {
|
|
|
72082
72252
|
return override;
|
|
72083
72253
|
const candidates = [
|
|
72084
72254
|
"/host-home/.switchroom/hostd/operator/sock",
|
|
72085
|
-
|
|
72255
|
+
join40(homedir21(), ".switchroom", "hostd", "operator", "sock")
|
|
72086
72256
|
];
|
|
72087
72257
|
for (const c of candidates) {
|
|
72088
|
-
if (
|
|
72258
|
+
if (existsSync45(c))
|
|
72089
72259
|
return c;
|
|
72090
72260
|
}
|
|
72091
72261
|
return null;
|
|
@@ -72178,7 +72348,7 @@ init_client2();
|
|
|
72178
72348
|
|
|
72179
72349
|
// telegram-plugin/registry/turns-schema.ts
|
|
72180
72350
|
import { chmodSync as chmodSync8, mkdirSync as mkdirSync26 } from "fs";
|
|
72181
|
-
import { join as
|
|
72351
|
+
import { join as join41 } from "path";
|
|
72182
72352
|
var DatabaseClass = null;
|
|
72183
72353
|
function loadDatabaseClass() {
|
|
72184
72354
|
if (DatabaseClass != null)
|
|
@@ -72241,9 +72411,9 @@ function applySchema(db) {
|
|
|
72241
72411
|
}
|
|
72242
72412
|
function openTurnsDb(agentDir) {
|
|
72243
72413
|
const Database2 = loadDatabaseClass();
|
|
72244
|
-
const dir =
|
|
72414
|
+
const dir = join41(agentDir, "telegram");
|
|
72245
72415
|
mkdirSync26(dir, { recursive: true, mode: 448 });
|
|
72246
|
-
const path4 =
|
|
72416
|
+
const path4 = join41(dir, "registry.db");
|
|
72247
72417
|
const db = new Database2(path4, { create: true });
|
|
72248
72418
|
applySchema(db);
|
|
72249
72419
|
try {
|
|
@@ -72350,7 +72520,7 @@ function listSubagents(db, opts = {}) {
|
|
|
72350
72520
|
function agentBridgeAlive(agentsDir, name, maxAgeMs = 30000, now = Date.now()) {
|
|
72351
72521
|
try {
|
|
72352
72522
|
const f = resolve27(agentsDir, name, "telegram", ".bridge-alive");
|
|
72353
|
-
return now -
|
|
72523
|
+
return now - statSync22(f).mtimeMs <= maxAgeMs;
|
|
72354
72524
|
} catch {
|
|
72355
72525
|
return false;
|
|
72356
72526
|
}
|
|
@@ -72675,7 +72845,7 @@ async function handleGetSystemHealth(config, home2) {
|
|
|
72675
72845
|
};
|
|
72676
72846
|
try {
|
|
72677
72847
|
const logPath = defaultAuditLogPath2(home2);
|
|
72678
|
-
if (
|
|
72848
|
+
if (existsSync46(logPath)) {
|
|
72679
72849
|
hostd.auditLogPresent = true;
|
|
72680
72850
|
const raw = readFileSync41(logPath, "utf-8");
|
|
72681
72851
|
hostd.recent = readAndFilter(raw, {}, 10);
|
|
@@ -72977,9 +73147,9 @@ async function handleGetApprovals() {
|
|
|
72977
73147
|
}
|
|
72978
73148
|
|
|
72979
73149
|
// src/web/webhook-handler.ts
|
|
72980
|
-
import { appendFileSync as appendFileSync3, existsSync as
|
|
72981
|
-
import { join as
|
|
72982
|
-
import { homedir as
|
|
73150
|
+
import { appendFileSync as appendFileSync3, existsSync as existsSync48, mkdirSync as mkdirSync27, readFileSync as readFileSync43, writeFileSync as writeFileSync25 } from "fs";
|
|
73151
|
+
import { join as join43 } from "path";
|
|
73152
|
+
import { homedir as homedir23 } from "os";
|
|
72983
73153
|
|
|
72984
73154
|
// src/web/webhook-verify.ts
|
|
72985
73155
|
import { createHmac as createHmac2, timingSafeEqual } from "crypto";
|
|
@@ -73129,18 +73299,18 @@ function forwardToGateway(socketPath, req, opts = {}) {
|
|
|
73129
73299
|
}
|
|
73130
73300
|
|
|
73131
73301
|
// src/web/webhook-edge.ts
|
|
73132
|
-
import { existsSync as
|
|
73133
|
-
import { join as
|
|
73134
|
-
import { homedir as
|
|
73302
|
+
import { existsSync as existsSync47, readFileSync as readFileSync42 } from "fs";
|
|
73303
|
+
import { join as join42 } from "path";
|
|
73304
|
+
import { homedir as homedir22 } from "os";
|
|
73135
73305
|
import { timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
73136
73306
|
var EDGE_HEADER = "x-switchroom-edge";
|
|
73137
73307
|
function edgeSecretPath() {
|
|
73138
|
-
return
|
|
73308
|
+
return join42(homedir22(), ".switchroom", "webhook-edge-secret");
|
|
73139
73309
|
}
|
|
73140
73310
|
function loadEdgeSecret(path4) {
|
|
73141
73311
|
const p = path4 ?? edgeSecretPath();
|
|
73142
73312
|
try {
|
|
73143
|
-
if (!
|
|
73313
|
+
if (!existsSync47(p))
|
|
73144
73314
|
return null;
|
|
73145
73315
|
const raw = readFileSync42(p, "utf-8").trim();
|
|
73146
73316
|
return raw.length > 0 ? raw : null;
|
|
@@ -73174,7 +73344,7 @@ var DEDUP_MAX = 1000;
|
|
|
73174
73344
|
var DEDUP_TTL_MS = 24 * 60 * 60 * 1000;
|
|
73175
73345
|
function loadDedupFile(path4) {
|
|
73176
73346
|
try {
|
|
73177
|
-
if (!
|
|
73347
|
+
if (!existsSync48(path4))
|
|
73178
73348
|
return {};
|
|
73179
73349
|
const raw = JSON.parse(readFileSync43(path4, "utf-8"));
|
|
73180
73350
|
return typeof raw.deliveries === "object" && raw.deliveries !== null ? raw.deliveries : {};
|
|
@@ -73198,8 +73368,8 @@ var agentDedupCache = new Map;
|
|
|
73198
73368
|
function createFileDedupStore(resolveAgentDir) {
|
|
73199
73369
|
return {
|
|
73200
73370
|
check(agent, deliveryId, now) {
|
|
73201
|
-
const telegramDir =
|
|
73202
|
-
const filePath =
|
|
73371
|
+
const telegramDir = join43(resolveAgentDir(agent), "telegram");
|
|
73372
|
+
const filePath = join43(telegramDir, "webhook-dedup.json");
|
|
73203
73373
|
if (!agentDedupCache.has(agent)) {
|
|
73204
73374
|
agentDedupCache.set(agent, loadDedupFile(filePath));
|
|
73205
73375
|
}
|
|
@@ -73251,7 +73421,7 @@ function shouldWriteThrottleIssue(agent, source, now, windowMap) {
|
|
|
73251
73421
|
return true;
|
|
73252
73422
|
}
|
|
73253
73423
|
function writeThrottleIssue(agent, source, now, telegramDir, log) {
|
|
73254
|
-
const issuesPath =
|
|
73424
|
+
const issuesPath = join43(telegramDir, "issues.jsonl");
|
|
73255
73425
|
try {
|
|
73256
73426
|
mkdirSync27(telegramDir, { recursive: true });
|
|
73257
73427
|
const record = {
|
|
@@ -73276,7 +73446,7 @@ function writeThrottleIssue(agent, source, now, telegramDir, log) {
|
|
|
73276
73446
|
async function handleWebhookIngest(args, deps = {}) {
|
|
73277
73447
|
const log = deps.log ?? ((s) => process.stderr.write(s));
|
|
73278
73448
|
const now = (deps.now ?? Date.now)();
|
|
73279
|
-
const resolveAgentDir = deps.resolveAgentDir ?? ((a) =>
|
|
73449
|
+
const resolveAgentDir = deps.resolveAgentDir ?? ((a) => join43(homedir23(), ".switchroom", "agents", a));
|
|
73280
73450
|
const rateLimiter = deps.rateLimiter ?? defaultRateLimiter;
|
|
73281
73451
|
const dedupStore = deps.dedupStore ?? createFileDedupStore(resolveAgentDir);
|
|
73282
73452
|
if (!args.agentExists) {
|
|
@@ -73340,7 +73510,7 @@ async function handleWebhookIngest(args, deps = {}) {
|
|
|
73340
73510
|
if (retryAfter !== null) {
|
|
73341
73511
|
if (!args.viaGateway) {
|
|
73342
73512
|
const agentDir2 = resolveAgentDir(args.agent);
|
|
73343
|
-
const telegramDir2 =
|
|
73513
|
+
const telegramDir2 = join43(agentDir2, "telegram");
|
|
73344
73514
|
if (shouldWriteThrottleIssue(args.agent, source, now)) {
|
|
73345
73515
|
writeThrottleIssue(args.agent, source, now, telegramDir2, log);
|
|
73346
73516
|
}
|
|
@@ -73360,7 +73530,7 @@ async function handleWebhookIngest(args, deps = {}) {
|
|
|
73360
73530
|
const eventType = source === "github" ? args.headers.get("x-github-event") ?? "unknown" : args.source;
|
|
73361
73531
|
const rendered = source === "github" ? renderGithubEvent(eventType, payload) : renderGenericEvent(args.source, payload);
|
|
73362
73532
|
if (args.viaGateway) {
|
|
73363
|
-
const socketPath =
|
|
73533
|
+
const socketPath = join43(resolveAgentDir(args.agent), "telegram", "webhook.sock");
|
|
73364
73534
|
const forward = deps.forwardFn ?? forwardToGateway;
|
|
73365
73535
|
const deliveryId = source === "github" ? args.headers.get("x-github-delivery") ?? undefined : undefined;
|
|
73366
73536
|
let resp;
|
|
@@ -73399,8 +73569,8 @@ async function handleWebhookIngest(args, deps = {}) {
|
|
|
73399
73569
|
return jsonReply(202, { ok: true, recorded: true, ts: resp.ts });
|
|
73400
73570
|
}
|
|
73401
73571
|
const agentDir = resolveAgentDir(args.agent);
|
|
73402
|
-
const telegramDir =
|
|
73403
|
-
const logPath =
|
|
73572
|
+
const telegramDir = join43(agentDir, "telegram");
|
|
73573
|
+
const logPath = join43(telegramDir, "webhook-events.jsonl");
|
|
73404
73574
|
try {
|
|
73405
73575
|
mkdirSync27(telegramDir, { recursive: true });
|
|
73406
73576
|
const record = {
|
|
@@ -73453,15 +73623,15 @@ function resolveWebToken() {
|
|
|
73453
73623
|
const fromEnv = process.env.SWITCHROOM_WEB_TOKEN;
|
|
73454
73624
|
if (fromEnv && fromEnv.length > 0)
|
|
73455
73625
|
return fromEnv;
|
|
73456
|
-
const home2 = process.env.HOME ??
|
|
73457
|
-
const tokenPath =
|
|
73458
|
-
if (
|
|
73626
|
+
const home2 = process.env.HOME ?? homedir24();
|
|
73627
|
+
const tokenPath = join44(home2, ".switchroom", "web-token");
|
|
73628
|
+
if (existsSync49(tokenPath)) {
|
|
73459
73629
|
const existing = readFileSync44(tokenPath, "utf8").trim();
|
|
73460
73630
|
if (existing.length > 0)
|
|
73461
73631
|
return existing;
|
|
73462
73632
|
}
|
|
73463
73633
|
const token = randomBytes11(32).toString("hex");
|
|
73464
|
-
mkdirSync28(
|
|
73634
|
+
mkdirSync28(dirname10(tokenPath), { recursive: true, mode: 448 });
|
|
73465
73635
|
try {
|
|
73466
73636
|
const fd = openSync10(tokenPath, fsConstants3.O_WRONLY | fsConstants3.O_CREAT | fsConstants3.O_EXCL, 384);
|
|
73467
73637
|
try {
|
|
@@ -73539,8 +73709,8 @@ function checkWsAuth(req, token, server) {
|
|
|
73539
73709
|
return presented !== null && constantTimeEqual(presented, token);
|
|
73540
73710
|
}
|
|
73541
73711
|
function loadWebhookSecrets() {
|
|
73542
|
-
const path4 =
|
|
73543
|
-
if (!
|
|
73712
|
+
const path4 = join44(homedir24(), ".switchroom", "webhook-secrets.json");
|
|
73713
|
+
if (!existsSync49(path4))
|
|
73544
73714
|
return {};
|
|
73545
73715
|
try {
|
|
73546
73716
|
const parsed = JSON.parse(readFileSync44(path4, "utf-8"));
|
|
@@ -73673,7 +73843,7 @@ function parseRoute(pathname, method) {
|
|
|
73673
73843
|
}
|
|
73674
73844
|
function startWebServer(config, port, hostname = "127.0.0.1", configPath) {
|
|
73675
73845
|
const uiDirRaw = resolve28(import.meta.dirname, "ui");
|
|
73676
|
-
const uiDir =
|
|
73846
|
+
const uiDir = existsSync49(uiDirRaw) ? realpathSync4(uiDirRaw) : uiDirRaw;
|
|
73677
73847
|
const token = resolveWebToken();
|
|
73678
73848
|
const freshConfig = () => {
|
|
73679
73849
|
if (!configPath)
|
|
@@ -73870,13 +74040,13 @@ function startWebServer(config, port, hostname = "127.0.0.1", configPath) {
|
|
|
73870
74040
|
}
|
|
73871
74041
|
}
|
|
73872
74042
|
let filePath = pathname === "/" ? "/index.html" : pathname;
|
|
73873
|
-
const fullPath =
|
|
73874
|
-
if (!
|
|
74043
|
+
const fullPath = join44(uiDir, filePath);
|
|
74044
|
+
if (!existsSync49(fullPath)) {
|
|
73875
74045
|
return new Response("Not Found", { status: 404 });
|
|
73876
74046
|
}
|
|
73877
74047
|
let realFullPath;
|
|
73878
74048
|
try {
|
|
73879
|
-
realFullPath =
|
|
74049
|
+
realFullPath = realpathSync4(fullPath);
|
|
73880
74050
|
} catch {
|
|
73881
74051
|
return new Response("Not Found", { status: 404 });
|
|
73882
74052
|
}
|
|
@@ -74020,8 +74190,8 @@ Starting Switchroom dashboard...
|
|
|
74020
74190
|
// src/cli/setup.ts
|
|
74021
74191
|
init_source();
|
|
74022
74192
|
init_loader();
|
|
74023
|
-
import { existsSync as
|
|
74024
|
-
import { resolve as resolve29, dirname as
|
|
74193
|
+
import { existsSync as existsSync50, copyFileSync as copyFileSync8, readFileSync as readFileSync45, writeFileSync as writeFileSync26, mkdirSync as mkdirSync29 } from "node:fs";
|
|
74194
|
+
import { resolve as resolve29, dirname as dirname11 } from "node:path";
|
|
74025
74195
|
init_vault();
|
|
74026
74196
|
init_manager();
|
|
74027
74197
|
|
|
@@ -74202,7 +74372,7 @@ async function stepConfigFile(configPath, nonInteractive) {
|
|
|
74202
74372
|
existingConfig = null;
|
|
74203
74373
|
}
|
|
74204
74374
|
}
|
|
74205
|
-
if (existingConfig &&
|
|
74375
|
+
if (existingConfig && existsSync50(existingConfig)) {
|
|
74206
74376
|
if (!nonInteractive) {
|
|
74207
74377
|
const useExisting = await askYesNo(` Found ${source_default.cyan(existingConfig)}. Use it?`, true);
|
|
74208
74378
|
if (!useExisting) {
|
|
@@ -74230,10 +74400,10 @@ async function copyExampleConfig(nonInteractive) {
|
|
|
74230
74400
|
}
|
|
74231
74401
|
const srcFile = resolve29(examplesDir, `${choice}.yaml`);
|
|
74232
74402
|
const destFile = resolvePath("~/.switchroom/switchroom.yaml");
|
|
74233
|
-
if (!
|
|
74403
|
+
if (!existsSync50(srcFile)) {
|
|
74234
74404
|
throw new ConfigError(`Example config not found: ${choice}.yaml`);
|
|
74235
74405
|
}
|
|
74236
|
-
mkdirSync29(
|
|
74406
|
+
mkdirSync29(dirname11(destFile), { recursive: true });
|
|
74237
74407
|
copyFileSync8(srcFile, destFile);
|
|
74238
74408
|
console.log(source_default.green(` Copied ${choice}.yaml -> ${destFile}`));
|
|
74239
74409
|
console.log(source_default.yellow(` Edit ${destFile} to customize, then re-run switchroom setup.`));
|
|
@@ -74314,7 +74484,7 @@ async function resolveOrPromptToken(rawToken, label, config, nonInteractive) {
|
|
|
74314
74484
|
try {
|
|
74315
74485
|
const { openVault: openVault2 } = await Promise.resolve().then(() => (init_vault(), exports_vault));
|
|
74316
74486
|
const vaultPath = resolvePath(config.vault?.path ?? "~/.switchroom/vault.enc");
|
|
74317
|
-
if (
|
|
74487
|
+
if (existsSync50(vaultPath)) {
|
|
74318
74488
|
const secrets = openVault2(passphrase, vaultPath);
|
|
74319
74489
|
const key = rawToken.replace("vault:", "");
|
|
74320
74490
|
const entry = secrets[key];
|
|
@@ -74342,7 +74512,7 @@ async function resolveOrPromptToken(rawToken, label, config, nonInteractive) {
|
|
|
74342
74512
|
async function storeTokenInVault(config, vaultRef, token) {
|
|
74343
74513
|
const vaultPath = resolvePath(config.vault?.path ?? "~/.switchroom/vault.enc");
|
|
74344
74514
|
const key = vaultRef.replace("vault:", "");
|
|
74345
|
-
if (!
|
|
74515
|
+
if (!existsSync50(vaultPath)) {
|
|
74346
74516
|
console.log(source_default.gray(" Creating encrypted vault..."));
|
|
74347
74517
|
let passphrase = process.env.SWITCHROOM_VAULT_PASSPHRASE;
|
|
74348
74518
|
if (!passphrase) {
|
|
@@ -74515,7 +74685,7 @@ async function stepMemoryBackend(config, nonInteractive, switchroomConfigPath) {
|
|
|
74515
74685
|
try {
|
|
74516
74686
|
const vaultPath = resolvePath(config.vault?.path ?? "~/.switchroom/vault.enc");
|
|
74517
74687
|
const passphrase = process.env.SWITCHROOM_VAULT_PASSPHRASE;
|
|
74518
|
-
if (passphrase &&
|
|
74688
|
+
if (passphrase && existsSync50(vaultPath)) {
|
|
74519
74689
|
const existing = getStringSecret(passphrase, vaultPath, "hindsight-api-key");
|
|
74520
74690
|
if (existing) {
|
|
74521
74691
|
console.log(source_default.gray(" Note: legacy 'hindsight-api-key' is in your vault but is no longer used. You can remove it with `switchroom vault rm hindsight-api-key`."));
|
|
@@ -74675,13 +74845,13 @@ async function stepAutoUnlock(config, switchroomConfigPath, nonInteractive) {
|
|
|
74675
74845
|
return;
|
|
74676
74846
|
}
|
|
74677
74847
|
const vaultPath = resolvePath(config.vault?.path ?? "~/.switchroom/vault.enc");
|
|
74678
|
-
if (!
|
|
74848
|
+
if (!existsSync50(vaultPath)) {
|
|
74679
74849
|
console.log(source_default.gray(" Skipping (vault not created yet)."));
|
|
74680
74850
|
return;
|
|
74681
74851
|
}
|
|
74682
74852
|
const credPathRaw = config.vault?.broker?.autoUnlockCredentialPath ?? "~/.switchroom/vault-auto-unlock";
|
|
74683
74853
|
const credPath = resolvePath(credPathRaw);
|
|
74684
|
-
if (config.vault?.broker?.autoUnlock === true &&
|
|
74854
|
+
if (config.vault?.broker?.autoUnlock === true && existsSync50(credPath)) {
|
|
74685
74855
|
console.log(source_default.green(` ${STEP_DONE} Already configured (${credPath})`));
|
|
74686
74856
|
return;
|
|
74687
74857
|
}
|
|
@@ -74747,8 +74917,8 @@ async function stepAutoUnlock(config, switchroomConfigPath, nonInteractive) {
|
|
|
74747
74917
|
const choice = await askChoice(" Approval posture", [PASSPHRASE_CHOICE, TELEGRAM_ID_CHOICE]);
|
|
74748
74918
|
if (choice === TELEGRAM_ID_CHOICE) {
|
|
74749
74919
|
try {
|
|
74750
|
-
const yamlPath =
|
|
74751
|
-
if (
|
|
74920
|
+
const yamlPath = existsSync50(resolve29(process.cwd(), "switchroom.yaml")) ? resolve29(process.cwd(), "switchroom.yaml") : resolve29(process.cwd(), "switchroom.yml");
|
|
74921
|
+
if (existsSync50(yamlPath)) {
|
|
74752
74922
|
const content = readFileSync45(yamlPath, "utf-8");
|
|
74753
74923
|
const result = insertVaultBrokerApprovalAuth(content, "telegram-id");
|
|
74754
74924
|
if (result.kind === "rewritten") {
|
|
@@ -74783,7 +74953,7 @@ async function stepDangerousMode(config, nonInteractive) {
|
|
|
74783
74953
|
resolve29(process.cwd(), "switchroom.yml")
|
|
74784
74954
|
];
|
|
74785
74955
|
for (const configPath of configPaths) {
|
|
74786
|
-
if (
|
|
74956
|
+
if (existsSync50(configPath)) {
|
|
74787
74957
|
let content = readFileSync45(configPath, "utf-8");
|
|
74788
74958
|
const agentNames = Object.keys(config.agents);
|
|
74789
74959
|
for (const name of agentNames) {
|
|
@@ -74913,22 +75083,22 @@ init_doctor();
|
|
|
74913
75083
|
init_source();
|
|
74914
75084
|
init_loader();
|
|
74915
75085
|
init_lifecycle();
|
|
74916
|
-
import { cpSync as cpSync2, existsSync as
|
|
75086
|
+
import { cpSync as cpSync2, existsSync as existsSync57, mkdirSync as mkdirSync31, readFileSync as readFileSync50, realpathSync as realpathSync6, rmSync as rmSync12, statSync as statSync26 } from "node:fs";
|
|
74917
75087
|
import { spawnSync as spawnSync9 } from "node:child_process";
|
|
74918
|
-
import { join as
|
|
74919
|
-
import { homedir as
|
|
74920
|
-
var DEFAULT_COMPOSE_PATH =
|
|
75088
|
+
import { join as join58, dirname as dirname14, resolve as resolve33 } from "node:path";
|
|
75089
|
+
import { homedir as homedir35 } from "node:os";
|
|
75090
|
+
var DEFAULT_COMPOSE_PATH = join58(homedir35(), ".switchroom", "compose", "docker-compose.yml");
|
|
74921
75091
|
function runningFromSwitchroomCheckout(scriptPath) {
|
|
74922
|
-
let dir =
|
|
75092
|
+
let dir = dirname14(scriptPath);
|
|
74923
75093
|
for (let i = 0;i < 12; i++) {
|
|
74924
|
-
if (
|
|
75094
|
+
if (existsSync57(join58(dir, ".git"))) {
|
|
74925
75095
|
try {
|
|
74926
|
-
const pkg = JSON.parse(readFileSync50(
|
|
75096
|
+
const pkg = JSON.parse(readFileSync50(join58(dir, "package.json"), "utf-8"));
|
|
74927
75097
|
if (pkg.name === "switchroom")
|
|
74928
75098
|
return true;
|
|
74929
75099
|
} catch {}
|
|
74930
75100
|
}
|
|
74931
|
-
const parent =
|
|
75101
|
+
const parent = dirname14(dir);
|
|
74932
75102
|
if (parent === dir)
|
|
74933
75103
|
break;
|
|
74934
75104
|
dir = parent;
|
|
@@ -74975,7 +75145,7 @@ function planUpdate(opts) {
|
|
|
74975
75145
|
steps.push({
|
|
74976
75146
|
name: "pull-images",
|
|
74977
75147
|
description: "Pull broker / kernel / agent images from GHCR",
|
|
74978
|
-
skipReason: opts.skipImages ? "--skip-images flag set" : !
|
|
75148
|
+
skipReason: opts.skipImages ? "--skip-images flag set" : !existsSync57(composePath) ? `compose file not found at ${composePath} (run \`switchroom apply --compose-only\` first)` : undefined,
|
|
74979
75149
|
run: () => {
|
|
74980
75150
|
const r = runner("docker", [
|
|
74981
75151
|
"compose",
|
|
@@ -75074,17 +75244,17 @@ function planUpdate(opts) {
|
|
|
75074
75244
|
return;
|
|
75075
75245
|
}
|
|
75076
75246
|
const source = resolve33(import.meta.dirname, "../../skills");
|
|
75077
|
-
const dest =
|
|
75078
|
-
if (!
|
|
75247
|
+
const dest = join58(homedir35(), ".switchroom", "skills", "_bundled");
|
|
75248
|
+
if (!existsSync57(source)) {
|
|
75079
75249
|
process.stderr.write(`switchroom update: sync-bundled-skills \u2014 CLI bundle has no adjacent skills/ at ${source}; skipping.
|
|
75080
75250
|
`);
|
|
75081
75251
|
return;
|
|
75082
75252
|
}
|
|
75083
75253
|
try {
|
|
75084
|
-
if (
|
|
75254
|
+
if (existsSync57(dest)) {
|
|
75085
75255
|
rmSync12(dest, { recursive: true, force: true });
|
|
75086
75256
|
}
|
|
75087
|
-
mkdirSync31(
|
|
75257
|
+
mkdirSync31(dirname14(dest), { recursive: true });
|
|
75088
75258
|
cpSync2(source, dest, { recursive: true, dereference: false });
|
|
75089
75259
|
} catch (err) {
|
|
75090
75260
|
throw new Error(`sync-bundled-skills failed: ${err.message}`);
|
|
@@ -75180,16 +75350,16 @@ function defaultStatusProbe(composePath) {
|
|
|
75180
75350
|
let scriptPath = rawScriptPath;
|
|
75181
75351
|
try {
|
|
75182
75352
|
if (rawScriptPath)
|
|
75183
|
-
scriptPath =
|
|
75353
|
+
scriptPath = realpathSync6(rawScriptPath);
|
|
75184
75354
|
} catch {}
|
|
75185
75355
|
if (scriptPath) {
|
|
75186
75356
|
try {
|
|
75187
|
-
cliBuiltAt = new Date(
|
|
75357
|
+
cliBuiltAt = new Date(statSync26(scriptPath).mtimeMs).toISOString();
|
|
75188
75358
|
} catch {}
|
|
75189
|
-
let dir =
|
|
75359
|
+
let dir = dirname14(scriptPath);
|
|
75190
75360
|
for (let i = 0;i < 8; i++) {
|
|
75191
|
-
const pkgPath =
|
|
75192
|
-
if (
|
|
75361
|
+
const pkgPath = join58(dir, "package.json");
|
|
75362
|
+
if (existsSync57(pkgPath)) {
|
|
75193
75363
|
try {
|
|
75194
75364
|
const pkg = JSON.parse(readFileSync50(pkgPath, "utf-8"));
|
|
75195
75365
|
if (typeof pkg.version === "string")
|
|
@@ -75199,7 +75369,7 @@ function defaultStatusProbe(composePath) {
|
|
|
75199
75369
|
}
|
|
75200
75370
|
break;
|
|
75201
75371
|
}
|
|
75202
|
-
const parent =
|
|
75372
|
+
const parent = dirname14(dir);
|
|
75203
75373
|
if (parent === dir)
|
|
75204
75374
|
break;
|
|
75205
75375
|
dir = parent;
|
|
@@ -75212,7 +75382,7 @@ function defaultStatusProbe(composePath) {
|
|
|
75212
75382
|
warnings.push("could not resolve CLI version (no package.json found above the resolved script path)");
|
|
75213
75383
|
}
|
|
75214
75384
|
const services = [];
|
|
75215
|
-
if (!
|
|
75385
|
+
if (!existsSync57(composePath)) {
|
|
75216
75386
|
warnings.push(`compose file not found at ${composePath}; service status unknown`);
|
|
75217
75387
|
return { cliVersion, cliBuiltAt, services, warnings };
|
|
75218
75388
|
}
|
|
@@ -75407,8 +75577,8 @@ init_source();
|
|
|
75407
75577
|
init_helpers();
|
|
75408
75578
|
init_lifecycle();
|
|
75409
75579
|
import { execSync as execSync4 } from "node:child_process";
|
|
75410
|
-
import { existsSync as
|
|
75411
|
-
import { dirname as
|
|
75580
|
+
import { existsSync as existsSync58, readFileSync as readFileSync51 } from "node:fs";
|
|
75581
|
+
import { dirname as dirname15, join as join59 } from "node:path";
|
|
75412
75582
|
function getClaudeCodeVersion() {
|
|
75413
75583
|
try {
|
|
75414
75584
|
const out = execSync4("claude --version 2>/dev/null", {
|
|
@@ -75458,16 +75628,16 @@ function formatUptime3(timestamp) {
|
|
|
75458
75628
|
function locateSwitchroomInstallDir() {
|
|
75459
75629
|
let dir = import.meta.dirname;
|
|
75460
75630
|
for (let i = 0;i < 10 && dir && dir !== "/"; i++) {
|
|
75461
|
-
const pkgPath =
|
|
75462
|
-
if (
|
|
75631
|
+
const pkgPath = join59(dir, "package.json");
|
|
75632
|
+
if (existsSync58(pkgPath)) {
|
|
75463
75633
|
try {
|
|
75464
75634
|
const pkg = JSON.parse(readFileSync51(pkgPath, "utf-8"));
|
|
75465
|
-
if (pkg.name === "switchroom" &&
|
|
75635
|
+
if (pkg.name === "switchroom" && existsSync58(join59(dir, ".git"))) {
|
|
75466
75636
|
return dir;
|
|
75467
75637
|
}
|
|
75468
75638
|
} catch {}
|
|
75469
75639
|
}
|
|
75470
|
-
dir =
|
|
75640
|
+
dir = dirname15(dir);
|
|
75471
75641
|
}
|
|
75472
75642
|
return null;
|
|
75473
75643
|
}
|
|
@@ -75688,18 +75858,18 @@ function registerHandoffCommand(program3) {
|
|
|
75688
75858
|
// src/issues/store.ts
|
|
75689
75859
|
import {
|
|
75690
75860
|
closeSync as closeSync11,
|
|
75691
|
-
existsSync as
|
|
75861
|
+
existsSync as existsSync59,
|
|
75692
75862
|
mkdirSync as mkdirSync32,
|
|
75693
75863
|
openSync as openSync11,
|
|
75694
|
-
readdirSync as
|
|
75864
|
+
readdirSync as readdirSync22,
|
|
75695
75865
|
readFileSync as readFileSync52,
|
|
75696
75866
|
renameSync as renameSync12,
|
|
75697
|
-
statSync as
|
|
75867
|
+
statSync as statSync27,
|
|
75698
75868
|
unlinkSync as unlinkSync11,
|
|
75699
75869
|
writeFileSync as writeFileSync27,
|
|
75700
75870
|
writeSync as writeSync7
|
|
75701
75871
|
} from "node:fs";
|
|
75702
|
-
import { join as
|
|
75872
|
+
import { join as join60 } from "node:path";
|
|
75703
75873
|
import { randomBytes as randomBytes12 } from "node:crypto";
|
|
75704
75874
|
import { execSync as execSync5 } from "node:child_process";
|
|
75705
75875
|
|
|
@@ -76097,8 +76267,8 @@ function redactedMarker(ruleId) {
|
|
|
76097
76267
|
var ISSUES_FILE = "issues.jsonl";
|
|
76098
76268
|
var ISSUES_LOCK = "issues.lock";
|
|
76099
76269
|
function readAll(stateDir) {
|
|
76100
|
-
const path4 =
|
|
76101
|
-
if (!
|
|
76270
|
+
const path4 = join60(stateDir, ISSUES_FILE);
|
|
76271
|
+
if (!existsSync59(path4))
|
|
76102
76272
|
return [];
|
|
76103
76273
|
let raw;
|
|
76104
76274
|
try {
|
|
@@ -76175,7 +76345,7 @@ function record(stateDir, input, nowFn = Date.now) {
|
|
|
76175
76345
|
});
|
|
76176
76346
|
}
|
|
76177
76347
|
function resolve36(stateDir, fingerprint, nowFn = Date.now) {
|
|
76178
|
-
if (!
|
|
76348
|
+
if (!existsSync59(join60(stateDir, ISSUES_FILE)))
|
|
76179
76349
|
return 0;
|
|
76180
76350
|
return withLock(stateDir, () => {
|
|
76181
76351
|
const all = readAll(stateDir);
|
|
@@ -76193,7 +76363,7 @@ function resolve36(stateDir, fingerprint, nowFn = Date.now) {
|
|
|
76193
76363
|
});
|
|
76194
76364
|
}
|
|
76195
76365
|
function resolveAllBySource(stateDir, source, nowFn = Date.now) {
|
|
76196
|
-
if (!
|
|
76366
|
+
if (!existsSync59(join60(stateDir, ISSUES_FILE)))
|
|
76197
76367
|
return 0;
|
|
76198
76368
|
return withLock(stateDir, () => {
|
|
76199
76369
|
const all = readAll(stateDir);
|
|
@@ -76211,7 +76381,7 @@ function resolveAllBySource(stateDir, source, nowFn = Date.now) {
|
|
|
76211
76381
|
});
|
|
76212
76382
|
}
|
|
76213
76383
|
function prune(stateDir, opts = {}) {
|
|
76214
|
-
if (!
|
|
76384
|
+
if (!existsSync59(join60(stateDir, ISSUES_FILE)))
|
|
76215
76385
|
return 0;
|
|
76216
76386
|
return withLock(stateDir, () => {
|
|
76217
76387
|
const all = readAll(stateDir);
|
|
@@ -76244,7 +76414,7 @@ function ensureDir(stateDir) {
|
|
|
76244
76414
|
mkdirSync32(stateDir, { recursive: true });
|
|
76245
76415
|
}
|
|
76246
76416
|
function writeAll(stateDir, events) {
|
|
76247
|
-
const path4 =
|
|
76417
|
+
const path4 = join60(stateDir, ISSUES_FILE);
|
|
76248
76418
|
sweepOrphanTmpFiles(stateDir);
|
|
76249
76419
|
const tmp = `${path4}.tmp-${process.pid}-${randomBytes12(4).toString("hex")}`;
|
|
76250
76420
|
const body = events.length === 0 ? "" : events.map((e) => JSON.stringify(e)).join(`
|
|
@@ -76258,7 +76428,7 @@ var TMP_PREFIX = `${ISSUES_FILE}.tmp-`;
|
|
|
76258
76428
|
function sweepOrphanTmpFiles(stateDir) {
|
|
76259
76429
|
let entries;
|
|
76260
76430
|
try {
|
|
76261
|
-
entries =
|
|
76431
|
+
entries = readdirSync22(stateDir);
|
|
76262
76432
|
} catch {
|
|
76263
76433
|
return;
|
|
76264
76434
|
}
|
|
@@ -76266,9 +76436,9 @@ function sweepOrphanTmpFiles(stateDir) {
|
|
|
76266
76436
|
for (const entry of entries) {
|
|
76267
76437
|
if (!entry.startsWith(TMP_PREFIX))
|
|
76268
76438
|
continue;
|
|
76269
|
-
const tmpPath =
|
|
76439
|
+
const tmpPath = join60(stateDir, entry);
|
|
76270
76440
|
try {
|
|
76271
|
-
const stat =
|
|
76441
|
+
const stat = statSync27(tmpPath);
|
|
76272
76442
|
if (stat.mtimeMs < cutoff) {
|
|
76273
76443
|
unlinkSync11(tmpPath);
|
|
76274
76444
|
}
|
|
@@ -76278,7 +76448,7 @@ function sweepOrphanTmpFiles(stateDir) {
|
|
|
76278
76448
|
var LOCK_RETRY_MS = 25;
|
|
76279
76449
|
var LOCK_TIMEOUT_MS = 1e4;
|
|
76280
76450
|
function withLock(stateDir, fn) {
|
|
76281
|
-
const lockPath =
|
|
76451
|
+
const lockPath = join60(stateDir, ISSUES_LOCK);
|
|
76282
76452
|
const startedAt = Date.now();
|
|
76283
76453
|
let fd = null;
|
|
76284
76454
|
while (fd === null) {
|
|
@@ -76561,21 +76731,21 @@ function relTime(deltaMs) {
|
|
|
76561
76731
|
|
|
76562
76732
|
// src/cli/deps.ts
|
|
76563
76733
|
init_source();
|
|
76564
|
-
import { existsSync as
|
|
76565
|
-
import { homedir as
|
|
76566
|
-
import { join as
|
|
76734
|
+
import { existsSync as existsSync62 } from "node:fs";
|
|
76735
|
+
import { homedir as homedir38 } from "node:os";
|
|
76736
|
+
import { join as join63, resolve as resolve37 } from "node:path";
|
|
76567
76737
|
|
|
76568
76738
|
// src/deps/python.ts
|
|
76569
76739
|
import { createHash as createHash11 } from "node:crypto";
|
|
76570
76740
|
import {
|
|
76571
|
-
existsSync as
|
|
76741
|
+
existsSync as existsSync60,
|
|
76572
76742
|
mkdirSync as mkdirSync33,
|
|
76573
76743
|
readFileSync as readFileSync53,
|
|
76574
76744
|
rmSync as rmSync13,
|
|
76575
76745
|
writeFileSync as writeFileSync28
|
|
76576
76746
|
} from "node:fs";
|
|
76577
|
-
import { dirname as
|
|
76578
|
-
import { homedir as
|
|
76747
|
+
import { dirname as dirname16, join as join61 } from "node:path";
|
|
76748
|
+
import { homedir as homedir36 } from "node:os";
|
|
76579
76749
|
import { execFileSync as execFileSync19 } from "node:child_process";
|
|
76580
76750
|
|
|
76581
76751
|
class PythonEnvError extends Error {
|
|
@@ -76587,7 +76757,7 @@ class PythonEnvError extends Error {
|
|
|
76587
76757
|
}
|
|
76588
76758
|
}
|
|
76589
76759
|
function defaultPythonCacheRoot() {
|
|
76590
|
-
return
|
|
76760
|
+
return join61(homedir36(), ".switchroom", "deps", "python");
|
|
76591
76761
|
}
|
|
76592
76762
|
function hashFile(path4) {
|
|
76593
76763
|
return createHash11("sha256").update(readFileSync53(path4)).digest("hex");
|
|
@@ -76596,16 +76766,16 @@ function ensurePythonEnv(opts) {
|
|
|
76596
76766
|
const { skillName, requirementsPath, force = false } = opts;
|
|
76597
76767
|
const cacheRoot = opts.cacheRoot ?? defaultPythonCacheRoot();
|
|
76598
76768
|
const hostPython = opts.pythonBin ?? "python3";
|
|
76599
|
-
if (!
|
|
76769
|
+
if (!existsSync60(requirementsPath)) {
|
|
76600
76770
|
throw new PythonEnvError(`requirements file not found: ${requirementsPath}`);
|
|
76601
76771
|
}
|
|
76602
|
-
const venvDir =
|
|
76603
|
-
const stampPath =
|
|
76604
|
-
const binDir =
|
|
76605
|
-
const pythonBin =
|
|
76606
|
-
const pipBin =
|
|
76772
|
+
const venvDir = join61(cacheRoot, skillName);
|
|
76773
|
+
const stampPath = join61(venvDir, ".requirements.sha256");
|
|
76774
|
+
const binDir = join61(venvDir, "bin");
|
|
76775
|
+
const pythonBin = join61(binDir, "python");
|
|
76776
|
+
const pipBin = join61(binDir, "pip");
|
|
76607
76777
|
const targetHash = hashFile(requirementsPath);
|
|
76608
|
-
if (!force &&
|
|
76778
|
+
if (!force && existsSync60(stampPath) && existsSync60(pythonBin)) {
|
|
76609
76779
|
const existingHash = readFileSync53(stampPath, "utf8").trim();
|
|
76610
76780
|
if (existingHash === targetHash) {
|
|
76611
76781
|
return {
|
|
@@ -76618,10 +76788,10 @@ function ensurePythonEnv(opts) {
|
|
|
76618
76788
|
};
|
|
76619
76789
|
}
|
|
76620
76790
|
}
|
|
76621
|
-
if (
|
|
76791
|
+
if (existsSync60(venvDir)) {
|
|
76622
76792
|
rmSync13(venvDir, { recursive: true, force: true });
|
|
76623
76793
|
}
|
|
76624
|
-
mkdirSync33(
|
|
76794
|
+
mkdirSync33(dirname16(venvDir), { recursive: true });
|
|
76625
76795
|
try {
|
|
76626
76796
|
execFileSync19(hostPython, ["-m", "venv", venvDir], { stdio: "pipe" });
|
|
76627
76797
|
} catch (err) {
|
|
@@ -76656,14 +76826,14 @@ function ensurePythonEnv(opts) {
|
|
|
76656
76826
|
import { createHash as createHash12 } from "node:crypto";
|
|
76657
76827
|
import {
|
|
76658
76828
|
copyFileSync as copyFileSync9,
|
|
76659
|
-
existsSync as
|
|
76829
|
+
existsSync as existsSync61,
|
|
76660
76830
|
mkdirSync as mkdirSync34,
|
|
76661
76831
|
readFileSync as readFileSync54,
|
|
76662
76832
|
rmSync as rmSync14,
|
|
76663
76833
|
writeFileSync as writeFileSync29
|
|
76664
76834
|
} from "node:fs";
|
|
76665
|
-
import { dirname as
|
|
76666
|
-
import { homedir as
|
|
76835
|
+
import { dirname as dirname17, join as join62 } from "node:path";
|
|
76836
|
+
import { homedir as homedir37 } from "node:os";
|
|
76667
76837
|
import { execFileSync as execFileSync20 } from "node:child_process";
|
|
76668
76838
|
|
|
76669
76839
|
class NodeEnvError extends Error {
|
|
@@ -76686,17 +76856,17 @@ var LOCKFILES_FOR = {
|
|
|
76686
76856
|
npm: ["package-lock.json"]
|
|
76687
76857
|
};
|
|
76688
76858
|
function defaultNodeCacheRoot() {
|
|
76689
|
-
return
|
|
76859
|
+
return join62(homedir37(), ".switchroom", "deps", "node");
|
|
76690
76860
|
}
|
|
76691
76861
|
function hashDepInputs(packageJsonPath) {
|
|
76692
|
-
const sourceDir =
|
|
76862
|
+
const sourceDir = dirname17(packageJsonPath);
|
|
76693
76863
|
const hasher = createHash12("sha256");
|
|
76694
76864
|
hasher.update(`package.json
|
|
76695
76865
|
`);
|
|
76696
76866
|
hasher.update(readFileSync54(packageJsonPath));
|
|
76697
76867
|
for (const lockName of ALL_LOCKFILES) {
|
|
76698
|
-
const lockPath =
|
|
76699
|
-
if (
|
|
76868
|
+
const lockPath = join62(sourceDir, lockName);
|
|
76869
|
+
if (existsSync61(lockPath)) {
|
|
76700
76870
|
hasher.update(`
|
|
76701
76871
|
`);
|
|
76702
76872
|
hasher.update(lockName);
|
|
@@ -76711,16 +76881,16 @@ function ensureNodeEnv(opts) {
|
|
|
76711
76881
|
const { skillName, packageJsonPath, force = false } = opts;
|
|
76712
76882
|
const cacheRoot = opts.cacheRoot ?? defaultNodeCacheRoot();
|
|
76713
76883
|
const installer = opts.installer ?? "bun";
|
|
76714
|
-
if (!
|
|
76884
|
+
if (!existsSync61(packageJsonPath)) {
|
|
76715
76885
|
throw new NodeEnvError(`package.json not found: ${packageJsonPath}`);
|
|
76716
76886
|
}
|
|
76717
|
-
const sourceDir =
|
|
76718
|
-
const envDir =
|
|
76719
|
-
const stampPath =
|
|
76720
|
-
const nodeModulesDir =
|
|
76721
|
-
const binDir =
|
|
76887
|
+
const sourceDir = dirname17(packageJsonPath);
|
|
76888
|
+
const envDir = join62(cacheRoot, skillName);
|
|
76889
|
+
const stampPath = join62(envDir, ".package.sha256");
|
|
76890
|
+
const nodeModulesDir = join62(envDir, "node_modules");
|
|
76891
|
+
const binDir = join62(nodeModulesDir, ".bin");
|
|
76722
76892
|
const targetHash = hashDepInputs(packageJsonPath);
|
|
76723
|
-
if (!force &&
|
|
76893
|
+
if (!force && existsSync61(stampPath) && existsSync61(nodeModulesDir)) {
|
|
76724
76894
|
const existingHash = readFileSync54(stampPath, "utf8").trim();
|
|
76725
76895
|
if (existingHash === targetHash) {
|
|
76726
76896
|
return {
|
|
@@ -76732,16 +76902,16 @@ function ensureNodeEnv(opts) {
|
|
|
76732
76902
|
};
|
|
76733
76903
|
}
|
|
76734
76904
|
}
|
|
76735
|
-
if (
|
|
76905
|
+
if (existsSync61(envDir)) {
|
|
76736
76906
|
rmSync14(envDir, { recursive: true, force: true });
|
|
76737
76907
|
}
|
|
76738
76908
|
mkdirSync34(envDir, { recursive: true });
|
|
76739
|
-
copyFileSync9(packageJsonPath,
|
|
76909
|
+
copyFileSync9(packageJsonPath, join62(envDir, "package.json"));
|
|
76740
76910
|
let copiedLockfile = false;
|
|
76741
76911
|
for (const lockName of LOCKFILES_FOR[installer]) {
|
|
76742
|
-
const lockPath =
|
|
76743
|
-
if (
|
|
76744
|
-
copyFileSync9(lockPath,
|
|
76912
|
+
const lockPath = join62(sourceDir, lockName);
|
|
76913
|
+
if (existsSync61(lockPath)) {
|
|
76914
|
+
copyFileSync9(lockPath, join62(envDir, lockName));
|
|
76745
76915
|
copiedLockfile = true;
|
|
76746
76916
|
}
|
|
76747
76917
|
}
|
|
@@ -76770,28 +76940,28 @@ function ensureNodeEnv(opts) {
|
|
|
76770
76940
|
|
|
76771
76941
|
// src/cli/deps.ts
|
|
76772
76942
|
function builtinSkillsRoot() {
|
|
76773
|
-
return resolve37(
|
|
76943
|
+
return resolve37(homedir38(), ".switchroom/skills/_bundled");
|
|
76774
76944
|
}
|
|
76775
76945
|
function registerDepsCommand(program3) {
|
|
76776
76946
|
const deps = program3.command("deps").description("Manage cached per-skill dependency environments");
|
|
76777
76947
|
deps.command("rebuild <skill>").description("Rebuild the Python venv and/or Node node_modules cache for a skill").option("-p, --python", "Rebuild only the Python env").option("-n, --node", "Rebuild only the Node env").action(async (skill, opts) => {
|
|
76778
76948
|
const skillsRoot = builtinSkillsRoot();
|
|
76779
|
-
if (!
|
|
76949
|
+
if (!existsSync62(skillsRoot)) {
|
|
76780
76950
|
console.error(source_default.red(`Bundled skills pool dir not found at ${skillsRoot} \u2014 run \`switchroom update\` to install it.`));
|
|
76781
76951
|
process.exit(1);
|
|
76782
76952
|
}
|
|
76783
|
-
const skillDir =
|
|
76784
|
-
if (!
|
|
76953
|
+
const skillDir = join63(skillsRoot, skill);
|
|
76954
|
+
if (!existsSync62(skillDir)) {
|
|
76785
76955
|
console.error(source_default.red(`Unknown skill: ${skill} (no dir at ${skillDir})`));
|
|
76786
76956
|
process.exit(1);
|
|
76787
76957
|
}
|
|
76788
|
-
const requirementsPath =
|
|
76789
|
-
const packageJsonPath =
|
|
76790
|
-
const wantPython = opts.python ?? (!opts.python && !opts.node &&
|
|
76791
|
-
const wantNode = opts.node ?? (!opts.python && !opts.node &&
|
|
76958
|
+
const requirementsPath = join63(skillDir, "requirements.txt");
|
|
76959
|
+
const packageJsonPath = join63(skillDir, "package.json");
|
|
76960
|
+
const wantPython = opts.python ?? (!opts.python && !opts.node && existsSync62(requirementsPath));
|
|
76961
|
+
const wantNode = opts.node ?? (!opts.python && !opts.node && existsSync62(packageJsonPath));
|
|
76792
76962
|
let did = 0;
|
|
76793
76963
|
if (wantPython) {
|
|
76794
|
-
if (!
|
|
76964
|
+
if (!existsSync62(requirementsPath)) {
|
|
76795
76965
|
console.error(source_default.red(`Skill "${skill}" has no requirements.txt at ${requirementsPath}`));
|
|
76796
76966
|
process.exit(1);
|
|
76797
76967
|
}
|
|
@@ -76815,7 +76985,7 @@ function registerDepsCommand(program3) {
|
|
|
76815
76985
|
}
|
|
76816
76986
|
}
|
|
76817
76987
|
if (wantNode) {
|
|
76818
|
-
if (!
|
|
76988
|
+
if (!existsSync62(packageJsonPath)) {
|
|
76819
76989
|
console.error(source_default.red(`Skill "${skill}" has no package.json at ${packageJsonPath}`));
|
|
76820
76990
|
process.exit(1);
|
|
76821
76991
|
}
|
|
@@ -76848,12 +77018,12 @@ function registerDepsCommand(program3) {
|
|
|
76848
77018
|
// src/cli/workspace.ts
|
|
76849
77019
|
init_helpers();
|
|
76850
77020
|
init_loader();
|
|
76851
|
-
import { existsSync as
|
|
77021
|
+
import { existsSync as existsSync63 } from "node:fs";
|
|
76852
77022
|
import { resolve as resolve38, sep as sep3 } from "node:path";
|
|
76853
77023
|
import { spawnSync as spawnSync10 } from "node:child_process";
|
|
76854
77024
|
|
|
76855
77025
|
// src/agents/workspace.ts
|
|
76856
|
-
import { readFile, stat } from "node:fs/promises";
|
|
77026
|
+
import { readFile as readFile2, stat } from "node:fs/promises";
|
|
76857
77027
|
import path5 from "node:path";
|
|
76858
77028
|
|
|
76859
77029
|
// src/agents/bootstrap-budget.ts
|
|
@@ -77091,7 +77261,7 @@ function resolveAgentWorkspaceDir(agentDir) {
|
|
|
77091
77261
|
}
|
|
77092
77262
|
async function readOptionalFile(filePath) {
|
|
77093
77263
|
try {
|
|
77094
|
-
const content = await
|
|
77264
|
+
const content = await readFile2(filePath, "utf8");
|
|
77095
77265
|
return content;
|
|
77096
77266
|
} catch (err) {
|
|
77097
77267
|
if (isErrnoException(err) && (err.code === "ENOENT" || err.code === "EISDIR")) {
|
|
@@ -77281,7 +77451,7 @@ async function buildDynamicBootstrapPrompt(params) {
|
|
|
77281
77451
|
}
|
|
77282
77452
|
|
|
77283
77453
|
// src/agents/memory-search.ts
|
|
77284
|
-
import { readFile as
|
|
77454
|
+
import { readFile as readFile3, readdir, realpath, stat as stat2 } from "node:fs/promises";
|
|
77285
77455
|
import path6 from "node:path";
|
|
77286
77456
|
var DEFAULT_MEMORY_SEARCH_MAX_RESULTS = 6;
|
|
77287
77457
|
var DEFAULT_MEMORY_SEARCH_SNIPPET_CHARS = 220;
|
|
@@ -77332,7 +77502,7 @@ async function loadIndex(workspaceDir) {
|
|
|
77332
77502
|
break;
|
|
77333
77503
|
let content;
|
|
77334
77504
|
try {
|
|
77335
|
-
content = await
|
|
77505
|
+
content = await readFile3(full, "utf8");
|
|
77336
77506
|
} catch {
|
|
77337
77507
|
continue;
|
|
77338
77508
|
}
|
|
@@ -77463,7 +77633,7 @@ async function getWorkspaceMemoryFile(params) {
|
|
|
77463
77633
|
if (!info.isFile()) {
|
|
77464
77634
|
throw new Error(`not a file: ${params.relativePath}`);
|
|
77465
77635
|
}
|
|
77466
|
-
const buf = await
|
|
77636
|
+
const buf = await readFile3(resolvedTarget);
|
|
77467
77637
|
if (buf.length <= maxBytes) {
|
|
77468
77638
|
return {
|
|
77469
77639
|
path: params.relativePath,
|
|
@@ -77627,7 +77797,7 @@ function registerWorkspaceCommand(program3) {
|
|
|
77627
77797
|
if (!dir)
|
|
77628
77798
|
return;
|
|
77629
77799
|
const gitDir = resolve38(dir, ".git");
|
|
77630
|
-
if (!
|
|
77800
|
+
if (!existsSync63(gitDir)) {
|
|
77631
77801
|
process.stdout.write(`Workspace is not a git repository. Re-run \`switchroom agent create ${agentName}\` ` + `or manually \`git init\` in ${dir} to enable versioning.
|
|
77632
77802
|
`);
|
|
77633
77803
|
return;
|
|
@@ -77681,7 +77851,7 @@ function registerWorkspaceCommand(program3) {
|
|
|
77681
77851
|
if (!dir)
|
|
77682
77852
|
return;
|
|
77683
77853
|
const gitDir = resolve38(dir, ".git");
|
|
77684
|
-
if (!
|
|
77854
|
+
if (!existsSync63(gitDir)) {
|
|
77685
77855
|
process.stdout.write(`Workspace is not a git repository.
|
|
77686
77856
|
`);
|
|
77687
77857
|
return;
|
|
@@ -77706,7 +77876,7 @@ function resolveAgentWorkspaceDirOrExit(program3, agentName) {
|
|
|
77706
77876
|
const agentsDir = resolveAgentsDir(config);
|
|
77707
77877
|
const agentDir = resolve38(agentsDir, agentName);
|
|
77708
77878
|
const dir = resolveAgentWorkspaceDir(agentDir);
|
|
77709
|
-
if (!
|
|
77879
|
+
if (!existsSync63(dir)) {
|
|
77710
77880
|
process.stderr.write(`workspace: ${dir} does not exist yet. Run \`switchroom setup\` or \`switchroom agent scaffold ${agentName}\` to seed it.
|
|
77711
77881
|
`);
|
|
77712
77882
|
return;
|
|
@@ -77742,8 +77912,8 @@ function safeParseInt(value, fallback) {
|
|
|
77742
77912
|
init_helpers();
|
|
77743
77913
|
init_loader();
|
|
77744
77914
|
init_merge();
|
|
77745
|
-
import { copyFileSync as copyFileSync10, existsSync as
|
|
77746
|
-
import { join as
|
|
77915
|
+
import { copyFileSync as copyFileSync10, existsSync as existsSync64, readFileSync as readFileSync55, writeFileSync as writeFileSync30 } from "node:fs";
|
|
77916
|
+
import { join as join64, resolve as resolve39 } from "node:path";
|
|
77747
77917
|
init_schema();
|
|
77748
77918
|
function resolveSoulTargetOrExit(program3, agentName) {
|
|
77749
77919
|
const config = getConfig(program3);
|
|
@@ -77758,7 +77928,7 @@ function resolveSoulTargetOrExit(program3, agentName) {
|
|
|
77758
77928
|
const agentsDir = resolveAgentsDir(config);
|
|
77759
77929
|
const agentDir = resolve39(agentsDir, agentName);
|
|
77760
77930
|
const workspaceDir = resolveAgentWorkspaceDir(agentDir);
|
|
77761
|
-
if (!
|
|
77931
|
+
if (!existsSync64(workspaceDir)) {
|
|
77762
77932
|
console.error(`soul: ${workspaceDir} does not exist yet. Run \`switchroom setup\` ` + `or \`switchroom agent scaffold ${agentName}\` to seed it.`);
|
|
77763
77933
|
process.exit(1);
|
|
77764
77934
|
}
|
|
@@ -77767,7 +77937,7 @@ function resolveSoulTargetOrExit(program3, agentName) {
|
|
|
77767
77937
|
profileName,
|
|
77768
77938
|
profilePath,
|
|
77769
77939
|
workspaceDir,
|
|
77770
|
-
soulPath:
|
|
77940
|
+
soulPath: join64(workspaceDir, "SOUL.md"),
|
|
77771
77941
|
soul: merged.soul
|
|
77772
77942
|
};
|
|
77773
77943
|
}
|
|
@@ -77784,7 +77954,7 @@ function registerSoulCommand(program3) {
|
|
|
77784
77954
|
const t = resolveSoulTargetOrExit(program3, agentName);
|
|
77785
77955
|
if (!t)
|
|
77786
77956
|
return;
|
|
77787
|
-
if (!
|
|
77957
|
+
if (!existsSync64(t.soulPath)) {
|
|
77788
77958
|
console.error(`soul: ${t.soulPath} does not exist yet \u2014 run ` + `\`switchroom soul reset ${agentName}\` to seed it.`);
|
|
77789
77959
|
process.exit(1);
|
|
77790
77960
|
}
|
|
@@ -77799,7 +77969,7 @@ function registerSoulCommand(program3) {
|
|
|
77799
77969
|
console.error(`soul: profile "${t.profileName}" ships no SOUL.md.hbs \u2014 ` + `nothing to re-seed from.`);
|
|
77800
77970
|
process.exit(1);
|
|
77801
77971
|
}
|
|
77802
|
-
const exists =
|
|
77972
|
+
const exists = existsSync64(t.soulPath);
|
|
77803
77973
|
if (exists && !opts.yes) {
|
|
77804
77974
|
if (!isInteractive()) {
|
|
77805
77975
|
console.error(`soul: ${t.soulPath} already exists. Re-run with --yes to ` + `replace it (the current file is backed up to SOUL.md.bak).`);
|
|
@@ -77814,7 +77984,7 @@ function registerSoulCommand(program3) {
|
|
|
77814
77984
|
let backupPath;
|
|
77815
77985
|
if (exists) {
|
|
77816
77986
|
backupPath = `${t.soulPath}.bak`;
|
|
77817
|
-
if (
|
|
77987
|
+
if (existsSync64(backupPath)) {
|
|
77818
77988
|
backupPath = `${t.soulPath}.bak.${Date.now()}`;
|
|
77819
77989
|
}
|
|
77820
77990
|
copyFileSync10(t.soulPath, backupPath);
|
|
@@ -77833,8 +78003,8 @@ function registerSoulCommand(program3) {
|
|
|
77833
78003
|
// src/cli/debug.ts
|
|
77834
78004
|
init_helpers();
|
|
77835
78005
|
init_loader();
|
|
77836
|
-
import { existsSync as
|
|
77837
|
-
import { resolve as resolve40, join as
|
|
78006
|
+
import { existsSync as existsSync65, readFileSync as readFileSync56, readdirSync as readdirSync23, statSync as statSync28 } from "node:fs";
|
|
78007
|
+
import { resolve as resolve40, join as join65 } from "node:path";
|
|
77838
78008
|
import { createHash as createHash13 } from "node:crypto";
|
|
77839
78009
|
init_merge();
|
|
77840
78010
|
init_hindsight();
|
|
@@ -77845,8 +78015,8 @@ function estimateTokens(bytes) {
|
|
|
77845
78015
|
return Math.round(bytes / 3.7);
|
|
77846
78016
|
}
|
|
77847
78017
|
function readMcpServerNames(agentDir) {
|
|
77848
|
-
const mcpPath =
|
|
77849
|
-
if (!
|
|
78018
|
+
const mcpPath = join65(agentDir, ".mcp.json");
|
|
78019
|
+
if (!existsSync65(mcpPath))
|
|
77850
78020
|
return [];
|
|
77851
78021
|
try {
|
|
77852
78022
|
const parsed = JSON.parse(readFileSync56(mcpPath, "utf-8"));
|
|
@@ -77859,20 +78029,20 @@ function sha256(content) {
|
|
|
77859
78029
|
return createHash13("sha256").update(content).digest("hex").slice(0, 16);
|
|
77860
78030
|
}
|
|
77861
78031
|
function findLatestTranscriptJsonl(claudeConfigDir) {
|
|
77862
|
-
const projectsDir =
|
|
77863
|
-
if (!
|
|
78032
|
+
const projectsDir = join65(claudeConfigDir, "projects");
|
|
78033
|
+
if (!existsSync65(projectsDir))
|
|
77864
78034
|
return;
|
|
77865
78035
|
try {
|
|
77866
|
-
const entries =
|
|
78036
|
+
const entries = readdirSync23(projectsDir, { withFileTypes: true });
|
|
77867
78037
|
let latest;
|
|
77868
78038
|
for (const entry of entries) {
|
|
77869
78039
|
if (!entry.isDirectory())
|
|
77870
78040
|
continue;
|
|
77871
|
-
const projectPath =
|
|
77872
|
-
const transcriptPath =
|
|
77873
|
-
if (!
|
|
78041
|
+
const projectPath = join65(projectsDir, entry.name);
|
|
78042
|
+
const transcriptPath = join65(projectPath, "transcript.jsonl");
|
|
78043
|
+
if (!existsSync65(transcriptPath))
|
|
77874
78044
|
continue;
|
|
77875
|
-
const stat3 =
|
|
78045
|
+
const stat3 = statSync28(transcriptPath);
|
|
77876
78046
|
if (!latest || stat3.mtimeMs > latest.mtime) {
|
|
77877
78047
|
latest = { path: transcriptPath, mtime: stat3.mtimeMs };
|
|
77878
78048
|
}
|
|
@@ -77933,16 +78103,16 @@ function registerDebugCommand(program3) {
|
|
|
77933
78103
|
}
|
|
77934
78104
|
const agentsDir = resolveAgentsDir(config);
|
|
77935
78105
|
const agentDir = resolve40(agentsDir, agentName);
|
|
77936
|
-
if (!
|
|
78106
|
+
if (!existsSync65(agentDir)) {
|
|
77937
78107
|
console.error(`Agent directory not found: ${agentDir}`);
|
|
77938
78108
|
process.exit(1);
|
|
77939
78109
|
}
|
|
77940
78110
|
const workspaceDir = resolveAgentWorkspaceDir(agentDir);
|
|
77941
|
-
const claudeConfigDir =
|
|
77942
|
-
const claudeMdPath =
|
|
77943
|
-
const soulMdPath =
|
|
77944
|
-
const workspaceSoulMdPath =
|
|
77945
|
-
const handoffPath =
|
|
78111
|
+
const claudeConfigDir = join65(agentDir, ".claude");
|
|
78112
|
+
const claudeMdPath = join65(agentDir, "CLAUDE.md");
|
|
78113
|
+
const soulMdPath = join65(agentDir, "SOUL.md");
|
|
78114
|
+
const workspaceSoulMdPath = join65(workspaceDir, "SOUL.md");
|
|
78115
|
+
const handoffPath = join65(agentDir, ".handoff.md");
|
|
77946
78116
|
const lastN = parseInt(opts.last, 10);
|
|
77947
78117
|
if (isNaN(lastN) || lastN < 1) {
|
|
77948
78118
|
console.error("--last must be a positive integer");
|
|
@@ -77988,7 +78158,7 @@ function registerDebugCommand(program3) {
|
|
|
77988
78158
|
}
|
|
77989
78159
|
console.log(`=== Append System Prompt (per-session) ===
|
|
77990
78160
|
`);
|
|
77991
|
-
const handoffContent =
|
|
78161
|
+
const handoffContent = existsSync65(handoffPath) ? readFileSync56(handoffPath, "utf-8") : "";
|
|
77992
78162
|
if (handoffContent.trim().length > 0) {
|
|
77993
78163
|
console.log(`-- Handoff Briefing (${formatBytes(handoffContent.length)}) --`);
|
|
77994
78164
|
console.log(handoffContent);
|
|
@@ -77999,7 +78169,7 @@ function registerDebugCommand(program3) {
|
|
|
77999
78169
|
}
|
|
78000
78170
|
console.log(`=== CLAUDE.md (auto-loaded by Claude Code) ===
|
|
78001
78171
|
`);
|
|
78002
|
-
const claudeMdContent =
|
|
78172
|
+
const claudeMdContent = existsSync65(claudeMdPath) ? readFileSync56(claudeMdPath, "utf-8") : "";
|
|
78003
78173
|
if (claudeMdContent.trim().length > 0) {
|
|
78004
78174
|
console.log(`(${formatBytes(claudeMdContent.length)})`);
|
|
78005
78175
|
console.log(claudeMdContent);
|
|
@@ -78010,7 +78180,7 @@ function registerDebugCommand(program3) {
|
|
|
78010
78180
|
}
|
|
78011
78181
|
console.log(`=== Persona (SOUL.md) ===
|
|
78012
78182
|
`);
|
|
78013
|
-
const soulMdContent =
|
|
78183
|
+
const soulMdContent = existsSync65(soulMdPath) ? readFileSync56(soulMdPath, "utf-8") : existsSync65(workspaceSoulMdPath) ? readFileSync56(workspaceSoulMdPath, "utf-8") : "";
|
|
78014
78184
|
if (soulMdContent.trim().length > 0) {
|
|
78015
78185
|
console.log(`(${formatBytes(soulMdContent.length)})`);
|
|
78016
78186
|
console.log(soulMdContent);
|
|
@@ -78071,11 +78241,11 @@ function registerDebugCommand(program3) {
|
|
|
78071
78241
|
const soulMdBytes = soulMdContent.length;
|
|
78072
78242
|
const perTurnBytes = dynamicResult.concatenated.length;
|
|
78073
78243
|
const userBytes = userMessage?.text.length ?? 0;
|
|
78074
|
-
const fleetDir =
|
|
78075
|
-
const fleetInvPath =
|
|
78076
|
-
const fleetClaudePath =
|
|
78077
|
-
const fleetInvBytes =
|
|
78078
|
-
const fleetClaudeBytes =
|
|
78244
|
+
const fleetDir = join65(agentsDir, "..", "fleet");
|
|
78245
|
+
const fleetInvPath = join65(fleetDir, "switchroom-invariants.md");
|
|
78246
|
+
const fleetClaudePath = join65(fleetDir, "CLAUDE.md");
|
|
78247
|
+
const fleetInvBytes = existsSync65(fleetInvPath) ? readFileSync56(fleetInvPath, "utf-8").length : 0;
|
|
78248
|
+
const fleetClaudeBytes = existsSync65(fleetClaudePath) ? readFileSync56(fleetClaudePath, "utf-8").length : 0;
|
|
78079
78249
|
const fleetBytes = fleetInvBytes + fleetClaudeBytes;
|
|
78080
78250
|
const totalBytes = stableBytes + perSessionBytes + claudeMdBytes + fleetBytes + perTurnBytes + userBytes;
|
|
78081
78251
|
console.log(`Stable prefix: ${formatBytes(stableBytes).padEnd(20)} (cache-hot; includes SOUL.md ${soulMdBytes.toLocaleString()}B)`);
|
|
@@ -78108,9 +78278,9 @@ init_source();
|
|
|
78108
78278
|
|
|
78109
78279
|
// src/worktree/claim.ts
|
|
78110
78280
|
import { execFileSync as execFileSync21 } from "node:child_process";
|
|
78111
|
-
import { closeSync as closeSync12, mkdirSync as mkdirSync36, openSync as openSync12, existsSync as
|
|
78112
|
-
import { join as
|
|
78113
|
-
import { homedir as
|
|
78281
|
+
import { closeSync as closeSync12, mkdirSync as mkdirSync36, openSync as openSync12, existsSync as existsSync67, unlinkSync as unlinkSync13 } from "node:fs";
|
|
78282
|
+
import { join as join67, resolve as resolve42 } from "node:path";
|
|
78283
|
+
import { homedir as homedir40 } from "node:os";
|
|
78114
78284
|
import { randomBytes as randomBytes13 } from "node:crypto";
|
|
78115
78285
|
|
|
78116
78286
|
// src/worktree/registry.ts
|
|
@@ -78118,18 +78288,18 @@ import {
|
|
|
78118
78288
|
mkdirSync as mkdirSync35,
|
|
78119
78289
|
writeFileSync as writeFileSync31,
|
|
78120
78290
|
readFileSync as readFileSync57,
|
|
78121
|
-
readdirSync as
|
|
78291
|
+
readdirSync as readdirSync24,
|
|
78122
78292
|
unlinkSync as unlinkSync12,
|
|
78123
|
-
existsSync as
|
|
78293
|
+
existsSync as existsSync66,
|
|
78124
78294
|
renameSync as renameSync13
|
|
78125
78295
|
} from "node:fs";
|
|
78126
|
-
import { join as
|
|
78127
|
-
import { homedir as
|
|
78296
|
+
import { join as join66, resolve as resolve41 } from "node:path";
|
|
78297
|
+
import { homedir as homedir39 } from "node:os";
|
|
78128
78298
|
function registryDir() {
|
|
78129
|
-
return resolve41(process.env.SWITCHROOM_WORKTREE_DIR ??
|
|
78299
|
+
return resolve41(process.env.SWITCHROOM_WORKTREE_DIR ?? join66(homedir39(), ".switchroom", "worktrees"));
|
|
78130
78300
|
}
|
|
78131
78301
|
function recordPath(id) {
|
|
78132
|
-
return
|
|
78302
|
+
return join66(registryDir(), `${id}.json`);
|
|
78133
78303
|
}
|
|
78134
78304
|
function ensureDir2() {
|
|
78135
78305
|
mkdirSync35(registryDir(), { recursive: true });
|
|
@@ -78161,7 +78331,7 @@ function listRecords() {
|
|
|
78161
78331
|
ensureDir2();
|
|
78162
78332
|
const dir = registryDir();
|
|
78163
78333
|
const records = [];
|
|
78164
|
-
for (const entry of
|
|
78334
|
+
for (const entry of readdirSync24(dir)) {
|
|
78165
78335
|
if (!entry.endsWith(".json"))
|
|
78166
78336
|
continue;
|
|
78167
78337
|
const id = entry.slice(0, -5);
|
|
@@ -78180,7 +78350,7 @@ function acquireRepoLock(repoPath) {
|
|
|
78180
78350
|
const lockDir = registryDir();
|
|
78181
78351
|
mkdirSync36(lockDir, { recursive: true });
|
|
78182
78352
|
const lockName = repoPath.replace(/[^A-Za-z0-9]/g, "_");
|
|
78183
|
-
const lockPath =
|
|
78353
|
+
const lockPath = join67(lockDir, `.lock-${lockName}`);
|
|
78184
78354
|
const deadline = Date.now() + 5000;
|
|
78185
78355
|
let fd = null;
|
|
78186
78356
|
while (fd === null) {
|
|
@@ -78207,7 +78377,7 @@ function acquireRepoLock(repoPath) {
|
|
|
78207
78377
|
}
|
|
78208
78378
|
var DEFAULT_CONCURRENCY = 5;
|
|
78209
78379
|
function worktreesBaseDir() {
|
|
78210
|
-
return resolve42(process.env.SWITCHROOM_WORKTREE_BASE ??
|
|
78380
|
+
return resolve42(process.env.SWITCHROOM_WORKTREE_BASE ?? join67(homedir40(), ".switchroom", "worktree-checkouts"));
|
|
78211
78381
|
}
|
|
78212
78382
|
function shortId() {
|
|
78213
78383
|
return randomBytes13(4).toString("hex");
|
|
@@ -78229,12 +78399,12 @@ function resolveRepoPath(repo, codeRepos) {
|
|
|
78229
78399
|
}
|
|
78230
78400
|
function expandHome(p) {
|
|
78231
78401
|
if (p.startsWith("~/"))
|
|
78232
|
-
return
|
|
78402
|
+
return join67(homedir40(), p.slice(2));
|
|
78233
78403
|
return p;
|
|
78234
78404
|
}
|
|
78235
78405
|
async function claimWorktree(input, codeRepos) {
|
|
78236
78406
|
const repoPath = resolveRepoPath(input.repo, codeRepos);
|
|
78237
|
-
if (!
|
|
78407
|
+
if (!existsSync67(repoPath)) {
|
|
78238
78408
|
throw new Error(`Repository path does not exist: ${repoPath}`);
|
|
78239
78409
|
}
|
|
78240
78410
|
let concurrencyCap = DEFAULT_CONCURRENCY;
|
|
@@ -78257,7 +78427,7 @@ async function claimWorktree(input, codeRepos) {
|
|
|
78257
78427
|
branch = `task/${taskSuffix}-${id}`;
|
|
78258
78428
|
const baseDir = worktreesBaseDir();
|
|
78259
78429
|
mkdirSync36(baseDir, { recursive: true });
|
|
78260
|
-
worktreePath =
|
|
78430
|
+
worktreePath = join67(baseDir, `${id}-${taskSuffix}`);
|
|
78261
78431
|
const now = new Date().toISOString();
|
|
78262
78432
|
const record2 = {
|
|
78263
78433
|
id,
|
|
@@ -78288,7 +78458,7 @@ async function claimWorktree(input, codeRepos) {
|
|
|
78288
78458
|
|
|
78289
78459
|
// src/worktree/release.ts
|
|
78290
78460
|
import { execFileSync as execFileSync22 } from "node:child_process";
|
|
78291
|
-
import { existsSync as
|
|
78461
|
+
import { existsSync as existsSync68 } from "node:fs";
|
|
78292
78462
|
function releaseWorktree(input) {
|
|
78293
78463
|
const { id } = input;
|
|
78294
78464
|
const record2 = readRecord(id);
|
|
@@ -78296,7 +78466,7 @@ function releaseWorktree(input) {
|
|
|
78296
78466
|
return { released: true };
|
|
78297
78467
|
}
|
|
78298
78468
|
let gitSuccess = true;
|
|
78299
|
-
if (
|
|
78469
|
+
if (existsSync68(record2.path)) {
|
|
78300
78470
|
try {
|
|
78301
78471
|
execFileSync22("git", ["worktree", "remove", "--force", record2.path], {
|
|
78302
78472
|
cwd: record2.repo,
|
|
@@ -78335,7 +78505,7 @@ function listWorktrees() {
|
|
|
78335
78505
|
|
|
78336
78506
|
// src/worktree/reaper.ts
|
|
78337
78507
|
import { execFileSync as execFileSync23 } from "node:child_process";
|
|
78338
|
-
import { existsSync as
|
|
78508
|
+
import { existsSync as existsSync69 } from "node:fs";
|
|
78339
78509
|
var STALE_THRESHOLD_MS = 10 * 60 * 1000;
|
|
78340
78510
|
function isPathInUse(path7) {
|
|
78341
78511
|
try {
|
|
@@ -78362,7 +78532,7 @@ function hasUncommittedChanges(repoPath, worktreePath) {
|
|
|
78362
78532
|
function reapRecord(record2) {
|
|
78363
78533
|
const { id, path: path7, repo, branch, ownerAgent } = record2;
|
|
78364
78534
|
let warning = null;
|
|
78365
|
-
if (
|
|
78535
|
+
if (existsSync69(path7)) {
|
|
78366
78536
|
if (hasUncommittedChanges(repo, path7)) {
|
|
78367
78537
|
warning = `[worktree-reaper] Reaped worktree with uncommitted changes: ` + `id=${id} branch=${branch} agent=${ownerAgent ?? "unknown"} path=${path7}`;
|
|
78368
78538
|
}
|
|
@@ -78383,7 +78553,7 @@ function runReaper(nowMs) {
|
|
|
78383
78553
|
const warnings = [];
|
|
78384
78554
|
for (const record2 of records) {
|
|
78385
78555
|
const heartbeatAge = now - new Date(record2.heartbeatAt).getTime();
|
|
78386
|
-
const worktreeExists =
|
|
78556
|
+
const worktreeExists = existsSync69(record2.path);
|
|
78387
78557
|
if (!worktreeExists) {
|
|
78388
78558
|
deleteRecord(record2.id);
|
|
78389
78559
|
reaped.push(record2.id);
|
|
@@ -78508,11 +78678,11 @@ init_scaffold_integration();
|
|
|
78508
78678
|
import {
|
|
78509
78679
|
chmodSync as chmodSync9,
|
|
78510
78680
|
mkdirSync as mkdirSync37,
|
|
78511
|
-
readdirSync as
|
|
78681
|
+
readdirSync as readdirSync25,
|
|
78512
78682
|
rmSync as rmSync15,
|
|
78513
78683
|
writeFileSync as writeFileSync32
|
|
78514
78684
|
} from "node:fs";
|
|
78515
|
-
import { join as
|
|
78685
|
+
import { join as join68 } from "node:path";
|
|
78516
78686
|
function encodeCredentialsFilename(email) {
|
|
78517
78687
|
const SAFE = new Set([
|
|
78518
78688
|
..."ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
|
|
@@ -78702,16 +78872,16 @@ function resolveCredentialsDir(env2) {
|
|
|
78702
78872
|
if (explicit && explicit.length > 0)
|
|
78703
78873
|
return explicit;
|
|
78704
78874
|
const stateBase = env2.SWITCHROOM_CONTAINER === "1" ? "/state/agent" : env2.HOME ?? ".";
|
|
78705
|
-
return
|
|
78875
|
+
return join68(stateBase, "google-workspace-mcp", "credentials");
|
|
78706
78876
|
}
|
|
78707
78877
|
function writeSeedFile(dir, email, seed) {
|
|
78708
78878
|
mkdirSync37(dir, { recursive: true, mode: 448 });
|
|
78709
78879
|
chmodSync9(dir, 448);
|
|
78710
|
-
for (const name of
|
|
78711
|
-
rmSync15(
|
|
78880
|
+
for (const name of readdirSync25(dir)) {
|
|
78881
|
+
rmSync15(join68(dir, name), { force: true, recursive: true });
|
|
78712
78882
|
}
|
|
78713
78883
|
const filename = encodeCredentialsFilename(email);
|
|
78714
|
-
const filePath =
|
|
78884
|
+
const filePath = join68(dir, filename);
|
|
78715
78885
|
writeFileSync32(filePath, JSON.stringify(seed), { mode: 384 });
|
|
78716
78886
|
chmodSync9(filePath, 384);
|
|
78717
78887
|
return filePath;
|
|
@@ -78871,7 +79041,7 @@ function registerDriveMcpLauncherCommand(program3) {
|
|
|
78871
79041
|
init_scaffold_integration();
|
|
78872
79042
|
import { spawn as spawn6 } from "node:child_process";
|
|
78873
79043
|
import { writeFileSync as writeFileSync33, mkdirSync as mkdirSync38 } from "node:fs";
|
|
78874
|
-
import { dirname as
|
|
79044
|
+
import { dirname as dirname18, join as join69 } from "node:path";
|
|
78875
79045
|
var SOFTERIA_TOKEN_ENV = "MS365_MCP_OAUTH_TOKEN";
|
|
78876
79046
|
var DEFAULT_REFRESH_LEAD_MS = 5 * 60 * 1000;
|
|
78877
79047
|
var MAX_REFRESH_INTERVAL_MS = 60 * 60 * 1000;
|
|
@@ -78896,14 +79066,14 @@ function computeRefreshDelayMs(expiresAt, now, leadMs = DEFAULT_REFRESH_LEAD_MS)
|
|
|
78896
79066
|
function writeRefreshHeartbeat(agentName, data) {
|
|
78897
79067
|
const path7 = heartbeatPath(agentName);
|
|
78898
79068
|
try {
|
|
78899
|
-
mkdirSync38(
|
|
79069
|
+
mkdirSync38(dirname18(path7), { recursive: true });
|
|
78900
79070
|
writeFileSync33(path7, JSON.stringify(data, null, 2), { mode: 420 });
|
|
78901
79071
|
} catch {}
|
|
78902
79072
|
}
|
|
78903
79073
|
function heartbeatPath(agentName) {
|
|
78904
79074
|
const override = process.env.SWITCHROOM_M365_HEARTBEAT_DIR;
|
|
78905
79075
|
if (override) {
|
|
78906
|
-
return
|
|
79076
|
+
return join69(override, `m365-launcher-${agentName}.heartbeat.json`);
|
|
78907
79077
|
}
|
|
78908
79078
|
return "/state/agent/m365-launcher.heartbeat.json";
|
|
78909
79079
|
}
|
|
@@ -79088,8 +79258,8 @@ function registerM365McpLauncherCommand(program3) {
|
|
|
79088
79258
|
// src/cli/notion-mcp-launcher.ts
|
|
79089
79259
|
init_scaffold_integration();
|
|
79090
79260
|
import { spawn as spawn7 } from "node:child_process";
|
|
79091
|
-
import { existsSync as
|
|
79092
|
-
import { dirname as
|
|
79261
|
+
import { existsSync as existsSync70, mkdirSync as mkdirSync39, writeFileSync as writeFileSync34 } from "node:fs";
|
|
79262
|
+
import { dirname as dirname19 } from "node:path";
|
|
79093
79263
|
var HEARTBEAT_WRITE_INTERVAL_MS = 30 * 1000;
|
|
79094
79264
|
var DEFAULT_HEARTBEAT_PATH = "/state/agent/notion-launcher.heartbeat.json";
|
|
79095
79265
|
var DEFAULT_VAULT_KEY = "notion/integration-token";
|
|
@@ -79099,8 +79269,8 @@ function buildNotionMcpArgs(opts) {
|
|
|
79099
79269
|
}
|
|
79100
79270
|
function defaultWriteHeartbeat(path7, contents) {
|
|
79101
79271
|
try {
|
|
79102
|
-
const dir =
|
|
79103
|
-
if (!
|
|
79272
|
+
const dir = dirname19(path7);
|
|
79273
|
+
if (!existsSync70(dir))
|
|
79104
79274
|
mkdirSync39(dir, { recursive: true });
|
|
79105
79275
|
writeFileSync34(path7, contents);
|
|
79106
79276
|
} catch {}
|
|
@@ -79212,7 +79382,7 @@ function registerNotionMcpLauncherCommand(program3) {
|
|
|
79212
79382
|
|
|
79213
79383
|
// src/cli/deliver-file.ts
|
|
79214
79384
|
init_client2();
|
|
79215
|
-
import { readFileSync as readFileSync58, statSync as
|
|
79385
|
+
import { readFileSync as readFileSync58, statSync as statSync29 } from "node:fs";
|
|
79216
79386
|
import { basename as basename7 } from "node:path";
|
|
79217
79387
|
|
|
79218
79388
|
// src/delivery/onedrive.ts
|
|
@@ -79502,7 +79672,7 @@ async function defaultResolveProvider() {
|
|
|
79502
79672
|
}
|
|
79503
79673
|
async function runDeliverFile(localPath, deps = {}) {
|
|
79504
79674
|
const agentName = safeAgentName(deps.agentName ?? process.env.SWITCHROOM_AGENT_NAME);
|
|
79505
|
-
const sizeOf = deps.fileSize ?? ((p) =>
|
|
79675
|
+
const sizeOf = deps.fileSize ?? ((p) => statSync29(p).size);
|
|
79506
79676
|
const read = deps.readFile ?? ((p) => new Uint8Array(readFileSync58(p)));
|
|
79507
79677
|
const resolveProvider = deps.resolveProvider ?? defaultResolveProvider;
|
|
79508
79678
|
let size;
|
|
@@ -79793,8 +79963,8 @@ async function fetchToken(vaultKey) {
|
|
|
79793
79963
|
|
|
79794
79964
|
// src/cli/apply.ts
|
|
79795
79965
|
init_source();
|
|
79796
|
-
import { accessSync as accessSync3, chownSync as
|
|
79797
|
-
import { mkdir
|
|
79966
|
+
import { accessSync as accessSync3, chownSync as chownSync5, constants as fsConstants6, copyFileSync as copyFileSync11, existsSync as existsSync73, mkdirSync as mkdirSync41, readFileSync as readFileSync60, readdirSync as readdirSync26, renameSync as renameSync14, writeFileSync as writeFileSync36 } from "node:fs";
|
|
79967
|
+
import { mkdir as mkdir2 } from "node:fs/promises";
|
|
79798
79968
|
import { spawnSync as childSpawnSync } from "node:child_process";
|
|
79799
79969
|
import readline from "node:readline";
|
|
79800
79970
|
|
|
@@ -80182,16 +80352,16 @@ agents:
|
|
|
80182
80352
|
|
|
80183
80353
|
// src/cli/apply.ts
|
|
80184
80354
|
init_resolver();
|
|
80185
|
-
import { dirname as
|
|
80186
|
-
import { homedir as
|
|
80355
|
+
import { dirname as dirname22, join as join72, resolve as resolve44 } from "node:path";
|
|
80356
|
+
import { homedir as homedir42 } from "node:os";
|
|
80187
80357
|
import { execFileSync as execFileSync24 } from "node:child_process";
|
|
80188
80358
|
init_vault();
|
|
80189
80359
|
init_loader();
|
|
80190
80360
|
init_loader();
|
|
80191
80361
|
|
|
80192
80362
|
// src/cli/update-prompt-hook.ts
|
|
80193
|
-
import { existsSync as
|
|
80194
|
-
import { join as
|
|
80363
|
+
import { existsSync as existsSync71, readFileSync as readFileSync59, writeFileSync as writeFileSync35, chmodSync as chmodSync10, mkdirSync as mkdirSync40 } from "node:fs";
|
|
80364
|
+
import { join as join70 } from "node:path";
|
|
80195
80365
|
var HOOK_FILENAME = "update-card-on-prompt.sh";
|
|
80196
80366
|
function updatePromptHookScript() {
|
|
80197
80367
|
return `#!/bin/bash
|
|
@@ -80257,12 +80427,12 @@ exit 0
|
|
|
80257
80427
|
`;
|
|
80258
80428
|
}
|
|
80259
80429
|
function installUpdatePromptHook(agentDir) {
|
|
80260
|
-
const hooksDir =
|
|
80430
|
+
const hooksDir = join70(agentDir, ".claude", "hooks");
|
|
80261
80431
|
mkdirSync40(hooksDir, { recursive: true });
|
|
80262
|
-
const scriptPath =
|
|
80432
|
+
const scriptPath = join70(hooksDir, HOOK_FILENAME);
|
|
80263
80433
|
const desired = updatePromptHookScript();
|
|
80264
80434
|
let installed = false;
|
|
80265
|
-
const existing =
|
|
80435
|
+
const existing = existsSync71(scriptPath) ? readFileSync59(scriptPath, "utf-8") : "";
|
|
80266
80436
|
if (existing !== desired) {
|
|
80267
80437
|
writeFileSync35(scriptPath, desired, { mode: 493 });
|
|
80268
80438
|
chmodSync10(scriptPath, 493);
|
|
@@ -80272,8 +80442,8 @@ function installUpdatePromptHook(agentDir) {
|
|
|
80272
80442
|
chmodSync10(scriptPath, 493);
|
|
80273
80443
|
} catch {}
|
|
80274
80444
|
}
|
|
80275
|
-
const settingsPath =
|
|
80276
|
-
if (!
|
|
80445
|
+
const settingsPath = join70(agentDir, ".claude", "settings.json");
|
|
80446
|
+
if (!existsSync71(settingsPath)) {
|
|
80277
80447
|
return { scriptPath, settingsPath, installed };
|
|
80278
80448
|
}
|
|
80279
80449
|
const raw = readFileSync59(settingsPath, "utf-8");
|
|
@@ -80319,26 +80489,6 @@ function installUpdatePromptHook(agentDir) {
|
|
|
80319
80489
|
// src/cli/apply.ts
|
|
80320
80490
|
init_compose();
|
|
80321
80491
|
|
|
80322
|
-
// src/config/release-resolve.ts
|
|
80323
|
-
function resolveImageTag(release) {
|
|
80324
|
-
if (!release)
|
|
80325
|
-
return "latest";
|
|
80326
|
-
if (release.pin)
|
|
80327
|
-
return release.pin;
|
|
80328
|
-
if (release.channel)
|
|
80329
|
-
return release.channel;
|
|
80330
|
-
return "latest";
|
|
80331
|
-
}
|
|
80332
|
-
function resolveRelease(opts) {
|
|
80333
|
-
if (opts.override)
|
|
80334
|
-
return opts.override;
|
|
80335
|
-
if (opts.perAgent)
|
|
80336
|
-
return opts.perAgent;
|
|
80337
|
-
if (opts.root)
|
|
80338
|
-
return opts.root;
|
|
80339
|
-
return;
|
|
80340
|
-
}
|
|
80341
|
-
|
|
80342
80492
|
// src/cli/install-detect.ts
|
|
80343
80493
|
import * as fs4 from "node:fs";
|
|
80344
80494
|
import * as path7 from "node:path";
|
|
@@ -80389,107 +80539,17 @@ function detectInstallType() {
|
|
|
80389
80539
|
}
|
|
80390
80540
|
}
|
|
80391
80541
|
|
|
80392
|
-
// src/cli/operator-uid.ts
|
|
80393
|
-
import {
|
|
80394
|
-
chownSync as chownSync3,
|
|
80395
|
-
existsSync as existsSync72,
|
|
80396
|
-
lstatSync as lstatSync7,
|
|
80397
|
-
readdirSync as readdirSync25,
|
|
80398
|
-
realpathSync as realpathSync6,
|
|
80399
|
-
statSync as statSync29
|
|
80400
|
-
} from "node:fs";
|
|
80401
|
-
import { join as join71 } from "node:path";
|
|
80402
|
-
function resolveOperatorUid() {
|
|
80403
|
-
const sudoUid = process.env.SUDO_UID;
|
|
80404
|
-
if (sudoUid !== undefined) {
|
|
80405
|
-
const parsed = parseInt(sudoUid, 10);
|
|
80406
|
-
if (Number.isFinite(parsed) && parsed > 0)
|
|
80407
|
-
return parsed;
|
|
80408
|
-
}
|
|
80409
|
-
if (typeof process.getuid === "function") {
|
|
80410
|
-
const uid = process.getuid();
|
|
80411
|
-
if (uid > 0)
|
|
80412
|
-
return uid;
|
|
80413
|
-
}
|
|
80414
|
-
return;
|
|
80415
|
-
}
|
|
80416
|
-
function operatorOwnedPaths(home2) {
|
|
80417
|
-
const root = join71(home2, ".switchroom");
|
|
80418
|
-
return [
|
|
80419
|
-
join71(root, "vault"),
|
|
80420
|
-
join71(root, "vault-auto-unlock"),
|
|
80421
|
-
join71(root, "vault-audit.log"),
|
|
80422
|
-
join71(root, "host-control-audit.log"),
|
|
80423
|
-
join71(root, "accounts"),
|
|
80424
|
-
join71(root, "compose")
|
|
80425
|
-
];
|
|
80426
|
-
}
|
|
80427
|
-
function restoreOperatorOwnership(home2, operatorUid, deps = {}) {
|
|
80428
|
-
const chown = deps.chown ?? ((p, u, g) => chownSync3(p, u, g));
|
|
80429
|
-
const exists = deps.exists ?? ((p) => existsSync72(p));
|
|
80430
|
-
const isSymlink = deps.isSymlink ?? ((p) => {
|
|
80431
|
-
try {
|
|
80432
|
-
return lstatSync7(p).isSymbolicLink();
|
|
80433
|
-
} catch {
|
|
80434
|
-
return false;
|
|
80435
|
-
}
|
|
80436
|
-
});
|
|
80437
|
-
const isDir = deps.isDir ?? ((p) => {
|
|
80438
|
-
try {
|
|
80439
|
-
return statSync29(p).isDirectory();
|
|
80440
|
-
} catch {
|
|
80441
|
-
return false;
|
|
80442
|
-
}
|
|
80443
|
-
});
|
|
80444
|
-
const realpath2 = deps.realpath ?? ((p) => {
|
|
80445
|
-
try {
|
|
80446
|
-
return realpathSync6(p);
|
|
80447
|
-
} catch {
|
|
80448
|
-
return p;
|
|
80449
|
-
}
|
|
80450
|
-
});
|
|
80451
|
-
const readdir2 = deps.readdir ?? ((p) => {
|
|
80452
|
-
try {
|
|
80453
|
-
return readdirSync25(p);
|
|
80454
|
-
} catch {
|
|
80455
|
-
return [];
|
|
80456
|
-
}
|
|
80457
|
-
});
|
|
80458
|
-
const chowned = [];
|
|
80459
|
-
const seen = new Set;
|
|
80460
|
-
const visit = (path8) => {
|
|
80461
|
-
if (!exists(path8))
|
|
80462
|
-
return;
|
|
80463
|
-
const target = isSymlink(path8) ? realpath2(path8) : path8;
|
|
80464
|
-
if (seen.has(target))
|
|
80465
|
-
return;
|
|
80466
|
-
seen.add(target);
|
|
80467
|
-
try {
|
|
80468
|
-
chown(target, operatorUid, operatorUid);
|
|
80469
|
-
chowned.push(target);
|
|
80470
|
-
} catch {}
|
|
80471
|
-
if (isDir(target)) {
|
|
80472
|
-
for (const entry of readdir2(target)) {
|
|
80473
|
-
visit(join71(target, entry));
|
|
80474
|
-
}
|
|
80475
|
-
}
|
|
80476
|
-
};
|
|
80477
|
-
for (const p of operatorOwnedPaths(home2))
|
|
80478
|
-
visit(p);
|
|
80479
|
-
return chowned;
|
|
80480
|
-
}
|
|
80481
|
-
|
|
80482
80542
|
// src/cli/apply.ts
|
|
80483
80543
|
var EMBEDDED_EXAMPLES = {
|
|
80484
80544
|
switchroom: switchroom_default,
|
|
80485
80545
|
minimal: minimal_default
|
|
80486
80546
|
};
|
|
80487
|
-
var DEFAULT_COMPOSE_PATH2 = join72(
|
|
80547
|
+
var DEFAULT_COMPOSE_PATH2 = join72(homedir42(), ".switchroom", "compose", "docker-compose.yml");
|
|
80488
80548
|
var COMPOSE_PROJECT2 = "switchroom";
|
|
80489
80549
|
function resolveVaultBindMountDir(homeDir, ctx) {
|
|
80490
80550
|
const isCustomPath = ctx.migrationKind === "custom-path-skipped";
|
|
80491
80551
|
if (isCustomPath && ctx.customVaultPath) {
|
|
80492
|
-
return
|
|
80552
|
+
return dirname22(ctx.customVaultPath);
|
|
80493
80553
|
}
|
|
80494
80554
|
return join72(homeDir, ".switchroom", "vault");
|
|
80495
80555
|
}
|
|
@@ -80520,7 +80580,7 @@ function hasVaultRefs(value) {
|
|
|
80520
80580
|
return false;
|
|
80521
80581
|
}
|
|
80522
80582
|
async function ensureHostMountSources(config) {
|
|
80523
|
-
const home2 =
|
|
80583
|
+
const home2 = homedir42();
|
|
80524
80584
|
const dirs = [
|
|
80525
80585
|
join72(home2, ".switchroom", "approvals"),
|
|
80526
80586
|
join72(home2, ".switchroom", "scheduler"),
|
|
@@ -80538,7 +80598,7 @@ async function ensureHostMountSources(config) {
|
|
|
80538
80598
|
}
|
|
80539
80599
|
}
|
|
80540
80600
|
for (const dir of dirs) {
|
|
80541
|
-
await
|
|
80601
|
+
await mkdir2(dir, { recursive: true });
|
|
80542
80602
|
}
|
|
80543
80603
|
const autoUnlockPath = join72(home2, ".switchroom", "vault-auto-unlock");
|
|
80544
80604
|
if (!existsSync73(autoUnlockPath)) {
|
|
@@ -80563,11 +80623,11 @@ async function ensureHostMountSources(config) {
|
|
|
80563
80623
|
}
|
|
80564
80624
|
try {
|
|
80565
80625
|
const uid = allocateAgentUid(name);
|
|
80566
|
-
|
|
80626
|
+
chownSync5(tokenPath, uid, uid);
|
|
80567
80627
|
} catch {}
|
|
80568
80628
|
}
|
|
80569
80629
|
const fleetDir = join72(home2, ".switchroom", "fleet");
|
|
80570
|
-
await
|
|
80630
|
+
await mkdir2(fleetDir, { recursive: true });
|
|
80571
80631
|
const invariantsPath = join72(fleetDir, "switchroom-invariants.md");
|
|
80572
80632
|
const invariantsCanonical = renderFleetInvariants();
|
|
80573
80633
|
const invariantsCurrent = existsSync73(invariantsPath) ? readFileSync60(invariantsPath, "utf-8") : null;
|
|
@@ -80657,7 +80717,7 @@ function detectAndReportLegacyGdriveSlots(vaultPath) {
|
|
|
80657
80717
|
`));
|
|
80658
80718
|
}
|
|
80659
80719
|
}
|
|
80660
|
-
function writeInstallTypeCache(homeDir =
|
|
80720
|
+
function writeInstallTypeCache(homeDir = homedir42()) {
|
|
80661
80721
|
const ctx = detectInstallType();
|
|
80662
80722
|
const dir = join72(homeDir, ".switchroom");
|
|
80663
80723
|
const out = join72(dir, "install-type.json");
|
|
@@ -80767,7 +80827,7 @@ Applying switchroom config...
|
|
|
80767
80827
|
}
|
|
80768
80828
|
const vaultPathConfigured = config.vault?.path;
|
|
80769
80829
|
const customVaultPath = vaultPathConfigured ? resolvePath(vaultPathConfigured) : undefined;
|
|
80770
|
-
const migrationResult = migrateVaultLayout(
|
|
80830
|
+
const migrationResult = migrateVaultLayout(homedir42(), {
|
|
80771
80831
|
customVaultPath
|
|
80772
80832
|
});
|
|
80773
80833
|
switch (migrationResult.kind) {
|
|
@@ -80793,7 +80853,7 @@ Applying switchroom config...
|
|
|
80793
80853
|
writeErr(formatDivergentRecoveryMessage(migrationResult.details));
|
|
80794
80854
|
process.exit(4);
|
|
80795
80855
|
}
|
|
80796
|
-
const postMigrationInspect = inspectVaultLayout(
|
|
80856
|
+
const postMigrationInspect = inspectVaultLayout(homedir42());
|
|
80797
80857
|
const acceptable = [
|
|
80798
80858
|
"no-vault",
|
|
80799
80859
|
"already-migrated",
|
|
@@ -80808,7 +80868,7 @@ Applying switchroom config...
|
|
|
80808
80868
|
`));
|
|
80809
80869
|
process.exit(5);
|
|
80810
80870
|
}
|
|
80811
|
-
const vaultDir = resolveVaultBindMountDir(
|
|
80871
|
+
const vaultDir = resolveVaultBindMountDir(homedir42(), {
|
|
80812
80872
|
migrationKind: migrationResult.kind,
|
|
80813
80873
|
customVaultPath
|
|
80814
80874
|
});
|
|
@@ -80828,26 +80888,14 @@ Applying switchroom config...
|
|
|
80828
80888
|
}
|
|
80829
80889
|
const composePath = options.outPath ?? DEFAULT_COMPOSE_PATH2;
|
|
80830
80890
|
const operatorUid = resolveOperatorUid();
|
|
80831
|
-
const
|
|
80832
|
-
override: options.releaseOverride,
|
|
80833
|
-
root: config.release
|
|
80834
|
-
});
|
|
80835
|
-
const composeImageTag = resolveImageTag(composeRelease);
|
|
80836
|
-
const composeContent = generateCompose({
|
|
80891
|
+
const { bytes: composeBytes } = await writeComposeFile({
|
|
80837
80892
|
config,
|
|
80838
|
-
|
|
80839
|
-
buildMode: options.buildLocal ? "local" : "pull",
|
|
80840
|
-
buildContext: options.buildContext,
|
|
80841
|
-
homeDir: homedir41(),
|
|
80893
|
+
composePath,
|
|
80842
80894
|
switchroomConfigPath,
|
|
80843
|
-
|
|
80844
|
-
|
|
80845
|
-
|
|
80846
|
-
await writeFile(composePath, composeContent, {
|
|
80847
|
-
encoding: "utf8",
|
|
80848
|
-
mode: 384
|
|
80895
|
+
releaseOverride: options.releaseOverride,
|
|
80896
|
+
buildMode: options.buildLocal ? "local" : "pull",
|
|
80897
|
+
buildContext: options.buildContext
|
|
80849
80898
|
});
|
|
80850
|
-
const composeBytes = Buffer.byteLength(composeContent, "utf8");
|
|
80851
80899
|
writeOut(source_default.bold(`
|
|
80852
80900
|
Wrote `) + composePath + source_default.gray(` (${composeBytes} bytes)
|
|
80853
80901
|
`));
|
|
@@ -80858,7 +80906,7 @@ Wrote `) + composePath + source_default.gray(` (${composeBytes} bytes)
|
|
|
80858
80906
|
writeOut(source_default.gray(` (If pull returns 401, login to ghcr.io first: see docs/operators/install.md#ghcr-auth)
|
|
80859
80907
|
`));
|
|
80860
80908
|
if (process.geteuid?.() === 0 && operatorUid !== undefined) {
|
|
80861
|
-
const restored = restoreOperatorOwnership(
|
|
80909
|
+
const restored = restoreOperatorOwnership(homedir42(), operatorUid);
|
|
80862
80910
|
if (restored.length > 0) {
|
|
80863
80911
|
writeOut(source_default.gray(` Restored operator ownership of ${restored.length} ~/.switchroom path(s)
|
|
80864
80912
|
`));
|
|
@@ -81109,7 +81157,7 @@ function runRedactStdin() {
|
|
|
81109
81157
|
// src/cli/status-ask.ts
|
|
81110
81158
|
import { readFileSync as readFileSync61, existsSync as existsSync74, readdirSync as readdirSync27 } from "node:fs";
|
|
81111
81159
|
import { join as join73 } from "node:path";
|
|
81112
|
-
import { homedir as
|
|
81160
|
+
import { homedir as homedir43 } from "node:os";
|
|
81113
81161
|
|
|
81114
81162
|
// src/status-ask/report.ts
|
|
81115
81163
|
function parseJsonl(content) {
|
|
@@ -81444,7 +81492,7 @@ function resolveSources(explicitPath) {
|
|
|
81444
81492
|
const config = loadConfig();
|
|
81445
81493
|
agentsDir = resolveAgentsDir(config);
|
|
81446
81494
|
} catch {
|
|
81447
|
-
agentsDir = join73(
|
|
81495
|
+
agentsDir = join73(homedir43(), ".switchroom", "agents");
|
|
81448
81496
|
}
|
|
81449
81497
|
if (!existsSync74(agentsDir))
|
|
81450
81498
|
return [];
|
|
@@ -81479,14 +81527,14 @@ function inferAgentFromPath(p) {
|
|
|
81479
81527
|
// src/cli/agent-config.ts
|
|
81480
81528
|
init_helpers();
|
|
81481
81529
|
import { join as join74 } from "node:path";
|
|
81482
|
-
import { homedir as
|
|
81530
|
+
import { homedir as homedir44 } from "node:os";
|
|
81483
81531
|
import {
|
|
81484
81532
|
existsSync as existsSync75,
|
|
81485
81533
|
mkdirSync as mkdirSync42,
|
|
81486
81534
|
appendFileSync as appendFileSync4,
|
|
81487
81535
|
readFileSync as readFileSync62
|
|
81488
81536
|
} from "node:fs";
|
|
81489
|
-
var AUDIT_ROOT = join74(
|
|
81537
|
+
var AUDIT_ROOT = join74(homedir44(), ".switchroom", "audit");
|
|
81490
81538
|
function auditPathFor(agent) {
|
|
81491
81539
|
return join74(AUDIT_ROOT, agent, "agent-config.jsonl");
|
|
81492
81540
|
}
|
|
@@ -82986,8 +83034,8 @@ import {
|
|
|
82986
83034
|
statSync as statSync31,
|
|
82987
83035
|
writeFileSync as writeFileSync38
|
|
82988
83036
|
} from "node:fs";
|
|
82989
|
-
import { tmpdir as tmpdir5, homedir as
|
|
82990
|
-
import { dirname as
|
|
83037
|
+
import { tmpdir as tmpdir5, homedir as homedir45 } from "node:os";
|
|
83038
|
+
import { dirname as dirname23, join as join78, relative as relative2, resolve as resolve46 } from "node:path";
|
|
82991
83039
|
import { spawnSync as spawnSync11 } from "node:child_process";
|
|
82992
83040
|
|
|
82993
83041
|
// src/cli/skill-common.ts
|
|
@@ -83181,10 +83229,10 @@ function scanForClaudeP2(content) {
|
|
|
83181
83229
|
function resolveSkillsPoolDir2(override) {
|
|
83182
83230
|
const raw = override ?? "~/.switchroom/skills";
|
|
83183
83231
|
if (raw.startsWith("~/")) {
|
|
83184
|
-
return join78(
|
|
83232
|
+
return join78(homedir45(), raw.slice(2));
|
|
83185
83233
|
}
|
|
83186
83234
|
if (raw === "~")
|
|
83187
|
-
return
|
|
83235
|
+
return homedir45();
|
|
83188
83236
|
return resolve46(raw);
|
|
83189
83237
|
}
|
|
83190
83238
|
function readStdinSync() {
|
|
@@ -83417,7 +83465,7 @@ function writePayload(poolDir, name, files) {
|
|
|
83417
83465
|
try {
|
|
83418
83466
|
for (const [path8, content] of Object.entries(files)) {
|
|
83419
83467
|
const full = join78(staging, path8);
|
|
83420
|
-
mkdirSync45(
|
|
83468
|
+
mkdirSync45(dirname23(full), { recursive: true, mode: 493 });
|
|
83421
83469
|
const fd = openSync15(full, "wx");
|
|
83422
83470
|
try {
|
|
83423
83471
|
writeFileSync38(fd, content);
|
|
@@ -83538,8 +83586,8 @@ import {
|
|
|
83538
83586
|
utimesSync,
|
|
83539
83587
|
writeFileSync as writeFileSync39
|
|
83540
83588
|
} from "node:fs";
|
|
83541
|
-
import { dirname as
|
|
83542
|
-
import { homedir as
|
|
83589
|
+
import { dirname as dirname24, join as join79, relative as relative3, resolve as resolve47 } from "node:path";
|
|
83590
|
+
import { homedir as homedir46, tmpdir as tmpdir6 } from "node:os";
|
|
83543
83591
|
import { spawnSync as spawnSync12 } from "node:child_process";
|
|
83544
83592
|
init_helpers();
|
|
83545
83593
|
init_source();
|
|
@@ -83549,7 +83597,7 @@ var TRASH_TTL_MS = 24 * 60 * 60 * 1000;
|
|
|
83549
83597
|
var PERSONAL_SKILLS_SUBPATH = "personal-skills";
|
|
83550
83598
|
function resolveConfigSkillsDir(agent) {
|
|
83551
83599
|
const override = process.env.SWITCHROOM_CONFIG_DIR;
|
|
83552
|
-
const candidate = override ? resolve47(override) : join79(
|
|
83600
|
+
const candidate = override ? resolve47(override) : join79(homedir46(), ".switchroom-config");
|
|
83553
83601
|
if (!existsSync81(candidate))
|
|
83554
83602
|
return null;
|
|
83555
83603
|
return join79(candidate, "agents", agent, PERSONAL_SKILLS_SUBPATH);
|
|
@@ -83645,7 +83693,7 @@ function resolveAgent(opts) {
|
|
|
83645
83693
|
function resolveAgentsRoot(opts) {
|
|
83646
83694
|
if (opts.root)
|
|
83647
83695
|
return resolve47(opts.root);
|
|
83648
|
-
return join79(
|
|
83696
|
+
return join79(homedir46(), ".switchroom", "agents");
|
|
83649
83697
|
}
|
|
83650
83698
|
function personalSkillDir(agentsRoot, agent, name) {
|
|
83651
83699
|
return join79(agentsRoot, agent, ".claude", "skills", PERSONAL_PREFIX + name);
|
|
@@ -83779,13 +83827,13 @@ function writePersonalSkill(targetDir, files) {
|
|
|
83779
83827
|
if (targetIsSymlink) {
|
|
83780
83828
|
fail3(`refusing to overwrite symlink at ${targetDir}; investigate manually`);
|
|
83781
83829
|
}
|
|
83782
|
-
mkdirSync46(
|
|
83783
|
-
const staging = mkdtempSync6(join79(
|
|
83830
|
+
mkdirSync46(dirname24(targetDir), { recursive: true, mode: 493 });
|
|
83831
|
+
const staging = mkdtempSync6(join79(dirname24(targetDir), `.skill-personal-stage-`));
|
|
83784
83832
|
let oldRename = null;
|
|
83785
83833
|
try {
|
|
83786
83834
|
for (const [path8, content] of Object.entries(files)) {
|
|
83787
83835
|
const full = join79(staging, path8);
|
|
83788
|
-
mkdirSync46(
|
|
83836
|
+
mkdirSync46(dirname24(full), { recursive: true, mode: 493 });
|
|
83789
83837
|
const fd = openSync16(full, "wx");
|
|
83790
83838
|
try {
|
|
83791
83839
|
writeFileSync39(fd, content);
|
|
@@ -83917,10 +83965,10 @@ function editPersonalAction(name, opts) {
|
|
|
83917
83965
|
}
|
|
83918
83966
|
var CLONE_SOURCE_RE = /^(shared|bundled):([a-z0-9][a-z0-9_-]{0,62})$/;
|
|
83919
83967
|
function defaultSharedRoot() {
|
|
83920
|
-
return join79(
|
|
83968
|
+
return join79(homedir46(), ".switchroom", "skills");
|
|
83921
83969
|
}
|
|
83922
83970
|
function defaultBundledRoot() {
|
|
83923
|
-
return join79(
|
|
83971
|
+
return join79(homedir46(), ".switchroom", "skills", "_bundled");
|
|
83924
83972
|
}
|
|
83925
83973
|
function resolveCloneSource(source, opts) {
|
|
83926
83974
|
const m = CLONE_SOURCE_RE.exec(source);
|
|
@@ -84136,19 +84184,19 @@ function registerSkillPersonalCommands(program3) {
|
|
|
84136
84184
|
init_helpers();
|
|
84137
84185
|
var import_yaml23 = __toESM(require_dist(), 1);
|
|
84138
84186
|
import { existsSync as existsSync82, readdirSync as readdirSync32, readFileSync as readFileSync68, statSync as statSync33 } from "node:fs";
|
|
84139
|
-
import { homedir as
|
|
84187
|
+
import { homedir as homedir47 } from "node:os";
|
|
84140
84188
|
import { join as join80, resolve as resolve48 } from "node:path";
|
|
84141
84189
|
var PERSONAL_PREFIX2 = "personal-";
|
|
84142
84190
|
var BUNDLED_SUBDIR = "_bundled";
|
|
84143
84191
|
var AGENT_NAME_RE3 = /^[a-z][a-z0-9_-]{0,62}$/;
|
|
84144
84192
|
function defaultAgentsRoot() {
|
|
84145
|
-
return resolve48(
|
|
84193
|
+
return resolve48(homedir47(), ".switchroom/agents");
|
|
84146
84194
|
}
|
|
84147
84195
|
function defaultSharedRoot2() {
|
|
84148
|
-
return resolve48(
|
|
84196
|
+
return resolve48(homedir47(), ".switchroom/skills");
|
|
84149
84197
|
}
|
|
84150
84198
|
function defaultBundledRoot2() {
|
|
84151
|
-
return resolve48(
|
|
84199
|
+
return resolve48(homedir47(), ".switchroom/skills/_bundled");
|
|
84152
84200
|
}
|
|
84153
84201
|
function readSkillFrontmatter(skillDir) {
|
|
84154
84202
|
const mdPath = join80(skillDir, "SKILL.md");
|
|
@@ -84429,7 +84477,7 @@ function registerHostdMcpCommand(program3) {
|
|
|
84429
84477
|
init_source();
|
|
84430
84478
|
init_helpers();
|
|
84431
84479
|
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";
|
|
84432
|
-
import { homedir as
|
|
84480
|
+
import { homedir as homedir48 } from "node:os";
|
|
84433
84481
|
import { join as join81 } from "node:path";
|
|
84434
84482
|
import { spawnSync as spawnSync14 } from "node:child_process";
|
|
84435
84483
|
init_audit_reader();
|
|
@@ -84521,7 +84569,7 @@ networks:
|
|
|
84521
84569
|
`;
|
|
84522
84570
|
}
|
|
84523
84571
|
function hostdDir() {
|
|
84524
|
-
return join81(
|
|
84572
|
+
return join81(homedir48(), ".switchroom", "hostd");
|
|
84525
84573
|
}
|
|
84526
84574
|
function hostdComposePath() {
|
|
84527
84575
|
return join81(hostdDir(), "docker-compose.yml");
|
|
@@ -84563,7 +84611,7 @@ async function doInstall(opts, program3) {
|
|
|
84563
84611
|
const composePath = hostdComposePath();
|
|
84564
84612
|
mkdirSync47(dir, { recursive: true });
|
|
84565
84613
|
const yaml = renderHostdComposeFile({
|
|
84566
|
-
hostHome:
|
|
84614
|
+
hostHome: homedir48(),
|
|
84567
84615
|
imageTag: opts.tag ?? DEFAULT_IMAGE_TAG,
|
|
84568
84616
|
operatorUid: resolveOperatorUid()
|
|
84569
84617
|
});
|
|
@@ -84726,7 +84774,7 @@ The log is created when hostd handles its first privileged-verb request.`));
|
|
|
84726
84774
|
init_source();
|
|
84727
84775
|
init_helpers();
|
|
84728
84776
|
import { existsSync as existsSync85, mkdirSync as mkdirSync48, writeFileSync as writeFileSync41, copyFileSync as copyFileSync13 } from "node:fs";
|
|
84729
|
-
import { homedir as
|
|
84777
|
+
import { homedir as homedir49 } from "node:os";
|
|
84730
84778
|
import { join as join82 } from "node:path";
|
|
84731
84779
|
import { spawnSync as spawnSync15 } from "node:child_process";
|
|
84732
84780
|
var DEFAULT_IMAGE_TAG2 = "latest";
|
|
@@ -84808,7 +84856,7 @@ services:
|
|
|
84808
84856
|
`;
|
|
84809
84857
|
}
|
|
84810
84858
|
function webdDir() {
|
|
84811
|
-
return join82(
|
|
84859
|
+
return join82(homedir49(), ".switchroom", "web");
|
|
84812
84860
|
}
|
|
84813
84861
|
function webdComposePath() {
|
|
84814
84862
|
return join82(webdDir(), "docker-compose.yml");
|
|
@@ -84842,7 +84890,7 @@ async function doInstall2(opts) {
|
|
|
84842
84890
|
const composePath = webdComposePath();
|
|
84843
84891
|
mkdirSync48(dir, { recursive: true });
|
|
84844
84892
|
const yaml = renderWebComposeFile({
|
|
84845
|
-
hostHome:
|
|
84893
|
+
hostHome: homedir49(),
|
|
84846
84894
|
imageTag: opts.tag ?? DEFAULT_IMAGE_TAG2,
|
|
84847
84895
|
operatorUid
|
|
84848
84896
|
});
|