@askexenow/exe-os 0.9.8 → 0.9.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/backfill-conversations.js +222 -49
- package/dist/bin/backfill-responses.js +221 -48
- package/dist/bin/backfill-vectors.js +225 -52
- package/dist/bin/cleanup-stale-review-tasks.js +150 -28
- package/dist/bin/cli.js +1295 -856
- package/dist/bin/exe-agent-config.js +36 -8
- package/dist/bin/exe-agent.js +14 -4
- package/dist/bin/exe-assign.js +221 -48
- package/dist/bin/exe-boot.js +778 -427
- package/dist/bin/exe-call.js +41 -13
- package/dist/bin/exe-cloud.js +163 -58
- package/dist/bin/exe-dispatch.js +276 -139
- package/dist/bin/exe-doctor.js +145 -27
- package/dist/bin/exe-export-behaviors.js +141 -23
- package/dist/bin/exe-forget.js +137 -19
- package/dist/bin/exe-gateway.js +677 -388
- package/dist/bin/exe-heartbeat.js +227 -108
- package/dist/bin/exe-kill.js +138 -20
- package/dist/bin/exe-launch-agent.js +172 -39
- package/dist/bin/exe-link.js +291 -100
- package/dist/bin/exe-new-employee.js +214 -106
- package/dist/bin/exe-pending-messages.js +395 -33
- package/dist/bin/exe-pending-notifications.js +684 -99
- package/dist/bin/exe-pending-reviews.js +420 -74
- package/dist/bin/exe-rename.js +147 -49
- package/dist/bin/exe-review.js +138 -20
- package/dist/bin/exe-search.js +240 -69
- package/dist/bin/exe-session-cleanup.js +440 -250
- package/dist/bin/exe-settings.js +61 -17
- package/dist/bin/exe-start-codex.js +158 -39
- package/dist/bin/exe-start-opencode.js +157 -38
- package/dist/bin/exe-status.js +151 -29
- package/dist/bin/exe-team.js +138 -20
- package/dist/bin/git-sweep.js +404 -212
- package/dist/bin/graph-backfill.js +137 -19
- package/dist/bin/graph-export.js +140 -22
- package/dist/bin/install.js +90 -61
- package/dist/bin/scan-tasks.js +412 -220
- package/dist/bin/setup.js +564 -293
- package/dist/bin/shard-migrate.js +139 -21
- package/dist/bin/update.js +138 -49
- package/dist/bin/wiki-sync.js +137 -19
- package/dist/gateway/index.js +533 -320
- package/dist/hooks/bug-report-worker.js +344 -193
- package/dist/hooks/codex-stop-task-finalizer.js +4678 -0
- package/dist/hooks/commit-complete.js +402 -210
- package/dist/hooks/error-recall.js +245 -74
- package/dist/hooks/exe-heartbeat-hook.js +16 -6
- package/dist/hooks/ingest-worker.js +3423 -3157
- package/dist/hooks/ingest.js +832 -97
- package/dist/hooks/instructions-loaded.js +227 -54
- package/dist/hooks/notification.js +216 -43
- package/dist/hooks/post-compact.js +239 -62
- package/dist/hooks/pre-compact.js +408 -216
- package/dist/hooks/pre-tool-use.js +268 -90
- package/dist/hooks/prompt-ingest-worker.js +352 -102
- package/dist/hooks/prompt-submit.js +541 -328
- package/dist/hooks/response-ingest-worker.js +372 -122
- package/dist/hooks/session-end.js +443 -240
- package/dist/hooks/session-start.js +313 -127
- package/dist/hooks/stop.js +293 -98
- package/dist/hooks/subagent-stop.js +239 -62
- package/dist/hooks/summary-worker.js +568 -236
- package/dist/index.js +538 -324
- package/dist/lib/agent-config.js +28 -6
- package/dist/lib/cloud-sync.js +284 -105
- package/dist/lib/config.js +30 -10
- package/dist/lib/consolidation.js +16 -6
- package/dist/lib/database.js +123 -25
- package/dist/lib/db-daemon-client.js +73 -19
- package/dist/lib/db.js +123 -25
- package/dist/lib/device-registry.js +133 -35
- package/dist/lib/embedder.js +107 -32
- package/dist/lib/employee-templates.js +14 -4
- package/dist/lib/employees.js +41 -13
- package/dist/lib/exe-daemon-client.js +88 -22
- package/dist/lib/exe-daemon.js +935 -587
- package/dist/lib/hybrid-search.js +240 -69
- package/dist/lib/identity.js +18 -8
- package/dist/lib/license.js +133 -48
- package/dist/lib/messaging.js +116 -56
- package/dist/lib/reminders.js +14 -4
- package/dist/lib/schedules.js +137 -19
- package/dist/lib/skill-learning.js +33 -6
- package/dist/lib/store.js +137 -19
- package/dist/lib/task-router.js +14 -4
- package/dist/lib/tasks.js +280 -234
- package/dist/lib/tmux-routing.js +172 -125
- package/dist/lib/token-spend.js +26 -8
- package/dist/mcp/server.js +1326 -609
- package/dist/mcp/tools/complete-reminder.js +14 -4
- package/dist/mcp/tools/create-reminder.js +14 -4
- package/dist/mcp/tools/create-task.js +306 -248
- package/dist/mcp/tools/deactivate-behavior.js +16 -6
- package/dist/mcp/tools/list-reminders.js +14 -4
- package/dist/mcp/tools/list-tasks.js +123 -107
- package/dist/mcp/tools/send-message.js +75 -29
- package/dist/mcp/tools/update-task.js +1848 -199
- package/dist/runtime/index.js +441 -248
- package/dist/tui/App.js +761 -424
- package/package.json +1 -1
package/dist/bin/install.js
CHANGED
|
@@ -15,9 +15,34 @@ var __export = (target, all) => {
|
|
|
15
15
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
+
// src/lib/secure-files.ts
|
|
19
|
+
import { chmodSync, existsSync, mkdirSync } from "fs";
|
|
20
|
+
import { chmod, mkdir } from "fs/promises";
|
|
21
|
+
function ensurePrivateDirSync(dirPath) {
|
|
22
|
+
mkdirSync(dirPath, { recursive: true, mode: PRIVATE_DIR_MODE });
|
|
23
|
+
try {
|
|
24
|
+
chmodSync(dirPath, PRIVATE_DIR_MODE);
|
|
25
|
+
} catch {
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function enforcePrivateFileSync(filePath) {
|
|
29
|
+
try {
|
|
30
|
+
if (existsSync(filePath)) chmodSync(filePath, PRIVATE_FILE_MODE);
|
|
31
|
+
} catch {
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
var PRIVATE_DIR_MODE, PRIVATE_FILE_MODE;
|
|
35
|
+
var init_secure_files = __esm({
|
|
36
|
+
"src/lib/secure-files.ts"() {
|
|
37
|
+
"use strict";
|
|
38
|
+
PRIVATE_DIR_MODE = 448;
|
|
39
|
+
PRIVATE_FILE_MODE = 384;
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
18
43
|
// src/lib/config.ts
|
|
19
|
-
import { readFile, writeFile
|
|
20
|
-
import { readFileSync, existsSync, renameSync } from "fs";
|
|
44
|
+
import { readFile, writeFile } from "fs/promises";
|
|
45
|
+
import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
|
|
21
46
|
import path from "path";
|
|
22
47
|
import os from "os";
|
|
23
48
|
function resolveDataDir() {
|
|
@@ -25,7 +50,7 @@ function resolveDataDir() {
|
|
|
25
50
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
26
51
|
const newDir = path.join(os.homedir(), ".exe-os");
|
|
27
52
|
const legacyDir = path.join(os.homedir(), ".exe-mem");
|
|
28
|
-
if (!
|
|
53
|
+
if (!existsSync2(newDir) && existsSync2(legacyDir)) {
|
|
29
54
|
try {
|
|
30
55
|
renameSync(legacyDir, newDir);
|
|
31
56
|
process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
|
|
@@ -40,6 +65,7 @@ var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CON
|
|
|
40
65
|
var init_config = __esm({
|
|
41
66
|
"src/lib/config.ts"() {
|
|
42
67
|
"use strict";
|
|
68
|
+
init_secure_files();
|
|
43
69
|
EXE_AI_DIR = resolveDataDir();
|
|
44
70
|
DB_PATH = path.join(EXE_AI_DIR, "memories.db");
|
|
45
71
|
MODELS_DIR = path.join(EXE_AI_DIR, "models");
|
|
@@ -146,10 +172,10 @@ __export(agent_config_exports, {
|
|
|
146
172
|
saveAgentConfig: () => saveAgentConfig,
|
|
147
173
|
setAgentRuntime: () => setAgentRuntime
|
|
148
174
|
});
|
|
149
|
-
import { readFileSync as readFileSync2, writeFileSync, existsSync as
|
|
175
|
+
import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync3 } from "fs";
|
|
150
176
|
import path2 from "path";
|
|
151
177
|
function loadAgentConfig() {
|
|
152
|
-
if (!
|
|
178
|
+
if (!existsSync3(AGENT_CONFIG_PATH)) return {};
|
|
153
179
|
try {
|
|
154
180
|
return JSON.parse(readFileSync2(AGENT_CONFIG_PATH, "utf-8"));
|
|
155
181
|
} catch {
|
|
@@ -158,8 +184,9 @@ function loadAgentConfig() {
|
|
|
158
184
|
}
|
|
159
185
|
function saveAgentConfig(config) {
|
|
160
186
|
const dir = path2.dirname(AGENT_CONFIG_PATH);
|
|
161
|
-
|
|
187
|
+
ensurePrivateDirSync(dir);
|
|
162
188
|
writeFileSync(AGENT_CONFIG_PATH, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
189
|
+
enforcePrivateFileSync(AGENT_CONFIG_PATH);
|
|
163
190
|
}
|
|
164
191
|
function getAgentRuntime(agentId) {
|
|
165
192
|
const config = loadAgentConfig();
|
|
@@ -199,6 +226,7 @@ var init_agent_config = __esm({
|
|
|
199
226
|
"use strict";
|
|
200
227
|
init_config();
|
|
201
228
|
init_runtime_table();
|
|
229
|
+
init_secure_files();
|
|
202
230
|
AGENT_CONFIG_PATH = path2.join(EXE_AI_DIR, "agent-config.json");
|
|
203
231
|
KNOWN_RUNTIMES = {
|
|
204
232
|
claude: ["claude-opus-4", "claude-sonnet-4", "claude-haiku-4.5"],
|
|
@@ -246,7 +274,7 @@ __export(employees_exports, {
|
|
|
246
274
|
validateEmployeeName: () => validateEmployeeName
|
|
247
275
|
});
|
|
248
276
|
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
249
|
-
import { existsSync as
|
|
277
|
+
import { existsSync as existsSync4, symlinkSync, readlinkSync, readFileSync as readFileSync3, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
|
|
250
278
|
import { execSync } from "child_process";
|
|
251
279
|
import path3 from "path";
|
|
252
280
|
import os2 from "os";
|
|
@@ -285,7 +313,7 @@ function validateEmployeeName(name) {
|
|
|
285
313
|
return { valid: true };
|
|
286
314
|
}
|
|
287
315
|
async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
|
|
288
|
-
if (!
|
|
316
|
+
if (!existsSync4(employeesPath)) {
|
|
289
317
|
return [];
|
|
290
318
|
}
|
|
291
319
|
const raw = await readFile2(employeesPath, "utf-8");
|
|
@@ -300,7 +328,7 @@ async function saveEmployees(employees, employeesPath = EMPLOYEES_PATH) {
|
|
|
300
328
|
await writeFile2(employeesPath, JSON.stringify(employees, null, 2) + "\n", "utf-8");
|
|
301
329
|
}
|
|
302
330
|
function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
|
|
303
|
-
if (!
|
|
331
|
+
if (!existsSync4(employeesPath)) return [];
|
|
304
332
|
try {
|
|
305
333
|
return JSON.parse(readFileSync3(employeesPath, "utf-8"));
|
|
306
334
|
} catch {
|
|
@@ -348,7 +376,7 @@ function appendToCoordinatorTeam(employee) {
|
|
|
348
376
|
const coordinator = getCoordinatorEmployee(loadEmployeesSync());
|
|
349
377
|
if (!coordinator) return;
|
|
350
378
|
const idPath = path3.join(IDENTITY_DIR, `${coordinator.name}.md`);
|
|
351
|
-
if (!
|
|
379
|
+
if (!existsSync4(idPath)) return;
|
|
352
380
|
const content = readFileSync3(idPath, "utf-8");
|
|
353
381
|
if (content.includes(`**${capitalize(employee.name)}`)) return;
|
|
354
382
|
const teamMatch = content.match(TEAM_SECTION_RE);
|
|
@@ -402,9 +430,9 @@ async function normalizeRosterCase(rosterPath) {
|
|
|
402
430
|
const identityDir = path3.join(os2.homedir(), ".exe-os", "identity");
|
|
403
431
|
const oldPath = path3.join(identityDir, `${oldName}.md`);
|
|
404
432
|
const newPath = path3.join(identityDir, `${emp.name}.md`);
|
|
405
|
-
if (
|
|
433
|
+
if (existsSync4(oldPath) && !existsSync4(newPath)) {
|
|
406
434
|
renameSync2(oldPath, newPath);
|
|
407
|
-
} else if (
|
|
435
|
+
} else if (existsSync4(oldPath) && oldPath !== newPath) {
|
|
408
436
|
const content = readFileSync3(oldPath, "utf-8");
|
|
409
437
|
writeFileSync2(newPath, content, "utf-8");
|
|
410
438
|
if (oldPath.toLowerCase() !== newPath.toLowerCase()) {
|
|
@@ -447,7 +475,7 @@ function registerBinSymlinks(name) {
|
|
|
447
475
|
for (const suffix of ["", "-opencode"]) {
|
|
448
476
|
const linkName = `${name}${suffix}`;
|
|
449
477
|
const linkPath = path3.join(binDir, linkName);
|
|
450
|
-
if (
|
|
478
|
+
if (existsSync4(linkPath)) {
|
|
451
479
|
skipped.push(linkName);
|
|
452
480
|
continue;
|
|
453
481
|
}
|
|
@@ -478,7 +506,7 @@ var init_employees = __esm({
|
|
|
478
506
|
import os3 from "os";
|
|
479
507
|
import path4 from "path";
|
|
480
508
|
import {
|
|
481
|
-
existsSync as
|
|
509
|
+
existsSync as existsSync5,
|
|
482
510
|
lstatSync,
|
|
483
511
|
mkdirSync as mkdirSync2,
|
|
484
512
|
readlinkSync as readlinkSync2,
|
|
@@ -497,7 +525,7 @@ function ensureAgentSymlink(agentId, homeDir = os3.homedir()) {
|
|
|
497
525
|
const target = identitySourcePath(homeDir, agentId);
|
|
498
526
|
const link = claudeAgentLinkPath(homeDir, agentId);
|
|
499
527
|
mkdirSync2(claudeAgentsDir(homeDir), { recursive: true });
|
|
500
|
-
if (
|
|
528
|
+
if (existsSync5(link)) {
|
|
501
529
|
let stat;
|
|
502
530
|
try {
|
|
503
531
|
stat = lstatSync(link);
|
|
@@ -566,12 +594,12 @@ var init_mcp_prefix = __esm({
|
|
|
566
594
|
});
|
|
567
595
|
|
|
568
596
|
// src/lib/preferences.ts
|
|
569
|
-
import { existsSync as
|
|
597
|
+
import { existsSync as existsSync6, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
570
598
|
import path5 from "path";
|
|
571
599
|
import os4 from "os";
|
|
572
600
|
function loadPreferences(homeDir = os4.homedir()) {
|
|
573
601
|
const configPath = path5.join(homeDir, ".exe-os", "config.json");
|
|
574
|
-
if (!
|
|
602
|
+
if (!existsSync6(configPath)) return {};
|
|
575
603
|
try {
|
|
576
604
|
const config = JSON.parse(readFileSync4(configPath, "utf-8"));
|
|
577
605
|
return config.preferences ?? {};
|
|
@@ -582,12 +610,13 @@ function loadPreferences(homeDir = os4.homedir()) {
|
|
|
582
610
|
var init_preferences = __esm({
|
|
583
611
|
"src/lib/preferences.ts"() {
|
|
584
612
|
"use strict";
|
|
613
|
+
init_secure_files();
|
|
585
614
|
}
|
|
586
615
|
});
|
|
587
616
|
|
|
588
617
|
// src/adapters/claude/installer.ts
|
|
589
618
|
import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3, readdir } from "fs/promises";
|
|
590
|
-
import { existsSync as
|
|
619
|
+
import { existsSync as existsSync7, readFileSync as readFileSync5, writeFileSync as writeFileSync4, copyFileSync, mkdirSync as mkdirSync3 } from "fs";
|
|
591
620
|
import path6 from "path";
|
|
592
621
|
import os5 from "os";
|
|
593
622
|
import { execSync as execSync2 } from "child_process";
|
|
@@ -598,7 +627,7 @@ function resolvePackageRoot() {
|
|
|
598
627
|
const root = path6.parse(dir).root;
|
|
599
628
|
while (dir !== root) {
|
|
600
629
|
const pkgPath = path6.join(dir, "package.json");
|
|
601
|
-
if (
|
|
630
|
+
if (existsSync7(pkgPath)) {
|
|
602
631
|
try {
|
|
603
632
|
const pkg = JSON.parse(readFileSync5(pkgPath, "utf-8"));
|
|
604
633
|
if (pkg.name === "@askexenow/exe-os" || pkg.name === "exe-os") return dir;
|
|
@@ -614,7 +643,7 @@ async function copySlashCommands(packageRoot, homeDir = os5.homedir()) {
|
|
|
614
643
|
let skipped = 0;
|
|
615
644
|
const skillsBase = path6.join(homeDir, ".claude", "skills");
|
|
616
645
|
const exeDir = path6.join(packageRoot, "src", "commands", "exe");
|
|
617
|
-
if (
|
|
646
|
+
if (existsSync7(exeDir)) {
|
|
618
647
|
const entries = await readdir(exeDir);
|
|
619
648
|
const mdFiles = entries.filter((f) => f.endsWith(".md"));
|
|
620
649
|
for (const file of mdFiles) {
|
|
@@ -629,7 +658,7 @@ async function copySlashCommands(packageRoot, homeDir = os5.homedir()) {
|
|
|
629
658
|
}
|
|
630
659
|
}
|
|
631
660
|
const topLevelSrc = path6.join(packageRoot, "src", "commands", "exe.md");
|
|
632
|
-
if (
|
|
661
|
+
if (existsSync7(topLevelSrc)) {
|
|
633
662
|
const destDir = path6.join(skillsBase, "exe");
|
|
634
663
|
await mkdir3(destDir, { recursive: true });
|
|
635
664
|
const destPath = path6.join(destDir, "SKILL.md");
|
|
@@ -655,7 +684,7 @@ name: ${skillName}
|
|
|
655
684
|
`);
|
|
656
685
|
}
|
|
657
686
|
}
|
|
658
|
-
if (
|
|
687
|
+
if (existsSync7(destPath)) {
|
|
659
688
|
const existing = await readFile3(destPath, "utf-8");
|
|
660
689
|
if (existing === content) return false;
|
|
661
690
|
}
|
|
@@ -665,7 +694,7 @@ name: ${skillName}
|
|
|
665
694
|
async function registerMcpServer(packageRoot, homeDir = os5.homedir()) {
|
|
666
695
|
const claudeJsonPath = path6.join(homeDir, ".claude.json");
|
|
667
696
|
let claudeJson = {};
|
|
668
|
-
if (
|
|
697
|
+
if (existsSync7(claudeJsonPath)) {
|
|
669
698
|
try {
|
|
670
699
|
claudeJson = JSON.parse(await readFile3(claudeJsonPath, "utf-8"));
|
|
671
700
|
} catch {
|
|
@@ -682,21 +711,21 @@ async function registerMcpServer(packageRoot, homeDir = os5.homedir()) {
|
|
|
682
711
|
env: {}
|
|
683
712
|
};
|
|
684
713
|
const currentMem = claudeJson.mcpServers[MCP_LEGACY_KEY];
|
|
685
|
-
const currentOs = claudeJson.mcpServers[MCP_PRIMARY_KEY];
|
|
686
714
|
const memMatches = currentMem && JSON.stringify(currentMem) === JSON.stringify(newEntry);
|
|
687
|
-
|
|
688
|
-
|
|
715
|
+
if (claudeJson.mcpServers[MCP_PRIMARY_KEY]) {
|
|
716
|
+
delete claudeJson.mcpServers[MCP_PRIMARY_KEY];
|
|
717
|
+
}
|
|
718
|
+
if (memMatches && !claudeJson.mcpServers[MCP_PRIMARY_KEY]) {
|
|
689
719
|
await cleanSettingsJsonMcp(path6.join(homeDir, ".claude", "settings.json"));
|
|
690
720
|
return false;
|
|
691
721
|
}
|
|
692
722
|
claudeJson.mcpServers[MCP_LEGACY_KEY] = newEntry;
|
|
693
|
-
claudeJson.mcpServers[MCP_PRIMARY_KEY] = newEntry;
|
|
694
723
|
await writeFile3(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
|
|
695
724
|
await cleanSettingsJsonMcp(path6.join(homeDir, ".claude", "settings.json"));
|
|
696
725
|
return true;
|
|
697
726
|
}
|
|
698
727
|
async function cleanSettingsJsonMcp(settingsPath) {
|
|
699
|
-
if (!
|
|
728
|
+
if (!existsSync7(settingsPath)) return;
|
|
700
729
|
try {
|
|
701
730
|
const settings = JSON.parse(await readFile3(settingsPath, "utf-8"));
|
|
702
731
|
const servers = settings.mcpServers;
|
|
@@ -723,7 +752,7 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
|
|
|
723
752
|
const logSuffix = ` 2>> "${hookLogPath}"`;
|
|
724
753
|
await mkdir3(logsDir, { recursive: true });
|
|
725
754
|
let settings = {};
|
|
726
|
-
if (
|
|
755
|
+
if (existsSync7(settingsPath)) {
|
|
727
756
|
try {
|
|
728
757
|
settings = JSON.parse(await readFile3(settingsPath, "utf-8"));
|
|
729
758
|
} catch {
|
|
@@ -991,7 +1020,7 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
|
|
|
991
1020
|
}
|
|
992
1021
|
async function cleanOldShellFunctions(homeDir = os5.homedir()) {
|
|
993
1022
|
const rosterPath = path6.join(homeDir, ".exe-os", "exe-employees.json");
|
|
994
|
-
if (!
|
|
1023
|
+
if (!existsSync7(rosterPath)) return 0;
|
|
995
1024
|
let employees;
|
|
996
1025
|
try {
|
|
997
1026
|
employees = JSON.parse(await readFile3(rosterPath, "utf-8"));
|
|
@@ -1012,7 +1041,7 @@ async function cleanOldShellFunctions(homeDir = os5.homedir()) {
|
|
|
1012
1041
|
const REMOVED_MARKER = "# Removed by exe-os \u2014 wrappers now at ~/.exe-os/bin/";
|
|
1013
1042
|
let totalRemoved = 0;
|
|
1014
1043
|
for (const rcPath of rcFiles) {
|
|
1015
|
-
if (!
|
|
1044
|
+
if (!existsSync7(rcPath)) continue;
|
|
1016
1045
|
let content;
|
|
1017
1046
|
try {
|
|
1018
1047
|
content = await readFile3(rcPath, "utf-8");
|
|
@@ -1145,13 +1174,13 @@ async function installStatusLine(packageRoot, homeDir = os5.homedir()) {
|
|
|
1145
1174
|
const claudeDir = path6.join(homeDir, ".claude");
|
|
1146
1175
|
await mkdir3(claudeDir, { recursive: true });
|
|
1147
1176
|
const assetPath = path6.join(packageRoot, "dist", "assets", "statusline-command.sh");
|
|
1148
|
-
if (!
|
|
1177
|
+
if (!existsSync7(assetPath)) return "asset-missing";
|
|
1149
1178
|
const destScript = path6.join(claudeDir, "statusline-command.sh");
|
|
1150
1179
|
const assetContent = await readFile3(assetPath, "utf-8");
|
|
1151
1180
|
await writeFile3(destScript, assetContent, { mode: 493 });
|
|
1152
1181
|
const settingsPath = path6.join(claudeDir, "settings.json");
|
|
1153
1182
|
let settings = {};
|
|
1154
|
-
if (
|
|
1183
|
+
if (existsSync7(settingsPath)) {
|
|
1155
1184
|
try {
|
|
1156
1185
|
settings = JSON.parse(await readFile3(settingsPath, "utf-8"));
|
|
1157
1186
|
} catch {
|
|
@@ -1190,7 +1219,7 @@ async function runInstaller(homeDir) {
|
|
|
1190
1219
|
);
|
|
1191
1220
|
const resolvedHome = homeDir ?? os5.homedir();
|
|
1192
1221
|
const exeWorkspace = path6.join(resolvedHome, "exe");
|
|
1193
|
-
if (!
|
|
1222
|
+
if (!existsSync7(exeWorkspace)) {
|
|
1194
1223
|
try {
|
|
1195
1224
|
await mkdir3(path6.join(exeWorkspace, "content"), { recursive: true });
|
|
1196
1225
|
await mkdir3(path6.join(exeWorkspace, "operations"), { recursive: true });
|
|
@@ -1237,17 +1266,17 @@ function setupTmux(home) {
|
|
|
1237
1266
|
const sourceLine = "source-file ~/.exe-os/tmux.conf";
|
|
1238
1267
|
const pkgRoot = resolvePackageRoot();
|
|
1239
1268
|
const assetPath = path6.join(pkgRoot, "dist", "assets", "tmux.conf");
|
|
1240
|
-
if (!
|
|
1269
|
+
if (!existsSync7(assetPath)) {
|
|
1241
1270
|
process.stderr.write(`exe-os: tmux.conf asset not found at ${assetPath} \u2014 skipping tmux setup
|
|
1242
1271
|
`);
|
|
1243
1272
|
return;
|
|
1244
1273
|
}
|
|
1245
|
-
|
|
1274
|
+
mkdirSync3(exeDir, { recursive: true });
|
|
1246
1275
|
copyFileSync(assetPath, exeTmuxConf);
|
|
1247
|
-
if (
|
|
1276
|
+
if (existsSync7(userTmuxConf)) {
|
|
1248
1277
|
const existing = readFileSync5(userTmuxConf, "utf8");
|
|
1249
1278
|
if (!existing.includes(sourceLine)) {
|
|
1250
|
-
if (!
|
|
1279
|
+
if (!existsSync7(backupPath)) {
|
|
1251
1280
|
copyFileSync(userTmuxConf, backupPath);
|
|
1252
1281
|
process.stderr.write(`exe-os: backed up existing tmux config to ${backupPath}
|
|
1253
1282
|
`);
|
|
@@ -1270,7 +1299,7 @@ function setupGhostty(home) {
|
|
|
1270
1299
|
const homeDir = home ?? os5.homedir();
|
|
1271
1300
|
const xdgConfig = path6.join(homeDir, ".config", "ghostty");
|
|
1272
1301
|
const macConfig = path6.join(homeDir, "Library", "Application Support", "com.mitchellh.ghostty");
|
|
1273
|
-
const ghosttyInstalled =
|
|
1302
|
+
const ghosttyInstalled = existsSync7(xdgConfig) || existsSync7(macConfig) || (() => {
|
|
1274
1303
|
try {
|
|
1275
1304
|
execSync2("which ghostty 2>/dev/null");
|
|
1276
1305
|
return true;
|
|
@@ -1283,28 +1312,28 @@ function setupGhostty(home) {
|
|
|
1283
1312
|
}
|
|
1284
1313
|
const pkgRoot = resolvePackageRoot();
|
|
1285
1314
|
const assetPath = path6.join(pkgRoot, "dist", "assets", "ghostty.conf");
|
|
1286
|
-
if (!
|
|
1315
|
+
if (!existsSync7(assetPath)) {
|
|
1287
1316
|
process.stderr.write("exe-os: ghostty.conf asset not found \u2014 skipping Ghostty setup\n");
|
|
1288
1317
|
return;
|
|
1289
1318
|
}
|
|
1290
1319
|
const configDir = xdgConfig;
|
|
1291
1320
|
const configPath = path6.join(configDir, "config");
|
|
1292
1321
|
const backupPath = path6.join(configDir, "config.backup");
|
|
1293
|
-
|
|
1322
|
+
mkdirSync3(configDir, { recursive: true });
|
|
1294
1323
|
const START_MARKER = "# \u2500\u2500 exe-os:ghostty-start \u2500\u2500";
|
|
1295
1324
|
const END_MARKER = "# \u2500\u2500 exe-os:ghostty-end \u2500\u2500";
|
|
1296
1325
|
const assetContent = readFileSync5(assetPath, "utf8").trim();
|
|
1297
1326
|
const markedSection = `${START_MARKER}
|
|
1298
1327
|
${assetContent}
|
|
1299
1328
|
${END_MARKER}`;
|
|
1300
|
-
if (
|
|
1329
|
+
if (existsSync7(configPath)) {
|
|
1301
1330
|
const existing = readFileSync5(configPath, "utf8");
|
|
1302
1331
|
if (existing.includes(START_MARKER) && existing.includes(END_MARKER)) {
|
|
1303
1332
|
const before = existing.slice(0, existing.indexOf(START_MARKER));
|
|
1304
1333
|
const after = existing.slice(existing.indexOf(END_MARKER) + END_MARKER.length);
|
|
1305
1334
|
writeFileSync4(configPath, `${before}${markedSection}${after}`);
|
|
1306
1335
|
} else if (existing.includes("Exe OS")) {
|
|
1307
|
-
if (!
|
|
1336
|
+
if (!existsSync7(backupPath)) {
|
|
1308
1337
|
copyFileSync(configPath, backupPath);
|
|
1309
1338
|
process.stderr.write(`exe-os: backed up existing Ghostty config to ${backupPath}
|
|
1310
1339
|
`);
|
|
@@ -1312,7 +1341,7 @@ ${END_MARKER}`;
|
|
|
1312
1341
|
writeFileSync4(configPath, `${markedSection}
|
|
1313
1342
|
`);
|
|
1314
1343
|
} else {
|
|
1315
|
-
if (!
|
|
1344
|
+
if (!existsSync7(backupPath)) {
|
|
1316
1345
|
copyFileSync(configPath, backupPath);
|
|
1317
1346
|
process.stderr.write(`exe-os: backed up existing Ghostty config to ${backupPath}
|
|
1318
1347
|
`);
|
|
@@ -1371,7 +1400,7 @@ __export(installer_exports, {
|
|
|
1371
1400
|
verifyCodexHooks: () => verifyCodexHooks
|
|
1372
1401
|
});
|
|
1373
1402
|
import { readFile as readFile4, writeFile as writeFile4, mkdir as mkdir4 } from "fs/promises";
|
|
1374
|
-
import { existsSync as
|
|
1403
|
+
import { existsSync as existsSync9 } from "fs";
|
|
1375
1404
|
import path8 from "path";
|
|
1376
1405
|
import os6 from "os";
|
|
1377
1406
|
async function mergeCodexHooks(packageRoot, homeDir = os6.homedir()) {
|
|
@@ -1383,7 +1412,7 @@ async function mergeCodexHooks(packageRoot, homeDir = os6.homedir()) {
|
|
|
1383
1412
|
await mkdir4(codexDir, { recursive: true });
|
|
1384
1413
|
await mkdir4(logsDir, { recursive: true });
|
|
1385
1414
|
let hooksJson = {};
|
|
1386
|
-
if (
|
|
1415
|
+
if (existsSync9(hooksPath)) {
|
|
1387
1416
|
try {
|
|
1388
1417
|
hooksJson = JSON.parse(await readFile4(hooksPath, "utf-8"));
|
|
1389
1418
|
} catch {
|
|
@@ -1494,7 +1523,7 @@ async function mergeCodexHooks(packageRoot, homeDir = os6.homedir()) {
|
|
|
1494
1523
|
}
|
|
1495
1524
|
function verifyCodexHooks(homeDir = os6.homedir()) {
|
|
1496
1525
|
const hooksPath = path8.join(homeDir, ".codex", "hooks.json");
|
|
1497
|
-
if (!
|
|
1526
|
+
if (!existsSync9(hooksPath)) return false;
|
|
1498
1527
|
try {
|
|
1499
1528
|
const hooksJson = JSON.parse(
|
|
1500
1529
|
__require("fs").readFileSync(hooksPath, "utf-8")
|
|
@@ -1521,7 +1550,7 @@ async function installCodexStatusLine(homeDir = os6.homedir()) {
|
|
|
1521
1550
|
const configPath = path8.join(codexDir, "config.toml");
|
|
1522
1551
|
await mkdir4(codexDir, { recursive: true });
|
|
1523
1552
|
let content = "";
|
|
1524
|
-
if (
|
|
1553
|
+
if (existsSync9(configPath)) {
|
|
1525
1554
|
content = await readFile4(configPath, "utf-8");
|
|
1526
1555
|
if (/\[tui\][\s\S]*?status_line\s*=/.test(content)) {
|
|
1527
1556
|
return "already-configured";
|
|
@@ -1570,18 +1599,18 @@ var init_installer2 = __esm({
|
|
|
1570
1599
|
|
|
1571
1600
|
// src/bin/install.ts
|
|
1572
1601
|
init_installer();
|
|
1573
|
-
import { existsSync as
|
|
1602
|
+
import { existsSync as existsSync10, readFileSync as readFileSync7, unlinkSync as unlinkSync3, readdirSync as readdirSync2, openSync, closeSync } from "fs";
|
|
1574
1603
|
import { spawn, execSync as execSync3 } from "child_process";
|
|
1575
1604
|
import path9 from "path";
|
|
1576
1605
|
import os7 from "os";
|
|
1577
1606
|
|
|
1578
1607
|
// src/lib/session-wrappers.ts
|
|
1579
1608
|
import {
|
|
1580
|
-
existsSync as
|
|
1609
|
+
existsSync as existsSync8,
|
|
1581
1610
|
readFileSync as readFileSync6,
|
|
1582
1611
|
writeFileSync as writeFileSync5,
|
|
1583
|
-
mkdirSync as
|
|
1584
|
-
chmodSync,
|
|
1612
|
+
mkdirSync as mkdirSync4,
|
|
1613
|
+
chmodSync as chmodSync2,
|
|
1585
1614
|
readdirSync,
|
|
1586
1615
|
unlinkSync as unlinkSync2
|
|
1587
1616
|
} from "fs";
|
|
@@ -1592,16 +1621,16 @@ function generateSessionWrappers(packageRoot, homeDir) {
|
|
|
1592
1621
|
const home = homeDir ?? homedir();
|
|
1593
1622
|
const binDir = path7.join(home, ".exe-os", "bin");
|
|
1594
1623
|
const rosterPath = path7.join(home, ".exe-os", "exe-employees.json");
|
|
1595
|
-
|
|
1624
|
+
mkdirSync4(binDir, { recursive: true });
|
|
1596
1625
|
const exeStartDst = path7.join(binDir, "exe-start");
|
|
1597
1626
|
const candidates = [
|
|
1598
1627
|
path7.join(packageRoot, "dist", "bin", "exe-start.sh"),
|
|
1599
1628
|
path7.join(packageRoot, "src", "bin", "exe-start.sh")
|
|
1600
1629
|
];
|
|
1601
1630
|
for (const src of candidates) {
|
|
1602
|
-
if (
|
|
1631
|
+
if (existsSync8(src)) {
|
|
1603
1632
|
writeFileSync5(exeStartDst, readFileSync6(src));
|
|
1604
|
-
|
|
1633
|
+
chmodSync2(exeStartDst, 493);
|
|
1605
1634
|
break;
|
|
1606
1635
|
}
|
|
1607
1636
|
}
|
|
@@ -1636,7 +1665,7 @@ exec "${exeStartDst}" "$0" "$@"
|
|
|
1636
1665
|
for (let n = 1; n <= MAX_N; n++) {
|
|
1637
1666
|
const wrapperPath = path7.join(binDir, `${emp.name}${n}`);
|
|
1638
1667
|
writeFileSync5(wrapperPath, wrapperContent);
|
|
1639
|
-
|
|
1668
|
+
chmodSync2(wrapperPath, 493);
|
|
1640
1669
|
created++;
|
|
1641
1670
|
}
|
|
1642
1671
|
}
|
|
@@ -1646,7 +1675,7 @@ exec "${exeStartDst}" "$0" "$@"
|
|
|
1646
1675
|
];
|
|
1647
1676
|
let codexLauncher = null;
|
|
1648
1677
|
for (const c of codexLauncherCandidates) {
|
|
1649
|
-
if (
|
|
1678
|
+
if (existsSync8(c)) {
|
|
1650
1679
|
codexLauncher = c;
|
|
1651
1680
|
break;
|
|
1652
1681
|
}
|
|
@@ -1658,7 +1687,7 @@ exec "${exeStartDst}" "$0" "$@"
|
|
|
1658
1687
|
exec node "${codexLauncher}" --agent ${emp.name} "$@"
|
|
1659
1688
|
`;
|
|
1660
1689
|
writeFileSync5(wrapperPath, content);
|
|
1661
|
-
|
|
1690
|
+
chmodSync2(wrapperPath, 493);
|
|
1662
1691
|
created++;
|
|
1663
1692
|
}
|
|
1664
1693
|
}
|
|
@@ -1709,7 +1738,7 @@ function restartDaemon() {
|
|
|
1709
1738
|
const pidPath = path9.join(EXE_DIR, "exed.pid");
|
|
1710
1739
|
const sockPath = path9.join(EXE_DIR, "exed.sock");
|
|
1711
1740
|
try {
|
|
1712
|
-
if (
|
|
1741
|
+
if (existsSync10(pidPath)) {
|
|
1713
1742
|
const pid = parseInt(readFileSync7(pidPath, "utf8").trim(), 10);
|
|
1714
1743
|
if (!isNaN(pid) && pid > 0) {
|
|
1715
1744
|
try {
|
|
@@ -1752,7 +1781,7 @@ function restartDaemon() {
|
|
|
1752
1781
|
}
|
|
1753
1782
|
try {
|
|
1754
1783
|
const wpDir = path9.join(EXE_DIR, "worker-pids");
|
|
1755
|
-
if (
|
|
1784
|
+
if (existsSync10(wpDir)) {
|
|
1756
1785
|
for (const f of readdirSync2(wpDir)) {
|
|
1757
1786
|
try {
|
|
1758
1787
|
unlinkSync3(path9.join(wpDir, f));
|
|
@@ -1783,7 +1812,7 @@ function restartDaemon() {
|
|
|
1783
1812
|
try {
|
|
1784
1813
|
const pkgRoot = resolvePackageRoot();
|
|
1785
1814
|
const daemonPath = path9.join(pkgRoot, "dist", "lib", "exe-daemon.js");
|
|
1786
|
-
if (!
|
|
1815
|
+
if (!existsSync10(daemonPath)) {
|
|
1787
1816
|
process.stderr.write(`exe-os: daemon not found at ${daemonPath} \u2014 skipping respawn
|
|
1788
1817
|
`);
|
|
1789
1818
|
return;
|