switchroom 0.13.58 → 0.13.59
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 +451 -343
- package/package.json +1 -1
- package/telegram-plugin/dist/gateway/gateway.js +252 -310
- package/telegram-plugin/gateway/gateway.ts +0 -35
package/dist/cli/switchroom.js
CHANGED
|
@@ -29659,19 +29659,123 @@ var init_doctor_drive = __esm(() => {
|
|
|
29659
29659
|
init_doctor_secret_access();
|
|
29660
29660
|
});
|
|
29661
29661
|
|
|
29662
|
+
// src/cli/doctor-scaffold-wiring.ts
|
|
29663
|
+
import { join as join45, resolve as resolve30 } from "node:path";
|
|
29664
|
+
function readJson2(d, path4) {
|
|
29665
|
+
if (!d.existsSync(path4))
|
|
29666
|
+
return { kind: "absent" };
|
|
29667
|
+
let raw;
|
|
29668
|
+
try {
|
|
29669
|
+
raw = d.readFileSync(path4);
|
|
29670
|
+
} catch (err) {
|
|
29671
|
+
const code = err?.code;
|
|
29672
|
+
if (code === "EACCES" || code === "EPERM")
|
|
29673
|
+
return { kind: "unreadable" };
|
|
29674
|
+
return { kind: "absent" };
|
|
29675
|
+
}
|
|
29676
|
+
try {
|
|
29677
|
+
return { kind: "ok", data: JSON.parse(raw) };
|
|
29678
|
+
} catch {
|
|
29679
|
+
return { kind: "corrupt" };
|
|
29680
|
+
}
|
|
29681
|
+
}
|
|
29682
|
+
function checkIntegrationScaffoldWiring(args) {
|
|
29683
|
+
const { label, mcpKey, agents, agentsDir, deps } = args;
|
|
29684
|
+
const results = [];
|
|
29685
|
+
if (agents.length === 0)
|
|
29686
|
+
return results;
|
|
29687
|
+
if (agentsDir === undefined) {
|
|
29688
|
+
return [
|
|
29689
|
+
{
|
|
29690
|
+
name: `${label}: scaffold wiring`,
|
|
29691
|
+
status: "warn",
|
|
29692
|
+
detail: "could not resolve the agents directory (no switchroom block) \u2014 skipped scaffold wiring check"
|
|
29693
|
+
}
|
|
29694
|
+
];
|
|
29695
|
+
}
|
|
29696
|
+
for (const name of agents) {
|
|
29697
|
+
const agentDir = resolve30(agentsDir, name);
|
|
29698
|
+
if (!deps.existsSync(agentDir)) {
|
|
29699
|
+
results.push({
|
|
29700
|
+
name: `${label}: ${name} scaffold`,
|
|
29701
|
+
status: "warn",
|
|
29702
|
+
detail: `${agentDir} not scaffolded yet \u2014 run \`switchroom apply\``
|
|
29703
|
+
});
|
|
29704
|
+
continue;
|
|
29705
|
+
}
|
|
29706
|
+
const mcpPath = join45(agentDir, ".mcp.json");
|
|
29707
|
+
const claudeJsonPath = join45(agentDir, ".claude", ".claude.json");
|
|
29708
|
+
const mcpRead = readJson2(deps, mcpPath);
|
|
29709
|
+
const trustRead = readJson2(deps, claudeJsonPath);
|
|
29710
|
+
if (mcpRead.kind === "unreadable" || trustRead.kind === "unreadable") {
|
|
29711
|
+
results.push({
|
|
29712
|
+
name: `${label}: ${name} scaffold`,
|
|
29713
|
+
status: "skip",
|
|
29714
|
+
detail: "scaffold files are agent-UID-owned (mode 0600) \u2014 unverifiable from the host operator; the agent process reads them fine. Verify in-container if needed: `docker exec switchroom-" + name + " sh -lc 'python3 -m json.tool /state/agent/.mcp.json >/dev/null && echo ok'`"
|
|
29715
|
+
});
|
|
29716
|
+
continue;
|
|
29717
|
+
}
|
|
29718
|
+
let mcpOk = false;
|
|
29719
|
+
let mcpDetail = `no .mcp.json`;
|
|
29720
|
+
if (mcpRead.kind === "ok") {
|
|
29721
|
+
const mcpServers = mcpRead.data?.mcpServers ?? {};
|
|
29722
|
+
const entry = mcpServers[mcpKey];
|
|
29723
|
+
if (!entry) {
|
|
29724
|
+
mcpDetail = `.mcp.json has no ${mcpKey} server`;
|
|
29725
|
+
} else if (!entry.env || Object.keys(entry.env).length === 0) {
|
|
29726
|
+
mcpDetail = `${mcpKey} entry has no env block \u2014 Claude spawns MCP with a sanitized env; the launcher can't reach switchroom.yaml/the broker (bug-8 class)`;
|
|
29727
|
+
} else {
|
|
29728
|
+
mcpOk = true;
|
|
29729
|
+
}
|
|
29730
|
+
} else if (mcpRead.kind === "corrupt") {
|
|
29731
|
+
mcpDetail = ".mcp.json exists but is not valid JSON (corrupt)";
|
|
29732
|
+
}
|
|
29733
|
+
let trustOk = false;
|
|
29734
|
+
let trustDetail = "no .claude/.claude.json";
|
|
29735
|
+
if (trustRead.kind === "ok") {
|
|
29736
|
+
const projects = trustRead.data?.projects ?? {};
|
|
29737
|
+
const proj = projects[resolve30(agentDir)];
|
|
29738
|
+
const enabled = proj?.enabledMcpjsonServers;
|
|
29739
|
+
if (Array.isArray(enabled) && enabled.includes(mcpKey)) {
|
|
29740
|
+
trustOk = true;
|
|
29741
|
+
} else {
|
|
29742
|
+
trustDetail = `${mcpKey} not in projects[].enabledMcpjsonServers \u2014 Claude silently ignores the un-allowlisted server (bug-9 / scaffold-ordering class)`;
|
|
29743
|
+
}
|
|
29744
|
+
} else if (trustRead.kind === "corrupt") {
|
|
29745
|
+
trustDetail = ".claude.json exists but is not valid JSON (corrupt)";
|
|
29746
|
+
}
|
|
29747
|
+
if (mcpOk && trustOk) {
|
|
29748
|
+
results.push({
|
|
29749
|
+
name: `${label}: ${name} scaffold`,
|
|
29750
|
+
status: "ok",
|
|
29751
|
+
detail: `${mcpKey} wired in .mcp.json (with env) and trusted in .claude.json`
|
|
29752
|
+
});
|
|
29753
|
+
} else {
|
|
29754
|
+
results.push({
|
|
29755
|
+
name: `${label}: ${name} scaffold`,
|
|
29756
|
+
status: "fail",
|
|
29757
|
+
detail: !mcpOk ? mcpDetail : trustDetail,
|
|
29758
|
+
fix: "`switchroom agent restart " + name + "` (reconcile regenerates .mcp.json + re-trusts); if it persists, this is a scaffold bug \u2014 report it"
|
|
29759
|
+
});
|
|
29760
|
+
}
|
|
29761
|
+
}
|
|
29762
|
+
return results;
|
|
29763
|
+
}
|
|
29764
|
+
var init_doctor_scaffold_wiring = () => {};
|
|
29765
|
+
|
|
29662
29766
|
// src/cli/doctor-microsoft.ts
|
|
29663
29767
|
import {
|
|
29664
29768
|
existsSync as realExistsSync2,
|
|
29665
29769
|
readFileSync as realReadFileSync2
|
|
29666
29770
|
} from "node:fs";
|
|
29667
|
-
import { join as
|
|
29771
|
+
import { join as join46 } from "node:path";
|
|
29668
29772
|
import { homedir as homedir25 } from "node:os";
|
|
29669
29773
|
function resolveDeps2(deps) {
|
|
29670
29774
|
const home2 = deps.homeDir?.() ?? homedir25();
|
|
29671
29775
|
return {
|
|
29672
29776
|
existsSync: deps.existsSync ?? realExistsSync2,
|
|
29673
29777
|
readFileSync: deps.readFileSync ?? realReadFileSync2,
|
|
29674
|
-
agentsDir:
|
|
29778
|
+
agentsDir: join46(home2, ".switchroom", "agents"),
|
|
29675
29779
|
now: deps.now ?? Date.now
|
|
29676
29780
|
};
|
|
29677
29781
|
}
|
|
@@ -29765,7 +29869,7 @@ function checkOAuthClient2(config, anyAgentEnabled) {
|
|
|
29765
29869
|
];
|
|
29766
29870
|
}
|
|
29767
29871
|
function readHeartbeat(d, agentName) {
|
|
29768
|
-
const path4 =
|
|
29872
|
+
const path4 = join46(d.agentsDir, agentName, "m365-launcher.heartbeat.json");
|
|
29769
29873
|
if (!d.existsSync(path4)) {
|
|
29770
29874
|
return { error: "heartbeat file missing \u2014 launcher has not yet started" };
|
|
29771
29875
|
}
|
|
@@ -29840,9 +29944,21 @@ function runMicrosoftChecks(config, deps = {}) {
|
|
|
29840
29944
|
const msAgents = computeMicrosoftEnabledAgents(config);
|
|
29841
29945
|
results.push(...checkOAuthClient2(config, msAgents.length > 0));
|
|
29842
29946
|
results.push(...checkLauncherHeartbeat(msAgents, d));
|
|
29947
|
+
results.push(...checkIntegrationScaffoldWiring({
|
|
29948
|
+
label: "microsoft",
|
|
29949
|
+
mcpKey: "ms-365",
|
|
29950
|
+
agents: msAgents,
|
|
29951
|
+
agentsDir: d.agentsDir,
|
|
29952
|
+
deps: {
|
|
29953
|
+
existsSync: d.existsSync,
|
|
29954
|
+
readFileSync: (path4) => d.readFileSync(path4, "utf-8")
|
|
29955
|
+
}
|
|
29956
|
+
}));
|
|
29843
29957
|
return results;
|
|
29844
29958
|
}
|
|
29845
|
-
var init_doctor_microsoft = () => {
|
|
29959
|
+
var init_doctor_microsoft = __esm(() => {
|
|
29960
|
+
init_doctor_scaffold_wiring();
|
|
29961
|
+
});
|
|
29846
29962
|
|
|
29847
29963
|
// src/cli/doctor-notion.ts
|
|
29848
29964
|
import {
|
|
@@ -29850,7 +29966,7 @@ import {
|
|
|
29850
29966
|
readFileSync as realReadFileSync3,
|
|
29851
29967
|
statSync as realStatSync
|
|
29852
29968
|
} from "node:fs";
|
|
29853
|
-
import { join as
|
|
29969
|
+
import { join as join47 } from "node:path";
|
|
29854
29970
|
import { homedir as homedir26 } from "node:os";
|
|
29855
29971
|
function resolveDeps3(deps) {
|
|
29856
29972
|
const home2 = deps.homeDir?.() ?? homedir26();
|
|
@@ -29858,7 +29974,7 @@ function resolveDeps3(deps) {
|
|
|
29858
29974
|
existsSync: deps.existsSync ?? realExistsSync3,
|
|
29859
29975
|
readFileSync: deps.readFileSync ?? realReadFileSync3,
|
|
29860
29976
|
statSync: deps.statSync ?? realStatSync,
|
|
29861
|
-
agentsDir:
|
|
29977
|
+
agentsDir: join47(home2, ".switchroom", "agents"),
|
|
29862
29978
|
now: deps.now ?? Date.now,
|
|
29863
29979
|
vaultAclReader: deps.vaultAclReader ?? (async () => ({ kind: "unreachable", msg: "no default reader wired" }))
|
|
29864
29980
|
};
|
|
@@ -29983,7 +30099,7 @@ function checkLauncherHeartbeat2(notionAgents, d) {
|
|
|
29983
30099
|
return [];
|
|
29984
30100
|
const results = [];
|
|
29985
30101
|
for (const name of notionAgents) {
|
|
29986
|
-
const heartbeatPath =
|
|
30102
|
+
const heartbeatPath = join47(d.agentsDir, name, "notion-launcher.heartbeat.json");
|
|
29987
30103
|
if (!d.existsSync(heartbeatPath)) {
|
|
29988
30104
|
results.push({
|
|
29989
30105
|
name: `notion:launcher-heartbeat:${name}`,
|
|
@@ -30033,11 +30149,22 @@ async function runNotionChecks(config, deps = {}) {
|
|
|
30033
30149
|
if (notionAgents.length > 0 && config.notion_workspace) {
|
|
30034
30150
|
results.push(...await checkVaultAclAligned(config, notionAgents, d));
|
|
30035
30151
|
results.push(...checkLauncherHeartbeat2(notionAgents, d));
|
|
30152
|
+
results.push(...checkIntegrationScaffoldWiring({
|
|
30153
|
+
label: "notion",
|
|
30154
|
+
mcpKey: "notion",
|
|
30155
|
+
agents: notionAgents,
|
|
30156
|
+
agentsDir: d.agentsDir,
|
|
30157
|
+
deps: {
|
|
30158
|
+
existsSync: d.existsSync,
|
|
30159
|
+
readFileSync: (path4) => d.readFileSync(path4, "utf-8")
|
|
30160
|
+
}
|
|
30161
|
+
}));
|
|
30036
30162
|
}
|
|
30037
30163
|
return results;
|
|
30038
30164
|
}
|
|
30039
30165
|
var HEARTBEAT_STALE_MS;
|
|
30040
30166
|
var init_doctor_notion = __esm(() => {
|
|
30167
|
+
init_doctor_scaffold_wiring();
|
|
30041
30168
|
HEARTBEAT_STALE_MS = 60 * 1000;
|
|
30042
30169
|
});
|
|
30043
30170
|
|
|
@@ -30048,9 +30175,9 @@ import {
|
|
|
30048
30175
|
statSync as realStatSync2
|
|
30049
30176
|
} from "node:fs";
|
|
30050
30177
|
import { homedir as homedir27 } from "node:os";
|
|
30051
|
-
import { join as
|
|
30178
|
+
import { join as join48 } from "node:path";
|
|
30052
30179
|
function runCredentialsMigrationChecks(config, deps = {}) {
|
|
30053
|
-
const credDir = deps.credentialsDir ??
|
|
30180
|
+
const credDir = deps.credentialsDir ?? join48(homedir27(), ".switchroom", "credentials");
|
|
30054
30181
|
const existsSync49 = deps.existsSync ?? ((p) => realExistsSync4(p));
|
|
30055
30182
|
const readdirSync19 = deps.readdirSync ?? ((p) => realReaddirSync(p));
|
|
30056
30183
|
const isDirectory = deps.isDirectory ?? ((p) => {
|
|
@@ -30078,7 +30205,7 @@ function runCredentialsMigrationChecks(config, deps = {}) {
|
|
|
30078
30205
|
const flat = [];
|
|
30079
30206
|
const perAgentDirs = [];
|
|
30080
30207
|
for (const e of entries) {
|
|
30081
|
-
const full =
|
|
30208
|
+
const full = join48(credDir, e);
|
|
30082
30209
|
if (isDirectory(full) && agentNames.has(e)) {
|
|
30083
30210
|
perAgentDirs.push(e);
|
|
30084
30211
|
} else {
|
|
@@ -30202,13 +30329,13 @@ var init_doctor_inlined_secrets = __esm(() => {
|
|
|
30202
30329
|
// src/cli/doctor-audit-integrity.ts
|
|
30203
30330
|
import { readFileSync as fsReadFileSync2 } from "node:fs";
|
|
30204
30331
|
import { homedir as homedir28 } from "node:os";
|
|
30205
|
-
import { join as
|
|
30332
|
+
import { join as join49 } from "node:path";
|
|
30206
30333
|
function rootWrittenLogs(home2) {
|
|
30207
30334
|
return [
|
|
30208
|
-
{ label: "vault-broker", path:
|
|
30335
|
+
{ label: "vault-broker", path: join49(home2, ".switchroom", "vault-audit.log") },
|
|
30209
30336
|
{
|
|
30210
30337
|
label: "hostd",
|
|
30211
|
-
path:
|
|
30338
|
+
path: join49(home2, ".switchroom", "host-control-audit.log")
|
|
30212
30339
|
}
|
|
30213
30340
|
];
|
|
30214
30341
|
}
|
|
@@ -30273,7 +30400,7 @@ var init_doctor_audit_integrity = __esm(() => {
|
|
|
30273
30400
|
import { connect as connect2 } from "node:net";
|
|
30274
30401
|
async function hostdRequest(opts, req) {
|
|
30275
30402
|
const timeoutMs = opts.timeoutMs ?? 5000;
|
|
30276
|
-
return new Promise((
|
|
30403
|
+
return new Promise((resolve31, reject) => {
|
|
30277
30404
|
const socket = connect2(opts.socketPath);
|
|
30278
30405
|
let buf = "";
|
|
30279
30406
|
let settled = false;
|
|
@@ -30319,7 +30446,7 @@ async function hostdRequest(opts, req) {
|
|
|
30319
30446
|
settled = true;
|
|
30320
30447
|
clearTimeout(timer);
|
|
30321
30448
|
socket.end();
|
|
30322
|
-
|
|
30449
|
+
resolve31(resp);
|
|
30323
30450
|
} catch (err) {
|
|
30324
30451
|
if (settled)
|
|
30325
30452
|
return;
|
|
@@ -30352,13 +30479,13 @@ var init_client4 = __esm(() => {
|
|
|
30352
30479
|
// src/cli/doctor-agent-smoke.ts
|
|
30353
30480
|
import { existsSync as existsSync49 } from "node:fs";
|
|
30354
30481
|
import { homedir as homedir29 } from "node:os";
|
|
30355
|
-
import { join as
|
|
30482
|
+
import { join as join50 } from "node:path";
|
|
30356
30483
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
30357
30484
|
async function runAgentSmokeChecks(config, deps = {}) {
|
|
30358
30485
|
if (deps.fast)
|
|
30359
30486
|
return [];
|
|
30360
30487
|
const home2 = deps.homeDir ?? homedir29();
|
|
30361
|
-
const sock = deps.operatorSockPath ??
|
|
30488
|
+
const sock = deps.operatorSockPath ?? join50(home2, ".switchroom", "hostd", "operator", "sock");
|
|
30362
30489
|
if (!deps.hostdRequestImpl && !existsSync49(sock)) {
|
|
30363
30490
|
return [
|
|
30364
30491
|
{
|
|
@@ -30439,7 +30566,7 @@ var init_doctor_agent_smoke = __esm(() => {
|
|
|
30439
30566
|
import { execFileSync as execFileSync14 } from "node:child_process";
|
|
30440
30567
|
import { existsSync as existsSync50, statSync as statSync22 } from "node:fs";
|
|
30441
30568
|
import { homedir as homedir30 } from "node:os";
|
|
30442
|
-
import { join as
|
|
30569
|
+
import { join as join51 } from "node:path";
|
|
30443
30570
|
function probeBindMountInode(hostPath, brokerContainerPath, opts) {
|
|
30444
30571
|
const statHost = opts?.statHost ?? defaultStatHost;
|
|
30445
30572
|
const statBroker = opts?.statBroker ?? defaultStatBroker;
|
|
@@ -30585,13 +30712,13 @@ function runVaultBrokerDurabilityChecks(_config, opts) {
|
|
|
30585
30712
|
probeBrokerUnlocked(opts?.statusProbe),
|
|
30586
30713
|
probeAutoUnlockBlob(home2),
|
|
30587
30714
|
probeMachineIdMount(),
|
|
30588
|
-
formatBindMountResult("vault-broker: vault.enc bind mount",
|
|
30589
|
-
formatBindMountResult("vault-broker: vault-grants.db bind mount (#1737)",
|
|
30590
|
-
formatBindMountResult("vault-broker: vault-audit.log bind mount (#1025)",
|
|
30715
|
+
formatBindMountResult("vault-broker: vault.enc bind mount", join51(home2, ".switchroom", "vault", "vault.enc"), "/state/vault/vault.enc", probe2(join51(home2, ".switchroom", "vault", "vault.enc"), "/state/vault/vault.enc")),
|
|
30716
|
+
formatBindMountResult("vault-broker: vault-grants.db bind mount (#1737)", join51(home2, ".switchroom", "vault-grants.db"), "/root/.switchroom/vault-grants.db", probe2(join51(home2, ".switchroom", "vault-grants.db"), "/root/.switchroom/vault-grants.db")),
|
|
30717
|
+
formatBindMountResult("vault-broker: vault-audit.log bind mount (#1025)", join51(home2, ".switchroom", "vault-audit.log"), "/root/.switchroom/vault-audit.log", probe2(join51(home2, ".switchroom", "vault-audit.log"), "/root/.switchroom/vault-audit.log"))
|
|
30591
30718
|
];
|
|
30592
30719
|
}
|
|
30593
30720
|
function probeAutoUnlockBlob(home2) {
|
|
30594
|
-
const blobPath =
|
|
30721
|
+
const blobPath = join51(home2, ".switchroom", "vault-auto-unlock");
|
|
30595
30722
|
if (!existsSync50(blobPath)) {
|
|
30596
30723
|
return {
|
|
30597
30724
|
name: "vault-broker: auto-unlock blob",
|
|
@@ -30702,16 +30829,16 @@ import {
|
|
|
30702
30829
|
readdirSync as readdirSync19,
|
|
30703
30830
|
statSync as statSync23
|
|
30704
30831
|
} from "node:fs";
|
|
30705
|
-
import { dirname as dirname12, join as
|
|
30832
|
+
import { dirname as dirname12, join as join52, resolve as resolve31 } from "node:path";
|
|
30706
30833
|
import { createPublicKey, createPrivateKey } from "node:crypto";
|
|
30707
30834
|
function findInNvm(bin) {
|
|
30708
|
-
const nvmRoot =
|
|
30835
|
+
const nvmRoot = join52(process.env.HOME ?? "", ".nvm", "versions", "node");
|
|
30709
30836
|
if (!existsSync51(nvmRoot))
|
|
30710
30837
|
return null;
|
|
30711
30838
|
try {
|
|
30712
30839
|
const versions = readdirSync19(nvmRoot).sort().reverse();
|
|
30713
30840
|
for (const v of versions) {
|
|
30714
|
-
const candidate =
|
|
30841
|
+
const candidate = join52(nvmRoot, v, "bin", bin);
|
|
30715
30842
|
try {
|
|
30716
30843
|
const s = statSync23(candidate);
|
|
30717
30844
|
if (s.isFile() || s.isSymbolicLink()) {
|
|
@@ -30876,7 +31003,7 @@ function findChromium(homeDir = process.env.HOME ?? "", envBrowsersPath = proces
|
|
|
30876
31003
|
if (envBrowsersPath && envBrowsersPath.length > 0) {
|
|
30877
31004
|
cacheLocations.push(envBrowsersPath);
|
|
30878
31005
|
}
|
|
30879
|
-
cacheLocations.push(
|
|
31006
|
+
cacheLocations.push(join52(homeDir, ".cache", "ms-playwright"));
|
|
30880
31007
|
for (const cacheDir of cacheLocations) {
|
|
30881
31008
|
if (!existsSync51(cacheDir))
|
|
30882
31009
|
continue;
|
|
@@ -30884,10 +31011,10 @@ function findChromium(homeDir = process.env.HOME ?? "", envBrowsersPath = proces
|
|
|
30884
31011
|
const entries = readdirSync19(cacheDir).filter((e) => e.startsWith("chromium"));
|
|
30885
31012
|
for (const entry of entries) {
|
|
30886
31013
|
const candidates2 = [
|
|
30887
|
-
|
|
30888
|
-
|
|
30889
|
-
|
|
30890
|
-
|
|
31014
|
+
join52(cacheDir, entry, "chrome-linux64", "chrome"),
|
|
31015
|
+
join52(cacheDir, entry, "chrome-linux", "chrome"),
|
|
31016
|
+
join52(cacheDir, entry, "chrome-linux64", "headless_shell"),
|
|
31017
|
+
join52(cacheDir, entry, "chrome-linux", "headless_shell")
|
|
30891
31018
|
];
|
|
30892
31019
|
for (const path4 of candidates2) {
|
|
30893
31020
|
if (existsSync51(path4))
|
|
@@ -30997,7 +31124,7 @@ function checkUserDeclaredMcps(name, agentConfig, config, renderedMcpServers) {
|
|
|
30997
31124
|
function checkLegacyState() {
|
|
30998
31125
|
const results = [];
|
|
30999
31126
|
const h = process.env.HOME ?? "/root";
|
|
31000
|
-
const clerkDir =
|
|
31127
|
+
const clerkDir = join52(h, LEGACY_STATE_DIR);
|
|
31001
31128
|
const clerkPresent = existsSync51(clerkDir);
|
|
31002
31129
|
results.push({
|
|
31003
31130
|
name: "legacy ~/.clerk state",
|
|
@@ -31007,7 +31134,7 @@ function checkLegacyState() {
|
|
|
31007
31134
|
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."
|
|
31008
31135
|
} : {}
|
|
31009
31136
|
});
|
|
31010
|
-
const legacySock =
|
|
31137
|
+
const legacySock = join52(h, ".switchroom", "vault-broker.sock");
|
|
31011
31138
|
let sockStat = null;
|
|
31012
31139
|
try {
|
|
31013
31140
|
sockStat = lstatSync5(legacySock);
|
|
@@ -31303,7 +31430,7 @@ async function checkHindsight(config) {
|
|
|
31303
31430
|
}
|
|
31304
31431
|
function checkPendingRetainsQueue(dir) {
|
|
31305
31432
|
const home2 = process.env.HOME ?? "";
|
|
31306
|
-
const pendingDir = dir ?? process.env.HINDSIGHT_PENDING_DIR ??
|
|
31433
|
+
const pendingDir = dir ?? process.env.HINDSIGHT_PENDING_DIR ?? join52(home2, ".hindsight", "pending-retains");
|
|
31307
31434
|
if (!existsSync51(pendingDir)) {
|
|
31308
31435
|
return {
|
|
31309
31436
|
name: "pending-retains queue",
|
|
@@ -31434,7 +31561,7 @@ async function checkTelegram(config) {
|
|
|
31434
31561
|
const plugin = agentConfig.channels?.telegram?.plugin ?? "switchroom";
|
|
31435
31562
|
if (plugin !== "switchroom")
|
|
31436
31563
|
continue;
|
|
31437
|
-
const envPath =
|
|
31564
|
+
const envPath = join52(agentsDir, name, "telegram", ".env");
|
|
31438
31565
|
const read = tryReadHostFile(envPath);
|
|
31439
31566
|
if (read.kind === "eacces") {
|
|
31440
31567
|
results.push({
|
|
@@ -31517,7 +31644,7 @@ function checkStartShStale(agentName, startShPath) {
|
|
|
31517
31644
|
}
|
|
31518
31645
|
function checkLeakedHomeSwitchroom(agentName, agentDir) {
|
|
31519
31646
|
const label = `${agentName}: $HOME/.switchroom symlink (#910)`;
|
|
31520
|
-
const path4 =
|
|
31647
|
+
const path4 = join52(agentDir, "home", ".switchroom");
|
|
31521
31648
|
let stats;
|
|
31522
31649
|
try {
|
|
31523
31650
|
stats = lstatSync5(path4);
|
|
@@ -31554,7 +31681,7 @@ function checkLeakedHomeSwitchroom(agentName, agentDir) {
|
|
|
31554
31681
|
}
|
|
31555
31682
|
function checkRepoHygiene(repoRoot) {
|
|
31556
31683
|
const results = [];
|
|
31557
|
-
const exportDir =
|
|
31684
|
+
const exportDir = join52(repoRoot, "clerk-export");
|
|
31558
31685
|
if (existsSync51(exportDir)) {
|
|
31559
31686
|
results.push({
|
|
31560
31687
|
name: "repo hygiene: clerk-export/ on disk (#1072)",
|
|
@@ -31563,7 +31690,7 @@ function checkRepoHygiene(repoRoot) {
|
|
|
31563
31690
|
fix: `Run scripts/migrate-clerk-export-to-vault.sh to move the bundle ` + `into the vault, then delete the on-disk copy.`
|
|
31564
31691
|
});
|
|
31565
31692
|
}
|
|
31566
|
-
const knownTarball =
|
|
31693
|
+
const knownTarball = join52(repoRoot, "clerk-export-with-secrets.tar.gz");
|
|
31567
31694
|
if (existsSync51(knownTarball)) {
|
|
31568
31695
|
results.push({
|
|
31569
31696
|
name: "repo hygiene: clerk-export-with-secrets.tar.gz on disk (#1072)",
|
|
@@ -31581,7 +31708,7 @@ function checkRepoHygiene(repoRoot) {
|
|
|
31581
31708
|
results.push({
|
|
31582
31709
|
name: `repo hygiene: ${name} on disk (#1072)`,
|
|
31583
31710
|
status: "warn",
|
|
31584
|
-
detail: `${
|
|
31711
|
+
detail: `${join52(repoRoot, name)} matches the *-with-secrets*.tar.gz ` + `pattern. Likely contains real credentials.`,
|
|
31585
31712
|
fix: `Inspect, migrate any secrets into the vault, then delete the ` + `archive.`
|
|
31586
31713
|
});
|
|
31587
31714
|
}
|
|
@@ -31604,9 +31731,9 @@ function checkRepoHygiene(repoRoot) {
|
|
|
31604
31731
|
}
|
|
31605
31732
|
function isSwitchroomCheckout(dir) {
|
|
31606
31733
|
try {
|
|
31607
|
-
if (!existsSync51(
|
|
31734
|
+
if (!existsSync51(join52(dir, ".git")))
|
|
31608
31735
|
return false;
|
|
31609
|
-
const pkgPath =
|
|
31736
|
+
const pkgPath = join52(dir, "package.json");
|
|
31610
31737
|
if (!existsSync51(pkgPath))
|
|
31611
31738
|
return false;
|
|
31612
31739
|
const pkg = JSON.parse(readFileSync46(pkgPath, "utf-8"));
|
|
@@ -31621,7 +31748,7 @@ function checkAgents(config, configPath) {
|
|
|
31621
31748
|
const statuses = getAllAgentStatuses(config);
|
|
31622
31749
|
const authStatuses = getAllAuthStatuses(config);
|
|
31623
31750
|
for (const [name, agentConfig] of Object.entries(config.agents)) {
|
|
31624
|
-
const agentDir =
|
|
31751
|
+
const agentDir = resolve31(agentsDir, name);
|
|
31625
31752
|
if (!existsSync51(agentDir)) {
|
|
31626
31753
|
results.push({
|
|
31627
31754
|
name: `${name}: scaffold`,
|
|
@@ -31643,7 +31770,7 @@ function checkAgents(config, configPath) {
|
|
|
31643
31770
|
fix: `Rotate the bot token (e.g. via \`switchroom vault\`), then run ` + `\`switchroom agent unquarantine ${name}\` and \`switchroom agent restart ${name}\``
|
|
31644
31771
|
});
|
|
31645
31772
|
}
|
|
31646
|
-
results.push(checkStartShStale(name,
|
|
31773
|
+
results.push(checkStartShStale(name, join52(agentDir, "start.sh")));
|
|
31647
31774
|
results.push(checkLeakedHomeSwitchroom(name, agentDir));
|
|
31648
31775
|
const status = statuses[name];
|
|
31649
31776
|
const active = status?.active ?? "unknown";
|
|
@@ -31720,7 +31847,7 @@ function checkAgents(config, configPath) {
|
|
|
31720
31847
|
}
|
|
31721
31848
|
}
|
|
31722
31849
|
if (agentConfig.channels?.telegram?.plugin === "switchroom") {
|
|
31723
|
-
const mcpJsonPath =
|
|
31850
|
+
const mcpJsonPath = join52(agentDir, ".mcp.json");
|
|
31724
31851
|
if (!existsSync51(mcpJsonPath)) {
|
|
31725
31852
|
results.push({
|
|
31726
31853
|
name: `${name}: .mcp.json`,
|
|
@@ -31804,7 +31931,7 @@ function mffAgentName(config) {
|
|
|
31804
31931
|
function mffEnvPath(config) {
|
|
31805
31932
|
const home2 = process.env.HOME ?? "/root";
|
|
31806
31933
|
const agent = mffAgentName(config);
|
|
31807
|
-
return agent ?
|
|
31934
|
+
return agent ? resolve31(home2, ".switchroom/credentials", agent, "my-family-finance/.env") : resolve31(home2, ".switchroom/credentials/my-family-finance/.env");
|
|
31808
31935
|
}
|
|
31809
31936
|
function mffEnvState(envPath) {
|
|
31810
31937
|
if (!existsSync51(envPath))
|
|
@@ -32022,7 +32149,7 @@ async function checkMffAuthFlow(envPath = mffEnvPath(), timeoutMs = 8000) {
|
|
|
32022
32149
|
};
|
|
32023
32150
|
}
|
|
32024
32151
|
const credDir = dirname12(envPath);
|
|
32025
|
-
const authScript =
|
|
32152
|
+
const authScript = join52(credDir, "claude-auth.py");
|
|
32026
32153
|
if (!existsSync51(authScript)) {
|
|
32027
32154
|
return {
|
|
32028
32155
|
name: "mff: auth flow",
|
|
@@ -32220,14 +32347,14 @@ async function checkManifestDrift(probers) {
|
|
|
32220
32347
|
return results;
|
|
32221
32348
|
}
|
|
32222
32349
|
function runDockerSection(config) {
|
|
32223
|
-
const composePath =
|
|
32350
|
+
const composePath = resolve31(process.env.HOME ?? "", ".switchroom", "compose", "docker-compose.yml");
|
|
32224
32351
|
const active = isDockerMode({ composePath });
|
|
32225
32352
|
let composeYaml;
|
|
32226
32353
|
let dockerfileAgent;
|
|
32227
32354
|
try {
|
|
32228
32355
|
composeYaml = readFileSync46(composePath, "utf8");
|
|
32229
32356
|
} catch {}
|
|
32230
|
-
const dockerfilePath =
|
|
32357
|
+
const dockerfilePath = resolve31(process.env.HOME ?? "", ".switchroom", "docker", "Dockerfile.agent");
|
|
32231
32358
|
try {
|
|
32232
32359
|
dockerfileAgent = readFileSync46(dockerfilePath, "utf8");
|
|
32233
32360
|
} catch {}
|
|
@@ -40594,7 +40721,7 @@ class Protocol {
|
|
|
40594
40721
|
return;
|
|
40595
40722
|
}
|
|
40596
40723
|
const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1000;
|
|
40597
|
-
await new Promise((
|
|
40724
|
+
await new Promise((resolve48) => setTimeout(resolve48, pollInterval));
|
|
40598
40725
|
options?.signal?.throwIfAborted();
|
|
40599
40726
|
}
|
|
40600
40727
|
} catch (error2) {
|
|
@@ -40606,7 +40733,7 @@ class Protocol {
|
|
|
40606
40733
|
}
|
|
40607
40734
|
request(request, resultSchema, options) {
|
|
40608
40735
|
const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
|
|
40609
|
-
return new Promise((
|
|
40736
|
+
return new Promise((resolve48, reject) => {
|
|
40610
40737
|
const earlyReject = (error2) => {
|
|
40611
40738
|
reject(error2);
|
|
40612
40739
|
};
|
|
@@ -40684,7 +40811,7 @@ class Protocol {
|
|
|
40684
40811
|
if (!parseResult.success) {
|
|
40685
40812
|
reject(parseResult.error);
|
|
40686
40813
|
} else {
|
|
40687
|
-
|
|
40814
|
+
resolve48(parseResult.data);
|
|
40688
40815
|
}
|
|
40689
40816
|
} catch (error2) {
|
|
40690
40817
|
reject(error2);
|
|
@@ -40875,12 +41002,12 @@ class Protocol {
|
|
|
40875
41002
|
interval = task.pollInterval;
|
|
40876
41003
|
}
|
|
40877
41004
|
} catch {}
|
|
40878
|
-
return new Promise((
|
|
41005
|
+
return new Promise((resolve48, reject) => {
|
|
40879
41006
|
if (signal.aborted) {
|
|
40880
41007
|
reject(new McpError(ErrorCode2.InvalidRequest, "Request cancelled"));
|
|
40881
41008
|
return;
|
|
40882
41009
|
}
|
|
40883
|
-
const timeoutId = setTimeout(
|
|
41010
|
+
const timeoutId = setTimeout(resolve48, interval);
|
|
40884
41011
|
signal.addEventListener("abort", () => {
|
|
40885
41012
|
clearTimeout(timeoutId);
|
|
40886
41013
|
reject(new McpError(ErrorCode2.InvalidRequest, "Request cancelled"));
|
|
@@ -43865,7 +43992,7 @@ var require_compile = __commonJS((exports2) => {
|
|
|
43865
43992
|
const schOrFunc = root.refs[ref];
|
|
43866
43993
|
if (schOrFunc)
|
|
43867
43994
|
return schOrFunc;
|
|
43868
|
-
let _sch =
|
|
43995
|
+
let _sch = resolve48.call(this, root, ref);
|
|
43869
43996
|
if (_sch === undefined) {
|
|
43870
43997
|
const schema = (_a = root.localRefs) === null || _a === undefined ? undefined : _a[ref];
|
|
43871
43998
|
const { schemaId } = this.opts;
|
|
@@ -43892,7 +44019,7 @@ var require_compile = __commonJS((exports2) => {
|
|
|
43892
44019
|
function sameSchemaEnv(s1, s2) {
|
|
43893
44020
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
43894
44021
|
}
|
|
43895
|
-
function
|
|
44022
|
+
function resolve48(root, ref) {
|
|
43896
44023
|
let sch;
|
|
43897
44024
|
while (typeof (sch = this.refs[ref]) == "string")
|
|
43898
44025
|
ref = sch;
|
|
@@ -44422,7 +44549,7 @@ var require_fast_uri = __commonJS((exports2, module) => {
|
|
|
44422
44549
|
}
|
|
44423
44550
|
return uri;
|
|
44424
44551
|
}
|
|
44425
|
-
function
|
|
44552
|
+
function resolve48(baseURI, relativeURI, options) {
|
|
44426
44553
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
44427
44554
|
const resolved = resolveComponent(parse6(baseURI, schemelessOptions), parse6(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
44428
44555
|
schemelessOptions.skipEscape = true;
|
|
@@ -44650,7 +44777,7 @@ var require_fast_uri = __commonJS((exports2, module) => {
|
|
|
44650
44777
|
var fastUri = {
|
|
44651
44778
|
SCHEMES,
|
|
44652
44779
|
normalize,
|
|
44653
|
-
resolve:
|
|
44780
|
+
resolve: resolve48,
|
|
44654
44781
|
resolveComponent,
|
|
44655
44782
|
equal,
|
|
44656
44783
|
serialize,
|
|
@@ -48033,12 +48160,12 @@ class StdioServerTransport {
|
|
|
48033
48160
|
this.onclose?.();
|
|
48034
48161
|
}
|
|
48035
48162
|
send(message) {
|
|
48036
|
-
return new Promise((
|
|
48163
|
+
return new Promise((resolve48) => {
|
|
48037
48164
|
const json = serializeMessage(message);
|
|
48038
48165
|
if (this._stdout.write(json)) {
|
|
48039
|
-
|
|
48166
|
+
resolve48();
|
|
48040
48167
|
} else {
|
|
48041
|
-
this._stdout.once("drain",
|
|
48168
|
+
this._stdout.once("drain", resolve48);
|
|
48042
48169
|
}
|
|
48043
48170
|
});
|
|
48044
48171
|
}
|
|
@@ -48930,8 +49057,8 @@ var {
|
|
|
48930
49057
|
} = import__.default;
|
|
48931
49058
|
|
|
48932
49059
|
// src/build-info.ts
|
|
48933
|
-
var VERSION = "0.13.
|
|
48934
|
-
var COMMIT_SHA = "
|
|
49060
|
+
var VERSION = "0.13.59";
|
|
49061
|
+
var COMMIT_SHA = "0f0b953e";
|
|
48935
49062
|
|
|
48936
49063
|
// src/cli/agent.ts
|
|
48937
49064
|
init_source();
|
|
@@ -50475,6 +50602,26 @@ function resolveNotionMcpEntry(agentName, agentConfig, switchroomConfig) {
|
|
|
50475
50602
|
};
|
|
50476
50603
|
return entry;
|
|
50477
50604
|
}
|
|
50605
|
+
var INTEGRATION_MCP_RESOLVERS = [
|
|
50606
|
+
{
|
|
50607
|
+
label: "Google Workspace",
|
|
50608
|
+
emitKey: "gdrive",
|
|
50609
|
+
retractionKey: "gdrive",
|
|
50610
|
+
resolve: resolveGdriveMcpEntry
|
|
50611
|
+
},
|
|
50612
|
+
{
|
|
50613
|
+
label: "Microsoft 365",
|
|
50614
|
+
emitKey: "ms-365",
|
|
50615
|
+
retractionKey: "ms-365",
|
|
50616
|
+
resolve: resolveMs365McpEntry
|
|
50617
|
+
},
|
|
50618
|
+
{
|
|
50619
|
+
label: "Notion",
|
|
50620
|
+
emitKey: "notion",
|
|
50621
|
+
retractionKey: "notion",
|
|
50622
|
+
resolve: resolveNotionMcpEntry
|
|
50623
|
+
}
|
|
50624
|
+
];
|
|
50478
50625
|
function scaffoldAgent(name, agentConfigRaw, agentsDir, telegramConfig, switchroomConfig, userIdOverride, switchroomConfigPath) {
|
|
50479
50626
|
const agentConfig = resolveAgentConfig(switchroomConfig?.defaults, switchroomConfig?.profiles, agentConfigRaw);
|
|
50480
50627
|
const agentDir = resolve10(agentsDir, name);
|
|
@@ -50583,18 +50730,10 @@ function scaffoldAgent(name, agentConfigRaw, agentsDir, telegramConfig, switchro
|
|
|
50583
50730
|
settings.mcpServers[entry.key] = entry.value;
|
|
50584
50731
|
}
|
|
50585
50732
|
}
|
|
50586
|
-
{
|
|
50587
|
-
const
|
|
50588
|
-
if (
|
|
50589
|
-
settings.mcpServers[
|
|
50590
|
-
}
|
|
50591
|
-
const ms365 = resolveMs365McpEntry(name, agentConfig, switchroomConfig);
|
|
50592
|
-
if (ms365 && !settings.mcpServers[ms365.key]) {
|
|
50593
|
-
settings.mcpServers[ms365.key] = ms365.value;
|
|
50594
|
-
}
|
|
50595
|
-
const notion = resolveNotionMcpEntry(name, agentConfig, switchroomConfig);
|
|
50596
|
-
if (notion && !settings.mcpServers[notion.key]) {
|
|
50597
|
-
settings.mcpServers[notion.key] = notion.value;
|
|
50733
|
+
for (const integration of INTEGRATION_MCP_RESOLVERS) {
|
|
50734
|
+
const entry = integration.resolve(name, agentConfig, switchroomConfig);
|
|
50735
|
+
if (entry && !settings.mcpServers[entry.key]) {
|
|
50736
|
+
settings.mcpServers[entry.key] = entry.value;
|
|
50598
50737
|
}
|
|
50599
50738
|
}
|
|
50600
50739
|
installHindsightPlugin(name, agentDir, switchroomConfig);
|
|
@@ -50661,17 +50800,11 @@ function scaffoldAgent(name, agentConfigRaw, agentsDir, telegramConfig, switchro
|
|
|
50661
50800
|
}
|
|
50662
50801
|
}
|
|
50663
50802
|
if (switchroomConfig) {
|
|
50664
|
-
const
|
|
50665
|
-
|
|
50666
|
-
|
|
50667
|
-
|
|
50668
|
-
|
|
50669
|
-
if (ms365) {
|
|
50670
|
-
mcpServers[ms365.key] = ms365.value;
|
|
50671
|
-
}
|
|
50672
|
-
const notion = resolveNotionMcpEntry(name, agentConfig, switchroomConfig);
|
|
50673
|
-
if (notion) {
|
|
50674
|
-
mcpServers[notion.key] = notion.value;
|
|
50803
|
+
for (const integration of INTEGRATION_MCP_RESOLVERS) {
|
|
50804
|
+
const entry = integration.resolve(name, agentConfig, switchroomConfig);
|
|
50805
|
+
if (entry) {
|
|
50806
|
+
mcpServers[entry.key] = entry.value;
|
|
50807
|
+
}
|
|
50675
50808
|
}
|
|
50676
50809
|
}
|
|
50677
50810
|
if (agentConfig.mcp_servers) {
|
|
@@ -51075,15 +51208,6 @@ function buildSettingsHooksBlock(p) {
|
|
|
51075
51208
|
}
|
|
51076
51209
|
]
|
|
51077
51210
|
},
|
|
51078
|
-
{
|
|
51079
|
-
hooks: [
|
|
51080
|
-
{
|
|
51081
|
-
type: "command",
|
|
51082
|
-
command: wrap("hook:ack-first-pretool", `node "${join8(DOCKER_BUNDLED_HOOKS_PATH, "ack-first-pretool.mjs")}"`),
|
|
51083
|
-
timeout: 5
|
|
51084
|
-
}
|
|
51085
|
-
]
|
|
51086
|
-
},
|
|
51087
51211
|
{
|
|
51088
51212
|
matcher: "^(Write|Edit|MultiEdit)$",
|
|
51089
51213
|
hooks: [
|
|
@@ -51478,23 +51602,13 @@ function reconcileAgent(name, agentConfigRaw, agentsDir, telegramConfig, switchr
|
|
|
51478
51602
|
}
|
|
51479
51603
|
}
|
|
51480
51604
|
{
|
|
51481
|
-
const
|
|
51482
|
-
|
|
51483
|
-
|
|
51484
|
-
|
|
51485
|
-
|
|
51486
|
-
|
|
51487
|
-
|
|
51488
|
-
if (ms365) {
|
|
51489
|
-
mcpServers[ms365.key] = ms365.value;
|
|
51490
|
-
} else {
|
|
51491
|
-
delete mcpServers["ms-365"];
|
|
51492
|
-
}
|
|
51493
|
-
const notion = resolveNotionMcpEntry(name, agentConfig, switchroomConfig);
|
|
51494
|
-
if (notion) {
|
|
51495
|
-
mcpServers[notion.key] = notion.value;
|
|
51496
|
-
} else {
|
|
51497
|
-
delete mcpServers["notion"];
|
|
51605
|
+
for (const integration of INTEGRATION_MCP_RESOLVERS) {
|
|
51606
|
+
const entry = integration.resolve(name, agentConfig, switchroomConfig);
|
|
51607
|
+
if (entry) {
|
|
51608
|
+
mcpServers[entry.key] = entry.value;
|
|
51609
|
+
} else {
|
|
51610
|
+
delete mcpServers[integration.retractionKey];
|
|
51611
|
+
}
|
|
51498
51612
|
}
|
|
51499
51613
|
}
|
|
51500
51614
|
if (agentConfig.mcp_servers) {
|
|
@@ -51677,17 +51791,11 @@ ${body}
|
|
|
51677
51791
|
}
|
|
51678
51792
|
}
|
|
51679
51793
|
{
|
|
51680
|
-
const
|
|
51681
|
-
|
|
51682
|
-
|
|
51683
|
-
|
|
51684
|
-
|
|
51685
|
-
if (ms365) {
|
|
51686
|
-
mcpServers[ms365.key] = ms365.value;
|
|
51687
|
-
}
|
|
51688
|
-
const notion = resolveNotionMcpEntry(name, agentConfig, switchroomConfig);
|
|
51689
|
-
if (notion) {
|
|
51690
|
-
mcpServers[notion.key] = notion.value;
|
|
51794
|
+
for (const integration of INTEGRATION_MCP_RESOLVERS) {
|
|
51795
|
+
const entry = integration.resolve(name, agentConfig, switchroomConfig);
|
|
51796
|
+
if (entry) {
|
|
51797
|
+
mcpServers[entry.key] = entry.value;
|
|
51798
|
+
}
|
|
51691
51799
|
}
|
|
51692
51800
|
}
|
|
51693
51801
|
if (agentConfig.mcp_servers) {
|
|
@@ -72182,15 +72290,15 @@ init_loader();
|
|
|
72182
72290
|
init_lifecycle();
|
|
72183
72291
|
import { cpSync as cpSync2, existsSync as existsSync52, mkdirSync as mkdirSync28, readFileSync as readFileSync47, realpathSync as realpathSync5, rmSync as rmSync12, statSync as statSync24 } from "node:fs";
|
|
72184
72292
|
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
72185
|
-
import { join as
|
|
72293
|
+
import { join as join53, dirname as dirname13, resolve as resolve32 } from "node:path";
|
|
72186
72294
|
import { homedir as homedir31 } from "node:os";
|
|
72187
|
-
var DEFAULT_COMPOSE_PATH =
|
|
72295
|
+
var DEFAULT_COMPOSE_PATH = join53(homedir31(), ".switchroom", "compose", "docker-compose.yml");
|
|
72188
72296
|
function runningFromSwitchroomCheckout(scriptPath) {
|
|
72189
72297
|
let dir = dirname13(scriptPath);
|
|
72190
72298
|
for (let i = 0;i < 12; i++) {
|
|
72191
|
-
if (existsSync52(
|
|
72299
|
+
if (existsSync52(join53(dir, ".git"))) {
|
|
72192
72300
|
try {
|
|
72193
|
-
const pkg = JSON.parse(readFileSync47(
|
|
72301
|
+
const pkg = JSON.parse(readFileSync47(join53(dir, "package.json"), "utf-8"));
|
|
72194
72302
|
if (pkg.name === "switchroom")
|
|
72195
72303
|
return true;
|
|
72196
72304
|
} catch {}
|
|
@@ -72320,8 +72428,8 @@ function planUpdate(opts) {
|
|
|
72320
72428
|
opts.syncBundledSkillsFn();
|
|
72321
72429
|
return;
|
|
72322
72430
|
}
|
|
72323
|
-
const source =
|
|
72324
|
-
const dest =
|
|
72431
|
+
const source = resolve32(import.meta.dirname, "../../skills");
|
|
72432
|
+
const dest = join53(homedir31(), ".switchroom", "skills", "_bundled");
|
|
72325
72433
|
if (!existsSync52(source)) {
|
|
72326
72434
|
process.stderr.write(`switchroom update: sync-bundled-skills \u2014 CLI bundle has no adjacent skills/ at ${source}; skipping.
|
|
72327
72435
|
`);
|
|
@@ -72435,7 +72543,7 @@ function defaultStatusProbe(composePath) {
|
|
|
72435
72543
|
} catch {}
|
|
72436
72544
|
let dir = dirname13(scriptPath);
|
|
72437
72545
|
for (let i = 0;i < 8; i++) {
|
|
72438
|
-
const pkgPath =
|
|
72546
|
+
const pkgPath = join53(dir, "package.json");
|
|
72439
72547
|
if (existsSync52(pkgPath)) {
|
|
72440
72548
|
try {
|
|
72441
72549
|
const pkg = JSON.parse(readFileSync47(pkgPath, "utf-8"));
|
|
@@ -72647,7 +72755,7 @@ init_source();
|
|
|
72647
72755
|
init_helpers();
|
|
72648
72756
|
init_loader();
|
|
72649
72757
|
init_lifecycle();
|
|
72650
|
-
import { resolve as
|
|
72758
|
+
import { resolve as resolve33 } from "node:path";
|
|
72651
72759
|
|
|
72652
72760
|
// src/cli/version.ts
|
|
72653
72761
|
init_source();
|
|
@@ -72655,7 +72763,7 @@ init_helpers();
|
|
|
72655
72763
|
init_lifecycle();
|
|
72656
72764
|
import { execSync as execSync4 } from "node:child_process";
|
|
72657
72765
|
import { existsSync as existsSync53, readFileSync as readFileSync48 } from "node:fs";
|
|
72658
|
-
import { dirname as dirname14, join as
|
|
72766
|
+
import { dirname as dirname14, join as join54 } from "node:path";
|
|
72659
72767
|
function getClaudeCodeVersion() {
|
|
72660
72768
|
try {
|
|
72661
72769
|
const out = execSync4("claude --version 2>/dev/null", {
|
|
@@ -72705,11 +72813,11 @@ function formatUptime3(timestamp) {
|
|
|
72705
72813
|
function locateSwitchroomInstallDir() {
|
|
72706
72814
|
let dir = import.meta.dirname;
|
|
72707
72815
|
for (let i = 0;i < 10 && dir && dir !== "/"; i++) {
|
|
72708
|
-
const pkgPath =
|
|
72816
|
+
const pkgPath = join54(dir, "package.json");
|
|
72709
72817
|
if (existsSync53(pkgPath)) {
|
|
72710
72818
|
try {
|
|
72711
72819
|
const pkg = JSON.parse(readFileSync48(pkgPath, "utf-8"));
|
|
72712
|
-
if (pkg.name === "switchroom" && existsSync53(
|
|
72820
|
+
if (pkg.name === "switchroom" && existsSync53(join54(dir, ".git"))) {
|
|
72713
72821
|
return dir;
|
|
72714
72822
|
}
|
|
72715
72823
|
} catch {}
|
|
@@ -72802,7 +72910,7 @@ function registerRestartCommand(program3) {
|
|
|
72802
72910
|
}
|
|
72803
72911
|
const didRestart = res.restarted || !graceful;
|
|
72804
72912
|
if (didRestart) {
|
|
72805
|
-
const agentDir =
|
|
72913
|
+
const agentDir = resolve33(agentsDir, name);
|
|
72806
72914
|
const converged = waitForAuthConverge(name, agentDir);
|
|
72807
72915
|
if (!converged) {
|
|
72808
72916
|
console.log(source_default.yellow(` ${name}: agent is up but auth status didn't converge in 30s \u2014 check logs`));
|
|
@@ -72883,7 +72991,7 @@ Dependency manifest`));
|
|
|
72883
72991
|
// src/cli/handoff.ts
|
|
72884
72992
|
init_helpers();
|
|
72885
72993
|
init_loader();
|
|
72886
|
-
import { resolve as
|
|
72994
|
+
import { resolve as resolve34 } from "node:path";
|
|
72887
72995
|
function registerHandoffCommand(program3) {
|
|
72888
72996
|
program3.command("handoff <agent>", { hidden: true }).description("Build the agent's session handoff sidecars \u2014 a transcript-tail " + "briefing (.handoff.md) and topic line (.handoff-topic). " + "[internal \u2014 used by the Stop hook]").option("--max-turns <n>", "Max turns kept in the handoff transcript tail", String(DEFAULT_MAX_TURNS)).action(withConfigError(async (agentName, opts) => {
|
|
72889
72997
|
let agentConfig;
|
|
@@ -72897,7 +73005,7 @@ function registerHandoffCommand(program3) {
|
|
|
72897
73005
|
return;
|
|
72898
73006
|
}
|
|
72899
73007
|
const agentsDir = resolveAgentsDir(config);
|
|
72900
|
-
agentDir =
|
|
73008
|
+
agentDir = resolve34(agentsDir, agentName);
|
|
72901
73009
|
} catch (err) {
|
|
72902
73010
|
if (!(err instanceof ConfigError))
|
|
72903
73011
|
throw err;
|
|
@@ -72912,7 +73020,7 @@ function registerHandoffCommand(program3) {
|
|
|
72912
73020
|
`);
|
|
72913
73021
|
return;
|
|
72914
73022
|
}
|
|
72915
|
-
const claudeConfigDir =
|
|
73023
|
+
const claudeConfigDir = resolve34(agentDir, ".claude");
|
|
72916
73024
|
const jsonl = findLatestSessionJsonl(claudeConfigDir);
|
|
72917
73025
|
if (!jsonl) {
|
|
72918
73026
|
process.stderr.write(`handoff: no session JSONL under ${claudeConfigDir}/projects; skipping
|
|
@@ -72946,7 +73054,7 @@ import {
|
|
|
72946
73054
|
writeFileSync as writeFileSync26,
|
|
72947
73055
|
writeSync as writeSync7
|
|
72948
73056
|
} from "node:fs";
|
|
72949
|
-
import { join as
|
|
73057
|
+
import { join as join55 } from "node:path";
|
|
72950
73058
|
import { randomBytes as randomBytes12 } from "node:crypto";
|
|
72951
73059
|
import { execSync as execSync5 } from "node:child_process";
|
|
72952
73060
|
|
|
@@ -73266,7 +73374,7 @@ function redactedMarker(ruleId) {
|
|
|
73266
73374
|
var ISSUES_FILE = "issues.jsonl";
|
|
73267
73375
|
var ISSUES_LOCK = "issues.lock";
|
|
73268
73376
|
function readAll(stateDir) {
|
|
73269
|
-
const path4 =
|
|
73377
|
+
const path4 = join55(stateDir, ISSUES_FILE);
|
|
73270
73378
|
if (!existsSync54(path4))
|
|
73271
73379
|
return [];
|
|
73272
73380
|
let raw;
|
|
@@ -73343,8 +73451,8 @@ function record(stateDir, input, nowFn = Date.now) {
|
|
|
73343
73451
|
return result;
|
|
73344
73452
|
});
|
|
73345
73453
|
}
|
|
73346
|
-
function
|
|
73347
|
-
if (!existsSync54(
|
|
73454
|
+
function resolve35(stateDir, fingerprint, nowFn = Date.now) {
|
|
73455
|
+
if (!existsSync54(join55(stateDir, ISSUES_FILE)))
|
|
73348
73456
|
return 0;
|
|
73349
73457
|
return withLock(stateDir, () => {
|
|
73350
73458
|
const all = readAll(stateDir);
|
|
@@ -73362,7 +73470,7 @@ function resolve34(stateDir, fingerprint, nowFn = Date.now) {
|
|
|
73362
73470
|
});
|
|
73363
73471
|
}
|
|
73364
73472
|
function resolveAllBySource(stateDir, source, nowFn = Date.now) {
|
|
73365
|
-
if (!existsSync54(
|
|
73473
|
+
if (!existsSync54(join55(stateDir, ISSUES_FILE)))
|
|
73366
73474
|
return 0;
|
|
73367
73475
|
return withLock(stateDir, () => {
|
|
73368
73476
|
const all = readAll(stateDir);
|
|
@@ -73380,7 +73488,7 @@ function resolveAllBySource(stateDir, source, nowFn = Date.now) {
|
|
|
73380
73488
|
});
|
|
73381
73489
|
}
|
|
73382
73490
|
function prune(stateDir, opts = {}) {
|
|
73383
|
-
if (!existsSync54(
|
|
73491
|
+
if (!existsSync54(join55(stateDir, ISSUES_FILE)))
|
|
73384
73492
|
return 0;
|
|
73385
73493
|
return withLock(stateDir, () => {
|
|
73386
73494
|
const all = readAll(stateDir);
|
|
@@ -73413,7 +73521,7 @@ function ensureDir(stateDir) {
|
|
|
73413
73521
|
mkdirSync29(stateDir, { recursive: true });
|
|
73414
73522
|
}
|
|
73415
73523
|
function writeAll(stateDir, events) {
|
|
73416
|
-
const path4 =
|
|
73524
|
+
const path4 = join55(stateDir, ISSUES_FILE);
|
|
73417
73525
|
sweepOrphanTmpFiles(stateDir);
|
|
73418
73526
|
const tmp = `${path4}.tmp-${process.pid}-${randomBytes12(4).toString("hex")}`;
|
|
73419
73527
|
const body = events.length === 0 ? "" : events.map((e) => JSON.stringify(e)).join(`
|
|
@@ -73435,7 +73543,7 @@ function sweepOrphanTmpFiles(stateDir) {
|
|
|
73435
73543
|
for (const entry of entries) {
|
|
73436
73544
|
if (!entry.startsWith(TMP_PREFIX))
|
|
73437
73545
|
continue;
|
|
73438
|
-
const tmpPath =
|
|
73546
|
+
const tmpPath = join55(stateDir, entry);
|
|
73439
73547
|
try {
|
|
73440
73548
|
const stat = statSync25(tmpPath);
|
|
73441
73549
|
if (stat.mtimeMs < cutoff) {
|
|
@@ -73447,7 +73555,7 @@ function sweepOrphanTmpFiles(stateDir) {
|
|
|
73447
73555
|
var LOCK_RETRY_MS = 25;
|
|
73448
73556
|
var LOCK_TIMEOUT_MS = 1e4;
|
|
73449
73557
|
function withLock(stateDir, fn) {
|
|
73450
|
-
const lockPath =
|
|
73558
|
+
const lockPath = join55(stateDir, ISSUES_LOCK);
|
|
73451
73559
|
const startedAt = Date.now();
|
|
73452
73560
|
let fd = null;
|
|
73453
73561
|
while (fd === null) {
|
|
@@ -73631,11 +73739,11 @@ function registerIssuesCommand(program3) {
|
|
|
73631
73739
|
const stateDir = resolveStateDir2(opts);
|
|
73632
73740
|
let flipped;
|
|
73633
73741
|
if (opts.source && opts.code) {
|
|
73634
|
-
flipped =
|
|
73742
|
+
flipped = resolve35(stateDir, computeFingerprint(opts.source, opts.code));
|
|
73635
73743
|
} else if (opts.source && !fingerprint) {
|
|
73636
73744
|
flipped = resolveAllBySource(stateDir, opts.source);
|
|
73637
73745
|
} else if (fingerprint) {
|
|
73638
|
-
flipped =
|
|
73746
|
+
flipped = resolve35(stateDir, fingerprint);
|
|
73639
73747
|
} else {
|
|
73640
73748
|
process.stderr.write(`issues resolve: need either <fingerprint>, --source, or --source + --code
|
|
73641
73749
|
`);
|
|
@@ -73732,7 +73840,7 @@ function relTime(deltaMs) {
|
|
|
73732
73840
|
init_source();
|
|
73733
73841
|
import { existsSync as existsSync57 } from "node:fs";
|
|
73734
73842
|
import { homedir as homedir34 } from "node:os";
|
|
73735
|
-
import { join as
|
|
73843
|
+
import { join as join58, resolve as resolve36 } from "node:path";
|
|
73736
73844
|
|
|
73737
73845
|
// src/deps/python.ts
|
|
73738
73846
|
import { createHash as createHash11 } from "node:crypto";
|
|
@@ -73743,7 +73851,7 @@ import {
|
|
|
73743
73851
|
rmSync as rmSync13,
|
|
73744
73852
|
writeFileSync as writeFileSync27
|
|
73745
73853
|
} from "node:fs";
|
|
73746
|
-
import { dirname as dirname15, join as
|
|
73854
|
+
import { dirname as dirname15, join as join56 } from "node:path";
|
|
73747
73855
|
import { homedir as homedir32 } from "node:os";
|
|
73748
73856
|
import { execFileSync as execFileSync15 } from "node:child_process";
|
|
73749
73857
|
|
|
@@ -73756,7 +73864,7 @@ class PythonEnvError extends Error {
|
|
|
73756
73864
|
}
|
|
73757
73865
|
}
|
|
73758
73866
|
function defaultPythonCacheRoot() {
|
|
73759
|
-
return
|
|
73867
|
+
return join56(homedir32(), ".switchroom", "deps", "python");
|
|
73760
73868
|
}
|
|
73761
73869
|
function hashFile(path4) {
|
|
73762
73870
|
return createHash11("sha256").update(readFileSync50(path4)).digest("hex");
|
|
@@ -73768,11 +73876,11 @@ function ensurePythonEnv(opts) {
|
|
|
73768
73876
|
if (!existsSync55(requirementsPath)) {
|
|
73769
73877
|
throw new PythonEnvError(`requirements file not found: ${requirementsPath}`);
|
|
73770
73878
|
}
|
|
73771
|
-
const venvDir =
|
|
73772
|
-
const stampPath =
|
|
73773
|
-
const binDir =
|
|
73774
|
-
const pythonBin =
|
|
73775
|
-
const pipBin =
|
|
73879
|
+
const venvDir = join56(cacheRoot, skillName);
|
|
73880
|
+
const stampPath = join56(venvDir, ".requirements.sha256");
|
|
73881
|
+
const binDir = join56(venvDir, "bin");
|
|
73882
|
+
const pythonBin = join56(binDir, "python");
|
|
73883
|
+
const pipBin = join56(binDir, "pip");
|
|
73776
73884
|
const targetHash = hashFile(requirementsPath);
|
|
73777
73885
|
if (!force && existsSync55(stampPath) && existsSync55(pythonBin)) {
|
|
73778
73886
|
const existingHash = readFileSync50(stampPath, "utf8").trim();
|
|
@@ -73831,7 +73939,7 @@ import {
|
|
|
73831
73939
|
rmSync as rmSync14,
|
|
73832
73940
|
writeFileSync as writeFileSync28
|
|
73833
73941
|
} from "node:fs";
|
|
73834
|
-
import { dirname as dirname16, join as
|
|
73942
|
+
import { dirname as dirname16, join as join57 } from "node:path";
|
|
73835
73943
|
import { homedir as homedir33 } from "node:os";
|
|
73836
73944
|
import { execFileSync as execFileSync16 } from "node:child_process";
|
|
73837
73945
|
|
|
@@ -73855,7 +73963,7 @@ var LOCKFILES_FOR = {
|
|
|
73855
73963
|
npm: ["package-lock.json"]
|
|
73856
73964
|
};
|
|
73857
73965
|
function defaultNodeCacheRoot() {
|
|
73858
|
-
return
|
|
73966
|
+
return join57(homedir33(), ".switchroom", "deps", "node");
|
|
73859
73967
|
}
|
|
73860
73968
|
function hashDepInputs(packageJsonPath) {
|
|
73861
73969
|
const sourceDir = dirname16(packageJsonPath);
|
|
@@ -73864,7 +73972,7 @@ function hashDepInputs(packageJsonPath) {
|
|
|
73864
73972
|
`);
|
|
73865
73973
|
hasher.update(readFileSync51(packageJsonPath));
|
|
73866
73974
|
for (const lockName of ALL_LOCKFILES) {
|
|
73867
|
-
const lockPath =
|
|
73975
|
+
const lockPath = join57(sourceDir, lockName);
|
|
73868
73976
|
if (existsSync56(lockPath)) {
|
|
73869
73977
|
hasher.update(`
|
|
73870
73978
|
`);
|
|
@@ -73884,10 +73992,10 @@ function ensureNodeEnv(opts) {
|
|
|
73884
73992
|
throw new NodeEnvError(`package.json not found: ${packageJsonPath}`);
|
|
73885
73993
|
}
|
|
73886
73994
|
const sourceDir = dirname16(packageJsonPath);
|
|
73887
|
-
const envDir =
|
|
73888
|
-
const stampPath =
|
|
73889
|
-
const nodeModulesDir =
|
|
73890
|
-
const binDir =
|
|
73995
|
+
const envDir = join57(cacheRoot, skillName);
|
|
73996
|
+
const stampPath = join57(envDir, ".package.sha256");
|
|
73997
|
+
const nodeModulesDir = join57(envDir, "node_modules");
|
|
73998
|
+
const binDir = join57(nodeModulesDir, ".bin");
|
|
73891
73999
|
const targetHash = hashDepInputs(packageJsonPath);
|
|
73892
74000
|
if (!force && existsSync56(stampPath) && existsSync56(nodeModulesDir)) {
|
|
73893
74001
|
const existingHash = readFileSync51(stampPath, "utf8").trim();
|
|
@@ -73905,12 +74013,12 @@ function ensureNodeEnv(opts) {
|
|
|
73905
74013
|
rmSync14(envDir, { recursive: true, force: true });
|
|
73906
74014
|
}
|
|
73907
74015
|
mkdirSync31(envDir, { recursive: true });
|
|
73908
|
-
copyFileSync9(packageJsonPath,
|
|
74016
|
+
copyFileSync9(packageJsonPath, join57(envDir, "package.json"));
|
|
73909
74017
|
let copiedLockfile = false;
|
|
73910
74018
|
for (const lockName of LOCKFILES_FOR[installer]) {
|
|
73911
|
-
const lockPath =
|
|
74019
|
+
const lockPath = join57(sourceDir, lockName);
|
|
73912
74020
|
if (existsSync56(lockPath)) {
|
|
73913
|
-
copyFileSync9(lockPath,
|
|
74021
|
+
copyFileSync9(lockPath, join57(envDir, lockName));
|
|
73914
74022
|
copiedLockfile = true;
|
|
73915
74023
|
}
|
|
73916
74024
|
}
|
|
@@ -73939,7 +74047,7 @@ function ensureNodeEnv(opts) {
|
|
|
73939
74047
|
|
|
73940
74048
|
// src/cli/deps.ts
|
|
73941
74049
|
function builtinSkillsRoot() {
|
|
73942
|
-
return
|
|
74050
|
+
return resolve36(homedir34(), ".switchroom/skills/_bundled");
|
|
73943
74051
|
}
|
|
73944
74052
|
function registerDepsCommand(program3) {
|
|
73945
74053
|
const deps = program3.command("deps").description("Manage cached per-skill dependency environments");
|
|
@@ -73949,13 +74057,13 @@ function registerDepsCommand(program3) {
|
|
|
73949
74057
|
console.error(source_default.red(`Bundled skills pool dir not found at ${skillsRoot} \u2014 run \`switchroom update\` to install it.`));
|
|
73950
74058
|
process.exit(1);
|
|
73951
74059
|
}
|
|
73952
|
-
const skillDir =
|
|
74060
|
+
const skillDir = join58(skillsRoot, skill);
|
|
73953
74061
|
if (!existsSync57(skillDir)) {
|
|
73954
74062
|
console.error(source_default.red(`Unknown skill: ${skill} (no dir at ${skillDir})`));
|
|
73955
74063
|
process.exit(1);
|
|
73956
74064
|
}
|
|
73957
|
-
const requirementsPath =
|
|
73958
|
-
const packageJsonPath =
|
|
74065
|
+
const requirementsPath = join58(skillDir, "requirements.txt");
|
|
74066
|
+
const packageJsonPath = join58(skillDir, "package.json");
|
|
73959
74067
|
const wantPython = opts.python ?? (!opts.python && !opts.node && existsSync57(requirementsPath));
|
|
73960
74068
|
const wantNode = opts.node ?? (!opts.python && !opts.node && existsSync57(packageJsonPath));
|
|
73961
74069
|
let did = 0;
|
|
@@ -74018,7 +74126,7 @@ function registerDepsCommand(program3) {
|
|
|
74018
74126
|
init_helpers();
|
|
74019
74127
|
init_loader();
|
|
74020
74128
|
import { existsSync as existsSync58 } from "node:fs";
|
|
74021
|
-
import { resolve as
|
|
74129
|
+
import { resolve as resolve37, sep as sep3 } from "node:path";
|
|
74022
74130
|
import { spawnSync as spawnSync9 } from "node:child_process";
|
|
74023
74131
|
|
|
74024
74132
|
// src/agents/workspace.ts
|
|
@@ -74724,8 +74832,8 @@ function registerWorkspaceCommand(program3) {
|
|
|
74724
74832
|
const dir = resolveAgentWorkspaceDirOrExit(program3, agentName);
|
|
74725
74833
|
if (!dir)
|
|
74726
74834
|
return;
|
|
74727
|
-
const resolvedWorkspace =
|
|
74728
|
-
const target =
|
|
74835
|
+
const resolvedWorkspace = resolve37(dir);
|
|
74836
|
+
const target = resolve37(resolvedWorkspace, file ?? "AGENTS.md");
|
|
74729
74837
|
if (!isInsideWorkspace(resolvedWorkspace, target)) {
|
|
74730
74838
|
process.stderr.write(`workspace edit: refusing path traversal outside workspace dir (${target})
|
|
74731
74839
|
`);
|
|
@@ -74793,7 +74901,7 @@ function registerWorkspaceCommand(program3) {
|
|
|
74793
74901
|
const dir = resolveAgentWorkspaceDirOrExit(program3, agentName);
|
|
74794
74902
|
if (!dir)
|
|
74795
74903
|
return;
|
|
74796
|
-
const gitDir =
|
|
74904
|
+
const gitDir = resolve37(dir, ".git");
|
|
74797
74905
|
if (!existsSync58(gitDir)) {
|
|
74798
74906
|
process.stdout.write(`Workspace is not a git repository. Re-run \`switchroom agent create ${agentName}\` ` + `or manually \`git init\` in ${dir} to enable versioning.
|
|
74799
74907
|
`);
|
|
@@ -74847,7 +74955,7 @@ function registerWorkspaceCommand(program3) {
|
|
|
74847
74955
|
const dir = resolveAgentWorkspaceDirOrExit(program3, agentName);
|
|
74848
74956
|
if (!dir)
|
|
74849
74957
|
return;
|
|
74850
|
-
const gitDir =
|
|
74958
|
+
const gitDir = resolve37(dir, ".git");
|
|
74851
74959
|
if (!existsSync58(gitDir)) {
|
|
74852
74960
|
process.stdout.write(`Workspace is not a git repository.
|
|
74853
74961
|
`);
|
|
@@ -74871,7 +74979,7 @@ function resolveAgentWorkspaceDirOrExit(program3, agentName) {
|
|
|
74871
74979
|
return;
|
|
74872
74980
|
}
|
|
74873
74981
|
const agentsDir = resolveAgentsDir(config);
|
|
74874
|
-
const agentDir =
|
|
74982
|
+
const agentDir = resolve37(agentsDir, agentName);
|
|
74875
74983
|
const dir = resolveAgentWorkspaceDir(agentDir);
|
|
74876
74984
|
if (!existsSync58(dir)) {
|
|
74877
74985
|
process.stderr.write(`workspace: ${dir} does not exist yet. Run \`switchroom setup\` or \`switchroom agent scaffold ${agentName}\` to seed it.
|
|
@@ -74910,7 +75018,7 @@ init_helpers();
|
|
|
74910
75018
|
init_loader();
|
|
74911
75019
|
init_merge();
|
|
74912
75020
|
import { copyFileSync as copyFileSync10, existsSync as existsSync59, readFileSync as readFileSync52, writeFileSync as writeFileSync29 } from "node:fs";
|
|
74913
|
-
import { join as
|
|
75021
|
+
import { join as join59, resolve as resolve38 } from "node:path";
|
|
74914
75022
|
init_schema();
|
|
74915
75023
|
function resolveSoulTargetOrExit(program3, agentName) {
|
|
74916
75024
|
const config = getConfig(program3);
|
|
@@ -74923,7 +75031,7 @@ function resolveSoulTargetOrExit(program3, agentName) {
|
|
|
74923
75031
|
const profileName = merged.extends ?? DEFAULT_PROFILE;
|
|
74924
75032
|
const profilePath = getProfilePath(profileName);
|
|
74925
75033
|
const agentsDir = resolveAgentsDir(config);
|
|
74926
|
-
const agentDir =
|
|
75034
|
+
const agentDir = resolve38(agentsDir, agentName);
|
|
74927
75035
|
const workspaceDir = resolveAgentWorkspaceDir(agentDir);
|
|
74928
75036
|
if (!existsSync59(workspaceDir)) {
|
|
74929
75037
|
console.error(`soul: ${workspaceDir} does not exist yet. Run \`switchroom setup\` ` + `or \`switchroom agent scaffold ${agentName}\` to seed it.`);
|
|
@@ -74934,7 +75042,7 @@ function resolveSoulTargetOrExit(program3, agentName) {
|
|
|
74934
75042
|
profileName,
|
|
74935
75043
|
profilePath,
|
|
74936
75044
|
workspaceDir,
|
|
74937
|
-
soulPath:
|
|
75045
|
+
soulPath: join59(workspaceDir, "SOUL.md"),
|
|
74938
75046
|
soul: merged.soul
|
|
74939
75047
|
};
|
|
74940
75048
|
}
|
|
@@ -75001,7 +75109,7 @@ function registerSoulCommand(program3) {
|
|
|
75001
75109
|
init_helpers();
|
|
75002
75110
|
init_loader();
|
|
75003
75111
|
import { existsSync as existsSync60, readFileSync as readFileSync53, readdirSync as readdirSync21, statSync as statSync26 } from "node:fs";
|
|
75004
|
-
import { resolve as
|
|
75112
|
+
import { resolve as resolve39, join as join60 } from "node:path";
|
|
75005
75113
|
import { createHash as createHash13 } from "node:crypto";
|
|
75006
75114
|
init_merge();
|
|
75007
75115
|
init_hindsight();
|
|
@@ -75015,7 +75123,7 @@ function sha256(content) {
|
|
|
75015
75123
|
return createHash13("sha256").update(content).digest("hex").slice(0, 16);
|
|
75016
75124
|
}
|
|
75017
75125
|
function findLatestTranscriptJsonl(claudeConfigDir) {
|
|
75018
|
-
const projectsDir =
|
|
75126
|
+
const projectsDir = join60(claudeConfigDir, "projects");
|
|
75019
75127
|
if (!existsSync60(projectsDir))
|
|
75020
75128
|
return;
|
|
75021
75129
|
try {
|
|
@@ -75024,8 +75132,8 @@ function findLatestTranscriptJsonl(claudeConfigDir) {
|
|
|
75024
75132
|
for (const entry of entries) {
|
|
75025
75133
|
if (!entry.isDirectory())
|
|
75026
75134
|
continue;
|
|
75027
|
-
const projectPath =
|
|
75028
|
-
const transcriptPath =
|
|
75135
|
+
const projectPath = join60(projectsDir, entry.name);
|
|
75136
|
+
const transcriptPath = join60(projectPath, "transcript.jsonl");
|
|
75029
75137
|
if (!existsSync60(transcriptPath))
|
|
75030
75138
|
continue;
|
|
75031
75139
|
const stat3 = statSync26(transcriptPath);
|
|
@@ -75088,17 +75196,17 @@ function registerDebugCommand(program3) {
|
|
|
75088
75196
|
process.exit(1);
|
|
75089
75197
|
}
|
|
75090
75198
|
const agentsDir = resolveAgentsDir(config);
|
|
75091
|
-
const agentDir =
|
|
75199
|
+
const agentDir = resolve39(agentsDir, agentName);
|
|
75092
75200
|
if (!existsSync60(agentDir)) {
|
|
75093
75201
|
console.error(`Agent directory not found: ${agentDir}`);
|
|
75094
75202
|
process.exit(1);
|
|
75095
75203
|
}
|
|
75096
75204
|
const workspaceDir = resolveAgentWorkspaceDir(agentDir);
|
|
75097
|
-
const claudeConfigDir =
|
|
75098
|
-
const claudeMdPath =
|
|
75099
|
-
const soulMdPath =
|
|
75100
|
-
const workspaceSoulMdPath =
|
|
75101
|
-
const handoffPath =
|
|
75205
|
+
const claudeConfigDir = join60(agentDir, ".claude");
|
|
75206
|
+
const claudeMdPath = join60(agentDir, "CLAUDE.md");
|
|
75207
|
+
const soulMdPath = join60(agentDir, "SOUL.md");
|
|
75208
|
+
const workspaceSoulMdPath = join60(workspaceDir, "SOUL.md");
|
|
75209
|
+
const handoffPath = join60(agentDir, ".handoff.md");
|
|
75102
75210
|
const lastN = parseInt(opts.last, 10);
|
|
75103
75211
|
if (isNaN(lastN) || lastN < 1) {
|
|
75104
75212
|
console.error("--last must be a positive integer");
|
|
@@ -75248,7 +75356,7 @@ init_source();
|
|
|
75248
75356
|
// src/worktree/claim.ts
|
|
75249
75357
|
import { execFileSync as execFileSync17 } from "node:child_process";
|
|
75250
75358
|
import { closeSync as closeSync12, mkdirSync as mkdirSync33, openSync as openSync12, existsSync as existsSync62, unlinkSync as unlinkSync13 } from "node:fs";
|
|
75251
|
-
import { join as
|
|
75359
|
+
import { join as join62, resolve as resolve41 } from "node:path";
|
|
75252
75360
|
import { homedir as homedir36 } from "node:os";
|
|
75253
75361
|
import { randomBytes as randomBytes13 } from "node:crypto";
|
|
75254
75362
|
|
|
@@ -75262,13 +75370,13 @@ import {
|
|
|
75262
75370
|
existsSync as existsSync61,
|
|
75263
75371
|
renameSync as renameSync12
|
|
75264
75372
|
} from "node:fs";
|
|
75265
|
-
import { join as
|
|
75373
|
+
import { join as join61, resolve as resolve40 } from "node:path";
|
|
75266
75374
|
import { homedir as homedir35 } from "node:os";
|
|
75267
75375
|
function registryDir() {
|
|
75268
|
-
return
|
|
75376
|
+
return resolve40(process.env.SWITCHROOM_WORKTREE_DIR ?? join61(homedir35(), ".switchroom", "worktrees"));
|
|
75269
75377
|
}
|
|
75270
75378
|
function recordPath(id) {
|
|
75271
|
-
return
|
|
75379
|
+
return join61(registryDir(), `${id}.json`);
|
|
75272
75380
|
}
|
|
75273
75381
|
function ensureDir2() {
|
|
75274
75382
|
mkdirSync32(registryDir(), { recursive: true });
|
|
@@ -75319,7 +75427,7 @@ function acquireRepoLock(repoPath) {
|
|
|
75319
75427
|
const lockDir = registryDir();
|
|
75320
75428
|
mkdirSync33(lockDir, { recursive: true });
|
|
75321
75429
|
const lockName = repoPath.replace(/[^A-Za-z0-9]/g, "_");
|
|
75322
|
-
const lockPath =
|
|
75430
|
+
const lockPath = join62(lockDir, `.lock-${lockName}`);
|
|
75323
75431
|
const deadline = Date.now() + 5000;
|
|
75324
75432
|
let fd = null;
|
|
75325
75433
|
while (fd === null) {
|
|
@@ -75346,7 +75454,7 @@ function acquireRepoLock(repoPath) {
|
|
|
75346
75454
|
}
|
|
75347
75455
|
var DEFAULT_CONCURRENCY = 5;
|
|
75348
75456
|
function worktreesBaseDir() {
|
|
75349
|
-
return
|
|
75457
|
+
return resolve41(process.env.SWITCHROOM_WORKTREE_BASE ?? join62(homedir36(), ".switchroom", "worktree-checkouts"));
|
|
75350
75458
|
}
|
|
75351
75459
|
function shortId() {
|
|
75352
75460
|
return randomBytes13(4).toString("hex");
|
|
@@ -75368,7 +75476,7 @@ function resolveRepoPath(repo, codeRepos) {
|
|
|
75368
75476
|
}
|
|
75369
75477
|
function expandHome(p) {
|
|
75370
75478
|
if (p.startsWith("~/"))
|
|
75371
|
-
return
|
|
75479
|
+
return join62(homedir36(), p.slice(2));
|
|
75372
75480
|
return p;
|
|
75373
75481
|
}
|
|
75374
75482
|
async function claimWorktree(input, codeRepos) {
|
|
@@ -75396,7 +75504,7 @@ async function claimWorktree(input, codeRepos) {
|
|
|
75396
75504
|
branch = `task/${taskSuffix}-${id}`;
|
|
75397
75505
|
const baseDir = worktreesBaseDir();
|
|
75398
75506
|
mkdirSync33(baseDir, { recursive: true });
|
|
75399
|
-
worktreePath =
|
|
75507
|
+
worktreePath = join62(baseDir, `${id}-${taskSuffix}`);
|
|
75400
75508
|
const now = new Date().toISOString();
|
|
75401
75509
|
const record2 = {
|
|
75402
75510
|
id,
|
|
@@ -75651,7 +75759,7 @@ import {
|
|
|
75651
75759
|
rmSync as rmSync15,
|
|
75652
75760
|
writeFileSync as writeFileSync31
|
|
75653
75761
|
} from "node:fs";
|
|
75654
|
-
import { join as
|
|
75762
|
+
import { join as join63 } from "node:path";
|
|
75655
75763
|
function encodeCredentialsFilename(email) {
|
|
75656
75764
|
const SAFE = new Set([
|
|
75657
75765
|
..."ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
|
|
@@ -75841,16 +75949,16 @@ function resolveCredentialsDir(env2) {
|
|
|
75841
75949
|
if (explicit && explicit.length > 0)
|
|
75842
75950
|
return explicit;
|
|
75843
75951
|
const stateBase = env2.SWITCHROOM_CONTAINER === "1" ? "/state/agent" : env2.HOME ?? ".";
|
|
75844
|
-
return
|
|
75952
|
+
return join63(stateBase, "google-workspace-mcp", "credentials");
|
|
75845
75953
|
}
|
|
75846
75954
|
function writeSeedFile(dir, email, seed) {
|
|
75847
75955
|
mkdirSync34(dir, { recursive: true, mode: 448 });
|
|
75848
75956
|
chmodSync9(dir, 448);
|
|
75849
75957
|
for (const name of readdirSync23(dir)) {
|
|
75850
|
-
rmSync15(
|
|
75958
|
+
rmSync15(join63(dir, name), { force: true, recursive: true });
|
|
75851
75959
|
}
|
|
75852
75960
|
const filename = encodeCredentialsFilename(email);
|
|
75853
|
-
const filePath =
|
|
75961
|
+
const filePath = join63(dir, filename);
|
|
75854
75962
|
writeFileSync31(filePath, JSON.stringify(seed), { mode: 384 });
|
|
75855
75963
|
chmodSync9(filePath, 384);
|
|
75856
75964
|
return filePath;
|
|
@@ -76010,7 +76118,7 @@ function registerDriveMcpLauncherCommand(program3) {
|
|
|
76010
76118
|
init_scaffold_integration();
|
|
76011
76119
|
import { spawn as spawn6 } from "node:child_process";
|
|
76012
76120
|
import { writeFileSync as writeFileSync32, mkdirSync as mkdirSync35 } from "node:fs";
|
|
76013
|
-
import { dirname as dirname17, join as
|
|
76121
|
+
import { dirname as dirname17, join as join64 } from "node:path";
|
|
76014
76122
|
var SOFTERIA_TOKEN_ENV = "MS365_MCP_OAUTH_TOKEN";
|
|
76015
76123
|
var DEFAULT_REFRESH_LEAD_MS = 5 * 60 * 1000;
|
|
76016
76124
|
var MAX_REFRESH_INTERVAL_MS = 60 * 60 * 1000;
|
|
@@ -76042,7 +76150,7 @@ function writeRefreshHeartbeat(agentName, data) {
|
|
|
76042
76150
|
function heartbeatPath(agentName) {
|
|
76043
76151
|
const override = process.env.SWITCHROOM_M365_HEARTBEAT_DIR;
|
|
76044
76152
|
if (override) {
|
|
76045
|
-
return
|
|
76153
|
+
return join64(override, `m365-launcher-${agentName}.heartbeat.json`);
|
|
76046
76154
|
}
|
|
76047
76155
|
return "/state/agent/m365-launcher.heartbeat.json";
|
|
76048
76156
|
}
|
|
@@ -76066,20 +76174,20 @@ function wireStdio(child) {
|
|
|
76066
76174
|
async function killChild(child, gracefulMs = 3000) {
|
|
76067
76175
|
if (child.exitCode !== null || child.signalCode !== null)
|
|
76068
76176
|
return;
|
|
76069
|
-
return new Promise((
|
|
76177
|
+
return new Promise((resolve42) => {
|
|
76070
76178
|
let killTimer = null;
|
|
76071
76179
|
const onExit = () => {
|
|
76072
76180
|
if (killTimer) {
|
|
76073
76181
|
clearTimeout(killTimer);
|
|
76074
76182
|
killTimer = null;
|
|
76075
76183
|
}
|
|
76076
|
-
|
|
76184
|
+
resolve42();
|
|
76077
76185
|
};
|
|
76078
76186
|
child.once("exit", onExit);
|
|
76079
76187
|
try {
|
|
76080
76188
|
child.kill("SIGTERM");
|
|
76081
76189
|
} catch {
|
|
76082
|
-
|
|
76190
|
+
resolve42();
|
|
76083
76191
|
return;
|
|
76084
76192
|
}
|
|
76085
76193
|
killTimer = setTimeout(() => {
|
|
@@ -76193,8 +76301,8 @@ async function runMs365McpLauncher(opts, rt) {
|
|
|
76193
76301
|
};
|
|
76194
76302
|
process.on("SIGINT", onSignal);
|
|
76195
76303
|
process.on("SIGTERM", onSignal);
|
|
76196
|
-
return new Promise((
|
|
76197
|
-
resolveLauncher =
|
|
76304
|
+
return new Promise((resolve42) => {
|
|
76305
|
+
resolveLauncher = resolve42;
|
|
76198
76306
|
});
|
|
76199
76307
|
}
|
|
76200
76308
|
function registerM365McpLauncherCommand(program3) {
|
|
@@ -76296,23 +76404,23 @@ async function runNotionMcpLauncher(opts, runtime) {
|
|
|
76296
76404
|
};
|
|
76297
76405
|
process.on("SIGTERM", () => forward("SIGTERM"));
|
|
76298
76406
|
process.on("SIGINT", () => forward("SIGINT"));
|
|
76299
|
-
const exitCode = await new Promise((
|
|
76407
|
+
const exitCode = await new Promise((resolve42) => {
|
|
76300
76408
|
child.once("exit", (code, signal) => {
|
|
76301
76409
|
clearTimer(heartbeatHandle);
|
|
76302
76410
|
if (typeof code === "number") {
|
|
76303
|
-
|
|
76411
|
+
resolve42(code);
|
|
76304
76412
|
} else if (signal) {
|
|
76305
76413
|
const sigCode = { SIGTERM: 15, SIGINT: 2, SIGKILL: 9 }[signal] ?? 1;
|
|
76306
|
-
|
|
76414
|
+
resolve42(128 + sigCode);
|
|
76307
76415
|
} else {
|
|
76308
|
-
|
|
76416
|
+
resolve42(1);
|
|
76309
76417
|
}
|
|
76310
76418
|
});
|
|
76311
76419
|
child.once("error", (err) => {
|
|
76312
76420
|
clearTimer(heartbeatHandle);
|
|
76313
76421
|
process.stderr.write(`notion-mcp-launcher: child spawn error: ${err.message}
|
|
76314
76422
|
`);
|
|
76315
|
-
|
|
76423
|
+
resolve42(1);
|
|
76316
76424
|
});
|
|
76317
76425
|
});
|
|
76318
76426
|
return exitCode;
|
|
@@ -76961,7 +77069,7 @@ agents:
|
|
|
76961
77069
|
|
|
76962
77070
|
// src/cli/apply.ts
|
|
76963
77071
|
init_resolver();
|
|
76964
|
-
import { dirname as dirname21, join as
|
|
77072
|
+
import { dirname as dirname21, join as join68, resolve as resolve43 } from "node:path";
|
|
76965
77073
|
import { homedir as homedir38 } from "node:os";
|
|
76966
77074
|
import { execFileSync as execFileSync20 } from "node:child_process";
|
|
76967
77075
|
init_vault();
|
|
@@ -76970,7 +77078,7 @@ init_loader();
|
|
|
76970
77078
|
|
|
76971
77079
|
// src/cli/update-prompt-hook.ts
|
|
76972
77080
|
import { existsSync as existsSync66, readFileSync as readFileSync55, writeFileSync as writeFileSync34, chmodSync as chmodSync10, mkdirSync as mkdirSync37 } from "node:fs";
|
|
76973
|
-
import { join as
|
|
77081
|
+
import { join as join65 } from "node:path";
|
|
76974
77082
|
var HOOK_FILENAME = "update-card-on-prompt.sh";
|
|
76975
77083
|
function updatePromptHookScript() {
|
|
76976
77084
|
return `#!/bin/bash
|
|
@@ -77036,9 +77144,9 @@ exit 0
|
|
|
77036
77144
|
`;
|
|
77037
77145
|
}
|
|
77038
77146
|
function installUpdatePromptHook(agentDir) {
|
|
77039
|
-
const hooksDir =
|
|
77147
|
+
const hooksDir = join65(agentDir, ".claude", "hooks");
|
|
77040
77148
|
mkdirSync37(hooksDir, { recursive: true });
|
|
77041
|
-
const scriptPath =
|
|
77149
|
+
const scriptPath = join65(hooksDir, HOOK_FILENAME);
|
|
77042
77150
|
const desired = updatePromptHookScript();
|
|
77043
77151
|
let installed = false;
|
|
77044
77152
|
const existing = existsSync66(scriptPath) ? readFileSync55(scriptPath, "utf-8") : "";
|
|
@@ -77051,7 +77159,7 @@ function installUpdatePromptHook(agentDir) {
|
|
|
77051
77159
|
chmodSync10(scriptPath, 493);
|
|
77052
77160
|
} catch {}
|
|
77053
77161
|
}
|
|
77054
|
-
const settingsPath =
|
|
77162
|
+
const settingsPath = join65(agentDir, ".claude", "settings.json");
|
|
77055
77163
|
if (!existsSync66(settingsPath)) {
|
|
77056
77164
|
return { scriptPath, settingsPath, installed };
|
|
77057
77165
|
}
|
|
@@ -77177,7 +77285,7 @@ import {
|
|
|
77177
77285
|
realpathSync as realpathSync6,
|
|
77178
77286
|
statSync as statSync27
|
|
77179
77287
|
} from "node:fs";
|
|
77180
|
-
import { join as
|
|
77288
|
+
import { join as join67 } from "node:path";
|
|
77181
77289
|
function resolveOperatorUid() {
|
|
77182
77290
|
const sudoUid = process.env.SUDO_UID;
|
|
77183
77291
|
if (sudoUid !== undefined) {
|
|
@@ -77193,14 +77301,14 @@ function resolveOperatorUid() {
|
|
|
77193
77301
|
return;
|
|
77194
77302
|
}
|
|
77195
77303
|
function operatorOwnedPaths(home2) {
|
|
77196
|
-
const root =
|
|
77304
|
+
const root = join67(home2, ".switchroom");
|
|
77197
77305
|
return [
|
|
77198
|
-
|
|
77199
|
-
|
|
77200
|
-
|
|
77201
|
-
|
|
77202
|
-
|
|
77203
|
-
|
|
77306
|
+
join67(root, "vault"),
|
|
77307
|
+
join67(root, "vault-auto-unlock"),
|
|
77308
|
+
join67(root, "vault-audit.log"),
|
|
77309
|
+
join67(root, "host-control-audit.log"),
|
|
77310
|
+
join67(root, "accounts"),
|
|
77311
|
+
join67(root, "compose")
|
|
77204
77312
|
];
|
|
77205
77313
|
}
|
|
77206
77314
|
function restoreOperatorOwnership(home2, operatorUid, deps = {}) {
|
|
@@ -77249,7 +77357,7 @@ function restoreOperatorOwnership(home2, operatorUid, deps = {}) {
|
|
|
77249
77357
|
} catch {}
|
|
77250
77358
|
if (isDir(target)) {
|
|
77251
77359
|
for (const entry of readdir2(target)) {
|
|
77252
|
-
visit(
|
|
77360
|
+
visit(join67(target, entry));
|
|
77253
77361
|
}
|
|
77254
77362
|
}
|
|
77255
77363
|
};
|
|
@@ -77263,14 +77371,14 @@ var EMBEDDED_EXAMPLES = {
|
|
|
77263
77371
|
switchroom: switchroom_default,
|
|
77264
77372
|
minimal: minimal_default
|
|
77265
77373
|
};
|
|
77266
|
-
var DEFAULT_COMPOSE_PATH2 =
|
|
77374
|
+
var DEFAULT_COMPOSE_PATH2 = join68(homedir38(), ".switchroom", "compose", "docker-compose.yml");
|
|
77267
77375
|
var COMPOSE_PROJECT2 = "switchroom";
|
|
77268
77376
|
function resolveVaultBindMountDir(homeDir, ctx) {
|
|
77269
77377
|
const isCustomPath = ctx.migrationKind === "custom-path-skipped";
|
|
77270
77378
|
if (isCustomPath && ctx.customVaultPath) {
|
|
77271
77379
|
return dirname21(ctx.customVaultPath);
|
|
77272
77380
|
}
|
|
77273
|
-
return
|
|
77381
|
+
return join68(homeDir, ".switchroom", "vault");
|
|
77274
77382
|
}
|
|
77275
77383
|
function inspectVaultBindMountDir(vaultDir) {
|
|
77276
77384
|
if (!existsSync69(vaultDir))
|
|
@@ -77301,42 +77409,42 @@ function hasVaultRefs(value) {
|
|
|
77301
77409
|
async function ensureHostMountSources(config) {
|
|
77302
77410
|
const home2 = homedir38();
|
|
77303
77411
|
const dirs = [
|
|
77304
|
-
|
|
77305
|
-
|
|
77306
|
-
|
|
77307
|
-
|
|
77308
|
-
|
|
77412
|
+
join68(home2, ".switchroom", "approvals"),
|
|
77413
|
+
join68(home2, ".switchroom", "scheduler"),
|
|
77414
|
+
join68(home2, ".switchroom", "logs"),
|
|
77415
|
+
join68(home2, ".switchroom", "compose"),
|
|
77416
|
+
join68(home2, ".switchroom", "broker-operator")
|
|
77309
77417
|
];
|
|
77310
77418
|
for (const name of Object.keys(config.agents)) {
|
|
77311
|
-
dirs.push(
|
|
77312
|
-
dirs.push(
|
|
77313
|
-
dirs.push(
|
|
77314
|
-
dirs.push(
|
|
77315
|
-
if (existsSync69(
|
|
77316
|
-
dirs.push(
|
|
77419
|
+
dirs.push(join68(home2, ".switchroom", "agents", name));
|
|
77420
|
+
dirs.push(join68(home2, ".switchroom", "logs", name));
|
|
77421
|
+
dirs.push(join68(home2, ".claude", "projects", name));
|
|
77422
|
+
dirs.push(join68(home2, ".switchroom", "audit", name));
|
|
77423
|
+
if (existsSync69(join68(home2, ".switchroom-config"))) {
|
|
77424
|
+
dirs.push(join68(home2, ".switchroom-config", "agents", name, "personal-skills"));
|
|
77317
77425
|
}
|
|
77318
77426
|
}
|
|
77319
77427
|
for (const dir of dirs) {
|
|
77320
77428
|
await mkdir(dir, { recursive: true });
|
|
77321
77429
|
}
|
|
77322
|
-
const autoUnlockPath =
|
|
77430
|
+
const autoUnlockPath = join68(home2, ".switchroom", "vault-auto-unlock");
|
|
77323
77431
|
if (!existsSync69(autoUnlockPath)) {
|
|
77324
77432
|
writeFileSync35(autoUnlockPath, "", { mode: 384 });
|
|
77325
77433
|
}
|
|
77326
|
-
const auditLogPath =
|
|
77434
|
+
const auditLogPath = join68(home2, ".switchroom", "vault-audit.log");
|
|
77327
77435
|
if (!existsSync69(auditLogPath)) {
|
|
77328
77436
|
writeFileSync35(auditLogPath, "", { mode: 420 });
|
|
77329
77437
|
}
|
|
77330
|
-
const grantsDbPath =
|
|
77438
|
+
const grantsDbPath = join68(home2, ".switchroom", "vault-grants.db");
|
|
77331
77439
|
if (!existsSync69(grantsDbPath)) {
|
|
77332
77440
|
writeFileSync35(grantsDbPath, "", { mode: 384 });
|
|
77333
77441
|
}
|
|
77334
|
-
const hostdAuditLogPath =
|
|
77442
|
+
const hostdAuditLogPath = join68(home2, ".switchroom", "host-control-audit.log");
|
|
77335
77443
|
if (!existsSync69(hostdAuditLogPath)) {
|
|
77336
77444
|
writeFileSync35(hostdAuditLogPath, "", { mode: 420 });
|
|
77337
77445
|
}
|
|
77338
77446
|
for (const name of Object.keys(config.agents)) {
|
|
77339
|
-
const tokenPath =
|
|
77447
|
+
const tokenPath = join68(home2, ".switchroom", "agents", name, ".vault-token");
|
|
77340
77448
|
if (!existsSync69(tokenPath)) {
|
|
77341
77449
|
writeFileSync35(tokenPath, "", { mode: 384 });
|
|
77342
77450
|
}
|
|
@@ -77345,15 +77453,15 @@ async function ensureHostMountSources(config) {
|
|
|
77345
77453
|
chownSync4(tokenPath, uid, uid);
|
|
77346
77454
|
} catch {}
|
|
77347
77455
|
}
|
|
77348
|
-
const fleetDir =
|
|
77456
|
+
const fleetDir = join68(home2, ".switchroom", "fleet");
|
|
77349
77457
|
await mkdir(fleetDir, { recursive: true });
|
|
77350
|
-
const invariantsPath =
|
|
77458
|
+
const invariantsPath = join68(fleetDir, "switchroom-invariants.md");
|
|
77351
77459
|
const invariantsCanonical = renderFleetInvariants();
|
|
77352
77460
|
const invariantsCurrent = existsSync69(invariantsPath) ? readFileSync56(invariantsPath, "utf-8") : null;
|
|
77353
77461
|
if (invariantsCurrent !== invariantsCanonical) {
|
|
77354
77462
|
writeFileSync35(invariantsPath, invariantsCanonical, { mode: 420 });
|
|
77355
77463
|
}
|
|
77356
|
-
const fleetClaudePath =
|
|
77464
|
+
const fleetClaudePath = join68(fleetDir, "CLAUDE.md");
|
|
77357
77465
|
if (!existsSync69(fleetClaudePath)) {
|
|
77358
77466
|
writeFileSync35(fleetClaudePath, [
|
|
77359
77467
|
"# Switchroom fleet defaults",
|
|
@@ -77438,8 +77546,8 @@ function detectAndReportLegacyGdriveSlots(vaultPath) {
|
|
|
77438
77546
|
}
|
|
77439
77547
|
function writeInstallTypeCache(homeDir = homedir38()) {
|
|
77440
77548
|
const ctx = detectInstallType();
|
|
77441
|
-
const dir =
|
|
77442
|
-
const out =
|
|
77549
|
+
const dir = join68(homeDir, ".switchroom");
|
|
77550
|
+
const out = join68(dir, "install-type.json");
|
|
77443
77551
|
const tmp = `${out}.tmp`;
|
|
77444
77552
|
mkdirSync38(dir, { recursive: true });
|
|
77445
77553
|
const payload = {
|
|
@@ -77488,14 +77596,14 @@ Applying switchroom config...
|
|
|
77488
77596
|
writeOut(source_default.green(` + ${name}`) + source_default.gray(` (${agentConfig.extends ?? "default"}) \u2014 ${detail}
|
|
77489
77597
|
`));
|
|
77490
77598
|
try {
|
|
77491
|
-
installUpdatePromptHook(
|
|
77599
|
+
installUpdatePromptHook(join68(agentsDir, name));
|
|
77492
77600
|
} catch (hookErr) {
|
|
77493
77601
|
writeOut(source_default.gray(` (update-prompt hook install failed for ${name}: ${hookErr.message})
|
|
77494
77602
|
`));
|
|
77495
77603
|
}
|
|
77496
77604
|
try {
|
|
77497
77605
|
const uid = allocateAgentUid(name);
|
|
77498
|
-
alignAgentUid(name,
|
|
77606
|
+
alignAgentUid(name, join68(agentsDir, name), uid, {
|
|
77499
77607
|
confirm: !options.nonInteractive,
|
|
77500
77608
|
writeOut
|
|
77501
77609
|
});
|
|
@@ -77532,7 +77640,7 @@ Applying switchroom config...
|
|
|
77532
77640
|
for (const name of agentNames) {
|
|
77533
77641
|
try {
|
|
77534
77642
|
const uid = allocateAgentUid(name);
|
|
77535
|
-
alignAgentUid(name,
|
|
77643
|
+
alignAgentUid(name, join68(agentsDir, name), uid, {
|
|
77536
77644
|
confirm: !options.nonInteractive,
|
|
77537
77645
|
writeOut
|
|
77538
77646
|
});
|
|
@@ -77684,7 +77792,7 @@ function copyExampleConfig2(name) {
|
|
|
77684
77792
|
if (!/^[a-z0-9_-]+$/.test(name)) {
|
|
77685
77793
|
throw new Error(`Invalid example name: ${name} (must match /^[a-z0-9_-]+$/)`);
|
|
77686
77794
|
}
|
|
77687
|
-
const dest =
|
|
77795
|
+
const dest = resolve43(process.cwd(), "switchroom.yaml");
|
|
77688
77796
|
if (existsSync69(dest)) {
|
|
77689
77797
|
console.error(source_default.yellow("switchroom.yaml already exists \u2014 skipping example copy"));
|
|
77690
77798
|
return;
|
|
@@ -77695,7 +77803,7 @@ function copyExampleConfig2(name) {
|
|
|
77695
77803
|
console.log(source_default.green(`Copied ${name}.yaml -> switchroom.yaml`));
|
|
77696
77804
|
return;
|
|
77697
77805
|
}
|
|
77698
|
-
const exampleFile =
|
|
77806
|
+
const exampleFile = resolve43(import.meta.dirname, `../../examples/${name}.yaml`);
|
|
77699
77807
|
if (!existsSync69(exampleFile)) {
|
|
77700
77808
|
throw new Error(`Example config not found: ${name}.yaml (available: ${Object.keys(EMBEDDED_EXAMPLES).join(", ")})`);
|
|
77701
77809
|
}
|
|
@@ -77707,7 +77815,7 @@ function findUnwritableAgentDirs(config, opts) {
|
|
|
77707
77815
|
const targets = opts.only ? [opts.only] : Object.keys(config.agents ?? {});
|
|
77708
77816
|
const unwritable = [];
|
|
77709
77817
|
for (const name of targets) {
|
|
77710
|
-
const startSh =
|
|
77818
|
+
const startSh = join68(agentsDir, name, "start.sh");
|
|
77711
77819
|
if (!existsSync69(startSh))
|
|
77712
77820
|
continue;
|
|
77713
77821
|
try {
|
|
@@ -77887,7 +77995,7 @@ function runRedactStdin() {
|
|
|
77887
77995
|
|
|
77888
77996
|
// src/cli/status-ask.ts
|
|
77889
77997
|
import { readFileSync as readFileSync57, existsSync as existsSync70, readdirSync as readdirSync26 } from "node:fs";
|
|
77890
|
-
import { join as
|
|
77998
|
+
import { join as join69 } from "node:path";
|
|
77891
77999
|
import { homedir as homedir39 } from "node:os";
|
|
77892
78000
|
|
|
77893
78001
|
// src/status-ask/report.ts
|
|
@@ -78223,7 +78331,7 @@ function resolveSources(explicitPath) {
|
|
|
78223
78331
|
const config = loadConfig();
|
|
78224
78332
|
agentsDir = resolveAgentsDir(config);
|
|
78225
78333
|
} catch {
|
|
78226
|
-
agentsDir =
|
|
78334
|
+
agentsDir = join69(homedir39(), ".switchroom", "agents");
|
|
78227
78335
|
}
|
|
78228
78336
|
if (!existsSync70(agentsDir))
|
|
78229
78337
|
return [];
|
|
@@ -78235,7 +78343,7 @@ function resolveSources(explicitPath) {
|
|
|
78235
78343
|
return [];
|
|
78236
78344
|
}
|
|
78237
78345
|
for (const name of entries) {
|
|
78238
|
-
const path8 =
|
|
78346
|
+
const path8 = join69(agentsDir, name, "runtime-metrics.jsonl");
|
|
78239
78347
|
if (existsSync70(path8)) {
|
|
78240
78348
|
sources.push({ path: path8, agent: name });
|
|
78241
78349
|
}
|
|
@@ -78257,7 +78365,7 @@ function inferAgentFromPath(p) {
|
|
|
78257
78365
|
|
|
78258
78366
|
// src/cli/agent-config.ts
|
|
78259
78367
|
init_helpers();
|
|
78260
|
-
import { join as
|
|
78368
|
+
import { join as join70 } from "node:path";
|
|
78261
78369
|
import { homedir as homedir40 } from "node:os";
|
|
78262
78370
|
import {
|
|
78263
78371
|
existsSync as existsSync71,
|
|
@@ -78265,9 +78373,9 @@ import {
|
|
|
78265
78373
|
appendFileSync as appendFileSync4,
|
|
78266
78374
|
readFileSync as readFileSync58
|
|
78267
78375
|
} from "node:fs";
|
|
78268
|
-
var AUDIT_ROOT =
|
|
78376
|
+
var AUDIT_ROOT = join70(homedir40(), ".switchroom", "audit");
|
|
78269
78377
|
function auditPathFor(agent) {
|
|
78270
|
-
return
|
|
78378
|
+
return join70(AUDIT_ROOT, agent, "agent-config.jsonl");
|
|
78271
78379
|
}
|
|
78272
78380
|
function appendAudit(agent, cmd, args, exit, opts = {}) {
|
|
78273
78381
|
const row = {
|
|
@@ -78525,21 +78633,21 @@ import {
|
|
|
78525
78633
|
unlinkSync as unlinkSync14,
|
|
78526
78634
|
writeSync as writeSync8
|
|
78527
78635
|
} from "node:fs";
|
|
78528
|
-
import { join as
|
|
78636
|
+
import { join as join71, resolve as resolve44 } from "node:path";
|
|
78529
78637
|
var STAGING_SUBDIR = ".staging";
|
|
78530
78638
|
function overlayPathsFor(agent, opts = {}) {
|
|
78531
|
-
const base = opts.root ?
|
|
78532
|
-
const scheduleDir =
|
|
78533
|
-
const scheduleStagingDir =
|
|
78534
|
-
const skillsDir =
|
|
78535
|
-
const skillsStagingDir =
|
|
78639
|
+
const base = opts.root ? resolve44(opts.root, agent) : resolve44(resolveDualPath(`~/.switchroom/agents/${agent}`));
|
|
78640
|
+
const scheduleDir = join71(base, "schedule.d");
|
|
78641
|
+
const scheduleStagingDir = join71(scheduleDir, STAGING_SUBDIR);
|
|
78642
|
+
const skillsDir = join71(base, "skills.d");
|
|
78643
|
+
const skillsStagingDir = join71(skillsDir, STAGING_SUBDIR);
|
|
78536
78644
|
return {
|
|
78537
78645
|
agentRoot: base,
|
|
78538
78646
|
scheduleDir,
|
|
78539
78647
|
scheduleStagingDir,
|
|
78540
78648
|
skillsDir,
|
|
78541
78649
|
skillsStagingDir,
|
|
78542
|
-
lockPath:
|
|
78650
|
+
lockPath: join71(base, ".lock"),
|
|
78543
78651
|
stagingDir: scheduleStagingDir
|
|
78544
78652
|
};
|
|
78545
78653
|
}
|
|
@@ -78593,8 +78701,8 @@ function writeOverlayEntry(agent, slug, yamlText, opts = {}) {
|
|
|
78593
78701
|
const paths = overlayPathsFor(agent, opts);
|
|
78594
78702
|
return withAgentLock(paths, () => {
|
|
78595
78703
|
ensureDirs(paths);
|
|
78596
|
-
const stagingPath =
|
|
78597
|
-
const finalPath =
|
|
78704
|
+
const stagingPath = join71(paths.scheduleStagingDir, `${slug}.yaml`);
|
|
78705
|
+
const finalPath = join71(paths.scheduleDir, `${slug}.yaml`);
|
|
78598
78706
|
const fd = openSync13(stagingPath, "w", 384);
|
|
78599
78707
|
try {
|
|
78600
78708
|
writeSync8(fd, yamlText);
|
|
@@ -78610,8 +78718,8 @@ function writeSkillsOverlayEntry(agent, slug, yamlText, opts = {}) {
|
|
|
78610
78718
|
const paths = overlayPathsFor(agent, opts);
|
|
78611
78719
|
return withAgentLock(paths, () => {
|
|
78612
78720
|
ensureSkillsDirs(paths);
|
|
78613
|
-
const stagingPath =
|
|
78614
|
-
const finalPath =
|
|
78721
|
+
const stagingPath = join71(paths.skillsStagingDir, `${slug}.yaml`);
|
|
78722
|
+
const finalPath = join71(paths.skillsDir, `${slug}.yaml`);
|
|
78615
78723
|
const fd = openSync13(stagingPath, "w", 384);
|
|
78616
78724
|
try {
|
|
78617
78725
|
writeSync8(fd, yamlText);
|
|
@@ -78626,7 +78734,7 @@ function writeSkillsOverlayEntry(agent, slug, yamlText, opts = {}) {
|
|
|
78626
78734
|
function deleteSkillsOverlayEntry(agent, slug, opts = {}) {
|
|
78627
78735
|
const paths = overlayPathsFor(agent, opts);
|
|
78628
78736
|
return withAgentLock(paths, () => {
|
|
78629
|
-
const finalPath =
|
|
78737
|
+
const finalPath = join71(paths.skillsDir, `${slug}.yaml`);
|
|
78630
78738
|
if (!existsSync72(finalPath))
|
|
78631
78739
|
return false;
|
|
78632
78740
|
unlinkSync14(finalPath);
|
|
@@ -78641,7 +78749,7 @@ function listSkillsOverlayEntries(agent, opts = {}) {
|
|
|
78641
78749
|
for (const name of readdirSync27(paths.skillsDir)) {
|
|
78642
78750
|
if (!/\.ya?ml$/i.test(name))
|
|
78643
78751
|
continue;
|
|
78644
|
-
const full =
|
|
78752
|
+
const full = join71(paths.skillsDir, name);
|
|
78645
78753
|
try {
|
|
78646
78754
|
const raw = readFileSync59(full, "utf-8");
|
|
78647
78755
|
const slug = name.replace(/\.ya?ml$/i, "");
|
|
@@ -78653,7 +78761,7 @@ function listSkillsOverlayEntries(agent, opts = {}) {
|
|
|
78653
78761
|
function deleteOverlayEntry(agent, slug, opts = {}) {
|
|
78654
78762
|
const paths = overlayPathsFor(agent, opts);
|
|
78655
78763
|
return withAgentLock(paths, () => {
|
|
78656
|
-
const finalPath =
|
|
78764
|
+
const finalPath = join71(paths.scheduleDir, `${slug}.yaml`);
|
|
78657
78765
|
if (!existsSync72(finalPath))
|
|
78658
78766
|
return false;
|
|
78659
78767
|
unlinkSync14(finalPath);
|
|
@@ -78668,7 +78776,7 @@ function listOverlayEntries(agent, opts = {}) {
|
|
|
78668
78776
|
for (const name of readdirSync27(paths.scheduleDir)) {
|
|
78669
78777
|
if (!/\.ya?ml$/i.test(name))
|
|
78670
78778
|
continue;
|
|
78671
|
-
const full =
|
|
78779
|
+
const full = join71(paths.scheduleDir, name);
|
|
78672
78780
|
try {
|
|
78673
78781
|
const raw = readFileSync59(full, "utf-8");
|
|
78674
78782
|
const slug = name.replace(/\.ya?ml$/i, "");
|
|
@@ -78824,12 +78932,12 @@ import {
|
|
|
78824
78932
|
writeFileSync as writeFileSync36,
|
|
78825
78933
|
writeSync as writeSync9
|
|
78826
78934
|
} from "node:fs";
|
|
78827
|
-
import { join as
|
|
78935
|
+
import { join as join72 } from "node:path";
|
|
78828
78936
|
import { randomBytes as randomBytes14 } from "node:crypto";
|
|
78829
78937
|
var STAGE_ID_PREFIX = "cap_";
|
|
78830
78938
|
function pendingDir(agent, opts = {}) {
|
|
78831
78939
|
const paths = overlayPathsFor(agent, opts);
|
|
78832
|
-
return
|
|
78940
|
+
return join72(paths.scheduleDir, ".pending");
|
|
78833
78941
|
}
|
|
78834
78942
|
function ensurePendingDir(agent, opts = {}) {
|
|
78835
78943
|
const dir = pendingDir(agent, opts);
|
|
@@ -78842,8 +78950,8 @@ function newStageId() {
|
|
|
78842
78950
|
function stagePendingScheduleEntry(opts) {
|
|
78843
78951
|
const dir = ensurePendingDir(opts.agent, { root: opts.root });
|
|
78844
78952
|
const stageId = opts.stageId ?? newStageId();
|
|
78845
|
-
const yamlPath =
|
|
78846
|
-
const metaPath =
|
|
78953
|
+
const yamlPath = join72(dir, `${stageId}.yaml`);
|
|
78954
|
+
const metaPath = join72(dir, `${stageId}.meta.json`);
|
|
78847
78955
|
const meta = {
|
|
78848
78956
|
v: 1,
|
|
78849
78957
|
stage_id: stageId,
|
|
@@ -78877,8 +78985,8 @@ function listPendingScheduleEntries(agent, opts = {}) {
|
|
|
78877
78985
|
if (!name.endsWith(".meta.json"))
|
|
78878
78986
|
continue;
|
|
78879
78987
|
const stageId = name.slice(0, -".meta.json".length);
|
|
78880
|
-
const metaPath =
|
|
78881
|
-
const yamlPath =
|
|
78988
|
+
const metaPath = join72(dir, name);
|
|
78989
|
+
const yamlPath = join72(dir, `${stageId}.yaml`);
|
|
78882
78990
|
if (!existsSync73(yamlPath))
|
|
78883
78991
|
continue;
|
|
78884
78992
|
try {
|
|
@@ -78897,7 +79005,7 @@ function commitPendingScheduleEntry(opts) {
|
|
|
78897
79005
|
return { committed: false, reason: "not_found" };
|
|
78898
79006
|
const slug = match.meta.entry.name ?? match.stageId;
|
|
78899
79007
|
const paths = overlayPathsFor(opts.agent, { root: opts.root });
|
|
78900
|
-
const finalPath =
|
|
79008
|
+
const finalPath = join72(paths.scheduleDir, `${slug}.yaml`);
|
|
78901
79009
|
if (existsSync73(finalPath)) {
|
|
78902
79010
|
return { committed: false, reason: "slug_collision" };
|
|
78903
79011
|
}
|
|
@@ -79403,7 +79511,7 @@ var import_yaml16 = __toESM(require_dist(), 1);
|
|
|
79403
79511
|
import { existsSync as existsSync75 } from "node:fs";
|
|
79404
79512
|
init_reconcile_default_skills();
|
|
79405
79513
|
var import_yaml17 = __toESM(require_dist(), 1);
|
|
79406
|
-
import { join as
|
|
79514
|
+
import { join as join73 } from "node:path";
|
|
79407
79515
|
var MAX_SKILLS_PER_AGENT = 20;
|
|
79408
79516
|
var V1_ALLOWED_SOURCE_PREFIX = "bundled:";
|
|
79409
79517
|
function exitCodeFor2(code) {
|
|
@@ -79478,7 +79586,7 @@ function skillInstall(opts) {
|
|
|
79478
79586
|
return err("E_SKILL_QUOTA_EXCEEDED", `agent ${agent} already has ${used} overlay-installed skills (cap ${MAX_SKILLS_PER_AGENT})`);
|
|
79479
79587
|
}
|
|
79480
79588
|
const poolDir = opts.bundledSkillsPoolDir ?? getBundledSkillsPoolDir();
|
|
79481
|
-
const skillPath =
|
|
79589
|
+
const skillPath = join73(poolDir, skillName);
|
|
79482
79590
|
if (!existsSync75(skillPath)) {
|
|
79483
79591
|
return err("E_SKILL_NOT_FOUND", `bundled skill not found at ${skillPath}. The operator needs to ` + `place the skill at this path before the agent can opt in.`);
|
|
79484
79592
|
}
|
|
@@ -79657,7 +79765,7 @@ import {
|
|
|
79657
79765
|
writeFileSync as writeFileSync37
|
|
79658
79766
|
} from "node:fs";
|
|
79659
79767
|
import { tmpdir as tmpdir4, homedir as homedir41 } from "node:os";
|
|
79660
|
-
import { dirname as dirname22, join as
|
|
79768
|
+
import { dirname as dirname22, join as join74, relative as relative2, resolve as resolve45 } from "node:path";
|
|
79661
79769
|
import { spawnSync as spawnSync10 } from "node:child_process";
|
|
79662
79770
|
|
|
79663
79771
|
// src/cli/skill-common.ts
|
|
@@ -79851,11 +79959,11 @@ function scanForClaudeP2(content) {
|
|
|
79851
79959
|
function resolveSkillsPoolDir2(override) {
|
|
79852
79960
|
const raw = override ?? "~/.switchroom/skills";
|
|
79853
79961
|
if (raw.startsWith("~/")) {
|
|
79854
|
-
return
|
|
79962
|
+
return join74(homedir41(), raw.slice(2));
|
|
79855
79963
|
}
|
|
79856
79964
|
if (raw === "~")
|
|
79857
79965
|
return homedir41();
|
|
79858
|
-
return
|
|
79966
|
+
return resolve45(raw);
|
|
79859
79967
|
}
|
|
79860
79968
|
function readStdinSync() {
|
|
79861
79969
|
const chunks = [];
|
|
@@ -79890,7 +79998,7 @@ function loadFromDir(dir) {
|
|
|
79890
79998
|
const walk2 = (sub) => {
|
|
79891
79999
|
const entries = readdirSync29(sub, { withFileTypes: true });
|
|
79892
80000
|
for (const ent of entries) {
|
|
79893
|
-
const full =
|
|
80001
|
+
const full = join74(sub, ent.name);
|
|
79894
80002
|
const rel = relative2(abs, full);
|
|
79895
80003
|
if (ent.isSymbolicLink()) {
|
|
79896
80004
|
fail2(`refusing to read symlink inside --from dir: ${rel}`);
|
|
@@ -79925,7 +80033,7 @@ function loadFromTarball(tarPath) {
|
|
|
79925
80033
|
fail2(`tarball contains disallowed path: ${JSON.stringify(entry)} \u2014 ` + `refusing to extract before any file is written`);
|
|
79926
80034
|
}
|
|
79927
80035
|
}
|
|
79928
|
-
const staging = mkdtempSync5(
|
|
80036
|
+
const staging = mkdtempSync5(join74(tmpdir4(), "skill-apply-extract-"));
|
|
79929
80037
|
try {
|
|
79930
80038
|
const flags = isGz ? ["-xzf"] : ["-xf"];
|
|
79931
80039
|
const r = spawnSync10("tar", [
|
|
@@ -80011,8 +80119,8 @@ function validatePayload(name, files) {
|
|
|
80011
80119
|
errors2.push(`${path8} fails \`bash -n\` syntax check: ${(r.stderr ?? "").trim()}`);
|
|
80012
80120
|
}
|
|
80013
80121
|
} else if (PY_SCRIPT_RE2.test(path8)) {
|
|
80014
|
-
const tmp = mkdtempSync5(
|
|
80015
|
-
const tmpPy =
|
|
80122
|
+
const tmp = mkdtempSync5(join74(tmpdir4(), "skill-apply-py-"));
|
|
80123
|
+
const tmpPy = join74(tmp, "check.py");
|
|
80016
80124
|
try {
|
|
80017
80125
|
writeFileSync37(tmpPy, content);
|
|
80018
80126
|
const r = spawnSync10("python3", ["-m", "py_compile", tmpPy], {
|
|
@@ -80035,7 +80143,7 @@ function diffSummary(currentDir, files) {
|
|
|
80035
80143
|
if (existsSync76(currentDir)) {
|
|
80036
80144
|
const walk2 = (sub) => {
|
|
80037
80145
|
for (const ent of readdirSync29(sub, { withFileTypes: true })) {
|
|
80038
|
-
const full =
|
|
80146
|
+
const full = join74(sub, ent.name);
|
|
80039
80147
|
const rel = relative2(currentDir, full);
|
|
80040
80148
|
if (ent.isDirectory()) {
|
|
80041
80149
|
walk2(full);
|
|
@@ -80071,7 +80179,7 @@ function writePayload(poolDir, name, files) {
|
|
|
80071
80179
|
if (!existsSync76(poolDir)) {
|
|
80072
80180
|
mkdirSync42(poolDir, { recursive: true, mode: 493 });
|
|
80073
80181
|
}
|
|
80074
|
-
const target =
|
|
80182
|
+
const target = join74(poolDir, name);
|
|
80075
80183
|
let targetIsSymlink = false;
|
|
80076
80184
|
try {
|
|
80077
80185
|
const st = lstatSync8(target);
|
|
@@ -80082,11 +80190,11 @@ function writePayload(poolDir, name, files) {
|
|
|
80082
80190
|
if (targetIsSymlink) {
|
|
80083
80191
|
fail2(`refusing to overwrite symlink at ${target}; investigate manually`);
|
|
80084
80192
|
}
|
|
80085
|
-
const staging = mkdtempSync5(
|
|
80193
|
+
const staging = mkdtempSync5(join74(poolDir, `.skill-apply-stage-${name}-`));
|
|
80086
80194
|
let oldRename = null;
|
|
80087
80195
|
try {
|
|
80088
80196
|
for (const [path8, content] of Object.entries(files)) {
|
|
80089
|
-
const full =
|
|
80197
|
+
const full = join74(staging, path8);
|
|
80090
80198
|
mkdirSync42(dirname22(full), { recursive: true, mode: 493 });
|
|
80091
80199
|
const fd = openSync15(full, "wx");
|
|
80092
80200
|
try {
|
|
@@ -80139,7 +80247,7 @@ function registerSkillCommand(program3) {
|
|
|
80139
80247
|
if (opts.from === undefined) {
|
|
80140
80248
|
files = loadFromStdin();
|
|
80141
80249
|
} else {
|
|
80142
|
-
const fromPath =
|
|
80250
|
+
const fromPath = resolve45(opts.from);
|
|
80143
80251
|
if (!existsSync76(fromPath)) {
|
|
80144
80252
|
fail2(`--from path does not exist: ${opts.from}`);
|
|
80145
80253
|
}
|
|
@@ -80164,7 +80272,7 @@ function registerSkillCommand(program3) {
|
|
|
80164
80272
|
}
|
|
80165
80273
|
const config = loadConfig();
|
|
80166
80274
|
const poolDir = resolveSkillsPoolDir2(config.switchroom?.skills_dir);
|
|
80167
|
-
const currentDir =
|
|
80275
|
+
const currentDir = join74(poolDir, name);
|
|
80168
80276
|
console.log(source_default.bold(`Skill: ${name}`) + source_default.gray(` (${Object.keys(files).length} files, ${sumBytes(files)} bytes)`));
|
|
80169
80277
|
console.log(source_default.bold("Diff vs current pool content:"));
|
|
80170
80278
|
console.log(diffSummary(currentDir, files));
|
|
@@ -80208,7 +80316,7 @@ import {
|
|
|
80208
80316
|
utimesSync,
|
|
80209
80317
|
writeFileSync as writeFileSync38
|
|
80210
80318
|
} from "node:fs";
|
|
80211
|
-
import { dirname as dirname23, join as
|
|
80319
|
+
import { dirname as dirname23, join as join75, relative as relative3, resolve as resolve46 } from "node:path";
|
|
80212
80320
|
import { homedir as homedir42, tmpdir as tmpdir5 } from "node:os";
|
|
80213
80321
|
import { spawnSync as spawnSync11 } from "node:child_process";
|
|
80214
80322
|
init_helpers();
|
|
@@ -80219,10 +80327,10 @@ var TRASH_TTL_MS = 24 * 60 * 60 * 1000;
|
|
|
80219
80327
|
var PERSONAL_SKILLS_SUBPATH = "personal-skills";
|
|
80220
80328
|
function resolveConfigSkillsDir(agent) {
|
|
80221
80329
|
const override = process.env.SWITCHROOM_CONFIG_DIR;
|
|
80222
|
-
const candidate = override ?
|
|
80330
|
+
const candidate = override ? resolve46(override) : join75(homedir42(), ".switchroom-config");
|
|
80223
80331
|
if (!existsSync77(candidate))
|
|
80224
80332
|
return null;
|
|
80225
|
-
return
|
|
80333
|
+
return join75(candidate, "agents", agent, PERSONAL_SKILLS_SUBPATH);
|
|
80226
80334
|
}
|
|
80227
80335
|
var MIRROR_PRIOR_TTL_MS = 24 * 60 * 60 * 1000;
|
|
80228
80336
|
function sweepMirrorPriors(configSkillsRoot) {
|
|
@@ -80240,7 +80348,7 @@ function sweepMirrorPriors(configSkillsRoot) {
|
|
|
80240
80348
|
if (now - ts < MIRROR_PRIOR_TTL_MS)
|
|
80241
80349
|
continue;
|
|
80242
80350
|
try {
|
|
80243
|
-
rmSync17(
|
|
80351
|
+
rmSync17(join75(configSkillsRoot, ent), { recursive: true, force: true });
|
|
80244
80352
|
} catch {}
|
|
80245
80353
|
}
|
|
80246
80354
|
} catch {}
|
|
@@ -80249,7 +80357,7 @@ function mirrorToConfigRepo(agent, name, liveSkillDir) {
|
|
|
80249
80357
|
const configSkillsRoot = resolveConfigSkillsDir(agent);
|
|
80250
80358
|
if (!configSkillsRoot)
|
|
80251
80359
|
return;
|
|
80252
|
-
const dest =
|
|
80360
|
+
const dest = join75(configSkillsRoot, name);
|
|
80253
80361
|
try {
|
|
80254
80362
|
if (liveSkillDir !== null) {
|
|
80255
80363
|
try {
|
|
@@ -80264,19 +80372,19 @@ function mirrorToConfigRepo(agent, name, liveSkillDir) {
|
|
|
80264
80372
|
if (liveSkillDir === null) {
|
|
80265
80373
|
sweepMirrorPriors(configSkillsRoot);
|
|
80266
80374
|
if (existsSync77(dest)) {
|
|
80267
|
-
const trash =
|
|
80375
|
+
const trash = join75(configSkillsRoot, `.${name}-trash-${Date.now()}`);
|
|
80268
80376
|
renameSync17(dest, trash);
|
|
80269
80377
|
}
|
|
80270
80378
|
return;
|
|
80271
80379
|
}
|
|
80272
80380
|
mkdirSync43(configSkillsRoot, { recursive: true, mode: 493 });
|
|
80273
80381
|
sweepMirrorPriors(configSkillsRoot);
|
|
80274
|
-
const staging = mkdtempSync6(
|
|
80382
|
+
const staging = mkdtempSync6(join75(configSkillsRoot, `.${name}-staging-`));
|
|
80275
80383
|
const walk2 = (src, dst) => {
|
|
80276
80384
|
mkdirSync43(dst, { recursive: true, mode: 493 });
|
|
80277
80385
|
for (const ent of readdirSync30(src, { withFileTypes: true })) {
|
|
80278
|
-
const s =
|
|
80279
|
-
const d =
|
|
80386
|
+
const s = join75(src, ent.name);
|
|
80387
|
+
const d = join75(dst, ent.name);
|
|
80280
80388
|
if (ent.isSymbolicLink())
|
|
80281
80389
|
continue;
|
|
80282
80390
|
if (ent.isDirectory())
|
|
@@ -80288,7 +80396,7 @@ function mirrorToConfigRepo(agent, name, liveSkillDir) {
|
|
|
80288
80396
|
};
|
|
80289
80397
|
walk2(liveSkillDir, staging);
|
|
80290
80398
|
if (existsSync77(dest)) {
|
|
80291
|
-
const prior =
|
|
80399
|
+
const prior = join75(configSkillsRoot, `.${name}-prior-${Date.now()}`);
|
|
80292
80400
|
renameSync17(dest, prior);
|
|
80293
80401
|
}
|
|
80294
80402
|
renameSync17(staging, dest);
|
|
@@ -80314,14 +80422,14 @@ function resolveAgent(opts) {
|
|
|
80314
80422
|
}
|
|
80315
80423
|
function resolveAgentsRoot(opts) {
|
|
80316
80424
|
if (opts.root)
|
|
80317
|
-
return
|
|
80318
|
-
return
|
|
80425
|
+
return resolve46(opts.root);
|
|
80426
|
+
return join75(homedir42(), ".switchroom", "agents");
|
|
80319
80427
|
}
|
|
80320
80428
|
function personalSkillDir(agentsRoot, agent, name) {
|
|
80321
|
-
return
|
|
80429
|
+
return join75(agentsRoot, agent, ".claude", "skills", PERSONAL_PREFIX + name);
|
|
80322
80430
|
}
|
|
80323
80431
|
function trashDir(agentsRoot, agent) {
|
|
80324
|
-
return
|
|
80432
|
+
return join75(agentsRoot, agent, ".claude", TRASH_DIRNAME);
|
|
80325
80433
|
}
|
|
80326
80434
|
function readStdinSync2() {
|
|
80327
80435
|
const chunks = [];
|
|
@@ -80344,14 +80452,14 @@ function readStdinSync2() {
|
|
|
80344
80452
|
return Buffer.concat(chunks).toString("utf-8");
|
|
80345
80453
|
}
|
|
80346
80454
|
function loadFromDir2(dir) {
|
|
80347
|
-
const abs =
|
|
80455
|
+
const abs = resolve46(dir);
|
|
80348
80456
|
if (!statSync30(abs).isDirectory()) {
|
|
80349
80457
|
fail3(`--from path is not a directory: ${dir}`);
|
|
80350
80458
|
}
|
|
80351
80459
|
const files = {};
|
|
80352
80460
|
const walk2 = (sub) => {
|
|
80353
80461
|
for (const ent of readdirSync30(sub, { withFileTypes: true })) {
|
|
80354
|
-
const full =
|
|
80462
|
+
const full = join75(sub, ent.name);
|
|
80355
80463
|
if (ent.isSymbolicLink()) {
|
|
80356
80464
|
fail3(`refusing to read symlink in --from dir: ${relative3(abs, full)}`);
|
|
80357
80465
|
}
|
|
@@ -80404,8 +80512,8 @@ function behavioralValidate(files) {
|
|
|
80404
80512
|
errors2.push(`${path8} fails \`bash -n\`: ${(r.stderr ?? "").trim()}`);
|
|
80405
80513
|
}
|
|
80406
80514
|
} else if (PY_SCRIPT_RE.test(path8)) {
|
|
80407
|
-
const tmp = mkdtempSync6(
|
|
80408
|
-
const tmpPy =
|
|
80515
|
+
const tmp = mkdtempSync6(join75(tmpdir5(), "skill-personal-py-"));
|
|
80516
|
+
const tmpPy = join75(tmp, "check.py");
|
|
80409
80517
|
try {
|
|
80410
80518
|
writeFileSync38(tmpPy, content);
|
|
80411
80519
|
const r = spawnSync11("python3", ["-m", "py_compile", tmpPy], {
|
|
@@ -80429,7 +80537,7 @@ function sweepTrash(agentsRoot, agent) {
|
|
|
80429
80537
|
for (const ent of readdirSync30(trash, { withFileTypes: true })) {
|
|
80430
80538
|
if (!ent.isDirectory())
|
|
80431
80539
|
continue;
|
|
80432
|
-
const entPath =
|
|
80540
|
+
const entPath = join75(trash, ent.name);
|
|
80433
80541
|
try {
|
|
80434
80542
|
const st = statSync30(entPath);
|
|
80435
80543
|
if (now - st.mtimeMs > TRASH_TTL_MS) {
|
|
@@ -80450,11 +80558,11 @@ function writePersonalSkill(targetDir, files) {
|
|
|
80450
80558
|
fail3(`refusing to overwrite symlink at ${targetDir}; investigate manually`);
|
|
80451
80559
|
}
|
|
80452
80560
|
mkdirSync43(dirname23(targetDir), { recursive: true, mode: 493 });
|
|
80453
|
-
const staging = mkdtempSync6(
|
|
80561
|
+
const staging = mkdtempSync6(join75(dirname23(targetDir), `.skill-personal-stage-`));
|
|
80454
80562
|
let oldRename = null;
|
|
80455
80563
|
try {
|
|
80456
80564
|
for (const [path8, content] of Object.entries(files)) {
|
|
80457
|
-
const full =
|
|
80565
|
+
const full = join75(staging, path8);
|
|
80458
80566
|
mkdirSync43(dirname23(full), { recursive: true, mode: 493 });
|
|
80459
80567
|
const fd = openSync16(full, "wx");
|
|
80460
80568
|
try {
|
|
@@ -80538,7 +80646,7 @@ function loadFiles(opts) {
|
|
|
80538
80646
|
if (opts.from === undefined) {
|
|
80539
80647
|
return loadFromStdin2();
|
|
80540
80648
|
}
|
|
80541
|
-
const p =
|
|
80649
|
+
const p = resolve46(opts.from);
|
|
80542
80650
|
if (!existsSync77(p)) {
|
|
80543
80651
|
fail3(`--from path does not exist: ${opts.from}`);
|
|
80544
80652
|
}
|
|
@@ -80587,10 +80695,10 @@ function editPersonalAction(name, opts) {
|
|
|
80587
80695
|
}
|
|
80588
80696
|
var CLONE_SOURCE_RE = /^(shared|bundled):([a-z0-9][a-z0-9_-]{0,62})$/;
|
|
80589
80697
|
function defaultSharedRoot() {
|
|
80590
|
-
return
|
|
80698
|
+
return join75(homedir42(), ".switchroom", "skills");
|
|
80591
80699
|
}
|
|
80592
80700
|
function defaultBundledRoot() {
|
|
80593
|
-
return
|
|
80701
|
+
return join75(homedir42(), ".switchroom", "skills", "_bundled");
|
|
80594
80702
|
}
|
|
80595
80703
|
function resolveCloneSource(source, opts) {
|
|
80596
80704
|
const m = CLONE_SOURCE_RE.exec(source);
|
|
@@ -80600,7 +80708,7 @@ function resolveCloneSource(source, opts) {
|
|
|
80600
80708
|
const tier = m[1];
|
|
80601
80709
|
const slug = m[2];
|
|
80602
80710
|
const root = tier === "bundled" ? opts.bundledRoot ?? defaultBundledRoot() : opts.sharedRoot ?? defaultSharedRoot();
|
|
80603
|
-
const dir =
|
|
80711
|
+
const dir = join75(root, slug);
|
|
80604
80712
|
if (!existsSync77(dir)) {
|
|
80605
80713
|
fail3(`clone source ${JSON.stringify(source)} not found at ${dir}; ` + `check \`switchroom skill search --tier ${tier}\``, 1);
|
|
80606
80714
|
}
|
|
@@ -80616,7 +80724,7 @@ function readSourceFiles(dir) {
|
|
|
80616
80724
|
const skipped = [];
|
|
80617
80725
|
const walk2 = (sub) => {
|
|
80618
80726
|
for (const ent of readdirSync30(sub, { withFileTypes: true })) {
|
|
80619
|
-
const full =
|
|
80727
|
+
const full = join75(sub, ent.name);
|
|
80620
80728
|
if (ent.isSymbolicLink()) {
|
|
80621
80729
|
continue;
|
|
80622
80730
|
}
|
|
@@ -80727,7 +80835,7 @@ function removePersonalAction(name, opts) {
|
|
|
80727
80835
|
const trashRoot = trashDir(agentsRoot, agent);
|
|
80728
80836
|
mkdirSync43(trashRoot, { recursive: true, mode: 493 });
|
|
80729
80837
|
const ts = Date.now();
|
|
80730
|
-
const trashTarget =
|
|
80838
|
+
const trashTarget = join75(trashRoot, `${name}-${ts}`);
|
|
80731
80839
|
renameSync17(target, trashTarget);
|
|
80732
80840
|
const now = new Date(ts);
|
|
80733
80841
|
utimesSync(trashTarget, now, now);
|
|
@@ -80746,7 +80854,7 @@ function listPersonalAction(opts) {
|
|
|
80746
80854
|
const agent = resolveAgent(opts);
|
|
80747
80855
|
const agentsRoot = resolveAgentsRoot(opts);
|
|
80748
80856
|
sweepTrash(agentsRoot, agent);
|
|
80749
|
-
const skillsDir =
|
|
80857
|
+
const skillsDir = join75(agentsRoot, agent, ".claude", "skills");
|
|
80750
80858
|
const personal = [];
|
|
80751
80859
|
if (existsSync77(skillsDir)) {
|
|
80752
80860
|
for (const ent of readdirSync30(skillsDir, { withFileTypes: true })) {
|
|
@@ -80755,7 +80863,7 @@ function listPersonalAction(opts) {
|
|
|
80755
80863
|
if (!ent.name.startsWith(PERSONAL_PREFIX))
|
|
80756
80864
|
continue;
|
|
80757
80865
|
const skillName = ent.name.slice(PERSONAL_PREFIX.length);
|
|
80758
|
-
const skillPath =
|
|
80866
|
+
const skillPath = join75(skillsDir, ent.name);
|
|
80759
80867
|
let fileCount = 0;
|
|
80760
80868
|
let totalBytes = 0;
|
|
80761
80869
|
const walk2 = (sub) => {
|
|
@@ -80763,10 +80871,10 @@ function listPersonalAction(opts) {
|
|
|
80763
80871
|
if (e.isFile()) {
|
|
80764
80872
|
fileCount += 1;
|
|
80765
80873
|
try {
|
|
80766
|
-
totalBytes += statSync30(
|
|
80874
|
+
totalBytes += statSync30(join75(sub, e.name)).size;
|
|
80767
80875
|
} catch {}
|
|
80768
80876
|
} else if (e.isDirectory()) {
|
|
80769
|
-
walk2(
|
|
80877
|
+
walk2(join75(sub, e.name));
|
|
80770
80878
|
}
|
|
80771
80879
|
}
|
|
80772
80880
|
};
|
|
@@ -80807,21 +80915,21 @@ init_helpers();
|
|
|
80807
80915
|
var import_yaml19 = __toESM(require_dist(), 1);
|
|
80808
80916
|
import { existsSync as existsSync78, readdirSync as readdirSync31, readFileSync as readFileSync64, statSync as statSync31 } from "node:fs";
|
|
80809
80917
|
import { homedir as homedir43 } from "node:os";
|
|
80810
|
-
import { join as
|
|
80918
|
+
import { join as join76, resolve as resolve47 } from "node:path";
|
|
80811
80919
|
var PERSONAL_PREFIX2 = "personal-";
|
|
80812
80920
|
var BUNDLED_SUBDIR = "_bundled";
|
|
80813
80921
|
var AGENT_NAME_RE3 = /^[a-z][a-z0-9_-]{0,62}$/;
|
|
80814
80922
|
function defaultAgentsRoot() {
|
|
80815
|
-
return
|
|
80923
|
+
return resolve47(homedir43(), ".switchroom/agents");
|
|
80816
80924
|
}
|
|
80817
80925
|
function defaultSharedRoot2() {
|
|
80818
|
-
return
|
|
80926
|
+
return resolve47(homedir43(), ".switchroom/skills");
|
|
80819
80927
|
}
|
|
80820
80928
|
function defaultBundledRoot2() {
|
|
80821
|
-
return
|
|
80929
|
+
return resolve47(homedir43(), ".switchroom/skills/_bundled");
|
|
80822
80930
|
}
|
|
80823
80931
|
function readSkillFrontmatter(skillDir) {
|
|
80824
|
-
const mdPath =
|
|
80932
|
+
const mdPath = join76(skillDir, "SKILL.md");
|
|
80825
80933
|
if (!existsSync78(mdPath))
|
|
80826
80934
|
return null;
|
|
80827
80935
|
let content;
|
|
@@ -80854,7 +80962,7 @@ function readSkillFrontmatter(skillDir) {
|
|
|
80854
80962
|
return { fm: parsed };
|
|
80855
80963
|
}
|
|
80856
80964
|
function statSkillMd(skillDir) {
|
|
80857
|
-
const mdPath =
|
|
80965
|
+
const mdPath = join76(skillDir, "SKILL.md");
|
|
80858
80966
|
try {
|
|
80859
80967
|
const st = statSync31(mdPath);
|
|
80860
80968
|
return { size: st.size, mtime: st.mtime.toISOString() };
|
|
@@ -80865,7 +80973,7 @@ function statSkillMd(skillDir) {
|
|
|
80865
80973
|
function listPersonalSkills(agent, agentsRoot = defaultAgentsRoot()) {
|
|
80866
80974
|
if (!AGENT_NAME_RE3.test(agent))
|
|
80867
80975
|
return [];
|
|
80868
|
-
const skillsDir =
|
|
80976
|
+
const skillsDir = join76(agentsRoot, agent, ".claude/skills");
|
|
80869
80977
|
if (!existsSync78(skillsDir))
|
|
80870
80978
|
return [];
|
|
80871
80979
|
const out = [];
|
|
@@ -80878,7 +80986,7 @@ function listPersonalSkills(agent, agentsRoot = defaultAgentsRoot()) {
|
|
|
80878
80986
|
for (const ent of entries) {
|
|
80879
80987
|
if (!ent.startsWith(PERSONAL_PREFIX2))
|
|
80880
80988
|
continue;
|
|
80881
|
-
const dirPath =
|
|
80989
|
+
const dirPath = join76(skillsDir, ent);
|
|
80882
80990
|
try {
|
|
80883
80991
|
if (!statSync31(dirPath).isDirectory())
|
|
80884
80992
|
continue;
|
|
@@ -80918,7 +81026,7 @@ function listSharedSkills(sharedRoot = defaultSharedRoot2()) {
|
|
|
80918
81026
|
continue;
|
|
80919
81027
|
if (ent.startsWith("."))
|
|
80920
81028
|
continue;
|
|
80921
|
-
const dirPath =
|
|
81029
|
+
const dirPath = join76(sharedRoot, ent);
|
|
80922
81030
|
try {
|
|
80923
81031
|
if (!statSync31(dirPath).isDirectory())
|
|
80924
81032
|
continue;
|
|
@@ -80954,7 +81062,7 @@ function listBundledSkills(bundledRoot = defaultBundledRoot2()) {
|
|
|
80954
81062
|
for (const ent of entries) {
|
|
80955
81063
|
if (ent.startsWith("."))
|
|
80956
81064
|
continue;
|
|
80957
|
-
const dirPath =
|
|
81065
|
+
const dirPath = join76(bundledRoot, ent);
|
|
80958
81066
|
try {
|
|
80959
81067
|
if (!statSync31(dirPath).isDirectory())
|
|
80960
81068
|
continue;
|
|
@@ -81100,7 +81208,7 @@ init_source();
|
|
|
81100
81208
|
init_helpers();
|
|
81101
81209
|
import { existsSync as existsSync80, mkdirSync as mkdirSync44, readdirSync as readdirSync32, readFileSync as readFileSync66, writeFileSync as writeFileSync39, statSync as statSync32, copyFileSync as copyFileSync12 } from "node:fs";
|
|
81102
81210
|
import { homedir as homedir44 } from "node:os";
|
|
81103
|
-
import { join as
|
|
81211
|
+
import { join as join77 } from "node:path";
|
|
81104
81212
|
import { spawnSync as spawnSync13 } from "node:child_process";
|
|
81105
81213
|
init_audit_reader();
|
|
81106
81214
|
var DEFAULT_IMAGE_TAG = "latest";
|
|
@@ -81191,10 +81299,10 @@ networks:
|
|
|
81191
81299
|
`;
|
|
81192
81300
|
}
|
|
81193
81301
|
function hostdDir() {
|
|
81194
|
-
return
|
|
81302
|
+
return join77(homedir44(), ".switchroom", "hostd");
|
|
81195
81303
|
}
|
|
81196
81304
|
function hostdComposePath() {
|
|
81197
|
-
return
|
|
81305
|
+
return join77(hostdDir(), "docker-compose.yml");
|
|
81198
81306
|
}
|
|
81199
81307
|
function backupExistingCompose() {
|
|
81200
81308
|
const p = hostdComposePath();
|
|
@@ -81302,7 +81410,7 @@ function doStatus() {
|
|
|
81302
81410
|
for (const name of readdirSync32(dir)) {
|
|
81303
81411
|
if (name === "docker-compose.yml" || name.startsWith("docker-compose.yml."))
|
|
81304
81412
|
continue;
|
|
81305
|
-
const sockPath =
|
|
81413
|
+
const sockPath = join77(dir, name, "sock");
|
|
81306
81414
|
if (existsSync80(sockPath)) {
|
|
81307
81415
|
const st = statSync32(sockPath);
|
|
81308
81416
|
if ((st.mode & 61440) === 49152) {
|