switchroom 0.19.37 → 0.19.39
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/auth-broker/index.js +3 -3
- package/dist/cli/switchroom.js +638 -385
- package/dist/host-control/main.js +4 -4
- package/dist/vault/approvals/kernel-server.js +3 -3
- package/dist/vault/broker/server.js +3 -3
- package/package.json +1 -1
- package/telegram-plugin/dist/gateway/gateway.js +149 -21
- package/telegram-plugin/gateway/gateway.ts +12 -4
- package/telegram-plugin/gateway/handback-preturn-signal.ts +68 -3
- package/telegram-plugin/gateway/stream-render.ts +238 -17
- package/telegram-plugin/hooks/tool-label-pretool.mjs +119 -1
- package/telegram-plugin/tests/activity-ever-opened-sticky.test.ts +19 -12
- package/telegram-plugin/tests/fixtures/pretool-main-2.1.219.json +15 -0
- package/telegram-plugin/tests/fixtures/pretool-subagent-2.1.219.json +16 -0
- package/telegram-plugin/tests/handback-preturn-signal.test.ts +67 -0
- package/telegram-plugin/tests/queued-card-surface.test.ts +262 -0
- package/telegram-plugin/tests/sidechain-label-filter-pretool.test.ts +272 -0
- package/vendor/hindsight-memory/scripts/lib/client.py +7 -4
- package/vendor/hindsight-memory/scripts/lib/config.py +151 -0
- package/vendor/hindsight-memory/scripts/retain.py +19 -15
- package/vendor/hindsight-memory/scripts/tests/test_backfill.py +14 -1
- package/vendor/hindsight-memory/scripts/tests/test_observation_scopes.py +192 -3
- package/vendor/hindsight-memory/scripts/tests/test_reconcile_durability.py +18 -2
- package/vendor/hindsight-memory/scripts/tests/test_subagent_retain.py +57 -4
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.39", COMMIT_SHA = "4aff2bdd";
|
|
2124
2124
|
|
|
2125
2125
|
// src/cli/resolve-version.ts
|
|
2126
2126
|
import { existsSync, readFileSync } from "node:fs";
|
|
@@ -15830,7 +15830,7 @@ function hindsightPgEnv(overrides = new Map) {
|
|
|
15830
15830
|
}
|
|
15831
15831
|
return out;
|
|
15832
15832
|
}
|
|
15833
|
-
var HINDSIGHT_PG_MEM_LIMIT_MIB_FOR_DERIVATION, HINDSIGHT_PG_APP_ANON_MIB = 2560, HINDSIGHT_PG_PAGE_CACHE_FLOOR_MIB = 2048, HINDSIGHT_PG_SHARED_BUFFERS_BUDGET_MIB, HINDSIGHT_PG_DEFAULT_SHARED_BUFFERS_MIB =
|
|
15833
|
+
var HINDSIGHT_PG_MEM_LIMIT_MIB_FOR_DERIVATION, HINDSIGHT_PG_APP_ANON_MIB = 2560, HINDSIGHT_PG_PAGE_CACHE_FLOOR_MIB = 2048, HINDSIGHT_PG_SHARED_BUFFERS_BUDGET_MIB, HINDSIGHT_PG_DEFAULT_SHARED_BUFFERS_MIB = 6144, HINDSIGHT_PG_DEFAULT_EFFECTIVE_CACHE_SIZE_MIB = 12288, HINDSIGHT_PG_EFFECTIVE_CACHE_SIZE_ENV = "SWITCHROOM_HINDSIGHT_PG_EFFECTIVE_CACHE_SIZE", HINDSIGHT_PG_SHARED_BUFFERS_ENV = "SWITCHROOM_HINDSIGHT_PG_SHARED_BUFFERS", HINDSIGHT_PG_FSYNC_ENV = "SWITCHROOM_HINDSIGHT_PG_FSYNC", HINDSIGHT_PG_DEFAULT_FSYNC = "on", HINDSIGHT_PG_DEFAULTS, HINDSIGHT_PG_ENV_KEYS;
|
|
15834
15834
|
var init_hindsight_pg_defaults = __esm(() => {
|
|
15835
15835
|
HINDSIGHT_PG_MEM_LIMIT_MIB_FOR_DERIVATION = 16 * 1024;
|
|
15836
15836
|
HINDSIGHT_PG_SHARED_BUFFERS_BUDGET_MIB = HINDSIGHT_PG_MEM_LIMIT_MIB_FOR_DERIVATION - HINDSIGHT_PG_APP_ANON_MIB - HINDSIGHT_PG_PAGE_CACHE_FLOOR_MIB;
|
|
@@ -15908,7 +15908,7 @@ function hindsightPerfEnv(caps, overrides = new Map) {
|
|
|
15908
15908
|
function findUnmanagedHindsightEnvKeys(configEnv) {
|
|
15909
15909
|
return Object.keys(configEnv ?? {}).filter((key) => !HINDSIGHT_PERF_ENV_KEYS.has(key) && !HINDSIGHT_PG_ENV_KEYS.has(key)).sort();
|
|
15910
15910
|
}
|
|
15911
|
-
var HINDSIGHT_RERANKER_MAX_CANDIDATES_FOR_DERIVATION = 150, HINDSIGHT_DEFAULT_RECALL_MAX_CANDIDATES_PER_SOURCE, HINDSIGHT_DEFAULT_LINK_EXPANSION_PER_ENTITY_LIMIT = 50, HINDSIGHT_DEFAULT_LINK_EXPANSION_TIMEOUT_S = 2, HINDSIGHT_DEFAULT_LLM_REASONING_EFFORT = "low", HINDSIGHT_DEFAULT_LLM_MAX_CONCURRENT = 4, HINDSIGHT_DEFAULT_RETAIN_LLM_MAX_CONCURRENT = 1, HINDSIGHT_DEFAULT_CONSOLIDATION_LLM_MAX_CONCURRENT, HINDSIGHT_DEFAULT_RERANKER_LOCAL_FP16 = "true", HINDSIGHT_DEFAULT_RERANKER_LOCAL_BATCH_SIZE = 128, HINDSIGHT_DEFAULT_LLM_STRICT_SCHEMA = "true", HINDSIGHT_DEFAULT_LLM_MAX_RETRIES = 2, HINDSIGHT_DEFAULT_CONSOLIDATION_LLM_PARALLELISM = 2, HINDSIGHT_DEFAULT_MAX_OBSERVATIONS_PER_SCOPE = 1000, HINDSIGHT_DEFAULT_RERANKER_BUCKET_BATCHING = "true", HINDSIGHT_DEFAULT_RERANKER_MAX_CANDIDATES = 150, HINDSIGHT_DEFAULT_RERANKER_LOCAL_MAX_CONCURRENT = 4, HINDSIGHT_DEFAULT_RECALL_MAX_CONCURRENT = 8, HINDSIGHT_DEFAULT_REFLECT_WALL_TIMEOUT_S = 600, HINDSIGHT_DEFAULT_CONSOLIDATION_MAX_MEMORIES_PER_ROUND =
|
|
15911
|
+
var HINDSIGHT_RERANKER_MAX_CANDIDATES_FOR_DERIVATION = 150, HINDSIGHT_DEFAULT_RECALL_MAX_CANDIDATES_PER_SOURCE, HINDSIGHT_DEFAULT_LINK_EXPANSION_PER_ENTITY_LIMIT = 50, HINDSIGHT_DEFAULT_LINK_EXPANSION_TIMEOUT_S = 2, HINDSIGHT_DEFAULT_LLM_REASONING_EFFORT = "low", HINDSIGHT_DEFAULT_LLM_MAX_CONCURRENT = 4, HINDSIGHT_DEFAULT_RETAIN_LLM_MAX_CONCURRENT = 1, HINDSIGHT_DEFAULT_CONSOLIDATION_LLM_MAX_CONCURRENT, HINDSIGHT_DEFAULT_RERANKER_LOCAL_FP16 = "true", HINDSIGHT_DEFAULT_RERANKER_LOCAL_BATCH_SIZE = 128, HINDSIGHT_DEFAULT_LLM_STRICT_SCHEMA = "true", HINDSIGHT_DEFAULT_LLM_MAX_RETRIES = 2, HINDSIGHT_DEFAULT_CONSOLIDATION_LLM_PARALLELISM = 2, HINDSIGHT_DEFAULT_MAX_OBSERVATIONS_PER_SCOPE = 1000, HINDSIGHT_DEFAULT_RERANKER_BUCKET_BATCHING = "true", HINDSIGHT_DEFAULT_RERANKER_MAX_CANDIDATES = 150, HINDSIGHT_DEFAULT_RERANKER_LOCAL_MAX_CONCURRENT = 4, HINDSIGHT_DEFAULT_RECALL_MAX_CONCURRENT = 8, HINDSIGHT_DEFAULT_REFLECT_WALL_TIMEOUT_S = 600, HINDSIGHT_DEFAULT_CONSOLIDATION_MAX_MEMORIES_PER_ROUND = 250, HINDSIGHT_DEFAULT_CONSOLIDATION_SLOT_LIMIT = 6, HINDSIGHT_DEFAULT_CONSOLIDATION_MAX_SLOTS = 1, HINDSIGHT_DEFAULT_RECENCY_DECAY_FUNCTION = "exponential", HINDSIGHT_DEFAULT_RECENCY_DECAY_HALFLIFE_DAYS = 30, HINDSIGHT_PERF_DEFAULTS_UNGATED, HINDSIGHT_PERF_DEFAULTS_GPU, HINDSIGHT_PERF_DEFAULTS_LOCAL_LLM, HINDSIGHT_PERF_OVERRIDE_ONLY_KEYS, HINDSIGHT_PERF_ENV_KEYS;
|
|
15912
15912
|
var init_hindsight_perf_defaults = __esm(() => {
|
|
15913
15913
|
init_hindsight_pg_defaults();
|
|
15914
15914
|
HINDSIGHT_DEFAULT_RECALL_MAX_CANDIDATES_PER_SOURCE = Math.ceil(HINDSIGHT_RERANKER_MAX_CANDIDATES_FOR_DERIVATION * 0.4);
|
|
@@ -45987,6 +45987,38 @@ function installCron(opts) {
|
|
|
45987
45987
|
renameSync15(tmp, path6);
|
|
45988
45988
|
return { status: "installed", path: path6, content };
|
|
45989
45989
|
}
|
|
45990
|
+
function parseCronUser(content) {
|
|
45991
|
+
for (const line of content.split(`
|
|
45992
|
+
`)) {
|
|
45993
|
+
const trimmed = line.trim();
|
|
45994
|
+
if (!trimmed || trimmed.startsWith("#"))
|
|
45995
|
+
continue;
|
|
45996
|
+
if (!trimmed.includes("hindsight-watch"))
|
|
45997
|
+
continue;
|
|
45998
|
+
const fields = trimmed.split(/\s+/);
|
|
45999
|
+
if (fields.length >= 7)
|
|
46000
|
+
return fields[5];
|
|
46001
|
+
}
|
|
46002
|
+
return null;
|
|
46003
|
+
}
|
|
46004
|
+
function reconcileCron(opts) {
|
|
46005
|
+
const path6 = opts.path ?? CRON_PATH;
|
|
46006
|
+
if (!existsSync63(path6))
|
|
46007
|
+
return { status: "absent", path: path6 };
|
|
46008
|
+
let user = opts.fallbackUser;
|
|
46009
|
+
try {
|
|
46010
|
+
user = parseCronUser(readFileSync60(path6, "utf8")) ?? opts.fallbackUser;
|
|
46011
|
+
} catch {}
|
|
46012
|
+
if (!user) {
|
|
46013
|
+
throw new Error(`cannot reconcile ${path6}: no cron-user parseable from the existing fragment and no fallback user available`);
|
|
46014
|
+
}
|
|
46015
|
+
const r = installCron({ user, binary: opts.binary, path: path6 });
|
|
46016
|
+
return {
|
|
46017
|
+
status: r.status === "installed" ? "reconciled" : "unchanged",
|
|
46018
|
+
path: path6,
|
|
46019
|
+
content: r.content
|
|
46020
|
+
};
|
|
46021
|
+
}
|
|
45990
46022
|
var CRON_PATH = "/etc/cron.d/hindsight-watch", CRON_SCHEDULE = "*/15 * * * *", CRON_LOG_PATH = "/var/log/hindsight-watch.log", CRON_LOCK_PATH = "/run/lock/hindsight-watch.lock";
|
|
45991
46023
|
var init_install_cron = () => {};
|
|
45992
46024
|
|
|
@@ -45994,13 +46026,15 @@ var init_install_cron = () => {};
|
|
|
45994
46026
|
function inParts(memories) {
|
|
45995
46027
|
return Math.round(memories * PARTS_PER_MEMORY);
|
|
45996
46028
|
}
|
|
45997
|
-
var RING_MAX = 8, MAX_SAMPLE_AGE_MS, MIN_RETAIN_SAMPLES = 20, RETAIN_FAILURE_RATE = 0.1, PARTS_PER_MEMORY = 6, QUEUE_FLOOR_MEMORIES = 100, QUEUE_FLOOR, QUEUE_GROWTH_FRACTION = 0.1, QUEUE_GROWTH_MIN_ABS_MEMORIES = 20, QUEUE_GROWTH_MIN_ABS, BREACHES_TO_FIRE_LEVEL = 2, BREACHES_TO_FIRE_EDGE = 1, CLEARS_TO_RESOLVE = 2, RENOTIFY_MS, DEFAULT_METRICS_URL = "http://127.0.0.1:18888/metrics", DEFAULT_CONTAINER = "switchroom-hindsight", METRICS_MAX_BYTES, METRICS_TIMEOUT_MS = 1e4, RECALL_OWN_BANK_TIMEOUT_WARN = 0.05, RECALL_OWN_BANK_TIMEOUT_PAGE = 0.15, RECALL_ZERO_MEMORY_WARN = 0.25, RECALL_ZERO_MEMORY_PAGE = 0.4, RECALL_POOL_MEDIAN_WARN = 8, RECALL_POOL_MEDIAN_PAGE = 3, RECALL_SCORE_P50_WARN = 0.02, RECALL_SCORE_P50_PAGE = 0.01, CONSOLIDATION_AGE_WARN_S, CONSOLIDATION_AGE_PAGE_S, CONSOLIDATION_FAILURE_STREAK_WARN = 3, CONSOLIDATION_FAILURE_STREAK_PAGE = 10, CONSOLIDATION_STREAK_RECENCY_S, PENDING_CONSOLIDATION_FLOOR = 500, PENDING_CONSOLIDATION_GROWTH_FRACTION = 0.5, PENDING_CONSOLIDATION_GROWTH_WARN_ABS = 500, PENDING_CONSOLIDATION_GROWTH_PAGE_ABS = 5000, VECTOR_INDEX_SAMPLE_ROWS = 3, RECALL_MIN_SAMPLES = 30, LLM_FAILURE_RATE_WARN = 0.02, LLM_FAILURE_RATE_PAGE = 0.1, LLM_MIN_SAMPLES = 20;
|
|
46029
|
+
var RING_MAX = 8, MAX_SAMPLE_AGE_MS, MIN_RETAIN_SAMPLES = 20, RETAIN_FAILURE_RATE = 0.1, PARTS_PER_MEMORY = 6, QUEUE_FLOOR_MEMORIES = 100, QUEUE_FLOOR, QUEUE_GROWTH_FRACTION = 0.1, QUEUE_GROWTH_MIN_ABS_MEMORIES = 20, QUEUE_GROWTH_MIN_ABS, BREACHES_TO_FIRE_LEVEL = 2, BREACHES_TO_FIRE_EDGE = 1, CLEARS_TO_RESOLVE = 2, RENOTIFY_MS, DEFAULT_METRICS_URL = "http://127.0.0.1:18888/metrics", DEFAULT_CONTAINER = "switchroom-hindsight", METRICS_MAX_BYTES, METRICS_TIMEOUT_MS = 1e4, RECALL_OWN_BANK_TIMEOUT_WARN = 0.05, RECALL_OWN_BANK_TIMEOUT_PAGE = 0.15, RECALL_ZERO_MEMORY_WARN = 0.25, RECALL_ZERO_MEMORY_PAGE = 0.4, RECALL_POOL_MEDIAN_WARN = 8, RECALL_POOL_MEDIAN_PAGE = 3, RECALL_SCORE_P50_WARN = 0.02, RECALL_SCORE_P50_PAGE = 0.01, RECALL_WALL_MS, CONSOLIDATION_AGE_WARN_S, CONSOLIDATION_AGE_PAGE_S, CONSOLIDATION_FAILURE_STREAK_WARN = 3, CONSOLIDATION_FAILURE_STREAK_PAGE = 10, CONSOLIDATION_STREAK_RECENCY_S, PENDING_CONSOLIDATION_FLOOR = 500, PENDING_CONSOLIDATION_GROWTH_FRACTION = 0.5, PENDING_CONSOLIDATION_GROWTH_WARN_ABS = 500, PENDING_CONSOLIDATION_GROWTH_PAGE_ABS = 5000, VECTOR_INDEX_SAMPLE_ROWS = 3, RECALL_MIN_SAMPLES = 30, LLM_FAILURE_RATE_WARN = 0.02, LLM_FAILURE_RATE_PAGE = 0.1, LLM_MIN_SAMPLES = 20;
|
|
45998
46030
|
var init_thresholds = __esm(() => {
|
|
46031
|
+
init_hindsight_recall_tunables();
|
|
45999
46032
|
MAX_SAMPLE_AGE_MS = 3 * 60 * 60000;
|
|
46000
46033
|
QUEUE_FLOOR = inParts(QUEUE_FLOOR_MEMORIES);
|
|
46001
46034
|
QUEUE_GROWTH_MIN_ABS = inParts(QUEUE_GROWTH_MIN_ABS_MEMORIES);
|
|
46002
46035
|
RENOTIFY_MS = 6 * 60 * 60 * 1000;
|
|
46003
46036
|
METRICS_MAX_BYTES = 16 * 1024 * 1024;
|
|
46037
|
+
RECALL_WALL_MS = resolveHindsightRecallTunables(undefined).parallelDeadlineSeconds * 1000;
|
|
46004
46038
|
CONSOLIDATION_AGE_WARN_S = 2 * 60 * 60;
|
|
46005
46039
|
CONSOLIDATION_AGE_PAGE_S = 12 * 60 * 60;
|
|
46006
46040
|
CONSOLIDATION_STREAK_RECENCY_S = 2 * 60 * 60;
|
|
@@ -51687,6 +51721,9 @@ import { spawnSync as spawnSync12 } from "node:child_process";
|
|
|
51687
51721
|
function fixFor(c, target) {
|
|
51688
51722
|
return remediationFor(classifyComponent(c), target);
|
|
51689
51723
|
}
|
|
51724
|
+
function hostCliBehindStatus(c) {
|
|
51725
|
+
return c.kind === "cli" ? "fail" : "warn";
|
|
51726
|
+
}
|
|
51690
51727
|
function runComponentVersionChecks(config, opts = {}) {
|
|
51691
51728
|
const exec = opts.exec ?? defaultExec2;
|
|
51692
51729
|
const components = collectComponents(opts.cliVersion ?? SWITCHROOM_VERSION, exec);
|
|
@@ -51710,10 +51747,11 @@ function runComponentVersionChecks(config, opts = {}) {
|
|
|
51710
51747
|
});
|
|
51711
51748
|
}
|
|
51712
51749
|
for (const c of report.behind) {
|
|
51750
|
+
const status = hostCliBehindStatus(c);
|
|
51713
51751
|
results.push({
|
|
51714
51752
|
name: `component behind: ${c.name}`,
|
|
51715
|
-
status
|
|
51716
|
-
detail: `on ${c.version}, expected ${report.target} (${src})`,
|
|
51753
|
+
status,
|
|
51754
|
+
detail: status === "fail" ? `on ${c.version}, expected ${report.target} (${src}) \u2014 the host CLI must never trail the fleet; it self-heals in-band via \`switchroom update\`` : `on ${c.version}, expected ${report.target} (${src})`,
|
|
51717
51755
|
fix: fixFor(c, report.target)
|
|
51718
51756
|
});
|
|
51719
51757
|
}
|
|
@@ -68978,9 +69016,9 @@ __export(exports_server, {
|
|
|
68978
69016
|
dispatchTool: () => dispatchTool,
|
|
68979
69017
|
TOOLS: () => TOOLS
|
|
68980
69018
|
});
|
|
68981
|
-
import { spawnSync as
|
|
69019
|
+
import { spawnSync as spawnSync23 } from "node:child_process";
|
|
68982
69020
|
function execCli(args, stdin) {
|
|
68983
|
-
const r =
|
|
69021
|
+
const r = spawnSync23(CLI_BIN, args, {
|
|
68984
69022
|
encoding: "utf-8",
|
|
68985
69023
|
env: process.env,
|
|
68986
69024
|
timeout: 15000,
|
|
@@ -69489,7 +69527,7 @@ __export(exports_server2, {
|
|
|
69489
69527
|
TOOLS: () => TOOLS2
|
|
69490
69528
|
});
|
|
69491
69529
|
import { randomBytes as randomBytes16 } from "node:crypto";
|
|
69492
|
-
import { existsSync as
|
|
69530
|
+
import { existsSync as existsSync106 } from "node:fs";
|
|
69493
69531
|
function selfSocketPath() {
|
|
69494
69532
|
return `/run/switchroom/hostd/${SELF_AGENT}/sock`;
|
|
69495
69533
|
}
|
|
@@ -69516,7 +69554,7 @@ async function dispatchTool2(name, args) {
|
|
|
69516
69554
|
return errorText2("hostd MCP: SWITCHROOM_AGENT_NAME env var is not set \u2014 cannot " + "determine which per-agent socket to talk to.");
|
|
69517
69555
|
}
|
|
69518
69556
|
const sockPath = selfSocketPath();
|
|
69519
|
-
if (!
|
|
69557
|
+
if (!existsSync106(sockPath)) {
|
|
69520
69558
|
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.`);
|
|
69521
69559
|
}
|
|
69522
69560
|
let req;
|
|
@@ -69767,13 +69805,13 @@ function resolveAuditLogPath() {
|
|
|
69767
69805
|
if (process.env.HOSTD_AUDIT_LOG_PATH)
|
|
69768
69806
|
return process.env.HOSTD_AUDIT_LOG_PATH;
|
|
69769
69807
|
const bindMounted = "/host-home/.switchroom/host-control-audit.log";
|
|
69770
|
-
if (
|
|
69808
|
+
if (existsSync106(bindMounted))
|
|
69771
69809
|
return bindMounted;
|
|
69772
69810
|
return defaultAuditLogPath2();
|
|
69773
69811
|
}
|
|
69774
69812
|
function getLastUpdateApplyStatus() {
|
|
69775
69813
|
const path10 = resolveAuditLogPath();
|
|
69776
|
-
if (!
|
|
69814
|
+
if (!existsSync106(path10)) {
|
|
69777
69815
|
return errorText2(`get_status: audit log not found at ${path10}. No update_apply has run yet?`);
|
|
69778
69816
|
}
|
|
69779
69817
|
let raw;
|
|
@@ -70492,11 +70530,11 @@ var init_test_agents = __esm(() => {
|
|
|
70492
70530
|
});
|
|
70493
70531
|
|
|
70494
70532
|
// src/litellm/header-passthrough-guard.ts
|
|
70495
|
-
import { existsSync as
|
|
70533
|
+
import { existsSync as existsSync109, readdirSync as readdirSync41 } from "node:fs";
|
|
70496
70534
|
function discoverLiveLitellmConfigPath(opts) {
|
|
70497
70535
|
const servicesDir = opts?.servicesDir ?? COOLIFY_SERVICES_DIR;
|
|
70498
70536
|
const readdir2 = opts?.readdirFn ?? ((p) => readdirSync41(p));
|
|
70499
|
-
const exists = opts?.existsFn ??
|
|
70537
|
+
const exists = opts?.existsFn ?? existsSync109;
|
|
70500
70538
|
let entries;
|
|
70501
70539
|
try {
|
|
70502
70540
|
entries = readdir2(servicesDir);
|
|
@@ -70586,7 +70624,7 @@ var init_header_passthrough_guard = __esm(() => {
|
|
|
70586
70624
|
});
|
|
70587
70625
|
|
|
70588
70626
|
// src/fleet-health/litellm-config-sensor.ts
|
|
70589
|
-
import { readFileSync as
|
|
70627
|
+
import { readFileSync as readFileSync98, existsSync as existsSync110 } from "node:fs";
|
|
70590
70628
|
function resolveLitellmConfigPath(explicit, discoverFn = () => discoverLiveLitellmConfigPath()) {
|
|
70591
70629
|
if (explicit)
|
|
70592
70630
|
return explicit;
|
|
@@ -70597,8 +70635,8 @@ function resolveLitellmConfigPath(explicit, discoverFn = () => discoverLiveLitel
|
|
|
70597
70635
|
}
|
|
70598
70636
|
function scanLitellmConfig(opts = {}) {
|
|
70599
70637
|
const path10 = resolveLitellmConfigPath(opts.path, opts.discoverFn);
|
|
70600
|
-
const exists = opts.existsFn ??
|
|
70601
|
-
const read = opts.readFn ?? ((p) =>
|
|
70638
|
+
const exists = opts.existsFn ?? existsSync110;
|
|
70639
|
+
const read = opts.readFn ?? ((p) => readFileSync98(p, "utf-8"));
|
|
70602
70640
|
const log = opts.log ?? (() => {});
|
|
70603
70641
|
const nowIso = opts.nowIso ?? new Date().toISOString();
|
|
70604
70642
|
if (path10 === null) {
|
|
@@ -70673,20 +70711,20 @@ __export(exports_scan, {
|
|
|
70673
70711
|
ledgerPathForBase: () => ledgerPathForBase
|
|
70674
70712
|
});
|
|
70675
70713
|
import {
|
|
70676
|
-
readFileSync as
|
|
70714
|
+
readFileSync as readFileSync99,
|
|
70677
70715
|
readdirSync as readdirSync42,
|
|
70678
|
-
existsSync as
|
|
70679
|
-
mkdirSync as
|
|
70680
|
-
writeFileSync as
|
|
70716
|
+
existsSync as existsSync111,
|
|
70717
|
+
mkdirSync as mkdirSync64,
|
|
70718
|
+
writeFileSync as writeFileSync47
|
|
70681
70719
|
} from "node:fs";
|
|
70682
|
-
import { resolve as resolve61, dirname as
|
|
70720
|
+
import { resolve as resolve61, dirname as dirname43 } from "node:path";
|
|
70683
70721
|
import { homedir as homedir61 } from "node:os";
|
|
70684
70722
|
function resolveSwitchroomBase(home2 = process.env.SWITCHROOM_HOME ?? process.env.HOME ?? homedir61()) {
|
|
70685
70723
|
return resolve61(home2, ".switchroom");
|
|
70686
70724
|
}
|
|
70687
70725
|
function listAgents(base) {
|
|
70688
70726
|
const dir = resolve61(base, "agents");
|
|
70689
|
-
if (!
|
|
70727
|
+
if (!existsSync111(dir))
|
|
70690
70728
|
return [];
|
|
70691
70729
|
try {
|
|
70692
70730
|
return readdirSync42(dir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).sort();
|
|
@@ -70715,16 +70753,16 @@ function runScan(opts = {}) {
|
|
|
70715
70753
|
let gwText = "";
|
|
70716
70754
|
let sawArtifact = false;
|
|
70717
70755
|
try {
|
|
70718
|
-
if (
|
|
70719
|
-
turnsText =
|
|
70756
|
+
if (existsSync111(turnsPath)) {
|
|
70757
|
+
turnsText = readFileSync99(turnsPath, "utf-8");
|
|
70720
70758
|
sawArtifact = true;
|
|
70721
70759
|
}
|
|
70722
70760
|
} catch (e) {
|
|
70723
70761
|
log(`fleet-health: WARN skipping ${agent} turns.jsonl unreadable: ${String(e)}`);
|
|
70724
70762
|
}
|
|
70725
70763
|
try {
|
|
70726
|
-
if (
|
|
70727
|
-
gwText =
|
|
70764
|
+
if (existsSync111(gwPath)) {
|
|
70765
|
+
gwText = readFileSync99(gwPath, "utf-8");
|
|
70728
70766
|
sawArtifact = true;
|
|
70729
70767
|
}
|
|
70730
70768
|
} catch (e) {
|
|
@@ -70766,20 +70804,20 @@ function runScan(opts = {}) {
|
|
|
70766
70804
|
function readLedgerIfPresent(base) {
|
|
70767
70805
|
const path10 = ledgerPathForBase(base);
|
|
70768
70806
|
try {
|
|
70769
|
-
if (!
|
|
70807
|
+
if (!existsSync111(path10))
|
|
70770
70808
|
return null;
|
|
70771
|
-
return JSON.parse(
|
|
70809
|
+
return JSON.parse(readFileSync99(path10, "utf-8"));
|
|
70772
70810
|
} catch {
|
|
70773
70811
|
return null;
|
|
70774
70812
|
}
|
|
70775
70813
|
}
|
|
70776
70814
|
function ledgerPathForBase(base) {
|
|
70777
|
-
return fleetHealthLedgerPath(
|
|
70815
|
+
return fleetHealthLedgerPath(dirname43(base));
|
|
70778
70816
|
}
|
|
70779
70817
|
function writeLedger(base, ledger) {
|
|
70780
70818
|
const path10 = ledgerPathForBase(base);
|
|
70781
|
-
|
|
70782
|
-
|
|
70819
|
+
mkdirSync64(dirname43(path10), { recursive: true });
|
|
70820
|
+
writeFileSync47(path10, JSON.stringify(ledger, null, 2) + `
|
|
70783
70821
|
`, "utf-8");
|
|
70784
70822
|
return path10;
|
|
70785
70823
|
}
|
|
@@ -92106,9 +92144,9 @@ init_source();
|
|
|
92106
92144
|
init_loader();
|
|
92107
92145
|
init_lifecycle();
|
|
92108
92146
|
init_compose_env();
|
|
92109
|
-
import { existsSync as
|
|
92110
|
-
import { spawnSync as
|
|
92111
|
-
import { join as join84, dirname as
|
|
92147
|
+
import { existsSync as existsSync81, mkdirSync as mkdirSync46, readFileSync as readFileSync75, realpathSync as realpathSync6, statSync as statSync45, chownSync as chownSync8 } from "node:fs";
|
|
92148
|
+
import { spawnSync as spawnSync17 } from "node:child_process";
|
|
92149
|
+
import { join as join84, dirname as dirname34, resolve as resolve45 } from "node:path";
|
|
92112
92150
|
import { homedir as homedir44 } from "node:os";
|
|
92113
92151
|
|
|
92114
92152
|
// src/cli/release-yaml.ts
|
|
@@ -92637,10 +92675,151 @@ function defaultSelfUpdateIO() {
|
|
|
92637
92675
|
// src/cli/update.ts
|
|
92638
92676
|
init_self_invoke();
|
|
92639
92677
|
init_component_versions();
|
|
92678
|
+
init_install_cron();
|
|
92679
|
+
|
|
92680
|
+
// src/host-cli-self-heal/install-timer.ts
|
|
92681
|
+
import { spawnSync as spawnSync16 } from "node:child_process";
|
|
92682
|
+
import { existsSync as existsSync80, mkdirSync as mkdirSync45, readFileSync as readFileSync74, renameSync as renameSync20, writeFileSync as writeFileSync31 } from "node:fs";
|
|
92683
|
+
import { dirname as dirname33 } from "node:path";
|
|
92684
|
+
var SERVICE_PATH = "/etc/systemd/system/switchroom-self-heal.service";
|
|
92685
|
+
var TIMER_PATH = "/etc/systemd/system/switchroom-self-heal.timer";
|
|
92686
|
+
var TIMER_UNIT = "switchroom-self-heal.timer";
|
|
92687
|
+
var SYSTEMD_MARKER = "/run/systemd/system";
|
|
92688
|
+
var DOC_URL = "https://github.com/switchroom/switchroom/blob/main/docs/operators/host-cli-self-heal.md";
|
|
92689
|
+
function renderService(opts) {
|
|
92690
|
+
const homeLine = opts.home ? `Environment=HOME=${opts.home}
|
|
92691
|
+
` : "";
|
|
92692
|
+
return `# switchroom host CLI self-heal \u2014 keeps /usr/local/bin/switchroom from silently
|
|
92693
|
+
` + `# trailing the fleet. Managed by \`switchroom update\`; edits are overwritten.
|
|
92694
|
+
` + `[Unit]
|
|
92695
|
+
` + `Description=Switchroom host CLI self-heal (re-run \`switchroom update\` so the host binary can't silently trail the fleet)
|
|
92696
|
+
` + `Documentation=${DOC_URL}
|
|
92697
|
+
` + `After=network-online.target docker.service
|
|
92698
|
+
` + `Wants=network-online.target
|
|
92699
|
+
` + `
|
|
92700
|
+
` + `[Service]
|
|
92701
|
+
` + `Type=oneshot
|
|
92702
|
+
` + `# Run as the operator whose ~/.switchroom holds the fleet config \u2014 NOT root.
|
|
92703
|
+
` + `User=${opts.user}
|
|
92704
|
+
` + homeLine + `# --skip-images keeps each tick cheap: self-update-cli (the host binary swap)
|
|
92705
|
+
` + `# still runs; GHCR pulls and container recreation do not.
|
|
92706
|
+
` + `ExecStart=${opts.binary} update --skip-images
|
|
92707
|
+
` + `# Self-heal must never wedge the host: bound the run and run at low priority.
|
|
92708
|
+
` + `TimeoutStartSec=600
|
|
92709
|
+
` + `Nice=10
|
|
92710
|
+
`;
|
|
92711
|
+
}
|
|
92712
|
+
function renderTimer() {
|
|
92713
|
+
return `# switchroom host CLI self-heal timer. Managed by \`switchroom update\`.
|
|
92714
|
+
` + `[Unit]
|
|
92715
|
+
` + `Description=Run the Switchroom host CLI self-heal every 30 minutes
|
|
92716
|
+
` + `Documentation=${DOC_URL}
|
|
92717
|
+
` + `
|
|
92718
|
+
` + `[Timer]
|
|
92719
|
+
` + `OnBootSec=5min
|
|
92720
|
+
` + `OnUnitActiveSec=30min
|
|
92721
|
+
` + `RandomizedDelaySec=2min
|
|
92722
|
+
` + `Persistent=true
|
|
92723
|
+
` + `
|
|
92724
|
+
` + `[Install]
|
|
92725
|
+
` + `WantedBy=timers.target
|
|
92726
|
+
`;
|
|
92727
|
+
}
|
|
92728
|
+
function writeUnitIdempotent(path7, content) {
|
|
92729
|
+
if (existsSync80(path7)) {
|
|
92730
|
+
try {
|
|
92731
|
+
if (readFileSync74(path7, "utf8") === content)
|
|
92732
|
+
return "unchanged";
|
|
92733
|
+
} catch {}
|
|
92734
|
+
}
|
|
92735
|
+
mkdirSync45(dirname33(path7), { recursive: true });
|
|
92736
|
+
const tmp = `${path7}.${process.pid}.tmp`;
|
|
92737
|
+
writeFileSync31(tmp, content, { mode: 420 });
|
|
92738
|
+
renameSync20(tmp, path7);
|
|
92739
|
+
return "written";
|
|
92740
|
+
}
|
|
92741
|
+
function homeFromPasswd(user) {
|
|
92742
|
+
try {
|
|
92743
|
+
for (const line of readFileSync74("/etc/passwd", "utf8").split(`
|
|
92744
|
+
`)) {
|
|
92745
|
+
const f = line.split(":");
|
|
92746
|
+
if (f[0] === user && f[5])
|
|
92747
|
+
return f[5];
|
|
92748
|
+
}
|
|
92749
|
+
} catch {}
|
|
92750
|
+
return;
|
|
92751
|
+
}
|
|
92752
|
+
function resolveOperatorUser(env2) {
|
|
92753
|
+
const user = env2.SUDO_USER ?? env2.USER ?? env2.LOGNAME;
|
|
92754
|
+
if (!user || user === "root")
|
|
92755
|
+
return null;
|
|
92756
|
+
return user;
|
|
92757
|
+
}
|
|
92758
|
+
function installSelfHealTimer(deps = {}) {
|
|
92759
|
+
const env2 = deps.env ?? process.env;
|
|
92760
|
+
const systemdBooted = deps.systemdBooted ?? (() => existsSync80(SYSTEMD_MARKER));
|
|
92761
|
+
const geteuid = deps.geteuid ?? (() => typeof process.geteuid === "function" ? process.geteuid() : undefined);
|
|
92762
|
+
const homeForUser = deps.homeForUser ?? homeFromPasswd;
|
|
92763
|
+
const servicePath = deps.servicePath ?? SERVICE_PATH;
|
|
92764
|
+
const timerPath = deps.timerPath ?? TIMER_PATH;
|
|
92765
|
+
const binary = env2.SWITCHROOM_BINARY ?? "/usr/local/bin/switchroom";
|
|
92766
|
+
const user = resolveOperatorUser(env2);
|
|
92767
|
+
const renderUser = user ?? "OPERATOR";
|
|
92768
|
+
const home2 = user ? homeForUser(user) : undefined;
|
|
92769
|
+
const serviceContent = renderService({ binary, user: renderUser, ...home2 ? { home: home2 } : {} });
|
|
92770
|
+
const timerContent = renderTimer();
|
|
92771
|
+
const manualCommands = [
|
|
92772
|
+
"sudo systemctl daemon-reload",
|
|
92773
|
+
`sudo systemctl enable --now ${TIMER_UNIT}`
|
|
92774
|
+
];
|
|
92775
|
+
const base = { servicePath, timerPath, serviceContent, timerContent, manualCommands };
|
|
92776
|
+
if (!binary.startsWith("/")) {
|
|
92777
|
+
return {
|
|
92778
|
+
status: "skipped",
|
|
92779
|
+
reason: `SWITCHROOM_BINARY must be an absolute path (got ${binary})`,
|
|
92780
|
+
...base
|
|
92781
|
+
};
|
|
92782
|
+
}
|
|
92783
|
+
if (!systemdBooted()) {
|
|
92784
|
+
return {
|
|
92785
|
+
status: "skipped",
|
|
92786
|
+
reason: "host is not systemd-booted (/run/systemd/system absent)",
|
|
92787
|
+
...base
|
|
92788
|
+
};
|
|
92789
|
+
}
|
|
92790
|
+
if (geteuid() !== 0) {
|
|
92791
|
+
return { status: "skipped", reason: "not privileged (euid != 0)", ...base };
|
|
92792
|
+
}
|
|
92793
|
+
if (!user) {
|
|
92794
|
+
return {
|
|
92795
|
+
status: "skipped",
|
|
92796
|
+
reason: "no non-root operator user resolvable (SUDO_USER / USER / LOGNAME all unset or root)",
|
|
92797
|
+
...base
|
|
92798
|
+
};
|
|
92799
|
+
}
|
|
92800
|
+
const svc = writeUnitIdempotent(servicePath, serviceContent);
|
|
92801
|
+
const tim = writeUnitIdempotent(timerPath, timerContent);
|
|
92802
|
+
const changed = svc === "written" || tim === "written";
|
|
92803
|
+
const runner = deps.runner ?? ((cmd, args) => {
|
|
92804
|
+
const r = spawnSync16(cmd, args, { stdio: "inherit" });
|
|
92805
|
+
return { status: r.status ?? 1 };
|
|
92806
|
+
});
|
|
92807
|
+
const reload = runner("systemctl", ["daemon-reload"]);
|
|
92808
|
+
if (reload.status !== 0) {
|
|
92809
|
+
throw new Error(`systemctl daemon-reload failed (exit ${reload.status})`);
|
|
92810
|
+
}
|
|
92811
|
+
const enable = runner("systemctl", ["enable", "--now", TIMER_UNIT]);
|
|
92812
|
+
if (enable.status !== 0) {
|
|
92813
|
+
throw new Error(`systemctl enable --now ${TIMER_UNIT} failed (exit ${enable.status})`);
|
|
92814
|
+
}
|
|
92815
|
+
return { status: changed ? "installed" : "unchanged", ...base };
|
|
92816
|
+
}
|
|
92817
|
+
|
|
92818
|
+
// src/cli/update.ts
|
|
92640
92819
|
function defaultPersistPin(configPath) {
|
|
92641
92820
|
return (pin) => {
|
|
92642
92821
|
const path7 = configPath ?? findConfigFile();
|
|
92643
|
-
const before =
|
|
92822
|
+
const before = readFileSync75(path7, "utf8");
|
|
92644
92823
|
const after = setReleasePinInConfig(before, pin);
|
|
92645
92824
|
if (after === before)
|
|
92646
92825
|
return;
|
|
@@ -92656,16 +92835,16 @@ function defaultPersistPin(configPath) {
|
|
|
92656
92835
|
}
|
|
92657
92836
|
var DEFAULT_COMPOSE_PATH2 = join84(homedir44(), ".switchroom", "compose", "docker-compose.yml");
|
|
92658
92837
|
function runningFromSwitchroomCheckout(scriptPath) {
|
|
92659
|
-
let dir =
|
|
92838
|
+
let dir = dirname34(scriptPath);
|
|
92660
92839
|
for (let i = 0;i < 12; i++) {
|
|
92661
|
-
if (
|
|
92840
|
+
if (existsSync81(join84(dir, ".git"))) {
|
|
92662
92841
|
try {
|
|
92663
|
-
const pkg = JSON.parse(
|
|
92842
|
+
const pkg = JSON.parse(readFileSync75(join84(dir, "package.json"), "utf-8"));
|
|
92664
92843
|
if (pkg.name === "switchroom")
|
|
92665
92844
|
return true;
|
|
92666
92845
|
} catch {}
|
|
92667
92846
|
}
|
|
92668
|
-
const parent =
|
|
92847
|
+
const parent = dirname34(dir);
|
|
92669
92848
|
if (parent === dir)
|
|
92670
92849
|
break;
|
|
92671
92850
|
dir = parent;
|
|
@@ -92726,7 +92905,7 @@ function planUpdate(opts) {
|
|
|
92726
92905
|
bundleDir: import.meta.dirname,
|
|
92727
92906
|
execPath: process.execPath,
|
|
92728
92907
|
scriptPath,
|
|
92729
|
-
inContainer: process.env.SWITCHROOM_HOSTD_CONTEXT === "1" ||
|
|
92908
|
+
inContainer: process.env.SWITCHROOM_HOSTD_CONTEXT === "1" || existsSync81("/.dockerenv")
|
|
92730
92909
|
});
|
|
92731
92910
|
if (detection.kind !== "static-binary") {
|
|
92732
92911
|
say(source_default.gray(` host CLI not self-updated: ${detection.reason}
|
|
@@ -92799,7 +92978,7 @@ function planUpdate(opts) {
|
|
|
92799
92978
|
steps.push({
|
|
92800
92979
|
name: "pull-images",
|
|
92801
92980
|
description: "Pull broker / kernel / agent images from GHCR",
|
|
92802
|
-
skipReason: opts.skipImages ? "--skip-images flag set" : !
|
|
92981
|
+
skipReason: opts.skipImages ? "--skip-images flag set" : !existsSync81(composePath) ? `compose file not found at ${composePath} (run \`switchroom apply --compose-only\` first)` : undefined,
|
|
92803
92982
|
run: () => {
|
|
92804
92983
|
const r = runner("docker", [
|
|
92805
92984
|
"compose",
|
|
@@ -92844,6 +93023,69 @@ function planUpdate(opts) {
|
|
|
92844
93023
|
throw new Error("switchroom apply failed");
|
|
92845
93024
|
}
|
|
92846
93025
|
});
|
|
93026
|
+
steps.push({
|
|
93027
|
+
name: "reconcile-hindsight-watch-cron",
|
|
93028
|
+
description: "Reconcile /etc/cron.d/hindsight-watch (binary path / schedule / flags) on already-armed hosts \u2014 idempotent; no-op when unarmed or already current",
|
|
93029
|
+
skipReason: hostdContext ? "deferred (hostd-context): /etc/cron.d is on the host, not in the hostd container \u2014 finish host-side with `switchroom hindsight-watch --install-cron`" : undefined,
|
|
93030
|
+
isHostdDeferred: hostdContext,
|
|
93031
|
+
run: () => {
|
|
93032
|
+
const say = opts.stdout ?? ((t) => process.stdout.write(t));
|
|
93033
|
+
const binary = process.env.SWITCHROOM_BINARY ?? "/usr/local/bin/switchroom";
|
|
93034
|
+
const fallbackUser = process.env.SUDO_USER ?? process.env.USER ?? process.env.LOGNAME;
|
|
93035
|
+
let res;
|
|
93036
|
+
try {
|
|
93037
|
+
res = reconcileCron({
|
|
93038
|
+
binary,
|
|
93039
|
+
fallbackUser,
|
|
93040
|
+
...opts.watchCronPath ? { path: opts.watchCronPath } : {}
|
|
93041
|
+
});
|
|
93042
|
+
} catch (e) {
|
|
93043
|
+
say(source_default.yellow(` hindsight-watch cron not reconciled: ${e.message}
|
|
93044
|
+
`));
|
|
93045
|
+
return;
|
|
93046
|
+
}
|
|
93047
|
+
if (res.status === "absent") {
|
|
93048
|
+
say(source_default.gray(" hindsight-watch cron not armed \u2014 skipping reconcile " + "(arm with `switchroom hindsight-watch --install-cron`; doctor FAILs while unarmed)\n"));
|
|
93049
|
+
} else if (res.status === "reconciled") {
|
|
93050
|
+
say(source_default.green(` hindsight-watch cron reconciled at ${res.path}
|
|
93051
|
+
`));
|
|
93052
|
+
} else {
|
|
93053
|
+
say(source_default.gray(` hindsight-watch cron already current at ${res.path}
|
|
93054
|
+
`));
|
|
93055
|
+
}
|
|
93056
|
+
}
|
|
93057
|
+
});
|
|
93058
|
+
steps.push({
|
|
93059
|
+
name: "install-self-heal-timer",
|
|
93060
|
+
description: "Install + enable the switchroom-self-heal systemd timer so a shipped release converges the host binary automatically \u2014 graceful no-op without systemd/privilege",
|
|
93061
|
+
skipReason: hostdContext ? "deferred (hostd-context): /etc/systemd/system is on the host, not in the hostd container \u2014 finish host-side by re-running `switchroom update` on the host" : undefined,
|
|
93062
|
+
isHostdDeferred: hostdContext,
|
|
93063
|
+
run: () => {
|
|
93064
|
+
const say = opts.stdout ?? ((t) => process.stdout.write(t));
|
|
93065
|
+
let res;
|
|
93066
|
+
try {
|
|
93067
|
+
res = installSelfHealTimer(opts.selfHealTimerDeps ?? {});
|
|
93068
|
+
} catch (e) {
|
|
93069
|
+
say(source_default.yellow(` self-heal timer not installed: ${e.message}
|
|
93070
|
+
`));
|
|
93071
|
+
return;
|
|
93072
|
+
}
|
|
93073
|
+
if (res.status === "installed") {
|
|
93074
|
+
say(source_default.green(` self-heal timer installed + enabled (${res.servicePath}, ${res.timerPath})
|
|
93075
|
+
`));
|
|
93076
|
+
} else if (res.status === "unchanged") {
|
|
93077
|
+
say(source_default.gray(` self-heal timer already current + enabled at ${res.timerPath}
|
|
93078
|
+
`));
|
|
93079
|
+
} else {
|
|
93080
|
+
say(source_default.gray(` self-heal timer not installed automatically: ${res.reason}
|
|
93081
|
+
`) + source_default.gray(` Install it by hand:
|
|
93082
|
+
`) + source_default.gray(` # ${res.servicePath}
|
|
93083
|
+
`) + res.serviceContent.replace(/^/gm, source_default.gray(" ")) + source_default.gray(` # ${res.timerPath}
|
|
93084
|
+
`) + res.timerContent.replace(/^/gm, source_default.gray(" ")) + res.manualCommands.map((c) => source_default.gray(` ${c}
|
|
93085
|
+
`)).join(""));
|
|
93086
|
+
}
|
|
93087
|
+
}
|
|
93088
|
+
});
|
|
92847
93089
|
let hostControlEnabled;
|
|
92848
93090
|
if (typeof opts.hostControlEnabled === "boolean") {
|
|
92849
93091
|
hostControlEnabled = opts.hostControlEnabled;
|
|
@@ -92920,13 +93162,13 @@ function planUpdate(opts) {
|
|
|
92920
93162
|
}
|
|
92921
93163
|
const source = resolve45(import.meta.dirname, "../../skills");
|
|
92922
93164
|
const dest = join84(homedir44(), ".switchroom", "skills", "_bundled");
|
|
92923
|
-
if (!
|
|
93165
|
+
if (!existsSync81(source)) {
|
|
92924
93166
|
process.stderr.write(`switchroom update: sync-bundled-skills \u2014 CLI bundle has no adjacent skills/ at ${source}; skipping.
|
|
92925
93167
|
`);
|
|
92926
93168
|
return;
|
|
92927
93169
|
}
|
|
92928
93170
|
try {
|
|
92929
|
-
|
|
93171
|
+
mkdirSync46(dirname34(dest), { recursive: true });
|
|
92930
93172
|
const r = syncBundledSkills({
|
|
92931
93173
|
source,
|
|
92932
93174
|
dest,
|
|
@@ -92952,10 +93194,10 @@ function planUpdate(opts) {
|
|
|
92952
93194
|
if (opts.syncBundledSkillsFn)
|
|
92953
93195
|
return;
|
|
92954
93196
|
const dest = join84(homedir44(), ".switchroom", "skills", "_bundled");
|
|
92955
|
-
if (!
|
|
93197
|
+
if (!existsSync81(dest)) {
|
|
92956
93198
|
return;
|
|
92957
93199
|
}
|
|
92958
|
-
const missing = getBuiltinDefaultSkillEntries().map((e) => e.key).filter((key) => !
|
|
93200
|
+
const missing = getBuiltinDefaultSkillEntries().map((e) => e.key).filter((key) => !existsSync81(join84(dest, key)));
|
|
92959
93201
|
if (missing.length > 0) {
|
|
92960
93202
|
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.`);
|
|
92961
93203
|
}
|
|
@@ -92990,7 +93232,7 @@ function planUpdate(opts) {
|
|
|
92990
93232
|
description: "docker compose up -d --remove-orphans (recreates services with new images / compose)",
|
|
92991
93233
|
run: () => {
|
|
92992
93234
|
try {
|
|
92993
|
-
const composeText =
|
|
93235
|
+
const composeText = readFileSync75(composePath, "utf8");
|
|
92994
93236
|
const pf = validateBindSources(composeText);
|
|
92995
93237
|
if (!pf.ok)
|
|
92996
93238
|
throw new Error(formatPreflightError(pf));
|
|
@@ -93024,7 +93266,7 @@ function planUpdate(opts) {
|
|
|
93024
93266
|
return steps;
|
|
93025
93267
|
}
|
|
93026
93268
|
function defaultRunner2(cmd, args) {
|
|
93027
|
-
const r =
|
|
93269
|
+
const r = spawnSync17(cmd, args, { stdio: "inherit" });
|
|
93028
93270
|
return { status: r.status ?? 1 };
|
|
93029
93271
|
}
|
|
93030
93272
|
function writeMarkerInPreferredLocation(agent, reason, runner) {
|
|
@@ -93067,12 +93309,12 @@ function defaultStatusProbe(composePath) {
|
|
|
93067
93309
|
try {
|
|
93068
93310
|
cliBuiltAt = new Date(statSync45(scriptPath).mtimeMs).toISOString();
|
|
93069
93311
|
} catch {}
|
|
93070
|
-
let dir =
|
|
93312
|
+
let dir = dirname34(scriptPath);
|
|
93071
93313
|
for (let i = 0;i < 8; i++) {
|
|
93072
93314
|
const pkgPath = join84(dir, "package.json");
|
|
93073
|
-
if (
|
|
93315
|
+
if (existsSync81(pkgPath)) {
|
|
93074
93316
|
try {
|
|
93075
|
-
const pkg = JSON.parse(
|
|
93317
|
+
const pkg = JSON.parse(readFileSync75(pkgPath, "utf-8"));
|
|
93076
93318
|
if (typeof pkg.version === "string")
|
|
93077
93319
|
cliVersion = pkg.version;
|
|
93078
93320
|
} catch (err) {
|
|
@@ -93080,7 +93322,7 @@ function defaultStatusProbe(composePath) {
|
|
|
93080
93322
|
}
|
|
93081
93323
|
break;
|
|
93082
93324
|
}
|
|
93083
|
-
const parent =
|
|
93325
|
+
const parent = dirname34(dir);
|
|
93084
93326
|
if (parent === dir)
|
|
93085
93327
|
break;
|
|
93086
93328
|
dir = parent;
|
|
@@ -93093,13 +93335,13 @@ function defaultStatusProbe(composePath) {
|
|
|
93093
93335
|
warnings.push("could not resolve CLI version (no package.json found above the resolved script path)");
|
|
93094
93336
|
}
|
|
93095
93337
|
const services = [];
|
|
93096
|
-
if (!
|
|
93338
|
+
if (!existsSync81(composePath)) {
|
|
93097
93339
|
warnings.push(`compose file not found at ${composePath}; service status unknown`);
|
|
93098
93340
|
return { cliVersion, cliBuiltAt, services, warnings };
|
|
93099
93341
|
}
|
|
93100
93342
|
let serviceList = [];
|
|
93101
93343
|
try {
|
|
93102
|
-
const r =
|
|
93344
|
+
const r = spawnSync17("docker", ["compose", "-p", "switchroom", "-f", composePath, "config", "--services"], { encoding: "utf-8", timeout: 1e4 });
|
|
93103
93345
|
if (r.status !== 0) {
|
|
93104
93346
|
warnings.push(`docker compose config --services failed: ${r.stderr?.trim() ?? r.error?.message ?? "unknown"}`);
|
|
93105
93347
|
return { cliVersion, cliBuiltAt, services, warnings };
|
|
@@ -93116,7 +93358,7 @@ function defaultStatusProbe(composePath) {
|
|
|
93116
93358
|
let containerCreatedAt = null;
|
|
93117
93359
|
let status = "<unknown>";
|
|
93118
93360
|
try {
|
|
93119
|
-
const r =
|
|
93361
|
+
const r = spawnSync17("docker", ["inspect", "-f", "{{.Config.Image}}|{{.Created}}|{{.State.Status}}", containerName2], { encoding: "utf-8", timeout: 5000 });
|
|
93120
93362
|
if (r.status === 0) {
|
|
93121
93363
|
const [img, created, st] = r.stdout.trim().split("|");
|
|
93122
93364
|
image = img ?? null;
|
|
@@ -93132,7 +93374,7 @@ function defaultStatusProbe(composePath) {
|
|
|
93132
93374
|
let imagePulledAt = null;
|
|
93133
93375
|
if (image) {
|
|
93134
93376
|
try {
|
|
93135
|
-
const r =
|
|
93377
|
+
const r = spawnSync17("docker", ["image", "inspect", "-f", "{{.Id}}|{{.Created}}|{{.Metadata.LastTagTime}}", image], { encoding: "utf-8", timeout: 5000 });
|
|
93136
93378
|
if (r.status === 0) {
|
|
93137
93379
|
const [id, created, lastTag] = r.stdout.trim().split("|");
|
|
93138
93380
|
imageDigestShort = id?.replace(/^sha256:/, "").slice(0, 12) ?? null;
|
|
@@ -93207,7 +93449,7 @@ function buildReexecArgs(opts) {
|
|
|
93207
93449
|
return args;
|
|
93208
93450
|
}
|
|
93209
93451
|
function defaultReexec(binaryPath, args) {
|
|
93210
|
-
const r =
|
|
93452
|
+
const r = spawnSync17(binaryPath, args, {
|
|
93211
93453
|
stdio: "inherit",
|
|
93212
93454
|
env: { ...process.env, [SELF_UPDATE_ENV_SENTINEL]: "1" }
|
|
93213
93455
|
});
|
|
@@ -93216,7 +93458,7 @@ function defaultReexec(binaryPath, args) {
|
|
|
93216
93458
|
function renderDriftPreamble(opts) {
|
|
93217
93459
|
try {
|
|
93218
93460
|
const exec = opts.componentExec ?? ((cmd, args) => {
|
|
93219
|
-
const r =
|
|
93461
|
+
const r = spawnSync17(cmd, args, { encoding: "utf-8", timeout: 1e4 });
|
|
93220
93462
|
return { status: r.status ?? 1, stdout: r.stdout ?? "" };
|
|
93221
93463
|
});
|
|
93222
93464
|
let pin;
|
|
@@ -93340,23 +93582,23 @@ function registerUpdateCommand(program3) {
|
|
|
93340
93582
|
|
|
93341
93583
|
// src/cli/rollout.ts
|
|
93342
93584
|
init_helpers();
|
|
93343
|
-
import { spawnSync as
|
|
93344
|
-
import { readFileSync as
|
|
93585
|
+
import { spawnSync as spawnSync19 } from "node:child_process";
|
|
93586
|
+
import { readFileSync as readFileSync77, chownSync as chownSync9, statSync as statSync47 } from "node:fs";
|
|
93345
93587
|
import { homedir as homedir46 } from "node:os";
|
|
93346
93588
|
|
|
93347
93589
|
// src/cli/rollout-pin-journal.ts
|
|
93348
93590
|
import {
|
|
93349
|
-
existsSync as
|
|
93350
|
-
readFileSync as
|
|
93351
|
-
writeFileSync as
|
|
93352
|
-
renameSync as
|
|
93591
|
+
existsSync as existsSync82,
|
|
93592
|
+
readFileSync as readFileSync76,
|
|
93593
|
+
writeFileSync as writeFileSync32,
|
|
93594
|
+
renameSync as renameSync21,
|
|
93353
93595
|
unlinkSync as unlinkSync15,
|
|
93354
93596
|
statSync as statSync46,
|
|
93355
|
-
mkdirSync as
|
|
93597
|
+
mkdirSync as mkdirSync47
|
|
93356
93598
|
} from "node:fs";
|
|
93357
93599
|
import { homedir as homedir45 } from "node:os";
|
|
93358
93600
|
import { createHash as createHash17 } from "node:crypto";
|
|
93359
|
-
import { join as join85, basename as basename9, resolve as resolve46, dirname as
|
|
93601
|
+
import { join as join85, basename as basename9, resolve as resolve46, dirname as dirname35 } from "node:path";
|
|
93360
93602
|
init_flock();
|
|
93361
93603
|
var PIN_JOURNAL_MAX_AGE_MS = 15 * 60 * 1000;
|
|
93362
93604
|
var STATE_DIR_NAME = ".switchroom";
|
|
@@ -93365,7 +93607,7 @@ function pinJournalDir(configPath) {
|
|
|
93365
93607
|
if (override && override.trim().length > 0)
|
|
93366
93608
|
return override.trim();
|
|
93367
93609
|
if (configPath) {
|
|
93368
|
-
const dir =
|
|
93610
|
+
const dir = dirname35(resolve46(configPath));
|
|
93369
93611
|
if (basename9(dir) === STATE_DIR_NAME)
|
|
93370
93612
|
return dir;
|
|
93371
93613
|
}
|
|
@@ -93408,9 +93650,9 @@ function readPinJournal(configPath, warn = (m) => process.stderr.write(m)) {
|
|
|
93408
93650
|
const p = pinJournalPath(configPath);
|
|
93409
93651
|
let raw;
|
|
93410
93652
|
try {
|
|
93411
|
-
raw =
|
|
93653
|
+
raw = readFileSync76(p, "utf8");
|
|
93412
93654
|
} catch (e) {
|
|
93413
|
-
if (
|
|
93655
|
+
if (existsSync82(p)) {
|
|
93414
93656
|
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.
|
|
93415
93657
|
`);
|
|
93416
93658
|
}
|
|
@@ -93461,7 +93703,7 @@ function beginPinPersist(configPath, pin, opts = {}) {
|
|
|
93461
93703
|
warn(`\u26a0\ufe0f rollout pin journal: overwriting an ABANDONED journal at ${p} ` + `(pid ${existing.pid} recorded ${existing.at}, provisional pin ` + `${existing.pin}). Its roll never committed or reverted; \`release.pin\` ` + `in ${configPath} may still name that unproven build \u2014 verify it.
|
|
93462
93704
|
`);
|
|
93463
93705
|
}
|
|
93464
|
-
const priorPin = getReleasePinFromConfig(
|
|
93706
|
+
const priorPin = getReleasePinFromConfig(readFileSync76(configPath, "utf8"));
|
|
93465
93707
|
const journal = {
|
|
93466
93708
|
v: 1,
|
|
93467
93709
|
configPath,
|
|
@@ -93470,10 +93712,10 @@ function beginPinPersist(configPath, pin, opts = {}) {
|
|
|
93470
93712
|
pid: process.pid,
|
|
93471
93713
|
at: new Date().toISOString()
|
|
93472
93714
|
};
|
|
93473
|
-
|
|
93715
|
+
mkdirSync47(dirname35(p), { recursive: true });
|
|
93474
93716
|
const tmp = `${p}.${process.pid}.tmp`;
|
|
93475
|
-
|
|
93476
|
-
|
|
93717
|
+
writeFileSync32(tmp, JSON.stringify(journal), { encoding: "utf8", mode: 384 });
|
|
93718
|
+
renameSync21(tmp, p);
|
|
93477
93719
|
return journal;
|
|
93478
93720
|
}
|
|
93479
93721
|
function commitPinPersist(configPath) {
|
|
@@ -93482,7 +93724,7 @@ function commitPinPersist(configPath) {
|
|
|
93482
93724
|
unlinkSync15(p);
|
|
93483
93725
|
return null;
|
|
93484
93726
|
} catch (e) {
|
|
93485
|
-
if (!
|
|
93727
|
+
if (!existsSync82(p))
|
|
93486
93728
|
return null;
|
|
93487
93729
|
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\`.`;
|
|
93488
93730
|
}
|
|
@@ -93504,7 +93746,7 @@ function rollbackPinPersist(configPath, opts = {}) {
|
|
|
93504
93746
|
}
|
|
93505
93747
|
}
|
|
93506
93748
|
try {
|
|
93507
|
-
const current =
|
|
93749
|
+
const current = readFileSync76(configPath, "utf8");
|
|
93508
93750
|
const next = journal.priorPin ? setReleasePinInConfig(current, journal.priorPin) : deleteReleasePinInConfig(current);
|
|
93509
93751
|
let mode = 384;
|
|
93510
93752
|
try {
|
|
@@ -93513,7 +93755,7 @@ function rollbackPinPersist(configPath, opts = {}) {
|
|
|
93513
93755
|
if (opts.writeConfig) {
|
|
93514
93756
|
opts.writeConfig(configPath, next, mode);
|
|
93515
93757
|
} else {
|
|
93516
|
-
|
|
93758
|
+
writeFileSync32(configPath, next, { encoding: "utf8", mode });
|
|
93517
93759
|
}
|
|
93518
93760
|
} catch (e) {
|
|
93519
93761
|
return {
|
|
@@ -93561,10 +93803,10 @@ init_audit_reader();
|
|
|
93561
93803
|
init_hindsight();
|
|
93562
93804
|
|
|
93563
93805
|
// src/cli/deploy-version-guard.ts
|
|
93564
|
-
import { spawnSync as
|
|
93806
|
+
import { spawnSync as spawnSync18 } from "node:child_process";
|
|
93565
93807
|
var DOCKER_INSPECT_TIMEOUT_MS = 60 * 1000;
|
|
93566
93808
|
var defaultRunner3 = (args) => {
|
|
93567
|
-
const r =
|
|
93809
|
+
const r = spawnSync18("docker", args, {
|
|
93568
93810
|
encoding: "utf8",
|
|
93569
93811
|
timeout: DOCKER_INSPECT_TIMEOUT_MS,
|
|
93570
93812
|
killSignal: "SIGKILL"
|
|
@@ -93988,7 +94230,7 @@ function isSpawnTimeout(r, killSignal) {
|
|
|
93988
94230
|
var ROLLOUT_KILL_SIGNAL = "SIGKILL";
|
|
93989
94231
|
function createRolloutDeps(params) {
|
|
93990
94232
|
const { configPath, scriptPath, hostdCtx } = params;
|
|
93991
|
-
const spawn6 = params.spawn ??
|
|
94233
|
+
const spawn6 = params.spawn ?? spawnSync19;
|
|
93992
94234
|
const warn = params.warn ?? ((line) => process.stderr.write(line));
|
|
93993
94235
|
const self = resolveSelfInvocation({
|
|
93994
94236
|
execPath: params.execPath ?? process.execPath,
|
|
@@ -94073,7 +94315,7 @@ function createRolloutDeps(params) {
|
|
|
94073
94315
|
return { status: r.ok ? 0 : 1, stdout: r.stdout };
|
|
94074
94316
|
}),
|
|
94075
94317
|
persistPin: (pin) => {
|
|
94076
|
-
const before =
|
|
94318
|
+
const before = readFileSync77(configPath, "utf8");
|
|
94077
94319
|
const after = setReleasePinInConfig(before, pin);
|
|
94078
94320
|
if (after === before)
|
|
94079
94321
|
return false;
|
|
@@ -94261,8 +94503,8 @@ init_helpers();
|
|
|
94261
94503
|
init_lifecycle();
|
|
94262
94504
|
init_resolve_version();
|
|
94263
94505
|
import { execSync as execSync3 } from "node:child_process";
|
|
94264
|
-
import { existsSync as
|
|
94265
|
-
import { dirname as
|
|
94506
|
+
import { existsSync as existsSync83, readFileSync as readFileSync78 } from "node:fs";
|
|
94507
|
+
import { dirname as dirname36, join as join86 } from "node:path";
|
|
94266
94508
|
function getClaudeCodeVersion() {
|
|
94267
94509
|
try {
|
|
94268
94510
|
const out = execSync3("claude --version 2>/dev/null", {
|
|
@@ -94313,15 +94555,15 @@ function locateSwitchroomInstallDir() {
|
|
|
94313
94555
|
let dir = import.meta.dirname;
|
|
94314
94556
|
for (let i = 0;i < 10 && dir && dir !== "/"; i++) {
|
|
94315
94557
|
const pkgPath = join86(dir, "package.json");
|
|
94316
|
-
if (
|
|
94558
|
+
if (existsSync83(pkgPath)) {
|
|
94317
94559
|
try {
|
|
94318
|
-
const pkg = JSON.parse(
|
|
94319
|
-
if (pkg.name === "switchroom" &&
|
|
94560
|
+
const pkg = JSON.parse(readFileSync78(pkgPath, "utf-8"));
|
|
94561
|
+
if (pkg.name === "switchroom" && existsSync83(join86(dir, ".git"))) {
|
|
94320
94562
|
return dir;
|
|
94321
94563
|
}
|
|
94322
94564
|
} catch {}
|
|
94323
94565
|
}
|
|
94324
|
-
dir =
|
|
94566
|
+
dir = dirname36(dir);
|
|
94325
94567
|
}
|
|
94326
94568
|
return null;
|
|
94327
94569
|
}
|
|
@@ -94495,7 +94737,7 @@ init_merge();
|
|
|
94495
94737
|
|
|
94496
94738
|
// src/agents/session-retention.ts
|
|
94497
94739
|
import {
|
|
94498
|
-
existsSync as
|
|
94740
|
+
existsSync as existsSync84,
|
|
94499
94741
|
readdirSync as readdirSync28,
|
|
94500
94742
|
statSync as statSync48,
|
|
94501
94743
|
unlinkSync as unlinkSync16
|
|
@@ -94506,7 +94748,7 @@ var DEFAULT_SESSION_RETENTION_MAX_AGE_DAYS = 30;
|
|
|
94506
94748
|
var MIN_KEEP = 2;
|
|
94507
94749
|
function collectSessionJsonl(claudeConfigDir) {
|
|
94508
94750
|
const projects = join87(claudeConfigDir, "projects");
|
|
94509
|
-
if (!
|
|
94751
|
+
if (!existsSync84(projects))
|
|
94510
94752
|
return [];
|
|
94511
94753
|
const found = [];
|
|
94512
94754
|
const walk2 = (dir) => {
|
|
@@ -94642,15 +94884,15 @@ function registerHandoffCommand(program3) {
|
|
|
94642
94884
|
// src/issues/store.ts
|
|
94643
94885
|
import {
|
|
94644
94886
|
closeSync as closeSync16,
|
|
94645
|
-
existsSync as
|
|
94646
|
-
mkdirSync as
|
|
94887
|
+
existsSync as existsSync85,
|
|
94888
|
+
mkdirSync as mkdirSync48,
|
|
94647
94889
|
openSync as openSync16,
|
|
94648
94890
|
readdirSync as readdirSync29,
|
|
94649
|
-
readFileSync as
|
|
94650
|
-
renameSync as
|
|
94891
|
+
readFileSync as readFileSync79,
|
|
94892
|
+
renameSync as renameSync22,
|
|
94651
94893
|
statSync as statSync49,
|
|
94652
94894
|
unlinkSync as unlinkSync17,
|
|
94653
|
-
writeFileSync as
|
|
94895
|
+
writeFileSync as writeFileSync33,
|
|
94654
94896
|
writeSync as writeSync9
|
|
94655
94897
|
} from "node:fs";
|
|
94656
94898
|
import { join as join88 } from "node:path";
|
|
@@ -94681,11 +94923,11 @@ var ISSUES_FILE = "issues.jsonl";
|
|
|
94681
94923
|
var ISSUES_LOCK = "issues.lock";
|
|
94682
94924
|
function readAll(stateDir) {
|
|
94683
94925
|
const path7 = join88(stateDir, ISSUES_FILE);
|
|
94684
|
-
if (!
|
|
94926
|
+
if (!existsSync85(path7))
|
|
94685
94927
|
return [];
|
|
94686
94928
|
let raw;
|
|
94687
94929
|
try {
|
|
94688
|
-
raw =
|
|
94930
|
+
raw = readFileSync79(path7, "utf-8");
|
|
94689
94931
|
} catch {
|
|
94690
94932
|
return [];
|
|
94691
94933
|
}
|
|
@@ -94758,7 +95000,7 @@ function record(stateDir, input, nowFn = Date.now) {
|
|
|
94758
95000
|
});
|
|
94759
95001
|
}
|
|
94760
95002
|
function resolve49(stateDir, fingerprint, nowFn = Date.now) {
|
|
94761
|
-
if (!
|
|
95003
|
+
if (!existsSync85(join88(stateDir, ISSUES_FILE)))
|
|
94762
95004
|
return 0;
|
|
94763
95005
|
return withLock(stateDir, () => {
|
|
94764
95006
|
const all = readAll(stateDir);
|
|
@@ -94776,7 +95018,7 @@ function resolve49(stateDir, fingerprint, nowFn = Date.now) {
|
|
|
94776
95018
|
});
|
|
94777
95019
|
}
|
|
94778
95020
|
function resolveAllBySource(stateDir, source, nowFn = Date.now) {
|
|
94779
|
-
if (!
|
|
95021
|
+
if (!existsSync85(join88(stateDir, ISSUES_FILE)))
|
|
94780
95022
|
return 0;
|
|
94781
95023
|
return withLock(stateDir, () => {
|
|
94782
95024
|
const all = readAll(stateDir);
|
|
@@ -94794,7 +95036,7 @@ function resolveAllBySource(stateDir, source, nowFn = Date.now) {
|
|
|
94794
95036
|
});
|
|
94795
95037
|
}
|
|
94796
95038
|
function prune(stateDir, opts = {}) {
|
|
94797
|
-
if (!
|
|
95039
|
+
if (!existsSync85(join88(stateDir, ISSUES_FILE)))
|
|
94798
95040
|
return 0;
|
|
94799
95041
|
return withLock(stateDir, () => {
|
|
94800
95042
|
const all = readAll(stateDir);
|
|
@@ -94824,7 +95066,7 @@ function prune(stateDir, opts = {}) {
|
|
|
94824
95066
|
});
|
|
94825
95067
|
}
|
|
94826
95068
|
function ensureDir(stateDir) {
|
|
94827
|
-
|
|
95069
|
+
mkdirSync48(stateDir, { recursive: true });
|
|
94828
95070
|
}
|
|
94829
95071
|
function writeAll(stateDir, events) {
|
|
94830
95072
|
const path7 = join88(stateDir, ISSUES_FILE);
|
|
@@ -94833,8 +95075,8 @@ function writeAll(stateDir, events) {
|
|
|
94833
95075
|
const body = events.length === 0 ? "" : events.map((e) => JSON.stringify(e)).join(`
|
|
94834
95076
|
`) + `
|
|
94835
95077
|
`;
|
|
94836
|
-
|
|
94837
|
-
|
|
95078
|
+
writeFileSync33(tmp, body, "utf-8");
|
|
95079
|
+
renameSync22(tmp, path7);
|
|
94838
95080
|
}
|
|
94839
95081
|
var ORPHAN_TMP_TTL_MS = 60000;
|
|
94840
95082
|
var TMP_PREFIX = `${ISSUES_FILE}.tmp-`;
|
|
@@ -94896,7 +95138,7 @@ function withLock(stateDir, fn) {
|
|
|
94896
95138
|
function tryStealStaleLock(lockPath) {
|
|
94897
95139
|
let pidStr;
|
|
94898
95140
|
try {
|
|
94899
|
-
pidStr =
|
|
95141
|
+
pidStr = readFileSync79(lockPath, "utf-8").trim();
|
|
94900
95142
|
} catch {
|
|
94901
95143
|
return true;
|
|
94902
95144
|
}
|
|
@@ -95144,20 +95386,20 @@ function relTime(deltaMs) {
|
|
|
95144
95386
|
|
|
95145
95387
|
// src/cli/deps.ts
|
|
95146
95388
|
init_source();
|
|
95147
|
-
import { existsSync as
|
|
95389
|
+
import { existsSync as existsSync88 } from "node:fs";
|
|
95148
95390
|
import { homedir as homedir49 } from "node:os";
|
|
95149
95391
|
import { join as join91, resolve as resolve50 } from "node:path";
|
|
95150
95392
|
|
|
95151
95393
|
// src/deps/python.ts
|
|
95152
95394
|
import { createHash as createHash18 } from "node:crypto";
|
|
95153
95395
|
import {
|
|
95154
|
-
existsSync as
|
|
95155
|
-
mkdirSync as
|
|
95156
|
-
readFileSync as
|
|
95396
|
+
existsSync as existsSync86,
|
|
95397
|
+
mkdirSync as mkdirSync49,
|
|
95398
|
+
readFileSync as readFileSync80,
|
|
95157
95399
|
rmSync as rmSync15,
|
|
95158
|
-
writeFileSync as
|
|
95400
|
+
writeFileSync as writeFileSync34
|
|
95159
95401
|
} from "node:fs";
|
|
95160
|
-
import { dirname as
|
|
95402
|
+
import { dirname as dirname37, join as join89 } from "node:path";
|
|
95161
95403
|
import { homedir as homedir47 } from "node:os";
|
|
95162
95404
|
import { execFileSync as execFileSync24 } from "node:child_process";
|
|
95163
95405
|
|
|
@@ -95173,13 +95415,13 @@ function defaultPythonCacheRoot() {
|
|
|
95173
95415
|
return join89(homedir47(), ".switchroom", "deps", "python");
|
|
95174
95416
|
}
|
|
95175
95417
|
function hashFile(path7) {
|
|
95176
|
-
return createHash18("sha256").update(
|
|
95418
|
+
return createHash18("sha256").update(readFileSync80(path7)).digest("hex");
|
|
95177
95419
|
}
|
|
95178
95420
|
function ensurePythonEnv(opts) {
|
|
95179
95421
|
const { skillName, requirementsPath, force = false } = opts;
|
|
95180
95422
|
const cacheRoot = opts.cacheRoot ?? defaultPythonCacheRoot();
|
|
95181
95423
|
const hostPython = opts.pythonBin ?? "python3";
|
|
95182
|
-
if (!
|
|
95424
|
+
if (!existsSync86(requirementsPath)) {
|
|
95183
95425
|
throw new PythonEnvError(`requirements file not found: ${requirementsPath}`);
|
|
95184
95426
|
}
|
|
95185
95427
|
const venvDir = join89(cacheRoot, skillName);
|
|
@@ -95188,8 +95430,8 @@ function ensurePythonEnv(opts) {
|
|
|
95188
95430
|
const pythonBin = join89(binDir, "python");
|
|
95189
95431
|
const pipBin = join89(binDir, "pip");
|
|
95190
95432
|
const targetHash = hashFile(requirementsPath);
|
|
95191
|
-
if (!force &&
|
|
95192
|
-
const existingHash =
|
|
95433
|
+
if (!force && existsSync86(stampPath) && existsSync86(pythonBin)) {
|
|
95434
|
+
const existingHash = readFileSync80(stampPath, "utf8").trim();
|
|
95193
95435
|
if (existingHash === targetHash) {
|
|
95194
95436
|
return {
|
|
95195
95437
|
skillName,
|
|
@@ -95201,10 +95443,10 @@ function ensurePythonEnv(opts) {
|
|
|
95201
95443
|
};
|
|
95202
95444
|
}
|
|
95203
95445
|
}
|
|
95204
|
-
if (
|
|
95446
|
+
if (existsSync86(venvDir)) {
|
|
95205
95447
|
rmSync15(venvDir, { recursive: true, force: true });
|
|
95206
95448
|
}
|
|
95207
|
-
|
|
95449
|
+
mkdirSync49(dirname37(venvDir), { recursive: true });
|
|
95208
95450
|
try {
|
|
95209
95451
|
execFileSync24(hostPython, ["-m", "venv", venvDir], { stdio: "pipe" });
|
|
95210
95452
|
} catch (err) {
|
|
@@ -95223,7 +95465,7 @@ function ensurePythonEnv(opts) {
|
|
|
95223
95465
|
const e = err;
|
|
95224
95466
|
throw new PythonEnvError(`Failed to install requirements for skill "${skillName}": ${e.message}`, e.stderr?.toString());
|
|
95225
95467
|
}
|
|
95226
|
-
|
|
95468
|
+
writeFileSync34(stampPath, targetHash + `
|
|
95227
95469
|
`);
|
|
95228
95470
|
return {
|
|
95229
95471
|
skillName,
|
|
@@ -95239,13 +95481,13 @@ function ensurePythonEnv(opts) {
|
|
|
95239
95481
|
import { createHash as createHash19 } from "node:crypto";
|
|
95240
95482
|
import {
|
|
95241
95483
|
copyFileSync as copyFileSync12,
|
|
95242
|
-
existsSync as
|
|
95243
|
-
mkdirSync as
|
|
95244
|
-
readFileSync as
|
|
95484
|
+
existsSync as existsSync87,
|
|
95485
|
+
mkdirSync as mkdirSync50,
|
|
95486
|
+
readFileSync as readFileSync81,
|
|
95245
95487
|
rmSync as rmSync16,
|
|
95246
|
-
writeFileSync as
|
|
95488
|
+
writeFileSync as writeFileSync35
|
|
95247
95489
|
} from "node:fs";
|
|
95248
|
-
import { dirname as
|
|
95490
|
+
import { dirname as dirname38, join as join90 } from "node:path";
|
|
95249
95491
|
import { homedir as homedir48 } from "node:os";
|
|
95250
95492
|
import { execFileSync as execFileSync25 } from "node:child_process";
|
|
95251
95493
|
|
|
@@ -95272,20 +95514,20 @@ function defaultNodeCacheRoot() {
|
|
|
95272
95514
|
return join90(homedir48(), ".switchroom", "deps", "node");
|
|
95273
95515
|
}
|
|
95274
95516
|
function hashDepInputs(packageJsonPath) {
|
|
95275
|
-
const sourceDir =
|
|
95517
|
+
const sourceDir = dirname38(packageJsonPath);
|
|
95276
95518
|
const hasher = createHash19("sha256");
|
|
95277
95519
|
hasher.update(`package.json
|
|
95278
95520
|
`);
|
|
95279
|
-
hasher.update(
|
|
95521
|
+
hasher.update(readFileSync81(packageJsonPath));
|
|
95280
95522
|
for (const lockName of ALL_LOCKFILES) {
|
|
95281
95523
|
const lockPath = join90(sourceDir, lockName);
|
|
95282
|
-
if (
|
|
95524
|
+
if (existsSync87(lockPath)) {
|
|
95283
95525
|
hasher.update(`
|
|
95284
95526
|
`);
|
|
95285
95527
|
hasher.update(lockName);
|
|
95286
95528
|
hasher.update(`
|
|
95287
95529
|
`);
|
|
95288
|
-
hasher.update(
|
|
95530
|
+
hasher.update(readFileSync81(lockPath));
|
|
95289
95531
|
}
|
|
95290
95532
|
}
|
|
95291
95533
|
return hasher.digest("hex");
|
|
@@ -95294,17 +95536,17 @@ function ensureNodeEnv(opts) {
|
|
|
95294
95536
|
const { skillName, packageJsonPath, force = false } = opts;
|
|
95295
95537
|
const cacheRoot = opts.cacheRoot ?? defaultNodeCacheRoot();
|
|
95296
95538
|
const installer = opts.installer ?? "bun";
|
|
95297
|
-
if (!
|
|
95539
|
+
if (!existsSync87(packageJsonPath)) {
|
|
95298
95540
|
throw new NodeEnvError(`package.json not found: ${packageJsonPath}`);
|
|
95299
95541
|
}
|
|
95300
|
-
const sourceDir =
|
|
95542
|
+
const sourceDir = dirname38(packageJsonPath);
|
|
95301
95543
|
const envDir = join90(cacheRoot, skillName);
|
|
95302
95544
|
const stampPath = join90(envDir, ".package.sha256");
|
|
95303
95545
|
const nodeModulesDir = join90(envDir, "node_modules");
|
|
95304
95546
|
const binDir = join90(nodeModulesDir, ".bin");
|
|
95305
95547
|
const targetHash = hashDepInputs(packageJsonPath);
|
|
95306
|
-
if (!force &&
|
|
95307
|
-
const existingHash =
|
|
95548
|
+
if (!force && existsSync87(stampPath) && existsSync87(nodeModulesDir)) {
|
|
95549
|
+
const existingHash = readFileSync81(stampPath, "utf8").trim();
|
|
95308
95550
|
if (existingHash === targetHash) {
|
|
95309
95551
|
return {
|
|
95310
95552
|
skillName,
|
|
@@ -95315,15 +95557,15 @@ function ensureNodeEnv(opts) {
|
|
|
95315
95557
|
};
|
|
95316
95558
|
}
|
|
95317
95559
|
}
|
|
95318
|
-
if (
|
|
95560
|
+
if (existsSync87(envDir)) {
|
|
95319
95561
|
rmSync16(envDir, { recursive: true, force: true });
|
|
95320
95562
|
}
|
|
95321
|
-
|
|
95563
|
+
mkdirSync50(envDir, { recursive: true });
|
|
95322
95564
|
copyFileSync12(packageJsonPath, join90(envDir, "package.json"));
|
|
95323
95565
|
let copiedLockfile = false;
|
|
95324
95566
|
for (const lockName of LOCKFILES_FOR[installer]) {
|
|
95325
95567
|
const lockPath = join90(sourceDir, lockName);
|
|
95326
|
-
if (
|
|
95568
|
+
if (existsSync87(lockPath)) {
|
|
95327
95569
|
copyFileSync12(lockPath, join90(envDir, lockName));
|
|
95328
95570
|
copiedLockfile = true;
|
|
95329
95571
|
}
|
|
@@ -95340,7 +95582,7 @@ function ensureNodeEnv(opts) {
|
|
|
95340
95582
|
const e = err;
|
|
95341
95583
|
throw new NodeEnvError(`Failed to install node deps for skill "${skillName}" with ${installer}: ${e.message}`, e.stderr?.toString());
|
|
95342
95584
|
}
|
|
95343
|
-
|
|
95585
|
+
writeFileSync35(stampPath, targetHash + `
|
|
95344
95586
|
`);
|
|
95345
95587
|
return {
|
|
95346
95588
|
skillName,
|
|
@@ -95359,22 +95601,22 @@ function registerDepsCommand(program3) {
|
|
|
95359
95601
|
const deps = program3.command("deps").description("Manage cached per-skill dependency environments");
|
|
95360
95602
|
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) => {
|
|
95361
95603
|
const skillsRoot = builtinSkillsRoot();
|
|
95362
|
-
if (!
|
|
95604
|
+
if (!existsSync88(skillsRoot)) {
|
|
95363
95605
|
console.error(source_default.red(`Bundled skills pool dir not found at ${skillsRoot} \u2014 run \`switchroom update\` to install it.`));
|
|
95364
95606
|
process.exit(1);
|
|
95365
95607
|
}
|
|
95366
95608
|
const skillDir = join91(skillsRoot, skill);
|
|
95367
|
-
if (!
|
|
95609
|
+
if (!existsSync88(skillDir)) {
|
|
95368
95610
|
console.error(source_default.red(`Unknown skill: ${skill} (no dir at ${skillDir})`));
|
|
95369
95611
|
process.exit(1);
|
|
95370
95612
|
}
|
|
95371
95613
|
const requirementsPath = join91(skillDir, "requirements.txt");
|
|
95372
95614
|
const packageJsonPath = join91(skillDir, "package.json");
|
|
95373
|
-
const wantPython = opts.python ?? (!opts.python && !opts.node &&
|
|
95374
|
-
const wantNode = opts.node ?? (!opts.python && !opts.node &&
|
|
95615
|
+
const wantPython = opts.python ?? (!opts.python && !opts.node && existsSync88(requirementsPath));
|
|
95616
|
+
const wantNode = opts.node ?? (!opts.python && !opts.node && existsSync88(packageJsonPath));
|
|
95375
95617
|
let did = 0;
|
|
95376
95618
|
if (wantPython) {
|
|
95377
|
-
if (!
|
|
95619
|
+
if (!existsSync88(requirementsPath)) {
|
|
95378
95620
|
console.error(source_default.red(`Skill "${skill}" has no requirements.txt at ${requirementsPath}`));
|
|
95379
95621
|
process.exit(1);
|
|
95380
95622
|
}
|
|
@@ -95398,7 +95640,7 @@ function registerDepsCommand(program3) {
|
|
|
95398
95640
|
}
|
|
95399
95641
|
}
|
|
95400
95642
|
if (wantNode) {
|
|
95401
|
-
if (!
|
|
95643
|
+
if (!existsSync88(packageJsonPath)) {
|
|
95402
95644
|
console.error(source_default.red(`Skill "${skill}" has no package.json at ${packageJsonPath}`));
|
|
95403
95645
|
process.exit(1);
|
|
95404
95646
|
}
|
|
@@ -95431,9 +95673,9 @@ function registerDepsCommand(program3) {
|
|
|
95431
95673
|
// src/cli/workspace.ts
|
|
95432
95674
|
init_helpers();
|
|
95433
95675
|
init_loader();
|
|
95434
|
-
import { existsSync as
|
|
95676
|
+
import { existsSync as existsSync89 } from "node:fs";
|
|
95435
95677
|
import { resolve as resolve51, sep as sep4 } from "node:path";
|
|
95436
|
-
import { spawnSync as
|
|
95678
|
+
import { spawnSync as spawnSync20 } from "node:child_process";
|
|
95437
95679
|
|
|
95438
95680
|
// src/agents/workspace.ts
|
|
95439
95681
|
import { readFile as readFile2, stat } from "node:fs/promises";
|
|
@@ -96146,7 +96388,7 @@ function registerWorkspaceCommand(program3) {
|
|
|
96146
96388
|
process.exit(1);
|
|
96147
96389
|
}
|
|
96148
96390
|
const editor = process.env["EDITOR"] ?? process.env["VISUAL"] ?? "vi";
|
|
96149
|
-
const child =
|
|
96391
|
+
const child = spawnSync20(editor, [target], { stdio: "inherit" });
|
|
96150
96392
|
if (child.status !== 0 && child.status !== null) {
|
|
96151
96393
|
process.exit(child.status);
|
|
96152
96394
|
}
|
|
@@ -96208,12 +96450,12 @@ function registerWorkspaceCommand(program3) {
|
|
|
96208
96450
|
if (!dir)
|
|
96209
96451
|
return;
|
|
96210
96452
|
const gitDir = resolve51(dir, ".git");
|
|
96211
|
-
if (!
|
|
96453
|
+
if (!existsSync89(gitDir)) {
|
|
96212
96454
|
process.stdout.write(`Workspace is not a git repository. Re-run \`switchroom agent create ${agentName}\` ` + `or manually \`git init\` in ${dir} to enable versioning.
|
|
96213
96455
|
`);
|
|
96214
96456
|
return;
|
|
96215
96457
|
}
|
|
96216
|
-
const statusResult =
|
|
96458
|
+
const statusResult = spawnSync20("git", ["status", "--short"], {
|
|
96217
96459
|
cwd: dir,
|
|
96218
96460
|
encoding: "utf-8"
|
|
96219
96461
|
});
|
|
@@ -96228,7 +96470,7 @@ function registerWorkspaceCommand(program3) {
|
|
|
96228
96470
|
return;
|
|
96229
96471
|
}
|
|
96230
96472
|
const message = opts.message || `checkpoint: ${new Date().toISOString()}`;
|
|
96231
|
-
const addResult =
|
|
96473
|
+
const addResult = spawnSync20("git", ["add", "-A"], {
|
|
96232
96474
|
cwd: dir,
|
|
96233
96475
|
encoding: "utf-8"
|
|
96234
96476
|
});
|
|
@@ -96237,7 +96479,7 @@ function registerWorkspaceCommand(program3) {
|
|
|
96237
96479
|
`);
|
|
96238
96480
|
process.exit(1);
|
|
96239
96481
|
}
|
|
96240
|
-
const commitResult =
|
|
96482
|
+
const commitResult = spawnSync20("git", ["commit", "-m", message], {
|
|
96241
96483
|
cwd: dir,
|
|
96242
96484
|
encoding: "utf-8"
|
|
96243
96485
|
});
|
|
@@ -96246,7 +96488,7 @@ function registerWorkspaceCommand(program3) {
|
|
|
96246
96488
|
`);
|
|
96247
96489
|
process.exit(1);
|
|
96248
96490
|
}
|
|
96249
|
-
const shaResult =
|
|
96491
|
+
const shaResult = spawnSync20("git", ["rev-parse", "--short", "HEAD"], {
|
|
96250
96492
|
cwd: dir,
|
|
96251
96493
|
encoding: "utf-8"
|
|
96252
96494
|
});
|
|
@@ -96262,12 +96504,12 @@ function registerWorkspaceCommand(program3) {
|
|
|
96262
96504
|
if (!dir)
|
|
96263
96505
|
return;
|
|
96264
96506
|
const gitDir = resolve51(dir, ".git");
|
|
96265
|
-
if (!
|
|
96507
|
+
if (!existsSync89(gitDir)) {
|
|
96266
96508
|
process.stdout.write(`Workspace is not a git repository.
|
|
96267
96509
|
`);
|
|
96268
96510
|
return;
|
|
96269
96511
|
}
|
|
96270
|
-
const child =
|
|
96512
|
+
const child = spawnSync20("git", ["status", "--short"], {
|
|
96271
96513
|
cwd: dir,
|
|
96272
96514
|
stdio: "inherit"
|
|
96273
96515
|
});
|
|
@@ -96287,7 +96529,7 @@ function resolveAgentWorkspaceDirOrExit(program3, agentName) {
|
|
|
96287
96529
|
const agentsDir = resolveAgentsDir(config);
|
|
96288
96530
|
const agentDir = resolve51(agentsDir, agentName);
|
|
96289
96531
|
const dir = resolveAgentWorkspaceDir(agentDir);
|
|
96290
|
-
if (!
|
|
96532
|
+
if (!existsSync89(dir)) {
|
|
96291
96533
|
process.stderr.write(`workspace: ${dir} does not exist yet. Run \`switchroom setup\` or \`switchroom agent scaffold ${agentName}\` to seed it.
|
|
96292
96534
|
`);
|
|
96293
96535
|
return;
|
|
@@ -96323,7 +96565,7 @@ function safeParseInt(value, fallback) {
|
|
|
96323
96565
|
init_helpers();
|
|
96324
96566
|
init_loader();
|
|
96325
96567
|
init_merge();
|
|
96326
|
-
import { copyFileSync as copyFileSync13, existsSync as
|
|
96568
|
+
import { copyFileSync as copyFileSync13, existsSync as existsSync90, readFileSync as readFileSync82, writeFileSync as writeFileSync36 } from "node:fs";
|
|
96327
96569
|
import { join as join92, resolve as resolve52 } from "node:path";
|
|
96328
96570
|
init_scaffold();
|
|
96329
96571
|
init_profiles();
|
|
@@ -96341,7 +96583,7 @@ function resolveSoulTargetOrExit(program3, agentName) {
|
|
|
96341
96583
|
const agentsDir = resolveAgentsDir(config);
|
|
96342
96584
|
const agentDir = resolve52(agentsDir, agentName);
|
|
96343
96585
|
const workspaceDir = resolveAgentWorkspaceDir(agentDir);
|
|
96344
|
-
if (!
|
|
96586
|
+
if (!existsSync90(workspaceDir)) {
|
|
96345
96587
|
console.error(`soul: ${workspaceDir} does not exist yet. Run \`switchroom setup\` ` + `or \`switchroom agent scaffold ${agentName}\` to seed it.`);
|
|
96346
96588
|
process.exit(1);
|
|
96347
96589
|
}
|
|
@@ -96367,11 +96609,11 @@ function registerSoulCommand(program3) {
|
|
|
96367
96609
|
const t = resolveSoulTargetOrExit(program3, agentName);
|
|
96368
96610
|
if (!t)
|
|
96369
96611
|
return;
|
|
96370
|
-
if (!
|
|
96612
|
+
if (!existsSync90(t.soulPath)) {
|
|
96371
96613
|
console.error(`soul: ${t.soulPath} does not exist yet \u2014 run ` + `\`switchroom soul reset ${agentName}\` to seed it.`);
|
|
96372
96614
|
process.exit(1);
|
|
96373
96615
|
}
|
|
96374
|
-
process.stdout.write(
|
|
96616
|
+
process.stdout.write(readFileSync82(t.soulPath, "utf-8"));
|
|
96375
96617
|
}));
|
|
96376
96618
|
cmd.command("reset <agent>").description("Re-seed SOUL.md from the agent's current profile " + "(backs the existing file up to SOUL.md.bak first)").option("-y, --yes", "Skip the confirmation prompt").action(withConfigError(async (agentName, opts) => {
|
|
96377
96619
|
const t = resolveSoulTargetOrExit(program3, agentName);
|
|
@@ -96382,7 +96624,7 @@ function registerSoulCommand(program3) {
|
|
|
96382
96624
|
console.error(`soul: profile "${t.profileName}" ships no SOUL.md.hbs \u2014 ` + `nothing to re-seed from.`);
|
|
96383
96625
|
process.exit(1);
|
|
96384
96626
|
}
|
|
96385
|
-
const exists =
|
|
96627
|
+
const exists = existsSync90(t.soulPath);
|
|
96386
96628
|
if (exists && !opts.yes) {
|
|
96387
96629
|
if (!isInteractive()) {
|
|
96388
96630
|
console.error(`soul: ${t.soulPath} already exists. Re-run with --yes to ` + `replace it (the current file is backed up to SOUL.md.bak).`);
|
|
@@ -96397,12 +96639,12 @@ function registerSoulCommand(program3) {
|
|
|
96397
96639
|
let backupPath;
|
|
96398
96640
|
if (exists) {
|
|
96399
96641
|
backupPath = `${t.soulPath}.bak`;
|
|
96400
|
-
if (
|
|
96642
|
+
if (existsSync90(backupPath)) {
|
|
96401
96643
|
backupPath = `${t.soulPath}.bak.${Date.now()}`;
|
|
96402
96644
|
}
|
|
96403
96645
|
copyFileSync13(t.soulPath, backupPath);
|
|
96404
96646
|
}
|
|
96405
|
-
|
|
96647
|
+
writeFileSync36(t.soulPath, content, "utf-8");
|
|
96406
96648
|
if (backupPath) {
|
|
96407
96649
|
console.log(`soul: re-seeded ${agentName}'s SOUL.md from profile ` + `"${t.profileName}".
|
|
96408
96650
|
` + ` Previous version saved to ${backupPath}`);
|
|
@@ -96416,7 +96658,7 @@ function registerSoulCommand(program3) {
|
|
|
96416
96658
|
// src/cli/debug.ts
|
|
96417
96659
|
init_helpers();
|
|
96418
96660
|
init_loader();
|
|
96419
|
-
import { existsSync as
|
|
96661
|
+
import { existsSync as existsSync91, readFileSync as readFileSync83, readdirSync as readdirSync30, statSync as statSync50 } from "node:fs";
|
|
96420
96662
|
import { resolve as resolve53, join as join93 } from "node:path";
|
|
96421
96663
|
import { createHash as createHash20 } from "node:crypto";
|
|
96422
96664
|
init_merge();
|
|
@@ -96429,10 +96671,10 @@ function estimateTokens(bytes) {
|
|
|
96429
96671
|
}
|
|
96430
96672
|
function readMcpServerNames(agentDir) {
|
|
96431
96673
|
const mcpPath = join93(agentDir, ".mcp.json");
|
|
96432
|
-
if (!
|
|
96674
|
+
if (!existsSync91(mcpPath))
|
|
96433
96675
|
return [];
|
|
96434
96676
|
try {
|
|
96435
|
-
const parsed = JSON.parse(
|
|
96677
|
+
const parsed = JSON.parse(readFileSync83(mcpPath, "utf-8"));
|
|
96436
96678
|
return Object.keys(parsed.mcpServers ?? {});
|
|
96437
96679
|
} catch {
|
|
96438
96680
|
return null;
|
|
@@ -96443,7 +96685,7 @@ function sha256(content) {
|
|
|
96443
96685
|
}
|
|
96444
96686
|
function findLatestTranscriptJsonl(claudeConfigDir) {
|
|
96445
96687
|
const projectsDir = join93(claudeConfigDir, "projects");
|
|
96446
|
-
if (!
|
|
96688
|
+
if (!existsSync91(projectsDir))
|
|
96447
96689
|
return;
|
|
96448
96690
|
try {
|
|
96449
96691
|
const entries = readdirSync30(projectsDir, { withFileTypes: true });
|
|
@@ -96453,7 +96695,7 @@ function findLatestTranscriptJsonl(claudeConfigDir) {
|
|
|
96453
96695
|
continue;
|
|
96454
96696
|
const projectPath = join93(projectsDir, entry.name);
|
|
96455
96697
|
const transcriptPath = join93(projectPath, "transcript.jsonl");
|
|
96456
|
-
if (!
|
|
96698
|
+
if (!existsSync91(transcriptPath))
|
|
96457
96699
|
continue;
|
|
96458
96700
|
const stat3 = statSync50(transcriptPath);
|
|
96459
96701
|
if (!latest || stat3.mtimeMs > latest.mtime) {
|
|
@@ -96467,7 +96709,7 @@ function findLatestTranscriptJsonl(claudeConfigDir) {
|
|
|
96467
96709
|
}
|
|
96468
96710
|
function extractLatestUserMessage(transcriptPath) {
|
|
96469
96711
|
try {
|
|
96470
|
-
const content =
|
|
96712
|
+
const content = readFileSync83(transcriptPath, "utf-8");
|
|
96471
96713
|
const lines = content.trim().split(`
|
|
96472
96714
|
`).filter(Boolean);
|
|
96473
96715
|
for (let i = lines.length - 1;i >= 0; i--) {
|
|
@@ -96516,7 +96758,7 @@ function registerDebugCommand(program3) {
|
|
|
96516
96758
|
}
|
|
96517
96759
|
const agentsDir = resolveAgentsDir(config);
|
|
96518
96760
|
const agentDir = resolve53(agentsDir, agentName);
|
|
96519
|
-
if (!
|
|
96761
|
+
if (!existsSync91(agentDir)) {
|
|
96520
96762
|
console.error(`Agent directory not found: ${agentDir}`);
|
|
96521
96763
|
process.exit(1);
|
|
96522
96764
|
}
|
|
@@ -96571,7 +96813,7 @@ function registerDebugCommand(program3) {
|
|
|
96571
96813
|
}
|
|
96572
96814
|
console.log(`=== Append System Prompt (per-session) ===
|
|
96573
96815
|
`);
|
|
96574
|
-
const handoffContent =
|
|
96816
|
+
const handoffContent = existsSync91(handoffPath) ? readFileSync83(handoffPath, "utf-8") : "";
|
|
96575
96817
|
if (handoffContent.trim().length > 0) {
|
|
96576
96818
|
console.log(`-- Handoff Briefing (${formatBytes(handoffContent.length)}) --`);
|
|
96577
96819
|
console.log(handoffContent);
|
|
@@ -96582,7 +96824,7 @@ function registerDebugCommand(program3) {
|
|
|
96582
96824
|
}
|
|
96583
96825
|
console.log(`=== CLAUDE.md (auto-loaded by Claude Code) ===
|
|
96584
96826
|
`);
|
|
96585
|
-
const claudeMdContent =
|
|
96827
|
+
const claudeMdContent = existsSync91(claudeMdPath) ? readFileSync83(claudeMdPath, "utf-8") : "";
|
|
96586
96828
|
if (claudeMdContent.trim().length > 0) {
|
|
96587
96829
|
console.log(`(${formatBytes(claudeMdContent.length)})`);
|
|
96588
96830
|
console.log(claudeMdContent);
|
|
@@ -96593,7 +96835,7 @@ function registerDebugCommand(program3) {
|
|
|
96593
96835
|
}
|
|
96594
96836
|
console.log(`=== Persona (SOUL.md) ===
|
|
96595
96837
|
`);
|
|
96596
|
-
const soulMdContent =
|
|
96838
|
+
const soulMdContent = existsSync91(soulMdPath) ? readFileSync83(soulMdPath, "utf-8") : existsSync91(workspaceSoulMdPath) ? readFileSync83(workspaceSoulMdPath, "utf-8") : "";
|
|
96597
96839
|
if (soulMdContent.trim().length > 0) {
|
|
96598
96840
|
console.log(`(${formatBytes(soulMdContent.length)})`);
|
|
96599
96841
|
console.log(soulMdContent);
|
|
@@ -96657,8 +96899,8 @@ function registerDebugCommand(program3) {
|
|
|
96657
96899
|
const fleetDir = join93(agentsDir, "..", "fleet");
|
|
96658
96900
|
const fleetInvPath = join93(fleetDir, "switchroom-invariants.md");
|
|
96659
96901
|
const fleetClaudePath = join93(fleetDir, "CLAUDE.md");
|
|
96660
|
-
const fleetInvBytes =
|
|
96661
|
-
const fleetClaudeBytes =
|
|
96902
|
+
const fleetInvBytes = existsSync91(fleetInvPath) ? readFileSync83(fleetInvPath, "utf-8").length : 0;
|
|
96903
|
+
const fleetClaudeBytes = existsSync91(fleetClaudePath) ? readFileSync83(fleetClaudePath, "utf-8").length : 0;
|
|
96662
96904
|
const fleetBytes = fleetInvBytes + fleetClaudeBytes;
|
|
96663
96905
|
const totalBytes = stableBytes + perSessionBytes + claudeMdBytes + fleetBytes + perTurnBytes + userBytes;
|
|
96664
96906
|
console.log(`Stable prefix: ${formatBytes(stableBytes).padEnd(20)} (cache-hot; includes SOUL.md ${soulMdBytes.toLocaleString()}B)`);
|
|
@@ -96691,20 +96933,20 @@ init_source();
|
|
|
96691
96933
|
|
|
96692
96934
|
// src/worktree/claim.ts
|
|
96693
96935
|
import { execFileSync as execFileSync26 } from "node:child_process";
|
|
96694
|
-
import { closeSync as closeSync17, mkdirSync as
|
|
96936
|
+
import { closeSync as closeSync17, mkdirSync as mkdirSync52, openSync as openSync17, existsSync as existsSync93, unlinkSync as unlinkSync19 } from "node:fs";
|
|
96695
96937
|
import { join as join95, resolve as resolve55 } from "node:path";
|
|
96696
96938
|
import { homedir as homedir51 } from "node:os";
|
|
96697
96939
|
import { randomBytes as randomBytes14 } from "node:crypto";
|
|
96698
96940
|
|
|
96699
96941
|
// src/worktree/registry.ts
|
|
96700
96942
|
import {
|
|
96701
|
-
mkdirSync as
|
|
96702
|
-
writeFileSync as
|
|
96703
|
-
readFileSync as
|
|
96943
|
+
mkdirSync as mkdirSync51,
|
|
96944
|
+
writeFileSync as writeFileSync37,
|
|
96945
|
+
readFileSync as readFileSync84,
|
|
96704
96946
|
readdirSync as readdirSync31,
|
|
96705
96947
|
unlinkSync as unlinkSync18,
|
|
96706
|
-
existsSync as
|
|
96707
|
-
renameSync as
|
|
96948
|
+
existsSync as existsSync92,
|
|
96949
|
+
renameSync as renameSync23
|
|
96708
96950
|
} from "node:fs";
|
|
96709
96951
|
import { join as join94, resolve as resolve54 } from "node:path";
|
|
96710
96952
|
import { homedir as homedir50 } from "node:os";
|
|
@@ -96715,20 +96957,20 @@ function recordPath(id) {
|
|
|
96715
96957
|
return join94(registryDir(), `${id}.json`);
|
|
96716
96958
|
}
|
|
96717
96959
|
function ensureDir2() {
|
|
96718
|
-
|
|
96960
|
+
mkdirSync51(registryDir(), { recursive: true });
|
|
96719
96961
|
}
|
|
96720
96962
|
function writeRecord(record2) {
|
|
96721
96963
|
ensureDir2();
|
|
96722
96964
|
const target = recordPath(record2.id);
|
|
96723
96965
|
const tmp = `${target}.tmp${process.pid}`;
|
|
96724
|
-
|
|
96966
|
+
writeFileSync37(tmp, JSON.stringify(record2, null, 2) + `
|
|
96725
96967
|
`, { mode: 384 });
|
|
96726
|
-
|
|
96968
|
+
renameSync23(tmp, target);
|
|
96727
96969
|
}
|
|
96728
96970
|
function readRecord(id) {
|
|
96729
96971
|
const path10 = recordPath(id);
|
|
96730
96972
|
try {
|
|
96731
|
-
const raw =
|
|
96973
|
+
const raw = readFileSync84(path10, "utf8");
|
|
96732
96974
|
return JSON.parse(raw);
|
|
96733
96975
|
} catch {
|
|
96734
96976
|
return null;
|
|
@@ -96761,7 +97003,7 @@ function countByRepo(repoPath) {
|
|
|
96761
97003
|
// src/worktree/claim.ts
|
|
96762
97004
|
function acquireRepoLock(repoPath) {
|
|
96763
97005
|
const lockDir = registryDir();
|
|
96764
|
-
|
|
97006
|
+
mkdirSync52(lockDir, { recursive: true });
|
|
96765
97007
|
const lockName = repoPath.replace(/[^A-Za-z0-9]/g, "_");
|
|
96766
97008
|
const lockPath = join95(lockDir, `.lock-${lockName}`);
|
|
96767
97009
|
const deadline = Date.now() + 5000;
|
|
@@ -96817,7 +97059,7 @@ function expandHome(p) {
|
|
|
96817
97059
|
}
|
|
96818
97060
|
async function claimWorktree(input, codeRepos) {
|
|
96819
97061
|
const repoPath = resolveRepoPath(input.repo, codeRepos);
|
|
96820
|
-
if (!
|
|
97062
|
+
if (!existsSync93(repoPath)) {
|
|
96821
97063
|
throw new Error(`Repository path does not exist: ${repoPath}`);
|
|
96822
97064
|
}
|
|
96823
97065
|
let concurrencyCap = DEFAULT_CONCURRENCY;
|
|
@@ -96839,7 +97081,7 @@ async function claimWorktree(input, codeRepos) {
|
|
|
96839
97081
|
const taskSuffix = input.taskName ? sanitizeTaskName(input.taskName) : "task";
|
|
96840
97082
|
branch = `task/${taskSuffix}-${id}`;
|
|
96841
97083
|
const baseDir = worktreesBaseDir();
|
|
96842
|
-
|
|
97084
|
+
mkdirSync52(baseDir, { recursive: true });
|
|
96843
97085
|
worktreePath = join95(baseDir, `${id}-${taskSuffix}`);
|
|
96844
97086
|
const ambientOwner = process.env.SWITCHROOM_AGENT_NAME;
|
|
96845
97087
|
const ownerAgent = input.ownerAgent ?? (ambientOwner != null && ambientOwner !== "" ? ambientOwner : undefined);
|
|
@@ -96873,7 +97115,7 @@ async function claimWorktree(input, codeRepos) {
|
|
|
96873
97115
|
|
|
96874
97116
|
// src/worktree/release.ts
|
|
96875
97117
|
import { execFileSync as execFileSync27 } from "node:child_process";
|
|
96876
|
-
import { existsSync as
|
|
97118
|
+
import { existsSync as existsSync94 } from "node:fs";
|
|
96877
97119
|
function releaseWorktree(input) {
|
|
96878
97120
|
const { id } = input;
|
|
96879
97121
|
const record2 = readRecord(id);
|
|
@@ -96881,7 +97123,7 @@ function releaseWorktree(input) {
|
|
|
96881
97123
|
return { released: true };
|
|
96882
97124
|
}
|
|
96883
97125
|
let gitSuccess = true;
|
|
96884
|
-
if (
|
|
97126
|
+
if (existsSync94(record2.path)) {
|
|
96885
97127
|
try {
|
|
96886
97128
|
execFileSync27("git", ["worktree", "remove", "--force", record2.path], {
|
|
96887
97129
|
cwd: record2.repo,
|
|
@@ -96920,7 +97162,7 @@ function listWorktrees() {
|
|
|
96920
97162
|
|
|
96921
97163
|
// src/worktree/reaper.ts
|
|
96922
97164
|
import { execFileSync as execFileSync28 } from "node:child_process";
|
|
96923
|
-
import { existsSync as
|
|
97165
|
+
import { existsSync as existsSync95 } from "node:fs";
|
|
96924
97166
|
var STALE_THRESHOLD_MS = 10 * 60 * 1000;
|
|
96925
97167
|
function reapSkipReasonText(action) {
|
|
96926
97168
|
switch (action) {
|
|
@@ -96981,7 +97223,7 @@ function planReaper(nowMs, deps = {}) {
|
|
|
96981
97223
|
const plan = [];
|
|
96982
97224
|
for (const record2 of listRecords()) {
|
|
96983
97225
|
const heartbeatAge = now - new Date(record2.heartbeatAt).getTime();
|
|
96984
|
-
const worktreeExists =
|
|
97226
|
+
const worktreeExists = existsSync95(record2.path);
|
|
96985
97227
|
if (!worktreeExists) {
|
|
96986
97228
|
plan.push({
|
|
96987
97229
|
record: record2,
|
|
@@ -97062,12 +97304,12 @@ function runReaper(nowMs, deps = {}) {
|
|
|
97062
97304
|
// src/worktree/gc.ts
|
|
97063
97305
|
import { execFileSync as execFileSync29 } from "node:child_process";
|
|
97064
97306
|
import {
|
|
97065
|
-
existsSync as
|
|
97066
|
-
readFileSync as
|
|
97307
|
+
existsSync as existsSync96,
|
|
97308
|
+
readFileSync as readFileSync85,
|
|
97067
97309
|
readdirSync as readdirSync32,
|
|
97068
97310
|
statSync as statSync51,
|
|
97069
|
-
renameSync as
|
|
97070
|
-
mkdirSync as
|
|
97311
|
+
renameSync as renameSync24,
|
|
97312
|
+
mkdirSync as mkdirSync53,
|
|
97071
97313
|
rmSync as rmSync17
|
|
97072
97314
|
} from "node:fs";
|
|
97073
97315
|
import { homedir as homedir52 } from "node:os";
|
|
@@ -97189,9 +97431,9 @@ function trashRoot() {
|
|
|
97189
97431
|
return resolve56(process.env.SWITCHROOM_WORKTREE_TRASH ?? join96(homedir52(), ".switchroom", "worktree-gc-trash"));
|
|
97190
97432
|
}
|
|
97191
97433
|
function planGc(roots, deps = {}) {
|
|
97192
|
-
const exists = deps.existsSync ??
|
|
97434
|
+
const exists = deps.existsSync ?? existsSync96;
|
|
97193
97435
|
const readDir = deps.readDir ?? ((p) => readdirSync32(p));
|
|
97194
|
-
const readFile4 = deps.readFile ?? ((p) =>
|
|
97436
|
+
const readFile4 = deps.readFile ?? ((p) => readFileSync85(p, "utf8"));
|
|
97195
97437
|
const stat3 = deps.stat ?? ((p) => statSync51(p));
|
|
97196
97438
|
const exec = deps.exec ?? defaultExec3;
|
|
97197
97439
|
const prSignal = deps.prSignal ?? ((repo, branch) => defaultPrSignal(repo, branch, exec));
|
|
@@ -97319,10 +97561,10 @@ function planGc(roots, deps = {}) {
|
|
|
97319
97561
|
}
|
|
97320
97562
|
function applyGc(plan, deps = {}) {
|
|
97321
97563
|
const exec = deps.exec ?? defaultExec3;
|
|
97322
|
-
const mkdirp = deps.mkdirp ?? ((p) => void
|
|
97564
|
+
const mkdirp = deps.mkdirp ?? ((p) => void mkdirSync53(p, { recursive: true }));
|
|
97323
97565
|
const move = deps.move ?? ((src, dest) => {
|
|
97324
97566
|
try {
|
|
97325
|
-
|
|
97567
|
+
renameSync24(src, dest);
|
|
97326
97568
|
} catch {
|
|
97327
97569
|
exec("mv", [src, dest]);
|
|
97328
97570
|
}
|
|
@@ -97368,7 +97610,7 @@ function selectPurgeTargets(entries, olderThanDays) {
|
|
|
97368
97610
|
return entries.filter((e) => e.ageDays >= olderThanDays).map((e) => e.path);
|
|
97369
97611
|
}
|
|
97370
97612
|
function listTrashEntries(nowMs, deps = {}) {
|
|
97371
|
-
const exists = deps.existsSync ??
|
|
97613
|
+
const exists = deps.existsSync ?? existsSync96;
|
|
97372
97614
|
const readDir = deps.readDir ?? ((p) => readdirSync32(p));
|
|
97373
97615
|
const root = trashRoot();
|
|
97374
97616
|
if (!exists(root))
|
|
@@ -97630,10 +97872,10 @@ init_drive();
|
|
|
97630
97872
|
init_scaffold_integration();
|
|
97631
97873
|
import {
|
|
97632
97874
|
chmodSync as chmodSync16,
|
|
97633
|
-
mkdirSync as
|
|
97875
|
+
mkdirSync as mkdirSync54,
|
|
97634
97876
|
readdirSync as readdirSync33,
|
|
97635
97877
|
rmSync as rmSync18,
|
|
97636
|
-
writeFileSync as
|
|
97878
|
+
writeFileSync as writeFileSync38
|
|
97637
97879
|
} from "node:fs";
|
|
97638
97880
|
import { join as join97 } from "node:path";
|
|
97639
97881
|
function encodeCredentialsFilename(email) {
|
|
@@ -97828,14 +98070,14 @@ function resolveCredentialsDir(env2) {
|
|
|
97828
98070
|
return join97(stateBase, "google-workspace-mcp", "credentials");
|
|
97829
98071
|
}
|
|
97830
98072
|
function writeSeedFile(dir, email, seed) {
|
|
97831
|
-
|
|
98073
|
+
mkdirSync54(dir, { recursive: true, mode: 448 });
|
|
97832
98074
|
chmodSync16(dir, 448);
|
|
97833
98075
|
for (const name of readdirSync33(dir)) {
|
|
97834
98076
|
rmSync18(join97(dir, name), { force: true, recursive: true });
|
|
97835
98077
|
}
|
|
97836
98078
|
const filename = encodeCredentialsFilename(email);
|
|
97837
98079
|
const filePath = join97(dir, filename);
|
|
97838
|
-
|
|
98080
|
+
writeFileSync38(filePath, JSON.stringify(seed), { mode: 384 });
|
|
97839
98081
|
chmodSync16(filePath, 384);
|
|
97840
98082
|
return filePath;
|
|
97841
98083
|
}
|
|
@@ -97993,8 +98235,8 @@ function registerDriveMcpLauncherCommand(program3) {
|
|
|
97993
98235
|
// src/cli/m365-mcp-launcher.ts
|
|
97994
98236
|
init_scaffold_integration();
|
|
97995
98237
|
import { spawn as spawn6 } from "node:child_process";
|
|
97996
|
-
import { writeFileSync as
|
|
97997
|
-
import { dirname as
|
|
98238
|
+
import { writeFileSync as writeFileSync39, mkdirSync as mkdirSync55 } from "node:fs";
|
|
98239
|
+
import { dirname as dirname39, join as join98 } from "node:path";
|
|
97998
98240
|
var SOFTERIA_TOKEN_ENV = "MS365_MCP_OAUTH_TOKEN";
|
|
97999
98241
|
var DEFAULT_REFRESH_LEAD_MS = 5 * 60 * 1000;
|
|
98000
98242
|
var MAX_REFRESH_INTERVAL_MS = 60 * 60 * 1000;
|
|
@@ -98030,8 +98272,8 @@ function computeRefreshDelayMs(expiresAt, now, leadMs = DEFAULT_REFRESH_LEAD_MS)
|
|
|
98030
98272
|
function writeRefreshHeartbeat(agentName, data, account) {
|
|
98031
98273
|
const path10 = heartbeatPath(agentName, account);
|
|
98032
98274
|
try {
|
|
98033
|
-
|
|
98034
|
-
|
|
98275
|
+
mkdirSync55(dirname39(path10), { recursive: true });
|
|
98276
|
+
writeFileSync39(path10, JSON.stringify(data, null, 2), { mode: 420 });
|
|
98035
98277
|
} catch {}
|
|
98036
98278
|
}
|
|
98037
98279
|
function heartbeatPath(agentName, account) {
|
|
@@ -98271,8 +98513,8 @@ function registerM365McpLauncherCommand(program3) {
|
|
|
98271
98513
|
// src/cli/notion-mcp-launcher.ts
|
|
98272
98514
|
init_scaffold_integration();
|
|
98273
98515
|
import { spawn as spawn7 } from "node:child_process";
|
|
98274
|
-
import { existsSync as
|
|
98275
|
-
import { dirname as
|
|
98516
|
+
import { existsSync as existsSync97, mkdirSync as mkdirSync56, writeFileSync as writeFileSync40 } from "node:fs";
|
|
98517
|
+
import { dirname as dirname40 } from "node:path";
|
|
98276
98518
|
var HEARTBEAT_WRITE_INTERVAL_MS = 30 * 1000;
|
|
98277
98519
|
var DEFAULT_HEARTBEAT_PATH = "/state/agent/notion-launcher.heartbeat.json";
|
|
98278
98520
|
var DEFAULT_VAULT_KEY = "notion/integration-token";
|
|
@@ -98282,10 +98524,10 @@ function buildNotionMcpArgs(opts) {
|
|
|
98282
98524
|
}
|
|
98283
98525
|
function defaultWriteHeartbeat(path10, contents) {
|
|
98284
98526
|
try {
|
|
98285
|
-
const dir =
|
|
98286
|
-
if (!
|
|
98287
|
-
|
|
98288
|
-
|
|
98527
|
+
const dir = dirname40(path10);
|
|
98528
|
+
if (!existsSync97(dir))
|
|
98529
|
+
mkdirSync56(dir, { recursive: true });
|
|
98530
|
+
writeFileSync40(path10, contents);
|
|
98289
98531
|
} catch {}
|
|
98290
98532
|
}
|
|
98291
98533
|
async function runNotionMcpLauncher(opts, runtime) {
|
|
@@ -98394,7 +98636,7 @@ function registerNotionMcpLauncherCommand(program3) {
|
|
|
98394
98636
|
}
|
|
98395
98637
|
|
|
98396
98638
|
// src/cli/hindsight-mcp-shim.ts
|
|
98397
|
-
import { mkdirSync as
|
|
98639
|
+
import { mkdirSync as mkdirSync57, readFileSync as readFileSync86, renameSync as renameSync25, writeFileSync as writeFileSync41 } from "node:fs";
|
|
98398
98640
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
98399
98641
|
import { join as join99 } from "node:path";
|
|
98400
98642
|
import { createInterface as createInterface6 } from "node:readline";
|
|
@@ -98846,18 +99088,18 @@ class HindsightShim {
|
|
|
98846
99088
|
}
|
|
98847
99089
|
writeCache(result) {
|
|
98848
99090
|
try {
|
|
98849
|
-
|
|
99091
|
+
mkdirSync57(this.opts.cacheDir, { recursive: true });
|
|
98850
99092
|
const tmp = join99(this.opts.cacheDir, `.${TOOLS_CACHE_FILENAME}.${process.pid}.tmp`);
|
|
98851
|
-
|
|
99093
|
+
writeFileSync41(tmp, JSON.stringify(result, null, 2) + `
|
|
98852
99094
|
`);
|
|
98853
|
-
|
|
99095
|
+
renameSync25(tmp, this.cachePath);
|
|
98854
99096
|
} catch (err) {
|
|
98855
99097
|
this.log(`[hindsight-shim] cache write failed: ${String(err)}`);
|
|
98856
99098
|
}
|
|
98857
99099
|
}
|
|
98858
99100
|
readCache() {
|
|
98859
99101
|
try {
|
|
98860
|
-
const parsed = JSON.parse(
|
|
99102
|
+
const parsed = JSON.parse(readFileSync86(this.cachePath, "utf-8"));
|
|
98861
99103
|
if (Array.isArray(parsed.tools))
|
|
98862
99104
|
return parsed;
|
|
98863
99105
|
return null;
|
|
@@ -99090,7 +99332,7 @@ function registerHindsightMcpShimCommand(program3) {
|
|
|
99090
99332
|
|
|
99091
99333
|
// src/cli/deliver-file.ts
|
|
99092
99334
|
init_client2();
|
|
99093
|
-
import { readFileSync as
|
|
99335
|
+
import { readFileSync as readFileSync87, statSync as statSync52 } from "node:fs";
|
|
99094
99336
|
import { basename as basename13 } from "node:path";
|
|
99095
99337
|
|
|
99096
99338
|
// src/delivery/onedrive.ts
|
|
@@ -99430,7 +99672,7 @@ async function defaultResolveProvider() {
|
|
|
99430
99672
|
async function runDeliverFile(localPath, deps = {}) {
|
|
99431
99673
|
const agentName = safeAgentName(deps.agentName ?? process.env.SWITCHROOM_AGENT_NAME);
|
|
99432
99674
|
const sizeOf = deps.fileSize ?? ((p) => statSync52(p).size);
|
|
99433
|
-
const read = deps.readFile ?? ((p) => new Uint8Array(
|
|
99675
|
+
const read = deps.readFile ?? ((p) => new Uint8Array(readFileSync87(p)));
|
|
99434
99676
|
const resolveProvider = deps.resolveProvider ?? defaultResolveProvider;
|
|
99435
99677
|
let size;
|
|
99436
99678
|
try {
|
|
@@ -99751,7 +99993,7 @@ function runRedactStdin() {
|
|
|
99751
99993
|
}
|
|
99752
99994
|
|
|
99753
99995
|
// src/cli/status-ask.ts
|
|
99754
|
-
import { readFileSync as
|
|
99996
|
+
import { readFileSync as readFileSync88, existsSync as existsSync98, readdirSync as readdirSync34 } from "node:fs";
|
|
99755
99997
|
import { join as join100 } from "node:path";
|
|
99756
99998
|
import { homedir as homedir53 } from "node:os";
|
|
99757
99999
|
|
|
@@ -100027,7 +100269,7 @@ function runReport(opts) {
|
|
|
100027
100269
|
for (const src of sources) {
|
|
100028
100270
|
let content;
|
|
100029
100271
|
try {
|
|
100030
|
-
content =
|
|
100272
|
+
content = readFileSync88(src.path, "utf-8");
|
|
100031
100273
|
} catch (err) {
|
|
100032
100274
|
process.stderr.write(`status-ask report: cannot read ${src.path}: ${err instanceof Error ? err.message : String(err)}
|
|
100033
100275
|
`);
|
|
@@ -100074,7 +100316,7 @@ function runReport(opts) {
|
|
|
100074
100316
|
function resolveSources(explicitPath) {
|
|
100075
100317
|
if (explicitPath != null && explicitPath.trim() !== "") {
|
|
100076
100318
|
const trimmed = explicitPath.trim();
|
|
100077
|
-
if (!
|
|
100319
|
+
if (!existsSync98(trimmed)) {
|
|
100078
100320
|
process.stderr.write(`status-ask report: ${trimmed}: file not found
|
|
100079
100321
|
`);
|
|
100080
100322
|
process.exit(1);
|
|
@@ -100090,7 +100332,7 @@ function resolveSources(explicitPath) {
|
|
|
100090
100332
|
} catch {
|
|
100091
100333
|
agentsDir = join100(homedir53(), ".switchroom", "agents");
|
|
100092
100334
|
}
|
|
100093
|
-
if (!
|
|
100335
|
+
if (!existsSync98(agentsDir))
|
|
100094
100336
|
return [];
|
|
100095
100337
|
const sources = [];
|
|
100096
100338
|
let entries;
|
|
@@ -100101,7 +100343,7 @@ function resolveSources(explicitPath) {
|
|
|
100101
100343
|
}
|
|
100102
100344
|
for (const name of entries) {
|
|
100103
100345
|
const path10 = join100(agentsDir, name, "runtime-metrics.jsonl");
|
|
100104
|
-
if (
|
|
100346
|
+
if (existsSync98(path10)) {
|
|
100105
100347
|
sources.push({ path: path10, agent: name });
|
|
100106
100348
|
}
|
|
100107
100349
|
}
|
|
@@ -100131,13 +100373,13 @@ var import_yaml21 = __toESM(require_dist(), 1);
|
|
|
100131
100373
|
init_paths();
|
|
100132
100374
|
import {
|
|
100133
100375
|
closeSync as closeSync18,
|
|
100134
|
-
existsSync as
|
|
100376
|
+
existsSync as existsSync99,
|
|
100135
100377
|
fsyncSync as fsyncSync8,
|
|
100136
|
-
mkdirSync as
|
|
100378
|
+
mkdirSync as mkdirSync58,
|
|
100137
100379
|
openSync as openSync18,
|
|
100138
100380
|
readdirSync as readdirSync35,
|
|
100139
|
-
readFileSync as
|
|
100140
|
-
renameSync as
|
|
100381
|
+
readFileSync as readFileSync89,
|
|
100382
|
+
renameSync as renameSync26,
|
|
100141
100383
|
statSync as statSync53,
|
|
100142
100384
|
unlinkSync as unlinkSync20,
|
|
100143
100385
|
writeSync as writeSync10
|
|
@@ -100161,15 +100403,15 @@ function overlayPathsFor(agent, opts = {}) {
|
|
|
100161
100403
|
};
|
|
100162
100404
|
}
|
|
100163
100405
|
function ensureDirs(paths) {
|
|
100164
|
-
|
|
100165
|
-
|
|
100406
|
+
mkdirSync58(paths.scheduleDir, { recursive: true });
|
|
100407
|
+
mkdirSync58(paths.scheduleStagingDir, { recursive: true });
|
|
100166
100408
|
}
|
|
100167
100409
|
function ensureSkillsDirs(paths) {
|
|
100168
|
-
|
|
100169
|
-
|
|
100410
|
+
mkdirSync58(paths.skillsDir, { recursive: true });
|
|
100411
|
+
mkdirSync58(paths.skillsStagingDir, { recursive: true });
|
|
100170
100412
|
}
|
|
100171
100413
|
function withAgentLock(paths, fn) {
|
|
100172
|
-
|
|
100414
|
+
mkdirSync58(paths.agentRoot, { recursive: true });
|
|
100173
100415
|
const start = Date.now();
|
|
100174
100416
|
const TIMEOUT_MS = 5000;
|
|
100175
100417
|
let fd = null;
|
|
@@ -100219,7 +100461,7 @@ function writeOverlayEntry(agent, slug, yamlText, opts = {}) {
|
|
|
100219
100461
|
} finally {
|
|
100220
100462
|
closeSync18(fd);
|
|
100221
100463
|
}
|
|
100222
|
-
|
|
100464
|
+
renameSync26(stagingPath, finalPath);
|
|
100223
100465
|
return finalPath;
|
|
100224
100466
|
});
|
|
100225
100467
|
}
|
|
@@ -100236,7 +100478,7 @@ function writeSkillsOverlayEntry(agent, slug, yamlText, opts = {}) {
|
|
|
100236
100478
|
} finally {
|
|
100237
100479
|
closeSync18(fd);
|
|
100238
100480
|
}
|
|
100239
|
-
|
|
100481
|
+
renameSync26(stagingPath, finalPath);
|
|
100240
100482
|
return finalPath;
|
|
100241
100483
|
});
|
|
100242
100484
|
}
|
|
@@ -100244,7 +100486,7 @@ function deleteSkillsOverlayEntry(agent, slug, opts = {}) {
|
|
|
100244
100486
|
const paths = overlayPathsFor(agent, opts);
|
|
100245
100487
|
return withAgentLock(paths, () => {
|
|
100246
100488
|
const finalPath = join101(paths.skillsDir, `${slug}.yaml`);
|
|
100247
|
-
if (!
|
|
100489
|
+
if (!existsSync99(finalPath))
|
|
100248
100490
|
return false;
|
|
100249
100491
|
unlinkSync20(finalPath);
|
|
100250
100492
|
return true;
|
|
@@ -100252,7 +100494,7 @@ function deleteSkillsOverlayEntry(agent, slug, opts = {}) {
|
|
|
100252
100494
|
}
|
|
100253
100495
|
function listSkillsOverlayEntries(agent, opts = {}) {
|
|
100254
100496
|
const paths = overlayPathsFor(agent, opts);
|
|
100255
|
-
if (!
|
|
100497
|
+
if (!existsSync99(paths.skillsDir))
|
|
100256
100498
|
return [];
|
|
100257
100499
|
const out = [];
|
|
100258
100500
|
for (const name of readdirSync35(paths.skillsDir)) {
|
|
@@ -100260,7 +100502,7 @@ function listSkillsOverlayEntries(agent, opts = {}) {
|
|
|
100260
100502
|
continue;
|
|
100261
100503
|
const full = join101(paths.skillsDir, name);
|
|
100262
100504
|
try {
|
|
100263
|
-
const raw =
|
|
100505
|
+
const raw = readFileSync89(full, "utf-8");
|
|
100264
100506
|
const slug = name.replace(/\.ya?ml$/i, "");
|
|
100265
100507
|
out.push({ slug, path: full, raw });
|
|
100266
100508
|
} catch {}
|
|
@@ -100271,7 +100513,7 @@ function deleteOverlayEntry(agent, slug, opts = {}) {
|
|
|
100271
100513
|
const paths = overlayPathsFor(agent, opts);
|
|
100272
100514
|
return withAgentLock(paths, () => {
|
|
100273
100515
|
const finalPath = join101(paths.scheduleDir, `${slug}.yaml`);
|
|
100274
|
-
if (!
|
|
100516
|
+
if (!existsSync99(finalPath))
|
|
100275
100517
|
return false;
|
|
100276
100518
|
unlinkSync20(finalPath);
|
|
100277
100519
|
return true;
|
|
@@ -100279,7 +100521,7 @@ function deleteOverlayEntry(agent, slug, opts = {}) {
|
|
|
100279
100521
|
}
|
|
100280
100522
|
function listOverlayEntries(agent, opts = {}) {
|
|
100281
100523
|
const paths = overlayPathsFor(agent, opts);
|
|
100282
|
-
if (!
|
|
100524
|
+
if (!existsSync99(paths.scheduleDir))
|
|
100283
100525
|
return [];
|
|
100284
100526
|
const out = [];
|
|
100285
100527
|
for (const name of readdirSync35(paths.scheduleDir)) {
|
|
@@ -100287,7 +100529,7 @@ function listOverlayEntries(agent, opts = {}) {
|
|
|
100287
100529
|
continue;
|
|
100288
100530
|
const full = join101(paths.scheduleDir, name);
|
|
100289
100531
|
try {
|
|
100290
|
-
const raw =
|
|
100532
|
+
const raw = readFileSync89(full, "utf-8");
|
|
100291
100533
|
const slug = name.replace(/\.ya?ml$/i, "");
|
|
100292
100534
|
out.push({ slug, path: full, raw });
|
|
100293
100535
|
} catch {}
|
|
@@ -100507,15 +100749,15 @@ function reconcileAgentCronOnly(agent) {
|
|
|
100507
100749
|
// src/cli/agent-config-pending.ts
|
|
100508
100750
|
import {
|
|
100509
100751
|
closeSync as closeSync19,
|
|
100510
|
-
existsSync as
|
|
100752
|
+
existsSync as existsSync100,
|
|
100511
100753
|
fsyncSync as fsyncSync9,
|
|
100512
|
-
mkdirSync as
|
|
100754
|
+
mkdirSync as mkdirSync59,
|
|
100513
100755
|
openSync as openSync19,
|
|
100514
100756
|
readdirSync as readdirSync36,
|
|
100515
|
-
readFileSync as
|
|
100516
|
-
renameSync as
|
|
100757
|
+
readFileSync as readFileSync90,
|
|
100758
|
+
renameSync as renameSync27,
|
|
100517
100759
|
unlinkSync as unlinkSync21,
|
|
100518
|
-
writeFileSync as
|
|
100760
|
+
writeFileSync as writeFileSync42,
|
|
100519
100761
|
writeSync as writeSync11
|
|
100520
100762
|
} from "node:fs";
|
|
100521
100763
|
import { join as join102 } from "node:path";
|
|
@@ -100527,7 +100769,7 @@ function pendingDir(agent, opts = {}) {
|
|
|
100527
100769
|
}
|
|
100528
100770
|
function ensurePendingDir(agent, opts = {}) {
|
|
100529
100771
|
const dir = pendingDir(agent, opts);
|
|
100530
|
-
|
|
100772
|
+
mkdirSync59(dir, { recursive: true });
|
|
100531
100773
|
return dir;
|
|
100532
100774
|
}
|
|
100533
100775
|
function newStageId() {
|
|
@@ -100556,15 +100798,15 @@ function stagePendingScheduleEntry(opts) {
|
|
|
100556
100798
|
} finally {
|
|
100557
100799
|
closeSync19(fd);
|
|
100558
100800
|
}
|
|
100559
|
-
|
|
100801
|
+
renameSync27(yamlTmp, yamlPath);
|
|
100560
100802
|
}
|
|
100561
|
-
|
|
100803
|
+
writeFileSync42(metaPath, JSON.stringify(meta, null, 2) + `
|
|
100562
100804
|
`, { mode: 384 });
|
|
100563
100805
|
return { stageId, yamlPath, metaPath };
|
|
100564
100806
|
}
|
|
100565
100807
|
function listPendingScheduleEntries(agent, opts = {}) {
|
|
100566
100808
|
const dir = pendingDir(agent, opts);
|
|
100567
|
-
if (!
|
|
100809
|
+
if (!existsSync100(dir))
|
|
100568
100810
|
return [];
|
|
100569
100811
|
const out = [];
|
|
100570
100812
|
for (const name of readdirSync36(dir).sort()) {
|
|
@@ -100573,10 +100815,10 @@ function listPendingScheduleEntries(agent, opts = {}) {
|
|
|
100573
100815
|
const stageId = name.slice(0, -".meta.json".length);
|
|
100574
100816
|
const metaPath = join102(dir, name);
|
|
100575
100817
|
const yamlPath = join102(dir, `${stageId}.yaml`);
|
|
100576
|
-
if (!
|
|
100818
|
+
if (!existsSync100(yamlPath))
|
|
100577
100819
|
continue;
|
|
100578
100820
|
try {
|
|
100579
|
-
const meta = JSON.parse(
|
|
100821
|
+
const meta = JSON.parse(readFileSync90(metaPath, "utf-8"));
|
|
100580
100822
|
if (meta?.v !== 1 || typeof meta.stage_id !== "string")
|
|
100581
100823
|
continue;
|
|
100582
100824
|
out.push({ stageId: meta.stage_id, agent: meta.agent, yamlPath, metaPath, meta });
|
|
@@ -100592,10 +100834,10 @@ function commitPendingScheduleEntry(opts) {
|
|
|
100592
100834
|
const slug = match.meta.entry.name ?? match.stageId;
|
|
100593
100835
|
const paths = overlayPathsFor(opts.agent, { root: opts.root });
|
|
100594
100836
|
const finalPath = join102(paths.scheduleDir, `${slug}.yaml`);
|
|
100595
|
-
if (
|
|
100837
|
+
if (existsSync100(finalPath)) {
|
|
100596
100838
|
return { committed: false, reason: "slug_collision" };
|
|
100597
100839
|
}
|
|
100598
|
-
|
|
100840
|
+
renameSync27(match.yamlPath, finalPath);
|
|
100599
100841
|
unlinkSync21(match.metaPath);
|
|
100600
100842
|
return { committed: true, path: finalPath, slug };
|
|
100601
100843
|
}
|
|
@@ -100614,7 +100856,7 @@ function denyPendingScheduleEntry(opts) {
|
|
|
100614
100856
|
}
|
|
100615
100857
|
|
|
100616
100858
|
// src/cli/agent-config-write.ts
|
|
100617
|
-
import { existsSync as
|
|
100859
|
+
import { existsSync as existsSync101, readFileSync as readFileSync91 } from "node:fs";
|
|
100618
100860
|
import { execFileSync as execFileSync30 } from "node:child_process";
|
|
100619
100861
|
|
|
100620
100862
|
// src/scheduler/schedule-report.ts
|
|
@@ -101004,8 +101246,8 @@ function scheduleRemove(opts) {
|
|
|
101004
101246
|
}
|
|
101005
101247
|
let priorContent = null;
|
|
101006
101248
|
try {
|
|
101007
|
-
if (
|
|
101008
|
-
priorContent =
|
|
101249
|
+
if (existsSync101(match.path))
|
|
101250
|
+
priorContent = readFileSync91(match.path, "utf-8");
|
|
101009
101251
|
} catch {}
|
|
101010
101252
|
deleteOverlayEntry(agent, match.slug, { root: opts.root });
|
|
101011
101253
|
const reconcileFn = opts.reconcile === undefined ? opts.root ? null : reconcileAgentCronOnly : opts.reconcile;
|
|
@@ -101208,7 +101450,7 @@ function registerAgentConfigWriteCommands(program3) {
|
|
|
101208
101450
|
}
|
|
101209
101451
|
let blob;
|
|
101210
101452
|
if (opts.jsonl) {
|
|
101211
|
-
blob =
|
|
101453
|
+
blob = existsSync101(opts.jsonl) ? readFileSync91(opts.jsonl, "utf-8") : "";
|
|
101212
101454
|
} else {
|
|
101213
101455
|
try {
|
|
101214
101456
|
blob = execFileSync30("docker", ["exec", `switchroom-${agent}`, "cat", "/state/agent/scheduler.jsonl"], {
|
|
@@ -101240,7 +101482,7 @@ function registerAgentConfigWriteCommands(program3) {
|
|
|
101240
101482
|
|
|
101241
101483
|
// src/cli/agent-config-skill-write.ts
|
|
101242
101484
|
var import_yaml22 = __toESM(require_dist(), 1);
|
|
101243
|
-
import { existsSync as
|
|
101485
|
+
import { existsSync as existsSync102 } from "node:fs";
|
|
101244
101486
|
init_reconcile_default_skills();
|
|
101245
101487
|
init_agent_config();
|
|
101246
101488
|
var import_yaml23 = __toESM(require_dist(), 1);
|
|
@@ -101320,7 +101562,7 @@ function skillInstall(opts) {
|
|
|
101320
101562
|
}
|
|
101321
101563
|
const poolDir = opts.bundledSkillsPoolDir ?? getBundledSkillsPoolDir();
|
|
101322
101564
|
const skillPath = join103(poolDir, skillName);
|
|
101323
|
-
if (!
|
|
101565
|
+
if (!existsSync102(skillPath)) {
|
|
101324
101566
|
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.`);
|
|
101325
101567
|
}
|
|
101326
101568
|
const yamlText = import_yaml22.stringify({ skills: [skillName] });
|
|
@@ -101484,22 +101726,22 @@ function registerAgentConfigSkillWriteCommands(program3) {
|
|
|
101484
101726
|
// src/cli/skill.ts
|
|
101485
101727
|
import {
|
|
101486
101728
|
closeSync as closeSync20,
|
|
101487
|
-
existsSync as
|
|
101729
|
+
existsSync as existsSync103,
|
|
101488
101730
|
lstatSync as lstatSync12,
|
|
101489
|
-
mkdirSync as
|
|
101731
|
+
mkdirSync as mkdirSync60,
|
|
101490
101732
|
mkdtempSync as mkdtempSync5,
|
|
101491
101733
|
openSync as openSync20,
|
|
101492
|
-
readFileSync as
|
|
101734
|
+
readFileSync as readFileSync92,
|
|
101493
101735
|
readdirSync as readdirSync37,
|
|
101494
101736
|
realpathSync as realpathSync7,
|
|
101495
|
-
renameSync as
|
|
101737
|
+
renameSync as renameSync28,
|
|
101496
101738
|
rmSync as rmSync19,
|
|
101497
101739
|
statSync as statSync54,
|
|
101498
|
-
writeFileSync as
|
|
101740
|
+
writeFileSync as writeFileSync43
|
|
101499
101741
|
} from "node:fs";
|
|
101500
101742
|
import { tmpdir as tmpdir6, homedir as homedir54 } from "node:os";
|
|
101501
|
-
import { dirname as
|
|
101502
|
-
import { spawnSync as
|
|
101743
|
+
import { dirname as dirname41, join as join104, relative as relative4, resolve as resolve58 } from "node:path";
|
|
101744
|
+
import { spawnSync as spawnSync21 } from "node:child_process";
|
|
101503
101745
|
|
|
101504
101746
|
// src/cli/skill-common.ts
|
|
101505
101747
|
var import_yaml24 = __toESM(require_dist(), 1);
|
|
@@ -101782,7 +102024,7 @@ function loadFromDir(dir) {
|
|
|
101782
102024
|
continue;
|
|
101783
102025
|
}
|
|
101784
102026
|
if (ent.isFile()) {
|
|
101785
|
-
const buf =
|
|
102027
|
+
const buf = readFileSync92(full);
|
|
101786
102028
|
files[rel.replace(/\\/g, "/")] = buf.toString("utf-8");
|
|
101787
102029
|
}
|
|
101788
102030
|
}
|
|
@@ -101793,7 +102035,7 @@ function loadFromDir(dir) {
|
|
|
101793
102035
|
function loadFromTarball(tarPath) {
|
|
101794
102036
|
const isGz = tarPath.endsWith(".gz") || tarPath.endsWith(".tgz");
|
|
101795
102037
|
const listFlags = isGz ? ["-tzf"] : ["-tf"];
|
|
101796
|
-
const list2 =
|
|
102038
|
+
const list2 = spawnSync21("tar", [...listFlags, tarPath], {
|
|
101797
102039
|
encoding: "utf-8",
|
|
101798
102040
|
stdio: ["ignore", "pipe", "pipe"]
|
|
101799
102041
|
});
|
|
@@ -101810,7 +102052,7 @@ function loadFromTarball(tarPath) {
|
|
|
101810
102052
|
const staging = mkdtempSync5(join104(tmpdir6(), "skill-apply-extract-"));
|
|
101811
102053
|
try {
|
|
101812
102054
|
const flags = isGz ? ["-xzf"] : ["-xf"];
|
|
101813
|
-
const r =
|
|
102055
|
+
const r = spawnSync21("tar", [
|
|
101814
102056
|
...flags,
|
|
101815
102057
|
tarPath,
|
|
101816
102058
|
"-C",
|
|
@@ -101831,7 +102073,7 @@ function loadFromTarball(tarPath) {
|
|
|
101831
102073
|
}
|
|
101832
102074
|
}
|
|
101833
102075
|
function loadSingleFile(filePath) {
|
|
101834
|
-
const content =
|
|
102076
|
+
const content = readFileSync92(filePath, "utf-8");
|
|
101835
102077
|
return { "SKILL.md": content };
|
|
101836
102078
|
}
|
|
101837
102079
|
function loadFromStdin() {
|
|
@@ -101885,7 +102127,7 @@ function validatePayload(name, files) {
|
|
|
101885
102127
|
if (errors2.length === 0) {
|
|
101886
102128
|
for (const [path10, content] of Object.entries(files)) {
|
|
101887
102129
|
if (SH_SCRIPT_RE2.test(path10)) {
|
|
101888
|
-
const r =
|
|
102130
|
+
const r = spawnSync21("bash", ["-n"], {
|
|
101889
102131
|
input: content,
|
|
101890
102132
|
encoding: "utf-8"
|
|
101891
102133
|
});
|
|
@@ -101896,8 +102138,8 @@ function validatePayload(name, files) {
|
|
|
101896
102138
|
const tmp = mkdtempSync5(join104(tmpdir6(), "skill-apply-py-"));
|
|
101897
102139
|
const tmpPy = join104(tmp, "check.py");
|
|
101898
102140
|
try {
|
|
101899
|
-
|
|
101900
|
-
const r =
|
|
102141
|
+
writeFileSync43(tmpPy, content);
|
|
102142
|
+
const r = spawnSync21("python3", ["-m", "py_compile", tmpPy], {
|
|
101901
102143
|
encoding: "utf-8"
|
|
101902
102144
|
});
|
|
101903
102145
|
if (r.status !== 0) {
|
|
@@ -101914,7 +102156,7 @@ function validatePayload(name, files) {
|
|
|
101914
102156
|
function diffSummary(currentDir, files) {
|
|
101915
102157
|
const lines = [];
|
|
101916
102158
|
const currentFiles = {};
|
|
101917
|
-
if (
|
|
102159
|
+
if (existsSync103(currentDir)) {
|
|
101918
102160
|
const walk2 = (sub) => {
|
|
101919
102161
|
for (const ent of readdirSync37(sub, { withFileTypes: true })) {
|
|
101920
102162
|
const full = join104(sub, ent.name);
|
|
@@ -101922,7 +102164,7 @@ function diffSummary(currentDir, files) {
|
|
|
101922
102164
|
if (ent.isDirectory()) {
|
|
101923
102165
|
walk2(full);
|
|
101924
102166
|
} else if (ent.isFile()) {
|
|
101925
|
-
currentFiles[rel.replace(/\\/g, "/")] =
|
|
102167
|
+
currentFiles[rel.replace(/\\/g, "/")] = readFileSync92(full, "utf-8");
|
|
101926
102168
|
}
|
|
101927
102169
|
}
|
|
101928
102170
|
};
|
|
@@ -101950,8 +102192,8 @@ function diffSummary(currentDir, files) {
|
|
|
101950
102192
|
`);
|
|
101951
102193
|
}
|
|
101952
102194
|
function writePayload(poolDir, name, files) {
|
|
101953
|
-
if (!
|
|
101954
|
-
|
|
102195
|
+
if (!existsSync103(poolDir)) {
|
|
102196
|
+
mkdirSync60(poolDir, { recursive: true, mode: 493 });
|
|
101955
102197
|
}
|
|
101956
102198
|
const target = join104(poolDir, name);
|
|
101957
102199
|
let targetIsSymlink = false;
|
|
@@ -101969,10 +102211,10 @@ function writePayload(poolDir, name, files) {
|
|
|
101969
102211
|
try {
|
|
101970
102212
|
for (const [path10, content] of Object.entries(files)) {
|
|
101971
102213
|
const full = join104(staging, path10);
|
|
101972
|
-
|
|
102214
|
+
mkdirSync60(dirname41(full), { recursive: true, mode: 493 });
|
|
101973
102215
|
const fd = openSync20(full, "wx");
|
|
101974
102216
|
try {
|
|
101975
|
-
|
|
102217
|
+
writeFileSync43(fd, content);
|
|
101976
102218
|
} finally {
|
|
101977
102219
|
closeSync20(fd);
|
|
101978
102220
|
}
|
|
@@ -101988,9 +102230,9 @@ function writePayload(poolDir, name, files) {
|
|
|
101988
102230
|
} catch {}
|
|
101989
102231
|
if (targetExists) {
|
|
101990
102232
|
oldRename = `${target}.skill-apply-old-${Date.now()}`;
|
|
101991
|
-
|
|
102233
|
+
renameSync28(target, oldRename);
|
|
101992
102234
|
}
|
|
101993
|
-
|
|
102235
|
+
renameSync28(staging, target);
|
|
101994
102236
|
if (oldRename) {
|
|
101995
102237
|
rmSync19(oldRename, { recursive: true, force: true });
|
|
101996
102238
|
oldRename = null;
|
|
@@ -101999,12 +102241,12 @@ function writePayload(poolDir, name, files) {
|
|
|
101999
102241
|
try {
|
|
102000
102242
|
rmSync19(staging, { recursive: true, force: true });
|
|
102001
102243
|
} catch {}
|
|
102002
|
-
if (oldRename &&
|
|
102244
|
+
if (oldRename && existsSync103(oldRename)) {
|
|
102003
102245
|
try {
|
|
102004
|
-
if (
|
|
102246
|
+
if (existsSync103(target)) {
|
|
102005
102247
|
rmSync19(target, { recursive: true, force: true });
|
|
102006
102248
|
}
|
|
102007
|
-
|
|
102249
|
+
renameSync28(oldRename, target);
|
|
102008
102250
|
} catch {}
|
|
102009
102251
|
}
|
|
102010
102252
|
throw err2;
|
|
@@ -102022,7 +102264,7 @@ function registerSkillCommand(program3) {
|
|
|
102022
102264
|
files = loadFromStdin();
|
|
102023
102265
|
} else {
|
|
102024
102266
|
const fromPath = resolve58(opts.from);
|
|
102025
|
-
if (!
|
|
102267
|
+
if (!existsSync103(fromPath)) {
|
|
102026
102268
|
fail4(`--from path does not exist: ${opts.from}`);
|
|
102027
102269
|
}
|
|
102028
102270
|
const st = statSync54(fromPath);
|
|
@@ -102060,7 +102302,7 @@ function registerSkillCommand(program3) {
|
|
|
102060
102302
|
\u2713 Wrote ${name} to ${currentDir}`));
|
|
102061
102303
|
const self = selfInvokeArgv(["apply", "--non-interactive"]);
|
|
102062
102304
|
console.log(source_default.gray(`Running \`switchroom apply --non-interactive\`...`));
|
|
102063
|
-
const r =
|
|
102305
|
+
const r = spawnSync21(self.command, self.argv, { stdio: "inherit" });
|
|
102064
102306
|
if (r.status !== 0) {
|
|
102065
102307
|
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.)`));
|
|
102066
102308
|
}
|
|
@@ -102078,22 +102320,22 @@ function sumBytes(files) {
|
|
|
102078
102320
|
init_esm();
|
|
102079
102321
|
import {
|
|
102080
102322
|
closeSync as closeSync21,
|
|
102081
|
-
existsSync as
|
|
102323
|
+
existsSync as existsSync104,
|
|
102082
102324
|
lstatSync as lstatSync13,
|
|
102083
|
-
mkdirSync as
|
|
102325
|
+
mkdirSync as mkdirSync61,
|
|
102084
102326
|
mkdtempSync as mkdtempSync6,
|
|
102085
102327
|
openSync as openSync21,
|
|
102086
|
-
readFileSync as
|
|
102328
|
+
readFileSync as readFileSync93,
|
|
102087
102329
|
readdirSync as readdirSync38,
|
|
102088
|
-
renameSync as
|
|
102330
|
+
renameSync as renameSync29,
|
|
102089
102331
|
rmSync as rmSync20,
|
|
102090
102332
|
statSync as statSync55,
|
|
102091
102333
|
utimesSync,
|
|
102092
|
-
writeFileSync as
|
|
102334
|
+
writeFileSync as writeFileSync44
|
|
102093
102335
|
} from "node:fs";
|
|
102094
|
-
import { dirname as
|
|
102336
|
+
import { dirname as dirname42, join as join105, relative as relative5, resolve as resolve59 } from "node:path";
|
|
102095
102337
|
import { homedir as homedir55, tmpdir as tmpdir7 } from "node:os";
|
|
102096
|
-
import { spawnSync as
|
|
102338
|
+
import { spawnSync as spawnSync22 } from "node:child_process";
|
|
102097
102339
|
init_helpers();
|
|
102098
102340
|
init_agent_config();
|
|
102099
102341
|
init_source();
|
|
@@ -102104,14 +102346,14 @@ var PERSONAL_SKILLS_SUBPATH = "personal-skills";
|
|
|
102104
102346
|
function resolveConfigSkillsDir(agent) {
|
|
102105
102347
|
const override = process.env.SWITCHROOM_CONFIG_DIR;
|
|
102106
102348
|
const candidate = override ? resolve59(override) : join105(homedir55(), ".switchroom-config");
|
|
102107
|
-
if (!
|
|
102349
|
+
if (!existsSync104(candidate))
|
|
102108
102350
|
return null;
|
|
102109
102351
|
return join105(candidate, "agents", agent, PERSONAL_SKILLS_SUBPATH);
|
|
102110
102352
|
}
|
|
102111
102353
|
var MIRROR_PRIOR_TTL_MS = 24 * 60 * 60 * 1000;
|
|
102112
102354
|
function sweepMirrorPriors(configSkillsRoot) {
|
|
102113
102355
|
try {
|
|
102114
|
-
if (!
|
|
102356
|
+
if (!existsSync104(configSkillsRoot))
|
|
102115
102357
|
return;
|
|
102116
102358
|
const now = Date.now();
|
|
102117
102359
|
for (const ent of readdirSync38(configSkillsRoot)) {
|
|
@@ -102147,17 +102389,17 @@ function mirrorToConfigRepo(agent, name, liveSkillDir) {
|
|
|
102147
102389
|
}
|
|
102148
102390
|
if (liveSkillDir === null) {
|
|
102149
102391
|
sweepMirrorPriors(configSkillsRoot);
|
|
102150
|
-
if (
|
|
102392
|
+
if (existsSync104(dest)) {
|
|
102151
102393
|
const trash = join105(configSkillsRoot, `.${name}-trash-${Date.now()}`);
|
|
102152
|
-
|
|
102394
|
+
renameSync29(dest, trash);
|
|
102153
102395
|
}
|
|
102154
102396
|
return;
|
|
102155
102397
|
}
|
|
102156
|
-
|
|
102398
|
+
mkdirSync61(configSkillsRoot, { recursive: true, mode: 493 });
|
|
102157
102399
|
sweepMirrorPriors(configSkillsRoot);
|
|
102158
102400
|
const staging = mkdtempSync6(join105(configSkillsRoot, `.${name}-staging-`));
|
|
102159
102401
|
const walk2 = (src, dst) => {
|
|
102160
|
-
|
|
102402
|
+
mkdirSync61(dst, { recursive: true, mode: 493 });
|
|
102161
102403
|
for (const ent of readdirSync38(src, { withFileTypes: true })) {
|
|
102162
102404
|
const s = join105(src, ent.name);
|
|
102163
102405
|
const d = join105(dst, ent.name);
|
|
@@ -102166,16 +102408,16 @@ function mirrorToConfigRepo(agent, name, liveSkillDir) {
|
|
|
102166
102408
|
if (ent.isDirectory())
|
|
102167
102409
|
walk2(s, d);
|
|
102168
102410
|
else if (ent.isFile()) {
|
|
102169
|
-
|
|
102411
|
+
writeFileSync44(d, readFileSync93(s));
|
|
102170
102412
|
}
|
|
102171
102413
|
}
|
|
102172
102414
|
};
|
|
102173
102415
|
walk2(liveSkillDir, staging);
|
|
102174
|
-
if (
|
|
102416
|
+
if (existsSync104(dest)) {
|
|
102175
102417
|
const prior = join105(configSkillsRoot, `.${name}-prior-${Date.now()}`);
|
|
102176
|
-
|
|
102418
|
+
renameSync29(dest, prior);
|
|
102177
102419
|
}
|
|
102178
|
-
|
|
102420
|
+
renameSync29(staging, dest);
|
|
102179
102421
|
} catch (err2) {
|
|
102180
102422
|
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.
|
|
102181
102423
|
`));
|
|
@@ -102212,7 +102454,7 @@ function trashDir(agentsRoot, agent) {
|
|
|
102212
102454
|
}
|
|
102213
102455
|
function countPersonalSkills(agentsRoot, agent) {
|
|
102214
102456
|
const skillsDir = join105(agentsRoot, agent, ".claude", "skills");
|
|
102215
|
-
if (!
|
|
102457
|
+
if (!existsSync104(skillsDir))
|
|
102216
102458
|
return 0;
|
|
102217
102459
|
let n = 0;
|
|
102218
102460
|
for (const ent of readdirSync38(skillsDir, { withFileTypes: true })) {
|
|
@@ -102259,7 +102501,7 @@ function loadFromDir2(dir) {
|
|
|
102259
102501
|
}
|
|
102260
102502
|
if (ent.isFile()) {
|
|
102261
102503
|
const rel = relative5(abs, full).replace(/\\/g, "/");
|
|
102262
|
-
files[rel] =
|
|
102504
|
+
files[rel] = readFileSync93(full, "utf-8");
|
|
102263
102505
|
}
|
|
102264
102506
|
}
|
|
102265
102507
|
};
|
|
@@ -102297,7 +102539,7 @@ function behavioralValidate(files) {
|
|
|
102297
102539
|
const errors2 = [];
|
|
102298
102540
|
for (const [path10, content] of Object.entries(files)) {
|
|
102299
102541
|
if (SH_SCRIPT_RE.test(path10)) {
|
|
102300
|
-
const r =
|
|
102542
|
+
const r = spawnSync22("bash", ["-n"], { input: content, encoding: "utf-8" });
|
|
102301
102543
|
if (r.status !== 0) {
|
|
102302
102544
|
errors2.push(`${path10} fails \`bash -n\`: ${(r.stderr ?? "").trim()}`);
|
|
102303
102545
|
}
|
|
@@ -102305,8 +102547,8 @@ function behavioralValidate(files) {
|
|
|
102305
102547
|
const tmp = mkdtempSync6(join105(tmpdir7(), "skill-personal-py-"));
|
|
102306
102548
|
const tmpPy = join105(tmp, "check.py");
|
|
102307
102549
|
try {
|
|
102308
|
-
|
|
102309
|
-
const r =
|
|
102550
|
+
writeFileSync44(tmpPy, content);
|
|
102551
|
+
const r = spawnSync22("python3", ["-m", "py_compile", tmpPy], {
|
|
102310
102552
|
encoding: "utf-8"
|
|
102311
102553
|
});
|
|
102312
102554
|
if (r.status !== 0) {
|
|
@@ -102321,7 +102563,7 @@ function behavioralValidate(files) {
|
|
|
102321
102563
|
}
|
|
102322
102564
|
function sweepTrash(agentsRoot, agent) {
|
|
102323
102565
|
const trash = trashDir(agentsRoot, agent);
|
|
102324
|
-
if (!
|
|
102566
|
+
if (!existsSync104(trash))
|
|
102325
102567
|
return;
|
|
102326
102568
|
const now = Date.now();
|
|
102327
102569
|
for (const ent of readdirSync38(trash, { withFileTypes: true })) {
|
|
@@ -102347,16 +102589,16 @@ function writePersonalSkill(targetDir, files) {
|
|
|
102347
102589
|
if (targetIsSymlink) {
|
|
102348
102590
|
fail5(`refusing to overwrite symlink at ${targetDir}; investigate manually`);
|
|
102349
102591
|
}
|
|
102350
|
-
|
|
102351
|
-
const staging = mkdtempSync6(join105(
|
|
102592
|
+
mkdirSync61(dirname42(targetDir), { recursive: true, mode: 493 });
|
|
102593
|
+
const staging = mkdtempSync6(join105(dirname42(targetDir), `.skill-personal-stage-`));
|
|
102352
102594
|
let oldRename = null;
|
|
102353
102595
|
try {
|
|
102354
102596
|
for (const [path10, content] of Object.entries(files)) {
|
|
102355
102597
|
const full = join105(staging, path10);
|
|
102356
|
-
|
|
102598
|
+
mkdirSync61(dirname42(full), { recursive: true, mode: 493 });
|
|
102357
102599
|
const fd = openSync21(full, "wx");
|
|
102358
102600
|
try {
|
|
102359
|
-
|
|
102601
|
+
writeFileSync44(fd, content);
|
|
102360
102602
|
} finally {
|
|
102361
102603
|
closeSync21(fd);
|
|
102362
102604
|
}
|
|
@@ -102372,9 +102614,9 @@ function writePersonalSkill(targetDir, files) {
|
|
|
102372
102614
|
} catch {}
|
|
102373
102615
|
if (targetExists) {
|
|
102374
102616
|
oldRename = `${targetDir}.personal-old-${Date.now()}`;
|
|
102375
|
-
|
|
102617
|
+
renameSync29(targetDir, oldRename);
|
|
102376
102618
|
}
|
|
102377
|
-
|
|
102619
|
+
renameSync29(staging, targetDir);
|
|
102378
102620
|
if (oldRename) {
|
|
102379
102621
|
rmSync20(oldRename, { recursive: true, force: true });
|
|
102380
102622
|
oldRename = null;
|
|
@@ -102383,12 +102625,12 @@ function writePersonalSkill(targetDir, files) {
|
|
|
102383
102625
|
try {
|
|
102384
102626
|
rmSync20(staging, { recursive: true, force: true });
|
|
102385
102627
|
} catch {}
|
|
102386
|
-
if (oldRename &&
|
|
102628
|
+
if (oldRename && existsSync104(oldRename)) {
|
|
102387
102629
|
try {
|
|
102388
|
-
if (
|
|
102630
|
+
if (existsSync104(targetDir)) {
|
|
102389
102631
|
rmSync20(targetDir, { recursive: true, force: true });
|
|
102390
102632
|
}
|
|
102391
|
-
|
|
102633
|
+
renameSync29(oldRename, targetDir);
|
|
102392
102634
|
} catch {}
|
|
102393
102635
|
}
|
|
102394
102636
|
throw err2;
|
|
@@ -102451,7 +102693,7 @@ function loadFiles(opts) {
|
|
|
102451
102693
|
return loadFromStdin2();
|
|
102452
102694
|
}
|
|
102453
102695
|
const p = resolve59(opts.from);
|
|
102454
|
-
if (!
|
|
102696
|
+
if (!existsSync104(p)) {
|
|
102455
102697
|
fail5(`--from path does not exist: ${opts.from}`);
|
|
102456
102698
|
}
|
|
102457
102699
|
const st = statSync55(p);
|
|
@@ -102459,7 +102701,7 @@ function loadFiles(opts) {
|
|
|
102459
102701
|
return loadFromDir2(p);
|
|
102460
102702
|
}
|
|
102461
102703
|
if (p.endsWith(".md")) {
|
|
102462
|
-
return { "SKILL.md":
|
|
102704
|
+
return { "SKILL.md": readFileSync93(p, "utf-8") };
|
|
102463
102705
|
}
|
|
102464
102706
|
fail5(`--from must be a directory or a .md file. Got: ${opts.from}`);
|
|
102465
102707
|
}
|
|
@@ -102513,7 +102755,7 @@ function resolveCloneSource(source, opts) {
|
|
|
102513
102755
|
const slug = m[2];
|
|
102514
102756
|
const root = tier === "bundled" ? opts.bundledRoot ?? defaultBundledRoot() : opts.sharedRoot ?? defaultSharedRoot();
|
|
102515
102757
|
const dir = join105(root, slug);
|
|
102516
|
-
if (!
|
|
102758
|
+
if (!existsSync104(dir)) {
|
|
102517
102759
|
fail5(`clone source ${JSON.stringify(source)} not found at ${dir}; ` + `check \`switchroom skill search --tier ${tier}\``, 1);
|
|
102518
102760
|
}
|
|
102519
102761
|
const st = lstatSync13(dir);
|
|
@@ -102548,7 +102790,7 @@ function readSourceFiles(dir) {
|
|
|
102548
102790
|
fail5(`clone source has oversized file ${rel} (${st.size} bytes > ${CLONE_MAX_FILE_BYTES}); ` + `refuse to read`, 3);
|
|
102549
102791
|
}
|
|
102550
102792
|
} catch {}
|
|
102551
|
-
files[rel] =
|
|
102793
|
+
files[rel] = readFileSync93(full, "utf-8");
|
|
102552
102794
|
}
|
|
102553
102795
|
}
|
|
102554
102796
|
};
|
|
@@ -102637,10 +102879,10 @@ function removePersonalAction(name, opts) {
|
|
|
102637
102879
|
throw err2;
|
|
102638
102880
|
}
|
|
102639
102881
|
const trashRoot2 = trashDir(agentsRoot, agent);
|
|
102640
|
-
|
|
102882
|
+
mkdirSync61(trashRoot2, { recursive: true, mode: 493 });
|
|
102641
102883
|
const ts = Date.now();
|
|
102642
102884
|
const trashTarget = join105(trashRoot2, `${name}-${ts}`);
|
|
102643
|
-
|
|
102885
|
+
renameSync29(target, trashTarget);
|
|
102644
102886
|
const now = new Date(ts);
|
|
102645
102887
|
utimesSync(trashTarget, now, now);
|
|
102646
102888
|
mirrorToConfigRepo(agent, name, null);
|
|
@@ -102660,7 +102902,7 @@ function listPersonalAction(opts) {
|
|
|
102660
102902
|
sweepTrash(agentsRoot, agent);
|
|
102661
102903
|
const skillsDir = join105(agentsRoot, agent, ".claude", "skills");
|
|
102662
102904
|
const personal = [];
|
|
102663
|
-
if (
|
|
102905
|
+
if (existsSync104(skillsDir)) {
|
|
102664
102906
|
for (const ent of readdirSync38(skillsDir, { withFileTypes: true })) {
|
|
102665
102907
|
if (!ent.isDirectory())
|
|
102666
102908
|
continue;
|
|
@@ -102718,7 +102960,7 @@ function registerSkillPersonalCommands(program3) {
|
|
|
102718
102960
|
import { createConnection as createConnection4 } from "node:net";
|
|
102719
102961
|
import { homedir as homedir56 } from "node:os";
|
|
102720
102962
|
import { join as join106 } from "node:path";
|
|
102721
|
-
import { readFileSync as
|
|
102963
|
+
import { readFileSync as readFileSync94 } from "node:fs";
|
|
102722
102964
|
var IPC_CONNECT_TIMEOUT_MS = 5000;
|
|
102723
102965
|
function gatewaySocketPath() {
|
|
102724
102966
|
return process.env.SWITCHROOM_GATEWAY_SOCKET ?? (process.env.TELEGRAM_STATE_DIR ? join106(process.env.TELEGRAM_STATE_DIR, "gateway.sock") : join106(homedir56(), ".claude", "channels", "telegram", "gateway.sock"));
|
|
@@ -102756,7 +102998,7 @@ function registerSelfImproveProposeSkillCommand(program3) {
|
|
|
102756
102998
|
fail6("agent name required (--agent or $SWITCHROOM_AGENT_NAME)");
|
|
102757
102999
|
let draft;
|
|
102758
103000
|
try {
|
|
102759
|
-
draft = JSON.parse(
|
|
103001
|
+
draft = JSON.parse(readFileSync94(opts.draft, "utf-8"));
|
|
102760
103002
|
} catch (e) {
|
|
102761
103003
|
fail6(`failed to read/parse --draft: ${e.message}`);
|
|
102762
103004
|
}
|
|
@@ -102793,7 +103035,7 @@ function registerSelfImproveProposeSkillCommand(program3) {
|
|
|
102793
103035
|
init_esm();
|
|
102794
103036
|
init_helpers();
|
|
102795
103037
|
var import_yaml25 = __toESM(require_dist(), 1);
|
|
102796
|
-
import { existsSync as
|
|
103038
|
+
import { existsSync as existsSync105, readdirSync as readdirSync39, readFileSync as readFileSync95, statSync as statSync56 } from "node:fs";
|
|
102797
103039
|
import { homedir as homedir57 } from "node:os";
|
|
102798
103040
|
import { join as join107, resolve as resolve60 } from "node:path";
|
|
102799
103041
|
var PERSONAL_PREFIX2 = "personal-";
|
|
@@ -102810,11 +103052,11 @@ function defaultBundledRoot2() {
|
|
|
102810
103052
|
}
|
|
102811
103053
|
function readSkillFrontmatter(skillDir) {
|
|
102812
103054
|
const mdPath = join107(skillDir, "SKILL.md");
|
|
102813
|
-
if (!
|
|
103055
|
+
if (!existsSync105(mdPath))
|
|
102814
103056
|
return null;
|
|
102815
103057
|
let content;
|
|
102816
103058
|
try {
|
|
102817
|
-
content =
|
|
103059
|
+
content = readFileSync95(mdPath, "utf-8");
|
|
102818
103060
|
} catch {
|
|
102819
103061
|
return null;
|
|
102820
103062
|
}
|
|
@@ -102854,7 +103096,7 @@ function listPersonalSkills(agent, agentsRoot = defaultAgentsRoot()) {
|
|
|
102854
103096
|
if (!AGENT_NAME_RE3.test(agent))
|
|
102855
103097
|
return [];
|
|
102856
103098
|
const skillsDir = join107(agentsRoot, agent, ".claude/skills");
|
|
102857
|
-
if (!
|
|
103099
|
+
if (!existsSync105(skillsDir))
|
|
102858
103100
|
return [];
|
|
102859
103101
|
const out = [];
|
|
102860
103102
|
let entries;
|
|
@@ -102892,7 +103134,7 @@ function listPersonalSkills(agent, agentsRoot = defaultAgentsRoot()) {
|
|
|
102892
103134
|
return out;
|
|
102893
103135
|
}
|
|
102894
103136
|
function listSharedSkills(sharedRoot = defaultSharedRoot2()) {
|
|
102895
|
-
if (!
|
|
103137
|
+
if (!existsSync105(sharedRoot))
|
|
102896
103138
|
return [];
|
|
102897
103139
|
const out = [];
|
|
102898
103140
|
let entries;
|
|
@@ -102930,7 +103172,7 @@ function listSharedSkills(sharedRoot = defaultSharedRoot2()) {
|
|
|
102930
103172
|
return out;
|
|
102931
103173
|
}
|
|
102932
103174
|
function listBundledSkills(bundledRoot = defaultBundledRoot2()) {
|
|
102933
|
-
if (!
|
|
103175
|
+
if (!existsSync105(bundledRoot))
|
|
102934
103176
|
return [];
|
|
102935
103177
|
const out = [];
|
|
102936
103178
|
let entries;
|
|
@@ -103088,10 +103330,10 @@ init_source();
|
|
|
103088
103330
|
init_helpers();
|
|
103089
103331
|
init_operator_uid();
|
|
103090
103332
|
import {
|
|
103091
|
-
existsSync as
|
|
103092
|
-
mkdirSync as
|
|
103333
|
+
existsSync as existsSync107,
|
|
103334
|
+
mkdirSync as mkdirSync62,
|
|
103093
103335
|
readdirSync as readdirSync40,
|
|
103094
|
-
writeFileSync as
|
|
103336
|
+
writeFileSync as writeFileSync45,
|
|
103095
103337
|
statSync as statSync57,
|
|
103096
103338
|
lstatSync as lstatSync14,
|
|
103097
103339
|
realpathSync as realpathSync8,
|
|
@@ -103099,13 +103341,13 @@ import {
|
|
|
103099
103341
|
} from "node:fs";
|
|
103100
103342
|
import { homedir as homedir58 } from "node:os";
|
|
103101
103343
|
import { join as join108 } from "node:path";
|
|
103102
|
-
import { spawnSync as
|
|
103344
|
+
import { spawnSync as spawnSync25 } from "node:child_process";
|
|
103103
103345
|
|
|
103104
103346
|
// src/cli/singleton-stale-cleanup.ts
|
|
103105
|
-
import { spawnSync as
|
|
103347
|
+
import { spawnSync as spawnSync24 } from "node:child_process";
|
|
103106
103348
|
function makeDockerRunner() {
|
|
103107
103349
|
return (args) => {
|
|
103108
|
-
const r =
|
|
103350
|
+
const r = spawnSync24("docker", args, { encoding: "utf8" });
|
|
103109
103351
|
return {
|
|
103110
103352
|
ok: r.status === 0,
|
|
103111
103353
|
stdout: r.stdout ?? "",
|
|
@@ -103464,7 +103706,7 @@ function resolveHostdSkillsTarget(hostHome) {
|
|
|
103464
103706
|
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.`);
|
|
103465
103707
|
return;
|
|
103466
103708
|
}
|
|
103467
|
-
if (!
|
|
103709
|
+
if (!existsSync107(target)) {
|
|
103468
103710
|
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.`);
|
|
103469
103711
|
return;
|
|
103470
103712
|
}
|
|
@@ -103478,7 +103720,7 @@ function hostdComposePath() {
|
|
|
103478
103720
|
}
|
|
103479
103721
|
function backupExistingCompose() {
|
|
103480
103722
|
const p = hostdComposePath();
|
|
103481
|
-
if (!
|
|
103723
|
+
if (!existsSync107(p))
|
|
103482
103724
|
return null;
|
|
103483
103725
|
const ts = new Date().toISOString().replace(/[:.]/g, "-");
|
|
103484
103726
|
const bak = `${p}.bak-${ts}`;
|
|
@@ -103486,7 +103728,7 @@ function backupExistingCompose() {
|
|
|
103486
103728
|
return bak;
|
|
103487
103729
|
}
|
|
103488
103730
|
function runDocker(args) {
|
|
103489
|
-
const r =
|
|
103731
|
+
const r = spawnSync25("docker", args, { encoding: "utf8" });
|
|
103490
103732
|
return {
|
|
103491
103733
|
ok: r.status === 0,
|
|
103492
103734
|
stdout: r.stdout ?? "",
|
|
@@ -103511,7 +103753,7 @@ async function doInstall(opts, program3) {
|
|
|
103511
103753
|
}
|
|
103512
103754
|
const dir = hostdDir();
|
|
103513
103755
|
const composePath = hostdComposePath();
|
|
103514
|
-
|
|
103756
|
+
mkdirSync62(dir, { recursive: true });
|
|
103515
103757
|
const imageTag = resolveHostdImageTag(opts.tag, cfg.release);
|
|
103516
103758
|
const guard = checkDowngrade({
|
|
103517
103759
|
container: "switchroom-hostd",
|
|
@@ -103544,7 +103786,7 @@ async function doInstall(opts, program3) {
|
|
|
103544
103786
|
const bak = backupExistingCompose();
|
|
103545
103787
|
if (bak)
|
|
103546
103788
|
console.log(source_default.dim(` Backed up existing compose to ${bak}`));
|
|
103547
|
-
|
|
103789
|
+
writeFileSync45(composePath, yaml, "utf8");
|
|
103548
103790
|
console.log(source_default.green(` \u2713 Wrote ${composePath}`));
|
|
103549
103791
|
const adminAgents = Object.entries(cfg.agents ?? {}).filter(([, a]) => a?.admin === true).map(([name]) => name);
|
|
103550
103792
|
console.log(source_default.dim(` agents served (one socket each): ${allAgents.length === 0 ? "(none)" : allAgents.join(", ")}`));
|
|
@@ -103576,7 +103818,7 @@ function doStatus() {
|
|
|
103576
103818
|
const composeYml = hostdComposePath();
|
|
103577
103819
|
console.log(source_default.bold("switchroom-hostd"));
|
|
103578
103820
|
console.log("");
|
|
103579
|
-
if (!
|
|
103821
|
+
if (!existsSync107(composeYml)) {
|
|
103580
103822
|
console.log(source_default.yellow(" compose: not installed"));
|
|
103581
103823
|
console.log(source_default.dim(" run `switchroom hostd install` to set up."));
|
|
103582
103824
|
return;
|
|
@@ -103597,14 +103839,14 @@ function doStatus() {
|
|
|
103597
103839
|
} else {
|
|
103598
103840
|
console.log(source_default.green(` container: ${ps.stdout.trim()}`));
|
|
103599
103841
|
}
|
|
103600
|
-
if (
|
|
103842
|
+
if (existsSync107(dir)) {
|
|
103601
103843
|
const entries = [];
|
|
103602
103844
|
try {
|
|
103603
103845
|
for (const name of readdirSync40(dir)) {
|
|
103604
103846
|
if (name === "docker-compose.yml" || name.startsWith("docker-compose.yml."))
|
|
103605
103847
|
continue;
|
|
103606
103848
|
const sockPath = join108(dir, name, "sock");
|
|
103607
|
-
if (
|
|
103849
|
+
if (existsSync107(sockPath)) {
|
|
103608
103850
|
const st = statSync57(sockPath);
|
|
103609
103851
|
if ((st.mode & 61440) === 49152) {
|
|
103610
103852
|
entries.push(`${name} \u2192 ${sockPath}`);
|
|
@@ -103623,7 +103865,7 @@ function doStatus() {
|
|
|
103623
103865
|
}
|
|
103624
103866
|
function doUninstall() {
|
|
103625
103867
|
const composeYml = hostdComposePath();
|
|
103626
|
-
if (!
|
|
103868
|
+
if (!existsSync107(composeYml)) {
|
|
103627
103869
|
console.log(source_default.yellow(" No hostd install detected (no compose file at this path)."));
|
|
103628
103870
|
return;
|
|
103629
103871
|
}
|
|
@@ -103647,7 +103889,7 @@ function registerHostdCommand(program3) {
|
|
|
103647
103889
|
hostd.command("uninstall").description("Stop the hostd container. Leaves the compose file in place for re-install.").action(() => doUninstall());
|
|
103648
103890
|
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) => {
|
|
103649
103891
|
const logPath = opts.path ?? defaultAuditLogPath2();
|
|
103650
|
-
if (!
|
|
103892
|
+
if (!existsSync107(logPath)) {
|
|
103651
103893
|
console.error(source_default.yellow(`Audit log not found at ${logPath}.`) + source_default.gray(`
|
|
103652
103894
|
The log is created when hostd handles its first privileged-verb request.`));
|
|
103653
103895
|
return;
|
|
@@ -103696,10 +103938,10 @@ init_source();
|
|
|
103696
103938
|
init_helpers();
|
|
103697
103939
|
init_operator_uid();
|
|
103698
103940
|
init_compose();
|
|
103699
|
-
import { chownSync as chownSync10, existsSync as
|
|
103941
|
+
import { chownSync as chownSync10, existsSync as existsSync108, mkdirSync as mkdirSync63, writeFileSync as writeFileSync46, copyFileSync as copyFileSync15 } from "node:fs";
|
|
103700
103942
|
import { homedir as homedir59 } from "node:os";
|
|
103701
103943
|
import { join as join109 } from "node:path";
|
|
103702
|
-
import { spawnSync as
|
|
103944
|
+
import { spawnSync as spawnSync26 } from "node:child_process";
|
|
103703
103945
|
function resolveWebImageTag(explicitTag, release) {
|
|
103704
103946
|
if (explicitTag)
|
|
103705
103947
|
return explicitTag;
|
|
@@ -103807,7 +104049,7 @@ function webdComposePath() {
|
|
|
103807
104049
|
}
|
|
103808
104050
|
function backupExistingCompose2() {
|
|
103809
104051
|
const p = webdComposePath();
|
|
103810
|
-
if (!
|
|
104052
|
+
if (!existsSync108(p))
|
|
103811
104053
|
return null;
|
|
103812
104054
|
const ts = new Date().toISOString().replace(/[:.]/g, "-");
|
|
103813
104055
|
const bak = `${p}.bak-${ts}`;
|
|
@@ -103815,7 +104057,7 @@ function backupExistingCompose2() {
|
|
|
103815
104057
|
return bak;
|
|
103816
104058
|
}
|
|
103817
104059
|
function runDocker2(args) {
|
|
103818
|
-
const r =
|
|
104060
|
+
const r = spawnSync26("docker", args, { encoding: "utf8" });
|
|
103819
104061
|
return {
|
|
103820
104062
|
ok: r.status === 0,
|
|
103821
104063
|
stdout: r.stdout ?? "",
|
|
@@ -103838,7 +104080,7 @@ async function doInstall2(opts, program3) {
|
|
|
103838
104080
|
}
|
|
103839
104081
|
const dir = webdDir();
|
|
103840
104082
|
const composePath = webdComposePath();
|
|
103841
|
-
|
|
104083
|
+
mkdirSync63(dir, { recursive: true });
|
|
103842
104084
|
const cfg = getConfig(program3);
|
|
103843
104085
|
const imageTag = resolveWebImageTag(opts.tag, cfg.release);
|
|
103844
104086
|
const port = cfg.web_service?.port ?? 8080;
|
|
@@ -103873,7 +104115,7 @@ async function doInstall2(opts, program3) {
|
|
|
103873
104115
|
const bak = backupExistingCompose2();
|
|
103874
104116
|
if (bak)
|
|
103875
104117
|
console.log(source_default.dim(` Backed up existing compose to ${bak}`));
|
|
103876
|
-
|
|
104118
|
+
writeFileSync46(composePath, yaml, "utf8");
|
|
103877
104119
|
try {
|
|
103878
104120
|
if (typeof process.geteuid === "function" && process.geteuid() === 0) {
|
|
103879
104121
|
chownSync10(dir, operatorUid, operatorUid);
|
|
@@ -103915,7 +104157,7 @@ function doStatus2() {
|
|
|
103915
104157
|
const composeYml = webdComposePath();
|
|
103916
104158
|
console.log(source_default.bold("switchroom-web"));
|
|
103917
104159
|
console.log("");
|
|
103918
|
-
if (!
|
|
104160
|
+
if (!existsSync108(composeYml)) {
|
|
103919
104161
|
console.log(source_default.yellow(" compose: not installed"));
|
|
103920
104162
|
console.log(source_default.dim(" run `switchroom webd install` to set up."));
|
|
103921
104163
|
return;
|
|
@@ -103939,7 +104181,7 @@ function doStatus2() {
|
|
|
103939
104181
|
}
|
|
103940
104182
|
function doUninstall2() {
|
|
103941
104183
|
const composeYml = webdComposePath();
|
|
103942
|
-
if (!
|
|
104184
|
+
if (!existsSync108(composeYml)) {
|
|
103943
104185
|
console.log(source_default.yellow(" No web-service install detected (no compose file at this path)."));
|
|
103944
104186
|
return;
|
|
103945
104187
|
}
|
|
@@ -104214,13 +104456,13 @@ init_helpers();
|
|
|
104214
104456
|
init_scan();
|
|
104215
104457
|
|
|
104216
104458
|
// src/fleet-health/gh-sync.ts
|
|
104217
|
-
import { spawnSync as
|
|
104459
|
+
import { spawnSync as spawnSync27 } from "node:child_process";
|
|
104218
104460
|
var LABEL = "fleet-health";
|
|
104219
104461
|
function defaultGhDeps(log) {
|
|
104220
104462
|
return {
|
|
104221
104463
|
log,
|
|
104222
104464
|
run: (args) => {
|
|
104223
|
-
const r =
|
|
104465
|
+
const r = spawnSync27("gh", args, { encoding: "utf-8" });
|
|
104224
104466
|
return {
|
|
104225
104467
|
ok: r.status === 0,
|
|
104226
104468
|
stdout: (r.stdout ?? "").trim(),
|
|
@@ -104425,7 +104667,7 @@ function printDeepDiveBrief(targets) {
|
|
|
104425
104667
|
|
|
104426
104668
|
// src/cli/hindsight-watch.ts
|
|
104427
104669
|
init_source();
|
|
104428
|
-
import { existsSync as
|
|
104670
|
+
import { existsSync as existsSync113, readdirSync as readdirSync45 } from "node:fs";
|
|
104429
104671
|
import { homedir as homedir63 } from "node:os";
|
|
104430
104672
|
import { join as join112, resolve as resolve63 } from "node:path";
|
|
104431
104673
|
|
|
@@ -104495,8 +104737,8 @@ function postOperatorNoticeViaGateways(candidates, text, log, connectTimeoutMs =
|
|
|
104495
104737
|
init_install_cron();
|
|
104496
104738
|
|
|
104497
104739
|
// src/hindsight-watch/probe.ts
|
|
104498
|
-
import { spawnSync as
|
|
104499
|
-
import { readFileSync as
|
|
104740
|
+
import { spawnSync as spawnSync28 } from "node:child_process";
|
|
104741
|
+
import { readFileSync as readFileSync100, readdirSync as readdirSync44, statSync as statSync59 } from "node:fs";
|
|
104500
104742
|
import { homedir as homedir62 } from "node:os";
|
|
104501
104743
|
import { resolve as resolve62 } from "node:path";
|
|
104502
104744
|
|
|
@@ -104624,7 +104866,7 @@ function readLlmSignals(series) {
|
|
|
104624
104866
|
}
|
|
104625
104867
|
|
|
104626
104868
|
// src/hindsight-watch/recall-log.ts
|
|
104627
|
-
import { closeSync as closeSync22, existsSync as
|
|
104869
|
+
import { closeSync as closeSync22, existsSync as existsSync112, openSync as openSync22, readdirSync as readdirSync43, readSync as readSync6, statSync as statSync58 } from "node:fs";
|
|
104628
104870
|
import { join as join111 } from "node:path";
|
|
104629
104871
|
var RECALL_WINDOW_ROWS = 200;
|
|
104630
104872
|
var RECALL_MAX_TAIL_BYTES = 1024 * 1024;
|
|
@@ -104633,7 +104875,7 @@ function recallLogPath2(agentDir) {
|
|
|
104633
104875
|
return join111(agentDir, ".claude", "plugins", "data", "hindsight-memory-inline", "state", "recall_log.jsonl");
|
|
104634
104876
|
}
|
|
104635
104877
|
function readRecallLogTail2(path10, windowRows = RECALL_WINDOW_ROWS) {
|
|
104636
|
-
if (!
|
|
104878
|
+
if (!existsSync112(path10))
|
|
104637
104879
|
return [];
|
|
104638
104880
|
let text;
|
|
104639
104881
|
let truncatedHead = false;
|
|
@@ -104845,7 +105087,7 @@ async function probeMetrics(url = DEFAULT_METRICS_URL, fetchImpl = fetch) {
|
|
|
104845
105087
|
}
|
|
104846
105088
|
}
|
|
104847
105089
|
var defaultRunner4 = (cmd, args) => {
|
|
104848
|
-
const r =
|
|
105090
|
+
const r = spawnSync28(cmd, args, { stdio: "pipe", timeout: 1e4, encoding: "utf8" });
|
|
104849
105091
|
if (r.error)
|
|
104850
105092
|
return { status: null, stdout: "", stderr: r.error.message };
|
|
104851
105093
|
return { status: r.status, stdout: r.stdout ?? "", stderr: r.stderr ?? "" };
|
|
@@ -104873,7 +105115,7 @@ function readDropCount(hindsightDir) {
|
|
|
104873
105115
|
try {
|
|
104874
105116
|
if (statSync59(path10).size > DROPS_LEDGER_MAX_BYTES)
|
|
104875
105117
|
return 0;
|
|
104876
|
-
parsed = JSON.parse(
|
|
105118
|
+
parsed = JSON.parse(readFileSync100(path10, "utf8"));
|
|
104877
105119
|
} catch {
|
|
104878
105120
|
return 0;
|
|
104879
105121
|
}
|
|
@@ -105312,7 +105554,7 @@ function latencySuffix(r) {
|
|
|
105312
105554
|
return "";
|
|
105313
105555
|
const n = typeof r.elapsedConsidered === "number" ? r.elapsedConsidered : 0;
|
|
105314
105556
|
return `
|
|
105315
|
-
recall wall time p95 ${Math.round(p95)}ms over ${n} fire(s) (not thresholded \u2014 the
|
|
105557
|
+
recall wall time p95 ${Math.round(p95)}ms over ${n} fire(s) (not thresholded \u2014 the ${RECALL_WALL_MS}ms recall deadline leaves no healthy band below it)`;
|
|
105316
105558
|
}
|
|
105317
105559
|
function evaluateRecallOwnBankTimeout(ring) {
|
|
105318
105560
|
const signal = "recall-own-bank-timeout";
|
|
@@ -105911,14 +106153,25 @@ function runInstallCron(cronUser) {
|
|
|
105911
106153
|
`);
|
|
105912
106154
|
return 0;
|
|
105913
106155
|
}
|
|
105914
|
-
|
|
106156
|
+
var PREFERRED_RELAY_AGENT = "overlord";
|
|
106157
|
+
function orderRelayCandidates(candidates, preferred = PREFERRED_RELAY_AGENT) {
|
|
106158
|
+
const first = candidates.filter((c) => c.agent === preferred);
|
|
106159
|
+
const rest = candidates.filter((c) => c.agent !== preferred);
|
|
106160
|
+
return [...first, ...rest];
|
|
106161
|
+
}
|
|
106162
|
+
function collectRelayCandidates(agentsDir) {
|
|
105915
106163
|
const candidates = [];
|
|
106164
|
+
for (const name of readdirSync45(agentsDir).sort()) {
|
|
106165
|
+
const sock = resolve63(agentsDir, name, "telegram", "gateway.sock");
|
|
106166
|
+
if (existsSync113(sock))
|
|
106167
|
+
candidates.push({ agent: name, sock });
|
|
106168
|
+
}
|
|
106169
|
+
return orderRelayCandidates(candidates);
|
|
106170
|
+
}
|
|
106171
|
+
async function notifyOperator(agentsDir, text, log) {
|
|
106172
|
+
let candidates = [];
|
|
105916
106173
|
try {
|
|
105917
|
-
|
|
105918
|
-
const sock = resolve63(agentsDir, name, "telegram", "gateway.sock");
|
|
105919
|
-
if (existsSync112(sock))
|
|
105920
|
-
candidates.push({ agent: name, sock });
|
|
105921
|
-
}
|
|
106174
|
+
candidates = collectRelayCandidates(agentsDir);
|
|
105922
106175
|
} catch (e) {
|
|
105923
106176
|
log(`hindsight-watch: agents dir unreadable (${e.message})`);
|
|
105924
106177
|
}
|
|
@@ -105932,13 +106185,13 @@ async function notifyOperator(agentsDir, text, log) {
|
|
|
105932
106185
|
|
|
105933
106186
|
// src/cli/openrouter-watch.ts
|
|
105934
106187
|
init_source();
|
|
105935
|
-
import { existsSync as
|
|
106188
|
+
import { existsSync as existsSync115, readdirSync as readdirSync46 } from "node:fs";
|
|
105936
106189
|
import { homedir as homedir65 } from "node:os";
|
|
105937
106190
|
import { join as join113, resolve as resolve65 } from "node:path";
|
|
105938
106191
|
|
|
105939
106192
|
// src/openrouter/install-cron.ts
|
|
105940
|
-
import { existsSync as
|
|
105941
|
-
import { dirname as
|
|
106193
|
+
import { existsSync as existsSync114, mkdirSync as mkdirSync65, readFileSync as readFileSync101, renameSync as renameSync30, writeFileSync as writeFileSync48 } from "node:fs";
|
|
106194
|
+
import { dirname as dirname44 } from "node:path";
|
|
105942
106195
|
var CRON_PATH2 = "/etc/cron.d/openrouter-watch";
|
|
105943
106196
|
var CRON_SCHEDULE2 = "17 * * * *";
|
|
105944
106197
|
var CRON_LOG_PATH2 = "/var/log/openrouter-watch.log";
|
|
@@ -105955,30 +106208,30 @@ function renderCron2(opts) {
|
|
|
105955
106208
|
function installCron2(opts) {
|
|
105956
106209
|
const path10 = opts.path ?? CRON_PATH2;
|
|
105957
106210
|
const content = renderCron2(opts);
|
|
105958
|
-
if (
|
|
106211
|
+
if (existsSync114(path10)) {
|
|
105959
106212
|
try {
|
|
105960
|
-
if (
|
|
106213
|
+
if (readFileSync101(path10, "utf8") === content) {
|
|
105961
106214
|
return { status: "unchanged", path: path10, content };
|
|
105962
106215
|
}
|
|
105963
106216
|
} catch {}
|
|
105964
106217
|
}
|
|
105965
|
-
|
|
106218
|
+
mkdirSync65(dirname44(path10), { recursive: true });
|
|
105966
106219
|
const tmp = `${path10}.${process.pid}.tmp`;
|
|
105967
|
-
|
|
105968
|
-
|
|
106220
|
+
writeFileSync48(tmp, content, { mode: 420 });
|
|
106221
|
+
renameSync30(tmp, path10);
|
|
105969
106222
|
return { status: "installed", path: path10, content };
|
|
105970
106223
|
}
|
|
105971
106224
|
// src/openrouter/state.ts
|
|
105972
|
-
import { mkdirSync as
|
|
106225
|
+
import { mkdirSync as mkdirSync66, readFileSync as readFileSync102, renameSync as renameSync31, writeFileSync as writeFileSync49 } from "node:fs";
|
|
105973
106226
|
import { homedir as homedir64 } from "node:os";
|
|
105974
|
-
import { dirname as
|
|
106227
|
+
import { dirname as dirname45, resolve as resolve64 } from "node:path";
|
|
105975
106228
|
function defaultStatePath3(home2 = process.env.SWITCHROOM_HOME ?? process.env.HOME ?? homedir64()) {
|
|
105976
106229
|
return resolve64(home2, ".switchroom", "openrouter-watch", "state.json");
|
|
105977
106230
|
}
|
|
105978
106231
|
function loadState2(path10) {
|
|
105979
106232
|
let parsed;
|
|
105980
106233
|
try {
|
|
105981
|
-
parsed = JSON.parse(
|
|
106234
|
+
parsed = JSON.parse(readFileSync102(path10, "utf8"));
|
|
105982
106235
|
} catch {
|
|
105983
106236
|
return {};
|
|
105984
106237
|
}
|
|
@@ -105998,12 +106251,12 @@ function loadState2(path10) {
|
|
|
105998
106251
|
return out;
|
|
105999
106252
|
}
|
|
106000
106253
|
function saveState2(path10, state) {
|
|
106001
|
-
|
|
106254
|
+
mkdirSync66(dirname45(path10), { recursive: true, mode: 448 });
|
|
106002
106255
|
const tmp = `${path10}.${process.pid}.tmp`;
|
|
106003
106256
|
const payload = { v: 1, ...state };
|
|
106004
|
-
|
|
106257
|
+
writeFileSync49(tmp, JSON.stringify(payload, null, 2) + `
|
|
106005
106258
|
`, { mode: 384 });
|
|
106006
|
-
|
|
106259
|
+
renameSync31(tmp, path10);
|
|
106007
106260
|
}
|
|
106008
106261
|
|
|
106009
106262
|
// src/openrouter/watch.ts
|
|
@@ -106188,7 +106441,7 @@ async function notifyOperator2(agentsDir, text, log) {
|
|
|
106188
106441
|
try {
|
|
106189
106442
|
for (const name of readdirSync46(agentsDir).sort()) {
|
|
106190
106443
|
const sock = resolve65(agentsDir, name, "telegram", "gateway.sock");
|
|
106191
|
-
if (
|
|
106444
|
+
if (existsSync115(sock))
|
|
106192
106445
|
candidates.push({ agent: name, sock });
|
|
106193
106446
|
}
|
|
106194
106447
|
} catch (e) {
|