switchroom 0.19.29 → 0.19.30
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
CHANGED
|
@@ -2120,7 +2120,7 @@ var init_esm = __esm(() => {
|
|
|
2120
2120
|
});
|
|
2121
2121
|
|
|
2122
2122
|
// src/build-info.ts
|
|
2123
|
-
var VERSION = "0.19.
|
|
2123
|
+
var VERSION = "0.19.30", COMMIT_SHA = "efe8e2a7";
|
|
2124
2124
|
|
|
2125
2125
|
// src/cli/resolve-version.ts
|
|
2126
2126
|
import { existsSync, readFileSync } from "node:fs";
|
|
@@ -50860,6 +50860,209 @@ var init_doctor_drift = __esm(() => {
|
|
|
50860
50860
|
init_write_compose();
|
|
50861
50861
|
});
|
|
50862
50862
|
|
|
50863
|
+
// src/cli/component-versions.ts
|
|
50864
|
+
function versionFromImageRef(ref) {
|
|
50865
|
+
const at = ref.indexOf("@");
|
|
50866
|
+
const withoutDigest = at >= 0 ? ref.slice(0, at) : ref;
|
|
50867
|
+
const slash = withoutDigest.lastIndexOf("/");
|
|
50868
|
+
const colon = withoutDigest.indexOf(":", slash + 1);
|
|
50869
|
+
if (colon < 0) {
|
|
50870
|
+
return { version: null, detail: `image ref has no tag (${ref})` };
|
|
50871
|
+
}
|
|
50872
|
+
const tag = withoutDigest.slice(colon + 1);
|
|
50873
|
+
if (SEMVER_TAG_RE.test(tag))
|
|
50874
|
+
return { version: tag };
|
|
50875
|
+
return { version: null, detail: `non-semver tag "${tag}"` };
|
|
50876
|
+
}
|
|
50877
|
+
function isSwitchroomReleaseImage(_name, imageRef) {
|
|
50878
|
+
return /\/switchroom-[a-z0-9-]+(:|@|$)/.test(imageRef);
|
|
50879
|
+
}
|
|
50880
|
+
function collectContainerComponents(exec) {
|
|
50881
|
+
const r = exec("docker", [
|
|
50882
|
+
"ps",
|
|
50883
|
+
"--filter",
|
|
50884
|
+
"name=switchroom-",
|
|
50885
|
+
"--format",
|
|
50886
|
+
"{{.Names}}\t{{.Image}}"
|
|
50887
|
+
]);
|
|
50888
|
+
if (r.status !== 0)
|
|
50889
|
+
return [];
|
|
50890
|
+
const out = [];
|
|
50891
|
+
for (const line of r.stdout.split(`
|
|
50892
|
+
`)) {
|
|
50893
|
+
const [name, imageRef] = line.trim().split("\t");
|
|
50894
|
+
if (!name || !imageRef)
|
|
50895
|
+
continue;
|
|
50896
|
+
if (!isSwitchroomReleaseImage(name, imageRef))
|
|
50897
|
+
continue;
|
|
50898
|
+
const { version: version2, detail } = versionFromImageRef(imageRef);
|
|
50899
|
+
out.push({
|
|
50900
|
+
name,
|
|
50901
|
+
kind: "container",
|
|
50902
|
+
version: version2,
|
|
50903
|
+
imageRef,
|
|
50904
|
+
...detail ? { detail } : {}
|
|
50905
|
+
});
|
|
50906
|
+
}
|
|
50907
|
+
return out.sort((a, b) => a.name.localeCompare(b.name));
|
|
50908
|
+
}
|
|
50909
|
+
function normalizeSemverTag(v) {
|
|
50910
|
+
if (!v)
|
|
50911
|
+
return null;
|
|
50912
|
+
const tag = `v${v.trim().replace(/^v/, "")}`;
|
|
50913
|
+
return SEMVER_TAG_RE.test(tag) ? tag : null;
|
|
50914
|
+
}
|
|
50915
|
+
function resolveDriftTarget(components, releasePin) {
|
|
50916
|
+
const pin = normalizeSemverTag(releasePin);
|
|
50917
|
+
if (pin)
|
|
50918
|
+
return { target: pin, targetSource: "release.pin" };
|
|
50919
|
+
let highest = null;
|
|
50920
|
+
for (const c of components) {
|
|
50921
|
+
if (!c.version)
|
|
50922
|
+
continue;
|
|
50923
|
+
if (highest === null) {
|
|
50924
|
+
highest = c.version;
|
|
50925
|
+
continue;
|
|
50926
|
+
}
|
|
50927
|
+
const cmp = compareReleaseTags(c.version, highest);
|
|
50928
|
+
if (cmp !== null && cmp > 0)
|
|
50929
|
+
highest = c.version;
|
|
50930
|
+
}
|
|
50931
|
+
return highest ? { target: highest, targetSource: "highest-deployed" } : { target: null, targetSource: "none" };
|
|
50932
|
+
}
|
|
50933
|
+
function detectComponentDrift(components, releasePin) {
|
|
50934
|
+
const { target, targetSource } = resolveDriftTarget(components, releasePin);
|
|
50935
|
+
const report = {
|
|
50936
|
+
target,
|
|
50937
|
+
targetSource,
|
|
50938
|
+
behind: [],
|
|
50939
|
+
ahead: [],
|
|
50940
|
+
current: [],
|
|
50941
|
+
unknown: []
|
|
50942
|
+
};
|
|
50943
|
+
for (const c of components) {
|
|
50944
|
+
if (!c.version || !target) {
|
|
50945
|
+
report.unknown.push(c);
|
|
50946
|
+
continue;
|
|
50947
|
+
}
|
|
50948
|
+
const cmp = compareReleaseTags(c.version, target);
|
|
50949
|
+
if (cmp === null)
|
|
50950
|
+
report.unknown.push(c);
|
|
50951
|
+
else if (cmp < 0)
|
|
50952
|
+
report.behind.push(c);
|
|
50953
|
+
else if (cmp > 0)
|
|
50954
|
+
report.ahead.push(c);
|
|
50955
|
+
else
|
|
50956
|
+
report.current.push(c);
|
|
50957
|
+
}
|
|
50958
|
+
return report;
|
|
50959
|
+
}
|
|
50960
|
+
function collectComponents(cliVersion, exec) {
|
|
50961
|
+
const cli = {
|
|
50962
|
+
name: "cli (host)",
|
|
50963
|
+
kind: "cli",
|
|
50964
|
+
version: normalizeSemverTag(cliVersion),
|
|
50965
|
+
...normalizeSemverTag(cliVersion) ? {} : { detail: `unparseable CLI version "${cliVersion}"` }
|
|
50966
|
+
};
|
|
50967
|
+
return [cli, ...collectContainerComponents(exec)];
|
|
50968
|
+
}
|
|
50969
|
+
function formatComponentDrift(report) {
|
|
50970
|
+
const lines = [];
|
|
50971
|
+
if (!report.target) {
|
|
50972
|
+
lines.push("Component versions: no comparable version found (no release.pin and no semver-tagged component).");
|
|
50973
|
+
} else {
|
|
50974
|
+
const src = report.targetSource === "release.pin" ? "release.pin" : "highest deployed version (no release.pin set)";
|
|
50975
|
+
lines.push(`Component versions \u2014 target ${report.target} (from ${src}):`);
|
|
50976
|
+
}
|
|
50977
|
+
for (const c of report.behind) {
|
|
50978
|
+
lines.push(` BEHIND ${c.name} \u2014 ${c.version} (target ${report.target})`);
|
|
50979
|
+
}
|
|
50980
|
+
for (const c of report.ahead) {
|
|
50981
|
+
lines.push(` ahead ${c.name} \u2014 ${c.version}`);
|
|
50982
|
+
}
|
|
50983
|
+
for (const c of report.unknown) {
|
|
50984
|
+
lines.push(` unknown ${c.name} \u2014 ${c.detail ?? "version not readable"}`);
|
|
50985
|
+
}
|
|
50986
|
+
for (const c of report.current) {
|
|
50987
|
+
lines.push(` ok ${c.name} \u2014 ${c.version}`);
|
|
50988
|
+
}
|
|
50989
|
+
return lines.join(`
|
|
50990
|
+
`);
|
|
50991
|
+
}
|
|
50992
|
+
var SEMVER_TAG_RE;
|
|
50993
|
+
var init_component_versions = __esm(() => {
|
|
50994
|
+
SEMVER_TAG_RE = /^v\d+\.\d+\.\d+$/;
|
|
50995
|
+
});
|
|
50996
|
+
|
|
50997
|
+
// src/cli/doctor-component-versions.ts
|
|
50998
|
+
import { spawnSync as spawnSync12 } from "node:child_process";
|
|
50999
|
+
function fixFor(c, target) {
|
|
51000
|
+
if (c.kind === "cli") {
|
|
51001
|
+
return `switchroom update (self-updates the host CLI to ${target} first, then everything else)`;
|
|
51002
|
+
}
|
|
51003
|
+
if (c.name === "switchroom-web") {
|
|
51004
|
+
return `switchroom webd install --tag ${target} (run host-side: webd install fails inside hostd when the hostd compose predates SWITCHROOM_HOSTD_OPERATOR_UID)`;
|
|
51005
|
+
}
|
|
51006
|
+
if (c.name === "switchroom-hindsight-autoheal" || c.name === "switchroom-hostd") {
|
|
51007
|
+
return `switchroom hostd install --tag ${target} (regenerates the hostd compose project \u2014 both hostd and the autoheal sidecar)`;
|
|
51008
|
+
}
|
|
51009
|
+
return `switchroom update`;
|
|
51010
|
+
}
|
|
51011
|
+
function runComponentVersionChecks(config, opts = {}) {
|
|
51012
|
+
const exec = opts.exec ?? defaultExec2;
|
|
51013
|
+
const components = collectComponents(opts.cliVersion ?? SWITCHROOM_VERSION, exec);
|
|
51014
|
+
const report = detectComponentDrift(components, config.release?.pin);
|
|
51015
|
+
if (!report.target) {
|
|
51016
|
+
return [
|
|
51017
|
+
{
|
|
51018
|
+
name: "component versions",
|
|
51019
|
+
status: "skip",
|
|
51020
|
+
detail: "no release.pin set and no semver-tagged switchroom container running \u2014 nothing to compare."
|
|
51021
|
+
}
|
|
51022
|
+
];
|
|
51023
|
+
}
|
|
51024
|
+
const results = [];
|
|
51025
|
+
const src = report.targetSource === "release.pin" ? `release.pin ${report.target}` : `${report.target} (highest deployed \u2014 no release.pin set)`;
|
|
51026
|
+
if (report.behind.length === 0) {
|
|
51027
|
+
results.push({
|
|
51028
|
+
name: "component versions",
|
|
51029
|
+
status: "ok",
|
|
51030
|
+
detail: `all ${report.current.length} comparable component(s) on ${src}`
|
|
51031
|
+
});
|
|
51032
|
+
}
|
|
51033
|
+
for (const c of report.behind) {
|
|
51034
|
+
results.push({
|
|
51035
|
+
name: `component behind: ${c.name}`,
|
|
51036
|
+
status: "warn",
|
|
51037
|
+
detail: `on ${c.version}, expected ${report.target} (${src})`,
|
|
51038
|
+
fix: fixFor(c, report.target)
|
|
51039
|
+
});
|
|
51040
|
+
}
|
|
51041
|
+
for (const c of report.ahead) {
|
|
51042
|
+
results.push({
|
|
51043
|
+
name: `component ahead: ${c.name}`,
|
|
51044
|
+
status: "warn",
|
|
51045
|
+
detail: `on ${c.version}, ahead of ${src} \u2014 a roll may be mid-flight, or release.pin is stale`
|
|
51046
|
+
});
|
|
51047
|
+
}
|
|
51048
|
+
for (const c of report.unknown) {
|
|
51049
|
+
results.push({
|
|
51050
|
+
name: `component version unknown: ${c.name}`,
|
|
51051
|
+
status: "skip",
|
|
51052
|
+
detail: c.detail ?? "version not readable"
|
|
51053
|
+
});
|
|
51054
|
+
}
|
|
51055
|
+
return results;
|
|
51056
|
+
}
|
|
51057
|
+
var defaultExec2 = (cmd, args) => {
|
|
51058
|
+
const r = spawnSync12(cmd, args, { encoding: "utf-8", timeout: 1e4 });
|
|
51059
|
+
return { status: r.status ?? 1, stdout: r.stdout ?? "" };
|
|
51060
|
+
};
|
|
51061
|
+
var init_doctor_component_versions = __esm(() => {
|
|
51062
|
+
init_resolve_version();
|
|
51063
|
+
init_component_versions();
|
|
51064
|
+
});
|
|
51065
|
+
|
|
50863
51066
|
// src/cli/doctor-scaffold-wiring.ts
|
|
50864
51067
|
import { join as join70, resolve as resolve43 } from "node:path";
|
|
50865
51068
|
function readJson2(d, path7) {
|
|
@@ -52614,7 +52817,7 @@ var init_doctor_fix_session_model = __esm(() => {
|
|
|
52614
52817
|
});
|
|
52615
52818
|
|
|
52616
52819
|
// src/cli/doctor-claude-cli.ts
|
|
52617
|
-
import { spawnSync as
|
|
52820
|
+
import { spawnSync as spawnSync13 } from "node:child_process";
|
|
52618
52821
|
import { existsSync as existsSync76, readFileSync as readFileSync70 } from "node:fs";
|
|
52619
52822
|
import { dirname as dirname30, join as join80 } from "node:path";
|
|
52620
52823
|
function parseClaudeCliVersion(raw) {
|
|
@@ -52679,7 +52882,7 @@ function parseClaudeCliProbeOutput(r) {
|
|
|
52679
52882
|
return { state: "read", bin, raw };
|
|
52680
52883
|
}
|
|
52681
52884
|
function probeAgentClaudeCli(agentName) {
|
|
52682
|
-
const r =
|
|
52885
|
+
const r = spawnSync13("docker", ["exec", `switchroom-${agentName}`, "sh", "-c", buildClaudeCliProbeScript()], { stdio: "pipe", timeout: 3000 });
|
|
52683
52886
|
return parseClaudeCliProbeOutput(r);
|
|
52684
52887
|
}
|
|
52685
52888
|
function assessClaudeCliFloor(input) {
|
|
@@ -52802,7 +53005,7 @@ __export(exports_doctor, {
|
|
|
52802
53005
|
PENDING_RETAINS_EVICTION_WINDOW_DAYS: () => PENDING_RETAINS_EVICTION_WINDOW_DAYS,
|
|
52803
53006
|
MFF_VAULT_KEY: () => MFF_VAULT_KEY
|
|
52804
53007
|
});
|
|
52805
|
-
import { spawnSync as
|
|
53008
|
+
import { spawnSync as spawnSync14 } from "node:child_process";
|
|
52806
53009
|
import { Socket as Socket3 } from "node:net";
|
|
52807
53010
|
import {
|
|
52808
53011
|
accessSync as accessSync3,
|
|
@@ -52948,7 +53151,7 @@ function readVersion(bin, parser) {
|
|
|
52948
53151
|
const path7 = which(bin);
|
|
52949
53152
|
if (!path7)
|
|
52950
53153
|
return null;
|
|
52951
|
-
const proc =
|
|
53154
|
+
const proc = spawnSync14(path7, ["--version"], {
|
|
52952
53155
|
stdio: ["ignore", "pipe", "pipe"]
|
|
52953
53156
|
});
|
|
52954
53157
|
if (proc.error || proc.status !== 0)
|
|
@@ -53240,7 +53443,7 @@ function probeVaultBrokerSocketPair(agentName) {
|
|
|
53240
53443
|
const dataPath = `/run/switchroom/broker/${agentName}/sock`;
|
|
53241
53444
|
const unlockPath = `/run/switchroom/broker/${agentName}/unlock`;
|
|
53242
53445
|
const script = `D=0; U=0; ` + `test -S '${dataPath}' && D=1; ` + `test -S '${unlockPath}' && U=1; ` + `echo "D=$D U=$U"`;
|
|
53243
|
-
const r =
|
|
53446
|
+
const r = spawnSync14("docker", ["exec", "switchroom-vault-broker", "sh", "-c", script], { stdio: "pipe", timeout: 3000 });
|
|
53244
53447
|
if (r.error || r.status === null)
|
|
53245
53448
|
return "unreachable";
|
|
53246
53449
|
if (r.status !== 0) {
|
|
@@ -53490,7 +53693,7 @@ function checkHindsightConsumer(config, opts) {
|
|
|
53490
53693
|
}
|
|
53491
53694
|
function probeAuthBrokerSocket(consumerName) {
|
|
53492
53695
|
const containerPath = `/run/switchroom/auth-broker/${consumerName}/sock`;
|
|
53493
|
-
const r =
|
|
53696
|
+
const r = spawnSync14("docker", ["exec", "switchroom-auth-broker", "test", "-S", containerPath], { stdio: "pipe", timeout: 3000 });
|
|
53494
53697
|
if (r.error || r.status === null)
|
|
53495
53698
|
return "unreachable";
|
|
53496
53699
|
if (r.status === 0)
|
|
@@ -53741,7 +53944,7 @@ async function checkHindsight(config) {
|
|
|
53741
53944
|
function probePendingRetainsQueue(agentName) {
|
|
53742
53945
|
const base = "/state/agent/home/.hindsight";
|
|
53743
53946
|
const script = buildPendingRetainsProbeScript(base);
|
|
53744
|
-
const r =
|
|
53947
|
+
const r = spawnSync14("docker", ["exec", `switchroom-${agentName}`, "sh", "-c", script], { stdio: "pipe", timeout: 3000 });
|
|
53745
53948
|
return parsePendingRetainsProbeOutput(r);
|
|
53746
53949
|
}
|
|
53747
53950
|
function buildPendingRetainsProbeScript(base, now = Date.now()) {
|
|
@@ -54608,7 +54811,7 @@ async function checkMffAuthFlow(envPath = mffEnvPath(), timeoutMs = 8000) {
|
|
|
54608
54811
|
const python3 = which("python3") ?? "python3";
|
|
54609
54812
|
let token;
|
|
54610
54813
|
try {
|
|
54611
|
-
const result =
|
|
54814
|
+
const result = spawnSync14(python3, [authScript, "--quiet"], {
|
|
54612
54815
|
timeout: timeoutMs,
|
|
54613
54816
|
encoding: "utf-8",
|
|
54614
54817
|
env: { ...process.env, ...env2 }
|
|
@@ -55037,6 +55240,22 @@ function registerDoctorCommand(program3) {
|
|
|
55037
55240
|
})
|
|
55038
55241
|
},
|
|
55039
55242
|
{ title: "Cron Session", results: runCronSessionChecks(config) },
|
|
55243
|
+
{
|
|
55244
|
+
title: "Component versions (#3919)",
|
|
55245
|
+
results: (() => {
|
|
55246
|
+
try {
|
|
55247
|
+
return runComponentVersionChecks(config);
|
|
55248
|
+
} catch (err) {
|
|
55249
|
+
return [
|
|
55250
|
+
{
|
|
55251
|
+
name: "component versions",
|
|
55252
|
+
status: "skip",
|
|
55253
|
+
detail: `not checkable: ${err?.message ?? String(err)}`
|
|
55254
|
+
}
|
|
55255
|
+
];
|
|
55256
|
+
}
|
|
55257
|
+
})()
|
|
55258
|
+
},
|
|
55040
55259
|
{
|
|
55041
55260
|
title: "Generated-surface drift (KEN-130)",
|
|
55042
55261
|
results: await runGeneratedSurfaceDriftChecks(config, configPath, {
|
|
@@ -55124,6 +55343,7 @@ var init_doctor = __esm(() => {
|
|
|
55124
55343
|
init_doctor_cron_session();
|
|
55125
55344
|
init_doctor_flood_pressure();
|
|
55126
55345
|
init_doctor_drift();
|
|
55346
|
+
init_doctor_component_versions();
|
|
55127
55347
|
init_doctor_microsoft();
|
|
55128
55348
|
init_doctor_notion();
|
|
55129
55349
|
init_doctor_credentials_migration();
|
|
@@ -68072,9 +68292,9 @@ __export(exports_server, {
|
|
|
68072
68292
|
dispatchTool: () => dispatchTool,
|
|
68073
68293
|
TOOLS: () => TOOLS
|
|
68074
68294
|
});
|
|
68075
|
-
import { spawnSync as
|
|
68295
|
+
import { spawnSync as spawnSync22 } from "node:child_process";
|
|
68076
68296
|
function execCli(args, stdin) {
|
|
68077
|
-
const r =
|
|
68297
|
+
const r = spawnSync22(CLI_BIN, args, {
|
|
68078
68298
|
encoding: "utf-8",
|
|
68079
68299
|
env: process.env,
|
|
68080
68300
|
timeout: 15000,
|
|
@@ -68583,7 +68803,7 @@ __export(exports_server2, {
|
|
|
68583
68803
|
TOOLS: () => TOOLS2
|
|
68584
68804
|
});
|
|
68585
68805
|
import { randomBytes as randomBytes16 } from "node:crypto";
|
|
68586
|
-
import { existsSync as
|
|
68806
|
+
import { existsSync as existsSync105 } from "node:fs";
|
|
68587
68807
|
function selfSocketPath() {
|
|
68588
68808
|
return `/run/switchroom/hostd/${SELF_AGENT}/sock`;
|
|
68589
68809
|
}
|
|
@@ -68610,7 +68830,7 @@ async function dispatchTool2(name, args) {
|
|
|
68610
68830
|
return errorText2("hostd MCP: SWITCHROOM_AGENT_NAME env var is not set \u2014 cannot " + "determine which per-agent socket to talk to.");
|
|
68611
68831
|
}
|
|
68612
68832
|
const sockPath = selfSocketPath();
|
|
68613
|
-
if (!
|
|
68833
|
+
if (!existsSync105(sockPath)) {
|
|
68614
68834
|
return errorText2(`hostd MCP: socket not bound at ${sockPath}. The host-control ` + `daemon is either not installed (run \`switchroom hostd install\`) ` + `or this agent isn't admin-flagged in switchroom.yaml. RFC C ` + `bind-mounts the per-agent socket only when host_control.enabled ` + `is true AND the agent has admin: true.`);
|
|
68615
68835
|
}
|
|
68616
68836
|
let req;
|
|
@@ -68861,13 +69081,13 @@ function resolveAuditLogPath() {
|
|
|
68861
69081
|
if (process.env.HOSTD_AUDIT_LOG_PATH)
|
|
68862
69082
|
return process.env.HOSTD_AUDIT_LOG_PATH;
|
|
68863
69083
|
const bindMounted = "/host-home/.switchroom/host-control-audit.log";
|
|
68864
|
-
if (
|
|
69084
|
+
if (existsSync105(bindMounted))
|
|
68865
69085
|
return bindMounted;
|
|
68866
69086
|
return defaultAuditLogPath2();
|
|
68867
69087
|
}
|
|
68868
69088
|
function getLastUpdateApplyStatus() {
|
|
68869
69089
|
const path10 = resolveAuditLogPath();
|
|
68870
|
-
if (!
|
|
69090
|
+
if (!existsSync105(path10)) {
|
|
68871
69091
|
return errorText2(`get_status: audit log not found at ${path10}. No update_apply has run yet?`);
|
|
68872
69092
|
}
|
|
68873
69093
|
let raw;
|
|
@@ -69586,11 +69806,11 @@ var init_test_agents = __esm(() => {
|
|
|
69586
69806
|
});
|
|
69587
69807
|
|
|
69588
69808
|
// src/litellm/header-passthrough-guard.ts
|
|
69589
|
-
import { existsSync as
|
|
69809
|
+
import { existsSync as existsSync108, readdirSync as readdirSync41 } from "node:fs";
|
|
69590
69810
|
function discoverLiveLitellmConfigPath(opts) {
|
|
69591
69811
|
const servicesDir = opts?.servicesDir ?? COOLIFY_SERVICES_DIR;
|
|
69592
69812
|
const readdir2 = opts?.readdirFn ?? ((p) => readdirSync41(p));
|
|
69593
|
-
const exists = opts?.existsFn ??
|
|
69813
|
+
const exists = opts?.existsFn ?? existsSync108;
|
|
69594
69814
|
let entries;
|
|
69595
69815
|
try {
|
|
69596
69816
|
entries = readdir2(servicesDir);
|
|
@@ -69680,7 +69900,7 @@ var init_header_passthrough_guard = __esm(() => {
|
|
|
69680
69900
|
});
|
|
69681
69901
|
|
|
69682
69902
|
// src/fleet-health/litellm-config-sensor.ts
|
|
69683
|
-
import { readFileSync as readFileSync96, existsSync as
|
|
69903
|
+
import { readFileSync as readFileSync96, existsSync as existsSync109 } from "node:fs";
|
|
69684
69904
|
function resolveLitellmConfigPath(explicit, discoverFn = () => discoverLiveLitellmConfigPath()) {
|
|
69685
69905
|
if (explicit)
|
|
69686
69906
|
return explicit;
|
|
@@ -69691,7 +69911,7 @@ function resolveLitellmConfigPath(explicit, discoverFn = () => discoverLiveLitel
|
|
|
69691
69911
|
}
|
|
69692
69912
|
function scanLitellmConfig(opts = {}) {
|
|
69693
69913
|
const path10 = resolveLitellmConfigPath(opts.path, opts.discoverFn);
|
|
69694
|
-
const exists = opts.existsFn ??
|
|
69914
|
+
const exists = opts.existsFn ?? existsSync109;
|
|
69695
69915
|
const read = opts.readFn ?? ((p) => readFileSync96(p, "utf-8"));
|
|
69696
69916
|
const log = opts.log ?? (() => {});
|
|
69697
69917
|
const nowIso = opts.nowIso ?? new Date().toISOString();
|
|
@@ -69769,18 +69989,18 @@ __export(exports_scan, {
|
|
|
69769
69989
|
import {
|
|
69770
69990
|
readFileSync as readFileSync97,
|
|
69771
69991
|
readdirSync as readdirSync42,
|
|
69772
|
-
existsSync as
|
|
69773
|
-
mkdirSync as
|
|
69992
|
+
existsSync as existsSync110,
|
|
69993
|
+
mkdirSync as mkdirSync63,
|
|
69774
69994
|
writeFileSync as writeFileSync46
|
|
69775
69995
|
} from "node:fs";
|
|
69776
|
-
import { resolve as resolve61, dirname as
|
|
69996
|
+
import { resolve as resolve61, dirname as dirname42 } from "node:path";
|
|
69777
69997
|
import { homedir as homedir60 } from "node:os";
|
|
69778
69998
|
function resolveSwitchroomBase(home2 = process.env.SWITCHROOM_HOME ?? process.env.HOME ?? homedir60()) {
|
|
69779
69999
|
return resolve61(home2, ".switchroom");
|
|
69780
70000
|
}
|
|
69781
70001
|
function listAgents(base) {
|
|
69782
70002
|
const dir = resolve61(base, "agents");
|
|
69783
|
-
if (!
|
|
70003
|
+
if (!existsSync110(dir))
|
|
69784
70004
|
return [];
|
|
69785
70005
|
try {
|
|
69786
70006
|
return readdirSync42(dir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).sort();
|
|
@@ -69809,7 +70029,7 @@ function runScan(opts = {}) {
|
|
|
69809
70029
|
let gwText = "";
|
|
69810
70030
|
let sawArtifact = false;
|
|
69811
70031
|
try {
|
|
69812
|
-
if (
|
|
70032
|
+
if (existsSync110(turnsPath)) {
|
|
69813
70033
|
turnsText = readFileSync97(turnsPath, "utf-8");
|
|
69814
70034
|
sawArtifact = true;
|
|
69815
70035
|
}
|
|
@@ -69817,7 +70037,7 @@ function runScan(opts = {}) {
|
|
|
69817
70037
|
log(`fleet-health: WARN skipping ${agent} turns.jsonl unreadable: ${String(e)}`);
|
|
69818
70038
|
}
|
|
69819
70039
|
try {
|
|
69820
|
-
if (
|
|
70040
|
+
if (existsSync110(gwPath)) {
|
|
69821
70041
|
gwText = readFileSync97(gwPath, "utf-8");
|
|
69822
70042
|
sawArtifact = true;
|
|
69823
70043
|
}
|
|
@@ -69860,7 +70080,7 @@ function runScan(opts = {}) {
|
|
|
69860
70080
|
function readLedgerIfPresent(base) {
|
|
69861
70081
|
const path10 = ledgerPathForBase(base);
|
|
69862
70082
|
try {
|
|
69863
|
-
if (!
|
|
70083
|
+
if (!existsSync110(path10))
|
|
69864
70084
|
return null;
|
|
69865
70085
|
return JSON.parse(readFileSync97(path10, "utf-8"));
|
|
69866
70086
|
} catch {
|
|
@@ -69868,11 +70088,11 @@ function readLedgerIfPresent(base) {
|
|
|
69868
70088
|
}
|
|
69869
70089
|
}
|
|
69870
70090
|
function ledgerPathForBase(base) {
|
|
69871
|
-
return fleetHealthLedgerPath(
|
|
70091
|
+
return fleetHealthLedgerPath(dirname42(base));
|
|
69872
70092
|
}
|
|
69873
70093
|
function writeLedger(base, ledger) {
|
|
69874
70094
|
const path10 = ledgerPathForBase(base);
|
|
69875
|
-
|
|
70095
|
+
mkdirSync63(dirname42(path10), { recursive: true });
|
|
69876
70096
|
writeFileSync46(path10, JSON.stringify(ledger, null, 2) + `
|
|
69877
70097
|
`, "utf-8");
|
|
69878
70098
|
return path10;
|
|
@@ -90583,9 +90803,9 @@ init_source();
|
|
|
90583
90803
|
init_loader();
|
|
90584
90804
|
init_lifecycle();
|
|
90585
90805
|
init_compose_env();
|
|
90586
|
-
import { existsSync as
|
|
90587
|
-
import { spawnSync as
|
|
90588
|
-
import { join as join83, dirname as
|
|
90806
|
+
import { existsSync as existsSync80, mkdirSync as mkdirSync45, readFileSync as readFileSync73, realpathSync as realpathSync6, statSync as statSync45, chownSync as chownSync8 } from "node:fs";
|
|
90807
|
+
import { spawnSync as spawnSync16 } from "node:child_process";
|
|
90808
|
+
import { join as join83, dirname as dirname33, resolve as resolve45 } from "node:path";
|
|
90589
90809
|
import { homedir as homedir43 } from "node:os";
|
|
90590
90810
|
|
|
90591
90811
|
// src/cli/release-yaml.ts
|
|
@@ -90833,6 +91053,286 @@ function syncBundledSkills(opts) {
|
|
|
90833
91053
|
|
|
90834
91054
|
// src/cli/update.ts
|
|
90835
91055
|
init_resolve_version();
|
|
91056
|
+
|
|
91057
|
+
// src/cli/self-update.ts
|
|
91058
|
+
var SELF_UPDATE_ENV_SENTINEL = "SWITCHROOM_SELF_UPDATED";
|
|
91059
|
+
var VERSION_STORE_DIRNAME = ".switchroom-versions";
|
|
91060
|
+
var GITHUB_LATEST_RELEASE_URL = "https://api.github.com/repos/switchroom/switchroom/releases/latest";
|
|
91061
|
+
function detectInstallKind(p) {
|
|
91062
|
+
if (p.inContainer) {
|
|
91063
|
+
return {
|
|
91064
|
+
kind: "container",
|
|
91065
|
+
reason: "running inside a switchroom container \u2014 the CLI here comes from the " + "container image and is updated by pulling a new image, not by " + "replacing a file. Nothing to self-update."
|
|
91066
|
+
};
|
|
91067
|
+
}
|
|
91068
|
+
if (p.bundleDir.startsWith("/$bunfs")) {
|
|
91069
|
+
if (!p.execPath) {
|
|
91070
|
+
return {
|
|
91071
|
+
kind: "unknown",
|
|
91072
|
+
reason: "compiled binary but process.execPath is empty \u2014 cannot locate the " + "file to replace. Re-run install.sh to upgrade."
|
|
91073
|
+
};
|
|
91074
|
+
}
|
|
91075
|
+
return {
|
|
91076
|
+
kind: "static-binary",
|
|
91077
|
+
binaryPath: p.execPath,
|
|
91078
|
+
reason: `published static binary at ${p.execPath}`
|
|
91079
|
+
};
|
|
91080
|
+
}
|
|
91081
|
+
if (/[/\\]node_modules[/\\]switchroom[/\\]/.test(p.scriptPath)) {
|
|
91082
|
+
return {
|
|
91083
|
+
kind: "npm-global",
|
|
91084
|
+
reason: "installed via npm \u2014 self-update does not manage npm installs. " + "Upgrade with `npm i -g switchroom@latest`."
|
|
91085
|
+
};
|
|
91086
|
+
}
|
|
91087
|
+
if (isSwitchroomSourceCheckoutPath(p.scriptPath)) {
|
|
91088
|
+
return {
|
|
91089
|
+
kind: "source-checkout",
|
|
91090
|
+
reason: "running from a switchroom source checkout \u2014 self-update would clobber " + "your working tree. Upgrade with `git pull && bun install && npm run build`."
|
|
91091
|
+
};
|
|
91092
|
+
}
|
|
91093
|
+
return {
|
|
91094
|
+
kind: "unknown",
|
|
91095
|
+
reason: `could not identify how switchroom was installed (running from ` + `"${p.scriptPath}"). Not touching it. Upgrade with the method you used ` + `to install, or re-run install.sh.`
|
|
91096
|
+
};
|
|
91097
|
+
}
|
|
91098
|
+
function isSwitchroomSourceCheckoutPath(scriptPath) {
|
|
91099
|
+
return /[/\\](src|dist)[/\\]cli[/\\]switchroom(\.js|\.ts)?$/.test(scriptPath);
|
|
91100
|
+
}
|
|
91101
|
+
function releaseAssetName(platform, arch) {
|
|
91102
|
+
const os6 = platform === "linux" ? "linux" : platform === "darwin" ? "macos" : null;
|
|
91103
|
+
const cpu = arch === "x64" ? "amd64" : arch === "arm64" ? "arm64" : null;
|
|
91104
|
+
if (!os6 || !cpu)
|
|
91105
|
+
return null;
|
|
91106
|
+
return `switchroom-${os6}-${cpu}`;
|
|
91107
|
+
}
|
|
91108
|
+
function parseLatestReleaseTag(body) {
|
|
91109
|
+
try {
|
|
91110
|
+
const parsed = JSON.parse(body);
|
|
91111
|
+
if (parsed?.draft === true)
|
|
91112
|
+
return null;
|
|
91113
|
+
const tag = parsed?.tag_name;
|
|
91114
|
+
if (typeof tag !== "string" || !/^v\d+\.\d+\.\d+$/.test(tag))
|
|
91115
|
+
return null;
|
|
91116
|
+
return tag;
|
|
91117
|
+
} catch {
|
|
91118
|
+
return null;
|
|
91119
|
+
}
|
|
91120
|
+
}
|
|
91121
|
+
function expectedChecksum(checksumsText, asset) {
|
|
91122
|
+
for (const line of checksumsText.split(`
|
|
91123
|
+
`)) {
|
|
91124
|
+
const idx = line.indexOf(` ${asset}`);
|
|
91125
|
+
if (idx <= 0)
|
|
91126
|
+
continue;
|
|
91127
|
+
if (line.slice(idx + 2).trim() !== asset)
|
|
91128
|
+
continue;
|
|
91129
|
+
const hash2 = line.slice(0, idx).trim();
|
|
91130
|
+
if (/^[0-9a-f]{64}$/i.test(hash2))
|
|
91131
|
+
return hash2.toLowerCase();
|
|
91132
|
+
}
|
|
91133
|
+
return null;
|
|
91134
|
+
}
|
|
91135
|
+
function planSelfUpdate(opts) {
|
|
91136
|
+
const { detection, currentVersion, latestTag } = opts;
|
|
91137
|
+
if (detection.kind !== "static-binary" || !detection.binaryPath) {
|
|
91138
|
+
return { action: "skip", reason: detection.reason };
|
|
91139
|
+
}
|
|
91140
|
+
if (!latestTag) {
|
|
91141
|
+
return {
|
|
91142
|
+
action: "skip",
|
|
91143
|
+
reason: "could not resolve the latest published release from GitHub " + "(offline, rate-limited, or the API changed shape) \u2014 leaving the CLI as-is."
|
|
91144
|
+
};
|
|
91145
|
+
}
|
|
91146
|
+
const current = `v${currentVersion.trim().replace(/^v/, "")}`;
|
|
91147
|
+
const cmp = compareReleaseTags(current, latestTag);
|
|
91148
|
+
if (cmp === null) {
|
|
91149
|
+
return {
|
|
91150
|
+
action: "skip",
|
|
91151
|
+
reason: `local CLI version "${currentVersion}" is not a comparable semver \u2014 ` + `refusing to guess whether ${latestTag} is an upgrade.`
|
|
91152
|
+
};
|
|
91153
|
+
}
|
|
91154
|
+
if (cmp >= 0)
|
|
91155
|
+
return { action: "current", version: current };
|
|
91156
|
+
return {
|
|
91157
|
+
action: "update",
|
|
91158
|
+
from: current,
|
|
91159
|
+
to: latestTag,
|
|
91160
|
+
binaryPath: detection.binaryPath
|
|
91161
|
+
};
|
|
91162
|
+
}
|
|
91163
|
+
function versionStorePath(installDir, version2, sep4 = "/") {
|
|
91164
|
+
return `${installDir}${sep4}${VERSION_STORE_DIRNAME}${sep4}switchroom-${version2.replace(/^v/, "")}`;
|
|
91165
|
+
}
|
|
91166
|
+
function rollbackHint(installDir, previousVersion) {
|
|
91167
|
+
return `Rollback: cp ${versionStorePath(installDir, previousVersion)} ` + `${installDir}/switchroom`;
|
|
91168
|
+
}
|
|
91169
|
+
function alreadySelfUpdated(env2) {
|
|
91170
|
+
return env2[SELF_UPDATE_ENV_SENTINEL] === "1";
|
|
91171
|
+
}
|
|
91172
|
+
async function fetchLatestReleaseTag(io) {
|
|
91173
|
+
try {
|
|
91174
|
+
return parseLatestReleaseTag(await io.httpGetText(GITHUB_LATEST_RELEASE_URL));
|
|
91175
|
+
} catch {
|
|
91176
|
+
return null;
|
|
91177
|
+
}
|
|
91178
|
+
}
|
|
91179
|
+
async function performSelfUpdate(opts) {
|
|
91180
|
+
const { plan, assetName, io } = opts;
|
|
91181
|
+
const log = opts.log ?? (() => {});
|
|
91182
|
+
const installDir = io.dirname(plan.binaryPath);
|
|
91183
|
+
const store = `${installDir}/${VERSION_STORE_DIRNAME}`;
|
|
91184
|
+
const base = `https://github.com/switchroom/switchroom/releases/download/${plan.to}`;
|
|
91185
|
+
const staged = versionStorePath(installDir, plan.to);
|
|
91186
|
+
const tmp = `${staged}.download`;
|
|
91187
|
+
io.mkdirp(store);
|
|
91188
|
+
io.remove(tmp);
|
|
91189
|
+
log(`downloading ${assetName} ${plan.to}`);
|
|
91190
|
+
try {
|
|
91191
|
+
await io.httpDownload(`${base}/${assetName}`, tmp);
|
|
91192
|
+
} catch (err) {
|
|
91193
|
+
io.remove(tmp);
|
|
91194
|
+
throw new Error(`self-update: download of ${base}/${assetName} failed (${err.message}). ` + `The installed CLI is unchanged.`);
|
|
91195
|
+
}
|
|
91196
|
+
let checksums;
|
|
91197
|
+
try {
|
|
91198
|
+
checksums = await io.httpGetText(`${base}/switchroom-checksums.txt`);
|
|
91199
|
+
} catch (err) {
|
|
91200
|
+
io.remove(tmp);
|
|
91201
|
+
throw new Error(`self-update: could not fetch switchroom-checksums.txt for ${plan.to} ` + `(${err.message}) \u2014 refusing to install an unverified binary. ` + `The installed CLI is unchanged.`);
|
|
91202
|
+
}
|
|
91203
|
+
const expected = expectedChecksum(checksums, assetName);
|
|
91204
|
+
if (!expected) {
|
|
91205
|
+
io.remove(tmp);
|
|
91206
|
+
throw new Error(`self-update: release ${plan.to} has no checksum entry for ${assetName} \u2014 ` + `refusing to install an unverified binary. The installed CLI is unchanged.`);
|
|
91207
|
+
}
|
|
91208
|
+
const actual = io.sha256File(tmp).toLowerCase();
|
|
91209
|
+
if (actual !== expected) {
|
|
91210
|
+
io.remove(tmp);
|
|
91211
|
+
throw new Error(`self-update: SHA256 mismatch for ${assetName} (expected ${expected}, got ${actual}) \u2014 ` + `refusing to install. The installed CLI is unchanged.`);
|
|
91212
|
+
}
|
|
91213
|
+
io.chmodExec(tmp);
|
|
91214
|
+
const proved = io.probeBinaryVersion(tmp);
|
|
91215
|
+
if (!proved) {
|
|
91216
|
+
io.remove(tmp);
|
|
91217
|
+
throw new Error(`self-update: the downloaded ${plan.to} binary did not run cleanly on this host ` + `(\`switchroom version\` failed) \u2014 refusing to install it. The installed CLI is unchanged.`);
|
|
91218
|
+
}
|
|
91219
|
+
const previousArchive = versionStorePath(installDir, plan.from);
|
|
91220
|
+
try {
|
|
91221
|
+
if (!io.exists(previousArchive))
|
|
91222
|
+
io.copyFile(plan.binaryPath, previousArchive);
|
|
91223
|
+
} catch (err) {
|
|
91224
|
+
io.remove(tmp);
|
|
91225
|
+
throw new Error(`self-update: could not archive the current binary to ${previousArchive} ` + `(${err.message}) \u2014 refusing to swap without a rollback copy. ` + `The installed CLI is unchanged.`);
|
|
91226
|
+
}
|
|
91227
|
+
io.rename(tmp, staged);
|
|
91228
|
+
io.copyFile(staged, `${plan.binaryPath}.new`);
|
|
91229
|
+
io.chmodExec(`${plan.binaryPath}.new`);
|
|
91230
|
+
io.rename(`${plan.binaryPath}.new`, plan.binaryPath);
|
|
91231
|
+
log(rollbackHint(installDir, plan.from));
|
|
91232
|
+
return {
|
|
91233
|
+
replaced: true,
|
|
91234
|
+
newVersion: plan.to,
|
|
91235
|
+
binaryPath: plan.binaryPath,
|
|
91236
|
+
message: `host CLI ${plan.from} \u2192 ${plan.to} (verified sha256, ran clean). ` + rollbackHint(installDir, plan.from)
|
|
91237
|
+
};
|
|
91238
|
+
}
|
|
91239
|
+
|
|
91240
|
+
// src/cli/self-update-io.ts
|
|
91241
|
+
import { createHash as createHash16 } from "node:crypto";
|
|
91242
|
+
import {
|
|
91243
|
+
chmodSync as chmodSync15,
|
|
91244
|
+
closeSync as closeSync15,
|
|
91245
|
+
copyFileSync as copyFileSync11,
|
|
91246
|
+
createWriteStream,
|
|
91247
|
+
existsSync as existsSync79,
|
|
91248
|
+
mkdirSync as mkdirSync44,
|
|
91249
|
+
openSync as openSync15,
|
|
91250
|
+
readSync as readSync5,
|
|
91251
|
+
renameSync as renameSync19,
|
|
91252
|
+
rmSync as rmSync14
|
|
91253
|
+
} from "node:fs";
|
|
91254
|
+
import { dirname as dirname32 } from "node:path";
|
|
91255
|
+
import { Readable } from "node:stream";
|
|
91256
|
+
import { pipeline } from "node:stream/promises";
|
|
91257
|
+
import { spawnSync as spawnSync15 } from "node:child_process";
|
|
91258
|
+
var HTTP_TIMEOUT_MS = 60000;
|
|
91259
|
+
function defaultSelfUpdateIO() {
|
|
91260
|
+
return {
|
|
91261
|
+
async httpGetText(url) {
|
|
91262
|
+
const res = await fetch(url, {
|
|
91263
|
+
headers: { "user-agent": "switchroom-cli-self-update" },
|
|
91264
|
+
signal: AbortSignal.timeout(HTTP_TIMEOUT_MS)
|
|
91265
|
+
});
|
|
91266
|
+
if (!res.ok)
|
|
91267
|
+
throw new Error(`HTTP ${res.status} for ${url}`);
|
|
91268
|
+
return await res.text();
|
|
91269
|
+
},
|
|
91270
|
+
async httpDownload(url, dest) {
|
|
91271
|
+
const res = await fetch(url, {
|
|
91272
|
+
headers: { "user-agent": "switchroom-cli-self-update" },
|
|
91273
|
+
redirect: "follow",
|
|
91274
|
+
signal: AbortSignal.timeout(HTTP_TIMEOUT_MS)
|
|
91275
|
+
});
|
|
91276
|
+
if (!res.ok)
|
|
91277
|
+
throw new Error(`HTTP ${res.status} for ${url}`);
|
|
91278
|
+
if (!res.body)
|
|
91279
|
+
throw new Error(`empty response body for ${url}`);
|
|
91280
|
+
await pipeline(Readable.fromWeb(res.body), createWriteStream(dest));
|
|
91281
|
+
},
|
|
91282
|
+
sha256File(path7) {
|
|
91283
|
+
const hash2 = createHash16("sha256");
|
|
91284
|
+
const fd = openSync15(path7, "r");
|
|
91285
|
+
try {
|
|
91286
|
+
const buf = Buffer.allocUnsafe(1 << 20);
|
|
91287
|
+
for (;; ) {
|
|
91288
|
+
const n = readSync5(fd, buf, 0, buf.length, null);
|
|
91289
|
+
if (n <= 0)
|
|
91290
|
+
break;
|
|
91291
|
+
hash2.update(buf.subarray(0, n));
|
|
91292
|
+
}
|
|
91293
|
+
} finally {
|
|
91294
|
+
closeSync15(fd);
|
|
91295
|
+
}
|
|
91296
|
+
return hash2.digest("hex");
|
|
91297
|
+
},
|
|
91298
|
+
probeBinaryVersion(path7) {
|
|
91299
|
+
const r = spawnSync15(path7, ["version"], {
|
|
91300
|
+
encoding: "utf-8",
|
|
91301
|
+
timeout: 30000,
|
|
91302
|
+
env: { ...process.env, SWITCHROOM_SELF_UPDATED: "" }
|
|
91303
|
+
});
|
|
91304
|
+
if (r.status !== 0)
|
|
91305
|
+
return null;
|
|
91306
|
+
const out = `${r.stdout ?? ""}`.trim();
|
|
91307
|
+
const m = out.match(/\d+\.\d+\.\d+/);
|
|
91308
|
+
return m ? m[0] : null;
|
|
91309
|
+
},
|
|
91310
|
+
mkdirp(dir) {
|
|
91311
|
+
mkdirSync44(dir, { recursive: true });
|
|
91312
|
+
},
|
|
91313
|
+
copyFile(src, dest) {
|
|
91314
|
+
copyFileSync11(src, dest);
|
|
91315
|
+
},
|
|
91316
|
+
chmodExec(path7) {
|
|
91317
|
+
chmodSync15(path7, 493);
|
|
91318
|
+
},
|
|
91319
|
+
rename(src, dest) {
|
|
91320
|
+
renameSync19(src, dest);
|
|
91321
|
+
},
|
|
91322
|
+
remove(path7) {
|
|
91323
|
+
rmSync14(path7, { force: true });
|
|
91324
|
+
},
|
|
91325
|
+
exists(path7) {
|
|
91326
|
+
return existsSync79(path7);
|
|
91327
|
+
},
|
|
91328
|
+
dirname(path7) {
|
|
91329
|
+
return dirname32(path7);
|
|
91330
|
+
}
|
|
91331
|
+
};
|
|
91332
|
+
}
|
|
91333
|
+
|
|
91334
|
+
// src/cli/update.ts
|
|
91335
|
+
init_component_versions();
|
|
90836
91336
|
function defaultPersistPin(configPath) {
|
|
90837
91337
|
return (pin) => {
|
|
90838
91338
|
const path7 = configPath ?? findConfigFile();
|
|
@@ -90852,16 +91352,16 @@ function defaultPersistPin(configPath) {
|
|
|
90852
91352
|
}
|
|
90853
91353
|
var DEFAULT_COMPOSE_PATH2 = join83(homedir43(), ".switchroom", "compose", "docker-compose.yml");
|
|
90854
91354
|
function runningFromSwitchroomCheckout(scriptPath) {
|
|
90855
|
-
let dir =
|
|
91355
|
+
let dir = dirname33(scriptPath);
|
|
90856
91356
|
for (let i = 0;i < 12; i++) {
|
|
90857
|
-
if (
|
|
91357
|
+
if (existsSync80(join83(dir, ".git"))) {
|
|
90858
91358
|
try {
|
|
90859
91359
|
const pkg = JSON.parse(readFileSync73(join83(dir, "package.json"), "utf-8"));
|
|
90860
91360
|
if (pkg.name === "switchroom")
|
|
90861
91361
|
return true;
|
|
90862
91362
|
} catch {}
|
|
90863
91363
|
}
|
|
90864
|
-
const parent =
|
|
91364
|
+
const parent = dirname33(dir);
|
|
90865
91365
|
if (parent === dir)
|
|
90866
91366
|
break;
|
|
90867
91367
|
dir = parent;
|
|
@@ -90906,6 +91406,61 @@ function planUpdate(opts) {
|
|
|
90906
91406
|
const scriptPath = opts.scriptPath ?? process.argv[1] ?? "";
|
|
90907
91407
|
const steps = [];
|
|
90908
91408
|
const hostdContext = typeof opts.hostdContext === "boolean" ? opts.hostdContext : isHostdContext();
|
|
91409
|
+
steps.push({
|
|
91410
|
+
name: "self-update-cli",
|
|
91411
|
+
description: "Replace the host operator CLI binary with the latest published release (checksum-verified, run-proved, atomic swap + versioned rollback copy), then re-exec the new binary for the remaining steps",
|
|
91412
|
+
skipReason: opts.skipSelfUpdate ? "--skip-self-update flag set" : alreadySelfUpdated(process.env) ? "already re-exec'd from a freshly installed binary in this run" : undefined,
|
|
91413
|
+
run: async () => {
|
|
91414
|
+
const say = opts.stdout ?? ((t) => process.stdout.write(t));
|
|
91415
|
+
const io = opts.selfUpdateIO ?? defaultSelfUpdateIO();
|
|
91416
|
+
const detection = detectInstallKind(opts.installProbe ?? {
|
|
91417
|
+
bundleDir: import.meta.dirname,
|
|
91418
|
+
execPath: process.execPath,
|
|
91419
|
+
scriptPath,
|
|
91420
|
+
inContainer: process.env.SWITCHROOM_HOSTD_CONTEXT === "1" || existsSync80("/.dockerenv")
|
|
91421
|
+
});
|
|
91422
|
+
if (detection.kind !== "static-binary") {
|
|
91423
|
+
say(source_default.gray(` host CLI not self-updated: ${detection.reason}
|
|
91424
|
+
`));
|
|
91425
|
+
return;
|
|
91426
|
+
}
|
|
91427
|
+
const latestTag = opts.latestReleaseTagFn ? await opts.latestReleaseTagFn() : await fetchLatestReleaseTag(io);
|
|
91428
|
+
const plan = planSelfUpdate({
|
|
91429
|
+
detection,
|
|
91430
|
+
currentVersion: SWITCHROOM_VERSION,
|
|
91431
|
+
latestTag
|
|
91432
|
+
});
|
|
91433
|
+
if (plan.action === "skip") {
|
|
91434
|
+
say(source_default.gray(` host CLI not self-updated: ${plan.reason}
|
|
91435
|
+
`));
|
|
91436
|
+
return;
|
|
91437
|
+
}
|
|
91438
|
+
if (plan.action === "current") {
|
|
91439
|
+
say(source_default.gray(` host CLI already on ${plan.version}
|
|
91440
|
+
`));
|
|
91441
|
+
return;
|
|
91442
|
+
}
|
|
91443
|
+
const asset = releaseAssetName(process.platform, process.arch);
|
|
91444
|
+
if (!asset) {
|
|
91445
|
+
say(source_default.gray(` host CLI not self-updated: no published binary for ${process.platform}/${process.arch}
|
|
91446
|
+
`));
|
|
91447
|
+
return;
|
|
91448
|
+
}
|
|
91449
|
+
const result = await performSelfUpdate({
|
|
91450
|
+
plan,
|
|
91451
|
+
assetName: asset,
|
|
91452
|
+
io,
|
|
91453
|
+
log: (s) => say(source_default.gray(` ${s}
|
|
91454
|
+
`))
|
|
91455
|
+
});
|
|
91456
|
+
if (result.replaced && opts.selfUpdateSink) {
|
|
91457
|
+
opts.selfUpdateSink.replacedWith = result.newVersion;
|
|
91458
|
+
opts.selfUpdateSink.binaryPath = result.binaryPath;
|
|
91459
|
+
}
|
|
91460
|
+
say(source_default.green(` ${result.message}
|
|
91461
|
+
`));
|
|
91462
|
+
}
|
|
91463
|
+
});
|
|
90909
91464
|
if (opts.pin) {
|
|
90910
91465
|
const pin = opts.pin;
|
|
90911
91466
|
const persist = opts.persistPinFn ?? defaultPersistPin(opts.configPath);
|
|
@@ -90941,7 +91496,7 @@ function planUpdate(opts) {
|
|
|
90941
91496
|
steps.push({
|
|
90942
91497
|
name: "pull-images",
|
|
90943
91498
|
description: "Pull broker / kernel / agent images from GHCR",
|
|
90944
|
-
skipReason: opts.skipImages ? "--skip-images flag set" : !
|
|
91499
|
+
skipReason: opts.skipImages ? "--skip-images flag set" : !existsSync80(composePath) ? `compose file not found at ${composePath} (run \`switchroom apply --compose-only\` first)` : undefined,
|
|
90945
91500
|
run: () => {
|
|
90946
91501
|
const r = runner("docker", [
|
|
90947
91502
|
"compose",
|
|
@@ -91068,13 +91623,13 @@ function planUpdate(opts) {
|
|
|
91068
91623
|
}
|
|
91069
91624
|
const source = resolve45(import.meta.dirname, "../../skills");
|
|
91070
91625
|
const dest = join83(homedir43(), ".switchroom", "skills", "_bundled");
|
|
91071
|
-
if (!
|
|
91626
|
+
if (!existsSync80(source)) {
|
|
91072
91627
|
process.stderr.write(`switchroom update: sync-bundled-skills \u2014 CLI bundle has no adjacent skills/ at ${source}; skipping.
|
|
91073
91628
|
`);
|
|
91074
91629
|
return;
|
|
91075
91630
|
}
|
|
91076
91631
|
try {
|
|
91077
|
-
|
|
91632
|
+
mkdirSync45(dirname33(dest), { recursive: true });
|
|
91078
91633
|
const r = syncBundledSkills({
|
|
91079
91634
|
source,
|
|
91080
91635
|
dest,
|
|
@@ -91100,10 +91655,10 @@ function planUpdate(opts) {
|
|
|
91100
91655
|
if (opts.syncBundledSkillsFn)
|
|
91101
91656
|
return;
|
|
91102
91657
|
const dest = join83(homedir43(), ".switchroom", "skills", "_bundled");
|
|
91103
|
-
if (!
|
|
91658
|
+
if (!existsSync80(dest)) {
|
|
91104
91659
|
return;
|
|
91105
91660
|
}
|
|
91106
|
-
const missing = getBuiltinDefaultSkillEntries().map((e) => e.key).filter((key) => !
|
|
91661
|
+
const missing = getBuiltinDefaultSkillEntries().map((e) => e.key).filter((key) => !existsSync80(join83(dest, key)));
|
|
91107
91662
|
if (missing.length > 0) {
|
|
91108
91663
|
throw new Error(`verify-bundled-skills: builtin default skill(s) missing from the pool after sync: ` + `${missing.join(", ")}. These ship in the CLI package and must exist in ${dest}. ` + `This is a broken sync or a packaging regression \u2014 the pool is not converged.`);
|
|
91109
91664
|
}
|
|
@@ -91172,7 +91727,7 @@ function planUpdate(opts) {
|
|
|
91172
91727
|
return steps;
|
|
91173
91728
|
}
|
|
91174
91729
|
function defaultRunner2(cmd, args) {
|
|
91175
|
-
const r =
|
|
91730
|
+
const r = spawnSync16(cmd, args, { stdio: "inherit" });
|
|
91176
91731
|
return { status: r.status ?? 1 };
|
|
91177
91732
|
}
|
|
91178
91733
|
function writeMarkerInPreferredLocation(agent, reason, runner) {
|
|
@@ -91215,10 +91770,10 @@ function defaultStatusProbe(composePath) {
|
|
|
91215
91770
|
try {
|
|
91216
91771
|
cliBuiltAt = new Date(statSync45(scriptPath).mtimeMs).toISOString();
|
|
91217
91772
|
} catch {}
|
|
91218
|
-
let dir =
|
|
91773
|
+
let dir = dirname33(scriptPath);
|
|
91219
91774
|
for (let i = 0;i < 8; i++) {
|
|
91220
91775
|
const pkgPath = join83(dir, "package.json");
|
|
91221
|
-
if (
|
|
91776
|
+
if (existsSync80(pkgPath)) {
|
|
91222
91777
|
try {
|
|
91223
91778
|
const pkg = JSON.parse(readFileSync73(pkgPath, "utf-8"));
|
|
91224
91779
|
if (typeof pkg.version === "string")
|
|
@@ -91228,7 +91783,7 @@ function defaultStatusProbe(composePath) {
|
|
|
91228
91783
|
}
|
|
91229
91784
|
break;
|
|
91230
91785
|
}
|
|
91231
|
-
const parent =
|
|
91786
|
+
const parent = dirname33(dir);
|
|
91232
91787
|
if (parent === dir)
|
|
91233
91788
|
break;
|
|
91234
91789
|
dir = parent;
|
|
@@ -91241,13 +91796,13 @@ function defaultStatusProbe(composePath) {
|
|
|
91241
91796
|
warnings.push("could not resolve CLI version (no package.json found above the resolved script path)");
|
|
91242
91797
|
}
|
|
91243
91798
|
const services = [];
|
|
91244
|
-
if (!
|
|
91799
|
+
if (!existsSync80(composePath)) {
|
|
91245
91800
|
warnings.push(`compose file not found at ${composePath}; service status unknown`);
|
|
91246
91801
|
return { cliVersion, cliBuiltAt, services, warnings };
|
|
91247
91802
|
}
|
|
91248
91803
|
let serviceList = [];
|
|
91249
91804
|
try {
|
|
91250
|
-
const r =
|
|
91805
|
+
const r = spawnSync16("docker", ["compose", "-p", "switchroom", "-f", composePath, "config", "--services"], { encoding: "utf-8", timeout: 1e4 });
|
|
91251
91806
|
if (r.status !== 0) {
|
|
91252
91807
|
warnings.push(`docker compose config --services failed: ${r.stderr?.trim() ?? r.error?.message ?? "unknown"}`);
|
|
91253
91808
|
return { cliVersion, cliBuiltAt, services, warnings };
|
|
@@ -91264,7 +91819,7 @@ function defaultStatusProbe(composePath) {
|
|
|
91264
91819
|
let containerCreatedAt = null;
|
|
91265
91820
|
let status = "<unknown>";
|
|
91266
91821
|
try {
|
|
91267
|
-
const r =
|
|
91822
|
+
const r = spawnSync16("docker", ["inspect", "-f", "{{.Config.Image}}|{{.Created}}|{{.State.Status}}", containerName2], { encoding: "utf-8", timeout: 5000 });
|
|
91268
91823
|
if (r.status === 0) {
|
|
91269
91824
|
const [img, created, st] = r.stdout.trim().split("|");
|
|
91270
91825
|
image = img ?? null;
|
|
@@ -91280,7 +91835,7 @@ function defaultStatusProbe(composePath) {
|
|
|
91280
91835
|
let imagePulledAt = null;
|
|
91281
91836
|
if (image) {
|
|
91282
91837
|
try {
|
|
91283
|
-
const r =
|
|
91838
|
+
const r = spawnSync16("docker", ["image", "inspect", "-f", "{{.Id}}|{{.Created}}|{{.Metadata.LastTagTime}}", image], { encoding: "utf-8", timeout: 5000 });
|
|
91284
91839
|
if (r.status === 0) {
|
|
91285
91840
|
const [id, created, lastTag] = r.stdout.trim().split("|");
|
|
91286
91841
|
imageDigestShort = id?.replace(/^sha256:/, "").slice(0, 12) ?? null;
|
|
@@ -91344,6 +91899,47 @@ function formatStatusReport(rep) {
|
|
|
91344
91899
|
return lines.join(`
|
|
91345
91900
|
`);
|
|
91346
91901
|
}
|
|
91902
|
+
function buildReexecArgs(opts) {
|
|
91903
|
+
const args = ["update", "--skip-self-update"];
|
|
91904
|
+
if (opts.skipImages)
|
|
91905
|
+
args.push("--skip-images");
|
|
91906
|
+
if (opts.channel)
|
|
91907
|
+
args.push("--channel", opts.channel);
|
|
91908
|
+
if (opts.pin)
|
|
91909
|
+
args.push("--pin", opts.pin);
|
|
91910
|
+
return args;
|
|
91911
|
+
}
|
|
91912
|
+
function defaultReexec(binaryPath, args) {
|
|
91913
|
+
const r = spawnSync16(binaryPath, args, {
|
|
91914
|
+
stdio: "inherit",
|
|
91915
|
+
env: { ...process.env, [SELF_UPDATE_ENV_SENTINEL]: "1" }
|
|
91916
|
+
});
|
|
91917
|
+
return { status: r.status ?? 1 };
|
|
91918
|
+
}
|
|
91919
|
+
function renderDriftPreamble(opts) {
|
|
91920
|
+
try {
|
|
91921
|
+
const exec = opts.componentExec ?? ((cmd, args) => {
|
|
91922
|
+
const r = spawnSync16(cmd, args, { encoding: "utf-8", timeout: 1e4 });
|
|
91923
|
+
return { status: r.status ?? 1, stdout: r.stdout ?? "" };
|
|
91924
|
+
});
|
|
91925
|
+
let pin;
|
|
91926
|
+
try {
|
|
91927
|
+
pin = loadConfig().release?.pin ?? undefined;
|
|
91928
|
+
} catch {
|
|
91929
|
+
pin = undefined;
|
|
91930
|
+
}
|
|
91931
|
+
const report = detectComponentDrift(collectComponents(SWITCHROOM_VERSION, exec), pin);
|
|
91932
|
+
const body = formatComponentDrift(report);
|
|
91933
|
+
return report.behind.length > 0 ? `${body}
|
|
91934
|
+
|
|
91935
|
+
${report.behind.length} component(s) BEHIND ${report.target} \u2014 this update targets them.
|
|
91936
|
+
` : `${body}
|
|
91937
|
+
`;
|
|
91938
|
+
} catch (err) {
|
|
91939
|
+
return `Component versions: not checkable (${err.message})
|
|
91940
|
+
`;
|
|
91941
|
+
}
|
|
91942
|
+
}
|
|
91347
91943
|
async function runUpdate(opts) {
|
|
91348
91944
|
const stdout = opts.stdout ?? ((s) => process.stdout.write(s));
|
|
91349
91945
|
const stderr = opts.stderr ?? ((s) => process.stderr.write(s));
|
|
@@ -91373,11 +91969,14 @@ async function runUpdate(opts) {
|
|
|
91373
91969
|
return 2;
|
|
91374
91970
|
}
|
|
91375
91971
|
}
|
|
91376
|
-
const
|
|
91972
|
+
const selfUpdateSink = opts.selfUpdateSink ?? {};
|
|
91973
|
+
const steps = planUpdate({ ...opts, selfUpdateSink });
|
|
91377
91974
|
if (opts.check) {
|
|
91378
91975
|
stdout(source_default.bold(`switchroom update --check (dry-run)
|
|
91379
91976
|
|
|
91380
91977
|
`));
|
|
91978
|
+
stdout(renderDriftPreamble(opts) + `
|
|
91979
|
+
`);
|
|
91381
91980
|
for (const step of steps) {
|
|
91382
91981
|
const status = step.skipReason ? source_default.gray(`[skip] ${step.skipReason}`) : source_default.green("[run]");
|
|
91383
91982
|
stdout(` ${status} ${step.name} \u2014 ${step.description}
|
|
@@ -91397,7 +91996,15 @@ Dry-run only; nothing was changed. Re-run without --check to apply.
|
|
|
91397
91996
|
stdout(source_default.bold(`\u25b8 ${step.name}
|
|
91398
91997
|
`));
|
|
91399
91998
|
try {
|
|
91400
|
-
step.run();
|
|
91999
|
+
await step.run();
|
|
92000
|
+
if (step.name === "self-update-cli" && selfUpdateSink.binaryPath) {
|
|
92001
|
+
const reexec = opts.reexecFn ?? defaultReexec;
|
|
92002
|
+
stdout(source_default.bold(`
|
|
92003
|
+
\u25b8 re-exec ${selfUpdateSink.binaryPath} (${selfUpdateSink.replacedWith}) for the remaining steps
|
|
92004
|
+
`));
|
|
92005
|
+
const r = reexec(selfUpdateSink.binaryPath, buildReexecArgs(opts));
|
|
92006
|
+
return r.status;
|
|
92007
|
+
}
|
|
91401
92008
|
} catch (err) {
|
|
91402
92009
|
stderr(source_default.red(`\u2717 ${step.name} failed: ${err.message}
|
|
91403
92010
|
`));
|
|
@@ -91420,7 +92027,7 @@ Dry-run only; nothing was changed. Re-run without --check to apply.
|
|
|
91420
92027
|
return 0;
|
|
91421
92028
|
}
|
|
91422
92029
|
function registerUpdateCommand(program3) {
|
|
91423
|
-
program3.command("update").description("Update switchroom on this host
|
|
92030
|
+
program3.command("update").description("Update EVERY switchroom component on this host \u2014 the operator CLI itself (first), images, scaffolds, the hostd / web / hindsight singletons, and the agent fleet. Wraps the full `self-update && pull && apply && up -d` flow.").option("--check", "Dry-run: print the steps that would execute, exit 0.").option("--skip-images", "Skip the docker image pull (offline mode).").option("--skip-self-update", "Do NOT replace the host operator CLI binary. By default `update` updates every switchroom component INCLUDING itself (and does it first, because `apply` renders scaffolds from templates shipped inside the CLI).").option("--rebuild", "Source-checkout / maintainer only: git pull + bun install + npm run build before applying. REFUSED on a published install \u2014 use `npm i -g switchroom@latest && switchroom update` there.").option("--status", "Read-only snapshot: report local CLI version, image digest + pull time, container creation time per service. Does NOT invoke any update steps. Wired by Telegram /upgrade-status (#927).").option("--json", "Output as JSON (currently only honored under --status; other modes ignore).").addOption(new Option("--channel <c>", "Override the resolved release block for this update run: follow the named channel (dev|rc|latest). Mutually exclusive with --pin.").choices(["dev", "rc", "latest"]).conflicts("pin")).addOption(new Option("--pin <p>", "Override the resolved release block for this update run: pin to a specific build (sha-<7-40 hex> or v<semver>). Mutually exclusive with --channel.").conflicts("channel")).option("--force", "[legacy v0.6 no-op]").option("--no-restart", "[legacy v0.6 no-op]").option("--resume <file>", "[legacy v0.6 no-op]").option("--phase <phase>", "[legacy v0.6 no-op]").action(async (opts) => {
|
|
91424
92031
|
if (opts.pin && !/^(sha-[0-9a-f]{7,40}|v\d+\.\d+\.\d+)$/.test(opts.pin)) {
|
|
91425
92032
|
console.error(source_default.red(`--pin "${opts.pin}" is invalid. Expected sha-<7-40 hex> or v<semver>.`));
|
|
91426
92033
|
process.exit(2);
|
|
@@ -91436,23 +92043,23 @@ function registerUpdateCommand(program3) {
|
|
|
91436
92043
|
|
|
91437
92044
|
// src/cli/rollout.ts
|
|
91438
92045
|
init_helpers();
|
|
91439
|
-
import { spawnSync as
|
|
92046
|
+
import { spawnSync as spawnSync18 } from "node:child_process";
|
|
91440
92047
|
import { readFileSync as readFileSync75, chownSync as chownSync9, statSync as statSync47 } from "node:fs";
|
|
91441
92048
|
import { homedir as homedir45 } from "node:os";
|
|
91442
92049
|
|
|
91443
92050
|
// src/cli/rollout-pin-journal.ts
|
|
91444
92051
|
import {
|
|
91445
|
-
existsSync as
|
|
92052
|
+
existsSync as existsSync81,
|
|
91446
92053
|
readFileSync as readFileSync74,
|
|
91447
92054
|
writeFileSync as writeFileSync31,
|
|
91448
|
-
renameSync as
|
|
92055
|
+
renameSync as renameSync20,
|
|
91449
92056
|
unlinkSync as unlinkSync15,
|
|
91450
92057
|
statSync as statSync46,
|
|
91451
|
-
mkdirSync as
|
|
92058
|
+
mkdirSync as mkdirSync46
|
|
91452
92059
|
} from "node:fs";
|
|
91453
92060
|
import { homedir as homedir44 } from "node:os";
|
|
91454
|
-
import { createHash as
|
|
91455
|
-
import { join as join84, basename as basename9, resolve as resolve46, dirname as
|
|
92061
|
+
import { createHash as createHash17 } from "node:crypto";
|
|
92062
|
+
import { join as join84, basename as basename9, resolve as resolve46, dirname as dirname34 } from "node:path";
|
|
91456
92063
|
init_flock();
|
|
91457
92064
|
var PIN_JOURNAL_MAX_AGE_MS = 15 * 60 * 1000;
|
|
91458
92065
|
var STATE_DIR_NAME = ".switchroom";
|
|
@@ -91461,7 +92068,7 @@ function pinJournalDir(configPath) {
|
|
|
91461
92068
|
if (override && override.trim().length > 0)
|
|
91462
92069
|
return override.trim();
|
|
91463
92070
|
if (configPath) {
|
|
91464
|
-
const dir =
|
|
92071
|
+
const dir = dirname34(resolve46(configPath));
|
|
91465
92072
|
if (basename9(dir) === STATE_DIR_NAME)
|
|
91466
92073
|
return dir;
|
|
91467
92074
|
}
|
|
@@ -91469,7 +92076,7 @@ function pinJournalDir(configPath) {
|
|
|
91469
92076
|
}
|
|
91470
92077
|
function pinJournalPath(configPath) {
|
|
91471
92078
|
const abs = resolve46(configPath);
|
|
91472
|
-
const key =
|
|
92079
|
+
const key = createHash17("sha256").update(abs).digest("hex").slice(0, 12);
|
|
91473
92080
|
return join84(pinJournalDir(abs), `.rollout-pin-journal.${basename9(abs)}.${key}.json`);
|
|
91474
92081
|
}
|
|
91475
92082
|
function isPidAlive(pid) {
|
|
@@ -91506,7 +92113,7 @@ function readPinJournal(configPath, warn = (m) => process.stderr.write(m)) {
|
|
|
91506
92113
|
try {
|
|
91507
92114
|
raw = readFileSync74(p, "utf8");
|
|
91508
92115
|
} catch (e) {
|
|
91509
|
-
if (
|
|
92116
|
+
if (existsSync81(p)) {
|
|
91510
92117
|
warn(`\u26a0\ufe0f rollout pin journal: ${p} exists but could not be read ` + `(${e.message}). A provisional \`release.pin\` may be ` + `uncommitted \u2014 verify it host-side before the next reconcile.
|
|
91511
92118
|
`);
|
|
91512
92119
|
}
|
|
@@ -91566,10 +92173,10 @@ function beginPinPersist(configPath, pin, opts = {}) {
|
|
|
91566
92173
|
pid: process.pid,
|
|
91567
92174
|
at: new Date().toISOString()
|
|
91568
92175
|
};
|
|
91569
|
-
|
|
92176
|
+
mkdirSync46(dirname34(p), { recursive: true });
|
|
91570
92177
|
const tmp = `${p}.${process.pid}.tmp`;
|
|
91571
92178
|
writeFileSync31(tmp, JSON.stringify(journal), { encoding: "utf8", mode: 384 });
|
|
91572
|
-
|
|
92179
|
+
renameSync20(tmp, p);
|
|
91573
92180
|
return journal;
|
|
91574
92181
|
}
|
|
91575
92182
|
function commitPinPersist(configPath) {
|
|
@@ -91578,7 +92185,7 @@ function commitPinPersist(configPath) {
|
|
|
91578
92185
|
unlinkSync15(p);
|
|
91579
92186
|
return null;
|
|
91580
92187
|
} catch (e) {
|
|
91581
|
-
if (!
|
|
92188
|
+
if (!existsSync81(p))
|
|
91582
92189
|
return null;
|
|
91583
92190
|
return `rollout pin journal: FAILED to clear ${p} after a SUCCESSFUL roll ` + `(${e.message}). Delete it host-side \u2014 while it exists, ` + `recovery may revert a proven \`release.pin\`.`;
|
|
91584
92191
|
}
|
|
@@ -91656,10 +92263,10 @@ init_audit_reader();
|
|
|
91656
92263
|
init_hindsight();
|
|
91657
92264
|
|
|
91658
92265
|
// src/cli/deploy-version-guard.ts
|
|
91659
|
-
import { spawnSync as
|
|
92266
|
+
import { spawnSync as spawnSync17 } from "node:child_process";
|
|
91660
92267
|
var DOCKER_INSPECT_TIMEOUT_MS = 60 * 1000;
|
|
91661
92268
|
var defaultRunner3 = (args) => {
|
|
91662
|
-
const r =
|
|
92269
|
+
const r = spawnSync17("docker", args, {
|
|
91663
92270
|
encoding: "utf8",
|
|
91664
92271
|
timeout: DOCKER_INSPECT_TIMEOUT_MS,
|
|
91665
92272
|
killSignal: "SIGKILL"
|
|
@@ -92033,7 +92640,7 @@ function isSpawnTimeout(r, killSignal) {
|
|
|
92033
92640
|
var ROLLOUT_KILL_SIGNAL = "SIGKILL";
|
|
92034
92641
|
function createRolloutDeps(params) {
|
|
92035
92642
|
const { configPath, scriptPath, hostdCtx } = params;
|
|
92036
|
-
const spawn6 = params.spawn ??
|
|
92643
|
+
const spawn6 = params.spawn ?? spawnSync18;
|
|
92037
92644
|
const warn = params.warn ?? ((line) => process.stderr.write(line));
|
|
92038
92645
|
const dockerRun = (args) => {
|
|
92039
92646
|
let r;
|
|
@@ -92287,8 +92894,8 @@ init_helpers();
|
|
|
92287
92894
|
init_lifecycle();
|
|
92288
92895
|
init_resolve_version();
|
|
92289
92896
|
import { execSync as execSync3 } from "node:child_process";
|
|
92290
|
-
import { existsSync as
|
|
92291
|
-
import { dirname as
|
|
92897
|
+
import { existsSync as existsSync82, readFileSync as readFileSync76 } from "node:fs";
|
|
92898
|
+
import { dirname as dirname35, join as join85 } from "node:path";
|
|
92292
92899
|
function getClaudeCodeVersion() {
|
|
92293
92900
|
try {
|
|
92294
92901
|
const out = execSync3("claude --version 2>/dev/null", {
|
|
@@ -92339,15 +92946,15 @@ function locateSwitchroomInstallDir() {
|
|
|
92339
92946
|
let dir = import.meta.dirname;
|
|
92340
92947
|
for (let i = 0;i < 10 && dir && dir !== "/"; i++) {
|
|
92341
92948
|
const pkgPath = join85(dir, "package.json");
|
|
92342
|
-
if (
|
|
92949
|
+
if (existsSync82(pkgPath)) {
|
|
92343
92950
|
try {
|
|
92344
92951
|
const pkg = JSON.parse(readFileSync76(pkgPath, "utf-8"));
|
|
92345
|
-
if (pkg.name === "switchroom" &&
|
|
92952
|
+
if (pkg.name === "switchroom" && existsSync82(join85(dir, ".git"))) {
|
|
92346
92953
|
return dir;
|
|
92347
92954
|
}
|
|
92348
92955
|
} catch {}
|
|
92349
92956
|
}
|
|
92350
|
-
dir =
|
|
92957
|
+
dir = dirname35(dir);
|
|
92351
92958
|
}
|
|
92352
92959
|
return null;
|
|
92353
92960
|
}
|
|
@@ -92521,7 +93128,7 @@ init_merge();
|
|
|
92521
93128
|
|
|
92522
93129
|
// src/agents/session-retention.ts
|
|
92523
93130
|
import {
|
|
92524
|
-
existsSync as
|
|
93131
|
+
existsSync as existsSync83,
|
|
92525
93132
|
readdirSync as readdirSync28,
|
|
92526
93133
|
statSync as statSync48,
|
|
92527
93134
|
unlinkSync as unlinkSync16
|
|
@@ -92532,7 +93139,7 @@ var DEFAULT_SESSION_RETENTION_MAX_AGE_DAYS = 30;
|
|
|
92532
93139
|
var MIN_KEEP = 2;
|
|
92533
93140
|
function collectSessionJsonl(claudeConfigDir) {
|
|
92534
93141
|
const projects = join86(claudeConfigDir, "projects");
|
|
92535
|
-
if (!
|
|
93142
|
+
if (!existsSync83(projects))
|
|
92536
93143
|
return [];
|
|
92537
93144
|
const found = [];
|
|
92538
93145
|
const walk2 = (dir) => {
|
|
@@ -92667,13 +93274,13 @@ function registerHandoffCommand(program3) {
|
|
|
92667
93274
|
|
|
92668
93275
|
// src/issues/store.ts
|
|
92669
93276
|
import {
|
|
92670
|
-
closeSync as
|
|
92671
|
-
existsSync as
|
|
92672
|
-
mkdirSync as
|
|
92673
|
-
openSync as
|
|
93277
|
+
closeSync as closeSync16,
|
|
93278
|
+
existsSync as existsSync84,
|
|
93279
|
+
mkdirSync as mkdirSync47,
|
|
93280
|
+
openSync as openSync16,
|
|
92674
93281
|
readdirSync as readdirSync29,
|
|
92675
93282
|
readFileSync as readFileSync77,
|
|
92676
|
-
renameSync as
|
|
93283
|
+
renameSync as renameSync21,
|
|
92677
93284
|
statSync as statSync49,
|
|
92678
93285
|
unlinkSync as unlinkSync17,
|
|
92679
93286
|
writeFileSync as writeFileSync32,
|
|
@@ -93111,7 +93718,7 @@ var ISSUES_FILE = "issues.jsonl";
|
|
|
93111
93718
|
var ISSUES_LOCK = "issues.lock";
|
|
93112
93719
|
function readAll(stateDir) {
|
|
93113
93720
|
const path7 = join87(stateDir, ISSUES_FILE);
|
|
93114
|
-
if (!
|
|
93721
|
+
if (!existsSync84(path7))
|
|
93115
93722
|
return [];
|
|
93116
93723
|
let raw;
|
|
93117
93724
|
try {
|
|
@@ -93188,7 +93795,7 @@ function record(stateDir, input, nowFn = Date.now) {
|
|
|
93188
93795
|
});
|
|
93189
93796
|
}
|
|
93190
93797
|
function resolve49(stateDir, fingerprint, nowFn = Date.now) {
|
|
93191
|
-
if (!
|
|
93798
|
+
if (!existsSync84(join87(stateDir, ISSUES_FILE)))
|
|
93192
93799
|
return 0;
|
|
93193
93800
|
return withLock(stateDir, () => {
|
|
93194
93801
|
const all = readAll(stateDir);
|
|
@@ -93206,7 +93813,7 @@ function resolve49(stateDir, fingerprint, nowFn = Date.now) {
|
|
|
93206
93813
|
});
|
|
93207
93814
|
}
|
|
93208
93815
|
function resolveAllBySource(stateDir, source, nowFn = Date.now) {
|
|
93209
|
-
if (!
|
|
93816
|
+
if (!existsSync84(join87(stateDir, ISSUES_FILE)))
|
|
93210
93817
|
return 0;
|
|
93211
93818
|
return withLock(stateDir, () => {
|
|
93212
93819
|
const all = readAll(stateDir);
|
|
@@ -93224,7 +93831,7 @@ function resolveAllBySource(stateDir, source, nowFn = Date.now) {
|
|
|
93224
93831
|
});
|
|
93225
93832
|
}
|
|
93226
93833
|
function prune(stateDir, opts = {}) {
|
|
93227
|
-
if (!
|
|
93834
|
+
if (!existsSync84(join87(stateDir, ISSUES_FILE)))
|
|
93228
93835
|
return 0;
|
|
93229
93836
|
return withLock(stateDir, () => {
|
|
93230
93837
|
const all = readAll(stateDir);
|
|
@@ -93254,7 +93861,7 @@ function prune(stateDir, opts = {}) {
|
|
|
93254
93861
|
});
|
|
93255
93862
|
}
|
|
93256
93863
|
function ensureDir(stateDir) {
|
|
93257
|
-
|
|
93864
|
+
mkdirSync47(stateDir, { recursive: true });
|
|
93258
93865
|
}
|
|
93259
93866
|
function writeAll(stateDir, events) {
|
|
93260
93867
|
const path7 = join87(stateDir, ISSUES_FILE);
|
|
@@ -93264,7 +93871,7 @@ function writeAll(stateDir, events) {
|
|
|
93264
93871
|
`) + `
|
|
93265
93872
|
`;
|
|
93266
93873
|
writeFileSync32(tmp, body, "utf-8");
|
|
93267
|
-
|
|
93874
|
+
renameSync21(tmp, path7);
|
|
93268
93875
|
}
|
|
93269
93876
|
var ORPHAN_TMP_TTL_MS = 60000;
|
|
93270
93877
|
var TMP_PREFIX = `${ISSUES_FILE}.tmp-`;
|
|
@@ -93296,7 +93903,7 @@ function withLock(stateDir, fn) {
|
|
|
93296
93903
|
let fd = null;
|
|
93297
93904
|
while (fd === null) {
|
|
93298
93905
|
try {
|
|
93299
|
-
fd =
|
|
93906
|
+
fd = openSync16(lockPath, "wx");
|
|
93300
93907
|
try {
|
|
93301
93908
|
writeSync9(fd, String(process.pid));
|
|
93302
93909
|
} catch {}
|
|
@@ -93316,7 +93923,7 @@ function withLock(stateDir, fn) {
|
|
|
93316
93923
|
return fn();
|
|
93317
93924
|
} finally {
|
|
93318
93925
|
try {
|
|
93319
|
-
|
|
93926
|
+
closeSync16(fd);
|
|
93320
93927
|
} catch {}
|
|
93321
93928
|
try {
|
|
93322
93929
|
unlinkSync17(lockPath);
|
|
@@ -93574,20 +94181,20 @@ function relTime(deltaMs) {
|
|
|
93574
94181
|
|
|
93575
94182
|
// src/cli/deps.ts
|
|
93576
94183
|
init_source();
|
|
93577
|
-
import { existsSync as
|
|
94184
|
+
import { existsSync as existsSync87 } from "node:fs";
|
|
93578
94185
|
import { homedir as homedir48 } from "node:os";
|
|
93579
94186
|
import { join as join90, resolve as resolve50 } from "node:path";
|
|
93580
94187
|
|
|
93581
94188
|
// src/deps/python.ts
|
|
93582
|
-
import { createHash as
|
|
94189
|
+
import { createHash as createHash18 } from "node:crypto";
|
|
93583
94190
|
import {
|
|
93584
|
-
existsSync as
|
|
93585
|
-
mkdirSync as
|
|
94191
|
+
existsSync as existsSync85,
|
|
94192
|
+
mkdirSync as mkdirSync48,
|
|
93586
94193
|
readFileSync as readFileSync78,
|
|
93587
|
-
rmSync as
|
|
94194
|
+
rmSync as rmSync15,
|
|
93588
94195
|
writeFileSync as writeFileSync33
|
|
93589
94196
|
} from "node:fs";
|
|
93590
|
-
import { dirname as
|
|
94197
|
+
import { dirname as dirname36, join as join88 } from "node:path";
|
|
93591
94198
|
import { homedir as homedir46 } from "node:os";
|
|
93592
94199
|
import { execFileSync as execFileSync24 } from "node:child_process";
|
|
93593
94200
|
|
|
@@ -93603,13 +94210,13 @@ function defaultPythonCacheRoot() {
|
|
|
93603
94210
|
return join88(homedir46(), ".switchroom", "deps", "python");
|
|
93604
94211
|
}
|
|
93605
94212
|
function hashFile(path7) {
|
|
93606
|
-
return
|
|
94213
|
+
return createHash18("sha256").update(readFileSync78(path7)).digest("hex");
|
|
93607
94214
|
}
|
|
93608
94215
|
function ensurePythonEnv(opts) {
|
|
93609
94216
|
const { skillName, requirementsPath, force = false } = opts;
|
|
93610
94217
|
const cacheRoot = opts.cacheRoot ?? defaultPythonCacheRoot();
|
|
93611
94218
|
const hostPython = opts.pythonBin ?? "python3";
|
|
93612
|
-
if (!
|
|
94219
|
+
if (!existsSync85(requirementsPath)) {
|
|
93613
94220
|
throw new PythonEnvError(`requirements file not found: ${requirementsPath}`);
|
|
93614
94221
|
}
|
|
93615
94222
|
const venvDir = join88(cacheRoot, skillName);
|
|
@@ -93618,7 +94225,7 @@ function ensurePythonEnv(opts) {
|
|
|
93618
94225
|
const pythonBin = join88(binDir, "python");
|
|
93619
94226
|
const pipBin = join88(binDir, "pip");
|
|
93620
94227
|
const targetHash = hashFile(requirementsPath);
|
|
93621
|
-
if (!force &&
|
|
94228
|
+
if (!force && existsSync85(stampPath) && existsSync85(pythonBin)) {
|
|
93622
94229
|
const existingHash = readFileSync78(stampPath, "utf8").trim();
|
|
93623
94230
|
if (existingHash === targetHash) {
|
|
93624
94231
|
return {
|
|
@@ -93631,10 +94238,10 @@ function ensurePythonEnv(opts) {
|
|
|
93631
94238
|
};
|
|
93632
94239
|
}
|
|
93633
94240
|
}
|
|
93634
|
-
if (
|
|
93635
|
-
|
|
94241
|
+
if (existsSync85(venvDir)) {
|
|
94242
|
+
rmSync15(venvDir, { recursive: true, force: true });
|
|
93636
94243
|
}
|
|
93637
|
-
|
|
94244
|
+
mkdirSync48(dirname36(venvDir), { recursive: true });
|
|
93638
94245
|
try {
|
|
93639
94246
|
execFileSync24(hostPython, ["-m", "venv", venvDir], { stdio: "pipe" });
|
|
93640
94247
|
} catch (err) {
|
|
@@ -93666,16 +94273,16 @@ function ensurePythonEnv(opts) {
|
|
|
93666
94273
|
}
|
|
93667
94274
|
|
|
93668
94275
|
// src/deps/node.ts
|
|
93669
|
-
import { createHash as
|
|
94276
|
+
import { createHash as createHash19 } from "node:crypto";
|
|
93670
94277
|
import {
|
|
93671
|
-
copyFileSync as
|
|
93672
|
-
existsSync as
|
|
93673
|
-
mkdirSync as
|
|
94278
|
+
copyFileSync as copyFileSync12,
|
|
94279
|
+
existsSync as existsSync86,
|
|
94280
|
+
mkdirSync as mkdirSync49,
|
|
93674
94281
|
readFileSync as readFileSync79,
|
|
93675
|
-
rmSync as
|
|
94282
|
+
rmSync as rmSync16,
|
|
93676
94283
|
writeFileSync as writeFileSync34
|
|
93677
94284
|
} from "node:fs";
|
|
93678
|
-
import { dirname as
|
|
94285
|
+
import { dirname as dirname37, join as join89 } from "node:path";
|
|
93679
94286
|
import { homedir as homedir47 } from "node:os";
|
|
93680
94287
|
import { execFileSync as execFileSync25 } from "node:child_process";
|
|
93681
94288
|
|
|
@@ -93702,14 +94309,14 @@ function defaultNodeCacheRoot() {
|
|
|
93702
94309
|
return join89(homedir47(), ".switchroom", "deps", "node");
|
|
93703
94310
|
}
|
|
93704
94311
|
function hashDepInputs(packageJsonPath) {
|
|
93705
|
-
const sourceDir =
|
|
93706
|
-
const hasher =
|
|
94312
|
+
const sourceDir = dirname37(packageJsonPath);
|
|
94313
|
+
const hasher = createHash19("sha256");
|
|
93707
94314
|
hasher.update(`package.json
|
|
93708
94315
|
`);
|
|
93709
94316
|
hasher.update(readFileSync79(packageJsonPath));
|
|
93710
94317
|
for (const lockName of ALL_LOCKFILES) {
|
|
93711
94318
|
const lockPath = join89(sourceDir, lockName);
|
|
93712
|
-
if (
|
|
94319
|
+
if (existsSync86(lockPath)) {
|
|
93713
94320
|
hasher.update(`
|
|
93714
94321
|
`);
|
|
93715
94322
|
hasher.update(lockName);
|
|
@@ -93724,16 +94331,16 @@ function ensureNodeEnv(opts) {
|
|
|
93724
94331
|
const { skillName, packageJsonPath, force = false } = opts;
|
|
93725
94332
|
const cacheRoot = opts.cacheRoot ?? defaultNodeCacheRoot();
|
|
93726
94333
|
const installer = opts.installer ?? "bun";
|
|
93727
|
-
if (!
|
|
94334
|
+
if (!existsSync86(packageJsonPath)) {
|
|
93728
94335
|
throw new NodeEnvError(`package.json not found: ${packageJsonPath}`);
|
|
93729
94336
|
}
|
|
93730
|
-
const sourceDir =
|
|
94337
|
+
const sourceDir = dirname37(packageJsonPath);
|
|
93731
94338
|
const envDir = join89(cacheRoot, skillName);
|
|
93732
94339
|
const stampPath = join89(envDir, ".package.sha256");
|
|
93733
94340
|
const nodeModulesDir = join89(envDir, "node_modules");
|
|
93734
94341
|
const binDir = join89(nodeModulesDir, ".bin");
|
|
93735
94342
|
const targetHash = hashDepInputs(packageJsonPath);
|
|
93736
|
-
if (!force &&
|
|
94343
|
+
if (!force && existsSync86(stampPath) && existsSync86(nodeModulesDir)) {
|
|
93737
94344
|
const existingHash = readFileSync79(stampPath, "utf8").trim();
|
|
93738
94345
|
if (existingHash === targetHash) {
|
|
93739
94346
|
return {
|
|
@@ -93745,16 +94352,16 @@ function ensureNodeEnv(opts) {
|
|
|
93745
94352
|
};
|
|
93746
94353
|
}
|
|
93747
94354
|
}
|
|
93748
|
-
if (
|
|
93749
|
-
|
|
94355
|
+
if (existsSync86(envDir)) {
|
|
94356
|
+
rmSync16(envDir, { recursive: true, force: true });
|
|
93750
94357
|
}
|
|
93751
|
-
|
|
93752
|
-
|
|
94358
|
+
mkdirSync49(envDir, { recursive: true });
|
|
94359
|
+
copyFileSync12(packageJsonPath, join89(envDir, "package.json"));
|
|
93753
94360
|
let copiedLockfile = false;
|
|
93754
94361
|
for (const lockName of LOCKFILES_FOR[installer]) {
|
|
93755
94362
|
const lockPath = join89(sourceDir, lockName);
|
|
93756
|
-
if (
|
|
93757
|
-
|
|
94363
|
+
if (existsSync86(lockPath)) {
|
|
94364
|
+
copyFileSync12(lockPath, join89(envDir, lockName));
|
|
93758
94365
|
copiedLockfile = true;
|
|
93759
94366
|
}
|
|
93760
94367
|
}
|
|
@@ -93789,22 +94396,22 @@ function registerDepsCommand(program3) {
|
|
|
93789
94396
|
const deps = program3.command("deps").description("Manage cached per-skill dependency environments");
|
|
93790
94397
|
deps.command("rebuild <skill>").description("Rebuild the Python venv and/or Node node_modules cache for a skill").option("-p, --python", "Rebuild only the Python env").option("-n, --node", "Rebuild only the Node env").action(async (skill, opts) => {
|
|
93791
94398
|
const skillsRoot = builtinSkillsRoot();
|
|
93792
|
-
if (!
|
|
94399
|
+
if (!existsSync87(skillsRoot)) {
|
|
93793
94400
|
console.error(source_default.red(`Bundled skills pool dir not found at ${skillsRoot} \u2014 run \`switchroom update\` to install it.`));
|
|
93794
94401
|
process.exit(1);
|
|
93795
94402
|
}
|
|
93796
94403
|
const skillDir = join90(skillsRoot, skill);
|
|
93797
|
-
if (!
|
|
94404
|
+
if (!existsSync87(skillDir)) {
|
|
93798
94405
|
console.error(source_default.red(`Unknown skill: ${skill} (no dir at ${skillDir})`));
|
|
93799
94406
|
process.exit(1);
|
|
93800
94407
|
}
|
|
93801
94408
|
const requirementsPath = join90(skillDir, "requirements.txt");
|
|
93802
94409
|
const packageJsonPath = join90(skillDir, "package.json");
|
|
93803
|
-
const wantPython = opts.python ?? (!opts.python && !opts.node &&
|
|
93804
|
-
const wantNode = opts.node ?? (!opts.python && !opts.node &&
|
|
94410
|
+
const wantPython = opts.python ?? (!opts.python && !opts.node && existsSync87(requirementsPath));
|
|
94411
|
+
const wantNode = opts.node ?? (!opts.python && !opts.node && existsSync87(packageJsonPath));
|
|
93805
94412
|
let did = 0;
|
|
93806
94413
|
if (wantPython) {
|
|
93807
|
-
if (!
|
|
94414
|
+
if (!existsSync87(requirementsPath)) {
|
|
93808
94415
|
console.error(source_default.red(`Skill "${skill}" has no requirements.txt at ${requirementsPath}`));
|
|
93809
94416
|
process.exit(1);
|
|
93810
94417
|
}
|
|
@@ -93828,7 +94435,7 @@ function registerDepsCommand(program3) {
|
|
|
93828
94435
|
}
|
|
93829
94436
|
}
|
|
93830
94437
|
if (wantNode) {
|
|
93831
|
-
if (!
|
|
94438
|
+
if (!existsSync87(packageJsonPath)) {
|
|
93832
94439
|
console.error(source_default.red(`Skill "${skill}" has no package.json at ${packageJsonPath}`));
|
|
93833
94440
|
process.exit(1);
|
|
93834
94441
|
}
|
|
@@ -93861,9 +94468,9 @@ function registerDepsCommand(program3) {
|
|
|
93861
94468
|
// src/cli/workspace.ts
|
|
93862
94469
|
init_helpers();
|
|
93863
94470
|
init_loader();
|
|
93864
|
-
import { existsSync as
|
|
94471
|
+
import { existsSync as existsSync88 } from "node:fs";
|
|
93865
94472
|
import { resolve as resolve51, sep as sep4 } from "node:path";
|
|
93866
|
-
import { spawnSync as
|
|
94473
|
+
import { spawnSync as spawnSync19 } from "node:child_process";
|
|
93867
94474
|
|
|
93868
94475
|
// src/agents/workspace.ts
|
|
93869
94476
|
import { readFile as readFile2, stat } from "node:fs/promises";
|
|
@@ -94576,7 +95183,7 @@ function registerWorkspaceCommand(program3) {
|
|
|
94576
95183
|
process.exit(1);
|
|
94577
95184
|
}
|
|
94578
95185
|
const editor = process.env["EDITOR"] ?? process.env["VISUAL"] ?? "vi";
|
|
94579
|
-
const child =
|
|
95186
|
+
const child = spawnSync19(editor, [target], { stdio: "inherit" });
|
|
94580
95187
|
if (child.status !== 0 && child.status !== null) {
|
|
94581
95188
|
process.exit(child.status);
|
|
94582
95189
|
}
|
|
@@ -94638,12 +95245,12 @@ function registerWorkspaceCommand(program3) {
|
|
|
94638
95245
|
if (!dir)
|
|
94639
95246
|
return;
|
|
94640
95247
|
const gitDir = resolve51(dir, ".git");
|
|
94641
|
-
if (!
|
|
95248
|
+
if (!existsSync88(gitDir)) {
|
|
94642
95249
|
process.stdout.write(`Workspace is not a git repository. Re-run \`switchroom agent create ${agentName}\` ` + `or manually \`git init\` in ${dir} to enable versioning.
|
|
94643
95250
|
`);
|
|
94644
95251
|
return;
|
|
94645
95252
|
}
|
|
94646
|
-
const statusResult =
|
|
95253
|
+
const statusResult = spawnSync19("git", ["status", "--short"], {
|
|
94647
95254
|
cwd: dir,
|
|
94648
95255
|
encoding: "utf-8"
|
|
94649
95256
|
});
|
|
@@ -94658,7 +95265,7 @@ function registerWorkspaceCommand(program3) {
|
|
|
94658
95265
|
return;
|
|
94659
95266
|
}
|
|
94660
95267
|
const message = opts.message || `checkpoint: ${new Date().toISOString()}`;
|
|
94661
|
-
const addResult =
|
|
95268
|
+
const addResult = spawnSync19("git", ["add", "-A"], {
|
|
94662
95269
|
cwd: dir,
|
|
94663
95270
|
encoding: "utf-8"
|
|
94664
95271
|
});
|
|
@@ -94667,7 +95274,7 @@ function registerWorkspaceCommand(program3) {
|
|
|
94667
95274
|
`);
|
|
94668
95275
|
process.exit(1);
|
|
94669
95276
|
}
|
|
94670
|
-
const commitResult =
|
|
95277
|
+
const commitResult = spawnSync19("git", ["commit", "-m", message], {
|
|
94671
95278
|
cwd: dir,
|
|
94672
95279
|
encoding: "utf-8"
|
|
94673
95280
|
});
|
|
@@ -94676,7 +95283,7 @@ function registerWorkspaceCommand(program3) {
|
|
|
94676
95283
|
`);
|
|
94677
95284
|
process.exit(1);
|
|
94678
95285
|
}
|
|
94679
|
-
const shaResult =
|
|
95286
|
+
const shaResult = spawnSync19("git", ["rev-parse", "--short", "HEAD"], {
|
|
94680
95287
|
cwd: dir,
|
|
94681
95288
|
encoding: "utf-8"
|
|
94682
95289
|
});
|
|
@@ -94692,12 +95299,12 @@ function registerWorkspaceCommand(program3) {
|
|
|
94692
95299
|
if (!dir)
|
|
94693
95300
|
return;
|
|
94694
95301
|
const gitDir = resolve51(dir, ".git");
|
|
94695
|
-
if (!
|
|
95302
|
+
if (!existsSync88(gitDir)) {
|
|
94696
95303
|
process.stdout.write(`Workspace is not a git repository.
|
|
94697
95304
|
`);
|
|
94698
95305
|
return;
|
|
94699
95306
|
}
|
|
94700
|
-
const child =
|
|
95307
|
+
const child = spawnSync19("git", ["status", "--short"], {
|
|
94701
95308
|
cwd: dir,
|
|
94702
95309
|
stdio: "inherit"
|
|
94703
95310
|
});
|
|
@@ -94717,7 +95324,7 @@ function resolveAgentWorkspaceDirOrExit(program3, agentName) {
|
|
|
94717
95324
|
const agentsDir = resolveAgentsDir(config);
|
|
94718
95325
|
const agentDir = resolve51(agentsDir, agentName);
|
|
94719
95326
|
const dir = resolveAgentWorkspaceDir(agentDir);
|
|
94720
|
-
if (!
|
|
95327
|
+
if (!existsSync88(dir)) {
|
|
94721
95328
|
process.stderr.write(`workspace: ${dir} does not exist yet. Run \`switchroom setup\` or \`switchroom agent scaffold ${agentName}\` to seed it.
|
|
94722
95329
|
`);
|
|
94723
95330
|
return;
|
|
@@ -94753,7 +95360,7 @@ function safeParseInt(value, fallback) {
|
|
|
94753
95360
|
init_helpers();
|
|
94754
95361
|
init_loader();
|
|
94755
95362
|
init_merge();
|
|
94756
|
-
import { copyFileSync as
|
|
95363
|
+
import { copyFileSync as copyFileSync13, existsSync as existsSync89, readFileSync as readFileSync80, writeFileSync as writeFileSync35 } from "node:fs";
|
|
94757
95364
|
import { join as join91, resolve as resolve52 } from "node:path";
|
|
94758
95365
|
init_scaffold();
|
|
94759
95366
|
init_profiles();
|
|
@@ -94771,7 +95378,7 @@ function resolveSoulTargetOrExit(program3, agentName) {
|
|
|
94771
95378
|
const agentsDir = resolveAgentsDir(config);
|
|
94772
95379
|
const agentDir = resolve52(agentsDir, agentName);
|
|
94773
95380
|
const workspaceDir = resolveAgentWorkspaceDir(agentDir);
|
|
94774
|
-
if (!
|
|
95381
|
+
if (!existsSync89(workspaceDir)) {
|
|
94775
95382
|
console.error(`soul: ${workspaceDir} does not exist yet. Run \`switchroom setup\` ` + `or \`switchroom agent scaffold ${agentName}\` to seed it.`);
|
|
94776
95383
|
process.exit(1);
|
|
94777
95384
|
}
|
|
@@ -94797,7 +95404,7 @@ function registerSoulCommand(program3) {
|
|
|
94797
95404
|
const t = resolveSoulTargetOrExit(program3, agentName);
|
|
94798
95405
|
if (!t)
|
|
94799
95406
|
return;
|
|
94800
|
-
if (!
|
|
95407
|
+
if (!existsSync89(t.soulPath)) {
|
|
94801
95408
|
console.error(`soul: ${t.soulPath} does not exist yet \u2014 run ` + `\`switchroom soul reset ${agentName}\` to seed it.`);
|
|
94802
95409
|
process.exit(1);
|
|
94803
95410
|
}
|
|
@@ -94812,7 +95419,7 @@ function registerSoulCommand(program3) {
|
|
|
94812
95419
|
console.error(`soul: profile "${t.profileName}" ships no SOUL.md.hbs \u2014 ` + `nothing to re-seed from.`);
|
|
94813
95420
|
process.exit(1);
|
|
94814
95421
|
}
|
|
94815
|
-
const exists =
|
|
95422
|
+
const exists = existsSync89(t.soulPath);
|
|
94816
95423
|
if (exists && !opts.yes) {
|
|
94817
95424
|
if (!isInteractive()) {
|
|
94818
95425
|
console.error(`soul: ${t.soulPath} already exists. Re-run with --yes to ` + `replace it (the current file is backed up to SOUL.md.bak).`);
|
|
@@ -94827,10 +95434,10 @@ function registerSoulCommand(program3) {
|
|
|
94827
95434
|
let backupPath;
|
|
94828
95435
|
if (exists) {
|
|
94829
95436
|
backupPath = `${t.soulPath}.bak`;
|
|
94830
|
-
if (
|
|
95437
|
+
if (existsSync89(backupPath)) {
|
|
94831
95438
|
backupPath = `${t.soulPath}.bak.${Date.now()}`;
|
|
94832
95439
|
}
|
|
94833
|
-
|
|
95440
|
+
copyFileSync13(t.soulPath, backupPath);
|
|
94834
95441
|
}
|
|
94835
95442
|
writeFileSync35(t.soulPath, content, "utf-8");
|
|
94836
95443
|
if (backupPath) {
|
|
@@ -94846,9 +95453,9 @@ function registerSoulCommand(program3) {
|
|
|
94846
95453
|
// src/cli/debug.ts
|
|
94847
95454
|
init_helpers();
|
|
94848
95455
|
init_loader();
|
|
94849
|
-
import { existsSync as
|
|
95456
|
+
import { existsSync as existsSync90, readFileSync as readFileSync81, readdirSync as readdirSync30, statSync as statSync50 } from "node:fs";
|
|
94850
95457
|
import { resolve as resolve53, join as join92 } from "node:path";
|
|
94851
|
-
import { createHash as
|
|
95458
|
+
import { createHash as createHash20 } from "node:crypto";
|
|
94852
95459
|
init_merge();
|
|
94853
95460
|
init_hindsight2();
|
|
94854
95461
|
function formatBytes(bytes) {
|
|
@@ -94859,7 +95466,7 @@ function estimateTokens(bytes) {
|
|
|
94859
95466
|
}
|
|
94860
95467
|
function readMcpServerNames(agentDir) {
|
|
94861
95468
|
const mcpPath = join92(agentDir, ".mcp.json");
|
|
94862
|
-
if (!
|
|
95469
|
+
if (!existsSync90(mcpPath))
|
|
94863
95470
|
return [];
|
|
94864
95471
|
try {
|
|
94865
95472
|
const parsed = JSON.parse(readFileSync81(mcpPath, "utf-8"));
|
|
@@ -94869,11 +95476,11 @@ function readMcpServerNames(agentDir) {
|
|
|
94869
95476
|
}
|
|
94870
95477
|
}
|
|
94871
95478
|
function sha256(content) {
|
|
94872
|
-
return
|
|
95479
|
+
return createHash20("sha256").update(content).digest("hex").slice(0, 16);
|
|
94873
95480
|
}
|
|
94874
95481
|
function findLatestTranscriptJsonl(claudeConfigDir) {
|
|
94875
95482
|
const projectsDir = join92(claudeConfigDir, "projects");
|
|
94876
|
-
if (!
|
|
95483
|
+
if (!existsSync90(projectsDir))
|
|
94877
95484
|
return;
|
|
94878
95485
|
try {
|
|
94879
95486
|
const entries = readdirSync30(projectsDir, { withFileTypes: true });
|
|
@@ -94883,7 +95490,7 @@ function findLatestTranscriptJsonl(claudeConfigDir) {
|
|
|
94883
95490
|
continue;
|
|
94884
95491
|
const projectPath = join92(projectsDir, entry.name);
|
|
94885
95492
|
const transcriptPath = join92(projectPath, "transcript.jsonl");
|
|
94886
|
-
if (!
|
|
95493
|
+
if (!existsSync90(transcriptPath))
|
|
94887
95494
|
continue;
|
|
94888
95495
|
const stat3 = statSync50(transcriptPath);
|
|
94889
95496
|
if (!latest || stat3.mtimeMs > latest.mtime) {
|
|
@@ -94946,7 +95553,7 @@ function registerDebugCommand(program3) {
|
|
|
94946
95553
|
}
|
|
94947
95554
|
const agentsDir = resolveAgentsDir(config);
|
|
94948
95555
|
const agentDir = resolve53(agentsDir, agentName);
|
|
94949
|
-
if (!
|
|
95556
|
+
if (!existsSync90(agentDir)) {
|
|
94950
95557
|
console.error(`Agent directory not found: ${agentDir}`);
|
|
94951
95558
|
process.exit(1);
|
|
94952
95559
|
}
|
|
@@ -95001,7 +95608,7 @@ function registerDebugCommand(program3) {
|
|
|
95001
95608
|
}
|
|
95002
95609
|
console.log(`=== Append System Prompt (per-session) ===
|
|
95003
95610
|
`);
|
|
95004
|
-
const handoffContent =
|
|
95611
|
+
const handoffContent = existsSync90(handoffPath) ? readFileSync81(handoffPath, "utf-8") : "";
|
|
95005
95612
|
if (handoffContent.trim().length > 0) {
|
|
95006
95613
|
console.log(`-- Handoff Briefing (${formatBytes(handoffContent.length)}) --`);
|
|
95007
95614
|
console.log(handoffContent);
|
|
@@ -95012,7 +95619,7 @@ function registerDebugCommand(program3) {
|
|
|
95012
95619
|
}
|
|
95013
95620
|
console.log(`=== CLAUDE.md (auto-loaded by Claude Code) ===
|
|
95014
95621
|
`);
|
|
95015
|
-
const claudeMdContent =
|
|
95622
|
+
const claudeMdContent = existsSync90(claudeMdPath) ? readFileSync81(claudeMdPath, "utf-8") : "";
|
|
95016
95623
|
if (claudeMdContent.trim().length > 0) {
|
|
95017
95624
|
console.log(`(${formatBytes(claudeMdContent.length)})`);
|
|
95018
95625
|
console.log(claudeMdContent);
|
|
@@ -95023,7 +95630,7 @@ function registerDebugCommand(program3) {
|
|
|
95023
95630
|
}
|
|
95024
95631
|
console.log(`=== Persona (SOUL.md) ===
|
|
95025
95632
|
`);
|
|
95026
|
-
const soulMdContent =
|
|
95633
|
+
const soulMdContent = existsSync90(soulMdPath) ? readFileSync81(soulMdPath, "utf-8") : existsSync90(workspaceSoulMdPath) ? readFileSync81(workspaceSoulMdPath, "utf-8") : "";
|
|
95027
95634
|
if (soulMdContent.trim().length > 0) {
|
|
95028
95635
|
console.log(`(${formatBytes(soulMdContent.length)})`);
|
|
95029
95636
|
console.log(soulMdContent);
|
|
@@ -95087,8 +95694,8 @@ function registerDebugCommand(program3) {
|
|
|
95087
95694
|
const fleetDir = join92(agentsDir, "..", "fleet");
|
|
95088
95695
|
const fleetInvPath = join92(fleetDir, "switchroom-invariants.md");
|
|
95089
95696
|
const fleetClaudePath = join92(fleetDir, "CLAUDE.md");
|
|
95090
|
-
const fleetInvBytes =
|
|
95091
|
-
const fleetClaudeBytes =
|
|
95697
|
+
const fleetInvBytes = existsSync90(fleetInvPath) ? readFileSync81(fleetInvPath, "utf-8").length : 0;
|
|
95698
|
+
const fleetClaudeBytes = existsSync90(fleetClaudePath) ? readFileSync81(fleetClaudePath, "utf-8").length : 0;
|
|
95092
95699
|
const fleetBytes = fleetInvBytes + fleetClaudeBytes;
|
|
95093
95700
|
const totalBytes = stableBytes + perSessionBytes + claudeMdBytes + fleetBytes + perTurnBytes + userBytes;
|
|
95094
95701
|
console.log(`Stable prefix: ${formatBytes(stableBytes).padEnd(20)} (cache-hot; includes SOUL.md ${soulMdBytes.toLocaleString()}B)`);
|
|
@@ -95121,20 +95728,20 @@ init_source();
|
|
|
95121
95728
|
|
|
95122
95729
|
// src/worktree/claim.ts
|
|
95123
95730
|
import { execFileSync as execFileSync26 } from "node:child_process";
|
|
95124
|
-
import { closeSync as
|
|
95731
|
+
import { closeSync as closeSync17, mkdirSync as mkdirSync51, openSync as openSync17, existsSync as existsSync92, unlinkSync as unlinkSync19 } from "node:fs";
|
|
95125
95732
|
import { join as join94, resolve as resolve55 } from "node:path";
|
|
95126
95733
|
import { homedir as homedir50 } from "node:os";
|
|
95127
95734
|
import { randomBytes as randomBytes14 } from "node:crypto";
|
|
95128
95735
|
|
|
95129
95736
|
// src/worktree/registry.ts
|
|
95130
95737
|
import {
|
|
95131
|
-
mkdirSync as
|
|
95738
|
+
mkdirSync as mkdirSync50,
|
|
95132
95739
|
writeFileSync as writeFileSync36,
|
|
95133
95740
|
readFileSync as readFileSync82,
|
|
95134
95741
|
readdirSync as readdirSync31,
|
|
95135
95742
|
unlinkSync as unlinkSync18,
|
|
95136
|
-
existsSync as
|
|
95137
|
-
renameSync as
|
|
95743
|
+
existsSync as existsSync91,
|
|
95744
|
+
renameSync as renameSync22
|
|
95138
95745
|
} from "node:fs";
|
|
95139
95746
|
import { join as join93, resolve as resolve54 } from "node:path";
|
|
95140
95747
|
import { homedir as homedir49 } from "node:os";
|
|
@@ -95145,7 +95752,7 @@ function recordPath(id) {
|
|
|
95145
95752
|
return join93(registryDir(), `${id}.json`);
|
|
95146
95753
|
}
|
|
95147
95754
|
function ensureDir2() {
|
|
95148
|
-
|
|
95755
|
+
mkdirSync50(registryDir(), { recursive: true });
|
|
95149
95756
|
}
|
|
95150
95757
|
function writeRecord(record2) {
|
|
95151
95758
|
ensureDir2();
|
|
@@ -95153,7 +95760,7 @@ function writeRecord(record2) {
|
|
|
95153
95760
|
const tmp = `${target}.tmp${process.pid}`;
|
|
95154
95761
|
writeFileSync36(tmp, JSON.stringify(record2, null, 2) + `
|
|
95155
95762
|
`, { mode: 384 });
|
|
95156
|
-
|
|
95763
|
+
renameSync22(tmp, target);
|
|
95157
95764
|
}
|
|
95158
95765
|
function readRecord(id) {
|
|
95159
95766
|
const path10 = recordPath(id);
|
|
@@ -95191,14 +95798,14 @@ function countByRepo(repoPath) {
|
|
|
95191
95798
|
// src/worktree/claim.ts
|
|
95192
95799
|
function acquireRepoLock(repoPath) {
|
|
95193
95800
|
const lockDir = registryDir();
|
|
95194
|
-
|
|
95801
|
+
mkdirSync51(lockDir, { recursive: true });
|
|
95195
95802
|
const lockName = repoPath.replace(/[^A-Za-z0-9]/g, "_");
|
|
95196
95803
|
const lockPath = join94(lockDir, `.lock-${lockName}`);
|
|
95197
95804
|
const deadline = Date.now() + 5000;
|
|
95198
95805
|
let fd = null;
|
|
95199
95806
|
while (fd === null) {
|
|
95200
95807
|
try {
|
|
95201
|
-
fd =
|
|
95808
|
+
fd = openSync17(lockPath, "wx");
|
|
95202
95809
|
} catch (err) {
|
|
95203
95810
|
if (err.code !== "EEXIST")
|
|
95204
95811
|
throw err;
|
|
@@ -95211,7 +95818,7 @@ function acquireRepoLock(repoPath) {
|
|
|
95211
95818
|
}
|
|
95212
95819
|
return () => {
|
|
95213
95820
|
try {
|
|
95214
|
-
|
|
95821
|
+
closeSync17(fd);
|
|
95215
95822
|
} catch {}
|
|
95216
95823
|
try {
|
|
95217
95824
|
unlinkSync19(lockPath);
|
|
@@ -95247,7 +95854,7 @@ function expandHome(p) {
|
|
|
95247
95854
|
}
|
|
95248
95855
|
async function claimWorktree(input, codeRepos) {
|
|
95249
95856
|
const repoPath = resolveRepoPath(input.repo, codeRepos);
|
|
95250
|
-
if (!
|
|
95857
|
+
if (!existsSync92(repoPath)) {
|
|
95251
95858
|
throw new Error(`Repository path does not exist: ${repoPath}`);
|
|
95252
95859
|
}
|
|
95253
95860
|
let concurrencyCap = DEFAULT_CONCURRENCY;
|
|
@@ -95269,7 +95876,7 @@ async function claimWorktree(input, codeRepos) {
|
|
|
95269
95876
|
const taskSuffix = input.taskName ? sanitizeTaskName(input.taskName) : "task";
|
|
95270
95877
|
branch = `task/${taskSuffix}-${id}`;
|
|
95271
95878
|
const baseDir = worktreesBaseDir();
|
|
95272
|
-
|
|
95879
|
+
mkdirSync51(baseDir, { recursive: true });
|
|
95273
95880
|
worktreePath = join94(baseDir, `${id}-${taskSuffix}`);
|
|
95274
95881
|
const ambientOwner = process.env.SWITCHROOM_AGENT_NAME;
|
|
95275
95882
|
const ownerAgent = input.ownerAgent ?? (ambientOwner != null && ambientOwner !== "" ? ambientOwner : undefined);
|
|
@@ -95303,7 +95910,7 @@ async function claimWorktree(input, codeRepos) {
|
|
|
95303
95910
|
|
|
95304
95911
|
// src/worktree/release.ts
|
|
95305
95912
|
import { execFileSync as execFileSync27 } from "node:child_process";
|
|
95306
|
-
import { existsSync as
|
|
95913
|
+
import { existsSync as existsSync93 } from "node:fs";
|
|
95307
95914
|
function releaseWorktree(input) {
|
|
95308
95915
|
const { id } = input;
|
|
95309
95916
|
const record2 = readRecord(id);
|
|
@@ -95311,7 +95918,7 @@ function releaseWorktree(input) {
|
|
|
95311
95918
|
return { released: true };
|
|
95312
95919
|
}
|
|
95313
95920
|
let gitSuccess = true;
|
|
95314
|
-
if (
|
|
95921
|
+
if (existsSync93(record2.path)) {
|
|
95315
95922
|
try {
|
|
95316
95923
|
execFileSync27("git", ["worktree", "remove", "--force", record2.path], {
|
|
95317
95924
|
cwd: record2.repo,
|
|
@@ -95350,7 +95957,7 @@ function listWorktrees() {
|
|
|
95350
95957
|
|
|
95351
95958
|
// src/worktree/reaper.ts
|
|
95352
95959
|
import { execFileSync as execFileSync28 } from "node:child_process";
|
|
95353
|
-
import { existsSync as
|
|
95960
|
+
import { existsSync as existsSync94 } from "node:fs";
|
|
95354
95961
|
var STALE_THRESHOLD_MS = 10 * 60 * 1000;
|
|
95355
95962
|
function reapSkipReasonText(action) {
|
|
95356
95963
|
switch (action) {
|
|
@@ -95411,7 +96018,7 @@ function planReaper(nowMs, deps = {}) {
|
|
|
95411
96018
|
const plan = [];
|
|
95412
96019
|
for (const record2 of listRecords()) {
|
|
95413
96020
|
const heartbeatAge = now - new Date(record2.heartbeatAt).getTime();
|
|
95414
|
-
const worktreeExists =
|
|
96021
|
+
const worktreeExists = existsSync94(record2.path);
|
|
95415
96022
|
if (!worktreeExists) {
|
|
95416
96023
|
plan.push({
|
|
95417
96024
|
record: record2,
|
|
@@ -95492,13 +96099,13 @@ function runReaper(nowMs, deps = {}) {
|
|
|
95492
96099
|
// src/worktree/gc.ts
|
|
95493
96100
|
import { execFileSync as execFileSync29 } from "node:child_process";
|
|
95494
96101
|
import {
|
|
95495
|
-
existsSync as
|
|
96102
|
+
existsSync as existsSync95,
|
|
95496
96103
|
readFileSync as readFileSync83,
|
|
95497
96104
|
readdirSync as readdirSync32,
|
|
95498
96105
|
statSync as statSync51,
|
|
95499
|
-
renameSync as
|
|
95500
|
-
mkdirSync as
|
|
95501
|
-
rmSync as
|
|
96106
|
+
renameSync as renameSync23,
|
|
96107
|
+
mkdirSync as mkdirSync52,
|
|
96108
|
+
rmSync as rmSync17
|
|
95502
96109
|
} from "node:fs";
|
|
95503
96110
|
import { homedir as homedir51 } from "node:os";
|
|
95504
96111
|
import { join as join95, resolve as resolve56 } from "node:path";
|
|
@@ -95583,7 +96190,7 @@ function isEphemeralPath(path10) {
|
|
|
95583
96190
|
}
|
|
95584
96191
|
return false;
|
|
95585
96192
|
}
|
|
95586
|
-
var
|
|
96193
|
+
var defaultExec3 = (file, args, cwd) => execFileSync29(file, args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).toString();
|
|
95587
96194
|
function defaultPrSignal(repo, branch, exec) {
|
|
95588
96195
|
try {
|
|
95589
96196
|
const out = exec("gh", [
|
|
@@ -95619,11 +96226,11 @@ function trashRoot() {
|
|
|
95619
96226
|
return resolve56(process.env.SWITCHROOM_WORKTREE_TRASH ?? join95(homedir51(), ".switchroom", "worktree-gc-trash"));
|
|
95620
96227
|
}
|
|
95621
96228
|
function planGc(roots, deps = {}) {
|
|
95622
|
-
const exists = deps.existsSync ??
|
|
96229
|
+
const exists = deps.existsSync ?? existsSync95;
|
|
95623
96230
|
const readDir = deps.readDir ?? ((p) => readdirSync32(p));
|
|
95624
96231
|
const readFile4 = deps.readFile ?? ((p) => readFileSync83(p, "utf8"));
|
|
95625
96232
|
const stat3 = deps.stat ?? ((p) => statSync51(p));
|
|
95626
|
-
const exec = deps.exec ??
|
|
96233
|
+
const exec = deps.exec ?? defaultExec3;
|
|
95627
96234
|
const prSignal = deps.prSignal ?? ((repo, branch) => defaultPrSignal(repo, branch, exec));
|
|
95628
96235
|
const stamp = deps.dateStamp ?? "undated";
|
|
95629
96236
|
const trash = join95(trashRoot(), stamp);
|
|
@@ -95748,11 +96355,11 @@ function planGc(roots, deps = {}) {
|
|
|
95748
96355
|
};
|
|
95749
96356
|
}
|
|
95750
96357
|
function applyGc(plan, deps = {}) {
|
|
95751
|
-
const exec = deps.exec ??
|
|
95752
|
-
const mkdirp = deps.mkdirp ?? ((p) => void
|
|
96358
|
+
const exec = deps.exec ?? defaultExec3;
|
|
96359
|
+
const mkdirp = deps.mkdirp ?? ((p) => void mkdirSync52(p, { recursive: true }));
|
|
95753
96360
|
const move = deps.move ?? ((src, dest) => {
|
|
95754
96361
|
try {
|
|
95755
|
-
|
|
96362
|
+
renameSync23(src, dest);
|
|
95756
96363
|
} catch {
|
|
95757
96364
|
exec("mv", [src, dest]);
|
|
95758
96365
|
}
|
|
@@ -95798,7 +96405,7 @@ function selectPurgeTargets(entries, olderThanDays) {
|
|
|
95798
96405
|
return entries.filter((e) => e.ageDays >= olderThanDays).map((e) => e.path);
|
|
95799
96406
|
}
|
|
95800
96407
|
function listTrashEntries(nowMs, deps = {}) {
|
|
95801
|
-
const exists = deps.existsSync ??
|
|
96408
|
+
const exists = deps.existsSync ?? existsSync95;
|
|
95802
96409
|
const readDir = deps.readDir ?? ((p) => readdirSync32(p));
|
|
95803
96410
|
const root = trashRoot();
|
|
95804
96411
|
if (!exists(root))
|
|
@@ -95828,7 +96435,7 @@ function purgeTrash(paths) {
|
|
|
95828
96435
|
const errors2 = [];
|
|
95829
96436
|
for (const p of paths) {
|
|
95830
96437
|
try {
|
|
95831
|
-
|
|
96438
|
+
rmSync17(p, { recursive: true, force: true });
|
|
95832
96439
|
deleted.push(p);
|
|
95833
96440
|
} catch (e) {
|
|
95834
96441
|
errors2.push(`${p}: ${e.message}`);
|
|
@@ -96059,10 +96666,10 @@ init_drive();
|
|
|
96059
96666
|
// src/cli/drive-mcp-launcher.ts
|
|
96060
96667
|
init_scaffold_integration();
|
|
96061
96668
|
import {
|
|
96062
|
-
chmodSync as
|
|
96063
|
-
mkdirSync as
|
|
96669
|
+
chmodSync as chmodSync16,
|
|
96670
|
+
mkdirSync as mkdirSync53,
|
|
96064
96671
|
readdirSync as readdirSync33,
|
|
96065
|
-
rmSync as
|
|
96672
|
+
rmSync as rmSync18,
|
|
96066
96673
|
writeFileSync as writeFileSync37
|
|
96067
96674
|
} from "node:fs";
|
|
96068
96675
|
import { join as join96 } from "node:path";
|
|
@@ -96258,15 +96865,15 @@ function resolveCredentialsDir(env2) {
|
|
|
96258
96865
|
return join96(stateBase, "google-workspace-mcp", "credentials");
|
|
96259
96866
|
}
|
|
96260
96867
|
function writeSeedFile(dir, email, seed) {
|
|
96261
|
-
|
|
96262
|
-
|
|
96868
|
+
mkdirSync53(dir, { recursive: true, mode: 448 });
|
|
96869
|
+
chmodSync16(dir, 448);
|
|
96263
96870
|
for (const name of readdirSync33(dir)) {
|
|
96264
|
-
|
|
96871
|
+
rmSync18(join96(dir, name), { force: true, recursive: true });
|
|
96265
96872
|
}
|
|
96266
96873
|
const filename = encodeCredentialsFilename(email);
|
|
96267
96874
|
const filePath = join96(dir, filename);
|
|
96268
96875
|
writeFileSync37(filePath, JSON.stringify(seed), { mode: 384 });
|
|
96269
|
-
|
|
96876
|
+
chmodSync16(filePath, 384);
|
|
96270
96877
|
return filePath;
|
|
96271
96878
|
}
|
|
96272
96879
|
async function fetchBrokerGoogleCreds() {
|
|
@@ -96423,8 +97030,8 @@ function registerDriveMcpLauncherCommand(program3) {
|
|
|
96423
97030
|
// src/cli/m365-mcp-launcher.ts
|
|
96424
97031
|
init_scaffold_integration();
|
|
96425
97032
|
import { spawn as spawn6 } from "node:child_process";
|
|
96426
|
-
import { writeFileSync as writeFileSync38, mkdirSync as
|
|
96427
|
-
import { dirname as
|
|
97033
|
+
import { writeFileSync as writeFileSync38, mkdirSync as mkdirSync54 } from "node:fs";
|
|
97034
|
+
import { dirname as dirname38, join as join97 } from "node:path";
|
|
96428
97035
|
var SOFTERIA_TOKEN_ENV = "MS365_MCP_OAUTH_TOKEN";
|
|
96429
97036
|
var DEFAULT_REFRESH_LEAD_MS = 5 * 60 * 1000;
|
|
96430
97037
|
var MAX_REFRESH_INTERVAL_MS = 60 * 60 * 1000;
|
|
@@ -96460,7 +97067,7 @@ function computeRefreshDelayMs(expiresAt, now, leadMs = DEFAULT_REFRESH_LEAD_MS)
|
|
|
96460
97067
|
function writeRefreshHeartbeat(agentName, data, account) {
|
|
96461
97068
|
const path10 = heartbeatPath(agentName, account);
|
|
96462
97069
|
try {
|
|
96463
|
-
|
|
97070
|
+
mkdirSync54(dirname38(path10), { recursive: true });
|
|
96464
97071
|
writeFileSync38(path10, JSON.stringify(data, null, 2), { mode: 420 });
|
|
96465
97072
|
} catch {}
|
|
96466
97073
|
}
|
|
@@ -96701,8 +97308,8 @@ function registerM365McpLauncherCommand(program3) {
|
|
|
96701
97308
|
// src/cli/notion-mcp-launcher.ts
|
|
96702
97309
|
init_scaffold_integration();
|
|
96703
97310
|
import { spawn as spawn7 } from "node:child_process";
|
|
96704
|
-
import { existsSync as
|
|
96705
|
-
import { dirname as
|
|
97311
|
+
import { existsSync as existsSync96, mkdirSync as mkdirSync55, writeFileSync as writeFileSync39 } from "node:fs";
|
|
97312
|
+
import { dirname as dirname39 } from "node:path";
|
|
96706
97313
|
var HEARTBEAT_WRITE_INTERVAL_MS = 30 * 1000;
|
|
96707
97314
|
var DEFAULT_HEARTBEAT_PATH = "/state/agent/notion-launcher.heartbeat.json";
|
|
96708
97315
|
var DEFAULT_VAULT_KEY = "notion/integration-token";
|
|
@@ -96712,9 +97319,9 @@ function buildNotionMcpArgs(opts) {
|
|
|
96712
97319
|
}
|
|
96713
97320
|
function defaultWriteHeartbeat(path10, contents) {
|
|
96714
97321
|
try {
|
|
96715
|
-
const dir =
|
|
96716
|
-
if (!
|
|
96717
|
-
|
|
97322
|
+
const dir = dirname39(path10);
|
|
97323
|
+
if (!existsSync96(dir))
|
|
97324
|
+
mkdirSync55(dir, { recursive: true });
|
|
96718
97325
|
writeFileSync39(path10, contents);
|
|
96719
97326
|
} catch {}
|
|
96720
97327
|
}
|
|
@@ -96825,7 +97432,7 @@ function registerNotionMcpLauncherCommand(program3) {
|
|
|
96825
97432
|
|
|
96826
97433
|
// src/cli/hindsight-mcp-shim.ts
|
|
96827
97434
|
init_hindsight();
|
|
96828
|
-
import { mkdirSync as
|
|
97435
|
+
import { mkdirSync as mkdirSync56, readFileSync as readFileSync84, renameSync as renameSync24, writeFileSync as writeFileSync40 } from "node:fs";
|
|
96829
97436
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
96830
97437
|
import { join as join98 } from "node:path";
|
|
96831
97438
|
import { createInterface as createInterface6 } from "node:readline";
|
|
@@ -97057,11 +97664,11 @@ class HindsightShim {
|
|
|
97057
97664
|
}
|
|
97058
97665
|
writeCache(result) {
|
|
97059
97666
|
try {
|
|
97060
|
-
|
|
97667
|
+
mkdirSync56(this.opts.cacheDir, { recursive: true });
|
|
97061
97668
|
const tmp = join98(this.opts.cacheDir, `.${TOOLS_CACHE_FILENAME}.${process.pid}.tmp`);
|
|
97062
97669
|
writeFileSync40(tmp, JSON.stringify(result, null, 2) + `
|
|
97063
97670
|
`);
|
|
97064
|
-
|
|
97671
|
+
renameSync24(tmp, this.cachePath);
|
|
97065
97672
|
} catch (err) {
|
|
97066
97673
|
this.log(`[hindsight-shim] cache write failed: ${String(err)}`);
|
|
97067
97674
|
}
|
|
@@ -97905,7 +98512,7 @@ function runRedactStdin() {
|
|
|
97905
98512
|
}
|
|
97906
98513
|
|
|
97907
98514
|
// src/cli/status-ask.ts
|
|
97908
|
-
import { readFileSync as readFileSync86, existsSync as
|
|
98515
|
+
import { readFileSync as readFileSync86, existsSync as existsSync97, readdirSync as readdirSync34 } from "node:fs";
|
|
97909
98516
|
import { join as join99 } from "node:path";
|
|
97910
98517
|
import { homedir as homedir52 } from "node:os";
|
|
97911
98518
|
|
|
@@ -98228,7 +98835,7 @@ function runReport(opts) {
|
|
|
98228
98835
|
function resolveSources(explicitPath) {
|
|
98229
98836
|
if (explicitPath != null && explicitPath.trim() !== "") {
|
|
98230
98837
|
const trimmed = explicitPath.trim();
|
|
98231
|
-
if (!
|
|
98838
|
+
if (!existsSync97(trimmed)) {
|
|
98232
98839
|
process.stderr.write(`status-ask report: ${trimmed}: file not found
|
|
98233
98840
|
`);
|
|
98234
98841
|
process.exit(1);
|
|
@@ -98244,7 +98851,7 @@ function resolveSources(explicitPath) {
|
|
|
98244
98851
|
} catch {
|
|
98245
98852
|
agentsDir = join99(homedir52(), ".switchroom", "agents");
|
|
98246
98853
|
}
|
|
98247
|
-
if (!
|
|
98854
|
+
if (!existsSync97(agentsDir))
|
|
98248
98855
|
return [];
|
|
98249
98856
|
const sources = [];
|
|
98250
98857
|
let entries;
|
|
@@ -98255,7 +98862,7 @@ function resolveSources(explicitPath) {
|
|
|
98255
98862
|
}
|
|
98256
98863
|
for (const name of entries) {
|
|
98257
98864
|
const path10 = join99(agentsDir, name, "runtime-metrics.jsonl");
|
|
98258
|
-
if (
|
|
98865
|
+
if (existsSync97(path10)) {
|
|
98259
98866
|
sources.push({ path: path10, agent: name });
|
|
98260
98867
|
}
|
|
98261
98868
|
}
|
|
@@ -98284,14 +98891,14 @@ var import_yaml21 = __toESM(require_dist(), 1);
|
|
|
98284
98891
|
// src/config/overlay-writer.ts
|
|
98285
98892
|
init_paths();
|
|
98286
98893
|
import {
|
|
98287
|
-
closeSync as
|
|
98288
|
-
existsSync as
|
|
98894
|
+
closeSync as closeSync18,
|
|
98895
|
+
existsSync as existsSync98,
|
|
98289
98896
|
fsyncSync as fsyncSync8,
|
|
98290
|
-
mkdirSync as
|
|
98291
|
-
openSync as
|
|
98897
|
+
mkdirSync as mkdirSync57,
|
|
98898
|
+
openSync as openSync18,
|
|
98292
98899
|
readdirSync as readdirSync35,
|
|
98293
98900
|
readFileSync as readFileSync87,
|
|
98294
|
-
renameSync as
|
|
98901
|
+
renameSync as renameSync25,
|
|
98295
98902
|
statSync as statSync53,
|
|
98296
98903
|
unlinkSync as unlinkSync20,
|
|
98297
98904
|
writeSync as writeSync10
|
|
@@ -98315,21 +98922,21 @@ function overlayPathsFor(agent, opts = {}) {
|
|
|
98315
98922
|
};
|
|
98316
98923
|
}
|
|
98317
98924
|
function ensureDirs(paths) {
|
|
98318
|
-
|
|
98319
|
-
|
|
98925
|
+
mkdirSync57(paths.scheduleDir, { recursive: true });
|
|
98926
|
+
mkdirSync57(paths.scheduleStagingDir, { recursive: true });
|
|
98320
98927
|
}
|
|
98321
98928
|
function ensureSkillsDirs(paths) {
|
|
98322
|
-
|
|
98323
|
-
|
|
98929
|
+
mkdirSync57(paths.skillsDir, { recursive: true });
|
|
98930
|
+
mkdirSync57(paths.skillsStagingDir, { recursive: true });
|
|
98324
98931
|
}
|
|
98325
98932
|
function withAgentLock(paths, fn) {
|
|
98326
|
-
|
|
98933
|
+
mkdirSync57(paths.agentRoot, { recursive: true });
|
|
98327
98934
|
const start = Date.now();
|
|
98328
98935
|
const TIMEOUT_MS = 5000;
|
|
98329
98936
|
let fd = null;
|
|
98330
98937
|
while (Date.now() - start < TIMEOUT_MS) {
|
|
98331
98938
|
try {
|
|
98332
|
-
fd =
|
|
98939
|
+
fd = openSync18(paths.lockPath, "wx");
|
|
98333
98940
|
break;
|
|
98334
98941
|
} catch (err) {
|
|
98335
98942
|
const e = err;
|
|
@@ -98353,7 +98960,7 @@ function withAgentLock(paths, fn) {
|
|
|
98353
98960
|
return fn();
|
|
98354
98961
|
} finally {
|
|
98355
98962
|
try {
|
|
98356
|
-
|
|
98963
|
+
closeSync18(fd);
|
|
98357
98964
|
} catch {}
|
|
98358
98965
|
try {
|
|
98359
98966
|
unlinkSync20(paths.lockPath);
|
|
@@ -98366,14 +98973,14 @@ function writeOverlayEntry(agent, slug, yamlText, opts = {}) {
|
|
|
98366
98973
|
ensureDirs(paths);
|
|
98367
98974
|
const stagingPath = join100(paths.scheduleStagingDir, `${slug}.yaml`);
|
|
98368
98975
|
const finalPath = join100(paths.scheduleDir, `${slug}.yaml`);
|
|
98369
|
-
const fd =
|
|
98976
|
+
const fd = openSync18(stagingPath, "w", 384);
|
|
98370
98977
|
try {
|
|
98371
98978
|
writeSync10(fd, yamlText);
|
|
98372
98979
|
fsyncSync8(fd);
|
|
98373
98980
|
} finally {
|
|
98374
|
-
|
|
98981
|
+
closeSync18(fd);
|
|
98375
98982
|
}
|
|
98376
|
-
|
|
98983
|
+
renameSync25(stagingPath, finalPath);
|
|
98377
98984
|
return finalPath;
|
|
98378
98985
|
});
|
|
98379
98986
|
}
|
|
@@ -98383,14 +98990,14 @@ function writeSkillsOverlayEntry(agent, slug, yamlText, opts = {}) {
|
|
|
98383
98990
|
ensureSkillsDirs(paths);
|
|
98384
98991
|
const stagingPath = join100(paths.skillsStagingDir, `${slug}.yaml`);
|
|
98385
98992
|
const finalPath = join100(paths.skillsDir, `${slug}.yaml`);
|
|
98386
|
-
const fd =
|
|
98993
|
+
const fd = openSync18(stagingPath, "w", 384);
|
|
98387
98994
|
try {
|
|
98388
98995
|
writeSync10(fd, yamlText);
|
|
98389
98996
|
fsyncSync8(fd);
|
|
98390
98997
|
} finally {
|
|
98391
|
-
|
|
98998
|
+
closeSync18(fd);
|
|
98392
98999
|
}
|
|
98393
|
-
|
|
99000
|
+
renameSync25(stagingPath, finalPath);
|
|
98394
99001
|
return finalPath;
|
|
98395
99002
|
});
|
|
98396
99003
|
}
|
|
@@ -98398,7 +99005,7 @@ function deleteSkillsOverlayEntry(agent, slug, opts = {}) {
|
|
|
98398
99005
|
const paths = overlayPathsFor(agent, opts);
|
|
98399
99006
|
return withAgentLock(paths, () => {
|
|
98400
99007
|
const finalPath = join100(paths.skillsDir, `${slug}.yaml`);
|
|
98401
|
-
if (!
|
|
99008
|
+
if (!existsSync98(finalPath))
|
|
98402
99009
|
return false;
|
|
98403
99010
|
unlinkSync20(finalPath);
|
|
98404
99011
|
return true;
|
|
@@ -98406,7 +99013,7 @@ function deleteSkillsOverlayEntry(agent, slug, opts = {}) {
|
|
|
98406
99013
|
}
|
|
98407
99014
|
function listSkillsOverlayEntries(agent, opts = {}) {
|
|
98408
99015
|
const paths = overlayPathsFor(agent, opts);
|
|
98409
|
-
if (!
|
|
99016
|
+
if (!existsSync98(paths.skillsDir))
|
|
98410
99017
|
return [];
|
|
98411
99018
|
const out = [];
|
|
98412
99019
|
for (const name of readdirSync35(paths.skillsDir)) {
|
|
@@ -98425,7 +99032,7 @@ function deleteOverlayEntry(agent, slug, opts = {}) {
|
|
|
98425
99032
|
const paths = overlayPathsFor(agent, opts);
|
|
98426
99033
|
return withAgentLock(paths, () => {
|
|
98427
99034
|
const finalPath = join100(paths.scheduleDir, `${slug}.yaml`);
|
|
98428
|
-
if (!
|
|
99035
|
+
if (!existsSync98(finalPath))
|
|
98429
99036
|
return false;
|
|
98430
99037
|
unlinkSync20(finalPath);
|
|
98431
99038
|
return true;
|
|
@@ -98433,7 +99040,7 @@ function deleteOverlayEntry(agent, slug, opts = {}) {
|
|
|
98433
99040
|
}
|
|
98434
99041
|
function listOverlayEntries(agent, opts = {}) {
|
|
98435
99042
|
const paths = overlayPathsFor(agent, opts);
|
|
98436
|
-
if (!
|
|
99043
|
+
if (!existsSync98(paths.scheduleDir))
|
|
98437
99044
|
return [];
|
|
98438
99045
|
const out = [];
|
|
98439
99046
|
for (const name of readdirSync35(paths.scheduleDir)) {
|
|
@@ -98660,14 +99267,14 @@ function reconcileAgentCronOnly(agent) {
|
|
|
98660
99267
|
|
|
98661
99268
|
// src/cli/agent-config-pending.ts
|
|
98662
99269
|
import {
|
|
98663
|
-
closeSync as
|
|
98664
|
-
existsSync as
|
|
99270
|
+
closeSync as closeSync19,
|
|
99271
|
+
existsSync as existsSync99,
|
|
98665
99272
|
fsyncSync as fsyncSync9,
|
|
98666
|
-
mkdirSync as
|
|
98667
|
-
openSync as
|
|
99273
|
+
mkdirSync as mkdirSync58,
|
|
99274
|
+
openSync as openSync19,
|
|
98668
99275
|
readdirSync as readdirSync36,
|
|
98669
99276
|
readFileSync as readFileSync88,
|
|
98670
|
-
renameSync as
|
|
99277
|
+
renameSync as renameSync26,
|
|
98671
99278
|
unlinkSync as unlinkSync21,
|
|
98672
99279
|
writeFileSync as writeFileSync41,
|
|
98673
99280
|
writeSync as writeSync11
|
|
@@ -98681,7 +99288,7 @@ function pendingDir(agent, opts = {}) {
|
|
|
98681
99288
|
}
|
|
98682
99289
|
function ensurePendingDir(agent, opts = {}) {
|
|
98683
99290
|
const dir = pendingDir(agent, opts);
|
|
98684
|
-
|
|
99291
|
+
mkdirSync58(dir, { recursive: true });
|
|
98685
99292
|
return dir;
|
|
98686
99293
|
}
|
|
98687
99294
|
function newStageId() {
|
|
@@ -98703,14 +99310,14 @@ function stagePendingScheduleEntry(opts) {
|
|
|
98703
99310
|
};
|
|
98704
99311
|
const yamlTmp = `${yamlPath}.tmp-${process.pid}`;
|
|
98705
99312
|
{
|
|
98706
|
-
const fd =
|
|
99313
|
+
const fd = openSync19(yamlTmp, "w", 384);
|
|
98707
99314
|
try {
|
|
98708
99315
|
writeSync11(fd, opts.yamlText);
|
|
98709
99316
|
fsyncSync9(fd);
|
|
98710
99317
|
} finally {
|
|
98711
|
-
|
|
99318
|
+
closeSync19(fd);
|
|
98712
99319
|
}
|
|
98713
|
-
|
|
99320
|
+
renameSync26(yamlTmp, yamlPath);
|
|
98714
99321
|
}
|
|
98715
99322
|
writeFileSync41(metaPath, JSON.stringify(meta, null, 2) + `
|
|
98716
99323
|
`, { mode: 384 });
|
|
@@ -98718,7 +99325,7 @@ function stagePendingScheduleEntry(opts) {
|
|
|
98718
99325
|
}
|
|
98719
99326
|
function listPendingScheduleEntries(agent, opts = {}) {
|
|
98720
99327
|
const dir = pendingDir(agent, opts);
|
|
98721
|
-
if (!
|
|
99328
|
+
if (!existsSync99(dir))
|
|
98722
99329
|
return [];
|
|
98723
99330
|
const out = [];
|
|
98724
99331
|
for (const name of readdirSync36(dir).sort()) {
|
|
@@ -98727,7 +99334,7 @@ function listPendingScheduleEntries(agent, opts = {}) {
|
|
|
98727
99334
|
const stageId = name.slice(0, -".meta.json".length);
|
|
98728
99335
|
const metaPath = join101(dir, name);
|
|
98729
99336
|
const yamlPath = join101(dir, `${stageId}.yaml`);
|
|
98730
|
-
if (!
|
|
99337
|
+
if (!existsSync99(yamlPath))
|
|
98731
99338
|
continue;
|
|
98732
99339
|
try {
|
|
98733
99340
|
const meta = JSON.parse(readFileSync88(metaPath, "utf-8"));
|
|
@@ -98746,10 +99353,10 @@ function commitPendingScheduleEntry(opts) {
|
|
|
98746
99353
|
const slug = match.meta.entry.name ?? match.stageId;
|
|
98747
99354
|
const paths = overlayPathsFor(opts.agent, { root: opts.root });
|
|
98748
99355
|
const finalPath = join101(paths.scheduleDir, `${slug}.yaml`);
|
|
98749
|
-
if (
|
|
99356
|
+
if (existsSync99(finalPath)) {
|
|
98750
99357
|
return { committed: false, reason: "slug_collision" };
|
|
98751
99358
|
}
|
|
98752
|
-
|
|
99359
|
+
renameSync26(match.yamlPath, finalPath);
|
|
98753
99360
|
unlinkSync21(match.metaPath);
|
|
98754
99361
|
return { committed: true, path: finalPath, slug };
|
|
98755
99362
|
}
|
|
@@ -98768,7 +99375,7 @@ function denyPendingScheduleEntry(opts) {
|
|
|
98768
99375
|
}
|
|
98769
99376
|
|
|
98770
99377
|
// src/cli/agent-config-write.ts
|
|
98771
|
-
import { existsSync as
|
|
99378
|
+
import { existsSync as existsSync100, readFileSync as readFileSync89 } from "node:fs";
|
|
98772
99379
|
import { execFileSync as execFileSync30 } from "node:child_process";
|
|
98773
99380
|
|
|
98774
99381
|
// src/scheduler/schedule-report.ts
|
|
@@ -99158,7 +99765,7 @@ function scheduleRemove(opts) {
|
|
|
99158
99765
|
}
|
|
99159
99766
|
let priorContent = null;
|
|
99160
99767
|
try {
|
|
99161
|
-
if (
|
|
99768
|
+
if (existsSync100(match.path))
|
|
99162
99769
|
priorContent = readFileSync89(match.path, "utf-8");
|
|
99163
99770
|
} catch {}
|
|
99164
99771
|
deleteOverlayEntry(agent, match.slug, { root: opts.root });
|
|
@@ -99362,7 +99969,7 @@ function registerAgentConfigWriteCommands(program3) {
|
|
|
99362
99969
|
}
|
|
99363
99970
|
let blob;
|
|
99364
99971
|
if (opts.jsonl) {
|
|
99365
|
-
blob =
|
|
99972
|
+
blob = existsSync100(opts.jsonl) ? readFileSync89(opts.jsonl, "utf-8") : "";
|
|
99366
99973
|
} else {
|
|
99367
99974
|
try {
|
|
99368
99975
|
blob = execFileSync30("docker", ["exec", `switchroom-${agent}`, "cat", "/state/agent/scheduler.jsonl"], {
|
|
@@ -99394,7 +100001,7 @@ function registerAgentConfigWriteCommands(program3) {
|
|
|
99394
100001
|
|
|
99395
100002
|
// src/cli/agent-config-skill-write.ts
|
|
99396
100003
|
var import_yaml22 = __toESM(require_dist(), 1);
|
|
99397
|
-
import { existsSync as
|
|
100004
|
+
import { existsSync as existsSync101 } from "node:fs";
|
|
99398
100005
|
init_reconcile_default_skills();
|
|
99399
100006
|
init_agent_config();
|
|
99400
100007
|
var import_yaml23 = __toESM(require_dist(), 1);
|
|
@@ -99474,7 +100081,7 @@ function skillInstall(opts) {
|
|
|
99474
100081
|
}
|
|
99475
100082
|
const poolDir = opts.bundledSkillsPoolDir ?? getBundledSkillsPoolDir();
|
|
99476
100083
|
const skillPath = join102(poolDir, skillName);
|
|
99477
|
-
if (!
|
|
100084
|
+
if (!existsSync101(skillPath)) {
|
|
99478
100085
|
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.`);
|
|
99479
100086
|
}
|
|
99480
100087
|
const yamlText = import_yaml22.stringify({ skills: [skillName] });
|
|
@@ -99637,23 +100244,23 @@ function registerAgentConfigSkillWriteCommands(program3) {
|
|
|
99637
100244
|
|
|
99638
100245
|
// src/cli/skill.ts
|
|
99639
100246
|
import {
|
|
99640
|
-
closeSync as
|
|
99641
|
-
existsSync as
|
|
100247
|
+
closeSync as closeSync20,
|
|
100248
|
+
existsSync as existsSync102,
|
|
99642
100249
|
lstatSync as lstatSync12,
|
|
99643
|
-
mkdirSync as
|
|
100250
|
+
mkdirSync as mkdirSync59,
|
|
99644
100251
|
mkdtempSync as mkdtempSync5,
|
|
99645
|
-
openSync as
|
|
100252
|
+
openSync as openSync20,
|
|
99646
100253
|
readFileSync as readFileSync90,
|
|
99647
100254
|
readdirSync as readdirSync37,
|
|
99648
100255
|
realpathSync as realpathSync7,
|
|
99649
|
-
renameSync as
|
|
99650
|
-
rmSync as
|
|
100256
|
+
renameSync as renameSync27,
|
|
100257
|
+
rmSync as rmSync19,
|
|
99651
100258
|
statSync as statSync54,
|
|
99652
100259
|
writeFileSync as writeFileSync42
|
|
99653
100260
|
} from "node:fs";
|
|
99654
100261
|
import { tmpdir as tmpdir6, homedir as homedir53 } from "node:os";
|
|
99655
|
-
import { dirname as
|
|
99656
|
-
import { spawnSync as
|
|
100262
|
+
import { dirname as dirname40, join as join103, relative as relative4, resolve as resolve58 } from "node:path";
|
|
100263
|
+
import { spawnSync as spawnSync20 } from "node:child_process";
|
|
99657
100264
|
|
|
99658
100265
|
// src/cli/skill-common.ts
|
|
99659
100266
|
var import_yaml24 = __toESM(require_dist(), 1);
|
|
@@ -99946,7 +100553,7 @@ function loadFromDir(dir) {
|
|
|
99946
100553
|
function loadFromTarball(tarPath) {
|
|
99947
100554
|
const isGz = tarPath.endsWith(".gz") || tarPath.endsWith(".tgz");
|
|
99948
100555
|
const listFlags = isGz ? ["-tzf"] : ["-tf"];
|
|
99949
|
-
const list2 =
|
|
100556
|
+
const list2 = spawnSync20("tar", [...listFlags, tarPath], {
|
|
99950
100557
|
encoding: "utf-8",
|
|
99951
100558
|
stdio: ["ignore", "pipe", "pipe"]
|
|
99952
100559
|
});
|
|
@@ -99963,7 +100570,7 @@ function loadFromTarball(tarPath) {
|
|
|
99963
100570
|
const staging = mkdtempSync5(join103(tmpdir6(), "skill-apply-extract-"));
|
|
99964
100571
|
try {
|
|
99965
100572
|
const flags = isGz ? ["-xzf"] : ["-xf"];
|
|
99966
|
-
const r =
|
|
100573
|
+
const r = spawnSync20("tar", [
|
|
99967
100574
|
...flags,
|
|
99968
100575
|
tarPath,
|
|
99969
100576
|
"-C",
|
|
@@ -99979,7 +100586,7 @@ function loadFromTarball(tarPath) {
|
|
|
99979
100586
|
return loadFromDir(staging);
|
|
99980
100587
|
} finally {
|
|
99981
100588
|
try {
|
|
99982
|
-
|
|
100589
|
+
rmSync19(staging, { recursive: true, force: true });
|
|
99983
100590
|
} catch {}
|
|
99984
100591
|
}
|
|
99985
100592
|
}
|
|
@@ -100038,7 +100645,7 @@ function validatePayload(name, files) {
|
|
|
100038
100645
|
if (errors2.length === 0) {
|
|
100039
100646
|
for (const [path10, content] of Object.entries(files)) {
|
|
100040
100647
|
if (SH_SCRIPT_RE2.test(path10)) {
|
|
100041
|
-
const r =
|
|
100648
|
+
const r = spawnSync20("bash", ["-n"], {
|
|
100042
100649
|
input: content,
|
|
100043
100650
|
encoding: "utf-8"
|
|
100044
100651
|
});
|
|
@@ -100050,14 +100657,14 @@ function validatePayload(name, files) {
|
|
|
100050
100657
|
const tmpPy = join103(tmp, "check.py");
|
|
100051
100658
|
try {
|
|
100052
100659
|
writeFileSync42(tmpPy, content);
|
|
100053
|
-
const r =
|
|
100660
|
+
const r = spawnSync20("python3", ["-m", "py_compile", tmpPy], {
|
|
100054
100661
|
encoding: "utf-8"
|
|
100055
100662
|
});
|
|
100056
100663
|
if (r.status !== 0) {
|
|
100057
100664
|
errors2.push(`${path10} fails \`python3 -m py_compile\` syntax check: ${(r.stderr ?? "").trim()}`);
|
|
100058
100665
|
}
|
|
100059
100666
|
} finally {
|
|
100060
|
-
|
|
100667
|
+
rmSync19(tmp, { recursive: true, force: true });
|
|
100061
100668
|
}
|
|
100062
100669
|
}
|
|
100063
100670
|
}
|
|
@@ -100067,7 +100674,7 @@ function validatePayload(name, files) {
|
|
|
100067
100674
|
function diffSummary(currentDir, files) {
|
|
100068
100675
|
const lines = [];
|
|
100069
100676
|
const currentFiles = {};
|
|
100070
|
-
if (
|
|
100677
|
+
if (existsSync102(currentDir)) {
|
|
100071
100678
|
const walk2 = (sub) => {
|
|
100072
100679
|
for (const ent of readdirSync37(sub, { withFileTypes: true })) {
|
|
100073
100680
|
const full = join103(sub, ent.name);
|
|
@@ -100103,8 +100710,8 @@ function diffSummary(currentDir, files) {
|
|
|
100103
100710
|
`);
|
|
100104
100711
|
}
|
|
100105
100712
|
function writePayload(poolDir, name, files) {
|
|
100106
|
-
if (!
|
|
100107
|
-
|
|
100713
|
+
if (!existsSync102(poolDir)) {
|
|
100714
|
+
mkdirSync59(poolDir, { recursive: true, mode: 493 });
|
|
100108
100715
|
}
|
|
100109
100716
|
const target = join103(poolDir, name);
|
|
100110
100717
|
let targetIsSymlink = false;
|
|
@@ -100122,12 +100729,12 @@ function writePayload(poolDir, name, files) {
|
|
|
100122
100729
|
try {
|
|
100123
100730
|
for (const [path10, content] of Object.entries(files)) {
|
|
100124
100731
|
const full = join103(staging, path10);
|
|
100125
|
-
|
|
100126
|
-
const fd =
|
|
100732
|
+
mkdirSync59(dirname40(full), { recursive: true, mode: 493 });
|
|
100733
|
+
const fd = openSync20(full, "wx");
|
|
100127
100734
|
try {
|
|
100128
100735
|
writeFileSync42(fd, content);
|
|
100129
100736
|
} finally {
|
|
100130
|
-
|
|
100737
|
+
closeSync20(fd);
|
|
100131
100738
|
}
|
|
100132
100739
|
if (SH_SCRIPT_RE2.test(path10) || PY_SCRIPT_RE2.test(path10)) {
|
|
100133
100740
|
const fs7 = __require("node:fs");
|
|
@@ -100141,23 +100748,23 @@ function writePayload(poolDir, name, files) {
|
|
|
100141
100748
|
} catch {}
|
|
100142
100749
|
if (targetExists) {
|
|
100143
100750
|
oldRename = `${target}.skill-apply-old-${Date.now()}`;
|
|
100144
|
-
|
|
100751
|
+
renameSync27(target, oldRename);
|
|
100145
100752
|
}
|
|
100146
|
-
|
|
100753
|
+
renameSync27(staging, target);
|
|
100147
100754
|
if (oldRename) {
|
|
100148
|
-
|
|
100755
|
+
rmSync19(oldRename, { recursive: true, force: true });
|
|
100149
100756
|
oldRename = null;
|
|
100150
100757
|
}
|
|
100151
100758
|
} catch (err2) {
|
|
100152
100759
|
try {
|
|
100153
|
-
|
|
100760
|
+
rmSync19(staging, { recursive: true, force: true });
|
|
100154
100761
|
} catch {}
|
|
100155
|
-
if (oldRename &&
|
|
100762
|
+
if (oldRename && existsSync102(oldRename)) {
|
|
100156
100763
|
try {
|
|
100157
|
-
if (
|
|
100158
|
-
|
|
100764
|
+
if (existsSync102(target)) {
|
|
100765
|
+
rmSync19(target, { recursive: true, force: true });
|
|
100159
100766
|
}
|
|
100160
|
-
|
|
100767
|
+
renameSync27(oldRename, target);
|
|
100161
100768
|
} catch {}
|
|
100162
100769
|
}
|
|
100163
100770
|
throw err2;
|
|
@@ -100175,7 +100782,7 @@ function registerSkillCommand(program3) {
|
|
|
100175
100782
|
files = loadFromStdin();
|
|
100176
100783
|
} else {
|
|
100177
100784
|
const fromPath = resolve58(opts.from);
|
|
100178
|
-
if (!
|
|
100785
|
+
if (!existsSync102(fromPath)) {
|
|
100179
100786
|
fail4(`--from path does not exist: ${opts.from}`);
|
|
100180
100787
|
}
|
|
100181
100788
|
const st = statSync54(fromPath);
|
|
@@ -100213,7 +100820,7 @@ function registerSkillCommand(program3) {
|
|
|
100213
100820
|
\u2713 Wrote ${name} to ${currentDir}`));
|
|
100214
100821
|
const applyBin = process.argv[1] ?? "switchroom";
|
|
100215
100822
|
console.log(source_default.gray(`Running \`switchroom apply --non-interactive\`...`));
|
|
100216
|
-
const r =
|
|
100823
|
+
const r = spawnSync20(process.argv0, [applyBin, "apply", "--non-interactive"], { stdio: "inherit" });
|
|
100217
100824
|
if (r.status !== 0) {
|
|
100218
100825
|
console.error(source_default.yellow(`(warning: \`switchroom apply\` exited ${r.status} \u2014 skill is ` + `in the pool but symlinks may not be refreshed. Re-run manually.)`));
|
|
100219
100826
|
}
|
|
@@ -100230,23 +100837,23 @@ function sumBytes(files) {
|
|
|
100230
100837
|
// src/cli/skill-personal.ts
|
|
100231
100838
|
init_esm();
|
|
100232
100839
|
import {
|
|
100233
|
-
closeSync as
|
|
100234
|
-
existsSync as
|
|
100840
|
+
closeSync as closeSync21,
|
|
100841
|
+
existsSync as existsSync103,
|
|
100235
100842
|
lstatSync as lstatSync13,
|
|
100236
|
-
mkdirSync as
|
|
100843
|
+
mkdirSync as mkdirSync60,
|
|
100237
100844
|
mkdtempSync as mkdtempSync6,
|
|
100238
|
-
openSync as
|
|
100845
|
+
openSync as openSync21,
|
|
100239
100846
|
readFileSync as readFileSync91,
|
|
100240
100847
|
readdirSync as readdirSync38,
|
|
100241
|
-
renameSync as
|
|
100242
|
-
rmSync as
|
|
100848
|
+
renameSync as renameSync28,
|
|
100849
|
+
rmSync as rmSync20,
|
|
100243
100850
|
statSync as statSync55,
|
|
100244
100851
|
utimesSync,
|
|
100245
100852
|
writeFileSync as writeFileSync43
|
|
100246
100853
|
} from "node:fs";
|
|
100247
|
-
import { dirname as
|
|
100854
|
+
import { dirname as dirname41, join as join104, relative as relative5, resolve as resolve59 } from "node:path";
|
|
100248
100855
|
import { homedir as homedir54, tmpdir as tmpdir7 } from "node:os";
|
|
100249
|
-
import { spawnSync as
|
|
100856
|
+
import { spawnSync as spawnSync21 } from "node:child_process";
|
|
100250
100857
|
init_helpers();
|
|
100251
100858
|
init_agent_config();
|
|
100252
100859
|
init_source();
|
|
@@ -100257,14 +100864,14 @@ var PERSONAL_SKILLS_SUBPATH = "personal-skills";
|
|
|
100257
100864
|
function resolveConfigSkillsDir(agent) {
|
|
100258
100865
|
const override = process.env.SWITCHROOM_CONFIG_DIR;
|
|
100259
100866
|
const candidate = override ? resolve59(override) : join104(homedir54(), ".switchroom-config");
|
|
100260
|
-
if (!
|
|
100867
|
+
if (!existsSync103(candidate))
|
|
100261
100868
|
return null;
|
|
100262
100869
|
return join104(candidate, "agents", agent, PERSONAL_SKILLS_SUBPATH);
|
|
100263
100870
|
}
|
|
100264
100871
|
var MIRROR_PRIOR_TTL_MS = 24 * 60 * 60 * 1000;
|
|
100265
100872
|
function sweepMirrorPriors(configSkillsRoot) {
|
|
100266
100873
|
try {
|
|
100267
|
-
if (!
|
|
100874
|
+
if (!existsSync103(configSkillsRoot))
|
|
100268
100875
|
return;
|
|
100269
100876
|
const now = Date.now();
|
|
100270
100877
|
for (const ent of readdirSync38(configSkillsRoot)) {
|
|
@@ -100277,7 +100884,7 @@ function sweepMirrorPriors(configSkillsRoot) {
|
|
|
100277
100884
|
if (now - ts < MIRROR_PRIOR_TTL_MS)
|
|
100278
100885
|
continue;
|
|
100279
100886
|
try {
|
|
100280
|
-
|
|
100887
|
+
rmSync20(join104(configSkillsRoot, ent), { recursive: true, force: true });
|
|
100281
100888
|
} catch {}
|
|
100282
100889
|
}
|
|
100283
100890
|
} catch {}
|
|
@@ -100300,17 +100907,17 @@ function mirrorToConfigRepo(agent, name, liveSkillDir) {
|
|
|
100300
100907
|
}
|
|
100301
100908
|
if (liveSkillDir === null) {
|
|
100302
100909
|
sweepMirrorPriors(configSkillsRoot);
|
|
100303
|
-
if (
|
|
100910
|
+
if (existsSync103(dest)) {
|
|
100304
100911
|
const trash = join104(configSkillsRoot, `.${name}-trash-${Date.now()}`);
|
|
100305
|
-
|
|
100912
|
+
renameSync28(dest, trash);
|
|
100306
100913
|
}
|
|
100307
100914
|
return;
|
|
100308
100915
|
}
|
|
100309
|
-
|
|
100916
|
+
mkdirSync60(configSkillsRoot, { recursive: true, mode: 493 });
|
|
100310
100917
|
sweepMirrorPriors(configSkillsRoot);
|
|
100311
100918
|
const staging = mkdtempSync6(join104(configSkillsRoot, `.${name}-staging-`));
|
|
100312
100919
|
const walk2 = (src, dst) => {
|
|
100313
|
-
|
|
100920
|
+
mkdirSync60(dst, { recursive: true, mode: 493 });
|
|
100314
100921
|
for (const ent of readdirSync38(src, { withFileTypes: true })) {
|
|
100315
100922
|
const s = join104(src, ent.name);
|
|
100316
100923
|
const d = join104(dst, ent.name);
|
|
@@ -100324,11 +100931,11 @@ function mirrorToConfigRepo(agent, name, liveSkillDir) {
|
|
|
100324
100931
|
}
|
|
100325
100932
|
};
|
|
100326
100933
|
walk2(liveSkillDir, staging);
|
|
100327
|
-
if (
|
|
100934
|
+
if (existsSync103(dest)) {
|
|
100328
100935
|
const prior = join104(configSkillsRoot, `.${name}-prior-${Date.now()}`);
|
|
100329
|
-
|
|
100936
|
+
renameSync28(dest, prior);
|
|
100330
100937
|
}
|
|
100331
|
-
|
|
100938
|
+
renameSync28(staging, dest);
|
|
100332
100939
|
} catch (err2) {
|
|
100333
100940
|
process.stderr.write(source_default.yellow(`warning: mirror to ${dest} failed (${err2.message ?? err2}); ` + `live copy still works, but this skill is not version-controlled until next successful sync.
|
|
100334
100941
|
`));
|
|
@@ -100365,7 +100972,7 @@ function trashDir(agentsRoot, agent) {
|
|
|
100365
100972
|
}
|
|
100366
100973
|
function countPersonalSkills(agentsRoot, agent) {
|
|
100367
100974
|
const skillsDir = join104(agentsRoot, agent, ".claude", "skills");
|
|
100368
|
-
if (!
|
|
100975
|
+
if (!existsSync103(skillsDir))
|
|
100369
100976
|
return 0;
|
|
100370
100977
|
let n = 0;
|
|
100371
100978
|
for (const ent of readdirSync38(skillsDir, { withFileTypes: true })) {
|
|
@@ -100450,7 +101057,7 @@ function behavioralValidate(files) {
|
|
|
100450
101057
|
const errors2 = [];
|
|
100451
101058
|
for (const [path10, content] of Object.entries(files)) {
|
|
100452
101059
|
if (SH_SCRIPT_RE.test(path10)) {
|
|
100453
|
-
const r =
|
|
101060
|
+
const r = spawnSync21("bash", ["-n"], { input: content, encoding: "utf-8" });
|
|
100454
101061
|
if (r.status !== 0) {
|
|
100455
101062
|
errors2.push(`${path10} fails \`bash -n\`: ${(r.stderr ?? "").trim()}`);
|
|
100456
101063
|
}
|
|
@@ -100459,14 +101066,14 @@ function behavioralValidate(files) {
|
|
|
100459
101066
|
const tmpPy = join104(tmp, "check.py");
|
|
100460
101067
|
try {
|
|
100461
101068
|
writeFileSync43(tmpPy, content);
|
|
100462
|
-
const r =
|
|
101069
|
+
const r = spawnSync21("python3", ["-m", "py_compile", tmpPy], {
|
|
100463
101070
|
encoding: "utf-8"
|
|
100464
101071
|
});
|
|
100465
101072
|
if (r.status !== 0) {
|
|
100466
101073
|
errors2.push(`${path10} fails \`python3 -m py_compile\`: ${(r.stderr ?? "").trim()}`);
|
|
100467
101074
|
}
|
|
100468
101075
|
} finally {
|
|
100469
|
-
|
|
101076
|
+
rmSync20(tmp, { recursive: true, force: true });
|
|
100470
101077
|
}
|
|
100471
101078
|
}
|
|
100472
101079
|
}
|
|
@@ -100474,7 +101081,7 @@ function behavioralValidate(files) {
|
|
|
100474
101081
|
}
|
|
100475
101082
|
function sweepTrash(agentsRoot, agent) {
|
|
100476
101083
|
const trash = trashDir(agentsRoot, agent);
|
|
100477
|
-
if (!
|
|
101084
|
+
if (!existsSync103(trash))
|
|
100478
101085
|
return;
|
|
100479
101086
|
const now = Date.now();
|
|
100480
101087
|
for (const ent of readdirSync38(trash, { withFileTypes: true })) {
|
|
@@ -100484,7 +101091,7 @@ function sweepTrash(agentsRoot, agent) {
|
|
|
100484
101091
|
try {
|
|
100485
101092
|
const st = statSync55(entPath);
|
|
100486
101093
|
if (now - st.mtimeMs > TRASH_TTL_MS) {
|
|
100487
|
-
|
|
101094
|
+
rmSync20(entPath, { recursive: true, force: true });
|
|
100488
101095
|
}
|
|
100489
101096
|
} catch {}
|
|
100490
101097
|
}
|
|
@@ -100500,18 +101107,18 @@ function writePersonalSkill(targetDir, files) {
|
|
|
100500
101107
|
if (targetIsSymlink) {
|
|
100501
101108
|
fail5(`refusing to overwrite symlink at ${targetDir}; investigate manually`);
|
|
100502
101109
|
}
|
|
100503
|
-
|
|
100504
|
-
const staging = mkdtempSync6(join104(
|
|
101110
|
+
mkdirSync60(dirname41(targetDir), { recursive: true, mode: 493 });
|
|
101111
|
+
const staging = mkdtempSync6(join104(dirname41(targetDir), `.skill-personal-stage-`));
|
|
100505
101112
|
let oldRename = null;
|
|
100506
101113
|
try {
|
|
100507
101114
|
for (const [path10, content] of Object.entries(files)) {
|
|
100508
101115
|
const full = join104(staging, path10);
|
|
100509
|
-
|
|
100510
|
-
const fd =
|
|
101116
|
+
mkdirSync60(dirname41(full), { recursive: true, mode: 493 });
|
|
101117
|
+
const fd = openSync21(full, "wx");
|
|
100511
101118
|
try {
|
|
100512
101119
|
writeFileSync43(fd, content);
|
|
100513
101120
|
} finally {
|
|
100514
|
-
|
|
101121
|
+
closeSync21(fd);
|
|
100515
101122
|
}
|
|
100516
101123
|
if (SH_SCRIPT_RE.test(path10) || PY_SCRIPT_RE.test(path10)) {
|
|
100517
101124
|
const fs7 = __require("node:fs");
|
|
@@ -100525,23 +101132,23 @@ function writePersonalSkill(targetDir, files) {
|
|
|
100525
101132
|
} catch {}
|
|
100526
101133
|
if (targetExists) {
|
|
100527
101134
|
oldRename = `${targetDir}.personal-old-${Date.now()}`;
|
|
100528
|
-
|
|
101135
|
+
renameSync28(targetDir, oldRename);
|
|
100529
101136
|
}
|
|
100530
|
-
|
|
101137
|
+
renameSync28(staging, targetDir);
|
|
100531
101138
|
if (oldRename) {
|
|
100532
|
-
|
|
101139
|
+
rmSync20(oldRename, { recursive: true, force: true });
|
|
100533
101140
|
oldRename = null;
|
|
100534
101141
|
}
|
|
100535
101142
|
} catch (err2) {
|
|
100536
101143
|
try {
|
|
100537
|
-
|
|
101144
|
+
rmSync20(staging, { recursive: true, force: true });
|
|
100538
101145
|
} catch {}
|
|
100539
|
-
if (oldRename &&
|
|
101146
|
+
if (oldRename && existsSync103(oldRename)) {
|
|
100540
101147
|
try {
|
|
100541
|
-
if (
|
|
100542
|
-
|
|
101148
|
+
if (existsSync103(targetDir)) {
|
|
101149
|
+
rmSync20(targetDir, { recursive: true, force: true });
|
|
100543
101150
|
}
|
|
100544
|
-
|
|
101151
|
+
renameSync28(oldRename, targetDir);
|
|
100545
101152
|
} catch {}
|
|
100546
101153
|
}
|
|
100547
101154
|
throw err2;
|
|
@@ -100604,7 +101211,7 @@ function loadFiles(opts) {
|
|
|
100604
101211
|
return loadFromStdin2();
|
|
100605
101212
|
}
|
|
100606
101213
|
const p = resolve59(opts.from);
|
|
100607
|
-
if (!
|
|
101214
|
+
if (!existsSync103(p)) {
|
|
100608
101215
|
fail5(`--from path does not exist: ${opts.from}`);
|
|
100609
101216
|
}
|
|
100610
101217
|
const st = statSync55(p);
|
|
@@ -100666,7 +101273,7 @@ function resolveCloneSource(source, opts) {
|
|
|
100666
101273
|
const slug = m[2];
|
|
100667
101274
|
const root = tier === "bundled" ? opts.bundledRoot ?? defaultBundledRoot() : opts.sharedRoot ?? defaultSharedRoot();
|
|
100668
101275
|
const dir = join104(root, slug);
|
|
100669
|
-
if (!
|
|
101276
|
+
if (!existsSync103(dir)) {
|
|
100670
101277
|
fail5(`clone source ${JSON.stringify(source)} not found at ${dir}; ` + `check \`switchroom skill search --tier ${tier}\``, 1);
|
|
100671
101278
|
}
|
|
100672
101279
|
const st = lstatSync13(dir);
|
|
@@ -100790,10 +101397,10 @@ function removePersonalAction(name, opts) {
|
|
|
100790
101397
|
throw err2;
|
|
100791
101398
|
}
|
|
100792
101399
|
const trashRoot2 = trashDir(agentsRoot, agent);
|
|
100793
|
-
|
|
101400
|
+
mkdirSync60(trashRoot2, { recursive: true, mode: 493 });
|
|
100794
101401
|
const ts = Date.now();
|
|
100795
101402
|
const trashTarget = join104(trashRoot2, `${name}-${ts}`);
|
|
100796
|
-
|
|
101403
|
+
renameSync28(target, trashTarget);
|
|
100797
101404
|
const now = new Date(ts);
|
|
100798
101405
|
utimesSync(trashTarget, now, now);
|
|
100799
101406
|
mirrorToConfigRepo(agent, name, null);
|
|
@@ -100813,7 +101420,7 @@ function listPersonalAction(opts) {
|
|
|
100813
101420
|
sweepTrash(agentsRoot, agent);
|
|
100814
101421
|
const skillsDir = join104(agentsRoot, agent, ".claude", "skills");
|
|
100815
101422
|
const personal = [];
|
|
100816
|
-
if (
|
|
101423
|
+
if (existsSync103(skillsDir)) {
|
|
100817
101424
|
for (const ent of readdirSync38(skillsDir, { withFileTypes: true })) {
|
|
100818
101425
|
if (!ent.isDirectory())
|
|
100819
101426
|
continue;
|
|
@@ -100946,7 +101553,7 @@ function registerSelfImproveProposeSkillCommand(program3) {
|
|
|
100946
101553
|
init_esm();
|
|
100947
101554
|
init_helpers();
|
|
100948
101555
|
var import_yaml25 = __toESM(require_dist(), 1);
|
|
100949
|
-
import { existsSync as
|
|
101556
|
+
import { existsSync as existsSync104, readdirSync as readdirSync39, readFileSync as readFileSync93, statSync as statSync56 } from "node:fs";
|
|
100950
101557
|
import { homedir as homedir56 } from "node:os";
|
|
100951
101558
|
import { join as join106, resolve as resolve60 } from "node:path";
|
|
100952
101559
|
var PERSONAL_PREFIX2 = "personal-";
|
|
@@ -100963,7 +101570,7 @@ function defaultBundledRoot2() {
|
|
|
100963
101570
|
}
|
|
100964
101571
|
function readSkillFrontmatter(skillDir) {
|
|
100965
101572
|
const mdPath = join106(skillDir, "SKILL.md");
|
|
100966
|
-
if (!
|
|
101573
|
+
if (!existsSync104(mdPath))
|
|
100967
101574
|
return null;
|
|
100968
101575
|
let content;
|
|
100969
101576
|
try {
|
|
@@ -101007,7 +101614,7 @@ function listPersonalSkills(agent, agentsRoot = defaultAgentsRoot()) {
|
|
|
101007
101614
|
if (!AGENT_NAME_RE3.test(agent))
|
|
101008
101615
|
return [];
|
|
101009
101616
|
const skillsDir = join106(agentsRoot, agent, ".claude/skills");
|
|
101010
|
-
if (!
|
|
101617
|
+
if (!existsSync104(skillsDir))
|
|
101011
101618
|
return [];
|
|
101012
101619
|
const out = [];
|
|
101013
101620
|
let entries;
|
|
@@ -101045,7 +101652,7 @@ function listPersonalSkills(agent, agentsRoot = defaultAgentsRoot()) {
|
|
|
101045
101652
|
return out;
|
|
101046
101653
|
}
|
|
101047
101654
|
function listSharedSkills(sharedRoot = defaultSharedRoot2()) {
|
|
101048
|
-
if (!
|
|
101655
|
+
if (!existsSync104(sharedRoot))
|
|
101049
101656
|
return [];
|
|
101050
101657
|
const out = [];
|
|
101051
101658
|
let entries;
|
|
@@ -101083,7 +101690,7 @@ function listSharedSkills(sharedRoot = defaultSharedRoot2()) {
|
|
|
101083
101690
|
return out;
|
|
101084
101691
|
}
|
|
101085
101692
|
function listBundledSkills(bundledRoot = defaultBundledRoot2()) {
|
|
101086
|
-
if (!
|
|
101693
|
+
if (!existsSync104(bundledRoot))
|
|
101087
101694
|
return [];
|
|
101088
101695
|
const out = [];
|
|
101089
101696
|
let entries;
|
|
@@ -101241,24 +101848,24 @@ init_source();
|
|
|
101241
101848
|
init_helpers();
|
|
101242
101849
|
init_operator_uid();
|
|
101243
101850
|
import {
|
|
101244
|
-
existsSync as
|
|
101245
|
-
mkdirSync as
|
|
101851
|
+
existsSync as existsSync106,
|
|
101852
|
+
mkdirSync as mkdirSync61,
|
|
101246
101853
|
readdirSync as readdirSync40,
|
|
101247
101854
|
writeFileSync as writeFileSync44,
|
|
101248
101855
|
statSync as statSync57,
|
|
101249
101856
|
lstatSync as lstatSync14,
|
|
101250
101857
|
realpathSync as realpathSync8,
|
|
101251
|
-
copyFileSync as
|
|
101858
|
+
copyFileSync as copyFileSync14
|
|
101252
101859
|
} from "node:fs";
|
|
101253
101860
|
import { homedir as homedir57 } from "node:os";
|
|
101254
101861
|
import { join as join107 } from "node:path";
|
|
101255
|
-
import { spawnSync as
|
|
101862
|
+
import { spawnSync as spawnSync24 } from "node:child_process";
|
|
101256
101863
|
|
|
101257
101864
|
// src/cli/singleton-stale-cleanup.ts
|
|
101258
|
-
import { spawnSync as
|
|
101865
|
+
import { spawnSync as spawnSync23 } from "node:child_process";
|
|
101259
101866
|
function makeDockerRunner() {
|
|
101260
101867
|
return (args) => {
|
|
101261
|
-
const r =
|
|
101868
|
+
const r = spawnSync23("docker", args, { encoding: "utf8" });
|
|
101262
101869
|
return {
|
|
101263
101870
|
ok: r.status === 0,
|
|
101264
101871
|
stdout: r.stdout ?? "",
|
|
@@ -101617,7 +102224,7 @@ function resolveHostdSkillsTarget(hostHome) {
|
|
|
101617
102224
|
console.warn(`switchroom hostd install: ~/.switchroom/skills is a symlink whose target ` + `does not resolve (dangling) \u2014 skipping the skills bind mount. Bundled ` + `skills will be unavailable to rollout/update until the symlink is fixed.`);
|
|
101618
102225
|
return;
|
|
101619
102226
|
}
|
|
101620
|
-
if (!
|
|
102227
|
+
if (!existsSync106(target)) {
|
|
101621
102228
|
console.warn(`switchroom hostd install: ~/.switchroom/skills resolves to "${target}", ` + `which does not exist \u2014 skipping the skills bind mount. Bundled skills ` + `will be unavailable to rollout/update until the symlink target exists.`);
|
|
101622
102229
|
return;
|
|
101623
102230
|
}
|
|
@@ -101631,15 +102238,15 @@ function hostdComposePath() {
|
|
|
101631
102238
|
}
|
|
101632
102239
|
function backupExistingCompose() {
|
|
101633
102240
|
const p = hostdComposePath();
|
|
101634
|
-
if (!
|
|
102241
|
+
if (!existsSync106(p))
|
|
101635
102242
|
return null;
|
|
101636
102243
|
const ts = new Date().toISOString().replace(/[:.]/g, "-");
|
|
101637
102244
|
const bak = `${p}.bak-${ts}`;
|
|
101638
|
-
|
|
102245
|
+
copyFileSync14(p, bak);
|
|
101639
102246
|
return bak;
|
|
101640
102247
|
}
|
|
101641
102248
|
function runDocker(args) {
|
|
101642
|
-
const r =
|
|
102249
|
+
const r = spawnSync24("docker", args, { encoding: "utf8" });
|
|
101643
102250
|
return {
|
|
101644
102251
|
ok: r.status === 0,
|
|
101645
102252
|
stdout: r.stdout ?? "",
|
|
@@ -101664,7 +102271,7 @@ async function doInstall(opts, program3) {
|
|
|
101664
102271
|
}
|
|
101665
102272
|
const dir = hostdDir();
|
|
101666
102273
|
const composePath = hostdComposePath();
|
|
101667
|
-
|
|
102274
|
+
mkdirSync61(dir, { recursive: true });
|
|
101668
102275
|
const imageTag = resolveHostdImageTag(opts.tag, cfg.release);
|
|
101669
102276
|
const guard = checkDowngrade({
|
|
101670
102277
|
container: "switchroom-hostd",
|
|
@@ -101729,7 +102336,7 @@ function doStatus() {
|
|
|
101729
102336
|
const composeYml = hostdComposePath();
|
|
101730
102337
|
console.log(source_default.bold("switchroom-hostd"));
|
|
101731
102338
|
console.log("");
|
|
101732
|
-
if (!
|
|
102339
|
+
if (!existsSync106(composeYml)) {
|
|
101733
102340
|
console.log(source_default.yellow(" compose: not installed"));
|
|
101734
102341
|
console.log(source_default.dim(" run `switchroom hostd install` to set up."));
|
|
101735
102342
|
return;
|
|
@@ -101750,14 +102357,14 @@ function doStatus() {
|
|
|
101750
102357
|
} else {
|
|
101751
102358
|
console.log(source_default.green(` container: ${ps.stdout.trim()}`));
|
|
101752
102359
|
}
|
|
101753
|
-
if (
|
|
102360
|
+
if (existsSync106(dir)) {
|
|
101754
102361
|
const entries = [];
|
|
101755
102362
|
try {
|
|
101756
102363
|
for (const name of readdirSync40(dir)) {
|
|
101757
102364
|
if (name === "docker-compose.yml" || name.startsWith("docker-compose.yml."))
|
|
101758
102365
|
continue;
|
|
101759
102366
|
const sockPath = join107(dir, name, "sock");
|
|
101760
|
-
if (
|
|
102367
|
+
if (existsSync106(sockPath)) {
|
|
101761
102368
|
const st = statSync57(sockPath);
|
|
101762
102369
|
if ((st.mode & 61440) === 49152) {
|
|
101763
102370
|
entries.push(`${name} \u2192 ${sockPath}`);
|
|
@@ -101776,7 +102383,7 @@ function doStatus() {
|
|
|
101776
102383
|
}
|
|
101777
102384
|
function doUninstall() {
|
|
101778
102385
|
const composeYml = hostdComposePath();
|
|
101779
|
-
if (!
|
|
102386
|
+
if (!existsSync106(composeYml)) {
|
|
101780
102387
|
console.log(source_default.yellow(" No hostd install detected (no compose file at this path)."));
|
|
101781
102388
|
return;
|
|
101782
102389
|
}
|
|
@@ -101800,7 +102407,7 @@ function registerHostdCommand(program3) {
|
|
|
101800
102407
|
hostd.command("uninstall").description("Stop the hostd container. Leaves the compose file in place for re-install.").action(() => doUninstall());
|
|
101801
102408
|
hostd.command("audit").description("Tail and filter the hostd audit log (privileged-verb call history)").option("--tail <n>", "Number of matching entries to show (default: 50)", "50").option("--agent <name>", "Filter to a specific caller agent").option("--op <verb>", "Filter to a specific hostd verb (e.g. update_apply, agent_restart)").option("--error", "Show only failed (error/denied) entries").option("--verbose", "Show the captured stderr / error tail under each failed row").option("--path <file>", "Override audit log path (for debugging)").action((opts) => {
|
|
101802
102409
|
const logPath = opts.path ?? defaultAuditLogPath2();
|
|
101803
|
-
if (!
|
|
102410
|
+
if (!existsSync106(logPath)) {
|
|
101804
102411
|
console.error(source_default.yellow(`Audit log not found at ${logPath}.`) + source_default.gray(`
|
|
101805
102412
|
The log is created when hostd handles its first privileged-verb request.`));
|
|
101806
102413
|
return;
|
|
@@ -101848,10 +102455,10 @@ The log is created when hostd handles its first privileged-verb request.`));
|
|
|
101848
102455
|
init_source();
|
|
101849
102456
|
init_helpers();
|
|
101850
102457
|
init_operator_uid();
|
|
101851
|
-
import { chownSync as chownSync10, existsSync as
|
|
102458
|
+
import { chownSync as chownSync10, existsSync as existsSync107, mkdirSync as mkdirSync62, writeFileSync as writeFileSync45, copyFileSync as copyFileSync15 } from "node:fs";
|
|
101852
102459
|
import { homedir as homedir58 } from "node:os";
|
|
101853
102460
|
import { join as join108 } from "node:path";
|
|
101854
|
-
import { spawnSync as
|
|
102461
|
+
import { spawnSync as spawnSync25 } from "node:child_process";
|
|
101855
102462
|
function resolveWebImageTag(explicitTag, release) {
|
|
101856
102463
|
if (explicitTag)
|
|
101857
102464
|
return explicitTag;
|
|
@@ -101957,15 +102564,15 @@ function webdComposePath() {
|
|
|
101957
102564
|
}
|
|
101958
102565
|
function backupExistingCompose2() {
|
|
101959
102566
|
const p = webdComposePath();
|
|
101960
|
-
if (!
|
|
102567
|
+
if (!existsSync107(p))
|
|
101961
102568
|
return null;
|
|
101962
102569
|
const ts = new Date().toISOString().replace(/[:.]/g, "-");
|
|
101963
102570
|
const bak = `${p}.bak-${ts}`;
|
|
101964
|
-
|
|
102571
|
+
copyFileSync15(p, bak);
|
|
101965
102572
|
return bak;
|
|
101966
102573
|
}
|
|
101967
102574
|
function runDocker2(args) {
|
|
101968
|
-
const r =
|
|
102575
|
+
const r = spawnSync25("docker", args, { encoding: "utf8" });
|
|
101969
102576
|
return {
|
|
101970
102577
|
ok: r.status === 0,
|
|
101971
102578
|
stdout: r.stdout ?? "",
|
|
@@ -101982,7 +102589,7 @@ async function doInstall2(opts, program3) {
|
|
|
101982
102589
|
}
|
|
101983
102590
|
const dir = webdDir();
|
|
101984
102591
|
const composePath = webdComposePath();
|
|
101985
|
-
|
|
102592
|
+
mkdirSync62(dir, { recursive: true });
|
|
101986
102593
|
const cfg = getConfig(program3);
|
|
101987
102594
|
const imageTag = resolveWebImageTag(opts.tag, cfg.release);
|
|
101988
102595
|
const port = cfg.web_service?.port ?? 8080;
|
|
@@ -102059,7 +102666,7 @@ function doStatus2() {
|
|
|
102059
102666
|
const composeYml = webdComposePath();
|
|
102060
102667
|
console.log(source_default.bold("switchroom-web"));
|
|
102061
102668
|
console.log("");
|
|
102062
|
-
if (!
|
|
102669
|
+
if (!existsSync107(composeYml)) {
|
|
102063
102670
|
console.log(source_default.yellow(" compose: not installed"));
|
|
102064
102671
|
console.log(source_default.dim(" run `switchroom webd install` to set up."));
|
|
102065
102672
|
return;
|
|
@@ -102083,7 +102690,7 @@ function doStatus2() {
|
|
|
102083
102690
|
}
|
|
102084
102691
|
function doUninstall2() {
|
|
102085
102692
|
const composeYml = webdComposePath();
|
|
102086
|
-
if (!
|
|
102693
|
+
if (!existsSync107(composeYml)) {
|
|
102087
102694
|
console.log(source_default.yellow(" No web-service install detected (no compose file at this path)."));
|
|
102088
102695
|
return;
|
|
102089
102696
|
}
|
|
@@ -102269,7 +102876,7 @@ function applyMountRepairs(items, deps) {
|
|
|
102269
102876
|
function registerHostCommand(program3) {
|
|
102270
102877
|
const host = program3.command("host").description("Host-level maintenance operations for switchroom");
|
|
102271
102878
|
host.command("repair-mounts").description("Detect and remove known auto-dir artifacts left by a container-context deploy " + "(2026-06-23 outage class). Default: dry-run. Pass --yes to apply.").option("--yes", "Actually perform the removals (default is dry-run)").action(async (opts) => {
|
|
102272
|
-
const { rmdirSync: rmdirSync2, rmSync:
|
|
102879
|
+
const { rmdirSync: rmdirSync2, rmSync: rmSync21, lstatSync: lstatSync15, readdirSync: readdirSync41 } = await import("node:fs");
|
|
102273
102880
|
const probe2 = {
|
|
102274
102881
|
lstat(path10) {
|
|
102275
102882
|
try {
|
|
@@ -102328,7 +102935,7 @@ ${safeItems.length} item(s) would be removed. Run with --yes to apply.`));
|
|
|
102328
102935
|
rmdirSync2(path10);
|
|
102329
102936
|
},
|
|
102330
102937
|
rmRf(path10) {
|
|
102331
|
-
|
|
102938
|
+
rmSync21(path10, { recursive: true, force: true });
|
|
102332
102939
|
}
|
|
102333
102940
|
};
|
|
102334
102941
|
const results = applyMountRepairs(safeItems, applyDeps);
|
|
@@ -102358,13 +102965,13 @@ init_helpers();
|
|
|
102358
102965
|
init_scan();
|
|
102359
102966
|
|
|
102360
102967
|
// src/fleet-health/gh-sync.ts
|
|
102361
|
-
import { spawnSync as
|
|
102968
|
+
import { spawnSync as spawnSync26 } from "node:child_process";
|
|
102362
102969
|
var LABEL = "fleet-health";
|
|
102363
102970
|
function defaultGhDeps(log) {
|
|
102364
102971
|
return {
|
|
102365
102972
|
log,
|
|
102366
102973
|
run: (args) => {
|
|
102367
|
-
const r =
|
|
102974
|
+
const r = spawnSync26("gh", args, { encoding: "utf-8" });
|
|
102368
102975
|
return {
|
|
102369
102976
|
ok: r.status === 0,
|
|
102370
102977
|
stdout: (r.stdout ?? "").trim(),
|
|
@@ -102569,7 +103176,7 @@ function printDeepDiveBrief(targets) {
|
|
|
102569
103176
|
|
|
102570
103177
|
// src/cli/hindsight-watch.ts
|
|
102571
103178
|
init_source();
|
|
102572
|
-
import { existsSync as
|
|
103179
|
+
import { existsSync as existsSync112, readdirSync as readdirSync45 } from "node:fs";
|
|
102573
103180
|
import { homedir as homedir62 } from "node:os";
|
|
102574
103181
|
import { join as join111, resolve as resolve63 } from "node:path";
|
|
102575
103182
|
|
|
@@ -102639,7 +103246,7 @@ function postOperatorNoticeViaGateways(candidates, text, log, connectTimeoutMs =
|
|
|
102639
103246
|
init_install_cron();
|
|
102640
103247
|
|
|
102641
103248
|
// src/hindsight-watch/probe.ts
|
|
102642
|
-
import { spawnSync as
|
|
103249
|
+
import { spawnSync as spawnSync27 } from "node:child_process";
|
|
102643
103250
|
import { readFileSync as readFileSync98, readdirSync as readdirSync44, statSync as statSync59 } from "node:fs";
|
|
102644
103251
|
import { homedir as homedir61 } from "node:os";
|
|
102645
103252
|
import { resolve as resolve62 } from "node:path";
|
|
@@ -102768,7 +103375,7 @@ function readLlmSignals(series) {
|
|
|
102768
103375
|
}
|
|
102769
103376
|
|
|
102770
103377
|
// src/hindsight-watch/recall-log.ts
|
|
102771
|
-
import { closeSync as
|
|
103378
|
+
import { closeSync as closeSync22, existsSync as existsSync111, openSync as openSync22, readdirSync as readdirSync43, readSync as readSync6, statSync as statSync58 } from "node:fs";
|
|
102772
103379
|
import { join as join110 } from "node:path";
|
|
102773
103380
|
var RECALL_WINDOW_ROWS = 200;
|
|
102774
103381
|
var RECALL_MAX_TAIL_BYTES = 1024 * 1024;
|
|
@@ -102777,7 +103384,7 @@ function recallLogPath2(agentDir) {
|
|
|
102777
103384
|
return join110(agentDir, ".claude", "plugins", "data", "hindsight-memory-inline", "state", "recall_log.jsonl");
|
|
102778
103385
|
}
|
|
102779
103386
|
function readRecallLogTail2(path10, windowRows = RECALL_WINDOW_ROWS) {
|
|
102780
|
-
if (!
|
|
103387
|
+
if (!existsSync111(path10))
|
|
102781
103388
|
return [];
|
|
102782
103389
|
let text;
|
|
102783
103390
|
let truncatedHead = false;
|
|
@@ -102788,10 +103395,10 @@ function readRecallLogTail2(path10, windowRows = RECALL_WINDOW_ROWS) {
|
|
|
102788
103395
|
truncatedHead = start > 0;
|
|
102789
103396
|
const length = size - start;
|
|
102790
103397
|
const buf = Buffer.alloc(length);
|
|
102791
|
-
fd =
|
|
103398
|
+
fd = openSync22(path10, "r");
|
|
102792
103399
|
let read = 0;
|
|
102793
103400
|
while (read < length) {
|
|
102794
|
-
const n =
|
|
103401
|
+
const n = readSync6(fd, buf, read, length - read, start + read);
|
|
102795
103402
|
if (n <= 0)
|
|
102796
103403
|
break;
|
|
102797
103404
|
read += n;
|
|
@@ -102802,7 +103409,7 @@ function readRecallLogTail2(path10, windowRows = RECALL_WINDOW_ROWS) {
|
|
|
102802
103409
|
} finally {
|
|
102803
103410
|
if (fd !== undefined) {
|
|
102804
103411
|
try {
|
|
102805
|
-
|
|
103412
|
+
closeSync22(fd);
|
|
102806
103413
|
} catch {}
|
|
102807
103414
|
}
|
|
102808
103415
|
}
|
|
@@ -102989,7 +103596,7 @@ async function probeMetrics(url = DEFAULT_METRICS_URL, fetchImpl = fetch) {
|
|
|
102989
103596
|
}
|
|
102990
103597
|
}
|
|
102991
103598
|
var defaultRunner4 = (cmd, args) => {
|
|
102992
|
-
const r =
|
|
103599
|
+
const r = spawnSync27(cmd, args, { stdio: "pipe", timeout: 1e4, encoding: "utf8" });
|
|
102993
103600
|
if (r.error)
|
|
102994
103601
|
return { status: null, stdout: "", stderr: r.error.message };
|
|
102995
103602
|
return { status: r.status, stdout: r.stdout ?? "", stderr: r.stderr ?? "" };
|
|
@@ -103809,7 +104416,7 @@ async function notifyOperator(agentsDir, text, log) {
|
|
|
103809
104416
|
try {
|
|
103810
104417
|
for (const name of readdirSync45(agentsDir).sort()) {
|
|
103811
104418
|
const sock = resolve63(agentsDir, name, "telegram", "gateway.sock");
|
|
103812
|
-
if (
|
|
104419
|
+
if (existsSync112(sock))
|
|
103813
104420
|
candidates.push({ agent: name, sock });
|
|
103814
104421
|
}
|
|
103815
104422
|
} catch (e) {
|
|
@@ -103825,13 +104432,13 @@ async function notifyOperator(agentsDir, text, log) {
|
|
|
103825
104432
|
|
|
103826
104433
|
// src/cli/openrouter-watch.ts
|
|
103827
104434
|
init_source();
|
|
103828
|
-
import { existsSync as
|
|
104435
|
+
import { existsSync as existsSync114, readdirSync as readdirSync46 } from "node:fs";
|
|
103829
104436
|
import { homedir as homedir64 } from "node:os";
|
|
103830
104437
|
import { join as join112, resolve as resolve65 } from "node:path";
|
|
103831
104438
|
|
|
103832
104439
|
// src/openrouter/install-cron.ts
|
|
103833
|
-
import { existsSync as
|
|
103834
|
-
import { dirname as
|
|
104440
|
+
import { existsSync as existsSync113, mkdirSync as mkdirSync64, readFileSync as readFileSync99, renameSync as renameSync29, writeFileSync as writeFileSync47 } from "node:fs";
|
|
104441
|
+
import { dirname as dirname43 } from "node:path";
|
|
103835
104442
|
var CRON_PATH2 = "/etc/cron.d/openrouter-watch";
|
|
103836
104443
|
var CRON_SCHEDULE2 = "17 * * * *";
|
|
103837
104444
|
var CRON_LOG_PATH2 = "/var/log/openrouter-watch.log";
|
|
@@ -103848,23 +104455,23 @@ function renderCron2(opts) {
|
|
|
103848
104455
|
function installCron2(opts) {
|
|
103849
104456
|
const path10 = opts.path ?? CRON_PATH2;
|
|
103850
104457
|
const content = renderCron2(opts);
|
|
103851
|
-
if (
|
|
104458
|
+
if (existsSync113(path10)) {
|
|
103852
104459
|
try {
|
|
103853
104460
|
if (readFileSync99(path10, "utf8") === content) {
|
|
103854
104461
|
return { status: "unchanged", path: path10, content };
|
|
103855
104462
|
}
|
|
103856
104463
|
} catch {}
|
|
103857
104464
|
}
|
|
103858
|
-
|
|
104465
|
+
mkdirSync64(dirname43(path10), { recursive: true });
|
|
103859
104466
|
const tmp = `${path10}.${process.pid}.tmp`;
|
|
103860
104467
|
writeFileSync47(tmp, content, { mode: 420 });
|
|
103861
|
-
|
|
104468
|
+
renameSync29(tmp, path10);
|
|
103862
104469
|
return { status: "installed", path: path10, content };
|
|
103863
104470
|
}
|
|
103864
104471
|
// src/openrouter/state.ts
|
|
103865
|
-
import { mkdirSync as
|
|
104472
|
+
import { mkdirSync as mkdirSync65, readFileSync as readFileSync100, renameSync as renameSync30, writeFileSync as writeFileSync48 } from "node:fs";
|
|
103866
104473
|
import { homedir as homedir63 } from "node:os";
|
|
103867
|
-
import { dirname as
|
|
104474
|
+
import { dirname as dirname44, resolve as resolve64 } from "node:path";
|
|
103868
104475
|
function defaultStatePath3(home2 = process.env.SWITCHROOM_HOME ?? process.env.HOME ?? homedir63()) {
|
|
103869
104476
|
return resolve64(home2, ".switchroom", "openrouter-watch", "state.json");
|
|
103870
104477
|
}
|
|
@@ -103891,12 +104498,12 @@ function loadState2(path10) {
|
|
|
103891
104498
|
return out;
|
|
103892
104499
|
}
|
|
103893
104500
|
function saveState2(path10, state) {
|
|
103894
|
-
|
|
104501
|
+
mkdirSync65(dirname44(path10), { recursive: true, mode: 448 });
|
|
103895
104502
|
const tmp = `${path10}.${process.pid}.tmp`;
|
|
103896
104503
|
const payload = { v: 1, ...state };
|
|
103897
104504
|
writeFileSync48(tmp, JSON.stringify(payload, null, 2) + `
|
|
103898
104505
|
`, { mode: 384 });
|
|
103899
|
-
|
|
104506
|
+
renameSync30(tmp, path10);
|
|
103900
104507
|
}
|
|
103901
104508
|
|
|
103902
104509
|
// src/openrouter/watch.ts
|
|
@@ -104081,7 +104688,7 @@ async function notifyOperator2(agentsDir, text, log) {
|
|
|
104081
104688
|
try {
|
|
104082
104689
|
for (const name of readdirSync46(agentsDir).sort()) {
|
|
104083
104690
|
const sock = resolve65(agentsDir, name, "telegram", "gateway.sock");
|
|
104084
|
-
if (
|
|
104691
|
+
if (existsSync114(sock))
|
|
104085
104692
|
candidates.push({ agent: name, sock });
|
|
104086
104693
|
}
|
|
104087
104694
|
} catch (e) {
|