switchroom 0.19.22 → 0.19.23
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/agent-scheduler/index.js +2 -1
- package/dist/auth-broker/index.js +68 -1
- package/dist/cli/notion-write-pretool.mjs +2 -1
- package/dist/cli/switchroom.js +552 -320
- package/dist/host-control/main.js +69 -2
- package/dist/vault/approvals/kernel-server.js +71 -4
- package/dist/vault/broker/server.js +71 -4
- package/package.json +5 -4
- package/profiles/_base/start.sh.hbs +101 -0
- package/profiles/_shared/agent-self-service.md.hbs +64 -109
- package/profiles/_shared/delegation-golden-rule.md.hbs +5 -5
- package/profiles/_shared/dev-protocol.md.hbs +13 -42
- package/profiles/_shared/execution-discipline.md.hbs +7 -14
- package/profiles/coding/CLAUDE.md.hbs +0 -6
- package/profiles/default/CLAUDE.md.hbs +21 -50
- package/skills/dev-protocol/SKILL.md +90 -107
- package/telegram-plugin/bunfig.toml +10 -0
- package/telegram-plugin/dist/gateway/gateway.js +108 -16
- package/telegram-plugin/gateway/backstop-delivery.ts +97 -16
- package/telegram-plugin/gateway/captured-answer-resume.ts +46 -17
- package/telegram-plugin/gateway/gateway.ts +9 -7
- package/telegram-plugin/gateway/outbound-send-path.ts +8 -1
- package/telegram-plugin/gateway/stream-render.ts +6 -0
- package/telegram-plugin/gateway/turn-record-status.ts +19 -0
- package/telegram-plugin/gateway/turns-jsonl-rotate.ts +65 -0
- package/telegram-plugin/tests/agent-state-dir-preload.test.ts +33 -0
- package/telegram-plugin/tests/backstop-delivery.test.ts +204 -7
- package/telegram-plugin/tests/backstop-readback-probe.test.ts +12 -0
- package/telegram-plugin/tests/captured-answer-resume.test.ts +104 -0
- package/telegram-plugin/tests/turns-jsonl-rotate.test.ts +92 -1
- package/vendor/hindsight-memory/scripts/drain_pending.py +113 -11
- package/vendor/hindsight-memory/scripts/lib/pending.py +802 -65
- package/vendor/hindsight-memory/scripts/lib/retain_split.py +54 -7
- package/vendor/hindsight-memory/scripts/tests/test_pending_drops.py +1445 -11
- package/vendor/hindsight-memory/scripts/tests/test_retain_split.py +78 -6
- package/vendor/hindsight-memory/tests/test_drain_pending.py +17 -2
- package/vendor/hindsight-memory/tests/test_pending.py +12 -4
package/dist/cli/switchroom.js
CHANGED
|
@@ -2120,7 +2120,7 @@ var init_esm = __esm(() => {
|
|
|
2120
2120
|
});
|
|
2121
2121
|
|
|
2122
2122
|
// src/build-info.ts
|
|
2123
|
-
var VERSION = "0.19.
|
|
2123
|
+
var VERSION = "0.19.23", COMMIT_SHA = "56e3c01e";
|
|
2124
2124
|
|
|
2125
2125
|
// src/cli/resolve-version.ts
|
|
2126
2126
|
import { existsSync, readFileSync } from "node:fs";
|
|
@@ -13948,7 +13948,8 @@ var init_schema = __esm(() => {
|
|
|
13948
13948
|
retain: HindsightPerOpLlmSchema.optional().describe("Per-op override for the `retain` LLM op (memory ingestion). Emits " + "`HINDSIGHT_API_RETAIN_LLM_*`. Absent \u2192 uses the global model/provider."),
|
|
13949
13949
|
reflect: HindsightPerOpLlmSchema.optional().describe("Per-op override for the `reflect` LLM op (synthesis / mental-model " + "refresh). Emits `HINDSIGHT_API_REFLECT_LLM_*`. Absent \u2192 uses global."),
|
|
13950
13950
|
consolidation: HindsightPerOpLlmSchema.optional().describe("Per-op override for the `consolidation` LLM op (background memory " + "merge). Emits `HINDSIGHT_API_CONSOLIDATION_LLM_*`. Absent \u2192 global.")
|
|
13951
|
-
}).optional().describe("LLM knob for the hindsight container. The flat `provider`/`model` set " + "the global default (backward-compatible); optional `retain`/`reflect`/" + "`consolidation` blocks override individual ops. All fields optional; " + "unset fields fall back to the hard-coded defaults.")
|
|
13951
|
+
}).optional().describe("LLM knob for the hindsight container. The flat `provider`/`model` set " + "the global default (backward-compatible); optional `retain`/`reflect`/" + "`consolidation` blocks override individual ops. All fields optional; " + "unset fields fall back to the hard-coded defaults."),
|
|
13952
|
+
env: exports_external.record(exports_external.union([exports_external.string(), exports_external.number(), exports_external.boolean()])).optional().describe("Operator overrides for switchroom's capability-gated Hindsight " + "performance defaults. Only the keys switchroom actually manages are " + "honoured (`HINDSIGHT_PERF_ENV_KEYS` in " + "src/setup/hindsight-perf-defaults.ts: RERANKER_LOCAL_FP16, " + "LLM_MAX_CONCURRENT, RETAIN/CONSOLIDATION_LLM_MAX_CONCURRENT, " + "RECALL_MAX_CANDIDATES_PER_SOURCE, LINK_EXPANSION_PER_ENTITY_LIMIT, " + "LINK_EXPANSION_TIMEOUT, LLM_REASONING_EFFORT), plus the " + "embedded-PostgreSQL (pg0) sizing keys switchroom manages in " + "src/setup/hindsight-pg-defaults.ts (`HINDSIGHT_PG_ENV_KEYS`: " + "SWITCHROOM_HINDSIGHT_PG_EFFECTIVE_CACHE_SIZE, " + "SWITCHROOM_HINDSIGHT_PG_SHARED_BUFFERS \u2014 a postgres size string such " + "as `4GB`, or the sentinel `off` to leave pg0's own default for that " + "one knob). A value set here " + "REPLACES switchroom's default and is emitted even when the gating " + "capability is absent, so an operator can always force a knob. Other " + "`HINDSIGHT_API_*` keys are deliberately IGNORED \u2014 a blanket " + "passthrough would collide with the vars startHindsight() derives " + "itself (HINDSIGHT_API_PORT, the retain token/deadline budget).")
|
|
13952
13953
|
});
|
|
13953
13954
|
MicrosoftWorkspaceConfigSchema = exports_external.object({
|
|
13954
13955
|
microsoft_client_id: exports_external.string().min(1).optional().describe("Microsoft OAuth application (client) ID from Entra portal " + "(literal string or vault reference e.g. " + "'vault:microsoft-oauth-client-id'). OPTIONAL \u2014 omit it to use " + "switchroom's shipped default Microsoft app (zero-config). " + "Set it only to bring your own Entra app (BYO)."),
|
|
@@ -15555,6 +15556,181 @@ var init_timeout_budget = __esm(() => {
|
|
|
15555
15556
|
};
|
|
15556
15557
|
});
|
|
15557
15558
|
|
|
15559
|
+
// src/setup/host-capabilities.ts
|
|
15560
|
+
import { existsSync as existsSync5, mkdirSync, readFileSync as readFileSync5, writeFileSync } from "node:fs";
|
|
15561
|
+
import { dirname as dirname2 } from "node:path";
|
|
15562
|
+
function hostCapabilitiesPath() {
|
|
15563
|
+
return resolveStatePath("host-capabilities.json");
|
|
15564
|
+
}
|
|
15565
|
+
function saveVoiceCapability(caps, now = () => new Date) {
|
|
15566
|
+
const doc = {
|
|
15567
|
+
version: HOST_CAPABILITIES_VERSION,
|
|
15568
|
+
voice: {
|
|
15569
|
+
gpuPresent: caps.gpuPresent,
|
|
15570
|
+
containerToolkit: caps.containerToolkit,
|
|
15571
|
+
engine: caps.engine,
|
|
15572
|
+
detectedAt: now().toISOString()
|
|
15573
|
+
}
|
|
15574
|
+
};
|
|
15575
|
+
const path = hostCapabilitiesPath();
|
|
15576
|
+
mkdirSync(dirname2(path), { recursive: true });
|
|
15577
|
+
writeFileSync(path, JSON.stringify(doc, null, 2) + `
|
|
15578
|
+
`, {
|
|
15579
|
+
encoding: "utf-8",
|
|
15580
|
+
mode: 384
|
|
15581
|
+
});
|
|
15582
|
+
return doc;
|
|
15583
|
+
}
|
|
15584
|
+
function loadHostCapabilities() {
|
|
15585
|
+
const path = hostCapabilitiesPath();
|
|
15586
|
+
if (!existsSync5(path))
|
|
15587
|
+
return null;
|
|
15588
|
+
try {
|
|
15589
|
+
const parsed = JSON.parse(readFileSync5(path, "utf-8"));
|
|
15590
|
+
if (parsed && typeof parsed === "object" && "voice" in parsed && typeof parsed.voice === "object") {
|
|
15591
|
+
return parsed;
|
|
15592
|
+
}
|
|
15593
|
+
return null;
|
|
15594
|
+
} catch {
|
|
15595
|
+
return null;
|
|
15596
|
+
}
|
|
15597
|
+
}
|
|
15598
|
+
var HOST_CAPABILITIES_VERSION = 1;
|
|
15599
|
+
var init_host_capabilities = __esm(() => {
|
|
15600
|
+
init_paths();
|
|
15601
|
+
});
|
|
15602
|
+
|
|
15603
|
+
// src/setup/hindsight-perf-defaults.ts
|
|
15604
|
+
function resolveHindsightPerfOverrides(configEnv, processEnv = process.env) {
|
|
15605
|
+
const out = new Map;
|
|
15606
|
+
for (const key of HINDSIGHT_PERF_ENV_KEYS) {
|
|
15607
|
+
const fromProcess = processEnv[key];
|
|
15608
|
+
if (typeof fromProcess === "string" && fromProcess.trim() !== "") {
|
|
15609
|
+
out.set(key, fromProcess.trim());
|
|
15610
|
+
}
|
|
15611
|
+
}
|
|
15612
|
+
for (const [key, raw] of Object.entries(configEnv ?? {})) {
|
|
15613
|
+
if (!HINDSIGHT_PERF_ENV_KEYS.has(key))
|
|
15614
|
+
continue;
|
|
15615
|
+
const value = String(raw).trim();
|
|
15616
|
+
if (value === "")
|
|
15617
|
+
continue;
|
|
15618
|
+
out.set(key, value);
|
|
15619
|
+
}
|
|
15620
|
+
return out;
|
|
15621
|
+
}
|
|
15622
|
+
function hindsightPerfEnv(caps, overrides = new Map) {
|
|
15623
|
+
const groups = [
|
|
15624
|
+
HINDSIGHT_PERF_DEFAULTS_UNGATED
|
|
15625
|
+
];
|
|
15626
|
+
if (caps.gpu === true)
|
|
15627
|
+
groups.push(HINDSIGHT_PERF_DEFAULTS_GPU);
|
|
15628
|
+
if (caps.localLlm === true)
|
|
15629
|
+
groups.push(HINDSIGHT_PERF_DEFAULTS_LOCAL_LLM);
|
|
15630
|
+
const out = [];
|
|
15631
|
+
const emitted = new Set;
|
|
15632
|
+
for (const group of groups) {
|
|
15633
|
+
for (const [key, value] of group) {
|
|
15634
|
+
if (emitted.has(key))
|
|
15635
|
+
continue;
|
|
15636
|
+
emitted.add(key);
|
|
15637
|
+
out.push([key, overrides.get(key) ?? value]);
|
|
15638
|
+
}
|
|
15639
|
+
}
|
|
15640
|
+
for (const key of [...overrides.keys()].sort()) {
|
|
15641
|
+
if (emitted.has(key))
|
|
15642
|
+
continue;
|
|
15643
|
+
emitted.add(key);
|
|
15644
|
+
out.push([key, overrides.get(key)]);
|
|
15645
|
+
}
|
|
15646
|
+
return out;
|
|
15647
|
+
}
|
|
15648
|
+
var HINDSIGHT_RERANKER_MAX_CANDIDATES_FOR_DERIVATION = 150, HINDSIGHT_DEFAULT_RECALL_MAX_CANDIDATES_PER_SOURCE, HINDSIGHT_DEFAULT_LINK_EXPANSION_PER_ENTITY_LIMIT = 50, HINDSIGHT_DEFAULT_LINK_EXPANSION_TIMEOUT_S = 2, HINDSIGHT_DEFAULT_LLM_REASONING_EFFORT = "low", HINDSIGHT_DEFAULT_LLM_MAX_CONCURRENT = 4, HINDSIGHT_DEFAULT_RETAIN_LLM_MAX_CONCURRENT = 1, HINDSIGHT_DEFAULT_CONSOLIDATION_LLM_MAX_CONCURRENT = 1, HINDSIGHT_DEFAULT_RERANKER_LOCAL_FP16 = "true", HINDSIGHT_PERF_DEFAULTS_UNGATED, HINDSIGHT_PERF_DEFAULTS_GPU, HINDSIGHT_PERF_DEFAULTS_LOCAL_LLM, HINDSIGHT_PERF_ENV_KEYS;
|
|
15649
|
+
var init_hindsight_perf_defaults = __esm(() => {
|
|
15650
|
+
HINDSIGHT_DEFAULT_RECALL_MAX_CANDIDATES_PER_SOURCE = Math.ceil(HINDSIGHT_RERANKER_MAX_CANDIDATES_FOR_DERIVATION * 0.4);
|
|
15651
|
+
HINDSIGHT_PERF_DEFAULTS_UNGATED = [
|
|
15652
|
+
[
|
|
15653
|
+
"HINDSIGHT_API_RECALL_MAX_CANDIDATES_PER_SOURCE",
|
|
15654
|
+
String(HINDSIGHT_DEFAULT_RECALL_MAX_CANDIDATES_PER_SOURCE)
|
|
15655
|
+
],
|
|
15656
|
+
[
|
|
15657
|
+
"HINDSIGHT_API_LINK_EXPANSION_PER_ENTITY_LIMIT",
|
|
15658
|
+
String(HINDSIGHT_DEFAULT_LINK_EXPANSION_PER_ENTITY_LIMIT)
|
|
15659
|
+
],
|
|
15660
|
+
[
|
|
15661
|
+
"HINDSIGHT_API_LINK_EXPANSION_TIMEOUT",
|
|
15662
|
+
String(HINDSIGHT_DEFAULT_LINK_EXPANSION_TIMEOUT_S)
|
|
15663
|
+
],
|
|
15664
|
+
["HINDSIGHT_API_LLM_REASONING_EFFORT", HINDSIGHT_DEFAULT_LLM_REASONING_EFFORT]
|
|
15665
|
+
];
|
|
15666
|
+
HINDSIGHT_PERF_DEFAULTS_GPU = [
|
|
15667
|
+
["HINDSIGHT_API_RERANKER_LOCAL_FP16", HINDSIGHT_DEFAULT_RERANKER_LOCAL_FP16]
|
|
15668
|
+
];
|
|
15669
|
+
HINDSIGHT_PERF_DEFAULTS_LOCAL_LLM = [
|
|
15670
|
+
["HINDSIGHT_API_LLM_MAX_CONCURRENT", String(HINDSIGHT_DEFAULT_LLM_MAX_CONCURRENT)],
|
|
15671
|
+
[
|
|
15672
|
+
"HINDSIGHT_API_RETAIN_LLM_MAX_CONCURRENT",
|
|
15673
|
+
String(HINDSIGHT_DEFAULT_RETAIN_LLM_MAX_CONCURRENT)
|
|
15674
|
+
],
|
|
15675
|
+
[
|
|
15676
|
+
"HINDSIGHT_API_CONSOLIDATION_LLM_MAX_CONCURRENT",
|
|
15677
|
+
String(HINDSIGHT_DEFAULT_CONSOLIDATION_LLM_MAX_CONCURRENT)
|
|
15678
|
+
]
|
|
15679
|
+
];
|
|
15680
|
+
HINDSIGHT_PERF_ENV_KEYS = new Set([
|
|
15681
|
+
...HINDSIGHT_PERF_DEFAULTS_UNGATED,
|
|
15682
|
+
...HINDSIGHT_PERF_DEFAULTS_GPU,
|
|
15683
|
+
...HINDSIGHT_PERF_DEFAULTS_LOCAL_LLM
|
|
15684
|
+
].map(([k]) => k));
|
|
15685
|
+
});
|
|
15686
|
+
|
|
15687
|
+
// src/setup/hindsight-pg-defaults.ts
|
|
15688
|
+
function pgMib(mib) {
|
|
15689
|
+
return `${mib}MB`;
|
|
15690
|
+
}
|
|
15691
|
+
function resolveHindsightPgOverrides(configEnv, processEnv = process.env) {
|
|
15692
|
+
const out = new Map;
|
|
15693
|
+
for (const key of HINDSIGHT_PG_ENV_KEYS) {
|
|
15694
|
+
const fromProcess = processEnv[key];
|
|
15695
|
+
if (typeof fromProcess === "string" && fromProcess.trim() !== "") {
|
|
15696
|
+
out.set(key, fromProcess.trim());
|
|
15697
|
+
}
|
|
15698
|
+
}
|
|
15699
|
+
for (const [key, raw] of Object.entries(configEnv ?? {})) {
|
|
15700
|
+
if (!HINDSIGHT_PG_ENV_KEYS.has(key))
|
|
15701
|
+
continue;
|
|
15702
|
+
const value = String(raw).trim();
|
|
15703
|
+
if (value === "")
|
|
15704
|
+
continue;
|
|
15705
|
+
out.set(key, value);
|
|
15706
|
+
}
|
|
15707
|
+
return out;
|
|
15708
|
+
}
|
|
15709
|
+
function hindsightPgEnv(overrides = new Map) {
|
|
15710
|
+
const out = [];
|
|
15711
|
+
const emitted = new Set;
|
|
15712
|
+
for (const [key, value] of HINDSIGHT_PG_DEFAULTS) {
|
|
15713
|
+
if (emitted.has(key))
|
|
15714
|
+
continue;
|
|
15715
|
+
emitted.add(key);
|
|
15716
|
+
out.push([key, overrides.get(key) ?? value]);
|
|
15717
|
+
}
|
|
15718
|
+
return out;
|
|
15719
|
+
}
|
|
15720
|
+
var HINDSIGHT_PG_MEM_LIMIT_MIB_FOR_DERIVATION, HINDSIGHT_PG_APP_ANON_MIB = 2560, HINDSIGHT_PG_PAGE_CACHE_FLOOR_MIB = 2048, HINDSIGHT_PG_SHARED_BUFFERS_BUDGET_MIB, HINDSIGHT_PG_DEFAULT_SHARED_BUFFERS_MIB = 1536, HINDSIGHT_PG_DEFAULT_EFFECTIVE_CACHE_SIZE_MIB = 4096, HINDSIGHT_PG_EFFECTIVE_CACHE_SIZE_ENV = "SWITCHROOM_HINDSIGHT_PG_EFFECTIVE_CACHE_SIZE", HINDSIGHT_PG_SHARED_BUFFERS_ENV = "SWITCHROOM_HINDSIGHT_PG_SHARED_BUFFERS", HINDSIGHT_PG_DEFAULTS, HINDSIGHT_PG_ENV_KEYS;
|
|
15721
|
+
var init_hindsight_pg_defaults = __esm(() => {
|
|
15722
|
+
HINDSIGHT_PG_MEM_LIMIT_MIB_FOR_DERIVATION = 8 * 1024;
|
|
15723
|
+
HINDSIGHT_PG_SHARED_BUFFERS_BUDGET_MIB = HINDSIGHT_PG_MEM_LIMIT_MIB_FOR_DERIVATION - HINDSIGHT_PG_APP_ANON_MIB - HINDSIGHT_PG_PAGE_CACHE_FLOOR_MIB;
|
|
15724
|
+
HINDSIGHT_PG_DEFAULTS = [
|
|
15725
|
+
[
|
|
15726
|
+
HINDSIGHT_PG_EFFECTIVE_CACHE_SIZE_ENV,
|
|
15727
|
+
pgMib(HINDSIGHT_PG_DEFAULT_EFFECTIVE_CACHE_SIZE_MIB)
|
|
15728
|
+
],
|
|
15729
|
+
[HINDSIGHT_PG_SHARED_BUFFERS_ENV, pgMib(HINDSIGHT_PG_DEFAULT_SHARED_BUFFERS_MIB)]
|
|
15730
|
+
];
|
|
15731
|
+
HINDSIGHT_PG_ENV_KEYS = new Set(HINDSIGHT_PG_DEFAULTS.map(([k]) => k));
|
|
15732
|
+
});
|
|
15733
|
+
|
|
15558
15734
|
// src/util/atomic.ts
|
|
15559
15735
|
var exports_atomic = {};
|
|
15560
15736
|
__export(exports_atomic, {
|
|
@@ -15841,7 +16017,7 @@ function resolveHindsightLlm(llm, litellm) {
|
|
|
15841
16017
|
function isLoopbackHttpUrl(url) {
|
|
15842
16018
|
try {
|
|
15843
16019
|
const u = new URL(url.includes("://") ? url : `http://${url}`);
|
|
15844
|
-
const h = (u.hostname || "").toLowerCase();
|
|
16020
|
+
const h = (u.hostname || "").toLowerCase().replace(/^\[|\]$/g, "");
|
|
15845
16021
|
return h === "localhost" || h === "127.0.0.1" || h === "::1";
|
|
15846
16022
|
} catch {
|
|
15847
16023
|
return false;
|
|
@@ -15869,6 +16045,45 @@ function hindsightNeedsHostNetwork(llm, litellm) {
|
|
|
15869
16045
|
return true;
|
|
15870
16046
|
return collectHindsightLlmBaseUrls(llm).some(isLoopbackHttpUrl);
|
|
15871
16047
|
}
|
|
16048
|
+
function isSelfHostedHttpUrl(url) {
|
|
16049
|
+
let host;
|
|
16050
|
+
try {
|
|
16051
|
+
const u = new URL(url.includes("://") ? url : `http://${url}`);
|
|
16052
|
+
host = (u.hostname || "").toLowerCase().replace(/^\[|\]$/g, "");
|
|
16053
|
+
} catch {
|
|
16054
|
+
return false;
|
|
16055
|
+
}
|
|
16056
|
+
if (!host)
|
|
16057
|
+
return false;
|
|
16058
|
+
if (isLoopbackHttpUrl(url))
|
|
16059
|
+
return true;
|
|
16060
|
+
if (host === "host.docker.internal" || host === "gateway.docker.internal")
|
|
16061
|
+
return true;
|
|
16062
|
+
if (host.endsWith(".local") || host.endsWith(".internal"))
|
|
16063
|
+
return true;
|
|
16064
|
+
if (/^f[cd][0-9a-f]{2}:/.test(host) || /^fe[89ab][0-9a-f]:/.test(host))
|
|
16065
|
+
return true;
|
|
16066
|
+
const v4 = host.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/);
|
|
16067
|
+
if (!v4)
|
|
16068
|
+
return false;
|
|
16069
|
+
const [a, b] = [Number(v4[1]), Number(v4[2])];
|
|
16070
|
+
if (a === 10)
|
|
16071
|
+
return true;
|
|
16072
|
+
if (a === 127)
|
|
16073
|
+
return true;
|
|
16074
|
+
if (a === 192 && b === 168)
|
|
16075
|
+
return true;
|
|
16076
|
+
if (a === 172 && b >= 16 && b <= 31)
|
|
16077
|
+
return true;
|
|
16078
|
+
if (a === 169 && b === 254)
|
|
16079
|
+
return true;
|
|
16080
|
+
return false;
|
|
16081
|
+
}
|
|
16082
|
+
function hindsightLocalLlmEnabled(llm, litellm, override) {
|
|
16083
|
+
if (override !== undefined)
|
|
16084
|
+
return override;
|
|
16085
|
+
return collectHindsightLlmBaseUrls(llm, litellm).some(isSelfHostedHttpUrl);
|
|
16086
|
+
}
|
|
15872
16087
|
function pickHindsightLiteLlmProbeUrl(llm, litellm) {
|
|
15873
16088
|
return collectHindsightLlmBaseUrls(llm, litellm)[0];
|
|
15874
16089
|
}
|
|
@@ -15885,7 +16100,22 @@ function buildLiteLlmAwareHealthPy(apiPort, litellmBaseUrl) {
|
|
|
15885
16100
|
function buildLiteLlmAwareHealthCmd(apiPort, litellmBaseUrl) {
|
|
15886
16101
|
return `python3 -c "${buildLiteLlmAwareHealthPy(apiPort, litellmBaseUrl)}"`;
|
|
15887
16102
|
}
|
|
15888
|
-
function
|
|
16103
|
+
function hindsightGpuEnabled(override) {
|
|
16104
|
+
if (override !== undefined)
|
|
16105
|
+
return override;
|
|
16106
|
+
const caps = loadHostCapabilities();
|
|
16107
|
+
return caps?.voice?.gpuPresent === true && caps?.voice?.containerToolkit === true;
|
|
16108
|
+
}
|
|
16109
|
+
function hindsightPerfEnvPairs(llm, litellm, gpu, perf) {
|
|
16110
|
+
return hindsightPerfEnv({
|
|
16111
|
+
gpu: hindsightGpuEnabled(gpu),
|
|
16112
|
+
localLlm: hindsightLocalLlmEnabled(llm, litellm, perf?.localLlm)
|
|
16113
|
+
}, resolveHindsightPerfOverrides(perf?.env, perf?.processEnv));
|
|
16114
|
+
}
|
|
16115
|
+
function hindsightPgEnvPairs(perf) {
|
|
16116
|
+
return hindsightPgEnv(resolveHindsightPgOverrides(perf?.env, perf?.processEnv));
|
|
16117
|
+
}
|
|
16118
|
+
function startHindsight(ports, litellm, imageTag, llm, mirrorDir, gpu, perf) {
|
|
15889
16119
|
const apiPort = ports?.apiPort ?? HINDSIGHT_DEFAULT_API_PORT;
|
|
15890
16120
|
const uiPort = ports?.uiPort ?? HINDSIGHT_DEFAULT_UI_PORT;
|
|
15891
16121
|
const { provider: llmProvider, model: llmModel } = resolveHindsightLlm(llm, litellm);
|
|
@@ -15920,7 +16150,9 @@ function startHindsight(ports, litellm, imageTag, llm, mirrorDir) {
|
|
|
15920
16150
|
"-e",
|
|
15921
16151
|
`HINDSIGHT_API_CONSOLIDATION_MAX_MEMORIES_PER_ROUND=${HINDSIGHT_DEFAULT_CONSOLIDATION_MAX_MEMORIES_PER_ROUND}`,
|
|
15922
16152
|
"-e",
|
|
15923
|
-
`HINDSIGHT_API_WORKER_ID=${HINDSIGHT_DEFAULT_WORKER_ID}
|
|
16153
|
+
`HINDSIGHT_API_WORKER_ID=${HINDSIGHT_DEFAULT_WORKER_ID}`,
|
|
16154
|
+
...hindsightPerfEnvPairs(llm, litellm, gpu, perf).flatMap(([k, v]) => ["-e", `${k}=${v}`]),
|
|
16155
|
+
...hindsightPgEnvPairs(perf).flatMap(([k, v]) => ["-e", `${k}=${v}`])
|
|
15924
16156
|
];
|
|
15925
16157
|
if (llmProvider === "claude-code") {
|
|
15926
16158
|
envArgs.push("-e", `ANTHROPIC_MODEL=${llmModel}`);
|
|
@@ -15943,6 +16175,7 @@ x-litellm-tags: service:hindsight`);
|
|
|
15943
16175
|
`--memory-reservation=${HINDSIGHT_DEFAULT_MEM_RESERVATION}`,
|
|
15944
16176
|
`--pids-limit=${HINDSIGHT_DEFAULT_PIDS_LIMIT}`,
|
|
15945
16177
|
`--shm-size=${HINDSIGHT_DEFAULT_SHM_SIZE}`,
|
|
16178
|
+
...hindsightGpuEnabled(gpu) ? ["--gpus", "all"] : [],
|
|
15946
16179
|
...(() => {
|
|
15947
16180
|
const hostNet = hindsightNeedsHostNetwork(llm, litellm);
|
|
15948
16181
|
const healthApiPort = hostNet ? apiPort : 8888;
|
|
@@ -16078,10 +16311,11 @@ function getHindsightStatus() {
|
|
|
16078
16311
|
return null;
|
|
16079
16312
|
}
|
|
16080
16313
|
}
|
|
16081
|
-
function generateHindsightComposeSnippet(llm, mirrorDir, litellm) {
|
|
16314
|
+
function generateHindsightComposeSnippet(llm, mirrorDir, litellm, gpu, perf) {
|
|
16082
16315
|
const { provider: llmProvider, model: llmModel } = resolveHindsightLlm(llm, litellm);
|
|
16083
16316
|
const perOpLlm = resolveHindsightPerOpLlm(llm);
|
|
16084
16317
|
const hostNetwork = hindsightNeedsHostNetwork(llm, litellm);
|
|
16318
|
+
const gpuEnabled = hindsightGpuEnabled(gpu);
|
|
16085
16319
|
const apiPort = HINDSIGHT_DEFAULT_API_PORT;
|
|
16086
16320
|
const internalApiPort = hostNetwork ? apiPort : 8888;
|
|
16087
16321
|
const probeUrl = pickHindsightLiteLlmProbeUrl(llm, litellm);
|
|
@@ -16147,10 +16381,21 @@ function generateHindsightComposeSnippet(llm, mirrorDir, litellm) {
|
|
|
16147
16381
|
` - HINDSIGHT_API_CONSOLIDATION_LLM_PARALLELISM=${HINDSIGHT_DEFAULT_CONSOLIDATION_LLM_PARALLELISM}`,
|
|
16148
16382
|
` - HINDSIGHT_API_CONSOLIDATION_MAX_MEMORIES_PER_ROUND=${HINDSIGHT_DEFAULT_CONSOLIDATION_MAX_MEMORIES_PER_ROUND}`,
|
|
16149
16383
|
` - HINDSIGHT_API_WORKER_ID=${HINDSIGHT_DEFAULT_WORKER_ID}`,
|
|
16384
|
+
...hindsightPerfEnvPairs(llm, litellm, gpu, perf).map(([k, v]) => ` - ${k}=${v}`),
|
|
16385
|
+
...hindsightPgEnvPairs(perf).map(([k, v]) => ` - ${k}=${v}`),
|
|
16150
16386
|
` mem_limit: ${HINDSIGHT_DEFAULT_MEM_LIMIT}`,
|
|
16151
16387
|
` mem_reservation: ${HINDSIGHT_DEFAULT_MEM_RESERVATION}`,
|
|
16152
16388
|
` pids_limit: ${HINDSIGHT_DEFAULT_PIDS_LIMIT}`,
|
|
16153
16389
|
` shm_size: ${HINDSIGHT_DEFAULT_SHM_SIZE}`,
|
|
16390
|
+
...gpuEnabled ? [
|
|
16391
|
+
" deploy:",
|
|
16392
|
+
" resources:",
|
|
16393
|
+
" reservations:",
|
|
16394
|
+
" devices:",
|
|
16395
|
+
" - driver: nvidia",
|
|
16396
|
+
" count: 1",
|
|
16397
|
+
' capabilities: ["gpu"]'
|
|
16398
|
+
] : [],
|
|
16154
16399
|
" healthcheck:",
|
|
16155
16400
|
` test: ${JSON.stringify(["CMD", "python3", "-c", healthPy])}`,
|
|
16156
16401
|
" interval: 30s",
|
|
@@ -16251,6 +16496,9 @@ var HINDSIGHT_DEFAULT_API_PORT = 18888, HINDSIGHT_DEFAULT_UI_PORT = 9999, HINDSI
|
|
|
16251
16496
|
var init_hindsight = __esm(() => {
|
|
16252
16497
|
init_model_command();
|
|
16253
16498
|
init_timeout_budget();
|
|
16499
|
+
init_host_capabilities();
|
|
16500
|
+
init_hindsight_perf_defaults();
|
|
16501
|
+
init_hindsight_pg_defaults();
|
|
16254
16502
|
HINDSIGHT_DEFAULT_MCP_URL = `http://127.0.0.1:${HINDSIGHT_DEFAULT_API_PORT}/mcp/`;
|
|
16255
16503
|
HINDSIGHT_DEFAULT_API_BASE_URL = HINDSIGHT_DEFAULT_MCP_URL.replace(/\/mcp\/?$/, "");
|
|
16256
16504
|
HINDSIGHT_IMAGE = `${HINDSIGHT_IMAGE_REPO}:latest`;
|
|
@@ -17021,7 +17269,7 @@ function parseSocketIdentity(socketPath, spec) {
|
|
|
17021
17269
|
|
|
17022
17270
|
// src/vault/broker/peercred.ts
|
|
17023
17271
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
17024
|
-
import { readFileSync as
|
|
17272
|
+
import { readFileSync as readFileSync6, readlinkSync as readlinkSync2, fstatSync } from "node:fs";
|
|
17025
17273
|
function socketPathToIdentity(socketPath) {
|
|
17026
17274
|
return parseSocketIdentity(socketPath, {
|
|
17027
17275
|
patterns: [SOCKET_PATH_AGENT_RE, SOCKET_PATH_AGENT_SUBDIR_RE],
|
|
@@ -17102,7 +17350,7 @@ function findClientPidByServerInode(rows, socketPath, serverInode) {
|
|
|
17102
17350
|
}
|
|
17103
17351
|
function readUid(pid) {
|
|
17104
17352
|
try {
|
|
17105
|
-
const status =
|
|
17353
|
+
const status = readFileSync6(`/proc/${pid}/status`, "utf8");
|
|
17106
17354
|
const m = status.match(/^Uid:\s+(\d+)/m);
|
|
17107
17355
|
if (!m)
|
|
17108
17356
|
return null;
|
|
@@ -17120,7 +17368,7 @@ function readExe(pid) {
|
|
|
17120
17368
|
}
|
|
17121
17369
|
function readSystemdUnit(pid) {
|
|
17122
17370
|
try {
|
|
17123
|
-
const content =
|
|
17371
|
+
const content = readFileSync6(`/proc/${pid}/cgroup`, "utf8");
|
|
17124
17372
|
const lines = content.split(`
|
|
17125
17373
|
`);
|
|
17126
17374
|
for (const line of lines) {
|
|
@@ -17287,7 +17535,7 @@ var init_agent_uid = __esm(() => {
|
|
|
17287
17535
|
|
|
17288
17536
|
// src/agents/agent-owned-tree.ts
|
|
17289
17537
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
17290
|
-
import { existsSync as
|
|
17538
|
+
import { existsSync as existsSync6, lstatSync, readdirSync as readdirSync2, statSync as statSync3 } from "node:fs";
|
|
17291
17539
|
import { join as join3 } from "node:path";
|
|
17292
17540
|
function scopedAssertCandidates(agentDir) {
|
|
17293
17541
|
return [
|
|
@@ -17306,7 +17554,7 @@ function chownScopedTree(uid, gid, agentDir) {
|
|
|
17306
17554
|
ownershipRuntime.chownShallow(uid, gid, [agentDir, ...children]);
|
|
17307
17555
|
for (const sub of SCOPED_RECURSIVE_SUBDIRS) {
|
|
17308
17556
|
const subPath = join3(agentDir, sub);
|
|
17309
|
-
if (
|
|
17557
|
+
if (existsSync6(subPath)) {
|
|
17310
17558
|
ownershipRuntime.chownTree(uid, gid, subPath);
|
|
17311
17559
|
}
|
|
17312
17560
|
}
|
|
@@ -17314,7 +17562,7 @@ function chownScopedTree(uid, gid, agentDir) {
|
|
|
17314
17562
|
function alignAgentTreeOwnershipIfRoot(name, agentDir) {
|
|
17315
17563
|
if (ownershipRuntime.geteuid() !== 0)
|
|
17316
17564
|
return null;
|
|
17317
|
-
if (!
|
|
17565
|
+
if (!existsSync6(agentDir))
|
|
17318
17566
|
return null;
|
|
17319
17567
|
const uid = allocateAgentUid(name);
|
|
17320
17568
|
const scoped = ownershipRuntime.scopedSweepEnabled();
|
|
@@ -17401,7 +17649,7 @@ var init_agent_owned_tree = __esm(() => {
|
|
|
17401
17649
|
|
|
17402
17650
|
// src/agents/generation-stamp.ts
|
|
17403
17651
|
import { createHash as createHash3 } from "node:crypto";
|
|
17404
|
-
import { existsSync as
|
|
17652
|
+
import { existsSync as existsSync7, readFileSync as readFileSync7, writeFileSync as writeFileSync2 } from "node:fs";
|
|
17405
17653
|
import { join as join4 } from "node:path";
|
|
17406
17654
|
function sha256Text(s) {
|
|
17407
17655
|
return createHash3("sha256").update(s, "utf-8").digest("hex");
|
|
@@ -17424,11 +17672,11 @@ function hashManagedClaudeMd(content) {
|
|
|
17424
17672
|
}
|
|
17425
17673
|
function hashStampedFileOnDisk(agentDir, rel) {
|
|
17426
17674
|
const p = join4(agentDir, rel);
|
|
17427
|
-
if (!
|
|
17675
|
+
if (!existsSync7(p))
|
|
17428
17676
|
return null;
|
|
17429
17677
|
let content;
|
|
17430
17678
|
try {
|
|
17431
|
-
content =
|
|
17679
|
+
content = readFileSync7(p, "utf-8");
|
|
17432
17680
|
} catch {
|
|
17433
17681
|
return null;
|
|
17434
17682
|
}
|
|
@@ -17451,15 +17699,15 @@ function writeGenerationStamp(agentDir, stamp) {
|
|
|
17451
17699
|
configHash: stamp.configHash,
|
|
17452
17700
|
files: stamp.files
|
|
17453
17701
|
};
|
|
17454
|
-
|
|
17702
|
+
writeFileSync2(join4(agentDir, GENERATION_STAMP_FILE), JSON.stringify(full, null, 2) + `
|
|
17455
17703
|
`, "utf-8");
|
|
17456
17704
|
}
|
|
17457
17705
|
function readGenerationStamp(agentDir) {
|
|
17458
17706
|
const p = join4(agentDir, GENERATION_STAMP_FILE);
|
|
17459
|
-
if (!
|
|
17707
|
+
if (!existsSync7(p))
|
|
17460
17708
|
return null;
|
|
17461
17709
|
try {
|
|
17462
|
-
const parsed = JSON.parse(
|
|
17710
|
+
const parsed = JSON.parse(readFileSync7(p, "utf-8"));
|
|
17463
17711
|
if (parsed?.version !== 1 || typeof parsed.files !== "object" || parsed.files === null || Array.isArray(parsed.files)) {
|
|
17464
17712
|
return null;
|
|
17465
17713
|
}
|
|
@@ -17976,10 +18224,10 @@ var init_cron_introspect = __esm(() => {
|
|
|
17976
18224
|
import { join as join5 } from "node:path";
|
|
17977
18225
|
import { homedir as homedir2 } from "node:os";
|
|
17978
18226
|
import {
|
|
17979
|
-
existsSync as
|
|
17980
|
-
mkdirSync,
|
|
18227
|
+
existsSync as existsSync8,
|
|
18228
|
+
mkdirSync as mkdirSync2,
|
|
17981
18229
|
appendFileSync,
|
|
17982
|
-
readFileSync as
|
|
18230
|
+
readFileSync as readFileSync8
|
|
17983
18231
|
} from "node:fs";
|
|
17984
18232
|
function auditPathFor(agent) {
|
|
17985
18233
|
return join5(AUDIT_ROOT, agent, "agent-config.jsonl");
|
|
@@ -17996,8 +18244,8 @@ function appendAudit(agent, cmd, args, exit, opts = {}) {
|
|
|
17996
18244
|
const path = opts.auditPath ?? auditPathFor(agent);
|
|
17997
18245
|
const dir = path.slice(0, path.lastIndexOf("/"));
|
|
17998
18246
|
try {
|
|
17999
|
-
if (!
|
|
18000
|
-
|
|
18247
|
+
if (!existsSync8(dir)) {
|
|
18248
|
+
mkdirSync2(dir, { recursive: true });
|
|
18001
18249
|
}
|
|
18002
18250
|
appendFileSync(path, JSON.stringify(row) + `
|
|
18003
18251
|
`, { flag: "a" });
|
|
@@ -18008,7 +18256,7 @@ function isContainerContext(env2 = process.env, opts = {}) {
|
|
|
18008
18256
|
return true;
|
|
18009
18257
|
const probe = opts.dockerEnvPath ?? "/.dockerenv";
|
|
18010
18258
|
try {
|
|
18011
|
-
if (
|
|
18259
|
+
if (existsSync8(probe))
|
|
18012
18260
|
return true;
|
|
18013
18261
|
} catch {}
|
|
18014
18262
|
return false;
|
|
@@ -18136,11 +18384,11 @@ function getAgentSlice(config, agent) {
|
|
|
18136
18384
|
}
|
|
18137
18385
|
function readAuditTail(agent, limit, opts = {}) {
|
|
18138
18386
|
const path = opts.auditPath ?? auditPathFor(agent);
|
|
18139
|
-
if (!
|
|
18387
|
+
if (!existsSync8(path))
|
|
18140
18388
|
return [];
|
|
18141
18389
|
let raw;
|
|
18142
18390
|
try {
|
|
18143
|
-
raw =
|
|
18391
|
+
raw = readFileSync8(path, "utf-8");
|
|
18144
18392
|
} catch {
|
|
18145
18393
|
return [];
|
|
18146
18394
|
}
|
|
@@ -23946,7 +24194,7 @@ var require_lib = __commonJS((exports, module) => {
|
|
|
23946
24194
|
});
|
|
23947
24195
|
|
|
23948
24196
|
// src/agents/profiles.ts
|
|
23949
|
-
import { readFileSync as
|
|
24197
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync3, existsSync as existsSync9, readdirSync as readdirSync3, statSync as statSync4, copyFileSync, mkdirSync as mkdirSync3, realpathSync } from "node:fs";
|
|
23950
24198
|
import { resolve as resolve4, join as join6, sep as pathSep } from "node:path";
|
|
23951
24199
|
function resolveProfilesRoot() {
|
|
23952
24200
|
const envOverride = process.env.SWITCHROOM_PROFILES_ROOT?.trim();
|
|
@@ -23958,7 +24206,7 @@ function resolveProfilesRoot() {
|
|
|
23958
24206
|
resolve4(import.meta.dirname, "profiles")
|
|
23959
24207
|
];
|
|
23960
24208
|
for (const candidate of candidates) {
|
|
23961
|
-
if (
|
|
24209
|
+
if (existsSync9(candidate)) {
|
|
23962
24210
|
return candidate;
|
|
23963
24211
|
}
|
|
23964
24212
|
}
|
|
@@ -23978,11 +24226,11 @@ function getProfilePath(profileName) {
|
|
|
23978
24226
|
if (real !== PROFILES_ROOT && !real.startsWith(PROFILES_ROOT + pathSep)) {
|
|
23979
24227
|
throw new Error(`Invalid profile name: ${profileName}`);
|
|
23980
24228
|
}
|
|
23981
|
-
if (
|
|
24229
|
+
if (existsSync9(requested) && hasProfileFiles(requested)) {
|
|
23982
24230
|
return requested;
|
|
23983
24231
|
}
|
|
23984
24232
|
const fallback = resolve4(PROFILES_ROOT, "default");
|
|
23985
|
-
if (
|
|
24233
|
+
if (existsSync9(fallback)) {
|
|
23986
24234
|
return fallback;
|
|
23987
24235
|
}
|
|
23988
24236
|
throw new Error(`Profile not found: ${profileName} (searched ${PROFILES_ROOT})`);
|
|
@@ -24012,19 +24260,19 @@ function getBaseProfilePath() {
|
|
|
24012
24260
|
return resolve4(PROFILES_ROOT, "_base");
|
|
24013
24261
|
}
|
|
24014
24262
|
function renderTemplate(templatePath, context) {
|
|
24015
|
-
const source =
|
|
24263
|
+
const source = readFileSync9(templatePath, "utf-8");
|
|
24016
24264
|
const template = import_handlebars.default.compile(source, { noEscape: true });
|
|
24017
24265
|
return template(context);
|
|
24018
24266
|
}
|
|
24019
24267
|
function copyProfileSkills(profilePath, destPath) {
|
|
24020
24268
|
const skillsSrc = join6(profilePath, "skills");
|
|
24021
|
-
if (!
|
|
24269
|
+
if (!existsSync9(skillsSrc)) {
|
|
24022
24270
|
return;
|
|
24023
24271
|
}
|
|
24024
24272
|
copyDirRecursive(skillsSrc, destPath);
|
|
24025
24273
|
}
|
|
24026
24274
|
function copyDirRecursive(src, dest) {
|
|
24027
|
-
|
|
24275
|
+
mkdirSync3(dest, { recursive: true });
|
|
24028
24276
|
const entries = readdirSync3(src);
|
|
24029
24277
|
for (const entry of entries) {
|
|
24030
24278
|
const srcPath = join6(src, entry);
|
|
@@ -24033,7 +24281,7 @@ function copyDirRecursive(src, dest) {
|
|
|
24033
24281
|
if (stat.isDirectory()) {
|
|
24034
24282
|
copyDirRecursive(srcPath, destPath);
|
|
24035
24283
|
} else {
|
|
24036
|
-
if (!
|
|
24284
|
+
if (!existsSync9(destPath)) {
|
|
24037
24285
|
copyFileSync(srcPath, destPath);
|
|
24038
24286
|
}
|
|
24039
24287
|
}
|
|
@@ -24041,49 +24289,49 @@ function copyDirRecursive(src, dest) {
|
|
|
24041
24289
|
}
|
|
24042
24290
|
function renderVaultProtocolFragment(context = {}, profilesRoot = PROFILES_ROOT) {
|
|
24043
24291
|
const fragPath = join6(resolve4(profilesRoot, "_shared"), "vault-protocol.md.hbs");
|
|
24044
|
-
if (!
|
|
24292
|
+
if (!existsSync9(fragPath))
|
|
24045
24293
|
return "";
|
|
24046
|
-
const source =
|
|
24294
|
+
const source = readFileSync9(fragPath, "utf-8");
|
|
24047
24295
|
const template = import_handlebars.default.compile(source, { noEscape: true });
|
|
24048
24296
|
return template(context).trimEnd();
|
|
24049
24297
|
}
|
|
24050
24298
|
function renderAgentSelfServiceFragment(context = {}, profilesRoot = PROFILES_ROOT) {
|
|
24051
24299
|
const fragPath = join6(resolve4(profilesRoot, "_shared"), "agent-self-service.md.hbs");
|
|
24052
|
-
if (!
|
|
24300
|
+
if (!existsSync9(fragPath))
|
|
24053
24301
|
return "";
|
|
24054
|
-
const source =
|
|
24302
|
+
const source = readFileSync9(fragPath, "utf-8");
|
|
24055
24303
|
const template = import_handlebars.default.compile(source, { noEscape: true });
|
|
24056
24304
|
return template(context).trimEnd();
|
|
24057
24305
|
}
|
|
24058
24306
|
function renderExecutionDisciplineFragment(context = {}, profilesRoot = PROFILES_ROOT) {
|
|
24059
24307
|
const fragPath = join6(resolve4(profilesRoot, "_shared"), "execution-discipline.md.hbs");
|
|
24060
|
-
if (!
|
|
24308
|
+
if (!existsSync9(fragPath))
|
|
24061
24309
|
return "";
|
|
24062
|
-
const source =
|
|
24310
|
+
const source = readFileSync9(fragPath, "utf-8");
|
|
24063
24311
|
const template = import_handlebars.default.compile(source, { noEscape: true });
|
|
24064
24312
|
return template(context).trimEnd();
|
|
24065
24313
|
}
|
|
24066
24314
|
function renderDevProtocolFragment(context = {}, profilesRoot = PROFILES_ROOT) {
|
|
24067
24315
|
const fragPath = join6(resolve4(profilesRoot, "_shared"), "dev-protocol.md.hbs");
|
|
24068
|
-
if (!
|
|
24316
|
+
if (!existsSync9(fragPath))
|
|
24069
24317
|
return "";
|
|
24070
|
-
const source =
|
|
24318
|
+
const source = readFileSync9(fragPath, "utf-8");
|
|
24071
24319
|
const template = import_handlebars.default.compile(source, { noEscape: true });
|
|
24072
24320
|
return template(context).trimEnd();
|
|
24073
24321
|
}
|
|
24074
24322
|
function renderDelegationGoldenRuleFragment(context = {}, profilesRoot = PROFILES_ROOT) {
|
|
24075
24323
|
const fragPath = join6(resolve4(profilesRoot, "_shared"), "delegation-golden-rule.md.hbs");
|
|
24076
|
-
if (!
|
|
24324
|
+
if (!existsSync9(fragPath))
|
|
24077
24325
|
return "";
|
|
24078
|
-
const source =
|
|
24326
|
+
const source = readFileSync9(fragPath, "utf-8");
|
|
24079
24327
|
const template = import_handlebars.default.compile(source, { noEscape: true });
|
|
24080
24328
|
return template(context).trimEnd();
|
|
24081
24329
|
}
|
|
24082
24330
|
function renderReplyDisciplineFragment(context = {}, profilesRoot = PROFILES_ROOT) {
|
|
24083
24331
|
const fragPath = join6(resolve4(profilesRoot, "_shared"), "reply-discipline.md.hbs");
|
|
24084
|
-
if (!
|
|
24332
|
+
if (!existsSync9(fragPath))
|
|
24085
24333
|
return "";
|
|
24086
|
-
const source =
|
|
24334
|
+
const source = readFileSync9(fragPath, "utf-8");
|
|
24087
24335
|
const template = import_handlebars.default.compile(source, { noEscape: true });
|
|
24088
24336
|
return template(context).trimEnd();
|
|
24089
24337
|
}
|
|
@@ -24091,14 +24339,14 @@ function renderProfileClaudeTemplate(profileName, profilesRoot = PROFILES_ROOT)
|
|
|
24091
24339
|
const profileDir = resolve4(profilesRoot, profileName);
|
|
24092
24340
|
const hbsPath = join6(profileDir, "CLAUDE.md.hbs");
|
|
24093
24341
|
const outPath = join6(profileDir, "CLAUDE.md");
|
|
24094
|
-
if (!
|
|
24342
|
+
if (!existsSync9(hbsPath)) {
|
|
24095
24343
|
return { wrote: false, path: outPath };
|
|
24096
24344
|
}
|
|
24097
|
-
const source =
|
|
24345
|
+
const source = readFileSync9(hbsPath, "utf-8");
|
|
24098
24346
|
const template = import_handlebars.default.compile(source, { noEscape: true });
|
|
24099
24347
|
const rendered = template({ profile: profileName });
|
|
24100
24348
|
try {
|
|
24101
|
-
|
|
24349
|
+
writeFileSync3(outPath, rendered, "utf-8");
|
|
24102
24350
|
return { wrote: true, path: outPath };
|
|
24103
24351
|
} catch (err) {
|
|
24104
24352
|
const code = err.code;
|
|
@@ -24123,8 +24371,8 @@ var init_profiles = __esm(() => {
|
|
|
24123
24371
|
SHARED_FRAGMENTS = ["vault-protocol", "agent-self-service", "execution-discipline", "reply-discipline", "dev-protocol"];
|
|
24124
24372
|
for (const name of SHARED_FRAGMENTS) {
|
|
24125
24373
|
const fragPath = join6(SHARED_FRAGMENTS_DIR, `${name}.md.hbs`);
|
|
24126
|
-
if (
|
|
24127
|
-
import_handlebars.default.registerPartial(name,
|
|
24374
|
+
if (existsSync9(fragPath)) {
|
|
24375
|
+
import_handlebars.default.registerPartial(name, readFileSync9(fragPath, "utf-8"));
|
|
24128
24376
|
}
|
|
24129
24377
|
}
|
|
24130
24378
|
});
|
|
@@ -24289,9 +24537,9 @@ function bindingsForAgent(agentName, mw, microsoftAccounts) {
|
|
|
24289
24537
|
}
|
|
24290
24538
|
|
|
24291
24539
|
// src/agents/reconcile-default-skills.ts
|
|
24292
|
-
import { existsSync as
|
|
24540
|
+
import { existsSync as existsSync10, lstatSync as lstatSync2, mkdirSync as mkdirSync4, readdirSync as readdirSync4, readlinkSync as readlinkSync3, rmSync as rmSync2, symlinkSync } from "node:fs";
|
|
24293
24541
|
import { homedir as homedir3 } from "node:os";
|
|
24294
|
-
import { dirname as
|
|
24542
|
+
import { dirname as dirname3, isAbsolute, join as join7, relative, resolve as resolve5 } from "node:path";
|
|
24295
24543
|
function warnMissingPoolDir(poolDir) {
|
|
24296
24544
|
if (warnedMissingPool.has(poolDir))
|
|
24297
24545
|
return;
|
|
@@ -24322,10 +24570,10 @@ function isOwnedStaleLink(target, poolDir) {
|
|
|
24322
24570
|
return false;
|
|
24323
24571
|
}
|
|
24324
24572
|
function absoluteLinkTarget(linkPath, storedTarget) {
|
|
24325
|
-
return isAbsolute(storedTarget) ? storedTarget : resolve5(
|
|
24573
|
+
return isAbsolute(storedTarget) ? storedTarget : resolve5(dirname3(linkPath), storedTarget);
|
|
24326
24574
|
}
|
|
24327
24575
|
function linkTargetFor(dest, src) {
|
|
24328
|
-
return relative(
|
|
24576
|
+
return relative(dirname3(dest), src);
|
|
24329
24577
|
}
|
|
24330
24578
|
function isOwnedBundledLink(dest, poolDir) {
|
|
24331
24579
|
let stored = null;
|
|
@@ -24338,7 +24586,7 @@ function isOwnedBundledLink(dest, poolDir) {
|
|
|
24338
24586
|
}
|
|
24339
24587
|
if (!stored)
|
|
24340
24588
|
return false;
|
|
24341
|
-
const resolved = isAbsolute(stored) ? stored : resolve5(
|
|
24589
|
+
const resolved = isAbsolute(stored) ? stored : resolve5(dirname3(dest), stored);
|
|
24342
24590
|
const poolPrefix = poolDir.endsWith("/") ? poolDir : poolDir + "/";
|
|
24343
24591
|
return resolved === poolDir || resolved.startsWith(poolPrefix);
|
|
24344
24592
|
}
|
|
@@ -24355,12 +24603,12 @@ function reconcileAgentDefaultSkills(agentDir, optOuts = {}, defaults = getBuilt
|
|
|
24355
24603
|
changed: false
|
|
24356
24604
|
};
|
|
24357
24605
|
const claudeDir = join7(agentDir, ".claude");
|
|
24358
|
-
if (!
|
|
24606
|
+
if (!existsSync10(claudeDir)) {
|
|
24359
24607
|
return result;
|
|
24360
24608
|
}
|
|
24361
24609
|
const targetDir = join7(claudeDir, "skills");
|
|
24362
|
-
|
|
24363
|
-
if (!
|
|
24610
|
+
mkdirSync4(targetDir, { recursive: true });
|
|
24611
|
+
if (!existsSync10(poolDir)) {
|
|
24364
24612
|
warnMissingPoolDir(poolDir);
|
|
24365
24613
|
return result;
|
|
24366
24614
|
}
|
|
@@ -24378,7 +24626,7 @@ function reconcileAgentDefaultSkills(agentDir, optOuts = {}, defaults = getBuilt
|
|
|
24378
24626
|
continue;
|
|
24379
24627
|
}
|
|
24380
24628
|
const src = join7(poolDir, entry.key);
|
|
24381
|
-
if (!
|
|
24629
|
+
if (!existsSync10(src)) {
|
|
24382
24630
|
result.missingFromPool.push(entry.key);
|
|
24383
24631
|
warnMissingBuiltinDefault(poolDir, entry.key);
|
|
24384
24632
|
if (isOwnedBundledLink(dest, poolDir)) {
|
|
@@ -24439,7 +24687,7 @@ function reconcileAgentDefaultSkills(agentDir, optOuts = {}, defaults = getBuilt
|
|
|
24439
24687
|
continue;
|
|
24440
24688
|
try {
|
|
24441
24689
|
const st = lstatSync2(join7(poolDir, poolName));
|
|
24442
|
-
if (st.isDirectory() &&
|
|
24690
|
+
if (st.isDirectory() && existsSync10(join7(poolDir, poolName, "SKILL.md"))) {
|
|
24443
24691
|
legitimate.add(poolName);
|
|
24444
24692
|
}
|
|
24445
24693
|
} catch {}
|
|
@@ -24518,25 +24766,25 @@ function applyTelegramProgressGuidance(body, args) {
|
|
|
24518
24766
|
|
|
24519
24767
|
// src/telegram/state.ts
|
|
24520
24768
|
import {
|
|
24521
|
-
readFileSync as
|
|
24522
|
-
writeFileSync as
|
|
24523
|
-
mkdirSync as
|
|
24524
|
-
existsSync as
|
|
24769
|
+
readFileSync as readFileSync10,
|
|
24770
|
+
writeFileSync as writeFileSync4,
|
|
24771
|
+
mkdirSync as mkdirSync5,
|
|
24772
|
+
existsSync as existsSync11,
|
|
24525
24773
|
renameSync as renameSync2,
|
|
24526
24774
|
copyFileSync as copyFileSync2,
|
|
24527
24775
|
unlinkSync
|
|
24528
24776
|
} from "node:fs";
|
|
24529
|
-
import { basename as basename2, dirname as
|
|
24777
|
+
import { basename as basename2, dirname as dirname4, resolve as resolve6 } from "node:path";
|
|
24530
24778
|
function defaultStatePath() {
|
|
24531
24779
|
return resolveStatePath("topics.json");
|
|
24532
24780
|
}
|
|
24533
24781
|
function loadTopicState(statePath) {
|
|
24534
24782
|
const path = statePath ?? defaultStatePath();
|
|
24535
|
-
if (!
|
|
24783
|
+
if (!existsSync11(path)) {
|
|
24536
24784
|
return { topics: {} };
|
|
24537
24785
|
}
|
|
24538
24786
|
try {
|
|
24539
|
-
const raw =
|
|
24787
|
+
const raw = readFileSync10(path, "utf-8");
|
|
24540
24788
|
const parsed = JSON.parse(raw);
|
|
24541
24789
|
if (parsed && typeof parsed === "object" && parsed.topics && typeof parsed.topics === "object") {
|
|
24542
24790
|
return parsed;
|
|
@@ -24553,19 +24801,19 @@ function loadTopicState(statePath) {
|
|
|
24553
24801
|
}
|
|
24554
24802
|
function saveTopicState(state, statePath) {
|
|
24555
24803
|
const path = statePath ?? defaultStatePath();
|
|
24556
|
-
const dir =
|
|
24557
|
-
if (!
|
|
24558
|
-
|
|
24804
|
+
const dir = dirname4(path);
|
|
24805
|
+
if (!existsSync11(dir)) {
|
|
24806
|
+
mkdirSync5(dir, { recursive: true });
|
|
24559
24807
|
}
|
|
24560
24808
|
const absDir = resolve6(dir);
|
|
24561
24809
|
const tmp = resolve6(absDir, `.${basename2(path)}.${process.pid}.${Date.now()}.tmp`);
|
|
24562
24810
|
try {
|
|
24563
|
-
|
|
24811
|
+
writeFileSync4(tmp, JSON.stringify(state, null, 2) + `
|
|
24564
24812
|
`, "utf-8");
|
|
24565
24813
|
renameSync2(tmp, path);
|
|
24566
24814
|
} catch (err) {
|
|
24567
24815
|
try {
|
|
24568
|
-
if (
|
|
24816
|
+
if (existsSync11(tmp))
|
|
24569
24817
|
unlinkSync(tmp);
|
|
24570
24818
|
} catch {}
|
|
24571
24819
|
throw err;
|
|
@@ -24577,13 +24825,13 @@ var init_state = __esm(() => {
|
|
|
24577
24825
|
|
|
24578
24826
|
// src/vault/flock.ts
|
|
24579
24827
|
import {
|
|
24580
|
-
existsSync as
|
|
24828
|
+
existsSync as existsSync12,
|
|
24581
24829
|
openSync as openSync3,
|
|
24582
24830
|
closeSync as closeSync3,
|
|
24583
24831
|
writeSync as writeSync2,
|
|
24584
24832
|
fsyncSync as fsyncSync2,
|
|
24585
24833
|
unlinkSync as unlinkSync2,
|
|
24586
|
-
readFileSync as
|
|
24834
|
+
readFileSync as readFileSync11,
|
|
24587
24835
|
readdirSync as readdirSync5,
|
|
24588
24836
|
rmdirSync,
|
|
24589
24837
|
statSync as statSync5,
|
|
@@ -24594,7 +24842,7 @@ function lockPathFor(vaultPath) {
|
|
|
24594
24842
|
}
|
|
24595
24843
|
function readLockHolder(lockPath) {
|
|
24596
24844
|
try {
|
|
24597
|
-
const raw =
|
|
24845
|
+
const raw = readFileSync11(lockPath, "utf8");
|
|
24598
24846
|
const lines = raw.split(`
|
|
24599
24847
|
`);
|
|
24600
24848
|
const pid = Number.parseInt(lines[0] ?? "", 10);
|
|
@@ -24610,7 +24858,7 @@ function readLockHolder(lockPath) {
|
|
|
24610
24858
|
}
|
|
24611
24859
|
function pidIsLive(pid) {
|
|
24612
24860
|
if (process.platform === "linux") {
|
|
24613
|
-
return
|
|
24861
|
+
return existsSync12(`/proc/${pid}`);
|
|
24614
24862
|
}
|
|
24615
24863
|
try {
|
|
24616
24864
|
process.kill(pid, 0);
|
|
@@ -24646,8 +24894,8 @@ function pidStartTimeMs(pid) {
|
|
|
24646
24894
|
if (process.platform !== "linux")
|
|
24647
24895
|
return null;
|
|
24648
24896
|
try {
|
|
24649
|
-
const statLine =
|
|
24650
|
-
const procStat =
|
|
24897
|
+
const statLine = readFileSync11(`/proc/${pid}/stat`, "utf8");
|
|
24898
|
+
const procStat = readFileSync11("/proc/stat", "utf8");
|
|
24651
24899
|
return parseProcStartTimeMs(statLine, procStat, Date.now());
|
|
24652
24900
|
} catch {
|
|
24653
24901
|
return null;
|
|
@@ -24670,7 +24918,7 @@ function lockFileMtimeIsOlderThan(lockPath, budgetMs) {
|
|
|
24670
24918
|
}
|
|
24671
24919
|
function clearStaleSentinelDir(lockPath) {
|
|
24672
24920
|
try {
|
|
24673
|
-
if (!
|
|
24921
|
+
if (!existsSync12(lockPath))
|
|
24674
24922
|
return true;
|
|
24675
24923
|
const s = statSync5(lockPath);
|
|
24676
24924
|
if (!s.isDirectory())
|
|
@@ -24813,11 +25061,11 @@ __export(exports_vault, {
|
|
|
24813
25061
|
});
|
|
24814
25062
|
import { randomBytes as randomBytes2, scryptSync, createCipheriv, createDecipheriv } from "node:crypto";
|
|
24815
25063
|
import {
|
|
24816
|
-
readFileSync as
|
|
25064
|
+
readFileSync as readFileSync12,
|
|
24817
25065
|
writeSync as writeSync3,
|
|
24818
|
-
existsSync as
|
|
25066
|
+
existsSync as existsSync13,
|
|
24819
25067
|
renameSync as renameSync3,
|
|
24820
|
-
mkdirSync as
|
|
25068
|
+
mkdirSync as mkdirSync6,
|
|
24821
25069
|
unlinkSync as unlinkSync3,
|
|
24822
25070
|
fsyncSync as fsyncSync3,
|
|
24823
25071
|
openSync as openSync4,
|
|
@@ -24825,15 +25073,15 @@ import {
|
|
|
24825
25073
|
lstatSync as lstatSync3,
|
|
24826
25074
|
realpathSync as realpathSync2
|
|
24827
25075
|
} from "node:fs";
|
|
24828
|
-
import { dirname as
|
|
25076
|
+
import { dirname as dirname5, basename as basename3, resolve as resolve7 } from "node:path";
|
|
24829
25077
|
function atomicWriteFileSync2(path, data, mode) {
|
|
24830
25078
|
let effectivePath = path;
|
|
24831
25079
|
try {
|
|
24832
|
-
if (
|
|
25080
|
+
if (existsSync13(path) && lstatSync3(path).isSymbolicLink()) {
|
|
24833
25081
|
effectivePath = realpathSync2(path);
|
|
24834
25082
|
}
|
|
24835
25083
|
} catch {}
|
|
24836
|
-
const dir =
|
|
25084
|
+
const dir = dirname5(resolve7(effectivePath));
|
|
24837
25085
|
const tmp = resolve7(dir, `.${basename3(effectivePath)}.${process.pid}.${Date.now()}.tmp`);
|
|
24838
25086
|
try {
|
|
24839
25087
|
const fd = openSync4(tmp, "wx", mode);
|
|
@@ -24854,7 +25102,7 @@ function atomicWriteFileSync2(path, data, mode) {
|
|
|
24854
25102
|
} catch {}
|
|
24855
25103
|
} catch (err) {
|
|
24856
25104
|
try {
|
|
24857
|
-
if (
|
|
25105
|
+
if (existsSync13(tmp))
|
|
24858
25106
|
unlinkSync3(tmp);
|
|
24859
25107
|
} catch {}
|
|
24860
25108
|
throw err;
|
|
@@ -24967,12 +25215,12 @@ function detectFormat(value) {
|
|
|
24967
25215
|
return null;
|
|
24968
25216
|
}
|
|
24969
25217
|
function createVault(passphrase, vaultPath) {
|
|
24970
|
-
if (
|
|
25218
|
+
if (existsSync13(vaultPath)) {
|
|
24971
25219
|
throw new VaultError(`Vault file already exists: ${vaultPath}`);
|
|
24972
25220
|
}
|
|
24973
|
-
const dir =
|
|
24974
|
-
if (!
|
|
24975
|
-
|
|
25221
|
+
const dir = dirname5(vaultPath);
|
|
25222
|
+
if (!existsSync13(dir)) {
|
|
25223
|
+
mkdirSync6(dir, { recursive: true, mode: 448 });
|
|
24976
25224
|
}
|
|
24977
25225
|
const salt = randomBytes2(16);
|
|
24978
25226
|
const key = deriveKey(passphrase, salt);
|
|
@@ -24988,12 +25236,12 @@ function createVault(passphrase, vaultPath) {
|
|
|
24988
25236
|
atomicWriteFileSync2(vaultPath, JSON.stringify(vaultFile, null, 2), 384);
|
|
24989
25237
|
}
|
|
24990
25238
|
function openVault(passphrase, vaultPath) {
|
|
24991
|
-
if (!
|
|
25239
|
+
if (!existsSync13(vaultPath)) {
|
|
24992
25240
|
throw new VaultError(`Vault file not found: ${vaultPath}`);
|
|
24993
25241
|
}
|
|
24994
25242
|
let vaultFile;
|
|
24995
25243
|
try {
|
|
24996
|
-
vaultFile = JSON.parse(
|
|
25244
|
+
vaultFile = JSON.parse(readFileSync12(vaultPath, "utf8"));
|
|
24997
25245
|
} catch {
|
|
24998
25246
|
throw new VaultError(`Failed to read vault file: ${vaultPath}`);
|
|
24999
25247
|
}
|
|
@@ -25015,7 +25263,7 @@ function openVault(passphrase, vaultPath) {
|
|
|
25015
25263
|
return normalizeSecrets(vaultData.secrets ?? {});
|
|
25016
25264
|
}
|
|
25017
25265
|
function saveVault(passphrase, vaultPath, secrets) {
|
|
25018
|
-
if (!
|
|
25266
|
+
if (!existsSync13(vaultPath)) {
|
|
25019
25267
|
throw new VaultError(`Vault file not found: ${vaultPath}`);
|
|
25020
25268
|
}
|
|
25021
25269
|
let releaseLock = null;
|
|
@@ -25030,7 +25278,7 @@ function saveVault(passphrase, vaultPath, secrets) {
|
|
|
25030
25278
|
try {
|
|
25031
25279
|
let vaultFile;
|
|
25032
25280
|
try {
|
|
25033
|
-
vaultFile = JSON.parse(
|
|
25281
|
+
vaultFile = JSON.parse(readFileSync12(vaultPath, "utf8"));
|
|
25034
25282
|
} catch {
|
|
25035
25283
|
throw new VaultError(`Failed to read vault file: ${vaultPath}`);
|
|
25036
25284
|
}
|
|
@@ -25937,7 +26185,7 @@ __export(exports_resolver, {
|
|
|
25937
26185
|
import {
|
|
25938
26186
|
chmodSync,
|
|
25939
26187
|
closeSync as closeSync5,
|
|
25940
|
-
mkdirSync as
|
|
26188
|
+
mkdirSync as mkdirSync7,
|
|
25941
26189
|
mkdtempSync,
|
|
25942
26190
|
openSync as openSync5,
|
|
25943
26191
|
rmSync as rmSync3,
|
|
@@ -25997,7 +26245,7 @@ function materializationRoot() {
|
|
|
25997
26245
|
const xdg = process.env.XDG_RUNTIME_DIR;
|
|
25998
26246
|
if (xdg) {
|
|
25999
26247
|
const base = join9(xdg, "switchroom", "vault");
|
|
26000
|
-
|
|
26248
|
+
mkdirSync7(base, { recursive: true, mode: 448 });
|
|
26001
26249
|
cachedRoot = mkdtempSync(join9(base, "run-"));
|
|
26002
26250
|
} else {
|
|
26003
26251
|
cachedRoot = mkdtempSync(join9(tmpdir(), "switchroom-vault-"));
|
|
@@ -26021,7 +26269,7 @@ function materializeFilesEntry(key, files) {
|
|
|
26021
26269
|
rmSync3(dir, { recursive: true, force: true });
|
|
26022
26270
|
} catch {}
|
|
26023
26271
|
}
|
|
26024
|
-
|
|
26272
|
+
mkdirSync7(dir, { recursive: true, mode: 448 });
|
|
26025
26273
|
chmodSync(dir, 448);
|
|
26026
26274
|
const st = statSync7(dir);
|
|
26027
26275
|
if (typeof process.getuid === "function" && st.uid !== process.getuid()) {
|
|
@@ -26178,7 +26426,7 @@ var init_resolver = __esm(() => {
|
|
|
26178
26426
|
});
|
|
26179
26427
|
|
|
26180
26428
|
// src/setup/onboarding.ts
|
|
26181
|
-
import { existsSync as
|
|
26429
|
+
import { existsSync as existsSync15, copyFileSync as copyFileSync3, mkdirSync as mkdirSync8, writeFileSync as writeFileSync5, readFileSync as readFileSync14 } from "node:fs";
|
|
26182
26430
|
import { resolve as resolve8, join as join10 } from "node:path";
|
|
26183
26431
|
function findExistingClaudeJson() {
|
|
26184
26432
|
const home2 = process.env.HOME ?? "/root";
|
|
@@ -26190,7 +26438,7 @@ function findExistingClaudeJson() {
|
|
|
26190
26438
|
resolve8(home2, ".claude", "config.json")
|
|
26191
26439
|
];
|
|
26192
26440
|
for (const candidate of candidates) {
|
|
26193
|
-
if (
|
|
26441
|
+
if (existsSync15(candidate)) {
|
|
26194
26442
|
return candidate;
|
|
26195
26443
|
}
|
|
26196
26444
|
}
|
|
@@ -26202,9 +26450,9 @@ function findExistingClaudeJson() {
|
|
|
26202
26450
|
}
|
|
26203
26451
|
function copyOnboardingState(sourcePath, agentDir, configDirName = ".claude") {
|
|
26204
26452
|
const claudeDir = join10(agentDir, configDirName);
|
|
26205
|
-
|
|
26453
|
+
mkdirSync8(claudeDir, { recursive: true });
|
|
26206
26454
|
const destPath = join10(claudeDir, ".claude.json");
|
|
26207
|
-
if (!
|
|
26455
|
+
if (!existsSync15(destPath)) {
|
|
26208
26456
|
copyFileSync3(sourcePath, destPath);
|
|
26209
26457
|
}
|
|
26210
26458
|
}
|
|
@@ -26227,18 +26475,18 @@ function buildAccessJson(userId, forumChatId, topicId, opts = {}) {
|
|
|
26227
26475
|
}
|
|
26228
26476
|
function writeAccessJson(agentDir, userId, forumChatId, topicId, opts = {}) {
|
|
26229
26477
|
const telegramDir = join10(agentDir, "telegram");
|
|
26230
|
-
|
|
26478
|
+
mkdirSync8(telegramDir, { recursive: true });
|
|
26231
26479
|
const accessPath = join10(telegramDir, "access.json");
|
|
26232
|
-
|
|
26480
|
+
writeFileSync5(accessPath, buildAccessJson(userId, forumChatId, topicId, opts), {
|
|
26233
26481
|
encoding: "utf-8",
|
|
26234
26482
|
mode: 384
|
|
26235
26483
|
});
|
|
26236
26484
|
}
|
|
26237
26485
|
function writeAgentEnv(agentDir, botToken) {
|
|
26238
26486
|
const telegramDir = join10(agentDir, "telegram");
|
|
26239
|
-
|
|
26487
|
+
mkdirSync8(telegramDir, { recursive: true });
|
|
26240
26488
|
const envPath = join10(telegramDir, ".env");
|
|
26241
|
-
|
|
26489
|
+
writeFileSync5(envPath, `TELEGRAM_BOT_TOKEN=${botToken}
|
|
26242
26490
|
`, {
|
|
26243
26491
|
encoding: "utf-8",
|
|
26244
26492
|
mode: 384
|
|
@@ -26250,12 +26498,12 @@ function userConfigPath() {
|
|
|
26250
26498
|
function saveUserConfig(userId, username) {
|
|
26251
26499
|
const configPath = userConfigPath();
|
|
26252
26500
|
const dir = join10(configPath, "..");
|
|
26253
|
-
|
|
26501
|
+
mkdirSync8(dir, { recursive: true });
|
|
26254
26502
|
const config = { userId };
|
|
26255
26503
|
if (username) {
|
|
26256
26504
|
config.username = username;
|
|
26257
26505
|
}
|
|
26258
|
-
|
|
26506
|
+
writeFileSync5(configPath, JSON.stringify(config, null, 2) + `
|
|
26259
26507
|
`, {
|
|
26260
26508
|
encoding: "utf-8",
|
|
26261
26509
|
mode: 384
|
|
@@ -26263,11 +26511,11 @@ function saveUserConfig(userId, username) {
|
|
|
26263
26511
|
}
|
|
26264
26512
|
function loadUserConfig() {
|
|
26265
26513
|
const configPath = userConfigPath();
|
|
26266
|
-
if (!
|
|
26514
|
+
if (!existsSync15(configPath)) {
|
|
26267
26515
|
return null;
|
|
26268
26516
|
}
|
|
26269
26517
|
try {
|
|
26270
|
-
const raw =
|
|
26518
|
+
const raw = readFileSync14(configPath, "utf-8");
|
|
26271
26519
|
const parsed = JSON.parse(raw);
|
|
26272
26520
|
if (parsed && typeof parsed === "object") {
|
|
26273
26521
|
return parsed;
|
|
@@ -26279,11 +26527,11 @@ function loadUserConfig() {
|
|
|
26279
26527
|
}
|
|
26280
26528
|
function preTrustWorkspace(agentDir, configDirName = ".claude") {
|
|
26281
26529
|
const configPath = join10(agentDir, configDirName, ".claude.json");
|
|
26282
|
-
if (!
|
|
26530
|
+
if (!existsSync15(configPath)) {
|
|
26283
26531
|
return;
|
|
26284
26532
|
}
|
|
26285
26533
|
try {
|
|
26286
|
-
const raw =
|
|
26534
|
+
const raw = readFileSync14(configPath, "utf-8");
|
|
26287
26535
|
const config = JSON.parse(raw);
|
|
26288
26536
|
if (!config.projects) {
|
|
26289
26537
|
config.projects = {};
|
|
@@ -26295,7 +26543,7 @@ function preTrustWorkspace(agentDir, configDirName = ".claude") {
|
|
|
26295
26543
|
allowedTools: []
|
|
26296
26544
|
};
|
|
26297
26545
|
}
|
|
26298
|
-
|
|
26546
|
+
writeFileSync5(configPath, JSON.stringify(config, null, 2) + `
|
|
26299
26547
|
`, {
|
|
26300
26548
|
encoding: "utf-8",
|
|
26301
26549
|
mode: 384
|
|
@@ -26304,11 +26552,11 @@ function preTrustWorkspace(agentDir, configDirName = ".claude") {
|
|
|
26304
26552
|
}
|
|
26305
26553
|
function ensureMcpServersTrusted(agentDir, serverKeys, configDirName = ".claude") {
|
|
26306
26554
|
const configPath = join10(agentDir, configDirName, ".claude.json");
|
|
26307
|
-
if (!
|
|
26555
|
+
if (!existsSync15(configPath)) {
|
|
26308
26556
|
return;
|
|
26309
26557
|
}
|
|
26310
26558
|
try {
|
|
26311
|
-
const raw =
|
|
26559
|
+
const raw = readFileSync14(configPath, "utf-8");
|
|
26312
26560
|
const config = JSON.parse(raw);
|
|
26313
26561
|
if (!config.projects) {
|
|
26314
26562
|
config.projects = {};
|
|
@@ -26322,7 +26570,7 @@ function ensureMcpServersTrusted(agentDir, serverKeys, configDirName = ".claude"
|
|
|
26322
26570
|
const existing = Array.isArray(project.enabledMcpjsonServers) ? project.enabledMcpjsonServers : [];
|
|
26323
26571
|
project.enabledMcpjsonServers = Array.from(new Set([...existing, ...serverKeys]));
|
|
26324
26572
|
config.projects[absDir] = project;
|
|
26325
|
-
|
|
26573
|
+
writeFileSync5(configPath, JSON.stringify(config, null, 2) + `
|
|
26326
26574
|
`, {
|
|
26327
26575
|
encoding: "utf-8",
|
|
26328
26576
|
mode: 384
|
|
@@ -26333,14 +26581,14 @@ function ensureMcpServersTrusted(agentDir, serverKeys, configDirName = ".claude"
|
|
|
26333
26581
|
}
|
|
26334
26582
|
function createMinimalClaudeConfig(agentDir, configDirName = ".claude") {
|
|
26335
26583
|
const claudeDir = join10(agentDir, configDirName);
|
|
26336
|
-
|
|
26584
|
+
mkdirSync8(claudeDir, { recursive: true });
|
|
26337
26585
|
const configPath = join10(claudeDir, ".claude.json");
|
|
26338
|
-
if (!
|
|
26586
|
+
if (!existsSync15(configPath)) {
|
|
26339
26587
|
const minimal = {
|
|
26340
26588
|
hasCompletedOnboarding: true,
|
|
26341
26589
|
numStartups: 1
|
|
26342
26590
|
};
|
|
26343
|
-
|
|
26591
|
+
writeFileSync5(configPath, JSON.stringify(minimal, null, 2) + `
|
|
26344
26592
|
`, {
|
|
26345
26593
|
encoding: "utf-8",
|
|
26346
26594
|
mode: 384
|
|
@@ -26351,8 +26599,8 @@ function seedCronConfigDir(agentDir, serverKeys) {
|
|
|
26351
26599
|
const mainConfig = join10(agentDir, ".claude", ".claude.json");
|
|
26352
26600
|
const cronDir = join10(agentDir, ".claude-cron");
|
|
26353
26601
|
const cronConfig = join10(cronDir, ".claude.json");
|
|
26354
|
-
|
|
26355
|
-
if (
|
|
26602
|
+
mkdirSync8(cronDir, { recursive: true });
|
|
26603
|
+
if (existsSync15(mainConfig)) {
|
|
26356
26604
|
try {
|
|
26357
26605
|
copyFileSync3(mainConfig, cronConfig);
|
|
26358
26606
|
} catch {
|
|
@@ -26370,16 +26618,16 @@ var init_onboarding = __esm(() => {
|
|
|
26370
26618
|
|
|
26371
26619
|
// src/repos/bare-clone.ts
|
|
26372
26620
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
26373
|
-
import { existsSync as
|
|
26621
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync9 } from "node:fs";
|
|
26374
26622
|
import { resolve as resolve9 } from "node:path";
|
|
26375
26623
|
function bareClonePath(slug) {
|
|
26376
26624
|
return resolveStatePath(`repos/${slug}.git`);
|
|
26377
26625
|
}
|
|
26378
26626
|
function ensureBareClone(slug, url) {
|
|
26379
26627
|
const reposDir = resolveStatePath("repos");
|
|
26380
|
-
|
|
26628
|
+
mkdirSync9(reposDir, { recursive: true });
|
|
26381
26629
|
const clonePath = bareClonePath(slug);
|
|
26382
|
-
if (!
|
|
26630
|
+
if (!existsSync16(clonePath)) {
|
|
26383
26631
|
process.stderr.write(`[switchroom] repo "${slug}": cloning ${url} \u2026
|
|
26384
26632
|
`);
|
|
26385
26633
|
execFileSync4("git", ["clone", "--bare", url, clonePath], {
|
|
@@ -26409,7 +26657,7 @@ var init_bare_clone = __esm(() => {
|
|
|
26409
26657
|
|
|
26410
26658
|
// src/repos/agent-worktree.ts
|
|
26411
26659
|
import { execFileSync as execFileSync5 } from "node:child_process";
|
|
26412
|
-
import { existsSync as
|
|
26660
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync10, readdirSync as readdirSync6 } from "node:fs";
|
|
26413
26661
|
import { join as join11, resolve as resolve10 } from "node:path";
|
|
26414
26662
|
function agentBranchName(agentName) {
|
|
26415
26663
|
return `agent/${agentName}/main`;
|
|
@@ -26468,8 +26716,8 @@ function ensureAgentWorktree(agentName, slug, bareClonePath2, agentDir) {
|
|
|
26468
26716
|
const worktreePath = agentWorktreePath(agentDir, slug);
|
|
26469
26717
|
const branch = agentBranchName(agentName);
|
|
26470
26718
|
const defaultBranch = resolveDefaultBranch(bareClonePath2);
|
|
26471
|
-
if (!
|
|
26472
|
-
|
|
26719
|
+
if (!existsSync17(worktreePath)) {
|
|
26720
|
+
mkdirSync10(join11(agentDir, "work"), { recursive: true });
|
|
26473
26721
|
if (branchExistsInBare(bareClonePath2, branch)) {
|
|
26474
26722
|
execFileSync5("git", ["worktree", "add", worktreePath, branch], {
|
|
26475
26723
|
cwd: bareClonePath2,
|
|
@@ -26524,7 +26772,7 @@ function ensureAgentWorktree(agentName, slug, bareClonePath2, agentDir) {
|
|
|
26524
26772
|
function removeAgentWorktree(agentName, slug, bareClonePath2, agentDir) {
|
|
26525
26773
|
const worktreePath = agentWorktreePath(agentDir, slug);
|
|
26526
26774
|
const branch = agentBranchName(agentName);
|
|
26527
|
-
if (
|
|
26775
|
+
if (existsSync17(worktreePath)) {
|
|
26528
26776
|
try {
|
|
26529
26777
|
execFileSync5("git", ["worktree", "remove", "--force", worktreePath], {
|
|
26530
26778
|
cwd: bareClonePath2,
|
|
@@ -26561,11 +26809,11 @@ var init_agent_worktree = () => {};
|
|
|
26561
26809
|
|
|
26562
26810
|
// src/agents/scaffold.ts
|
|
26563
26811
|
import {
|
|
26564
|
-
existsSync as
|
|
26565
|
-
mkdirSync as
|
|
26566
|
-
writeFileSync as
|
|
26812
|
+
existsSync as existsSync18,
|
|
26813
|
+
mkdirSync as mkdirSync11,
|
|
26814
|
+
writeFileSync as writeFileSync6,
|
|
26567
26815
|
appendFileSync as appendFileSync2,
|
|
26568
|
-
readFileSync as
|
|
26816
|
+
readFileSync as readFileSync15,
|
|
26569
26817
|
renameSync as renameSync4,
|
|
26570
26818
|
chmodSync as chmodSync2,
|
|
26571
26819
|
symlinkSync as symlinkSync2,
|
|
@@ -26579,7 +26827,7 @@ import {
|
|
|
26579
26827
|
} from "node:fs";
|
|
26580
26828
|
import { homedir as homedir5 } from "node:os";
|
|
26581
26829
|
import { execSync, execFileSync as execFileSync6 } from "node:child_process";
|
|
26582
|
-
import { dirname as
|
|
26830
|
+
import { dirname as dirname6, isAbsolute as isAbsolute2, join as join12, relative as relative2, resolve as resolve11 } from "node:path";
|
|
26583
26831
|
import { createHash as createHash4 } from "node:crypto";
|
|
26584
26832
|
function prependReplyDiscipline(rendered, context) {
|
|
26585
26833
|
const replyDiscipline = renderReplyDisciplineFragment(context);
|
|
@@ -26661,12 +26909,12 @@ function maybeWriteCronMcp(agentDir, mcpServers, cronSessionEnabled) {
|
|
|
26661
26909
|
"switchroom-telegram": cronTelegram
|
|
26662
26910
|
};
|
|
26663
26911
|
const cronDir = join12(agentDir, ".claude-cron");
|
|
26664
|
-
|
|
26912
|
+
mkdirSync11(cronDir, { recursive: true });
|
|
26665
26913
|
const path = join12(cronDir, ".mcp.json");
|
|
26666
26914
|
const content = JSON.stringify({ mcpServers: cronServers }, null, 2) + `
|
|
26667
26915
|
`;
|
|
26668
|
-
if (!
|
|
26669
|
-
|
|
26916
|
+
if (!existsSync18(path) || readFileSync15(path, "utf-8") !== content) {
|
|
26917
|
+
writeFileSync6(path, content, { encoding: "utf-8", mode: 384 });
|
|
26670
26918
|
}
|
|
26671
26919
|
seedCronConfigDir(agentDir, Object.keys(cronServers));
|
|
26672
26920
|
return path;
|
|
@@ -26677,13 +26925,13 @@ function alignAgentUid(name, agentDir, uid, opts = {}) {
|
|
|
26677
26925
|
const auditDir = join12(homedir5(), ".switchroom", "audit", name);
|
|
26678
26926
|
const configMirrorDir = join12(homedir5(), ".switchroom-config", "agents", name, "personal-skills");
|
|
26679
26927
|
const paths = [];
|
|
26680
|
-
if (
|
|
26928
|
+
if (existsSync18(agentDir))
|
|
26681
26929
|
paths.push(agentDir);
|
|
26682
|
-
if (
|
|
26930
|
+
if (existsSync18(logsDir))
|
|
26683
26931
|
paths.push(logsDir);
|
|
26684
|
-
if (
|
|
26932
|
+
if (existsSync18(auditDir))
|
|
26685
26933
|
paths.push(auditDir);
|
|
26686
|
-
if (
|
|
26934
|
+
if (existsSync18(configMirrorDir))
|
|
26687
26935
|
paths.push(configMirrorDir);
|
|
26688
26936
|
if (paths.length === 0)
|
|
26689
26937
|
return { chowned: false, paths: [] };
|
|
@@ -26700,7 +26948,7 @@ function alignAgentUid(name, agentDir, uid, opts = {}) {
|
|
|
26700
26948
|
return { chowned: false, paths };
|
|
26701
26949
|
try {
|
|
26702
26950
|
const logPath = join12(homedir5(), ".switchroom", ".uid-alignment.log");
|
|
26703
|
-
|
|
26951
|
+
mkdirSync11(join12(homedir5(), ".switchroom"), { recursive: true });
|
|
26704
26952
|
const ts = new Date().toISOString();
|
|
26705
26953
|
for (const prior of priors) {
|
|
26706
26954
|
if (prior.uid !== undefined && prior.gid !== undefined && (prior.uid !== uid || prior.gid !== uid)) {
|
|
@@ -26756,16 +27004,16 @@ function refreshTelegramBotTokenEnv(agentDir, resolvedBotToken, changes) {
|
|
|
26756
27004
|
if (!resolvedBotToken)
|
|
26757
27005
|
return;
|
|
26758
27006
|
const envPath = join12(agentDir, "telegram", ".env");
|
|
26759
|
-
if (!
|
|
27007
|
+
if (!existsSync18(envPath))
|
|
26760
27008
|
return;
|
|
26761
|
-
const current =
|
|
27009
|
+
const current = readFileSync15(envPath, "utf-8");
|
|
26762
27010
|
if (!isTelegramEnvPlaceholder(current))
|
|
26763
27011
|
return;
|
|
26764
27012
|
const next = `TELEGRAM_BOT_TOKEN=${resolvedBotToken}
|
|
26765
27013
|
`;
|
|
26766
27014
|
if (next === current)
|
|
26767
27015
|
return;
|
|
26768
|
-
|
|
27016
|
+
writeFileSync6(envPath, next, { encoding: "utf-8", mode: 384 });
|
|
26769
27017
|
changes.push(envPath);
|
|
26770
27018
|
}
|
|
26771
27019
|
function stripOfficialTelegramPlugin(payload) {
|
|
@@ -26793,10 +27041,10 @@ function setupPlugins(agentDir, useSwitchroomPlugin = false) {
|
|
|
26793
27041
|
const globalPluginsDir = join12(home2, ".claude", "plugins");
|
|
26794
27042
|
const agentPluginsDir = join12(agentDir, ".claude", "plugins");
|
|
26795
27043
|
const agentMarketplacesDir = join12(agentPluginsDir, "marketplaces");
|
|
26796
|
-
|
|
27044
|
+
mkdirSync11(agentMarketplacesDir, { recursive: true });
|
|
26797
27045
|
const globalMarketplace = join12(globalPluginsDir, "marketplaces", "claude-plugins-official");
|
|
26798
27046
|
const agentMarketplace = join12(agentMarketplacesDir, "claude-plugins-official");
|
|
26799
|
-
if (
|
|
27047
|
+
if (existsSync18(globalMarketplace) && !existsSync18(agentMarketplace)) {
|
|
26800
27048
|
try {
|
|
26801
27049
|
symlinkSync2(globalMarketplace, agentMarketplace);
|
|
26802
27050
|
} catch {}
|
|
@@ -26805,11 +27053,11 @@ function setupPlugins(agentDir, useSwitchroomPlugin = false) {
|
|
|
26805
27053
|
for (const file of configFiles) {
|
|
26806
27054
|
const globalFile = join12(globalPluginsDir, file);
|
|
26807
27055
|
const agentFile = join12(agentPluginsDir, file);
|
|
26808
|
-
if (
|
|
27056
|
+
if (existsSync18(globalFile) && !existsSync18(agentFile)) {
|
|
26809
27057
|
try {
|
|
26810
27058
|
if (useSwitchroomPlugin && file === "installed_plugins.json") {
|
|
26811
|
-
const scrubbed = stripOfficialTelegramPlugin(
|
|
26812
|
-
|
|
27059
|
+
const scrubbed = stripOfficialTelegramPlugin(readFileSync15(globalFile, "utf8"));
|
|
27060
|
+
writeFileSync6(agentFile, scrubbed);
|
|
26813
27061
|
} else {
|
|
26814
27062
|
copyFileSync4(globalFile, agentFile);
|
|
26815
27063
|
}
|
|
@@ -26820,9 +27068,9 @@ function setupPlugins(agentDir, useSwitchroomPlugin = false) {
|
|
|
26820
27068
|
function webkiteBinaryAvailable() {
|
|
26821
27069
|
const override = process.env.SWITCHROOM_WEBKITE_BINARY;
|
|
26822
27070
|
if (override !== undefined && override !== "") {
|
|
26823
|
-
return
|
|
27071
|
+
return existsSync18(override);
|
|
26824
27072
|
}
|
|
26825
|
-
return
|
|
27073
|
+
return existsSync18(join12(homedir5(), ".switchroom", "bin", "webkite")) || existsSync18(WEBKITE_BINARY_CONTAINER_PATH);
|
|
26826
27074
|
}
|
|
26827
27075
|
function webkiteDenyForAgent(agentConfig) {
|
|
26828
27076
|
if (agentConfig.mcp_servers?.["webkite"] === false)
|
|
@@ -26875,9 +27123,9 @@ function toHostHomePath(p) {
|
|
|
26875
27123
|
return p;
|
|
26876
27124
|
}
|
|
26877
27125
|
function composeWithSidecar(renderedBase, sidecarPath) {
|
|
26878
|
-
if (!
|
|
27126
|
+
if (!existsSync18(sidecarPath))
|
|
26879
27127
|
return renderedBase;
|
|
26880
|
-
const sidecar =
|
|
27128
|
+
const sidecar = readFileSync15(sidecarPath, "utf-8").trimEnd();
|
|
26881
27129
|
if (sidecar.length === 0)
|
|
26882
27130
|
return renderedBase;
|
|
26883
27131
|
return `${renderedBase.trimEnd()}
|
|
@@ -26895,8 +27143,8 @@ function resolveClaudeMdYoursSection(existingFileContent, sidecarPath) {
|
|
|
26895
27143
|
return afterMarker.trimEnd();
|
|
26896
27144
|
}
|
|
26897
27145
|
}
|
|
26898
|
-
if (
|
|
26899
|
-
const sidecar =
|
|
27146
|
+
if (existsSync18(sidecarPath)) {
|
|
27147
|
+
const sidecar = readFileSync15(sidecarPath, "utf-8").trimEnd();
|
|
26900
27148
|
if (sidecar.length > 0) {
|
|
26901
27149
|
const deprecatedPath = sidecarPath + ".deprecated";
|
|
26902
27150
|
try {
|
|
@@ -26919,7 +27167,7 @@ ${yours.trimEnd()}
|
|
|
26919
27167
|
}
|
|
26920
27168
|
function renderSoulMd(profilePath, agentWorkspaceDir, soul) {
|
|
26921
27169
|
const soulMdSrc = join12(profilePath, "workspace", "SOUL.md.hbs");
|
|
26922
|
-
if (!
|
|
27170
|
+
if (!existsSync18(soulMdSrc))
|
|
26923
27171
|
return null;
|
|
26924
27172
|
const rendered = renderTemplate(soulMdSrc, { soul });
|
|
26925
27173
|
const customSoulPath = join12(agentWorkspaceDir, "SOUL.custom.md");
|
|
@@ -27007,7 +27255,7 @@ function migrateLegacySkillsDir(agentDir, skillsPool) {
|
|
|
27007
27255
|
} catch {
|
|
27008
27256
|
continue;
|
|
27009
27257
|
}
|
|
27010
|
-
const resolved = target ? isAbsolute2(target) ? target : resolve11(
|
|
27258
|
+
const resolved = target ? isAbsolute2(target) ? target : resolve11(dirname6(entryPath), target) : null;
|
|
27011
27259
|
if (resolved && resolved.startsWith(skillsPool)) {
|
|
27012
27260
|
try {
|
|
27013
27261
|
rmSync4(entryPath, { force: true });
|
|
@@ -27018,7 +27266,7 @@ function migrateLegacySkillsDir(agentDir, skillsPool) {
|
|
|
27018
27266
|
function syncGlobalSkills(agentDir, declared, skillsDirOverride) {
|
|
27019
27267
|
const skillsPool = resolveSkillsPoolDir(skillsDirOverride);
|
|
27020
27268
|
const agentSkillsDir = join12(agentDir, ".claude", "skills");
|
|
27021
|
-
|
|
27269
|
+
mkdirSync11(agentSkillsDir, { recursive: true });
|
|
27022
27270
|
migrateLegacySkillsDir(agentDir, skillsPool);
|
|
27023
27271
|
for (const name of declared) {
|
|
27024
27272
|
if (!name || name.includes("/") || name === "." || name === "..") {
|
|
@@ -27027,11 +27275,11 @@ function syncGlobalSkills(agentDir, declared, skillsDirOverride) {
|
|
|
27027
27275
|
}
|
|
27028
27276
|
const src = join12(skillsPool, name);
|
|
27029
27277
|
const dest = join12(agentSkillsDir, name);
|
|
27030
|
-
if (!
|
|
27278
|
+
if (!existsSync18(src)) {
|
|
27031
27279
|
console.warn(` WARNING: skill "${name}" not found in pool (${skillsPool}) \u2014 skipping`);
|
|
27032
27280
|
continue;
|
|
27033
27281
|
}
|
|
27034
|
-
const relTarget = relative2(
|
|
27282
|
+
const relTarget = relative2(dirname6(dest), src);
|
|
27035
27283
|
let linkStat;
|
|
27036
27284
|
try {
|
|
27037
27285
|
linkStat = lstatSync4(dest);
|
|
@@ -27047,7 +27295,7 @@ function syncGlobalSkills(agentDir, declared, skillsDirOverride) {
|
|
|
27047
27295
|
if (target === relTarget) {
|
|
27048
27296
|
continue;
|
|
27049
27297
|
}
|
|
27050
|
-
const resolved = target ? isAbsolute2(target) ? target : resolve11(
|
|
27298
|
+
const resolved = target ? isAbsolute2(target) ? target : resolve11(dirname6(dest), target) : null;
|
|
27051
27299
|
if (resolved && resolved.startsWith(skillsPool)) {
|
|
27052
27300
|
try {
|
|
27053
27301
|
rmSync4(dest, { force: true });
|
|
@@ -27076,7 +27324,7 @@ function syncGlobalSkills(agentDir, declared, skillsDirOverride) {
|
|
|
27076
27324
|
} catch {
|
|
27077
27325
|
continue;
|
|
27078
27326
|
}
|
|
27079
|
-
const resolved = linkTarget ? isAbsolute2(linkTarget) ? linkTarget : resolve11(
|
|
27327
|
+
const resolved = linkTarget ? isAbsolute2(linkTarget) ? linkTarget : resolve11(dirname6(entryPath), linkTarget) : null;
|
|
27080
27328
|
if (resolved && resolved.includes("/.switchroom/skills/_bundled/")) {
|
|
27081
27329
|
continue;
|
|
27082
27330
|
}
|
|
@@ -27087,13 +27335,13 @@ function syncGlobalSkills(agentDir, declared, skillsDirOverride) {
|
|
|
27087
27335
|
}
|
|
27088
27336
|
function installSwitchroomSkills(agentDir, opts = {}) {
|
|
27089
27337
|
const builtinSkillsDir = resolve11(homedir5(), ".switchroom/skills/_bundled");
|
|
27090
|
-
if (!
|
|
27338
|
+
if (!existsSync18(builtinSkillsDir)) {
|
|
27091
27339
|
process.stderr.write(`switchroom: bundled skills pool dir not found at ${builtinSkillsDir} \u2014 run \`switchroom update\` to install it.
|
|
27092
27340
|
`);
|
|
27093
27341
|
return;
|
|
27094
27342
|
}
|
|
27095
27343
|
const targetDir = join12(agentDir, ".claude", "skills");
|
|
27096
|
-
|
|
27344
|
+
mkdirSync11(targetDir, { recursive: true });
|
|
27097
27345
|
let entries;
|
|
27098
27346
|
try {
|
|
27099
27347
|
entries = readdirSync7(builtinSkillsDir);
|
|
@@ -27113,7 +27361,7 @@ function installSwitchroomSkills(agentDir, opts = {}) {
|
|
|
27113
27361
|
const src = join12(builtinSkillsDir, name);
|
|
27114
27362
|
try {
|
|
27115
27363
|
const st = lstatSync4(src);
|
|
27116
|
-
return st.isDirectory() &&
|
|
27364
|
+
return st.isDirectory() && existsSync18(join12(src, "SKILL.md"));
|
|
27117
27365
|
} catch {
|
|
27118
27366
|
return false;
|
|
27119
27367
|
}
|
|
@@ -27135,7 +27383,7 @@ function installSwitchroomSkills(agentDir, opts = {}) {
|
|
|
27135
27383
|
} catch {}
|
|
27136
27384
|
if (!currentTarget)
|
|
27137
27385
|
continue;
|
|
27138
|
-
const resolvedTarget = isAbsolute2(currentTarget) ? currentTarget : resolve11(
|
|
27386
|
+
const resolvedTarget = isAbsolute2(currentTarget) ? currentTarget : resolve11(dirname6(dest), currentTarget);
|
|
27139
27387
|
if (resolvedTarget !== join12(builtinSkillsDir, name))
|
|
27140
27388
|
continue;
|
|
27141
27389
|
try {
|
|
@@ -27147,7 +27395,7 @@ function installSwitchroomSkills(agentDir, opts = {}) {
|
|
|
27147
27395
|
for (const name of switchroomSkillNames) {
|
|
27148
27396
|
const src = join12(builtinSkillsDir, name);
|
|
27149
27397
|
const dest = join12(targetDir, name);
|
|
27150
|
-
const relTarget = relative2(
|
|
27398
|
+
const relTarget = relative2(dirname6(dest), src);
|
|
27151
27399
|
let existing;
|
|
27152
27400
|
try {
|
|
27153
27401
|
existing = lstatSync4(dest);
|
|
@@ -27289,9 +27537,9 @@ function filterMcpServers(servers) {
|
|
|
27289
27537
|
return Object.keys(out).length > 0 ? out : undefined;
|
|
27290
27538
|
}
|
|
27291
27539
|
function copyDirRecursive2(src, dest) {
|
|
27292
|
-
if (!
|
|
27540
|
+
if (!existsSync18(src))
|
|
27293
27541
|
return;
|
|
27294
|
-
|
|
27542
|
+
mkdirSync11(dest, { recursive: true });
|
|
27295
27543
|
for (const entry of readdirSync7(src)) {
|
|
27296
27544
|
const srcPath = join12(src, entry);
|
|
27297
27545
|
const destPath = join12(dest, entry);
|
|
@@ -27307,17 +27555,17 @@ function copyDirRecursive2(src, dest) {
|
|
|
27307
27555
|
}
|
|
27308
27556
|
}
|
|
27309
27557
|
function writeFileSyncIfChanged(filePath, content, mode) {
|
|
27310
|
-
if (
|
|
27558
|
+
if (existsSync18(filePath)) {
|
|
27311
27559
|
try {
|
|
27312
|
-
if (
|
|
27560
|
+
if (readFileSync15(filePath, "utf-8") === content)
|
|
27313
27561
|
return false;
|
|
27314
27562
|
} catch {}
|
|
27315
27563
|
}
|
|
27316
|
-
|
|
27564
|
+
writeFileSync6(filePath, content, mode !== undefined ? { encoding: "utf-8", mode } : "utf-8");
|
|
27317
27565
|
return true;
|
|
27318
27566
|
}
|
|
27319
27567
|
function dirContentEquals(src, dest, topLevelOverrides) {
|
|
27320
|
-
if (!
|
|
27568
|
+
if (!existsSync18(src) || !existsSync18(dest))
|
|
27321
27569
|
return false;
|
|
27322
27570
|
let srcEntries;
|
|
27323
27571
|
let destEntries;
|
|
@@ -27355,9 +27603,9 @@ function dirContentEquals(src, dest, topLevelOverrides) {
|
|
|
27355
27603
|
try {
|
|
27356
27604
|
const expected = topLevelOverrides?.[entry];
|
|
27357
27605
|
if (expected !== undefined) {
|
|
27358
|
-
if (
|
|
27606
|
+
if (readFileSync15(d, "utf-8") !== expected)
|
|
27359
27607
|
return false;
|
|
27360
|
-
} else if (!
|
|
27608
|
+
} else if (!readFileSync15(s).equals(readFileSync15(d))) {
|
|
27361
27609
|
return false;
|
|
27362
27610
|
}
|
|
27363
27611
|
} catch {
|
|
@@ -27369,14 +27617,14 @@ function dirContentEquals(src, dest, topLevelOverrides) {
|
|
|
27369
27617
|
}
|
|
27370
27618
|
function seedWorkspaceBootstrapFiles(params) {
|
|
27371
27619
|
const profileWorkspaceDir = join12(params.profilePath, "workspace");
|
|
27372
|
-
if (!
|
|
27620
|
+
if (!existsSync18(profileWorkspaceDir)) {
|
|
27373
27621
|
return;
|
|
27374
27622
|
}
|
|
27375
27623
|
const agentWorkspaceDir = join12(params.agentDir, "workspace");
|
|
27376
|
-
|
|
27624
|
+
mkdirSync11(agentWorkspaceDir, { recursive: true });
|
|
27377
27625
|
const walk = (relDir) => {
|
|
27378
27626
|
const srcDir = join12(profileWorkspaceDir, relDir);
|
|
27379
|
-
if (!
|
|
27627
|
+
if (!existsSync18(srcDir))
|
|
27380
27628
|
return;
|
|
27381
27629
|
for (const entry of readdirSync7(srcDir)) {
|
|
27382
27630
|
if (entry.startsWith(".") && entry !== ".gitkeep")
|
|
@@ -27385,7 +27633,7 @@ function seedWorkspaceBootstrapFiles(params) {
|
|
|
27385
27633
|
const srcPath = join12(profileWorkspaceDir, relPath);
|
|
27386
27634
|
const srcStat = statSync8(srcPath);
|
|
27387
27635
|
if (srcStat.isDirectory()) {
|
|
27388
|
-
|
|
27636
|
+
mkdirSync11(join12(agentWorkspaceDir, relPath), { recursive: true });
|
|
27389
27637
|
walk(relPath);
|
|
27390
27638
|
continue;
|
|
27391
27639
|
}
|
|
@@ -27400,10 +27648,10 @@ function seedWorkspaceBootstrapFiles(params) {
|
|
|
27400
27648
|
const destPath = join12(agentWorkspaceDir, destRel);
|
|
27401
27649
|
if (destRel === "SOUL.default.md") {
|
|
27402
27650
|
const rendered = renderTemplate(srcPath, params.context);
|
|
27403
|
-
const existed =
|
|
27404
|
-
const current = existed ?
|
|
27651
|
+
const existed = existsSync18(destPath);
|
|
27652
|
+
const current = existed ? readFileSync15(destPath, "utf8") : null;
|
|
27405
27653
|
if (current !== rendered) {
|
|
27406
|
-
|
|
27654
|
+
writeFileSync6(destPath, rendered);
|
|
27407
27655
|
params.created.push(destPath);
|
|
27408
27656
|
} else {
|
|
27409
27657
|
params.skipped.push(destPath);
|
|
@@ -27419,7 +27667,7 @@ function seedWorkspaceBootstrapFiles(params) {
|
|
|
27419
27667
|
writeIfMissing(destPath, renderFn, params.created, params.skipped);
|
|
27420
27668
|
} else {
|
|
27421
27669
|
const destPath = join12(agentWorkspaceDir, relPath);
|
|
27422
|
-
if (!
|
|
27670
|
+
if (!existsSync18(destPath)) {
|
|
27423
27671
|
copyFileSync4(srcPath, destPath);
|
|
27424
27672
|
params.created.push(destPath);
|
|
27425
27673
|
} else {
|
|
@@ -27433,27 +27681,27 @@ function seedWorkspaceBootstrapFiles(params) {
|
|
|
27433
27681
|
function migrateLegacyAgentsMdIfPresent(agentWorkspaceDir, created) {
|
|
27434
27682
|
const agentsMd = join12(agentWorkspaceDir, "AGENTS.md");
|
|
27435
27683
|
const claudeMd = join12(agentWorkspaceDir, "CLAUDE.md");
|
|
27436
|
-
if (!
|
|
27684
|
+
if (!existsSync18(agentsMd))
|
|
27437
27685
|
return;
|
|
27438
27686
|
const stat = lstatSync4(agentsMd);
|
|
27439
27687
|
if (stat.isSymbolicLink())
|
|
27440
27688
|
return;
|
|
27441
|
-
if (
|
|
27689
|
+
if (existsSync18(claudeMd)) {
|
|
27442
27690
|
return;
|
|
27443
27691
|
}
|
|
27444
|
-
const content =
|
|
27445
|
-
|
|
27692
|
+
const content = readFileSync15(agentsMd, "utf-8");
|
|
27693
|
+
writeFileSync6(claudeMd, content, "utf-8");
|
|
27446
27694
|
rmSync4(agentsMd);
|
|
27447
27695
|
created.push(claudeMd);
|
|
27448
27696
|
console.log(source_default.dim(` migrated legacy workspace/AGENTS.md \u2192 workspace/CLAUDE.md (content preserved)`));
|
|
27449
27697
|
}
|
|
27450
27698
|
function ensureClaudeMdSymlinks(agentWorkspaceDir, changes) {
|
|
27451
27699
|
const claudeMd = join12(agentWorkspaceDir, "CLAUDE.md");
|
|
27452
|
-
if (!
|
|
27700
|
+
if (!existsSync18(claudeMd))
|
|
27453
27701
|
return;
|
|
27454
27702
|
for (const name of ["AGENTS.md", "AGENT.md"]) {
|
|
27455
27703
|
const linkPath = join12(agentWorkspaceDir, name);
|
|
27456
|
-
if (
|
|
27704
|
+
if (existsSync18(linkPath) || lstatExists(linkPath)) {
|
|
27457
27705
|
const stat = lstatSync4(linkPath);
|
|
27458
27706
|
if (stat.isSymbolicLink()) {
|
|
27459
27707
|
const target = readlinkSync4(linkPath);
|
|
@@ -27484,7 +27732,7 @@ function initWorkspaceGitRepo(workspaceDir, agentName) {
|
|
|
27484
27732
|
return false;
|
|
27485
27733
|
}
|
|
27486
27734
|
const gitDir = join12(workspaceDir, ".git");
|
|
27487
|
-
if (
|
|
27735
|
+
if (existsSync18(gitDir)) {
|
|
27488
27736
|
return true;
|
|
27489
27737
|
}
|
|
27490
27738
|
const gitignore = `# Ephemeral runtime state
|
|
@@ -27496,7 +27744,7 @@ Thumbs.db
|
|
|
27496
27744
|
*.swp
|
|
27497
27745
|
*~
|
|
27498
27746
|
`;
|
|
27499
|
-
|
|
27747
|
+
writeFileSync6(join12(workspaceDir, ".gitignore"), gitignore, "utf-8");
|
|
27500
27748
|
try {
|
|
27501
27749
|
execSync("git init --quiet", { cwd: workspaceDir, stdio: "pipe" });
|
|
27502
27750
|
execSync("git add -A", { cwd: workspaceDir, stdio: "pipe" });
|
|
@@ -27533,7 +27781,7 @@ function installHindsightPlugin(agentName, agentDir, switchroomConfig) {
|
|
|
27533
27781
|
if (agentMemory?.auto_recall === false)
|
|
27534
27782
|
return null;
|
|
27535
27783
|
const sourcePath = resolveHindsightVendorPath();
|
|
27536
|
-
if (!
|
|
27784
|
+
if (!existsSync18(sourcePath)) {
|
|
27537
27785
|
process.stderr.write(`installHindsightPlugin: vendor source missing at ${sourcePath} ` + `\u2014 hindsight plugin NOT installed for ${agentName}. ` + `Likely a packaging regression: check the npm tarball's files array.
|
|
27538
27786
|
`);
|
|
27539
27787
|
return null;
|
|
@@ -27544,13 +27792,13 @@ function installHindsightPlugin(agentName, agentDir, switchroomConfig) {
|
|
|
27544
27792
|
let expectedSettings = null;
|
|
27545
27793
|
try {
|
|
27546
27794
|
const vendorSettingsPath = join12(sourcePath, "settings.json");
|
|
27547
|
-
if (
|
|
27548
|
-
expectedSettings = renderHindsightSettingsOverrides(
|
|
27795
|
+
if (existsSync18(vendorSettingsPath)) {
|
|
27796
|
+
expectedSettings = renderHindsightSettingsOverrides(readFileSync15(vendorSettingsPath, "utf-8"), additionalBanks, retainConfig);
|
|
27549
27797
|
}
|
|
27550
27798
|
} catch {}
|
|
27551
27799
|
const upToDate = dirContentEquals(sourcePath, destPath, expectedSettings != null ? { "settings.json": expectedSettings } : undefined);
|
|
27552
27800
|
if (!upToDate) {
|
|
27553
|
-
if (
|
|
27801
|
+
if (existsSync18(destPath)) {
|
|
27554
27802
|
rmSync4(destPath, { recursive: true, force: true });
|
|
27555
27803
|
}
|
|
27556
27804
|
copyDirRecursive2(sourcePath, destPath);
|
|
@@ -27571,11 +27819,11 @@ function resolveHindsightRetainConfig(switchroomConfig, agentName) {
|
|
|
27571
27819
|
}
|
|
27572
27820
|
function applyHindsightSettingsOverrides(pluginDestPath, additionalBanks, retainConfig) {
|
|
27573
27821
|
const settingsPath = join12(pluginDestPath, "settings.json");
|
|
27574
|
-
if (!
|
|
27822
|
+
if (!existsSync18(settingsPath))
|
|
27575
27823
|
return;
|
|
27576
27824
|
let raw;
|
|
27577
27825
|
try {
|
|
27578
|
-
raw =
|
|
27826
|
+
raw = readFileSync15(settingsPath, "utf-8");
|
|
27579
27827
|
} catch {
|
|
27580
27828
|
return;
|
|
27581
27829
|
}
|
|
@@ -27974,23 +28222,23 @@ function scaffoldAgent(name, agentConfigRaw, agentsDir, telegramConfig, switchro
|
|
|
27974
28222
|
join12(agentDir, "telegram")
|
|
27975
28223
|
];
|
|
27976
28224
|
for (const dir of dirs) {
|
|
27977
|
-
|
|
28225
|
+
mkdirSync11(dir, { recursive: true });
|
|
27978
28226
|
}
|
|
27979
28227
|
writeIfChanged(join12(agentDir, "start.sh"), () => renderTemplate(join12(basePath, "start.sh.hbs"), context), created, skipped);
|
|
27980
|
-
if (
|
|
28228
|
+
if (existsSync18(join12(agentDir, "start.sh"))) {
|
|
27981
28229
|
chmodSync2(join12(agentDir, "start.sh"), 448);
|
|
27982
28230
|
}
|
|
27983
28231
|
if (context.cronSessionEnabled) {
|
|
27984
28232
|
writeIfChanged(join12(agentDir, "cron-session.sh"), () => renderTemplate(join12(basePath, "cron-session.sh.hbs"), context), created, skipped);
|
|
27985
|
-
if (
|
|
28233
|
+
if (existsSync18(join12(agentDir, "cron-session.sh"))) {
|
|
27986
28234
|
chmodSync2(join12(agentDir, "cron-session.sh"), 448);
|
|
27987
28235
|
}
|
|
27988
28236
|
}
|
|
27989
28237
|
writeIfMissing(join12(agentDir, ".claude", "settings.json"), () => renderTemplate(join12(basePath, "settings.json.hbs"), context), created, skipped, 384);
|
|
27990
28238
|
if (switchroomConfig) {
|
|
27991
28239
|
const settingsPath = join12(agentDir, ".claude", "settings.json");
|
|
27992
|
-
if (
|
|
27993
|
-
const settings = JSON.parse(
|
|
28240
|
+
if (existsSync18(settingsPath)) {
|
|
28241
|
+
const settings = JSON.parse(readFileSync15(settingsPath, "utf-8"));
|
|
27994
28242
|
if (!settings.mcpServers) {
|
|
27995
28243
|
settings.mcpServers = {};
|
|
27996
28244
|
}
|
|
@@ -28133,7 +28381,7 @@ function scaffoldAgent(name, agentConfigRaw, agentsDir, telegramConfig, switchro
|
|
|
28133
28381
|
];
|
|
28134
28382
|
for (const { src, dest } of templateFiles) {
|
|
28135
28383
|
const srcPath = join12(profilePath, src);
|
|
28136
|
-
if (
|
|
28384
|
+
if (existsSync18(srcPath)) {
|
|
28137
28385
|
const renderManaged = () => {
|
|
28138
28386
|
let rendered = renderTemplate(srcPath, context);
|
|
28139
28387
|
if (dest === "CLAUDE.md") {
|
|
@@ -28190,7 +28438,7 @@ function scaffoldAgent(name, agentConfigRaw, agentsDir, telegramConfig, switchro
|
|
|
28190
28438
|
}
|
|
28191
28439
|
}
|
|
28192
28440
|
const phase5WorkspaceDir = join12(agentDir, "workspace");
|
|
28193
|
-
|
|
28441
|
+
mkdirSync11(phase5WorkspaceDir, { recursive: true });
|
|
28194
28442
|
migrateLegacyAgentsMdIfPresent(phase5WorkspaceDir, created);
|
|
28195
28443
|
seedWorkspaceBootstrapFiles({
|
|
28196
28444
|
profilePath,
|
|
@@ -28203,9 +28451,9 @@ function scaffoldAgent(name, agentConfigRaw, agentsDir, telegramConfig, switchro
|
|
|
28203
28451
|
});
|
|
28204
28452
|
ensureClaudeMdSymlinks(phase5WorkspaceDir, created);
|
|
28205
28453
|
const persistentHomeDir = join12(agentDir, "home");
|
|
28206
|
-
|
|
28454
|
+
mkdirSync11(persistentHomeDir, { recursive: true });
|
|
28207
28455
|
for (const sub of [".local/bin", ".npm-global", "bin"]) {
|
|
28208
|
-
|
|
28456
|
+
mkdirSync11(join12(persistentHomeDir, sub), { recursive: true });
|
|
28209
28457
|
}
|
|
28210
28458
|
if (!isContainerContext() && process.env.HOME) {
|
|
28211
28459
|
const dotSwitchroomLink = join12(persistentHomeDir, ".switchroom");
|
|
@@ -28247,7 +28495,7 @@ function scaffoldAgent(name, agentConfigRaw, agentsDir, telegramConfig, switchro
|
|
|
28247
28495
|
const existingClaudeJson = findExistingClaudeJson();
|
|
28248
28496
|
if (existingClaudeJson) {
|
|
28249
28497
|
copyOnboardingState(existingClaudeJson, agentDir);
|
|
28250
|
-
if (!
|
|
28498
|
+
if (!existsSync18(join12(agentDir, ".claude", "config.json"))) {
|
|
28251
28499
|
writeIfMissing(join12(agentDir, ".claude", "config.json"), () => JSON.stringify({ hasCompletedOnboarding: true, numStartups: 1 }, null, 2) + `
|
|
28252
28500
|
`, created, skipped, 384);
|
|
28253
28501
|
}
|
|
@@ -28274,7 +28522,7 @@ This file is auto-maintained. Do not edit manually.
|
|
|
28274
28522
|
writeFileSyncIfChanged(join12(agentDir, "telegram", "people.json"), buildPeopleJson(switchroomConfig), 384);
|
|
28275
28523
|
if (agentConfig.subagents) {
|
|
28276
28524
|
const agentsDir2 = join12(agentDir, ".claude", "agents");
|
|
28277
|
-
|
|
28525
|
+
mkdirSync11(agentsDir2, { recursive: true });
|
|
28278
28526
|
for (const [saName, saDef] of Object.entries(agentConfig.subagents)) {
|
|
28279
28527
|
const mdPath = join12(agentsDir2, `${saName}.md`);
|
|
28280
28528
|
if (!saDef.description) {
|
|
@@ -28331,13 +28579,13 @@ ${body}
|
|
|
28331
28579
|
}
|
|
28332
28580
|
{
|
|
28333
28581
|
const telegramDir = join12(agentDir, "telegram");
|
|
28334
|
-
if (
|
|
28582
|
+
if (existsSync18(telegramDir)) {
|
|
28335
28583
|
for (const file of readdirSync7(telegramDir)) {
|
|
28336
28584
|
const isCronScript = CRON_SCRIPT_BASENAME_RE.test(file) || LEGACY_CRON_SCRIPT_BASENAME_RE.test(file);
|
|
28337
28585
|
if (isCronScript) {
|
|
28338
28586
|
unlinkSync4(join12(telegramDir, file));
|
|
28339
28587
|
const sidecar = join12(telegramDir, file.replace(/\.sh$/, ".source"));
|
|
28340
|
-
if (
|
|
28588
|
+
if (existsSync18(sidecar))
|
|
28341
28589
|
unlinkSync4(sidecar);
|
|
28342
28590
|
}
|
|
28343
28591
|
}
|
|
@@ -28353,8 +28601,8 @@ ${body}
|
|
|
28353
28601
|
setupPlugins(agentDir, usesSwitchroomTelegramPlugin(agentConfig));
|
|
28354
28602
|
const agentSoulPath = join12(agentDir, "SOUL.md");
|
|
28355
28603
|
const workspaceSoulPath = join12(agentDir, "workspace", "SOUL.md");
|
|
28356
|
-
if (
|
|
28357
|
-
if (
|
|
28604
|
+
if (existsSync18(workspaceSoulPath)) {
|
|
28605
|
+
if (existsSync18(agentSoulPath)) {
|
|
28358
28606
|
const stat = lstatSync4(agentSoulPath);
|
|
28359
28607
|
if (stat.isSymbolicLink()) {
|
|
28360
28608
|
const target = readlinkSync4(agentSoulPath);
|
|
@@ -28829,13 +29077,13 @@ function reconcileAgentInner(name, agentConfigRaw, agentsDir, telegramConfig, sw
|
|
|
28829
29077
|
}
|
|
28830
29078
|
});
|
|
28831
29079
|
}
|
|
28832
|
-
if (!
|
|
29080
|
+
if (!existsSync18(agentDir)) {
|
|
28833
29081
|
throw new Error(`Agent directory does not exist: ${agentDir}. Run \`switchroom agent create ${name}\` first.`);
|
|
28834
29082
|
}
|
|
28835
29083
|
{
|
|
28836
29084
|
const explicitResumeMode = agentConfig.session_continuity?.resume_mode;
|
|
28837
29085
|
const markerPath = join12(agentDir, ".resume-mode-migration-warned");
|
|
28838
|
-
if (!explicitResumeMode && !
|
|
29086
|
+
if (!explicitResumeMode && !existsSync18(markerPath)) {
|
|
28839
29087
|
console.warn(` ${source_default.yellow("\u26a0")} [${name}] resume_mode default changed from 'auto' to 'handoff' (switchroom #362).`);
|
|
28840
29088
|
console.warn(` Your agent will now start a fresh Claude session on every restart, using a`);
|
|
28841
29089
|
console.warn(` context briefing instead of --continue. This prevents stale MCP servers`);
|
|
@@ -28845,7 +29093,7 @@ function reconcileAgentInner(name, agentConfigRaw, agentsDir, telegramConfig, sw
|
|
|
28845
29093
|
console.warn(` resume_mode: auto`);
|
|
28846
29094
|
console.warn(` (This warning fires once per agent directory and is then suppressed.)`);
|
|
28847
29095
|
try {
|
|
28848
|
-
|
|
29096
|
+
writeFileSync6(markerPath, `resume_mode default changed to handoff at reconcile
|
|
28849
29097
|
`, "utf-8");
|
|
28850
29098
|
} catch {}
|
|
28851
29099
|
}
|
|
@@ -28853,10 +29101,10 @@ function reconcileAgentInner(name, agentConfigRaw, agentsDir, telegramConfig, sw
|
|
|
28853
29101
|
const legacyCustomPath = join12(agentDir, "CLAUDE.custom.md");
|
|
28854
29102
|
const workspaceDir = join12(agentDir, "workspace");
|
|
28855
29103
|
const newCustomPath = join12(workspaceDir, "CLAUDE.custom.md");
|
|
28856
|
-
if (
|
|
28857
|
-
|
|
28858
|
-
const legacyContent =
|
|
28859
|
-
|
|
29104
|
+
if (existsSync18(legacyCustomPath) && !existsSync18(newCustomPath)) {
|
|
29105
|
+
mkdirSync11(workspaceDir, { recursive: true });
|
|
29106
|
+
const legacyContent = readFileSync15(legacyCustomPath, "utf-8");
|
|
29107
|
+
writeFileSync6(newCustomPath, legacyContent, "utf-8");
|
|
28860
29108
|
rmSync4(legacyCustomPath);
|
|
28861
29109
|
console.log(source_default.green(` moved CLAUDE.custom.md \u2192 workspace/CLAUDE.custom.md`));
|
|
28862
29110
|
}
|
|
@@ -28989,19 +29237,19 @@ ${baseAppend}` : TELEGRAM_FORMATTING_FLOOR_CARD;
|
|
|
28989
29237
|
resumeMaxBytes: agentConfig.session_continuity?.resume_max_bytes ?? 2000000,
|
|
28990
29238
|
bootResumeMode: agentConfig.session_continuity?.boot_resume ?? "in-flight"
|
|
28991
29239
|
};
|
|
28992
|
-
const beforeStartSh =
|
|
29240
|
+
const beforeStartSh = existsSync18(startShPath) ? readFileSync15(startShPath, "utf-8") : "";
|
|
28993
29241
|
const afterStartSh = renderTemplate(join12(basePath, "start.sh.hbs"), startShContext);
|
|
28994
29242
|
if (afterStartSh !== beforeStartSh) {
|
|
28995
|
-
|
|
29243
|
+
writeFileSync6(startShPath, afterStartSh, "utf-8");
|
|
28996
29244
|
chmodSync2(startShPath, 493);
|
|
28997
29245
|
changes.push(startShPath);
|
|
28998
29246
|
}
|
|
28999
29247
|
if (startShContext.cronSessionEnabled) {
|
|
29000
29248
|
const cronShPath = join12(agentDir, "cron-session.sh");
|
|
29001
|
-
const beforeCronSh =
|
|
29249
|
+
const beforeCronSh = existsSync18(cronShPath) ? readFileSync15(cronShPath, "utf-8") : "";
|
|
29002
29250
|
const afterCronSh = renderTemplate(join12(basePath, "cron-session.sh.hbs"), startShContext);
|
|
29003
29251
|
if (afterCronSh !== beforeCronSh) {
|
|
29004
|
-
|
|
29252
|
+
writeFileSync6(cronShPath, afterCronSh, "utf-8");
|
|
29005
29253
|
chmodSync2(cronShPath, 493);
|
|
29006
29254
|
changes.push(cronShPath);
|
|
29007
29255
|
}
|
|
@@ -29012,7 +29260,7 @@ ${baseAppend}` : TELEGRAM_FORMATTING_FLOOR_CARD;
|
|
|
29012
29260
|
const claudeMdSrc = join12(profilePath, "CLAUDE.md.hbs");
|
|
29013
29261
|
const claudeMdDest = join12(agentDir, "CLAUDE.md");
|
|
29014
29262
|
const claudeCustomPath = join12(agentDir, "workspace", "CLAUDE.custom.md");
|
|
29015
|
-
if (
|
|
29263
|
+
if (existsSync18(claudeMdSrc)) {
|
|
29016
29264
|
const claudeContext = {
|
|
29017
29265
|
name,
|
|
29018
29266
|
agentDir,
|
|
@@ -29071,17 +29319,17 @@ ${baseAppend}` : TELEGRAM_FORMATTING_FLOOR_CARD;
|
|
|
29071
29319
|
` + agentConfig.claude_md_raw + `
|
|
29072
29320
|
`;
|
|
29073
29321
|
}
|
|
29074
|
-
const before =
|
|
29322
|
+
const before = existsSync18(claudeMdDest) ? readFileSync15(claudeMdDest, "utf-8") : "";
|
|
29075
29323
|
const composed = composeTwoSectionClaudeMd(rendered, before.length > 0 ? before : null, claudeCustomPath);
|
|
29076
29324
|
if (composed !== before) {
|
|
29077
|
-
|
|
29325
|
+
writeFileSync6(claudeMdDest, composed, "utf-8");
|
|
29078
29326
|
changes.push(claudeMdDest);
|
|
29079
29327
|
}
|
|
29080
29328
|
}
|
|
29081
29329
|
}
|
|
29082
29330
|
const settingsPath = join12(agentDir, ".claude", "settings.json");
|
|
29083
|
-
if (
|
|
29084
|
-
const before =
|
|
29331
|
+
if (existsSync18(settingsPath)) {
|
|
29332
|
+
const before = readFileSync15(settingsPath, "utf-8");
|
|
29085
29333
|
const settings = JSON.parse(before);
|
|
29086
29334
|
settings.permissions = settings.permissions ?? {};
|
|
29087
29335
|
settings.permissions.allow = desiredAllow;
|
|
@@ -29143,15 +29391,15 @@ ${baseAppend}` : TELEGRAM_FORMATTING_FLOOR_CARD;
|
|
|
29143
29391
|
});
|
|
29144
29392
|
let greetingUserId;
|
|
29145
29393
|
const accessPath = join12(agentDir, "telegram", "access.json");
|
|
29146
|
-
if (
|
|
29394
|
+
if (existsSync18(accessPath)) {
|
|
29147
29395
|
try {
|
|
29148
|
-
const access = JSON.parse(
|
|
29396
|
+
const access = JSON.parse(readFileSync15(accessPath, "utf-8"));
|
|
29149
29397
|
greetingUserId = access.allowFrom?.[0];
|
|
29150
29398
|
} catch {}
|
|
29151
29399
|
}
|
|
29152
29400
|
if (agentConfig.subagents) {
|
|
29153
29401
|
const saDir = join12(agentDir, ".claude", "agents");
|
|
29154
|
-
|
|
29402
|
+
mkdirSync11(saDir, { recursive: true });
|
|
29155
29403
|
for (const [saName, saDef] of Object.entries(agentConfig.subagents)) {
|
|
29156
29404
|
const mdPath = join12(saDir, `${saName}.md`);
|
|
29157
29405
|
if (!saDef.description) {
|
|
@@ -29203,9 +29451,9 @@ ${fmLines}
|
|
|
29203
29451
|
|
|
29204
29452
|
${body}
|
|
29205
29453
|
`;
|
|
29206
|
-
const before2 =
|
|
29454
|
+
const before2 = existsSync18(mdPath) ? readFileSync15(mdPath, "utf-8") : "";
|
|
29207
29455
|
if (content !== before2) {
|
|
29208
|
-
|
|
29456
|
+
writeFileSync6(mdPath, content, "utf-8");
|
|
29209
29457
|
changes.push(mdPath);
|
|
29210
29458
|
}
|
|
29211
29459
|
}
|
|
@@ -29223,7 +29471,7 @@ ${body}
|
|
|
29223
29471
|
}
|
|
29224
29472
|
}
|
|
29225
29473
|
const telegramDir = join12(agentDir, "telegram");
|
|
29226
|
-
if (
|
|
29474
|
+
if (existsSync18(telegramDir)) {
|
|
29227
29475
|
const files = readdirSync7(telegramDir);
|
|
29228
29476
|
for (const file of files) {
|
|
29229
29477
|
const isCronScript = CRON_SCRIPT_BASENAME_RE.test(file) || LEGACY_CRON_SCRIPT_BASENAME_RE.test(file);
|
|
@@ -29232,7 +29480,7 @@ ${body}
|
|
|
29232
29480
|
unlinkSync4(staleScript);
|
|
29233
29481
|
changes.push(staleScript);
|
|
29234
29482
|
const sourceSidecar = staleScript.replace(/\.sh$/, ".source");
|
|
29235
|
-
if (
|
|
29483
|
+
if (existsSync18(sourceSidecar)) {
|
|
29236
29484
|
unlinkSync4(sourceSidecar);
|
|
29237
29485
|
changes.push(sourceSidecar);
|
|
29238
29486
|
}
|
|
@@ -29310,7 +29558,7 @@ ${body}
|
|
|
29310
29558
|
const mcpJson = { mcpServers };
|
|
29311
29559
|
const after = JSON.stringify(mcpJson, null, 2) + `
|
|
29312
29560
|
`;
|
|
29313
|
-
const before =
|
|
29561
|
+
const before = existsSync18(mcpJsonPath) ? readFileSync15(mcpJsonPath, "utf-8") : "";
|
|
29314
29562
|
if (after !== before) {
|
|
29315
29563
|
atomicWriteFileSync(mcpJsonPath, after, 384);
|
|
29316
29564
|
changes.push(mcpJsonPath);
|
|
@@ -29349,7 +29597,7 @@ ${body}
|
|
|
29349
29597
|
hindsightSenderBanksJson,
|
|
29350
29598
|
hindsightTopicFilterMode
|
|
29351
29599
|
});
|
|
29352
|
-
|
|
29600
|
+
mkdirSync11(reconcileWorkspaceDir, { recursive: true });
|
|
29353
29601
|
migrateLegacyAgentsMdIfPresent(reconcileWorkspaceDir, changes);
|
|
29354
29602
|
seedWorkspaceBootstrapFiles({
|
|
29355
29603
|
profilePath: reconcileProfilePath,
|
|
@@ -29362,13 +29610,13 @@ ${body}
|
|
|
29362
29610
|
});
|
|
29363
29611
|
ensureClaudeMdSymlinks(reconcileWorkspaceDir, changes);
|
|
29364
29612
|
}
|
|
29365
|
-
if (
|
|
29613
|
+
if (existsSync18(reconcileWorkspaceDir)) {
|
|
29366
29614
|
initWorkspaceGitRepo(reconcileWorkspaceDir, name);
|
|
29367
29615
|
}
|
|
29368
29616
|
const agentSoulPath = join12(agentDir, "SOUL.md");
|
|
29369
29617
|
const workspaceSoulPath = join12(agentDir, "workspace", "SOUL.md");
|
|
29370
|
-
if (
|
|
29371
|
-
if (
|
|
29618
|
+
if (existsSync18(workspaceSoulPath)) {
|
|
29619
|
+
if (existsSync18(agentSoulPath)) {
|
|
29372
29620
|
const stat = lstatSync4(agentSoulPath);
|
|
29373
29621
|
if (stat.isSymbolicLink()) {
|
|
29374
29622
|
const target = readlinkSync4(agentSoulPath);
|
|
@@ -29479,7 +29727,7 @@ ${body}
|
|
|
29479
29727
|
};
|
|
29480
29728
|
}
|
|
29481
29729
|
function writeIfMissing(filePath, contentFn, created, skipped, mode) {
|
|
29482
|
-
if (
|
|
29730
|
+
if (existsSync18(filePath)) {
|
|
29483
29731
|
skipped.push(filePath);
|
|
29484
29732
|
return;
|
|
29485
29733
|
}
|
|
@@ -29488,12 +29736,12 @@ function writeIfMissing(filePath, contentFn, created, skipped, mode) {
|
|
|
29488
29736
|
}
|
|
29489
29737
|
function writeIfChanged(filePath, contentFn, created, skipped, mode) {
|
|
29490
29738
|
const next = contentFn();
|
|
29491
|
-
const prev =
|
|
29739
|
+
const prev = existsSync18(filePath) ? readFileSync15(filePath, "utf-8") : null;
|
|
29492
29740
|
if (prev === next) {
|
|
29493
29741
|
skipped.push(filePath);
|
|
29494
29742
|
return;
|
|
29495
29743
|
}
|
|
29496
|
-
|
|
29744
|
+
writeFileSync6(filePath, next, mode !== undefined ? { encoding: "utf-8", mode } : "utf-8");
|
|
29497
29745
|
created.push(filePath);
|
|
29498
29746
|
}
|
|
29499
29747
|
function claudeMdManagedSection(content) {
|
|
@@ -29503,42 +29751,42 @@ function claudeMdManagedSection(content) {
|
|
|
29503
29751
|
return content.slice(0, idx + CLAUDE_MD_YOURS_MARKER.length);
|
|
29504
29752
|
}
|
|
29505
29753
|
function writeTwoSectionClaudeMdWithFingerprint(filePath, managedFn, sidecarPath, created, skipped, rewrittenWithBackup) {
|
|
29506
|
-
const prev =
|
|
29754
|
+
const prev = existsSync18(filePath) ? readFileSync15(filePath, "utf-8") : null;
|
|
29507
29755
|
const next = composeTwoSectionClaudeMd(managedFn(), prev, sidecarPath);
|
|
29508
29756
|
const nextManagedHash = createHash4("sha256").update(claudeMdManagedSection(next), "utf-8").digest("hex");
|
|
29509
29757
|
const fingerprintPath = filePath + ".fingerprint";
|
|
29510
29758
|
if (prev === null) {
|
|
29511
|
-
|
|
29512
|
-
|
|
29759
|
+
writeFileSync6(filePath, next, "utf-8");
|
|
29760
|
+
writeFileSync6(fingerprintPath, nextManagedHash, "utf-8");
|
|
29513
29761
|
created.push(filePath);
|
|
29514
29762
|
return;
|
|
29515
29763
|
}
|
|
29516
29764
|
if (prev === next) {
|
|
29517
29765
|
try {
|
|
29518
|
-
|
|
29766
|
+
writeFileSync6(fingerprintPath, nextManagedHash, "utf-8");
|
|
29519
29767
|
} catch {}
|
|
29520
29768
|
skipped.push(filePath);
|
|
29521
29769
|
return;
|
|
29522
29770
|
}
|
|
29523
29771
|
const prevManagedHash = createHash4("sha256").update(claudeMdManagedSection(prev), "utf-8").digest("hex");
|
|
29524
|
-
const recordedFingerprint =
|
|
29772
|
+
const recordedFingerprint = existsSync18(fingerprintPath) ? readFileSync15(fingerprintPath, "utf-8").trim() : null;
|
|
29525
29773
|
if (recordedFingerprint === prevManagedHash) {
|
|
29526
|
-
|
|
29527
|
-
|
|
29774
|
+
writeFileSync6(filePath, next, "utf-8");
|
|
29775
|
+
writeFileSync6(fingerprintPath, nextManagedHash, "utf-8");
|
|
29528
29776
|
created.push(filePath);
|
|
29529
29777
|
return;
|
|
29530
29778
|
}
|
|
29531
29779
|
const backupPath = `${filePath}.before-rerender.${Date.now()}`;
|
|
29532
29780
|
try {
|
|
29533
|
-
|
|
29781
|
+
writeFileSync6(backupPath, prev, "utf-8");
|
|
29534
29782
|
} catch (err) {
|
|
29535
29783
|
process.stderr.write(`scaffold: refusing to overwrite ${filePath} \u2014 backup write failed ` + `(${err.message}). Operator edits preserved.
|
|
29536
29784
|
`);
|
|
29537
29785
|
skipped.push(filePath);
|
|
29538
29786
|
return;
|
|
29539
29787
|
}
|
|
29540
|
-
|
|
29541
|
-
|
|
29788
|
+
writeFileSync6(filePath, next, "utf-8");
|
|
29789
|
+
writeFileSync6(fingerprintPath, nextManagedHash, "utf-8");
|
|
29542
29790
|
rewrittenWithBackup.push(filePath);
|
|
29543
29791
|
created.push(filePath);
|
|
29544
29792
|
}
|
|
@@ -29547,39 +29795,39 @@ function rerenderWithFingerprint(filePath, contentFn, created, skipped, rewritte
|
|
|
29547
29795
|
const nextHash = createHash4("sha256").update(next, "utf-8").digest("hex");
|
|
29548
29796
|
const fingerprintPath = filePath + ".fingerprint";
|
|
29549
29797
|
const writeMode = mode !== undefined ? { encoding: "utf-8", mode } : "utf-8";
|
|
29550
|
-
if (!
|
|
29551
|
-
|
|
29552
|
-
|
|
29798
|
+
if (!existsSync18(filePath)) {
|
|
29799
|
+
writeFileSync6(filePath, next, writeMode);
|
|
29800
|
+
writeFileSync6(fingerprintPath, nextHash, "utf-8");
|
|
29553
29801
|
created.push(filePath);
|
|
29554
29802
|
return;
|
|
29555
29803
|
}
|
|
29556
|
-
const prev =
|
|
29804
|
+
const prev = readFileSync15(filePath, "utf-8");
|
|
29557
29805
|
if (prev === next) {
|
|
29558
29806
|
try {
|
|
29559
|
-
|
|
29807
|
+
writeFileSync6(fingerprintPath, nextHash, "utf-8");
|
|
29560
29808
|
} catch {}
|
|
29561
29809
|
skipped.push(filePath);
|
|
29562
29810
|
return;
|
|
29563
29811
|
}
|
|
29564
29812
|
const prevHash = createHash4("sha256").update(prev, "utf-8").digest("hex");
|
|
29565
|
-
const recordedFingerprint =
|
|
29813
|
+
const recordedFingerprint = existsSync18(fingerprintPath) ? readFileSync15(fingerprintPath, "utf-8").trim() : null;
|
|
29566
29814
|
if (recordedFingerprint === prevHash) {
|
|
29567
|
-
|
|
29568
|
-
|
|
29815
|
+
writeFileSync6(filePath, next, writeMode);
|
|
29816
|
+
writeFileSync6(fingerprintPath, nextHash, "utf-8");
|
|
29569
29817
|
created.push(filePath);
|
|
29570
29818
|
return;
|
|
29571
29819
|
}
|
|
29572
29820
|
const backupPath = `${filePath}.before-rerender.${Date.now()}`;
|
|
29573
29821
|
try {
|
|
29574
|
-
|
|
29822
|
+
writeFileSync6(backupPath, prev, "utf-8");
|
|
29575
29823
|
} catch (err) {
|
|
29576
29824
|
process.stderr.write(`scaffold: refusing to overwrite ${filePath} \u2014 backup write failed ` + `(${err.message}). Operator edits preserved.
|
|
29577
29825
|
`);
|
|
29578
29826
|
skipped.push(filePath);
|
|
29579
29827
|
return;
|
|
29580
29828
|
}
|
|
29581
|
-
|
|
29582
|
-
|
|
29829
|
+
writeFileSync6(filePath, next, writeMode);
|
|
29830
|
+
writeFileSync6(fingerprintPath, nextHash, "utf-8");
|
|
29583
29831
|
rewrittenWithBackup.push(filePath);
|
|
29584
29832
|
created.push(filePath);
|
|
29585
29833
|
}
|
|
@@ -29590,7 +29838,7 @@ function resolveAgentForumChatId(agentConfig, telegramConfig) {
|
|
|
29590
29838
|
return telegramConfig.forum_chat_id ?? "";
|
|
29591
29839
|
}
|
|
29592
29840
|
function reconcileConfiguredGroup(accessPath, agentConfig, telegramConfig) {
|
|
29593
|
-
if (!
|
|
29841
|
+
if (!existsSync18(accessPath))
|
|
29594
29842
|
return;
|
|
29595
29843
|
const forumChatId = resolveAgentForumChatId(agentConfig, telegramConfig);
|
|
29596
29844
|
const hasRealForumChat = forumChatId !== "" && forumChatId !== "0";
|
|
@@ -29598,7 +29846,7 @@ function reconcileConfiguredGroup(accessPath, agentConfig, telegramConfig) {
|
|
|
29598
29846
|
return;
|
|
29599
29847
|
let access;
|
|
29600
29848
|
try {
|
|
29601
|
-
access = JSON.parse(
|
|
29849
|
+
access = JSON.parse(readFileSync15(accessPath, "utf-8"));
|
|
29602
29850
|
} catch {
|
|
29603
29851
|
return;
|
|
29604
29852
|
}
|
|
@@ -29608,7 +29856,7 @@ function reconcileConfiguredGroup(accessPath, agentConfig, telegramConfig) {
|
|
|
29608
29856
|
const allowFrom = Array.isArray(access.allowFrom) ? access.allowFrom : [];
|
|
29609
29857
|
groups[forumChatId] = { requireMention: false, allowFrom };
|
|
29610
29858
|
const tmp = accessPath + ".tmp";
|
|
29611
|
-
|
|
29859
|
+
writeFileSync6(tmp, JSON.stringify(access, null, 2) + `
|
|
29612
29860
|
`, { mode: 384 });
|
|
29613
29861
|
renameSync4(tmp, accessPath);
|
|
29614
29862
|
console.log(source_default.green(` registered supergroup ${forumChatId} in access.json ` + `(responds to all topics; requireMention=false)`));
|
|
@@ -30200,50 +30448,6 @@ var init_scaffold = __esm(() => {
|
|
|
30200
30448
|
];
|
|
30201
30449
|
});
|
|
30202
30450
|
|
|
30203
|
-
// src/setup/host-capabilities.ts
|
|
30204
|
-
import { existsSync as existsSync18, mkdirSync as mkdirSync11, readFileSync as readFileSync15, writeFileSync as writeFileSync6 } from "node:fs";
|
|
30205
|
-
import { dirname as dirname6 } from "node:path";
|
|
30206
|
-
function hostCapabilitiesPath() {
|
|
30207
|
-
return resolveStatePath("host-capabilities.json");
|
|
30208
|
-
}
|
|
30209
|
-
function saveVoiceCapability(caps, now = () => new Date) {
|
|
30210
|
-
const doc = {
|
|
30211
|
-
version: HOST_CAPABILITIES_VERSION,
|
|
30212
|
-
voice: {
|
|
30213
|
-
gpuPresent: caps.gpuPresent,
|
|
30214
|
-
containerToolkit: caps.containerToolkit,
|
|
30215
|
-
engine: caps.engine,
|
|
30216
|
-
detectedAt: now().toISOString()
|
|
30217
|
-
}
|
|
30218
|
-
};
|
|
30219
|
-
const path = hostCapabilitiesPath();
|
|
30220
|
-
mkdirSync11(dirname6(path), { recursive: true });
|
|
30221
|
-
writeFileSync6(path, JSON.stringify(doc, null, 2) + `
|
|
30222
|
-
`, {
|
|
30223
|
-
encoding: "utf-8",
|
|
30224
|
-
mode: 384
|
|
30225
|
-
});
|
|
30226
|
-
return doc;
|
|
30227
|
-
}
|
|
30228
|
-
function loadHostCapabilities() {
|
|
30229
|
-
const path = hostCapabilitiesPath();
|
|
30230
|
-
if (!existsSync18(path))
|
|
30231
|
-
return null;
|
|
30232
|
-
try {
|
|
30233
|
-
const parsed = JSON.parse(readFileSync15(path, "utf-8"));
|
|
30234
|
-
if (parsed && typeof parsed === "object" && "voice" in parsed && typeof parsed.voice === "object") {
|
|
30235
|
-
return parsed;
|
|
30236
|
-
}
|
|
30237
|
-
return null;
|
|
30238
|
-
} catch {
|
|
30239
|
-
return null;
|
|
30240
|
-
}
|
|
30241
|
-
}
|
|
30242
|
-
var HOST_CAPABILITIES_VERSION = 1;
|
|
30243
|
-
var init_host_capabilities = __esm(() => {
|
|
30244
|
-
init_paths();
|
|
30245
|
-
});
|
|
30246
|
-
|
|
30247
30451
|
// src/vault/grants-db-path.ts
|
|
30248
30452
|
var exports_grants_db_path = {};
|
|
30249
30453
|
__export(exports_grants_db_path, {
|
|
@@ -51186,7 +51390,7 @@ function probePendingRetainsQueue(agentName) {
|
|
|
51186
51390
|
function buildPendingRetainsProbeScript(base, now = Date.now()) {
|
|
51187
51391
|
const dir = `${base}/pending-retains`;
|
|
51188
51392
|
const cutoff = new Date(now - PENDING_RETAINS_EVICTION_WINDOW_DAYS * 86400000).toISOString().replace(/\.\d+Z$/, "Z");
|
|
51189
|
-
return `P=0; D=0; X=0; E=0; C=\${HINDSIGHT_PENDING_MAX_ENTRIES:-${PENDING_RETAINS_DEFAULT_MAX_ENTRIES}}; ` + `if [ -d '${dir}' ]; then ` + `P=$(ls -1 '${dir}' 2>/dev/null | grep -c '\\.json$' || true); ` + `D=$(ls -1 '${dir}' 2>/dev/null | grep -c '\\.json\\.dead$' || true); ` + `fi; ` + `for L in '${base}/pending-drops.json' '${dir}/.drops.json'; do ` + `if [ "$X" = 0 ] && [ -f "$L" ]; then ` + `X=$(grep -o '"count"[^0-9]*[0-9][0-9]*' "$L" 2>/dev/null ` + `| grep -o '[0-9][0-9]*$' | head -n1); ` + `[ -n "$X" ] || X=0; ` + `fi; done; ` + `if [ -f '${base}/pending-evictions.log' ]; then ` + `E=$(awk -v c='${cutoff}' '$1 >= c && /evicted=/ {n++} END {print n+0}' ` + `'${base}/pending-evictions.log' 2>/dev/null || echo 0); ` + `[ -n "$E" ] || E=0; ` + `fi; ` + `echo "P=$P D=$D X=$X E=$E C=$C"`;
|
|
51393
|
+
return `P=0; D=0; X=0; E=0; C=\${HINDSIGHT_PENDING_MAX_ENTRIES:-${PENDING_RETAINS_DEFAULT_MAX_ENTRIES}}; ` + `if [ -d '${dir}' ]; then ` + `P=$(ls -1 '${dir}' 2>/dev/null | grep -c '\\.json$' || true); ` + `D=$(ls -1 '${dir}' 2>/dev/null | grep -c '\\.json\\.dead$' || true); ` + `fi; ` + `if [ -d '${base}/pending-dead' ]; then ` + `D=$((D + $(ls -1 '${base}/pending-dead' 2>/dev/null | grep -c '\\.dead$' || true))); ` + `fi; ` + `for L in '${base}/pending-drops.json' '${dir}/.drops.json'; do ` + `if [ "$X" = 0 ] && [ -f "$L" ]; then ` + `X=$(grep -o '"count"[^0-9]*[0-9][0-9]*' "$L" 2>/dev/null ` + `| grep -o '[0-9][0-9]*$' | head -n1); ` + `[ -n "$X" ] || X=0; ` + `fi; done; ` + `if [ -f '${base}/pending-evictions.log' ]; then ` + `E=$(awk -v c='${cutoff}' '$1 >= c && /evicted=/ {n++} END {print n+0}' ` + `'${base}/pending-evictions.log' 2>/dev/null || echo 0); ` + `[ -n "$E" ] || E=0; ` + `fi; ` + `echo "P=$P D=$D X=$X E=$E C=$C"`;
|
|
51190
51394
|
}
|
|
51191
51395
|
function parsePendingRetainsProbeOutput(r) {
|
|
51192
51396
|
const unreachable = {
|
|
@@ -66572,11 +66776,24 @@ function parseTurns(text) {
|
|
|
66572
66776
|
if (!line)
|
|
66573
66777
|
continue;
|
|
66574
66778
|
try {
|
|
66575
|
-
|
|
66779
|
+
const parsed = JSON.parse(line);
|
|
66780
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed))
|
|
66781
|
+
continue;
|
|
66782
|
+
out.push(parsed);
|
|
66576
66783
|
} catch {}
|
|
66577
66784
|
}
|
|
66578
66785
|
return out;
|
|
66579
66786
|
}
|
|
66787
|
+
function ownedTurns(agent, turns) {
|
|
66788
|
+
const slug = agent.trim().toLowerCase();
|
|
66789
|
+
return turns.filter((t) => {
|
|
66790
|
+
const raw = t?.agent;
|
|
66791
|
+
if (typeof raw !== "string")
|
|
66792
|
+
return true;
|
|
66793
|
+
const owner = raw.trim().toLowerCase();
|
|
66794
|
+
return owner === "" || owner === slug;
|
|
66795
|
+
});
|
|
66796
|
+
}
|
|
66580
66797
|
function isoFromTs(ts) {
|
|
66581
66798
|
if (typeof ts !== "number" || !Number.isFinite(ts))
|
|
66582
66799
|
return null;
|
|
@@ -66585,8 +66802,8 @@ function isoFromTs(ts) {
|
|
|
66585
66802
|
function detectTurnFindings(agent, turns, opts = {}) {
|
|
66586
66803
|
const findings = [];
|
|
66587
66804
|
const silentNoopFloorTs = opts.silentNoopFloorTs ?? SILENT_NOOP_FLOOR_TS;
|
|
66588
|
-
for (const t of turns) {
|
|
66589
|
-
const tid = t.turn_id
|
|
66805
|
+
for (const t of ownedTurns(agent, turns)) {
|
|
66806
|
+
const tid = typeof t.turn_id === "string" ? t.turn_id : "?";
|
|
66590
66807
|
const st = t.status;
|
|
66591
66808
|
const tl = typeof t.tools === "number" ? t.tools : 0;
|
|
66592
66809
|
const dur = typeof t.duration_ms === "number" ? t.duration_ms : 0;
|
|
@@ -66667,7 +66884,7 @@ function extractTs(line) {
|
|
|
66667
66884
|
return m ? m[0] : null;
|
|
66668
66885
|
}
|
|
66669
66886
|
function scanAgent(agent, turnsText, gatewayText, opts = {}) {
|
|
66670
|
-
const turns = parseTurns(turnsText);
|
|
66887
|
+
const turns = ownedTurns(agent, parseTurns(turnsText));
|
|
66671
66888
|
const status_mix = {};
|
|
66672
66889
|
for (const t of turns) {
|
|
66673
66890
|
const st = t.status ?? "unknown";
|
|
@@ -66677,7 +66894,16 @@ function scanAgent(agent, turnsText, gatewayText, opts = {}) {
|
|
|
66677
66894
|
const { findings: gwFindings, gw_hits } = detectGatewayFindings(agent, gatewayText);
|
|
66678
66895
|
const findings = [...turnFindings, ...gwFindings];
|
|
66679
66896
|
const escalate = turnFindings.some((f) => f.signal === "killed-incomplete-turn" || f.signal === "hang-long-stalled" || f.signal === "silent-no-op-candidate" || f.signal === "send-failed-delivery") || gw_hits["duplicate-delivery-represent"] > 0 || gw_hits["reply-delivery-failure"] > 0;
|
|
66680
|
-
|
|
66897
|
+
const landed_unconfirmed_turns = turns.filter((t) => (t.landed_unconfirmed ?? 0) > 0).length;
|
|
66898
|
+
return {
|
|
66899
|
+
agent,
|
|
66900
|
+
turns: turns.length,
|
|
66901
|
+
status_mix,
|
|
66902
|
+
findings,
|
|
66903
|
+
gw_hits,
|
|
66904
|
+
landed_unconfirmed_turns,
|
|
66905
|
+
escalate
|
|
66906
|
+
};
|
|
66681
66907
|
}
|
|
66682
66908
|
var HANG_MS = 360000, HANG_MAXTOOLS = 2, SILENT_NOOP_FLOOR_TS = 1783900800, GATEWAY_SIGNATURES;
|
|
66683
66909
|
var init_detect = __esm(() => {
|
|
@@ -81563,7 +81789,7 @@ Cross-agent reflection plan
|
|
|
81563
81789
|
try {
|
|
81564
81790
|
const hindsightConfig = getConfig(program3);
|
|
81565
81791
|
const litellmCfg = await resolveLiteLLMForHindsight(hindsightConfig);
|
|
81566
|
-
startHindsight(ports, litellmCfg, effectiveTag, hindsightConfig.hindsight?.llm, hindsightConsumerMirrorDir(hindsightConfig));
|
|
81792
|
+
startHindsight(ports, litellmCfg, effectiveTag, hindsightConfig.hindsight?.llm, hindsightConsumerMirrorDir(hindsightConfig), undefined, { env: hindsightConfig.hindsight?.env });
|
|
81567
81793
|
if (litellmCfg) {
|
|
81568
81794
|
console.log(source_default.gray(" LiteLLM routing enabled for hindsight (--network host)."));
|
|
81569
81795
|
}
|
|
@@ -81594,7 +81820,7 @@ Cross-agent reflection plan
|
|
|
81594
81820
|
`));
|
|
81595
81821
|
{
|
|
81596
81822
|
const snippetConfig = getConfig(program3);
|
|
81597
|
-
console.log(generateHindsightComposeSnippet(snippetConfig.hindsight?.llm, hindsightConsumerMirrorDir(snippetConfig)));
|
|
81823
|
+
console.log(generateHindsightComposeSnippet(snippetConfig.hindsight?.llm, hindsightConsumerMirrorDir(snippetConfig), undefined, undefined, { env: snippetConfig.hindsight?.env }));
|
|
81598
81824
|
}
|
|
81599
81825
|
console.log();
|
|
81600
81826
|
});
|
|
@@ -99752,7 +99978,7 @@ var RING_MAX = 8;
|
|
|
99752
99978
|
var MAX_SAMPLE_AGE_MS = 3 * 60 * 60000;
|
|
99753
99979
|
var MIN_RETAIN_SAMPLES = 20;
|
|
99754
99980
|
var RETAIN_FAILURE_RATE = 0.1;
|
|
99755
|
-
var PARTS_PER_MEMORY =
|
|
99981
|
+
var PARTS_PER_MEMORY = 6;
|
|
99756
99982
|
function inParts(memories) {
|
|
99757
99983
|
return Math.round(memories * PARTS_PER_MEMORY);
|
|
99758
99984
|
}
|
|
@@ -99878,6 +100104,12 @@ function probeSpool(agentsDir = resolve61(process.env.SWITCHROOM_HOME ?? process
|
|
|
99878
100104
|
evicted++;
|
|
99879
100105
|
}
|
|
99880
100106
|
} catch {}
|
|
100107
|
+
try {
|
|
100108
|
+
for (const f of readdirSync43(resolve61(hindsightDir, "pending-dead"))) {
|
|
100109
|
+
if (f.endsWith(".dead"))
|
|
100110
|
+
dead++;
|
|
100111
|
+
}
|
|
100112
|
+
} catch {}
|
|
99881
100113
|
drops += readDropCount(hindsightDir);
|
|
99882
100114
|
}
|
|
99883
100115
|
return { pending, dead, evicted, drops, agents };
|