@askexenow/exe-os 0.9.37 → 0.9.38
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/deploy/stack-manifests/v0.9.json +55 -0
- package/dist/bin/backfill-conversations.js +2 -2
- package/dist/bin/backfill-responses.js +2 -2
- package/dist/bin/backfill-vectors.js +2 -2
- package/dist/bin/cleanup-stale-review-tasks.js +2 -2
- package/dist/bin/cli.js +554 -164
- package/dist/bin/exe-agent.js +2 -2
- package/dist/bin/exe-assign.js +2 -2
- package/dist/bin/exe-boot.js +2 -2
- package/dist/bin/exe-call.js +2 -2
- package/dist/bin/exe-dispatch.js +2 -2
- package/dist/bin/exe-doctor.js +2 -2
- package/dist/bin/exe-export-behaviors.js +2 -2
- package/dist/bin/exe-forget.js +2 -2
- package/dist/bin/exe-gateway.js +24 -3
- package/dist/bin/exe-heartbeat.js +2 -2
- package/dist/bin/exe-kill.js +2 -2
- package/dist/bin/exe-launch-agent.js +2 -2
- package/dist/bin/exe-new-employee.js +71 -4
- package/dist/bin/exe-pending-messages.js +2 -2
- package/dist/bin/exe-pending-notifications.js +2 -2
- package/dist/bin/exe-pending-reviews.js +2 -2
- package/dist/bin/exe-rename.js +1747 -199
- package/dist/bin/exe-review.js +2 -2
- package/dist/bin/exe-search.js +2 -2
- package/dist/bin/exe-session-cleanup.js +2 -2
- package/dist/bin/exe-start-codex.js +2 -2
- package/dist/bin/exe-start-opencode.js +2 -2
- package/dist/bin/exe-status.js +2 -2
- package/dist/bin/exe-team.js +2 -2
- package/dist/bin/git-sweep.js +2 -2
- package/dist/bin/graph-backfill.js +2 -2
- package/dist/bin/graph-export.js +2 -2
- package/dist/bin/install.js +68 -2
- package/dist/bin/intercom-check.js +2 -2
- package/dist/bin/scan-tasks.js +2 -2
- package/dist/bin/setup.js +2 -2
- package/dist/bin/shard-migrate.js +2 -2
- package/dist/bin/stack-update.js +308 -0
- package/dist/gateway/index.js +24 -3
- package/dist/hooks/bug-report-worker.js +2 -2
- package/dist/hooks/codex-stop-task-finalizer.js +2 -2
- package/dist/hooks/commit-complete.js +2 -2
- package/dist/hooks/error-recall.js +2 -2
- package/dist/hooks/ingest.js +2 -2
- package/dist/hooks/instructions-loaded.js +2 -2
- package/dist/hooks/notification.js +2 -2
- package/dist/hooks/post-compact.js +2 -2
- package/dist/hooks/post-tool-combined.js +2 -2
- package/dist/hooks/pre-compact.js +2 -2
- package/dist/hooks/pre-tool-use.js +2 -2
- package/dist/hooks/prompt-submit.js +2 -2
- package/dist/hooks/session-end.js +2 -2
- package/dist/hooks/session-start.js +2 -2
- package/dist/hooks/stop.js +2 -2
- package/dist/hooks/subagent-stop.js +2 -2
- package/dist/hooks/summary-worker.js +2 -2
- package/dist/index.js +24 -3
- package/dist/lib/employee-templates.js +2 -2
- package/dist/lib/exe-daemon.js +11005 -10413
- package/dist/lib/hybrid-search.js +2 -2
- package/dist/lib/schedules.js +2 -2
- package/dist/lib/store.js +2 -2
- package/dist/mcp/server.js +6865 -6341
- package/dist/runtime/index.js +2 -2
- package/dist/tui/App.js +2 -2
- package/package.json +4 -1
- package/stack.release.json +31 -0
- package/stack.release.schema.json +31 -0
package/dist/bin/cli.js
CHANGED
|
@@ -814,6 +814,7 @@ var installer_exports = {};
|
|
|
814
814
|
__export(installer_exports, {
|
|
815
815
|
cleanOldShellFunctions: () => cleanOldShellFunctions,
|
|
816
816
|
copySlashCommands: () => copySlashCommands,
|
|
817
|
+
detectMcpNameCollisions: () => detectMcpNameCollisions,
|
|
817
818
|
installStatusLine: () => installStatusLine,
|
|
818
819
|
mergeHooks: () => mergeHooks,
|
|
819
820
|
registerMcpServer: () => registerMcpServer,
|
|
@@ -899,6 +900,60 @@ name: ${skillName}
|
|
|
899
900
|
await writeFile3(destPath, content);
|
|
900
901
|
return true;
|
|
901
902
|
}
|
|
903
|
+
function readJsonFile(filePath) {
|
|
904
|
+
try {
|
|
905
|
+
return JSON.parse(readFileSync5(filePath, "utf-8"));
|
|
906
|
+
} catch {
|
|
907
|
+
return null;
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
function findAncestorMcpJsons(startDir, homeDir) {
|
|
911
|
+
const files = [];
|
|
912
|
+
let dir = path6.resolve(startDir);
|
|
913
|
+
const root = path6.parse(dir).root;
|
|
914
|
+
const stop = path6.resolve(homeDir);
|
|
915
|
+
while (dir !== root) {
|
|
916
|
+
const candidate = path6.join(dir, ".mcp.json");
|
|
917
|
+
if (existsSync7(candidate)) files.push(candidate);
|
|
918
|
+
if (dir === stop) break;
|
|
919
|
+
dir = path6.dirname(dir);
|
|
920
|
+
}
|
|
921
|
+
return files;
|
|
922
|
+
}
|
|
923
|
+
function pathApplies(projectPath, cwd2) {
|
|
924
|
+
const project = path6.resolve(projectPath);
|
|
925
|
+
const current = path6.resolve(cwd2);
|
|
926
|
+
return current === project || current.startsWith(project + path6.sep);
|
|
927
|
+
}
|
|
928
|
+
function detectMcpNameCollisions(homeDir = os5.homedir(), cwd2 = process.cwd()) {
|
|
929
|
+
const claudeJsonPath = path6.join(homeDir, ".claude.json");
|
|
930
|
+
if (!existsSync7(claudeJsonPath)) return [];
|
|
931
|
+
const claudeJson = readJsonFile(claudeJsonPath);
|
|
932
|
+
if (!claudeJson?.projects) return [];
|
|
933
|
+
const collisions = [];
|
|
934
|
+
const mcpJsons = findAncestorMcpJsons(cwd2, homeDir);
|
|
935
|
+
if (mcpJsons.length === 0) return [];
|
|
936
|
+
for (const [projectPath, projectConfig] of Object.entries(claudeJson.projects)) {
|
|
937
|
+
if (!pathApplies(projectPath, cwd2)) continue;
|
|
938
|
+
const projectServerNames = new Set(Object.keys(projectConfig.mcpServers ?? {}));
|
|
939
|
+
if (projectServerNames.size === 0) continue;
|
|
940
|
+
const enabled = new Set(projectConfig.enabledMcpjsonServers ?? []);
|
|
941
|
+
for (const mcpJsonPath of mcpJsons) {
|
|
942
|
+
const mcpJson = readJsonFile(mcpJsonPath);
|
|
943
|
+
const mcpServerNames = Object.keys(mcpJson?.mcpServers ?? {});
|
|
944
|
+
for (const serverName of mcpServerNames) {
|
|
945
|
+
if (!projectServerNames.has(serverName)) continue;
|
|
946
|
+
collisions.push({
|
|
947
|
+
mcpJsonPath,
|
|
948
|
+
projectPath,
|
|
949
|
+
serverName,
|
|
950
|
+
disabledInMcpJson: !enabled.has(serverName)
|
|
951
|
+
});
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
return collisions;
|
|
956
|
+
}
|
|
902
957
|
async function registerMcpServer(packageRoot, homeDir = os5.homedir()) {
|
|
903
958
|
const claudeJsonPath = path6.join(homeDir, ".claude.json");
|
|
904
959
|
let claudeJson = {};
|
|
@@ -927,12 +982,26 @@ async function registerMcpServer(packageRoot, homeDir = os5.homedir()) {
|
|
|
927
982
|
if (osMatches) {
|
|
928
983
|
await cleanSettingsJsonMcp(path6.join(homeDir, ".claude", "settings.json"));
|
|
929
984
|
await migratePermissionsToExeOs(path6.join(homeDir, ".claude", "settings.json"));
|
|
985
|
+
const collisions2 = detectMcpNameCollisions(homeDir, packageRoot).filter((c) => c.serverName === MCP_PRIMARY_KEY || c.serverName === MCP_LEGACY_KEY);
|
|
986
|
+
for (const c of collisions2) {
|
|
987
|
+
process.stderr.write(
|
|
988
|
+
`exe-os: WARNING Claude Code MCP name collision: ${c.serverName} exists in ${c.mcpJsonPath} and ~/.claude.json project ${c.projectPath}. Remove or rename the .mcp.json entry if tools do not surface.
|
|
989
|
+
`
|
|
990
|
+
);
|
|
991
|
+
}
|
|
930
992
|
return false;
|
|
931
993
|
}
|
|
932
994
|
claudeJson.mcpServers[MCP_PRIMARY_KEY] = newEntry;
|
|
933
995
|
await writeFile3(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
|
|
934
996
|
await cleanSettingsJsonMcp(path6.join(homeDir, ".claude", "settings.json"));
|
|
935
997
|
await migratePermissionsToExeOs(path6.join(homeDir, ".claude", "settings.json"));
|
|
998
|
+
const collisions = detectMcpNameCollisions(homeDir, packageRoot).filter((c) => c.serverName === MCP_PRIMARY_KEY || c.serverName === MCP_LEGACY_KEY);
|
|
999
|
+
for (const c of collisions) {
|
|
1000
|
+
process.stderr.write(
|
|
1001
|
+
`exe-os: WARNING Claude Code MCP name collision: ${c.serverName} exists in ${c.mcpJsonPath} and ~/.claude.json project ${c.projectPath}. Remove or rename the .mcp.json entry if tools do not surface.
|
|
1002
|
+
`
|
|
1003
|
+
);
|
|
1004
|
+
}
|
|
936
1005
|
return true;
|
|
937
1006
|
}
|
|
938
1007
|
async function cleanSettingsJsonMcp(settingsPath) {
|
|
@@ -1234,8 +1303,6 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
|
|
|
1234
1303
|
"purge_document",
|
|
1235
1304
|
"rerank_documents",
|
|
1236
1305
|
"set_document_importance",
|
|
1237
|
-
"create_wiki_page",
|
|
1238
|
-
"update_wiki_page",
|
|
1239
1306
|
"get_wiki_page",
|
|
1240
1307
|
"list_wiki_pages",
|
|
1241
1308
|
// System
|
|
@@ -1773,8 +1840,8 @@ function deriveMachineKey() {
|
|
|
1773
1840
|
}
|
|
1774
1841
|
function readMachineId() {
|
|
1775
1842
|
try {
|
|
1776
|
-
const { readFileSync:
|
|
1777
|
-
return
|
|
1843
|
+
const { readFileSync: readFileSync30 } = __require("fs");
|
|
1844
|
+
return readFileSync30("/etc/machine-id", "utf-8").trim();
|
|
1778
1845
|
} catch {
|
|
1779
1846
|
return "";
|
|
1780
1847
|
}
|
|
@@ -7494,7 +7561,7 @@ var init_platform_procedures = __esm({
|
|
|
7494
7561
|
title: "MCP tools \u2014 wiki, documents, and content",
|
|
7495
7562
|
domain: "tool-use",
|
|
7496
7563
|
priority: "p1",
|
|
7497
|
-
content: "
|
|
7564
|
+
content: "wiki: read/list wiki pages only. Direct wiki write tools are removed; wiki updates flow through raw-data ingestion/projection into the curated wiki store. Legacy aliases: list_wiki_pages/get_wiki_page. crm: read/list/get CRM records from exe-db. raw_data: read capped raw landing-pad events from exe-db with payload opt-in. ingest_document: import a file (PDF, MD, etc.) into memory as chunks. list_documents: browse ingested documents by workspace. purge_document: remove a document and its memory chunks. set_document_importance: adjust chunk importance scores. rerank_documents: re-score document relevance for a query."
|
|
7498
7565
|
},
|
|
7499
7566
|
{
|
|
7500
7567
|
title: "MCP tools \u2014 system, operations, and admin",
|
|
@@ -7512,7 +7579,7 @@ var init_platform_procedures = __esm({
|
|
|
7512
7579
|
title: "MCP tools \u2014 advanced (triggers, skills, orchestration)",
|
|
7513
7580
|
domain: "tool-use",
|
|
7514
7581
|
priority: "p1",
|
|
7515
|
-
content: "create_trigger: set up a scheduled recurring agent job (cron). list_triggers: view active triggers. load_skill: load a slash-command skill dynamically. apply_starter_pack: import a pre-built behavior + identity pack for a role. export_orchestration: export full org state (tasks, behaviors, identities) as portable JSON. import_orchestration: import org state into a new instance. deploy_client: deploy a customer client instance. query_company_brain: unified RAG query across all company knowledge. create_reminder: set a text reminder (shown in boot brief). list_reminders: view pending reminders. complete_reminder: mark a reminder done. global_procedure: manage
|
|
7582
|
+
content: "create_trigger: set up a scheduled recurring agent job (cron). list_triggers: view active triggers. load_skill: load a slash-command skill dynamically. apply_starter_pack: import a pre-built behavior + identity pack for a role. export_orchestration: export full org state (tasks, behaviors, identities) as portable JSON. import_orchestration: import org state into a new instance. deploy_client: deploy a customer client instance. query_company_brain: unified RAG query across all company knowledge. create_reminder: set a text reminder (shown in boot brief). list_reminders: view pending reminders. complete_reminder: mark a reminder done. global_procedure: manage customer-owned company procedures (Layer 0; actions: store, list, deactivate). Legacy aliases: store_global_procedure, list_global_procedures, deactivate_global_procedure."
|
|
7516
7583
|
}
|
|
7517
7584
|
];
|
|
7518
7585
|
PLATFORM_PROCEDURE_TITLES = new Set(
|
|
@@ -8994,9 +9061,9 @@ Unclassified: ${unclassified}
|
|
|
8994
9061
|
}
|
|
8995
9062
|
async function exportBatches(options) {
|
|
8996
9063
|
const fs8 = await import("fs");
|
|
8997
|
-
const
|
|
9064
|
+
const path49 = await import("path");
|
|
8998
9065
|
const client = getClient();
|
|
8999
|
-
const outDir =
|
|
9066
|
+
const outDir = path49.join(process.cwd(), "exe/output/classifications/input");
|
|
9000
9067
|
fs8.mkdirSync(outDir, { recursive: true });
|
|
9001
9068
|
const countResult = await client.execute({
|
|
9002
9069
|
sql: "SELECT COUNT(*) as cnt FROM memories WHERE intent IS NULL AND outcome IS NULL AND domain IS NULL",
|
|
@@ -9020,7 +9087,7 @@ async function exportBatches(options) {
|
|
|
9020
9087
|
const text = String(row.text || "").replace(/\n/g, " ");
|
|
9021
9088
|
return JSON.stringify({ id: row.id, text });
|
|
9022
9089
|
});
|
|
9023
|
-
const batchFile =
|
|
9090
|
+
const batchFile = path49.join(outDir, `batch-${String(batchNum).padStart(4, "0")}.jsonl`);
|
|
9024
9091
|
fs8.writeFileSync(batchFile, lines.join("\n") + "\n");
|
|
9025
9092
|
exported += batch.rows.length;
|
|
9026
9093
|
offset += options.batchSize;
|
|
@@ -9036,7 +9103,7 @@ async function exportBatches(options) {
|
|
|
9036
9103
|
}
|
|
9037
9104
|
async function importClassifications(importDir) {
|
|
9038
9105
|
const fs8 = await import("fs");
|
|
9039
|
-
const
|
|
9106
|
+
const path49 = await import("path");
|
|
9040
9107
|
const client = getClient();
|
|
9041
9108
|
const files = fs8.readdirSync(importDir).filter((f) => f.endsWith(".jsonl")).sort();
|
|
9042
9109
|
process.stderr.write(`[backfill-metadata] Found ${files.length} JSONL files to import from ${importDir}
|
|
@@ -9044,7 +9111,7 @@ async function importClassifications(importDir) {
|
|
|
9044
9111
|
let imported = 0;
|
|
9045
9112
|
let invalid = 0;
|
|
9046
9113
|
for (const file of files) {
|
|
9047
|
-
const lines = fs8.readFileSync(
|
|
9114
|
+
const lines = fs8.readFileSync(path49.join(importDir, file), "utf-8").split("\n").filter(Boolean);
|
|
9048
9115
|
for (const line of lines) {
|
|
9049
9116
|
try {
|
|
9050
9117
|
const rec = JSON.parse(line);
|
|
@@ -11677,10 +11744,10 @@ async function disposeEmbedder() {
|
|
|
11677
11744
|
async function embedDirect(text) {
|
|
11678
11745
|
const llamaCpp = await import("node-llama-cpp");
|
|
11679
11746
|
const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
11680
|
-
const { existsSync:
|
|
11681
|
-
const
|
|
11682
|
-
const modelPath =
|
|
11683
|
-
if (!
|
|
11747
|
+
const { existsSync: existsSync35 } = await import("fs");
|
|
11748
|
+
const path49 = await import("path");
|
|
11749
|
+
const modelPath = path49.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
|
|
11750
|
+
if (!existsSync35(modelPath)) {
|
|
11684
11751
|
throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
|
|
11685
11752
|
}
|
|
11686
11753
|
const llama = await llamaCpp.getLlama();
|
|
@@ -14583,6 +14650,8 @@ async function main2() {
|
|
|
14583
14650
|
process.exit(1);
|
|
14584
14651
|
}
|
|
14585
14652
|
const [oldName, newName] = args2;
|
|
14653
|
+
const { initStore: initStore2 } = await Promise.resolve().then(() => (init_store(), store_exports));
|
|
14654
|
+
await initStore2({ lightweight: true });
|
|
14586
14655
|
const result = await renameEmployee(oldName, newName);
|
|
14587
14656
|
if (!result.success) {
|
|
14588
14657
|
console.error(`Error: ${result.error}`);
|
|
@@ -16465,6 +16534,309 @@ var init_update = __esm({
|
|
|
16465
16534
|
}
|
|
16466
16535
|
});
|
|
16467
16536
|
|
|
16537
|
+
// src/lib/stack-update.ts
|
|
16538
|
+
import { execFileSync as execFileSync3 } from "child_process";
|
|
16539
|
+
import { existsSync as existsSync30, mkdirSync as mkdirSync19, readFileSync as readFileSync25, renameSync as renameSync6, writeFileSync as writeFileSync20 } from "fs";
|
|
16540
|
+
import http from "http";
|
|
16541
|
+
import https from "https";
|
|
16542
|
+
import path37 from "path";
|
|
16543
|
+
function parseStackManifest(raw) {
|
|
16544
|
+
const parsed = JSON.parse(raw);
|
|
16545
|
+
if (parsed.schemaVersion !== 1) throw new Error("Unsupported stack manifest schemaVersion");
|
|
16546
|
+
if (!parsed.latest || !parsed.stacks || typeof parsed.stacks !== "object") {
|
|
16547
|
+
throw new Error("Invalid stack manifest: latest and stacks are required");
|
|
16548
|
+
}
|
|
16549
|
+
for (const [version, release] of Object.entries(parsed.stacks)) {
|
|
16550
|
+
if (!release.version) release.version = version;
|
|
16551
|
+
if (!release.services || typeof release.services !== "object") {
|
|
16552
|
+
throw new Error(`Invalid stack manifest: release ${version} has no services`);
|
|
16553
|
+
}
|
|
16554
|
+
for (const [serviceName, service] of Object.entries(release.services)) {
|
|
16555
|
+
if (!service.image || !service.env) {
|
|
16556
|
+
throw new Error(`Invalid stack manifest: ${version}.${serviceName} requires image and env`);
|
|
16557
|
+
}
|
|
16558
|
+
}
|
|
16559
|
+
}
|
|
16560
|
+
return parsed;
|
|
16561
|
+
}
|
|
16562
|
+
async function loadStackManifest(ref, fetchText = defaultFetchText) {
|
|
16563
|
+
if (/^https?:\/\//.test(ref)) return parseStackManifest(await fetchText(ref));
|
|
16564
|
+
return parseStackManifest(readFileSync25(ref, "utf8"));
|
|
16565
|
+
}
|
|
16566
|
+
function parseEnv(raw) {
|
|
16567
|
+
const env = /* @__PURE__ */ new Map();
|
|
16568
|
+
for (const line of raw.split(/\r?\n/)) {
|
|
16569
|
+
const trimmed = line.trim();
|
|
16570
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
16571
|
+
const idx = line.indexOf("=");
|
|
16572
|
+
if (idx <= 0) continue;
|
|
16573
|
+
env.set(line.slice(0, idx).trim(), line.slice(idx + 1));
|
|
16574
|
+
}
|
|
16575
|
+
return env;
|
|
16576
|
+
}
|
|
16577
|
+
function patchEnv(raw, updates) {
|
|
16578
|
+
const seen = /* @__PURE__ */ new Set();
|
|
16579
|
+
const lines = raw.replace(/\n$/, "").split(/\r?\n/);
|
|
16580
|
+
const patched = lines.map((line) => {
|
|
16581
|
+
const idx = line.indexOf("=");
|
|
16582
|
+
if (idx <= 0 || line.trim().startsWith("#")) return line;
|
|
16583
|
+
const key = line.slice(0, idx).trim();
|
|
16584
|
+
if (!(key in updates)) return line;
|
|
16585
|
+
seen.add(key);
|
|
16586
|
+
return `${key}=${updates[key]}`;
|
|
16587
|
+
});
|
|
16588
|
+
for (const [key, value] of Object.entries(updates)) {
|
|
16589
|
+
if (!seen.has(key)) patched.push(`${key}=${value}`);
|
|
16590
|
+
}
|
|
16591
|
+
return patched.join("\n").replace(/\n*$/, "\n");
|
|
16592
|
+
}
|
|
16593
|
+
function createStackUpdatePlan(manifest, envRaw, targetVersion) {
|
|
16594
|
+
const version = targetVersion ?? manifest.latest;
|
|
16595
|
+
const release = manifest.stacks[version];
|
|
16596
|
+
if (!release) throw new Error(`Stack version ${version} not found in manifest`);
|
|
16597
|
+
const env = parseEnv(envRaw);
|
|
16598
|
+
const changes = [];
|
|
16599
|
+
for (const [serviceName, service] of Object.entries(release.services)) {
|
|
16600
|
+
const before = env.get(service.env);
|
|
16601
|
+
if (before !== service.image) {
|
|
16602
|
+
changes.push({ key: service.env, before, after: service.image, service: serviceName });
|
|
16603
|
+
}
|
|
16604
|
+
}
|
|
16605
|
+
return {
|
|
16606
|
+
manifest,
|
|
16607
|
+
release,
|
|
16608
|
+
targetVersion: version,
|
|
16609
|
+
changes,
|
|
16610
|
+
breakingChanges: release.breakingChanges ?? []
|
|
16611
|
+
};
|
|
16612
|
+
}
|
|
16613
|
+
function assertBreakingChangesAllowed(plan, allowedIds) {
|
|
16614
|
+
const required = plan.breakingChanges.filter((c) => c.requiresConfirmation !== false);
|
|
16615
|
+
const missing = required.filter((c) => !allowedIds.includes(c.id));
|
|
16616
|
+
if (missing.length > 0) {
|
|
16617
|
+
const details = missing.map((c) => `- ${c.id}: ${c.title}
|
|
16618
|
+
${c.description}
|
|
16619
|
+
Action: ${c.requiredAction ?? "Review release notes."}`).join("\n");
|
|
16620
|
+
throw new Error(
|
|
16621
|
+
`Stack ${plan.targetVersion} has breaking changes that require confirmation:
|
|
16622
|
+
${details}
|
|
16623
|
+
Re-run with --allow-breaking ${missing.map((c) => c.id).join(",")}`
|
|
16624
|
+
);
|
|
16625
|
+
}
|
|
16626
|
+
}
|
|
16627
|
+
async function runStackUpdate(options) {
|
|
16628
|
+
const exec2 = options.exec ?? defaultExec;
|
|
16629
|
+
const now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
16630
|
+
const manifest = await loadStackManifest(options.manifestRef, options.fetchText);
|
|
16631
|
+
const envRaw = readFileSync25(options.envFile, "utf8");
|
|
16632
|
+
const plan = createStackUpdatePlan(manifest, envRaw, options.targetVersion);
|
|
16633
|
+
assertBreakingChangesAllowed(plan, options.allowedBreakingChangeIds ?? []);
|
|
16634
|
+
const lockFile = options.lockFile ?? path37.join(path37.dirname(options.envFile), ".exe-stack-lock.json");
|
|
16635
|
+
if (options.dryRun || plan.changes.length === 0) {
|
|
16636
|
+
return { status: "planned", targetVersion: plan.targetVersion, changes: plan.changes, lockFile };
|
|
16637
|
+
}
|
|
16638
|
+
const backupDir = path37.join(path37.dirname(options.envFile), ".exe-stack-backups");
|
|
16639
|
+
mkdirSync19(backupDir, { recursive: true });
|
|
16640
|
+
const stamp = now().toISOString().replace(/[:.]/g, "-");
|
|
16641
|
+
const backupEnvFile = path37.join(backupDir, `env-${stamp}.bak`);
|
|
16642
|
+
writeFileSync20(backupEnvFile, envRaw, { mode: 384 });
|
|
16643
|
+
const updates = Object.fromEntries(plan.changes.map((c) => [c.key, c.after]));
|
|
16644
|
+
const patched = patchEnv(envRaw, updates);
|
|
16645
|
+
const tmp = `${options.envFile}.tmp-${process.pid}`;
|
|
16646
|
+
writeFileSync20(tmp, patched, { mode: 384 });
|
|
16647
|
+
renameSync6(tmp, options.envFile);
|
|
16648
|
+
const composeArgs = ["compose", "--file", options.composeFile, "--env-file", options.envFile];
|
|
16649
|
+
try {
|
|
16650
|
+
exec2("docker", [...composeArgs, "pull"]);
|
|
16651
|
+
exec2("docker", [...composeArgs, "up", "-d"]);
|
|
16652
|
+
await verifyReleaseHealth(plan.release, options.healthRetries ?? 12, options.healthDelayMs ?? 5e3);
|
|
16653
|
+
writeFileSync20(lockFile, JSON.stringify({ stackVersion: plan.targetVersion, updatedAt: now().toISOString(), services: plan.release.services }, null, 2) + "\n");
|
|
16654
|
+
return { status: "updated", targetVersion: plan.targetVersion, changes: plan.changes, backupEnvFile, lockFile };
|
|
16655
|
+
} catch (err) {
|
|
16656
|
+
writeFileSync20(options.envFile, envRaw, { mode: 384 });
|
|
16657
|
+
try {
|
|
16658
|
+
exec2("docker", [...composeArgs, "up", "-d"]);
|
|
16659
|
+
} catch {
|
|
16660
|
+
}
|
|
16661
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
16662
|
+
throw new Error(`Stack update failed and rollback was attempted: ${reason}`);
|
|
16663
|
+
}
|
|
16664
|
+
}
|
|
16665
|
+
async function verifyReleaseHealth(release, retries, delayMs) {
|
|
16666
|
+
for (const [serviceName, service] of Object.entries(release.services)) {
|
|
16667
|
+
if (!service.healthUrl) continue;
|
|
16668
|
+
await waitForHttpOk(service.healthUrl, retries, delayMs, serviceName);
|
|
16669
|
+
}
|
|
16670
|
+
}
|
|
16671
|
+
async function waitForHttpOk(url, retries, delayMs, label) {
|
|
16672
|
+
let last = "";
|
|
16673
|
+
for (let i = 0; i < retries; i++) {
|
|
16674
|
+
try {
|
|
16675
|
+
const status = await httpStatus(url);
|
|
16676
|
+
if (status >= 200 && status < 300) return;
|
|
16677
|
+
last = `HTTP ${status}`;
|
|
16678
|
+
} catch (err) {
|
|
16679
|
+
last = err instanceof Error ? err.message : String(err);
|
|
16680
|
+
}
|
|
16681
|
+
if (i < retries - 1) await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
16682
|
+
}
|
|
16683
|
+
throw new Error(`Health check failed for ${label} (${url}): ${last}`);
|
|
16684
|
+
}
|
|
16685
|
+
function httpStatus(urlString) {
|
|
16686
|
+
return new Promise((resolve, reject) => {
|
|
16687
|
+
const url = new URL(urlString);
|
|
16688
|
+
const mod = url.protocol === "https:" ? https : http;
|
|
16689
|
+
const req = mod.request(url, { method: "GET", timeout: 5e3 }, (res) => {
|
|
16690
|
+
res.resume();
|
|
16691
|
+
resolve(res.statusCode ?? 0);
|
|
16692
|
+
});
|
|
16693
|
+
req.on("timeout", () => req.destroy(new Error("timeout")));
|
|
16694
|
+
req.on("error", reject);
|
|
16695
|
+
req.end();
|
|
16696
|
+
});
|
|
16697
|
+
}
|
|
16698
|
+
function defaultExec(cmd, args2, opts) {
|
|
16699
|
+
execFileSync3(cmd, args2, { stdio: "inherit", cwd: opts?.cwd });
|
|
16700
|
+
}
|
|
16701
|
+
async function defaultFetchText(ref) {
|
|
16702
|
+
const res = await fetch(ref);
|
|
16703
|
+
if (!res.ok) throw new Error(`Failed to fetch ${ref}: HTTP ${res.status}`);
|
|
16704
|
+
return res.text();
|
|
16705
|
+
}
|
|
16706
|
+
function defaultStackPaths() {
|
|
16707
|
+
const cwdCompose = path37.resolve("docker-compose.yml");
|
|
16708
|
+
const cwdEnv = path37.resolve(".env");
|
|
16709
|
+
return {
|
|
16710
|
+
composeFile: process.env.EXE_STACK_COMPOSE_FILE || (existsSync30(cwdCompose) ? cwdCompose : "/opt/exe-stack/docker-compose.yml"),
|
|
16711
|
+
envFile: process.env.EXE_STACK_ENV_FILE || (existsSync30(cwdEnv) ? cwdEnv : "/opt/exe-stack/.env"),
|
|
16712
|
+
manifestRef: process.env.EXE_STACK_MANIFEST || "https://updates.askexe.com/stack-manifest.json"
|
|
16713
|
+
};
|
|
16714
|
+
}
|
|
16715
|
+
var init_stack_update = __esm({
|
|
16716
|
+
"src/lib/stack-update.ts"() {
|
|
16717
|
+
"use strict";
|
|
16718
|
+
}
|
|
16719
|
+
});
|
|
16720
|
+
|
|
16721
|
+
// src/bin/stack-update.ts
|
|
16722
|
+
var stack_update_exports = {};
|
|
16723
|
+
__export(stack_update_exports, {
|
|
16724
|
+
runStackUpdateCli: () => main3
|
|
16725
|
+
});
|
|
16726
|
+
import { readFileSync as readFileSync26 } from "fs";
|
|
16727
|
+
function parseArgs4(args2) {
|
|
16728
|
+
const defaults = defaultStackPaths();
|
|
16729
|
+
const opts = {
|
|
16730
|
+
manifestRef: defaults.manifestRef,
|
|
16731
|
+
composeFile: defaults.composeFile,
|
|
16732
|
+
envFile: defaults.envFile,
|
|
16733
|
+
dryRun: false,
|
|
16734
|
+
check: false,
|
|
16735
|
+
yes: false,
|
|
16736
|
+
allowedBreakingChangeIds: []
|
|
16737
|
+
};
|
|
16738
|
+
for (let i = 0; i < args2.length; i++) {
|
|
16739
|
+
const arg = args2[i];
|
|
16740
|
+
const next = () => args2[++i] ?? "";
|
|
16741
|
+
if (arg === "--manifest") opts.manifestRef = next();
|
|
16742
|
+
else if (arg.startsWith("--manifest=")) opts.manifestRef = arg.split("=").slice(1).join("=");
|
|
16743
|
+
else if (arg === "--target") opts.targetVersion = next();
|
|
16744
|
+
else if (arg.startsWith("--target=")) opts.targetVersion = arg.split("=")[1];
|
|
16745
|
+
else if (arg === "--compose-file") opts.composeFile = next();
|
|
16746
|
+
else if (arg.startsWith("--compose-file=")) opts.composeFile = arg.split("=").slice(1).join("=");
|
|
16747
|
+
else if (arg === "--env-file") opts.envFile = next();
|
|
16748
|
+
else if (arg.startsWith("--env-file=")) opts.envFile = arg.split("=").slice(1).join("=");
|
|
16749
|
+
else if (arg === "--lock-file") opts.lockFile = next();
|
|
16750
|
+
else if (arg === "--dry-run") opts.dryRun = true;
|
|
16751
|
+
else if (arg === "--check") opts.check = true;
|
|
16752
|
+
else if (arg === "--yes" || arg === "-y") opts.yes = true;
|
|
16753
|
+
else if (arg === "--allow-breaking") opts.allowedBreakingChangeIds.push(...next().split(",").map((s) => s.trim()).filter(Boolean));
|
|
16754
|
+
else if (arg.startsWith("--allow-breaking=")) opts.allowedBreakingChangeIds.push(...arg.split("=")[1].split(",").map((s) => s.trim()).filter(Boolean));
|
|
16755
|
+
else if (arg === "--help" || arg === "-h") {
|
|
16756
|
+
printHelp();
|
|
16757
|
+
process.exit(0);
|
|
16758
|
+
} else {
|
|
16759
|
+
throw new Error(`Unknown option: ${arg}`);
|
|
16760
|
+
}
|
|
16761
|
+
}
|
|
16762
|
+
return opts;
|
|
16763
|
+
}
|
|
16764
|
+
function printHelp() {
|
|
16765
|
+
console.log(`exe-os stack-update \u2014 update a self-hosted Exe OS stack from a pinned manifest
|
|
16766
|
+
|
|
16767
|
+
Usage:
|
|
16768
|
+
exe-os stack-update [--manifest <path-or-url>] [--target <version>] [--yes]
|
|
16769
|
+
|
|
16770
|
+
Options:
|
|
16771
|
+
--manifest <ref> Stack manifest JSON path or URL (default: updates.askexe.com)
|
|
16772
|
+
--target <version> Stack version to install (default: manifest.latest)
|
|
16773
|
+
--compose-file <path> docker-compose.yml path (default: ./docker-compose.yml or /opt/exe-stack/docker-compose.yml)
|
|
16774
|
+
--env-file <path> .env path (default: ./.env or /opt/exe-stack/.env)
|
|
16775
|
+
--lock-file <path> Lock file path (default: beside .env)
|
|
16776
|
+
--check Print available changes only
|
|
16777
|
+
--dry-run Plan only; do not run Docker
|
|
16778
|
+
--allow-breaking <ids> Confirm breaking changes, comma-separated
|
|
16779
|
+
-y, --yes Non-interactive confirmation
|
|
16780
|
+
`);
|
|
16781
|
+
}
|
|
16782
|
+
function printChanges(changes) {
|
|
16783
|
+
if (changes.length === 0) {
|
|
16784
|
+
console.log("\u2705 Stack already matches target manifest.");
|
|
16785
|
+
return;
|
|
16786
|
+
}
|
|
16787
|
+
console.log("Planned image tag changes:");
|
|
16788
|
+
for (const c of changes) {
|
|
16789
|
+
console.log(` - ${c.service}: ${c.key}`);
|
|
16790
|
+
console.log(` ${c.before ?? "<unset>"} \u2192 ${c.after}`);
|
|
16791
|
+
}
|
|
16792
|
+
}
|
|
16793
|
+
function printBreaking(changes) {
|
|
16794
|
+
if (changes.length === 0) return;
|
|
16795
|
+
console.log("\nBreaking-change notices:");
|
|
16796
|
+
for (const c of changes) {
|
|
16797
|
+
console.log(` - ${c.id}: ${c.title}`);
|
|
16798
|
+
console.log(` ${c.description}`);
|
|
16799
|
+
if (c.requiredAction) console.log(` Action: ${c.requiredAction}`);
|
|
16800
|
+
if (c.expectedDowntimeMinutes) console.log(` Expected downtime: ${c.expectedDowntimeMinutes} minutes`);
|
|
16801
|
+
}
|
|
16802
|
+
}
|
|
16803
|
+
async function main3() {
|
|
16804
|
+
const opts = parseArgs4(process.argv.slice(2));
|
|
16805
|
+
const manifest = await loadStackManifest(opts.manifestRef);
|
|
16806
|
+
const envRaw = readFileSync26(opts.envFile, "utf8");
|
|
16807
|
+
const plan = createStackUpdatePlan(manifest, envRaw, opts.targetVersion);
|
|
16808
|
+
console.log(`Exe OS stack target: ${plan.targetVersion}`);
|
|
16809
|
+
console.log(`Manifest: ${opts.manifestRef}`);
|
|
16810
|
+
console.log(`Compose: ${opts.composeFile}`);
|
|
16811
|
+
console.log(`Env: ${opts.envFile}
|
|
16812
|
+
`);
|
|
16813
|
+
printChanges(plan.changes);
|
|
16814
|
+
printBreaking(plan.breakingChanges);
|
|
16815
|
+
if (opts.check || opts.dryRun) return;
|
|
16816
|
+
if (!opts.yes) {
|
|
16817
|
+
console.error("\nRefusing to update without --yes. Re-run with --yes after reviewing the plan.");
|
|
16818
|
+
process.exit(2);
|
|
16819
|
+
}
|
|
16820
|
+
const result = await runStackUpdate(opts);
|
|
16821
|
+
console.log(`
|
|
16822
|
+
\u2705 Stack ${result.status}: ${result.targetVersion}`);
|
|
16823
|
+
if (result.backupEnvFile) console.log(`Backup env: ${result.backupEnvFile}`);
|
|
16824
|
+
console.log(`Lock file: ${result.lockFile}`);
|
|
16825
|
+
}
|
|
16826
|
+
var init_stack_update2 = __esm({
|
|
16827
|
+
"src/bin/stack-update.ts"() {
|
|
16828
|
+
"use strict";
|
|
16829
|
+
init_is_main();
|
|
16830
|
+
init_stack_update();
|
|
16831
|
+
if (isMainModule(import.meta.url)) {
|
|
16832
|
+
main3().catch((err) => {
|
|
16833
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
16834
|
+
process.exit(1);
|
|
16835
|
+
});
|
|
16836
|
+
}
|
|
16837
|
+
}
|
|
16838
|
+
});
|
|
16839
|
+
|
|
16468
16840
|
// node_modules/es-toolkit/dist/function/debounce.mjs
|
|
16469
16841
|
function debounce(func, debounceMs, { signal, edges } = {}) {
|
|
16470
16842
|
let pendingThis = void 0;
|
|
@@ -18266,7 +18638,7 @@ var init_src = __esm({
|
|
|
18266
18638
|
|
|
18267
18639
|
// node_modules/terminal-size/index.js
|
|
18268
18640
|
import process2 from "process";
|
|
18269
|
-
import { execFileSync as
|
|
18641
|
+
import { execFileSync as execFileSync4 } from "child_process";
|
|
18270
18642
|
import fs from "fs";
|
|
18271
18643
|
import tty from "tty";
|
|
18272
18644
|
function terminalSize() {
|
|
@@ -18298,7 +18670,7 @@ var init_terminal_size = __esm({
|
|
|
18298
18670
|
"use strict";
|
|
18299
18671
|
defaultColumns = 80;
|
|
18300
18672
|
defaultRows = 24;
|
|
18301
|
-
exec = (command, arguments_, { shell, env } = {}) =>
|
|
18673
|
+
exec = (command, arguments_, { shell, env } = {}) => execFileSync4(command, arguments_, {
|
|
18302
18674
|
encoding: "utf8",
|
|
18303
18675
|
stdio: ["ignore", "pipe", "ignore"],
|
|
18304
18676
|
timeout: 500,
|
|
@@ -20823,8 +21195,8 @@ var init_ErrorOverview = __esm({
|
|
|
20823
21195
|
"use strict";
|
|
20824
21196
|
init_Box();
|
|
20825
21197
|
init_Text();
|
|
20826
|
-
cleanupPath = (
|
|
20827
|
-
return
|
|
21198
|
+
cleanupPath = (path49) => {
|
|
21199
|
+
return path49?.replace(`file://${cwd()}/`, "");
|
|
20828
21200
|
};
|
|
20829
21201
|
stackUtils = new StackUtils({
|
|
20830
21202
|
cwd: cwd(),
|
|
@@ -23232,11 +23604,11 @@ function Footer() {
|
|
|
23232
23604
|
} catch {
|
|
23233
23605
|
}
|
|
23234
23606
|
try {
|
|
23235
|
-
const { existsSync:
|
|
23607
|
+
const { existsSync: existsSync35 } = await import("fs");
|
|
23236
23608
|
const { join } = await import("path");
|
|
23237
23609
|
const home = process.env.HOME ?? "";
|
|
23238
23610
|
const pidPath = join(home, ".exe-os", "exed.pid");
|
|
23239
|
-
setDaemon(
|
|
23611
|
+
setDaemon(existsSync35(pidPath) ? "running" : "stopped");
|
|
23240
23612
|
} catch {
|
|
23241
23613
|
setDaemon("unknown");
|
|
23242
23614
|
}
|
|
@@ -25287,10 +25659,10 @@ var init_hooks = __esm({
|
|
|
25287
25659
|
});
|
|
25288
25660
|
|
|
25289
25661
|
// src/runtime/safety-checks.ts
|
|
25290
|
-
import
|
|
25662
|
+
import path38 from "path";
|
|
25291
25663
|
import os18 from "os";
|
|
25292
25664
|
function checkPathSafety(filePath) {
|
|
25293
|
-
const resolved =
|
|
25665
|
+
const resolved = path38.resolve(filePath);
|
|
25294
25666
|
for (const { pattern, reason } of BYPASS_IMMUNE_PATTERNS) {
|
|
25295
25667
|
const matches = typeof pattern === "function" ? pattern(resolved) : pattern.test(resolved);
|
|
25296
25668
|
if (matches) {
|
|
@@ -25300,7 +25672,7 @@ function checkPathSafety(filePath) {
|
|
|
25300
25672
|
return { safe: true, bypassImmune: true };
|
|
25301
25673
|
}
|
|
25302
25674
|
function checkReadPathSafety(filePath) {
|
|
25303
|
-
const resolved =
|
|
25675
|
+
const resolved = path38.resolve(filePath);
|
|
25304
25676
|
const credPatterns = BYPASS_IMMUNE_PATTERNS.filter(
|
|
25305
25677
|
(p) => typeof p.pattern !== "function" && (p.reason.includes("secrets") || p.reason.includes("Private key") || p.reason.includes("Credential"))
|
|
25306
25678
|
);
|
|
@@ -25326,11 +25698,11 @@ var init_safety_checks = __esm({
|
|
|
25326
25698
|
reason: "Git config can set hooks and command execution"
|
|
25327
25699
|
},
|
|
25328
25700
|
{
|
|
25329
|
-
pattern: (p) => p.startsWith(
|
|
25701
|
+
pattern: (p) => p.startsWith(path38.join(HOME, ".claude")),
|
|
25330
25702
|
reason: "Claude configuration files are protected"
|
|
25331
25703
|
},
|
|
25332
25704
|
{
|
|
25333
|
-
pattern: (p) => p.startsWith(
|
|
25705
|
+
pattern: (p) => p.startsWith(path38.join(HOME, ".exe-os")),
|
|
25334
25706
|
reason: "exe-os configuration files are protected"
|
|
25335
25707
|
},
|
|
25336
25708
|
{
|
|
@@ -25347,7 +25719,7 @@ var init_safety_checks = __esm({
|
|
|
25347
25719
|
},
|
|
25348
25720
|
{
|
|
25349
25721
|
pattern: (p) => {
|
|
25350
|
-
const name =
|
|
25722
|
+
const name = path38.basename(p);
|
|
25351
25723
|
return [".bashrc", ".zshrc", ".profile", ".bash_profile", ".zprofile", ".zshenv"].includes(name);
|
|
25352
25724
|
},
|
|
25353
25725
|
reason: "Shell configuration files can execute arbitrary code on login"
|
|
@@ -25374,7 +25746,7 @@ __export(file_read_exports, {
|
|
|
25374
25746
|
FileReadTool: () => FileReadTool
|
|
25375
25747
|
});
|
|
25376
25748
|
import fs3 from "fs/promises";
|
|
25377
|
-
import
|
|
25749
|
+
import path39 from "path";
|
|
25378
25750
|
import { z } from "zod";
|
|
25379
25751
|
function isBinary(buf) {
|
|
25380
25752
|
for (let i = 0; i < buf.length; i++) {
|
|
@@ -25410,7 +25782,7 @@ var init_file_read = __esm({
|
|
|
25410
25782
|
return { behavior: "allow" };
|
|
25411
25783
|
},
|
|
25412
25784
|
async call(input, context) {
|
|
25413
|
-
const filePath =
|
|
25785
|
+
const filePath = path39.isAbsolute(input.file_path) ? input.file_path : path39.resolve(context.cwd, input.file_path);
|
|
25414
25786
|
let stat2;
|
|
25415
25787
|
try {
|
|
25416
25788
|
stat2 = await fs3.stat(filePath);
|
|
@@ -25450,7 +25822,7 @@ __export(glob_exports, {
|
|
|
25450
25822
|
GlobTool: () => GlobTool
|
|
25451
25823
|
});
|
|
25452
25824
|
import fs4 from "fs/promises";
|
|
25453
|
-
import
|
|
25825
|
+
import path40 from "path";
|
|
25454
25826
|
import { z as z2 } from "zod";
|
|
25455
25827
|
async function walkDir(dir, maxDepth = 10) {
|
|
25456
25828
|
const results = [];
|
|
@@ -25466,7 +25838,7 @@ async function walkDir(dir, maxDepth = 10) {
|
|
|
25466
25838
|
if (entry.isDirectory() && (entry.name === "node_modules" || entry.name === ".git")) {
|
|
25467
25839
|
continue;
|
|
25468
25840
|
}
|
|
25469
|
-
const fullPath =
|
|
25841
|
+
const fullPath = path40.join(current, entry.name);
|
|
25470
25842
|
if (entry.isDirectory()) {
|
|
25471
25843
|
await walk(fullPath, depth + 1);
|
|
25472
25844
|
} else {
|
|
@@ -25500,11 +25872,11 @@ var init_glob = __esm({
|
|
|
25500
25872
|
inputSchema: inputSchema2,
|
|
25501
25873
|
isReadOnly: true,
|
|
25502
25874
|
async call(input, context) {
|
|
25503
|
-
const baseDir = input.path ?
|
|
25875
|
+
const baseDir = input.path ? path40.isAbsolute(input.path) ? input.path : path40.resolve(context.cwd, input.path) : context.cwd;
|
|
25504
25876
|
try {
|
|
25505
25877
|
const entries = await walkDir(baseDir);
|
|
25506
25878
|
const matched = entries.filter(
|
|
25507
|
-
(e) => simpleGlobMatch(
|
|
25879
|
+
(e) => simpleGlobMatch(path40.relative(baseDir, e.path), input.pattern)
|
|
25508
25880
|
);
|
|
25509
25881
|
matched.sort((a, b) => b.mtime - a.mtime);
|
|
25510
25882
|
if (matched.length === 0) {
|
|
@@ -25530,7 +25902,7 @@ __export(grep_exports, {
|
|
|
25530
25902
|
});
|
|
25531
25903
|
import { spawn as spawn2 } from "child_process";
|
|
25532
25904
|
import fs5 from "fs/promises";
|
|
25533
|
-
import
|
|
25905
|
+
import path41 from "path";
|
|
25534
25906
|
import { z as z3 } from "zod";
|
|
25535
25907
|
function runRipgrep(input, searchPath, context) {
|
|
25536
25908
|
return new Promise((resolve, reject) => {
|
|
@@ -25584,7 +25956,7 @@ async function nodeGrep(input, searchPath) {
|
|
|
25584
25956
|
}
|
|
25585
25957
|
for (const entry of entries) {
|
|
25586
25958
|
if (entry.name === "node_modules" || entry.name === ".git") continue;
|
|
25587
|
-
const fullPath =
|
|
25959
|
+
const fullPath = path41.join(dir, entry.name);
|
|
25588
25960
|
if (entry.isDirectory()) {
|
|
25589
25961
|
await walk(fullPath);
|
|
25590
25962
|
} else {
|
|
@@ -25630,7 +26002,7 @@ var init_grep = __esm({
|
|
|
25630
26002
|
inputSchema: inputSchema3,
|
|
25631
26003
|
isReadOnly: true,
|
|
25632
26004
|
async call(input, context) {
|
|
25633
|
-
const searchPath = input.path ?
|
|
26005
|
+
const searchPath = input.path ? path41.isAbsolute(input.path) ? input.path : path41.resolve(context.cwd, input.path) : context.cwd;
|
|
25634
26006
|
try {
|
|
25635
26007
|
const result = await runRipgrep(input, searchPath, context);
|
|
25636
26008
|
return result;
|
|
@@ -25655,7 +26027,7 @@ __export(file_write_exports, {
|
|
|
25655
26027
|
FileWriteTool: () => FileWriteTool
|
|
25656
26028
|
});
|
|
25657
26029
|
import fs6 from "fs/promises";
|
|
25658
|
-
import
|
|
26030
|
+
import path42 from "path";
|
|
25659
26031
|
import { z as z4 } from "zod";
|
|
25660
26032
|
var inputSchema4, FileWriteTool;
|
|
25661
26033
|
var init_file_write = __esm({
|
|
@@ -25683,8 +26055,8 @@ var init_file_write = __esm({
|
|
|
25683
26055
|
return { behavior: "allow" };
|
|
25684
26056
|
},
|
|
25685
26057
|
async call(input, context) {
|
|
25686
|
-
const filePath =
|
|
25687
|
-
const dir =
|
|
26058
|
+
const filePath = path42.isAbsolute(input.file_path) ? input.file_path : path42.resolve(context.cwd, input.file_path);
|
|
26059
|
+
const dir = path42.dirname(filePath);
|
|
25688
26060
|
await fs6.mkdir(dir, { recursive: true });
|
|
25689
26061
|
await fs6.writeFile(filePath, input.content, "utf-8");
|
|
25690
26062
|
return {
|
|
@@ -25702,7 +26074,7 @@ __export(file_edit_exports, {
|
|
|
25702
26074
|
FileEditTool: () => FileEditTool
|
|
25703
26075
|
});
|
|
25704
26076
|
import fs7 from "fs/promises";
|
|
25705
|
-
import
|
|
26077
|
+
import path43 from "path";
|
|
25706
26078
|
import { z as z5 } from "zod";
|
|
25707
26079
|
function countOccurrences(haystack, needle) {
|
|
25708
26080
|
let count = 0;
|
|
@@ -25743,7 +26115,7 @@ var init_file_edit = __esm({
|
|
|
25743
26115
|
return { behavior: "allow" };
|
|
25744
26116
|
},
|
|
25745
26117
|
async call(input, context) {
|
|
25746
|
-
const filePath =
|
|
26118
|
+
const filePath = path43.isAbsolute(input.file_path) ? input.file_path : path43.resolve(context.cwd, input.file_path);
|
|
25747
26119
|
let content;
|
|
25748
26120
|
try {
|
|
25749
26121
|
content = await fs7.readFile(filePath, "utf-8");
|
|
@@ -25985,7 +26357,7 @@ var init_bash = __esm({
|
|
|
25985
26357
|
// src/tui/views/CommandCenter.tsx
|
|
25986
26358
|
import { useState as useState6, useEffect as useEffect8, useMemo as useMemo4, useCallback as useCallback4, useRef as useRef4 } from "react";
|
|
25987
26359
|
import TextInput from "ink-text-input";
|
|
25988
|
-
import
|
|
26360
|
+
import path44 from "path";
|
|
25989
26361
|
import { homedir as homedir6 } from "os";
|
|
25990
26362
|
import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
25991
26363
|
function CommandCenterView({
|
|
@@ -26020,15 +26392,15 @@ function CommandCenterView({
|
|
|
26020
26392
|
const { createPermissionsFromPreset: createPermissionsFromPreset2, EMPLOYEE_PERMISSIONS: EMPLOYEE_PERMISSIONS2 } = await Promise.resolve().then(() => (init_permissions(), permissions_exports));
|
|
26021
26393
|
const { getPresetByRole: getPresetByRole2 } = await Promise.resolve().then(() => (init_permission_presets(), permission_presets_exports));
|
|
26022
26394
|
const { createDefaultHooks: createDefaultHooks2 } = await Promise.resolve().then(() => (init_hooks(), hooks_exports));
|
|
26023
|
-
const { readFileSync:
|
|
26395
|
+
const { readFileSync: readFileSync30, existsSync: existsSync35 } = await import("fs");
|
|
26024
26396
|
const { join } = await import("path");
|
|
26025
26397
|
const { homedir: homedir8 } = await import("os");
|
|
26026
26398
|
const configPath = join(homedir8(), ".exe-os", "config.json");
|
|
26027
26399
|
let failoverChain = ["anthropic", "opencode", "gemini", "openai"];
|
|
26028
26400
|
let providerConfigs = {};
|
|
26029
|
-
if (
|
|
26401
|
+
if (existsSync35(configPath)) {
|
|
26030
26402
|
try {
|
|
26031
|
-
const raw = JSON.parse(
|
|
26403
|
+
const raw = JSON.parse(readFileSync30(configPath, "utf8"));
|
|
26032
26404
|
if (Array.isArray(raw.failoverChain)) failoverChain = raw.failoverChain;
|
|
26033
26405
|
if (raw.providers && typeof raw.providers === "object") {
|
|
26034
26406
|
providerConfigs = raw.providers;
|
|
@@ -26089,7 +26461,7 @@ function CommandCenterView({
|
|
|
26089
26461
|
const markerDir = join(homedir8(), ".exe-os", "session-cache");
|
|
26090
26462
|
const agentFiles = (await import("fs")).readdirSync(markerDir).filter((f) => f.startsWith("active-agent-"));
|
|
26091
26463
|
for (const f of agentFiles) {
|
|
26092
|
-
const data = JSON.parse(
|
|
26464
|
+
const data = JSON.parse(readFileSync30(join(markerDir, f), "utf8"));
|
|
26093
26465
|
if (data.agentRole) {
|
|
26094
26466
|
agentRole = data.agentRole;
|
|
26095
26467
|
break;
|
|
@@ -26234,7 +26606,7 @@ function CommandCenterView({
|
|
|
26234
26606
|
const demoEntries = DEMO_PROJECTS.map((p) => ({
|
|
26235
26607
|
projectName: p.projectName,
|
|
26236
26608
|
exeSession: p.exeSession,
|
|
26237
|
-
projectDir:
|
|
26609
|
+
projectDir: path44.join(homedir6(), p.projectName),
|
|
26238
26610
|
employeeCount: p.employees.length,
|
|
26239
26611
|
activeCount: p.employees.filter((e) => e.status === "active").length,
|
|
26240
26612
|
memoryCount: p.employees.length * 4e3,
|
|
@@ -26272,7 +26644,7 @@ function CommandCenterView({
|
|
|
26272
26644
|
const { listSessions: listSessions2 } = await Promise.resolve().then(() => (init_session_registry(), session_registry_exports));
|
|
26273
26645
|
const { listTmuxSessions: listTmuxSessions2, inTmux: inTmux2 } = await Promise.resolve().then(() => (init_tmux_status(), tmux_status_exports));
|
|
26274
26646
|
const { loadEmployees: loadEmployees2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
26275
|
-
const { existsSync:
|
|
26647
|
+
const { existsSync: existsSync35 } = await import("fs");
|
|
26276
26648
|
const { join } = await import("path");
|
|
26277
26649
|
const client = getClient2();
|
|
26278
26650
|
if (!client) {
|
|
@@ -26343,7 +26715,7 @@ function CommandCenterView({
|
|
|
26343
26715
|
}
|
|
26344
26716
|
const memoryCount = memoryCounts.get(name) ?? 0;
|
|
26345
26717
|
const openTaskCount = openTaskCounts.get(name) ?? 0;
|
|
26346
|
-
const hasGit = projectDir ?
|
|
26718
|
+
const hasGit = projectDir ? existsSync35(join(projectDir, ".git")) : false;
|
|
26347
26719
|
const type = hasGit ? "code" : memoryCount > 0 ? "code" : "automation";
|
|
26348
26720
|
projectList.push({
|
|
26349
26721
|
projectName: name,
|
|
@@ -26368,7 +26740,7 @@ function CommandCenterView({
|
|
|
26368
26740
|
setHealth((h) => ({ ...h, memories: Number(totalResult.rows[0]?.cnt ?? 0) }));
|
|
26369
26741
|
try {
|
|
26370
26742
|
const pidPath = join(process.env.HOME ?? "", ".exe-os", "exed.pid");
|
|
26371
|
-
setHealth((h) => ({ ...h, daemon:
|
|
26743
|
+
setHealth((h) => ({ ...h, daemon: existsSync35(pidPath) ? "running" : "stopped" }));
|
|
26372
26744
|
} catch {
|
|
26373
26745
|
}
|
|
26374
26746
|
const activityResult = await client.execute(
|
|
@@ -27238,7 +27610,7 @@ var init_useOrchestrator = __esm({
|
|
|
27238
27610
|
|
|
27239
27611
|
// src/tui/views/Sessions.tsx
|
|
27240
27612
|
import React19, { useState as useState9, useEffect as useEffect11, useCallback as useCallback6 } from "react";
|
|
27241
|
-
import
|
|
27613
|
+
import path45 from "path";
|
|
27242
27614
|
import { homedir as homedir7 } from "os";
|
|
27243
27615
|
import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
27244
27616
|
function isCoordinatorEntry(entry) {
|
|
@@ -27276,7 +27648,7 @@ function SessionsView({
|
|
|
27276
27648
|
if (demo) {
|
|
27277
27649
|
setProjects(DEMO_PROJECTS.map((p) => ({
|
|
27278
27650
|
...p,
|
|
27279
|
-
projectDir:
|
|
27651
|
+
projectDir: path45.join(homedir7(), p.projectName),
|
|
27280
27652
|
employees: p.employees.map((e) => ({ ...e, attached: e.status === "active" }))
|
|
27281
27653
|
})));
|
|
27282
27654
|
return;
|
|
@@ -28491,12 +28863,12 @@ async function loadGatewayConfig() {
|
|
|
28491
28863
|
state.running = false;
|
|
28492
28864
|
}
|
|
28493
28865
|
try {
|
|
28494
|
-
const { existsSync:
|
|
28866
|
+
const { existsSync: existsSync35, readFileSync: readFileSync30 } = await import("fs");
|
|
28495
28867
|
const { join } = await import("path");
|
|
28496
28868
|
const home = process.env.HOME ?? "";
|
|
28497
28869
|
const configPath = join(home, ".exe-os", "gateway.json");
|
|
28498
|
-
if (
|
|
28499
|
-
const raw = JSON.parse(
|
|
28870
|
+
if (existsSync35(configPath)) {
|
|
28871
|
+
const raw = JSON.parse(readFileSync30(configPath, "utf8"));
|
|
28500
28872
|
state.port = raw.port ?? 3100;
|
|
28501
28873
|
state.gatewayUrl = raw.gatewayUrl ?? "";
|
|
28502
28874
|
if (raw.adapters) {
|
|
@@ -29094,12 +29466,12 @@ function TeamView({ onBack, onViewSessions }) {
|
|
|
29094
29466
|
setMembers(teamData);
|
|
29095
29467
|
setDbError(null);
|
|
29096
29468
|
try {
|
|
29097
|
-
const { existsSync:
|
|
29469
|
+
const { existsSync: existsSync35, readFileSync: readFileSync30 } = await import("fs");
|
|
29098
29470
|
const { join } = await import("path");
|
|
29099
29471
|
const home = process.env.HOME ?? "";
|
|
29100
29472
|
const gatewayConfig = join(home, ".exe-os", "gateway.json");
|
|
29101
|
-
if (
|
|
29102
|
-
const raw = JSON.parse(
|
|
29473
|
+
if (existsSync35(gatewayConfig)) {
|
|
29474
|
+
const raw = JSON.parse(readFileSync30(gatewayConfig, "utf8"));
|
|
29103
29475
|
if (raw.agents && raw.agents.length > 0) {
|
|
29104
29476
|
setExternals(raw.agents.map((a) => ({
|
|
29105
29477
|
name: a.name,
|
|
@@ -29279,8 +29651,8 @@ __export(wiki_client_exports, {
|
|
|
29279
29651
|
listDocuments: () => listDocuments,
|
|
29280
29652
|
listWorkspaces: () => listWorkspaces
|
|
29281
29653
|
});
|
|
29282
|
-
async function wikiFetch(config,
|
|
29283
|
-
const url = `${config.baseUrl}/api/v1${
|
|
29654
|
+
async function wikiFetch(config, path49, method = "GET", body) {
|
|
29655
|
+
const url = `${config.baseUrl}/api/v1${path49}`;
|
|
29284
29656
|
const headers = {
|
|
29285
29657
|
Authorization: `Bearer ${config.apiKey}`,
|
|
29286
29658
|
"Content-Type": "application/json"
|
|
@@ -29313,7 +29685,7 @@ async function wikiFetch(config, path48, method = "GET", body) {
|
|
|
29313
29685
|
}
|
|
29314
29686
|
}
|
|
29315
29687
|
if (!response.ok) {
|
|
29316
|
-
throw new Error(`Wiki API ${method} ${
|
|
29688
|
+
throw new Error(`Wiki API ${method} ${path49}: ${response.status} ${response.statusText}`);
|
|
29317
29689
|
}
|
|
29318
29690
|
return response.json();
|
|
29319
29691
|
} finally {
|
|
@@ -29907,12 +30279,12 @@ function SettingsView({ onBack }) {
|
|
|
29907
30279
|
}
|
|
29908
30280
|
setProviders(providerList);
|
|
29909
30281
|
try {
|
|
29910
|
-
const { existsSync:
|
|
30282
|
+
const { existsSync: existsSync35 } = await import("fs");
|
|
29911
30283
|
const { join } = await import("path");
|
|
29912
30284
|
const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
29913
30285
|
const cfg = await loadConfig2();
|
|
29914
30286
|
const home = process.env.HOME ?? "";
|
|
29915
|
-
const hasKey =
|
|
30287
|
+
const hasKey = existsSync35(join(home, ".exe-os", "master.key"));
|
|
29916
30288
|
if (cfg.cloud) {
|
|
29917
30289
|
setCloud({
|
|
29918
30290
|
configured: true,
|
|
@@ -29925,22 +30297,22 @@ function SettingsView({ onBack }) {
|
|
|
29925
30297
|
const pidPath = join(home, ".exe-os", "exed.pid");
|
|
29926
30298
|
let daemon = "unknown";
|
|
29927
30299
|
try {
|
|
29928
|
-
daemon =
|
|
30300
|
+
daemon = existsSync35(pidPath) ? "running" : "stopped";
|
|
29929
30301
|
} catch {
|
|
29930
30302
|
}
|
|
29931
30303
|
let version = "unknown";
|
|
29932
30304
|
try {
|
|
29933
|
-
const { readFileSync:
|
|
30305
|
+
const { readFileSync: readFileSync30 } = await import("fs");
|
|
29934
30306
|
const { createRequire: createRequire3 } = await import("module");
|
|
29935
30307
|
const require2 = createRequire3(import.meta.url);
|
|
29936
30308
|
const pkgPath = require2.resolve("@askexenow/exe-os/package.json");
|
|
29937
|
-
const pkg = JSON.parse(
|
|
30309
|
+
const pkg = JSON.parse(readFileSync30(pkgPath, "utf8"));
|
|
29938
30310
|
version = pkg.version;
|
|
29939
30311
|
} catch {
|
|
29940
30312
|
try {
|
|
29941
|
-
const { readFileSync:
|
|
30313
|
+
const { readFileSync: readFileSync30 } = await import("fs");
|
|
29942
30314
|
const { join: joinPath } = await import("path");
|
|
29943
|
-
const pkg = JSON.parse(
|
|
30315
|
+
const pkg = JSON.parse(readFileSync30(joinPath(process.cwd(), "package.json"), "utf8"));
|
|
29944
30316
|
version = pkg.version;
|
|
29945
30317
|
} catch {
|
|
29946
30318
|
}
|
|
@@ -30741,15 +31113,15 @@ __export(installer_exports2, {
|
|
|
30741
31113
|
verifyOpenCodeHooks: () => verifyOpenCodeHooks
|
|
30742
31114
|
});
|
|
30743
31115
|
import { readFile as readFile7, writeFile as writeFile8, mkdir as mkdir8 } from "fs/promises";
|
|
30744
|
-
import { existsSync as
|
|
30745
|
-
import
|
|
31116
|
+
import { existsSync as existsSync32, readFileSync as readFileSync28 } from "fs";
|
|
31117
|
+
import path46 from "path";
|
|
30746
31118
|
import os19 from "os";
|
|
30747
31119
|
async function registerOpenCodeMcp(packageRoot, homeDir = os19.homedir()) {
|
|
30748
|
-
const configDir =
|
|
30749
|
-
const configPath =
|
|
31120
|
+
const configDir = path46.join(homeDir, ".config", "opencode");
|
|
31121
|
+
const configPath = path46.join(configDir, "opencode.json");
|
|
30750
31122
|
await mkdir8(configDir, { recursive: true });
|
|
30751
31123
|
let config = {};
|
|
30752
|
-
if (
|
|
31124
|
+
if (existsSync32(configPath)) {
|
|
30753
31125
|
try {
|
|
30754
31126
|
config = JSON.parse(await readFile7(configPath, "utf-8"));
|
|
30755
31127
|
} catch {
|
|
@@ -30761,7 +31133,7 @@ async function registerOpenCodeMcp(packageRoot, homeDir = os19.homedir()) {
|
|
|
30761
31133
|
}
|
|
30762
31134
|
const newEntry = {
|
|
30763
31135
|
type: "local",
|
|
30764
|
-
command: ["node",
|
|
31136
|
+
command: ["node", path46.join(packageRoot, "dist", "mcp", "server.js")],
|
|
30765
31137
|
enabled: true
|
|
30766
31138
|
};
|
|
30767
31139
|
const current = config.mcp["exe-os"];
|
|
@@ -30776,14 +31148,14 @@ async function registerOpenCodeMcp(packageRoot, homeDir = os19.homedir()) {
|
|
|
30776
31148
|
return true;
|
|
30777
31149
|
}
|
|
30778
31150
|
async function installOpenCodePlugin(packageRoot, homeDir = os19.homedir()) {
|
|
30779
|
-
const pluginDir =
|
|
30780
|
-
const pluginPath =
|
|
31151
|
+
const pluginDir = path46.join(homeDir, ".config", "opencode", "plugins");
|
|
31152
|
+
const pluginPath = path46.join(pluginDir, "exe-os.mjs");
|
|
30781
31153
|
await mkdir8(pluginDir, { recursive: true });
|
|
30782
31154
|
const pluginContent = PLUGIN_TEMPLATE.replace(
|
|
30783
31155
|
/__PACKAGE_ROOT__/g,
|
|
30784
31156
|
packageRoot.replace(/\\/g, "\\\\")
|
|
30785
31157
|
);
|
|
30786
|
-
if (
|
|
31158
|
+
if (existsSync32(pluginPath)) {
|
|
30787
31159
|
const existing = await readFile7(pluginPath, "utf-8");
|
|
30788
31160
|
if (existing === pluginContent) {
|
|
30789
31161
|
return false;
|
|
@@ -30793,16 +31165,16 @@ async function installOpenCodePlugin(packageRoot, homeDir = os19.homedir()) {
|
|
|
30793
31165
|
return true;
|
|
30794
31166
|
}
|
|
30795
31167
|
function verifyOpenCodeHooks(homeDir = os19.homedir()) {
|
|
30796
|
-
const configPath =
|
|
30797
|
-
const pluginPath =
|
|
30798
|
-
if (!
|
|
31168
|
+
const configPath = path46.join(homeDir, ".config", "opencode", "opencode.json");
|
|
31169
|
+
const pluginPath = path46.join(homeDir, ".config", "opencode", "plugins", "exe-os.mjs");
|
|
31170
|
+
if (!existsSync32(configPath)) return false;
|
|
30799
31171
|
try {
|
|
30800
|
-
const config = JSON.parse(
|
|
31172
|
+
const config = JSON.parse(readFileSync28(configPath, "utf-8"));
|
|
30801
31173
|
if (!config.mcp?.["exe-os"]?.enabled) return false;
|
|
30802
31174
|
} catch {
|
|
30803
31175
|
return false;
|
|
30804
31176
|
}
|
|
30805
|
-
if (!
|
|
31177
|
+
if (!existsSync32(pluginPath)) return false;
|
|
30806
31178
|
return true;
|
|
30807
31179
|
}
|
|
30808
31180
|
async function runOpenCodeInstaller(homeDir) {
|
|
@@ -30837,19 +31209,19 @@ __export(installer_exports3, {
|
|
|
30837
31209
|
verifyCodexHooks: () => verifyCodexHooks
|
|
30838
31210
|
});
|
|
30839
31211
|
import { readFile as readFile8, writeFile as writeFile9, mkdir as mkdir9 } from "fs/promises";
|
|
30840
|
-
import { existsSync as
|
|
30841
|
-
import
|
|
31212
|
+
import { existsSync as existsSync33 } from "fs";
|
|
31213
|
+
import path47 from "path";
|
|
30842
31214
|
import os20 from "os";
|
|
30843
31215
|
async function mergeCodexHooks(packageRoot, homeDir = os20.homedir()) {
|
|
30844
|
-
const codexDir =
|
|
30845
|
-
const hooksPath =
|
|
30846
|
-
const logsDir =
|
|
30847
|
-
const hookLogPath =
|
|
31216
|
+
const codexDir = path47.join(homeDir, ".codex");
|
|
31217
|
+
const hooksPath = path47.join(codexDir, "hooks.json");
|
|
31218
|
+
const logsDir = path47.join(homeDir, ".exe-os", "logs");
|
|
31219
|
+
const hookLogPath = path47.join(logsDir, "hooks.log");
|
|
30848
31220
|
const logSuffix = ` 2>> "${hookLogPath}"`;
|
|
30849
31221
|
await mkdir9(codexDir, { recursive: true });
|
|
30850
31222
|
await mkdir9(logsDir, { recursive: true });
|
|
30851
31223
|
let hooksJson = {};
|
|
30852
|
-
if (
|
|
31224
|
+
if (existsSync33(hooksPath)) {
|
|
30853
31225
|
try {
|
|
30854
31226
|
hooksJson = JSON.parse(await readFile8(hooksPath, "utf-8"));
|
|
30855
31227
|
} catch {
|
|
@@ -30866,7 +31238,7 @@ async function mergeCodexHooks(packageRoot, homeDir = os20.homedir()) {
|
|
|
30866
31238
|
hooks: [
|
|
30867
31239
|
{
|
|
30868
31240
|
type: "command",
|
|
30869
|
-
command: `node "${
|
|
31241
|
+
command: `node "${path47.join(packageRoot, "dist", "hooks", "session-start.js")}"${logSuffix}`,
|
|
30870
31242
|
timeout: 30
|
|
30871
31243
|
}
|
|
30872
31244
|
]
|
|
@@ -30882,7 +31254,7 @@ async function mergeCodexHooks(packageRoot, homeDir = os20.homedir()) {
|
|
|
30882
31254
|
// Combined hook: runs ingest + error-recall in one Node process.
|
|
30883
31255
|
// Eliminates a cold-start cycle per tool call (~3-6s savings on Codex).
|
|
30884
31256
|
type: "command",
|
|
30885
|
-
command: `node "${
|
|
31257
|
+
command: `node "${path47.join(packageRoot, "dist", "hooks", "post-tool-combined.js")}"${logSuffix}`
|
|
30886
31258
|
}
|
|
30887
31259
|
]
|
|
30888
31260
|
},
|
|
@@ -30896,7 +31268,7 @@ async function mergeCodexHooks(packageRoot, homeDir = os20.homedir()) {
|
|
|
30896
31268
|
// Single hook: prompt-submit handles memory retrieval + entity boost.
|
|
30897
31269
|
// exe-heartbeat-hook is CC-specific (intercom) — omitted on Codex.
|
|
30898
31270
|
type: "command",
|
|
30899
|
-
command: `node "${
|
|
31271
|
+
command: `node "${path47.join(packageRoot, "dist", "hooks", "prompt-submit.js")}"${logSuffix}`
|
|
30900
31272
|
}
|
|
30901
31273
|
]
|
|
30902
31274
|
},
|
|
@@ -30908,7 +31280,7 @@ async function mergeCodexHooks(packageRoot, homeDir = os20.homedir()) {
|
|
|
30908
31280
|
hooks: [
|
|
30909
31281
|
{
|
|
30910
31282
|
type: "command",
|
|
30911
|
-
command: `node "${
|
|
31283
|
+
command: `node "${path47.join(packageRoot, "dist", "hooks", "stop.js")}"${logSuffix}`
|
|
30912
31284
|
}
|
|
30913
31285
|
]
|
|
30914
31286
|
},
|
|
@@ -30921,7 +31293,7 @@ async function mergeCodexHooks(packageRoot, homeDir = os20.homedir()) {
|
|
|
30921
31293
|
hooks: [
|
|
30922
31294
|
{
|
|
30923
31295
|
type: "command",
|
|
30924
|
-
command: `node "${
|
|
31296
|
+
command: `node "${path47.join(packageRoot, "dist", "hooks", "pre-tool-use.js")}"${logSuffix}`
|
|
30925
31297
|
}
|
|
30926
31298
|
]
|
|
30927
31299
|
},
|
|
@@ -30953,8 +31325,8 @@ async function mergeCodexHooks(packageRoot, homeDir = os20.homedir()) {
|
|
|
30953
31325
|
return { added, skipped };
|
|
30954
31326
|
}
|
|
30955
31327
|
function verifyCodexHooks(homeDir = os20.homedir()) {
|
|
30956
|
-
const hooksPath =
|
|
30957
|
-
if (!
|
|
31328
|
+
const hooksPath = path47.join(homeDir, ".codex", "hooks.json");
|
|
31329
|
+
if (!existsSync33(hooksPath)) return false;
|
|
30958
31330
|
try {
|
|
30959
31331
|
const hooksJson = JSON.parse(
|
|
30960
31332
|
__require("fs").readFileSync(hooksPath, "utf-8")
|
|
@@ -30977,11 +31349,11 @@ function verifyCodexHooks(homeDir = os20.homedir()) {
|
|
|
30977
31349
|
async function installCodexStatusLine(homeDir = os20.homedir()) {
|
|
30978
31350
|
const prefs = loadPreferences(homeDir);
|
|
30979
31351
|
if (prefs.codexStatusLine === false) return "opted-out";
|
|
30980
|
-
const codexDir =
|
|
30981
|
-
const configPath =
|
|
31352
|
+
const codexDir = path47.join(homeDir, ".codex");
|
|
31353
|
+
const configPath = path47.join(codexDir, "config.toml");
|
|
30982
31354
|
await mkdir9(codexDir, { recursive: true });
|
|
30983
31355
|
let content = "";
|
|
30984
|
-
if (
|
|
31356
|
+
if (existsSync33(configPath)) {
|
|
30985
31357
|
content = await readFile8(configPath, "utf-8");
|
|
30986
31358
|
if (/\[tui\][\s\S]*?status_line\s*=/.test(content)) {
|
|
30987
31359
|
return "already-configured";
|
|
@@ -31039,12 +31411,12 @@ ${desired}
|
|
|
31039
31411
|
return { content: next, changed };
|
|
31040
31412
|
}
|
|
31041
31413
|
async function registerCodexMcpServer(packageRoot, homeDir = os20.homedir()) {
|
|
31042
|
-
const codexDir =
|
|
31043
|
-
const configPath =
|
|
31044
|
-
const serverJsPath =
|
|
31414
|
+
const codexDir = path47.join(homeDir, ".codex");
|
|
31415
|
+
const configPath = path47.join(codexDir, "config.toml");
|
|
31416
|
+
const serverJsPath = path47.join(packageRoot, "dist", "mcp", "server.js");
|
|
31045
31417
|
await mkdir9(codexDir, { recursive: true });
|
|
31046
31418
|
let content = "";
|
|
31047
|
-
if (
|
|
31419
|
+
if (existsSync33(configPath)) {
|
|
31048
31420
|
content = await readFile8(configPath, "utf-8");
|
|
31049
31421
|
}
|
|
31050
31422
|
const sectionHeader = "[mcp_servers.exe-os]";
|
|
@@ -31069,10 +31441,10 @@ async function registerCodexMcpServer(packageRoot, homeDir = os20.homedir()) {
|
|
|
31069
31441
|
return "registered";
|
|
31070
31442
|
}
|
|
31071
31443
|
async function ensureCodexHooksFeature(homeDir = os20.homedir()) {
|
|
31072
|
-
const configPath =
|
|
31073
|
-
await mkdir9(
|
|
31444
|
+
const configPath = path47.join(homeDir, ".codex", "config.toml");
|
|
31445
|
+
await mkdir9(path47.join(homeDir, ".codex"), { recursive: true });
|
|
31074
31446
|
let content = "";
|
|
31075
|
-
if (
|
|
31447
|
+
if (existsSync33(configPath)) {
|
|
31076
31448
|
content = await readFile8(configPath, "utf-8");
|
|
31077
31449
|
}
|
|
31078
31450
|
if (/\[features\][\s\S]*?codex_hooks\s*=\s*true/.test(content)) {
|
|
@@ -31140,14 +31512,14 @@ var init_installer3 = __esm({
|
|
|
31140
31512
|
});
|
|
31141
31513
|
|
|
31142
31514
|
// src/bin/cli.ts
|
|
31143
|
-
import { existsSync as
|
|
31144
|
-
import
|
|
31515
|
+
import { existsSync as existsSync34, readFileSync as readFileSync29, writeFileSync as writeFileSync21, readdirSync as readdirSync10, rmSync } from "fs";
|
|
31516
|
+
import path48 from "path";
|
|
31145
31517
|
import os21 from "os";
|
|
31146
31518
|
var args = process.argv.slice(2);
|
|
31147
31519
|
if (args.includes("--version") || args.includes("-v")) {
|
|
31148
31520
|
try {
|
|
31149
|
-
const pkgPath =
|
|
31150
|
-
const pkg = JSON.parse(
|
|
31521
|
+
const pkgPath = path48.join(path48.dirname(new URL(import.meta.url).pathname), "..", "..", "package.json");
|
|
31522
|
+
const pkg = JSON.parse(readFileSync29(pkgPath, "utf8"));
|
|
31151
31523
|
console.log(pkg.version);
|
|
31152
31524
|
} catch {
|
|
31153
31525
|
console.log("unknown");
|
|
@@ -31306,16 +31678,19 @@ ID: ${result.id}`);
|
|
|
31306
31678
|
} else if (args[0] === "update") {
|
|
31307
31679
|
const { runUpdate: runUpdate2 } = await Promise.resolve().then(() => (init_update(), update_exports));
|
|
31308
31680
|
await runUpdate2(args.slice(1));
|
|
31681
|
+
} else if (args[0] === "stack-update") {
|
|
31682
|
+
const { runStackUpdateCli } = await Promise.resolve().then(() => (init_stack_update2(), stack_update_exports));
|
|
31683
|
+
await runStackUpdateCli();
|
|
31309
31684
|
} else if (args.includes("--tui") || args.includes("--demo") || args[0] === "tui") {
|
|
31310
31685
|
checkForUpdateOnBoot().catch(() => {
|
|
31311
31686
|
});
|
|
31312
31687
|
await init_App2().then(() => App_exports);
|
|
31313
31688
|
} else {
|
|
31314
|
-
const claudeDir =
|
|
31315
|
-
const settingsPath =
|
|
31316
|
-
const hasClaudeCode =
|
|
31689
|
+
const claudeDir = path48.join(os21.homedir(), ".claude");
|
|
31690
|
+
const settingsPath = path48.join(claudeDir, "settings.json");
|
|
31691
|
+
const hasClaudeCode = existsSync34(settingsPath) && (() => {
|
|
31317
31692
|
try {
|
|
31318
|
-
const raw =
|
|
31693
|
+
const raw = readFileSync29(settingsPath, "utf8");
|
|
31319
31694
|
return raw.includes("exe-os") || raw.includes("exe-mem");
|
|
31320
31695
|
} catch {
|
|
31321
31696
|
return false;
|
|
@@ -31325,9 +31700,9 @@ ID: ${result.id}`);
|
|
|
31325
31700
|
const { DEFAULT_COORDINATOR_TEMPLATE_NAME: DEFAULT_COORDINATOR_TEMPLATE_NAME2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
31326
31701
|
let cooName = DEFAULT_COORDINATOR_TEMPLATE_NAME2;
|
|
31327
31702
|
try {
|
|
31328
|
-
const rosterPath =
|
|
31329
|
-
if (
|
|
31330
|
-
const roster = JSON.parse(
|
|
31703
|
+
const rosterPath = path48.join(os21.homedir(), ".exe-os", "exe-employees.json");
|
|
31704
|
+
if (existsSync34(rosterPath)) {
|
|
31705
|
+
const roster = JSON.parse(readFileSync29(rosterPath, "utf8"));
|
|
31331
31706
|
const coo = roster.find((e) => e.role === "COO");
|
|
31332
31707
|
if (coo) cooName = coo.name;
|
|
31333
31708
|
}
|
|
@@ -31391,14 +31766,15 @@ async function runCodexInstall() {
|
|
|
31391
31766
|
}
|
|
31392
31767
|
}
|
|
31393
31768
|
async function runClaudeCheck() {
|
|
31394
|
-
const
|
|
31395
|
-
const
|
|
31396
|
-
const
|
|
31769
|
+
const { detectMcpNameCollisions: detectMcpNameCollisions2 } = await Promise.resolve().then(() => (init_installer(), installer_exports));
|
|
31770
|
+
const claudeDir = path48.join(os21.homedir(), ".claude");
|
|
31771
|
+
const settingsPath = path48.join(claudeDir, "settings.json");
|
|
31772
|
+
const claudeJsonPath = path48.join(os21.homedir(), ".claude.json");
|
|
31397
31773
|
let ok = true;
|
|
31398
|
-
if (
|
|
31774
|
+
if (existsSync34(settingsPath)) {
|
|
31399
31775
|
let settings;
|
|
31400
31776
|
try {
|
|
31401
|
-
settings = JSON.parse(
|
|
31777
|
+
settings = JSON.parse(readFileSync29(settingsPath, "utf8"));
|
|
31402
31778
|
} catch {
|
|
31403
31779
|
console.log("\x1B[31m\u2717\x1B[0m settings.json is malformed (invalid JSON)");
|
|
31404
31780
|
ok = false;
|
|
@@ -31424,10 +31800,10 @@ async function runClaudeCheck() {
|
|
|
31424
31800
|
console.log("\x1B[31m\u2717\x1B[0m settings.json not found");
|
|
31425
31801
|
ok = false;
|
|
31426
31802
|
}
|
|
31427
|
-
if (
|
|
31803
|
+
if (existsSync34(claudeJsonPath)) {
|
|
31428
31804
|
let claudeJson;
|
|
31429
31805
|
try {
|
|
31430
|
-
claudeJson = JSON.parse(
|
|
31806
|
+
claudeJson = JSON.parse(readFileSync29(claudeJsonPath, "utf8"));
|
|
31431
31807
|
} catch {
|
|
31432
31808
|
console.log("\x1B[31m\u2717\x1B[0m claude.json is malformed (invalid JSON)");
|
|
31433
31809
|
ok = false;
|
|
@@ -31446,8 +31822,22 @@ async function runClaudeCheck() {
|
|
|
31446
31822
|
console.log("\x1B[31m\u2717\x1B[0m claude.json not found");
|
|
31447
31823
|
ok = false;
|
|
31448
31824
|
}
|
|
31449
|
-
const
|
|
31450
|
-
|
|
31825
|
+
const collisions = detectMcpNameCollisions2(os21.homedir(), process.cwd());
|
|
31826
|
+
const disabledCollisions = collisions.filter((c) => c.disabledInMcpJson);
|
|
31827
|
+
if (disabledCollisions.length > 0) {
|
|
31828
|
+
console.log("\x1B[31m\u2717\x1B[0m MCP name collision: disabled .mcp.json entries shadow project MCP servers");
|
|
31829
|
+
for (const c of disabledCollisions) {
|
|
31830
|
+
console.log(` - ${c.serverName}: ${c.mcpJsonPath} shadows ~/.claude.json project ${c.projectPath}`);
|
|
31831
|
+
}
|
|
31832
|
+
console.log(" Fix: remove/rename the duplicate .mcp.json server entry, or use one MCP config source of truth.");
|
|
31833
|
+
ok = false;
|
|
31834
|
+
} else if (collisions.length > 0) {
|
|
31835
|
+
console.log("\x1B[33m!\x1B[0m MCP server names duplicated between .mcp.json and project config");
|
|
31836
|
+
} else {
|
|
31837
|
+
console.log("\x1B[32m\u2713\x1B[0m No .mcp.json/project MCP name collisions detected");
|
|
31838
|
+
}
|
|
31839
|
+
const skillsDir = path48.join(claudeDir, "skills");
|
|
31840
|
+
if (existsSync34(skillsDir)) {
|
|
31451
31841
|
console.log("\x1B[32m\u2713\x1B[0m Slash skills directory exists");
|
|
31452
31842
|
} else {
|
|
31453
31843
|
console.log("\x1B[31m\u2717\x1B[0m Slash skills directory missing");
|
|
@@ -31464,16 +31854,16 @@ async function runClaudeUninstall(flags = []) {
|
|
|
31464
31854
|
const dryRun = flags.includes("--dry-run");
|
|
31465
31855
|
const purge = flags.includes("--purge");
|
|
31466
31856
|
const homeDir = os21.homedir();
|
|
31467
|
-
const claudeDir =
|
|
31468
|
-
const settingsPath =
|
|
31469
|
-
const claudeJsonPath =
|
|
31470
|
-
const exeOsDir =
|
|
31857
|
+
const claudeDir = path48.join(homeDir, ".claude");
|
|
31858
|
+
const settingsPath = path48.join(claudeDir, "settings.json");
|
|
31859
|
+
const claudeJsonPath = path48.join(homeDir, ".claude.json");
|
|
31860
|
+
const exeOsDir = path48.join(homeDir, ".exe-os");
|
|
31471
31861
|
let removed = 0;
|
|
31472
31862
|
const log = (msg) => console.log(dryRun ? `[dry-run] ${msg}` : msg);
|
|
31473
31863
|
let settings = {};
|
|
31474
|
-
if (
|
|
31864
|
+
if (existsSync34(settingsPath)) {
|
|
31475
31865
|
try {
|
|
31476
|
-
settings = JSON.parse(
|
|
31866
|
+
settings = JSON.parse(readFileSync29(settingsPath, "utf8"));
|
|
31477
31867
|
} catch {
|
|
31478
31868
|
console.error("Your ~/.claude/settings.json appears malformed.");
|
|
31479
31869
|
if (purge) {
|
|
@@ -31511,15 +31901,15 @@ async function runClaudeUninstall(flags = []) {
|
|
|
31511
31901
|
permCount = before - settings.permissions.allow.length;
|
|
31512
31902
|
}
|
|
31513
31903
|
if (!dryRun) {
|
|
31514
|
-
|
|
31904
|
+
writeFileSync21(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
31515
31905
|
}
|
|
31516
31906
|
log("\u2713 Removed exe-os hooks from settings.json");
|
|
31517
31907
|
if (permCount > 0) log(`\u2713 Removed ${permCount} MCP permission entries`);
|
|
31518
31908
|
removed++;
|
|
31519
31909
|
}
|
|
31520
31910
|
}
|
|
31521
|
-
if (
|
|
31522
|
-
const raw =
|
|
31911
|
+
if (existsSync34(claudeJsonPath)) {
|
|
31912
|
+
const raw = readFileSync29(claudeJsonPath, "utf8");
|
|
31523
31913
|
if (raw.length > 1e6) {
|
|
31524
31914
|
console.error("claude.json exceeds 1 MB \u2014 skipping parse.");
|
|
31525
31915
|
} else {
|
|
@@ -31540,7 +31930,7 @@ async function runClaudeUninstall(flags = []) {
|
|
|
31540
31930
|
}
|
|
31541
31931
|
if (removedMcp) {
|
|
31542
31932
|
if (!dryRun) {
|
|
31543
|
-
|
|
31933
|
+
writeFileSync21(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
|
|
31544
31934
|
}
|
|
31545
31935
|
log("\u2713 Removed exe-os MCP server from claude.json");
|
|
31546
31936
|
removed++;
|
|
@@ -31548,14 +31938,14 @@ async function runClaudeUninstall(flags = []) {
|
|
|
31548
31938
|
}
|
|
31549
31939
|
}
|
|
31550
31940
|
}
|
|
31551
|
-
const skillsDir =
|
|
31552
|
-
if (
|
|
31941
|
+
const skillsDir = path48.join(claudeDir, "skills");
|
|
31942
|
+
if (existsSync34(skillsDir)) {
|
|
31553
31943
|
let skillCount = 0;
|
|
31554
31944
|
try {
|
|
31555
31945
|
const entries = readdirSync10(skillsDir);
|
|
31556
31946
|
for (const entry of entries) {
|
|
31557
31947
|
if (entry.startsWith("exe")) {
|
|
31558
|
-
const fullPath =
|
|
31948
|
+
const fullPath = path48.join(skillsDir, entry);
|
|
31559
31949
|
if (!dryRun) rmSync(fullPath, { recursive: true, force: true });
|
|
31560
31950
|
skillCount++;
|
|
31561
31951
|
}
|
|
@@ -31567,30 +31957,30 @@ async function runClaudeUninstall(flags = []) {
|
|
|
31567
31957
|
removed++;
|
|
31568
31958
|
}
|
|
31569
31959
|
}
|
|
31570
|
-
const claudeMdPath =
|
|
31571
|
-
if (
|
|
31572
|
-
const content =
|
|
31960
|
+
const claudeMdPath = path48.join(claudeDir, "CLAUDE.md");
|
|
31961
|
+
if (existsSync34(claudeMdPath)) {
|
|
31962
|
+
const content = readFileSync29(claudeMdPath, "utf8");
|
|
31573
31963
|
const startMarker = "<!-- exe-os:orchestration-start -->";
|
|
31574
31964
|
const endMarker = "<!-- exe-os:orchestration-end -->";
|
|
31575
31965
|
const startIdx = content.indexOf(startMarker);
|
|
31576
31966
|
const endIdx = content.indexOf(endMarker);
|
|
31577
31967
|
if (startIdx !== -1 && endIdx !== -1) {
|
|
31578
31968
|
const cleaned = (content.slice(0, startIdx) + content.slice(endIdx + endMarker.length)).replace(/\n{3,}/g, "\n\n").trim() + "\n";
|
|
31579
|
-
if (!dryRun)
|
|
31969
|
+
if (!dryRun) writeFileSync21(claudeMdPath, cleaned);
|
|
31580
31970
|
log("\u2713 Removed orchestration block from CLAUDE.md");
|
|
31581
31971
|
removed++;
|
|
31582
31972
|
}
|
|
31583
31973
|
}
|
|
31584
|
-
const agentsDir =
|
|
31585
|
-
if (
|
|
31974
|
+
const agentsDir = path48.join(claudeDir, "agents");
|
|
31975
|
+
if (existsSync34(agentsDir)) {
|
|
31586
31976
|
let agentCount = 0;
|
|
31587
31977
|
try {
|
|
31588
31978
|
const entries = readdirSync10(agentsDir).filter((f) => f.endsWith(".md"));
|
|
31589
31979
|
let knownNames = /* @__PURE__ */ new Set();
|
|
31590
|
-
const rosterPath =
|
|
31591
|
-
if (
|
|
31980
|
+
const rosterPath = path48.join(exeOsDir, "exe-employees.json");
|
|
31981
|
+
if (existsSync34(rosterPath)) {
|
|
31592
31982
|
try {
|
|
31593
|
-
const roster = JSON.parse(
|
|
31983
|
+
const roster = JSON.parse(readFileSync29(rosterPath, "utf8"));
|
|
31594
31984
|
knownNames = new Set(roster.map((e) => e.name));
|
|
31595
31985
|
} catch {
|
|
31596
31986
|
}
|
|
@@ -31598,7 +31988,7 @@ async function runClaudeUninstall(flags = []) {
|
|
|
31598
31988
|
for (const entry of entries) {
|
|
31599
31989
|
const name = entry.replace(/\.md$/, "");
|
|
31600
31990
|
if (knownNames.has(name)) {
|
|
31601
|
-
if (!dryRun) rmSync(
|
|
31991
|
+
if (!dryRun) rmSync(path48.join(agentsDir, entry), { force: true });
|
|
31602
31992
|
agentCount++;
|
|
31603
31993
|
}
|
|
31604
31994
|
}
|
|
@@ -31609,16 +31999,16 @@ async function runClaudeUninstall(flags = []) {
|
|
|
31609
31999
|
removed++;
|
|
31610
32000
|
}
|
|
31611
32001
|
}
|
|
31612
|
-
const projectsDir =
|
|
31613
|
-
if (
|
|
32002
|
+
const projectsDir = path48.join(claudeDir, "projects");
|
|
32003
|
+
if (existsSync34(projectsDir)) {
|
|
31614
32004
|
let projectCount = 0;
|
|
31615
32005
|
try {
|
|
31616
32006
|
const projects = readdirSync10(projectsDir);
|
|
31617
32007
|
for (const proj of projects) {
|
|
31618
|
-
const projSettings =
|
|
31619
|
-
if (!
|
|
32008
|
+
const projSettings = path48.join(projectsDir, proj, "settings.json");
|
|
32009
|
+
if (!existsSync34(projSettings)) continue;
|
|
31620
32010
|
try {
|
|
31621
|
-
const pSettings = JSON.parse(
|
|
32011
|
+
const pSettings = JSON.parse(readFileSync29(projSettings, "utf8"));
|
|
31622
32012
|
let changed = false;
|
|
31623
32013
|
if (Array.isArray(pSettings.permissions?.allow)) {
|
|
31624
32014
|
const before = pSettings.permissions.allow.length;
|
|
@@ -31628,7 +32018,7 @@ async function runClaudeUninstall(flags = []) {
|
|
|
31628
32018
|
if (pSettings.permissions.allow.length < before) changed = true;
|
|
31629
32019
|
}
|
|
31630
32020
|
if (changed && !dryRun) {
|
|
31631
|
-
|
|
32021
|
+
writeFileSync21(projSettings, JSON.stringify(pSettings, null, 2) + "\n");
|
|
31632
32022
|
}
|
|
31633
32023
|
if (changed) projectCount++;
|
|
31634
32024
|
} catch {
|
|
@@ -31652,18 +32042,18 @@ async function runClaudeUninstall(flags = []) {
|
|
|
31652
32042
|
};
|
|
31653
32043
|
const exeBinPath = findExeBin3();
|
|
31654
32044
|
if (!exeBinPath) throw new Error("exe-os not found in PATH");
|
|
31655
|
-
const binDir =
|
|
32045
|
+
const binDir = path48.dirname(exeBinPath);
|
|
31656
32046
|
let symlinkCount = 0;
|
|
31657
|
-
const rosterPath =
|
|
31658
|
-
if (
|
|
31659
|
-
const roster = JSON.parse(
|
|
32047
|
+
const rosterPath = path48.join(exeOsDir, "exe-employees.json");
|
|
32048
|
+
if (existsSync34(rosterPath)) {
|
|
32049
|
+
const roster = JSON.parse(readFileSync29(rosterPath, "utf8"));
|
|
31660
32050
|
const { DEFAULT_COORDINATOR_TEMPLATE_NAME: DEFAULT_COORDINATOR_TEMPLATE_NAME2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
31661
32051
|
const coordinatorName = roster.find((e) => e.role?.toLowerCase() === "coo")?.name ?? DEFAULT_COORDINATOR_TEMPLATE_NAME2;
|
|
31662
32052
|
for (const emp of roster) {
|
|
31663
32053
|
if (emp.name === coordinatorName) continue;
|
|
31664
32054
|
for (const suffix of ["", "-opencode"]) {
|
|
31665
|
-
const linkPath =
|
|
31666
|
-
if (
|
|
32055
|
+
const linkPath = path48.join(binDir, `${emp.name}${suffix}`);
|
|
32056
|
+
if (existsSync34(linkPath)) {
|
|
31667
32057
|
if (!dryRun) rmSync(linkPath, { force: true });
|
|
31668
32058
|
symlinkCount++;
|
|
31669
32059
|
}
|
|
@@ -31676,7 +32066,7 @@ async function runClaudeUninstall(flags = []) {
|
|
|
31676
32066
|
}
|
|
31677
32067
|
} catch {
|
|
31678
32068
|
}
|
|
31679
|
-
if (purge &&
|
|
32069
|
+
if (purge && existsSync34(exeOsDir)) {
|
|
31680
32070
|
if (!dryRun) {
|
|
31681
32071
|
process.stdout.write("\x1B[33m\u26A0 This will delete all memories, identities, and agent data.\x1B[0m\n");
|
|
31682
32072
|
process.stdout.write(" Removing ~/.exe-os...\n");
|
|
@@ -31701,7 +32091,7 @@ async function checkForUpdateOnBoot() {
|
|
|
31701
32091
|
const config = await loadConfig2();
|
|
31702
32092
|
if (!config.autoUpdate.checkOnBoot) return;
|
|
31703
32093
|
const { checkForUpdate: checkForUpdate2 } = await Promise.resolve().then(() => (init_update(), update_exports));
|
|
31704
|
-
const packageRoot =
|
|
32094
|
+
const packageRoot = path48.resolve(
|
|
31705
32095
|
new URL("../..", import.meta.url).pathname
|
|
31706
32096
|
);
|
|
31707
32097
|
const result = checkForUpdate2(packageRoot);
|
|
@@ -31761,7 +32151,7 @@ async function runActivate(key) {
|
|
|
31761
32151
|
const idTemplate = getIdentityTemplate(identityKey);
|
|
31762
32152
|
if (idTemplate) {
|
|
31763
32153
|
const idPath = identityPath2(name);
|
|
31764
|
-
const dir =
|
|
32154
|
+
const dir = path48.dirname(idPath);
|
|
31765
32155
|
if (!fs8.existsSync(dir)) fs8.mkdirSync(dir, { recursive: true });
|
|
31766
32156
|
fs8.writeFileSync(idPath, idTemplate.replace(/^agent_id: \w+/m, `agent_id: ${name}`), "utf-8");
|
|
31767
32157
|
}
|