@askexenow/exe-os 0.9.6 → 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 +668 -37
- package/dist/bin/cli.js +1399 -607
- 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 +795 -155
- package/dist/bin/exe-call.js +209 -138
- package/dist/bin/exe-cloud.js +35 -12
- package/dist/bin/exe-dispatch.js +703 -72
- 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 +1064 -273
- package/dist/bin/exe-heartbeat.js +676 -45
- 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 +845 -152
- 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 +668 -37
- package/dist/bin/exe-team.js +635 -13
- package/dist/bin/git-sweep.js +731 -91
- 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 +735 -95
- 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 +1038 -247
- package/dist/hooks/bug-report-worker.js +902 -172
- package/dist/hooks/commit-complete.js +729 -89
- package/dist/hooks/error-recall.js +776 -93
- package/dist/hooks/exe-heartbeat-hook.js +85 -71
- package/dist/hooks/ingest-worker.js +851 -158
- 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 +685 -45
- package/dist/hooks/pre-compact.js +729 -89
- package/dist/hooks/pre-tool-use.js +883 -127
- package/dist/hooks/prompt-ingest-worker.js +758 -83
- package/dist/hooks/prompt-submit.js +1071 -321
- package/dist/hooks/response-ingest-worker.js +758 -83
- package/dist/hooks/session-end.js +732 -92
- package/dist/hooks/session-start.js +1042 -209
- package/dist/hooks/stop.js +691 -51
- package/dist/hooks/subagent-stop.js +685 -45
- package/dist/hooks/summary-worker.js +827 -134
- package/dist/index.js +1026 -234
- 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 +905 -164
- package/dist/lib/hybrid-search.js +771 -88
- package/dist/lib/identity.js +27 -7
- package/dist/lib/messaging.js +66 -30
- 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 +109 -73
- package/dist/lib/tmux-routing.js +98 -62
- package/dist/lib/token-spend.js +26 -6
- package/dist/mcp/server.js +1807 -472
- 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 +301 -166
- 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 +206 -40
- package/dist/mcp/tools/send-message.js +69 -33
- package/dist/mcp/tools/update-task.js +86 -50
- package/dist/runtime/index.js +731 -91
- package/dist/tui/App.js +864 -125
- 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;
|
|
2669
|
+
}
|
|
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);
|
|
1894
2700
|
}
|
|
1895
|
-
|
|
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;
|
|
@@ -10571,15 +11354,24 @@ function getDispatchedBy(sessionKey) {
|
|
|
10571
11354
|
function resolveExeSession() {
|
|
10572
11355
|
const mySession = getMySession();
|
|
10573
11356
|
if (!mySession) return null;
|
|
11357
|
+
const fromSessionName = extractRootExe(mySession);
|
|
10574
11358
|
try {
|
|
10575
11359
|
const key = getSessionKey();
|
|
10576
11360
|
const parentExe = getParentExe(key);
|
|
10577
11361
|
if (parentExe) {
|
|
10578
|
-
|
|
11362
|
+
const fromCache = extractRootExe(parentExe) ?? parentExe;
|
|
11363
|
+
if (fromSessionName && fromCache !== fromSessionName) {
|
|
11364
|
+
process.stderr.write(
|
|
11365
|
+
`[tmux-routing] WARN: cache says "${fromCache}" but session name says "${fromSessionName}". Trusting session name.
|
|
11366
|
+
`
|
|
11367
|
+
);
|
|
11368
|
+
return fromSessionName;
|
|
11369
|
+
}
|
|
11370
|
+
return fromCache;
|
|
10579
11371
|
}
|
|
10580
11372
|
} catch {
|
|
10581
11373
|
}
|
|
10582
|
-
return
|
|
11374
|
+
return fromSessionName ?? mySession;
|
|
10583
11375
|
}
|
|
10584
11376
|
function isEmployeeAlive(sessionName) {
|
|
10585
11377
|
return getTransport().isAlive(sessionName);
|
|
@@ -10737,7 +11529,7 @@ function sendIntercom(targetSession) {
|
|
|
10737
11529
|
try {
|
|
10738
11530
|
const rawAgent = targetSession.split("-")[0] ?? targetSession;
|
|
10739
11531
|
const agent = baseAgentName(rawAgent);
|
|
10740
|
-
const markerPath =
|
|
11532
|
+
const markerPath = path27.join(SESSION_CACHE, `current-task-${agent}.json`);
|
|
10741
11533
|
if (existsSync21(markerPath)) {
|
|
10742
11534
|
logIntercom(`SKIP \u2192 ${targetSession} (has in_progress task marker \u2014 will auto-chain)`);
|
|
10743
11535
|
return "debounced";
|
|
@@ -10747,7 +11539,7 @@ function sendIntercom(targetSession) {
|
|
|
10747
11539
|
try {
|
|
10748
11540
|
const rawAgent = targetSession.split("-")[0] ?? targetSession;
|
|
10749
11541
|
const agent = baseAgentName(rawAgent);
|
|
10750
|
-
const taskDir =
|
|
11542
|
+
const taskDir = path27.join(process.cwd(), "exe", agent);
|
|
10751
11543
|
if (existsSync21(taskDir)) {
|
|
10752
11544
|
const files = readdirSync6(taskDir).filter(
|
|
10753
11545
|
(f) => f.endsWith(".md") && f !== "DONE.txt"
|
|
@@ -10881,8 +11673,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
10881
11673
|
const transport = getTransport();
|
|
10882
11674
|
const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
|
|
10883
11675
|
const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
|
|
10884
|
-
const logDir =
|
|
10885
|
-
const logFile =
|
|
11676
|
+
const logDir = path27.join(os14.homedir(), ".exe-os", "session-logs");
|
|
11677
|
+
const logFile = path27.join(logDir, `${instanceLabel}-${Date.now()}.log`);
|
|
10886
11678
|
if (!existsSync21(logDir)) {
|
|
10887
11679
|
mkdirSync15(logDir, { recursive: true });
|
|
10888
11680
|
}
|
|
@@ -10890,14 +11682,14 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
10890
11682
|
let cleanupSuffix = "";
|
|
10891
11683
|
try {
|
|
10892
11684
|
const thisFile = fileURLToPath4(import.meta.url);
|
|
10893
|
-
const cleanupScript =
|
|
11685
|
+
const cleanupScript = path27.join(path27.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
|
|
10894
11686
|
if (existsSync21(cleanupScript)) {
|
|
10895
11687
|
cleanupSuffix = `; ${process.execPath} "${cleanupScript}" "${employeeName}" "${exeSession}"`;
|
|
10896
11688
|
}
|
|
10897
11689
|
} catch {
|
|
10898
11690
|
}
|
|
10899
11691
|
try {
|
|
10900
|
-
const claudeJsonPath =
|
|
11692
|
+
const claudeJsonPath = path27.join(os14.homedir(), ".claude.json");
|
|
10901
11693
|
let claudeJson = {};
|
|
10902
11694
|
try {
|
|
10903
11695
|
claudeJson = JSON.parse(readFileSync18(claudeJsonPath, "utf8"));
|
|
@@ -10912,10 +11704,10 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
10912
11704
|
} catch {
|
|
10913
11705
|
}
|
|
10914
11706
|
try {
|
|
10915
|
-
const settingsDir =
|
|
11707
|
+
const settingsDir = path27.join(os14.homedir(), ".claude", "projects");
|
|
10916
11708
|
const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
|
|
10917
|
-
const projSettingsDir =
|
|
10918
|
-
const settingsPath =
|
|
11709
|
+
const projSettingsDir = path27.join(settingsDir, normalizedKey);
|
|
11710
|
+
const settingsPath = path27.join(projSettingsDir, "settings.json");
|
|
10919
11711
|
let settings = {};
|
|
10920
11712
|
try {
|
|
10921
11713
|
settings = JSON.parse(readFileSync18(settingsPath, "utf8"));
|
|
@@ -10962,8 +11754,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
10962
11754
|
let behaviorsFlag = "";
|
|
10963
11755
|
let legacyFallbackWarned = false;
|
|
10964
11756
|
if (!useExeAgent && !useBinSymlink) {
|
|
10965
|
-
const identityPath2 =
|
|
10966
|
-
|
|
11757
|
+
const identityPath2 = path27.join(
|
|
11758
|
+
os14.homedir(),
|
|
10967
11759
|
".exe-os",
|
|
10968
11760
|
"identity",
|
|
10969
11761
|
`${employeeName}.md`
|
|
@@ -10978,7 +11770,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
10978
11770
|
}
|
|
10979
11771
|
const behaviorsFile = exportBehaviorsSync(
|
|
10980
11772
|
employeeName,
|
|
10981
|
-
|
|
11773
|
+
path27.basename(spawnCwd),
|
|
10982
11774
|
sessionName
|
|
10983
11775
|
);
|
|
10984
11776
|
if (behaviorsFile) {
|
|
@@ -10993,9 +11785,9 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
10993
11785
|
}
|
|
10994
11786
|
let sessionContextFlag = "";
|
|
10995
11787
|
try {
|
|
10996
|
-
const ctxDir =
|
|
11788
|
+
const ctxDir = path27.join(os14.homedir(), ".exe-os", "session-cache");
|
|
10997
11789
|
mkdirSync15(ctxDir, { recursive: true });
|
|
10998
|
-
const ctxFile =
|
|
11790
|
+
const ctxFile = path27.join(ctxDir, `session-context-${sessionName}.md`);
|
|
10999
11791
|
const ctxContent = [
|
|
11000
11792
|
`## Session Context`,
|
|
11001
11793
|
`You are running in tmux session: ${sessionName}.`,
|
|
@@ -11079,7 +11871,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
11079
11871
|
transport.pipeLog(sessionName, logFile);
|
|
11080
11872
|
try {
|
|
11081
11873
|
const mySession = getMySession();
|
|
11082
|
-
const dispatchInfo =
|
|
11874
|
+
const dispatchInfo = path27.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
|
|
11083
11875
|
writeFileSync14(dispatchInfo, JSON.stringify({
|
|
11084
11876
|
dispatchedBy: mySession,
|
|
11085
11877
|
rootExe: exeSession,
|
|
@@ -11154,15 +11946,15 @@ var init_tmux_routing = __esm({
|
|
|
11154
11946
|
init_intercom_queue();
|
|
11155
11947
|
init_plan_limits();
|
|
11156
11948
|
init_employees();
|
|
11157
|
-
SPAWN_LOCK_DIR =
|
|
11158
|
-
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");
|
|
11159
11951
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
11160
11952
|
VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
|
|
11161
11953
|
VERIFY_PANE_LINES = 200;
|
|
11162
11954
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
11163
11955
|
CODEX_DEBOUNCE_MS = 12e4;
|
|
11164
|
-
INTERCOM_LOG2 =
|
|
11165
|
-
DEBOUNCE_FILE =
|
|
11956
|
+
INTERCOM_LOG2 = path27.join(os14.homedir(), ".exe-os", "intercom.log");
|
|
11957
|
+
DEBOUNCE_FILE = path27.join(SESSION_CACHE, "intercom-debounce.json");
|
|
11166
11958
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
11167
11959
|
BUSY_PATTERN = /[✻✽✶✳·].*…|Running…|• Working|• Ran |• Explored|• Called|esc to interrupt/;
|
|
11168
11960
|
}
|
|
@@ -11431,7 +12223,7 @@ __export(active_agent_exports, {
|
|
|
11431
12223
|
});
|
|
11432
12224
|
import { readFileSync as readFileSync19, writeFileSync as writeFileSync15, mkdirSync as mkdirSync16, unlinkSync as unlinkSync9, readdirSync as readdirSync7 } from "fs";
|
|
11433
12225
|
import { execSync as execSync9 } from "child_process";
|
|
11434
|
-
import
|
|
12226
|
+
import path28 from "path";
|
|
11435
12227
|
function isNameWithOptionalInstance(candidate, baseName) {
|
|
11436
12228
|
if (candidate === baseName) return true;
|
|
11437
12229
|
if (!candidate.startsWith(baseName)) return false;
|
|
@@ -11475,7 +12267,7 @@ function resolveActiveAgentFromTmuxSession(sessionName) {
|
|
|
11475
12267
|
return null;
|
|
11476
12268
|
}
|
|
11477
12269
|
function getMarkerPath() {
|
|
11478
|
-
return
|
|
12270
|
+
return path28.join(CACHE_DIR, `active-agent-${getSessionKey()}.json`);
|
|
11479
12271
|
}
|
|
11480
12272
|
function writeActiveAgent(agentId, agentRole) {
|
|
11481
12273
|
try {
|
|
@@ -11544,14 +12336,14 @@ function getAllActiveAgents() {
|
|
|
11544
12336
|
const key = file.slice("active-agent-".length, -".json".length);
|
|
11545
12337
|
if (key === "undefined") continue;
|
|
11546
12338
|
try {
|
|
11547
|
-
const raw = readFileSync19(
|
|
12339
|
+
const raw = readFileSync19(path28.join(CACHE_DIR, file), "utf8");
|
|
11548
12340
|
const data = JSON.parse(raw);
|
|
11549
12341
|
if (!data.agentId) continue;
|
|
11550
12342
|
if (data.startedAt) {
|
|
11551
12343
|
const age = Date.now() - new Date(data.startedAt).getTime();
|
|
11552
12344
|
if (age > STALE_MS) {
|
|
11553
12345
|
try {
|
|
11554
|
-
unlinkSync9(
|
|
12346
|
+
unlinkSync9(path28.join(CACHE_DIR, file));
|
|
11555
12347
|
} catch {
|
|
11556
12348
|
}
|
|
11557
12349
|
continue;
|
|
@@ -11574,11 +12366,11 @@ function getAllActiveAgents() {
|
|
|
11574
12366
|
function cleanupSessionMarkers() {
|
|
11575
12367
|
const key = getSessionKey();
|
|
11576
12368
|
try {
|
|
11577
|
-
unlinkSync9(
|
|
12369
|
+
unlinkSync9(path28.join(CACHE_DIR, `active-agent-${key}.json`));
|
|
11578
12370
|
} catch {
|
|
11579
12371
|
}
|
|
11580
12372
|
try {
|
|
11581
|
-
unlinkSync9(
|
|
12373
|
+
unlinkSync9(path28.join(CACHE_DIR, "active-agent-undefined.json"));
|
|
11582
12374
|
} catch {
|
|
11583
12375
|
}
|
|
11584
12376
|
}
|
|
@@ -11589,7 +12381,7 @@ var init_active_agent = __esm({
|
|
|
11589
12381
|
init_config();
|
|
11590
12382
|
init_session_key();
|
|
11591
12383
|
init_employees();
|
|
11592
|
-
CACHE_DIR =
|
|
12384
|
+
CACHE_DIR = path28.join(EXE_AI_DIR, "session-cache");
|
|
11593
12385
|
STALE_MS = 24 * 60 * 60 * 1e3;
|
|
11594
12386
|
}
|
|
11595
12387
|
});
|
|
@@ -12219,12 +13011,12 @@ __export(exe_rename_exports, {
|
|
|
12219
13011
|
});
|
|
12220
13012
|
import { readFileSync as readFileSync20, writeFileSync as writeFileSync16, renameSync as renameSync4, unlinkSync as unlinkSync10, existsSync as existsSync22 } from "fs";
|
|
12221
13013
|
import { execSync as execSync10 } from "child_process";
|
|
12222
|
-
import
|
|
13014
|
+
import path29 from "path";
|
|
12223
13015
|
import { homedir as homedir4 } from "os";
|
|
12224
13016
|
async function renameEmployee(oldName, newName, opts = {}) {
|
|
12225
|
-
const rosterPath = opts.rosterPath ??
|
|
12226
|
-
const identityDir = opts.identityDir ??
|
|
12227
|
-
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");
|
|
12228
13020
|
const validation = validateEmployeeName(newName);
|
|
12229
13021
|
if (!validation.valid) {
|
|
12230
13022
|
return { success: false, error: validation.error };
|
|
@@ -12256,8 +13048,8 @@ async function renameEmployee(oldName, newName, opts = {}) {
|
|
|
12256
13048
|
writeFileSync16(rosterPath, JSON.stringify(employees, null, 2) + "\n", "utf-8");
|
|
12257
13049
|
}
|
|
12258
13050
|
});
|
|
12259
|
-
const oldIdentityPath =
|
|
12260
|
-
const newIdentityPath =
|
|
13051
|
+
const oldIdentityPath = path29.join(identityDir, `${rosterOldName}.md`);
|
|
13052
|
+
const newIdentityPath = path29.join(identityDir, `${newName}.md`);
|
|
12261
13053
|
if (existsSync22(oldIdentityPath)) {
|
|
12262
13054
|
const content = readFileSync20(oldIdentityPath, "utf-8");
|
|
12263
13055
|
const updatedContent = content.replace(
|
|
@@ -12276,8 +13068,8 @@ async function renameEmployee(oldName, newName, opts = {}) {
|
|
|
12276
13068
|
}
|
|
12277
13069
|
});
|
|
12278
13070
|
}
|
|
12279
|
-
const oldAgentPath =
|
|
12280
|
-
const newAgentPath =
|
|
13071
|
+
const oldAgentPath = path29.join(agentsDir, `${rosterOldName}.md`);
|
|
13072
|
+
const newAgentPath = path29.join(agentsDir, `${newName}.md`);
|
|
12281
13073
|
if (existsSync22(oldAgentPath)) {
|
|
12282
13074
|
const agentContent = readFileSync20(oldAgentPath, "utf-8");
|
|
12283
13075
|
renameSync4(oldAgentPath, newAgentPath);
|
|
@@ -12364,9 +13156,9 @@ function removeOldSymlinks(name) {
|
|
|
12364
13156
|
try {
|
|
12365
13157
|
const exeBinPath = findExeBin2();
|
|
12366
13158
|
if (!exeBinPath) return;
|
|
12367
|
-
const binDir =
|
|
13159
|
+
const binDir = path29.dirname(exeBinPath);
|
|
12368
13160
|
for (const suffix of ["", "-opencode"]) {
|
|
12369
|
-
const linkPath =
|
|
13161
|
+
const linkPath = path29.join(binDir, `${name}${suffix}`);
|
|
12370
13162
|
if (existsSync22(linkPath)) {
|
|
12371
13163
|
try {
|
|
12372
13164
|
unlinkSync10(linkPath);
|
|
@@ -12415,10 +13207,10 @@ var init_exe_rename = __esm({
|
|
|
12415
13207
|
import { createWriteStream, createReadStream as createReadStream2, existsSync as existsSync23, unlinkSync as unlinkSync11, renameSync as renameSync5 } from "fs";
|
|
12416
13208
|
import { mkdir as mkdir6 } from "fs/promises";
|
|
12417
13209
|
import { createHash as createHash3 } from "crypto";
|
|
12418
|
-
import
|
|
13210
|
+
import path30 from "path";
|
|
12419
13211
|
async function downloadModel(opts) {
|
|
12420
13212
|
const { destDir, onProgress, fetchFn = globalThis.fetch } = opts;
|
|
12421
|
-
const destPath =
|
|
13213
|
+
const destPath = path30.join(destDir, LOCAL_FILENAME);
|
|
12422
13214
|
const tmpPath = destPath + ".tmp";
|
|
12423
13215
|
await mkdir6(destDir, { recursive: true });
|
|
12424
13216
|
if (existsSync23(destPath)) {
|
|
@@ -12542,8 +13334,8 @@ async function embedDirect(text) {
|
|
|
12542
13334
|
const llamaCpp = await import("node-llama-cpp");
|
|
12543
13335
|
const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
12544
13336
|
const { existsSync: existsSync30 } = await import("fs");
|
|
12545
|
-
const
|
|
12546
|
-
const modelPath =
|
|
13337
|
+
const path45 = await import("path");
|
|
13338
|
+
const modelPath = path45.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
|
|
12547
13339
|
if (!existsSync30(modelPath)) {
|
|
12548
13340
|
throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
|
|
12549
13341
|
}
|
|
@@ -13127,17 +13919,17 @@ import {
|
|
|
13127
13919
|
readdirSync as readdirSync8,
|
|
13128
13920
|
unlinkSync as unlinkSync12
|
|
13129
13921
|
} from "fs";
|
|
13130
|
-
import
|
|
13922
|
+
import path31 from "path";
|
|
13131
13923
|
import { homedir as homedir5 } from "os";
|
|
13132
13924
|
function generateSessionWrappers(packageRoot, homeDir) {
|
|
13133
13925
|
const home = homeDir ?? homedir5();
|
|
13134
|
-
const binDir =
|
|
13135
|
-
const rosterPath =
|
|
13926
|
+
const binDir = path31.join(home, ".exe-os", "bin");
|
|
13927
|
+
const rosterPath = path31.join(home, ".exe-os", "exe-employees.json");
|
|
13136
13928
|
mkdirSync17(binDir, { recursive: true });
|
|
13137
|
-
const exeStartDst =
|
|
13929
|
+
const exeStartDst = path31.join(binDir, "exe-start");
|
|
13138
13930
|
const candidates = [
|
|
13139
|
-
|
|
13140
|
-
|
|
13931
|
+
path31.join(packageRoot, "dist", "bin", "exe-start.sh"),
|
|
13932
|
+
path31.join(packageRoot, "src", "bin", "exe-start.sh")
|
|
13141
13933
|
];
|
|
13142
13934
|
for (const src of candidates) {
|
|
13143
13935
|
if (existsSync24(src)) {
|
|
@@ -13158,7 +13950,7 @@ function generateSessionWrappers(packageRoot, homeDir) {
|
|
|
13158
13950
|
try {
|
|
13159
13951
|
for (const f of readdirSync8(binDir)) {
|
|
13160
13952
|
if (f === "exe-start") continue;
|
|
13161
|
-
const fPath =
|
|
13953
|
+
const fPath = path31.join(binDir, f);
|
|
13162
13954
|
try {
|
|
13163
13955
|
const content = readFileSync21(fPath, "utf8");
|
|
13164
13956
|
if (content.includes("exe-start")) {
|
|
@@ -13175,15 +13967,15 @@ exec "${exeStartDst}" "$0" "$@"
|
|
|
13175
13967
|
`;
|
|
13176
13968
|
for (const emp of employees) {
|
|
13177
13969
|
for (let n = 1; n <= MAX_N; n++) {
|
|
13178
|
-
const wrapperPath =
|
|
13970
|
+
const wrapperPath = path31.join(binDir, `${emp.name}${n}`);
|
|
13179
13971
|
writeFileSync17(wrapperPath, wrapperContent);
|
|
13180
13972
|
chmodSync(wrapperPath, 493);
|
|
13181
13973
|
created++;
|
|
13182
13974
|
}
|
|
13183
13975
|
}
|
|
13184
13976
|
const codexLauncherCandidates = [
|
|
13185
|
-
|
|
13186
|
-
|
|
13977
|
+
path31.join(packageRoot, "dist", "bin", "exe-start-codex.js"),
|
|
13978
|
+
path31.join(packageRoot, "src", "bin", "exe-start-codex.ts")
|
|
13187
13979
|
];
|
|
13188
13980
|
let codexLauncher = null;
|
|
13189
13981
|
for (const c of codexLauncherCandidates) {
|
|
@@ -13194,7 +13986,7 @@ exec "${exeStartDst}" "$0" "$@"
|
|
|
13194
13986
|
}
|
|
13195
13987
|
if (codexLauncher) {
|
|
13196
13988
|
for (const emp of employees) {
|
|
13197
|
-
const wrapperPath =
|
|
13989
|
+
const wrapperPath = path31.join(binDir, `${emp.name}-codex`);
|
|
13198
13990
|
const content = `#!/bin/bash
|
|
13199
13991
|
exec node "${codexLauncher}" --agent ${emp.name} "$@"
|
|
13200
13992
|
`;
|
|
@@ -13217,12 +14009,12 @@ export PATH="${binDir}:$PATH"
|
|
|
13217
14009
|
const shell = process.env.SHELL ?? "/bin/bash";
|
|
13218
14010
|
const profilePaths = [];
|
|
13219
14011
|
if (shell.includes("zsh")) {
|
|
13220
|
-
profilePaths.push(
|
|
14012
|
+
profilePaths.push(path31.join(home, ".zshrc"));
|
|
13221
14013
|
} else if (shell.includes("bash")) {
|
|
13222
|
-
profilePaths.push(
|
|
13223
|
-
profilePaths.push(
|
|
14014
|
+
profilePaths.push(path31.join(home, ".bashrc"));
|
|
14015
|
+
profilePaths.push(path31.join(home, ".bash_profile"));
|
|
13224
14016
|
} else {
|
|
13225
|
-
profilePaths.push(
|
|
14017
|
+
profilePaths.push(path31.join(home, ".profile"));
|
|
13226
14018
|
}
|
|
13227
14019
|
for (const profilePath of profilePaths) {
|
|
13228
14020
|
try {
|
|
@@ -13258,14 +14050,14 @@ __export(setup_wizard_exports, {
|
|
|
13258
14050
|
});
|
|
13259
14051
|
import crypto11 from "crypto";
|
|
13260
14052
|
import { existsSync as existsSync25, mkdirSync as mkdirSync18, readFileSync as readFileSync22, writeFileSync as writeFileSync18, unlinkSync as unlinkSync13 } from "fs";
|
|
13261
|
-
import
|
|
13262
|
-
import
|
|
14053
|
+
import os15 from "os";
|
|
14054
|
+
import path32 from "path";
|
|
13263
14055
|
import { createInterface as createInterface3 } from "readline";
|
|
13264
14056
|
function findPackageRoot2() {
|
|
13265
|
-
let dir =
|
|
13266
|
-
const root =
|
|
14057
|
+
let dir = path32.dirname(new URL(import.meta.url).pathname);
|
|
14058
|
+
const root = path32.parse(dir).root;
|
|
13267
14059
|
while (dir !== root) {
|
|
13268
|
-
const pkgPath =
|
|
14060
|
+
const pkgPath = path32.join(dir, "package.json");
|
|
13269
14061
|
if (existsSync25(pkgPath)) {
|
|
13270
14062
|
try {
|
|
13271
14063
|
const pkg = JSON.parse(readFileSync22(pkgPath, "utf-8"));
|
|
@@ -13273,7 +14065,7 @@ function findPackageRoot2() {
|
|
|
13273
14065
|
} catch {
|
|
13274
14066
|
}
|
|
13275
14067
|
}
|
|
13276
|
-
dir =
|
|
14068
|
+
dir = path32.dirname(dir);
|
|
13277
14069
|
}
|
|
13278
14070
|
return null;
|
|
13279
14071
|
}
|
|
@@ -13285,7 +14077,7 @@ function loadSetupState() {
|
|
|
13285
14077
|
}
|
|
13286
14078
|
}
|
|
13287
14079
|
function saveSetupState(state) {
|
|
13288
|
-
mkdirSync18(
|
|
14080
|
+
mkdirSync18(path32.dirname(SETUP_STATE_PATH), { recursive: true });
|
|
13289
14081
|
writeFileSync18(SETUP_STATE_PATH, JSON.stringify(state, null, 2));
|
|
13290
14082
|
}
|
|
13291
14083
|
function clearSetupState() {
|
|
@@ -13305,10 +14097,10 @@ function ask2(rl, prompt) {
|
|
|
13305
14097
|
});
|
|
13306
14098
|
}
|
|
13307
14099
|
function getAvailableMemoryGB() {
|
|
13308
|
-
return
|
|
14100
|
+
return os15.freemem() / (1024 * 1024 * 1024);
|
|
13309
14101
|
}
|
|
13310
14102
|
function getTotalMemoryGB() {
|
|
13311
|
-
return
|
|
14103
|
+
return os15.totalmem() / (1024 * 1024 * 1024);
|
|
13312
14104
|
}
|
|
13313
14105
|
function isLowMemory() {
|
|
13314
14106
|
return getAvailableMemoryGB() < 2;
|
|
@@ -13319,7 +14111,7 @@ async function validateModel(log) {
|
|
|
13319
14111
|
if (totalGB <= 8 || isLowMemory()) {
|
|
13320
14112
|
log(`System memory: ${totalGB.toFixed(0)}GB total, ${freeGB.toFixed(1)}GB free`);
|
|
13321
14113
|
log("Skipping in-memory model validation (low memory \u2014 will validate on first use).");
|
|
13322
|
-
const modelPath =
|
|
14114
|
+
const modelPath = path32.join(MODELS_DIR, LOCAL_FILENAME);
|
|
13323
14115
|
if (existsSync25(modelPath)) {
|
|
13324
14116
|
const { statSync: statSync2 } = await import("fs");
|
|
13325
14117
|
const size = statSync2(modelPath).size;
|
|
@@ -13575,7 +14367,7 @@ async function runSetupWizard(opts = {}) {
|
|
|
13575
14367
|
await saveConfig(config);
|
|
13576
14368
|
log("");
|
|
13577
14369
|
try {
|
|
13578
|
-
const claudeJsonPath =
|
|
14370
|
+
const claudeJsonPath = path32.join(os15.homedir(), ".claude.json");
|
|
13579
14371
|
let claudeJson = {};
|
|
13580
14372
|
try {
|
|
13581
14373
|
claudeJson = JSON.parse(readFileSync22(claudeJsonPath, "utf8"));
|
|
@@ -13583,7 +14375,7 @@ async function runSetupWizard(opts = {}) {
|
|
|
13583
14375
|
}
|
|
13584
14376
|
if (!claudeJson.projects) claudeJson.projects = {};
|
|
13585
14377
|
const projects = claudeJson.projects;
|
|
13586
|
-
for (const dir of [process.cwd(),
|
|
14378
|
+
for (const dir of [process.cwd(), os15.homedir()]) {
|
|
13587
14379
|
if (!projects[dir]) projects[dir] = {};
|
|
13588
14380
|
projects[dir].hasTrustDialogAccepted = true;
|
|
13589
14381
|
}
|
|
@@ -13601,7 +14393,7 @@ async function runSetupWizard(opts = {}) {
|
|
|
13601
14393
|
const prefs = { ...existingPrefs };
|
|
13602
14394
|
log("=== Config Defaults ===");
|
|
13603
14395
|
log("");
|
|
13604
|
-
const ghosttyDetected = existsSync25(
|
|
14396
|
+
const ghosttyDetected = existsSync25(path32.join(os15.homedir(), ".config", "ghostty")) || existsSync25(path32.join(os15.homedir(), "Library", "Application Support", "com.mitchellh.ghostty"));
|
|
13605
14397
|
if (ghosttyDetected) {
|
|
13606
14398
|
const ghosttyAnswer = await ask2(rl, "Detected Ghostty terminal. Use exe-os Ghostty defaults? (Y/n) ");
|
|
13607
14399
|
prefs.ghostty = ghosttyAnswer.toLowerCase() !== "n";
|
|
@@ -13745,7 +14537,7 @@ async function runSetupWizard(opts = {}) {
|
|
|
13745
14537
|
const cooIdentityContent = getIdentityTemplate("coo");
|
|
13746
14538
|
if (cooIdentityContent) {
|
|
13747
14539
|
const cooIdPath = identityPath2(cooName);
|
|
13748
|
-
mkdirSync18(
|
|
14540
|
+
mkdirSync18(path32.dirname(cooIdPath), { recursive: true });
|
|
13749
14541
|
const replaced = cooIdentityContent.replace(/agent_id:\s*exe/g, `agent_id: ${cooName}`).replace(/\$\{agent_id\}/g, cooName);
|
|
13750
14542
|
writeFileSync18(cooIdPath, replaced, "utf-8");
|
|
13751
14543
|
}
|
|
@@ -13841,7 +14633,7 @@ async function runSetupWizard(opts = {}) {
|
|
|
13841
14633
|
const ctoIdentityContent = getIdentityTemplate("cto");
|
|
13842
14634
|
if (ctoIdentityContent) {
|
|
13843
14635
|
const ctoIdPath = identityPath2(ctoName);
|
|
13844
|
-
mkdirSync18(
|
|
14636
|
+
mkdirSync18(path32.dirname(ctoIdPath), { recursive: true });
|
|
13845
14637
|
const replaced = ctoIdentityContent.replace(/agent_id:\s*\w+/g, `agent_id: ${ctoName}`).replace(/\$\{agent_id\}/g, ctoName);
|
|
13846
14638
|
writeFileSync18(ctoIdPath, replaced, "utf-8");
|
|
13847
14639
|
}
|
|
@@ -13864,7 +14656,7 @@ async function runSetupWizard(opts = {}) {
|
|
|
13864
14656
|
const cmoIdentityContent = getIdentityTemplate("cmo");
|
|
13865
14657
|
if (cmoIdentityContent) {
|
|
13866
14658
|
const cmoIdPath = identityPath2(cmoName);
|
|
13867
|
-
mkdirSync18(
|
|
14659
|
+
mkdirSync18(path32.dirname(cmoIdPath), { recursive: true });
|
|
13868
14660
|
const replaced = cmoIdentityContent.replace(/agent_id:\s*\w+/g, `agent_id: ${cmoName}`).replace(/\$\{agent_id\}/g, cmoName);
|
|
13869
14661
|
writeFileSync18(cmoIdPath, replaced, "utf-8");
|
|
13870
14662
|
}
|
|
@@ -13888,7 +14680,7 @@ async function runSetupWizard(opts = {}) {
|
|
|
13888
14680
|
log(`Session shortcuts generated (${cooName}1, ${cooName}2, ...)`);
|
|
13889
14681
|
}
|
|
13890
14682
|
if (wrapResult.pathConfigured) {
|
|
13891
|
-
const binDir =
|
|
14683
|
+
const binDir = path32.join(os15.homedir(), ".exe-os", "bin");
|
|
13892
14684
|
process.env.PATH = `${binDir}:${process.env.PATH ?? ""}`;
|
|
13893
14685
|
pathJustConfigured = true;
|
|
13894
14686
|
}
|
|
@@ -13931,7 +14723,7 @@ async function runSetupWizard(opts = {}) {
|
|
|
13931
14723
|
const pkgRoot2 = findPackageRoot2();
|
|
13932
14724
|
if (pkgRoot2) {
|
|
13933
14725
|
try {
|
|
13934
|
-
version = JSON.parse(readFileSync22(
|
|
14726
|
+
version = JSON.parse(readFileSync22(path32.join(pkgRoot2, "package.json"), "utf-8")).version;
|
|
13935
14727
|
} catch {
|
|
13936
14728
|
}
|
|
13937
14729
|
}
|
|
@@ -13965,16 +14757,16 @@ var init_setup_wizard = __esm({
|
|
|
13965
14757
|
init_config();
|
|
13966
14758
|
init_keychain();
|
|
13967
14759
|
init_model_downloader();
|
|
13968
|
-
SETUP_STATE_PATH =
|
|
14760
|
+
SETUP_STATE_PATH = path32.join(os15.homedir(), ".exe-os", "setup-state.json");
|
|
13969
14761
|
}
|
|
13970
14762
|
});
|
|
13971
14763
|
|
|
13972
14764
|
// src/lib/update-check.ts
|
|
13973
14765
|
import { execSync as execSync11 } from "child_process";
|
|
13974
14766
|
import { readFileSync as readFileSync23 } from "fs";
|
|
13975
|
-
import
|
|
14767
|
+
import path33 from "path";
|
|
13976
14768
|
function getLocalVersion(packageRoot) {
|
|
13977
|
-
const pkgPath =
|
|
14769
|
+
const pkgPath = path33.join(packageRoot, "package.json");
|
|
13978
14770
|
const pkg = JSON.parse(readFileSync23(pkgPath, "utf-8"));
|
|
13979
14771
|
return pkg.version;
|
|
13980
14772
|
}
|
|
@@ -18499,8 +19291,8 @@ var init_ErrorOverview = __esm({
|
|
|
18499
19291
|
"use strict";
|
|
18500
19292
|
init_Box();
|
|
18501
19293
|
init_Text();
|
|
18502
|
-
cleanupPath = (
|
|
18503
|
-
return
|
|
19294
|
+
cleanupPath = (path45) => {
|
|
19295
|
+
return path45?.replace(`file://${cwd()}/`, "");
|
|
18504
19296
|
};
|
|
18505
19297
|
stackUtils = new StackUtils({
|
|
18506
19298
|
cwd: cwd(),
|
|
@@ -22954,10 +23746,10 @@ var init_hooks = __esm({
|
|
|
22954
23746
|
});
|
|
22955
23747
|
|
|
22956
23748
|
// src/runtime/safety-checks.ts
|
|
22957
|
-
import
|
|
22958
|
-
import
|
|
23749
|
+
import path34 from "path";
|
|
23750
|
+
import os16 from "os";
|
|
22959
23751
|
function checkPathSafety(filePath) {
|
|
22960
|
-
const resolved =
|
|
23752
|
+
const resolved = path34.resolve(filePath);
|
|
22961
23753
|
for (const { pattern, reason } of BYPASS_IMMUNE_PATTERNS) {
|
|
22962
23754
|
const matches = typeof pattern === "function" ? pattern(resolved) : pattern.test(resolved);
|
|
22963
23755
|
if (matches) {
|
|
@@ -22967,7 +23759,7 @@ function checkPathSafety(filePath) {
|
|
|
22967
23759
|
return { safe: true, bypassImmune: true };
|
|
22968
23760
|
}
|
|
22969
23761
|
function checkReadPathSafety(filePath) {
|
|
22970
|
-
const resolved =
|
|
23762
|
+
const resolved = path34.resolve(filePath);
|
|
22971
23763
|
const credPatterns = BYPASS_IMMUNE_PATTERNS.filter(
|
|
22972
23764
|
(p) => typeof p.pattern !== "function" && (p.reason.includes("secrets") || p.reason.includes("Private key") || p.reason.includes("Credential"))
|
|
22973
23765
|
);
|
|
@@ -22982,7 +23774,7 @@ var HOME, BYPASS_IMMUNE_PATTERNS;
|
|
|
22982
23774
|
var init_safety_checks = __esm({
|
|
22983
23775
|
"src/runtime/safety-checks.ts"() {
|
|
22984
23776
|
"use strict";
|
|
22985
|
-
HOME =
|
|
23777
|
+
HOME = os16.homedir();
|
|
22986
23778
|
BYPASS_IMMUNE_PATTERNS = [
|
|
22987
23779
|
{
|
|
22988
23780
|
pattern: /\/\.git\/hooks\//,
|
|
@@ -22993,11 +23785,11 @@ var init_safety_checks = __esm({
|
|
|
22993
23785
|
reason: "Git config can set hooks and command execution"
|
|
22994
23786
|
},
|
|
22995
23787
|
{
|
|
22996
|
-
pattern: (p) => p.startsWith(
|
|
23788
|
+
pattern: (p) => p.startsWith(path34.join(HOME, ".claude")),
|
|
22997
23789
|
reason: "Claude configuration files are protected"
|
|
22998
23790
|
},
|
|
22999
23791
|
{
|
|
23000
|
-
pattern: (p) => p.startsWith(
|
|
23792
|
+
pattern: (p) => p.startsWith(path34.join(HOME, ".exe-os")),
|
|
23001
23793
|
reason: "exe-os configuration files are protected"
|
|
23002
23794
|
},
|
|
23003
23795
|
{
|
|
@@ -23014,7 +23806,7 @@ var init_safety_checks = __esm({
|
|
|
23014
23806
|
},
|
|
23015
23807
|
{
|
|
23016
23808
|
pattern: (p) => {
|
|
23017
|
-
const name =
|
|
23809
|
+
const name = path34.basename(p);
|
|
23018
23810
|
return [".bashrc", ".zshrc", ".profile", ".bash_profile", ".zprofile", ".zshenv"].includes(name);
|
|
23019
23811
|
},
|
|
23020
23812
|
reason: "Shell configuration files can execute arbitrary code on login"
|
|
@@ -23041,7 +23833,7 @@ __export(file_read_exports, {
|
|
|
23041
23833
|
FileReadTool: () => FileReadTool
|
|
23042
23834
|
});
|
|
23043
23835
|
import fs3 from "fs/promises";
|
|
23044
|
-
import
|
|
23836
|
+
import path35 from "path";
|
|
23045
23837
|
import { z } from "zod";
|
|
23046
23838
|
function isBinary(buf) {
|
|
23047
23839
|
for (let i = 0; i < buf.length; i++) {
|
|
@@ -23077,7 +23869,7 @@ var init_file_read = __esm({
|
|
|
23077
23869
|
return { behavior: "allow" };
|
|
23078
23870
|
},
|
|
23079
23871
|
async call(input, context) {
|
|
23080
|
-
const filePath =
|
|
23872
|
+
const filePath = path35.isAbsolute(input.file_path) ? input.file_path : path35.resolve(context.cwd, input.file_path);
|
|
23081
23873
|
let stat2;
|
|
23082
23874
|
try {
|
|
23083
23875
|
stat2 = await fs3.stat(filePath);
|
|
@@ -23117,7 +23909,7 @@ __export(glob_exports, {
|
|
|
23117
23909
|
GlobTool: () => GlobTool
|
|
23118
23910
|
});
|
|
23119
23911
|
import fs4 from "fs/promises";
|
|
23120
|
-
import
|
|
23912
|
+
import path36 from "path";
|
|
23121
23913
|
import { z as z2 } from "zod";
|
|
23122
23914
|
async function walkDir(dir, maxDepth = 10) {
|
|
23123
23915
|
const results = [];
|
|
@@ -23133,7 +23925,7 @@ async function walkDir(dir, maxDepth = 10) {
|
|
|
23133
23925
|
if (entry.isDirectory() && (entry.name === "node_modules" || entry.name === ".git")) {
|
|
23134
23926
|
continue;
|
|
23135
23927
|
}
|
|
23136
|
-
const fullPath =
|
|
23928
|
+
const fullPath = path36.join(current, entry.name);
|
|
23137
23929
|
if (entry.isDirectory()) {
|
|
23138
23930
|
await walk(fullPath, depth + 1);
|
|
23139
23931
|
} else {
|
|
@@ -23167,11 +23959,11 @@ var init_glob = __esm({
|
|
|
23167
23959
|
inputSchema: inputSchema2,
|
|
23168
23960
|
isReadOnly: true,
|
|
23169
23961
|
async call(input, context) {
|
|
23170
|
-
const baseDir = input.path ?
|
|
23962
|
+
const baseDir = input.path ? path36.isAbsolute(input.path) ? input.path : path36.resolve(context.cwd, input.path) : context.cwd;
|
|
23171
23963
|
try {
|
|
23172
23964
|
const entries = await walkDir(baseDir);
|
|
23173
23965
|
const matched = entries.filter(
|
|
23174
|
-
(e) => simpleGlobMatch(
|
|
23966
|
+
(e) => simpleGlobMatch(path36.relative(baseDir, e.path), input.pattern)
|
|
23175
23967
|
);
|
|
23176
23968
|
matched.sort((a, b) => b.mtime - a.mtime);
|
|
23177
23969
|
if (matched.length === 0) {
|
|
@@ -23197,7 +23989,7 @@ __export(grep_exports, {
|
|
|
23197
23989
|
});
|
|
23198
23990
|
import { spawn as spawn2 } from "child_process";
|
|
23199
23991
|
import fs5 from "fs/promises";
|
|
23200
|
-
import
|
|
23992
|
+
import path37 from "path";
|
|
23201
23993
|
import { z as z3 } from "zod";
|
|
23202
23994
|
function runRipgrep(input, searchPath, context) {
|
|
23203
23995
|
return new Promise((resolve, reject) => {
|
|
@@ -23251,7 +24043,7 @@ async function nodeGrep(input, searchPath) {
|
|
|
23251
24043
|
}
|
|
23252
24044
|
for (const entry of entries) {
|
|
23253
24045
|
if (entry.name === "node_modules" || entry.name === ".git") continue;
|
|
23254
|
-
const fullPath =
|
|
24046
|
+
const fullPath = path37.join(dir, entry.name);
|
|
23255
24047
|
if (entry.isDirectory()) {
|
|
23256
24048
|
await walk(fullPath);
|
|
23257
24049
|
} else {
|
|
@@ -23297,7 +24089,7 @@ var init_grep = __esm({
|
|
|
23297
24089
|
inputSchema: inputSchema3,
|
|
23298
24090
|
isReadOnly: true,
|
|
23299
24091
|
async call(input, context) {
|
|
23300
|
-
const searchPath = input.path ?
|
|
24092
|
+
const searchPath = input.path ? path37.isAbsolute(input.path) ? input.path : path37.resolve(context.cwd, input.path) : context.cwd;
|
|
23301
24093
|
try {
|
|
23302
24094
|
const result = await runRipgrep(input, searchPath, context);
|
|
23303
24095
|
return result;
|
|
@@ -23322,7 +24114,7 @@ __export(file_write_exports, {
|
|
|
23322
24114
|
FileWriteTool: () => FileWriteTool
|
|
23323
24115
|
});
|
|
23324
24116
|
import fs6 from "fs/promises";
|
|
23325
|
-
import
|
|
24117
|
+
import path38 from "path";
|
|
23326
24118
|
import { z as z4 } from "zod";
|
|
23327
24119
|
var inputSchema4, FileWriteTool;
|
|
23328
24120
|
var init_file_write = __esm({
|
|
@@ -23350,8 +24142,8 @@ var init_file_write = __esm({
|
|
|
23350
24142
|
return { behavior: "allow" };
|
|
23351
24143
|
},
|
|
23352
24144
|
async call(input, context) {
|
|
23353
|
-
const filePath =
|
|
23354
|
-
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);
|
|
23355
24147
|
await fs6.mkdir(dir, { recursive: true });
|
|
23356
24148
|
await fs6.writeFile(filePath, input.content, "utf-8");
|
|
23357
24149
|
return {
|
|
@@ -23369,7 +24161,7 @@ __export(file_edit_exports, {
|
|
|
23369
24161
|
FileEditTool: () => FileEditTool
|
|
23370
24162
|
});
|
|
23371
24163
|
import fs7 from "fs/promises";
|
|
23372
|
-
import
|
|
24164
|
+
import path39 from "path";
|
|
23373
24165
|
import { z as z5 } from "zod";
|
|
23374
24166
|
function countOccurrences(haystack, needle) {
|
|
23375
24167
|
let count = 0;
|
|
@@ -23410,7 +24202,7 @@ var init_file_edit = __esm({
|
|
|
23410
24202
|
return { behavior: "allow" };
|
|
23411
24203
|
},
|
|
23412
24204
|
async call(input, context) {
|
|
23413
|
-
const filePath =
|
|
24205
|
+
const filePath = path39.isAbsolute(input.file_path) ? input.file_path : path39.resolve(context.cwd, input.file_path);
|
|
23414
24206
|
let content;
|
|
23415
24207
|
try {
|
|
23416
24208
|
content = await fs7.readFile(filePath, "utf-8");
|
|
@@ -23652,7 +24444,7 @@ var init_bash = __esm({
|
|
|
23652
24444
|
// src/tui/views/CommandCenter.tsx
|
|
23653
24445
|
import { useState as useState6, useEffect as useEffect8, useMemo as useMemo4, useCallback as useCallback4, useRef as useRef4 } from "react";
|
|
23654
24446
|
import TextInput from "ink-text-input";
|
|
23655
|
-
import
|
|
24447
|
+
import path40 from "path";
|
|
23656
24448
|
import { homedir as homedir6 } from "os";
|
|
23657
24449
|
import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
23658
24450
|
function CommandCenterView({
|
|
@@ -23901,7 +24693,7 @@ function CommandCenterView({
|
|
|
23901
24693
|
const demoEntries = DEMO_PROJECTS.map((p) => ({
|
|
23902
24694
|
projectName: p.projectName,
|
|
23903
24695
|
exeSession: p.exeSession,
|
|
23904
|
-
projectDir:
|
|
24696
|
+
projectDir: path40.join(homedir6(), p.projectName),
|
|
23905
24697
|
employeeCount: p.employees.length,
|
|
23906
24698
|
activeCount: p.employees.filter((e) => e.status === "active").length,
|
|
23907
24699
|
memoryCount: p.employees.length * 4e3,
|
|
@@ -24905,7 +25697,7 @@ var init_useOrchestrator = __esm({
|
|
|
24905
25697
|
|
|
24906
25698
|
// src/tui/views/Sessions.tsx
|
|
24907
25699
|
import React19, { useState as useState9, useEffect as useEffect11, useCallback as useCallback6 } from "react";
|
|
24908
|
-
import
|
|
25700
|
+
import path41 from "path";
|
|
24909
25701
|
import { homedir as homedir7 } from "os";
|
|
24910
25702
|
import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
24911
25703
|
function isCoordinatorEntry(entry) {
|
|
@@ -24943,7 +25735,7 @@ function SessionsView({
|
|
|
24943
25735
|
if (demo) {
|
|
24944
25736
|
setProjects(DEMO_PROJECTS.map((p) => ({
|
|
24945
25737
|
...p,
|
|
24946
|
-
projectDir:
|
|
25738
|
+
projectDir: path41.join(homedir7(), p.projectName),
|
|
24947
25739
|
employees: p.employees.map((e) => ({ ...e, attached: e.status === "active" }))
|
|
24948
25740
|
})));
|
|
24949
25741
|
return;
|
|
@@ -26861,8 +27653,8 @@ __export(wiki_client_exports, {
|
|
|
26861
27653
|
listDocuments: () => listDocuments,
|
|
26862
27654
|
listWorkspaces: () => listWorkspaces
|
|
26863
27655
|
});
|
|
26864
|
-
async function wikiFetch(config,
|
|
26865
|
-
const url = `${config.baseUrl}/api/v1${
|
|
27656
|
+
async function wikiFetch(config, path45, method = "GET", body) {
|
|
27657
|
+
const url = `${config.baseUrl}/api/v1${path45}`;
|
|
26866
27658
|
const headers = {
|
|
26867
27659
|
Authorization: `Bearer ${config.apiKey}`,
|
|
26868
27660
|
"Content-Type": "application/json"
|
|
@@ -26895,7 +27687,7 @@ async function wikiFetch(config, path44, method = "GET", body) {
|
|
|
26895
27687
|
}
|
|
26896
27688
|
}
|
|
26897
27689
|
if (!response.ok) {
|
|
26898
|
-
throw new Error(`Wiki API ${method} ${
|
|
27690
|
+
throw new Error(`Wiki API ${method} ${path45}: ${response.status} ${response.statusText}`);
|
|
26899
27691
|
}
|
|
26900
27692
|
return response.json();
|
|
26901
27693
|
} finally {
|
|
@@ -27529,8 +28321,8 @@ function SettingsView({ onBack }) {
|
|
|
27529
28321
|
let version = "unknown";
|
|
27530
28322
|
try {
|
|
27531
28323
|
const { readFileSync: readFileSync27 } = await import("fs");
|
|
27532
|
-
const { createRequire } = await import("module");
|
|
27533
|
-
const require2 =
|
|
28324
|
+
const { createRequire: createRequire2 } = await import("module");
|
|
28325
|
+
const require2 = createRequire2(import.meta.url);
|
|
27534
28326
|
const pkgPath = require2.resolve("@askexenow/exe-os/package.json");
|
|
27535
28327
|
const pkg = JSON.parse(readFileSync27(pkgPath, "utf8"));
|
|
27536
28328
|
version = pkg.version;
|
|
@@ -28340,11 +29132,11 @@ __export(installer_exports2, {
|
|
|
28340
29132
|
});
|
|
28341
29133
|
import { readFile as readFile6, writeFile as writeFile7, mkdir as mkdir7 } from "fs/promises";
|
|
28342
29134
|
import { existsSync as existsSync27, readFileSync as readFileSync25 } from "fs";
|
|
28343
|
-
import
|
|
28344
|
-
import
|
|
28345
|
-
async function registerOpenCodeMcp(packageRoot, homeDir =
|
|
28346
|
-
const configDir =
|
|
28347
|
-
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");
|
|
28348
29140
|
await mkdir7(configDir, { recursive: true });
|
|
28349
29141
|
let config = {};
|
|
28350
29142
|
if (existsSync27(configPath)) {
|
|
@@ -28359,7 +29151,7 @@ async function registerOpenCodeMcp(packageRoot, homeDir = os16.homedir()) {
|
|
|
28359
29151
|
}
|
|
28360
29152
|
const newEntry = {
|
|
28361
29153
|
type: "local",
|
|
28362
|
-
command: ["node",
|
|
29154
|
+
command: ["node", path42.join(packageRoot, "dist", "mcp", "server.js")],
|
|
28363
29155
|
enabled: true
|
|
28364
29156
|
};
|
|
28365
29157
|
const current = config.mcp["exe-os"];
|
|
@@ -28373,9 +29165,9 @@ async function registerOpenCodeMcp(packageRoot, homeDir = os16.homedir()) {
|
|
|
28373
29165
|
await writeFile7(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
28374
29166
|
return true;
|
|
28375
29167
|
}
|
|
28376
|
-
async function installOpenCodePlugin(packageRoot, homeDir =
|
|
28377
|
-
const pluginDir =
|
|
28378
|
-
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");
|
|
28379
29171
|
await mkdir7(pluginDir, { recursive: true });
|
|
28380
29172
|
const pluginContent = PLUGIN_TEMPLATE.replace(
|
|
28381
29173
|
/__PACKAGE_ROOT__/g,
|
|
@@ -28390,9 +29182,9 @@ async function installOpenCodePlugin(packageRoot, homeDir = os16.homedir()) {
|
|
|
28390
29182
|
await writeFile7(pluginPath, pluginContent);
|
|
28391
29183
|
return true;
|
|
28392
29184
|
}
|
|
28393
|
-
function verifyOpenCodeHooks(homeDir =
|
|
28394
|
-
const configPath =
|
|
28395
|
-
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");
|
|
28396
29188
|
if (!existsSync27(configPath)) return false;
|
|
28397
29189
|
try {
|
|
28398
29190
|
const config = JSON.parse(readFileSync25(configPath, "utf-8"));
|
|
@@ -28434,13 +29226,13 @@ __export(installer_exports3, {
|
|
|
28434
29226
|
});
|
|
28435
29227
|
import { readFile as readFile7, writeFile as writeFile8, mkdir as mkdir8 } from "fs/promises";
|
|
28436
29228
|
import { existsSync as existsSync28 } from "fs";
|
|
28437
|
-
import
|
|
28438
|
-
import
|
|
28439
|
-
async function mergeCodexHooks(packageRoot, homeDir =
|
|
28440
|
-
const codexDir =
|
|
28441
|
-
const hooksPath =
|
|
28442
|
-
const logsDir =
|
|
28443
|
-
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");
|
|
28444
29236
|
const logSuffix = ` 2>> "${hookLogPath}"`;
|
|
28445
29237
|
await mkdir8(codexDir, { recursive: true });
|
|
28446
29238
|
await mkdir8(logsDir, { recursive: true });
|
|
@@ -28462,7 +29254,7 @@ async function mergeCodexHooks(packageRoot, homeDir = os17.homedir()) {
|
|
|
28462
29254
|
hooks: [
|
|
28463
29255
|
{
|
|
28464
29256
|
type: "command",
|
|
28465
|
-
command: `node "${
|
|
29257
|
+
command: `node "${path43.join(packageRoot, "dist", "hooks", "session-start.js")}"${logSuffix}`,
|
|
28466
29258
|
timeout: 30,
|
|
28467
29259
|
statusMessage: "exe-os: loading memory brief"
|
|
28468
29260
|
}
|
|
@@ -28477,11 +29269,11 @@ async function mergeCodexHooks(packageRoot, homeDir = os17.homedir()) {
|
|
|
28477
29269
|
hooks: [
|
|
28478
29270
|
{
|
|
28479
29271
|
type: "command",
|
|
28480
|
-
command: `node "${
|
|
29272
|
+
command: `node "${path43.join(packageRoot, "dist", "hooks", "ingest.js")}"${logSuffix}`
|
|
28481
29273
|
},
|
|
28482
29274
|
{
|
|
28483
29275
|
type: "command",
|
|
28484
|
-
command: `node "${
|
|
29276
|
+
command: `node "${path43.join(packageRoot, "dist", "hooks", "error-recall.js")}"${logSuffix}`
|
|
28485
29277
|
}
|
|
28486
29278
|
]
|
|
28487
29279
|
},
|
|
@@ -28493,11 +29285,11 @@ async function mergeCodexHooks(packageRoot, homeDir = os17.homedir()) {
|
|
|
28493
29285
|
hooks: [
|
|
28494
29286
|
{
|
|
28495
29287
|
type: "command",
|
|
28496
|
-
command: `node "${
|
|
29288
|
+
command: `node "${path43.join(packageRoot, "dist", "hooks", "prompt-submit.js")}"${logSuffix}`
|
|
28497
29289
|
},
|
|
28498
29290
|
{
|
|
28499
29291
|
type: "command",
|
|
28500
|
-
command: `node "${
|
|
29292
|
+
command: `node "${path43.join(packageRoot, "dist", "hooks", "exe-heartbeat-hook.js")}"${logSuffix}`,
|
|
28501
29293
|
timeout: 5
|
|
28502
29294
|
}
|
|
28503
29295
|
]
|
|
@@ -28510,7 +29302,7 @@ async function mergeCodexHooks(packageRoot, homeDir = os17.homedir()) {
|
|
|
28510
29302
|
hooks: [
|
|
28511
29303
|
{
|
|
28512
29304
|
type: "command",
|
|
28513
|
-
command: `node "${
|
|
29305
|
+
command: `node "${path43.join(packageRoot, "dist", "hooks", "stop.js")}"${logSuffix}`
|
|
28514
29306
|
}
|
|
28515
29307
|
]
|
|
28516
29308
|
},
|
|
@@ -28523,7 +29315,7 @@ async function mergeCodexHooks(packageRoot, homeDir = os17.homedir()) {
|
|
|
28523
29315
|
hooks: [
|
|
28524
29316
|
{
|
|
28525
29317
|
type: "command",
|
|
28526
|
-
command: `node "${
|
|
29318
|
+
command: `node "${path43.join(packageRoot, "dist", "hooks", "pre-tool-use.js")}"${logSuffix}`
|
|
28527
29319
|
}
|
|
28528
29320
|
]
|
|
28529
29321
|
},
|
|
@@ -28554,15 +29346,15 @@ async function mergeCodexHooks(packageRoot, homeDir = os17.homedir()) {
|
|
|
28554
29346
|
await writeFile8(hooksPath, JSON.stringify(hooksJson, null, 2) + "\n");
|
|
28555
29347
|
return { added, skipped };
|
|
28556
29348
|
}
|
|
28557
|
-
function verifyCodexHooks(homeDir =
|
|
28558
|
-
const hooksPath =
|
|
29349
|
+
function verifyCodexHooks(homeDir = os18.homedir()) {
|
|
29350
|
+
const hooksPath = path43.join(homeDir, ".codex", "hooks.json");
|
|
28559
29351
|
if (!existsSync28(hooksPath)) return false;
|
|
28560
29352
|
try {
|
|
28561
29353
|
const hooksJson = JSON.parse(
|
|
28562
29354
|
__require("fs").readFileSync(hooksPath, "utf-8")
|
|
28563
29355
|
);
|
|
28564
29356
|
if (!hooksJson.hooks) return false;
|
|
28565
|
-
const required = ["SessionStart", "PostToolUse", "UserPromptSubmit", "Stop"];
|
|
29357
|
+
const required = ["SessionStart", "PostToolUse", "UserPromptSubmit", "Stop", "PreToolUse"];
|
|
28566
29358
|
for (const event of required) {
|
|
28567
29359
|
const groups = hooksJson.hooks[event];
|
|
28568
29360
|
if (!groups || !groups.some(
|
|
@@ -28576,11 +29368,11 @@ function verifyCodexHooks(homeDir = os17.homedir()) {
|
|
|
28576
29368
|
return false;
|
|
28577
29369
|
}
|
|
28578
29370
|
}
|
|
28579
|
-
async function installCodexStatusLine(homeDir =
|
|
29371
|
+
async function installCodexStatusLine(homeDir = os18.homedir()) {
|
|
28580
29372
|
const prefs = loadPreferences(homeDir);
|
|
28581
29373
|
if (prefs.codexStatusLine === false) return "opted-out";
|
|
28582
|
-
const codexDir =
|
|
28583
|
-
const configPath =
|
|
29374
|
+
const codexDir = path43.join(homeDir, ".codex");
|
|
29375
|
+
const configPath = path43.join(codexDir, "config.toml");
|
|
28584
29376
|
await mkdir8(codexDir, { recursive: true });
|
|
28585
29377
|
let content = "";
|
|
28586
29378
|
if (existsSync28(configPath)) {
|
|
@@ -28632,12 +29424,12 @@ var init_installer3 = __esm({
|
|
|
28632
29424
|
|
|
28633
29425
|
// src/bin/cli.ts
|
|
28634
29426
|
import { existsSync as existsSync29, readFileSync as readFileSync26, writeFileSync as writeFileSync19, readdirSync as readdirSync9, rmSync } from "fs";
|
|
28635
|
-
import
|
|
28636
|
-
import
|
|
29427
|
+
import path44 from "path";
|
|
29428
|
+
import os19 from "os";
|
|
28637
29429
|
var args = process.argv.slice(2);
|
|
28638
29430
|
if (args.includes("--version") || args.includes("-v")) {
|
|
28639
29431
|
try {
|
|
28640
|
-
const pkgPath =
|
|
29432
|
+
const pkgPath = path44.join(path44.dirname(new URL(import.meta.url).pathname), "..", "..", "package.json");
|
|
28641
29433
|
const pkg = JSON.parse(readFileSync26(pkgPath, "utf8"));
|
|
28642
29434
|
console.log(pkg.version);
|
|
28643
29435
|
} catch {
|
|
@@ -28802,8 +29594,8 @@ ID: ${result.id}`);
|
|
|
28802
29594
|
});
|
|
28803
29595
|
await init_App2().then(() => App_exports);
|
|
28804
29596
|
} else {
|
|
28805
|
-
const claudeDir =
|
|
28806
|
-
const settingsPath =
|
|
29597
|
+
const claudeDir = path44.join(os19.homedir(), ".claude");
|
|
29598
|
+
const settingsPath = path44.join(claudeDir, "settings.json");
|
|
28807
29599
|
const hasClaudeCode = existsSync29(settingsPath) && (() => {
|
|
28808
29600
|
try {
|
|
28809
29601
|
const raw = readFileSync26(settingsPath, "utf8");
|
|
@@ -28816,7 +29608,7 @@ ID: ${result.id}`);
|
|
|
28816
29608
|
const { DEFAULT_COORDINATOR_TEMPLATE_NAME: DEFAULT_COORDINATOR_TEMPLATE_NAME2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
28817
29609
|
let cooName = DEFAULT_COORDINATOR_TEMPLATE_NAME2;
|
|
28818
29610
|
try {
|
|
28819
|
-
const rosterPath =
|
|
29611
|
+
const rosterPath = path44.join(os19.homedir(), ".exe-os", "exe-employees.json");
|
|
28820
29612
|
if (existsSync29(rosterPath)) {
|
|
28821
29613
|
const roster = JSON.parse(readFileSync26(rosterPath, "utf8"));
|
|
28822
29614
|
const coo = roster.find((e) => e.role === "COO");
|
|
@@ -28882,9 +29674,9 @@ async function runCodexInstall() {
|
|
|
28882
29674
|
}
|
|
28883
29675
|
}
|
|
28884
29676
|
async function runClaudeCheck() {
|
|
28885
|
-
const claudeDir =
|
|
28886
|
-
const settingsPath =
|
|
28887
|
-
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");
|
|
28888
29680
|
let ok = true;
|
|
28889
29681
|
if (existsSync29(settingsPath)) {
|
|
28890
29682
|
let settings;
|
|
@@ -28937,7 +29729,7 @@ async function runClaudeCheck() {
|
|
|
28937
29729
|
console.log("\x1B[31m\u2717\x1B[0m claude.json not found");
|
|
28938
29730
|
ok = false;
|
|
28939
29731
|
}
|
|
28940
|
-
const skillsDir =
|
|
29732
|
+
const skillsDir = path44.join(claudeDir, "skills");
|
|
28941
29733
|
if (existsSync29(skillsDir)) {
|
|
28942
29734
|
console.log("\x1B[32m\u2713\x1B[0m Slash skills directory exists");
|
|
28943
29735
|
} else {
|
|
@@ -28954,11 +29746,11 @@ async function runClaudeCheck() {
|
|
|
28954
29746
|
async function runClaudeUninstall(flags = []) {
|
|
28955
29747
|
const dryRun = flags.includes("--dry-run");
|
|
28956
29748
|
const purge = flags.includes("--purge");
|
|
28957
|
-
const homeDir =
|
|
28958
|
-
const claudeDir =
|
|
28959
|
-
const settingsPath =
|
|
28960
|
-
const claudeJsonPath =
|
|
28961
|
-
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");
|
|
28962
29754
|
let removed = 0;
|
|
28963
29755
|
const log = (msg) => console.log(dryRun ? `[dry-run] ${msg}` : msg);
|
|
28964
29756
|
let settings = {};
|
|
@@ -29039,14 +29831,14 @@ async function runClaudeUninstall(flags = []) {
|
|
|
29039
29831
|
}
|
|
29040
29832
|
}
|
|
29041
29833
|
}
|
|
29042
|
-
const skillsDir =
|
|
29834
|
+
const skillsDir = path44.join(claudeDir, "skills");
|
|
29043
29835
|
if (existsSync29(skillsDir)) {
|
|
29044
29836
|
let skillCount = 0;
|
|
29045
29837
|
try {
|
|
29046
29838
|
const entries = readdirSync9(skillsDir);
|
|
29047
29839
|
for (const entry of entries) {
|
|
29048
29840
|
if (entry.startsWith("exe")) {
|
|
29049
|
-
const fullPath =
|
|
29841
|
+
const fullPath = path44.join(skillsDir, entry);
|
|
29050
29842
|
if (!dryRun) rmSync(fullPath, { recursive: true, force: true });
|
|
29051
29843
|
skillCount++;
|
|
29052
29844
|
}
|
|
@@ -29058,7 +29850,7 @@ async function runClaudeUninstall(flags = []) {
|
|
|
29058
29850
|
removed++;
|
|
29059
29851
|
}
|
|
29060
29852
|
}
|
|
29061
|
-
const claudeMdPath =
|
|
29853
|
+
const claudeMdPath = path44.join(claudeDir, "CLAUDE.md");
|
|
29062
29854
|
if (existsSync29(claudeMdPath)) {
|
|
29063
29855
|
const content = readFileSync26(claudeMdPath, "utf8");
|
|
29064
29856
|
const startMarker = "<!-- exe-os:orchestration-start -->";
|
|
@@ -29072,13 +29864,13 @@ async function runClaudeUninstall(flags = []) {
|
|
|
29072
29864
|
removed++;
|
|
29073
29865
|
}
|
|
29074
29866
|
}
|
|
29075
|
-
const agentsDir =
|
|
29867
|
+
const agentsDir = path44.join(claudeDir, "agents");
|
|
29076
29868
|
if (existsSync29(agentsDir)) {
|
|
29077
29869
|
let agentCount = 0;
|
|
29078
29870
|
try {
|
|
29079
29871
|
const entries = readdirSync9(agentsDir).filter((f) => f.endsWith(".md"));
|
|
29080
29872
|
let knownNames = /* @__PURE__ */ new Set();
|
|
29081
|
-
const rosterPath =
|
|
29873
|
+
const rosterPath = path44.join(exeOsDir, "exe-employees.json");
|
|
29082
29874
|
if (existsSync29(rosterPath)) {
|
|
29083
29875
|
try {
|
|
29084
29876
|
const roster = JSON.parse(readFileSync26(rosterPath, "utf8"));
|
|
@@ -29089,7 +29881,7 @@ async function runClaudeUninstall(flags = []) {
|
|
|
29089
29881
|
for (const entry of entries) {
|
|
29090
29882
|
const name = entry.replace(/\.md$/, "");
|
|
29091
29883
|
if (knownNames.has(name)) {
|
|
29092
|
-
if (!dryRun) rmSync(
|
|
29884
|
+
if (!dryRun) rmSync(path44.join(agentsDir, entry), { force: true });
|
|
29093
29885
|
agentCount++;
|
|
29094
29886
|
}
|
|
29095
29887
|
}
|
|
@@ -29100,13 +29892,13 @@ async function runClaudeUninstall(flags = []) {
|
|
|
29100
29892
|
removed++;
|
|
29101
29893
|
}
|
|
29102
29894
|
}
|
|
29103
|
-
const projectsDir =
|
|
29895
|
+
const projectsDir = path44.join(claudeDir, "projects");
|
|
29104
29896
|
if (existsSync29(projectsDir)) {
|
|
29105
29897
|
let projectCount = 0;
|
|
29106
29898
|
try {
|
|
29107
29899
|
const projects = readdirSync9(projectsDir);
|
|
29108
29900
|
for (const proj of projects) {
|
|
29109
|
-
const projSettings =
|
|
29901
|
+
const projSettings = path44.join(projectsDir, proj, "settings.json");
|
|
29110
29902
|
if (!existsSync29(projSettings)) continue;
|
|
29111
29903
|
try {
|
|
29112
29904
|
const pSettings = JSON.parse(readFileSync26(projSettings, "utf8"));
|
|
@@ -29143,9 +29935,9 @@ async function runClaudeUninstall(flags = []) {
|
|
|
29143
29935
|
};
|
|
29144
29936
|
const exeBinPath = findExeBin3();
|
|
29145
29937
|
if (!exeBinPath) throw new Error("exe-os not found in PATH");
|
|
29146
|
-
const binDir =
|
|
29938
|
+
const binDir = path44.dirname(exeBinPath);
|
|
29147
29939
|
let symlinkCount = 0;
|
|
29148
|
-
const rosterPath =
|
|
29940
|
+
const rosterPath = path44.join(exeOsDir, "exe-employees.json");
|
|
29149
29941
|
if (existsSync29(rosterPath)) {
|
|
29150
29942
|
const roster = JSON.parse(readFileSync26(rosterPath, "utf8"));
|
|
29151
29943
|
const { DEFAULT_COORDINATOR_TEMPLATE_NAME: DEFAULT_COORDINATOR_TEMPLATE_NAME2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
@@ -29153,7 +29945,7 @@ async function runClaudeUninstall(flags = []) {
|
|
|
29153
29945
|
for (const emp of roster) {
|
|
29154
29946
|
if (emp.name === coordinatorName) continue;
|
|
29155
29947
|
for (const suffix of ["", "-opencode"]) {
|
|
29156
|
-
const linkPath =
|
|
29948
|
+
const linkPath = path44.join(binDir, `${emp.name}${suffix}`);
|
|
29157
29949
|
if (existsSync29(linkPath)) {
|
|
29158
29950
|
if (!dryRun) rmSync(linkPath, { force: true });
|
|
29159
29951
|
symlinkCount++;
|
|
@@ -29192,7 +29984,7 @@ async function checkForUpdateOnBoot() {
|
|
|
29192
29984
|
const config = await loadConfig2();
|
|
29193
29985
|
if (!config.autoUpdate.checkOnBoot) return;
|
|
29194
29986
|
const { checkForUpdate: checkForUpdate2 } = await Promise.resolve().then(() => (init_update(), update_exports));
|
|
29195
|
-
const packageRoot =
|
|
29987
|
+
const packageRoot = path44.resolve(
|
|
29196
29988
|
new URL("../..", import.meta.url).pathname
|
|
29197
29989
|
);
|
|
29198
29990
|
const result = checkForUpdate2(packageRoot);
|
|
@@ -29252,7 +30044,7 @@ async function runActivate(key) {
|
|
|
29252
30044
|
const idTemplate = getIdentityTemplate(identityKey);
|
|
29253
30045
|
if (idTemplate) {
|
|
29254
30046
|
const idPath = identityPath2(name);
|
|
29255
|
-
const dir =
|
|
30047
|
+
const dir = path44.dirname(idPath);
|
|
29256
30048
|
if (!fs8.existsSync(dir)) fs8.mkdirSync(dir, { recursive: true });
|
|
29257
30049
|
fs8.writeFileSync(idPath, idTemplate.replace(/^agent_id: \w+/m, `agent_id: ${name}`), "utf-8");
|
|
29258
30050
|
}
|