@askexenow/exe-os 0.9.20 → 0.9.22
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/LICENSE +24 -15
- package/dist/bin/backfill-conversations.js +17 -4
- package/dist/bin/backfill-responses.js +17 -4
- package/dist/bin/backfill-vectors.js +2 -2
- package/dist/bin/cleanup-stale-review-tasks.js +17 -4
- package/dist/bin/cli.js +420 -180
- package/dist/bin/exe-assign.js +17 -4
- package/dist/bin/exe-boot.js +2 -2
- package/dist/bin/exe-dispatch.js +17 -4
- package/dist/bin/exe-doctor.js +2 -2
- package/dist/bin/exe-export-behaviors.js +17 -4
- package/dist/bin/exe-forget.js +17 -4
- package/dist/bin/exe-gateway.js +17 -4
- package/dist/bin/exe-heartbeat.js +17 -4
- package/dist/bin/exe-kill.js +17 -4
- package/dist/bin/exe-launch-agent.js +17 -4
- package/dist/bin/exe-new-employee.js +42 -18
- package/dist/bin/exe-pending-messages.js +17 -4
- package/dist/bin/exe-pending-notifications.js +17 -4
- package/dist/bin/exe-pending-reviews.js +17 -4
- package/dist/bin/exe-review.js +17 -4
- package/dist/bin/exe-search.js +23 -8
- package/dist/bin/exe-session-cleanup.js +17 -4
- package/dist/bin/exe-start-codex.js +209 -32
- package/dist/bin/exe-start-opencode.js +17 -4
- package/dist/bin/exe-status.js +17 -4
- package/dist/bin/exe-team.js +17 -4
- package/dist/bin/git-sweep.js +17 -4
- package/dist/bin/graph-backfill.js +17 -4
- package/dist/bin/graph-export.js +17 -4
- package/dist/bin/install.js +84 -18
- package/dist/bin/intercom-check.js +17 -4
- package/dist/bin/scan-tasks.js +17 -4
- package/dist/bin/shard-migrate.js +17 -4
- package/dist/bin/update.js +187 -42
- package/dist/gateway/index.js +17 -4
- package/dist/hooks/bug-report-worker.js +793 -150
- package/dist/hooks/codex-stop-task-finalizer.js +3020 -2375
- package/dist/hooks/commit-complete.js +156 -6
- package/dist/hooks/error-recall.js +23 -8
- package/dist/hooks/ingest.js +17 -4
- package/dist/hooks/instructions-loaded.js +17 -4
- package/dist/hooks/notification.js +17 -4
- package/dist/hooks/post-compact.js +17 -4
- package/dist/hooks/post-tool-combined.js +23 -8
- package/dist/hooks/pre-compact.js +156 -8
- package/dist/hooks/pre-tool-use.js +21 -12
- package/dist/hooks/prompt-submit.js +23 -8
- package/dist/hooks/session-end.js +156 -8
- package/dist/hooks/session-start.js +23 -8
- package/dist/hooks/stop.js +306 -9
- package/dist/hooks/subagent-stop.js +306 -9
- package/dist/hooks/summary-worker.js +2 -2
- package/dist/index.js +17 -4
- package/dist/lib/exe-daemon.js +17 -4
- package/dist/lib/hybrid-search.js +23 -8
- package/dist/lib/schedules.js +2 -2
- package/dist/lib/store.js +17 -4
- package/dist/mcp/server.js +36 -10
- package/dist/runtime/index.js +17 -4
- package/dist/tui/App.js +17 -4
- package/package.json +2 -2
package/dist/bin/cli.js
CHANGED
|
@@ -917,18 +917,21 @@ async function registerMcpServer(packageRoot, homeDir = os5.homedir()) {
|
|
|
917
917
|
args: [path6.join(packageRoot, "dist", "mcp", "server.js")],
|
|
918
918
|
env: {}
|
|
919
919
|
};
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
delete claudeJson.mcpServers[MCP_PRIMARY_KEY];
|
|
920
|
+
if (claudeJson.mcpServers[MCP_LEGACY_KEY]) {
|
|
921
|
+
delete claudeJson.mcpServers[MCP_LEGACY_KEY];
|
|
922
|
+
process.stderr.write("exe-os: migrated MCP server key exe-mem \u2192 exe-os\n");
|
|
924
923
|
}
|
|
925
|
-
|
|
924
|
+
const currentOs = claudeJson.mcpServers[MCP_PRIMARY_KEY];
|
|
925
|
+
const osMatches = currentOs && JSON.stringify(currentOs) === JSON.stringify(newEntry);
|
|
926
|
+
if (osMatches) {
|
|
926
927
|
await cleanSettingsJsonMcp(path6.join(homeDir, ".claude", "settings.json"));
|
|
928
|
+
await migratePermissionsToExeOs(path6.join(homeDir, ".claude", "settings.json"));
|
|
927
929
|
return false;
|
|
928
930
|
}
|
|
929
|
-
claudeJson.mcpServers[
|
|
931
|
+
claudeJson.mcpServers[MCP_PRIMARY_KEY] = newEntry;
|
|
930
932
|
await writeFile3(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
|
|
931
933
|
await cleanSettingsJsonMcp(path6.join(homeDir, ".claude", "settings.json"));
|
|
934
|
+
await migratePermissionsToExeOs(path6.join(homeDir, ".claude", "settings.json"));
|
|
932
935
|
return true;
|
|
933
936
|
}
|
|
934
937
|
async function cleanSettingsJsonMcp(settingsPath) {
|
|
@@ -952,6 +955,35 @@ async function cleanSettingsJsonMcp(settingsPath) {
|
|
|
952
955
|
} catch {
|
|
953
956
|
}
|
|
954
957
|
}
|
|
958
|
+
async function migratePermissionsToExeOs(settingsPath) {
|
|
959
|
+
if (!existsSync7(settingsPath)) return;
|
|
960
|
+
try {
|
|
961
|
+
const settings = JSON.parse(await readFile3(settingsPath, "utf-8"));
|
|
962
|
+
const permissions = settings.permissions;
|
|
963
|
+
if (!permissions || !Array.isArray(permissions.allow)) return;
|
|
964
|
+
const allow = permissions.allow;
|
|
965
|
+
let migrated = 0;
|
|
966
|
+
for (let i = 0; i < allow.length; i++) {
|
|
967
|
+
if (allow[i].startsWith("mcp__exe-mem__")) {
|
|
968
|
+
const newName = allow[i].replace("mcp__exe-mem__", "mcp__exe-os__");
|
|
969
|
+
if (!allow.includes(newName)) {
|
|
970
|
+
allow[i] = newName;
|
|
971
|
+
} else {
|
|
972
|
+
allow[i] = "__REMOVE__";
|
|
973
|
+
}
|
|
974
|
+
migrated++;
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
if (migrated > 0) {
|
|
978
|
+
permissions.allow = allow.filter((e) => e !== "__REMOVE__");
|
|
979
|
+
permissions.allow = [...new Set(permissions.allow)];
|
|
980
|
+
await writeFile3(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
981
|
+
process.stderr.write(`exe-os: migrated ${migrated} permission(s) from exe-mem \u2192 exe-os
|
|
982
|
+
`);
|
|
983
|
+
}
|
|
984
|
+
} catch {
|
|
985
|
+
}
|
|
986
|
+
}
|
|
955
987
|
async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
|
|
956
988
|
const settingsPath = path6.join(homeDir, ".claude", "settings.json");
|
|
957
989
|
const logsDir = path6.join(homeDir, ".exe-os", "logs");
|
|
@@ -1212,9 +1244,10 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
|
|
|
1212
1244
|
"deploy_client"
|
|
1213
1245
|
];
|
|
1214
1246
|
const allowList = permissions.allow;
|
|
1215
|
-
for (const
|
|
1216
|
-
|
|
1217
|
-
|
|
1247
|
+
for (const name of toolNames) {
|
|
1248
|
+
const fullName = `mcp__${MCP_PRIMARY_KEY}__${name}`;
|
|
1249
|
+
if (!allowList.includes(fullName)) {
|
|
1250
|
+
allowList.push(fullName);
|
|
1218
1251
|
}
|
|
1219
1252
|
}
|
|
1220
1253
|
await mkdir3(path6.dirname(settingsPath), { recursive: true });
|
|
@@ -5952,9 +5985,9 @@ async function cloudPullGraphRAG(config) {
|
|
|
5952
5985
|
pulled += stmts.length;
|
|
5953
5986
|
}
|
|
5954
5987
|
if (blob.relationship_memories.length > 0) {
|
|
5955
|
-
const stmts = blob.relationship_memories.map((
|
|
5988
|
+
const stmts = blob.relationship_memories.map((rm2) => ({
|
|
5956
5989
|
sql: `INSERT OR IGNORE INTO relationship_memories (relationship_id, memory_id) VALUES (?, ?)`,
|
|
5957
|
-
args: [sqlSafe(
|
|
5990
|
+
args: [sqlSafe(rm2.relationship_id), sqlSafe(rm2.memory_id)]
|
|
5958
5991
|
}));
|
|
5959
5992
|
await client.batch(stmts, "write");
|
|
5960
5993
|
pulled += stmts.length;
|
|
@@ -6471,8 +6504,8 @@ function getShardClient(projectName) {
|
|
|
6471
6504
|
throw new Error("Shard manager not initialized. Call initShardManager() first.");
|
|
6472
6505
|
}
|
|
6473
6506
|
const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
6474
|
-
if (!safeName) {
|
|
6475
|
-
throw new Error(`Invalid project name for shard: "${projectName}"`);
|
|
6507
|
+
if (!safeName || safeName === "unknown") {
|
|
6508
|
+
throw new Error(`Invalid project name for shard: "${projectName}" (resolved to "${safeName}")`);
|
|
6476
6509
|
}
|
|
6477
6510
|
const cached = _shards.get(safeName);
|
|
6478
6511
|
if (cached) {
|
|
@@ -7341,19 +7374,32 @@ async function flushBatch() {
|
|
|
7341
7374
|
const { isShardingEnabled: isShardingEnabled2, getReadyShardClient: getReadyShardClient2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
7342
7375
|
if (isShardingEnabled2()) {
|
|
7343
7376
|
const byProject = /* @__PURE__ */ new Map();
|
|
7377
|
+
let skippedUnknown = 0;
|
|
7344
7378
|
for (const row of batch) {
|
|
7345
|
-
const proj = row.project_name
|
|
7379
|
+
const proj = row.project_name?.trim();
|
|
7380
|
+
if (!proj) {
|
|
7381
|
+
skippedUnknown++;
|
|
7382
|
+
continue;
|
|
7383
|
+
}
|
|
7346
7384
|
if (!byProject.has(proj)) byProject.set(proj, []);
|
|
7347
7385
|
byProject.get(proj).push(row);
|
|
7348
7386
|
}
|
|
7387
|
+
if (skippedUnknown > 0) {
|
|
7388
|
+
process.stderr.write(
|
|
7389
|
+
`[store] Shard skip: ${skippedUnknown} record(s) with empty project_name (kept in main DB only)
|
|
7390
|
+
`
|
|
7391
|
+
);
|
|
7392
|
+
}
|
|
7349
7393
|
for (const [project, rows] of byProject) {
|
|
7350
7394
|
try {
|
|
7351
7395
|
const shardClient = await getReadyShardClient2(project);
|
|
7352
7396
|
const shardStmts = rows.map(buildStmt);
|
|
7353
7397
|
await shardClient.batch(shardStmts, "write");
|
|
7354
7398
|
} catch (err) {
|
|
7399
|
+
const fullError = err instanceof Error ? `${err.name}: ${err.message}${err.stack ? `
|
|
7400
|
+
${err.stack.split("\n").slice(1, 3).join("\n")}` : ""}` : String(err);
|
|
7355
7401
|
process.stderr.write(
|
|
7356
|
-
`[store] Shard write failed for ${project}
|
|
7402
|
+
`[store] Shard write failed for ${project} (${rows.length} records): ${fullError}
|
|
7357
7403
|
`
|
|
7358
7404
|
);
|
|
7359
7405
|
}
|
|
@@ -8381,9 +8427,9 @@ Unclassified: ${unclassified}
|
|
|
8381
8427
|
}
|
|
8382
8428
|
async function exportBatches(options) {
|
|
8383
8429
|
const fs8 = await import("fs");
|
|
8384
|
-
const
|
|
8430
|
+
const path47 = await import("path");
|
|
8385
8431
|
const client = getClient();
|
|
8386
|
-
const outDir =
|
|
8432
|
+
const outDir = path47.join(process.cwd(), "exe/output/classifications/input");
|
|
8387
8433
|
fs8.mkdirSync(outDir, { recursive: true });
|
|
8388
8434
|
const countResult = await client.execute({
|
|
8389
8435
|
sql: "SELECT COUNT(*) as cnt FROM memories WHERE intent IS NULL AND outcome IS NULL AND domain IS NULL",
|
|
@@ -8407,7 +8453,7 @@ async function exportBatches(options) {
|
|
|
8407
8453
|
const text = String(row.text || "").replace(/\n/g, " ");
|
|
8408
8454
|
return JSON.stringify({ id: row.id, text });
|
|
8409
8455
|
});
|
|
8410
|
-
const batchFile =
|
|
8456
|
+
const batchFile = path47.join(outDir, `batch-${String(batchNum).padStart(4, "0")}.jsonl`);
|
|
8411
8457
|
fs8.writeFileSync(batchFile, lines.join("\n") + "\n");
|
|
8412
8458
|
exported += batch.rows.length;
|
|
8413
8459
|
offset += options.batchSize;
|
|
@@ -8423,7 +8469,7 @@ async function exportBatches(options) {
|
|
|
8423
8469
|
}
|
|
8424
8470
|
async function importClassifications(importDir) {
|
|
8425
8471
|
const fs8 = await import("fs");
|
|
8426
|
-
const
|
|
8472
|
+
const path47 = await import("path");
|
|
8427
8473
|
const client = getClient();
|
|
8428
8474
|
const files = fs8.readdirSync(importDir).filter((f) => f.endsWith(".jsonl")).sort();
|
|
8429
8475
|
process.stderr.write(`[backfill-metadata] Found ${files.length} JSONL files to import from ${importDir}
|
|
@@ -8431,7 +8477,7 @@ async function importClassifications(importDir) {
|
|
|
8431
8477
|
let imported = 0;
|
|
8432
8478
|
let invalid = 0;
|
|
8433
8479
|
for (const file of files) {
|
|
8434
|
-
const lines = fs8.readFileSync(
|
|
8480
|
+
const lines = fs8.readFileSync(path47.join(importDir, file), "utf-8").split("\n").filter(Boolean);
|
|
8435
8481
|
for (const line of lines) {
|
|
8436
8482
|
try {
|
|
8437
8483
|
const rec = JSON.parse(line);
|
|
@@ -11064,10 +11110,10 @@ async function disposeEmbedder() {
|
|
|
11064
11110
|
async function embedDirect(text) {
|
|
11065
11111
|
const llamaCpp = await import("node-llama-cpp");
|
|
11066
11112
|
const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
11067
|
-
const { existsSync:
|
|
11068
|
-
const
|
|
11069
|
-
const modelPath =
|
|
11070
|
-
if (!
|
|
11113
|
+
const { existsSync: existsSync33 } = await import("fs");
|
|
11114
|
+
const path47 = await import("path");
|
|
11115
|
+
const modelPath = path47.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
|
|
11116
|
+
if (!existsSync33(modelPath)) {
|
|
11071
11117
|
throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
|
|
11072
11118
|
}
|
|
11073
11119
|
const llama = await llamaCpp.getLlama();
|
|
@@ -15482,12 +15528,108 @@ var init_setup_wizard = __esm({
|
|
|
15482
15528
|
}
|
|
15483
15529
|
});
|
|
15484
15530
|
|
|
15531
|
+
// src/lib/update-backup.ts
|
|
15532
|
+
import { copyFile, readFile as readFile6, readdir as readdir3, writeFile as writeFile7, rm, mkdir as mkdir7, cp } from "fs/promises";
|
|
15533
|
+
import { existsSync as existsSync28 } from "fs";
|
|
15534
|
+
import path34 from "path";
|
|
15535
|
+
import os17 from "os";
|
|
15536
|
+
function resolveDataDir2() {
|
|
15537
|
+
if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
|
|
15538
|
+
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
15539
|
+
return path34.join(os17.homedir(), ".exe-os");
|
|
15540
|
+
}
|
|
15541
|
+
async function createUpdateBackup(currentVersion, dataDir) {
|
|
15542
|
+
const dir = dataDir ?? resolveDataDir2();
|
|
15543
|
+
const backupDir = path34.join(dir, BACKUP_DIR_NAME);
|
|
15544
|
+
if (existsSync28(backupDir)) {
|
|
15545
|
+
await rm(backupDir, { recursive: true, force: true });
|
|
15546
|
+
}
|
|
15547
|
+
await mkdir7(backupDir, { recursive: true });
|
|
15548
|
+
const backedUpFiles = [];
|
|
15549
|
+
for (const target of BACKUP_TARGETS) {
|
|
15550
|
+
const src = path34.join(dir, target.name);
|
|
15551
|
+
if (!existsSync28(src)) continue;
|
|
15552
|
+
const dest = path34.join(backupDir, target.name);
|
|
15553
|
+
if (target.type === "file") {
|
|
15554
|
+
await copyFile(src, dest);
|
|
15555
|
+
} else {
|
|
15556
|
+
await cp(src, dest, { recursive: true });
|
|
15557
|
+
}
|
|
15558
|
+
backedUpFiles.push(target.name);
|
|
15559
|
+
}
|
|
15560
|
+
const entries = await readdir3(dir, { withFileTypes: true });
|
|
15561
|
+
for (const entry of entries) {
|
|
15562
|
+
if (entry.isFile() && entry.name.endsWith(".db") && entry.name !== BACKUP_DIR_NAME) {
|
|
15563
|
+
const src = path34.join(dir, entry.name);
|
|
15564
|
+
const dest = path34.join(backupDir, entry.name);
|
|
15565
|
+
await copyFile(src, dest);
|
|
15566
|
+
backedUpFiles.push(entry.name);
|
|
15567
|
+
}
|
|
15568
|
+
}
|
|
15569
|
+
const manifest = {
|
|
15570
|
+
version: currentVersion,
|
|
15571
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
15572
|
+
files: backedUpFiles
|
|
15573
|
+
};
|
|
15574
|
+
await writeFile7(
|
|
15575
|
+
path34.join(backupDir, "manifest.json"),
|
|
15576
|
+
JSON.stringify(manifest, null, 2) + "\n"
|
|
15577
|
+
);
|
|
15578
|
+
return manifest;
|
|
15579
|
+
}
|
|
15580
|
+
async function restoreFromBackup(dataDir) {
|
|
15581
|
+
const dir = dataDir ?? resolveDataDir2();
|
|
15582
|
+
const backupDir = path34.join(dir, BACKUP_DIR_NAME);
|
|
15583
|
+
const manifestPath = path34.join(backupDir, "manifest.json");
|
|
15584
|
+
if (!existsSync28(manifestPath)) {
|
|
15585
|
+
throw new Error(
|
|
15586
|
+
`No backup found at ${backupDir}. Nothing to restore.`
|
|
15587
|
+
);
|
|
15588
|
+
}
|
|
15589
|
+
const manifest = JSON.parse(
|
|
15590
|
+
await readFile6(manifestPath, "utf-8")
|
|
15591
|
+
);
|
|
15592
|
+
for (const fileName of manifest.files) {
|
|
15593
|
+
const src = path34.join(backupDir, fileName);
|
|
15594
|
+
const dest = path34.join(dir, fileName);
|
|
15595
|
+
if (!existsSync28(src)) continue;
|
|
15596
|
+
const stat2 = await import("fs/promises").then((m) => m.stat(src));
|
|
15597
|
+
if (stat2.isDirectory()) {
|
|
15598
|
+
await cp(src, dest, { recursive: true, force: true });
|
|
15599
|
+
} else {
|
|
15600
|
+
await copyFile(src, dest);
|
|
15601
|
+
}
|
|
15602
|
+
}
|
|
15603
|
+
return manifest;
|
|
15604
|
+
}
|
|
15605
|
+
async function deleteBackup(dataDir) {
|
|
15606
|
+
const dir = dataDir ?? resolveDataDir2();
|
|
15607
|
+
const backupDir = path34.join(dir, BACKUP_DIR_NAME);
|
|
15608
|
+
if (existsSync28(backupDir)) {
|
|
15609
|
+
await rm(backupDir, { recursive: true, force: true });
|
|
15610
|
+
}
|
|
15611
|
+
}
|
|
15612
|
+
var BACKUP_DIR_NAME, BACKUP_TARGETS;
|
|
15613
|
+
var init_update_backup = __esm({
|
|
15614
|
+
"src/lib/update-backup.ts"() {
|
|
15615
|
+
"use strict";
|
|
15616
|
+
BACKUP_DIR_NAME = ".update-backup";
|
|
15617
|
+
BACKUP_TARGETS = [
|
|
15618
|
+
{ name: "config.json", type: "file" },
|
|
15619
|
+
{ name: "exe-employees.json", type: "file" },
|
|
15620
|
+
{ name: "master.key", type: "file" },
|
|
15621
|
+
{ name: "identity", type: "dir" }
|
|
15622
|
+
// All .db files (SQLCipher databases) — matched dynamically
|
|
15623
|
+
];
|
|
15624
|
+
}
|
|
15625
|
+
});
|
|
15626
|
+
|
|
15485
15627
|
// src/lib/update-check.ts
|
|
15486
15628
|
import { execSync as execSync11 } from "child_process";
|
|
15487
15629
|
import { readFileSync as readFileSync24 } from "fs";
|
|
15488
|
-
import
|
|
15630
|
+
import path35 from "path";
|
|
15489
15631
|
function getLocalVersion(packageRoot) {
|
|
15490
|
-
const pkgPath =
|
|
15632
|
+
const pkgPath = path35.join(packageRoot, "package.json");
|
|
15491
15633
|
const pkg = JSON.parse(readFileSync24(pkgPath, "utf-8"));
|
|
15492
15634
|
return pkg.version;
|
|
15493
15635
|
}
|
|
@@ -15534,10 +15676,47 @@ __export(update_exports, {
|
|
|
15534
15676
|
});
|
|
15535
15677
|
import { execSync as execSync12 } from "child_process";
|
|
15536
15678
|
import { createInterface as createInterface4 } from "readline";
|
|
15679
|
+
async function runRestore() {
|
|
15680
|
+
console.log("\n\u{1F504} Restoring from update backup...");
|
|
15681
|
+
try {
|
|
15682
|
+
const manifest = await restoreFromBackup();
|
|
15683
|
+
console.log(` Restored ${manifest.files.length} file(s) from v${manifest.version} backup.`);
|
|
15684
|
+
console.log(` Backup was created at ${manifest.timestamp}`);
|
|
15685
|
+
console.log(`
|
|
15686
|
+
\u{1F4E5} Reinstalling @askexenow/exe-os@${manifest.version}...`);
|
|
15687
|
+
try {
|
|
15688
|
+
execSync12(`npm install -g @askexenow/exe-os@${manifest.version}`, {
|
|
15689
|
+
stdio: ["pipe", "pipe", "inherit"],
|
|
15690
|
+
timeout: 3e5
|
|
15691
|
+
});
|
|
15692
|
+
console.log(`
|
|
15693
|
+
\u2705 Restored to v${manifest.version}`);
|
|
15694
|
+
} catch {
|
|
15695
|
+
console.error(`
|
|
15696
|
+
\u26A0\uFE0F Could not reinstall v${manifest.version} via npm.`);
|
|
15697
|
+
console.error(` Your data files have been restored. Try manually:`);
|
|
15698
|
+
console.error(` npm install -g @askexenow/exe-os@${manifest.version}`);
|
|
15699
|
+
}
|
|
15700
|
+
try {
|
|
15701
|
+
await deleteBackup();
|
|
15702
|
+
} catch {
|
|
15703
|
+
}
|
|
15704
|
+
console.log("\n\u{1F680} Restore complete. Restart your sessions.\n");
|
|
15705
|
+
} catch (err) {
|
|
15706
|
+
console.error("\u274C Restore failed.");
|
|
15707
|
+
if (err instanceof Error) console.error(` ${err.message}`);
|
|
15708
|
+
process.exit(1);
|
|
15709
|
+
}
|
|
15710
|
+
}
|
|
15537
15711
|
async function runUpdate(cliArgs) {
|
|
15538
15712
|
const args2 = cliArgs ?? process.argv.slice(2);
|
|
15539
15713
|
const autoMode = args2.includes("--auto") || args2.includes("-y");
|
|
15540
15714
|
const checkOnly = args2.includes("--check");
|
|
15715
|
+
const restoreMode = args2.includes("--restore");
|
|
15716
|
+
if (restoreMode) {
|
|
15717
|
+
await runRestore();
|
|
15718
|
+
return;
|
|
15719
|
+
}
|
|
15541
15720
|
const packageRoot = new URL("../..", import.meta.url).pathname;
|
|
15542
15721
|
const result = checkForUpdate(packageRoot);
|
|
15543
15722
|
if (result.error) {
|
|
@@ -15572,7 +15751,16 @@ async function runUpdate(cliArgs) {
|
|
|
15572
15751
|
console.log("Update skipped.");
|
|
15573
15752
|
process.exit(0);
|
|
15574
15753
|
}
|
|
15575
|
-
console.log("\n\u{
|
|
15754
|
+
console.log("\n\u{1F4BE} Backing up customer data...");
|
|
15755
|
+
try {
|
|
15756
|
+
const backupResult = await createUpdateBackup(result.localVersion);
|
|
15757
|
+
console.log(` Backed up ${backupResult.files.length} file(s) to ${BACKUP_DIR_NAME}/`);
|
|
15758
|
+
} catch (err) {
|
|
15759
|
+
console.error("\u274C Backup failed \u2014 aborting update to protect your data.");
|
|
15760
|
+
if (err instanceof Error) console.error(` ${err.message}`);
|
|
15761
|
+
process.exit(1);
|
|
15762
|
+
}
|
|
15763
|
+
console.log("\u{1F9F9} Clearing npm cache...");
|
|
15576
15764
|
try {
|
|
15577
15765
|
execSync12("npm cache clean --force", { stdio: "pipe" });
|
|
15578
15766
|
console.log(" Done");
|
|
@@ -15587,8 +15775,9 @@ async function runUpdate(cliArgs) {
|
|
|
15587
15775
|
timeout: 3e5
|
|
15588
15776
|
});
|
|
15589
15777
|
} catch (err) {
|
|
15590
|
-
console.error("\n\u274C Update failed.");
|
|
15591
|
-
console.error(
|
|
15778
|
+
console.error("\n\u274C Update failed. Your backup is preserved.");
|
|
15779
|
+
console.error(` Restore with: exe-os update --restore`);
|
|
15780
|
+
console.error(" Or try manually: npm install -g @askexenow/exe-os@latest");
|
|
15592
15781
|
if (err instanceof Error && err.message) {
|
|
15593
15782
|
console.error(` Error: ${err.message.split("\n")[0]}`);
|
|
15594
15783
|
}
|
|
@@ -15607,30 +15796,38 @@ async function runUpdate(cliArgs) {
|
|
|
15607
15796
|
}
|
|
15608
15797
|
}
|
|
15609
15798
|
const remoteVersion = result.remoteVersion;
|
|
15799
|
+
const updateSucceeded = newVersion !== result.localVersion;
|
|
15610
15800
|
if (newVersion === remoteVersion) {
|
|
15611
15801
|
console.log(`
|
|
15612
15802
|
\u2705 Updated to v${newVersion}`);
|
|
15613
|
-
} else if (
|
|
15803
|
+
} else if (updateSucceeded) {
|
|
15614
15804
|
console.log(`
|
|
15615
15805
|
\u2705 Updated to v${newVersion} (latest: v${remoteVersion})`);
|
|
15616
15806
|
} else {
|
|
15617
15807
|
console.log(`
|
|
15618
15808
|
\u26A0\uFE0F Version unchanged (v${newVersion}). npm cache may be stale.`);
|
|
15809
|
+
console.log(" Backup preserved. Restore with: exe-os update --restore");
|
|
15619
15810
|
console.log(" Try: npm cache clean --force && npm install -g @askexenow/exe-os@latest");
|
|
15620
15811
|
}
|
|
15812
|
+
if (updateSucceeded) {
|
|
15813
|
+
try {
|
|
15814
|
+
await deleteBackup();
|
|
15815
|
+
} catch {
|
|
15816
|
+
}
|
|
15817
|
+
}
|
|
15621
15818
|
console.log(" Hooks re-wired, daemon restarted automatically.");
|
|
15622
15819
|
console.log("");
|
|
15623
15820
|
console.log(" \x1B[33m\u26A1 Run /mcp in each active Claude Code session to pick up new tools.\x1B[0m");
|
|
15624
15821
|
console.log(" \x1B[2m(MCP servers can't hot-reload \u2014 Claude Code needs to reconnect them.)\x1B[0m");
|
|
15625
15822
|
try {
|
|
15626
|
-
const { existsSync: exists, readFileSync:
|
|
15823
|
+
const { existsSync: exists, readFileSync: readFile9 } = await import("fs");
|
|
15627
15824
|
const p = await import("path");
|
|
15628
15825
|
const { homedir: home } = await import("os");
|
|
15629
15826
|
const exeDir = p.default.join(home(), ".exe-os");
|
|
15630
15827
|
const licKeyPath = p.default.join(exeDir, "license.key");
|
|
15631
15828
|
const configPath = p.default.join(exeDir, "config.json");
|
|
15632
15829
|
if (!exists(licKeyPath) && exists(configPath)) {
|
|
15633
|
-
const cfg = JSON.parse(
|
|
15830
|
+
const cfg = JSON.parse(readFile9(configPath, "utf8"));
|
|
15634
15831
|
const cloud = cfg.cloud;
|
|
15635
15832
|
if (cloud?.apiKey) {
|
|
15636
15833
|
const { mirrorLicenseKey: mirrorLicenseKey2 } = await Promise.resolve().then(() => (init_license(), license_exports));
|
|
@@ -15646,6 +15843,7 @@ var init_update = __esm({
|
|
|
15646
15843
|
"src/bin/update.ts"() {
|
|
15647
15844
|
"use strict";
|
|
15648
15845
|
init_is_main();
|
|
15846
|
+
init_update_backup();
|
|
15649
15847
|
init_update_check();
|
|
15650
15848
|
init_update_check();
|
|
15651
15849
|
if (isMainModule(import.meta.url) && process.argv[1]?.includes("update")) {
|
|
@@ -20015,8 +20213,8 @@ var init_ErrorOverview = __esm({
|
|
|
20015
20213
|
"use strict";
|
|
20016
20214
|
init_Box();
|
|
20017
20215
|
init_Text();
|
|
20018
|
-
cleanupPath = (
|
|
20019
|
-
return
|
|
20216
|
+
cleanupPath = (path47) => {
|
|
20217
|
+
return path47?.replace(`file://${cwd()}/`, "");
|
|
20020
20218
|
};
|
|
20021
20219
|
stackUtils = new StackUtils({
|
|
20022
20220
|
cwd: cwd(),
|
|
@@ -21434,8 +21632,8 @@ var init_parse_keypress = __esm({
|
|
|
21434
21632
|
57453: "isoLevel3Shift",
|
|
21435
21633
|
57454: "isoLevel5Shift"
|
|
21436
21634
|
};
|
|
21437
|
-
isValidCodepoint = (
|
|
21438
|
-
safeFromCodePoint = (
|
|
21635
|
+
isValidCodepoint = (cp2) => cp2 >= 0 && cp2 <= 1114111 && !(cp2 >= 55296 && cp2 <= 57343);
|
|
21636
|
+
safeFromCodePoint = (cp2) => isValidCodepoint(cp2) ? String.fromCodePoint(cp2) : "?";
|
|
21439
21637
|
parseKittyKeypress = (s) => {
|
|
21440
21638
|
const match = kittyKeyRe.exec(s);
|
|
21441
21639
|
if (!match)
|
|
@@ -21449,7 +21647,7 @@ var init_parse_keypress = __esm({
|
|
|
21449
21647
|
}
|
|
21450
21648
|
let text;
|
|
21451
21649
|
if (textField) {
|
|
21452
|
-
text = textField.split(":").map((
|
|
21650
|
+
text = textField.split(":").map((cp2) => safeFromCodePoint(parseInt(cp2, 10))).join("");
|
|
21453
21651
|
}
|
|
21454
21652
|
let name;
|
|
21455
21653
|
let isPrintable;
|
|
@@ -22424,11 +22622,11 @@ function Footer() {
|
|
|
22424
22622
|
} catch {
|
|
22425
22623
|
}
|
|
22426
22624
|
try {
|
|
22427
|
-
const { existsSync:
|
|
22625
|
+
const { existsSync: existsSync33 } = await import("fs");
|
|
22428
22626
|
const { join } = await import("path");
|
|
22429
22627
|
const home = process.env.HOME ?? "";
|
|
22430
22628
|
const pidPath = join(home, ".exe-os", "exed.pid");
|
|
22431
|
-
setDaemon(
|
|
22629
|
+
setDaemon(existsSync33(pidPath) ? "running" : "stopped");
|
|
22432
22630
|
} catch {
|
|
22433
22631
|
setDaemon("unknown");
|
|
22434
22632
|
}
|
|
@@ -24479,10 +24677,10 @@ var init_hooks = __esm({
|
|
|
24479
24677
|
});
|
|
24480
24678
|
|
|
24481
24679
|
// src/runtime/safety-checks.ts
|
|
24482
|
-
import
|
|
24483
|
-
import
|
|
24680
|
+
import path36 from "path";
|
|
24681
|
+
import os18 from "os";
|
|
24484
24682
|
function checkPathSafety(filePath) {
|
|
24485
|
-
const resolved =
|
|
24683
|
+
const resolved = path36.resolve(filePath);
|
|
24486
24684
|
for (const { pattern, reason } of BYPASS_IMMUNE_PATTERNS) {
|
|
24487
24685
|
const matches = typeof pattern === "function" ? pattern(resolved) : pattern.test(resolved);
|
|
24488
24686
|
if (matches) {
|
|
@@ -24492,7 +24690,7 @@ function checkPathSafety(filePath) {
|
|
|
24492
24690
|
return { safe: true, bypassImmune: true };
|
|
24493
24691
|
}
|
|
24494
24692
|
function checkReadPathSafety(filePath) {
|
|
24495
|
-
const resolved =
|
|
24693
|
+
const resolved = path36.resolve(filePath);
|
|
24496
24694
|
const credPatterns = BYPASS_IMMUNE_PATTERNS.filter(
|
|
24497
24695
|
(p) => typeof p.pattern !== "function" && (p.reason.includes("secrets") || p.reason.includes("Private key") || p.reason.includes("Credential"))
|
|
24498
24696
|
);
|
|
@@ -24507,7 +24705,7 @@ var HOME, BYPASS_IMMUNE_PATTERNS;
|
|
|
24507
24705
|
var init_safety_checks = __esm({
|
|
24508
24706
|
"src/runtime/safety-checks.ts"() {
|
|
24509
24707
|
"use strict";
|
|
24510
|
-
HOME =
|
|
24708
|
+
HOME = os18.homedir();
|
|
24511
24709
|
BYPASS_IMMUNE_PATTERNS = [
|
|
24512
24710
|
{
|
|
24513
24711
|
pattern: /\/\.git\/hooks\//,
|
|
@@ -24518,11 +24716,11 @@ var init_safety_checks = __esm({
|
|
|
24518
24716
|
reason: "Git config can set hooks and command execution"
|
|
24519
24717
|
},
|
|
24520
24718
|
{
|
|
24521
|
-
pattern: (p) => p.startsWith(
|
|
24719
|
+
pattern: (p) => p.startsWith(path36.join(HOME, ".claude")),
|
|
24522
24720
|
reason: "Claude configuration files are protected"
|
|
24523
24721
|
},
|
|
24524
24722
|
{
|
|
24525
|
-
pattern: (p) => p.startsWith(
|
|
24723
|
+
pattern: (p) => p.startsWith(path36.join(HOME, ".exe-os")),
|
|
24526
24724
|
reason: "exe-os configuration files are protected"
|
|
24527
24725
|
},
|
|
24528
24726
|
{
|
|
@@ -24539,7 +24737,7 @@ var init_safety_checks = __esm({
|
|
|
24539
24737
|
},
|
|
24540
24738
|
{
|
|
24541
24739
|
pattern: (p) => {
|
|
24542
|
-
const name =
|
|
24740
|
+
const name = path36.basename(p);
|
|
24543
24741
|
return [".bashrc", ".zshrc", ".profile", ".bash_profile", ".zprofile", ".zshenv"].includes(name);
|
|
24544
24742
|
},
|
|
24545
24743
|
reason: "Shell configuration files can execute arbitrary code on login"
|
|
@@ -24566,7 +24764,7 @@ __export(file_read_exports, {
|
|
|
24566
24764
|
FileReadTool: () => FileReadTool
|
|
24567
24765
|
});
|
|
24568
24766
|
import fs3 from "fs/promises";
|
|
24569
|
-
import
|
|
24767
|
+
import path37 from "path";
|
|
24570
24768
|
import { z } from "zod";
|
|
24571
24769
|
function isBinary(buf) {
|
|
24572
24770
|
for (let i = 0; i < buf.length; i++) {
|
|
@@ -24602,7 +24800,7 @@ var init_file_read = __esm({
|
|
|
24602
24800
|
return { behavior: "allow" };
|
|
24603
24801
|
},
|
|
24604
24802
|
async call(input, context) {
|
|
24605
|
-
const filePath =
|
|
24803
|
+
const filePath = path37.isAbsolute(input.file_path) ? input.file_path : path37.resolve(context.cwd, input.file_path);
|
|
24606
24804
|
let stat2;
|
|
24607
24805
|
try {
|
|
24608
24806
|
stat2 = await fs3.stat(filePath);
|
|
@@ -24642,7 +24840,7 @@ __export(glob_exports, {
|
|
|
24642
24840
|
GlobTool: () => GlobTool
|
|
24643
24841
|
});
|
|
24644
24842
|
import fs4 from "fs/promises";
|
|
24645
|
-
import
|
|
24843
|
+
import path38 from "path";
|
|
24646
24844
|
import { z as z2 } from "zod";
|
|
24647
24845
|
async function walkDir(dir, maxDepth = 10) {
|
|
24648
24846
|
const results = [];
|
|
@@ -24658,7 +24856,7 @@ async function walkDir(dir, maxDepth = 10) {
|
|
|
24658
24856
|
if (entry.isDirectory() && (entry.name === "node_modules" || entry.name === ".git")) {
|
|
24659
24857
|
continue;
|
|
24660
24858
|
}
|
|
24661
|
-
const fullPath =
|
|
24859
|
+
const fullPath = path38.join(current, entry.name);
|
|
24662
24860
|
if (entry.isDirectory()) {
|
|
24663
24861
|
await walk(fullPath, depth + 1);
|
|
24664
24862
|
} else {
|
|
@@ -24692,11 +24890,11 @@ var init_glob = __esm({
|
|
|
24692
24890
|
inputSchema: inputSchema2,
|
|
24693
24891
|
isReadOnly: true,
|
|
24694
24892
|
async call(input, context) {
|
|
24695
|
-
const baseDir = input.path ?
|
|
24893
|
+
const baseDir = input.path ? path38.isAbsolute(input.path) ? input.path : path38.resolve(context.cwd, input.path) : context.cwd;
|
|
24696
24894
|
try {
|
|
24697
24895
|
const entries = await walkDir(baseDir);
|
|
24698
24896
|
const matched = entries.filter(
|
|
24699
|
-
(e) => simpleGlobMatch(
|
|
24897
|
+
(e) => simpleGlobMatch(path38.relative(baseDir, e.path), input.pattern)
|
|
24700
24898
|
);
|
|
24701
24899
|
matched.sort((a, b) => b.mtime - a.mtime);
|
|
24702
24900
|
if (matched.length === 0) {
|
|
@@ -24722,7 +24920,7 @@ __export(grep_exports, {
|
|
|
24722
24920
|
});
|
|
24723
24921
|
import { spawn as spawn2 } from "child_process";
|
|
24724
24922
|
import fs5 from "fs/promises";
|
|
24725
|
-
import
|
|
24923
|
+
import path39 from "path";
|
|
24726
24924
|
import { z as z3 } from "zod";
|
|
24727
24925
|
function runRipgrep(input, searchPath, context) {
|
|
24728
24926
|
return new Promise((resolve, reject) => {
|
|
@@ -24776,7 +24974,7 @@ async function nodeGrep(input, searchPath) {
|
|
|
24776
24974
|
}
|
|
24777
24975
|
for (const entry of entries) {
|
|
24778
24976
|
if (entry.name === "node_modules" || entry.name === ".git") continue;
|
|
24779
|
-
const fullPath =
|
|
24977
|
+
const fullPath = path39.join(dir, entry.name);
|
|
24780
24978
|
if (entry.isDirectory()) {
|
|
24781
24979
|
await walk(fullPath);
|
|
24782
24980
|
} else {
|
|
@@ -24822,7 +25020,7 @@ var init_grep = __esm({
|
|
|
24822
25020
|
inputSchema: inputSchema3,
|
|
24823
25021
|
isReadOnly: true,
|
|
24824
25022
|
async call(input, context) {
|
|
24825
|
-
const searchPath = input.path ?
|
|
25023
|
+
const searchPath = input.path ? path39.isAbsolute(input.path) ? input.path : path39.resolve(context.cwd, input.path) : context.cwd;
|
|
24826
25024
|
try {
|
|
24827
25025
|
const result = await runRipgrep(input, searchPath, context);
|
|
24828
25026
|
return result;
|
|
@@ -24847,7 +25045,7 @@ __export(file_write_exports, {
|
|
|
24847
25045
|
FileWriteTool: () => FileWriteTool
|
|
24848
25046
|
});
|
|
24849
25047
|
import fs6 from "fs/promises";
|
|
24850
|
-
import
|
|
25048
|
+
import path40 from "path";
|
|
24851
25049
|
import { z as z4 } from "zod";
|
|
24852
25050
|
var inputSchema4, FileWriteTool;
|
|
24853
25051
|
var init_file_write = __esm({
|
|
@@ -24875,8 +25073,8 @@ var init_file_write = __esm({
|
|
|
24875
25073
|
return { behavior: "allow" };
|
|
24876
25074
|
},
|
|
24877
25075
|
async call(input, context) {
|
|
24878
|
-
const filePath =
|
|
24879
|
-
const dir =
|
|
25076
|
+
const filePath = path40.isAbsolute(input.file_path) ? input.file_path : path40.resolve(context.cwd, input.file_path);
|
|
25077
|
+
const dir = path40.dirname(filePath);
|
|
24880
25078
|
await fs6.mkdir(dir, { recursive: true });
|
|
24881
25079
|
await fs6.writeFile(filePath, input.content, "utf-8");
|
|
24882
25080
|
return {
|
|
@@ -24894,7 +25092,7 @@ __export(file_edit_exports, {
|
|
|
24894
25092
|
FileEditTool: () => FileEditTool
|
|
24895
25093
|
});
|
|
24896
25094
|
import fs7 from "fs/promises";
|
|
24897
|
-
import
|
|
25095
|
+
import path41 from "path";
|
|
24898
25096
|
import { z as z5 } from "zod";
|
|
24899
25097
|
function countOccurrences(haystack, needle) {
|
|
24900
25098
|
let count = 0;
|
|
@@ -24935,7 +25133,7 @@ var init_file_edit = __esm({
|
|
|
24935
25133
|
return { behavior: "allow" };
|
|
24936
25134
|
},
|
|
24937
25135
|
async call(input, context) {
|
|
24938
|
-
const filePath =
|
|
25136
|
+
const filePath = path41.isAbsolute(input.file_path) ? input.file_path : path41.resolve(context.cwd, input.file_path);
|
|
24939
25137
|
let content;
|
|
24940
25138
|
try {
|
|
24941
25139
|
content = await fs7.readFile(filePath, "utf-8");
|
|
@@ -25177,7 +25375,7 @@ var init_bash = __esm({
|
|
|
25177
25375
|
// src/tui/views/CommandCenter.tsx
|
|
25178
25376
|
import { useState as useState6, useEffect as useEffect8, useMemo as useMemo4, useCallback as useCallback4, useRef as useRef4 } from "react";
|
|
25179
25377
|
import TextInput from "ink-text-input";
|
|
25180
|
-
import
|
|
25378
|
+
import path42 from "path";
|
|
25181
25379
|
import { homedir as homedir6 } from "os";
|
|
25182
25380
|
import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
25183
25381
|
function CommandCenterView({
|
|
@@ -25212,13 +25410,13 @@ function CommandCenterView({
|
|
|
25212
25410
|
const { createPermissionsFromPreset: createPermissionsFromPreset2, EMPLOYEE_PERMISSIONS: EMPLOYEE_PERMISSIONS2 } = await Promise.resolve().then(() => (init_permissions(), permissions_exports));
|
|
25213
25411
|
const { getPresetByRole: getPresetByRole2 } = await Promise.resolve().then(() => (init_permission_presets(), permission_presets_exports));
|
|
25214
25412
|
const { createDefaultHooks: createDefaultHooks2 } = await Promise.resolve().then(() => (init_hooks(), hooks_exports));
|
|
25215
|
-
const { readFileSync: readFileSync28, existsSync:
|
|
25413
|
+
const { readFileSync: readFileSync28, existsSync: existsSync33 } = await import("fs");
|
|
25216
25414
|
const { join } = await import("path");
|
|
25217
25415
|
const { homedir: homedir8 } = await import("os");
|
|
25218
25416
|
const configPath = join(homedir8(), ".exe-os", "config.json");
|
|
25219
25417
|
let failoverChain = ["anthropic", "opencode", "gemini", "openai"];
|
|
25220
25418
|
let providerConfigs = {};
|
|
25221
|
-
if (
|
|
25419
|
+
if (existsSync33(configPath)) {
|
|
25222
25420
|
try {
|
|
25223
25421
|
const raw = JSON.parse(readFileSync28(configPath, "utf8"));
|
|
25224
25422
|
if (Array.isArray(raw.failoverChain)) failoverChain = raw.failoverChain;
|
|
@@ -25426,7 +25624,7 @@ function CommandCenterView({
|
|
|
25426
25624
|
const demoEntries = DEMO_PROJECTS.map((p) => ({
|
|
25427
25625
|
projectName: p.projectName,
|
|
25428
25626
|
exeSession: p.exeSession,
|
|
25429
|
-
projectDir:
|
|
25627
|
+
projectDir: path42.join(homedir6(), p.projectName),
|
|
25430
25628
|
employeeCount: p.employees.length,
|
|
25431
25629
|
activeCount: p.employees.filter((e) => e.status === "active").length,
|
|
25432
25630
|
memoryCount: p.employees.length * 4e3,
|
|
@@ -25464,7 +25662,7 @@ function CommandCenterView({
|
|
|
25464
25662
|
const { listSessions: listSessions2 } = await Promise.resolve().then(() => (init_session_registry(), session_registry_exports));
|
|
25465
25663
|
const { listTmuxSessions: listTmuxSessions2, inTmux: inTmux2 } = await Promise.resolve().then(() => (init_tmux_status(), tmux_status_exports));
|
|
25466
25664
|
const { loadEmployees: loadEmployees2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
25467
|
-
const { existsSync:
|
|
25665
|
+
const { existsSync: existsSync33 } = await import("fs");
|
|
25468
25666
|
const { join } = await import("path");
|
|
25469
25667
|
const client = getClient2();
|
|
25470
25668
|
if (!client) {
|
|
@@ -25535,7 +25733,7 @@ function CommandCenterView({
|
|
|
25535
25733
|
}
|
|
25536
25734
|
const memoryCount = memoryCounts.get(name) ?? 0;
|
|
25537
25735
|
const openTaskCount = openTaskCounts.get(name) ?? 0;
|
|
25538
|
-
const hasGit = projectDir ?
|
|
25736
|
+
const hasGit = projectDir ? existsSync33(join(projectDir, ".git")) : false;
|
|
25539
25737
|
const type = hasGit ? "code" : memoryCount > 0 ? "code" : "automation";
|
|
25540
25738
|
projectList.push({
|
|
25541
25739
|
projectName: name,
|
|
@@ -25560,7 +25758,7 @@ function CommandCenterView({
|
|
|
25560
25758
|
setHealth((h) => ({ ...h, memories: Number(totalResult.rows[0]?.cnt ?? 0) }));
|
|
25561
25759
|
try {
|
|
25562
25760
|
const pidPath = join(process.env.HOME ?? "", ".exe-os", "exed.pid");
|
|
25563
|
-
setHealth((h) => ({ ...h, daemon:
|
|
25761
|
+
setHealth((h) => ({ ...h, daemon: existsSync33(pidPath) ? "running" : "stopped" }));
|
|
25564
25762
|
} catch {
|
|
25565
25763
|
}
|
|
25566
25764
|
const activityResult = await client.execute(
|
|
@@ -26430,7 +26628,7 @@ var init_useOrchestrator = __esm({
|
|
|
26430
26628
|
|
|
26431
26629
|
// src/tui/views/Sessions.tsx
|
|
26432
26630
|
import React19, { useState as useState9, useEffect as useEffect11, useCallback as useCallback6 } from "react";
|
|
26433
|
-
import
|
|
26631
|
+
import path43 from "path";
|
|
26434
26632
|
import { homedir as homedir7 } from "os";
|
|
26435
26633
|
import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
26436
26634
|
function isCoordinatorEntry(entry) {
|
|
@@ -26468,7 +26666,7 @@ function SessionsView({
|
|
|
26468
26666
|
if (demo) {
|
|
26469
26667
|
setProjects(DEMO_PROJECTS.map((p) => ({
|
|
26470
26668
|
...p,
|
|
26471
|
-
projectDir:
|
|
26669
|
+
projectDir: path43.join(homedir7(), p.projectName),
|
|
26472
26670
|
employees: p.employees.map((e) => ({ ...e, attached: e.status === "active" }))
|
|
26473
26671
|
})));
|
|
26474
26672
|
return;
|
|
@@ -27683,11 +27881,11 @@ async function loadGatewayConfig() {
|
|
|
27683
27881
|
state.running = false;
|
|
27684
27882
|
}
|
|
27685
27883
|
try {
|
|
27686
|
-
const { existsSync:
|
|
27884
|
+
const { existsSync: existsSync33, readFileSync: readFileSync28 } = await import("fs");
|
|
27687
27885
|
const { join } = await import("path");
|
|
27688
27886
|
const home = process.env.HOME ?? "";
|
|
27689
27887
|
const configPath = join(home, ".exe-os", "gateway.json");
|
|
27690
|
-
if (
|
|
27888
|
+
if (existsSync33(configPath)) {
|
|
27691
27889
|
const raw = JSON.parse(readFileSync28(configPath, "utf8"));
|
|
27692
27890
|
state.port = raw.port ?? 3100;
|
|
27693
27891
|
state.gatewayUrl = raw.gatewayUrl ?? "";
|
|
@@ -28286,11 +28484,11 @@ function TeamView({ onBack, onViewSessions }) {
|
|
|
28286
28484
|
setMembers(teamData);
|
|
28287
28485
|
setDbError(null);
|
|
28288
28486
|
try {
|
|
28289
|
-
const { existsSync:
|
|
28487
|
+
const { existsSync: existsSync33, readFileSync: readFileSync28 } = await import("fs");
|
|
28290
28488
|
const { join } = await import("path");
|
|
28291
28489
|
const home = process.env.HOME ?? "";
|
|
28292
28490
|
const gatewayConfig = join(home, ".exe-os", "gateway.json");
|
|
28293
|
-
if (
|
|
28491
|
+
if (existsSync33(gatewayConfig)) {
|
|
28294
28492
|
const raw = JSON.parse(readFileSync28(gatewayConfig, "utf8"));
|
|
28295
28493
|
if (raw.agents && raw.agents.length > 0) {
|
|
28296
28494
|
setExternals(raw.agents.map((a) => ({
|
|
@@ -28471,8 +28669,8 @@ __export(wiki_client_exports, {
|
|
|
28471
28669
|
listDocuments: () => listDocuments,
|
|
28472
28670
|
listWorkspaces: () => listWorkspaces
|
|
28473
28671
|
});
|
|
28474
|
-
async function wikiFetch(config,
|
|
28475
|
-
const url = `${config.baseUrl}/api/v1${
|
|
28672
|
+
async function wikiFetch(config, path47, method = "GET", body) {
|
|
28673
|
+
const url = `${config.baseUrl}/api/v1${path47}`;
|
|
28476
28674
|
const headers = {
|
|
28477
28675
|
Authorization: `Bearer ${config.apiKey}`,
|
|
28478
28676
|
"Content-Type": "application/json"
|
|
@@ -28505,7 +28703,7 @@ async function wikiFetch(config, path46, method = "GET", body) {
|
|
|
28505
28703
|
}
|
|
28506
28704
|
}
|
|
28507
28705
|
if (!response.ok) {
|
|
28508
|
-
throw new Error(`Wiki API ${method} ${
|
|
28706
|
+
throw new Error(`Wiki API ${method} ${path47}: ${response.status} ${response.statusText}`);
|
|
28509
28707
|
}
|
|
28510
28708
|
return response.json();
|
|
28511
28709
|
} finally {
|
|
@@ -29099,12 +29297,12 @@ function SettingsView({ onBack }) {
|
|
|
29099
29297
|
}
|
|
29100
29298
|
setProviders(providerList);
|
|
29101
29299
|
try {
|
|
29102
|
-
const { existsSync:
|
|
29300
|
+
const { existsSync: existsSync33 } = await import("fs");
|
|
29103
29301
|
const { join } = await import("path");
|
|
29104
29302
|
const { loadConfig: loadConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
29105
29303
|
const cfg = await loadConfig2();
|
|
29106
29304
|
const home = process.env.HOME ?? "";
|
|
29107
|
-
const hasKey =
|
|
29305
|
+
const hasKey = existsSync33(join(home, ".exe-os", "master.key"));
|
|
29108
29306
|
if (cfg.cloud) {
|
|
29109
29307
|
setCloud({
|
|
29110
29308
|
configured: true,
|
|
@@ -29117,7 +29315,7 @@ function SettingsView({ onBack }) {
|
|
|
29117
29315
|
const pidPath = join(home, ".exe-os", "exed.pid");
|
|
29118
29316
|
let daemon = "unknown";
|
|
29119
29317
|
try {
|
|
29120
|
-
daemon =
|
|
29318
|
+
daemon = existsSync33(pidPath) ? "running" : "stopped";
|
|
29121
29319
|
} catch {
|
|
29122
29320
|
}
|
|
29123
29321
|
let version = "unknown";
|
|
@@ -29932,18 +30130,18 @@ __export(installer_exports2, {
|
|
|
29932
30130
|
runOpenCodeInstaller: () => runOpenCodeInstaller,
|
|
29933
30131
|
verifyOpenCodeHooks: () => verifyOpenCodeHooks
|
|
29934
30132
|
});
|
|
29935
|
-
import { readFile as
|
|
29936
|
-
import { existsSync as
|
|
29937
|
-
import
|
|
29938
|
-
import
|
|
29939
|
-
async function registerOpenCodeMcp(packageRoot, homeDir =
|
|
29940
|
-
const configDir =
|
|
29941
|
-
const configPath =
|
|
29942
|
-
await
|
|
30133
|
+
import { readFile as readFile7, writeFile as writeFile8, mkdir as mkdir8 } from "fs/promises";
|
|
30134
|
+
import { existsSync as existsSync30, readFileSync as readFileSync26 } from "fs";
|
|
30135
|
+
import path44 from "path";
|
|
30136
|
+
import os19 from "os";
|
|
30137
|
+
async function registerOpenCodeMcp(packageRoot, homeDir = os19.homedir()) {
|
|
30138
|
+
const configDir = path44.join(homeDir, ".config", "opencode");
|
|
30139
|
+
const configPath = path44.join(configDir, "opencode.json");
|
|
30140
|
+
await mkdir8(configDir, { recursive: true });
|
|
29943
30141
|
let config = {};
|
|
29944
|
-
if (
|
|
30142
|
+
if (existsSync30(configPath)) {
|
|
29945
30143
|
try {
|
|
29946
|
-
config = JSON.parse(await
|
|
30144
|
+
config = JSON.parse(await readFile7(configPath, "utf-8"));
|
|
29947
30145
|
} catch {
|
|
29948
30146
|
config = {};
|
|
29949
30147
|
}
|
|
@@ -29953,7 +30151,7 @@ async function registerOpenCodeMcp(packageRoot, homeDir = os18.homedir()) {
|
|
|
29953
30151
|
}
|
|
29954
30152
|
const newEntry = {
|
|
29955
30153
|
type: "local",
|
|
29956
|
-
command: ["node",
|
|
30154
|
+
command: ["node", path44.join(packageRoot, "dist", "mcp", "server.js")],
|
|
29957
30155
|
enabled: true
|
|
29958
30156
|
};
|
|
29959
30157
|
const current = config.mcp["exe-os"];
|
|
@@ -29964,37 +30162,37 @@ async function registerOpenCodeMcp(packageRoot, homeDir = os18.homedir()) {
|
|
|
29964
30162
|
if (!config.$schema) {
|
|
29965
30163
|
config.$schema = "https://opencode.ai/config.json";
|
|
29966
30164
|
}
|
|
29967
|
-
await
|
|
30165
|
+
await writeFile8(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
29968
30166
|
return true;
|
|
29969
30167
|
}
|
|
29970
|
-
async function installOpenCodePlugin(packageRoot, homeDir =
|
|
29971
|
-
const pluginDir =
|
|
29972
|
-
const pluginPath =
|
|
29973
|
-
await
|
|
30168
|
+
async function installOpenCodePlugin(packageRoot, homeDir = os19.homedir()) {
|
|
30169
|
+
const pluginDir = path44.join(homeDir, ".config", "opencode", "plugins");
|
|
30170
|
+
const pluginPath = path44.join(pluginDir, "exe-os.mjs");
|
|
30171
|
+
await mkdir8(pluginDir, { recursive: true });
|
|
29974
30172
|
const pluginContent = PLUGIN_TEMPLATE.replace(
|
|
29975
30173
|
/__PACKAGE_ROOT__/g,
|
|
29976
30174
|
packageRoot.replace(/\\/g, "\\\\")
|
|
29977
30175
|
);
|
|
29978
|
-
if (
|
|
29979
|
-
const existing = await
|
|
30176
|
+
if (existsSync30(pluginPath)) {
|
|
30177
|
+
const existing = await readFile7(pluginPath, "utf-8");
|
|
29980
30178
|
if (existing === pluginContent) {
|
|
29981
30179
|
return false;
|
|
29982
30180
|
}
|
|
29983
30181
|
}
|
|
29984
|
-
await
|
|
30182
|
+
await writeFile8(pluginPath, pluginContent);
|
|
29985
30183
|
return true;
|
|
29986
30184
|
}
|
|
29987
|
-
function verifyOpenCodeHooks(homeDir =
|
|
29988
|
-
const configPath =
|
|
29989
|
-
const pluginPath =
|
|
29990
|
-
if (!
|
|
30185
|
+
function verifyOpenCodeHooks(homeDir = os19.homedir()) {
|
|
30186
|
+
const configPath = path44.join(homeDir, ".config", "opencode", "opencode.json");
|
|
30187
|
+
const pluginPath = path44.join(homeDir, ".config", "opencode", "plugins", "exe-os.mjs");
|
|
30188
|
+
if (!existsSync30(configPath)) return false;
|
|
29991
30189
|
try {
|
|
29992
30190
|
const config = JSON.parse(readFileSync26(configPath, "utf-8"));
|
|
29993
30191
|
if (!config.mcp?.["exe-os"]?.enabled) return false;
|
|
29994
30192
|
} catch {
|
|
29995
30193
|
return false;
|
|
29996
30194
|
}
|
|
29997
|
-
if (!
|
|
30195
|
+
if (!existsSync30(pluginPath)) return false;
|
|
29998
30196
|
return true;
|
|
29999
30197
|
}
|
|
30000
30198
|
async function runOpenCodeInstaller(homeDir) {
|
|
@@ -30023,25 +30221,26 @@ var installer_exports3 = {};
|
|
|
30023
30221
|
__export(installer_exports3, {
|
|
30024
30222
|
installCodexStatusLine: () => installCodexStatusLine,
|
|
30025
30223
|
mergeCodexHooks: () => mergeCodexHooks,
|
|
30224
|
+
registerCodexMcpServer: () => registerCodexMcpServer,
|
|
30026
30225
|
runCodexInstaller: () => runCodexInstaller,
|
|
30027
30226
|
verifyCodexHooks: () => verifyCodexHooks
|
|
30028
30227
|
});
|
|
30029
|
-
import { readFile as
|
|
30030
|
-
import { existsSync as
|
|
30031
|
-
import
|
|
30032
|
-
import
|
|
30033
|
-
async function mergeCodexHooks(packageRoot, homeDir =
|
|
30034
|
-
const codexDir =
|
|
30035
|
-
const hooksPath =
|
|
30036
|
-
const logsDir =
|
|
30037
|
-
const hookLogPath =
|
|
30228
|
+
import { readFile as readFile8, writeFile as writeFile9, mkdir as mkdir9 } from "fs/promises";
|
|
30229
|
+
import { existsSync as existsSync31 } from "fs";
|
|
30230
|
+
import path45 from "path";
|
|
30231
|
+
import os20 from "os";
|
|
30232
|
+
async function mergeCodexHooks(packageRoot, homeDir = os20.homedir()) {
|
|
30233
|
+
const codexDir = path45.join(homeDir, ".codex");
|
|
30234
|
+
const hooksPath = path45.join(codexDir, "hooks.json");
|
|
30235
|
+
const logsDir = path45.join(homeDir, ".exe-os", "logs");
|
|
30236
|
+
const hookLogPath = path45.join(logsDir, "hooks.log");
|
|
30038
30237
|
const logSuffix = ` 2>> "${hookLogPath}"`;
|
|
30039
|
-
await
|
|
30040
|
-
await
|
|
30238
|
+
await mkdir9(codexDir, { recursive: true });
|
|
30239
|
+
await mkdir9(logsDir, { recursive: true });
|
|
30041
30240
|
let hooksJson = {};
|
|
30042
|
-
if (
|
|
30241
|
+
if (existsSync31(hooksPath)) {
|
|
30043
30242
|
try {
|
|
30044
|
-
hooksJson = JSON.parse(await
|
|
30243
|
+
hooksJson = JSON.parse(await readFile8(hooksPath, "utf-8"));
|
|
30045
30244
|
} catch {
|
|
30046
30245
|
hooksJson = {};
|
|
30047
30246
|
}
|
|
@@ -30056,7 +30255,7 @@ async function mergeCodexHooks(packageRoot, homeDir = os19.homedir()) {
|
|
|
30056
30255
|
hooks: [
|
|
30057
30256
|
{
|
|
30058
30257
|
type: "command",
|
|
30059
|
-
command: `node "${
|
|
30258
|
+
command: `node "${path45.join(packageRoot, "dist", "hooks", "session-start.js")}"${logSuffix}`,
|
|
30060
30259
|
timeout: 30,
|
|
30061
30260
|
statusMessage: "exe-os: loading memory brief"
|
|
30062
30261
|
}
|
|
@@ -30071,11 +30270,11 @@ async function mergeCodexHooks(packageRoot, homeDir = os19.homedir()) {
|
|
|
30071
30270
|
hooks: [
|
|
30072
30271
|
{
|
|
30073
30272
|
type: "command",
|
|
30074
|
-
command: `node "${
|
|
30273
|
+
command: `node "${path45.join(packageRoot, "dist", "hooks", "ingest.js")}"${logSuffix}`
|
|
30075
30274
|
},
|
|
30076
30275
|
{
|
|
30077
30276
|
type: "command",
|
|
30078
|
-
command: `node "${
|
|
30277
|
+
command: `node "${path45.join(packageRoot, "dist", "hooks", "error-recall.js")}"${logSuffix}`
|
|
30079
30278
|
}
|
|
30080
30279
|
]
|
|
30081
30280
|
},
|
|
@@ -30087,11 +30286,11 @@ async function mergeCodexHooks(packageRoot, homeDir = os19.homedir()) {
|
|
|
30087
30286
|
hooks: [
|
|
30088
30287
|
{
|
|
30089
30288
|
type: "command",
|
|
30090
|
-
command: `node "${
|
|
30289
|
+
command: `node "${path45.join(packageRoot, "dist", "hooks", "prompt-submit.js")}"${logSuffix}`
|
|
30091
30290
|
},
|
|
30092
30291
|
{
|
|
30093
30292
|
type: "command",
|
|
30094
|
-
command: `node "${
|
|
30293
|
+
command: `node "${path45.join(packageRoot, "dist", "hooks", "exe-heartbeat-hook.js")}"${logSuffix}`,
|
|
30095
30294
|
timeout: 5
|
|
30096
30295
|
}
|
|
30097
30296
|
]
|
|
@@ -30104,7 +30303,7 @@ async function mergeCodexHooks(packageRoot, homeDir = os19.homedir()) {
|
|
|
30104
30303
|
hooks: [
|
|
30105
30304
|
{
|
|
30106
30305
|
type: "command",
|
|
30107
|
-
command: `node "${
|
|
30306
|
+
command: `node "${path45.join(packageRoot, "dist", "hooks", "stop.js")}"${logSuffix}`
|
|
30108
30307
|
}
|
|
30109
30308
|
]
|
|
30110
30309
|
},
|
|
@@ -30117,7 +30316,7 @@ async function mergeCodexHooks(packageRoot, homeDir = os19.homedir()) {
|
|
|
30117
30316
|
hooks: [
|
|
30118
30317
|
{
|
|
30119
30318
|
type: "command",
|
|
30120
|
-
command: `node "${
|
|
30319
|
+
command: `node "${path45.join(packageRoot, "dist", "hooks", "pre-tool-use.js")}"${logSuffix}`
|
|
30121
30320
|
}
|
|
30122
30321
|
]
|
|
30123
30322
|
},
|
|
@@ -30145,12 +30344,12 @@ async function mergeCodexHooks(packageRoot, homeDir = os19.homedir()) {
|
|
|
30145
30344
|
added++;
|
|
30146
30345
|
}
|
|
30147
30346
|
}
|
|
30148
|
-
await
|
|
30347
|
+
await writeFile9(hooksPath, JSON.stringify(hooksJson, null, 2) + "\n");
|
|
30149
30348
|
return { added, skipped };
|
|
30150
30349
|
}
|
|
30151
|
-
function verifyCodexHooks(homeDir =
|
|
30152
|
-
const hooksPath =
|
|
30153
|
-
if (!
|
|
30350
|
+
function verifyCodexHooks(homeDir = os20.homedir()) {
|
|
30351
|
+
const hooksPath = path45.join(homeDir, ".codex", "hooks.json");
|
|
30352
|
+
if (!existsSync31(hooksPath)) return false;
|
|
30154
30353
|
try {
|
|
30155
30354
|
const hooksJson = JSON.parse(
|
|
30156
30355
|
__require("fs").readFileSync(hooksPath, "utf-8")
|
|
@@ -30170,15 +30369,15 @@ function verifyCodexHooks(homeDir = os19.homedir()) {
|
|
|
30170
30369
|
return false;
|
|
30171
30370
|
}
|
|
30172
30371
|
}
|
|
30173
|
-
async function installCodexStatusLine(homeDir =
|
|
30372
|
+
async function installCodexStatusLine(homeDir = os20.homedir()) {
|
|
30174
30373
|
const prefs = loadPreferences(homeDir);
|
|
30175
30374
|
if (prefs.codexStatusLine === false) return "opted-out";
|
|
30176
|
-
const codexDir =
|
|
30177
|
-
const configPath =
|
|
30178
|
-
await
|
|
30375
|
+
const codexDir = path45.join(homeDir, ".codex");
|
|
30376
|
+
const configPath = path45.join(codexDir, "config.toml");
|
|
30377
|
+
await mkdir9(codexDir, { recursive: true });
|
|
30179
30378
|
let content = "";
|
|
30180
|
-
if (
|
|
30181
|
-
content = await
|
|
30379
|
+
if (existsSync31(configPath)) {
|
|
30380
|
+
content = await readFile8(configPath, "utf-8");
|
|
30182
30381
|
if (/\[tui\][\s\S]*?status_line\s*=/.test(content)) {
|
|
30183
30382
|
return "already-configured";
|
|
30184
30383
|
}
|
|
@@ -30191,14 +30390,55 @@ status_line = [${DEFAULT_CODEX_STATUS_LINE.map((s) => `"${s}"`).join(", ")}]`;
|
|
|
30191
30390
|
const separator = content.length > 0 && !content.endsWith("\n") ? "\n\n" : content.length > 0 ? "\n" : "";
|
|
30192
30391
|
content = content + separator + statusLineToml + "\n";
|
|
30193
30392
|
}
|
|
30194
|
-
await
|
|
30393
|
+
await writeFile9(configPath, content);
|
|
30195
30394
|
return "installed";
|
|
30196
30395
|
}
|
|
30396
|
+
async function registerCodexMcpServer(packageRoot, homeDir = os20.homedir()) {
|
|
30397
|
+
const codexDir = path45.join(homeDir, ".codex");
|
|
30398
|
+
const configPath = path45.join(codexDir, "config.toml");
|
|
30399
|
+
const serverJsPath = path45.join(packageRoot, "dist", "mcp", "server.js");
|
|
30400
|
+
await mkdir9(codexDir, { recursive: true });
|
|
30401
|
+
let content = "";
|
|
30402
|
+
if (existsSync31(configPath)) {
|
|
30403
|
+
content = await readFile8(configPath, "utf-8");
|
|
30404
|
+
}
|
|
30405
|
+
const sectionHeader = "[mcp_servers.exe-os]";
|
|
30406
|
+
const headerIndex = content.indexOf(sectionHeader);
|
|
30407
|
+
if (headerIndex !== -1) {
|
|
30408
|
+
const afterHeader = content.slice(headerIndex + sectionHeader.length);
|
|
30409
|
+
const nextSectionMatch = afterHeader.match(/\n\[(?!mcp_servers\.exe-os)/);
|
|
30410
|
+
const sectionEnd = nextSectionMatch ? headerIndex + sectionHeader.length + nextSectionMatch.index : content.length;
|
|
30411
|
+
const sectionContent = content.slice(headerIndex, sectionEnd);
|
|
30412
|
+
if (sectionContent.includes(serverJsPath)) {
|
|
30413
|
+
return "already-registered";
|
|
30414
|
+
}
|
|
30415
|
+
const newSection2 = `${sectionHeader}
|
|
30416
|
+
command = "node"
|
|
30417
|
+
args = ["${serverJsPath}"]
|
|
30418
|
+
`;
|
|
30419
|
+
content = content.slice(0, headerIndex) + newSection2 + content.slice(sectionEnd);
|
|
30420
|
+
await writeFile9(configPath, content);
|
|
30421
|
+
return "updated";
|
|
30422
|
+
}
|
|
30423
|
+
const newSection = `[mcp_servers.exe-os]
|
|
30424
|
+
command = "node"
|
|
30425
|
+
args = ["${serverJsPath}"]
|
|
30426
|
+
`;
|
|
30427
|
+
const separator = content.length > 0 && !content.endsWith("\n") ? "\n\n" : content.length > 0 ? "\n" : "";
|
|
30428
|
+
content = content + separator + newSection;
|
|
30429
|
+
await writeFile9(configPath, content);
|
|
30430
|
+
return "registered";
|
|
30431
|
+
}
|
|
30197
30432
|
async function runCodexInstaller(homeDir) {
|
|
30198
30433
|
const packageRoot = resolvePackageRoot();
|
|
30199
30434
|
const result = await mergeCodexHooks(packageRoot, homeDir);
|
|
30200
30435
|
process.stderr.write(
|
|
30201
30436
|
`[exe-os] Codex hooks: ${result.added} added, ${result.skipped} unchanged
|
|
30437
|
+
`
|
|
30438
|
+
);
|
|
30439
|
+
const mcpResult = await registerCodexMcpServer(packageRoot, homeDir);
|
|
30440
|
+
process.stderr.write(
|
|
30441
|
+
`[exe-os] Codex MCP server: ${mcpResult}
|
|
30202
30442
|
`
|
|
30203
30443
|
);
|
|
30204
30444
|
const statusResult = await installCodexStatusLine(homeDir);
|
|
@@ -30225,13 +30465,13 @@ var init_installer3 = __esm({
|
|
|
30225
30465
|
});
|
|
30226
30466
|
|
|
30227
30467
|
// src/bin/cli.ts
|
|
30228
|
-
import { existsSync as
|
|
30229
|
-
import
|
|
30230
|
-
import
|
|
30468
|
+
import { existsSync as existsSync32, readFileSync as readFileSync27, writeFileSync as writeFileSync20, readdirSync as readdirSync9, rmSync } from "fs";
|
|
30469
|
+
import path46 from "path";
|
|
30470
|
+
import os21 from "os";
|
|
30231
30471
|
var args = process.argv.slice(2);
|
|
30232
30472
|
if (args.includes("--version") || args.includes("-v")) {
|
|
30233
30473
|
try {
|
|
30234
|
-
const pkgPath =
|
|
30474
|
+
const pkgPath = path46.join(path46.dirname(new URL(import.meta.url).pathname), "..", "..", "package.json");
|
|
30235
30475
|
const pkg = JSON.parse(readFileSync27(pkgPath, "utf8"));
|
|
30236
30476
|
console.log(pkg.version);
|
|
30237
30477
|
} catch {
|
|
@@ -30396,9 +30636,9 @@ ID: ${result.id}`);
|
|
|
30396
30636
|
});
|
|
30397
30637
|
await init_App2().then(() => App_exports);
|
|
30398
30638
|
} else {
|
|
30399
|
-
const claudeDir =
|
|
30400
|
-
const settingsPath =
|
|
30401
|
-
const hasClaudeCode =
|
|
30639
|
+
const claudeDir = path46.join(os21.homedir(), ".claude");
|
|
30640
|
+
const settingsPath = path46.join(claudeDir, "settings.json");
|
|
30641
|
+
const hasClaudeCode = existsSync32(settingsPath) && (() => {
|
|
30402
30642
|
try {
|
|
30403
30643
|
const raw = readFileSync27(settingsPath, "utf8");
|
|
30404
30644
|
return raw.includes("exe-os") || raw.includes("exe-mem");
|
|
@@ -30410,8 +30650,8 @@ ID: ${result.id}`);
|
|
|
30410
30650
|
const { DEFAULT_COORDINATOR_TEMPLATE_NAME: DEFAULT_COORDINATOR_TEMPLATE_NAME2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
30411
30651
|
let cooName = DEFAULT_COORDINATOR_TEMPLATE_NAME2;
|
|
30412
30652
|
try {
|
|
30413
|
-
const rosterPath =
|
|
30414
|
-
if (
|
|
30653
|
+
const rosterPath = path46.join(os21.homedir(), ".exe-os", "exe-employees.json");
|
|
30654
|
+
if (existsSync32(rosterPath)) {
|
|
30415
30655
|
const roster = JSON.parse(readFileSync27(rosterPath, "utf8"));
|
|
30416
30656
|
const coo = roster.find((e) => e.role === "COO");
|
|
30417
30657
|
if (coo) cooName = coo.name;
|
|
@@ -30476,11 +30716,11 @@ async function runCodexInstall() {
|
|
|
30476
30716
|
}
|
|
30477
30717
|
}
|
|
30478
30718
|
async function runClaudeCheck() {
|
|
30479
|
-
const claudeDir =
|
|
30480
|
-
const settingsPath =
|
|
30481
|
-
const claudeJsonPath =
|
|
30719
|
+
const claudeDir = path46.join(os21.homedir(), ".claude");
|
|
30720
|
+
const settingsPath = path46.join(claudeDir, "settings.json");
|
|
30721
|
+
const claudeJsonPath = path46.join(os21.homedir(), ".claude.json");
|
|
30482
30722
|
let ok = true;
|
|
30483
|
-
if (
|
|
30723
|
+
if (existsSync32(settingsPath)) {
|
|
30484
30724
|
let settings;
|
|
30485
30725
|
try {
|
|
30486
30726
|
settings = JSON.parse(readFileSync27(settingsPath, "utf8"));
|
|
@@ -30509,7 +30749,7 @@ async function runClaudeCheck() {
|
|
|
30509
30749
|
console.log("\x1B[31m\u2717\x1B[0m settings.json not found");
|
|
30510
30750
|
ok = false;
|
|
30511
30751
|
}
|
|
30512
|
-
if (
|
|
30752
|
+
if (existsSync32(claudeJsonPath)) {
|
|
30513
30753
|
let claudeJson;
|
|
30514
30754
|
try {
|
|
30515
30755
|
claudeJson = JSON.parse(readFileSync27(claudeJsonPath, "utf8"));
|
|
@@ -30531,8 +30771,8 @@ async function runClaudeCheck() {
|
|
|
30531
30771
|
console.log("\x1B[31m\u2717\x1B[0m claude.json not found");
|
|
30532
30772
|
ok = false;
|
|
30533
30773
|
}
|
|
30534
|
-
const skillsDir =
|
|
30535
|
-
if (
|
|
30774
|
+
const skillsDir = path46.join(claudeDir, "skills");
|
|
30775
|
+
if (existsSync32(skillsDir)) {
|
|
30536
30776
|
console.log("\x1B[32m\u2713\x1B[0m Slash skills directory exists");
|
|
30537
30777
|
} else {
|
|
30538
30778
|
console.log("\x1B[31m\u2717\x1B[0m Slash skills directory missing");
|
|
@@ -30548,15 +30788,15 @@ async function runClaudeCheck() {
|
|
|
30548
30788
|
async function runClaudeUninstall(flags = []) {
|
|
30549
30789
|
const dryRun = flags.includes("--dry-run");
|
|
30550
30790
|
const purge = flags.includes("--purge");
|
|
30551
|
-
const homeDir =
|
|
30552
|
-
const claudeDir =
|
|
30553
|
-
const settingsPath =
|
|
30554
|
-
const claudeJsonPath =
|
|
30555
|
-
const exeOsDir =
|
|
30791
|
+
const homeDir = os21.homedir();
|
|
30792
|
+
const claudeDir = path46.join(homeDir, ".claude");
|
|
30793
|
+
const settingsPath = path46.join(claudeDir, "settings.json");
|
|
30794
|
+
const claudeJsonPath = path46.join(homeDir, ".claude.json");
|
|
30795
|
+
const exeOsDir = path46.join(homeDir, ".exe-os");
|
|
30556
30796
|
let removed = 0;
|
|
30557
30797
|
const log = (msg) => console.log(dryRun ? `[dry-run] ${msg}` : msg);
|
|
30558
30798
|
let settings = {};
|
|
30559
|
-
if (
|
|
30799
|
+
if (existsSync32(settingsPath)) {
|
|
30560
30800
|
try {
|
|
30561
30801
|
settings = JSON.parse(readFileSync27(settingsPath, "utf8"));
|
|
30562
30802
|
} catch {
|
|
@@ -30603,7 +30843,7 @@ async function runClaudeUninstall(flags = []) {
|
|
|
30603
30843
|
removed++;
|
|
30604
30844
|
}
|
|
30605
30845
|
}
|
|
30606
|
-
if (
|
|
30846
|
+
if (existsSync32(claudeJsonPath)) {
|
|
30607
30847
|
const raw = readFileSync27(claudeJsonPath, "utf8");
|
|
30608
30848
|
if (raw.length > 1e6) {
|
|
30609
30849
|
console.error("claude.json exceeds 1 MB \u2014 skipping parse.");
|
|
@@ -30633,14 +30873,14 @@ async function runClaudeUninstall(flags = []) {
|
|
|
30633
30873
|
}
|
|
30634
30874
|
}
|
|
30635
30875
|
}
|
|
30636
|
-
const skillsDir =
|
|
30637
|
-
if (
|
|
30876
|
+
const skillsDir = path46.join(claudeDir, "skills");
|
|
30877
|
+
if (existsSync32(skillsDir)) {
|
|
30638
30878
|
let skillCount = 0;
|
|
30639
30879
|
try {
|
|
30640
30880
|
const entries = readdirSync9(skillsDir);
|
|
30641
30881
|
for (const entry of entries) {
|
|
30642
30882
|
if (entry.startsWith("exe")) {
|
|
30643
|
-
const fullPath =
|
|
30883
|
+
const fullPath = path46.join(skillsDir, entry);
|
|
30644
30884
|
if (!dryRun) rmSync(fullPath, { recursive: true, force: true });
|
|
30645
30885
|
skillCount++;
|
|
30646
30886
|
}
|
|
@@ -30652,8 +30892,8 @@ async function runClaudeUninstall(flags = []) {
|
|
|
30652
30892
|
removed++;
|
|
30653
30893
|
}
|
|
30654
30894
|
}
|
|
30655
|
-
const claudeMdPath =
|
|
30656
|
-
if (
|
|
30895
|
+
const claudeMdPath = path46.join(claudeDir, "CLAUDE.md");
|
|
30896
|
+
if (existsSync32(claudeMdPath)) {
|
|
30657
30897
|
const content = readFileSync27(claudeMdPath, "utf8");
|
|
30658
30898
|
const startMarker = "<!-- exe-os:orchestration-start -->";
|
|
30659
30899
|
const endMarker = "<!-- exe-os:orchestration-end -->";
|
|
@@ -30666,14 +30906,14 @@ async function runClaudeUninstall(flags = []) {
|
|
|
30666
30906
|
removed++;
|
|
30667
30907
|
}
|
|
30668
30908
|
}
|
|
30669
|
-
const agentsDir =
|
|
30670
|
-
if (
|
|
30909
|
+
const agentsDir = path46.join(claudeDir, "agents");
|
|
30910
|
+
if (existsSync32(agentsDir)) {
|
|
30671
30911
|
let agentCount = 0;
|
|
30672
30912
|
try {
|
|
30673
30913
|
const entries = readdirSync9(agentsDir).filter((f) => f.endsWith(".md"));
|
|
30674
30914
|
let knownNames = /* @__PURE__ */ new Set();
|
|
30675
|
-
const rosterPath =
|
|
30676
|
-
if (
|
|
30915
|
+
const rosterPath = path46.join(exeOsDir, "exe-employees.json");
|
|
30916
|
+
if (existsSync32(rosterPath)) {
|
|
30677
30917
|
try {
|
|
30678
30918
|
const roster = JSON.parse(readFileSync27(rosterPath, "utf8"));
|
|
30679
30919
|
knownNames = new Set(roster.map((e) => e.name));
|
|
@@ -30683,7 +30923,7 @@ async function runClaudeUninstall(flags = []) {
|
|
|
30683
30923
|
for (const entry of entries) {
|
|
30684
30924
|
const name = entry.replace(/\.md$/, "");
|
|
30685
30925
|
if (knownNames.has(name)) {
|
|
30686
|
-
if (!dryRun) rmSync(
|
|
30926
|
+
if (!dryRun) rmSync(path46.join(agentsDir, entry), { force: true });
|
|
30687
30927
|
agentCount++;
|
|
30688
30928
|
}
|
|
30689
30929
|
}
|
|
@@ -30694,14 +30934,14 @@ async function runClaudeUninstall(flags = []) {
|
|
|
30694
30934
|
removed++;
|
|
30695
30935
|
}
|
|
30696
30936
|
}
|
|
30697
|
-
const projectsDir =
|
|
30698
|
-
if (
|
|
30937
|
+
const projectsDir = path46.join(claudeDir, "projects");
|
|
30938
|
+
if (existsSync32(projectsDir)) {
|
|
30699
30939
|
let projectCount = 0;
|
|
30700
30940
|
try {
|
|
30701
30941
|
const projects = readdirSync9(projectsDir);
|
|
30702
30942
|
for (const proj of projects) {
|
|
30703
|
-
const projSettings =
|
|
30704
|
-
if (!
|
|
30943
|
+
const projSettings = path46.join(projectsDir, proj, "settings.json");
|
|
30944
|
+
if (!existsSync32(projSettings)) continue;
|
|
30705
30945
|
try {
|
|
30706
30946
|
const pSettings = JSON.parse(readFileSync27(projSettings, "utf8"));
|
|
30707
30947
|
let changed = false;
|
|
@@ -30737,18 +30977,18 @@ async function runClaudeUninstall(flags = []) {
|
|
|
30737
30977
|
};
|
|
30738
30978
|
const exeBinPath = findExeBin3();
|
|
30739
30979
|
if (!exeBinPath) throw new Error("exe-os not found in PATH");
|
|
30740
|
-
const binDir =
|
|
30980
|
+
const binDir = path46.dirname(exeBinPath);
|
|
30741
30981
|
let symlinkCount = 0;
|
|
30742
|
-
const rosterPath =
|
|
30743
|
-
if (
|
|
30982
|
+
const rosterPath = path46.join(exeOsDir, "exe-employees.json");
|
|
30983
|
+
if (existsSync32(rosterPath)) {
|
|
30744
30984
|
const roster = JSON.parse(readFileSync27(rosterPath, "utf8"));
|
|
30745
30985
|
const { DEFAULT_COORDINATOR_TEMPLATE_NAME: DEFAULT_COORDINATOR_TEMPLATE_NAME2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
30746
30986
|
const coordinatorName = roster.find((e) => e.role?.toLowerCase() === "coo")?.name ?? DEFAULT_COORDINATOR_TEMPLATE_NAME2;
|
|
30747
30987
|
for (const emp of roster) {
|
|
30748
30988
|
if (emp.name === coordinatorName) continue;
|
|
30749
30989
|
for (const suffix of ["", "-opencode"]) {
|
|
30750
|
-
const linkPath =
|
|
30751
|
-
if (
|
|
30990
|
+
const linkPath = path46.join(binDir, `${emp.name}${suffix}`);
|
|
30991
|
+
if (existsSync32(linkPath)) {
|
|
30752
30992
|
if (!dryRun) rmSync(linkPath, { force: true });
|
|
30753
30993
|
symlinkCount++;
|
|
30754
30994
|
}
|
|
@@ -30761,7 +31001,7 @@ async function runClaudeUninstall(flags = []) {
|
|
|
30761
31001
|
}
|
|
30762
31002
|
} catch {
|
|
30763
31003
|
}
|
|
30764
|
-
if (purge &&
|
|
31004
|
+
if (purge && existsSync32(exeOsDir)) {
|
|
30765
31005
|
if (!dryRun) {
|
|
30766
31006
|
process.stdout.write("\x1B[33m\u26A0 This will delete all memories, identities, and agent data.\x1B[0m\n");
|
|
30767
31007
|
process.stdout.write(" Removing ~/.exe-os...\n");
|
|
@@ -30786,7 +31026,7 @@ async function checkForUpdateOnBoot() {
|
|
|
30786
31026
|
const config = await loadConfig2();
|
|
30787
31027
|
if (!config.autoUpdate.checkOnBoot) return;
|
|
30788
31028
|
const { checkForUpdate: checkForUpdate2 } = await Promise.resolve().then(() => (init_update(), update_exports));
|
|
30789
|
-
const packageRoot =
|
|
31029
|
+
const packageRoot = path46.resolve(
|
|
30790
31030
|
new URL("../..", import.meta.url).pathname
|
|
30791
31031
|
);
|
|
30792
31032
|
const result = checkForUpdate2(packageRoot);
|
|
@@ -30846,7 +31086,7 @@ async function runActivate(key) {
|
|
|
30846
31086
|
const idTemplate = getIdentityTemplate(identityKey);
|
|
30847
31087
|
if (idTemplate) {
|
|
30848
31088
|
const idPath = identityPath2(name);
|
|
30849
|
-
const dir =
|
|
31089
|
+
const dir = path46.dirname(idPath);
|
|
30850
31090
|
if (!fs8.existsSync(dir)) fs8.mkdirSync(dir, { recursive: true });
|
|
30851
31091
|
fs8.writeFileSync(idPath, idTemplate.replace(/^agent_id: \w+/m, `agent_id: ${name}`), "utf-8");
|
|
30852
31092
|
}
|