@askexenow/exe-os 0.9.7 → 0.9.8
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 +754 -79
- package/dist/bin/backfill-responses.js +752 -77
- package/dist/bin/backfill-vectors.js +752 -77
- package/dist/bin/cleanup-stale-review-tasks.js +657 -35
- package/dist/bin/cli.js +1388 -605
- package/dist/bin/exe-agent-config.js +123 -95
- package/dist/bin/exe-agent.js +41 -25
- package/dist/bin/exe-assign.js +732 -57
- package/dist/bin/exe-boot.js +784 -153
- package/dist/bin/exe-call.js +209 -138
- package/dist/bin/exe-cloud.js +35 -12
- package/dist/bin/exe-dispatch.js +692 -70
- package/dist/bin/exe-doctor.js +648 -26
- package/dist/bin/exe-export-behaviors.js +650 -20
- package/dist/bin/exe-forget.js +635 -13
- package/dist/bin/exe-gateway.js +1053 -271
- package/dist/bin/exe-heartbeat.js +665 -43
- package/dist/bin/exe-kill.js +646 -16
- package/dist/bin/exe-launch-agent.js +887 -97
- package/dist/bin/exe-link.js +658 -43
- package/dist/bin/exe-new-employee.js +378 -177
- package/dist/bin/exe-pending-messages.js +656 -34
- package/dist/bin/exe-pending-notifications.js +635 -13
- package/dist/bin/exe-pending-reviews.js +659 -37
- package/dist/bin/exe-rename.js +645 -30
- package/dist/bin/exe-review.js +635 -13
- package/dist/bin/exe-search.js +771 -88
- package/dist/bin/exe-session-cleanup.js +834 -150
- package/dist/bin/exe-settings.js +127 -91
- package/dist/bin/exe-start-codex.js +729 -94
- package/dist/bin/exe-start-opencode.js +717 -82
- package/dist/bin/exe-status.js +657 -35
- package/dist/bin/exe-team.js +635 -13
- package/dist/bin/git-sweep.js +720 -89
- package/dist/bin/graph-backfill.js +643 -13
- package/dist/bin/graph-export.js +646 -16
- package/dist/bin/install.js +596 -193
- package/dist/bin/scan-tasks.js +724 -93
- package/dist/bin/setup.js +1038 -210
- package/dist/bin/shard-migrate.js +645 -15
- package/dist/bin/wiki-sync.js +646 -16
- package/dist/gateway/index.js +1027 -245
- package/dist/hooks/bug-report-worker.js +891 -170
- package/dist/hooks/commit-complete.js +718 -87
- package/dist/hooks/error-recall.js +776 -93
- package/dist/hooks/exe-heartbeat-hook.js +85 -71
- package/dist/hooks/ingest-worker.js +840 -156
- package/dist/hooks/ingest.js +90 -73
- package/dist/hooks/instructions-loaded.js +669 -38
- package/dist/hooks/notification.js +661 -30
- package/dist/hooks/post-compact.js +674 -43
- package/dist/hooks/pre-compact.js +718 -87
- package/dist/hooks/pre-tool-use.js +872 -125
- package/dist/hooks/prompt-ingest-worker.js +758 -83
- package/dist/hooks/prompt-submit.js +1060 -319
- package/dist/hooks/response-ingest-worker.js +758 -83
- package/dist/hooks/session-end.js +721 -90
- package/dist/hooks/session-start.js +1031 -207
- package/dist/hooks/stop.js +680 -49
- package/dist/hooks/subagent-stop.js +674 -43
- package/dist/hooks/summary-worker.js +816 -132
- package/dist/index.js +1015 -232
- package/dist/lib/cloud-sync.js +663 -48
- package/dist/lib/consolidation.js +26 -3
- package/dist/lib/database.js +626 -18
- package/dist/lib/db.js +2261 -0
- package/dist/lib/device-registry.js +640 -25
- package/dist/lib/embedder.js +96 -43
- package/dist/lib/employee-templates.js +16 -0
- package/dist/lib/employees.js +259 -83
- package/dist/lib/exe-daemon-client.js +101 -63
- package/dist/lib/exe-daemon.js +894 -162
- package/dist/lib/hybrid-search.js +771 -88
- package/dist/lib/identity.js +27 -7
- package/dist/lib/messaging.js +55 -28
- package/dist/lib/reminders.js +21 -1
- package/dist/lib/schedules.js +636 -14
- package/dist/lib/skill-learning.js +21 -1
- package/dist/lib/store.js +643 -13
- package/dist/lib/task-router.js +82 -71
- package/dist/lib/tasks.js +98 -71
- package/dist/lib/tmux-routing.js +87 -60
- package/dist/lib/token-spend.js +26 -6
- package/dist/mcp/server.js +1784 -458
- package/dist/mcp/tools/complete-reminder.js +21 -1
- package/dist/mcp/tools/create-reminder.js +21 -1
- package/dist/mcp/tools/create-task.js +290 -164
- package/dist/mcp/tools/deactivate-behavior.js +24 -4
- package/dist/mcp/tools/list-reminders.js +21 -1
- package/dist/mcp/tools/list-tasks.js +195 -38
- package/dist/mcp/tools/send-message.js +58 -31
- package/dist/mcp/tools/update-task.js +75 -48
- package/dist/runtime/index.js +720 -89
- package/dist/tui/App.js +853 -123
- package/package.json +3 -2
package/dist/bin/cli.js
CHANGED
|
@@ -266,6 +266,118 @@ var init_config = __esm({
|
|
|
266
266
|
}
|
|
267
267
|
});
|
|
268
268
|
|
|
269
|
+
// src/lib/runtime-table.ts
|
|
270
|
+
var RUNTIME_TABLE, DEFAULT_RUNTIME;
|
|
271
|
+
var init_runtime_table = __esm({
|
|
272
|
+
"src/lib/runtime-table.ts"() {
|
|
273
|
+
"use strict";
|
|
274
|
+
RUNTIME_TABLE = {
|
|
275
|
+
codex: {
|
|
276
|
+
binary: "codex",
|
|
277
|
+
launchMode: "interactive",
|
|
278
|
+
autoApproveFlag: "--dangerously-bypass-approvals-and-sandbox",
|
|
279
|
+
inlineFlag: "--no-alt-screen",
|
|
280
|
+
apiKeyEnv: "OPENAI_API_KEY",
|
|
281
|
+
defaultModel: "gpt-5.4"
|
|
282
|
+
},
|
|
283
|
+
opencode: {
|
|
284
|
+
binary: "opencode",
|
|
285
|
+
launchMode: "exec",
|
|
286
|
+
autoApproveFlag: "--dangerously-skip-permissions",
|
|
287
|
+
inlineFlag: "",
|
|
288
|
+
apiKeyEnv: "ANTHROPIC_API_KEY",
|
|
289
|
+
defaultModel: "anthropic/claude-sonnet-4-6"
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
DEFAULT_RUNTIME = "claude";
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
// src/lib/agent-config.ts
|
|
297
|
+
var agent_config_exports = {};
|
|
298
|
+
__export(agent_config_exports, {
|
|
299
|
+
AGENT_CONFIG_PATH: () => AGENT_CONFIG_PATH,
|
|
300
|
+
DEFAULT_MODELS: () => DEFAULT_MODELS,
|
|
301
|
+
KNOWN_RUNTIMES: () => KNOWN_RUNTIMES,
|
|
302
|
+
RUNTIME_LABELS: () => RUNTIME_LABELS,
|
|
303
|
+
clearAgentRuntime: () => clearAgentRuntime,
|
|
304
|
+
getAgentRuntime: () => getAgentRuntime,
|
|
305
|
+
loadAgentConfig: () => loadAgentConfig,
|
|
306
|
+
saveAgentConfig: () => saveAgentConfig,
|
|
307
|
+
setAgentRuntime: () => setAgentRuntime
|
|
308
|
+
});
|
|
309
|
+
import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync2, mkdirSync } from "fs";
|
|
310
|
+
import path2 from "path";
|
|
311
|
+
function loadAgentConfig() {
|
|
312
|
+
if (!existsSync2(AGENT_CONFIG_PATH)) return {};
|
|
313
|
+
try {
|
|
314
|
+
return JSON.parse(readFileSync2(AGENT_CONFIG_PATH, "utf-8"));
|
|
315
|
+
} catch {
|
|
316
|
+
return {};
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
function saveAgentConfig(config) {
|
|
320
|
+
const dir = path2.dirname(AGENT_CONFIG_PATH);
|
|
321
|
+
if (!existsSync2(dir)) mkdirSync(dir, { recursive: true });
|
|
322
|
+
writeFileSync(AGENT_CONFIG_PATH, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
323
|
+
}
|
|
324
|
+
function getAgentRuntime(agentId) {
|
|
325
|
+
const config = loadAgentConfig();
|
|
326
|
+
const entry = config[agentId];
|
|
327
|
+
if (entry) return entry;
|
|
328
|
+
const orgDefault = config["default"];
|
|
329
|
+
if (orgDefault) return orgDefault;
|
|
330
|
+
return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
|
|
331
|
+
}
|
|
332
|
+
function setAgentRuntime(agentId, runtime, model) {
|
|
333
|
+
const knownModels = KNOWN_RUNTIMES[runtime];
|
|
334
|
+
if (!knownModels) {
|
|
335
|
+
return {
|
|
336
|
+
ok: false,
|
|
337
|
+
error: `Unknown runtime "${runtime}". Valid: ${Object.keys(KNOWN_RUNTIMES).join(", ")}`
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
if (!knownModels.includes(model)) {
|
|
341
|
+
return {
|
|
342
|
+
ok: false,
|
|
343
|
+
error: `Unknown model "${model}" for runtime "${runtime}". Valid: ${knownModels.join(", ")}`
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
const config = loadAgentConfig();
|
|
347
|
+
config[agentId] = { runtime, model };
|
|
348
|
+
saveAgentConfig(config);
|
|
349
|
+
return { ok: true };
|
|
350
|
+
}
|
|
351
|
+
function clearAgentRuntime(agentId) {
|
|
352
|
+
const config = loadAgentConfig();
|
|
353
|
+
delete config[agentId];
|
|
354
|
+
saveAgentConfig(config);
|
|
355
|
+
}
|
|
356
|
+
var AGENT_CONFIG_PATH, KNOWN_RUNTIMES, RUNTIME_LABELS, DEFAULT_MODELS;
|
|
357
|
+
var init_agent_config = __esm({
|
|
358
|
+
"src/lib/agent-config.ts"() {
|
|
359
|
+
"use strict";
|
|
360
|
+
init_config();
|
|
361
|
+
init_runtime_table();
|
|
362
|
+
AGENT_CONFIG_PATH = path2.join(EXE_AI_DIR, "agent-config.json");
|
|
363
|
+
KNOWN_RUNTIMES = {
|
|
364
|
+
claude: ["claude-opus-4", "claude-sonnet-4", "claude-haiku-4.5"],
|
|
365
|
+
codex: ["gpt-5.4", "gpt-5.5", "gpt-5.3-codex-spark", "o3", "o4-mini"],
|
|
366
|
+
opencode: ["anthropic/claude-sonnet-4-6", "openai/gpt-5.4", "google/gemini-2.5-pro", "deepseek/deepseek-r3", "minimax/minimax-m2.5"]
|
|
367
|
+
};
|
|
368
|
+
RUNTIME_LABELS = {
|
|
369
|
+
claude: "Claude Code (Anthropic)",
|
|
370
|
+
codex: "Codex (OpenAI)",
|
|
371
|
+
opencode: "OpenCode (open source)"
|
|
372
|
+
};
|
|
373
|
+
DEFAULT_MODELS = {
|
|
374
|
+
claude: "claude-opus-4",
|
|
375
|
+
codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
|
|
376
|
+
opencode: RUNTIME_TABLE.opencode?.defaultModel ?? "anthropic/claude-sonnet-4-6"
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
|
|
269
381
|
// src/lib/employees.ts
|
|
270
382
|
var employees_exports = {};
|
|
271
383
|
__export(employees_exports, {
|
|
@@ -281,6 +393,7 @@ __export(employees_exports, {
|
|
|
281
393
|
getEmployeeByRole: () => getEmployeeByRole,
|
|
282
394
|
getEmployeeNamesByRole: () => getEmployeeNamesByRole,
|
|
283
395
|
hasRole: () => hasRole,
|
|
396
|
+
hireEmployee: () => hireEmployee,
|
|
284
397
|
isCoordinatorName: () => isCoordinatorName,
|
|
285
398
|
isCoordinatorRole: () => isCoordinatorRole,
|
|
286
399
|
isMultiInstance: () => isMultiInstance,
|
|
@@ -293,9 +406,9 @@ __export(employees_exports, {
|
|
|
293
406
|
validateEmployeeName: () => validateEmployeeName
|
|
294
407
|
});
|
|
295
408
|
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
296
|
-
import { existsSync as
|
|
409
|
+
import { existsSync as existsSync3, symlinkSync, readlinkSync, readFileSync as readFileSync3, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
|
|
297
410
|
import { execSync } from "child_process";
|
|
298
|
-
import
|
|
411
|
+
import path3 from "path";
|
|
299
412
|
import os2 from "os";
|
|
300
413
|
function normalizeRole(role) {
|
|
301
414
|
return (role ?? "").trim().toLowerCase();
|
|
@@ -332,7 +445,7 @@ function validateEmployeeName(name) {
|
|
|
332
445
|
return { valid: true };
|
|
333
446
|
}
|
|
334
447
|
async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
|
|
335
|
-
if (!
|
|
448
|
+
if (!existsSync3(employeesPath)) {
|
|
336
449
|
return [];
|
|
337
450
|
}
|
|
338
451
|
const raw = await readFile2(employeesPath, "utf-8");
|
|
@@ -343,13 +456,13 @@ async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
|
|
|
343
456
|
}
|
|
344
457
|
}
|
|
345
458
|
async function saveEmployees(employees, employeesPath = EMPLOYEES_PATH) {
|
|
346
|
-
await mkdir2(
|
|
459
|
+
await mkdir2(path3.dirname(employeesPath), { recursive: true });
|
|
347
460
|
await writeFile2(employeesPath, JSON.stringify(employees, null, 2) + "\n", "utf-8");
|
|
348
461
|
}
|
|
349
462
|
function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
|
|
350
|
-
if (!
|
|
463
|
+
if (!existsSync3(employeesPath)) return [];
|
|
351
464
|
try {
|
|
352
|
-
return JSON.parse(
|
|
465
|
+
return JSON.parse(readFileSync3(employeesPath, "utf-8"));
|
|
353
466
|
} catch {
|
|
354
467
|
return [];
|
|
355
468
|
}
|
|
@@ -391,6 +504,52 @@ function addEmployee(employees, employee) {
|
|
|
391
504
|
}
|
|
392
505
|
return [...employees, normalized];
|
|
393
506
|
}
|
|
507
|
+
function appendToCoordinatorTeam(employee) {
|
|
508
|
+
const coordinator = getCoordinatorEmployee(loadEmployeesSync());
|
|
509
|
+
if (!coordinator) return;
|
|
510
|
+
const idPath = path3.join(IDENTITY_DIR, `${coordinator.name}.md`);
|
|
511
|
+
if (!existsSync3(idPath)) return;
|
|
512
|
+
const content = readFileSync3(idPath, "utf-8");
|
|
513
|
+
if (content.includes(`**${capitalize(employee.name)}`)) return;
|
|
514
|
+
const teamMatch = content.match(TEAM_SECTION_RE);
|
|
515
|
+
if (!teamMatch || teamMatch.index === void 0) return;
|
|
516
|
+
const afterTeam = content.slice(teamMatch.index + teamMatch[0].length);
|
|
517
|
+
const nextHeading = afterTeam.match(/\n## /);
|
|
518
|
+
const entry = `
|
|
519
|
+
**${capitalize(employee.name)} (${employee.role}):** Newly hired. Update this description as the role develops.
|
|
520
|
+
`;
|
|
521
|
+
let updated;
|
|
522
|
+
if (nextHeading && nextHeading.index !== void 0) {
|
|
523
|
+
const insertAt = teamMatch.index + teamMatch[0].length + nextHeading.index;
|
|
524
|
+
updated = content.slice(0, insertAt) + entry + content.slice(insertAt);
|
|
525
|
+
} else {
|
|
526
|
+
updated = content.trimEnd() + "\n" + entry;
|
|
527
|
+
}
|
|
528
|
+
writeFileSync2(idPath, updated, "utf-8");
|
|
529
|
+
}
|
|
530
|
+
function capitalize(s) {
|
|
531
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
532
|
+
}
|
|
533
|
+
async function hireEmployee(employee) {
|
|
534
|
+
const employees = await loadEmployees();
|
|
535
|
+
const updated = addEmployee(employees, employee);
|
|
536
|
+
await saveEmployees(updated);
|
|
537
|
+
try {
|
|
538
|
+
appendToCoordinatorTeam(employee);
|
|
539
|
+
} catch {
|
|
540
|
+
}
|
|
541
|
+
try {
|
|
542
|
+
const { loadAgentConfig: loadAgentConfig2, saveAgentConfig: saveAgentConfig2 } = await Promise.resolve().then(() => (init_agent_config(), agent_config_exports));
|
|
543
|
+
const config = loadAgentConfig2();
|
|
544
|
+
const name = employee.name.toLowerCase();
|
|
545
|
+
if (!config[name] && config["default"]) {
|
|
546
|
+
config[name] = { ...config["default"] };
|
|
547
|
+
saveAgentConfig2(config);
|
|
548
|
+
}
|
|
549
|
+
} catch {
|
|
550
|
+
}
|
|
551
|
+
return updated;
|
|
552
|
+
}
|
|
394
553
|
async function normalizeRosterCase(rosterPath) {
|
|
395
554
|
const employees = await loadEmployees(rosterPath);
|
|
396
555
|
let changed = false;
|
|
@@ -400,14 +559,14 @@ async function normalizeRosterCase(rosterPath) {
|
|
|
400
559
|
emp.name = emp.name.toLowerCase();
|
|
401
560
|
changed = true;
|
|
402
561
|
try {
|
|
403
|
-
const identityDir =
|
|
404
|
-
const oldPath =
|
|
405
|
-
const newPath =
|
|
406
|
-
if (
|
|
562
|
+
const identityDir = path3.join(os2.homedir(), ".exe-os", "identity");
|
|
563
|
+
const oldPath = path3.join(identityDir, `${oldName}.md`);
|
|
564
|
+
const newPath = path3.join(identityDir, `${emp.name}.md`);
|
|
565
|
+
if (existsSync3(oldPath) && !existsSync3(newPath)) {
|
|
407
566
|
renameSync2(oldPath, newPath);
|
|
408
|
-
} else if (
|
|
409
|
-
const content =
|
|
410
|
-
|
|
567
|
+
} else if (existsSync3(oldPath) && oldPath !== newPath) {
|
|
568
|
+
const content = readFileSync3(oldPath, "utf-8");
|
|
569
|
+
writeFileSync2(newPath, content, "utf-8");
|
|
411
570
|
if (oldPath.toLowerCase() !== newPath.toLowerCase()) {
|
|
412
571
|
unlinkSync(oldPath);
|
|
413
572
|
}
|
|
@@ -437,7 +596,7 @@ function registerBinSymlinks(name) {
|
|
|
437
596
|
errors.push("Could not find 'exe-os' in PATH");
|
|
438
597
|
return { created, skipped, errors };
|
|
439
598
|
}
|
|
440
|
-
const binDir =
|
|
599
|
+
const binDir = path3.dirname(exeBinPath);
|
|
441
600
|
let target;
|
|
442
601
|
try {
|
|
443
602
|
target = readlinkSync(exeBinPath);
|
|
@@ -447,8 +606,8 @@ function registerBinSymlinks(name) {
|
|
|
447
606
|
}
|
|
448
607
|
for (const suffix of ["", "-opencode"]) {
|
|
449
608
|
const linkName = `${name}${suffix}`;
|
|
450
|
-
const linkPath =
|
|
451
|
-
if (
|
|
609
|
+
const linkPath = path3.join(binDir, linkName);
|
|
610
|
+
if (existsSync3(linkPath)) {
|
|
452
611
|
skipped.push(linkName);
|
|
453
612
|
continue;
|
|
454
613
|
}
|
|
@@ -461,42 +620,44 @@ function registerBinSymlinks(name) {
|
|
|
461
620
|
}
|
|
462
621
|
return { created, skipped, errors };
|
|
463
622
|
}
|
|
464
|
-
var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES;
|
|
623
|
+
var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES, IDENTITY_DIR, TEAM_SECTION_RE;
|
|
465
624
|
var init_employees = __esm({
|
|
466
625
|
"src/lib/employees.ts"() {
|
|
467
626
|
"use strict";
|
|
468
627
|
init_config();
|
|
469
|
-
EMPLOYEES_PATH =
|
|
628
|
+
EMPLOYEES_PATH = path3.join(EXE_AI_DIR, "exe-employees.json");
|
|
470
629
|
DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
|
|
471
630
|
COORDINATOR_ROLE = "COO";
|
|
472
631
|
MULTI_INSTANCE_ROLES = /* @__PURE__ */ new Set(["principal engineer", "content production specialist", "staff code reviewer"]);
|
|
632
|
+
IDENTITY_DIR = path3.join(EXE_AI_DIR, "identity");
|
|
633
|
+
TEAM_SECTION_RE = /^## Team\b.*$/m;
|
|
473
634
|
}
|
|
474
635
|
});
|
|
475
636
|
|
|
476
637
|
// src/lib/agent-symlinks.ts
|
|
477
638
|
import os3 from "os";
|
|
478
|
-
import
|
|
639
|
+
import path4 from "path";
|
|
479
640
|
import {
|
|
480
|
-
existsSync as
|
|
641
|
+
existsSync as existsSync4,
|
|
481
642
|
lstatSync,
|
|
482
|
-
mkdirSync,
|
|
643
|
+
mkdirSync as mkdirSync2,
|
|
483
644
|
readlinkSync as readlinkSync2,
|
|
484
645
|
symlinkSync as symlinkSync2
|
|
485
646
|
} from "fs";
|
|
486
647
|
function claudeAgentsDir(homeDir) {
|
|
487
|
-
return
|
|
648
|
+
return path4.join(homeDir, ".claude", "agents");
|
|
488
649
|
}
|
|
489
650
|
function identitySourcePath(homeDir, agentId) {
|
|
490
|
-
return
|
|
651
|
+
return path4.join(homeDir, ".exe-os", "identity", `${agentId}.md`);
|
|
491
652
|
}
|
|
492
653
|
function claudeAgentLinkPath(homeDir, agentId) {
|
|
493
|
-
return
|
|
654
|
+
return path4.join(claudeAgentsDir(homeDir), `${agentId}.md`);
|
|
494
655
|
}
|
|
495
656
|
function ensureAgentSymlink(agentId, homeDir = os3.homedir()) {
|
|
496
657
|
const target = identitySourcePath(homeDir, agentId);
|
|
497
658
|
const link = claudeAgentLinkPath(homeDir, agentId);
|
|
498
|
-
|
|
499
|
-
if (
|
|
659
|
+
mkdirSync2(claudeAgentsDir(homeDir), { recursive: true });
|
|
660
|
+
if (existsSync4(link)) {
|
|
500
661
|
let stat2;
|
|
501
662
|
try {
|
|
502
663
|
stat2 = lstatSync(link);
|
|
@@ -570,33 +731,33 @@ __export(preferences_exports, {
|
|
|
570
731
|
loadPreferences: () => loadPreferences,
|
|
571
732
|
savePreferences: () => savePreferences
|
|
572
733
|
});
|
|
573
|
-
import { existsSync as
|
|
574
|
-
import
|
|
734
|
+
import { existsSync as existsSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "fs";
|
|
735
|
+
import path5 from "path";
|
|
575
736
|
import os4 from "os";
|
|
576
737
|
function loadPreferences(homeDir = os4.homedir()) {
|
|
577
|
-
const configPath =
|
|
578
|
-
if (!
|
|
738
|
+
const configPath = path5.join(homeDir, ".exe-os", "config.json");
|
|
739
|
+
if (!existsSync5(configPath)) return {};
|
|
579
740
|
try {
|
|
580
|
-
const config = JSON.parse(
|
|
741
|
+
const config = JSON.parse(readFileSync4(configPath, "utf-8"));
|
|
581
742
|
return config.preferences ?? {};
|
|
582
743
|
} catch {
|
|
583
744
|
return {};
|
|
584
745
|
}
|
|
585
746
|
}
|
|
586
747
|
function savePreferences(prefs, homeDir = os4.homedir()) {
|
|
587
|
-
const configDir =
|
|
588
|
-
const configPath =
|
|
589
|
-
|
|
748
|
+
const configDir = path5.join(homeDir, ".exe-os");
|
|
749
|
+
const configPath = path5.join(configDir, "config.json");
|
|
750
|
+
mkdirSync3(configDir, { recursive: true });
|
|
590
751
|
let config = {};
|
|
591
|
-
if (
|
|
752
|
+
if (existsSync5(configPath)) {
|
|
592
753
|
try {
|
|
593
|
-
config = JSON.parse(
|
|
754
|
+
config = JSON.parse(readFileSync4(configPath, "utf-8"));
|
|
594
755
|
} catch {
|
|
595
756
|
config = {};
|
|
596
757
|
}
|
|
597
758
|
}
|
|
598
759
|
config.preferences = prefs;
|
|
599
|
-
|
|
760
|
+
writeFileSync3(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
600
761
|
}
|
|
601
762
|
var init_preferences = __esm({
|
|
602
763
|
"src/lib/preferences.ts"() {
|
|
@@ -618,52 +779,52 @@ __export(installer_exports, {
|
|
|
618
779
|
setupTmux: () => setupTmux
|
|
619
780
|
});
|
|
620
781
|
import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3, readdir } from "fs/promises";
|
|
621
|
-
import { existsSync as
|
|
622
|
-
import
|
|
782
|
+
import { existsSync as existsSync6, readFileSync as readFileSync5, writeFileSync as writeFileSync4, copyFileSync, mkdirSync as mkdirSync4 } from "fs";
|
|
783
|
+
import path6 from "path";
|
|
623
784
|
import os5 from "os";
|
|
624
785
|
import { execSync as execSync2 } from "child_process";
|
|
625
786
|
import { fileURLToPath } from "url";
|
|
626
787
|
function resolvePackageRoot() {
|
|
627
788
|
const thisFile = fileURLToPath(import.meta.url);
|
|
628
|
-
let dir =
|
|
629
|
-
const root =
|
|
789
|
+
let dir = path6.dirname(thisFile);
|
|
790
|
+
const root = path6.parse(dir).root;
|
|
630
791
|
while (dir !== root) {
|
|
631
|
-
const pkgPath =
|
|
632
|
-
if (
|
|
792
|
+
const pkgPath = path6.join(dir, "package.json");
|
|
793
|
+
if (existsSync6(pkgPath)) {
|
|
633
794
|
try {
|
|
634
|
-
const pkg = JSON.parse(
|
|
795
|
+
const pkg = JSON.parse(readFileSync5(pkgPath, "utf-8"));
|
|
635
796
|
if (pkg.name === "@askexenow/exe-os" || pkg.name === "exe-os") return dir;
|
|
636
797
|
} catch {
|
|
637
798
|
}
|
|
638
799
|
}
|
|
639
|
-
dir =
|
|
800
|
+
dir = path6.dirname(dir);
|
|
640
801
|
}
|
|
641
|
-
return
|
|
802
|
+
return path6.resolve(path6.dirname(thisFile), "..", "..", "..");
|
|
642
803
|
}
|
|
643
804
|
async function copySlashCommands(packageRoot, homeDir = os5.homedir()) {
|
|
644
805
|
let copied = 0;
|
|
645
806
|
let skipped = 0;
|
|
646
|
-
const skillsBase =
|
|
647
|
-
const exeDir =
|
|
648
|
-
if (
|
|
807
|
+
const skillsBase = path6.join(homeDir, ".claude", "skills");
|
|
808
|
+
const exeDir = path6.join(packageRoot, "src", "commands", "exe");
|
|
809
|
+
if (existsSync6(exeDir)) {
|
|
649
810
|
const entries = await readdir(exeDir);
|
|
650
811
|
const mdFiles = entries.filter((f) => f.endsWith(".md"));
|
|
651
812
|
for (const file of mdFiles) {
|
|
652
813
|
const name = file.replace(".md", "");
|
|
653
|
-
const destDir =
|
|
814
|
+
const destDir = path6.join(skillsBase, `exe-${name}`);
|
|
654
815
|
await mkdir3(destDir, { recursive: true });
|
|
655
|
-
const srcPath =
|
|
656
|
-
const destPath =
|
|
816
|
+
const srcPath = path6.join(exeDir, file);
|
|
817
|
+
const destPath = path6.join(destDir, "SKILL.md");
|
|
657
818
|
const result = await copyAsSkill(srcPath, destPath, `exe-${name}`);
|
|
658
819
|
if (result) copied++;
|
|
659
820
|
else skipped++;
|
|
660
821
|
}
|
|
661
822
|
}
|
|
662
|
-
const topLevelSrc =
|
|
663
|
-
if (
|
|
664
|
-
const destDir =
|
|
823
|
+
const topLevelSrc = path6.join(packageRoot, "src", "commands", "exe.md");
|
|
824
|
+
if (existsSync6(topLevelSrc)) {
|
|
825
|
+
const destDir = path6.join(skillsBase, "exe");
|
|
665
826
|
await mkdir3(destDir, { recursive: true });
|
|
666
|
-
const destPath =
|
|
827
|
+
const destPath = path6.join(destDir, "SKILL.md");
|
|
667
828
|
const result = await copyAsSkill(topLevelSrc, destPath, "exe");
|
|
668
829
|
if (result) copied++;
|
|
669
830
|
else skipped++;
|
|
@@ -686,7 +847,7 @@ name: ${skillName}
|
|
|
686
847
|
`);
|
|
687
848
|
}
|
|
688
849
|
}
|
|
689
|
-
if (
|
|
850
|
+
if (existsSync6(destPath)) {
|
|
690
851
|
const existing = await readFile3(destPath, "utf-8");
|
|
691
852
|
if (existing === content) return false;
|
|
692
853
|
}
|
|
@@ -694,9 +855,9 @@ name: ${skillName}
|
|
|
694
855
|
return true;
|
|
695
856
|
}
|
|
696
857
|
async function registerMcpServer(packageRoot, homeDir = os5.homedir()) {
|
|
697
|
-
const claudeJsonPath =
|
|
858
|
+
const claudeJsonPath = path6.join(homeDir, ".claude.json");
|
|
698
859
|
let claudeJson = {};
|
|
699
|
-
if (
|
|
860
|
+
if (existsSync6(claudeJsonPath)) {
|
|
700
861
|
try {
|
|
701
862
|
claudeJson = JSON.parse(await readFile3(claudeJsonPath, "utf-8"));
|
|
702
863
|
} catch {
|
|
@@ -709,7 +870,7 @@ async function registerMcpServer(packageRoot, homeDir = os5.homedir()) {
|
|
|
709
870
|
const newEntry = {
|
|
710
871
|
type: "stdio",
|
|
711
872
|
command: "node",
|
|
712
|
-
args: [
|
|
873
|
+
args: [path6.join(packageRoot, "dist", "mcp", "server.js")],
|
|
713
874
|
env: {}
|
|
714
875
|
};
|
|
715
876
|
const currentMem = claudeJson.mcpServers[MCP_LEGACY_KEY];
|
|
@@ -717,17 +878,17 @@ async function registerMcpServer(packageRoot, homeDir = os5.homedir()) {
|
|
|
717
878
|
const memMatches = currentMem && JSON.stringify(currentMem) === JSON.stringify(newEntry);
|
|
718
879
|
const osMatches = currentOs && JSON.stringify(currentOs) === JSON.stringify(newEntry);
|
|
719
880
|
if (memMatches && osMatches) {
|
|
720
|
-
await cleanSettingsJsonMcp(
|
|
881
|
+
await cleanSettingsJsonMcp(path6.join(homeDir, ".claude", "settings.json"));
|
|
721
882
|
return false;
|
|
722
883
|
}
|
|
723
884
|
claudeJson.mcpServers[MCP_LEGACY_KEY] = newEntry;
|
|
724
885
|
claudeJson.mcpServers[MCP_PRIMARY_KEY] = newEntry;
|
|
725
886
|
await writeFile3(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
|
|
726
|
-
await cleanSettingsJsonMcp(
|
|
887
|
+
await cleanSettingsJsonMcp(path6.join(homeDir, ".claude", "settings.json"));
|
|
727
888
|
return true;
|
|
728
889
|
}
|
|
729
890
|
async function cleanSettingsJsonMcp(settingsPath) {
|
|
730
|
-
if (!
|
|
891
|
+
if (!existsSync6(settingsPath)) return;
|
|
731
892
|
try {
|
|
732
893
|
const settings = JSON.parse(await readFile3(settingsPath, "utf-8"));
|
|
733
894
|
const servers = settings.mcpServers;
|
|
@@ -748,13 +909,13 @@ async function cleanSettingsJsonMcp(settingsPath) {
|
|
|
748
909
|
}
|
|
749
910
|
}
|
|
750
911
|
async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
|
|
751
|
-
const settingsPath =
|
|
752
|
-
const logsDir =
|
|
753
|
-
const hookLogPath =
|
|
912
|
+
const settingsPath = path6.join(homeDir, ".claude", "settings.json");
|
|
913
|
+
const logsDir = path6.join(homeDir, ".exe-os", "logs");
|
|
914
|
+
const hookLogPath = path6.join(logsDir, "hooks.log");
|
|
754
915
|
const logSuffix = ` 2>> "${hookLogPath}"`;
|
|
755
916
|
await mkdir3(logsDir, { recursive: true });
|
|
756
917
|
let settings = {};
|
|
757
|
-
if (
|
|
918
|
+
if (existsSync6(settingsPath)) {
|
|
758
919
|
try {
|
|
759
920
|
settings = JSON.parse(await readFile3(settingsPath, "utf-8"));
|
|
760
921
|
} catch {
|
|
@@ -776,11 +937,11 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
|
|
|
776
937
|
hooks: [
|
|
777
938
|
{
|
|
778
939
|
type: "command",
|
|
779
|
-
command: `node "${
|
|
940
|
+
command: `node "${path6.join(packageRoot, "dist", "hooks", "ingest.js")}"${logSuffix}`
|
|
780
941
|
},
|
|
781
942
|
{
|
|
782
943
|
type: "command",
|
|
783
|
-
command: `node "${
|
|
944
|
+
command: `node "${path6.join(packageRoot, "dist", "hooks", "error-recall.js")}"${logSuffix}`
|
|
784
945
|
}
|
|
785
946
|
]
|
|
786
947
|
},
|
|
@@ -792,7 +953,7 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
|
|
|
792
953
|
hooks: [
|
|
793
954
|
{
|
|
794
955
|
type: "command",
|
|
795
|
-
command: `node "${
|
|
956
|
+
command: `node "${path6.join(packageRoot, "dist", "hooks", "session-start.js")}"${logSuffix}`,
|
|
796
957
|
timeout: 1e4
|
|
797
958
|
}
|
|
798
959
|
]
|
|
@@ -805,7 +966,7 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
|
|
|
805
966
|
hooks: [
|
|
806
967
|
{
|
|
807
968
|
type: "command",
|
|
808
|
-
command: `node "${
|
|
969
|
+
command: `node "${path6.join(packageRoot, "dist", "hooks", "prompt-submit.js")}"${logSuffix}`
|
|
809
970
|
}
|
|
810
971
|
]
|
|
811
972
|
},
|
|
@@ -817,7 +978,7 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
|
|
|
817
978
|
hooks: [
|
|
818
979
|
{
|
|
819
980
|
type: "command",
|
|
820
|
-
command: `node "${
|
|
981
|
+
command: `node "${path6.join(packageRoot, "dist", "hooks", "exe-heartbeat-hook.js")}"${logSuffix}`,
|
|
821
982
|
timeout: 5e3
|
|
822
983
|
}
|
|
823
984
|
]
|
|
@@ -830,7 +991,7 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
|
|
|
830
991
|
hooks: [
|
|
831
992
|
{
|
|
832
993
|
type: "command",
|
|
833
|
-
command: `node "${
|
|
994
|
+
command: `node "${path6.join(packageRoot, "dist", "hooks", "stop.js")}"${logSuffix}`
|
|
834
995
|
}
|
|
835
996
|
]
|
|
836
997
|
},
|
|
@@ -843,7 +1004,7 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
|
|
|
843
1004
|
hooks: [
|
|
844
1005
|
{
|
|
845
1006
|
type: "command",
|
|
846
|
-
command: `node "${
|
|
1007
|
+
command: `node "${path6.join(packageRoot, "dist", "hooks", "pre-tool-use.js")}"${logSuffix}`
|
|
847
1008
|
}
|
|
848
1009
|
]
|
|
849
1010
|
},
|
|
@@ -855,7 +1016,7 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
|
|
|
855
1016
|
hooks: [
|
|
856
1017
|
{
|
|
857
1018
|
type: "command",
|
|
858
|
-
command: `node "${
|
|
1019
|
+
command: `node "${path6.join(packageRoot, "dist", "hooks", "subagent-stop.js")}"${logSuffix}`
|
|
859
1020
|
}
|
|
860
1021
|
]
|
|
861
1022
|
},
|
|
@@ -867,7 +1028,7 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
|
|
|
867
1028
|
hooks: [
|
|
868
1029
|
{
|
|
869
1030
|
type: "command",
|
|
870
|
-
command: `node "${
|
|
1031
|
+
command: `node "${path6.join(packageRoot, "dist", "hooks", "pre-compact.js")}"${logSuffix}`,
|
|
871
1032
|
timeout: 1e4
|
|
872
1033
|
}
|
|
873
1034
|
]
|
|
@@ -880,7 +1041,7 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
|
|
|
880
1041
|
hooks: [
|
|
881
1042
|
{
|
|
882
1043
|
type: "command",
|
|
883
|
-
command: `node "${
|
|
1044
|
+
command: `node "${path6.join(packageRoot, "dist", "hooks", "session-end.js")}"${logSuffix}`
|
|
884
1045
|
}
|
|
885
1046
|
]
|
|
886
1047
|
},
|
|
@@ -892,7 +1053,7 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
|
|
|
892
1053
|
hooks: [
|
|
893
1054
|
{
|
|
894
1055
|
type: "command",
|
|
895
|
-
command: `node "${
|
|
1056
|
+
command: `node "${path6.join(packageRoot, "dist", "hooks", "notification.js")}"${logSuffix}`
|
|
896
1057
|
}
|
|
897
1058
|
]
|
|
898
1059
|
},
|
|
@@ -904,7 +1065,7 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
|
|
|
904
1065
|
hooks: [
|
|
905
1066
|
{
|
|
906
1067
|
type: "command",
|
|
907
|
-
command: `node "${
|
|
1068
|
+
command: `node "${path6.join(packageRoot, "dist", "hooks", "post-compact.js")}"${logSuffix}`,
|
|
908
1069
|
timeout: 1e4
|
|
909
1070
|
}
|
|
910
1071
|
]
|
|
@@ -917,7 +1078,7 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
|
|
|
917
1078
|
hooks: [
|
|
918
1079
|
{
|
|
919
1080
|
type: "command",
|
|
920
|
-
command: `node "${
|
|
1081
|
+
command: `node "${path6.join(packageRoot, "dist", "hooks", "instructions-loaded.js")}"${logSuffix}`
|
|
921
1082
|
}
|
|
922
1083
|
]
|
|
923
1084
|
},
|
|
@@ -1016,13 +1177,13 @@ async function mergeHooks(packageRoot, homeDir = os5.homedir()) {
|
|
|
1016
1177
|
allowList.push(tool);
|
|
1017
1178
|
}
|
|
1018
1179
|
}
|
|
1019
|
-
await mkdir3(
|
|
1180
|
+
await mkdir3(path6.dirname(settingsPath), { recursive: true });
|
|
1020
1181
|
await writeFile3(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
1021
1182
|
return { added, skipped };
|
|
1022
1183
|
}
|
|
1023
1184
|
async function cleanOldShellFunctions(homeDir = os5.homedir()) {
|
|
1024
|
-
const rosterPath =
|
|
1025
|
-
if (!
|
|
1185
|
+
const rosterPath = path6.join(homeDir, ".exe-os", "exe-employees.json");
|
|
1186
|
+
if (!existsSync6(rosterPath)) return 0;
|
|
1026
1187
|
let employees;
|
|
1027
1188
|
try {
|
|
1028
1189
|
employees = JSON.parse(await readFile3(rosterPath, "utf-8"));
|
|
@@ -1037,13 +1198,13 @@ async function cleanOldShellFunctions(homeDir = os5.homedir()) {
|
|
|
1037
1198
|
return { name: n, funcDef, forLoop };
|
|
1038
1199
|
});
|
|
1039
1200
|
const rcFiles = [
|
|
1040
|
-
|
|
1041
|
-
|
|
1201
|
+
path6.join(homeDir, ".zshrc"),
|
|
1202
|
+
path6.join(homeDir, ".bashrc")
|
|
1042
1203
|
];
|
|
1043
1204
|
const REMOVED_MARKER = "# Removed by exe-os \u2014 wrappers now at ~/.exe-os/bin/";
|
|
1044
1205
|
let totalRemoved = 0;
|
|
1045
1206
|
for (const rcPath of rcFiles) {
|
|
1046
|
-
if (!
|
|
1207
|
+
if (!existsSync6(rcPath)) continue;
|
|
1047
1208
|
let content;
|
|
1048
1209
|
try {
|
|
1049
1210
|
content = await readFile3(rcPath, "utf-8");
|
|
@@ -1147,8 +1308,8 @@ function escapeRegExp(s) {
|
|
|
1147
1308
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1148
1309
|
}
|
|
1149
1310
|
async function injectOrchestrationRules(homeDir) {
|
|
1150
|
-
const claudeDir =
|
|
1151
|
-
const claudeMdPath =
|
|
1311
|
+
const claudeDir = path6.join(homeDir, ".claude");
|
|
1312
|
+
const claudeMdPath = path6.join(claudeDir, "CLAUDE.md");
|
|
1152
1313
|
await mkdir3(claudeDir, { recursive: true });
|
|
1153
1314
|
let existing = "";
|
|
1154
1315
|
try {
|
|
@@ -1173,16 +1334,16 @@ async function injectOrchestrationRules(homeDir) {
|
|
|
1173
1334
|
async function installStatusLine(packageRoot, homeDir = os5.homedir()) {
|
|
1174
1335
|
const prefs = loadPreferences(homeDir);
|
|
1175
1336
|
if (prefs.ccStatusLine === false) return "opted-out";
|
|
1176
|
-
const claudeDir =
|
|
1337
|
+
const claudeDir = path6.join(homeDir, ".claude");
|
|
1177
1338
|
await mkdir3(claudeDir, { recursive: true });
|
|
1178
|
-
const assetPath =
|
|
1179
|
-
if (!
|
|
1180
|
-
const destScript =
|
|
1339
|
+
const assetPath = path6.join(packageRoot, "dist", "assets", "statusline-command.sh");
|
|
1340
|
+
if (!existsSync6(assetPath)) return "asset-missing";
|
|
1341
|
+
const destScript = path6.join(claudeDir, "statusline-command.sh");
|
|
1181
1342
|
const assetContent = await readFile3(assetPath, "utf-8");
|
|
1182
1343
|
await writeFile3(destScript, assetContent, { mode: 493 });
|
|
1183
|
-
const settingsPath =
|
|
1344
|
+
const settingsPath = path6.join(claudeDir, "settings.json");
|
|
1184
1345
|
let settings = {};
|
|
1185
|
-
if (
|
|
1346
|
+
if (existsSync6(settingsPath)) {
|
|
1186
1347
|
try {
|
|
1187
1348
|
settings = JSON.parse(await readFile3(settingsPath, "utf-8"));
|
|
1188
1349
|
} catch {
|
|
@@ -1220,12 +1381,12 @@ async function runInstaller(homeDir) {
|
|
|
1220
1381
|
`
|
|
1221
1382
|
);
|
|
1222
1383
|
const resolvedHome = homeDir ?? os5.homedir();
|
|
1223
|
-
const exeWorkspace =
|
|
1224
|
-
if (!
|
|
1384
|
+
const exeWorkspace = path6.join(resolvedHome, "exe");
|
|
1385
|
+
if (!existsSync6(exeWorkspace)) {
|
|
1225
1386
|
try {
|
|
1226
|
-
await mkdir3(
|
|
1227
|
-
await mkdir3(
|
|
1228
|
-
await mkdir3(
|
|
1387
|
+
await mkdir3(path6.join(exeWorkspace, "content"), { recursive: true });
|
|
1388
|
+
await mkdir3(path6.join(exeWorkspace, "operations"), { recursive: true });
|
|
1389
|
+
await mkdir3(path6.join(exeWorkspace, "output"), { recursive: true });
|
|
1229
1390
|
process.stderr.write(
|
|
1230
1391
|
`Created ~/exe/ \u2014 your automation workspace for non-code projects
|
|
1231
1392
|
`
|
|
@@ -1261,33 +1422,33 @@ exe-os installed successfully.
|
|
|
1261
1422
|
}
|
|
1262
1423
|
function setupTmux(home) {
|
|
1263
1424
|
const homeDir = home ?? os5.homedir();
|
|
1264
|
-
const exeDir =
|
|
1265
|
-
const exeTmuxConf =
|
|
1266
|
-
const userTmuxConf =
|
|
1267
|
-
const backupPath =
|
|
1425
|
+
const exeDir = path6.join(homeDir, ".exe-os");
|
|
1426
|
+
const exeTmuxConf = path6.join(exeDir, "tmux.conf");
|
|
1427
|
+
const userTmuxConf = path6.join(homeDir, ".tmux.conf");
|
|
1428
|
+
const backupPath = path6.join(homeDir, ".tmux.conf.backup");
|
|
1268
1429
|
const sourceLine = "source-file ~/.exe-os/tmux.conf";
|
|
1269
1430
|
const pkgRoot = resolvePackageRoot();
|
|
1270
|
-
const assetPath =
|
|
1271
|
-
if (!
|
|
1431
|
+
const assetPath = path6.join(pkgRoot, "dist", "assets", "tmux.conf");
|
|
1432
|
+
if (!existsSync6(assetPath)) {
|
|
1272
1433
|
process.stderr.write(`exe-os: tmux.conf asset not found at ${assetPath} \u2014 skipping tmux setup
|
|
1273
1434
|
`);
|
|
1274
1435
|
return;
|
|
1275
1436
|
}
|
|
1276
|
-
|
|
1437
|
+
mkdirSync4(exeDir, { recursive: true });
|
|
1277
1438
|
copyFileSync(assetPath, exeTmuxConf);
|
|
1278
|
-
if (
|
|
1279
|
-
const existing =
|
|
1439
|
+
if (existsSync6(userTmuxConf)) {
|
|
1440
|
+
const existing = readFileSync5(userTmuxConf, "utf8");
|
|
1280
1441
|
if (!existing.includes(sourceLine)) {
|
|
1281
|
-
if (!
|
|
1442
|
+
if (!existsSync6(backupPath)) {
|
|
1282
1443
|
copyFileSync(userTmuxConf, backupPath);
|
|
1283
1444
|
process.stderr.write(`exe-os: backed up existing tmux config to ${backupPath}
|
|
1284
1445
|
`);
|
|
1285
1446
|
}
|
|
1286
|
-
|
|
1447
|
+
writeFileSync4(userTmuxConf, `${sourceLine}
|
|
1287
1448
|
${existing}`);
|
|
1288
1449
|
}
|
|
1289
1450
|
} else {
|
|
1290
|
-
|
|
1451
|
+
writeFileSync4(userTmuxConf, `# Exe OS tmux defaults \u2014 remove this line to use your own config
|
|
1291
1452
|
${sourceLine}
|
|
1292
1453
|
`);
|
|
1293
1454
|
}
|
|
@@ -1299,9 +1460,9 @@ ${sourceLine}
|
|
|
1299
1460
|
}
|
|
1300
1461
|
function setupGhostty(home) {
|
|
1301
1462
|
const homeDir = home ?? os5.homedir();
|
|
1302
|
-
const xdgConfig =
|
|
1303
|
-
const macConfig =
|
|
1304
|
-
const ghosttyInstalled =
|
|
1463
|
+
const xdgConfig = path6.join(homeDir, ".config", "ghostty");
|
|
1464
|
+
const macConfig = path6.join(homeDir, "Library", "Application Support", "com.mitchellh.ghostty");
|
|
1465
|
+
const ghosttyInstalled = existsSync6(xdgConfig) || existsSync6(macConfig) || (() => {
|
|
1305
1466
|
try {
|
|
1306
1467
|
execSync2("which ghostty 2>/dev/null");
|
|
1307
1468
|
return true;
|
|
@@ -1313,47 +1474,47 @@ function setupGhostty(home) {
|
|
|
1313
1474
|
return;
|
|
1314
1475
|
}
|
|
1315
1476
|
const pkgRoot = resolvePackageRoot();
|
|
1316
|
-
const assetPath =
|
|
1317
|
-
if (!
|
|
1477
|
+
const assetPath = path6.join(pkgRoot, "dist", "assets", "ghostty.conf");
|
|
1478
|
+
if (!existsSync6(assetPath)) {
|
|
1318
1479
|
process.stderr.write("exe-os: ghostty.conf asset not found \u2014 skipping Ghostty setup\n");
|
|
1319
1480
|
return;
|
|
1320
1481
|
}
|
|
1321
1482
|
const configDir = xdgConfig;
|
|
1322
|
-
const configPath =
|
|
1323
|
-
const backupPath =
|
|
1324
|
-
|
|
1483
|
+
const configPath = path6.join(configDir, "config");
|
|
1484
|
+
const backupPath = path6.join(configDir, "config.backup");
|
|
1485
|
+
mkdirSync4(configDir, { recursive: true });
|
|
1325
1486
|
const START_MARKER = "# \u2500\u2500 exe-os:ghostty-start \u2500\u2500";
|
|
1326
1487
|
const END_MARKER = "# \u2500\u2500 exe-os:ghostty-end \u2500\u2500";
|
|
1327
|
-
const assetContent =
|
|
1488
|
+
const assetContent = readFileSync5(assetPath, "utf8").trim();
|
|
1328
1489
|
const markedSection = `${START_MARKER}
|
|
1329
1490
|
${assetContent}
|
|
1330
1491
|
${END_MARKER}`;
|
|
1331
|
-
if (
|
|
1332
|
-
const existing =
|
|
1492
|
+
if (existsSync6(configPath)) {
|
|
1493
|
+
const existing = readFileSync5(configPath, "utf8");
|
|
1333
1494
|
if (existing.includes(START_MARKER) && existing.includes(END_MARKER)) {
|
|
1334
1495
|
const before = existing.slice(0, existing.indexOf(START_MARKER));
|
|
1335
1496
|
const after = existing.slice(existing.indexOf(END_MARKER) + END_MARKER.length);
|
|
1336
|
-
|
|
1497
|
+
writeFileSync4(configPath, `${before}${markedSection}${after}`);
|
|
1337
1498
|
} else if (existing.includes("Exe OS")) {
|
|
1338
|
-
if (!
|
|
1499
|
+
if (!existsSync6(backupPath)) {
|
|
1339
1500
|
copyFileSync(configPath, backupPath);
|
|
1340
1501
|
process.stderr.write(`exe-os: backed up existing Ghostty config to ${backupPath}
|
|
1341
1502
|
`);
|
|
1342
1503
|
}
|
|
1343
|
-
|
|
1504
|
+
writeFileSync4(configPath, `${markedSection}
|
|
1344
1505
|
`);
|
|
1345
1506
|
} else {
|
|
1346
|
-
if (!
|
|
1507
|
+
if (!existsSync6(backupPath)) {
|
|
1347
1508
|
copyFileSync(configPath, backupPath);
|
|
1348
1509
|
process.stderr.write(`exe-os: backed up existing Ghostty config to ${backupPath}
|
|
1349
1510
|
`);
|
|
1350
1511
|
}
|
|
1351
|
-
|
|
1512
|
+
writeFileSync4(configPath, `${markedSection}
|
|
1352
1513
|
|
|
1353
1514
|
${existing}`);
|
|
1354
1515
|
}
|
|
1355
1516
|
} else {
|
|
1356
|
-
|
|
1517
|
+
writeFileSync4(configPath, `${markedSection}
|
|
1357
1518
|
`);
|
|
1358
1519
|
}
|
|
1359
1520
|
process.stderr.write("exe-os: Ghostty config installed\n");
|
|
@@ -1403,14 +1564,14 @@ __export(keychain_exports, {
|
|
|
1403
1564
|
setMasterKey: () => setMasterKey
|
|
1404
1565
|
});
|
|
1405
1566
|
import { readFile as readFile4, writeFile as writeFile4, unlink, mkdir as mkdir4, chmod as chmod2 } from "fs/promises";
|
|
1406
|
-
import { existsSync as
|
|
1407
|
-
import
|
|
1567
|
+
import { existsSync as existsSync7 } from "fs";
|
|
1568
|
+
import path7 from "path";
|
|
1408
1569
|
import os6 from "os";
|
|
1409
1570
|
function getKeyDir() {
|
|
1410
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ??
|
|
1571
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path7.join(os6.homedir(), ".exe-os");
|
|
1411
1572
|
}
|
|
1412
1573
|
function getKeyPath() {
|
|
1413
|
-
return
|
|
1574
|
+
return path7.join(getKeyDir(), "master.key");
|
|
1414
1575
|
}
|
|
1415
1576
|
async function tryKeytar() {
|
|
1416
1577
|
try {
|
|
@@ -1431,7 +1592,7 @@ async function getMasterKey() {
|
|
|
1431
1592
|
}
|
|
1432
1593
|
}
|
|
1433
1594
|
const keyPath = getKeyPath();
|
|
1434
|
-
if (!
|
|
1595
|
+
if (!existsSync7(keyPath)) {
|
|
1435
1596
|
process.stderr.write(
|
|
1436
1597
|
`[keychain] Key not found at ${keyPath} (HOME=${os6.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
|
|
1437
1598
|
`
|
|
@@ -1474,7 +1635,7 @@ async function deleteMasterKey() {
|
|
|
1474
1635
|
}
|
|
1475
1636
|
}
|
|
1476
1637
|
const keyPath = getKeyPath();
|
|
1477
|
-
if (
|
|
1638
|
+
if (existsSync7(keyPath)) {
|
|
1478
1639
|
await unlink(keyPath);
|
|
1479
1640
|
}
|
|
1480
1641
|
}
|
|
@@ -1618,13 +1779,597 @@ var init_db_retry = __esm({
|
|
|
1618
1779
|
}
|
|
1619
1780
|
});
|
|
1620
1781
|
|
|
1782
|
+
// src/lib/database-adapter.ts
|
|
1783
|
+
import os7 from "os";
|
|
1784
|
+
import path8 from "path";
|
|
1785
|
+
import { createRequire } from "module";
|
|
1786
|
+
import { pathToFileURL } from "url";
|
|
1787
|
+
function quotedIdentifier(identifier) {
|
|
1788
|
+
return `"${identifier.replace(/"/g, '""')}"`;
|
|
1789
|
+
}
|
|
1790
|
+
function unqualifiedTableName(name) {
|
|
1791
|
+
const raw = name.trim().replace(/^"|"$/g, "");
|
|
1792
|
+
const parts = raw.split(".");
|
|
1793
|
+
return parts[parts.length - 1].replace(/^"|"$/g, "").toLowerCase();
|
|
1794
|
+
}
|
|
1795
|
+
function stripTrailingSemicolon(sql) {
|
|
1796
|
+
return sql.trim().replace(/;+\s*$/u, "");
|
|
1797
|
+
}
|
|
1798
|
+
function appendClause(sql, clause) {
|
|
1799
|
+
const trimmed = stripTrailingSemicolon(sql);
|
|
1800
|
+
const returningMatch = /\sRETURNING\b[\s\S]*$/iu.exec(trimmed);
|
|
1801
|
+
if (!returningMatch) {
|
|
1802
|
+
return `${trimmed}${clause}`;
|
|
1803
|
+
}
|
|
1804
|
+
const idx = returningMatch.index;
|
|
1805
|
+
return `${trimmed.slice(0, idx)}${clause}${trimmed.slice(idx)}`;
|
|
1806
|
+
}
|
|
1807
|
+
function normalizeStatement(stmt) {
|
|
1808
|
+
if (typeof stmt === "string") {
|
|
1809
|
+
return { kind: "positional", sql: stmt, args: [] };
|
|
1810
|
+
}
|
|
1811
|
+
const sql = stmt.sql;
|
|
1812
|
+
if (Array.isArray(stmt.args) || stmt.args === void 0) {
|
|
1813
|
+
return { kind: "positional", sql, args: stmt.args ?? [] };
|
|
1814
|
+
}
|
|
1815
|
+
return { kind: "named", sql, args: stmt.args };
|
|
1816
|
+
}
|
|
1817
|
+
function rewriteBooleanLiterals(sql) {
|
|
1818
|
+
let out = sql;
|
|
1819
|
+
for (const column of BOOLEAN_COLUMN_NAMES) {
|
|
1820
|
+
const scoped = `((?:\\b[a-z_][a-z0-9_]*\\.)?${column})`;
|
|
1821
|
+
out = out.replace(new RegExp(`${scoped}\\s*=\\s*0\\b`, "giu"), "$1 = FALSE");
|
|
1822
|
+
out = out.replace(new RegExp(`${scoped}\\s*=\\s*1\\b`, "giu"), "$1 = TRUE");
|
|
1823
|
+
out = out.replace(new RegExp(`${scoped}\\s*!=\\s*0\\b`, "giu"), "$1 != FALSE");
|
|
1824
|
+
out = out.replace(new RegExp(`${scoped}\\s*!=\\s*1\\b`, "giu"), "$1 != TRUE");
|
|
1825
|
+
out = out.replace(new RegExp(`${scoped}\\s*<>\\s*0\\b`, "giu"), "$1 <> FALSE");
|
|
1826
|
+
out = out.replace(new RegExp(`${scoped}\\s*<>\\s*1\\b`, "giu"), "$1 <> TRUE");
|
|
1827
|
+
}
|
|
1828
|
+
return out;
|
|
1829
|
+
}
|
|
1830
|
+
function rewriteInsertOrIgnore(sql) {
|
|
1831
|
+
if (!/^\s*INSERT\s+OR\s+IGNORE\s+INTO\b/iu.test(sql)) {
|
|
1832
|
+
return sql;
|
|
1833
|
+
}
|
|
1834
|
+
const replaced = sql.replace(/^\s*INSERT\s+OR\s+IGNORE\s+INTO\b/iu, "INSERT INTO");
|
|
1835
|
+
return /\bON\s+CONFLICT\b/iu.test(replaced) ? replaced : appendClause(replaced, " ON CONFLICT DO NOTHING");
|
|
1836
|
+
}
|
|
1837
|
+
function rewriteInsertOrReplace(sql) {
|
|
1838
|
+
const match = /^\s*INSERT\s+OR\s+REPLACE\s+INTO\s+([A-Za-z0-9_."]+)\s*\(([^)]+)\)([\s\S]*)$/iu.exec(sql);
|
|
1839
|
+
if (!match) {
|
|
1840
|
+
return sql;
|
|
1841
|
+
}
|
|
1842
|
+
const rawTable = match[1];
|
|
1843
|
+
const rawColumns = match[2];
|
|
1844
|
+
const remainder = match[3];
|
|
1845
|
+
const tableName = unqualifiedTableName(rawTable);
|
|
1846
|
+
const conflictKeys = UPSERT_KEYS[tableName];
|
|
1847
|
+
if (!conflictKeys?.length) {
|
|
1848
|
+
return sql;
|
|
1849
|
+
}
|
|
1850
|
+
const columns = rawColumns.split(",").map((col) => col.trim().replace(/^"|"$/g, ""));
|
|
1851
|
+
const updateColumns = columns.filter((col) => !conflictKeys.includes(col));
|
|
1852
|
+
const conflictTarget = conflictKeys.map(quotedIdentifier).join(", ");
|
|
1853
|
+
const updateClause = updateColumns.length === 0 ? " DO NOTHING" : ` DO UPDATE SET ${updateColumns.map((col) => `${quotedIdentifier(col)} = EXCLUDED.${quotedIdentifier(col)}`).join(", ")}`;
|
|
1854
|
+
return `INSERT INTO ${rawTable} (${rawColumns})${appendClause(remainder, ` ON CONFLICT (${conflictTarget})${updateClause}`)}`;
|
|
1855
|
+
}
|
|
1856
|
+
function rewriteSql(sql) {
|
|
1857
|
+
let out = sql;
|
|
1858
|
+
out = out.replace(/\bdatetime\(\s*['"]now['"]\s*\)/giu, "CURRENT_TIMESTAMP");
|
|
1859
|
+
out = out.replace(/\bvector32\s*\(\s*\?\s*\)/giu, "?");
|
|
1860
|
+
out = rewriteBooleanLiterals(out);
|
|
1861
|
+
out = rewriteInsertOrReplace(out);
|
|
1862
|
+
out = rewriteInsertOrIgnore(out);
|
|
1863
|
+
return stripTrailingSemicolon(out);
|
|
1864
|
+
}
|
|
1865
|
+
function toBoolean(value) {
|
|
1866
|
+
if (value === null || value === void 0) return value;
|
|
1867
|
+
if (typeof value === "boolean") return value;
|
|
1868
|
+
if (typeof value === "number") return value !== 0;
|
|
1869
|
+
if (typeof value === "bigint") return value !== 0n;
|
|
1870
|
+
if (typeof value === "string") {
|
|
1871
|
+
const normalized = value.trim().toLowerCase();
|
|
1872
|
+
if (normalized === "0" || normalized === "false") return false;
|
|
1873
|
+
if (normalized === "1" || normalized === "true") return true;
|
|
1874
|
+
}
|
|
1875
|
+
return Boolean(value);
|
|
1876
|
+
}
|
|
1877
|
+
function countQuestionMarks(sql, end) {
|
|
1878
|
+
let count = 0;
|
|
1879
|
+
let inSingle = false;
|
|
1880
|
+
let inDouble = false;
|
|
1881
|
+
let inLineComment = false;
|
|
1882
|
+
let inBlockComment = false;
|
|
1883
|
+
for (let i = 0; i < end; i++) {
|
|
1884
|
+
const ch = sql[i];
|
|
1885
|
+
const next = sql[i + 1];
|
|
1886
|
+
if (inLineComment) {
|
|
1887
|
+
if (ch === "\n") inLineComment = false;
|
|
1888
|
+
continue;
|
|
1889
|
+
}
|
|
1890
|
+
if (inBlockComment) {
|
|
1891
|
+
if (ch === "*" && next === "/") {
|
|
1892
|
+
inBlockComment = false;
|
|
1893
|
+
i += 1;
|
|
1894
|
+
}
|
|
1895
|
+
continue;
|
|
1896
|
+
}
|
|
1897
|
+
if (!inSingle && !inDouble && ch === "-" && next === "-") {
|
|
1898
|
+
inLineComment = true;
|
|
1899
|
+
i += 1;
|
|
1900
|
+
continue;
|
|
1901
|
+
}
|
|
1902
|
+
if (!inSingle && !inDouble && ch === "/" && next === "*") {
|
|
1903
|
+
inBlockComment = true;
|
|
1904
|
+
i += 1;
|
|
1905
|
+
continue;
|
|
1906
|
+
}
|
|
1907
|
+
if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
|
|
1908
|
+
inSingle = !inSingle;
|
|
1909
|
+
continue;
|
|
1910
|
+
}
|
|
1911
|
+
if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
|
|
1912
|
+
inDouble = !inDouble;
|
|
1913
|
+
continue;
|
|
1914
|
+
}
|
|
1915
|
+
if (!inSingle && !inDouble && ch === "?") {
|
|
1916
|
+
count += 1;
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
1919
|
+
return count;
|
|
1920
|
+
}
|
|
1921
|
+
function findBooleanPlaceholderIndexes(sql) {
|
|
1922
|
+
const indexes = /* @__PURE__ */ new Set();
|
|
1923
|
+
for (const column of BOOLEAN_COLUMN_NAMES) {
|
|
1924
|
+
const pattern = new RegExp(`(?:\\b[a-z_][a-z0-9_]*\\.)?${column}\\s*=\\s*\\?`, "giu");
|
|
1925
|
+
for (const match of sql.matchAll(pattern)) {
|
|
1926
|
+
const matchText = match[0];
|
|
1927
|
+
const qIndex = match.index + matchText.lastIndexOf("?");
|
|
1928
|
+
indexes.add(countQuestionMarks(sql, qIndex + 1));
|
|
1929
|
+
}
|
|
1930
|
+
}
|
|
1931
|
+
return indexes;
|
|
1932
|
+
}
|
|
1933
|
+
function coerceInsertBooleanArgs(sql, args2) {
|
|
1934
|
+
const match = /^\s*INSERT(?:\s+OR\s+(?:IGNORE|REPLACE))?\s+INTO\s+([A-Za-z0-9_."]+)\s*\(([^)]+)\)/iu.exec(sql);
|
|
1935
|
+
if (!match) return;
|
|
1936
|
+
const rawTable = match[1];
|
|
1937
|
+
const rawColumns = match[2];
|
|
1938
|
+
const boolColumns = BOOLEAN_COLUMNS_BY_TABLE[unqualifiedTableName(rawTable)];
|
|
1939
|
+
if (!boolColumns?.size) return;
|
|
1940
|
+
const columns = rawColumns.split(",").map((col) => col.trim().replace(/^"|"$/g, ""));
|
|
1941
|
+
for (const [index, column] of columns.entries()) {
|
|
1942
|
+
if (boolColumns.has(column) && index < args2.length) {
|
|
1943
|
+
args2[index] = toBoolean(args2[index]);
|
|
1944
|
+
}
|
|
1945
|
+
}
|
|
1946
|
+
}
|
|
1947
|
+
function coerceUpdateBooleanArgs(sql, args2) {
|
|
1948
|
+
const match = /^\s*UPDATE\s+([A-Za-z0-9_."]+)\s+SET\s+([\s\S]+?)(?:\s+WHERE\b|$)/iu.exec(sql);
|
|
1949
|
+
if (!match) return;
|
|
1950
|
+
const rawTable = match[1];
|
|
1951
|
+
const setClause = match[2];
|
|
1952
|
+
const boolColumns = BOOLEAN_COLUMNS_BY_TABLE[unqualifiedTableName(rawTable)];
|
|
1953
|
+
if (!boolColumns?.size) return;
|
|
1954
|
+
const assignments = setClause.split(",");
|
|
1955
|
+
let placeholderIndex = 0;
|
|
1956
|
+
for (const assignment of assignments) {
|
|
1957
|
+
if (!assignment.includes("?")) continue;
|
|
1958
|
+
placeholderIndex += 1;
|
|
1959
|
+
const colMatch = /^\s*(?:[A-Za-z_][A-Za-z0-9_]*\.)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*\?/iu.exec(assignment);
|
|
1960
|
+
if (colMatch && boolColumns.has(colMatch[1])) {
|
|
1961
|
+
args2[placeholderIndex - 1] = toBoolean(args2[placeholderIndex - 1]);
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1965
|
+
function coerceBooleanArgs(sql, args2) {
|
|
1966
|
+
const nextArgs = [...args2];
|
|
1967
|
+
coerceInsertBooleanArgs(sql, nextArgs);
|
|
1968
|
+
coerceUpdateBooleanArgs(sql, nextArgs);
|
|
1969
|
+
const placeholderIndexes = findBooleanPlaceholderIndexes(sql);
|
|
1970
|
+
for (const index of placeholderIndexes) {
|
|
1971
|
+
if (index > 0 && index <= nextArgs.length) {
|
|
1972
|
+
nextArgs[index - 1] = toBoolean(nextArgs[index - 1]);
|
|
1973
|
+
}
|
|
1974
|
+
}
|
|
1975
|
+
return nextArgs;
|
|
1976
|
+
}
|
|
1977
|
+
function convertQuestionMarksToDollarParams(sql) {
|
|
1978
|
+
let out = "";
|
|
1979
|
+
let placeholder = 0;
|
|
1980
|
+
let inSingle = false;
|
|
1981
|
+
let inDouble = false;
|
|
1982
|
+
let inLineComment = false;
|
|
1983
|
+
let inBlockComment = false;
|
|
1984
|
+
for (let i = 0; i < sql.length; i++) {
|
|
1985
|
+
const ch = sql[i];
|
|
1986
|
+
const next = sql[i + 1];
|
|
1987
|
+
if (inLineComment) {
|
|
1988
|
+
out += ch;
|
|
1989
|
+
if (ch === "\n") inLineComment = false;
|
|
1990
|
+
continue;
|
|
1991
|
+
}
|
|
1992
|
+
if (inBlockComment) {
|
|
1993
|
+
out += ch;
|
|
1994
|
+
if (ch === "*" && next === "/") {
|
|
1995
|
+
out += next;
|
|
1996
|
+
inBlockComment = false;
|
|
1997
|
+
i += 1;
|
|
1998
|
+
}
|
|
1999
|
+
continue;
|
|
2000
|
+
}
|
|
2001
|
+
if (!inSingle && !inDouble && ch === "-" && next === "-") {
|
|
2002
|
+
out += ch + next;
|
|
2003
|
+
inLineComment = true;
|
|
2004
|
+
i += 1;
|
|
2005
|
+
continue;
|
|
2006
|
+
}
|
|
2007
|
+
if (!inSingle && !inDouble && ch === "/" && next === "*") {
|
|
2008
|
+
out += ch + next;
|
|
2009
|
+
inBlockComment = true;
|
|
2010
|
+
i += 1;
|
|
2011
|
+
continue;
|
|
2012
|
+
}
|
|
2013
|
+
if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
|
|
2014
|
+
inSingle = !inSingle;
|
|
2015
|
+
out += ch;
|
|
2016
|
+
continue;
|
|
2017
|
+
}
|
|
2018
|
+
if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
|
|
2019
|
+
inDouble = !inDouble;
|
|
2020
|
+
out += ch;
|
|
2021
|
+
continue;
|
|
2022
|
+
}
|
|
2023
|
+
if (!inSingle && !inDouble && ch === "?") {
|
|
2024
|
+
placeholder += 1;
|
|
2025
|
+
out += `$${placeholder}`;
|
|
2026
|
+
continue;
|
|
2027
|
+
}
|
|
2028
|
+
out += ch;
|
|
2029
|
+
}
|
|
2030
|
+
return out;
|
|
2031
|
+
}
|
|
2032
|
+
function translateStatementForPostgres(stmt) {
|
|
2033
|
+
const normalized = normalizeStatement(stmt);
|
|
2034
|
+
if (normalized.kind === "named") {
|
|
2035
|
+
throw new Error("Named SQL parameters are not supported by the Prisma adapter.");
|
|
2036
|
+
}
|
|
2037
|
+
const rewrittenSql = rewriteSql(normalized.sql);
|
|
2038
|
+
const coercedArgs = coerceBooleanArgs(rewrittenSql, normalized.args);
|
|
2039
|
+
return {
|
|
2040
|
+
sql: convertQuestionMarksToDollarParams(rewrittenSql),
|
|
2041
|
+
args: coercedArgs
|
|
2042
|
+
};
|
|
2043
|
+
}
|
|
2044
|
+
function shouldBypassPostgres(stmt) {
|
|
2045
|
+
const normalized = normalizeStatement(stmt);
|
|
2046
|
+
if (normalized.kind === "named") {
|
|
2047
|
+
return true;
|
|
2048
|
+
}
|
|
2049
|
+
return IMMEDIATE_FALLBACK_PATTERNS.some((pattern) => pattern.test(normalized.sql));
|
|
2050
|
+
}
|
|
2051
|
+
function shouldFallbackOnError(error) {
|
|
2052
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2053
|
+
return /42P01|42883|42601|does not exist|syntax error|not supported|Named SQL parameters are not supported/iu.test(message);
|
|
2054
|
+
}
|
|
2055
|
+
function isReadQuery(sql) {
|
|
2056
|
+
const trimmed = sql.trimStart();
|
|
2057
|
+
return /^(SELECT|WITH|SHOW|EXPLAIN|VALUES)\b/iu.test(trimmed) || /\bRETURNING\b/iu.test(trimmed);
|
|
2058
|
+
}
|
|
2059
|
+
function buildRow(row, columns) {
|
|
2060
|
+
const values = columns.map((column) => row[column]);
|
|
2061
|
+
return Object.assign(values, row);
|
|
2062
|
+
}
|
|
2063
|
+
function buildResultSet(rows, rowsAffected = 0) {
|
|
2064
|
+
const columns = rows[0] ? Object.keys(rows[0]) : [];
|
|
2065
|
+
const resultRows = rows.map((row) => buildRow(row, columns));
|
|
2066
|
+
return {
|
|
2067
|
+
columns,
|
|
2068
|
+
columnTypes: columns.map(() => ""),
|
|
2069
|
+
rows: resultRows,
|
|
2070
|
+
rowsAffected,
|
|
2071
|
+
lastInsertRowid: void 0,
|
|
2072
|
+
toJSON() {
|
|
2073
|
+
return {
|
|
2074
|
+
columns,
|
|
2075
|
+
columnTypes: columns.map(() => ""),
|
|
2076
|
+
rows,
|
|
2077
|
+
rowsAffected,
|
|
2078
|
+
lastInsertRowid: void 0
|
|
2079
|
+
};
|
|
2080
|
+
}
|
|
2081
|
+
};
|
|
2082
|
+
}
|
|
2083
|
+
async function loadPrismaClient() {
|
|
2084
|
+
if (!prismaClientPromise) {
|
|
2085
|
+
prismaClientPromise = (async () => {
|
|
2086
|
+
const explicitPath = process.env.EXE_OS_PRISMA_CLIENT_PATH;
|
|
2087
|
+
if (explicitPath) {
|
|
2088
|
+
const module2 = await import(pathToFileURL(explicitPath).href);
|
|
2089
|
+
const PrismaClient2 = module2.PrismaClient ?? module2.default?.PrismaClient;
|
|
2090
|
+
if (!PrismaClient2) {
|
|
2091
|
+
throw new Error(`No PrismaClient export found at ${explicitPath}`);
|
|
2092
|
+
}
|
|
2093
|
+
return new PrismaClient2();
|
|
2094
|
+
}
|
|
2095
|
+
const exeDbRoot = process.env.EXE_DB_ROOT ?? path8.join(os7.homedir(), "exe-db");
|
|
2096
|
+
const requireFromExeDb = createRequire(path8.join(exeDbRoot, "package.json"));
|
|
2097
|
+
const prismaEntry = requireFromExeDb.resolve("@prisma/client");
|
|
2098
|
+
const module = await import(pathToFileURL(prismaEntry).href);
|
|
2099
|
+
const PrismaClient = module.PrismaClient ?? module.default?.PrismaClient;
|
|
2100
|
+
if (!PrismaClient) {
|
|
2101
|
+
throw new Error(`No PrismaClient export found in ${prismaEntry}`);
|
|
2102
|
+
}
|
|
2103
|
+
return new PrismaClient();
|
|
2104
|
+
})();
|
|
2105
|
+
}
|
|
2106
|
+
return prismaClientPromise;
|
|
2107
|
+
}
|
|
2108
|
+
async function ensureCompatibilityViews(prisma) {
|
|
2109
|
+
if (!compatibilityBootstrapPromise) {
|
|
2110
|
+
compatibilityBootstrapPromise = (async () => {
|
|
2111
|
+
for (const mapping of VIEW_MAPPINGS) {
|
|
2112
|
+
const relation = mapping.source.replace(/"/g, "");
|
|
2113
|
+
const rows = await prisma.$queryRawUnsafe(
|
|
2114
|
+
"SELECT to_regclass($1) AS regclass",
|
|
2115
|
+
relation
|
|
2116
|
+
);
|
|
2117
|
+
if (!rows[0]?.regclass) {
|
|
2118
|
+
continue;
|
|
2119
|
+
}
|
|
2120
|
+
await prisma.$executeRawUnsafe(
|
|
2121
|
+
`CREATE OR REPLACE VIEW public.${quotedIdentifier(mapping.view)} AS SELECT * FROM ${mapping.source}`
|
|
2122
|
+
);
|
|
2123
|
+
}
|
|
2124
|
+
})();
|
|
2125
|
+
}
|
|
2126
|
+
return compatibilityBootstrapPromise;
|
|
2127
|
+
}
|
|
2128
|
+
async function executeOnPrisma(executor, stmt) {
|
|
2129
|
+
const translated = translateStatementForPostgres(stmt);
|
|
2130
|
+
if (isReadQuery(translated.sql)) {
|
|
2131
|
+
const rows = await executor.$queryRawUnsafe(
|
|
2132
|
+
translated.sql,
|
|
2133
|
+
...translated.args
|
|
2134
|
+
);
|
|
2135
|
+
return buildResultSet(rows, /\bRETURNING\b/iu.test(translated.sql) ? rows.length : 0);
|
|
2136
|
+
}
|
|
2137
|
+
const rowsAffected = await executor.$executeRawUnsafe(translated.sql, ...translated.args);
|
|
2138
|
+
return buildResultSet([], rowsAffected);
|
|
2139
|
+
}
|
|
2140
|
+
function splitSqlStatements(sql) {
|
|
2141
|
+
const parts = [];
|
|
2142
|
+
let current = "";
|
|
2143
|
+
let inSingle = false;
|
|
2144
|
+
let inDouble = false;
|
|
2145
|
+
let inLineComment = false;
|
|
2146
|
+
let inBlockComment = false;
|
|
2147
|
+
for (let i = 0; i < sql.length; i++) {
|
|
2148
|
+
const ch = sql[i];
|
|
2149
|
+
const next = sql[i + 1];
|
|
2150
|
+
if (inLineComment) {
|
|
2151
|
+
current += ch;
|
|
2152
|
+
if (ch === "\n") inLineComment = false;
|
|
2153
|
+
continue;
|
|
2154
|
+
}
|
|
2155
|
+
if (inBlockComment) {
|
|
2156
|
+
current += ch;
|
|
2157
|
+
if (ch === "*" && next === "/") {
|
|
2158
|
+
current += next;
|
|
2159
|
+
inBlockComment = false;
|
|
2160
|
+
i += 1;
|
|
2161
|
+
}
|
|
2162
|
+
continue;
|
|
2163
|
+
}
|
|
2164
|
+
if (!inSingle && !inDouble && ch === "-" && next === "-") {
|
|
2165
|
+
current += ch + next;
|
|
2166
|
+
inLineComment = true;
|
|
2167
|
+
i += 1;
|
|
2168
|
+
continue;
|
|
2169
|
+
}
|
|
2170
|
+
if (!inSingle && !inDouble && ch === "/" && next === "*") {
|
|
2171
|
+
current += ch + next;
|
|
2172
|
+
inBlockComment = true;
|
|
2173
|
+
i += 1;
|
|
2174
|
+
continue;
|
|
2175
|
+
}
|
|
2176
|
+
if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
|
|
2177
|
+
inSingle = !inSingle;
|
|
2178
|
+
current += ch;
|
|
2179
|
+
continue;
|
|
2180
|
+
}
|
|
2181
|
+
if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
|
|
2182
|
+
inDouble = !inDouble;
|
|
2183
|
+
current += ch;
|
|
2184
|
+
continue;
|
|
2185
|
+
}
|
|
2186
|
+
if (!inSingle && !inDouble && ch === ";") {
|
|
2187
|
+
if (current.trim()) {
|
|
2188
|
+
parts.push(current.trim());
|
|
2189
|
+
}
|
|
2190
|
+
current = "";
|
|
2191
|
+
continue;
|
|
2192
|
+
}
|
|
2193
|
+
current += ch;
|
|
2194
|
+
}
|
|
2195
|
+
if (current.trim()) {
|
|
2196
|
+
parts.push(current.trim());
|
|
2197
|
+
}
|
|
2198
|
+
return parts;
|
|
2199
|
+
}
|
|
2200
|
+
async function createPrismaDbAdapter(fallbackClient) {
|
|
2201
|
+
const prisma = await loadPrismaClient();
|
|
2202
|
+
await ensureCompatibilityViews(prisma);
|
|
2203
|
+
let closed = false;
|
|
2204
|
+
let adapter;
|
|
2205
|
+
const fallbackExecute = async (stmt, error) => {
|
|
2206
|
+
if (!fallbackClient) {
|
|
2207
|
+
if (error) throw error;
|
|
2208
|
+
throw new Error("No fallback SQLite client is available for this Prisma-routed query.");
|
|
2209
|
+
}
|
|
2210
|
+
if (error) {
|
|
2211
|
+
process.stderr.write(
|
|
2212
|
+
`[database-adapter] Falling back to SQLite: ${error instanceof Error ? error.message : String(error)}
|
|
2213
|
+
`
|
|
2214
|
+
);
|
|
2215
|
+
}
|
|
2216
|
+
return fallbackClient.execute(stmt);
|
|
2217
|
+
};
|
|
2218
|
+
adapter = {
|
|
2219
|
+
async execute(stmt) {
|
|
2220
|
+
if (shouldBypassPostgres(stmt)) {
|
|
2221
|
+
return fallbackExecute(stmt);
|
|
2222
|
+
}
|
|
2223
|
+
try {
|
|
2224
|
+
return await executeOnPrisma(prisma, stmt);
|
|
2225
|
+
} catch (error) {
|
|
2226
|
+
if (shouldFallbackOnError(error)) {
|
|
2227
|
+
return fallbackExecute(stmt, error);
|
|
2228
|
+
}
|
|
2229
|
+
throw error;
|
|
2230
|
+
}
|
|
2231
|
+
},
|
|
2232
|
+
async batch(stmts, mode) {
|
|
2233
|
+
if (stmts.some((stmt) => shouldBypassPostgres(stmt))) {
|
|
2234
|
+
if (!fallbackClient) {
|
|
2235
|
+
throw new Error("Cannot batch unsupported SQLite-only statements without a fallback client.");
|
|
2236
|
+
}
|
|
2237
|
+
return fallbackClient.batch(stmts, mode);
|
|
2238
|
+
}
|
|
2239
|
+
try {
|
|
2240
|
+
if (prisma.$transaction) {
|
|
2241
|
+
return await prisma.$transaction(async (tx) => {
|
|
2242
|
+
const results2 = [];
|
|
2243
|
+
for (const stmt of stmts) {
|
|
2244
|
+
results2.push(await executeOnPrisma(tx, stmt));
|
|
2245
|
+
}
|
|
2246
|
+
return results2;
|
|
2247
|
+
});
|
|
2248
|
+
}
|
|
2249
|
+
const results = [];
|
|
2250
|
+
for (const stmt of stmts) {
|
|
2251
|
+
results.push(await executeOnPrisma(prisma, stmt));
|
|
2252
|
+
}
|
|
2253
|
+
return results;
|
|
2254
|
+
} catch (error) {
|
|
2255
|
+
if (fallbackClient && shouldFallbackOnError(error)) {
|
|
2256
|
+
process.stderr.write(
|
|
2257
|
+
`[database-adapter] Falling back batch to SQLite: ${error instanceof Error ? error.message : String(error)}
|
|
2258
|
+
`
|
|
2259
|
+
);
|
|
2260
|
+
return fallbackClient.batch(stmts, mode);
|
|
2261
|
+
}
|
|
2262
|
+
throw error;
|
|
2263
|
+
}
|
|
2264
|
+
},
|
|
2265
|
+
async migrate(stmts) {
|
|
2266
|
+
if (fallbackClient) {
|
|
2267
|
+
return fallbackClient.migrate(stmts);
|
|
2268
|
+
}
|
|
2269
|
+
return adapter.batch(stmts, "deferred");
|
|
2270
|
+
},
|
|
2271
|
+
async transaction(mode) {
|
|
2272
|
+
if (!fallbackClient) {
|
|
2273
|
+
throw new Error("Interactive transactions are only supported on the SQLite fallback client.");
|
|
2274
|
+
}
|
|
2275
|
+
return fallbackClient.transaction(mode);
|
|
2276
|
+
},
|
|
2277
|
+
async executeMultiple(sql) {
|
|
2278
|
+
if (fallbackClient && shouldBypassPostgres(sql)) {
|
|
2279
|
+
return fallbackClient.executeMultiple(sql);
|
|
2280
|
+
}
|
|
2281
|
+
for (const statement of splitSqlStatements(sql)) {
|
|
2282
|
+
await adapter.execute(statement);
|
|
2283
|
+
}
|
|
2284
|
+
},
|
|
2285
|
+
async sync() {
|
|
2286
|
+
if (fallbackClient) {
|
|
2287
|
+
return fallbackClient.sync();
|
|
2288
|
+
}
|
|
2289
|
+
return { frame_no: 0, frames_synced: 0 };
|
|
2290
|
+
},
|
|
2291
|
+
close() {
|
|
2292
|
+
closed = true;
|
|
2293
|
+
prismaClientPromise = null;
|
|
2294
|
+
compatibilityBootstrapPromise = null;
|
|
2295
|
+
void prisma.$disconnect?.();
|
|
2296
|
+
},
|
|
2297
|
+
get closed() {
|
|
2298
|
+
return closed;
|
|
2299
|
+
},
|
|
2300
|
+
get protocol() {
|
|
2301
|
+
return "prisma-postgres";
|
|
2302
|
+
}
|
|
2303
|
+
};
|
|
2304
|
+
return adapter;
|
|
2305
|
+
}
|
|
2306
|
+
var VIEW_MAPPINGS, UPSERT_KEYS, BOOLEAN_COLUMNS_BY_TABLE, BOOLEAN_COLUMN_NAMES, IMMEDIATE_FALLBACK_PATTERNS, prismaClientPromise, compatibilityBootstrapPromise;
|
|
2307
|
+
var init_database_adapter = __esm({
|
|
2308
|
+
"src/lib/database-adapter.ts"() {
|
|
2309
|
+
"use strict";
|
|
2310
|
+
VIEW_MAPPINGS = [
|
|
2311
|
+
{ view: "memories", source: "memory.memory_records" },
|
|
2312
|
+
{ view: "tasks", source: "memory.tasks" },
|
|
2313
|
+
{ view: "behaviors", source: "memory.behaviors" },
|
|
2314
|
+
{ view: "entities", source: "memory.entities" },
|
|
2315
|
+
{ view: "relationships", source: "memory.relationships" },
|
|
2316
|
+
{ view: "entity_memories", source: "memory.entity_memories" },
|
|
2317
|
+
{ view: "entity_aliases", source: "memory.entity_aliases" },
|
|
2318
|
+
{ view: "notifications", source: "memory.notifications" },
|
|
2319
|
+
{ view: "messages", source: "memory.messages" },
|
|
2320
|
+
{ view: "users", source: "wiki.users" },
|
|
2321
|
+
{ view: "workspaces", source: "wiki.workspaces" },
|
|
2322
|
+
{ view: "workspace_users", source: "wiki.workspace_users" },
|
|
2323
|
+
{ view: "documents", source: "wiki.workspace_documents" },
|
|
2324
|
+
{ view: "chats", source: "wiki.workspace_chats" }
|
|
2325
|
+
];
|
|
2326
|
+
UPSERT_KEYS = {
|
|
2327
|
+
memories: ["id"],
|
|
2328
|
+
tasks: ["id"],
|
|
2329
|
+
behaviors: ["id"],
|
|
2330
|
+
entities: ["id"],
|
|
2331
|
+
relationships: ["id"],
|
|
2332
|
+
entity_aliases: ["alias"],
|
|
2333
|
+
notifications: ["id"],
|
|
2334
|
+
messages: ["id"],
|
|
2335
|
+
users: ["id"],
|
|
2336
|
+
workspaces: ["id"],
|
|
2337
|
+
workspace_users: ["id"],
|
|
2338
|
+
documents: ["id"],
|
|
2339
|
+
chats: ["id"]
|
|
2340
|
+
};
|
|
2341
|
+
BOOLEAN_COLUMNS_BY_TABLE = {
|
|
2342
|
+
memories: /* @__PURE__ */ new Set(["has_error", "draft"]),
|
|
2343
|
+
behaviors: /* @__PURE__ */ new Set(["active"]),
|
|
2344
|
+
notifications: /* @__PURE__ */ new Set(["read"]),
|
|
2345
|
+
users: /* @__PURE__ */ new Set(["has_personal_memory"])
|
|
2346
|
+
};
|
|
2347
|
+
BOOLEAN_COLUMN_NAMES = new Set(
|
|
2348
|
+
Object.values(BOOLEAN_COLUMNS_BY_TABLE).flatMap((cols) => [...cols])
|
|
2349
|
+
);
|
|
2350
|
+
IMMEDIATE_FALLBACK_PATTERNS = [
|
|
2351
|
+
/\bPRAGMA\b/i,
|
|
2352
|
+
/\bsqlite_master\b/i,
|
|
2353
|
+
/(?:^|[.\s])(?:memories|conversations|entities)_fts\b/i,
|
|
2354
|
+
/\bMATCH\b/i,
|
|
2355
|
+
/\bvector_distance_cos\s*\(/i,
|
|
2356
|
+
/\bjson_extract\s*\(/i,
|
|
2357
|
+
/\bjulianday\s*\(/i,
|
|
2358
|
+
/\bstrftime\s*\(/i,
|
|
2359
|
+
/\blast_insert_rowid\s*\(/i
|
|
2360
|
+
];
|
|
2361
|
+
prismaClientPromise = null;
|
|
2362
|
+
compatibilityBootstrapPromise = null;
|
|
2363
|
+
}
|
|
2364
|
+
});
|
|
2365
|
+
|
|
1621
2366
|
// src/lib/exe-daemon-client.ts
|
|
1622
2367
|
import net from "net";
|
|
1623
|
-
import
|
|
2368
|
+
import os8 from "os";
|
|
1624
2369
|
import { spawn } from "child_process";
|
|
1625
2370
|
import { randomUUID } from "crypto";
|
|
1626
|
-
import { existsSync as
|
|
1627
|
-
import
|
|
2371
|
+
import { existsSync as existsSync8, unlinkSync as unlinkSync2, readFileSync as readFileSync6, openSync, closeSync, statSync } from "fs";
|
|
2372
|
+
import path9 from "path";
|
|
1628
2373
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
1629
2374
|
function handleData(chunk) {
|
|
1630
2375
|
_buffer += chunk.toString();
|
|
@@ -1652,9 +2397,9 @@ function handleData(chunk) {
|
|
|
1652
2397
|
}
|
|
1653
2398
|
}
|
|
1654
2399
|
function cleanupStaleFiles() {
|
|
1655
|
-
if (
|
|
2400
|
+
if (existsSync8(PID_PATH)) {
|
|
1656
2401
|
try {
|
|
1657
|
-
const pid = parseInt(
|
|
2402
|
+
const pid = parseInt(readFileSync6(PID_PATH, "utf8").trim(), 10);
|
|
1658
2403
|
if (pid > 0) {
|
|
1659
2404
|
try {
|
|
1660
2405
|
process.kill(pid, 0);
|
|
@@ -1675,17 +2420,17 @@ function cleanupStaleFiles() {
|
|
|
1675
2420
|
}
|
|
1676
2421
|
}
|
|
1677
2422
|
function findPackageRoot() {
|
|
1678
|
-
let dir =
|
|
1679
|
-
const { root } =
|
|
2423
|
+
let dir = path9.dirname(fileURLToPath3(import.meta.url));
|
|
2424
|
+
const { root } = path9.parse(dir);
|
|
1680
2425
|
while (dir !== root) {
|
|
1681
|
-
if (
|
|
1682
|
-
dir =
|
|
2426
|
+
if (existsSync8(path9.join(dir, "package.json"))) return dir;
|
|
2427
|
+
dir = path9.dirname(dir);
|
|
1683
2428
|
}
|
|
1684
2429
|
return null;
|
|
1685
2430
|
}
|
|
1686
2431
|
function spawnDaemon() {
|
|
1687
|
-
const freeGB =
|
|
1688
|
-
const totalGB =
|
|
2432
|
+
const freeGB = os8.freemem() / (1024 * 1024 * 1024);
|
|
2433
|
+
const totalGB = os8.totalmem() / (1024 * 1024 * 1024);
|
|
1689
2434
|
if (totalGB <= 8) {
|
|
1690
2435
|
process.stderr.write(
|
|
1691
2436
|
`[exed-client] SKIP: ${totalGB.toFixed(0)}GB system \u2014 embedding daemon disabled. Using keyword search only. Minimum 16GB recommended for vector search.
|
|
@@ -1705,8 +2450,8 @@ function spawnDaemon() {
|
|
|
1705
2450
|
process.stderr.write("[exed-client] WARN: cannot find package root\n");
|
|
1706
2451
|
return;
|
|
1707
2452
|
}
|
|
1708
|
-
const daemonPath =
|
|
1709
|
-
if (!
|
|
2453
|
+
const daemonPath = path9.join(pkgRoot, "dist", "lib", "exe-daemon.js");
|
|
2454
|
+
if (!existsSync8(daemonPath)) {
|
|
1710
2455
|
process.stderr.write(`[exed-client] WARN: daemon script not found at ${daemonPath}
|
|
1711
2456
|
`);
|
|
1712
2457
|
return;
|
|
@@ -1714,7 +2459,7 @@ function spawnDaemon() {
|
|
|
1714
2459
|
const resolvedPath = daemonPath;
|
|
1715
2460
|
process.stderr.write(`[exed-client] Spawning daemon: ${resolvedPath}
|
|
1716
2461
|
`);
|
|
1717
|
-
const logPath =
|
|
2462
|
+
const logPath = path9.join(path9.dirname(SOCKET_PATH), "exed.log");
|
|
1718
2463
|
let stderrFd = "ignore";
|
|
1719
2464
|
try {
|
|
1720
2465
|
stderrFd = openSync(logPath, "a");
|
|
@@ -1865,74 +2610,123 @@ async function pingDaemon() {
|
|
|
1865
2610
|
return null;
|
|
1866
2611
|
}
|
|
1867
2612
|
function killAndRespawnDaemon() {
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
2613
|
+
if (!acquireSpawnLock()) {
|
|
2614
|
+
process.stderr.write("[exed-client] Another process is already restarting daemon \u2014 skipping\n");
|
|
2615
|
+
if (_socket) {
|
|
2616
|
+
_socket.destroy();
|
|
2617
|
+
_socket = null;
|
|
2618
|
+
}
|
|
2619
|
+
_connected = false;
|
|
2620
|
+
_buffer = "";
|
|
2621
|
+
return;
|
|
2622
|
+
}
|
|
2623
|
+
try {
|
|
2624
|
+
process.stderr.write("[exed-client] Killing daemon for restart...\n");
|
|
2625
|
+
if (existsSync8(PID_PATH)) {
|
|
2626
|
+
try {
|
|
2627
|
+
const pid = parseInt(readFileSync6(PID_PATH, "utf8").trim(), 10);
|
|
2628
|
+
if (pid > 0) {
|
|
2629
|
+
try {
|
|
2630
|
+
process.kill(pid, "SIGKILL");
|
|
2631
|
+
} catch {
|
|
2632
|
+
}
|
|
1876
2633
|
}
|
|
2634
|
+
} catch {
|
|
1877
2635
|
}
|
|
2636
|
+
}
|
|
2637
|
+
if (_socket) {
|
|
2638
|
+
_socket.destroy();
|
|
2639
|
+
_socket = null;
|
|
2640
|
+
}
|
|
2641
|
+
_connected = false;
|
|
2642
|
+
_buffer = "";
|
|
2643
|
+
try {
|
|
2644
|
+
unlinkSync2(PID_PATH);
|
|
1878
2645
|
} catch {
|
|
1879
2646
|
}
|
|
2647
|
+
try {
|
|
2648
|
+
unlinkSync2(SOCKET_PATH);
|
|
2649
|
+
} catch {
|
|
2650
|
+
}
|
|
2651
|
+
spawnDaemon();
|
|
2652
|
+
} finally {
|
|
2653
|
+
releaseSpawnLock();
|
|
1880
2654
|
}
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
_socket = null;
|
|
1884
|
-
}
|
|
1885
|
-
_connected = false;
|
|
1886
|
-
_buffer = "";
|
|
2655
|
+
}
|
|
2656
|
+
function isDaemonTooYoung() {
|
|
1887
2657
|
try {
|
|
1888
|
-
|
|
2658
|
+
const stat2 = statSync(PID_PATH);
|
|
2659
|
+
return Date.now() - stat2.mtimeMs < MIN_DAEMON_AGE_MS;
|
|
1889
2660
|
} catch {
|
|
2661
|
+
return false;
|
|
1890
2662
|
}
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
2663
|
+
}
|
|
2664
|
+
async function retryThenRestart(doRequest, label) {
|
|
2665
|
+
const result = await doRequest();
|
|
2666
|
+
if (!result.error) {
|
|
2667
|
+
_consecutiveFailures = 0;
|
|
2668
|
+
return result;
|
|
1894
2669
|
}
|
|
1895
|
-
|
|
2670
|
+
_consecutiveFailures++;
|
|
2671
|
+
for (let i = 0; i < MAX_RETRIES_BEFORE_RESTART; i++) {
|
|
2672
|
+
const delayMs = RETRY_DELAYS_MS[i] ?? 5e3;
|
|
2673
|
+
process.stderr.write(`[exed-client] ${label} failed (${result.error}), retry ${i + 1}/${MAX_RETRIES_BEFORE_RESTART} in ${delayMs}ms
|
|
2674
|
+
`);
|
|
2675
|
+
await new Promise((r) => setTimeout(r, delayMs));
|
|
2676
|
+
if (!_connected) {
|
|
2677
|
+
if (!await connectToSocket()) continue;
|
|
2678
|
+
}
|
|
2679
|
+
const retry = await doRequest();
|
|
2680
|
+
if (!retry.error) {
|
|
2681
|
+
_consecutiveFailures = 0;
|
|
2682
|
+
return retry;
|
|
2683
|
+
}
|
|
2684
|
+
_consecutiveFailures++;
|
|
2685
|
+
}
|
|
2686
|
+
if (isDaemonTooYoung()) {
|
|
2687
|
+
process.stderr.write(`[exed-client] ${label}: daemon too young (< ${MIN_DAEMON_AGE_MS / 1e3}s) \u2014 skipping restart
|
|
2688
|
+
`);
|
|
2689
|
+
return { error: result.error };
|
|
2690
|
+
}
|
|
2691
|
+
process.stderr.write(`[exed-client] ${label}: ${_consecutiveFailures} consecutive failures \u2014 restarting daemon
|
|
2692
|
+
`);
|
|
2693
|
+
killAndRespawnDaemon();
|
|
2694
|
+
const start = Date.now();
|
|
2695
|
+
let delay2 = 200;
|
|
2696
|
+
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
2697
|
+
await new Promise((r) => setTimeout(r, delay2));
|
|
2698
|
+
if (await connectToSocket()) break;
|
|
2699
|
+
delay2 = Math.min(delay2 * 2, 3e3);
|
|
2700
|
+
}
|
|
2701
|
+
if (!_connected) return { error: "Daemon restart failed" };
|
|
2702
|
+
const final = await doRequest();
|
|
2703
|
+
if (!final.error) _consecutiveFailures = 0;
|
|
2704
|
+
return final;
|
|
1896
2705
|
}
|
|
1897
2706
|
async function embedViaClient(text, priority = "high") {
|
|
1898
2707
|
if (!_connected && !await connectEmbedDaemon()) return null;
|
|
1899
2708
|
_requestCount++;
|
|
1900
2709
|
if (_requestCount % HEALTH_CHECK_INTERVAL === 0) {
|
|
1901
2710
|
const health = await pingDaemon();
|
|
1902
|
-
if (!health) {
|
|
2711
|
+
if (!health && !isDaemonTooYoung()) {
|
|
1903
2712
|
process.stderr.write(`[exed-client] Periodic health check failed at request ${_requestCount} \u2014 restarting daemon
|
|
1904
2713
|
`);
|
|
1905
2714
|
killAndRespawnDaemon();
|
|
1906
2715
|
const start = Date.now();
|
|
1907
|
-
let
|
|
2716
|
+
let d = 200;
|
|
1908
2717
|
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
1909
|
-
await new Promise((r) => setTimeout(r,
|
|
2718
|
+
await new Promise((r) => setTimeout(r, d));
|
|
1910
2719
|
if (await connectToSocket()) break;
|
|
1911
|
-
|
|
2720
|
+
d = Math.min(d * 2, 3e3);
|
|
1912
2721
|
}
|
|
1913
2722
|
if (!_connected) return null;
|
|
1914
2723
|
}
|
|
1915
2724
|
}
|
|
1916
|
-
const result = await
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
killAndRespawnDaemon();
|
|
1922
|
-
const start = Date.now();
|
|
1923
|
-
let delay2 = 200;
|
|
1924
|
-
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
1925
|
-
await new Promise((r) => setTimeout(r, delay2));
|
|
1926
|
-
if (await connectToSocket()) break;
|
|
1927
|
-
delay2 = Math.min(delay2 * 2, 3e3);
|
|
1928
|
-
}
|
|
1929
|
-
if (!_connected) return null;
|
|
1930
|
-
const retry = await sendRequest([text], priority);
|
|
1931
|
-
if (!retry.error && retry.vectors?.[0]) return retry.vectors[0];
|
|
1932
|
-
process.stderr.write(`[exed-client] Embed retry also failed: ${retry.error ?? "no vector"}
|
|
1933
|
-
`);
|
|
1934
|
-
}
|
|
1935
|
-
return null;
|
|
2725
|
+
const result = await retryThenRestart(
|
|
2726
|
+
() => sendRequest([text], priority),
|
|
2727
|
+
"Embed"
|
|
2728
|
+
);
|
|
2729
|
+
return !result.error && result.vectors?.[0] ? result.vectors[0] : null;
|
|
1936
2730
|
}
|
|
1937
2731
|
function disconnectClient() {
|
|
1938
2732
|
if (_socket) {
|
|
@@ -1950,14 +2744,14 @@ function disconnectClient() {
|
|
|
1950
2744
|
function isClientConnected() {
|
|
1951
2745
|
return _connected;
|
|
1952
2746
|
}
|
|
1953
|
-
var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, _socket, _connected, _buffer, _requestCount, HEALTH_CHECK_INTERVAL, _pending, MAX_BUFFER;
|
|
2747
|
+
var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, _socket, _connected, _buffer, _requestCount, _consecutiveFailures, HEALTH_CHECK_INTERVAL, MAX_RETRIES_BEFORE_RESTART, RETRY_DELAYS_MS, MIN_DAEMON_AGE_MS, _pending, MAX_BUFFER;
|
|
1954
2748
|
var init_exe_daemon_client = __esm({
|
|
1955
2749
|
"src/lib/exe-daemon-client.ts"() {
|
|
1956
2750
|
"use strict";
|
|
1957
2751
|
init_config();
|
|
1958
|
-
SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ??
|
|
1959
|
-
PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ??
|
|
1960
|
-
SPAWN_LOCK_PATH =
|
|
2752
|
+
SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path9.join(EXE_AI_DIR, "exed.sock");
|
|
2753
|
+
PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path9.join(EXE_AI_DIR, "exed.pid");
|
|
2754
|
+
SPAWN_LOCK_PATH = path9.join(EXE_AI_DIR, "exed-spawn.lock");
|
|
1961
2755
|
SPAWN_LOCK_STALE_MS = 3e4;
|
|
1962
2756
|
CONNECT_TIMEOUT_MS = 15e3;
|
|
1963
2757
|
REQUEST_TIMEOUT_MS = 3e4;
|
|
@@ -1965,7 +2759,11 @@ var init_exe_daemon_client = __esm({
|
|
|
1965
2759
|
_connected = false;
|
|
1966
2760
|
_buffer = "";
|
|
1967
2761
|
_requestCount = 0;
|
|
2762
|
+
_consecutiveFailures = 0;
|
|
1968
2763
|
HEALTH_CHECK_INTERVAL = 100;
|
|
2764
|
+
MAX_RETRIES_BEFORE_RESTART = 3;
|
|
2765
|
+
RETRY_DELAYS_MS = [1e3, 3e3, 5e3];
|
|
2766
|
+
MIN_DAEMON_AGE_MS = 3e4;
|
|
1969
2767
|
_pending = /* @__PURE__ */ new Map();
|
|
1970
2768
|
MAX_BUFFER = 1e7;
|
|
1971
2769
|
}
|
|
@@ -2041,7 +2839,7 @@ __export(db_daemon_client_exports, {
|
|
|
2041
2839
|
createDaemonDbClient: () => createDaemonDbClient,
|
|
2042
2840
|
initDaemonDbClient: () => initDaemonDbClient
|
|
2043
2841
|
});
|
|
2044
|
-
function
|
|
2842
|
+
function normalizeStatement2(stmt) {
|
|
2045
2843
|
if (typeof stmt === "string") {
|
|
2046
2844
|
return { sql: stmt, args: [] };
|
|
2047
2845
|
}
|
|
@@ -2065,7 +2863,7 @@ function createDaemonDbClient(fallbackClient) {
|
|
|
2065
2863
|
if (!_useDaemon || !isClientConnected()) {
|
|
2066
2864
|
return fallbackClient.execute(stmt);
|
|
2067
2865
|
}
|
|
2068
|
-
const { sql, args: args2 } =
|
|
2866
|
+
const { sql, args: args2 } = normalizeStatement2(stmt);
|
|
2069
2867
|
const response = await sendDaemonRequest({
|
|
2070
2868
|
type: "db-execute",
|
|
2071
2869
|
sql,
|
|
@@ -2090,7 +2888,7 @@ function createDaemonDbClient(fallbackClient) {
|
|
|
2090
2888
|
if (!_useDaemon || !isClientConnected()) {
|
|
2091
2889
|
return fallbackClient.batch(stmts, mode);
|
|
2092
2890
|
}
|
|
2093
|
-
const statements = stmts.map(
|
|
2891
|
+
const statements = stmts.map(normalizeStatement2);
|
|
2094
2892
|
const response = await sendDaemonRequest({
|
|
2095
2893
|
type: "db-batch",
|
|
2096
2894
|
statements,
|
|
@@ -2185,6 +2983,18 @@ __export(database_exports, {
|
|
|
2185
2983
|
});
|
|
2186
2984
|
import { createClient } from "@libsql/client";
|
|
2187
2985
|
async function initDatabase(config) {
|
|
2986
|
+
if (_walCheckpointTimer) {
|
|
2987
|
+
clearInterval(_walCheckpointTimer);
|
|
2988
|
+
_walCheckpointTimer = null;
|
|
2989
|
+
}
|
|
2990
|
+
if (_daemonClient) {
|
|
2991
|
+
_daemonClient.close();
|
|
2992
|
+
_daemonClient = null;
|
|
2993
|
+
}
|
|
2994
|
+
if (_adapterClient && _adapterClient !== _resilientClient) {
|
|
2995
|
+
_adapterClient.close();
|
|
2996
|
+
}
|
|
2997
|
+
_adapterClient = null;
|
|
2188
2998
|
if (_client) {
|
|
2189
2999
|
_client.close();
|
|
2190
3000
|
_client = null;
|
|
@@ -2198,6 +3008,7 @@ async function initDatabase(config) {
|
|
|
2198
3008
|
}
|
|
2199
3009
|
_client = createClient(opts);
|
|
2200
3010
|
_resilientClient = wrapWithRetry(_client);
|
|
3011
|
+
_adapterClient = _resilientClient;
|
|
2201
3012
|
_client.execute("PRAGMA busy_timeout = 30000").catch(() => {
|
|
2202
3013
|
});
|
|
2203
3014
|
_client.execute("PRAGMA journal_mode = WAL").catch(() => {
|
|
@@ -2208,14 +3019,20 @@ async function initDatabase(config) {
|
|
|
2208
3019
|
});
|
|
2209
3020
|
}, 3e4);
|
|
2210
3021
|
_walCheckpointTimer.unref();
|
|
3022
|
+
if (process.env.DATABASE_URL) {
|
|
3023
|
+
_adapterClient = await createPrismaDbAdapter(_resilientClient);
|
|
3024
|
+
}
|
|
2211
3025
|
}
|
|
2212
3026
|
function isInitialized() {
|
|
2213
|
-
return _client !== null;
|
|
3027
|
+
return _adapterClient !== null || _client !== null;
|
|
2214
3028
|
}
|
|
2215
3029
|
function getClient() {
|
|
2216
|
-
if (!
|
|
3030
|
+
if (!_adapterClient) {
|
|
2217
3031
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
2218
3032
|
}
|
|
3033
|
+
if (process.env.DATABASE_URL) {
|
|
3034
|
+
return _adapterClient;
|
|
3035
|
+
}
|
|
2219
3036
|
if (process.env.EXE_IS_DAEMON === "1") {
|
|
2220
3037
|
return _resilientClient;
|
|
2221
3038
|
}
|
|
@@ -2225,6 +3042,7 @@ function getClient() {
|
|
|
2225
3042
|
return _resilientClient;
|
|
2226
3043
|
}
|
|
2227
3044
|
async function initDaemonClient() {
|
|
3045
|
+
if (process.env.DATABASE_URL) return;
|
|
2228
3046
|
if (process.env.EXE_IS_DAEMON === "1") return;
|
|
2229
3047
|
if (!_resilientClient) return;
|
|
2230
3048
|
try {
|
|
@@ -3169,26 +3987,36 @@ async function ensureSchema() {
|
|
|
3169
3987
|
}
|
|
3170
3988
|
}
|
|
3171
3989
|
async function disposeDatabase() {
|
|
3990
|
+
if (_walCheckpointTimer) {
|
|
3991
|
+
clearInterval(_walCheckpointTimer);
|
|
3992
|
+
_walCheckpointTimer = null;
|
|
3993
|
+
}
|
|
3172
3994
|
if (_daemonClient) {
|
|
3173
3995
|
_daemonClient.close();
|
|
3174
3996
|
_daemonClient = null;
|
|
3175
3997
|
}
|
|
3998
|
+
if (_adapterClient && _adapterClient !== _resilientClient) {
|
|
3999
|
+
_adapterClient.close();
|
|
4000
|
+
}
|
|
4001
|
+
_adapterClient = null;
|
|
3176
4002
|
if (_client) {
|
|
3177
4003
|
_client.close();
|
|
3178
4004
|
_client = null;
|
|
3179
4005
|
_resilientClient = null;
|
|
3180
4006
|
}
|
|
3181
4007
|
}
|
|
3182
|
-
var _client, _resilientClient, _walCheckpointTimer, _daemonClient, initTurso, disposeTurso;
|
|
4008
|
+
var _client, _resilientClient, _walCheckpointTimer, _daemonClient, _adapterClient, initTurso, disposeTurso;
|
|
3183
4009
|
var init_database = __esm({
|
|
3184
4010
|
"src/lib/database.ts"() {
|
|
3185
4011
|
"use strict";
|
|
3186
4012
|
init_db_retry();
|
|
3187
4013
|
init_employees();
|
|
4014
|
+
init_database_adapter();
|
|
3188
4015
|
_client = null;
|
|
3189
4016
|
_resilientClient = null;
|
|
3190
4017
|
_walCheckpointTimer = null;
|
|
3191
4018
|
_daemonClient = null;
|
|
4019
|
+
_adapterClient = null;
|
|
3192
4020
|
initTurso = initDatabase;
|
|
3193
4021
|
disposeTurso = disposeDatabase;
|
|
3194
4022
|
}
|
|
@@ -3290,9 +4118,9 @@ __export(license_exports, {
|
|
|
3290
4118
|
stopLicenseRevalidation: () => stopLicenseRevalidation,
|
|
3291
4119
|
validateLicense: () => validateLicense
|
|
3292
4120
|
});
|
|
3293
|
-
import { readFileSync as
|
|
4121
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, existsSync as existsSync9, mkdirSync as mkdirSync5 } from "fs";
|
|
3294
4122
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
3295
|
-
import
|
|
4123
|
+
import path10 from "path";
|
|
3296
4124
|
import { jwtVerify, importSPKI } from "jose";
|
|
3297
4125
|
async function fetchRetry(url, init) {
|
|
3298
4126
|
try {
|
|
@@ -3303,37 +4131,37 @@ async function fetchRetry(url, init) {
|
|
|
3303
4131
|
}
|
|
3304
4132
|
}
|
|
3305
4133
|
function loadDeviceId() {
|
|
3306
|
-
const deviceJsonPath =
|
|
4134
|
+
const deviceJsonPath = path10.join(EXE_AI_DIR, "device.json");
|
|
3307
4135
|
try {
|
|
3308
|
-
if (
|
|
3309
|
-
const data = JSON.parse(
|
|
4136
|
+
if (existsSync9(deviceJsonPath)) {
|
|
4137
|
+
const data = JSON.parse(readFileSync7(deviceJsonPath, "utf8"));
|
|
3310
4138
|
if (data.deviceId) return data.deviceId;
|
|
3311
4139
|
}
|
|
3312
4140
|
} catch {
|
|
3313
4141
|
}
|
|
3314
4142
|
try {
|
|
3315
|
-
if (
|
|
3316
|
-
const id2 =
|
|
4143
|
+
if (existsSync9(DEVICE_ID_PATH)) {
|
|
4144
|
+
const id2 = readFileSync7(DEVICE_ID_PATH, "utf8").trim();
|
|
3317
4145
|
if (id2) return id2;
|
|
3318
4146
|
}
|
|
3319
4147
|
} catch {
|
|
3320
4148
|
}
|
|
3321
4149
|
const id = randomUUID2();
|
|
3322
|
-
|
|
3323
|
-
|
|
4150
|
+
mkdirSync5(EXE_AI_DIR, { recursive: true });
|
|
4151
|
+
writeFileSync5(DEVICE_ID_PATH, id, "utf8");
|
|
3324
4152
|
return id;
|
|
3325
4153
|
}
|
|
3326
4154
|
function loadLicense() {
|
|
3327
4155
|
try {
|
|
3328
|
-
if (!
|
|
3329
|
-
return
|
|
4156
|
+
if (!existsSync9(LICENSE_PATH)) return null;
|
|
4157
|
+
return readFileSync7(LICENSE_PATH, "utf8").trim();
|
|
3330
4158
|
} catch {
|
|
3331
4159
|
return null;
|
|
3332
4160
|
}
|
|
3333
4161
|
}
|
|
3334
4162
|
function saveLicense(apiKey) {
|
|
3335
|
-
|
|
3336
|
-
|
|
4163
|
+
mkdirSync5(EXE_AI_DIR, { recursive: true });
|
|
4164
|
+
writeFileSync5(LICENSE_PATH, apiKey.trim(), { encoding: "utf8", mode: 384 });
|
|
3337
4165
|
}
|
|
3338
4166
|
async function verifyLicenseJwt(token) {
|
|
3339
4167
|
try {
|
|
@@ -3359,8 +4187,8 @@ async function verifyLicenseJwt(token) {
|
|
|
3359
4187
|
}
|
|
3360
4188
|
async function getCachedLicense() {
|
|
3361
4189
|
try {
|
|
3362
|
-
if (!
|
|
3363
|
-
const raw = JSON.parse(
|
|
4190
|
+
if (!existsSync9(CACHE_PATH)) return null;
|
|
4191
|
+
const raw = JSON.parse(readFileSync7(CACHE_PATH, "utf8"));
|
|
3364
4192
|
if (!raw.token || typeof raw.token !== "string") return null;
|
|
3365
4193
|
return await verifyLicenseJwt(raw.token);
|
|
3366
4194
|
} catch {
|
|
@@ -3369,8 +4197,8 @@ async function getCachedLicense() {
|
|
|
3369
4197
|
}
|
|
3370
4198
|
function readCachedToken() {
|
|
3371
4199
|
try {
|
|
3372
|
-
if (!
|
|
3373
|
-
const raw = JSON.parse(
|
|
4200
|
+
if (!existsSync9(CACHE_PATH)) return null;
|
|
4201
|
+
const raw = JSON.parse(readFileSync7(CACHE_PATH, "utf8"));
|
|
3374
4202
|
return typeof raw.token === "string" ? raw.token : null;
|
|
3375
4203
|
} catch {
|
|
3376
4204
|
return null;
|
|
@@ -3404,7 +4232,7 @@ function getRawCachedPlan() {
|
|
|
3404
4232
|
}
|
|
3405
4233
|
function cacheResponse(token) {
|
|
3406
4234
|
try {
|
|
3407
|
-
|
|
4235
|
+
writeFileSync5(CACHE_PATH, JSON.stringify({ token }), "utf8");
|
|
3408
4236
|
} catch {
|
|
3409
4237
|
}
|
|
3410
4238
|
}
|
|
@@ -3468,9 +4296,9 @@ async function checkLicense() {
|
|
|
3468
4296
|
let key = loadLicense();
|
|
3469
4297
|
if (!key) {
|
|
3470
4298
|
try {
|
|
3471
|
-
const configPath =
|
|
3472
|
-
if (
|
|
3473
|
-
const raw = JSON.parse(
|
|
4299
|
+
const configPath = path10.join(EXE_AI_DIR, "config.json");
|
|
4300
|
+
if (existsSync9(configPath)) {
|
|
4301
|
+
const raw = JSON.parse(readFileSync7(configPath, "utf8"));
|
|
3474
4302
|
const cloud = raw.cloud;
|
|
3475
4303
|
if (cloud?.apiKey) {
|
|
3476
4304
|
key = cloud.apiKey;
|
|
@@ -3629,9 +4457,9 @@ var init_license = __esm({
|
|
|
3629
4457
|
"src/lib/license.ts"() {
|
|
3630
4458
|
"use strict";
|
|
3631
4459
|
init_config();
|
|
3632
|
-
LICENSE_PATH =
|
|
3633
|
-
CACHE_PATH =
|
|
3634
|
-
DEVICE_ID_PATH =
|
|
4460
|
+
LICENSE_PATH = path10.join(EXE_AI_DIR, "license.key");
|
|
4461
|
+
CACHE_PATH = path10.join(EXE_AI_DIR, "license-cache.json");
|
|
4462
|
+
DEVICE_ID_PATH = path10.join(EXE_AI_DIR, "device-id");
|
|
3635
4463
|
API_BASE = "https://askexe.com/cloud";
|
|
3636
4464
|
RETRY_DELAY_MS = 500;
|
|
3637
4465
|
LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
|
|
@@ -3679,8 +4507,8 @@ __export(crdt_sync_exports, {
|
|
|
3679
4507
|
rebuildFromDb: () => rebuildFromDb
|
|
3680
4508
|
});
|
|
3681
4509
|
import * as Y from "yjs";
|
|
3682
|
-
import { readFileSync as
|
|
3683
|
-
import
|
|
4510
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, existsSync as existsSync10, mkdirSync as mkdirSync6, unlinkSync as unlinkSync3 } from "fs";
|
|
4511
|
+
import path11 from "path";
|
|
3684
4512
|
import { homedir } from "os";
|
|
3685
4513
|
function getStatePath() {
|
|
3686
4514
|
return _statePathOverride ?? DEFAULT_STATE_PATH;
|
|
@@ -3692,9 +4520,9 @@ function initCrdtDoc() {
|
|
|
3692
4520
|
if (doc) return doc;
|
|
3693
4521
|
doc = new Y.Doc();
|
|
3694
4522
|
const sp = getStatePath();
|
|
3695
|
-
if (
|
|
4523
|
+
if (existsSync10(sp)) {
|
|
3696
4524
|
try {
|
|
3697
|
-
const state =
|
|
4525
|
+
const state = readFileSync8(sp);
|
|
3698
4526
|
Y.applyUpdate(doc, new Uint8Array(state));
|
|
3699
4527
|
} catch {
|
|
3700
4528
|
console.warn("[crdt-sync] WARN: corrupted state file, rebuilding from DB");
|
|
@@ -3836,10 +4664,10 @@ function persistState() {
|
|
|
3836
4664
|
if (!doc) return;
|
|
3837
4665
|
try {
|
|
3838
4666
|
const sp = getStatePath();
|
|
3839
|
-
const dir =
|
|
3840
|
-
if (!
|
|
4667
|
+
const dir = path11.dirname(sp);
|
|
4668
|
+
if (!existsSync10(dir)) mkdirSync6(dir, { recursive: true });
|
|
3841
4669
|
const state = Y.encodeStateAsUpdate(doc);
|
|
3842
|
-
|
|
4670
|
+
writeFileSync6(sp, Buffer.from(state));
|
|
3843
4671
|
} catch {
|
|
3844
4672
|
}
|
|
3845
4673
|
}
|
|
@@ -3880,7 +4708,7 @@ var DEFAULT_STATE_PATH, _statePathOverride, doc;
|
|
|
3880
4708
|
var init_crdt_sync = __esm({
|
|
3881
4709
|
"src/lib/crdt-sync.ts"() {
|
|
3882
4710
|
"use strict";
|
|
3883
|
-
DEFAULT_STATE_PATH =
|
|
4711
|
+
DEFAULT_STATE_PATH = path11.join(homedir(), ".exe-os", "crdt-state.bin");
|
|
3884
4712
|
_statePathOverride = null;
|
|
3885
4713
|
doc = null;
|
|
3886
4714
|
}
|
|
@@ -3914,16 +4742,16 @@ __export(cloud_sync_exports, {
|
|
|
3914
4742
|
mergeRosterFromRemote: () => mergeRosterFromRemote,
|
|
3915
4743
|
recordRosterDeletion: () => recordRosterDeletion
|
|
3916
4744
|
});
|
|
3917
|
-
import { readFileSync as
|
|
4745
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync7, existsSync as existsSync11, readdirSync, mkdirSync as mkdirSync7, appendFileSync, unlinkSync as unlinkSync4, openSync as openSync2, closeSync as closeSync2 } from "fs";
|
|
3918
4746
|
import crypto3 from "crypto";
|
|
3919
|
-
import
|
|
4747
|
+
import path12 from "path";
|
|
3920
4748
|
import { homedir as homedir2 } from "os";
|
|
3921
4749
|
function sqlSafe(v) {
|
|
3922
4750
|
return v === void 0 ? null : v;
|
|
3923
4751
|
}
|
|
3924
4752
|
function logError(msg) {
|
|
3925
4753
|
try {
|
|
3926
|
-
const logPath =
|
|
4754
|
+
const logPath = path12.join(homedir2(), ".exe-os", "workers.log");
|
|
3927
4755
|
appendFileSync(logPath, `${(/* @__PURE__ */ new Date()).toISOString()} ${msg}
|
|
3928
4756
|
`);
|
|
3929
4757
|
} catch {
|
|
@@ -3933,18 +4761,18 @@ async function withRosterLock(fn) {
|
|
|
3933
4761
|
try {
|
|
3934
4762
|
const fd = openSync2(ROSTER_LOCK_PATH, "wx");
|
|
3935
4763
|
closeSync2(fd);
|
|
3936
|
-
|
|
4764
|
+
writeFileSync7(ROSTER_LOCK_PATH, String(Date.now()));
|
|
3937
4765
|
} catch (err) {
|
|
3938
4766
|
if (err.code === "EEXIST") {
|
|
3939
4767
|
try {
|
|
3940
|
-
const ts = parseInt(
|
|
4768
|
+
const ts = parseInt(readFileSync9(ROSTER_LOCK_PATH, "utf-8"), 10);
|
|
3941
4769
|
if (Date.now() - ts < LOCK_STALE_MS) {
|
|
3942
4770
|
throw new Error("Roster merge already in progress \u2014 another sync is running");
|
|
3943
4771
|
}
|
|
3944
4772
|
unlinkSync4(ROSTER_LOCK_PATH);
|
|
3945
4773
|
const fd = openSync2(ROSTER_LOCK_PATH, "wx");
|
|
3946
4774
|
closeSync2(fd);
|
|
3947
|
-
|
|
4775
|
+
writeFileSync7(ROSTER_LOCK_PATH, String(Date.now()));
|
|
3948
4776
|
} catch (retryErr) {
|
|
3949
4777
|
if (retryErr instanceof Error && retryErr.message.includes("already in progress")) throw retryErr;
|
|
3950
4778
|
throw new Error("Roster merge already in progress \u2014 another sync is running");
|
|
@@ -4318,8 +5146,8 @@ async function cloudSync(config) {
|
|
|
4318
5146
|
try {
|
|
4319
5147
|
const employees = await loadEmployees();
|
|
4320
5148
|
rosterResult.employees = employees.length;
|
|
4321
|
-
const idDir =
|
|
4322
|
-
if (
|
|
5149
|
+
const idDir = path12.join(EXE_AI_DIR, "identity");
|
|
5150
|
+
if (existsSync11(idDir)) {
|
|
4323
5151
|
rosterResult.identities = readdirSync(idDir).filter((f) => f.endsWith(".md")).length;
|
|
4324
5152
|
}
|
|
4325
5153
|
} catch {
|
|
@@ -4340,56 +5168,56 @@ async function cloudSync(config) {
|
|
|
4340
5168
|
function recordRosterDeletion(name) {
|
|
4341
5169
|
let deletions = [];
|
|
4342
5170
|
try {
|
|
4343
|
-
if (
|
|
4344
|
-
deletions = JSON.parse(
|
|
5171
|
+
if (existsSync11(ROSTER_DELETIONS_PATH)) {
|
|
5172
|
+
deletions = JSON.parse(readFileSync9(ROSTER_DELETIONS_PATH, "utf-8"));
|
|
4345
5173
|
}
|
|
4346
5174
|
} catch {
|
|
4347
5175
|
}
|
|
4348
5176
|
if (!deletions.includes(name)) deletions.push(name);
|
|
4349
|
-
|
|
5177
|
+
writeFileSync7(ROSTER_DELETIONS_PATH, JSON.stringify(deletions));
|
|
4350
5178
|
}
|
|
4351
5179
|
function consumeRosterDeletions() {
|
|
4352
5180
|
try {
|
|
4353
|
-
if (!
|
|
4354
|
-
const deletions = JSON.parse(
|
|
4355
|
-
|
|
5181
|
+
if (!existsSync11(ROSTER_DELETIONS_PATH)) return [];
|
|
5182
|
+
const deletions = JSON.parse(readFileSync9(ROSTER_DELETIONS_PATH, "utf-8"));
|
|
5183
|
+
writeFileSync7(ROSTER_DELETIONS_PATH, "[]");
|
|
4356
5184
|
return deletions;
|
|
4357
5185
|
} catch {
|
|
4358
5186
|
return [];
|
|
4359
5187
|
}
|
|
4360
5188
|
}
|
|
4361
5189
|
function buildRosterBlob(paths) {
|
|
4362
|
-
const rosterPath = paths?.rosterPath ??
|
|
4363
|
-
const identityDir = paths?.identityDir ??
|
|
4364
|
-
const configPath = paths?.configPath ??
|
|
5190
|
+
const rosterPath = paths?.rosterPath ?? path12.join(EXE_AI_DIR, "exe-employees.json");
|
|
5191
|
+
const identityDir = paths?.identityDir ?? path12.join(EXE_AI_DIR, "identity");
|
|
5192
|
+
const configPath = paths?.configPath ?? path12.join(EXE_AI_DIR, "config.json");
|
|
4365
5193
|
let roster = [];
|
|
4366
|
-
if (
|
|
5194
|
+
if (existsSync11(rosterPath)) {
|
|
4367
5195
|
try {
|
|
4368
|
-
roster = JSON.parse(
|
|
5196
|
+
roster = JSON.parse(readFileSync9(rosterPath, "utf-8"));
|
|
4369
5197
|
} catch {
|
|
4370
5198
|
}
|
|
4371
5199
|
}
|
|
4372
5200
|
const identities = {};
|
|
4373
|
-
if (
|
|
5201
|
+
if (existsSync11(identityDir)) {
|
|
4374
5202
|
for (const file of readdirSync(identityDir).filter((f) => f.endsWith(".md"))) {
|
|
4375
5203
|
try {
|
|
4376
|
-
identities[file] =
|
|
5204
|
+
identities[file] = readFileSync9(path12.join(identityDir, file), "utf-8");
|
|
4377
5205
|
} catch {
|
|
4378
5206
|
}
|
|
4379
5207
|
}
|
|
4380
5208
|
}
|
|
4381
5209
|
let config;
|
|
4382
|
-
if (
|
|
5210
|
+
if (existsSync11(configPath)) {
|
|
4383
5211
|
try {
|
|
4384
|
-
config = JSON.parse(
|
|
5212
|
+
config = JSON.parse(readFileSync9(configPath, "utf-8"));
|
|
4385
5213
|
} catch {
|
|
4386
5214
|
}
|
|
4387
5215
|
}
|
|
4388
5216
|
let agentConfig;
|
|
4389
|
-
const agentConfigPath =
|
|
4390
|
-
if (
|
|
5217
|
+
const agentConfigPath = path12.join(EXE_AI_DIR, "agent-config.json");
|
|
5218
|
+
if (existsSync11(agentConfigPath)) {
|
|
4391
5219
|
try {
|
|
4392
|
-
agentConfig = JSON.parse(
|
|
5220
|
+
agentConfig = JSON.parse(readFileSync9(agentConfigPath, "utf-8"));
|
|
4393
5221
|
} catch {
|
|
4394
5222
|
}
|
|
4395
5223
|
}
|
|
@@ -4465,23 +5293,23 @@ async function cloudPullRoster(config) {
|
|
|
4465
5293
|
}
|
|
4466
5294
|
}
|
|
4467
5295
|
function mergeConfig(remoteConfig, configPath) {
|
|
4468
|
-
const cfgPath = configPath ??
|
|
5296
|
+
const cfgPath = configPath ?? path12.join(EXE_AI_DIR, "config.json");
|
|
4469
5297
|
let local = {};
|
|
4470
|
-
if (
|
|
5298
|
+
if (existsSync11(cfgPath)) {
|
|
4471
5299
|
try {
|
|
4472
|
-
local = JSON.parse(
|
|
5300
|
+
local = JSON.parse(readFileSync9(cfgPath, "utf-8"));
|
|
4473
5301
|
} catch {
|
|
4474
5302
|
}
|
|
4475
5303
|
}
|
|
4476
5304
|
const merged = { ...remoteConfig, ...local };
|
|
4477
|
-
const dir =
|
|
4478
|
-
if (!
|
|
4479
|
-
|
|
5305
|
+
const dir = path12.dirname(cfgPath);
|
|
5306
|
+
if (!existsSync11(dir)) mkdirSync7(dir, { recursive: true });
|
|
5307
|
+
writeFileSync7(cfgPath, JSON.stringify(merged, null, 2), "utf-8");
|
|
4480
5308
|
}
|
|
4481
5309
|
async function mergeRosterFromRemote(remote, paths) {
|
|
4482
5310
|
return withRosterLock(async () => {
|
|
4483
5311
|
const rosterPath = paths?.rosterPath ?? void 0;
|
|
4484
|
-
const identityDir = paths?.identityDir ??
|
|
5312
|
+
const identityDir = paths?.identityDir ?? path12.join(EXE_AI_DIR, "identity");
|
|
4485
5313
|
const localEmployees = await loadEmployees(rosterPath);
|
|
4486
5314
|
const localNames = new Set(localEmployees.map((e) => e.name));
|
|
4487
5315
|
let added = 0;
|
|
@@ -4502,15 +5330,15 @@ async function mergeRosterFromRemote(remote, paths) {
|
|
|
4502
5330
|
) ?? lookupKey;
|
|
4503
5331
|
const remoteIdentity = remote.identities[matchedKey];
|
|
4504
5332
|
if (remoteIdentity) {
|
|
4505
|
-
if (!
|
|
4506
|
-
const idPath =
|
|
5333
|
+
if (!existsSync11(identityDir)) mkdirSync7(identityDir, { recursive: true });
|
|
5334
|
+
const idPath = path12.join(identityDir, `${remoteEmp.name}.md`);
|
|
4507
5335
|
let localIdentity = null;
|
|
4508
5336
|
try {
|
|
4509
|
-
localIdentity =
|
|
5337
|
+
localIdentity = existsSync11(idPath) ? readFileSync9(idPath, "utf-8") : null;
|
|
4510
5338
|
} catch {
|
|
4511
5339
|
}
|
|
4512
5340
|
if (localIdentity !== remoteIdentity) {
|
|
4513
|
-
|
|
5341
|
+
writeFileSync7(idPath, remoteIdentity, "utf-8");
|
|
4514
5342
|
identitiesUpdated++;
|
|
4515
5343
|
}
|
|
4516
5344
|
}
|
|
@@ -4536,16 +5364,16 @@ async function mergeRosterFromRemote(remote, paths) {
|
|
|
4536
5364
|
}
|
|
4537
5365
|
if (remote.agentConfig && Object.keys(remote.agentConfig).length > 0) {
|
|
4538
5366
|
try {
|
|
4539
|
-
const agentConfigPath =
|
|
5367
|
+
const agentConfigPath = path12.join(EXE_AI_DIR, "agent-config.json");
|
|
4540
5368
|
let local = {};
|
|
4541
|
-
if (
|
|
5369
|
+
if (existsSync11(agentConfigPath)) {
|
|
4542
5370
|
try {
|
|
4543
|
-
local = JSON.parse(
|
|
5371
|
+
local = JSON.parse(readFileSync9(agentConfigPath, "utf-8"));
|
|
4544
5372
|
} catch {
|
|
4545
5373
|
}
|
|
4546
5374
|
}
|
|
4547
5375
|
const merged = { ...remote.agentConfig, ...local };
|
|
4548
|
-
|
|
5376
|
+
writeFileSync7(agentConfigPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
|
|
4549
5377
|
} catch {
|
|
4550
5378
|
}
|
|
4551
5379
|
}
|
|
@@ -4983,9 +5811,9 @@ var init_cloud_sync = __esm({
|
|
|
4983
5811
|
LOCALHOST_PATTERNS = /^(localhost|127\.0\.0\.1|\[::1\])$/i;
|
|
4984
5812
|
FETCH_TIMEOUT_MS = 3e4;
|
|
4985
5813
|
PUSH_BATCH_SIZE = 5e3;
|
|
4986
|
-
ROSTER_LOCK_PATH =
|
|
5814
|
+
ROSTER_LOCK_PATH = path12.join(EXE_AI_DIR, "roster-merge.lock");
|
|
4987
5815
|
LOCK_STALE_MS = 3e4;
|
|
4988
|
-
ROSTER_DELETIONS_PATH =
|
|
5816
|
+
ROSTER_DELETIONS_PATH = path12.join(EXE_AI_DIR, "roster-deletions.json");
|
|
4989
5817
|
}
|
|
4990
5818
|
});
|
|
4991
5819
|
|
|
@@ -5291,13 +6119,13 @@ __export(shard_manager_exports, {
|
|
|
5291
6119
|
listShards: () => listShards,
|
|
5292
6120
|
shardExists: () => shardExists
|
|
5293
6121
|
});
|
|
5294
|
-
import
|
|
5295
|
-
import { existsSync as
|
|
6122
|
+
import path13 from "path";
|
|
6123
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync8, readdirSync as readdirSync2 } from "fs";
|
|
5296
6124
|
import { createClient as createClient2 } from "@libsql/client";
|
|
5297
6125
|
function initShardManager(encryptionKey) {
|
|
5298
6126
|
_encryptionKey = encryptionKey;
|
|
5299
|
-
if (!
|
|
5300
|
-
|
|
6127
|
+
if (!existsSync12(SHARDS_DIR)) {
|
|
6128
|
+
mkdirSync8(SHARDS_DIR, { recursive: true });
|
|
5301
6129
|
}
|
|
5302
6130
|
_shardingEnabled = true;
|
|
5303
6131
|
}
|
|
@@ -5317,7 +6145,7 @@ function getShardClient(projectName) {
|
|
|
5317
6145
|
}
|
|
5318
6146
|
const cached = _shards.get(safeName);
|
|
5319
6147
|
if (cached) return cached;
|
|
5320
|
-
const dbPath =
|
|
6148
|
+
const dbPath = path13.join(SHARDS_DIR, `${safeName}.db`);
|
|
5321
6149
|
const client = createClient2({
|
|
5322
6150
|
url: `file:${dbPath}`,
|
|
5323
6151
|
encryptionKey: _encryptionKey
|
|
@@ -5327,10 +6155,10 @@ function getShardClient(projectName) {
|
|
|
5327
6155
|
}
|
|
5328
6156
|
function shardExists(projectName) {
|
|
5329
6157
|
const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
5330
|
-
return
|
|
6158
|
+
return existsSync12(path13.join(SHARDS_DIR, `${safeName}.db`));
|
|
5331
6159
|
}
|
|
5332
6160
|
function listShards() {
|
|
5333
|
-
if (!
|
|
6161
|
+
if (!existsSync12(SHARDS_DIR)) return [];
|
|
5334
6162
|
return readdirSync2(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
5335
6163
|
}
|
|
5336
6164
|
async function ensureShardSchema(client) {
|
|
@@ -5404,7 +6232,23 @@ async function ensureShardSchema(client) {
|
|
|
5404
6232
|
// MS-11: draft staging, MS-6a: memory_type, MS-7: trajectory
|
|
5405
6233
|
"ALTER TABLE memories ADD COLUMN draft INTEGER DEFAULT 0",
|
|
5406
6234
|
"ALTER TABLE memories ADD COLUMN memory_type TEXT DEFAULT 'raw'",
|
|
5407
|
-
"ALTER TABLE memories ADD COLUMN trajectory TEXT"
|
|
6235
|
+
"ALTER TABLE memories ADD COLUMN trajectory TEXT",
|
|
6236
|
+
// Metadata enrichment columns (must match database.ts)
|
|
6237
|
+
"ALTER TABLE memories ADD COLUMN intent TEXT",
|
|
6238
|
+
"ALTER TABLE memories ADD COLUMN outcome TEXT",
|
|
6239
|
+
"ALTER TABLE memories ADD COLUMN domain TEXT",
|
|
6240
|
+
"ALTER TABLE memories ADD COLUMN referenced_entities TEXT",
|
|
6241
|
+
"ALTER TABLE memories ADD COLUMN retrieval_count INTEGER DEFAULT 0",
|
|
6242
|
+
"ALTER TABLE memories ADD COLUMN chain_position TEXT",
|
|
6243
|
+
"ALTER TABLE memories ADD COLUMN review_status TEXT",
|
|
6244
|
+
"ALTER TABLE memories ADD COLUMN context_window_pct INTEGER",
|
|
6245
|
+
"ALTER TABLE memories ADD COLUMN file_paths TEXT",
|
|
6246
|
+
"ALTER TABLE memories ADD COLUMN commit_hash TEXT",
|
|
6247
|
+
"ALTER TABLE memories ADD COLUMN duration_ms INTEGER",
|
|
6248
|
+
"ALTER TABLE memories ADD COLUMN token_cost REAL",
|
|
6249
|
+
"ALTER TABLE memories ADD COLUMN audience TEXT",
|
|
6250
|
+
"ALTER TABLE memories ADD COLUMN language_type TEXT",
|
|
6251
|
+
"ALTER TABLE memories ADD COLUMN parent_memory_id TEXT"
|
|
5408
6252
|
]) {
|
|
5409
6253
|
try {
|
|
5410
6254
|
await client.execute(col);
|
|
@@ -5516,7 +6360,7 @@ var init_shard_manager = __esm({
|
|
|
5516
6360
|
"src/lib/shard-manager.ts"() {
|
|
5517
6361
|
"use strict";
|
|
5518
6362
|
init_config();
|
|
5519
|
-
SHARDS_DIR =
|
|
6363
|
+
SHARDS_DIR = path13.join(EXE_AI_DIR, "shards");
|
|
5520
6364
|
_shards = /* @__PURE__ */ new Map();
|
|
5521
6365
|
_encryptionKey = null;
|
|
5522
6366
|
_shardingEnabled = false;
|
|
@@ -6288,12 +7132,12 @@ __export(backfill_conversations_exports, {
|
|
|
6288
7132
|
import crypto4 from "crypto";
|
|
6289
7133
|
import { createReadStream } from "fs";
|
|
6290
7134
|
import { readdir as readdir2, stat } from "fs/promises";
|
|
6291
|
-
import
|
|
7135
|
+
import path14 from "path";
|
|
6292
7136
|
import { createInterface as createInterface2 } from "readline";
|
|
6293
7137
|
import { homedir as homedir3 } from "os";
|
|
6294
7138
|
import { parseArgs } from "util";
|
|
6295
7139
|
async function findJsonlFiles(sinceDate, projectFilter) {
|
|
6296
|
-
const projectsDir =
|
|
7140
|
+
const projectsDir = path14.join(homedir3(), ".claude", "projects");
|
|
6297
7141
|
const files = [];
|
|
6298
7142
|
async function walk(dir, depth = 0) {
|
|
6299
7143
|
if (depth > MAX_WALK_DEPTH) return;
|
|
@@ -6304,7 +7148,7 @@ async function findJsonlFiles(sinceDate, projectFilter) {
|
|
|
6304
7148
|
return;
|
|
6305
7149
|
}
|
|
6306
7150
|
for (const entry of entries) {
|
|
6307
|
-
const full =
|
|
7151
|
+
const full = path14.join(dir, entry.name);
|
|
6308
7152
|
if (entry.isDirectory()) {
|
|
6309
7153
|
if (entry.name === "subagents" || entry.name === "tool-results") continue;
|
|
6310
7154
|
await walk(full, depth + 1);
|
|
@@ -6329,7 +7173,7 @@ async function findJsonlFiles(sinceDate, projectFilter) {
|
|
|
6329
7173
|
if (!entry.isDirectory()) continue;
|
|
6330
7174
|
const decoded = decodeProjectDir(entry.name);
|
|
6331
7175
|
if (decoded.toLowerCase().includes(projectFilter.toLowerCase())) {
|
|
6332
|
-
await walk(
|
|
7176
|
+
await walk(path14.join(projectsDir, entry.name));
|
|
6333
7177
|
}
|
|
6334
7178
|
}
|
|
6335
7179
|
} else {
|
|
@@ -6346,14 +7190,14 @@ function decodeProjectDir(dirName) {
|
|
|
6346
7190
|
return dirName;
|
|
6347
7191
|
}
|
|
6348
7192
|
function projectNameFromPath(filePath) {
|
|
6349
|
-
const projectsDir =
|
|
6350
|
-
const relative =
|
|
6351
|
-
const projectDir = relative.split(
|
|
7193
|
+
const projectsDir = path14.join(homedir3(), ".claude", "projects");
|
|
7194
|
+
const relative = path14.relative(projectsDir, filePath);
|
|
7195
|
+
const projectDir = relative.split(path14.sep)[0] ?? "unknown";
|
|
6352
7196
|
return decodeProjectDir(projectDir);
|
|
6353
7197
|
}
|
|
6354
7198
|
async function parseConversation(filePath) {
|
|
6355
7199
|
const conv = {
|
|
6356
|
-
sessionId:
|
|
7200
|
+
sessionId: path14.basename(filePath, ".jsonl"),
|
|
6357
7201
|
projectName: projectNameFromPath(filePath),
|
|
6358
7202
|
cwd: void 0,
|
|
6359
7203
|
startTime: void 0,
|
|
@@ -6417,7 +7261,7 @@ async function parseConversation(filePath) {
|
|
|
6417
7261
|
}
|
|
6418
7262
|
}
|
|
6419
7263
|
if (conv.cwd) {
|
|
6420
|
-
conv.projectName =
|
|
7264
|
+
conv.projectName = path14.basename(conv.cwd);
|
|
6421
7265
|
const worktreeMatch = conv.cwd.match(/\.worktrees\/([^/]+)/);
|
|
6422
7266
|
if (worktreeMatch?.[1]) {
|
|
6423
7267
|
conv.agentId = worktreeMatch[1];
|
|
@@ -7069,9 +7913,9 @@ Unclassified: ${unclassified}
|
|
|
7069
7913
|
}
|
|
7070
7914
|
async function exportBatches(options) {
|
|
7071
7915
|
const fs8 = await import("fs");
|
|
7072
|
-
const
|
|
7916
|
+
const path45 = await import("path");
|
|
7073
7917
|
const client = getClient();
|
|
7074
|
-
const outDir =
|
|
7918
|
+
const outDir = path45.join(process.cwd(), "exe/output/classifications/input");
|
|
7075
7919
|
fs8.mkdirSync(outDir, { recursive: true });
|
|
7076
7920
|
const countResult = await client.execute({
|
|
7077
7921
|
sql: "SELECT COUNT(*) as cnt FROM memories WHERE intent IS NULL AND outcome IS NULL AND domain IS NULL",
|
|
@@ -7095,7 +7939,7 @@ async function exportBatches(options) {
|
|
|
7095
7939
|
const text = String(row.text || "").replace(/\n/g, " ");
|
|
7096
7940
|
return JSON.stringify({ id: row.id, text });
|
|
7097
7941
|
});
|
|
7098
|
-
const batchFile =
|
|
7942
|
+
const batchFile = path45.join(outDir, `batch-${String(batchNum).padStart(4, "0")}.jsonl`);
|
|
7099
7943
|
fs8.writeFileSync(batchFile, lines.join("\n") + "\n");
|
|
7100
7944
|
exported += batch.rows.length;
|
|
7101
7945
|
offset += options.batchSize;
|
|
@@ -7111,7 +7955,7 @@ async function exportBatches(options) {
|
|
|
7111
7955
|
}
|
|
7112
7956
|
async function importClassifications(importDir) {
|
|
7113
7957
|
const fs8 = await import("fs");
|
|
7114
|
-
const
|
|
7958
|
+
const path45 = await import("path");
|
|
7115
7959
|
const client = getClient();
|
|
7116
7960
|
const files = fs8.readdirSync(importDir).filter((f) => f.endsWith(".jsonl")).sort();
|
|
7117
7961
|
process.stderr.write(`[backfill-metadata] Found ${files.length} JSONL files to import from ${importDir}
|
|
@@ -7119,7 +7963,7 @@ async function importClassifications(importDir) {
|
|
|
7119
7963
|
let imported = 0;
|
|
7120
7964
|
let invalid = 0;
|
|
7121
7965
|
for (const file of files) {
|
|
7122
|
-
const lines = fs8.readFileSync(
|
|
7966
|
+
const lines = fs8.readFileSync(path45.join(importDir, file), "utf-8").split("\n").filter(Boolean);
|
|
7123
7967
|
for (const line of lines) {
|
|
7124
7968
|
try {
|
|
7125
7969
|
const rec = JSON.parse(line);
|
|
@@ -7260,17 +8104,17 @@ __export(identity_exports, {
|
|
|
7260
8104
|
listIdentities: () => listIdentities,
|
|
7261
8105
|
updateIdentity: () => updateIdentity
|
|
7262
8106
|
});
|
|
7263
|
-
import { existsSync as
|
|
8107
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync9, readFileSync as readFileSync10, writeFileSync as writeFileSync8 } from "fs";
|
|
7264
8108
|
import { readdirSync as readdirSync3 } from "fs";
|
|
7265
|
-
import
|
|
8109
|
+
import path15 from "path";
|
|
7266
8110
|
import { createHash as createHash2 } from "crypto";
|
|
7267
8111
|
function ensureDir() {
|
|
7268
|
-
if (!
|
|
7269
|
-
|
|
8112
|
+
if (!existsSync13(IDENTITY_DIR2)) {
|
|
8113
|
+
mkdirSync9(IDENTITY_DIR2, { recursive: true });
|
|
7270
8114
|
}
|
|
7271
8115
|
}
|
|
7272
8116
|
function identityPath(agentId) {
|
|
7273
|
-
return
|
|
8117
|
+
return path15.join(IDENTITY_DIR2, `${agentId}.md`);
|
|
7274
8118
|
}
|
|
7275
8119
|
function parseFrontmatter(raw) {
|
|
7276
8120
|
const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
@@ -7311,8 +8155,8 @@ function contentHash(content) {
|
|
|
7311
8155
|
}
|
|
7312
8156
|
function getIdentity(agentId) {
|
|
7313
8157
|
const filePath = identityPath(agentId);
|
|
7314
|
-
if (!
|
|
7315
|
-
const raw =
|
|
8158
|
+
if (!existsSync13(filePath)) return null;
|
|
8159
|
+
const raw = readFileSync10(filePath, "utf-8");
|
|
7316
8160
|
const { frontmatter, body } = parseFrontmatter(raw);
|
|
7317
8161
|
return {
|
|
7318
8162
|
agentId,
|
|
@@ -7326,7 +8170,7 @@ async function updateIdentity(agentId, content, updatedBy) {
|
|
|
7326
8170
|
ensureDir();
|
|
7327
8171
|
const filePath = identityPath(agentId);
|
|
7328
8172
|
const hash = contentHash(content);
|
|
7329
|
-
|
|
8173
|
+
writeFileSync8(filePath, content, "utf-8");
|
|
7330
8174
|
try {
|
|
7331
8175
|
const client = getClient();
|
|
7332
8176
|
await client.execute({
|
|
@@ -7343,7 +8187,7 @@ async function updateIdentity(agentId, content, updatedBy) {
|
|
|
7343
8187
|
}
|
|
7344
8188
|
function listIdentities() {
|
|
7345
8189
|
ensureDir();
|
|
7346
|
-
const files = readdirSync3(
|
|
8190
|
+
const files = readdirSync3(IDENTITY_DIR2).filter((f) => f.endsWith(".md"));
|
|
7347
8191
|
const results = [];
|
|
7348
8192
|
for (const file of files) {
|
|
7349
8193
|
const agentId = file.replace(".md", "");
|
|
@@ -7376,21 +8220,21 @@ ${teamLines.join("\n")}`);
|
|
|
7376
8220
|
}
|
|
7377
8221
|
return parts.join("\n\n");
|
|
7378
8222
|
}
|
|
7379
|
-
var
|
|
8223
|
+
var IDENTITY_DIR2;
|
|
7380
8224
|
var init_identity = __esm({
|
|
7381
8225
|
"src/lib/identity.ts"() {
|
|
7382
8226
|
"use strict";
|
|
7383
8227
|
init_config();
|
|
7384
8228
|
init_database();
|
|
7385
|
-
|
|
8229
|
+
IDENTITY_DIR2 = path15.join(EXE_AI_DIR, "identity");
|
|
7386
8230
|
}
|
|
7387
8231
|
});
|
|
7388
8232
|
|
|
7389
8233
|
// src/lib/orchestration-package.ts
|
|
7390
8234
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
7391
|
-
import { copyFileSync as copyFileSync2, existsSync as
|
|
7392
|
-
import
|
|
7393
|
-
import
|
|
8235
|
+
import { copyFileSync as copyFileSync2, existsSync as existsSync14, mkdirSync as mkdirSync10, readFileSync as readFileSync11, writeFileSync as writeFileSync9 } from "fs";
|
|
8236
|
+
import os9 from "os";
|
|
8237
|
+
import path16 from "path";
|
|
7394
8238
|
function ensureObject(value, label) {
|
|
7395
8239
|
if (value == null || Array.isArray(value) || typeof value !== "object") {
|
|
7396
8240
|
throw new Error(`${label} must be an object`);
|
|
@@ -7449,15 +8293,15 @@ function validateProcedureEntry(value, index) {
|
|
|
7449
8293
|
};
|
|
7450
8294
|
}
|
|
7451
8295
|
function getRosterPath() {
|
|
7452
|
-
return
|
|
8296
|
+
return path16.join(os9.homedir(), EXE_OS_DIRNAME, ROSTER_FILENAME);
|
|
7453
8297
|
}
|
|
7454
8298
|
function getBackupPath() {
|
|
7455
|
-
return
|
|
8299
|
+
return path16.join(os9.homedir(), EXE_OS_DIRNAME, ROSTER_BACKUP_FILENAME);
|
|
7456
8300
|
}
|
|
7457
8301
|
function readRosterFile() {
|
|
7458
8302
|
const rosterPath = getRosterPath();
|
|
7459
|
-
if (!
|
|
7460
|
-
const raw =
|
|
8303
|
+
if (!existsSync14(rosterPath)) return [];
|
|
8304
|
+
const raw = readFileSync11(rosterPath, "utf-8");
|
|
7461
8305
|
const parsed = JSON.parse(raw);
|
|
7462
8306
|
if (!Array.isArray(parsed)) {
|
|
7463
8307
|
throw new Error("Roster file must contain a JSON array");
|
|
@@ -7469,8 +8313,8 @@ function writeRosterFile(roster) {
|
|
|
7469
8313
|
throw new Error("Refusing to write empty roster \u2014 this would delete all employees");
|
|
7470
8314
|
}
|
|
7471
8315
|
const rosterPath = getRosterPath();
|
|
7472
|
-
|
|
7473
|
-
if (
|
|
8316
|
+
mkdirSync10(path16.dirname(rosterPath), { recursive: true });
|
|
8317
|
+
if (existsSync14(rosterPath)) {
|
|
7474
8318
|
const currentRoster = readRosterFile();
|
|
7475
8319
|
if (roster.length < currentRoster.length) {
|
|
7476
8320
|
throw new Error(
|
|
@@ -7479,7 +8323,7 @@ function writeRosterFile(roster) {
|
|
|
7479
8323
|
}
|
|
7480
8324
|
copyFileSync2(rosterPath, getBackupPath());
|
|
7481
8325
|
}
|
|
7482
|
-
|
|
8326
|
+
writeFileSync9(rosterPath, `${JSON.stringify(roster, null, 2)}
|
|
7483
8327
|
`, "utf-8");
|
|
7484
8328
|
}
|
|
7485
8329
|
function buildImportedRosterEntries(roster, timestamp) {
|
|
@@ -7746,8 +8590,8 @@ var exe_export_exports = {};
|
|
|
7746
8590
|
__export(exe_export_exports, {
|
|
7747
8591
|
runExeExport: () => runExeExport
|
|
7748
8592
|
});
|
|
7749
|
-
import { mkdirSync as
|
|
7750
|
-
import
|
|
8593
|
+
import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync10 } from "fs";
|
|
8594
|
+
import path17 from "path";
|
|
7751
8595
|
function printUsage() {
|
|
7752
8596
|
process.stdout.write("Usage: exe-os export --output <path>\n");
|
|
7753
8597
|
}
|
|
@@ -7768,8 +8612,8 @@ async function runExeExport(argv = process.argv.slice(2)) {
|
|
|
7768
8612
|
await initStore();
|
|
7769
8613
|
try {
|
|
7770
8614
|
const pkg = await exportOrchestration("cli");
|
|
7771
|
-
|
|
7772
|
-
|
|
8615
|
+
mkdirSync11(path17.dirname(outputPath), { recursive: true });
|
|
8616
|
+
writeFileSync10(outputPath, `${JSON.stringify(pkg, null, 2)}
|
|
7773
8617
|
`, "utf-8");
|
|
7774
8618
|
process.stdout.write(
|
|
7775
8619
|
`Exported ${pkg.roster.length} roster entries, ${Object.keys(pkg.identities).length} identities, ${pkg.behaviors.length} behaviors, ${pkg.procedures.length} procedures to ${outputPath}
|
|
@@ -7805,7 +8649,7 @@ var exe_import_exports = {};
|
|
|
7805
8649
|
__export(exe_import_exports, {
|
|
7806
8650
|
runExeImport: () => runExeImport
|
|
7807
8651
|
});
|
|
7808
|
-
import { readFileSync as
|
|
8652
|
+
import { readFileSync as readFileSync12 } from "fs";
|
|
7809
8653
|
function printUsage2() {
|
|
7810
8654
|
process.stdout.write("Usage: exe-os import --from <path> [--merge]\n");
|
|
7811
8655
|
}
|
|
@@ -7828,7 +8672,7 @@ async function runExeImport(argv = process.argv.slice(2)) {
|
|
|
7828
8672
|
if (parsed == null) return;
|
|
7829
8673
|
await initStore();
|
|
7830
8674
|
try {
|
|
7831
|
-
const raw =
|
|
8675
|
+
const raw = readFileSync12(parsed.packagePath, "utf-8");
|
|
7832
8676
|
const pkg = validatePackage(JSON.parse(raw));
|
|
7833
8677
|
const result = await importOrchestration(pkg, parsed.strategy);
|
|
7834
8678
|
process.stdout.write(
|
|
@@ -7868,14 +8712,14 @@ __export(session_registry_exports, {
|
|
|
7868
8712
|
pruneStaleSessions: () => pruneStaleSessions,
|
|
7869
8713
|
registerSession: () => registerSession
|
|
7870
8714
|
});
|
|
7871
|
-
import { readFileSync as
|
|
8715
|
+
import { readFileSync as readFileSync13, writeFileSync as writeFileSync11, mkdirSync as mkdirSync12, existsSync as existsSync15 } from "fs";
|
|
7872
8716
|
import { execSync as execSync3 } from "child_process";
|
|
7873
|
-
import
|
|
7874
|
-
import
|
|
8717
|
+
import path18 from "path";
|
|
8718
|
+
import os10 from "os";
|
|
7875
8719
|
function registerSession(entry) {
|
|
7876
|
-
const dir =
|
|
7877
|
-
if (!
|
|
7878
|
-
|
|
8720
|
+
const dir = path18.dirname(REGISTRY_PATH);
|
|
8721
|
+
if (!existsSync15(dir)) {
|
|
8722
|
+
mkdirSync12(dir, { recursive: true });
|
|
7879
8723
|
}
|
|
7880
8724
|
const sessions = listSessions();
|
|
7881
8725
|
const idx = sessions.findIndex((s) => s.windowName === entry.windowName);
|
|
@@ -7884,11 +8728,11 @@ function registerSession(entry) {
|
|
|
7884
8728
|
} else {
|
|
7885
8729
|
sessions.push(entry);
|
|
7886
8730
|
}
|
|
7887
|
-
|
|
8731
|
+
writeFileSync11(REGISTRY_PATH, JSON.stringify(sessions, null, 2));
|
|
7888
8732
|
}
|
|
7889
8733
|
function listSessions() {
|
|
7890
8734
|
try {
|
|
7891
|
-
const raw =
|
|
8735
|
+
const raw = readFileSync13(REGISTRY_PATH, "utf8");
|
|
7892
8736
|
return JSON.parse(raw);
|
|
7893
8737
|
} catch {
|
|
7894
8738
|
return [];
|
|
@@ -7909,7 +8753,7 @@ function pruneStaleSessions() {
|
|
|
7909
8753
|
const alive = sessions.filter((s) => liveSet.has(s.windowName));
|
|
7910
8754
|
const pruned = sessions.length - alive.length;
|
|
7911
8755
|
if (pruned > 0) {
|
|
7912
|
-
|
|
8756
|
+
writeFileSync11(REGISTRY_PATH, JSON.stringify(alive, null, 2));
|
|
7913
8757
|
}
|
|
7914
8758
|
return pruned;
|
|
7915
8759
|
}
|
|
@@ -7917,7 +8761,7 @@ var REGISTRY_PATH;
|
|
|
7917
8761
|
var init_session_registry = __esm({
|
|
7918
8762
|
"src/lib/session-registry.ts"() {
|
|
7919
8763
|
"use strict";
|
|
7920
|
-
REGISTRY_PATH =
|
|
8764
|
+
REGISTRY_PATH = path18.join(os10.homedir(), ".exe-os", "session-registry.json");
|
|
7921
8765
|
}
|
|
7922
8766
|
});
|
|
7923
8767
|
|
|
@@ -8154,67 +8998,6 @@ var init_provider_table = __esm({
|
|
|
8154
8998
|
}
|
|
8155
8999
|
});
|
|
8156
9000
|
|
|
8157
|
-
// src/lib/runtime-table.ts
|
|
8158
|
-
var RUNTIME_TABLE, DEFAULT_RUNTIME;
|
|
8159
|
-
var init_runtime_table = __esm({
|
|
8160
|
-
"src/lib/runtime-table.ts"() {
|
|
8161
|
-
"use strict";
|
|
8162
|
-
RUNTIME_TABLE = {
|
|
8163
|
-
codex: {
|
|
8164
|
-
binary: "codex",
|
|
8165
|
-
launchMode: "interactive",
|
|
8166
|
-
autoApproveFlag: "--dangerously-bypass-approvals-and-sandbox",
|
|
8167
|
-
inlineFlag: "--no-alt-screen",
|
|
8168
|
-
apiKeyEnv: "OPENAI_API_KEY",
|
|
8169
|
-
defaultModel: "gpt-5.4"
|
|
8170
|
-
},
|
|
8171
|
-
opencode: {
|
|
8172
|
-
binary: "opencode",
|
|
8173
|
-
launchMode: "exec",
|
|
8174
|
-
autoApproveFlag: "--dangerously-skip-permissions",
|
|
8175
|
-
inlineFlag: "",
|
|
8176
|
-
apiKeyEnv: "ANTHROPIC_API_KEY",
|
|
8177
|
-
defaultModel: "anthropic/claude-sonnet-4-6"
|
|
8178
|
-
}
|
|
8179
|
-
};
|
|
8180
|
-
DEFAULT_RUNTIME = "claude";
|
|
8181
|
-
}
|
|
8182
|
-
});
|
|
8183
|
-
|
|
8184
|
-
// src/lib/agent-config.ts
|
|
8185
|
-
import { readFileSync as readFileSync13, writeFileSync as writeFileSync11, existsSync as existsSync15, mkdirSync as mkdirSync12 } from "fs";
|
|
8186
|
-
import path17 from "path";
|
|
8187
|
-
function loadAgentConfig() {
|
|
8188
|
-
if (!existsSync15(AGENT_CONFIG_PATH)) return {};
|
|
8189
|
-
try {
|
|
8190
|
-
return JSON.parse(readFileSync13(AGENT_CONFIG_PATH, "utf-8"));
|
|
8191
|
-
} catch {
|
|
8192
|
-
return {};
|
|
8193
|
-
}
|
|
8194
|
-
}
|
|
8195
|
-
function getAgentRuntime(agentId) {
|
|
8196
|
-
const config = loadAgentConfig();
|
|
8197
|
-
const entry = config[agentId];
|
|
8198
|
-
if (entry) return entry;
|
|
8199
|
-
const orgDefault = config["default"];
|
|
8200
|
-
if (orgDefault) return orgDefault;
|
|
8201
|
-
return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
|
|
8202
|
-
}
|
|
8203
|
-
var AGENT_CONFIG_PATH, DEFAULT_MODELS;
|
|
8204
|
-
var init_agent_config = __esm({
|
|
8205
|
-
"src/lib/agent-config.ts"() {
|
|
8206
|
-
"use strict";
|
|
8207
|
-
init_config();
|
|
8208
|
-
init_runtime_table();
|
|
8209
|
-
AGENT_CONFIG_PATH = path17.join(EXE_AI_DIR, "agent-config.json");
|
|
8210
|
-
DEFAULT_MODELS = {
|
|
8211
|
-
claude: "claude-opus-4",
|
|
8212
|
-
codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
|
|
8213
|
-
opencode: RUNTIME_TABLE.opencode?.defaultModel ?? "anthropic/claude-sonnet-4-6"
|
|
8214
|
-
};
|
|
8215
|
-
}
|
|
8216
|
-
});
|
|
8217
|
-
|
|
8218
9001
|
// src/lib/intercom-queue.ts
|
|
8219
9002
|
var intercom_queue_exports = {};
|
|
8220
9003
|
__export(intercom_queue_exports, {
|
|
@@ -8225,10 +9008,10 @@ __export(intercom_queue_exports, {
|
|
|
8225
9008
|
readQueue: () => readQueue
|
|
8226
9009
|
});
|
|
8227
9010
|
import { readFileSync as readFileSync14, writeFileSync as writeFileSync12, renameSync as renameSync3, existsSync as existsSync16, mkdirSync as mkdirSync13 } from "fs";
|
|
8228
|
-
import
|
|
8229
|
-
import
|
|
9011
|
+
import path19 from "path";
|
|
9012
|
+
import os11 from "os";
|
|
8230
9013
|
function ensureDir2() {
|
|
8231
|
-
const dir =
|
|
9014
|
+
const dir = path19.dirname(QUEUE_PATH);
|
|
8232
9015
|
if (!existsSync16(dir)) mkdirSync13(dir, { recursive: true });
|
|
8233
9016
|
}
|
|
8234
9017
|
function readQueue() {
|
|
@@ -8334,16 +9117,16 @@ var QUEUE_PATH, MAX_RETRIES2, TTL_MS, INTERCOM_LOG;
|
|
|
8334
9117
|
var init_intercom_queue = __esm({
|
|
8335
9118
|
"src/lib/intercom-queue.ts"() {
|
|
8336
9119
|
"use strict";
|
|
8337
|
-
QUEUE_PATH =
|
|
9120
|
+
QUEUE_PATH = path19.join(os11.homedir(), ".exe-os", "intercom-queue.json");
|
|
8338
9121
|
MAX_RETRIES2 = 5;
|
|
8339
9122
|
TTL_MS = 60 * 60 * 1e3;
|
|
8340
|
-
INTERCOM_LOG =
|
|
9123
|
+
INTERCOM_LOG = path19.join(os11.homedir(), ".exe-os", "intercom.log");
|
|
8341
9124
|
}
|
|
8342
9125
|
});
|
|
8343
9126
|
|
|
8344
9127
|
// src/lib/plan-limits.ts
|
|
8345
9128
|
import { readFileSync as readFileSync15, existsSync as existsSync17 } from "fs";
|
|
8346
|
-
import
|
|
9129
|
+
import path20 from "path";
|
|
8347
9130
|
function getLicenseSync() {
|
|
8348
9131
|
try {
|
|
8349
9132
|
if (!existsSync17(CACHE_PATH2)) return freeLicense();
|
|
@@ -8415,14 +9198,14 @@ var init_plan_limits = __esm({
|
|
|
8415
9198
|
this.name = "PlanLimitError";
|
|
8416
9199
|
}
|
|
8417
9200
|
};
|
|
8418
|
-
CACHE_PATH2 =
|
|
9201
|
+
CACHE_PATH2 = path20.join(EXE_AI_DIR, "license-cache.json");
|
|
8419
9202
|
}
|
|
8420
9203
|
});
|
|
8421
9204
|
|
|
8422
9205
|
// src/lib/notifications.ts
|
|
8423
9206
|
import crypto5 from "crypto";
|
|
8424
|
-
import
|
|
8425
|
-
import
|
|
9207
|
+
import path21 from "path";
|
|
9208
|
+
import os12 from "os";
|
|
8426
9209
|
import {
|
|
8427
9210
|
readFileSync as readFileSync16,
|
|
8428
9211
|
readdirSync as readdirSync4,
|
|
@@ -8552,8 +9335,8 @@ __export(tasks_crud_exports, {
|
|
|
8552
9335
|
writeCheckpoint: () => writeCheckpoint
|
|
8553
9336
|
});
|
|
8554
9337
|
import crypto7 from "crypto";
|
|
8555
|
-
import
|
|
8556
|
-
import
|
|
9338
|
+
import path22 from "path";
|
|
9339
|
+
import os13 from "os";
|
|
8557
9340
|
import { execSync as execSync6 } from "child_process";
|
|
8558
9341
|
import { mkdir as mkdir5, writeFile as writeFile5, appendFile } from "fs/promises";
|
|
8559
9342
|
import { existsSync as existsSync19, readFileSync as readFileSync17 } from "fs";
|
|
@@ -8731,8 +9514,8 @@ ${laneWarning}` : laneWarning;
|
|
|
8731
9514
|
}
|
|
8732
9515
|
if (input.baseDir) {
|
|
8733
9516
|
try {
|
|
8734
|
-
await mkdir5(
|
|
8735
|
-
await mkdir5(
|
|
9517
|
+
await mkdir5(path22.join(input.baseDir, "exe", "output"), { recursive: true });
|
|
9518
|
+
await mkdir5(path22.join(input.baseDir, "exe", "research"), { recursive: true });
|
|
8736
9519
|
await ensureArchitectureDoc(input.baseDir, input.projectName);
|
|
8737
9520
|
await ensureGitignoreExe(input.baseDir);
|
|
8738
9521
|
} catch {
|
|
@@ -8768,9 +9551,9 @@ ${laneWarning}` : laneWarning;
|
|
|
8768
9551
|
});
|
|
8769
9552
|
if (input.baseDir) {
|
|
8770
9553
|
try {
|
|
8771
|
-
const EXE_OS_DIR =
|
|
8772
|
-
const mdPath =
|
|
8773
|
-
const mdDir =
|
|
9554
|
+
const EXE_OS_DIR = path22.join(os13.homedir(), ".exe-os");
|
|
9555
|
+
const mdPath = path22.join(EXE_OS_DIR, taskFile);
|
|
9556
|
+
const mdDir = path22.dirname(mdPath);
|
|
8774
9557
|
if (!existsSync19(mdDir)) await mkdir5(mdDir, { recursive: true });
|
|
8775
9558
|
const reviewer = input.reviewer ?? input.assignedBy;
|
|
8776
9559
|
const mdContent = `# ${input.title}
|
|
@@ -9071,7 +9854,7 @@ async function deleteTaskCore(taskId, _baseDir) {
|
|
|
9071
9854
|
return { taskFile, assignedTo, assignedBy, taskSlug };
|
|
9072
9855
|
}
|
|
9073
9856
|
async function ensureArchitectureDoc(baseDir, projectName) {
|
|
9074
|
-
const archPath =
|
|
9857
|
+
const archPath = path22.join(baseDir, "exe", "ARCHITECTURE.md");
|
|
9075
9858
|
try {
|
|
9076
9859
|
if (existsSync19(archPath)) return;
|
|
9077
9860
|
const template = [
|
|
@@ -9106,7 +9889,7 @@ async function ensureArchitectureDoc(baseDir, projectName) {
|
|
|
9106
9889
|
}
|
|
9107
9890
|
}
|
|
9108
9891
|
async function ensureGitignoreExe(baseDir) {
|
|
9109
|
-
const gitignorePath =
|
|
9892
|
+
const gitignorePath = path22.join(baseDir, ".gitignore");
|
|
9110
9893
|
try {
|
|
9111
9894
|
if (existsSync19(gitignorePath)) {
|
|
9112
9895
|
const content = readFileSync17(gitignorePath, "utf-8");
|
|
@@ -9140,13 +9923,13 @@ var init_tasks_crud = __esm({
|
|
|
9140
9923
|
});
|
|
9141
9924
|
|
|
9142
9925
|
// src/lib/tasks-review.ts
|
|
9143
|
-
import
|
|
9926
|
+
import path23 from "path";
|
|
9144
9927
|
import { existsSync as existsSync20, readdirSync as readdirSync5, unlinkSync as unlinkSync6 } from "fs";
|
|
9145
9928
|
async function countPendingReviews(sessionScope) {
|
|
9146
9929
|
const client = getClient();
|
|
9147
9930
|
if (sessionScope) {
|
|
9148
9931
|
const result2 = await client.execute({
|
|
9149
|
-
sql: "SELECT COUNT(*) as cnt FROM tasks WHERE status = 'needs_review' AND
|
|
9932
|
+
sql: "SELECT COUNT(*) as cnt FROM tasks WHERE status = 'needs_review' AND session_scope = ?",
|
|
9150
9933
|
args: [sessionScope]
|
|
9151
9934
|
});
|
|
9152
9935
|
return Number(result2.rows[0]?.cnt) || 0;
|
|
@@ -9322,11 +10105,11 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
|
|
|
9322
10105
|
);
|
|
9323
10106
|
}
|
|
9324
10107
|
try {
|
|
9325
|
-
const cacheDir =
|
|
10108
|
+
const cacheDir = path23.join(EXE_AI_DIR, "session-cache");
|
|
9326
10109
|
if (existsSync20(cacheDir)) {
|
|
9327
10110
|
for (const f of readdirSync5(cacheDir)) {
|
|
9328
10111
|
if (f.startsWith("review-notified-")) {
|
|
9329
|
-
unlinkSync6(
|
|
10112
|
+
unlinkSync6(path23.join(cacheDir, f));
|
|
9330
10113
|
}
|
|
9331
10114
|
}
|
|
9332
10115
|
}
|
|
@@ -9347,7 +10130,7 @@ var init_tasks_review = __esm({
|
|
|
9347
10130
|
});
|
|
9348
10131
|
|
|
9349
10132
|
// src/lib/tasks-chain.ts
|
|
9350
|
-
import
|
|
10133
|
+
import path24 from "path";
|
|
9351
10134
|
import { readFile as readFile5, writeFile as writeFile6 } from "fs/promises";
|
|
9352
10135
|
async function cascadeUnblock(taskId, baseDir, now) {
|
|
9353
10136
|
const client = getClient();
|
|
@@ -9364,7 +10147,7 @@ async function cascadeUnblock(taskId, baseDir, now) {
|
|
|
9364
10147
|
});
|
|
9365
10148
|
for (const ur of unblockedRows.rows) {
|
|
9366
10149
|
try {
|
|
9367
|
-
const ubFile =
|
|
10150
|
+
const ubFile = path24.join(baseDir, String(ur.task_file));
|
|
9368
10151
|
let ubContent = await readFile5(ubFile, "utf-8");
|
|
9369
10152
|
ubContent = ubContent.replace(/\*\*Status:\*\* blocked/, "**Status:** open");
|
|
9370
10153
|
ubContent = ubContent.replace(/\n\*\*Blocked by:\*\*.*\n/, "\n");
|
|
@@ -9433,7 +10216,7 @@ var init_tasks_chain = __esm({
|
|
|
9433
10216
|
|
|
9434
10217
|
// src/lib/project-name.ts
|
|
9435
10218
|
import { execSync as execSync7 } from "child_process";
|
|
9436
|
-
import
|
|
10219
|
+
import path25 from "path";
|
|
9437
10220
|
function getProjectName(cwd2) {
|
|
9438
10221
|
const dir = cwd2 ?? process.cwd();
|
|
9439
10222
|
if (_cached2 && _cachedCwd === dir) return _cached2;
|
|
@@ -9446,7 +10229,7 @@ function getProjectName(cwd2) {
|
|
|
9446
10229
|
timeout: 2e3,
|
|
9447
10230
|
stdio: ["pipe", "pipe", "pipe"]
|
|
9448
10231
|
}).trim();
|
|
9449
|
-
repoRoot =
|
|
10232
|
+
repoRoot = path25.dirname(gitCommonDir);
|
|
9450
10233
|
} catch {
|
|
9451
10234
|
repoRoot = execSync7("git rev-parse --show-toplevel", {
|
|
9452
10235
|
cwd: dir,
|
|
@@ -9455,11 +10238,11 @@ function getProjectName(cwd2) {
|
|
|
9455
10238
|
stdio: ["pipe", "pipe", "pipe"]
|
|
9456
10239
|
}).trim();
|
|
9457
10240
|
}
|
|
9458
|
-
_cached2 =
|
|
10241
|
+
_cached2 = path25.basename(repoRoot);
|
|
9459
10242
|
_cachedCwd = dir;
|
|
9460
10243
|
return _cached2;
|
|
9461
10244
|
} catch {
|
|
9462
|
-
_cached2 =
|
|
10245
|
+
_cached2 = path25.basename(dir);
|
|
9463
10246
|
_cachedCwd = dir;
|
|
9464
10247
|
return _cached2;
|
|
9465
10248
|
}
|
|
@@ -9932,7 +10715,7 @@ __export(tasks_exports, {
|
|
|
9932
10715
|
updateTaskStatus: () => updateTaskStatus,
|
|
9933
10716
|
writeCheckpoint: () => writeCheckpoint
|
|
9934
10717
|
});
|
|
9935
|
-
import
|
|
10718
|
+
import path26 from "path";
|
|
9936
10719
|
import { writeFileSync as writeFileSync13, mkdirSync as mkdirSync14, unlinkSync as unlinkSync7 } from "fs";
|
|
9937
10720
|
async function createTask(input) {
|
|
9938
10721
|
const result = await createTaskCore(input);
|
|
@@ -9952,8 +10735,8 @@ async function updateTask(input) {
|
|
|
9952
10735
|
const { row, taskFile, now, taskId } = await updateTaskStatus(input);
|
|
9953
10736
|
try {
|
|
9954
10737
|
const agent = String(row.assigned_to);
|
|
9955
|
-
const cacheDir =
|
|
9956
|
-
const cachePath =
|
|
10738
|
+
const cacheDir = path26.join(EXE_AI_DIR, "session-cache");
|
|
10739
|
+
const cachePath = path26.join(cacheDir, `current-task-${agent}.json`);
|
|
9957
10740
|
if (input.status === "in_progress") {
|
|
9958
10741
|
mkdirSync14(cacheDir, { recursive: true });
|
|
9959
10742
|
writeFileSync13(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
|
|
@@ -10424,12 +11207,12 @@ __export(tmux_routing_exports, {
|
|
|
10424
11207
|
});
|
|
10425
11208
|
import { execFileSync as execFileSync2, execSync as execSync8 } from "child_process";
|
|
10426
11209
|
import { readFileSync as readFileSync18, writeFileSync as writeFileSync14, mkdirSync as mkdirSync15, existsSync as existsSync21, appendFileSync as appendFileSync2, readdirSync as readdirSync6 } from "fs";
|
|
10427
|
-
import
|
|
10428
|
-
import
|
|
11210
|
+
import path27 from "path";
|
|
11211
|
+
import os14 from "os";
|
|
10429
11212
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
10430
11213
|
import { unlinkSync as unlinkSync8 } from "fs";
|
|
10431
11214
|
function spawnLockPath(sessionName) {
|
|
10432
|
-
return
|
|
11215
|
+
return path27.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
|
|
10433
11216
|
}
|
|
10434
11217
|
function isProcessAlive(pid) {
|
|
10435
11218
|
try {
|
|
@@ -10466,8 +11249,8 @@ function releaseSpawnLock2(sessionName) {
|
|
|
10466
11249
|
function resolveBehaviorsExporterScript() {
|
|
10467
11250
|
try {
|
|
10468
11251
|
const thisFile = fileURLToPath4(import.meta.url);
|
|
10469
|
-
const scriptPath =
|
|
10470
|
-
|
|
11252
|
+
const scriptPath = path27.join(
|
|
11253
|
+
path27.dirname(thisFile),
|
|
10471
11254
|
"..",
|
|
10472
11255
|
"bin",
|
|
10473
11256
|
"exe-export-behaviors.js"
|
|
@@ -10542,7 +11325,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
|
10542
11325
|
mkdirSync15(SESSION_CACHE, { recursive: true });
|
|
10543
11326
|
}
|
|
10544
11327
|
const rootExe = extractRootExe(parentExe) ?? parentExe;
|
|
10545
|
-
const filePath =
|
|
11328
|
+
const filePath = path27.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
|
|
10546
11329
|
writeFileSync14(filePath, JSON.stringify({
|
|
10547
11330
|
parentExe: rootExe,
|
|
10548
11331
|
dispatchedBy: dispatchedBy || rootExe,
|
|
@@ -10551,7 +11334,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
|
10551
11334
|
}
|
|
10552
11335
|
function getParentExe(sessionKey) {
|
|
10553
11336
|
try {
|
|
10554
|
-
const data = JSON.parse(readFileSync18(
|
|
11337
|
+
const data = JSON.parse(readFileSync18(path27.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
10555
11338
|
return data.parentExe || null;
|
|
10556
11339
|
} catch {
|
|
10557
11340
|
return null;
|
|
@@ -10560,7 +11343,7 @@ function getParentExe(sessionKey) {
|
|
|
10560
11343
|
function getDispatchedBy(sessionKey) {
|
|
10561
11344
|
try {
|
|
10562
11345
|
const data = JSON.parse(readFileSync18(
|
|
10563
|
-
|
|
11346
|
+
path27.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
|
|
10564
11347
|
"utf8"
|
|
10565
11348
|
));
|
|
10566
11349
|
return data.dispatchedBy ?? data.parentExe ?? null;
|
|
@@ -10746,7 +11529,7 @@ function sendIntercom(targetSession) {
|
|
|
10746
11529
|
try {
|
|
10747
11530
|
const rawAgent = targetSession.split("-")[0] ?? targetSession;
|
|
10748
11531
|
const agent = baseAgentName(rawAgent);
|
|
10749
|
-
const markerPath =
|
|
11532
|
+
const markerPath = path27.join(SESSION_CACHE, `current-task-${agent}.json`);
|
|
10750
11533
|
if (existsSync21(markerPath)) {
|
|
10751
11534
|
logIntercom(`SKIP \u2192 ${targetSession} (has in_progress task marker \u2014 will auto-chain)`);
|
|
10752
11535
|
return "debounced";
|
|
@@ -10756,7 +11539,7 @@ function sendIntercom(targetSession) {
|
|
|
10756
11539
|
try {
|
|
10757
11540
|
const rawAgent = targetSession.split("-")[0] ?? targetSession;
|
|
10758
11541
|
const agent = baseAgentName(rawAgent);
|
|
10759
|
-
const taskDir =
|
|
11542
|
+
const taskDir = path27.join(process.cwd(), "exe", agent);
|
|
10760
11543
|
if (existsSync21(taskDir)) {
|
|
10761
11544
|
const files = readdirSync6(taskDir).filter(
|
|
10762
11545
|
(f) => f.endsWith(".md") && f !== "DONE.txt"
|
|
@@ -10890,8 +11673,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
10890
11673
|
const transport = getTransport();
|
|
10891
11674
|
const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
|
|
10892
11675
|
const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
|
|
10893
|
-
const logDir =
|
|
10894
|
-
const logFile =
|
|
11676
|
+
const logDir = path27.join(os14.homedir(), ".exe-os", "session-logs");
|
|
11677
|
+
const logFile = path27.join(logDir, `${instanceLabel}-${Date.now()}.log`);
|
|
10895
11678
|
if (!existsSync21(logDir)) {
|
|
10896
11679
|
mkdirSync15(logDir, { recursive: true });
|
|
10897
11680
|
}
|
|
@@ -10899,14 +11682,14 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
10899
11682
|
let cleanupSuffix = "";
|
|
10900
11683
|
try {
|
|
10901
11684
|
const thisFile = fileURLToPath4(import.meta.url);
|
|
10902
|
-
const cleanupScript =
|
|
11685
|
+
const cleanupScript = path27.join(path27.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
|
|
10903
11686
|
if (existsSync21(cleanupScript)) {
|
|
10904
11687
|
cleanupSuffix = `; ${process.execPath} "${cleanupScript}" "${employeeName}" "${exeSession}"`;
|
|
10905
11688
|
}
|
|
10906
11689
|
} catch {
|
|
10907
11690
|
}
|
|
10908
11691
|
try {
|
|
10909
|
-
const claudeJsonPath =
|
|
11692
|
+
const claudeJsonPath = path27.join(os14.homedir(), ".claude.json");
|
|
10910
11693
|
let claudeJson = {};
|
|
10911
11694
|
try {
|
|
10912
11695
|
claudeJson = JSON.parse(readFileSync18(claudeJsonPath, "utf8"));
|
|
@@ -10921,10 +11704,10 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
10921
11704
|
} catch {
|
|
10922
11705
|
}
|
|
10923
11706
|
try {
|
|
10924
|
-
const settingsDir =
|
|
11707
|
+
const settingsDir = path27.join(os14.homedir(), ".claude", "projects");
|
|
10925
11708
|
const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
|
|
10926
|
-
const projSettingsDir =
|
|
10927
|
-
const settingsPath =
|
|
11709
|
+
const projSettingsDir = path27.join(settingsDir, normalizedKey);
|
|
11710
|
+
const settingsPath = path27.join(projSettingsDir, "settings.json");
|
|
10928
11711
|
let settings = {};
|
|
10929
11712
|
try {
|
|
10930
11713
|
settings = JSON.parse(readFileSync18(settingsPath, "utf8"));
|
|
@@ -10971,8 +11754,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
10971
11754
|
let behaviorsFlag = "";
|
|
10972
11755
|
let legacyFallbackWarned = false;
|
|
10973
11756
|
if (!useExeAgent && !useBinSymlink) {
|
|
10974
|
-
const identityPath2 =
|
|
10975
|
-
|
|
11757
|
+
const identityPath2 = path27.join(
|
|
11758
|
+
os14.homedir(),
|
|
10976
11759
|
".exe-os",
|
|
10977
11760
|
"identity",
|
|
10978
11761
|
`${employeeName}.md`
|
|
@@ -10987,7 +11770,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
10987
11770
|
}
|
|
10988
11771
|
const behaviorsFile = exportBehaviorsSync(
|
|
10989
11772
|
employeeName,
|
|
10990
|
-
|
|
11773
|
+
path27.basename(spawnCwd),
|
|
10991
11774
|
sessionName
|
|
10992
11775
|
);
|
|
10993
11776
|
if (behaviorsFile) {
|
|
@@ -11002,9 +11785,9 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
11002
11785
|
}
|
|
11003
11786
|
let sessionContextFlag = "";
|
|
11004
11787
|
try {
|
|
11005
|
-
const ctxDir =
|
|
11788
|
+
const ctxDir = path27.join(os14.homedir(), ".exe-os", "session-cache");
|
|
11006
11789
|
mkdirSync15(ctxDir, { recursive: true });
|
|
11007
|
-
const ctxFile =
|
|
11790
|
+
const ctxFile = path27.join(ctxDir, `session-context-${sessionName}.md`);
|
|
11008
11791
|
const ctxContent = [
|
|
11009
11792
|
`## Session Context`,
|
|
11010
11793
|
`You are running in tmux session: ${sessionName}.`,
|
|
@@ -11088,7 +11871,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
11088
11871
|
transport.pipeLog(sessionName, logFile);
|
|
11089
11872
|
try {
|
|
11090
11873
|
const mySession = getMySession();
|
|
11091
|
-
const dispatchInfo =
|
|
11874
|
+
const dispatchInfo = path27.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
|
|
11092
11875
|
writeFileSync14(dispatchInfo, JSON.stringify({
|
|
11093
11876
|
dispatchedBy: mySession,
|
|
11094
11877
|
rootExe: exeSession,
|
|
@@ -11163,15 +11946,15 @@ var init_tmux_routing = __esm({
|
|
|
11163
11946
|
init_intercom_queue();
|
|
11164
11947
|
init_plan_limits();
|
|
11165
11948
|
init_employees();
|
|
11166
|
-
SPAWN_LOCK_DIR =
|
|
11167
|
-
SESSION_CACHE =
|
|
11949
|
+
SPAWN_LOCK_DIR = path27.join(os14.homedir(), ".exe-os", "spawn-locks");
|
|
11950
|
+
SESSION_CACHE = path27.join(os14.homedir(), ".exe-os", "session-cache");
|
|
11168
11951
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
11169
11952
|
VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
|
|
11170
11953
|
VERIFY_PANE_LINES = 200;
|
|
11171
11954
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
11172
11955
|
CODEX_DEBOUNCE_MS = 12e4;
|
|
11173
|
-
INTERCOM_LOG2 =
|
|
11174
|
-
DEBOUNCE_FILE =
|
|
11956
|
+
INTERCOM_LOG2 = path27.join(os14.homedir(), ".exe-os", "intercom.log");
|
|
11957
|
+
DEBOUNCE_FILE = path27.join(SESSION_CACHE, "intercom-debounce.json");
|
|
11175
11958
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
11176
11959
|
BUSY_PATTERN = /[✻✽✶✳·].*…|Running…|• Working|• Ran |• Explored|• Called|esc to interrupt/;
|
|
11177
11960
|
}
|
|
@@ -11440,7 +12223,7 @@ __export(active_agent_exports, {
|
|
|
11440
12223
|
});
|
|
11441
12224
|
import { readFileSync as readFileSync19, writeFileSync as writeFileSync15, mkdirSync as mkdirSync16, unlinkSync as unlinkSync9, readdirSync as readdirSync7 } from "fs";
|
|
11442
12225
|
import { execSync as execSync9 } from "child_process";
|
|
11443
|
-
import
|
|
12226
|
+
import path28 from "path";
|
|
11444
12227
|
function isNameWithOptionalInstance(candidate, baseName) {
|
|
11445
12228
|
if (candidate === baseName) return true;
|
|
11446
12229
|
if (!candidate.startsWith(baseName)) return false;
|
|
@@ -11484,7 +12267,7 @@ function resolveActiveAgentFromTmuxSession(sessionName) {
|
|
|
11484
12267
|
return null;
|
|
11485
12268
|
}
|
|
11486
12269
|
function getMarkerPath() {
|
|
11487
|
-
return
|
|
12270
|
+
return path28.join(CACHE_DIR, `active-agent-${getSessionKey()}.json`);
|
|
11488
12271
|
}
|
|
11489
12272
|
function writeActiveAgent(agentId, agentRole) {
|
|
11490
12273
|
try {
|
|
@@ -11553,14 +12336,14 @@ function getAllActiveAgents() {
|
|
|
11553
12336
|
const key = file.slice("active-agent-".length, -".json".length);
|
|
11554
12337
|
if (key === "undefined") continue;
|
|
11555
12338
|
try {
|
|
11556
|
-
const raw = readFileSync19(
|
|
12339
|
+
const raw = readFileSync19(path28.join(CACHE_DIR, file), "utf8");
|
|
11557
12340
|
const data = JSON.parse(raw);
|
|
11558
12341
|
if (!data.agentId) continue;
|
|
11559
12342
|
if (data.startedAt) {
|
|
11560
12343
|
const age = Date.now() - new Date(data.startedAt).getTime();
|
|
11561
12344
|
if (age > STALE_MS) {
|
|
11562
12345
|
try {
|
|
11563
|
-
unlinkSync9(
|
|
12346
|
+
unlinkSync9(path28.join(CACHE_DIR, file));
|
|
11564
12347
|
} catch {
|
|
11565
12348
|
}
|
|
11566
12349
|
continue;
|
|
@@ -11583,11 +12366,11 @@ function getAllActiveAgents() {
|
|
|
11583
12366
|
function cleanupSessionMarkers() {
|
|
11584
12367
|
const key = getSessionKey();
|
|
11585
12368
|
try {
|
|
11586
|
-
unlinkSync9(
|
|
12369
|
+
unlinkSync9(path28.join(CACHE_DIR, `active-agent-${key}.json`));
|
|
11587
12370
|
} catch {
|
|
11588
12371
|
}
|
|
11589
12372
|
try {
|
|
11590
|
-
unlinkSync9(
|
|
12373
|
+
unlinkSync9(path28.join(CACHE_DIR, "active-agent-undefined.json"));
|
|
11591
12374
|
} catch {
|
|
11592
12375
|
}
|
|
11593
12376
|
}
|
|
@@ -11598,7 +12381,7 @@ var init_active_agent = __esm({
|
|
|
11598
12381
|
init_config();
|
|
11599
12382
|
init_session_key();
|
|
11600
12383
|
init_employees();
|
|
11601
|
-
CACHE_DIR =
|
|
12384
|
+
CACHE_DIR = path28.join(EXE_AI_DIR, "session-cache");
|
|
11602
12385
|
STALE_MS = 24 * 60 * 60 * 1e3;
|
|
11603
12386
|
}
|
|
11604
12387
|
});
|
|
@@ -12228,12 +13011,12 @@ __export(exe_rename_exports, {
|
|
|
12228
13011
|
});
|
|
12229
13012
|
import { readFileSync as readFileSync20, writeFileSync as writeFileSync16, renameSync as renameSync4, unlinkSync as unlinkSync10, existsSync as existsSync22 } from "fs";
|
|
12230
13013
|
import { execSync as execSync10 } from "child_process";
|
|
12231
|
-
import
|
|
13014
|
+
import path29 from "path";
|
|
12232
13015
|
import { homedir as homedir4 } from "os";
|
|
12233
13016
|
async function renameEmployee(oldName, newName, opts = {}) {
|
|
12234
|
-
const rosterPath = opts.rosterPath ??
|
|
12235
|
-
const identityDir = opts.identityDir ??
|
|
12236
|
-
const agentsDir = opts.agentsDir ??
|
|
13017
|
+
const rosterPath = opts.rosterPath ?? path29.join(homedir4(), ".exe-os", "exe-employees.json");
|
|
13018
|
+
const identityDir = opts.identityDir ?? path29.join(homedir4(), ".exe-os", "identity");
|
|
13019
|
+
const agentsDir = opts.agentsDir ?? path29.join(homedir4(), ".claude", "agents");
|
|
12237
13020
|
const validation = validateEmployeeName(newName);
|
|
12238
13021
|
if (!validation.valid) {
|
|
12239
13022
|
return { success: false, error: validation.error };
|
|
@@ -12265,8 +13048,8 @@ async function renameEmployee(oldName, newName, opts = {}) {
|
|
|
12265
13048
|
writeFileSync16(rosterPath, JSON.stringify(employees, null, 2) + "\n", "utf-8");
|
|
12266
13049
|
}
|
|
12267
13050
|
});
|
|
12268
|
-
const oldIdentityPath =
|
|
12269
|
-
const newIdentityPath =
|
|
13051
|
+
const oldIdentityPath = path29.join(identityDir, `${rosterOldName}.md`);
|
|
13052
|
+
const newIdentityPath = path29.join(identityDir, `${newName}.md`);
|
|
12270
13053
|
if (existsSync22(oldIdentityPath)) {
|
|
12271
13054
|
const content = readFileSync20(oldIdentityPath, "utf-8");
|
|
12272
13055
|
const updatedContent = content.replace(
|
|
@@ -12285,8 +13068,8 @@ async function renameEmployee(oldName, newName, opts = {}) {
|
|
|
12285
13068
|
}
|
|
12286
13069
|
});
|
|
12287
13070
|
}
|
|
12288
|
-
const oldAgentPath =
|
|
12289
|
-
const newAgentPath =
|
|
13071
|
+
const oldAgentPath = path29.join(agentsDir, `${rosterOldName}.md`);
|
|
13072
|
+
const newAgentPath = path29.join(agentsDir, `${newName}.md`);
|
|
12290
13073
|
if (existsSync22(oldAgentPath)) {
|
|
12291
13074
|
const agentContent = readFileSync20(oldAgentPath, "utf-8");
|
|
12292
13075
|
renameSync4(oldAgentPath, newAgentPath);
|
|
@@ -12373,9 +13156,9 @@ function removeOldSymlinks(name) {
|
|
|
12373
13156
|
try {
|
|
12374
13157
|
const exeBinPath = findExeBin2();
|
|
12375
13158
|
if (!exeBinPath) return;
|
|
12376
|
-
const binDir =
|
|
13159
|
+
const binDir = path29.dirname(exeBinPath);
|
|
12377
13160
|
for (const suffix of ["", "-opencode"]) {
|
|
12378
|
-
const linkPath =
|
|
13161
|
+
const linkPath = path29.join(binDir, `${name}${suffix}`);
|
|
12379
13162
|
if (existsSync22(linkPath)) {
|
|
12380
13163
|
try {
|
|
12381
13164
|
unlinkSync10(linkPath);
|
|
@@ -12424,10 +13207,10 @@ var init_exe_rename = __esm({
|
|
|
12424
13207
|
import { createWriteStream, createReadStream as createReadStream2, existsSync as existsSync23, unlinkSync as unlinkSync11, renameSync as renameSync5 } from "fs";
|
|
12425
13208
|
import { mkdir as mkdir6 } from "fs/promises";
|
|
12426
13209
|
import { createHash as createHash3 } from "crypto";
|
|
12427
|
-
import
|
|
13210
|
+
import path30 from "path";
|
|
12428
13211
|
async function downloadModel(opts) {
|
|
12429
13212
|
const { destDir, onProgress, fetchFn = globalThis.fetch } = opts;
|
|
12430
|
-
const destPath =
|
|
13213
|
+
const destPath = path30.join(destDir, LOCAL_FILENAME);
|
|
12431
13214
|
const tmpPath = destPath + ".tmp";
|
|
12432
13215
|
await mkdir6(destDir, { recursive: true });
|
|
12433
13216
|
if (existsSync23(destPath)) {
|
|
@@ -12551,8 +13334,8 @@ async function embedDirect(text) {
|
|
|
12551
13334
|
const llamaCpp = await import("node-llama-cpp");
|
|
12552
13335
|
const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
12553
13336
|
const { existsSync: existsSync30 } = await import("fs");
|
|
12554
|
-
const
|
|
12555
|
-
const modelPath =
|
|
13337
|
+
const path45 = await import("path");
|
|
13338
|
+
const modelPath = path45.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
|
|
12556
13339
|
if (!existsSync30(modelPath)) {
|
|
12557
13340
|
throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
|
|
12558
13341
|
}
|
|
@@ -13136,17 +13919,17 @@ import {
|
|
|
13136
13919
|
readdirSync as readdirSync8,
|
|
13137
13920
|
unlinkSync as unlinkSync12
|
|
13138
13921
|
} from "fs";
|
|
13139
|
-
import
|
|
13922
|
+
import path31 from "path";
|
|
13140
13923
|
import { homedir as homedir5 } from "os";
|
|
13141
13924
|
function generateSessionWrappers(packageRoot, homeDir) {
|
|
13142
13925
|
const home = homeDir ?? homedir5();
|
|
13143
|
-
const binDir =
|
|
13144
|
-
const rosterPath =
|
|
13926
|
+
const binDir = path31.join(home, ".exe-os", "bin");
|
|
13927
|
+
const rosterPath = path31.join(home, ".exe-os", "exe-employees.json");
|
|
13145
13928
|
mkdirSync17(binDir, { recursive: true });
|
|
13146
|
-
const exeStartDst =
|
|
13929
|
+
const exeStartDst = path31.join(binDir, "exe-start");
|
|
13147
13930
|
const candidates = [
|
|
13148
|
-
|
|
13149
|
-
|
|
13931
|
+
path31.join(packageRoot, "dist", "bin", "exe-start.sh"),
|
|
13932
|
+
path31.join(packageRoot, "src", "bin", "exe-start.sh")
|
|
13150
13933
|
];
|
|
13151
13934
|
for (const src of candidates) {
|
|
13152
13935
|
if (existsSync24(src)) {
|
|
@@ -13167,7 +13950,7 @@ function generateSessionWrappers(packageRoot, homeDir) {
|
|
|
13167
13950
|
try {
|
|
13168
13951
|
for (const f of readdirSync8(binDir)) {
|
|
13169
13952
|
if (f === "exe-start") continue;
|
|
13170
|
-
const fPath =
|
|
13953
|
+
const fPath = path31.join(binDir, f);
|
|
13171
13954
|
try {
|
|
13172
13955
|
const content = readFileSync21(fPath, "utf8");
|
|
13173
13956
|
if (content.includes("exe-start")) {
|
|
@@ -13184,15 +13967,15 @@ exec "${exeStartDst}" "$0" "$@"
|
|
|
13184
13967
|
`;
|
|
13185
13968
|
for (const emp of employees) {
|
|
13186
13969
|
for (let n = 1; n <= MAX_N; n++) {
|
|
13187
|
-
const wrapperPath =
|
|
13970
|
+
const wrapperPath = path31.join(binDir, `${emp.name}${n}`);
|
|
13188
13971
|
writeFileSync17(wrapperPath, wrapperContent);
|
|
13189
13972
|
chmodSync(wrapperPath, 493);
|
|
13190
13973
|
created++;
|
|
13191
13974
|
}
|
|
13192
13975
|
}
|
|
13193
13976
|
const codexLauncherCandidates = [
|
|
13194
|
-
|
|
13195
|
-
|
|
13977
|
+
path31.join(packageRoot, "dist", "bin", "exe-start-codex.js"),
|
|
13978
|
+
path31.join(packageRoot, "src", "bin", "exe-start-codex.ts")
|
|
13196
13979
|
];
|
|
13197
13980
|
let codexLauncher = null;
|
|
13198
13981
|
for (const c of codexLauncherCandidates) {
|
|
@@ -13203,7 +13986,7 @@ exec "${exeStartDst}" "$0" "$@"
|
|
|
13203
13986
|
}
|
|
13204
13987
|
if (codexLauncher) {
|
|
13205
13988
|
for (const emp of employees) {
|
|
13206
|
-
const wrapperPath =
|
|
13989
|
+
const wrapperPath = path31.join(binDir, `${emp.name}-codex`);
|
|
13207
13990
|
const content = `#!/bin/bash
|
|
13208
13991
|
exec node "${codexLauncher}" --agent ${emp.name} "$@"
|
|
13209
13992
|
`;
|
|
@@ -13226,12 +14009,12 @@ export PATH="${binDir}:$PATH"
|
|
|
13226
14009
|
const shell = process.env.SHELL ?? "/bin/bash";
|
|
13227
14010
|
const profilePaths = [];
|
|
13228
14011
|
if (shell.includes("zsh")) {
|
|
13229
|
-
profilePaths.push(
|
|
14012
|
+
profilePaths.push(path31.join(home, ".zshrc"));
|
|
13230
14013
|
} else if (shell.includes("bash")) {
|
|
13231
|
-
profilePaths.push(
|
|
13232
|
-
profilePaths.push(
|
|
14014
|
+
profilePaths.push(path31.join(home, ".bashrc"));
|
|
14015
|
+
profilePaths.push(path31.join(home, ".bash_profile"));
|
|
13233
14016
|
} else {
|
|
13234
|
-
profilePaths.push(
|
|
14017
|
+
profilePaths.push(path31.join(home, ".profile"));
|
|
13235
14018
|
}
|
|
13236
14019
|
for (const profilePath of profilePaths) {
|
|
13237
14020
|
try {
|
|
@@ -13267,14 +14050,14 @@ __export(setup_wizard_exports, {
|
|
|
13267
14050
|
});
|
|
13268
14051
|
import crypto11 from "crypto";
|
|
13269
14052
|
import { existsSync as existsSync25, mkdirSync as mkdirSync18, readFileSync as readFileSync22, writeFileSync as writeFileSync18, unlinkSync as unlinkSync13 } from "fs";
|
|
13270
|
-
import
|
|
13271
|
-
import
|
|
14053
|
+
import os15 from "os";
|
|
14054
|
+
import path32 from "path";
|
|
13272
14055
|
import { createInterface as createInterface3 } from "readline";
|
|
13273
14056
|
function findPackageRoot2() {
|
|
13274
|
-
let dir =
|
|
13275
|
-
const root =
|
|
14057
|
+
let dir = path32.dirname(new URL(import.meta.url).pathname);
|
|
14058
|
+
const root = path32.parse(dir).root;
|
|
13276
14059
|
while (dir !== root) {
|
|
13277
|
-
const pkgPath =
|
|
14060
|
+
const pkgPath = path32.join(dir, "package.json");
|
|
13278
14061
|
if (existsSync25(pkgPath)) {
|
|
13279
14062
|
try {
|
|
13280
14063
|
const pkg = JSON.parse(readFileSync22(pkgPath, "utf-8"));
|
|
@@ -13282,7 +14065,7 @@ function findPackageRoot2() {
|
|
|
13282
14065
|
} catch {
|
|
13283
14066
|
}
|
|
13284
14067
|
}
|
|
13285
|
-
dir =
|
|
14068
|
+
dir = path32.dirname(dir);
|
|
13286
14069
|
}
|
|
13287
14070
|
return null;
|
|
13288
14071
|
}
|
|
@@ -13294,7 +14077,7 @@ function loadSetupState() {
|
|
|
13294
14077
|
}
|
|
13295
14078
|
}
|
|
13296
14079
|
function saveSetupState(state) {
|
|
13297
|
-
mkdirSync18(
|
|
14080
|
+
mkdirSync18(path32.dirname(SETUP_STATE_PATH), { recursive: true });
|
|
13298
14081
|
writeFileSync18(SETUP_STATE_PATH, JSON.stringify(state, null, 2));
|
|
13299
14082
|
}
|
|
13300
14083
|
function clearSetupState() {
|
|
@@ -13314,10 +14097,10 @@ function ask2(rl, prompt) {
|
|
|
13314
14097
|
});
|
|
13315
14098
|
}
|
|
13316
14099
|
function getAvailableMemoryGB() {
|
|
13317
|
-
return
|
|
14100
|
+
return os15.freemem() / (1024 * 1024 * 1024);
|
|
13318
14101
|
}
|
|
13319
14102
|
function getTotalMemoryGB() {
|
|
13320
|
-
return
|
|
14103
|
+
return os15.totalmem() / (1024 * 1024 * 1024);
|
|
13321
14104
|
}
|
|
13322
14105
|
function isLowMemory() {
|
|
13323
14106
|
return getAvailableMemoryGB() < 2;
|
|
@@ -13328,7 +14111,7 @@ async function validateModel(log) {
|
|
|
13328
14111
|
if (totalGB <= 8 || isLowMemory()) {
|
|
13329
14112
|
log(`System memory: ${totalGB.toFixed(0)}GB total, ${freeGB.toFixed(1)}GB free`);
|
|
13330
14113
|
log("Skipping in-memory model validation (low memory \u2014 will validate on first use).");
|
|
13331
|
-
const modelPath =
|
|
14114
|
+
const modelPath = path32.join(MODELS_DIR, LOCAL_FILENAME);
|
|
13332
14115
|
if (existsSync25(modelPath)) {
|
|
13333
14116
|
const { statSync: statSync2 } = await import("fs");
|
|
13334
14117
|
const size = statSync2(modelPath).size;
|
|
@@ -13584,7 +14367,7 @@ async function runSetupWizard(opts = {}) {
|
|
|
13584
14367
|
await saveConfig(config);
|
|
13585
14368
|
log("");
|
|
13586
14369
|
try {
|
|
13587
|
-
const claudeJsonPath =
|
|
14370
|
+
const claudeJsonPath = path32.join(os15.homedir(), ".claude.json");
|
|
13588
14371
|
let claudeJson = {};
|
|
13589
14372
|
try {
|
|
13590
14373
|
claudeJson = JSON.parse(readFileSync22(claudeJsonPath, "utf8"));
|
|
@@ -13592,7 +14375,7 @@ async function runSetupWizard(opts = {}) {
|
|
|
13592
14375
|
}
|
|
13593
14376
|
if (!claudeJson.projects) claudeJson.projects = {};
|
|
13594
14377
|
const projects = claudeJson.projects;
|
|
13595
|
-
for (const dir of [process.cwd(),
|
|
14378
|
+
for (const dir of [process.cwd(), os15.homedir()]) {
|
|
13596
14379
|
if (!projects[dir]) projects[dir] = {};
|
|
13597
14380
|
projects[dir].hasTrustDialogAccepted = true;
|
|
13598
14381
|
}
|
|
@@ -13610,7 +14393,7 @@ async function runSetupWizard(opts = {}) {
|
|
|
13610
14393
|
const prefs = { ...existingPrefs };
|
|
13611
14394
|
log("=== Config Defaults ===");
|
|
13612
14395
|
log("");
|
|
13613
|
-
const ghosttyDetected = existsSync25(
|
|
14396
|
+
const ghosttyDetected = existsSync25(path32.join(os15.homedir(), ".config", "ghostty")) || existsSync25(path32.join(os15.homedir(), "Library", "Application Support", "com.mitchellh.ghostty"));
|
|
13614
14397
|
if (ghosttyDetected) {
|
|
13615
14398
|
const ghosttyAnswer = await ask2(rl, "Detected Ghostty terminal. Use exe-os Ghostty defaults? (Y/n) ");
|
|
13616
14399
|
prefs.ghostty = ghosttyAnswer.toLowerCase() !== "n";
|
|
@@ -13754,7 +14537,7 @@ async function runSetupWizard(opts = {}) {
|
|
|
13754
14537
|
const cooIdentityContent = getIdentityTemplate("coo");
|
|
13755
14538
|
if (cooIdentityContent) {
|
|
13756
14539
|
const cooIdPath = identityPath2(cooName);
|
|
13757
|
-
mkdirSync18(
|
|
14540
|
+
mkdirSync18(path32.dirname(cooIdPath), { recursive: true });
|
|
13758
14541
|
const replaced = cooIdentityContent.replace(/agent_id:\s*exe/g, `agent_id: ${cooName}`).replace(/\$\{agent_id\}/g, cooName);
|
|
13759
14542
|
writeFileSync18(cooIdPath, replaced, "utf-8");
|
|
13760
14543
|
}
|
|
@@ -13850,7 +14633,7 @@ async function runSetupWizard(opts = {}) {
|
|
|
13850
14633
|
const ctoIdentityContent = getIdentityTemplate("cto");
|
|
13851
14634
|
if (ctoIdentityContent) {
|
|
13852
14635
|
const ctoIdPath = identityPath2(ctoName);
|
|
13853
|
-
mkdirSync18(
|
|
14636
|
+
mkdirSync18(path32.dirname(ctoIdPath), { recursive: true });
|
|
13854
14637
|
const replaced = ctoIdentityContent.replace(/agent_id:\s*\w+/g, `agent_id: ${ctoName}`).replace(/\$\{agent_id\}/g, ctoName);
|
|
13855
14638
|
writeFileSync18(ctoIdPath, replaced, "utf-8");
|
|
13856
14639
|
}
|
|
@@ -13873,7 +14656,7 @@ async function runSetupWizard(opts = {}) {
|
|
|
13873
14656
|
const cmoIdentityContent = getIdentityTemplate("cmo");
|
|
13874
14657
|
if (cmoIdentityContent) {
|
|
13875
14658
|
const cmoIdPath = identityPath2(cmoName);
|
|
13876
|
-
mkdirSync18(
|
|
14659
|
+
mkdirSync18(path32.dirname(cmoIdPath), { recursive: true });
|
|
13877
14660
|
const replaced = cmoIdentityContent.replace(/agent_id:\s*\w+/g, `agent_id: ${cmoName}`).replace(/\$\{agent_id\}/g, cmoName);
|
|
13878
14661
|
writeFileSync18(cmoIdPath, replaced, "utf-8");
|
|
13879
14662
|
}
|
|
@@ -13897,7 +14680,7 @@ async function runSetupWizard(opts = {}) {
|
|
|
13897
14680
|
log(`Session shortcuts generated (${cooName}1, ${cooName}2, ...)`);
|
|
13898
14681
|
}
|
|
13899
14682
|
if (wrapResult.pathConfigured) {
|
|
13900
|
-
const binDir =
|
|
14683
|
+
const binDir = path32.join(os15.homedir(), ".exe-os", "bin");
|
|
13901
14684
|
process.env.PATH = `${binDir}:${process.env.PATH ?? ""}`;
|
|
13902
14685
|
pathJustConfigured = true;
|
|
13903
14686
|
}
|
|
@@ -13940,7 +14723,7 @@ async function runSetupWizard(opts = {}) {
|
|
|
13940
14723
|
const pkgRoot2 = findPackageRoot2();
|
|
13941
14724
|
if (pkgRoot2) {
|
|
13942
14725
|
try {
|
|
13943
|
-
version = JSON.parse(readFileSync22(
|
|
14726
|
+
version = JSON.parse(readFileSync22(path32.join(pkgRoot2, "package.json"), "utf-8")).version;
|
|
13944
14727
|
} catch {
|
|
13945
14728
|
}
|
|
13946
14729
|
}
|
|
@@ -13974,16 +14757,16 @@ var init_setup_wizard = __esm({
|
|
|
13974
14757
|
init_config();
|
|
13975
14758
|
init_keychain();
|
|
13976
14759
|
init_model_downloader();
|
|
13977
|
-
SETUP_STATE_PATH =
|
|
14760
|
+
SETUP_STATE_PATH = path32.join(os15.homedir(), ".exe-os", "setup-state.json");
|
|
13978
14761
|
}
|
|
13979
14762
|
});
|
|
13980
14763
|
|
|
13981
14764
|
// src/lib/update-check.ts
|
|
13982
14765
|
import { execSync as execSync11 } from "child_process";
|
|
13983
14766
|
import { readFileSync as readFileSync23 } from "fs";
|
|
13984
|
-
import
|
|
14767
|
+
import path33 from "path";
|
|
13985
14768
|
function getLocalVersion(packageRoot) {
|
|
13986
|
-
const pkgPath =
|
|
14769
|
+
const pkgPath = path33.join(packageRoot, "package.json");
|
|
13987
14770
|
const pkg = JSON.parse(readFileSync23(pkgPath, "utf-8"));
|
|
13988
14771
|
return pkg.version;
|
|
13989
14772
|
}
|
|
@@ -18508,8 +19291,8 @@ var init_ErrorOverview = __esm({
|
|
|
18508
19291
|
"use strict";
|
|
18509
19292
|
init_Box();
|
|
18510
19293
|
init_Text();
|
|
18511
|
-
cleanupPath = (
|
|
18512
|
-
return
|
|
19294
|
+
cleanupPath = (path45) => {
|
|
19295
|
+
return path45?.replace(`file://${cwd()}/`, "");
|
|
18513
19296
|
};
|
|
18514
19297
|
stackUtils = new StackUtils({
|
|
18515
19298
|
cwd: cwd(),
|
|
@@ -22963,10 +23746,10 @@ var init_hooks = __esm({
|
|
|
22963
23746
|
});
|
|
22964
23747
|
|
|
22965
23748
|
// src/runtime/safety-checks.ts
|
|
22966
|
-
import
|
|
22967
|
-
import
|
|
23749
|
+
import path34 from "path";
|
|
23750
|
+
import os16 from "os";
|
|
22968
23751
|
function checkPathSafety(filePath) {
|
|
22969
|
-
const resolved =
|
|
23752
|
+
const resolved = path34.resolve(filePath);
|
|
22970
23753
|
for (const { pattern, reason } of BYPASS_IMMUNE_PATTERNS) {
|
|
22971
23754
|
const matches = typeof pattern === "function" ? pattern(resolved) : pattern.test(resolved);
|
|
22972
23755
|
if (matches) {
|
|
@@ -22976,7 +23759,7 @@ function checkPathSafety(filePath) {
|
|
|
22976
23759
|
return { safe: true, bypassImmune: true };
|
|
22977
23760
|
}
|
|
22978
23761
|
function checkReadPathSafety(filePath) {
|
|
22979
|
-
const resolved =
|
|
23762
|
+
const resolved = path34.resolve(filePath);
|
|
22980
23763
|
const credPatterns = BYPASS_IMMUNE_PATTERNS.filter(
|
|
22981
23764
|
(p) => typeof p.pattern !== "function" && (p.reason.includes("secrets") || p.reason.includes("Private key") || p.reason.includes("Credential"))
|
|
22982
23765
|
);
|
|
@@ -22991,7 +23774,7 @@ var HOME, BYPASS_IMMUNE_PATTERNS;
|
|
|
22991
23774
|
var init_safety_checks = __esm({
|
|
22992
23775
|
"src/runtime/safety-checks.ts"() {
|
|
22993
23776
|
"use strict";
|
|
22994
|
-
HOME =
|
|
23777
|
+
HOME = os16.homedir();
|
|
22995
23778
|
BYPASS_IMMUNE_PATTERNS = [
|
|
22996
23779
|
{
|
|
22997
23780
|
pattern: /\/\.git\/hooks\//,
|
|
@@ -23002,11 +23785,11 @@ var init_safety_checks = __esm({
|
|
|
23002
23785
|
reason: "Git config can set hooks and command execution"
|
|
23003
23786
|
},
|
|
23004
23787
|
{
|
|
23005
|
-
pattern: (p) => p.startsWith(
|
|
23788
|
+
pattern: (p) => p.startsWith(path34.join(HOME, ".claude")),
|
|
23006
23789
|
reason: "Claude configuration files are protected"
|
|
23007
23790
|
},
|
|
23008
23791
|
{
|
|
23009
|
-
pattern: (p) => p.startsWith(
|
|
23792
|
+
pattern: (p) => p.startsWith(path34.join(HOME, ".exe-os")),
|
|
23010
23793
|
reason: "exe-os configuration files are protected"
|
|
23011
23794
|
},
|
|
23012
23795
|
{
|
|
@@ -23023,7 +23806,7 @@ var init_safety_checks = __esm({
|
|
|
23023
23806
|
},
|
|
23024
23807
|
{
|
|
23025
23808
|
pattern: (p) => {
|
|
23026
|
-
const name =
|
|
23809
|
+
const name = path34.basename(p);
|
|
23027
23810
|
return [".bashrc", ".zshrc", ".profile", ".bash_profile", ".zprofile", ".zshenv"].includes(name);
|
|
23028
23811
|
},
|
|
23029
23812
|
reason: "Shell configuration files can execute arbitrary code on login"
|
|
@@ -23050,7 +23833,7 @@ __export(file_read_exports, {
|
|
|
23050
23833
|
FileReadTool: () => FileReadTool
|
|
23051
23834
|
});
|
|
23052
23835
|
import fs3 from "fs/promises";
|
|
23053
|
-
import
|
|
23836
|
+
import path35 from "path";
|
|
23054
23837
|
import { z } from "zod";
|
|
23055
23838
|
function isBinary(buf) {
|
|
23056
23839
|
for (let i = 0; i < buf.length; i++) {
|
|
@@ -23086,7 +23869,7 @@ var init_file_read = __esm({
|
|
|
23086
23869
|
return { behavior: "allow" };
|
|
23087
23870
|
},
|
|
23088
23871
|
async call(input, context) {
|
|
23089
|
-
const filePath =
|
|
23872
|
+
const filePath = path35.isAbsolute(input.file_path) ? input.file_path : path35.resolve(context.cwd, input.file_path);
|
|
23090
23873
|
let stat2;
|
|
23091
23874
|
try {
|
|
23092
23875
|
stat2 = await fs3.stat(filePath);
|
|
@@ -23126,7 +23909,7 @@ __export(glob_exports, {
|
|
|
23126
23909
|
GlobTool: () => GlobTool
|
|
23127
23910
|
});
|
|
23128
23911
|
import fs4 from "fs/promises";
|
|
23129
|
-
import
|
|
23912
|
+
import path36 from "path";
|
|
23130
23913
|
import { z as z2 } from "zod";
|
|
23131
23914
|
async function walkDir(dir, maxDepth = 10) {
|
|
23132
23915
|
const results = [];
|
|
@@ -23142,7 +23925,7 @@ async function walkDir(dir, maxDepth = 10) {
|
|
|
23142
23925
|
if (entry.isDirectory() && (entry.name === "node_modules" || entry.name === ".git")) {
|
|
23143
23926
|
continue;
|
|
23144
23927
|
}
|
|
23145
|
-
const fullPath =
|
|
23928
|
+
const fullPath = path36.join(current, entry.name);
|
|
23146
23929
|
if (entry.isDirectory()) {
|
|
23147
23930
|
await walk(fullPath, depth + 1);
|
|
23148
23931
|
} else {
|
|
@@ -23176,11 +23959,11 @@ var init_glob = __esm({
|
|
|
23176
23959
|
inputSchema: inputSchema2,
|
|
23177
23960
|
isReadOnly: true,
|
|
23178
23961
|
async call(input, context) {
|
|
23179
|
-
const baseDir = input.path ?
|
|
23962
|
+
const baseDir = input.path ? path36.isAbsolute(input.path) ? input.path : path36.resolve(context.cwd, input.path) : context.cwd;
|
|
23180
23963
|
try {
|
|
23181
23964
|
const entries = await walkDir(baseDir);
|
|
23182
23965
|
const matched = entries.filter(
|
|
23183
|
-
(e) => simpleGlobMatch(
|
|
23966
|
+
(e) => simpleGlobMatch(path36.relative(baseDir, e.path), input.pattern)
|
|
23184
23967
|
);
|
|
23185
23968
|
matched.sort((a, b) => b.mtime - a.mtime);
|
|
23186
23969
|
if (matched.length === 0) {
|
|
@@ -23206,7 +23989,7 @@ __export(grep_exports, {
|
|
|
23206
23989
|
});
|
|
23207
23990
|
import { spawn as spawn2 } from "child_process";
|
|
23208
23991
|
import fs5 from "fs/promises";
|
|
23209
|
-
import
|
|
23992
|
+
import path37 from "path";
|
|
23210
23993
|
import { z as z3 } from "zod";
|
|
23211
23994
|
function runRipgrep(input, searchPath, context) {
|
|
23212
23995
|
return new Promise((resolve, reject) => {
|
|
@@ -23260,7 +24043,7 @@ async function nodeGrep(input, searchPath) {
|
|
|
23260
24043
|
}
|
|
23261
24044
|
for (const entry of entries) {
|
|
23262
24045
|
if (entry.name === "node_modules" || entry.name === ".git") continue;
|
|
23263
|
-
const fullPath =
|
|
24046
|
+
const fullPath = path37.join(dir, entry.name);
|
|
23264
24047
|
if (entry.isDirectory()) {
|
|
23265
24048
|
await walk(fullPath);
|
|
23266
24049
|
} else {
|
|
@@ -23306,7 +24089,7 @@ var init_grep = __esm({
|
|
|
23306
24089
|
inputSchema: inputSchema3,
|
|
23307
24090
|
isReadOnly: true,
|
|
23308
24091
|
async call(input, context) {
|
|
23309
|
-
const searchPath = input.path ?
|
|
24092
|
+
const searchPath = input.path ? path37.isAbsolute(input.path) ? input.path : path37.resolve(context.cwd, input.path) : context.cwd;
|
|
23310
24093
|
try {
|
|
23311
24094
|
const result = await runRipgrep(input, searchPath, context);
|
|
23312
24095
|
return result;
|
|
@@ -23331,7 +24114,7 @@ __export(file_write_exports, {
|
|
|
23331
24114
|
FileWriteTool: () => FileWriteTool
|
|
23332
24115
|
});
|
|
23333
24116
|
import fs6 from "fs/promises";
|
|
23334
|
-
import
|
|
24117
|
+
import path38 from "path";
|
|
23335
24118
|
import { z as z4 } from "zod";
|
|
23336
24119
|
var inputSchema4, FileWriteTool;
|
|
23337
24120
|
var init_file_write = __esm({
|
|
@@ -23359,8 +24142,8 @@ var init_file_write = __esm({
|
|
|
23359
24142
|
return { behavior: "allow" };
|
|
23360
24143
|
},
|
|
23361
24144
|
async call(input, context) {
|
|
23362
|
-
const filePath =
|
|
23363
|
-
const dir =
|
|
24145
|
+
const filePath = path38.isAbsolute(input.file_path) ? input.file_path : path38.resolve(context.cwd, input.file_path);
|
|
24146
|
+
const dir = path38.dirname(filePath);
|
|
23364
24147
|
await fs6.mkdir(dir, { recursive: true });
|
|
23365
24148
|
await fs6.writeFile(filePath, input.content, "utf-8");
|
|
23366
24149
|
return {
|
|
@@ -23378,7 +24161,7 @@ __export(file_edit_exports, {
|
|
|
23378
24161
|
FileEditTool: () => FileEditTool
|
|
23379
24162
|
});
|
|
23380
24163
|
import fs7 from "fs/promises";
|
|
23381
|
-
import
|
|
24164
|
+
import path39 from "path";
|
|
23382
24165
|
import { z as z5 } from "zod";
|
|
23383
24166
|
function countOccurrences(haystack, needle) {
|
|
23384
24167
|
let count = 0;
|
|
@@ -23419,7 +24202,7 @@ var init_file_edit = __esm({
|
|
|
23419
24202
|
return { behavior: "allow" };
|
|
23420
24203
|
},
|
|
23421
24204
|
async call(input, context) {
|
|
23422
|
-
const filePath =
|
|
24205
|
+
const filePath = path39.isAbsolute(input.file_path) ? input.file_path : path39.resolve(context.cwd, input.file_path);
|
|
23423
24206
|
let content;
|
|
23424
24207
|
try {
|
|
23425
24208
|
content = await fs7.readFile(filePath, "utf-8");
|
|
@@ -23661,7 +24444,7 @@ var init_bash = __esm({
|
|
|
23661
24444
|
// src/tui/views/CommandCenter.tsx
|
|
23662
24445
|
import { useState as useState6, useEffect as useEffect8, useMemo as useMemo4, useCallback as useCallback4, useRef as useRef4 } from "react";
|
|
23663
24446
|
import TextInput from "ink-text-input";
|
|
23664
|
-
import
|
|
24447
|
+
import path40 from "path";
|
|
23665
24448
|
import { homedir as homedir6 } from "os";
|
|
23666
24449
|
import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
23667
24450
|
function CommandCenterView({
|
|
@@ -23910,7 +24693,7 @@ function CommandCenterView({
|
|
|
23910
24693
|
const demoEntries = DEMO_PROJECTS.map((p) => ({
|
|
23911
24694
|
projectName: p.projectName,
|
|
23912
24695
|
exeSession: p.exeSession,
|
|
23913
|
-
projectDir:
|
|
24696
|
+
projectDir: path40.join(homedir6(), p.projectName),
|
|
23914
24697
|
employeeCount: p.employees.length,
|
|
23915
24698
|
activeCount: p.employees.filter((e) => e.status === "active").length,
|
|
23916
24699
|
memoryCount: p.employees.length * 4e3,
|
|
@@ -24914,7 +25697,7 @@ var init_useOrchestrator = __esm({
|
|
|
24914
25697
|
|
|
24915
25698
|
// src/tui/views/Sessions.tsx
|
|
24916
25699
|
import React19, { useState as useState9, useEffect as useEffect11, useCallback as useCallback6 } from "react";
|
|
24917
|
-
import
|
|
25700
|
+
import path41 from "path";
|
|
24918
25701
|
import { homedir as homedir7 } from "os";
|
|
24919
25702
|
import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
24920
25703
|
function isCoordinatorEntry(entry) {
|
|
@@ -24952,7 +25735,7 @@ function SessionsView({
|
|
|
24952
25735
|
if (demo) {
|
|
24953
25736
|
setProjects(DEMO_PROJECTS.map((p) => ({
|
|
24954
25737
|
...p,
|
|
24955
|
-
projectDir:
|
|
25738
|
+
projectDir: path41.join(homedir7(), p.projectName),
|
|
24956
25739
|
employees: p.employees.map((e) => ({ ...e, attached: e.status === "active" }))
|
|
24957
25740
|
})));
|
|
24958
25741
|
return;
|
|
@@ -26870,8 +27653,8 @@ __export(wiki_client_exports, {
|
|
|
26870
27653
|
listDocuments: () => listDocuments,
|
|
26871
27654
|
listWorkspaces: () => listWorkspaces
|
|
26872
27655
|
});
|
|
26873
|
-
async function wikiFetch(config,
|
|
26874
|
-
const url = `${config.baseUrl}/api/v1${
|
|
27656
|
+
async function wikiFetch(config, path45, method = "GET", body) {
|
|
27657
|
+
const url = `${config.baseUrl}/api/v1${path45}`;
|
|
26875
27658
|
const headers = {
|
|
26876
27659
|
Authorization: `Bearer ${config.apiKey}`,
|
|
26877
27660
|
"Content-Type": "application/json"
|
|
@@ -26904,7 +27687,7 @@ async function wikiFetch(config, path44, method = "GET", body) {
|
|
|
26904
27687
|
}
|
|
26905
27688
|
}
|
|
26906
27689
|
if (!response.ok) {
|
|
26907
|
-
throw new Error(`Wiki API ${method} ${
|
|
27690
|
+
throw new Error(`Wiki API ${method} ${path45}: ${response.status} ${response.statusText}`);
|
|
26908
27691
|
}
|
|
26909
27692
|
return response.json();
|
|
26910
27693
|
} finally {
|
|
@@ -27538,8 +28321,8 @@ function SettingsView({ onBack }) {
|
|
|
27538
28321
|
let version = "unknown";
|
|
27539
28322
|
try {
|
|
27540
28323
|
const { readFileSync: readFileSync27 } = await import("fs");
|
|
27541
|
-
const { createRequire } = await import("module");
|
|
27542
|
-
const require2 =
|
|
28324
|
+
const { createRequire: createRequire2 } = await import("module");
|
|
28325
|
+
const require2 = createRequire2(import.meta.url);
|
|
27543
28326
|
const pkgPath = require2.resolve("@askexenow/exe-os/package.json");
|
|
27544
28327
|
const pkg = JSON.parse(readFileSync27(pkgPath, "utf8"));
|
|
27545
28328
|
version = pkg.version;
|
|
@@ -28349,11 +29132,11 @@ __export(installer_exports2, {
|
|
|
28349
29132
|
});
|
|
28350
29133
|
import { readFile as readFile6, writeFile as writeFile7, mkdir as mkdir7 } from "fs/promises";
|
|
28351
29134
|
import { existsSync as existsSync27, readFileSync as readFileSync25 } from "fs";
|
|
28352
|
-
import
|
|
28353
|
-
import
|
|
28354
|
-
async function registerOpenCodeMcp(packageRoot, homeDir =
|
|
28355
|
-
const configDir =
|
|
28356
|
-
const configPath =
|
|
29135
|
+
import path42 from "path";
|
|
29136
|
+
import os17 from "os";
|
|
29137
|
+
async function registerOpenCodeMcp(packageRoot, homeDir = os17.homedir()) {
|
|
29138
|
+
const configDir = path42.join(homeDir, ".config", "opencode");
|
|
29139
|
+
const configPath = path42.join(configDir, "opencode.json");
|
|
28357
29140
|
await mkdir7(configDir, { recursive: true });
|
|
28358
29141
|
let config = {};
|
|
28359
29142
|
if (existsSync27(configPath)) {
|
|
@@ -28368,7 +29151,7 @@ async function registerOpenCodeMcp(packageRoot, homeDir = os16.homedir()) {
|
|
|
28368
29151
|
}
|
|
28369
29152
|
const newEntry = {
|
|
28370
29153
|
type: "local",
|
|
28371
|
-
command: ["node",
|
|
29154
|
+
command: ["node", path42.join(packageRoot, "dist", "mcp", "server.js")],
|
|
28372
29155
|
enabled: true
|
|
28373
29156
|
};
|
|
28374
29157
|
const current = config.mcp["exe-os"];
|
|
@@ -28382,9 +29165,9 @@ async function registerOpenCodeMcp(packageRoot, homeDir = os16.homedir()) {
|
|
|
28382
29165
|
await writeFile7(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
28383
29166
|
return true;
|
|
28384
29167
|
}
|
|
28385
|
-
async function installOpenCodePlugin(packageRoot, homeDir =
|
|
28386
|
-
const pluginDir =
|
|
28387
|
-
const pluginPath =
|
|
29168
|
+
async function installOpenCodePlugin(packageRoot, homeDir = os17.homedir()) {
|
|
29169
|
+
const pluginDir = path42.join(homeDir, ".config", "opencode", "plugins");
|
|
29170
|
+
const pluginPath = path42.join(pluginDir, "exe-os.mjs");
|
|
28388
29171
|
await mkdir7(pluginDir, { recursive: true });
|
|
28389
29172
|
const pluginContent = PLUGIN_TEMPLATE.replace(
|
|
28390
29173
|
/__PACKAGE_ROOT__/g,
|
|
@@ -28399,9 +29182,9 @@ async function installOpenCodePlugin(packageRoot, homeDir = os16.homedir()) {
|
|
|
28399
29182
|
await writeFile7(pluginPath, pluginContent);
|
|
28400
29183
|
return true;
|
|
28401
29184
|
}
|
|
28402
|
-
function verifyOpenCodeHooks(homeDir =
|
|
28403
|
-
const configPath =
|
|
28404
|
-
const pluginPath =
|
|
29185
|
+
function verifyOpenCodeHooks(homeDir = os17.homedir()) {
|
|
29186
|
+
const configPath = path42.join(homeDir, ".config", "opencode", "opencode.json");
|
|
29187
|
+
const pluginPath = path42.join(homeDir, ".config", "opencode", "plugins", "exe-os.mjs");
|
|
28405
29188
|
if (!existsSync27(configPath)) return false;
|
|
28406
29189
|
try {
|
|
28407
29190
|
const config = JSON.parse(readFileSync25(configPath, "utf-8"));
|
|
@@ -28443,13 +29226,13 @@ __export(installer_exports3, {
|
|
|
28443
29226
|
});
|
|
28444
29227
|
import { readFile as readFile7, writeFile as writeFile8, mkdir as mkdir8 } from "fs/promises";
|
|
28445
29228
|
import { existsSync as existsSync28 } from "fs";
|
|
28446
|
-
import
|
|
28447
|
-
import
|
|
28448
|
-
async function mergeCodexHooks(packageRoot, homeDir =
|
|
28449
|
-
const codexDir =
|
|
28450
|
-
const hooksPath =
|
|
28451
|
-
const logsDir =
|
|
28452
|
-
const hookLogPath =
|
|
29229
|
+
import path43 from "path";
|
|
29230
|
+
import os18 from "os";
|
|
29231
|
+
async function mergeCodexHooks(packageRoot, homeDir = os18.homedir()) {
|
|
29232
|
+
const codexDir = path43.join(homeDir, ".codex");
|
|
29233
|
+
const hooksPath = path43.join(codexDir, "hooks.json");
|
|
29234
|
+
const logsDir = path43.join(homeDir, ".exe-os", "logs");
|
|
29235
|
+
const hookLogPath = path43.join(logsDir, "hooks.log");
|
|
28453
29236
|
const logSuffix = ` 2>> "${hookLogPath}"`;
|
|
28454
29237
|
await mkdir8(codexDir, { recursive: true });
|
|
28455
29238
|
await mkdir8(logsDir, { recursive: true });
|
|
@@ -28471,7 +29254,7 @@ async function mergeCodexHooks(packageRoot, homeDir = os17.homedir()) {
|
|
|
28471
29254
|
hooks: [
|
|
28472
29255
|
{
|
|
28473
29256
|
type: "command",
|
|
28474
|
-
command: `node "${
|
|
29257
|
+
command: `node "${path43.join(packageRoot, "dist", "hooks", "session-start.js")}"${logSuffix}`,
|
|
28475
29258
|
timeout: 30,
|
|
28476
29259
|
statusMessage: "exe-os: loading memory brief"
|
|
28477
29260
|
}
|
|
@@ -28486,11 +29269,11 @@ async function mergeCodexHooks(packageRoot, homeDir = os17.homedir()) {
|
|
|
28486
29269
|
hooks: [
|
|
28487
29270
|
{
|
|
28488
29271
|
type: "command",
|
|
28489
|
-
command: `node "${
|
|
29272
|
+
command: `node "${path43.join(packageRoot, "dist", "hooks", "ingest.js")}"${logSuffix}`
|
|
28490
29273
|
},
|
|
28491
29274
|
{
|
|
28492
29275
|
type: "command",
|
|
28493
|
-
command: `node "${
|
|
29276
|
+
command: `node "${path43.join(packageRoot, "dist", "hooks", "error-recall.js")}"${logSuffix}`
|
|
28494
29277
|
}
|
|
28495
29278
|
]
|
|
28496
29279
|
},
|
|
@@ -28502,11 +29285,11 @@ async function mergeCodexHooks(packageRoot, homeDir = os17.homedir()) {
|
|
|
28502
29285
|
hooks: [
|
|
28503
29286
|
{
|
|
28504
29287
|
type: "command",
|
|
28505
|
-
command: `node "${
|
|
29288
|
+
command: `node "${path43.join(packageRoot, "dist", "hooks", "prompt-submit.js")}"${logSuffix}`
|
|
28506
29289
|
},
|
|
28507
29290
|
{
|
|
28508
29291
|
type: "command",
|
|
28509
|
-
command: `node "${
|
|
29292
|
+
command: `node "${path43.join(packageRoot, "dist", "hooks", "exe-heartbeat-hook.js")}"${logSuffix}`,
|
|
28510
29293
|
timeout: 5
|
|
28511
29294
|
}
|
|
28512
29295
|
]
|
|
@@ -28519,7 +29302,7 @@ async function mergeCodexHooks(packageRoot, homeDir = os17.homedir()) {
|
|
|
28519
29302
|
hooks: [
|
|
28520
29303
|
{
|
|
28521
29304
|
type: "command",
|
|
28522
|
-
command: `node "${
|
|
29305
|
+
command: `node "${path43.join(packageRoot, "dist", "hooks", "stop.js")}"${logSuffix}`
|
|
28523
29306
|
}
|
|
28524
29307
|
]
|
|
28525
29308
|
},
|
|
@@ -28532,7 +29315,7 @@ async function mergeCodexHooks(packageRoot, homeDir = os17.homedir()) {
|
|
|
28532
29315
|
hooks: [
|
|
28533
29316
|
{
|
|
28534
29317
|
type: "command",
|
|
28535
|
-
command: `node "${
|
|
29318
|
+
command: `node "${path43.join(packageRoot, "dist", "hooks", "pre-tool-use.js")}"${logSuffix}`
|
|
28536
29319
|
}
|
|
28537
29320
|
]
|
|
28538
29321
|
},
|
|
@@ -28563,15 +29346,15 @@ async function mergeCodexHooks(packageRoot, homeDir = os17.homedir()) {
|
|
|
28563
29346
|
await writeFile8(hooksPath, JSON.stringify(hooksJson, null, 2) + "\n");
|
|
28564
29347
|
return { added, skipped };
|
|
28565
29348
|
}
|
|
28566
|
-
function verifyCodexHooks(homeDir =
|
|
28567
|
-
const hooksPath =
|
|
29349
|
+
function verifyCodexHooks(homeDir = os18.homedir()) {
|
|
29350
|
+
const hooksPath = path43.join(homeDir, ".codex", "hooks.json");
|
|
28568
29351
|
if (!existsSync28(hooksPath)) return false;
|
|
28569
29352
|
try {
|
|
28570
29353
|
const hooksJson = JSON.parse(
|
|
28571
29354
|
__require("fs").readFileSync(hooksPath, "utf-8")
|
|
28572
29355
|
);
|
|
28573
29356
|
if (!hooksJson.hooks) return false;
|
|
28574
|
-
const required = ["SessionStart", "PostToolUse", "UserPromptSubmit", "Stop"];
|
|
29357
|
+
const required = ["SessionStart", "PostToolUse", "UserPromptSubmit", "Stop", "PreToolUse"];
|
|
28575
29358
|
for (const event of required) {
|
|
28576
29359
|
const groups = hooksJson.hooks[event];
|
|
28577
29360
|
if (!groups || !groups.some(
|
|
@@ -28585,11 +29368,11 @@ function verifyCodexHooks(homeDir = os17.homedir()) {
|
|
|
28585
29368
|
return false;
|
|
28586
29369
|
}
|
|
28587
29370
|
}
|
|
28588
|
-
async function installCodexStatusLine(homeDir =
|
|
29371
|
+
async function installCodexStatusLine(homeDir = os18.homedir()) {
|
|
28589
29372
|
const prefs = loadPreferences(homeDir);
|
|
28590
29373
|
if (prefs.codexStatusLine === false) return "opted-out";
|
|
28591
|
-
const codexDir =
|
|
28592
|
-
const configPath =
|
|
29374
|
+
const codexDir = path43.join(homeDir, ".codex");
|
|
29375
|
+
const configPath = path43.join(codexDir, "config.toml");
|
|
28593
29376
|
await mkdir8(codexDir, { recursive: true });
|
|
28594
29377
|
let content = "";
|
|
28595
29378
|
if (existsSync28(configPath)) {
|
|
@@ -28641,12 +29424,12 @@ var init_installer3 = __esm({
|
|
|
28641
29424
|
|
|
28642
29425
|
// src/bin/cli.ts
|
|
28643
29426
|
import { existsSync as existsSync29, readFileSync as readFileSync26, writeFileSync as writeFileSync19, readdirSync as readdirSync9, rmSync } from "fs";
|
|
28644
|
-
import
|
|
28645
|
-
import
|
|
29427
|
+
import path44 from "path";
|
|
29428
|
+
import os19 from "os";
|
|
28646
29429
|
var args = process.argv.slice(2);
|
|
28647
29430
|
if (args.includes("--version") || args.includes("-v")) {
|
|
28648
29431
|
try {
|
|
28649
|
-
const pkgPath =
|
|
29432
|
+
const pkgPath = path44.join(path44.dirname(new URL(import.meta.url).pathname), "..", "..", "package.json");
|
|
28650
29433
|
const pkg = JSON.parse(readFileSync26(pkgPath, "utf8"));
|
|
28651
29434
|
console.log(pkg.version);
|
|
28652
29435
|
} catch {
|
|
@@ -28811,8 +29594,8 @@ ID: ${result.id}`);
|
|
|
28811
29594
|
});
|
|
28812
29595
|
await init_App2().then(() => App_exports);
|
|
28813
29596
|
} else {
|
|
28814
|
-
const claudeDir =
|
|
28815
|
-
const settingsPath =
|
|
29597
|
+
const claudeDir = path44.join(os19.homedir(), ".claude");
|
|
29598
|
+
const settingsPath = path44.join(claudeDir, "settings.json");
|
|
28816
29599
|
const hasClaudeCode = existsSync29(settingsPath) && (() => {
|
|
28817
29600
|
try {
|
|
28818
29601
|
const raw = readFileSync26(settingsPath, "utf8");
|
|
@@ -28825,7 +29608,7 @@ ID: ${result.id}`);
|
|
|
28825
29608
|
const { DEFAULT_COORDINATOR_TEMPLATE_NAME: DEFAULT_COORDINATOR_TEMPLATE_NAME2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
28826
29609
|
let cooName = DEFAULT_COORDINATOR_TEMPLATE_NAME2;
|
|
28827
29610
|
try {
|
|
28828
|
-
const rosterPath =
|
|
29611
|
+
const rosterPath = path44.join(os19.homedir(), ".exe-os", "exe-employees.json");
|
|
28829
29612
|
if (existsSync29(rosterPath)) {
|
|
28830
29613
|
const roster = JSON.parse(readFileSync26(rosterPath, "utf8"));
|
|
28831
29614
|
const coo = roster.find((e) => e.role === "COO");
|
|
@@ -28891,9 +29674,9 @@ async function runCodexInstall() {
|
|
|
28891
29674
|
}
|
|
28892
29675
|
}
|
|
28893
29676
|
async function runClaudeCheck() {
|
|
28894
|
-
const claudeDir =
|
|
28895
|
-
const settingsPath =
|
|
28896
|
-
const claudeJsonPath =
|
|
29677
|
+
const claudeDir = path44.join(os19.homedir(), ".claude");
|
|
29678
|
+
const settingsPath = path44.join(claudeDir, "settings.json");
|
|
29679
|
+
const claudeJsonPath = path44.join(os19.homedir(), ".claude.json");
|
|
28897
29680
|
let ok = true;
|
|
28898
29681
|
if (existsSync29(settingsPath)) {
|
|
28899
29682
|
let settings;
|
|
@@ -28946,7 +29729,7 @@ async function runClaudeCheck() {
|
|
|
28946
29729
|
console.log("\x1B[31m\u2717\x1B[0m claude.json not found");
|
|
28947
29730
|
ok = false;
|
|
28948
29731
|
}
|
|
28949
|
-
const skillsDir =
|
|
29732
|
+
const skillsDir = path44.join(claudeDir, "skills");
|
|
28950
29733
|
if (existsSync29(skillsDir)) {
|
|
28951
29734
|
console.log("\x1B[32m\u2713\x1B[0m Slash skills directory exists");
|
|
28952
29735
|
} else {
|
|
@@ -28963,11 +29746,11 @@ async function runClaudeCheck() {
|
|
|
28963
29746
|
async function runClaudeUninstall(flags = []) {
|
|
28964
29747
|
const dryRun = flags.includes("--dry-run");
|
|
28965
29748
|
const purge = flags.includes("--purge");
|
|
28966
|
-
const homeDir =
|
|
28967
|
-
const claudeDir =
|
|
28968
|
-
const settingsPath =
|
|
28969
|
-
const claudeJsonPath =
|
|
28970
|
-
const exeOsDir =
|
|
29749
|
+
const homeDir = os19.homedir();
|
|
29750
|
+
const claudeDir = path44.join(homeDir, ".claude");
|
|
29751
|
+
const settingsPath = path44.join(claudeDir, "settings.json");
|
|
29752
|
+
const claudeJsonPath = path44.join(homeDir, ".claude.json");
|
|
29753
|
+
const exeOsDir = path44.join(homeDir, ".exe-os");
|
|
28971
29754
|
let removed = 0;
|
|
28972
29755
|
const log = (msg) => console.log(dryRun ? `[dry-run] ${msg}` : msg);
|
|
28973
29756
|
let settings = {};
|
|
@@ -29048,14 +29831,14 @@ async function runClaudeUninstall(flags = []) {
|
|
|
29048
29831
|
}
|
|
29049
29832
|
}
|
|
29050
29833
|
}
|
|
29051
|
-
const skillsDir =
|
|
29834
|
+
const skillsDir = path44.join(claudeDir, "skills");
|
|
29052
29835
|
if (existsSync29(skillsDir)) {
|
|
29053
29836
|
let skillCount = 0;
|
|
29054
29837
|
try {
|
|
29055
29838
|
const entries = readdirSync9(skillsDir);
|
|
29056
29839
|
for (const entry of entries) {
|
|
29057
29840
|
if (entry.startsWith("exe")) {
|
|
29058
|
-
const fullPath =
|
|
29841
|
+
const fullPath = path44.join(skillsDir, entry);
|
|
29059
29842
|
if (!dryRun) rmSync(fullPath, { recursive: true, force: true });
|
|
29060
29843
|
skillCount++;
|
|
29061
29844
|
}
|
|
@@ -29067,7 +29850,7 @@ async function runClaudeUninstall(flags = []) {
|
|
|
29067
29850
|
removed++;
|
|
29068
29851
|
}
|
|
29069
29852
|
}
|
|
29070
|
-
const claudeMdPath =
|
|
29853
|
+
const claudeMdPath = path44.join(claudeDir, "CLAUDE.md");
|
|
29071
29854
|
if (existsSync29(claudeMdPath)) {
|
|
29072
29855
|
const content = readFileSync26(claudeMdPath, "utf8");
|
|
29073
29856
|
const startMarker = "<!-- exe-os:orchestration-start -->";
|
|
@@ -29081,13 +29864,13 @@ async function runClaudeUninstall(flags = []) {
|
|
|
29081
29864
|
removed++;
|
|
29082
29865
|
}
|
|
29083
29866
|
}
|
|
29084
|
-
const agentsDir =
|
|
29867
|
+
const agentsDir = path44.join(claudeDir, "agents");
|
|
29085
29868
|
if (existsSync29(agentsDir)) {
|
|
29086
29869
|
let agentCount = 0;
|
|
29087
29870
|
try {
|
|
29088
29871
|
const entries = readdirSync9(agentsDir).filter((f) => f.endsWith(".md"));
|
|
29089
29872
|
let knownNames = /* @__PURE__ */ new Set();
|
|
29090
|
-
const rosterPath =
|
|
29873
|
+
const rosterPath = path44.join(exeOsDir, "exe-employees.json");
|
|
29091
29874
|
if (existsSync29(rosterPath)) {
|
|
29092
29875
|
try {
|
|
29093
29876
|
const roster = JSON.parse(readFileSync26(rosterPath, "utf8"));
|
|
@@ -29098,7 +29881,7 @@ async function runClaudeUninstall(flags = []) {
|
|
|
29098
29881
|
for (const entry of entries) {
|
|
29099
29882
|
const name = entry.replace(/\.md$/, "");
|
|
29100
29883
|
if (knownNames.has(name)) {
|
|
29101
|
-
if (!dryRun) rmSync(
|
|
29884
|
+
if (!dryRun) rmSync(path44.join(agentsDir, entry), { force: true });
|
|
29102
29885
|
agentCount++;
|
|
29103
29886
|
}
|
|
29104
29887
|
}
|
|
@@ -29109,13 +29892,13 @@ async function runClaudeUninstall(flags = []) {
|
|
|
29109
29892
|
removed++;
|
|
29110
29893
|
}
|
|
29111
29894
|
}
|
|
29112
|
-
const projectsDir =
|
|
29895
|
+
const projectsDir = path44.join(claudeDir, "projects");
|
|
29113
29896
|
if (existsSync29(projectsDir)) {
|
|
29114
29897
|
let projectCount = 0;
|
|
29115
29898
|
try {
|
|
29116
29899
|
const projects = readdirSync9(projectsDir);
|
|
29117
29900
|
for (const proj of projects) {
|
|
29118
|
-
const projSettings =
|
|
29901
|
+
const projSettings = path44.join(projectsDir, proj, "settings.json");
|
|
29119
29902
|
if (!existsSync29(projSettings)) continue;
|
|
29120
29903
|
try {
|
|
29121
29904
|
const pSettings = JSON.parse(readFileSync26(projSettings, "utf8"));
|
|
@@ -29152,9 +29935,9 @@ async function runClaudeUninstall(flags = []) {
|
|
|
29152
29935
|
};
|
|
29153
29936
|
const exeBinPath = findExeBin3();
|
|
29154
29937
|
if (!exeBinPath) throw new Error("exe-os not found in PATH");
|
|
29155
|
-
const binDir =
|
|
29938
|
+
const binDir = path44.dirname(exeBinPath);
|
|
29156
29939
|
let symlinkCount = 0;
|
|
29157
|
-
const rosterPath =
|
|
29940
|
+
const rosterPath = path44.join(exeOsDir, "exe-employees.json");
|
|
29158
29941
|
if (existsSync29(rosterPath)) {
|
|
29159
29942
|
const roster = JSON.parse(readFileSync26(rosterPath, "utf8"));
|
|
29160
29943
|
const { DEFAULT_COORDINATOR_TEMPLATE_NAME: DEFAULT_COORDINATOR_TEMPLATE_NAME2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
@@ -29162,7 +29945,7 @@ async function runClaudeUninstall(flags = []) {
|
|
|
29162
29945
|
for (const emp of roster) {
|
|
29163
29946
|
if (emp.name === coordinatorName) continue;
|
|
29164
29947
|
for (const suffix of ["", "-opencode"]) {
|
|
29165
|
-
const linkPath =
|
|
29948
|
+
const linkPath = path44.join(binDir, `${emp.name}${suffix}`);
|
|
29166
29949
|
if (existsSync29(linkPath)) {
|
|
29167
29950
|
if (!dryRun) rmSync(linkPath, { force: true });
|
|
29168
29951
|
symlinkCount++;
|
|
@@ -29201,7 +29984,7 @@ async function checkForUpdateOnBoot() {
|
|
|
29201
29984
|
const config = await loadConfig2();
|
|
29202
29985
|
if (!config.autoUpdate.checkOnBoot) return;
|
|
29203
29986
|
const { checkForUpdate: checkForUpdate2 } = await Promise.resolve().then(() => (init_update(), update_exports));
|
|
29204
|
-
const packageRoot =
|
|
29987
|
+
const packageRoot = path44.resolve(
|
|
29205
29988
|
new URL("../..", import.meta.url).pathname
|
|
29206
29989
|
);
|
|
29207
29990
|
const result = checkForUpdate2(packageRoot);
|
|
@@ -29261,7 +30044,7 @@ async function runActivate(key) {
|
|
|
29261
30044
|
const idTemplate = getIdentityTemplate(identityKey);
|
|
29262
30045
|
if (idTemplate) {
|
|
29263
30046
|
const idPath = identityPath2(name);
|
|
29264
|
-
const dir =
|
|
30047
|
+
const dir = path44.dirname(idPath);
|
|
29265
30048
|
if (!fs8.existsSync(dir)) fs8.mkdirSync(dir, { recursive: true });
|
|
29266
30049
|
fs8.writeFileSync(idPath, idTemplate.replace(/^agent_id: \w+/m, `agent_id: ${name}`), "utf-8");
|
|
29267
30050
|
}
|