@askexenow/exe-os 0.9.65 → 0.9.67
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 +54 -5
- package/dist/bin/age-ontology-load.js +61 -0
- package/dist/bin/agentic-ontology-backfill.js +4708 -0
- package/dist/bin/agentic-reflection-backfill.js +4144 -0
- package/dist/bin/{exe-link.js → agentic-semantic-label.js} +1532 -2173
- package/dist/bin/backfill-conversations.js +528 -20
- package/dist/bin/backfill-responses.js +528 -20
- package/dist/bin/backfill-vectors.js +255 -20
- package/dist/bin/bulk-sync-postgres.js +4876 -0
- package/dist/bin/cleanup-stale-review-tasks.js +529 -21
- package/dist/bin/cli.js +3471 -1491
- package/dist/bin/exe-agent-config.js +4 -0
- package/dist/bin/exe-agent.js +16 -0
- package/dist/bin/exe-assign.js +528 -20
- package/dist/bin/exe-boot.js +492 -54
- package/dist/bin/exe-call.js +16 -0
- package/dist/bin/exe-cloud.js +7415 -518
- package/dist/bin/exe-dispatch.js +540 -22
- package/dist/bin/exe-doctor.js +3404 -1225
- package/dist/bin/exe-export-behaviors.js +542 -24
- package/dist/bin/exe-forget.js +529 -21
- package/dist/bin/exe-gateway.js +595 -25
- package/dist/bin/exe-heartbeat.js +541 -24
- package/dist/bin/exe-kill.js +529 -21
- package/dist/bin/exe-launch-agent.js +2334 -1067
- package/dist/bin/exe-new-employee.js +324 -166
- package/dist/bin/exe-pending-messages.js +529 -21
- package/dist/bin/exe-pending-notifications.js +529 -21
- package/dist/bin/exe-pending-reviews.js +529 -21
- package/dist/bin/exe-rename.js +529 -21
- package/dist/bin/exe-review.js +529 -21
- package/dist/bin/exe-search.js +542 -24
- package/dist/bin/exe-session-cleanup.js +540 -22
- package/dist/bin/exe-settings.js +14 -0
- package/dist/bin/exe-start-codex.js +817 -144
- package/dist/bin/exe-start-opencode.js +776 -80
- package/dist/bin/exe-status.js +529 -21
- package/dist/bin/exe-team.js +529 -21
- package/dist/bin/git-sweep.js +540 -22
- package/dist/bin/graph-backfill.js +580 -21
- package/dist/bin/graph-export.js +529 -21
- package/dist/bin/graph-layer-benchmark.js +109 -0
- package/dist/bin/install.js +420 -289
- package/dist/bin/intercom-check.js +540 -22
- package/dist/bin/postgres-agentic-reflection-backfill.js +187 -0
- package/dist/bin/postgres-agentic-semantic-backfill.js +237 -0
- package/dist/bin/scan-tasks.js +540 -22
- package/dist/bin/setup.js +790 -206
- package/dist/bin/shard-migrate.js +528 -20
- package/dist/bin/update.js +4 -0
- package/dist/gateway/index.js +593 -23
- package/dist/hooks/bug-report-worker.js +651 -64
- package/dist/hooks/codex-stop-task-finalizer.js +540 -22
- package/dist/hooks/commit-complete.js +540 -22
- package/dist/hooks/error-recall.js +542 -24
- package/dist/hooks/exe-heartbeat-hook.js +4 -0
- package/dist/hooks/ingest-worker.js +4 -0
- package/dist/hooks/ingest.js +539 -22
- package/dist/hooks/instructions-loaded.js +529 -21
- package/dist/hooks/notification.js +529 -21
- package/dist/hooks/post-compact.js +529 -21
- package/dist/hooks/post-tool-combined.js +543 -25
- package/dist/hooks/pre-compact.js +772 -127
- package/dist/hooks/pre-tool-use.js +529 -21
- package/dist/hooks/prompt-submit.js +543 -25
- package/dist/hooks/session-end.js +673 -140
- package/dist/hooks/session-start.js +662 -26
- package/dist/hooks/stop.js +540 -23
- package/dist/hooks/subagent-stop.js +529 -21
- package/dist/hooks/summary-worker.js +571 -126
- package/dist/index.js +593 -23
- package/dist/lib/agent-config.js +4 -0
- package/dist/lib/cloud-sync.js +408 -47
- package/dist/lib/config.js +25 -1
- package/dist/lib/consolidation.js +5 -1
- package/dist/lib/database.js +128 -0
- package/dist/lib/db-daemon-client.js +4 -0
- package/dist/lib/db.js +128 -0
- package/dist/lib/device-registry.js +128 -0
- package/dist/lib/embedder.js +25 -1
- package/dist/lib/employee-templates.js +16 -0
- package/dist/lib/employees.js +4 -0
- package/dist/lib/exe-daemon-client.js +4 -0
- package/dist/lib/exe-daemon.js +3158 -930
- package/dist/lib/hybrid-search.js +542 -24
- package/dist/lib/identity.js +7 -0
- package/dist/lib/keychain.js +178 -22
- package/dist/lib/license.js +4 -0
- package/dist/lib/messaging.js +7 -0
- package/dist/lib/reminders.js +7 -0
- package/dist/lib/schedules.js +255 -20
- package/dist/lib/skill-learning.js +28 -1
- package/dist/lib/status-brief.js +39 -0
- package/dist/lib/store.js +528 -20
- package/dist/lib/task-router.js +4 -0
- package/dist/lib/tasks.js +28 -1
- package/dist/lib/tmux-routing.js +28 -1
- package/dist/lib/token-spend.js +7 -0
- package/dist/mcp/server.js +2739 -813
- package/dist/mcp/tools/complete-reminder.js +7 -0
- package/dist/mcp/tools/create-reminder.js +7 -0
- package/dist/mcp/tools/create-task.js +28 -1
- package/dist/mcp/tools/deactivate-behavior.js +7 -0
- package/dist/mcp/tools/list-reminders.js +7 -0
- package/dist/mcp/tools/list-tasks.js +7 -0
- package/dist/mcp/tools/send-message.js +7 -0
- package/dist/mcp/tools/update-task.js +28 -1
- package/dist/runtime/index.js +540 -22
- package/dist/tui/App.js +618 -29
- package/package.json +9 -5
- package/src/commands/exe/cloud.md +11 -8
- package/stack.release.json +3 -3
- package/src/commands/exe/link.md +0 -17
|
@@ -127,6 +127,10 @@ var init_config = __esm({
|
|
|
127
127
|
checkOnBoot: true,
|
|
128
128
|
autoInstall: false,
|
|
129
129
|
checkIntervalMs: 24 * 60 * 60 * 1e3
|
|
130
|
+
},
|
|
131
|
+
orchestration: {
|
|
132
|
+
phase: "phase_1_coo",
|
|
133
|
+
phaseSetBy: "default"
|
|
130
134
|
}
|
|
131
135
|
};
|
|
132
136
|
}
|
|
@@ -457,6 +461,9 @@ function getClient() {
|
|
|
457
461
|
if (_daemonClient && _daemonClient._isDaemonActive()) {
|
|
458
462
|
return _daemonClient;
|
|
459
463
|
}
|
|
464
|
+
if (!_resilientClient) {
|
|
465
|
+
return _adapterClient;
|
|
466
|
+
}
|
|
460
467
|
return _resilientClient;
|
|
461
468
|
}
|
|
462
469
|
var _resilientClient, _daemonClient, _adapterClient;
|
|
@@ -1257,6 +1264,63 @@ var init_preferences = __esm({
|
|
|
1257
1264
|
}
|
|
1258
1265
|
});
|
|
1259
1266
|
|
|
1267
|
+
// src/adapters/mcp-http-config.ts
|
|
1268
|
+
import { chmodSync as chmodSync3, existsSync as existsSync11, mkdirSync as mkdirSync6, readFileSync as readFileSync9, writeFileSync as writeFileSync7 } from "fs";
|
|
1269
|
+
import { randomBytes } from "crypto";
|
|
1270
|
+
import path11 from "path";
|
|
1271
|
+
import os7 from "os";
|
|
1272
|
+
function mcpHttpPort() {
|
|
1273
|
+
return process.env.EXE_MCP_PORT || DEFAULT_MCP_HTTP_PORT;
|
|
1274
|
+
}
|
|
1275
|
+
function mcpHttpUrl() {
|
|
1276
|
+
return `http://127.0.0.1:${mcpHttpPort()}/mcp`;
|
|
1277
|
+
}
|
|
1278
|
+
function readOrCreateDaemonToken(homeDir = os7.homedir()) {
|
|
1279
|
+
const exeDir = path11.join(homeDir, ".exe-os");
|
|
1280
|
+
const tokenPath = path11.join(exeDir, "exed.token");
|
|
1281
|
+
if (existsSync11(tokenPath)) {
|
|
1282
|
+
try {
|
|
1283
|
+
const token2 = readFileSync9(tokenPath, "utf-8").trim();
|
|
1284
|
+
if (/^[a-f0-9]{64}$/i.test(token2)) return token2;
|
|
1285
|
+
} catch {
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
const token = randomBytes(32).toString("hex");
|
|
1289
|
+
mkdirSync6(exeDir, { recursive: true });
|
|
1290
|
+
writeFileSync7(tokenPath, `${token}
|
|
1291
|
+
`, "utf-8");
|
|
1292
|
+
try {
|
|
1293
|
+
chmodSync3(tokenPath, 384);
|
|
1294
|
+
} catch {
|
|
1295
|
+
}
|
|
1296
|
+
return token;
|
|
1297
|
+
}
|
|
1298
|
+
function buildMcpHttpHeaders(homeDir = os7.homedir(), opts = {}) {
|
|
1299
|
+
const agentId = opts.useShellPlaceholders ? "${AGENT_ID:-exe}" : opts.agentId ?? DEFAULT_MCP_HTTP_AGENT_ID;
|
|
1300
|
+
const agentRole = opts.useShellPlaceholders ? "${AGENT_ROLE:-COO}" : opts.agentRole ?? DEFAULT_MCP_HTTP_AGENT_ROLE;
|
|
1301
|
+
return {
|
|
1302
|
+
Authorization: `Bearer ${readOrCreateDaemonToken(homeDir)}`,
|
|
1303
|
+
"X-Agent-Id": agentId,
|
|
1304
|
+
"X-Agent-Role": agentRole
|
|
1305
|
+
};
|
|
1306
|
+
}
|
|
1307
|
+
function buildClaudeHttpMcpEntry(homeDir = os7.homedir()) {
|
|
1308
|
+
return {
|
|
1309
|
+
type: "http",
|
|
1310
|
+
url: mcpHttpUrl(),
|
|
1311
|
+
headers: buildMcpHttpHeaders(homeDir, { useShellPlaceholders: true })
|
|
1312
|
+
};
|
|
1313
|
+
}
|
|
1314
|
+
var DEFAULT_MCP_HTTP_PORT, DEFAULT_MCP_HTTP_AGENT_ID, DEFAULT_MCP_HTTP_AGENT_ROLE;
|
|
1315
|
+
var init_mcp_http_config = __esm({
|
|
1316
|
+
"src/adapters/mcp-http-config.ts"() {
|
|
1317
|
+
"use strict";
|
|
1318
|
+
DEFAULT_MCP_HTTP_PORT = "48739";
|
|
1319
|
+
DEFAULT_MCP_HTTP_AGENT_ID = "exe";
|
|
1320
|
+
DEFAULT_MCP_HTTP_AGENT_ROLE = "COO";
|
|
1321
|
+
}
|
|
1322
|
+
});
|
|
1323
|
+
|
|
1260
1324
|
// src/adapters/runtime-hook-manifest.ts
|
|
1261
1325
|
function commandHasAnyMarker(command, markers) {
|
|
1262
1326
|
return markers.some((marker) => command.includes(marker));
|
|
@@ -1264,7 +1328,7 @@ function commandHasAnyMarker(command, markers) {
|
|
|
1264
1328
|
function isLegacySplitPostToolCommand(command) {
|
|
1265
1329
|
return commandHasAnyMarker(command, LEGACY_SPLIT_POST_TOOL_HOOK_MARKERS);
|
|
1266
1330
|
}
|
|
1267
|
-
var EXE_HOOKS, LEGACY_SPLIT_POST_TOOL_HOOK_MARKERS;
|
|
1331
|
+
var EXE_HOOKS, EXE_HOOK_MANIFEST, LEGACY_SPLIT_POST_TOOL_HOOK_MARKERS;
|
|
1268
1332
|
var init_runtime_hook_manifest = __esm({
|
|
1269
1333
|
"src/adapters/runtime-hook-manifest.ts"() {
|
|
1270
1334
|
"use strict";
|
|
@@ -1282,6 +1346,116 @@ var init_runtime_hook_manifest = __esm({
|
|
|
1282
1346
|
notification: "dist/hooks/notification.js",
|
|
1283
1347
|
instructionsLoaded: "dist/hooks/instructions-loaded.js"
|
|
1284
1348
|
};
|
|
1349
|
+
EXE_HOOK_MANIFEST = [
|
|
1350
|
+
{
|
|
1351
|
+
key: "postToolCombined",
|
|
1352
|
+
event: "PostToolUse",
|
|
1353
|
+
commandMarker: EXE_HOOKS.postToolCombined,
|
|
1354
|
+
owner: "exe-os",
|
|
1355
|
+
purpose: "Single PostToolUse entrypoint for ingestion, error recall, summaries, and bug detection.",
|
|
1356
|
+
runtimes: ["claude", "codex", "opencode"],
|
|
1357
|
+
checkpointRole: "none"
|
|
1358
|
+
},
|
|
1359
|
+
{
|
|
1360
|
+
key: "sessionStart",
|
|
1361
|
+
event: "SessionStart",
|
|
1362
|
+
commandMarker: EXE_HOOKS.sessionStart,
|
|
1363
|
+
owner: "exe-os",
|
|
1364
|
+
purpose: "Loads agent identity, procedures, and boot context.",
|
|
1365
|
+
runtimes: ["claude", "codex", "opencode"],
|
|
1366
|
+
checkpointRole: "none"
|
|
1367
|
+
},
|
|
1368
|
+
{
|
|
1369
|
+
key: "promptSubmit",
|
|
1370
|
+
event: "UserPromptSubmit",
|
|
1371
|
+
commandMarker: EXE_HOOKS.promptSubmit,
|
|
1372
|
+
owner: "exe-os",
|
|
1373
|
+
purpose: "Injects current tasks, pending reviews, and local context before each prompt.",
|
|
1374
|
+
runtimes: ["claude", "codex", "opencode"],
|
|
1375
|
+
checkpointRole: "none"
|
|
1376
|
+
},
|
|
1377
|
+
{
|
|
1378
|
+
key: "heartbeat",
|
|
1379
|
+
event: "UserPromptSubmit",
|
|
1380
|
+
commandMarker: EXE_HOOKS.heartbeat,
|
|
1381
|
+
owner: "exe-os",
|
|
1382
|
+
purpose: "Lightweight heartbeat/status sidecar for Claude Code sessions.",
|
|
1383
|
+
runtimes: ["claude"],
|
|
1384
|
+
checkpointRole: "none"
|
|
1385
|
+
},
|
|
1386
|
+
{
|
|
1387
|
+
key: "stop",
|
|
1388
|
+
event: "Stop",
|
|
1389
|
+
commandMarker: EXE_HOOKS.stop,
|
|
1390
|
+
owner: "exe-os",
|
|
1391
|
+
purpose: "Finalizes task state, capacity signals, and emergency checkpointing.",
|
|
1392
|
+
runtimes: ["claude", "codex", "opencode"],
|
|
1393
|
+
checkpointRole: "capacity_checkpoint"
|
|
1394
|
+
},
|
|
1395
|
+
{
|
|
1396
|
+
key: "preToolUse",
|
|
1397
|
+
event: "PreToolUse",
|
|
1398
|
+
commandMarker: EXE_HOOKS.preToolUse,
|
|
1399
|
+
owner: "exe-os",
|
|
1400
|
+
purpose: "Preflight guardrails before shell/tool execution.",
|
|
1401
|
+
runtimes: ["claude", "codex", "opencode"],
|
|
1402
|
+
checkpointRole: "none"
|
|
1403
|
+
},
|
|
1404
|
+
{
|
|
1405
|
+
key: "subagentStop",
|
|
1406
|
+
event: "SubagentStop",
|
|
1407
|
+
commandMarker: EXE_HOOKS.subagentStop,
|
|
1408
|
+
owner: "exe-os",
|
|
1409
|
+
purpose: "Captures subagent completion context.",
|
|
1410
|
+
runtimes: ["claude"],
|
|
1411
|
+
checkpointRole: "none"
|
|
1412
|
+
},
|
|
1413
|
+
{
|
|
1414
|
+
key: "preCompact",
|
|
1415
|
+
event: "PreCompact",
|
|
1416
|
+
commandMarker: EXE_HOOKS.preCompact,
|
|
1417
|
+
owner: "exe-os",
|
|
1418
|
+
purpose: "Writes active-task snapshot and compaction recovery context.",
|
|
1419
|
+
runtimes: ["claude"],
|
|
1420
|
+
checkpointRole: "recovery_context"
|
|
1421
|
+
},
|
|
1422
|
+
{
|
|
1423
|
+
key: "postCompact",
|
|
1424
|
+
event: "PostCompact",
|
|
1425
|
+
commandMarker: EXE_HOOKS.postCompact,
|
|
1426
|
+
owner: "exe-os",
|
|
1427
|
+
purpose: "Rehydrates recovery context after compaction.",
|
|
1428
|
+
runtimes: ["claude"],
|
|
1429
|
+
checkpointRole: "recovery_context"
|
|
1430
|
+
},
|
|
1431
|
+
{
|
|
1432
|
+
key: "sessionEnd",
|
|
1433
|
+
event: "SessionEnd",
|
|
1434
|
+
commandMarker: EXE_HOOKS.sessionEnd,
|
|
1435
|
+
owner: "exe-os",
|
|
1436
|
+
purpose: "Stores session-end checkpoint and triages orphaned in-progress tasks.",
|
|
1437
|
+
runtimes: ["claude"],
|
|
1438
|
+
checkpointRole: "session_summary"
|
|
1439
|
+
},
|
|
1440
|
+
{
|
|
1441
|
+
key: "notification",
|
|
1442
|
+
event: "Notification",
|
|
1443
|
+
commandMarker: EXE_HOOKS.notification,
|
|
1444
|
+
owner: "exe-os",
|
|
1445
|
+
purpose: "Captures runtime notifications and nudges.",
|
|
1446
|
+
runtimes: ["claude"],
|
|
1447
|
+
checkpointRole: "none"
|
|
1448
|
+
},
|
|
1449
|
+
{
|
|
1450
|
+
key: "instructionsLoaded",
|
|
1451
|
+
event: "InstructionsLoaded",
|
|
1452
|
+
commandMarker: EXE_HOOKS.instructionsLoaded,
|
|
1453
|
+
owner: "exe-os",
|
|
1454
|
+
purpose: "Applies runtime instruction post-processing.",
|
|
1455
|
+
runtimes: ["claude"],
|
|
1456
|
+
checkpointRole: "none"
|
|
1457
|
+
}
|
|
1458
|
+
];
|
|
1285
1459
|
LEGACY_SPLIT_POST_TOOL_HOOK_MARKERS = [
|
|
1286
1460
|
"dist/hooks/ingest.js",
|
|
1287
1461
|
"dist/hooks/error-recall.js",
|
|
@@ -1304,54 +1478,58 @@ __export(installer_exports, {
|
|
|
1304
1478
|
setupGhostty: () => setupGhostty,
|
|
1305
1479
|
setupTmux: () => setupTmux
|
|
1306
1480
|
});
|
|
1307
|
-
import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3, readdir } from "fs/promises";
|
|
1308
|
-
import { existsSync as
|
|
1309
|
-
import { createHash as createHash2
|
|
1310
|
-
import
|
|
1311
|
-
import
|
|
1481
|
+
import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3, readdir, rm } from "fs/promises";
|
|
1482
|
+
import { existsSync as existsSync12, readFileSync as readFileSync10, writeFileSync as writeFileSync8, copyFileSync, mkdirSync as mkdirSync7 } from "fs";
|
|
1483
|
+
import { createHash as createHash2 } from "crypto";
|
|
1484
|
+
import path12 from "path";
|
|
1485
|
+
import os8 from "os";
|
|
1312
1486
|
import { execSync as execSync2 } from "child_process";
|
|
1313
1487
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1314
1488
|
function resolvePackageRoot() {
|
|
1315
1489
|
const thisFile = fileURLToPath2(import.meta.url);
|
|
1316
|
-
let dir =
|
|
1317
|
-
const root =
|
|
1490
|
+
let dir = path12.dirname(thisFile);
|
|
1491
|
+
const root = path12.parse(dir).root;
|
|
1318
1492
|
while (dir !== root) {
|
|
1319
|
-
const pkgPath =
|
|
1320
|
-
if (
|
|
1493
|
+
const pkgPath = path12.join(dir, "package.json");
|
|
1494
|
+
if (existsSync12(pkgPath)) {
|
|
1321
1495
|
try {
|
|
1322
|
-
const pkg = JSON.parse(
|
|
1496
|
+
const pkg = JSON.parse(readFileSync10(pkgPath, "utf-8"));
|
|
1323
1497
|
if (pkg.name === "@askexenow/exe-os" || pkg.name === "exe-os") return dir;
|
|
1324
1498
|
} catch {
|
|
1325
1499
|
}
|
|
1326
1500
|
}
|
|
1327
|
-
dir =
|
|
1501
|
+
dir = path12.dirname(dir);
|
|
1328
1502
|
}
|
|
1329
|
-
return
|
|
1503
|
+
return path12.resolve(path12.dirname(thisFile), "..", "..", "..");
|
|
1330
1504
|
}
|
|
1331
|
-
async function copySlashCommands(packageRoot, homeDir =
|
|
1505
|
+
async function copySlashCommands(packageRoot, homeDir = os8.homedir()) {
|
|
1332
1506
|
let copied = 0;
|
|
1333
1507
|
let skipped = 0;
|
|
1334
|
-
const skillsBase =
|
|
1335
|
-
const
|
|
1336
|
-
if (
|
|
1508
|
+
const skillsBase = path12.join(homeDir, ".claude", "skills");
|
|
1509
|
+
const deprecatedExeLink = path12.join(skillsBase, "exe-link");
|
|
1510
|
+
if (existsSync12(deprecatedExeLink)) {
|
|
1511
|
+
await rm(deprecatedExeLink, { recursive: true, force: true });
|
|
1512
|
+
}
|
|
1513
|
+
const exeDir = path12.join(packageRoot, "src", "commands", "exe");
|
|
1514
|
+
if (existsSync12(exeDir)) {
|
|
1337
1515
|
const entries = await readdir(exeDir);
|
|
1338
1516
|
const mdFiles = entries.filter((f) => f.endsWith(".md"));
|
|
1339
1517
|
for (const file of mdFiles) {
|
|
1340
1518
|
const name = file.replace(".md", "");
|
|
1341
|
-
const destDir =
|
|
1519
|
+
const destDir = path12.join(skillsBase, `exe-${name}`);
|
|
1342
1520
|
await mkdir3(destDir, { recursive: true });
|
|
1343
|
-
const srcPath =
|
|
1344
|
-
const destPath =
|
|
1521
|
+
const srcPath = path12.join(exeDir, file);
|
|
1522
|
+
const destPath = path12.join(destDir, "SKILL.md");
|
|
1345
1523
|
const result = await copyAsSkill(srcPath, destPath, `exe-${name}`);
|
|
1346
1524
|
if (result) copied++;
|
|
1347
1525
|
else skipped++;
|
|
1348
1526
|
}
|
|
1349
1527
|
}
|
|
1350
|
-
const topLevelSrc =
|
|
1351
|
-
if (
|
|
1352
|
-
const destDir =
|
|
1528
|
+
const topLevelSrc = path12.join(packageRoot, "src", "commands", "exe.md");
|
|
1529
|
+
if (existsSync12(topLevelSrc)) {
|
|
1530
|
+
const destDir = path12.join(skillsBase, "exe");
|
|
1353
1531
|
await mkdir3(destDir, { recursive: true });
|
|
1354
|
-
const destPath =
|
|
1532
|
+
const destPath = path12.join(destDir, "SKILL.md");
|
|
1355
1533
|
const result = await copyAsSkill(topLevelSrc, destPath, "exe");
|
|
1356
1534
|
if (result) copied++;
|
|
1357
1535
|
else skipped++;
|
|
@@ -1374,7 +1552,7 @@ name: ${skillName}
|
|
|
1374
1552
|
`);
|
|
1375
1553
|
}
|
|
1376
1554
|
}
|
|
1377
|
-
if (
|
|
1555
|
+
if (existsSync12(destPath)) {
|
|
1378
1556
|
const existing = await readFile3(destPath, "utf-8");
|
|
1379
1557
|
if (existing === content) return false;
|
|
1380
1558
|
}
|
|
@@ -1383,32 +1561,32 @@ name: ${skillName}
|
|
|
1383
1561
|
}
|
|
1384
1562
|
function readJsonFile(filePath) {
|
|
1385
1563
|
try {
|
|
1386
|
-
return JSON.parse(
|
|
1564
|
+
return JSON.parse(readFileSync10(filePath, "utf-8"));
|
|
1387
1565
|
} catch {
|
|
1388
1566
|
return null;
|
|
1389
1567
|
}
|
|
1390
1568
|
}
|
|
1391
1569
|
function findAncestorMcpJsons(startDir, homeDir) {
|
|
1392
1570
|
const files = [];
|
|
1393
|
-
let dir =
|
|
1394
|
-
const root =
|
|
1395
|
-
const stop =
|
|
1571
|
+
let dir = path12.resolve(startDir);
|
|
1572
|
+
const root = path12.parse(dir).root;
|
|
1573
|
+
const stop = path12.resolve(homeDir);
|
|
1396
1574
|
while (dir !== root) {
|
|
1397
|
-
const candidate =
|
|
1398
|
-
if (
|
|
1575
|
+
const candidate = path12.join(dir, ".mcp.json");
|
|
1576
|
+
if (existsSync12(candidate)) files.push(candidate);
|
|
1399
1577
|
if (dir === stop) break;
|
|
1400
|
-
dir =
|
|
1578
|
+
dir = path12.dirname(dir);
|
|
1401
1579
|
}
|
|
1402
1580
|
return files;
|
|
1403
1581
|
}
|
|
1404
1582
|
function pathApplies(projectPath, cwd) {
|
|
1405
|
-
const project =
|
|
1406
|
-
const current =
|
|
1407
|
-
return current === project || current.startsWith(project +
|
|
1583
|
+
const project = path12.resolve(projectPath);
|
|
1584
|
+
const current = path12.resolve(cwd);
|
|
1585
|
+
return current === project || current.startsWith(project + path12.sep);
|
|
1408
1586
|
}
|
|
1409
|
-
function detectMcpNameCollisions(homeDir =
|
|
1410
|
-
const claudeJsonPath =
|
|
1411
|
-
if (!
|
|
1587
|
+
function detectMcpNameCollisions(homeDir = os8.homedir(), cwd = process.cwd()) {
|
|
1588
|
+
const claudeJsonPath = path12.join(homeDir, ".claude.json");
|
|
1589
|
+
if (!existsSync12(claudeJsonPath)) return [];
|
|
1412
1590
|
const claudeJson = readJsonFile(claudeJsonPath);
|
|
1413
1591
|
if (!claudeJson?.projects) return [];
|
|
1414
1592
|
const collisions = [];
|
|
@@ -1435,44 +1613,11 @@ function detectMcpNameCollisions(homeDir = os7.homedir(), cwd = process.cwd()) {
|
|
|
1435
1613
|
}
|
|
1436
1614
|
return collisions;
|
|
1437
1615
|
}
|
|
1438
|
-
function readOrCreateDaemonToken(homeDir) {
|
|
1439
|
-
const exeDir = path11.join(homeDir, ".exe-os");
|
|
1440
|
-
const tokenPath = path11.join(exeDir, "exed.token");
|
|
1441
|
-
try {
|
|
1442
|
-
if (existsSync11(tokenPath)) {
|
|
1443
|
-
const token2 = readFileSync9(tokenPath, "utf-8").trim();
|
|
1444
|
-
if (token2) return token2;
|
|
1445
|
-
}
|
|
1446
|
-
} catch {
|
|
1447
|
-
}
|
|
1448
|
-
const token = randomBytes(32).toString("hex");
|
|
1449
|
-
mkdirSync6(exeDir, { recursive: true });
|
|
1450
|
-
writeFileSync7(tokenPath, `${token}
|
|
1451
|
-
`, "utf-8");
|
|
1452
|
-
try {
|
|
1453
|
-
chmodSync3(tokenPath, 384);
|
|
1454
|
-
} catch {
|
|
1455
|
-
}
|
|
1456
|
-
return token;
|
|
1457
|
-
}
|
|
1458
|
-
function buildHttpMcpEntry(homeDir) {
|
|
1459
|
-
const port = process.env.EXE_MCP_PORT || "48739";
|
|
1460
|
-
const token = readOrCreateDaemonToken(homeDir);
|
|
1461
|
-
return {
|
|
1462
|
-
type: "http",
|
|
1463
|
-
url: `http://127.0.0.1:${port}/mcp`,
|
|
1464
|
-
headers: {
|
|
1465
|
-
Authorization: `Bearer ${token}`,
|
|
1466
|
-
"X-Agent-Id": "${AGENT_ID:-exe}",
|
|
1467
|
-
"X-Agent-Role": "${AGENT_ROLE:-COO}"
|
|
1468
|
-
}
|
|
1469
|
-
};
|
|
1470
|
-
}
|
|
1471
1616
|
function buildStdioMcpEntry(packageRoot) {
|
|
1472
1617
|
return {
|
|
1473
1618
|
type: "stdio",
|
|
1474
1619
|
command: "node",
|
|
1475
|
-
args: [
|
|
1620
|
+
args: [path12.join(packageRoot, "dist", "mcp", "server.js")],
|
|
1476
1621
|
env: {}
|
|
1477
1622
|
};
|
|
1478
1623
|
}
|
|
@@ -1480,14 +1625,14 @@ function mcpTransportMode() {
|
|
|
1480
1625
|
const value = process.env.EXE_OS_MCP_TRANSPORT?.trim().toLowerCase();
|
|
1481
1626
|
if (value === "stdio") return "stdio";
|
|
1482
1627
|
if (value === "http") return "http";
|
|
1483
|
-
const totalGB =
|
|
1628
|
+
const totalGB = os8.totalmem() / (1024 * 1024 * 1024);
|
|
1484
1629
|
if (totalGB <= 8) return "stdio";
|
|
1485
1630
|
return "http";
|
|
1486
1631
|
}
|
|
1487
|
-
async function registerMcpServer(packageRoot, homeDir =
|
|
1488
|
-
const claudeJsonPath =
|
|
1632
|
+
async function registerMcpServer(packageRoot, homeDir = os8.homedir()) {
|
|
1633
|
+
const claudeJsonPath = path12.join(homeDir, ".claude.json");
|
|
1489
1634
|
let claudeJson = {};
|
|
1490
|
-
if (
|
|
1635
|
+
if (existsSync12(claudeJsonPath)) {
|
|
1491
1636
|
try {
|
|
1492
1637
|
claudeJson = JSON.parse(await readFile3(claudeJsonPath, "utf-8"));
|
|
1493
1638
|
} catch {
|
|
@@ -1497,7 +1642,7 @@ async function registerMcpServer(packageRoot, homeDir = os7.homedir()) {
|
|
|
1497
1642
|
if (!claudeJson.mcpServers) {
|
|
1498
1643
|
claudeJson.mcpServers = {};
|
|
1499
1644
|
}
|
|
1500
|
-
const newEntry = mcpTransportMode() === "stdio" ? buildStdioMcpEntry(packageRoot) :
|
|
1645
|
+
const newEntry = mcpTransportMode() === "stdio" ? buildStdioMcpEntry(packageRoot) : buildClaudeHttpMcpEntry(homeDir);
|
|
1501
1646
|
if (claudeJson.mcpServers[MCP_LEGACY_KEY]) {
|
|
1502
1647
|
delete claudeJson.mcpServers[MCP_LEGACY_KEY];
|
|
1503
1648
|
process.stderr.write("exe-os: migrated MCP server key exe-mem \u2192 exe-os\n");
|
|
@@ -1505,8 +1650,8 @@ async function registerMcpServer(packageRoot, homeDir = os7.homedir()) {
|
|
|
1505
1650
|
const currentOs = claudeJson.mcpServers[MCP_PRIMARY_KEY];
|
|
1506
1651
|
const osMatches = currentOs && JSON.stringify(currentOs) === JSON.stringify(newEntry);
|
|
1507
1652
|
if (osMatches) {
|
|
1508
|
-
await cleanSettingsJsonMcp(
|
|
1509
|
-
await migratePermissionsToExeOs(
|
|
1653
|
+
await cleanSettingsJsonMcp(path12.join(homeDir, ".claude", "settings.json"));
|
|
1654
|
+
await migratePermissionsToExeOs(path12.join(homeDir, ".claude", "settings.json"));
|
|
1510
1655
|
const collisions2 = detectMcpNameCollisions(homeDir, packageRoot).filter((c) => c.serverName === MCP_PRIMARY_KEY || c.serverName === MCP_LEGACY_KEY);
|
|
1511
1656
|
for (const c of collisions2) {
|
|
1512
1657
|
process.stderr.write(
|
|
@@ -1518,8 +1663,8 @@ async function registerMcpServer(packageRoot, homeDir = os7.homedir()) {
|
|
|
1518
1663
|
}
|
|
1519
1664
|
claudeJson.mcpServers[MCP_PRIMARY_KEY] = newEntry;
|
|
1520
1665
|
await writeFile3(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
|
|
1521
|
-
await cleanSettingsJsonMcp(
|
|
1522
|
-
await migratePermissionsToExeOs(
|
|
1666
|
+
await cleanSettingsJsonMcp(path12.join(homeDir, ".claude", "settings.json"));
|
|
1667
|
+
await migratePermissionsToExeOs(path12.join(homeDir, ".claude", "settings.json"));
|
|
1523
1668
|
const collisions = detectMcpNameCollisions(homeDir, packageRoot).filter((c) => c.serverName === MCP_PRIMARY_KEY || c.serverName === MCP_LEGACY_KEY);
|
|
1524
1669
|
for (const c of collisions) {
|
|
1525
1670
|
process.stderr.write(
|
|
@@ -1530,7 +1675,7 @@ async function registerMcpServer(packageRoot, homeDir = os7.homedir()) {
|
|
|
1530
1675
|
return true;
|
|
1531
1676
|
}
|
|
1532
1677
|
async function cleanSettingsJsonMcp(settingsPath) {
|
|
1533
|
-
if (!
|
|
1678
|
+
if (!existsSync12(settingsPath)) return;
|
|
1534
1679
|
try {
|
|
1535
1680
|
const settings = JSON.parse(await readFile3(settingsPath, "utf-8"));
|
|
1536
1681
|
const servers = settings.mcpServers;
|
|
@@ -1551,7 +1696,7 @@ async function cleanSettingsJsonMcp(settingsPath) {
|
|
|
1551
1696
|
}
|
|
1552
1697
|
}
|
|
1553
1698
|
async function migratePermissionsToExeOs(settingsPath) {
|
|
1554
|
-
if (!
|
|
1699
|
+
if (!existsSync12(settingsPath)) return;
|
|
1555
1700
|
try {
|
|
1556
1701
|
const settings = JSON.parse(await readFile3(settingsPath, "utf-8"));
|
|
1557
1702
|
const permissions = settings.permissions;
|
|
@@ -1579,14 +1724,14 @@ async function migratePermissionsToExeOs(settingsPath) {
|
|
|
1579
1724
|
} catch {
|
|
1580
1725
|
}
|
|
1581
1726
|
}
|
|
1582
|
-
async function mergeHooks(packageRoot, homeDir =
|
|
1583
|
-
const settingsPath =
|
|
1584
|
-
const logsDir =
|
|
1585
|
-
const hookLogPath =
|
|
1727
|
+
async function mergeHooks(packageRoot, homeDir = os8.homedir()) {
|
|
1728
|
+
const settingsPath = path12.join(homeDir, ".claude", "settings.json");
|
|
1729
|
+
const logsDir = path12.join(homeDir, ".exe-os", "logs");
|
|
1730
|
+
const hookLogPath = path12.join(logsDir, "hooks.log");
|
|
1586
1731
|
const logSuffix = ` 2>> "${hookLogPath}"`;
|
|
1587
1732
|
await mkdir3(logsDir, { recursive: true });
|
|
1588
1733
|
let settings = {};
|
|
1589
|
-
if (
|
|
1734
|
+
if (existsSync12(settingsPath)) {
|
|
1590
1735
|
try {
|
|
1591
1736
|
settings = JSON.parse(await readFile3(settingsPath, "utf-8"));
|
|
1592
1737
|
} catch {
|
|
@@ -1608,7 +1753,7 @@ async function mergeHooks(packageRoot, homeDir = os7.homedir()) {
|
|
|
1608
1753
|
hooks: [
|
|
1609
1754
|
{
|
|
1610
1755
|
type: "command",
|
|
1611
|
-
command: `node "${
|
|
1756
|
+
command: `node "${path12.join(packageRoot, "dist", "hooks", "post-tool-combined.js")}"${logSuffix}`
|
|
1612
1757
|
}
|
|
1613
1758
|
]
|
|
1614
1759
|
},
|
|
@@ -1620,7 +1765,7 @@ async function mergeHooks(packageRoot, homeDir = os7.homedir()) {
|
|
|
1620
1765
|
hooks: [
|
|
1621
1766
|
{
|
|
1622
1767
|
type: "command",
|
|
1623
|
-
command: `node "${
|
|
1768
|
+
command: `node "${path12.join(packageRoot, "dist", "hooks", "session-start.js")}"${logSuffix}`,
|
|
1624
1769
|
timeout: 1e4
|
|
1625
1770
|
}
|
|
1626
1771
|
]
|
|
@@ -1633,7 +1778,7 @@ async function mergeHooks(packageRoot, homeDir = os7.homedir()) {
|
|
|
1633
1778
|
hooks: [
|
|
1634
1779
|
{
|
|
1635
1780
|
type: "command",
|
|
1636
|
-
command: `node "${
|
|
1781
|
+
command: `node "${path12.join(packageRoot, "dist", "hooks", "prompt-submit.js")}"${logSuffix}`
|
|
1637
1782
|
}
|
|
1638
1783
|
]
|
|
1639
1784
|
},
|
|
@@ -1645,7 +1790,7 @@ async function mergeHooks(packageRoot, homeDir = os7.homedir()) {
|
|
|
1645
1790
|
hooks: [
|
|
1646
1791
|
{
|
|
1647
1792
|
type: "command",
|
|
1648
|
-
command: `node "${
|
|
1793
|
+
command: `node "${path12.join(packageRoot, "dist", "hooks", "exe-heartbeat-hook.js")}"${logSuffix}`,
|
|
1649
1794
|
timeout: 5e3
|
|
1650
1795
|
}
|
|
1651
1796
|
]
|
|
@@ -1658,7 +1803,7 @@ async function mergeHooks(packageRoot, homeDir = os7.homedir()) {
|
|
|
1658
1803
|
hooks: [
|
|
1659
1804
|
{
|
|
1660
1805
|
type: "command",
|
|
1661
|
-
command: `node "${
|
|
1806
|
+
command: `node "${path12.join(packageRoot, "dist", "hooks", "stop.js")}"${logSuffix}`
|
|
1662
1807
|
}
|
|
1663
1808
|
]
|
|
1664
1809
|
},
|
|
@@ -1671,7 +1816,7 @@ async function mergeHooks(packageRoot, homeDir = os7.homedir()) {
|
|
|
1671
1816
|
hooks: [
|
|
1672
1817
|
{
|
|
1673
1818
|
type: "command",
|
|
1674
|
-
command: `node "${
|
|
1819
|
+
command: `node "${path12.join(packageRoot, "dist", "hooks", "pre-tool-use.js")}"${logSuffix}`
|
|
1675
1820
|
}
|
|
1676
1821
|
]
|
|
1677
1822
|
},
|
|
@@ -1683,7 +1828,7 @@ async function mergeHooks(packageRoot, homeDir = os7.homedir()) {
|
|
|
1683
1828
|
hooks: [
|
|
1684
1829
|
{
|
|
1685
1830
|
type: "command",
|
|
1686
|
-
command: `node "${
|
|
1831
|
+
command: `node "${path12.join(packageRoot, "dist", "hooks", "subagent-stop.js")}"${logSuffix}`
|
|
1687
1832
|
}
|
|
1688
1833
|
]
|
|
1689
1834
|
},
|
|
@@ -1695,7 +1840,7 @@ async function mergeHooks(packageRoot, homeDir = os7.homedir()) {
|
|
|
1695
1840
|
hooks: [
|
|
1696
1841
|
{
|
|
1697
1842
|
type: "command",
|
|
1698
|
-
command: `node "${
|
|
1843
|
+
command: `node "${path12.join(packageRoot, "dist", "hooks", "pre-compact.js")}"${logSuffix}`,
|
|
1699
1844
|
timeout: 1e4
|
|
1700
1845
|
}
|
|
1701
1846
|
]
|
|
@@ -1708,7 +1853,7 @@ async function mergeHooks(packageRoot, homeDir = os7.homedir()) {
|
|
|
1708
1853
|
hooks: [
|
|
1709
1854
|
{
|
|
1710
1855
|
type: "command",
|
|
1711
|
-
command: `node "${
|
|
1856
|
+
command: `node "${path12.join(packageRoot, "dist", "hooks", "session-end.js")}"${logSuffix}`
|
|
1712
1857
|
}
|
|
1713
1858
|
]
|
|
1714
1859
|
},
|
|
@@ -1720,7 +1865,7 @@ async function mergeHooks(packageRoot, homeDir = os7.homedir()) {
|
|
|
1720
1865
|
hooks: [
|
|
1721
1866
|
{
|
|
1722
1867
|
type: "command",
|
|
1723
|
-
command: `node "${
|
|
1868
|
+
command: `node "${path12.join(packageRoot, "dist", "hooks", "notification.js")}"${logSuffix}`
|
|
1724
1869
|
}
|
|
1725
1870
|
]
|
|
1726
1871
|
},
|
|
@@ -1732,7 +1877,7 @@ async function mergeHooks(packageRoot, homeDir = os7.homedir()) {
|
|
|
1732
1877
|
hooks: [
|
|
1733
1878
|
{
|
|
1734
1879
|
type: "command",
|
|
1735
|
-
command: `node "${
|
|
1880
|
+
command: `node "${path12.join(packageRoot, "dist", "hooks", "post-compact.js")}"${logSuffix}`,
|
|
1736
1881
|
timeout: 1e4
|
|
1737
1882
|
}
|
|
1738
1883
|
]
|
|
@@ -1745,7 +1890,7 @@ async function mergeHooks(packageRoot, homeDir = os7.homedir()) {
|
|
|
1745
1890
|
hooks: [
|
|
1746
1891
|
{
|
|
1747
1892
|
type: "command",
|
|
1748
|
-
command: `node "${
|
|
1893
|
+
command: `node "${path12.join(packageRoot, "dist", "hooks", "instructions-loaded.js")}"${logSuffix}`
|
|
1749
1894
|
}
|
|
1750
1895
|
]
|
|
1751
1896
|
},
|
|
@@ -1850,13 +1995,13 @@ async function mergeHooks(packageRoot, homeDir = os7.homedir()) {
|
|
|
1850
1995
|
allowList.push(fullName);
|
|
1851
1996
|
}
|
|
1852
1997
|
}
|
|
1853
|
-
await mkdir3(
|
|
1998
|
+
await mkdir3(path12.dirname(settingsPath), { recursive: true });
|
|
1854
1999
|
await writeFile3(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
1855
2000
|
return { added, skipped };
|
|
1856
2001
|
}
|
|
1857
|
-
async function cleanOldShellFunctions(homeDir =
|
|
1858
|
-
const rosterPath =
|
|
1859
|
-
if (!
|
|
2002
|
+
async function cleanOldShellFunctions(homeDir = os8.homedir()) {
|
|
2003
|
+
const rosterPath = path12.join(homeDir, ".exe-os", "exe-employees.json");
|
|
2004
|
+
if (!existsSync12(rosterPath)) return 0;
|
|
1860
2005
|
let employees;
|
|
1861
2006
|
try {
|
|
1862
2007
|
employees = JSON.parse(await readFile3(rosterPath, "utf-8"));
|
|
@@ -1871,13 +2016,13 @@ async function cleanOldShellFunctions(homeDir = os7.homedir()) {
|
|
|
1871
2016
|
return { name: n, funcDef, forLoop };
|
|
1872
2017
|
});
|
|
1873
2018
|
const rcFiles = [
|
|
1874
|
-
|
|
1875
|
-
|
|
2019
|
+
path12.join(homeDir, ".zshrc"),
|
|
2020
|
+
path12.join(homeDir, ".bashrc")
|
|
1876
2021
|
];
|
|
1877
2022
|
const REMOVED_MARKER = "# Removed by exe-os \u2014 wrappers now at ~/.exe-os/bin/";
|
|
1878
2023
|
let totalRemoved = 0;
|
|
1879
2024
|
for (const rcPath of rcFiles) {
|
|
1880
|
-
if (!
|
|
2025
|
+
if (!existsSync12(rcPath)) continue;
|
|
1881
2026
|
let content;
|
|
1882
2027
|
try {
|
|
1883
2028
|
content = await readFile3(rcPath, "utf-8");
|
|
@@ -1981,8 +2126,8 @@ function escapeRegExp(s) {
|
|
|
1981
2126
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1982
2127
|
}
|
|
1983
2128
|
async function injectOrchestrationRules(homeDir) {
|
|
1984
|
-
const claudeDir =
|
|
1985
|
-
const claudeMdPath =
|
|
2129
|
+
const claudeDir = path12.join(homeDir, ".claude");
|
|
2130
|
+
const claudeMdPath = path12.join(claudeDir, "CLAUDE.md");
|
|
1986
2131
|
await mkdir3(claudeDir, { recursive: true });
|
|
1987
2132
|
let existing = "";
|
|
1988
2133
|
try {
|
|
@@ -2004,19 +2149,19 @@ async function injectOrchestrationRules(homeDir) {
|
|
|
2004
2149
|
await writeFile3(claudeMdPath, existing + separator + ORCHESTRATION_RULES + "\n", "utf-8");
|
|
2005
2150
|
return "injected";
|
|
2006
2151
|
}
|
|
2007
|
-
async function installStatusLine(packageRoot, homeDir =
|
|
2152
|
+
async function installStatusLine(packageRoot, homeDir = os8.homedir()) {
|
|
2008
2153
|
const prefs = loadPreferences(homeDir);
|
|
2009
2154
|
if (prefs.ccStatusLine === false) return "opted-out";
|
|
2010
|
-
const claudeDir =
|
|
2155
|
+
const claudeDir = path12.join(homeDir, ".claude");
|
|
2011
2156
|
await mkdir3(claudeDir, { recursive: true });
|
|
2012
|
-
const assetPath =
|
|
2013
|
-
if (!
|
|
2014
|
-
const destScript =
|
|
2157
|
+
const assetPath = path12.join(packageRoot, "dist", "assets", "statusline-command.sh");
|
|
2158
|
+
if (!existsSync12(assetPath)) return "asset-missing";
|
|
2159
|
+
const destScript = path12.join(claudeDir, "statusline-command.sh");
|
|
2015
2160
|
const assetContent = await readFile3(assetPath, "utf-8");
|
|
2016
2161
|
await writeFile3(destScript, assetContent, { mode: 493 });
|
|
2017
|
-
const settingsPath =
|
|
2162
|
+
const settingsPath = path12.join(claudeDir, "settings.json");
|
|
2018
2163
|
let settings = {};
|
|
2019
|
-
if (
|
|
2164
|
+
if (existsSync12(settingsPath)) {
|
|
2020
2165
|
try {
|
|
2021
2166
|
settings = JSON.parse(await readFile3(settingsPath, "utf-8"));
|
|
2022
2167
|
} catch {
|
|
@@ -2053,13 +2198,13 @@ async function runInstaller(homeDir) {
|
|
|
2053
2198
|
`Hooks: ${hookResult.added} added, ${hookResult.skipped} unchanged
|
|
2054
2199
|
`
|
|
2055
2200
|
);
|
|
2056
|
-
const resolvedHome = homeDir ??
|
|
2057
|
-
const exeWorkspace =
|
|
2058
|
-
if (!
|
|
2201
|
+
const resolvedHome = homeDir ?? os8.homedir();
|
|
2202
|
+
const exeWorkspace = path12.join(resolvedHome, "exe");
|
|
2203
|
+
if (!existsSync12(exeWorkspace)) {
|
|
2059
2204
|
try {
|
|
2060
|
-
await mkdir3(
|
|
2061
|
-
await mkdir3(
|
|
2062
|
-
await mkdir3(
|
|
2205
|
+
await mkdir3(path12.join(exeWorkspace, "content"), { recursive: true });
|
|
2206
|
+
await mkdir3(path12.join(exeWorkspace, "operations"), { recursive: true });
|
|
2207
|
+
await mkdir3(path12.join(exeWorkspace, "output"), { recursive: true });
|
|
2063
2208
|
process.stderr.write(
|
|
2064
2209
|
`Created ~/exe/ \u2014 your automation workspace for non-code projects
|
|
2065
2210
|
`
|
|
@@ -2094,57 +2239,57 @@ exe-os installed successfully.
|
|
|
2094
2239
|
`);
|
|
2095
2240
|
}
|
|
2096
2241
|
function setupTmux(home) {
|
|
2097
|
-
const homeDir = home ??
|
|
2098
|
-
const exeDir =
|
|
2099
|
-
const exeTmuxConf =
|
|
2100
|
-
const userTmuxConf =
|
|
2101
|
-
const backupPath =
|
|
2242
|
+
const homeDir = home ?? os8.homedir();
|
|
2243
|
+
const exeDir = path12.join(homeDir, ".exe-os");
|
|
2244
|
+
const exeTmuxConf = path12.join(exeDir, "tmux.conf");
|
|
2245
|
+
const userTmuxConf = path12.join(homeDir, ".tmux.conf");
|
|
2246
|
+
const backupPath = path12.join(homeDir, ".tmux.conf.backup");
|
|
2102
2247
|
const sourceLine = "source-file ~/.exe-os/tmux.conf";
|
|
2103
2248
|
const pkgRoot = resolvePackageRoot();
|
|
2104
|
-
const assetPath =
|
|
2105
|
-
if (!
|
|
2249
|
+
const assetPath = path12.join(pkgRoot, "dist", "assets", "tmux.conf");
|
|
2250
|
+
if (!existsSync12(assetPath)) {
|
|
2106
2251
|
process.stderr.write(`exe-os: tmux.conf asset not found at ${assetPath} \u2014 skipping tmux setup
|
|
2107
2252
|
`);
|
|
2108
2253
|
return;
|
|
2109
2254
|
}
|
|
2110
|
-
|
|
2111
|
-
if (
|
|
2112
|
-
const currentContent =
|
|
2113
|
-
const newContent =
|
|
2255
|
+
mkdirSync7(exeDir, { recursive: true });
|
|
2256
|
+
if (existsSync12(exeTmuxConf)) {
|
|
2257
|
+
const currentContent = readFileSync10(exeTmuxConf, "utf8");
|
|
2258
|
+
const newContent = readFileSync10(assetPath, "utf8");
|
|
2114
2259
|
const currentHash = createHash2("sha256").update(currentContent).digest("hex");
|
|
2115
2260
|
const newHash = createHash2("sha256").update(newContent).digest("hex");
|
|
2116
2261
|
if (currentHash !== newHash) {
|
|
2117
|
-
const shippedPath =
|
|
2118
|
-
const lastShippedHash =
|
|
2262
|
+
const shippedPath = path12.join(exeDir, ".tmux.conf.shipped-hash");
|
|
2263
|
+
const lastShippedHash = existsSync12(shippedPath) ? readFileSync10(shippedPath, "utf8").trim() : "";
|
|
2119
2264
|
if (lastShippedHash && currentHash !== lastShippedHash) {
|
|
2120
2265
|
process.stderr.write("exe-os: tmux config has user customizations \u2014 skipping overwrite\n");
|
|
2121
2266
|
} else {
|
|
2122
2267
|
copyFileSync(assetPath, exeTmuxConf);
|
|
2123
2268
|
process.stderr.write("exe-os: tmux config updated\n");
|
|
2124
2269
|
}
|
|
2125
|
-
|
|
2270
|
+
writeFileSync8(shippedPath, newHash, "utf8");
|
|
2126
2271
|
} else {
|
|
2127
2272
|
process.stderr.write("exe-os: tmux config already up to date\n");
|
|
2128
2273
|
}
|
|
2129
2274
|
} else {
|
|
2130
2275
|
copyFileSync(assetPath, exeTmuxConf);
|
|
2131
|
-
const newContent =
|
|
2276
|
+
const newContent = readFileSync10(assetPath, "utf8");
|
|
2132
2277
|
const newHash = createHash2("sha256").update(newContent).digest("hex");
|
|
2133
|
-
|
|
2278
|
+
writeFileSync8(path12.join(exeDir, ".tmux.conf.shipped-hash"), newHash, "utf8");
|
|
2134
2279
|
}
|
|
2135
|
-
if (
|
|
2136
|
-
const existing =
|
|
2280
|
+
if (existsSync12(userTmuxConf)) {
|
|
2281
|
+
const existing = readFileSync10(userTmuxConf, "utf8");
|
|
2137
2282
|
if (!existing.includes(sourceLine)) {
|
|
2138
|
-
if (!
|
|
2283
|
+
if (!existsSync12(backupPath)) {
|
|
2139
2284
|
copyFileSync(userTmuxConf, backupPath);
|
|
2140
2285
|
process.stderr.write(`exe-os: backed up existing tmux config to ${backupPath}
|
|
2141
2286
|
`);
|
|
2142
2287
|
}
|
|
2143
|
-
|
|
2288
|
+
writeFileSync8(userTmuxConf, `${sourceLine}
|
|
2144
2289
|
${existing}`);
|
|
2145
2290
|
}
|
|
2146
2291
|
} else {
|
|
2147
|
-
|
|
2292
|
+
writeFileSync8(userTmuxConf, `# Exe OS tmux defaults \u2014 remove this line to use your own config
|
|
2148
2293
|
${sourceLine}
|
|
2149
2294
|
`);
|
|
2150
2295
|
}
|
|
@@ -2155,10 +2300,10 @@ ${sourceLine}
|
|
|
2155
2300
|
process.stderr.write("exe-os: tmux config installed\n");
|
|
2156
2301
|
}
|
|
2157
2302
|
function setupGhostty(home) {
|
|
2158
|
-
const homeDir = home ??
|
|
2159
|
-
const xdgConfig =
|
|
2160
|
-
const macConfig =
|
|
2161
|
-
const ghosttyInstalled =
|
|
2303
|
+
const homeDir = home ?? os8.homedir();
|
|
2304
|
+
const xdgConfig = path12.join(homeDir, ".config", "ghostty");
|
|
2305
|
+
const macConfig = path12.join(homeDir, "Library", "Application Support", "com.mitchellh.ghostty");
|
|
2306
|
+
const ghosttyInstalled = existsSync12(xdgConfig) || existsSync12(macConfig) || (() => {
|
|
2162
2307
|
try {
|
|
2163
2308
|
execSync2("which ghostty 2>/dev/null");
|
|
2164
2309
|
return true;
|
|
@@ -2170,48 +2315,48 @@ function setupGhostty(home) {
|
|
|
2170
2315
|
return;
|
|
2171
2316
|
}
|
|
2172
2317
|
const pkgRoot = resolvePackageRoot();
|
|
2173
|
-
const assetPath =
|
|
2174
|
-
if (!
|
|
2318
|
+
const assetPath = path12.join(pkgRoot, "dist", "assets", "ghostty.conf");
|
|
2319
|
+
if (!existsSync12(assetPath)) {
|
|
2175
2320
|
process.stderr.write("exe-os: ghostty.conf asset not found \u2014 skipping Ghostty setup\n");
|
|
2176
2321
|
return;
|
|
2177
2322
|
}
|
|
2178
2323
|
const configDir = xdgConfig;
|
|
2179
|
-
const configPath =
|
|
2180
|
-
const backupPath =
|
|
2181
|
-
|
|
2324
|
+
const configPath = path12.join(configDir, "config");
|
|
2325
|
+
const backupPath = path12.join(configDir, "config.backup");
|
|
2326
|
+
mkdirSync7(configDir, { recursive: true });
|
|
2182
2327
|
const START_MARKER = "# \u2500\u2500 exe-os:ghostty-start \u2500\u2500";
|
|
2183
2328
|
const END_MARKER = "# \u2500\u2500 exe-os:ghostty-end \u2500\u2500";
|
|
2184
|
-
const assetContent =
|
|
2329
|
+
const assetContent = readFileSync10(assetPath, "utf8").trim();
|
|
2185
2330
|
const markedSection = `${START_MARKER}
|
|
2186
2331
|
${assetContent}
|
|
2187
2332
|
${END_MARKER}`;
|
|
2188
|
-
if (
|
|
2189
|
-
const existing =
|
|
2333
|
+
if (existsSync12(configPath)) {
|
|
2334
|
+
const existing = readFileSync10(configPath, "utf8");
|
|
2190
2335
|
if (existing.includes(START_MARKER) && existing.includes(END_MARKER)) {
|
|
2191
2336
|
process.stderr.write("exe-os: Ghostty config already installed \u2014 preserving local settings\n");
|
|
2192
2337
|
return;
|
|
2193
2338
|
} else if (existing.includes("Exe OS")) {
|
|
2194
|
-
if (!
|
|
2339
|
+
if (!existsSync12(backupPath)) {
|
|
2195
2340
|
copyFileSync(configPath, backupPath);
|
|
2196
2341
|
process.stderr.write(`exe-os: backed up existing Ghostty config to ${backupPath}
|
|
2197
2342
|
`);
|
|
2198
2343
|
}
|
|
2199
|
-
|
|
2344
|
+
writeFileSync8(configPath, `${START_MARKER}
|
|
2200
2345
|
${existing.trim()}
|
|
2201
2346
|
${END_MARKER}
|
|
2202
2347
|
`);
|
|
2203
2348
|
} else {
|
|
2204
|
-
if (!
|
|
2349
|
+
if (!existsSync12(backupPath)) {
|
|
2205
2350
|
copyFileSync(configPath, backupPath);
|
|
2206
2351
|
process.stderr.write(`exe-os: backed up existing Ghostty config to ${backupPath}
|
|
2207
2352
|
`);
|
|
2208
2353
|
}
|
|
2209
|
-
|
|
2354
|
+
writeFileSync8(configPath, `${markedSection}
|
|
2210
2355
|
|
|
2211
2356
|
${existing}`);
|
|
2212
2357
|
}
|
|
2213
2358
|
} else {
|
|
2214
|
-
|
|
2359
|
+
writeFileSync8(configPath, `${markedSection}
|
|
2215
2360
|
`);
|
|
2216
2361
|
}
|
|
2217
2362
|
process.stderr.write("exe-os: Ghostty config installed\n");
|
|
@@ -2235,6 +2380,7 @@ var init_installer = __esm({
|
|
|
2235
2380
|
init_agent_symlinks();
|
|
2236
2381
|
init_mcp_prefix();
|
|
2237
2382
|
init_preferences();
|
|
2383
|
+
init_mcp_http_config();
|
|
2238
2384
|
init_runtime_hook_manifest();
|
|
2239
2385
|
EXE_SECTION_START = "<!-- exe-os:orchestration-start -->";
|
|
2240
2386
|
EXE_SECTION_END = "<!-- exe-os:orchestration-end -->";
|
|
@@ -2253,8 +2399,8 @@ ${EXE_SECTION_END}`;
|
|
|
2253
2399
|
});
|
|
2254
2400
|
|
|
2255
2401
|
// src/bin/exe-new-employee.ts
|
|
2256
|
-
import { existsSync as
|
|
2257
|
-
import
|
|
2402
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync8 } from "fs";
|
|
2403
|
+
import path13 from "path";
|
|
2258
2404
|
|
|
2259
2405
|
// src/lib/session-wrappers.ts
|
|
2260
2406
|
import {
|
|
@@ -2428,6 +2574,12 @@ var PLATFORM_PROCEDURES = [
|
|
|
2428
2574
|
priority: "p0",
|
|
2429
2575
|
content: "Founder -> coordinator (the executive agent, internally routed as 'COO') -> CTO/CMO. CTO -> engineers. CMO -> content production. Never skip levels: the coordinator does not bypass managers for specialist work. Specialists report to their manager. If you need cross-team info, use ask_team_memory \u2014 don't read other agents' task folders. Each level owns dispatch downward and review upward."
|
|
2430
2576
|
},
|
|
2577
|
+
{
|
|
2578
|
+
title: "Customer orchestration maturity \u2014 recommend, never trap",
|
|
2579
|
+
domain: "workflow",
|
|
2580
|
+
priority: "p1",
|
|
2581
|
+
content: "New customers start best in Phase 1: founder \u2194 coordinator/Chief of Staff, building company context. Suggest Phase 2 executives when domain work repeats; suggest Phase 3 parallel execution only when review/permission gates are ready. This is guidance, not a blocker: users may jump phases anytime. Never overwrite their phase, role titles, identities, or custom org design."
|
|
2582
|
+
},
|
|
2431
2583
|
{
|
|
2432
2584
|
title: "Single dispatch path \u2014 create_task only",
|
|
2433
2585
|
domain: "workflow",
|
|
@@ -2486,6 +2638,12 @@ var PLATFORM_PROCEDURES = [
|
|
|
2486
2638
|
priority: "p0",
|
|
2487
2639
|
content: "exe-build-adv is MANDATORY for ALL work touching 3+ files. Run /exe-build-adv --auto BEFORE implementation. Pipeline: Spec \u2192 AC \u2192 Tests \u2192 Evaluate \u2192 Fix. No multi-file feature ships without pipeline artifacts. No exceptions \u2014 managers reject work without them."
|
|
2488
2640
|
},
|
|
2641
|
+
{
|
|
2642
|
+
title: "Commit discipline \u2014 never leave verified work floating",
|
|
2643
|
+
domain: "workflow",
|
|
2644
|
+
priority: "p1",
|
|
2645
|
+
content: "After any code-change batch passes typecheck/tests/build, run git status, summarize changed files, and commit with a clear message before ending the session. If work must remain uncommitted for review/dogfood, explicitly say so, list the files, and state the blocker. Never imply work is complete while verified changes are still floating locally."
|
|
2646
|
+
},
|
|
2489
2647
|
{
|
|
2490
2648
|
title: "Desktop and TUI are the same product",
|
|
2491
2649
|
domain: "architecture",
|
|
@@ -3351,7 +3509,7 @@ async function main() {
|
|
|
3351
3509
|
const templateKey = roleMap[effectiveTemplate] ?? null;
|
|
3352
3510
|
const identityTemplate = templateKey ? getIdentityTemplate(templateKey) : null;
|
|
3353
3511
|
const idPath = identityPath2(name);
|
|
3354
|
-
const dir =
|
|
3512
|
+
const dir = path13.dirname(idPath);
|
|
3355
3513
|
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
3356
3514
|
if (identityTemplate) {
|
|
3357
3515
|
const content = identityTemplate.replace(/^agent_id: \w+/m, `agent_id: ${name}`);
|
|
@@ -3373,9 +3531,9 @@ ${rolePrompt}`;
|
|
|
3373
3531
|
}
|
|
3374
3532
|
} catch {
|
|
3375
3533
|
}
|
|
3376
|
-
const taskDir =
|
|
3377
|
-
if (!
|
|
3378
|
-
|
|
3534
|
+
const taskDir = path13.join(process.cwd(), "exe", name);
|
|
3535
|
+
if (!existsSync13(taskDir)) {
|
|
3536
|
+
mkdirSync8(taskDir, { recursive: true });
|
|
3379
3537
|
}
|
|
3380
3538
|
const bins = registerBinSymlinks(newEmployee.name);
|
|
3381
3539
|
if (bins.created.length > 0) {
|