switchroom 0.21.13 → 0.21.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/switchroom.js +663 -263
- package/dist/host-control/main.js +16 -14
- package/dist/vault/broker/server.js +126 -9
- package/package.json +1 -1
- package/profiles/_shared/agent-self-service.md.hbs +32 -86
- package/profiles/_shared/vault-protocol.md.hbs +17 -62
- package/profiles/default/CLAUDE.md.hbs +76 -74
- package/skills/switchroom-runtime/SKILL.md +32 -0
- package/telegram-plugin/dist/gateway/gateway.js +4 -4
- package/vendor/hindsight-memory/scripts/lib/directives.py +18 -0
- package/vendor/hindsight-memory/scripts/recall.py +14 -0
- package/vendor/hindsight-memory/scripts/tests/test_directives.py +46 -0
- package/vendor/hindsight-memory/scripts/tests/test_recall_integration.py +53 -0
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.21.
|
|
2123
|
+
var VERSION = "0.21.14", COMMIT_SHA = "2d43063c", COMMIT_DATE = "2026-08-16T08:34:12Z";
|
|
2124
2124
|
|
|
2125
2125
|
// src/cli/resolve-version.ts
|
|
2126
2126
|
import { existsSync, readFileSync } from "node:fs";
|
|
@@ -16025,6 +16025,23 @@ function loadHostCapabilities() {
|
|
|
16025
16025
|
warnDegradedHostCapabilities(read);
|
|
16026
16026
|
return read.caps;
|
|
16027
16027
|
}
|
|
16028
|
+
function isDefaultedVoiceEngine(r) {
|
|
16029
|
+
return r.reason !== "verdict";
|
|
16030
|
+
}
|
|
16031
|
+
function resolveVoiceEngine() {
|
|
16032
|
+
const read = readHostCapabilities();
|
|
16033
|
+
warnDegradedHostCapabilities(read);
|
|
16034
|
+
if (read.status === "ok" && read.caps) {
|
|
16035
|
+
return {
|
|
16036
|
+
engine: read.caps.voice.engine,
|
|
16037
|
+
reason: "verdict",
|
|
16038
|
+
path: read.path,
|
|
16039
|
+
detail: ""
|
|
16040
|
+
};
|
|
16041
|
+
}
|
|
16042
|
+
const reason = read.status === "absent" ? "no-verdict" : read.status === "unreadable" ? "unreadable" : "malformed";
|
|
16043
|
+
return { engine: "cloud", reason, path: read.path, detail: read.detail };
|
|
16044
|
+
}
|
|
16028
16045
|
var HOST_CAPABILITIES_VERSION = 1, _warnedReads;
|
|
16029
16046
|
var init_host_capabilities = __esm(() => {
|
|
16030
16047
|
init_paths();
|
|
@@ -33772,7 +33789,7 @@ function generateCompose(opts) {
|
|
|
33772
33789
|
const precreateHostDirs = opts.precreateHostDirs ?? (opts.homeDir !== undefined || opts.probeHomeDir !== undefined);
|
|
33773
33790
|
const switchroomConfigPath = resolveConfigMountSource(opts.switchroomConfigPath, homePrefix);
|
|
33774
33791
|
const bundledSkillsPoolDir = opts.bundledSkillsPoolDir ?? getBundledSkillsPoolDir();
|
|
33775
|
-
const voiceEngine = opts.voiceEngine ??
|
|
33792
|
+
const voiceEngine = opts.voiceEngine ?? resolveVoiceEngine().engine;
|
|
33776
33793
|
let resolvedAnalyticsId = null;
|
|
33777
33794
|
if (probeHome !== "") {
|
|
33778
33795
|
const idPath = join18(probeHome, ".switchroom", "analytics-id");
|
|
@@ -34549,11 +34566,118 @@ function restoreOperatorOwnership(home2, operatorUid, deps = {}) {
|
|
|
34549
34566
|
var CONTAINER_OPERATOR_HOME = "/host-home", SWITCHROOM_HOME_MARKER = "switchroom.yaml";
|
|
34550
34567
|
var init_operator_uid = () => {};
|
|
34551
34568
|
|
|
34569
|
+
// src/agents/compose-env.ts
|
|
34570
|
+
import { existsSync as existsSync25 } from "node:fs";
|
|
34571
|
+
import { dirname as dirname10 } from "node:path";
|
|
34572
|
+
function composeEnvPath(composePath) {
|
|
34573
|
+
return dirname10(composePath) + "/.env";
|
|
34574
|
+
}
|
|
34575
|
+
function composeEnvFileArgs(composePath) {
|
|
34576
|
+
const envPath = composeEnvPath(composePath);
|
|
34577
|
+
return existsSync25(envPath) ? ["--env-file", envPath] : [];
|
|
34578
|
+
}
|
|
34579
|
+
var init_compose_env = () => {};
|
|
34580
|
+
|
|
34581
|
+
// src/agents/singleton-reconcile.ts
|
|
34582
|
+
import { execFileSync as execFileSync9 } from "node:child_process";
|
|
34583
|
+
import { readFileSync as readFileSync19 } from "node:fs";
|
|
34584
|
+
function resolveSingletonServices(voiceEngine) {
|
|
34585
|
+
const engine = voiceEngine ?? resolveVoiceEngine().engine;
|
|
34586
|
+
return engine === "local" ? [...CORE_SINGLETON_SERVICES, VOICE_SIDECAR_SERVICE] : [...CORE_SINGLETON_SERVICES];
|
|
34587
|
+
}
|
|
34588
|
+
function singletonContainerName(svc) {
|
|
34589
|
+
return svc.startsWith("switchroom-") ? svc : `switchroom-${svc}`;
|
|
34590
|
+
}
|
|
34591
|
+
function readPinnedSingletonImages(composeText, services = SINGLETON_SERVICES) {
|
|
34592
|
+
let doc;
|
|
34593
|
+
try {
|
|
34594
|
+
doc = import_yaml3.parse(composeText);
|
|
34595
|
+
} catch {
|
|
34596
|
+
return {};
|
|
34597
|
+
}
|
|
34598
|
+
const out = {};
|
|
34599
|
+
for (const svc of services) {
|
|
34600
|
+
const img = doc?.services?.[svc]?.image;
|
|
34601
|
+
if (typeof img === "string" && img.length > 0)
|
|
34602
|
+
out[svc] = img;
|
|
34603
|
+
}
|
|
34604
|
+
return out;
|
|
34605
|
+
}
|
|
34606
|
+
function defaultInspectImage(dockerBin, container) {
|
|
34607
|
+
try {
|
|
34608
|
+
const out = execFileSync9(dockerBin, ["inspect", "-f", "{{.Config.Image}}", container], { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"], timeout: 5000 }).trim();
|
|
34609
|
+
return out.length > 0 ? out : null;
|
|
34610
|
+
} catch {
|
|
34611
|
+
return null;
|
|
34612
|
+
}
|
|
34613
|
+
}
|
|
34614
|
+
function detectSingletonDrift(deps) {
|
|
34615
|
+
const dockerBin = deps.dockerBin ?? "docker";
|
|
34616
|
+
const readCompose = deps.readCompose ?? ((p) => readFileSync19(p, "utf-8"));
|
|
34617
|
+
const inspectImage = deps.inspectImage ?? ((c) => defaultInspectImage(dockerBin, c));
|
|
34618
|
+
const services = resolveSingletonServices(deps.voiceEngine);
|
|
34619
|
+
let pinned = {};
|
|
34620
|
+
try {
|
|
34621
|
+
pinned = readPinnedSingletonImages(readCompose(deps.composeFile), services);
|
|
34622
|
+
} catch {
|
|
34623
|
+
pinned = {};
|
|
34624
|
+
}
|
|
34625
|
+
return services.map((service) => {
|
|
34626
|
+
const container = singletonContainerName(service);
|
|
34627
|
+
const running = inspectImage(container);
|
|
34628
|
+
const pin = pinned[service] ?? null;
|
|
34629
|
+
const needsRecreate = pin !== null && running !== pin;
|
|
34630
|
+
return { service, container, running, pinned: pin, needsRecreate };
|
|
34631
|
+
});
|
|
34632
|
+
}
|
|
34633
|
+
function defaultRecreate(dockerBin, project, composeFile, service) {
|
|
34634
|
+
execFileSync9(dockerBin, ["compose", "-p", project, "-f", composeFile, ...composeEnvFileArgs(composeFile), "up", "-d", "--no-deps", service], { stdio: ["ignore", "pipe", "pipe"], timeout: 120000 });
|
|
34635
|
+
}
|
|
34636
|
+
function reconcileSingletons(deps) {
|
|
34637
|
+
const dockerBin = deps.dockerBin ?? "docker";
|
|
34638
|
+
const project = deps.project ?? "switchroom";
|
|
34639
|
+
const log = deps.log ?? ((m) => process.stderr.write(m + `
|
|
34640
|
+
`));
|
|
34641
|
+
const recreate = deps.recreate ?? ((svc) => defaultRecreate(dockerBin, project, deps.composeFile, svc));
|
|
34642
|
+
const drift = detectSingletonDrift(deps);
|
|
34643
|
+
const recreated = [];
|
|
34644
|
+
const failed = [];
|
|
34645
|
+
for (const d of drift) {
|
|
34646
|
+
if (!d.needsRecreate)
|
|
34647
|
+
continue;
|
|
34648
|
+
log(`singleton-reconcile: ${d.service} drift ${d.running ?? "<absent>"} \u2192 ${d.pinned} \u2014 recreating`);
|
|
34649
|
+
try {
|
|
34650
|
+
recreate(d.service);
|
|
34651
|
+
recreated.push(d.service);
|
|
34652
|
+
} catch (err) {
|
|
34653
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
34654
|
+
log(`singleton-reconcile: ${d.service} recreate FAILED: ${msg}`);
|
|
34655
|
+
failed.push({ service: d.service, error: msg });
|
|
34656
|
+
}
|
|
34657
|
+
}
|
|
34658
|
+
return { drift, recreated, failed };
|
|
34659
|
+
}
|
|
34660
|
+
var import_yaml3, CORE_SINGLETON_SERVICES, VOICE_SIDECAR_SERVICE = "voice-sidecar", SINGLETON_SERVICES;
|
|
34661
|
+
var init_singleton_reconcile = __esm(() => {
|
|
34662
|
+
init_host_capabilities();
|
|
34663
|
+
init_compose_env();
|
|
34664
|
+
import_yaml3 = __toESM(require_dist(), 1);
|
|
34665
|
+
CORE_SINGLETON_SERVICES = [
|
|
34666
|
+
"vault-broker",
|
|
34667
|
+
"approval-kernel",
|
|
34668
|
+
"switchroom-auth-broker"
|
|
34669
|
+
];
|
|
34670
|
+
SINGLETON_SERVICES = [
|
|
34671
|
+
...CORE_SINGLETON_SERVICES,
|
|
34672
|
+
VOICE_SIDECAR_SERVICE
|
|
34673
|
+
];
|
|
34674
|
+
});
|
|
34675
|
+
|
|
34552
34676
|
// src/cli/write-compose.ts
|
|
34553
34677
|
import { chownSync as chownSync3 } from "node:fs";
|
|
34554
34678
|
import { mkdir, readFile, writeFile, rename, copyFile } from "node:fs/promises";
|
|
34555
34679
|
import { homedir as homedir10 } from "node:os";
|
|
34556
|
-
import { basename as basename4, dirname as
|
|
34680
|
+
import { basename as basename4, dirname as dirname11, join as join20 } from "node:path";
|
|
34557
34681
|
function agentHadLiteLLMRouting(composeContent, agentName) {
|
|
34558
34682
|
const lines = composeContent.split(`
|
|
34559
34683
|
`);
|
|
@@ -34665,6 +34789,46 @@ function resolveHostHomeForCompose() {
|
|
|
34665
34789
|
}
|
|
34666
34790
|
return homedir10();
|
|
34667
34791
|
}
|
|
34792
|
+
function parseComposeServiceNames(compose) {
|
|
34793
|
+
const lines = compose.split(`
|
|
34794
|
+
`);
|
|
34795
|
+
const names = [];
|
|
34796
|
+
let inServices = false;
|
|
34797
|
+
for (const line of lines) {
|
|
34798
|
+
if (/^services:\s*$/.test(line)) {
|
|
34799
|
+
inServices = true;
|
|
34800
|
+
continue;
|
|
34801
|
+
}
|
|
34802
|
+
if (inServices && /^\S/.test(line))
|
|
34803
|
+
break;
|
|
34804
|
+
if (!inServices)
|
|
34805
|
+
continue;
|
|
34806
|
+
const m = /^ {2}([A-Za-z0-9_.-]+):\s*$/.exec(line);
|
|
34807
|
+
if (m)
|
|
34808
|
+
names.push(m[1]);
|
|
34809
|
+
}
|
|
34810
|
+
return names;
|
|
34811
|
+
}
|
|
34812
|
+
function voiceSidecarDropMessage(r) {
|
|
34813
|
+
const why = r.reason === "no-verdict" ? `no verdict file at ${r.path}` : `the verdict at ${r.path} is ${r.reason} \u2014 ${r.detail}`;
|
|
34814
|
+
return `voice-sidecar is being REMOVED because ${why}, so the voice engine ` + "defaulted to `cloud`. This host is not known to lack a GPU \u2014 switchroom " + "could not tell. Re-run `switchroom setup` to re-probe before applying, or confirm the removal is intended.";
|
|
34815
|
+
}
|
|
34816
|
+
function detectVoiceSidecarDrop(previous, content, resolution) {
|
|
34817
|
+
if (!isDefaultedVoiceEngine(resolution))
|
|
34818
|
+
return null;
|
|
34819
|
+
if (previous === null)
|
|
34820
|
+
return null;
|
|
34821
|
+
if (!parseComposeServiceNames(previous).includes(VOICE_SIDECAR_SERVICE))
|
|
34822
|
+
return null;
|
|
34823
|
+
if (parseComposeServiceNames(content).includes(VOICE_SIDECAR_SERVICE))
|
|
34824
|
+
return null;
|
|
34825
|
+
return {
|
|
34826
|
+
reason: resolution.reason,
|
|
34827
|
+
path: resolution.path,
|
|
34828
|
+
detail: resolution.detail,
|
|
34829
|
+
message: voiceSidecarDropMessage(resolution)
|
|
34830
|
+
};
|
|
34831
|
+
}
|
|
34668
34832
|
async function computeComposeContent(opts) {
|
|
34669
34833
|
const release = resolveRelease({ override: opts.releaseOverride, root: opts.config.release });
|
|
34670
34834
|
const imageTag = resolveImageTag(release);
|
|
@@ -34677,10 +34841,12 @@ async function computeComposeContent(opts) {
|
|
|
34677
34841
|
previous = null;
|
|
34678
34842
|
}
|
|
34679
34843
|
const litellmConfirmedAgents = await resolveLiteLLMConfirmedAgents(opts.config, previous);
|
|
34844
|
+
const voiceResolution = resolveVoiceEngine();
|
|
34680
34845
|
const content = generateCompose({
|
|
34681
34846
|
config: opts.config,
|
|
34682
34847
|
imageTag,
|
|
34683
34848
|
litellmConfirmedAgents,
|
|
34849
|
+
voiceEngine: voiceResolution.engine,
|
|
34684
34850
|
buildMode: opts.buildMode ?? "pull",
|
|
34685
34851
|
buildContext: opts.buildContext,
|
|
34686
34852
|
homeDir: resolveHostHomeForCompose(),
|
|
@@ -34690,7 +34856,13 @@ async function computeComposeContent(opts) {
|
|
|
34690
34856
|
dockerSocketPath: resolveDockerSocketPath()
|
|
34691
34857
|
});
|
|
34692
34858
|
const previousImageTag = previous ? AGENT_IMAGE_TAG_RE.exec(previous)?.[1] ?? null : null;
|
|
34693
|
-
|
|
34859
|
+
const voiceSidecarDrop = detectVoiceSidecarDrop(previous, content, voiceResolution);
|
|
34860
|
+
if (voiceSidecarDrop && !_warnedVoiceDrop) {
|
|
34861
|
+
_warnedVoiceDrop = true;
|
|
34862
|
+
process.stderr.write(`[switchroom] WARNING: ${voiceSidecarDrop.message}
|
|
34863
|
+
`);
|
|
34864
|
+
}
|
|
34865
|
+
return { content, imageTag, previous, previousImageTag, voiceSidecarDrop };
|
|
34694
34866
|
}
|
|
34695
34867
|
function composeBackupPath(composePath) {
|
|
34696
34868
|
return composePath + BACKUP_SUFFIX;
|
|
@@ -34721,7 +34893,7 @@ function shouldBackupCompose(previous, next, existingBackupTag) {
|
|
|
34721
34893
|
async function writeComposeFile(opts) {
|
|
34722
34894
|
const { content, imageTag, previous, previousImageTag } = await computeComposeContent(opts);
|
|
34723
34895
|
const operatorUid = resolveOperatorUid();
|
|
34724
|
-
await mkdir(
|
|
34896
|
+
await mkdir(dirname11(opts.composePath), { recursive: true });
|
|
34725
34897
|
if (shouldBackupCompose(previous, content, await readBackupImageTag(opts.composePath))) {
|
|
34726
34898
|
try {
|
|
34727
34899
|
await copyFile(opts.composePath, composeBackupPath(opts.composePath));
|
|
@@ -34743,18 +34915,20 @@ async function writeComposeFile(opts) {
|
|
|
34743
34915
|
previousImageTag
|
|
34744
34916
|
};
|
|
34745
34917
|
}
|
|
34746
|
-
var AGENT_IMAGE_TAG_RE, CONTAINER_CONFIG_PREFIX = "/state/config/", BACKUP_SUFFIX = ".bak";
|
|
34918
|
+
var AGENT_IMAGE_TAG_RE, CONTAINER_CONFIG_PREFIX = "/state/config/", _warnedVoiceDrop = false, BACKUP_SUFFIX = ".bak";
|
|
34747
34919
|
var init_write_compose = __esm(() => {
|
|
34748
34920
|
init_compose();
|
|
34749
34921
|
init_docker_socket();
|
|
34750
34922
|
init_agent_config();
|
|
34751
34923
|
init_operator_uid();
|
|
34752
34924
|
init_merge();
|
|
34925
|
+
init_singleton_reconcile();
|
|
34926
|
+
init_host_capabilities();
|
|
34753
34927
|
AGENT_IMAGE_TAG_RE = /image:\s*\S*switchroom-agent:(\S+)/;
|
|
34754
34928
|
});
|
|
34755
34929
|
|
|
34756
34930
|
// src/agents/tmux.ts
|
|
34757
|
-
import { execFileSync as
|
|
34931
|
+
import { execFileSync as execFileSync10 } from "node:child_process";
|
|
34758
34932
|
function sendAgentInterrupt(opts) {
|
|
34759
34933
|
const { agentName } = opts;
|
|
34760
34934
|
const attempts = typeof opts.attempts === "number" && opts.attempts > 0 ? opts.attempts : 1;
|
|
@@ -34764,7 +34938,7 @@ function sendAgentInterrupt(opts) {
|
|
|
34764
34938
|
let lastError = null;
|
|
34765
34939
|
for (let i = 0;i < attempts; i++) {
|
|
34766
34940
|
try {
|
|
34767
|
-
|
|
34941
|
+
execFileSync10("tmux", args, {
|
|
34768
34942
|
timeout: 3000,
|
|
34769
34943
|
stdio: ["ignore", "pipe", "pipe"]
|
|
34770
34944
|
});
|
|
@@ -34789,23 +34963,11 @@ var init_tmux = __esm(() => {
|
|
|
34789
34963
|
MAX_BYTES = 10 * 1024 * 1024;
|
|
34790
34964
|
});
|
|
34791
34965
|
|
|
34792
|
-
// src/agents/compose-env.ts
|
|
34793
|
-
import { existsSync as existsSync25 } from "node:fs";
|
|
34794
|
-
import { dirname as dirname11 } from "node:path";
|
|
34795
|
-
function composeEnvPath(composePath) {
|
|
34796
|
-
return dirname11(composePath) + "/.env";
|
|
34797
|
-
}
|
|
34798
|
-
function composeEnvFileArgs(composePath) {
|
|
34799
|
-
const envPath = composeEnvPath(composePath);
|
|
34800
|
-
return existsSync25(envPath) ? ["--env-file", envPath] : [];
|
|
34801
|
-
}
|
|
34802
|
-
var init_compose_env = () => {};
|
|
34803
|
-
|
|
34804
34966
|
// src/agents/docker-fleet.ts
|
|
34805
34967
|
import { resolve as resolve17 } from "node:path";
|
|
34806
34968
|
import { mkdirSync as mkdirSync17, writeFileSync as writeFileSync8 } from "node:fs";
|
|
34807
34969
|
import { homedir as homedir11 } from "node:os";
|
|
34808
|
-
import { execFileSync as
|
|
34970
|
+
import { execFileSync as execFileSync11 } from "node:child_process";
|
|
34809
34971
|
function resolveSwitchroomHome(explicit) {
|
|
34810
34972
|
if (explicit && explicit.length > 0)
|
|
34811
34973
|
return explicit;
|
|
@@ -34837,7 +34999,7 @@ function bringUpAgentService(opts) {
|
|
|
34837
34999
|
const dockerBin = opts.dockerBin ?? "docker";
|
|
34838
35000
|
const stdio = opts.stdio ?? "inherit";
|
|
34839
35001
|
for (const svc of ["vault-broker", "approval-kernel", "switchroom-auth-broker"]) {
|
|
34840
|
-
|
|
35002
|
+
execFileSync11(dockerBin, [
|
|
34841
35003
|
"compose",
|
|
34842
35004
|
"-f",
|
|
34843
35005
|
composePath,
|
|
@@ -34849,7 +35011,7 @@ function bringUpAgentService(opts) {
|
|
|
34849
35011
|
svc
|
|
34850
35012
|
], { stdio });
|
|
34851
35013
|
}
|
|
34852
|
-
|
|
35014
|
+
execFileSync11(dockerBin, [
|
|
34853
35015
|
"compose",
|
|
34854
35016
|
"-f",
|
|
34855
35017
|
composePath,
|
|
@@ -34868,101 +35030,6 @@ var init_docker_fleet = __esm(() => {
|
|
|
34868
35030
|
init_loader();
|
|
34869
35031
|
});
|
|
34870
35032
|
|
|
34871
|
-
// src/agents/singleton-reconcile.ts
|
|
34872
|
-
import { execFileSync as execFileSync11 } from "node:child_process";
|
|
34873
|
-
import { readFileSync as readFileSync19 } from "node:fs";
|
|
34874
|
-
function resolveSingletonServices(voiceEngine) {
|
|
34875
|
-
const engine = voiceEngine ?? loadHostCapabilities()?.voice.engine ?? "cloud";
|
|
34876
|
-
return engine === "local" ? [...CORE_SINGLETON_SERVICES, VOICE_SIDECAR_SERVICE] : [...CORE_SINGLETON_SERVICES];
|
|
34877
|
-
}
|
|
34878
|
-
function singletonContainerName(svc) {
|
|
34879
|
-
return svc.startsWith("switchroom-") ? svc : `switchroom-${svc}`;
|
|
34880
|
-
}
|
|
34881
|
-
function readPinnedSingletonImages(composeText, services = SINGLETON_SERVICES) {
|
|
34882
|
-
let doc;
|
|
34883
|
-
try {
|
|
34884
|
-
doc = import_yaml3.parse(composeText);
|
|
34885
|
-
} catch {
|
|
34886
|
-
return {};
|
|
34887
|
-
}
|
|
34888
|
-
const out = {};
|
|
34889
|
-
for (const svc of services) {
|
|
34890
|
-
const img = doc?.services?.[svc]?.image;
|
|
34891
|
-
if (typeof img === "string" && img.length > 0)
|
|
34892
|
-
out[svc] = img;
|
|
34893
|
-
}
|
|
34894
|
-
return out;
|
|
34895
|
-
}
|
|
34896
|
-
function defaultInspectImage(dockerBin, container) {
|
|
34897
|
-
try {
|
|
34898
|
-
const out = execFileSync11(dockerBin, ["inspect", "-f", "{{.Config.Image}}", container], { encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"], timeout: 5000 }).trim();
|
|
34899
|
-
return out.length > 0 ? out : null;
|
|
34900
|
-
} catch {
|
|
34901
|
-
return null;
|
|
34902
|
-
}
|
|
34903
|
-
}
|
|
34904
|
-
function detectSingletonDrift(deps) {
|
|
34905
|
-
const dockerBin = deps.dockerBin ?? "docker";
|
|
34906
|
-
const readCompose = deps.readCompose ?? ((p) => readFileSync19(p, "utf-8"));
|
|
34907
|
-
const inspectImage = deps.inspectImage ?? ((c) => defaultInspectImage(dockerBin, c));
|
|
34908
|
-
const services = resolveSingletonServices(deps.voiceEngine);
|
|
34909
|
-
let pinned = {};
|
|
34910
|
-
try {
|
|
34911
|
-
pinned = readPinnedSingletonImages(readCompose(deps.composeFile), services);
|
|
34912
|
-
} catch {
|
|
34913
|
-
pinned = {};
|
|
34914
|
-
}
|
|
34915
|
-
return services.map((service) => {
|
|
34916
|
-
const container = singletonContainerName(service);
|
|
34917
|
-
const running = inspectImage(container);
|
|
34918
|
-
const pin = pinned[service] ?? null;
|
|
34919
|
-
const needsRecreate = pin !== null && running !== pin;
|
|
34920
|
-
return { service, container, running, pinned: pin, needsRecreate };
|
|
34921
|
-
});
|
|
34922
|
-
}
|
|
34923
|
-
function defaultRecreate(dockerBin, project, composeFile, service) {
|
|
34924
|
-
execFileSync11(dockerBin, ["compose", "-p", project, "-f", composeFile, ...composeEnvFileArgs(composeFile), "up", "-d", "--no-deps", service], { stdio: ["ignore", "pipe", "pipe"], timeout: 120000 });
|
|
34925
|
-
}
|
|
34926
|
-
function reconcileSingletons(deps) {
|
|
34927
|
-
const dockerBin = deps.dockerBin ?? "docker";
|
|
34928
|
-
const project = deps.project ?? "switchroom";
|
|
34929
|
-
const log = deps.log ?? ((m) => process.stderr.write(m + `
|
|
34930
|
-
`));
|
|
34931
|
-
const recreate = deps.recreate ?? ((svc) => defaultRecreate(dockerBin, project, deps.composeFile, svc));
|
|
34932
|
-
const drift = detectSingletonDrift(deps);
|
|
34933
|
-
const recreated = [];
|
|
34934
|
-
const failed = [];
|
|
34935
|
-
for (const d of drift) {
|
|
34936
|
-
if (!d.needsRecreate)
|
|
34937
|
-
continue;
|
|
34938
|
-
log(`singleton-reconcile: ${d.service} drift ${d.running ?? "<absent>"} \u2192 ${d.pinned} \u2014 recreating`);
|
|
34939
|
-
try {
|
|
34940
|
-
recreate(d.service);
|
|
34941
|
-
recreated.push(d.service);
|
|
34942
|
-
} catch (err) {
|
|
34943
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
34944
|
-
log(`singleton-reconcile: ${d.service} recreate FAILED: ${msg}`);
|
|
34945
|
-
failed.push({ service: d.service, error: msg });
|
|
34946
|
-
}
|
|
34947
|
-
}
|
|
34948
|
-
return { drift, recreated, failed };
|
|
34949
|
-
}
|
|
34950
|
-
var import_yaml3, CORE_SINGLETON_SERVICES, VOICE_SIDECAR_SERVICE = "voice-sidecar", SINGLETON_SERVICES;
|
|
34951
|
-
var init_singleton_reconcile = __esm(() => {
|
|
34952
|
-
init_host_capabilities();
|
|
34953
|
-
init_compose_env();
|
|
34954
|
-
import_yaml3 = __toESM(require_dist(), 1);
|
|
34955
|
-
CORE_SINGLETON_SERVICES = [
|
|
34956
|
-
"vault-broker",
|
|
34957
|
-
"approval-kernel",
|
|
34958
|
-
"switchroom-auth-broker"
|
|
34959
|
-
];
|
|
34960
|
-
SINGLETON_SERVICES = [
|
|
34961
|
-
...CORE_SINGLETON_SERVICES,
|
|
34962
|
-
VOICE_SIDECAR_SERVICE
|
|
34963
|
-
];
|
|
34964
|
-
});
|
|
34965
|
-
|
|
34966
35033
|
// src/agents/lifecycle.ts
|
|
34967
35034
|
import { execFileSync as execFileSync12, spawn, spawnSync as spawnSync2 } from "node:child_process";
|
|
34968
35035
|
import { existsSync as existsSync26, mkdirSync as mkdirSync18, writeFileSync as writeFileSync9, renameSync as renameSync7, readFileSync as readFileSync20 } from "node:fs";
|
|
@@ -48724,8 +48791,213 @@ var init_doctor_memory = __esm(() => {
|
|
|
48724
48791
|
MIN_HINDSIGHT_SHM_BYTES = 1024 * 1024 * 1024;
|
|
48725
48792
|
});
|
|
48726
48793
|
|
|
48794
|
+
// src/memory/hindsight-shim-contract.ts
|
|
48795
|
+
function openApiHasRoute(spec, route) {
|
|
48796
|
+
const methods = spec.paths?.[route.path];
|
|
48797
|
+
if (!methods || typeof methods !== "object")
|
|
48798
|
+
return false;
|
|
48799
|
+
return Object.prototype.hasOwnProperty.call(methods, route.method.toLowerCase());
|
|
48800
|
+
}
|
|
48801
|
+
function missingRoutesForTool(spec, toolName) {
|
|
48802
|
+
const required = SYNTHESIZED_TOOL_ROUTES[toolName];
|
|
48803
|
+
if (!required)
|
|
48804
|
+
return [];
|
|
48805
|
+
return required.filter((r) => !openApiHasRoute(spec, r));
|
|
48806
|
+
}
|
|
48807
|
+
async function fetchHindsightOpenApi(apiBaseUrl, opts = {}) {
|
|
48808
|
+
const doFetch = opts.fetchImpl ?? fetch;
|
|
48809
|
+
const base = apiBaseUrl.replace(/\/+$/, "");
|
|
48810
|
+
const controller = new AbortController;
|
|
48811
|
+
const timer = setTimeout(() => controller.abort(), opts.timeoutMs ?? OPENAPI_FETCH_TIMEOUT_MS);
|
|
48812
|
+
try {
|
|
48813
|
+
const res = await doFetch(`${base}/openapi.json`, { signal: controller.signal });
|
|
48814
|
+
if (!res.ok)
|
|
48815
|
+
return null;
|
|
48816
|
+
const body = await res.json();
|
|
48817
|
+
if (!body || typeof body !== "object" || typeof body.paths !== "object") {
|
|
48818
|
+
return null;
|
|
48819
|
+
}
|
|
48820
|
+
return body;
|
|
48821
|
+
} catch {
|
|
48822
|
+
return null;
|
|
48823
|
+
} finally {
|
|
48824
|
+
clearTimeout(timer);
|
|
48825
|
+
}
|
|
48826
|
+
}
|
|
48827
|
+
|
|
48828
|
+
class ShimContractPin {
|
|
48829
|
+
apiBaseUrl;
|
|
48830
|
+
opts;
|
|
48831
|
+
cached = null;
|
|
48832
|
+
cachedAt = null;
|
|
48833
|
+
failedAt = null;
|
|
48834
|
+
constructor(apiBaseUrl, opts = {}) {
|
|
48835
|
+
this.apiBaseUrl = apiBaseUrl;
|
|
48836
|
+
this.opts = opts;
|
|
48837
|
+
}
|
|
48838
|
+
now() {
|
|
48839
|
+
return this.opts.now ? this.opts.now() : Date.now();
|
|
48840
|
+
}
|
|
48841
|
+
async spec() {
|
|
48842
|
+
const positiveCacheMs = this.opts.positiveCacheMs ?? 0;
|
|
48843
|
+
if (this.cached) {
|
|
48844
|
+
const stale = positiveCacheMs > 0 && this.cachedAt !== null && this.now() - this.cachedAt >= positiveCacheMs;
|
|
48845
|
+
if (!stale)
|
|
48846
|
+
return this.cached;
|
|
48847
|
+
this.cached = null;
|
|
48848
|
+
this.cachedAt = null;
|
|
48849
|
+
}
|
|
48850
|
+
const negativeCacheMs = this.opts.negativeCacheMs ?? 0;
|
|
48851
|
+
if (negativeCacheMs > 0 && this.failedAt !== null && this.now() - this.failedAt < negativeCacheMs) {
|
|
48852
|
+
return null;
|
|
48853
|
+
}
|
|
48854
|
+
const fetched = await fetchHindsightOpenApi(this.apiBaseUrl, this.opts);
|
|
48855
|
+
if (fetched) {
|
|
48856
|
+
this.cached = fetched;
|
|
48857
|
+
this.cachedAt = this.now();
|
|
48858
|
+
this.failedAt = null;
|
|
48859
|
+
} else if (negativeCacheMs > 0) {
|
|
48860
|
+
this.failedAt = this.now();
|
|
48861
|
+
}
|
|
48862
|
+
return fetched;
|
|
48863
|
+
}
|
|
48864
|
+
async preflight(toolName) {
|
|
48865
|
+
const spec = await this.spec();
|
|
48866
|
+
if (!spec)
|
|
48867
|
+
return { ok: true };
|
|
48868
|
+
const missing = missingRoutesForTool(spec, toolName);
|
|
48869
|
+
if (missing.length === 0)
|
|
48870
|
+
return { ok: true };
|
|
48871
|
+
const engineVersion = spec.info?.version ?? "unknown";
|
|
48872
|
+
const routeList = missing.map((r) => `${r.method.toUpperCase()} ${r.path}`).join(", ");
|
|
48873
|
+
return {
|
|
48874
|
+
ok: false,
|
|
48875
|
+
text: `${toolName} is unavailable: the live Hindsight engine (api_version ` + `${engineVersion}) no longer exposes the REST route(s) this tool is ` + `synthesized over: ${routeList}. This is not a silent empty result \u2014 ` + `the shim confirmed the route is gone and is refusing the call rather ` + `than guessing. If the engine renamed/moved the route, this tool's ` + `implementation needs updating; if the engine now ships this ` + `capability as a real MCP tool, the synthesis should be retired (see ` + `the retirement seam in withSynthesizedTools, hindsight-mcp-shim.ts). ` + `\`switchroom doctor\`'s hindsight shim contract rows carry the same ` + `finding fleet-wide.`
|
|
48876
|
+
};
|
|
48877
|
+
}
|
|
48878
|
+
}
|
|
48879
|
+
var OPENAPI_FETCH_TIMEOUT_MS = 3000, SYNTHESIZED_TOOL_ROUTES, SYNTHESIZED_ROUTE_TOOL_NAMES;
|
|
48880
|
+
var init_hindsight_shim_contract = __esm(() => {
|
|
48881
|
+
SYNTHESIZED_TOOL_ROUTES = {
|
|
48882
|
+
deactivate_directive: [
|
|
48883
|
+
{ path: "/v1/default/banks/{bank_id}/directives", method: "get" },
|
|
48884
|
+
{
|
|
48885
|
+
path: "/v1/default/banks/{bank_id}/directives/{directive_id}",
|
|
48886
|
+
method: "patch"
|
|
48887
|
+
}
|
|
48888
|
+
],
|
|
48889
|
+
reactivate_directive: [
|
|
48890
|
+
{ path: "/v1/default/banks/{bank_id}/directives", method: "get" },
|
|
48891
|
+
{
|
|
48892
|
+
path: "/v1/default/banks/{bank_id}/directives/{directive_id}",
|
|
48893
|
+
method: "patch"
|
|
48894
|
+
}
|
|
48895
|
+
],
|
|
48896
|
+
search_knowledge_pages: [
|
|
48897
|
+
{
|
|
48898
|
+
path: "/v1/default/banks/{bank_id}/knowledge-base/search",
|
|
48899
|
+
method: "get"
|
|
48900
|
+
}
|
|
48901
|
+
],
|
|
48902
|
+
get_knowledge_page: [
|
|
48903
|
+
{
|
|
48904
|
+
path: "/v1/default/banks/{bank_id}/knowledge-base/pages/{page_id}",
|
|
48905
|
+
method: "get"
|
|
48906
|
+
}
|
|
48907
|
+
],
|
|
48908
|
+
get_knowledge_tree: [
|
|
48909
|
+
{
|
|
48910
|
+
path: "/v1/default/banks/{bank_id}/knowledge-base/tree",
|
|
48911
|
+
method: "get"
|
|
48912
|
+
}
|
|
48913
|
+
]
|
|
48914
|
+
};
|
|
48915
|
+
SYNTHESIZED_ROUTE_TOOL_NAMES = Object.keys(SYNTHESIZED_TOOL_ROUTES);
|
|
48916
|
+
});
|
|
48917
|
+
|
|
48918
|
+
// src/cli/doctor-hindsight-shim-contract.ts
|
|
48919
|
+
function classifySynthesizedToolRoute(spec, toolName) {
|
|
48920
|
+
const missing = missingRoutesForTool(spec, toolName);
|
|
48921
|
+
if (missing.length === 0)
|
|
48922
|
+
return null;
|
|
48923
|
+
const routeList = missing.map((r) => `${r.method.toUpperCase()} ${r.path}`).join(", ");
|
|
48924
|
+
return {
|
|
48925
|
+
name: `${SHIM_CONTRACT_CHECK_PREFIX}: ${toolName}`,
|
|
48926
|
+
status: "fail",
|
|
48927
|
+
detail: `the live engine's /openapi.json no longer declares [${routeList}] \u2014 ` + `the REST route(s) '${toolName}' is synthesized over. Every call to ` + `this tool will now be loud-rejected by the shim's contract preflight ` + `(ShimContractPin.preflight in hindsight-mcp-shim.ts) rather than ` + `silently returning nothing, but the tool is effectively dead until ` + `this is fixed.`,
|
|
48928
|
+
fix: "If the engine renamed/moved the route, update SYNTHESIZED_TOOL_ROUTES " + "(src/memory/hindsight-shim-contract.ts) and the corresponding " + "DirectiveAdmin/KnowledgeAdmin call to match. If the engine now " + "registers this capability as a real MCP tool, retire the synthesis " + "instead \u2014 see the retirement seam in withSynthesizedTools " + "(src/cli/hindsight-mcp-shim.ts)."
|
|
48929
|
+
};
|
|
48930
|
+
}
|
|
48931
|
+
function classifyShimContractVersion(spec) {
|
|
48932
|
+
const name = `${SHIM_CONTRACT_CHECK_PREFIX}: version`;
|
|
48933
|
+
const live = spec.info?.version;
|
|
48934
|
+
if (typeof live !== "string" || live.length === 0) {
|
|
48935
|
+
return {
|
|
48936
|
+
name,
|
|
48937
|
+
status: "warn",
|
|
48938
|
+
detail: "/openapi.json has no info.version \u2014 cannot confirm the shim's " + "REST route contract is pinned to a known engine version."
|
|
48939
|
+
};
|
|
48940
|
+
}
|
|
48941
|
+
const cmp = compareApiVersion(live, HINDSIGHT_MIN_API_VERSION);
|
|
48942
|
+
if (cmp === 0) {
|
|
48943
|
+
return {
|
|
48944
|
+
name,
|
|
48945
|
+
status: "ok",
|
|
48946
|
+
detail: `/openapi.json info.version ${live} matches the pinned ${HINDSIGHT_MIN_API_VERSION}`
|
|
48947
|
+
};
|
|
48948
|
+
}
|
|
48949
|
+
if (cmp < 0) {
|
|
48950
|
+
return {
|
|
48951
|
+
name,
|
|
48952
|
+
status: "fail",
|
|
48953
|
+
detail: `/openapi.json info.version ${live} is OLDER than the pinned ` + `${HINDSIGHT_MIN_API_VERSION} \u2014 the REST route contract the five ` + `synthesized tools depend on may not exist on this server.`,
|
|
48954
|
+
fix: "Same remediation as the `hindsight version` check: update the " + "pinned image, or deliberately re-pin HINDSIGHT_MIN_API_VERSION to " + "this older version."
|
|
48955
|
+
};
|
|
48956
|
+
}
|
|
48957
|
+
return {
|
|
48958
|
+
name,
|
|
48959
|
+
status: "warn",
|
|
48960
|
+
detail: `/openapi.json info.version ${live} is NEWER than the pinned ` + `${HINDSIGHT_MIN_API_VERSION} \u2014 the engine may have grown a native ` + `MCP tool that makes one of the five synthesized tools obsolete; ` + `re-check the retirement seam (withSynthesizedTools, ` + `hindsight-mcp-shim.ts).`
|
|
48961
|
+
};
|
|
48962
|
+
}
|
|
48963
|
+
function classifyHindsightShimContract(spec) {
|
|
48964
|
+
const results = [classifyShimContractVersion(spec)];
|
|
48965
|
+
const routeRows = SYNTHESIZED_ROUTE_TOOL_NAMES.map((tool) => classifySynthesizedToolRoute(spec, tool)).filter((r) => r !== null);
|
|
48966
|
+
if (routeRows.length === 0) {
|
|
48967
|
+
results.push({
|
|
48968
|
+
name: `${SHIM_CONTRACT_CHECK_PREFIX}: routes`,
|
|
48969
|
+
status: "ok",
|
|
48970
|
+
detail: `all ${SYNTHESIZED_ROUTE_TOOL_NAMES.length} synthesized tools' REST routes are present in /openapi.json`
|
|
48971
|
+
});
|
|
48972
|
+
} else {
|
|
48973
|
+
results.push(...routeRows);
|
|
48974
|
+
}
|
|
48975
|
+
return results;
|
|
48976
|
+
}
|
|
48977
|
+
async function runHindsightShimContractCheck(mcpUrl, opts = {}) {
|
|
48978
|
+
const origin = mcpUrl.replace(/\/mcp\/?$/, "").replace(/\/$/, "");
|
|
48979
|
+
const spec = await fetchHindsightOpenApi(origin, opts);
|
|
48980
|
+
if (!spec) {
|
|
48981
|
+
return [
|
|
48982
|
+
{
|
|
48983
|
+
name: `${SHIM_CONTRACT_CHECK_PREFIX}: routes`,
|
|
48984
|
+
status: "warn",
|
|
48985
|
+
detail: `the engine is reachable but /openapi.json did not return a usable ` + `spec \u2014 the shim contract guard is INACTIVE: neither this doctor ` + `check nor ShimContractPin's loud call-time preflight (` + `hindsight-mcp-shim.ts) can detect a route rename/removal under the ` + `five synthesized tools (deactivate_directive, reactivate_directive, ` + `search_knowledge_pages, get_knowledge_page, get_knowledge_tree) ` + `right now. Calls degrade to "unknown, proceed" and a route drop ` + `would surface as a bare failed REST call instead of a named refusal.`,
|
|
48986
|
+
fix: "Confirm /openapi.json is served at the engine's origin (FastAPI " + "serves it by default; check for `docs_url`/`openapi_url` disabled " + "in the engine's startup config, or a reverse proxy stripping the " + "route). If OpenAPI docs are deliberately disabled in production, " + "this warning is expected and the route contract is unverifiable " + "by design \u2014 the REST layer's own error handling remains the " + "backstop for the five synthesized tools."
|
|
48987
|
+
}
|
|
48988
|
+
];
|
|
48989
|
+
}
|
|
48990
|
+
return classifyHindsightShimContract(spec);
|
|
48991
|
+
}
|
|
48992
|
+
var SHIM_CONTRACT_CHECK_PREFIX = "hindsight shim contract";
|
|
48993
|
+
var init_doctor_hindsight_shim_contract = __esm(() => {
|
|
48994
|
+
init_hindsight_repair();
|
|
48995
|
+
init_hindsight_shim_contract();
|
|
48996
|
+
init_hindsight_tools();
|
|
48997
|
+
});
|
|
48998
|
+
|
|
48727
48999
|
// src/cli/doctor-recall-health.ts
|
|
48728
|
-
import { closeSync as closeSync13, existsSync as existsSync60, openSync as openSync13, readSync as readSync3, statSync as
|
|
49000
|
+
import { closeSync as closeSync13, existsSync as existsSync60, openSync as openSync13, readSync as readSync3, statSync as statSync33 } from "node:fs";
|
|
48729
49001
|
import { join as join54 } from "node:path";
|
|
48730
49002
|
function filterRecentRecallRows(rows, maxAgeMs = RECALL_HEALTH_WINDOW_MAX_AGE_MS, now = Date.now()) {
|
|
48731
49003
|
if (!Number.isFinite(maxAgeMs) || maxAgeMs <= 0)
|
|
@@ -48821,7 +49093,7 @@ function readRecallLogTail(path7, windowRows = RECALL_HEALTH_WINDOW_ROWS) {
|
|
|
48821
49093
|
let truncatedHead = false;
|
|
48822
49094
|
let fd;
|
|
48823
49095
|
try {
|
|
48824
|
-
const size =
|
|
49096
|
+
const size = statSync33(path7).size;
|
|
48825
49097
|
const start = Math.max(0, size - RECALL_HEALTH_MAX_TAIL_BYTES);
|
|
48826
49098
|
truncatedHead = start > 0;
|
|
48827
49099
|
const length = size - start;
|
|
@@ -49253,7 +49525,7 @@ var init_doctor_observation_scopes = __esm(() => {
|
|
|
49253
49525
|
|
|
49254
49526
|
// src/hindsight-watch/install-cron.ts
|
|
49255
49527
|
import { execFileSync as execFileSync21 } from "node:child_process";
|
|
49256
|
-
import { chownSync as chownSync8, existsSync as existsSync61, mkdirSync as mkdirSync37, readFileSync as readFileSync51, renameSync as renameSync17, statSync as
|
|
49528
|
+
import { chownSync as chownSync8, existsSync as existsSync61, mkdirSync as mkdirSync37, readFileSync as readFileSync51, renameSync as renameSync17, statSync as statSync34, writeFileSync as writeFileSync24 } from "node:fs";
|
|
49257
49529
|
import { dirname as dirname24 } from "node:path";
|
|
49258
49530
|
function renderCron(opts) {
|
|
49259
49531
|
return `# switchroom hindsight-watch \u2014 model-free memory watchdog.
|
|
@@ -49290,7 +49562,7 @@ function ensureLogFile(opts) {
|
|
|
49290
49562
|
const isRoot = process.getuid?.() === 0;
|
|
49291
49563
|
let alreadyOwned = false;
|
|
49292
49564
|
try {
|
|
49293
|
-
const st =
|
|
49565
|
+
const st = statSync34(path7);
|
|
49294
49566
|
alreadyOwned = st.uid === uid && st.gid === gid;
|
|
49295
49567
|
} catch {}
|
|
49296
49568
|
if (isRoot && !alreadyOwned) {
|
|
@@ -49554,7 +49826,7 @@ var init_state2 = __esm(() => {
|
|
|
49554
49826
|
});
|
|
49555
49827
|
|
|
49556
49828
|
// src/cli/doctor-hindsight-watch.ts
|
|
49557
|
-
import { existsSync as existsSync62, statSync as
|
|
49829
|
+
import { existsSync as existsSync62, statSync as statSync35 } from "node:fs";
|
|
49558
49830
|
function classifyWatchArmed(cronPresent, stateMtimeMs, now) {
|
|
49559
49831
|
const name = "hindsight-watch armed";
|
|
49560
49832
|
if (stateMtimeMs === null) {
|
|
@@ -49592,7 +49864,7 @@ function classifyWatchArmed(cronPresent, stateMtimeMs, now) {
|
|
|
49592
49864
|
function checkHindsightWatchArmed(now = Date.now(), cronPath = CRON_PATH, statePath = defaultStatePath2()) {
|
|
49593
49865
|
let mtime = null;
|
|
49594
49866
|
try {
|
|
49595
|
-
mtime =
|
|
49867
|
+
mtime = statSync35(statePath).mtimeMs;
|
|
49596
49868
|
} catch {}
|
|
49597
49869
|
return classifyWatchArmed(existsSync62(cronPath), mtime, now);
|
|
49598
49870
|
}
|
|
@@ -50520,7 +50792,7 @@ import {
|
|
|
50520
50792
|
readdirSync as readdirSync24,
|
|
50521
50793
|
readFileSync as readFileSync53,
|
|
50522
50794
|
realpathSync as realpathSync5,
|
|
50523
|
-
statSync as
|
|
50795
|
+
statSync as statSync36,
|
|
50524
50796
|
unlinkSync as unlinkSync15
|
|
50525
50797
|
} from "node:fs";
|
|
50526
50798
|
import { join as join55, relative as relative3, sep as sep5 } from "node:path";
|
|
@@ -50575,7 +50847,7 @@ function guardedCopyFile(src, dest, allowedRoot) {
|
|
|
50575
50847
|
}
|
|
50576
50848
|
let realStat;
|
|
50577
50849
|
try {
|
|
50578
|
-
realStat =
|
|
50850
|
+
realStat = statSync36(real);
|
|
50579
50851
|
} catch {
|
|
50580
50852
|
return { status: "missing" };
|
|
50581
50853
|
}
|
|
@@ -50622,7 +50894,7 @@ function copyAgentWorkspace(agentName, liveWorkspace, repoWorkspace, skipped, lo
|
|
|
50622
50894
|
}
|
|
50623
50895
|
function dirExists(p) {
|
|
50624
50896
|
try {
|
|
50625
|
-
return
|
|
50897
|
+
return statSync36(p).isDirectory();
|
|
50626
50898
|
} catch {
|
|
50627
50899
|
return false;
|
|
50628
50900
|
}
|
|
@@ -50676,7 +50948,7 @@ function scanStagedForSecrets(repoPath, git, log) {
|
|
|
50676
50948
|
const abs = join55(repoPath, relPath);
|
|
50677
50949
|
let content;
|
|
50678
50950
|
try {
|
|
50679
|
-
const st =
|
|
50951
|
+
const st = statSync36(abs);
|
|
50680
50952
|
if (!st.isFile() || st.size > SCAN_MAX_FILE_BYTES)
|
|
50681
50953
|
continue;
|
|
50682
50954
|
const buf = readFileSync53(abs);
|
|
@@ -50834,7 +51106,7 @@ import {
|
|
|
50834
51106
|
readFileSync as readFileSync54,
|
|
50835
51107
|
renameSync as renameSync19,
|
|
50836
51108
|
rmSync as rmSync17,
|
|
50837
|
-
statSync as
|
|
51109
|
+
statSync as statSync37,
|
|
50838
51110
|
writeFileSync as writeFileSync26
|
|
50839
51111
|
} from "node:fs";
|
|
50840
51112
|
import { dirname as dirname26 } from "node:path";
|
|
@@ -50896,7 +51168,7 @@ function ensureLogFile2(opts) {
|
|
|
50896
51168
|
const isRoot = process.getuid?.() === 0;
|
|
50897
51169
|
let alreadyOwned = false;
|
|
50898
51170
|
try {
|
|
50899
|
-
const st =
|
|
51171
|
+
const st = statSync37(path7);
|
|
50900
51172
|
alreadyOwned = st.uid === uid && st.gid === gid;
|
|
50901
51173
|
} catch {}
|
|
50902
51174
|
if (isRoot && !alreadyOwned) {
|
|
@@ -50993,7 +51265,7 @@ var CRON_PATH2 = "/etc/cron.d/switchroom-config-sync", CRON_LOG_PATH2 = "/var/lo
|
|
|
50993
51265
|
var init_install_cron2 = () => {};
|
|
50994
51266
|
|
|
50995
51267
|
// src/cli/doctor-config-repo.ts
|
|
50996
|
-
import { existsSync as existsSync65, readdirSync as readdirSync25, statSync as
|
|
51268
|
+
import { existsSync as existsSync65, readdirSync as readdirSync25, statSync as statSync38 } from "node:fs";
|
|
50997
51269
|
import { spawnSync as spawnSync9 } from "node:child_process";
|
|
50998
51270
|
import { homedir as homedir27 } from "node:os";
|
|
50999
51271
|
import { join as join56 } from "node:path";
|
|
@@ -51168,7 +51440,7 @@ function countUntrackedPersonalSkills(repoPath, git) {
|
|
|
51168
51440
|
const rel = relPrefix ? `${relPrefix}/${ent}` : ent;
|
|
51169
51441
|
let st;
|
|
51170
51442
|
try {
|
|
51171
|
-
st =
|
|
51443
|
+
st = statSync38(abs);
|
|
51172
51444
|
} catch {
|
|
51173
51445
|
continue;
|
|
51174
51446
|
}
|
|
@@ -51188,7 +51460,7 @@ function countUntrackedPersonalSkills(repoPath, git) {
|
|
|
51188
51460
|
const abs = join56(ps, ent);
|
|
51189
51461
|
let st;
|
|
51190
51462
|
try {
|
|
51191
|
-
st =
|
|
51463
|
+
st = statSync38(abs);
|
|
51192
51464
|
} catch {
|
|
51193
51465
|
continue;
|
|
51194
51466
|
}
|
|
@@ -51280,7 +51552,7 @@ function checkConfigRepo(config, now = Date.now()) {
|
|
|
51280
51552
|
}
|
|
51281
51553
|
function safeMtimeMs2(path7) {
|
|
51282
51554
|
try {
|
|
51283
|
-
return
|
|
51555
|
+
return statSync38(path7).mtimeMs;
|
|
51284
51556
|
} catch {
|
|
51285
51557
|
return null;
|
|
51286
51558
|
}
|
|
@@ -52282,7 +52554,7 @@ import {
|
|
|
52282
52554
|
constants as fsConstants3,
|
|
52283
52555
|
existsSync as existsSync67,
|
|
52284
52556
|
realpathSync as realpathSync6,
|
|
52285
|
-
statSync as
|
|
52557
|
+
statSync as statSync39
|
|
52286
52558
|
} from "node:fs";
|
|
52287
52559
|
import { userInfo, homedir as homedir29 } from "node:os";
|
|
52288
52560
|
import { join as join59 } from "node:path";
|
|
@@ -52300,7 +52572,7 @@ function defaultStatVault(path7) {
|
|
|
52300
52572
|
let uid = -1;
|
|
52301
52573
|
let mode = 0;
|
|
52302
52574
|
try {
|
|
52303
|
-
const s =
|
|
52575
|
+
const s = statSync39(real);
|
|
52304
52576
|
uid = s.uid;
|
|
52305
52577
|
mode = s.mode & 511;
|
|
52306
52578
|
} catch {
|
|
@@ -63851,7 +64123,7 @@ import {
|
|
|
63851
64123
|
mkdirSync as mkdirSync43,
|
|
63852
64124
|
readFileSync as readFileSync63,
|
|
63853
64125
|
renameSync as renameSync21,
|
|
63854
|
-
statSync as
|
|
64126
|
+
statSync as statSync40,
|
|
63855
64127
|
writeFileSync as writeFileSync30
|
|
63856
64128
|
} from "node:fs";
|
|
63857
64129
|
import { homedir as homedir33 } from "node:os";
|
|
@@ -63869,7 +64141,7 @@ function resolveIo(io) {
|
|
|
63869
64141
|
}),
|
|
63870
64142
|
statUid: io.statUid ?? ((p) => {
|
|
63871
64143
|
try {
|
|
63872
|
-
return
|
|
64144
|
+
return statSync40(p).uid;
|
|
63873
64145
|
} catch {
|
|
63874
64146
|
return;
|
|
63875
64147
|
}
|
|
@@ -63879,7 +64151,7 @@ function resolveIo(io) {
|
|
|
63879
64151
|
chown: io.chown ?? ((p, uid, gid) => chownSync10(p, uid, gid)),
|
|
63880
64152
|
statOwner: io.statOwner ?? ((p) => {
|
|
63881
64153
|
try {
|
|
63882
|
-
const st =
|
|
64154
|
+
const st = statSync40(p);
|
|
63883
64155
|
return { uid: st.uid, gid: st.gid };
|
|
63884
64156
|
} catch {
|
|
63885
64157
|
return;
|
|
@@ -65179,7 +65451,7 @@ function runCredentialsMigrationChecks(config, deps = {}) {
|
|
|
65179
65451
|
var init_doctor_credentials_migration = () => {};
|
|
65180
65452
|
|
|
65181
65453
|
// src/cli/doctor-agent-dotfile-ownership.ts
|
|
65182
|
-
import { existsSync as existsSync72, lstatSync as lstatSync11, statSync as
|
|
65454
|
+
import { existsSync as existsSync72, lstatSync as lstatSync11, statSync as statSync41 } from "node:fs";
|
|
65183
65455
|
import { join as join74 } from "node:path";
|
|
65184
65456
|
function agentDotfileCandidates(agentDir) {
|
|
65185
65457
|
return [
|
|
@@ -65196,7 +65468,7 @@ function runAgentDotfileOwnershipChecks(config, deps = {}) {
|
|
|
65196
65468
|
if (agents.length === 0)
|
|
65197
65469
|
return results;
|
|
65198
65470
|
const exists = deps.existsSync ?? existsSync72;
|
|
65199
|
-
const scanFs = deps.scanFs ?? { lstatSync: lstatSync11, statSync:
|
|
65471
|
+
const scanFs = deps.scanFs ?? { lstatSync: lstatSync11, statSync: statSync41 };
|
|
65200
65472
|
let agentsDir = deps.agentsDir;
|
|
65201
65473
|
if (agentsDir === undefined) {
|
|
65202
65474
|
try {
|
|
@@ -65803,7 +66075,7 @@ var init_doctor_agent_smoke = __esm(() => {
|
|
|
65803
66075
|
|
|
65804
66076
|
// src/cli/doctor-vault-broker-durability.ts
|
|
65805
66077
|
import { execFileSync as execFileSync25 } from "node:child_process";
|
|
65806
|
-
import { existsSync as existsSync74, statSync as
|
|
66078
|
+
import { existsSync as existsSync74, statSync as statSync42, readFileSync as readFileSync64 } from "node:fs";
|
|
65807
66079
|
import { homedir as homedir40 } from "node:os";
|
|
65808
66080
|
import { join as join78 } from "node:path";
|
|
65809
66081
|
import { createRequire as createRequire2 } from "node:module";
|
|
@@ -65831,7 +66103,7 @@ function defaultStatHost(p) {
|
|
|
65831
66103
|
if (!existsSync74(p))
|
|
65832
66104
|
return null;
|
|
65833
66105
|
try {
|
|
65834
|
-
const s =
|
|
66106
|
+
const s = statSync42(p, { bigint: true });
|
|
65835
66107
|
return { ino: s.ino, size: Number(s.size) };
|
|
65836
66108
|
} catch {
|
|
65837
66109
|
return null;
|
|
@@ -66169,7 +66441,7 @@ function probeOrphanVaultTokens(config, opts) {
|
|
|
66169
66441
|
}
|
|
66170
66442
|
function defaultTokenMtimeMs(agent, home2) {
|
|
66171
66443
|
try {
|
|
66172
|
-
return
|
|
66444
|
+
return statSync42(join78(home2, ".switchroom", "agents", agent, ".vault-token")).mtimeMs;
|
|
66173
66445
|
} catch {
|
|
66174
66446
|
return null;
|
|
66175
66447
|
}
|
|
@@ -66217,7 +66489,7 @@ function probeAutoUnlockBlob(home2) {
|
|
|
66217
66489
|
fix: "Run `switchroom vault broker enable-auto-unlock` to seal the blob with the current passphrase + machine-id"
|
|
66218
66490
|
};
|
|
66219
66491
|
}
|
|
66220
|
-
const sz =
|
|
66492
|
+
const sz = statSync42(blobPath).size;
|
|
66221
66493
|
if (sz === 0) {
|
|
66222
66494
|
return {
|
|
66223
66495
|
name: "vault-broker: auto-unlock blob",
|
|
@@ -66383,7 +66655,7 @@ var init_doctor_timezone = __esm(() => {
|
|
|
66383
66655
|
});
|
|
66384
66656
|
|
|
66385
66657
|
// src/cli/doctor-disk.ts
|
|
66386
|
-
import { closeSync as closeSync14, fstatSync as fstatSync4, openSync as openSync14, readSync as readSync4, statfsSync, statSync as
|
|
66658
|
+
import { closeSync as closeSync14, fstatSync as fstatSync4, openSync as openSync14, readSync as readSync4, statfsSync, statSync as statSync43 } from "node:fs";
|
|
66387
66659
|
import { dirname as dirname31 } from "node:path";
|
|
66388
66660
|
function usageFromStatfs(s) {
|
|
66389
66661
|
const bsize = s.bsize > 0 ? s.bsize : 0;
|
|
@@ -66406,7 +66678,7 @@ function fmtBytes(n) {
|
|
|
66406
66678
|
}
|
|
66407
66679
|
function nearestExistingPath(path7, exists = (p) => {
|
|
66408
66680
|
try {
|
|
66409
|
-
|
|
66681
|
+
statSync43(p);
|
|
66410
66682
|
return true;
|
|
66411
66683
|
} catch {
|
|
66412
66684
|
return false;
|
|
@@ -66854,7 +67126,7 @@ import {
|
|
|
66854
67126
|
mkdirSync as mkdirSync44,
|
|
66855
67127
|
readFileSync as readFileSync67,
|
|
66856
67128
|
readdirSync as readdirSync28,
|
|
66857
|
-
statSync as
|
|
67129
|
+
statSync as statSync44
|
|
66858
67130
|
} from "node:fs";
|
|
66859
67131
|
import { dirname as dirname33, join as join81, resolve as resolve41 } from "node:path";
|
|
66860
67132
|
import { createPublicKey, createPrivateKey } from "node:crypto";
|
|
@@ -66881,7 +67153,7 @@ function findInNvm(bin) {
|
|
|
66881
67153
|
for (const v of versions) {
|
|
66882
67154
|
const candidate = join81(nvmRoot, v, "bin", bin);
|
|
66883
67155
|
try {
|
|
66884
|
-
const s =
|
|
67156
|
+
const s = statSync44(candidate);
|
|
66885
67157
|
if (s.isFile() || s.isSymbolicLink()) {
|
|
66886
67158
|
return candidate;
|
|
66887
67159
|
}
|
|
@@ -67541,7 +67813,7 @@ function checkHostCapabilitiesReadable(config, read = readHostCapabilities()) {
|
|
|
67541
67813
|
const proven = voice?.gpuPresent === true && voice?.containerToolkit === true;
|
|
67542
67814
|
let mode;
|
|
67543
67815
|
try {
|
|
67544
|
-
mode =
|
|
67816
|
+
mode = statSync44(read.path).mode & 511;
|
|
67545
67817
|
} catch {
|
|
67546
67818
|
mode = undefined;
|
|
67547
67819
|
}
|
|
@@ -67827,6 +68099,7 @@ async function checkHindsight(config) {
|
|
|
67827
68099
|
const versionRow = await checkHindsightVersion(url);
|
|
67828
68100
|
if (versionRow)
|
|
67829
68101
|
results.push(versionRow);
|
|
68102
|
+
results.push(...await runHindsightShimContractCheck(url));
|
|
67830
68103
|
results.push(checkHindsightConsumer(config));
|
|
67831
68104
|
results.push(checkHindsightEnvKeysAreManaged(config));
|
|
67832
68105
|
results.push(...checkHindsightContainerHealth());
|
|
@@ -69297,6 +69570,7 @@ var init_doctor = __esm(() => {
|
|
|
69297
69570
|
init_hindsight_perf_defaults();
|
|
69298
69571
|
init_memory_key_drift();
|
|
69299
69572
|
init_doctor_memory();
|
|
69573
|
+
init_doctor_hindsight_shim_contract();
|
|
69300
69574
|
init_doctor_recall_health();
|
|
69301
69575
|
init_doctor_hnsw_index();
|
|
69302
69576
|
init_doctor_observation_scopes();
|
|
@@ -69374,7 +69648,7 @@ __export(exports_apply, {
|
|
|
69374
69648
|
DEFAULT_COMPOSE_PATH: () => DEFAULT_COMPOSE_PATH,
|
|
69375
69649
|
COMPOSE_PROJECT: () => COMPOSE_PROJECT2
|
|
69376
69650
|
});
|
|
69377
|
-
import { accessSync as accessSync3, chmodSync as chmodSync14, chownSync as chownSync11, constants as fsConstants5, existsSync as existsSync77, mkdirSync as mkdirSync45, readFileSync as readFileSync68, readdirSync as readdirSync29, renameSync as renameSync22, statSync as
|
|
69651
|
+
import { accessSync as accessSync3, chmodSync as chmodSync14, chownSync as chownSync11, constants as fsConstants5, existsSync as existsSync77, mkdirSync as mkdirSync45, readFileSync as readFileSync68, readdirSync as readdirSync29, renameSync as renameSync22, statSync as statSync45, writeFileSync as writeFileSync31 } from "node:fs";
|
|
69378
69652
|
import { mkdir as mkdir2 } from "node:fs/promises";
|
|
69379
69653
|
import { spawnSync as childSpawnSync } from "node:child_process";
|
|
69380
69654
|
import readline from "node:readline";
|
|
@@ -69679,7 +69953,7 @@ async function provisionLiteLLMKeys(config, agentNames, switchroomConfigPath, ct
|
|
|
69679
69953
|
try {
|
|
69680
69954
|
let cfgMode = 420;
|
|
69681
69955
|
try {
|
|
69682
|
-
cfgMode =
|
|
69956
|
+
cfgMode = statSync45(switchroomConfigPath).mode & 511;
|
|
69683
69957
|
} catch {}
|
|
69684
69958
|
writeConfigFileSync(switchroomConfigPath, configText, cfgMode);
|
|
69685
69959
|
writeOut(source_default.gray(` ~ litellm: granted read-ACL on per-agent keys (updated ${switchroomConfigPath})
|
|
@@ -70291,26 +70565,6 @@ async function probeVaultProvisioning(config, agentNames, home2) {
|
|
|
70291
70565
|
needsHindsight
|
|
70292
70566
|
};
|
|
70293
70567
|
}
|
|
70294
|
-
function parseComposeServiceNames(compose) {
|
|
70295
|
-
const lines = compose.split(`
|
|
70296
|
-
`);
|
|
70297
|
-
const names = [];
|
|
70298
|
-
let inServices = false;
|
|
70299
|
-
for (const line of lines) {
|
|
70300
|
-
if (/^services:\s*$/.test(line)) {
|
|
70301
|
-
inServices = true;
|
|
70302
|
-
continue;
|
|
70303
|
-
}
|
|
70304
|
-
if (inServices && /^\S/.test(line))
|
|
70305
|
-
break;
|
|
70306
|
-
if (!inServices)
|
|
70307
|
-
continue;
|
|
70308
|
-
const m = /^ {2}([A-Za-z0-9_.-]+):\s*$/.exec(line);
|
|
70309
|
-
if (m)
|
|
70310
|
-
names.push(m[1]);
|
|
70311
|
-
}
|
|
70312
|
-
return names;
|
|
70313
|
-
}
|
|
70314
70568
|
async function runApplyDryRun(config, options, deps = {}, switchroomConfigPath) {
|
|
70315
70569
|
const writeOut = deps.writeOut ?? ((s) => process.stdout.write(s));
|
|
70316
70570
|
const writeErr = deps.writeErr ?? ((s) => process.stderr.write(s));
|
|
@@ -70398,6 +70652,9 @@ Dry-run: validating switchroom config (no changes will be written)...
|
|
|
70398
70652
|
if (removedServices.length > 0) {
|
|
70399
70653
|
info.push(`compose: services removed: ${removedServices.join(", ")}.`);
|
|
70400
70654
|
}
|
|
70655
|
+
if (computed.voiceSidecarDrop) {
|
|
70656
|
+
warnings.push(`compose: ${computed.voiceSidecarDrop.message}`);
|
|
70657
|
+
}
|
|
70401
70658
|
if (previousImageTag !== null && !composeChanged) {
|
|
70402
70659
|
info.push(`compose: no change (would be byte-identical to the current file).`);
|
|
70403
70660
|
}
|
|
@@ -70708,7 +70965,7 @@ var init_apply = __esm(() => {
|
|
|
70708
70965
|
});
|
|
70709
70966
|
|
|
70710
70967
|
// src/host-control/audit-reader.ts
|
|
70711
|
-
import { closeSync as closeSync15, existsSync as existsSync81, openSync as openSync15, readSync as readSync5, statSync as
|
|
70968
|
+
import { closeSync as closeSync15, existsSync as existsSync81, openSync as openSync15, readSync as readSync5, statSync as statSync49 } from "node:fs";
|
|
70712
70969
|
import { homedir as homedir43 } from "node:os";
|
|
70713
70970
|
import { join as join87 } from "node:path";
|
|
70714
70971
|
function defaultAuditLogPath2(home2 = homedir43()) {
|
|
@@ -70735,7 +70992,7 @@ function tailBytes(path7, n, strict = false) {
|
|
|
70735
70992
|
let fd;
|
|
70736
70993
|
let size;
|
|
70737
70994
|
try {
|
|
70738
|
-
size =
|
|
70995
|
+
size = statSync49(path7).size;
|
|
70739
70996
|
fd = openSync15(path7, "r");
|
|
70740
70997
|
} catch (err) {
|
|
70741
70998
|
if (strict && err.code !== "ENOENT")
|
|
@@ -84273,7 +84530,12 @@ var init_server3 = __esm(() => {
|
|
|
84273
84530
|
required: ["cron_expr", "prompt"],
|
|
84274
84531
|
properties: {
|
|
84275
84532
|
cron_expr: { type: "string" },
|
|
84276
|
-
prompt: {
|
|
84533
|
+
prompt: {
|
|
84534
|
+
type: "string",
|
|
84535
|
+
minLength: 1,
|
|
84536
|
+
maxLength: 4000,
|
|
84537
|
+
description: "The inbound turn YOU receive when this cron fires \u2014 not a message " + "sent to the user. Phrase it from your future-self's perspective " + `("Time for the daily digest \u2014 pull yesterday's GitHub activity and ` + 'DM the summary to chat 12345"), not as a request to you ("please ' + 'send the digest"). Include any ids/context that future turn will ' + "need, since a Tier-1 fire has no conversation context."
|
|
84538
|
+
},
|
|
84277
84539
|
secrets: { type: "array", items: { type: "string" } },
|
|
84278
84540
|
name: { type: "string", pattern: "^[a-z0-9-]{1,40}$" },
|
|
84279
84541
|
model: {
|
|
@@ -85098,6 +85360,9 @@ function classifyOrphanedDbTick(lines, alarmIdx) {
|
|
|
85098
85360
|
}
|
|
85099
85361
|
return verdict ?? "unrecovered";
|
|
85100
85362
|
}
|
|
85363
|
+
function isFloodRejection(line) {
|
|
85364
|
+
return FLOOD_REJECTION_RE.test(line.split(" desc=")[0] ?? line);
|
|
85365
|
+
}
|
|
85101
85366
|
function lineInstantMs(line) {
|
|
85102
85367
|
const iso = extractTs(line);
|
|
85103
85368
|
if (iso === null)
|
|
@@ -85116,7 +85381,7 @@ function classifyReplyDeliveryEpisode(lines, failIdx) {
|
|
|
85116
85381
|
const failMs = lineInstantMs(failLine);
|
|
85117
85382
|
if (failMs === null)
|
|
85118
85383
|
return "unrecovered";
|
|
85119
|
-
let ladderEvidence =
|
|
85384
|
+
let ladderEvidence = isFloodRejection(failLine);
|
|
85120
85385
|
for (let j = failIdx + 1;j < lines.length; j++) {
|
|
85121
85386
|
const line = lines[j];
|
|
85122
85387
|
if (!line)
|
|
@@ -85124,7 +85389,9 @@ function classifyReplyDeliveryEpisode(lines, failIdx) {
|
|
|
85124
85389
|
const ms = lineInstantMs(line);
|
|
85125
85390
|
if (ms !== null && ms - failMs > REPLY_DELIVERY_RECOVERY_WINDOW_MS)
|
|
85126
85391
|
break;
|
|
85127
|
-
if (
|
|
85392
|
+
if (GATEWAY_FLOOD_LADDER_RE.test(line))
|
|
85393
|
+
ladderEvidence = true;
|
|
85394
|
+
else if (FUSE_SEND_DEFERRAL_RE.exec(line)?.[1] === chat)
|
|
85128
85395
|
ladderEvidence = true;
|
|
85129
85396
|
if (!TG_POST_RICH_LINE_RE.test(line))
|
|
85130
85397
|
continue;
|
|
@@ -85136,7 +85403,7 @@ function classifyReplyDeliveryEpisode(lines, failIdx) {
|
|
|
85136
85403
|
if (ms === null)
|
|
85137
85404
|
continue;
|
|
85138
85405
|
if (TG_POST_STATUS_RE.exec(line)?.[1] !== "ok") {
|
|
85139
|
-
if (
|
|
85406
|
+
if (isFloodRejection(line))
|
|
85140
85407
|
ladderEvidence = true;
|
|
85141
85408
|
continue;
|
|
85142
85409
|
}
|
|
@@ -85319,7 +85586,7 @@ function scanAgent(agent, turnsText, gatewayText, opts = {}) {
|
|
|
85319
85586
|
escalate
|
|
85320
85587
|
};
|
|
85321
85588
|
}
|
|
85322
|
-
var HANG_MS = 360000, HANG_MAXTOOLS = 2, SILENT_NOOP_FLOOR_TS = 1783900800, GATEWAY_SIGNATURES, GATEWAY_SIGNAL_MEMBERS, GATEWAY_SIGNAL_NAMES, ORPHANED_DB_RECOVERED_RE, ORPHANED_DB_SWEEP_LINE_RE, ORPHANED_DB_ALARM_TARGET_RE, ORPHANED_DB_ALARM_COUNT_RE, ORPHANED_DB_LANE_VETO_RE, TG_POST_RICH_LINE_RE, TG_POST_STATUS_RE, TG_POST_CHAT_RE, TG_POST_THREAD_RE,
|
|
85589
|
+
var HANG_MS = 360000, HANG_MAXTOOLS = 2, SILENT_NOOP_FLOOR_TS = 1783900800, GATEWAY_SIGNATURES, GATEWAY_SIGNAL_MEMBERS, GATEWAY_SIGNAL_NAMES, ORPHANED_DB_RECOVERED_RE, ORPHANED_DB_SWEEP_LINE_RE, ORPHANED_DB_ALARM_TARGET_RE, ORPHANED_DB_ALARM_COUNT_RE, ORPHANED_DB_LANE_VETO_RE, TG_POST_RICH_LINE_RE, TG_POST_STATUS_RE, TG_POST_CHAT_RE, TG_POST_THREAD_RE, GATEWAY_FLOOD_LADDER_RE, FUSE_SEND_DEFERRAL_RE, FLOOD_REJECTION_RE, REPLY_DELIVERY_IMMEDIATE_RESEND_MS = 2000, REPLY_DELIVERY_RECOVERY_WINDOW_MS, ISO_TS_RE;
|
|
85323
85590
|
var init_detect = __esm(() => {
|
|
85324
85591
|
init_retry_api_call();
|
|
85325
85592
|
GATEWAY_SIGNATURES = {
|
|
@@ -85346,8 +85613,9 @@ var init_detect = __esm(() => {
|
|
|
85346
85613
|
TG_POST_STATUS_RE = /\bstatus=(ok|benign|retry|err)(?![a-z])/;
|
|
85347
85614
|
TG_POST_CHAT_RE = /\bchat=(-?\d+)\b/;
|
|
85348
85615
|
TG_POST_THREAD_RE = /\bthread=(\S+)/;
|
|
85349
|
-
|
|
85350
|
-
|
|
85616
|
+
GATEWAY_FLOOD_LADDER_RE = /429 rate limited|outbox-sweep: deferred/;
|
|
85617
|
+
FUSE_SEND_DEFERRAL_RE = /\bedit-flood-fuse deferred method=sendRichMessage\b[^\n]*\bkey=(?:cs|cer|ce|lr|t):(-?\d+)\b/;
|
|
85618
|
+
FLOOD_REJECTION_RE = /\berr=telegram_429\b|\bcode=429\b/;
|
|
85351
85619
|
REPLY_DELIVERY_RECOVERY_WINDOW_MS = DEFAULT_MAX_FLOOD_SLEEP_MS;
|
|
85352
85620
|
ISO_TS_RE = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(Z|[+-]\d{2}:?\d{2})?/;
|
|
85353
85621
|
});
|
|
@@ -93400,7 +93668,7 @@ import { spawn as spawn4 } from "node:child_process";
|
|
|
93400
93668
|
// src/vault/broker/server.ts
|
|
93401
93669
|
init_compose();
|
|
93402
93670
|
import * as net3 from "node:net";
|
|
93403
|
-
import { mkdirSync as mkdirSync29, chmodSync as chmodSync9, chownSync as chownSync6, existsSync as existsSync47, readFileSync as readFileSync40, readdirSync as readdirSync20, statSync as
|
|
93671
|
+
import { mkdirSync as mkdirSync29, chmodSync as chmodSync9, chownSync as chownSync6, existsSync as existsSync47, readFileSync as readFileSync40, readdirSync as readdirSync20, statSync as statSync30, unlinkSync as unlinkSync12, writeFileSync as writeFileSync18 } from "node:fs";
|
|
93404
93672
|
|
|
93405
93673
|
// src/vault/broker/write-token-file.ts
|
|
93406
93674
|
init_agent_uid();
|
|
@@ -93485,6 +93753,66 @@ import { dirname as dirname16, resolve as resolve32, basename as basename8 } fro
|
|
|
93485
93753
|
import * as os4 from "node:os";
|
|
93486
93754
|
import * as path5 from "node:path";
|
|
93487
93755
|
|
|
93756
|
+
// src/vault/broker/vault-refresh.ts
|
|
93757
|
+
init_vault();
|
|
93758
|
+
import { statSync as statSync29 } from "node:fs";
|
|
93759
|
+
function sameVaultStamp(a, b) {
|
|
93760
|
+
return a.mtimeNs === b.mtimeNs && a.size === b.size && a.ino === b.ino;
|
|
93761
|
+
}
|
|
93762
|
+
function readVaultStamp(vaultPath) {
|
|
93763
|
+
try {
|
|
93764
|
+
const st = statSync29(vaultPath, { bigint: true });
|
|
93765
|
+
return { mtimeNs: st.mtimeNs, size: st.size, ino: st.ino };
|
|
93766
|
+
} catch {
|
|
93767
|
+
return null;
|
|
93768
|
+
}
|
|
93769
|
+
}
|
|
93770
|
+
function zeroSecrets(secrets) {
|
|
93771
|
+
for (const [, entry] of Object.entries(secrets)) {
|
|
93772
|
+
try {
|
|
93773
|
+
if (entry.kind === "string" || entry.kind === "binary") {
|
|
93774
|
+
entry.value = "";
|
|
93775
|
+
}
|
|
93776
|
+
} catch {}
|
|
93777
|
+
}
|
|
93778
|
+
}
|
|
93779
|
+
function refreshVaultIfChanged(state, opts) {
|
|
93780
|
+
const { vaultPath, force = false } = opts;
|
|
93781
|
+
const open = opts.open ?? openVault;
|
|
93782
|
+
const warn = opts.warn ?? ((m) => {
|
|
93783
|
+
process.stderr.write(m);
|
|
93784
|
+
});
|
|
93785
|
+
const secrets = state.secrets;
|
|
93786
|
+
const passphrase = state.passphrase;
|
|
93787
|
+
if (secrets === null || passphrase === null)
|
|
93788
|
+
return state;
|
|
93789
|
+
const known = state.loadedStamp;
|
|
93790
|
+
if (known === null)
|
|
93791
|
+
return state;
|
|
93792
|
+
const current = readVaultStamp(vaultPath);
|
|
93793
|
+
if (current === null)
|
|
93794
|
+
return state;
|
|
93795
|
+
if (!force && sameVaultStamp(current, known))
|
|
93796
|
+
return state;
|
|
93797
|
+
if (!force && state.failedStamp !== null && sameVaultStamp(state.failedStamp, current)) {
|
|
93798
|
+
return state;
|
|
93799
|
+
}
|
|
93800
|
+
opts.beforeOpen?.(vaultPath);
|
|
93801
|
+
let next;
|
|
93802
|
+
try {
|
|
93803
|
+
next = open(passphrase, vaultPath);
|
|
93804
|
+
} catch (err) {
|
|
93805
|
+
const alreadyWarned = state.failedStamp !== null && sameVaultStamp(state.failedStamp, current);
|
|
93806
|
+
if (!alreadyWarned) {
|
|
93807
|
+
warn(`[vault-broker] WARNING: ${vaultPath} changed on disk but ` + `could not be re-opened (${err?.message ?? "unknown error"}) \u2014 ` + `continuing to serve the previously loaded secrets; will retry when ` + `the file changes again
|
|
93808
|
+
`);
|
|
93809
|
+
}
|
|
93810
|
+
return { ...state, failedStamp: current };
|
|
93811
|
+
}
|
|
93812
|
+
zeroSecrets(secrets);
|
|
93813
|
+
return { secrets: next, passphrase, loadedStamp: current, failedStamp: null };
|
|
93814
|
+
}
|
|
93815
|
+
|
|
93488
93816
|
// src/vault/grants.ts
|
|
93489
93817
|
import { createHash as createHash10, randomBytes as randomBytes9 } from "node:crypto";
|
|
93490
93818
|
|
|
@@ -95883,6 +96211,8 @@ class VaultBroker {
|
|
|
95883
96211
|
testOpts;
|
|
95884
96212
|
secrets = null;
|
|
95885
96213
|
passphrase = null;
|
|
96214
|
+
vaultStamp = null;
|
|
96215
|
+
failedVaultStamp = null;
|
|
95886
96216
|
config = null;
|
|
95887
96217
|
startedAt = Date.now();
|
|
95888
96218
|
server = null;
|
|
@@ -95977,13 +96307,53 @@ class VaultBroker {
|
|
|
95977
96307
|
}
|
|
95978
96308
|
unlockFromPassphrase(passphrase) {
|
|
95979
96309
|
detectVaultLayoutDrift(this.vaultPath);
|
|
96310
|
+
const stamp = this._readVaultStamp();
|
|
95980
96311
|
const secrets = openVault(passphrase, this.vaultPath);
|
|
95981
96312
|
this.secrets = secrets;
|
|
95982
96313
|
this.passphrase = passphrase;
|
|
96314
|
+
this.vaultStamp = stamp;
|
|
96315
|
+
this.failedVaultStamp = null;
|
|
95983
96316
|
this._setReadinessSentinel(true);
|
|
95984
96317
|
}
|
|
96318
|
+
_readVaultStamp() {
|
|
96319
|
+
return readVaultStamp(this.vaultPath);
|
|
96320
|
+
}
|
|
96321
|
+
_reloadSecretsIfVaultChanged(force = false) {
|
|
96322
|
+
let next;
|
|
96323
|
+
try {
|
|
96324
|
+
next = refreshVaultIfChanged({
|
|
96325
|
+
secrets: this.secrets,
|
|
96326
|
+
passphrase: this.passphrase,
|
|
96327
|
+
loadedStamp: this.vaultStamp,
|
|
96328
|
+
failedStamp: this.failedVaultStamp
|
|
96329
|
+
}, { vaultPath: this.vaultPath, force, beforeOpen: detectVaultLayoutDrift });
|
|
96330
|
+
} catch (err) {
|
|
96331
|
+
this._failClosedOnVaultDrift(err);
|
|
96332
|
+
return;
|
|
96333
|
+
}
|
|
96334
|
+
this.secrets = next.secrets;
|
|
96335
|
+
this.vaultStamp = next.loadedStamp;
|
|
96336
|
+
this.failedVaultStamp = next.failedStamp;
|
|
96337
|
+
}
|
|
96338
|
+
_failClosedOnVaultDrift(err) {
|
|
96339
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
96340
|
+
process.stderr.write(`[vault-broker] FATAL: ${detail}
|
|
96341
|
+
[vault-broker] Refusing to serve secrets from a vault whose on-disk ` + `layout has diverged \u2014 locking. Fix the layout and restart the broker ` + `(\`switchroom apply\`); see docs/operators/state-e-recovery.md.
|
|
96342
|
+
`);
|
|
96343
|
+
try {
|
|
96344
|
+
this.auditLogger.write({
|
|
96345
|
+
ts: new Date().toISOString(),
|
|
96346
|
+
op: "lock",
|
|
96347
|
+
caller: `pid:${process.pid}`,
|
|
96348
|
+
pid: process.pid,
|
|
96349
|
+
result: "error:vault-layout-drift"
|
|
96350
|
+
});
|
|
96351
|
+
} catch {}
|
|
96352
|
+
this.lock();
|
|
96353
|
+
}
|
|
95985
96354
|
reload(config) {
|
|
95986
96355
|
this.config = config;
|
|
96356
|
+
this._reloadSecretsIfVaultChanged(true);
|
|
95987
96357
|
}
|
|
95988
96358
|
_setReadinessSentinel(ready) {
|
|
95989
96359
|
const p = process.env.SWITCHROOM_VAULT_BROKER_READY_PATH;
|
|
@@ -95999,15 +96369,11 @@ class VaultBroker {
|
|
|
95999
96369
|
}
|
|
96000
96370
|
lock() {
|
|
96001
96371
|
if (this.secrets !== null) {
|
|
96002
|
-
|
|
96003
|
-
try {
|
|
96004
|
-
if (entry.kind === "string" || entry.kind === "binary") {
|
|
96005
|
-
entry.value = "";
|
|
96006
|
-
}
|
|
96007
|
-
} catch {}
|
|
96008
|
-
}
|
|
96372
|
+
zeroSecrets(this.secrets);
|
|
96009
96373
|
this.secrets = null;
|
|
96010
96374
|
}
|
|
96375
|
+
this.vaultStamp = null;
|
|
96376
|
+
this.failedVaultStamp = null;
|
|
96011
96377
|
this.passphrase = null;
|
|
96012
96378
|
this._setReadinessSentinel(false);
|
|
96013
96379
|
}
|
|
@@ -96327,6 +96693,7 @@ class VaultBroker {
|
|
|
96327
96693
|
socket.write(encodeResponse(errorResponse("DENIED", "preflight_access is operator-only")));
|
|
96328
96694
|
return;
|
|
96329
96695
|
}
|
|
96696
|
+
this._reloadSecretsIfVaultChanged();
|
|
96330
96697
|
if (this.secrets === null) {
|
|
96331
96698
|
socket.write(encodeResponse(errorResponse("LOCKED", "Vault is locked")));
|
|
96332
96699
|
return;
|
|
@@ -96358,6 +96725,7 @@ class VaultBroker {
|
|
|
96358
96725
|
return;
|
|
96359
96726
|
}
|
|
96360
96727
|
if (req.op === "list") {
|
|
96728
|
+
this._reloadSecretsIfVaultChanged();
|
|
96361
96729
|
if (this.secrets === null) {
|
|
96362
96730
|
socket.write(encodeResponse(errorResponse("LOCKED", "Vault is locked")));
|
|
96363
96731
|
return;
|
|
@@ -96433,6 +96801,7 @@ class VaultBroker {
|
|
|
96433
96801
|
return;
|
|
96434
96802
|
}
|
|
96435
96803
|
if (req.op === "get") {
|
|
96804
|
+
this._reloadSecretsIfVaultChanged();
|
|
96436
96805
|
if (this.secrets === null) {
|
|
96437
96806
|
socket.write(encodeResponse(errorResponse("LOCKED", "Vault is locked")));
|
|
96438
96807
|
return;
|
|
@@ -96620,10 +96989,24 @@ class VaultBroker {
|
|
|
96620
96989
|
return;
|
|
96621
96990
|
}
|
|
96622
96991
|
if (req.op === "put") {
|
|
96992
|
+
this._reloadSecretsIfVaultChanged();
|
|
96623
96993
|
if (this.secrets === null || this.passphrase === null) {
|
|
96624
96994
|
socket.write(encodeResponse(errorResponse("LOCKED", "Vault is locked")));
|
|
96625
96995
|
return;
|
|
96626
96996
|
}
|
|
96997
|
+
if (this.failedVaultStamp !== null) {
|
|
96998
|
+
writeAudit({
|
|
96999
|
+
ts: new Date().toISOString(),
|
|
97000
|
+
op: "put",
|
|
97001
|
+
key: req.key,
|
|
97002
|
+
caller: auditCaller,
|
|
97003
|
+
pid: auditPid,
|
|
97004
|
+
cgroup: auditCgroup,
|
|
97005
|
+
result: "denied:vault-file-unreadable"
|
|
97006
|
+
});
|
|
97007
|
+
socket.write(encodeResponse(errorResponse("INTERNAL", "put refused: the vault file on disk changed and could not be decrypted with the passphrase this broker holds. Writing now would overwrite it with the broker's older in-memory state. Restore the vault file the broker was unlocked with, or restart the broker and unlock it with the current passphrase (reads keep serving the previously loaded secrets meanwhile).")));
|
|
97008
|
+
return;
|
|
97009
|
+
}
|
|
96627
97010
|
let passphraseAttested = false;
|
|
96628
97011
|
const requestedPostureAttest = req.attest_via_posture === true;
|
|
96629
97012
|
if (requestedPostureAttest && req.passphrase !== undefined && req.passphrase !== "") {
|
|
@@ -96867,6 +97250,8 @@ class VaultBroker {
|
|
|
96867
97250
|
return;
|
|
96868
97251
|
}
|
|
96869
97252
|
this.chownVaultToOperator();
|
|
97253
|
+
this.vaultStamp = this._readVaultStamp();
|
|
97254
|
+
this.failedVaultStamp = null;
|
|
96870
97255
|
this.auditLogger.write({
|
|
96871
97256
|
ts: new Date().toISOString(),
|
|
96872
97257
|
op: "put",
|
|
@@ -97442,7 +97827,7 @@ class VaultBroker {
|
|
|
97442
97827
|
if (!existsSync47(filePath))
|
|
97443
97828
|
return false;
|
|
97444
97829
|
try {
|
|
97445
|
-
if (
|
|
97830
|
+
if (statSync30(filePath).size === 0)
|
|
97446
97831
|
return false;
|
|
97447
97832
|
} catch {
|
|
97448
97833
|
return false;
|
|
@@ -97650,7 +98035,7 @@ init_client();
|
|
|
97650
98035
|
init_auto_unlock();
|
|
97651
98036
|
var import_yaml11 = __toESM(require_dist(), 1);
|
|
97652
98037
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
97653
|
-
import { readFileSync as readFileSync41, statSync as
|
|
98038
|
+
import { readFileSync as readFileSync41, statSync as statSync31 } from "node:fs";
|
|
97654
98039
|
import { homedir as homedir21 } from "node:os";
|
|
97655
98040
|
import { join as join44 } from "node:path";
|
|
97656
98041
|
|
|
@@ -97686,7 +98071,7 @@ function setVaultBrokerAutoUnlock(configPath, value) {
|
|
|
97686
98071
|
doc.setIn(["vault", "broker", "autoUnlock"], value);
|
|
97687
98072
|
let mode = 420;
|
|
97688
98073
|
try {
|
|
97689
|
-
mode =
|
|
98074
|
+
mode = statSync31(configPath).mode & 511;
|
|
97690
98075
|
} catch {}
|
|
97691
98076
|
writeConfigFileSync(configPath, doc.toString(), mode);
|
|
97692
98077
|
}
|
|
@@ -98572,7 +98957,7 @@ import {
|
|
|
98572
98957
|
readdirSync as readdirSync21,
|
|
98573
98958
|
readFileSync as readFileSync44,
|
|
98574
98959
|
renameSync as renameSync15,
|
|
98575
|
-
statSync as
|
|
98960
|
+
statSync as statSync32,
|
|
98576
98961
|
symlinkSync as symlinkSync4,
|
|
98577
98962
|
unlinkSync as unlinkSync14,
|
|
98578
98963
|
writeSync as writeSync7
|
|
@@ -98724,7 +99109,7 @@ function backupVault(opts) {
|
|
|
98724
99109
|
throw new Error(`vault backup refused: '${fullPath}' already exists ` + `(sub-second collision with another backup). Retry in 1 second, ` + `or check for a concurrent backup process.`);
|
|
98725
99110
|
}
|
|
98726
99111
|
renameSync15(tmpPath, fullPath);
|
|
98727
|
-
const stat =
|
|
99112
|
+
const stat = statSync32(fullPath);
|
|
98728
99113
|
const sha256 = sha256OfFile(fullPath);
|
|
98729
99114
|
const row = {
|
|
98730
99115
|
ts: now.toISOString(),
|
|
@@ -107320,7 +107705,7 @@ function registerBuzzCommand(program3) {
|
|
|
107320
107705
|
// src/cli/telegram.ts
|
|
107321
107706
|
init_source();
|
|
107322
107707
|
init_atomic();
|
|
107323
|
-
import { existsSync as existsSync79, readFileSync as readFileSync70, statSync as
|
|
107708
|
+
import { existsSync as existsSync79, readFileSync as readFileSync70, statSync as statSync46 } from "node:fs";
|
|
107324
107709
|
import { join as join84 } from "node:path";
|
|
107325
107710
|
|
|
107326
107711
|
// src/web/webhook-dispatch.ts
|
|
@@ -107785,7 +108170,7 @@ function emitDiffOrWrite(path7, before, after, dryRun) {
|
|
|
107785
108170
|
}
|
|
107786
108171
|
let mode = 420;
|
|
107787
108172
|
try {
|
|
107788
|
-
mode =
|
|
108173
|
+
mode = statSync46(path7).mode & 511;
|
|
107789
108174
|
} catch {}
|
|
107790
108175
|
writeConfigFileSync(path7, after, mode);
|
|
107791
108176
|
}
|
|
@@ -108007,7 +108392,7 @@ init_source();
|
|
|
108007
108392
|
init_helpers();
|
|
108008
108393
|
init_atomic();
|
|
108009
108394
|
init_telegram_yaml();
|
|
108010
|
-
import { readFileSync as readFileSync71, statSync as
|
|
108395
|
+
import { readFileSync as readFileSync71, statSync as statSync47 } from "node:fs";
|
|
108011
108396
|
|
|
108012
108397
|
// src/linear/oauth-refresh.ts
|
|
108013
108398
|
var LINEAR_TOKEN_ENDPOINT = "https://api.linear.app/oauth/token";
|
|
@@ -108117,7 +108502,7 @@ async function performLinearRefresh(io) {
|
|
|
108117
108502
|
function writeConfigAtomic(path7, after) {
|
|
108118
108503
|
let mode = 420;
|
|
108119
108504
|
try {
|
|
108120
|
-
mode =
|
|
108505
|
+
mode = statSync47(path7).mode & 511;
|
|
108121
108506
|
} catch {}
|
|
108122
108507
|
writeConfigFileSync(path7, after, mode);
|
|
108123
108508
|
}
|
|
@@ -108994,7 +109379,7 @@ init_loader();
|
|
|
108994
109379
|
init_hindsight();
|
|
108995
109380
|
var import_yaml16 = __toESM(require_dist(), 1);
|
|
108996
109381
|
import { spawn as spawn5 } from "node:child_process";
|
|
108997
|
-
import { existsSync as existsSync80, readFileSync as readFileSync72, statSync as
|
|
109382
|
+
import { existsSync as existsSync80, readFileSync as readFileSync72, statSync as statSync48 } from "node:fs";
|
|
108998
109383
|
import { join as join85 } from "node:path";
|
|
108999
109384
|
function persistMemoryConfigUrl(configPath, provider, url) {
|
|
109000
109385
|
if (!existsSync80(configPath))
|
|
@@ -109017,7 +109402,7 @@ function persistMemoryConfigUrl(configPath, provider, url) {
|
|
|
109017
109402
|
}
|
|
109018
109403
|
let mode = 420;
|
|
109019
109404
|
try {
|
|
109020
|
-
mode =
|
|
109405
|
+
mode = statSync48(configPath).mode & 511;
|
|
109021
109406
|
} catch {}
|
|
109022
109407
|
writeConfigFileSync(configPath, doc.toString(), mode);
|
|
109023
109408
|
return true;
|
|
@@ -110083,7 +110468,7 @@ init_lifecycle();
|
|
|
110083
110468
|
init_manager();
|
|
110084
110469
|
init_hindsight2();
|
|
110085
110470
|
import { spawnSync as spawnSync17 } from "node:child_process";
|
|
110086
|
-
import { existsSync as existsSync84, readFileSync as readFileSync75, statSync as
|
|
110471
|
+
import { existsSync as existsSync84, readFileSync as readFileSync75, statSync as statSync51 } from "node:fs";
|
|
110087
110472
|
import { resolve as resolve44, join as join92 } from "node:path";
|
|
110088
110473
|
|
|
110089
110474
|
// src/web/memory-remediation.ts
|
|
@@ -110686,7 +111071,7 @@ import {
|
|
|
110686
111071
|
mkdirSync as mkdirSync47,
|
|
110687
111072
|
openSync as openSync16,
|
|
110688
111073
|
readdirSync as readdirSync31,
|
|
110689
|
-
statSync as
|
|
111074
|
+
statSync as statSync50,
|
|
110690
111075
|
writeFileSync as writeFileSync33
|
|
110691
111076
|
} from "node:fs";
|
|
110692
111077
|
import { dirname as dirname35, join as join90, relative as relative4, sep as sep6 } from "node:path";
|
|
@@ -110715,7 +111100,7 @@ function resolveStateOwner(dir) {
|
|
|
110715
111100
|
return cached;
|
|
110716
111101
|
let owner = null;
|
|
110717
111102
|
try {
|
|
110718
|
-
const st =
|
|
111103
|
+
const st = statSync50(dir);
|
|
110719
111104
|
owner = st.uid === 0 && st.gid === 0 ? null : { uid: st.uid, gid: st.gid };
|
|
110720
111105
|
} catch {
|
|
110721
111106
|
owner = null;
|
|
@@ -111088,7 +111473,7 @@ function readLastTurnAt(agentsDir, name) {
|
|
|
111088
111473
|
function agentBridgeAlive(agentsDir, name, maxAgeMs = 30000, now2 = Date.now()) {
|
|
111089
111474
|
try {
|
|
111090
111475
|
const f = resolve44(agentsDir, name, "telegram", ".bridge-alive");
|
|
111091
|
-
return now2 -
|
|
111476
|
+
return now2 - statSync51(f).mtimeMs <= maxAgeMs;
|
|
111092
111477
|
} catch {
|
|
111093
111478
|
return false;
|
|
111094
111479
|
}
|
|
@@ -114605,10 +114990,10 @@ init_helpers();
|
|
|
114605
114990
|
init_loader();
|
|
114606
114991
|
|
|
114607
114992
|
// src/web/startup-guard.ts
|
|
114608
|
-
import { existsSync as existsSync89, readFileSync as readFileSync81, writeFileSync as writeFileSync35, mkdirSync as mkdirSync50, statSync as
|
|
114993
|
+
import { existsSync as existsSync89, readFileSync as readFileSync81, writeFileSync as writeFileSync35, mkdirSync as mkdirSync50, statSync as statSync52, unlinkSync as unlinkSync18 } from "node:fs";
|
|
114609
114994
|
import { dirname as dirname37 } from "node:path";
|
|
114610
114995
|
function detectConfigMountFault(configPath, deps = {}) {
|
|
114611
|
-
const stat = deps.stat ?? ((p) =>
|
|
114996
|
+
const stat = deps.stat ?? ((p) => statSync52(p));
|
|
114612
114997
|
let st;
|
|
114613
114998
|
try {
|
|
114614
114999
|
st = stat(configPath);
|
|
@@ -114749,7 +115134,7 @@ init_embedded_examples();
|
|
|
114749
115134
|
init_atomic();
|
|
114750
115135
|
init_loader();
|
|
114751
115136
|
init_scaffold();
|
|
114752
|
-
import { existsSync as existsSync91, readFileSync as readFileSync82, mkdirSync as mkdirSync51, statSync as
|
|
115137
|
+
import { existsSync as existsSync91, readFileSync as readFileSync82, mkdirSync as mkdirSync51, statSync as statSync53, writeFileSync as writeFileSync36 } from "node:fs";
|
|
114753
115138
|
import { execFileSync as execFileSync29 } from "node:child_process";
|
|
114754
115139
|
import { resolve as resolve48, dirname as dirname38 } from "node:path";
|
|
114755
115140
|
init_state();
|
|
@@ -115473,7 +115858,7 @@ async function stepMemoryBackend(config, nonInteractive, switchroomConfigPath, d
|
|
|
115473
115858
|
function writeSwitchroomYaml(configPath, text) {
|
|
115474
115859
|
let mode = 420;
|
|
115475
115860
|
try {
|
|
115476
|
-
mode =
|
|
115861
|
+
mode = statSync53(configPath).mode & 511;
|
|
115477
115862
|
} catch {}
|
|
115478
115863
|
writeConfigFileSync(configPath, text, mode);
|
|
115479
115864
|
}
|
|
@@ -116360,7 +116745,7 @@ init_source();
|
|
|
116360
116745
|
init_loader();
|
|
116361
116746
|
init_lifecycle();
|
|
116362
116747
|
init_compose_env();
|
|
116363
|
-
import { existsSync as existsSync94, mkdirSync as mkdirSync54, readFileSync as readFileSync85, realpathSync as realpathSync8, statSync as
|
|
116748
|
+
import { existsSync as existsSync94, mkdirSync as mkdirSync54, readFileSync as readFileSync85, realpathSync as realpathSync8, statSync as statSync55, chownSync as chownSync12 } from "node:fs";
|
|
116364
116749
|
import { spawnSync as spawnSync20 } from "node:child_process";
|
|
116365
116750
|
import { join as join98, dirname as dirname41 } from "node:path";
|
|
116366
116751
|
import { homedir as homedir51 } from "node:os";
|
|
@@ -116423,7 +116808,7 @@ init_operator_uid();
|
|
|
116423
116808
|
init_atomic();
|
|
116424
116809
|
|
|
116425
116810
|
// src/cli/preflight-mounts.ts
|
|
116426
|
-
import { statSync as
|
|
116811
|
+
import { statSync as statSync54 } from "node:fs";
|
|
116427
116812
|
function parseHostBindSources(composeText) {
|
|
116428
116813
|
const out = [];
|
|
116429
116814
|
const FILE_HINT = /\.(ya?ml|db|log|toml|json|token|id)$|\/\.vault-token$|machine-id$|localtime$|vault-auto-unlock$|\/webkite$/;
|
|
@@ -116450,7 +116835,7 @@ function parseHostBindSources(composeText) {
|
|
|
116450
116835
|
return out;
|
|
116451
116836
|
}
|
|
116452
116837
|
function validateBindSources(composeText, deps = {}) {
|
|
116453
|
-
const stat = deps.stat ?? ((p) =>
|
|
116838
|
+
const stat = deps.stat ?? ((p) => statSync54(p));
|
|
116454
116839
|
const sources = parseHostBindSources(composeText);
|
|
116455
116840
|
const issues = [];
|
|
116456
116841
|
const seen = new Set;
|
|
@@ -116812,7 +117197,7 @@ function defaultPersistPin(configPath) {
|
|
|
116812
117197
|
const after = setReleasePinInConfig(before, pin);
|
|
116813
117198
|
if (after === before)
|
|
116814
117199
|
return;
|
|
116815
|
-
writeConfigFileSync(path7, after,
|
|
117200
|
+
writeConfigFileSync(path7, after, statSync55(path7).mode & 511);
|
|
116816
117201
|
try {
|
|
116817
117202
|
if (typeof process.geteuid === "function" && process.geteuid() === 0) {
|
|
116818
117203
|
const uid = resolveOperatorUid();
|
|
@@ -117371,7 +117756,7 @@ function defaultStatusProbe(composePath) {
|
|
|
117371
117756
|
} catch {}
|
|
117372
117757
|
if (scriptPath) {
|
|
117373
117758
|
try {
|
|
117374
|
-
cliBuiltAt = new Date(
|
|
117759
|
+
cliBuiltAt = new Date(statSync55(scriptPath).mtimeMs).toISOString();
|
|
117375
117760
|
} catch {}
|
|
117376
117761
|
let dir = dirname41(scriptPath);
|
|
117377
117762
|
for (let i2 = 0;i2 < 8; i2++) {
|
|
@@ -117662,7 +118047,7 @@ function registerUpdateCommand(program3) {
|
|
|
117662
118047
|
// src/cli/rollout.ts
|
|
117663
118048
|
init_helpers();
|
|
117664
118049
|
import { spawnSync as spawnSync22 } from "node:child_process";
|
|
117665
|
-
import { readFileSync as readFileSync87, chownSync as chownSync13, statSync as
|
|
118050
|
+
import { readFileSync as readFileSync87, chownSync as chownSync13, statSync as statSync58 } from "node:fs";
|
|
117666
118051
|
import { homedir as homedir53 } from "node:os";
|
|
117667
118052
|
|
|
117668
118053
|
// src/cli/rollout-pin-journal.ts
|
|
@@ -117672,7 +118057,7 @@ import {
|
|
|
117672
118057
|
writeFileSync as writeFileSync38,
|
|
117673
118058
|
renameSync as renameSync25,
|
|
117674
118059
|
unlinkSync as unlinkSync19,
|
|
117675
|
-
statSync as
|
|
118060
|
+
statSync as statSync56,
|
|
117676
118061
|
mkdirSync as mkdirSync55
|
|
117677
118062
|
} from "node:fs";
|
|
117678
118063
|
import { homedir as homedir52 } from "node:os";
|
|
@@ -117829,7 +118214,7 @@ function rollbackPinPersist(configPath, opts = {}) {
|
|
|
117829
118214
|
const next = journal.priorPin ? setReleasePinInConfig(current, journal.priorPin) : deleteReleasePinInConfig(current);
|
|
117830
118215
|
let mode = 384;
|
|
117831
118216
|
try {
|
|
117832
|
-
mode =
|
|
118217
|
+
mode = statSync56(configPath).mode & 511;
|
|
117833
118218
|
} catch {}
|
|
117834
118219
|
if (opts.writeConfig) {
|
|
117835
118220
|
opts.writeConfig(configPath, next, mode);
|
|
@@ -117879,7 +118264,7 @@ init_host_cli_stamp();
|
|
|
117879
118264
|
|
|
117880
118265
|
// src/cli/host-cli-upgrade.ts
|
|
117881
118266
|
init_self_update();
|
|
117882
|
-
import { lchownSync, lstatSync as lstatSync14, readdirSync as readdirSync33, statSync as
|
|
118267
|
+
import { lchownSync, lstatSync as lstatSync14, readdirSync as readdirSync33, statSync as statSync57 } from "node:fs";
|
|
117883
118268
|
import { basename as basename10, dirname as dirname43, join as join100 } from "node:path";
|
|
117884
118269
|
init_shipped_assets();
|
|
117885
118270
|
var HOST_CLI_UPGRADE_SENTINEL = "SWITCHROOM_HOST_CLI_UPGRADE:";
|
|
@@ -117916,7 +118301,7 @@ function defaultIo() {
|
|
|
117916
118301
|
return {
|
|
117917
118302
|
isFile: (p) => {
|
|
117918
118303
|
try {
|
|
117919
|
-
return
|
|
118304
|
+
return statSync57(p).isFile();
|
|
117920
118305
|
} catch {
|
|
117921
118306
|
return false;
|
|
117922
118307
|
}
|
|
@@ -118881,7 +119266,7 @@ function createRolloutDeps(params) {
|
|
|
118881
119266
|
if (after === before)
|
|
118882
119267
|
return false;
|
|
118883
119268
|
beginPinPersist(configPath, pin);
|
|
118884
|
-
writeConfigPreservingOwnership(configPath, after,
|
|
119269
|
+
writeConfigPreservingOwnership(configPath, after, statSync58(configPath).mode & 511);
|
|
118885
119270
|
return true;
|
|
118886
119271
|
},
|
|
118887
119272
|
commitPin: () => {
|
|
@@ -119403,7 +119788,7 @@ init_merge();
|
|
|
119403
119788
|
import {
|
|
119404
119789
|
existsSync as existsSync97,
|
|
119405
119790
|
readdirSync as readdirSync34,
|
|
119406
|
-
statSync as
|
|
119791
|
+
statSync as statSync59,
|
|
119407
119792
|
unlinkSync as unlinkSync20
|
|
119408
119793
|
} from "node:fs";
|
|
119409
119794
|
import { join as join102 } from "node:path";
|
|
@@ -119426,7 +119811,7 @@ function collectSessionJsonl(claudeConfigDir) {
|
|
|
119426
119811
|
const full = join102(dir, name);
|
|
119427
119812
|
let st;
|
|
119428
119813
|
try {
|
|
119429
|
-
st =
|
|
119814
|
+
st = statSync59(full);
|
|
119430
119815
|
} catch {
|
|
119431
119816
|
continue;
|
|
119432
119817
|
}
|
|
@@ -119550,7 +119935,7 @@ import {
|
|
|
119550
119935
|
readdirSync as readdirSync35,
|
|
119551
119936
|
readFileSync as readFileSync89,
|
|
119552
119937
|
renameSync as renameSync26,
|
|
119553
|
-
statSync as
|
|
119938
|
+
statSync as statSync60,
|
|
119554
119939
|
unlinkSync as unlinkSync21,
|
|
119555
119940
|
writeFileSync as writeFileSync39,
|
|
119556
119941
|
writeSync as writeSync9
|
|
@@ -119753,7 +120138,7 @@ function sweepOrphanTmpFiles(stateDir) {
|
|
|
119753
120138
|
continue;
|
|
119754
120139
|
const tmpPath = join103(stateDir, entry);
|
|
119755
120140
|
try {
|
|
119756
|
-
const stat =
|
|
120141
|
+
const stat = statSync60(tmpPath);
|
|
119757
120142
|
if (stat.mtimeMs < cutoff) {
|
|
119758
120143
|
unlinkSync21(tmpPath);
|
|
119759
120144
|
}
|
|
@@ -121318,7 +121703,7 @@ function registerSoulCommand(program3) {
|
|
|
121318
121703
|
// src/cli/debug.ts
|
|
121319
121704
|
init_helpers();
|
|
121320
121705
|
init_loader();
|
|
121321
|
-
import { existsSync as existsSync104, readFileSync as readFileSync93, readdirSync as readdirSync36, statSync as
|
|
121706
|
+
import { existsSync as existsSync104, readFileSync as readFileSync93, readdirSync as readdirSync36, statSync as statSync61 } from "node:fs";
|
|
121322
121707
|
import { resolve as resolve57, join as join108 } from "node:path";
|
|
121323
121708
|
import { createHash as createHash20 } from "node:crypto";
|
|
121324
121709
|
init_merge();
|
|
@@ -121357,7 +121742,7 @@ function findLatestTranscriptJsonl(claudeConfigDir) {
|
|
|
121357
121742
|
const transcriptPath = join108(projectPath, "transcript.jsonl");
|
|
121358
121743
|
if (!existsSync104(transcriptPath))
|
|
121359
121744
|
continue;
|
|
121360
|
-
const stat3 =
|
|
121745
|
+
const stat3 = statSync61(transcriptPath);
|
|
121361
121746
|
if (!latest || stat3.mtimeMs > latest.mtime) {
|
|
121362
121747
|
latest = { path: transcriptPath, mtime: stat3.mtimeMs };
|
|
121363
121748
|
}
|
|
@@ -121644,7 +122029,7 @@ import { execFileSync as execFileSync32 } from "node:child_process";
|
|
|
121644
122029
|
import { existsSync as existsSync106 } from "node:fs";
|
|
121645
122030
|
|
|
121646
122031
|
// src/worktree/proc-liveness.ts
|
|
121647
|
-
import { readdirSync as readdirSync37, readlinkSync as readlinkSync8, realpathSync as realpathSync9, statSync as
|
|
122032
|
+
import { readdirSync as readdirSync37, readlinkSync as readlinkSync8, realpathSync as realpathSync9, statSync as statSync62, readFileSync as readFileSync94 } from "node:fs";
|
|
121648
122033
|
import { join as join109, sep as sep8 } from "node:path";
|
|
121649
122034
|
function isPidDir(name) {
|
|
121650
122035
|
return /^\d+$/.test(name);
|
|
@@ -121672,7 +122057,7 @@ function cwdIsUnderRootByInode(linkPath, rootId, maxDepth) {
|
|
|
121672
122057
|
for (let hop = 0;hop <= maxDepth; hop++) {
|
|
121673
122058
|
let st;
|
|
121674
122059
|
try {
|
|
121675
|
-
st =
|
|
122060
|
+
st = statSync62(linkPath + suffix);
|
|
121676
122061
|
} catch {
|
|
121677
122062
|
return false;
|
|
121678
122063
|
}
|
|
@@ -121693,7 +122078,7 @@ function scanProcForHolders(path10, opts = {}) {
|
|
|
121693
122078
|
let rootId;
|
|
121694
122079
|
try {
|
|
121695
122080
|
root = realpathSync9(path10);
|
|
121696
|
-
const st =
|
|
122081
|
+
const st = statSync62(root);
|
|
121697
122082
|
rootId = { dev: st.dev, ino: st.ino };
|
|
121698
122083
|
} catch {
|
|
121699
122084
|
return { state: "unavailable", inaccessible: 0 };
|
|
@@ -121916,7 +122301,7 @@ import {
|
|
|
121916
122301
|
existsSync as existsSync107,
|
|
121917
122302
|
readFileSync as readFileSync95,
|
|
121918
122303
|
readdirSync as readdirSync38,
|
|
121919
|
-
statSync as
|
|
122304
|
+
statSync as statSync63,
|
|
121920
122305
|
renameSync as renameSync27,
|
|
121921
122306
|
mkdirSync as mkdirSync59,
|
|
121922
122307
|
rmSync as rmSync21
|
|
@@ -122124,7 +122509,7 @@ function defaultNewestTrackedMtimeMs(dir, exec) {
|
|
|
122124
122509
|
let newest = 0;
|
|
122125
122510
|
for (const f of files) {
|
|
122126
122511
|
try {
|
|
122127
|
-
const m =
|
|
122512
|
+
const m = statSync63(join110(dir, f)).mtimeMs;
|
|
122128
122513
|
if (m > newest)
|
|
122129
122514
|
newest = m;
|
|
122130
122515
|
} catch {}
|
|
@@ -122149,7 +122534,7 @@ function planGc(roots, deps = {}, taskTreeRoots = [], taskTreeDirs = []) {
|
|
|
122149
122534
|
const exists = deps.existsSync ?? existsSync107;
|
|
122150
122535
|
const readDir = deps.readDir ?? ((p) => readdirSync38(p));
|
|
122151
122536
|
const readFile4 = deps.readFile ?? ((p) => readFileSync95(p, "utf8"));
|
|
122152
|
-
const stat3 = deps.stat ?? ((p) =>
|
|
122537
|
+
const stat3 = deps.stat ?? ((p) => statSync63(p));
|
|
122153
122538
|
const exec = deps.exec ?? execCapture;
|
|
122154
122539
|
const prSignal = deps.prSignal ?? ((repo, branch) => defaultPrSignal(repo, branch, exec));
|
|
122155
122540
|
const stamp = deps.dateStamp ?? "undated";
|
|
@@ -122526,7 +122911,7 @@ function listTrashEntries(nowMs, deps = {}) {
|
|
|
122526
122911
|
const p = join110(stampDir, name);
|
|
122527
122912
|
let mtimeMs = nowMs;
|
|
122528
122913
|
try {
|
|
122529
|
-
mtimeMs =
|
|
122914
|
+
mtimeMs = statSync63(p).mtimeMs;
|
|
122530
122915
|
} catch {}
|
|
122531
122916
|
out.push({ path: p, ageDays: (nowMs - mtimeMs) / 86400000 });
|
|
122532
122917
|
}
|
|
@@ -122879,7 +123264,7 @@ import {
|
|
|
122879
123264
|
mkdirSync as mkdirSync60,
|
|
122880
123265
|
mkdtempSync as mkdtempSync5,
|
|
122881
123266
|
rmSync as rmSync22,
|
|
122882
|
-
statSync as
|
|
123267
|
+
statSync as statSync64,
|
|
122883
123268
|
writeFileSync as writeFileSync43
|
|
122884
123269
|
} from "node:fs";
|
|
122885
123270
|
import { homedir as homedir58 } from "node:os";
|
|
@@ -123036,7 +123421,7 @@ function captureCheckout(opts) {
|
|
|
123036
123421
|
};
|
|
123037
123422
|
let st;
|
|
123038
123423
|
try {
|
|
123039
|
-
st =
|
|
123424
|
+
st = statSync64(source);
|
|
123040
123425
|
} catch {
|
|
123041
123426
|
return { ...base, failure: "missing", error: `No such directory: ${source}` };
|
|
123042
123427
|
}
|
|
@@ -123194,7 +123579,7 @@ function captureCheckout(opts) {
|
|
|
123194
123579
|
};
|
|
123195
123580
|
}
|
|
123196
123581
|
opts.onBundleWritten?.(bundlePath);
|
|
123197
|
-
const bytes =
|
|
123582
|
+
const bytes = statSync64(bundlePath).size;
|
|
123198
123583
|
if (bytes === 0) {
|
|
123199
123584
|
return {
|
|
123200
123585
|
...base,
|
|
@@ -124623,6 +125008,7 @@ class KnowledgeAdmin {
|
|
|
124623
125008
|
}
|
|
124624
125009
|
|
|
124625
125010
|
// src/cli/hindsight-mcp-shim.ts
|
|
125011
|
+
init_hindsight_shim_contract();
|
|
124626
125012
|
init_hindsight();
|
|
124627
125013
|
var SHIM_SUPPORTED_PROTOCOL_VERSIONS = [
|
|
124628
125014
|
"2025-06-18",
|
|
@@ -125234,6 +125620,17 @@ class HindsightShim {
|
|
|
125234
125620
|
}
|
|
125235
125621
|
return this.knowledgeAdminCache;
|
|
125236
125622
|
}
|
|
125623
|
+
contractPinCache = null;
|
|
125624
|
+
get contractPin() {
|
|
125625
|
+
if (!this.contractPinCache) {
|
|
125626
|
+
this.contractPinCache = new ShimContractPin(this.opts.apiBaseUrl ?? this.opts.url.replace(/\/mcp\/?$/, ""), {
|
|
125627
|
+
...this.opts.fetchImpl ? { fetchImpl: this.opts.fetchImpl } : {},
|
|
125628
|
+
negativeCacheMs: 30000,
|
|
125629
|
+
positiveCacheMs: 5 * 60000
|
|
125630
|
+
});
|
|
125631
|
+
}
|
|
125632
|
+
return this.contractPinCache;
|
|
125633
|
+
}
|
|
125237
125634
|
async synthesizedCall(name, rawArgs) {
|
|
125238
125635
|
const fail4 = (text) => ({
|
|
125239
125636
|
content: [{ type: "text", text }],
|
|
@@ -125261,6 +125658,9 @@ class HindsightShim {
|
|
|
125261
125658
|
if (!this.opts.bankId) {
|
|
125262
125659
|
return fail4(`${name} is unavailable: this agent has no HINDSIGHT_BANK_ID, so ` + "there is no bank to pin it to.");
|
|
125263
125660
|
}
|
|
125661
|
+
const preflight = await this.contractPin.preflight(name);
|
|
125662
|
+
if (!preflight.ok)
|
|
125663
|
+
return fail4(preflight.text);
|
|
125264
125664
|
try {
|
|
125265
125665
|
const text = await this.runSynthesized(name, clean3);
|
|
125266
125666
|
return { content: [{ type: "text", text }], isError: false };
|
|
@@ -125425,7 +125825,7 @@ function registerHindsightMcpShimCommand(program3) {
|
|
|
125425
125825
|
|
|
125426
125826
|
// src/cli/deliver-file.ts
|
|
125427
125827
|
init_client2();
|
|
125428
|
-
import { readFileSync as readFileSync97, statSync as
|
|
125828
|
+
import { readFileSync as readFileSync97, statSync as statSync65 } from "node:fs";
|
|
125429
125829
|
import { basename as basename15 } from "node:path";
|
|
125430
125830
|
|
|
125431
125831
|
// src/delivery/onedrive.ts
|
|
@@ -125764,7 +126164,7 @@ async function defaultResolveProvider() {
|
|
|
125764
126164
|
}
|
|
125765
126165
|
async function runDeliverFile(localPath, deps = {}) {
|
|
125766
126166
|
const agentName = safeAgentName(deps.agentName ?? process.env.SWITCHROOM_AGENT_NAME);
|
|
125767
|
-
const sizeOf = deps.fileSize ?? ((p) =>
|
|
126167
|
+
const sizeOf = deps.fileSize ?? ((p) => statSync65(p).size);
|
|
125768
126168
|
const read = deps.readFile ?? ((p) => new Uint8Array(readFileSync97(p)));
|
|
125769
126169
|
const resolveProvider = deps.resolveProvider ?? defaultResolveProvider;
|
|
125770
126170
|
let size;
|
|
@@ -126474,7 +126874,7 @@ import {
|
|
|
126474
126874
|
readdirSync as readdirSync41,
|
|
126475
126875
|
readFileSync as readFileSync99,
|
|
126476
126876
|
renameSync as renameSync29,
|
|
126477
|
-
statSync as
|
|
126877
|
+
statSync as statSync66,
|
|
126478
126878
|
unlinkSync as unlinkSync22,
|
|
126479
126879
|
writeSync as writeSync10
|
|
126480
126880
|
} from "node:fs";
|
|
@@ -126518,7 +126918,7 @@ function withAgentLock(paths, fn) {
|
|
|
126518
126918
|
if (e.code !== "EEXIST")
|
|
126519
126919
|
throw err;
|
|
126520
126920
|
try {
|
|
126521
|
-
const age = Date.now() -
|
|
126921
|
+
const age = Date.now() - statSync66(paths.lockPath).mtimeMs;
|
|
126522
126922
|
if (age > 30000) {
|
|
126523
126923
|
unlinkSync22(paths.lockPath);
|
|
126524
126924
|
continue;
|
|
@@ -126551,7 +126951,7 @@ function alignStagedOwnerToDir(stagingPath, targetDir) {
|
|
|
126551
126951
|
const euid = overlayWriterRuntime.geteuid();
|
|
126552
126952
|
if (euid === undefined)
|
|
126553
126953
|
return;
|
|
126554
|
-
const dirStat =
|
|
126954
|
+
const dirStat = statSync66(targetDir);
|
|
126555
126955
|
if (dirStat.uid === euid)
|
|
126556
126956
|
return;
|
|
126557
126957
|
overlayWriterRuntime.chown(stagingPath, dirStat.uid, dirStat.gid);
|
|
@@ -127853,7 +128253,7 @@ import {
|
|
|
127853
128253
|
realpathSync as realpathSync10,
|
|
127854
128254
|
renameSync as renameSync31,
|
|
127855
128255
|
rmSync as rmSync24,
|
|
127856
|
-
statSync as
|
|
128256
|
+
statSync as statSync67,
|
|
127857
128257
|
writeFileSync as writeFileSync49
|
|
127858
128258
|
} from "node:fs";
|
|
127859
128259
|
import { tmpdir as tmpdir7, homedir as homedir60 } from "node:os";
|
|
@@ -127903,7 +128303,7 @@ function isTarballPath(p) {
|
|
|
127903
128303
|
}
|
|
127904
128304
|
function loadFromDir(dir) {
|
|
127905
128305
|
const abs = realpathSync10(dir);
|
|
127906
|
-
if (!
|
|
128306
|
+
if (!statSync67(abs).isDirectory()) {
|
|
127907
128307
|
fail4(`--from path is not a directory: ${dir}`);
|
|
127908
128308
|
}
|
|
127909
128309
|
const files = {};
|
|
@@ -128164,7 +128564,7 @@ function registerSkillCommand(program3) {
|
|
|
128164
128564
|
if (!existsSync115(fromPath)) {
|
|
128165
128565
|
fail4(`--from path does not exist: ${opts.from}`);
|
|
128166
128566
|
}
|
|
128167
|
-
const st =
|
|
128567
|
+
const st = statSync67(fromPath);
|
|
128168
128568
|
if (st.isDirectory()) {
|
|
128169
128569
|
files = loadFromDir(fromPath);
|
|
128170
128570
|
} else if (isTarballPath(fromPath)) {
|
|
@@ -128231,7 +128631,7 @@ import {
|
|
|
128231
128631
|
readdirSync as readdirSync44,
|
|
128232
128632
|
renameSync as renameSync32,
|
|
128233
128633
|
rmSync as rmSync25,
|
|
128234
|
-
statSync as
|
|
128634
|
+
statSync as statSync68,
|
|
128235
128635
|
utimesSync,
|
|
128236
128636
|
writeFileSync as writeFileSync50
|
|
128237
128637
|
} from "node:fs";
|
|
@@ -128385,7 +128785,7 @@ function readStdinSync2() {
|
|
|
128385
128785
|
}
|
|
128386
128786
|
function loadFromDir2(dir) {
|
|
128387
128787
|
const abs = resolve62(dir);
|
|
128388
|
-
if (!
|
|
128788
|
+
if (!statSync68(abs).isDirectory()) {
|
|
128389
128789
|
fail5(`--from path is not a directory: ${dir}`);
|
|
128390
128790
|
}
|
|
128391
128791
|
const files = {};
|
|
@@ -128471,7 +128871,7 @@ function sweepTrash(agentsRoot, agent) {
|
|
|
128471
128871
|
continue;
|
|
128472
128872
|
const entPath = join120(trash, ent.name);
|
|
128473
128873
|
try {
|
|
128474
|
-
const st =
|
|
128874
|
+
const st = statSync68(entPath);
|
|
128475
128875
|
if (now2 - st.mtimeMs > TRASH_TTL_MS) {
|
|
128476
128876
|
rmSync25(entPath, { recursive: true, force: true });
|
|
128477
128877
|
}
|
|
@@ -128597,7 +128997,7 @@ function loadFiles(opts) {
|
|
|
128597
128997
|
if (!existsSync116(p)) {
|
|
128598
128998
|
fail5(`--from path does not exist: ${opts.from}`);
|
|
128599
128999
|
}
|
|
128600
|
-
const st =
|
|
129000
|
+
const st = statSync68(p);
|
|
128601
129001
|
if (st.isDirectory()) {
|
|
128602
129002
|
return loadFromDir2(p);
|
|
128603
129003
|
}
|
|
@@ -128818,7 +129218,7 @@ function listPersonalAction(opts) {
|
|
|
128818
129218
|
if (e.isFile()) {
|
|
128819
129219
|
fileCount += 1;
|
|
128820
129220
|
try {
|
|
128821
|
-
totalBytes +=
|
|
129221
|
+
totalBytes += statSync68(join120(sub, e.name)).size;
|
|
128822
129222
|
} catch {}
|
|
128823
129223
|
} else if (e.isDirectory()) {
|
|
128824
129224
|
walk2(join120(sub, e.name));
|
|
@@ -128992,7 +129392,7 @@ import { join as join125, resolve as resolve63, sep as sep10 } from "node:path";
|
|
|
128992
129392
|
import { existsSync as existsSync121, readFileSync as readFileSync109, realpathSync as realpathSync11 } from "node:fs";
|
|
128993
129393
|
|
|
128994
129394
|
// src/self-improve/apply-guard.ts
|
|
128995
|
-
import { existsSync as existsSync119, lstatSync as lstatSync17, readFileSync as readFileSync107, statSync as
|
|
129395
|
+
import { existsSync as existsSync119, lstatSync as lstatSync17, readFileSync as readFileSync107, statSync as statSync70 } from "node:fs";
|
|
128996
129396
|
|
|
128997
129397
|
// src/self-improve/config.ts
|
|
128998
129398
|
function intEnv(name, def) {
|
|
@@ -129013,7 +129413,7 @@ function resolveSelfImproveConfig() {
|
|
|
129013
129413
|
}
|
|
129014
129414
|
|
|
129015
129415
|
// src/self-improve/eval-gate.ts
|
|
129016
|
-
import { existsSync as existsSync117, readFileSync as readFileSync105, readdirSync as readdirSync45, statSync as
|
|
129416
|
+
import { existsSync as existsSync117, readFileSync as readFileSync105, readdirSync as readdirSync45, statSync as statSync69 } from "node:fs";
|
|
129017
129417
|
import { join as join122 } from "node:path";
|
|
129018
129418
|
import { spawnSync as spawnSync26 } from "node:child_process";
|
|
129019
129419
|
function evalsJsonPath(skillDir) {
|
|
@@ -129049,7 +129449,7 @@ function aggregateBenchmark(benchmarkDir, repoRoot, pythonBin = process.env.SWIT
|
|
|
129049
129449
|
}
|
|
129050
129450
|
function isBenchmarkDir(dir) {
|
|
129051
129451
|
try {
|
|
129052
|
-
if (!
|
|
129452
|
+
if (!statSync69(dir).isDirectory())
|
|
129053
129453
|
return false;
|
|
129054
129454
|
} catch {
|
|
129055
129455
|
return false;
|
|
@@ -129080,7 +129480,7 @@ function resolveBenchmarkDir(baseDir, explicit) {
|
|
|
129080
129480
|
}
|
|
129081
129481
|
if (entries.length === 0)
|
|
129082
129482
|
return null;
|
|
129083
|
-
entries.sort((a, b) =>
|
|
129483
|
+
entries.sort((a, b) => statSync69(b).mtimeMs - statSync69(a).mtimeMs);
|
|
129084
129484
|
return entries[0];
|
|
129085
129485
|
}
|
|
129086
129486
|
var CANDIDATE_CONFIGS = ["with_skill", "candidate", "new_skill", "after"];
|
|
@@ -129779,7 +130179,7 @@ function registerSelfImproveBenchCommand(program3) {
|
|
|
129779
130179
|
init_esm();
|
|
129780
130180
|
init_helpers();
|
|
129781
130181
|
var import_yaml26 = __toESM(require_dist(), 1);
|
|
129782
|
-
import { existsSync as existsSync122, readdirSync as readdirSync47, readFileSync as readFileSync110, statSync as
|
|
130182
|
+
import { existsSync as existsSync122, readdirSync as readdirSync47, readFileSync as readFileSync110, statSync as statSync71 } from "node:fs";
|
|
129783
130183
|
import { homedir as homedir65 } from "node:os";
|
|
129784
130184
|
import { join as join127, resolve as resolve64 } from "node:path";
|
|
129785
130185
|
var PERSONAL_PREFIX2 = "personal-";
|
|
@@ -129830,7 +130230,7 @@ function readSkillFrontmatter(skillDir) {
|
|
|
129830
130230
|
function statSkillMd(skillDir) {
|
|
129831
130231
|
const mdPath = join127(skillDir, "SKILL.md");
|
|
129832
130232
|
try {
|
|
129833
|
-
const st =
|
|
130233
|
+
const st = statSync71(mdPath);
|
|
129834
130234
|
return { size: st.size, mtime: st.mtime.toISOString() };
|
|
129835
130235
|
} catch {
|
|
129836
130236
|
return null;
|
|
@@ -129854,7 +130254,7 @@ function listPersonalSkills(agent, agentsRoot = defaultAgentsRoot()) {
|
|
|
129854
130254
|
continue;
|
|
129855
130255
|
const dirPath = join127(skillsDir, ent);
|
|
129856
130256
|
try {
|
|
129857
|
-
if (!
|
|
130257
|
+
if (!statSync71(dirPath).isDirectory())
|
|
129858
130258
|
continue;
|
|
129859
130259
|
} catch {
|
|
129860
130260
|
continue;
|
|
@@ -129894,7 +130294,7 @@ function listSharedSkills(sharedRoot = defaultSharedRoot2()) {
|
|
|
129894
130294
|
continue;
|
|
129895
130295
|
const dirPath = join127(sharedRoot, ent);
|
|
129896
130296
|
try {
|
|
129897
|
-
if (!
|
|
130297
|
+
if (!statSync71(dirPath).isDirectory())
|
|
129898
130298
|
continue;
|
|
129899
130299
|
} catch {
|
|
129900
130300
|
continue;
|
|
@@ -129930,7 +130330,7 @@ function listBundledSkills(bundledRoot = defaultBundledRoot2()) {
|
|
|
129930
130330
|
continue;
|
|
129931
130331
|
const dirPath = join127(bundledRoot, ent);
|
|
129932
130332
|
try {
|
|
129933
|
-
if (!
|
|
130333
|
+
if (!statSync71(dirPath).isDirectory())
|
|
129934
130334
|
continue;
|
|
129935
130335
|
} catch {
|
|
129936
130336
|
continue;
|
|
@@ -130079,7 +130479,7 @@ import {
|
|
|
130079
130479
|
mkdirSync as mkdirSync71,
|
|
130080
130480
|
readdirSync as readdirSync48,
|
|
130081
130481
|
writeFileSync as writeFileSync53,
|
|
130082
|
-
statSync as
|
|
130482
|
+
statSync as statSync72,
|
|
130083
130483
|
lstatSync as lstatSync18,
|
|
130084
130484
|
realpathSync as realpathSync12,
|
|
130085
130485
|
copyFileSync as copyFileSync16
|
|
@@ -130600,7 +131000,7 @@ function doStatus() {
|
|
|
130600
131000
|
continue;
|
|
130601
131001
|
const sockPath = join128(dir, name, "sock");
|
|
130602
131002
|
if (existsSync124(sockPath)) {
|
|
130603
|
-
const st =
|
|
131003
|
+
const st = statSync72(sockPath);
|
|
130604
131004
|
if ((st.mode & 61440) === 49152) {
|
|
130605
131005
|
entries.push(`${name} \u2192 ${sockPath}`);
|
|
130606
131006
|
}
|
|
@@ -131501,7 +131901,7 @@ init_install_cron();
|
|
|
131501
131901
|
|
|
131502
131902
|
// src/hindsight-watch/probe.ts
|
|
131503
131903
|
import { spawnSync as spawnSync32 } from "node:child_process";
|
|
131504
|
-
import { readFileSync as readFileSync115, readdirSync as readdirSync52, statSync as
|
|
131904
|
+
import { readFileSync as readFileSync115, readdirSync as readdirSync52, statSync as statSync74 } from "node:fs";
|
|
131505
131905
|
import { homedir as homedir70 } from "node:os";
|
|
131506
131906
|
import { resolve as resolve66 } from "node:path";
|
|
131507
131907
|
|
|
@@ -131629,7 +132029,7 @@ function readLlmSignals(series) {
|
|
|
131629
132029
|
}
|
|
131630
132030
|
|
|
131631
132031
|
// src/hindsight-watch/recall-log.ts
|
|
131632
|
-
import { closeSync as closeSync26, existsSync as existsSync129, openSync as openSync26, readdirSync as readdirSync51, readSync as readSync7, statSync as
|
|
132032
|
+
import { closeSync as closeSync26, existsSync as existsSync129, openSync as openSync26, readdirSync as readdirSync51, readSync as readSync7, statSync as statSync73 } from "node:fs";
|
|
131633
132033
|
import { join as join132 } from "node:path";
|
|
131634
132034
|
var RECALL_WINDOW_ROWS = 200;
|
|
131635
132035
|
var RECALL_MAX_TAIL_BYTES = 1024 * 1024;
|
|
@@ -131644,7 +132044,7 @@ function readRecallLogTail2(path10, windowRows = RECALL_WINDOW_ROWS) {
|
|
|
131644
132044
|
let truncatedHead = false;
|
|
131645
132045
|
let fd;
|
|
131646
132046
|
try {
|
|
131647
|
-
const size =
|
|
132047
|
+
const size = statSync73(path10).size;
|
|
131648
132048
|
const start = Math.max(0, size - RECALL_MAX_TAIL_BYTES);
|
|
131649
132049
|
truncatedHead = start > 0;
|
|
131650
132050
|
const length = size - start;
|
|
@@ -131892,7 +132292,7 @@ function readDropCount(hindsightDir) {
|
|
|
131892
132292
|
const path10 = resolve66(hindsightDir, "pending-drops.json");
|
|
131893
132293
|
let parsed;
|
|
131894
132294
|
try {
|
|
131895
|
-
if (
|
|
132295
|
+
if (statSync74(path10).size > DROPS_LEDGER_MAX_BYTES)
|
|
131896
132296
|
return 0;
|
|
131897
132297
|
parsed = JSON.parse(readFileSync115(path10, "utf8"));
|
|
131898
132298
|
} catch {
|