@askexenow/exe-os 0.9.7 → 0.9.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/backfill-conversations.js +754 -79
- package/dist/bin/backfill-responses.js +752 -77
- package/dist/bin/backfill-vectors.js +752 -77
- package/dist/bin/cleanup-stale-review-tasks.js +657 -35
- package/dist/bin/cli.js +1388 -605
- package/dist/bin/exe-agent-config.js +123 -95
- package/dist/bin/exe-agent.js +41 -25
- package/dist/bin/exe-assign.js +732 -57
- package/dist/bin/exe-boot.js +784 -153
- package/dist/bin/exe-call.js +209 -138
- package/dist/bin/exe-cloud.js +35 -12
- package/dist/bin/exe-dispatch.js +692 -70
- package/dist/bin/exe-doctor.js +648 -26
- package/dist/bin/exe-export-behaviors.js +650 -20
- package/dist/bin/exe-forget.js +635 -13
- package/dist/bin/exe-gateway.js +1053 -271
- package/dist/bin/exe-heartbeat.js +665 -43
- package/dist/bin/exe-kill.js +646 -16
- package/dist/bin/exe-launch-agent.js +887 -97
- package/dist/bin/exe-link.js +658 -43
- package/dist/bin/exe-new-employee.js +378 -177
- package/dist/bin/exe-pending-messages.js +656 -34
- package/dist/bin/exe-pending-notifications.js +635 -13
- package/dist/bin/exe-pending-reviews.js +659 -37
- package/dist/bin/exe-rename.js +645 -30
- package/dist/bin/exe-review.js +635 -13
- package/dist/bin/exe-search.js +771 -88
- package/dist/bin/exe-session-cleanup.js +834 -150
- package/dist/bin/exe-settings.js +127 -91
- package/dist/bin/exe-start-codex.js +729 -94
- package/dist/bin/exe-start-opencode.js +717 -82
- package/dist/bin/exe-status.js +657 -35
- package/dist/bin/exe-team.js +635 -13
- package/dist/bin/git-sweep.js +720 -89
- package/dist/bin/graph-backfill.js +643 -13
- package/dist/bin/graph-export.js +646 -16
- package/dist/bin/install.js +596 -193
- package/dist/bin/scan-tasks.js +724 -93
- package/dist/bin/setup.js +1038 -210
- package/dist/bin/shard-migrate.js +645 -15
- package/dist/bin/wiki-sync.js +646 -16
- package/dist/gateway/index.js +1027 -245
- package/dist/hooks/bug-report-worker.js +891 -170
- package/dist/hooks/commit-complete.js +718 -87
- package/dist/hooks/error-recall.js +776 -93
- package/dist/hooks/exe-heartbeat-hook.js +85 -71
- package/dist/hooks/ingest-worker.js +840 -156
- package/dist/hooks/ingest.js +90 -73
- package/dist/hooks/instructions-loaded.js +669 -38
- package/dist/hooks/notification.js +661 -30
- package/dist/hooks/post-compact.js +674 -43
- package/dist/hooks/pre-compact.js +718 -87
- package/dist/hooks/pre-tool-use.js +872 -125
- package/dist/hooks/prompt-ingest-worker.js +758 -83
- package/dist/hooks/prompt-submit.js +1060 -319
- package/dist/hooks/response-ingest-worker.js +758 -83
- package/dist/hooks/session-end.js +721 -90
- package/dist/hooks/session-start.js +1031 -207
- package/dist/hooks/stop.js +680 -49
- package/dist/hooks/subagent-stop.js +674 -43
- package/dist/hooks/summary-worker.js +816 -132
- package/dist/index.js +1015 -232
- package/dist/lib/cloud-sync.js +663 -48
- package/dist/lib/consolidation.js +26 -3
- package/dist/lib/database.js +626 -18
- package/dist/lib/db.js +2261 -0
- package/dist/lib/device-registry.js +640 -25
- package/dist/lib/embedder.js +96 -43
- package/dist/lib/employee-templates.js +16 -0
- package/dist/lib/employees.js +259 -83
- package/dist/lib/exe-daemon-client.js +101 -63
- package/dist/lib/exe-daemon.js +894 -162
- package/dist/lib/hybrid-search.js +771 -88
- package/dist/lib/identity.js +27 -7
- package/dist/lib/messaging.js +55 -28
- package/dist/lib/reminders.js +21 -1
- package/dist/lib/schedules.js +636 -14
- package/dist/lib/skill-learning.js +21 -1
- package/dist/lib/store.js +643 -13
- package/dist/lib/task-router.js +82 -71
- package/dist/lib/tasks.js +98 -71
- package/dist/lib/tmux-routing.js +87 -60
- package/dist/lib/token-spend.js +26 -6
- package/dist/mcp/server.js +1784 -458
- package/dist/mcp/tools/complete-reminder.js +21 -1
- package/dist/mcp/tools/create-reminder.js +21 -1
- package/dist/mcp/tools/create-task.js +290 -164
- package/dist/mcp/tools/deactivate-behavior.js +24 -4
- package/dist/mcp/tools/list-reminders.js +21 -1
- package/dist/mcp/tools/list-tasks.js +195 -38
- package/dist/mcp/tools/send-message.js +58 -31
- package/dist/mcp/tools/update-task.js +75 -48
- package/dist/runtime/index.js +720 -89
- package/dist/tui/App.js +853 -123
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -265,6 +265,118 @@ var init_config = __esm({
|
|
|
265
265
|
}
|
|
266
266
|
});
|
|
267
267
|
|
|
268
|
+
// src/lib/runtime-table.ts
|
|
269
|
+
var RUNTIME_TABLE, DEFAULT_RUNTIME;
|
|
270
|
+
var init_runtime_table = __esm({
|
|
271
|
+
"src/lib/runtime-table.ts"() {
|
|
272
|
+
"use strict";
|
|
273
|
+
RUNTIME_TABLE = {
|
|
274
|
+
codex: {
|
|
275
|
+
binary: "codex",
|
|
276
|
+
launchMode: "interactive",
|
|
277
|
+
autoApproveFlag: "--dangerously-bypass-approvals-and-sandbox",
|
|
278
|
+
inlineFlag: "--no-alt-screen",
|
|
279
|
+
apiKeyEnv: "OPENAI_API_KEY",
|
|
280
|
+
defaultModel: "gpt-5.4"
|
|
281
|
+
},
|
|
282
|
+
opencode: {
|
|
283
|
+
binary: "opencode",
|
|
284
|
+
launchMode: "exec",
|
|
285
|
+
autoApproveFlag: "--dangerously-skip-permissions",
|
|
286
|
+
inlineFlag: "",
|
|
287
|
+
apiKeyEnv: "ANTHROPIC_API_KEY",
|
|
288
|
+
defaultModel: "anthropic/claude-sonnet-4-6"
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
DEFAULT_RUNTIME = "claude";
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
// src/lib/agent-config.ts
|
|
296
|
+
var agent_config_exports = {};
|
|
297
|
+
__export(agent_config_exports, {
|
|
298
|
+
AGENT_CONFIG_PATH: () => AGENT_CONFIG_PATH,
|
|
299
|
+
DEFAULT_MODELS: () => DEFAULT_MODELS,
|
|
300
|
+
KNOWN_RUNTIMES: () => KNOWN_RUNTIMES,
|
|
301
|
+
RUNTIME_LABELS: () => RUNTIME_LABELS,
|
|
302
|
+
clearAgentRuntime: () => clearAgentRuntime,
|
|
303
|
+
getAgentRuntime: () => getAgentRuntime,
|
|
304
|
+
loadAgentConfig: () => loadAgentConfig,
|
|
305
|
+
saveAgentConfig: () => saveAgentConfig,
|
|
306
|
+
setAgentRuntime: () => setAgentRuntime
|
|
307
|
+
});
|
|
308
|
+
import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync2, mkdirSync } from "fs";
|
|
309
|
+
import path3 from "path";
|
|
310
|
+
function loadAgentConfig() {
|
|
311
|
+
if (!existsSync2(AGENT_CONFIG_PATH)) return {};
|
|
312
|
+
try {
|
|
313
|
+
return JSON.parse(readFileSync2(AGENT_CONFIG_PATH, "utf-8"));
|
|
314
|
+
} catch {
|
|
315
|
+
return {};
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
function saveAgentConfig(config2) {
|
|
319
|
+
const dir = path3.dirname(AGENT_CONFIG_PATH);
|
|
320
|
+
if (!existsSync2(dir)) mkdirSync(dir, { recursive: true });
|
|
321
|
+
writeFileSync(AGENT_CONFIG_PATH, JSON.stringify(config2, null, 2) + "\n", "utf-8");
|
|
322
|
+
}
|
|
323
|
+
function getAgentRuntime(agentId) {
|
|
324
|
+
const config2 = loadAgentConfig();
|
|
325
|
+
const entry = config2[agentId];
|
|
326
|
+
if (entry) return entry;
|
|
327
|
+
const orgDefault = config2["default"];
|
|
328
|
+
if (orgDefault) return orgDefault;
|
|
329
|
+
return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
|
|
330
|
+
}
|
|
331
|
+
function setAgentRuntime(agentId, runtime, model) {
|
|
332
|
+
const knownModels = KNOWN_RUNTIMES[runtime];
|
|
333
|
+
if (!knownModels) {
|
|
334
|
+
return {
|
|
335
|
+
ok: false,
|
|
336
|
+
error: `Unknown runtime "${runtime}". Valid: ${Object.keys(KNOWN_RUNTIMES).join(", ")}`
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
if (!knownModels.includes(model)) {
|
|
340
|
+
return {
|
|
341
|
+
ok: false,
|
|
342
|
+
error: `Unknown model "${model}" for runtime "${runtime}". Valid: ${knownModels.join(", ")}`
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
const config2 = loadAgentConfig();
|
|
346
|
+
config2[agentId] = { runtime, model };
|
|
347
|
+
saveAgentConfig(config2);
|
|
348
|
+
return { ok: true };
|
|
349
|
+
}
|
|
350
|
+
function clearAgentRuntime(agentId) {
|
|
351
|
+
const config2 = loadAgentConfig();
|
|
352
|
+
delete config2[agentId];
|
|
353
|
+
saveAgentConfig(config2);
|
|
354
|
+
}
|
|
355
|
+
var AGENT_CONFIG_PATH, KNOWN_RUNTIMES, RUNTIME_LABELS, DEFAULT_MODELS;
|
|
356
|
+
var init_agent_config = __esm({
|
|
357
|
+
"src/lib/agent-config.ts"() {
|
|
358
|
+
"use strict";
|
|
359
|
+
init_config();
|
|
360
|
+
init_runtime_table();
|
|
361
|
+
AGENT_CONFIG_PATH = path3.join(EXE_AI_DIR, "agent-config.json");
|
|
362
|
+
KNOWN_RUNTIMES = {
|
|
363
|
+
claude: ["claude-opus-4", "claude-sonnet-4", "claude-haiku-4.5"],
|
|
364
|
+
codex: ["gpt-5.4", "gpt-5.5", "gpt-5.3-codex-spark", "o3", "o4-mini"],
|
|
365
|
+
opencode: ["anthropic/claude-sonnet-4-6", "openai/gpt-5.4", "google/gemini-2.5-pro", "deepseek/deepseek-r3", "minimax/minimax-m2.5"]
|
|
366
|
+
};
|
|
367
|
+
RUNTIME_LABELS = {
|
|
368
|
+
claude: "Claude Code (Anthropic)",
|
|
369
|
+
codex: "Codex (OpenAI)",
|
|
370
|
+
opencode: "OpenCode (open source)"
|
|
371
|
+
};
|
|
372
|
+
DEFAULT_MODELS = {
|
|
373
|
+
claude: "claude-opus-4",
|
|
374
|
+
codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
|
|
375
|
+
opencode: RUNTIME_TABLE.opencode?.defaultModel ?? "anthropic/claude-sonnet-4-6"
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
|
|
268
380
|
// src/lib/employees.ts
|
|
269
381
|
var employees_exports = {};
|
|
270
382
|
__export(employees_exports, {
|
|
@@ -280,6 +392,7 @@ __export(employees_exports, {
|
|
|
280
392
|
getEmployeeByRole: () => getEmployeeByRole,
|
|
281
393
|
getEmployeeNamesByRole: () => getEmployeeNamesByRole,
|
|
282
394
|
hasRole: () => hasRole,
|
|
395
|
+
hireEmployee: () => hireEmployee,
|
|
283
396
|
isCoordinatorName: () => isCoordinatorName,
|
|
284
397
|
isCoordinatorRole: () => isCoordinatorRole,
|
|
285
398
|
isMultiInstance: () => isMultiInstance,
|
|
@@ -292,9 +405,9 @@ __export(employees_exports, {
|
|
|
292
405
|
validateEmployeeName: () => validateEmployeeName
|
|
293
406
|
});
|
|
294
407
|
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
295
|
-
import { existsSync as
|
|
408
|
+
import { existsSync as existsSync3, symlinkSync, readlinkSync, readFileSync as readFileSync3, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
|
|
296
409
|
import { execSync } from "child_process";
|
|
297
|
-
import
|
|
410
|
+
import path4 from "path";
|
|
298
411
|
import os3 from "os";
|
|
299
412
|
function normalizeRole(role) {
|
|
300
413
|
return (role ?? "").trim().toLowerCase();
|
|
@@ -331,7 +444,7 @@ function validateEmployeeName(name) {
|
|
|
331
444
|
return { valid: true };
|
|
332
445
|
}
|
|
333
446
|
async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
|
|
334
|
-
if (!
|
|
447
|
+
if (!existsSync3(employeesPath)) {
|
|
335
448
|
return [];
|
|
336
449
|
}
|
|
337
450
|
const raw = await readFile2(employeesPath, "utf-8");
|
|
@@ -342,13 +455,13 @@ async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
|
|
|
342
455
|
}
|
|
343
456
|
}
|
|
344
457
|
async function saveEmployees(employees, employeesPath = EMPLOYEES_PATH) {
|
|
345
|
-
await mkdir2(
|
|
458
|
+
await mkdir2(path4.dirname(employeesPath), { recursive: true });
|
|
346
459
|
await writeFile2(employeesPath, JSON.stringify(employees, null, 2) + "\n", "utf-8");
|
|
347
460
|
}
|
|
348
461
|
function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
|
|
349
|
-
if (!
|
|
462
|
+
if (!existsSync3(employeesPath)) return [];
|
|
350
463
|
try {
|
|
351
|
-
return JSON.parse(
|
|
464
|
+
return JSON.parse(readFileSync3(employeesPath, "utf-8"));
|
|
352
465
|
} catch {
|
|
353
466
|
return [];
|
|
354
467
|
}
|
|
@@ -390,6 +503,52 @@ function addEmployee(employees, employee) {
|
|
|
390
503
|
}
|
|
391
504
|
return [...employees, normalized];
|
|
392
505
|
}
|
|
506
|
+
function appendToCoordinatorTeam(employee) {
|
|
507
|
+
const coordinator = getCoordinatorEmployee(loadEmployeesSync());
|
|
508
|
+
if (!coordinator) return;
|
|
509
|
+
const idPath = path4.join(IDENTITY_DIR, `${coordinator.name}.md`);
|
|
510
|
+
if (!existsSync3(idPath)) return;
|
|
511
|
+
const content = readFileSync3(idPath, "utf-8");
|
|
512
|
+
if (content.includes(`**${capitalize(employee.name)}`)) return;
|
|
513
|
+
const teamMatch = content.match(TEAM_SECTION_RE);
|
|
514
|
+
if (!teamMatch || teamMatch.index === void 0) return;
|
|
515
|
+
const afterTeam = content.slice(teamMatch.index + teamMatch[0].length);
|
|
516
|
+
const nextHeading = afterTeam.match(/\n## /);
|
|
517
|
+
const entry = `
|
|
518
|
+
**${capitalize(employee.name)} (${employee.role}):** Newly hired. Update this description as the role develops.
|
|
519
|
+
`;
|
|
520
|
+
let updated;
|
|
521
|
+
if (nextHeading && nextHeading.index !== void 0) {
|
|
522
|
+
const insertAt = teamMatch.index + teamMatch[0].length + nextHeading.index;
|
|
523
|
+
updated = content.slice(0, insertAt) + entry + content.slice(insertAt);
|
|
524
|
+
} else {
|
|
525
|
+
updated = content.trimEnd() + "\n" + entry;
|
|
526
|
+
}
|
|
527
|
+
writeFileSync2(idPath, updated, "utf-8");
|
|
528
|
+
}
|
|
529
|
+
function capitalize(s) {
|
|
530
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
531
|
+
}
|
|
532
|
+
async function hireEmployee(employee) {
|
|
533
|
+
const employees = await loadEmployees();
|
|
534
|
+
const updated = addEmployee(employees, employee);
|
|
535
|
+
await saveEmployees(updated);
|
|
536
|
+
try {
|
|
537
|
+
appendToCoordinatorTeam(employee);
|
|
538
|
+
} catch {
|
|
539
|
+
}
|
|
540
|
+
try {
|
|
541
|
+
const { loadAgentConfig: loadAgentConfig2, saveAgentConfig: saveAgentConfig2 } = await Promise.resolve().then(() => (init_agent_config(), agent_config_exports));
|
|
542
|
+
const config2 = loadAgentConfig2();
|
|
543
|
+
const name = employee.name.toLowerCase();
|
|
544
|
+
if (!config2[name] && config2["default"]) {
|
|
545
|
+
config2[name] = { ...config2["default"] };
|
|
546
|
+
saveAgentConfig2(config2);
|
|
547
|
+
}
|
|
548
|
+
} catch {
|
|
549
|
+
}
|
|
550
|
+
return updated;
|
|
551
|
+
}
|
|
393
552
|
async function normalizeRosterCase(rosterPath) {
|
|
394
553
|
const employees = await loadEmployees(rosterPath);
|
|
395
554
|
let changed = false;
|
|
@@ -399,14 +558,14 @@ async function normalizeRosterCase(rosterPath) {
|
|
|
399
558
|
emp.name = emp.name.toLowerCase();
|
|
400
559
|
changed = true;
|
|
401
560
|
try {
|
|
402
|
-
const identityDir =
|
|
403
|
-
const oldPath =
|
|
404
|
-
const newPath =
|
|
405
|
-
if (
|
|
561
|
+
const identityDir = path4.join(os3.homedir(), ".exe-os", "identity");
|
|
562
|
+
const oldPath = path4.join(identityDir, `${oldName}.md`);
|
|
563
|
+
const newPath = path4.join(identityDir, `${emp.name}.md`);
|
|
564
|
+
if (existsSync3(oldPath) && !existsSync3(newPath)) {
|
|
406
565
|
renameSync2(oldPath, newPath);
|
|
407
|
-
} else if (
|
|
408
|
-
const content =
|
|
409
|
-
|
|
566
|
+
} else if (existsSync3(oldPath) && oldPath !== newPath) {
|
|
567
|
+
const content = readFileSync3(oldPath, "utf-8");
|
|
568
|
+
writeFileSync2(newPath, content, "utf-8");
|
|
410
569
|
if (oldPath.toLowerCase() !== newPath.toLowerCase()) {
|
|
411
570
|
unlinkSync(oldPath);
|
|
412
571
|
}
|
|
@@ -436,7 +595,7 @@ function registerBinSymlinks(name) {
|
|
|
436
595
|
errors.push("Could not find 'exe-os' in PATH");
|
|
437
596
|
return { created, skipped, errors };
|
|
438
597
|
}
|
|
439
|
-
const binDir =
|
|
598
|
+
const binDir = path4.dirname(exeBinPath);
|
|
440
599
|
let target;
|
|
441
600
|
try {
|
|
442
601
|
target = readlinkSync(exeBinPath);
|
|
@@ -446,8 +605,8 @@ function registerBinSymlinks(name) {
|
|
|
446
605
|
}
|
|
447
606
|
for (const suffix of ["", "-opencode"]) {
|
|
448
607
|
const linkName = `${name}${suffix}`;
|
|
449
|
-
const linkPath =
|
|
450
|
-
if (
|
|
608
|
+
const linkPath = path4.join(binDir, linkName);
|
|
609
|
+
if (existsSync3(linkPath)) {
|
|
451
610
|
skipped.push(linkName);
|
|
452
611
|
continue;
|
|
453
612
|
}
|
|
@@ -460,15 +619,17 @@ function registerBinSymlinks(name) {
|
|
|
460
619
|
}
|
|
461
620
|
return { created, skipped, errors };
|
|
462
621
|
}
|
|
463
|
-
var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES;
|
|
622
|
+
var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES, IDENTITY_DIR, TEAM_SECTION_RE;
|
|
464
623
|
var init_employees = __esm({
|
|
465
624
|
"src/lib/employees.ts"() {
|
|
466
625
|
"use strict";
|
|
467
626
|
init_config();
|
|
468
|
-
EMPLOYEES_PATH =
|
|
627
|
+
EMPLOYEES_PATH = path4.join(EXE_AI_DIR, "exe-employees.json");
|
|
469
628
|
DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
|
|
470
629
|
COORDINATOR_ROLE = "COO";
|
|
471
630
|
MULTI_INSTANCE_ROLES = /* @__PURE__ */ new Set(["principal engineer", "content production specialist", "staff code reviewer"]);
|
|
631
|
+
IDENTITY_DIR = path4.join(EXE_AI_DIR, "identity");
|
|
632
|
+
TEAM_SECTION_RE = /^## Team\b.*$/m;
|
|
472
633
|
}
|
|
473
634
|
});
|
|
474
635
|
|
|
@@ -479,14 +640,14 @@ __export(session_registry_exports, {
|
|
|
479
640
|
pruneStaleSessions: () => pruneStaleSessions,
|
|
480
641
|
registerSession: () => registerSession
|
|
481
642
|
});
|
|
482
|
-
import { readFileSync as
|
|
643
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, mkdirSync as mkdirSync2, existsSync as existsSync4 } from "fs";
|
|
483
644
|
import { execSync as execSync2 } from "child_process";
|
|
484
|
-
import
|
|
645
|
+
import path5 from "path";
|
|
485
646
|
import os4 from "os";
|
|
486
647
|
function registerSession(entry) {
|
|
487
|
-
const dir =
|
|
488
|
-
if (!
|
|
489
|
-
|
|
648
|
+
const dir = path5.dirname(REGISTRY_PATH);
|
|
649
|
+
if (!existsSync4(dir)) {
|
|
650
|
+
mkdirSync2(dir, { recursive: true });
|
|
490
651
|
}
|
|
491
652
|
const sessions = listSessions();
|
|
492
653
|
const idx = sessions.findIndex((s) => s.windowName === entry.windowName);
|
|
@@ -495,11 +656,11 @@ function registerSession(entry) {
|
|
|
495
656
|
} else {
|
|
496
657
|
sessions.push(entry);
|
|
497
658
|
}
|
|
498
|
-
|
|
659
|
+
writeFileSync3(REGISTRY_PATH, JSON.stringify(sessions, null, 2));
|
|
499
660
|
}
|
|
500
661
|
function listSessions() {
|
|
501
662
|
try {
|
|
502
|
-
const raw =
|
|
663
|
+
const raw = readFileSync4(REGISTRY_PATH, "utf8");
|
|
503
664
|
return JSON.parse(raw);
|
|
504
665
|
} catch {
|
|
505
666
|
return [];
|
|
@@ -520,7 +681,7 @@ function pruneStaleSessions() {
|
|
|
520
681
|
const alive = sessions.filter((s) => liveSet.has(s.windowName));
|
|
521
682
|
const pruned = sessions.length - alive.length;
|
|
522
683
|
if (pruned > 0) {
|
|
523
|
-
|
|
684
|
+
writeFileSync3(REGISTRY_PATH, JSON.stringify(alive, null, 2));
|
|
524
685
|
}
|
|
525
686
|
return pruned;
|
|
526
687
|
}
|
|
@@ -528,7 +689,7 @@ var REGISTRY_PATH;
|
|
|
528
689
|
var init_session_registry = __esm({
|
|
529
690
|
"src/lib/session-registry.ts"() {
|
|
530
691
|
"use strict";
|
|
531
|
-
REGISTRY_PATH =
|
|
692
|
+
REGISTRY_PATH = path5.join(os4.homedir(), ".exe-os", "session-registry.json");
|
|
532
693
|
}
|
|
533
694
|
});
|
|
534
695
|
|
|
@@ -790,67 +951,6 @@ var init_provider_table = __esm({
|
|
|
790
951
|
}
|
|
791
952
|
});
|
|
792
953
|
|
|
793
|
-
// src/lib/runtime-table.ts
|
|
794
|
-
var RUNTIME_TABLE, DEFAULT_RUNTIME;
|
|
795
|
-
var init_runtime_table = __esm({
|
|
796
|
-
"src/lib/runtime-table.ts"() {
|
|
797
|
-
"use strict";
|
|
798
|
-
RUNTIME_TABLE = {
|
|
799
|
-
codex: {
|
|
800
|
-
binary: "codex",
|
|
801
|
-
launchMode: "interactive",
|
|
802
|
-
autoApproveFlag: "--dangerously-bypass-approvals-and-sandbox",
|
|
803
|
-
inlineFlag: "--no-alt-screen",
|
|
804
|
-
apiKeyEnv: "OPENAI_API_KEY",
|
|
805
|
-
defaultModel: "gpt-5.4"
|
|
806
|
-
},
|
|
807
|
-
opencode: {
|
|
808
|
-
binary: "opencode",
|
|
809
|
-
launchMode: "exec",
|
|
810
|
-
autoApproveFlag: "--dangerously-skip-permissions",
|
|
811
|
-
inlineFlag: "",
|
|
812
|
-
apiKeyEnv: "ANTHROPIC_API_KEY",
|
|
813
|
-
defaultModel: "anthropic/claude-sonnet-4-6"
|
|
814
|
-
}
|
|
815
|
-
};
|
|
816
|
-
DEFAULT_RUNTIME = "claude";
|
|
817
|
-
}
|
|
818
|
-
});
|
|
819
|
-
|
|
820
|
-
// src/lib/agent-config.ts
|
|
821
|
-
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync4, mkdirSync as mkdirSync2 } from "fs";
|
|
822
|
-
import path5 from "path";
|
|
823
|
-
function loadAgentConfig() {
|
|
824
|
-
if (!existsSync4(AGENT_CONFIG_PATH)) return {};
|
|
825
|
-
try {
|
|
826
|
-
return JSON.parse(readFileSync4(AGENT_CONFIG_PATH, "utf-8"));
|
|
827
|
-
} catch {
|
|
828
|
-
return {};
|
|
829
|
-
}
|
|
830
|
-
}
|
|
831
|
-
function getAgentRuntime(agentId) {
|
|
832
|
-
const config2 = loadAgentConfig();
|
|
833
|
-
const entry = config2[agentId];
|
|
834
|
-
if (entry) return entry;
|
|
835
|
-
const orgDefault = config2["default"];
|
|
836
|
-
if (orgDefault) return orgDefault;
|
|
837
|
-
return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
|
|
838
|
-
}
|
|
839
|
-
var AGENT_CONFIG_PATH, DEFAULT_MODELS;
|
|
840
|
-
var init_agent_config = __esm({
|
|
841
|
-
"src/lib/agent-config.ts"() {
|
|
842
|
-
"use strict";
|
|
843
|
-
init_config();
|
|
844
|
-
init_runtime_table();
|
|
845
|
-
AGENT_CONFIG_PATH = path5.join(EXE_AI_DIR, "agent-config.json");
|
|
846
|
-
DEFAULT_MODELS = {
|
|
847
|
-
claude: "claude-opus-4",
|
|
848
|
-
codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
|
|
849
|
-
opencode: RUNTIME_TABLE.opencode?.defaultModel ?? "anthropic/claude-sonnet-4-6"
|
|
850
|
-
};
|
|
851
|
-
}
|
|
852
|
-
});
|
|
853
|
-
|
|
854
954
|
// src/lib/intercom-queue.ts
|
|
855
955
|
var intercom_queue_exports = {};
|
|
856
956
|
__export(intercom_queue_exports, {
|
|
@@ -1032,13 +1132,597 @@ var init_db_retry = __esm({
|
|
|
1032
1132
|
}
|
|
1033
1133
|
});
|
|
1034
1134
|
|
|
1135
|
+
// src/lib/database-adapter.ts
|
|
1136
|
+
import os6 from "os";
|
|
1137
|
+
import path7 from "path";
|
|
1138
|
+
import { createRequire } from "module";
|
|
1139
|
+
import { pathToFileURL } from "url";
|
|
1140
|
+
function quotedIdentifier(identifier) {
|
|
1141
|
+
return `"${identifier.replace(/"/g, '""')}"`;
|
|
1142
|
+
}
|
|
1143
|
+
function unqualifiedTableName(name) {
|
|
1144
|
+
const raw = name.trim().replace(/^"|"$/g, "");
|
|
1145
|
+
const parts = raw.split(".");
|
|
1146
|
+
return parts[parts.length - 1].replace(/^"|"$/g, "").toLowerCase();
|
|
1147
|
+
}
|
|
1148
|
+
function stripTrailingSemicolon(sql) {
|
|
1149
|
+
return sql.trim().replace(/;+\s*$/u, "");
|
|
1150
|
+
}
|
|
1151
|
+
function appendClause(sql, clause) {
|
|
1152
|
+
const trimmed = stripTrailingSemicolon(sql);
|
|
1153
|
+
const returningMatch = /\sRETURNING\b[\s\S]*$/iu.exec(trimmed);
|
|
1154
|
+
if (!returningMatch) {
|
|
1155
|
+
return `${trimmed}${clause}`;
|
|
1156
|
+
}
|
|
1157
|
+
const idx = returningMatch.index;
|
|
1158
|
+
return `${trimmed.slice(0, idx)}${clause}${trimmed.slice(idx)}`;
|
|
1159
|
+
}
|
|
1160
|
+
function normalizeStatement(stmt) {
|
|
1161
|
+
if (typeof stmt === "string") {
|
|
1162
|
+
return { kind: "positional", sql: stmt, args: [] };
|
|
1163
|
+
}
|
|
1164
|
+
const sql = stmt.sql;
|
|
1165
|
+
if (Array.isArray(stmt.args) || stmt.args === void 0) {
|
|
1166
|
+
return { kind: "positional", sql, args: stmt.args ?? [] };
|
|
1167
|
+
}
|
|
1168
|
+
return { kind: "named", sql, args: stmt.args };
|
|
1169
|
+
}
|
|
1170
|
+
function rewriteBooleanLiterals(sql) {
|
|
1171
|
+
let out = sql;
|
|
1172
|
+
for (const column of BOOLEAN_COLUMN_NAMES) {
|
|
1173
|
+
const scoped = `((?:\\b[a-z_][a-z0-9_]*\\.)?${column})`;
|
|
1174
|
+
out = out.replace(new RegExp(`${scoped}\\s*=\\s*0\\b`, "giu"), "$1 = FALSE");
|
|
1175
|
+
out = out.replace(new RegExp(`${scoped}\\s*=\\s*1\\b`, "giu"), "$1 = TRUE");
|
|
1176
|
+
out = out.replace(new RegExp(`${scoped}\\s*!=\\s*0\\b`, "giu"), "$1 != FALSE");
|
|
1177
|
+
out = out.replace(new RegExp(`${scoped}\\s*!=\\s*1\\b`, "giu"), "$1 != TRUE");
|
|
1178
|
+
out = out.replace(new RegExp(`${scoped}\\s*<>\\s*0\\b`, "giu"), "$1 <> FALSE");
|
|
1179
|
+
out = out.replace(new RegExp(`${scoped}\\s*<>\\s*1\\b`, "giu"), "$1 <> TRUE");
|
|
1180
|
+
}
|
|
1181
|
+
return out;
|
|
1182
|
+
}
|
|
1183
|
+
function rewriteInsertOrIgnore(sql) {
|
|
1184
|
+
if (!/^\s*INSERT\s+OR\s+IGNORE\s+INTO\b/iu.test(sql)) {
|
|
1185
|
+
return sql;
|
|
1186
|
+
}
|
|
1187
|
+
const replaced = sql.replace(/^\s*INSERT\s+OR\s+IGNORE\s+INTO\b/iu, "INSERT INTO");
|
|
1188
|
+
return /\bON\s+CONFLICT\b/iu.test(replaced) ? replaced : appendClause(replaced, " ON CONFLICT DO NOTHING");
|
|
1189
|
+
}
|
|
1190
|
+
function rewriteInsertOrReplace(sql) {
|
|
1191
|
+
const match = /^\s*INSERT\s+OR\s+REPLACE\s+INTO\s+([A-Za-z0-9_."]+)\s*\(([^)]+)\)([\s\S]*)$/iu.exec(sql);
|
|
1192
|
+
if (!match) {
|
|
1193
|
+
return sql;
|
|
1194
|
+
}
|
|
1195
|
+
const rawTable = match[1];
|
|
1196
|
+
const rawColumns = match[2];
|
|
1197
|
+
const remainder = match[3];
|
|
1198
|
+
const tableName = unqualifiedTableName(rawTable);
|
|
1199
|
+
const conflictKeys = UPSERT_KEYS[tableName];
|
|
1200
|
+
if (!conflictKeys?.length) {
|
|
1201
|
+
return sql;
|
|
1202
|
+
}
|
|
1203
|
+
const columns = rawColumns.split(",").map((col) => col.trim().replace(/^"|"$/g, ""));
|
|
1204
|
+
const updateColumns = columns.filter((col) => !conflictKeys.includes(col));
|
|
1205
|
+
const conflictTarget = conflictKeys.map(quotedIdentifier).join(", ");
|
|
1206
|
+
const updateClause = updateColumns.length === 0 ? " DO NOTHING" : ` DO UPDATE SET ${updateColumns.map((col) => `${quotedIdentifier(col)} = EXCLUDED.${quotedIdentifier(col)}`).join(", ")}`;
|
|
1207
|
+
return `INSERT INTO ${rawTable} (${rawColumns})${appendClause(remainder, ` ON CONFLICT (${conflictTarget})${updateClause}`)}`;
|
|
1208
|
+
}
|
|
1209
|
+
function rewriteSql(sql) {
|
|
1210
|
+
let out = sql;
|
|
1211
|
+
out = out.replace(/\bdatetime\(\s*['"]now['"]\s*\)/giu, "CURRENT_TIMESTAMP");
|
|
1212
|
+
out = out.replace(/\bvector32\s*\(\s*\?\s*\)/giu, "?");
|
|
1213
|
+
out = rewriteBooleanLiterals(out);
|
|
1214
|
+
out = rewriteInsertOrReplace(out);
|
|
1215
|
+
out = rewriteInsertOrIgnore(out);
|
|
1216
|
+
return stripTrailingSemicolon(out);
|
|
1217
|
+
}
|
|
1218
|
+
function toBoolean(value) {
|
|
1219
|
+
if (value === null || value === void 0) return value;
|
|
1220
|
+
if (typeof value === "boolean") return value;
|
|
1221
|
+
if (typeof value === "number") return value !== 0;
|
|
1222
|
+
if (typeof value === "bigint") return value !== 0n;
|
|
1223
|
+
if (typeof value === "string") {
|
|
1224
|
+
const normalized = value.trim().toLowerCase();
|
|
1225
|
+
if (normalized === "0" || normalized === "false") return false;
|
|
1226
|
+
if (normalized === "1" || normalized === "true") return true;
|
|
1227
|
+
}
|
|
1228
|
+
return Boolean(value);
|
|
1229
|
+
}
|
|
1230
|
+
function countQuestionMarks(sql, end) {
|
|
1231
|
+
let count = 0;
|
|
1232
|
+
let inSingle = false;
|
|
1233
|
+
let inDouble = false;
|
|
1234
|
+
let inLineComment = false;
|
|
1235
|
+
let inBlockComment = false;
|
|
1236
|
+
for (let i = 0; i < end; i++) {
|
|
1237
|
+
const ch = sql[i];
|
|
1238
|
+
const next = sql[i + 1];
|
|
1239
|
+
if (inLineComment) {
|
|
1240
|
+
if (ch === "\n") inLineComment = false;
|
|
1241
|
+
continue;
|
|
1242
|
+
}
|
|
1243
|
+
if (inBlockComment) {
|
|
1244
|
+
if (ch === "*" && next === "/") {
|
|
1245
|
+
inBlockComment = false;
|
|
1246
|
+
i += 1;
|
|
1247
|
+
}
|
|
1248
|
+
continue;
|
|
1249
|
+
}
|
|
1250
|
+
if (!inSingle && !inDouble && ch === "-" && next === "-") {
|
|
1251
|
+
inLineComment = true;
|
|
1252
|
+
i += 1;
|
|
1253
|
+
continue;
|
|
1254
|
+
}
|
|
1255
|
+
if (!inSingle && !inDouble && ch === "/" && next === "*") {
|
|
1256
|
+
inBlockComment = true;
|
|
1257
|
+
i += 1;
|
|
1258
|
+
continue;
|
|
1259
|
+
}
|
|
1260
|
+
if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
|
|
1261
|
+
inSingle = !inSingle;
|
|
1262
|
+
continue;
|
|
1263
|
+
}
|
|
1264
|
+
if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
|
|
1265
|
+
inDouble = !inDouble;
|
|
1266
|
+
continue;
|
|
1267
|
+
}
|
|
1268
|
+
if (!inSingle && !inDouble && ch === "?") {
|
|
1269
|
+
count += 1;
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
return count;
|
|
1273
|
+
}
|
|
1274
|
+
function findBooleanPlaceholderIndexes(sql) {
|
|
1275
|
+
const indexes = /* @__PURE__ */ new Set();
|
|
1276
|
+
for (const column of BOOLEAN_COLUMN_NAMES) {
|
|
1277
|
+
const pattern = new RegExp(`(?:\\b[a-z_][a-z0-9_]*\\.)?${column}\\s*=\\s*\\?`, "giu");
|
|
1278
|
+
for (const match of sql.matchAll(pattern)) {
|
|
1279
|
+
const matchText = match[0];
|
|
1280
|
+
const qIndex = match.index + matchText.lastIndexOf("?");
|
|
1281
|
+
indexes.add(countQuestionMarks(sql, qIndex + 1));
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
return indexes;
|
|
1285
|
+
}
|
|
1286
|
+
function coerceInsertBooleanArgs(sql, args) {
|
|
1287
|
+
const match = /^\s*INSERT(?:\s+OR\s+(?:IGNORE|REPLACE))?\s+INTO\s+([A-Za-z0-9_."]+)\s*\(([^)]+)\)/iu.exec(sql);
|
|
1288
|
+
if (!match) return;
|
|
1289
|
+
const rawTable = match[1];
|
|
1290
|
+
const rawColumns = match[2];
|
|
1291
|
+
const boolColumns = BOOLEAN_COLUMNS_BY_TABLE[unqualifiedTableName(rawTable)];
|
|
1292
|
+
if (!boolColumns?.size) return;
|
|
1293
|
+
const columns = rawColumns.split(",").map((col) => col.trim().replace(/^"|"$/g, ""));
|
|
1294
|
+
for (const [index, column] of columns.entries()) {
|
|
1295
|
+
if (boolColumns.has(column) && index < args.length) {
|
|
1296
|
+
args[index] = toBoolean(args[index]);
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
function coerceUpdateBooleanArgs(sql, args) {
|
|
1301
|
+
const match = /^\s*UPDATE\s+([A-Za-z0-9_."]+)\s+SET\s+([\s\S]+?)(?:\s+WHERE\b|$)/iu.exec(sql);
|
|
1302
|
+
if (!match) return;
|
|
1303
|
+
const rawTable = match[1];
|
|
1304
|
+
const setClause = match[2];
|
|
1305
|
+
const boolColumns = BOOLEAN_COLUMNS_BY_TABLE[unqualifiedTableName(rawTable)];
|
|
1306
|
+
if (!boolColumns?.size) return;
|
|
1307
|
+
const assignments = setClause.split(",");
|
|
1308
|
+
let placeholderIndex = 0;
|
|
1309
|
+
for (const assignment of assignments) {
|
|
1310
|
+
if (!assignment.includes("?")) continue;
|
|
1311
|
+
placeholderIndex += 1;
|
|
1312
|
+
const colMatch = /^\s*(?:[A-Za-z_][A-Za-z0-9_]*\.)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*\?/iu.exec(assignment);
|
|
1313
|
+
if (colMatch && boolColumns.has(colMatch[1])) {
|
|
1314
|
+
args[placeholderIndex - 1] = toBoolean(args[placeholderIndex - 1]);
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
function coerceBooleanArgs(sql, args) {
|
|
1319
|
+
const nextArgs = [...args];
|
|
1320
|
+
coerceInsertBooleanArgs(sql, nextArgs);
|
|
1321
|
+
coerceUpdateBooleanArgs(sql, nextArgs);
|
|
1322
|
+
const placeholderIndexes = findBooleanPlaceholderIndexes(sql);
|
|
1323
|
+
for (const index of placeholderIndexes) {
|
|
1324
|
+
if (index > 0 && index <= nextArgs.length) {
|
|
1325
|
+
nextArgs[index - 1] = toBoolean(nextArgs[index - 1]);
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
return nextArgs;
|
|
1329
|
+
}
|
|
1330
|
+
function convertQuestionMarksToDollarParams(sql) {
|
|
1331
|
+
let out = "";
|
|
1332
|
+
let placeholder = 0;
|
|
1333
|
+
let inSingle = false;
|
|
1334
|
+
let inDouble = false;
|
|
1335
|
+
let inLineComment = false;
|
|
1336
|
+
let inBlockComment = false;
|
|
1337
|
+
for (let i = 0; i < sql.length; i++) {
|
|
1338
|
+
const ch = sql[i];
|
|
1339
|
+
const next = sql[i + 1];
|
|
1340
|
+
if (inLineComment) {
|
|
1341
|
+
out += ch;
|
|
1342
|
+
if (ch === "\n") inLineComment = false;
|
|
1343
|
+
continue;
|
|
1344
|
+
}
|
|
1345
|
+
if (inBlockComment) {
|
|
1346
|
+
out += ch;
|
|
1347
|
+
if (ch === "*" && next === "/") {
|
|
1348
|
+
out += next;
|
|
1349
|
+
inBlockComment = false;
|
|
1350
|
+
i += 1;
|
|
1351
|
+
}
|
|
1352
|
+
continue;
|
|
1353
|
+
}
|
|
1354
|
+
if (!inSingle && !inDouble && ch === "-" && next === "-") {
|
|
1355
|
+
out += ch + next;
|
|
1356
|
+
inLineComment = true;
|
|
1357
|
+
i += 1;
|
|
1358
|
+
continue;
|
|
1359
|
+
}
|
|
1360
|
+
if (!inSingle && !inDouble && ch === "/" && next === "*") {
|
|
1361
|
+
out += ch + next;
|
|
1362
|
+
inBlockComment = true;
|
|
1363
|
+
i += 1;
|
|
1364
|
+
continue;
|
|
1365
|
+
}
|
|
1366
|
+
if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
|
|
1367
|
+
inSingle = !inSingle;
|
|
1368
|
+
out += ch;
|
|
1369
|
+
continue;
|
|
1370
|
+
}
|
|
1371
|
+
if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
|
|
1372
|
+
inDouble = !inDouble;
|
|
1373
|
+
out += ch;
|
|
1374
|
+
continue;
|
|
1375
|
+
}
|
|
1376
|
+
if (!inSingle && !inDouble && ch === "?") {
|
|
1377
|
+
placeholder += 1;
|
|
1378
|
+
out += `$${placeholder}`;
|
|
1379
|
+
continue;
|
|
1380
|
+
}
|
|
1381
|
+
out += ch;
|
|
1382
|
+
}
|
|
1383
|
+
return out;
|
|
1384
|
+
}
|
|
1385
|
+
function translateStatementForPostgres(stmt) {
|
|
1386
|
+
const normalized = normalizeStatement(stmt);
|
|
1387
|
+
if (normalized.kind === "named") {
|
|
1388
|
+
throw new Error("Named SQL parameters are not supported by the Prisma adapter.");
|
|
1389
|
+
}
|
|
1390
|
+
const rewrittenSql = rewriteSql(normalized.sql);
|
|
1391
|
+
const coercedArgs = coerceBooleanArgs(rewrittenSql, normalized.args);
|
|
1392
|
+
return {
|
|
1393
|
+
sql: convertQuestionMarksToDollarParams(rewrittenSql),
|
|
1394
|
+
args: coercedArgs
|
|
1395
|
+
};
|
|
1396
|
+
}
|
|
1397
|
+
function shouldBypassPostgres(stmt) {
|
|
1398
|
+
const normalized = normalizeStatement(stmt);
|
|
1399
|
+
if (normalized.kind === "named") {
|
|
1400
|
+
return true;
|
|
1401
|
+
}
|
|
1402
|
+
return IMMEDIATE_FALLBACK_PATTERNS.some((pattern) => pattern.test(normalized.sql));
|
|
1403
|
+
}
|
|
1404
|
+
function shouldFallbackOnError(error) {
|
|
1405
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1406
|
+
return /42P01|42883|42601|does not exist|syntax error|not supported|Named SQL parameters are not supported/iu.test(message);
|
|
1407
|
+
}
|
|
1408
|
+
function isReadQuery(sql) {
|
|
1409
|
+
const trimmed = sql.trimStart();
|
|
1410
|
+
return /^(SELECT|WITH|SHOW|EXPLAIN|VALUES)\b/iu.test(trimmed) || /\bRETURNING\b/iu.test(trimmed);
|
|
1411
|
+
}
|
|
1412
|
+
function buildRow(row, columns) {
|
|
1413
|
+
const values = columns.map((column) => row[column]);
|
|
1414
|
+
return Object.assign(values, row);
|
|
1415
|
+
}
|
|
1416
|
+
function buildResultSet(rows, rowsAffected = 0) {
|
|
1417
|
+
const columns = rows[0] ? Object.keys(rows[0]) : [];
|
|
1418
|
+
const resultRows = rows.map((row) => buildRow(row, columns));
|
|
1419
|
+
return {
|
|
1420
|
+
columns,
|
|
1421
|
+
columnTypes: columns.map(() => ""),
|
|
1422
|
+
rows: resultRows,
|
|
1423
|
+
rowsAffected,
|
|
1424
|
+
lastInsertRowid: void 0,
|
|
1425
|
+
toJSON() {
|
|
1426
|
+
return {
|
|
1427
|
+
columns,
|
|
1428
|
+
columnTypes: columns.map(() => ""),
|
|
1429
|
+
rows,
|
|
1430
|
+
rowsAffected,
|
|
1431
|
+
lastInsertRowid: void 0
|
|
1432
|
+
};
|
|
1433
|
+
}
|
|
1434
|
+
};
|
|
1435
|
+
}
|
|
1436
|
+
async function loadPrismaClient() {
|
|
1437
|
+
if (!prismaClientPromise) {
|
|
1438
|
+
prismaClientPromise = (async () => {
|
|
1439
|
+
const explicitPath = process.env.EXE_OS_PRISMA_CLIENT_PATH;
|
|
1440
|
+
if (explicitPath) {
|
|
1441
|
+
const module2 = await import(pathToFileURL(explicitPath).href);
|
|
1442
|
+
const PrismaClient2 = module2.PrismaClient ?? module2.default?.PrismaClient;
|
|
1443
|
+
if (!PrismaClient2) {
|
|
1444
|
+
throw new Error(`No PrismaClient export found at ${explicitPath}`);
|
|
1445
|
+
}
|
|
1446
|
+
return new PrismaClient2();
|
|
1447
|
+
}
|
|
1448
|
+
const exeDbRoot = process.env.EXE_DB_ROOT ?? path7.join(os6.homedir(), "exe-db");
|
|
1449
|
+
const requireFromExeDb = createRequire(path7.join(exeDbRoot, "package.json"));
|
|
1450
|
+
const prismaEntry = requireFromExeDb.resolve("@prisma/client");
|
|
1451
|
+
const module = await import(pathToFileURL(prismaEntry).href);
|
|
1452
|
+
const PrismaClient = module.PrismaClient ?? module.default?.PrismaClient;
|
|
1453
|
+
if (!PrismaClient) {
|
|
1454
|
+
throw new Error(`No PrismaClient export found in ${prismaEntry}`);
|
|
1455
|
+
}
|
|
1456
|
+
return new PrismaClient();
|
|
1457
|
+
})();
|
|
1458
|
+
}
|
|
1459
|
+
return prismaClientPromise;
|
|
1460
|
+
}
|
|
1461
|
+
async function ensureCompatibilityViews(prisma) {
|
|
1462
|
+
if (!compatibilityBootstrapPromise) {
|
|
1463
|
+
compatibilityBootstrapPromise = (async () => {
|
|
1464
|
+
for (const mapping of VIEW_MAPPINGS) {
|
|
1465
|
+
const relation = mapping.source.replace(/"/g, "");
|
|
1466
|
+
const rows = await prisma.$queryRawUnsafe(
|
|
1467
|
+
"SELECT to_regclass($1) AS regclass",
|
|
1468
|
+
relation
|
|
1469
|
+
);
|
|
1470
|
+
if (!rows[0]?.regclass) {
|
|
1471
|
+
continue;
|
|
1472
|
+
}
|
|
1473
|
+
await prisma.$executeRawUnsafe(
|
|
1474
|
+
`CREATE OR REPLACE VIEW public.${quotedIdentifier(mapping.view)} AS SELECT * FROM ${mapping.source}`
|
|
1475
|
+
);
|
|
1476
|
+
}
|
|
1477
|
+
})();
|
|
1478
|
+
}
|
|
1479
|
+
return compatibilityBootstrapPromise;
|
|
1480
|
+
}
|
|
1481
|
+
async function executeOnPrisma(executor, stmt) {
|
|
1482
|
+
const translated = translateStatementForPostgres(stmt);
|
|
1483
|
+
if (isReadQuery(translated.sql)) {
|
|
1484
|
+
const rows = await executor.$queryRawUnsafe(
|
|
1485
|
+
translated.sql,
|
|
1486
|
+
...translated.args
|
|
1487
|
+
);
|
|
1488
|
+
return buildResultSet(rows, /\bRETURNING\b/iu.test(translated.sql) ? rows.length : 0);
|
|
1489
|
+
}
|
|
1490
|
+
const rowsAffected = await executor.$executeRawUnsafe(translated.sql, ...translated.args);
|
|
1491
|
+
return buildResultSet([], rowsAffected);
|
|
1492
|
+
}
|
|
1493
|
+
function splitSqlStatements(sql) {
|
|
1494
|
+
const parts = [];
|
|
1495
|
+
let current = "";
|
|
1496
|
+
let inSingle = false;
|
|
1497
|
+
let inDouble = false;
|
|
1498
|
+
let inLineComment = false;
|
|
1499
|
+
let inBlockComment = false;
|
|
1500
|
+
for (let i = 0; i < sql.length; i++) {
|
|
1501
|
+
const ch = sql[i];
|
|
1502
|
+
const next = sql[i + 1];
|
|
1503
|
+
if (inLineComment) {
|
|
1504
|
+
current += ch;
|
|
1505
|
+
if (ch === "\n") inLineComment = false;
|
|
1506
|
+
continue;
|
|
1507
|
+
}
|
|
1508
|
+
if (inBlockComment) {
|
|
1509
|
+
current += ch;
|
|
1510
|
+
if (ch === "*" && next === "/") {
|
|
1511
|
+
current += next;
|
|
1512
|
+
inBlockComment = false;
|
|
1513
|
+
i += 1;
|
|
1514
|
+
}
|
|
1515
|
+
continue;
|
|
1516
|
+
}
|
|
1517
|
+
if (!inSingle && !inDouble && ch === "-" && next === "-") {
|
|
1518
|
+
current += ch + next;
|
|
1519
|
+
inLineComment = true;
|
|
1520
|
+
i += 1;
|
|
1521
|
+
continue;
|
|
1522
|
+
}
|
|
1523
|
+
if (!inSingle && !inDouble && ch === "/" && next === "*") {
|
|
1524
|
+
current += ch + next;
|
|
1525
|
+
inBlockComment = true;
|
|
1526
|
+
i += 1;
|
|
1527
|
+
continue;
|
|
1528
|
+
}
|
|
1529
|
+
if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
|
|
1530
|
+
inSingle = !inSingle;
|
|
1531
|
+
current += ch;
|
|
1532
|
+
continue;
|
|
1533
|
+
}
|
|
1534
|
+
if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
|
|
1535
|
+
inDouble = !inDouble;
|
|
1536
|
+
current += ch;
|
|
1537
|
+
continue;
|
|
1538
|
+
}
|
|
1539
|
+
if (!inSingle && !inDouble && ch === ";") {
|
|
1540
|
+
if (current.trim()) {
|
|
1541
|
+
parts.push(current.trim());
|
|
1542
|
+
}
|
|
1543
|
+
current = "";
|
|
1544
|
+
continue;
|
|
1545
|
+
}
|
|
1546
|
+
current += ch;
|
|
1547
|
+
}
|
|
1548
|
+
if (current.trim()) {
|
|
1549
|
+
parts.push(current.trim());
|
|
1550
|
+
}
|
|
1551
|
+
return parts;
|
|
1552
|
+
}
|
|
1553
|
+
async function createPrismaDbAdapter(fallbackClient) {
|
|
1554
|
+
const prisma = await loadPrismaClient();
|
|
1555
|
+
await ensureCompatibilityViews(prisma);
|
|
1556
|
+
let closed = false;
|
|
1557
|
+
let adapter;
|
|
1558
|
+
const fallbackExecute = async (stmt, error) => {
|
|
1559
|
+
if (!fallbackClient) {
|
|
1560
|
+
if (error) throw error;
|
|
1561
|
+
throw new Error("No fallback SQLite client is available for this Prisma-routed query.");
|
|
1562
|
+
}
|
|
1563
|
+
if (error) {
|
|
1564
|
+
process.stderr.write(
|
|
1565
|
+
`[database-adapter] Falling back to SQLite: ${error instanceof Error ? error.message : String(error)}
|
|
1566
|
+
`
|
|
1567
|
+
);
|
|
1568
|
+
}
|
|
1569
|
+
return fallbackClient.execute(stmt);
|
|
1570
|
+
};
|
|
1571
|
+
adapter = {
|
|
1572
|
+
async execute(stmt) {
|
|
1573
|
+
if (shouldBypassPostgres(stmt)) {
|
|
1574
|
+
return fallbackExecute(stmt);
|
|
1575
|
+
}
|
|
1576
|
+
try {
|
|
1577
|
+
return await executeOnPrisma(prisma, stmt);
|
|
1578
|
+
} catch (error) {
|
|
1579
|
+
if (shouldFallbackOnError(error)) {
|
|
1580
|
+
return fallbackExecute(stmt, error);
|
|
1581
|
+
}
|
|
1582
|
+
throw error;
|
|
1583
|
+
}
|
|
1584
|
+
},
|
|
1585
|
+
async batch(stmts, mode) {
|
|
1586
|
+
if (stmts.some((stmt) => shouldBypassPostgres(stmt))) {
|
|
1587
|
+
if (!fallbackClient) {
|
|
1588
|
+
throw new Error("Cannot batch unsupported SQLite-only statements without a fallback client.");
|
|
1589
|
+
}
|
|
1590
|
+
return fallbackClient.batch(stmts, mode);
|
|
1591
|
+
}
|
|
1592
|
+
try {
|
|
1593
|
+
if (prisma.$transaction) {
|
|
1594
|
+
return await prisma.$transaction(async (tx) => {
|
|
1595
|
+
const results2 = [];
|
|
1596
|
+
for (const stmt of stmts) {
|
|
1597
|
+
results2.push(await executeOnPrisma(tx, stmt));
|
|
1598
|
+
}
|
|
1599
|
+
return results2;
|
|
1600
|
+
});
|
|
1601
|
+
}
|
|
1602
|
+
const results = [];
|
|
1603
|
+
for (const stmt of stmts) {
|
|
1604
|
+
results.push(await executeOnPrisma(prisma, stmt));
|
|
1605
|
+
}
|
|
1606
|
+
return results;
|
|
1607
|
+
} catch (error) {
|
|
1608
|
+
if (fallbackClient && shouldFallbackOnError(error)) {
|
|
1609
|
+
process.stderr.write(
|
|
1610
|
+
`[database-adapter] Falling back batch to SQLite: ${error instanceof Error ? error.message : String(error)}
|
|
1611
|
+
`
|
|
1612
|
+
);
|
|
1613
|
+
return fallbackClient.batch(stmts, mode);
|
|
1614
|
+
}
|
|
1615
|
+
throw error;
|
|
1616
|
+
}
|
|
1617
|
+
},
|
|
1618
|
+
async migrate(stmts) {
|
|
1619
|
+
if (fallbackClient) {
|
|
1620
|
+
return fallbackClient.migrate(stmts);
|
|
1621
|
+
}
|
|
1622
|
+
return adapter.batch(stmts, "deferred");
|
|
1623
|
+
},
|
|
1624
|
+
async transaction(mode) {
|
|
1625
|
+
if (!fallbackClient) {
|
|
1626
|
+
throw new Error("Interactive transactions are only supported on the SQLite fallback client.");
|
|
1627
|
+
}
|
|
1628
|
+
return fallbackClient.transaction(mode);
|
|
1629
|
+
},
|
|
1630
|
+
async executeMultiple(sql) {
|
|
1631
|
+
if (fallbackClient && shouldBypassPostgres(sql)) {
|
|
1632
|
+
return fallbackClient.executeMultiple(sql);
|
|
1633
|
+
}
|
|
1634
|
+
for (const statement of splitSqlStatements(sql)) {
|
|
1635
|
+
await adapter.execute(statement);
|
|
1636
|
+
}
|
|
1637
|
+
},
|
|
1638
|
+
async sync() {
|
|
1639
|
+
if (fallbackClient) {
|
|
1640
|
+
return fallbackClient.sync();
|
|
1641
|
+
}
|
|
1642
|
+
return { frame_no: 0, frames_synced: 0 };
|
|
1643
|
+
},
|
|
1644
|
+
close() {
|
|
1645
|
+
closed = true;
|
|
1646
|
+
prismaClientPromise = null;
|
|
1647
|
+
compatibilityBootstrapPromise = null;
|
|
1648
|
+
void prisma.$disconnect?.();
|
|
1649
|
+
},
|
|
1650
|
+
get closed() {
|
|
1651
|
+
return closed;
|
|
1652
|
+
},
|
|
1653
|
+
get protocol() {
|
|
1654
|
+
return "prisma-postgres";
|
|
1655
|
+
}
|
|
1656
|
+
};
|
|
1657
|
+
return adapter;
|
|
1658
|
+
}
|
|
1659
|
+
var VIEW_MAPPINGS, UPSERT_KEYS, BOOLEAN_COLUMNS_BY_TABLE, BOOLEAN_COLUMN_NAMES, IMMEDIATE_FALLBACK_PATTERNS, prismaClientPromise, compatibilityBootstrapPromise;
|
|
1660
|
+
var init_database_adapter = __esm({
|
|
1661
|
+
"src/lib/database-adapter.ts"() {
|
|
1662
|
+
"use strict";
|
|
1663
|
+
VIEW_MAPPINGS = [
|
|
1664
|
+
{ view: "memories", source: "memory.memory_records" },
|
|
1665
|
+
{ view: "tasks", source: "memory.tasks" },
|
|
1666
|
+
{ view: "behaviors", source: "memory.behaviors" },
|
|
1667
|
+
{ view: "entities", source: "memory.entities" },
|
|
1668
|
+
{ view: "relationships", source: "memory.relationships" },
|
|
1669
|
+
{ view: "entity_memories", source: "memory.entity_memories" },
|
|
1670
|
+
{ view: "entity_aliases", source: "memory.entity_aliases" },
|
|
1671
|
+
{ view: "notifications", source: "memory.notifications" },
|
|
1672
|
+
{ view: "messages", source: "memory.messages" },
|
|
1673
|
+
{ view: "users", source: "wiki.users" },
|
|
1674
|
+
{ view: "workspaces", source: "wiki.workspaces" },
|
|
1675
|
+
{ view: "workspace_users", source: "wiki.workspace_users" },
|
|
1676
|
+
{ view: "documents", source: "wiki.workspace_documents" },
|
|
1677
|
+
{ view: "chats", source: "wiki.workspace_chats" }
|
|
1678
|
+
];
|
|
1679
|
+
UPSERT_KEYS = {
|
|
1680
|
+
memories: ["id"],
|
|
1681
|
+
tasks: ["id"],
|
|
1682
|
+
behaviors: ["id"],
|
|
1683
|
+
entities: ["id"],
|
|
1684
|
+
relationships: ["id"],
|
|
1685
|
+
entity_aliases: ["alias"],
|
|
1686
|
+
notifications: ["id"],
|
|
1687
|
+
messages: ["id"],
|
|
1688
|
+
users: ["id"],
|
|
1689
|
+
workspaces: ["id"],
|
|
1690
|
+
workspace_users: ["id"],
|
|
1691
|
+
documents: ["id"],
|
|
1692
|
+
chats: ["id"]
|
|
1693
|
+
};
|
|
1694
|
+
BOOLEAN_COLUMNS_BY_TABLE = {
|
|
1695
|
+
memories: /* @__PURE__ */ new Set(["has_error", "draft"]),
|
|
1696
|
+
behaviors: /* @__PURE__ */ new Set(["active"]),
|
|
1697
|
+
notifications: /* @__PURE__ */ new Set(["read"]),
|
|
1698
|
+
users: /* @__PURE__ */ new Set(["has_personal_memory"])
|
|
1699
|
+
};
|
|
1700
|
+
BOOLEAN_COLUMN_NAMES = new Set(
|
|
1701
|
+
Object.values(BOOLEAN_COLUMNS_BY_TABLE).flatMap((cols) => [...cols])
|
|
1702
|
+
);
|
|
1703
|
+
IMMEDIATE_FALLBACK_PATTERNS = [
|
|
1704
|
+
/\bPRAGMA\b/i,
|
|
1705
|
+
/\bsqlite_master\b/i,
|
|
1706
|
+
/(?:^|[.\s])(?:memories|conversations|entities)_fts\b/i,
|
|
1707
|
+
/\bMATCH\b/i,
|
|
1708
|
+
/\bvector_distance_cos\s*\(/i,
|
|
1709
|
+
/\bjson_extract\s*\(/i,
|
|
1710
|
+
/\bjulianday\s*\(/i,
|
|
1711
|
+
/\bstrftime\s*\(/i,
|
|
1712
|
+
/\blast_insert_rowid\s*\(/i
|
|
1713
|
+
];
|
|
1714
|
+
prismaClientPromise = null;
|
|
1715
|
+
compatibilityBootstrapPromise = null;
|
|
1716
|
+
}
|
|
1717
|
+
});
|
|
1718
|
+
|
|
1035
1719
|
// src/lib/exe-daemon-client.ts
|
|
1036
1720
|
import net from "net";
|
|
1037
|
-
import
|
|
1721
|
+
import os7 from "os";
|
|
1038
1722
|
import { spawn } from "child_process";
|
|
1039
1723
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
1040
1724
|
import { existsSync as existsSync6, unlinkSync as unlinkSync2, readFileSync as readFileSync6, openSync, closeSync, statSync } from "fs";
|
|
1041
|
-
import
|
|
1725
|
+
import path8 from "path";
|
|
1042
1726
|
import { fileURLToPath } from "url";
|
|
1043
1727
|
function handleData(chunk) {
|
|
1044
1728
|
_buffer += chunk.toString();
|
|
@@ -1089,17 +1773,17 @@ function cleanupStaleFiles() {
|
|
|
1089
1773
|
}
|
|
1090
1774
|
}
|
|
1091
1775
|
function findPackageRoot() {
|
|
1092
|
-
let dir =
|
|
1093
|
-
const { root } =
|
|
1776
|
+
let dir = path8.dirname(fileURLToPath(import.meta.url));
|
|
1777
|
+
const { root } = path8.parse(dir);
|
|
1094
1778
|
while (dir !== root) {
|
|
1095
|
-
if (existsSync6(
|
|
1096
|
-
dir =
|
|
1779
|
+
if (existsSync6(path8.join(dir, "package.json"))) return dir;
|
|
1780
|
+
dir = path8.dirname(dir);
|
|
1097
1781
|
}
|
|
1098
1782
|
return null;
|
|
1099
1783
|
}
|
|
1100
1784
|
function spawnDaemon() {
|
|
1101
|
-
const freeGB =
|
|
1102
|
-
const totalGB =
|
|
1785
|
+
const freeGB = os7.freemem() / (1024 * 1024 * 1024);
|
|
1786
|
+
const totalGB = os7.totalmem() / (1024 * 1024 * 1024);
|
|
1103
1787
|
if (totalGB <= 8) {
|
|
1104
1788
|
process.stderr.write(
|
|
1105
1789
|
`[exed-client] SKIP: ${totalGB.toFixed(0)}GB system \u2014 embedding daemon disabled. Using keyword search only. Minimum 16GB recommended for vector search.
|
|
@@ -1119,7 +1803,7 @@ function spawnDaemon() {
|
|
|
1119
1803
|
process.stderr.write("[exed-client] WARN: cannot find package root\n");
|
|
1120
1804
|
return;
|
|
1121
1805
|
}
|
|
1122
|
-
const daemonPath =
|
|
1806
|
+
const daemonPath = path8.join(pkgRoot, "dist", "lib", "exe-daemon.js");
|
|
1123
1807
|
if (!existsSync6(daemonPath)) {
|
|
1124
1808
|
process.stderr.write(`[exed-client] WARN: daemon script not found at ${daemonPath}
|
|
1125
1809
|
`);
|
|
@@ -1128,7 +1812,7 @@ function spawnDaemon() {
|
|
|
1128
1812
|
const resolvedPath = daemonPath;
|
|
1129
1813
|
process.stderr.write(`[exed-client] Spawning daemon: ${resolvedPath}
|
|
1130
1814
|
`);
|
|
1131
|
-
const logPath =
|
|
1815
|
+
const logPath = path8.join(path8.dirname(SOCKET_PATH), "exed.log");
|
|
1132
1816
|
let stderrFd = "ignore";
|
|
1133
1817
|
try {
|
|
1134
1818
|
stderrFd = openSync(logPath, "a");
|
|
@@ -1279,74 +1963,123 @@ async function pingDaemon() {
|
|
|
1279
1963
|
return null;
|
|
1280
1964
|
}
|
|
1281
1965
|
function killAndRespawnDaemon() {
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1966
|
+
if (!acquireSpawnLock()) {
|
|
1967
|
+
process.stderr.write("[exed-client] Another process is already restarting daemon \u2014 skipping\n");
|
|
1968
|
+
if (_socket) {
|
|
1969
|
+
_socket.destroy();
|
|
1970
|
+
_socket = null;
|
|
1971
|
+
}
|
|
1972
|
+
_connected = false;
|
|
1973
|
+
_buffer = "";
|
|
1974
|
+
return;
|
|
1975
|
+
}
|
|
1976
|
+
try {
|
|
1977
|
+
process.stderr.write("[exed-client] Killing daemon for restart...\n");
|
|
1978
|
+
if (existsSync6(PID_PATH)) {
|
|
1979
|
+
try {
|
|
1980
|
+
const pid = parseInt(readFileSync6(PID_PATH, "utf8").trim(), 10);
|
|
1981
|
+
if (pid > 0) {
|
|
1982
|
+
try {
|
|
1983
|
+
process.kill(pid, "SIGKILL");
|
|
1984
|
+
} catch {
|
|
1985
|
+
}
|
|
1290
1986
|
}
|
|
1987
|
+
} catch {
|
|
1291
1988
|
}
|
|
1989
|
+
}
|
|
1990
|
+
if (_socket) {
|
|
1991
|
+
_socket.destroy();
|
|
1992
|
+
_socket = null;
|
|
1993
|
+
}
|
|
1994
|
+
_connected = false;
|
|
1995
|
+
_buffer = "";
|
|
1996
|
+
try {
|
|
1997
|
+
unlinkSync2(PID_PATH);
|
|
1292
1998
|
} catch {
|
|
1293
1999
|
}
|
|
2000
|
+
try {
|
|
2001
|
+
unlinkSync2(SOCKET_PATH);
|
|
2002
|
+
} catch {
|
|
2003
|
+
}
|
|
2004
|
+
spawnDaemon();
|
|
2005
|
+
} finally {
|
|
2006
|
+
releaseSpawnLock();
|
|
1294
2007
|
}
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
_socket = null;
|
|
1298
|
-
}
|
|
1299
|
-
_connected = false;
|
|
1300
|
-
_buffer = "";
|
|
2008
|
+
}
|
|
2009
|
+
function isDaemonTooYoung() {
|
|
1301
2010
|
try {
|
|
1302
|
-
|
|
2011
|
+
const stat = statSync(PID_PATH);
|
|
2012
|
+
return Date.now() - stat.mtimeMs < MIN_DAEMON_AGE_MS;
|
|
1303
2013
|
} catch {
|
|
2014
|
+
return false;
|
|
1304
2015
|
}
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
2016
|
+
}
|
|
2017
|
+
async function retryThenRestart(doRequest, label) {
|
|
2018
|
+
const result = await doRequest();
|
|
2019
|
+
if (!result.error) {
|
|
2020
|
+
_consecutiveFailures = 0;
|
|
2021
|
+
return result;
|
|
2022
|
+
}
|
|
2023
|
+
_consecutiveFailures++;
|
|
2024
|
+
for (let i = 0; i < MAX_RETRIES_BEFORE_RESTART; i++) {
|
|
2025
|
+
const delayMs = RETRY_DELAYS_MS[i] ?? 5e3;
|
|
2026
|
+
process.stderr.write(`[exed-client] ${label} failed (${result.error}), retry ${i + 1}/${MAX_RETRIES_BEFORE_RESTART} in ${delayMs}ms
|
|
2027
|
+
`);
|
|
2028
|
+
await new Promise((r) => setTimeout(r, delayMs));
|
|
2029
|
+
if (!_connected) {
|
|
2030
|
+
if (!await connectToSocket()) continue;
|
|
2031
|
+
}
|
|
2032
|
+
const retry = await doRequest();
|
|
2033
|
+
if (!retry.error) {
|
|
2034
|
+
_consecutiveFailures = 0;
|
|
2035
|
+
return retry;
|
|
2036
|
+
}
|
|
2037
|
+
_consecutiveFailures++;
|
|
2038
|
+
}
|
|
2039
|
+
if (isDaemonTooYoung()) {
|
|
2040
|
+
process.stderr.write(`[exed-client] ${label}: daemon too young (< ${MIN_DAEMON_AGE_MS / 1e3}s) \u2014 skipping restart
|
|
2041
|
+
`);
|
|
2042
|
+
return { error: result.error };
|
|
1308
2043
|
}
|
|
1309
|
-
|
|
2044
|
+
process.stderr.write(`[exed-client] ${label}: ${_consecutiveFailures} consecutive failures \u2014 restarting daemon
|
|
2045
|
+
`);
|
|
2046
|
+
killAndRespawnDaemon();
|
|
2047
|
+
const start = Date.now();
|
|
2048
|
+
let delay2 = 200;
|
|
2049
|
+
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
2050
|
+
await new Promise((r) => setTimeout(r, delay2));
|
|
2051
|
+
if (await connectToSocket()) break;
|
|
2052
|
+
delay2 = Math.min(delay2 * 2, 3e3);
|
|
2053
|
+
}
|
|
2054
|
+
if (!_connected) return { error: "Daemon restart failed" };
|
|
2055
|
+
const final = await doRequest();
|
|
2056
|
+
if (!final.error) _consecutiveFailures = 0;
|
|
2057
|
+
return final;
|
|
1310
2058
|
}
|
|
1311
2059
|
async function embedViaClient(text, priority = "high") {
|
|
1312
2060
|
if (!_connected && !await connectEmbedDaemon()) return null;
|
|
1313
2061
|
_requestCount++;
|
|
1314
2062
|
if (_requestCount % HEALTH_CHECK_INTERVAL === 0) {
|
|
1315
2063
|
const health = await pingDaemon();
|
|
1316
|
-
if (!health) {
|
|
2064
|
+
if (!health && !isDaemonTooYoung()) {
|
|
1317
2065
|
process.stderr.write(`[exed-client] Periodic health check failed at request ${_requestCount} \u2014 restarting daemon
|
|
1318
2066
|
`);
|
|
1319
2067
|
killAndRespawnDaemon();
|
|
1320
2068
|
const start = Date.now();
|
|
1321
|
-
let
|
|
2069
|
+
let d = 200;
|
|
1322
2070
|
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
1323
|
-
await new Promise((r) => setTimeout(r,
|
|
2071
|
+
await new Promise((r) => setTimeout(r, d));
|
|
1324
2072
|
if (await connectToSocket()) break;
|
|
1325
|
-
|
|
2073
|
+
d = Math.min(d * 2, 3e3);
|
|
1326
2074
|
}
|
|
1327
2075
|
if (!_connected) return null;
|
|
1328
2076
|
}
|
|
1329
2077
|
}
|
|
1330
|
-
const result = await
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
killAndRespawnDaemon();
|
|
1336
|
-
const start = Date.now();
|
|
1337
|
-
let delay2 = 200;
|
|
1338
|
-
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
1339
|
-
await new Promise((r) => setTimeout(r, delay2));
|
|
1340
|
-
if (await connectToSocket()) break;
|
|
1341
|
-
delay2 = Math.min(delay2 * 2, 3e3);
|
|
1342
|
-
}
|
|
1343
|
-
if (!_connected) return null;
|
|
1344
|
-
const retry = await sendRequest([text], priority);
|
|
1345
|
-
if (!retry.error && retry.vectors?.[0]) return retry.vectors[0];
|
|
1346
|
-
process.stderr.write(`[exed-client] Embed retry also failed: ${retry.error ?? "no vector"}
|
|
1347
|
-
`);
|
|
1348
|
-
}
|
|
1349
|
-
return null;
|
|
2078
|
+
const result = await retryThenRestart(
|
|
2079
|
+
() => sendRequest([text], priority),
|
|
2080
|
+
"Embed"
|
|
2081
|
+
);
|
|
2082
|
+
return !result.error && result.vectors?.[0] ? result.vectors[0] : null;
|
|
1350
2083
|
}
|
|
1351
2084
|
function disconnectClient() {
|
|
1352
2085
|
if (_socket) {
|
|
@@ -1364,14 +2097,14 @@ function disconnectClient() {
|
|
|
1364
2097
|
function isClientConnected() {
|
|
1365
2098
|
return _connected;
|
|
1366
2099
|
}
|
|
1367
|
-
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;
|
|
2100
|
+
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;
|
|
1368
2101
|
var init_exe_daemon_client = __esm({
|
|
1369
2102
|
"src/lib/exe-daemon-client.ts"() {
|
|
1370
2103
|
"use strict";
|
|
1371
2104
|
init_config();
|
|
1372
|
-
SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ??
|
|
1373
|
-
PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ??
|
|
1374
|
-
SPAWN_LOCK_PATH =
|
|
2105
|
+
SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path8.join(EXE_AI_DIR, "exed.sock");
|
|
2106
|
+
PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path8.join(EXE_AI_DIR, "exed.pid");
|
|
2107
|
+
SPAWN_LOCK_PATH = path8.join(EXE_AI_DIR, "exed-spawn.lock");
|
|
1375
2108
|
SPAWN_LOCK_STALE_MS = 3e4;
|
|
1376
2109
|
CONNECT_TIMEOUT_MS = 15e3;
|
|
1377
2110
|
REQUEST_TIMEOUT_MS = 3e4;
|
|
@@ -1379,7 +2112,11 @@ var init_exe_daemon_client = __esm({
|
|
|
1379
2112
|
_connected = false;
|
|
1380
2113
|
_buffer = "";
|
|
1381
2114
|
_requestCount = 0;
|
|
2115
|
+
_consecutiveFailures = 0;
|
|
1382
2116
|
HEALTH_CHECK_INTERVAL = 100;
|
|
2117
|
+
MAX_RETRIES_BEFORE_RESTART = 3;
|
|
2118
|
+
RETRY_DELAYS_MS = [1e3, 3e3, 5e3];
|
|
2119
|
+
MIN_DAEMON_AGE_MS = 3e4;
|
|
1383
2120
|
_pending = /* @__PURE__ */ new Map();
|
|
1384
2121
|
MAX_BUFFER = 1e7;
|
|
1385
2122
|
}
|
|
@@ -1455,7 +2192,7 @@ __export(db_daemon_client_exports, {
|
|
|
1455
2192
|
createDaemonDbClient: () => createDaemonDbClient,
|
|
1456
2193
|
initDaemonDbClient: () => initDaemonDbClient
|
|
1457
2194
|
});
|
|
1458
|
-
function
|
|
2195
|
+
function normalizeStatement2(stmt) {
|
|
1459
2196
|
if (typeof stmt === "string") {
|
|
1460
2197
|
return { sql: stmt, args: [] };
|
|
1461
2198
|
}
|
|
@@ -1479,7 +2216,7 @@ function createDaemonDbClient(fallbackClient) {
|
|
|
1479
2216
|
if (!_useDaemon || !isClientConnected()) {
|
|
1480
2217
|
return fallbackClient.execute(stmt);
|
|
1481
2218
|
}
|
|
1482
|
-
const { sql, args } =
|
|
2219
|
+
const { sql, args } = normalizeStatement2(stmt);
|
|
1483
2220
|
const response = await sendDaemonRequest({
|
|
1484
2221
|
type: "db-execute",
|
|
1485
2222
|
sql,
|
|
@@ -1504,7 +2241,7 @@ function createDaemonDbClient(fallbackClient) {
|
|
|
1504
2241
|
if (!_useDaemon || !isClientConnected()) {
|
|
1505
2242
|
return fallbackClient.batch(stmts, mode);
|
|
1506
2243
|
}
|
|
1507
|
-
const statements = stmts.map(
|
|
2244
|
+
const statements = stmts.map(normalizeStatement2);
|
|
1508
2245
|
const response = await sendDaemonRequest({
|
|
1509
2246
|
type: "db-batch",
|
|
1510
2247
|
statements,
|
|
@@ -1599,6 +2336,18 @@ __export(database_exports, {
|
|
|
1599
2336
|
});
|
|
1600
2337
|
import { createClient } from "@libsql/client";
|
|
1601
2338
|
async function initDatabase(config2) {
|
|
2339
|
+
if (_walCheckpointTimer) {
|
|
2340
|
+
clearInterval(_walCheckpointTimer);
|
|
2341
|
+
_walCheckpointTimer = null;
|
|
2342
|
+
}
|
|
2343
|
+
if (_daemonClient) {
|
|
2344
|
+
_daemonClient.close();
|
|
2345
|
+
_daemonClient = null;
|
|
2346
|
+
}
|
|
2347
|
+
if (_adapterClient && _adapterClient !== _resilientClient) {
|
|
2348
|
+
_adapterClient.close();
|
|
2349
|
+
}
|
|
2350
|
+
_adapterClient = null;
|
|
1602
2351
|
if (_client) {
|
|
1603
2352
|
_client.close();
|
|
1604
2353
|
_client = null;
|
|
@@ -1612,6 +2361,7 @@ async function initDatabase(config2) {
|
|
|
1612
2361
|
}
|
|
1613
2362
|
_client = createClient(opts);
|
|
1614
2363
|
_resilientClient = wrapWithRetry(_client);
|
|
2364
|
+
_adapterClient = _resilientClient;
|
|
1615
2365
|
_client.execute("PRAGMA busy_timeout = 30000").catch(() => {
|
|
1616
2366
|
});
|
|
1617
2367
|
_client.execute("PRAGMA journal_mode = WAL").catch(() => {
|
|
@@ -1622,14 +2372,20 @@ async function initDatabase(config2) {
|
|
|
1622
2372
|
});
|
|
1623
2373
|
}, 3e4);
|
|
1624
2374
|
_walCheckpointTimer.unref();
|
|
2375
|
+
if (process.env.DATABASE_URL) {
|
|
2376
|
+
_adapterClient = await createPrismaDbAdapter(_resilientClient);
|
|
2377
|
+
}
|
|
1625
2378
|
}
|
|
1626
2379
|
function isInitialized() {
|
|
1627
|
-
return _client !== null;
|
|
2380
|
+
return _adapterClient !== null || _client !== null;
|
|
1628
2381
|
}
|
|
1629
2382
|
function getClient() {
|
|
1630
|
-
if (!
|
|
2383
|
+
if (!_adapterClient) {
|
|
1631
2384
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
1632
2385
|
}
|
|
2386
|
+
if (process.env.DATABASE_URL) {
|
|
2387
|
+
return _adapterClient;
|
|
2388
|
+
}
|
|
1633
2389
|
if (process.env.EXE_IS_DAEMON === "1") {
|
|
1634
2390
|
return _resilientClient;
|
|
1635
2391
|
}
|
|
@@ -1639,6 +2395,7 @@ function getClient() {
|
|
|
1639
2395
|
return _resilientClient;
|
|
1640
2396
|
}
|
|
1641
2397
|
async function initDaemonClient() {
|
|
2398
|
+
if (process.env.DATABASE_URL) return;
|
|
1642
2399
|
if (process.env.EXE_IS_DAEMON === "1") return;
|
|
1643
2400
|
if (!_resilientClient) return;
|
|
1644
2401
|
try {
|
|
@@ -2583,26 +3340,36 @@ async function ensureSchema() {
|
|
|
2583
3340
|
}
|
|
2584
3341
|
}
|
|
2585
3342
|
async function disposeDatabase() {
|
|
3343
|
+
if (_walCheckpointTimer) {
|
|
3344
|
+
clearInterval(_walCheckpointTimer);
|
|
3345
|
+
_walCheckpointTimer = null;
|
|
3346
|
+
}
|
|
2586
3347
|
if (_daemonClient) {
|
|
2587
3348
|
_daemonClient.close();
|
|
2588
3349
|
_daemonClient = null;
|
|
2589
3350
|
}
|
|
3351
|
+
if (_adapterClient && _adapterClient !== _resilientClient) {
|
|
3352
|
+
_adapterClient.close();
|
|
3353
|
+
}
|
|
3354
|
+
_adapterClient = null;
|
|
2590
3355
|
if (_client) {
|
|
2591
3356
|
_client.close();
|
|
2592
3357
|
_client = null;
|
|
2593
3358
|
_resilientClient = null;
|
|
2594
3359
|
}
|
|
2595
3360
|
}
|
|
2596
|
-
var _client, _resilientClient, _walCheckpointTimer, _daemonClient, initTurso, disposeTurso;
|
|
3361
|
+
var _client, _resilientClient, _walCheckpointTimer, _daemonClient, _adapterClient, initTurso, disposeTurso;
|
|
2597
3362
|
var init_database = __esm({
|
|
2598
3363
|
"src/lib/database.ts"() {
|
|
2599
3364
|
"use strict";
|
|
2600
3365
|
init_db_retry();
|
|
2601
3366
|
init_employees();
|
|
3367
|
+
init_database_adapter();
|
|
2602
3368
|
_client = null;
|
|
2603
3369
|
_resilientClient = null;
|
|
2604
3370
|
_walCheckpointTimer = null;
|
|
2605
3371
|
_daemonClient = null;
|
|
3372
|
+
_adapterClient = null;
|
|
2606
3373
|
initTurso = initDatabase;
|
|
2607
3374
|
disposeTurso = disposeDatabase;
|
|
2608
3375
|
}
|
|
@@ -2611,16 +3378,16 @@ var init_database = __esm({
|
|
|
2611
3378
|
// src/lib/license.ts
|
|
2612
3379
|
import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, existsSync as existsSync7, mkdirSync as mkdirSync4 } from "fs";
|
|
2613
3380
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
2614
|
-
import
|
|
3381
|
+
import path9 from "path";
|
|
2615
3382
|
import { jwtVerify, importSPKI } from "jose";
|
|
2616
3383
|
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, PLAN_LIMITS;
|
|
2617
3384
|
var init_license = __esm({
|
|
2618
3385
|
"src/lib/license.ts"() {
|
|
2619
3386
|
"use strict";
|
|
2620
3387
|
init_config();
|
|
2621
|
-
LICENSE_PATH =
|
|
2622
|
-
CACHE_PATH =
|
|
2623
|
-
DEVICE_ID_PATH =
|
|
3388
|
+
LICENSE_PATH = path9.join(EXE_AI_DIR, "license.key");
|
|
3389
|
+
CACHE_PATH = path9.join(EXE_AI_DIR, "license-cache.json");
|
|
3390
|
+
DEVICE_ID_PATH = path9.join(EXE_AI_DIR, "device-id");
|
|
2624
3391
|
PLAN_LIMITS = {
|
|
2625
3392
|
free: { devices: 1, employees: 1, memories: 5e3 },
|
|
2626
3393
|
pro: { devices: 3, employees: 5, memories: 1e5 },
|
|
@@ -2633,7 +3400,7 @@ var init_license = __esm({
|
|
|
2633
3400
|
|
|
2634
3401
|
// src/lib/plan-limits.ts
|
|
2635
3402
|
import { readFileSync as readFileSync8, existsSync as existsSync8 } from "fs";
|
|
2636
|
-
import
|
|
3403
|
+
import path10 from "path";
|
|
2637
3404
|
function getLicenseSync() {
|
|
2638
3405
|
try {
|
|
2639
3406
|
if (!existsSync8(CACHE_PATH2)) return freeLicense();
|
|
@@ -2705,14 +3472,14 @@ var init_plan_limits = __esm({
|
|
|
2705
3472
|
this.name = "PlanLimitError";
|
|
2706
3473
|
}
|
|
2707
3474
|
};
|
|
2708
|
-
CACHE_PATH2 =
|
|
3475
|
+
CACHE_PATH2 = path10.join(EXE_AI_DIR, "license-cache.json");
|
|
2709
3476
|
}
|
|
2710
3477
|
});
|
|
2711
3478
|
|
|
2712
3479
|
// src/lib/notifications.ts
|
|
2713
3480
|
import crypto from "crypto";
|
|
2714
|
-
import
|
|
2715
|
-
import
|
|
3481
|
+
import path11 from "path";
|
|
3482
|
+
import os8 from "os";
|
|
2716
3483
|
import {
|
|
2717
3484
|
readFileSync as readFileSync9,
|
|
2718
3485
|
readdirSync,
|
|
@@ -2881,8 +3648,8 @@ var init_state_bus = __esm({
|
|
|
2881
3648
|
|
|
2882
3649
|
// src/lib/tasks-crud.ts
|
|
2883
3650
|
import crypto3 from "crypto";
|
|
2884
|
-
import
|
|
2885
|
-
import
|
|
3651
|
+
import path12 from "path";
|
|
3652
|
+
import os9 from "os";
|
|
2886
3653
|
import { execSync as execSync5 } from "child_process";
|
|
2887
3654
|
import { mkdir as mkdir3, writeFile as writeFile3, appendFile } from "fs/promises";
|
|
2888
3655
|
import { existsSync as existsSync10, readFileSync as readFileSync10 } from "fs";
|
|
@@ -3060,8 +3827,8 @@ ${laneWarning}` : laneWarning;
|
|
|
3060
3827
|
}
|
|
3061
3828
|
if (input.baseDir) {
|
|
3062
3829
|
try {
|
|
3063
|
-
await mkdir3(
|
|
3064
|
-
await mkdir3(
|
|
3830
|
+
await mkdir3(path12.join(input.baseDir, "exe", "output"), { recursive: true });
|
|
3831
|
+
await mkdir3(path12.join(input.baseDir, "exe", "research"), { recursive: true });
|
|
3065
3832
|
await ensureArchitectureDoc(input.baseDir, input.projectName);
|
|
3066
3833
|
await ensureGitignoreExe(input.baseDir);
|
|
3067
3834
|
} catch {
|
|
@@ -3097,9 +3864,9 @@ ${laneWarning}` : laneWarning;
|
|
|
3097
3864
|
});
|
|
3098
3865
|
if (input.baseDir) {
|
|
3099
3866
|
try {
|
|
3100
|
-
const EXE_OS_DIR =
|
|
3101
|
-
const mdPath =
|
|
3102
|
-
const mdDir =
|
|
3867
|
+
const EXE_OS_DIR = path12.join(os9.homedir(), ".exe-os");
|
|
3868
|
+
const mdPath = path12.join(EXE_OS_DIR, taskFile);
|
|
3869
|
+
const mdDir = path12.dirname(mdPath);
|
|
3103
3870
|
if (!existsSync10(mdDir)) await mkdir3(mdDir, { recursive: true });
|
|
3104
3871
|
const reviewer = input.reviewer ?? input.assignedBy;
|
|
3105
3872
|
const mdContent = `# ${input.title}
|
|
@@ -3400,7 +4167,7 @@ async function deleteTaskCore(taskId, _baseDir) {
|
|
|
3400
4167
|
return { taskFile, assignedTo, assignedBy, taskSlug };
|
|
3401
4168
|
}
|
|
3402
4169
|
async function ensureArchitectureDoc(baseDir, projectName) {
|
|
3403
|
-
const archPath =
|
|
4170
|
+
const archPath = path12.join(baseDir, "exe", "ARCHITECTURE.md");
|
|
3404
4171
|
try {
|
|
3405
4172
|
if (existsSync10(archPath)) return;
|
|
3406
4173
|
const template = [
|
|
@@ -3435,7 +4202,7 @@ async function ensureArchitectureDoc(baseDir, projectName) {
|
|
|
3435
4202
|
}
|
|
3436
4203
|
}
|
|
3437
4204
|
async function ensureGitignoreExe(baseDir) {
|
|
3438
|
-
const gitignorePath =
|
|
4205
|
+
const gitignorePath = path12.join(baseDir, ".gitignore");
|
|
3439
4206
|
try {
|
|
3440
4207
|
if (existsSync10(gitignorePath)) {
|
|
3441
4208
|
const content = readFileSync10(gitignorePath, "utf-8");
|
|
@@ -3469,13 +4236,13 @@ var init_tasks_crud = __esm({
|
|
|
3469
4236
|
});
|
|
3470
4237
|
|
|
3471
4238
|
// src/lib/tasks-review.ts
|
|
3472
|
-
import
|
|
4239
|
+
import path13 from "path";
|
|
3473
4240
|
import { existsSync as existsSync11, readdirSync as readdirSync2, unlinkSync as unlinkSync4 } from "fs";
|
|
3474
4241
|
async function countPendingReviews(sessionScope) {
|
|
3475
4242
|
const client = getClient();
|
|
3476
4243
|
if (sessionScope) {
|
|
3477
4244
|
const result2 = await client.execute({
|
|
3478
|
-
sql: "SELECT COUNT(*) as cnt FROM tasks WHERE status = 'needs_review' AND
|
|
4245
|
+
sql: "SELECT COUNT(*) as cnt FROM tasks WHERE status = 'needs_review' AND session_scope = ?",
|
|
3479
4246
|
args: [sessionScope]
|
|
3480
4247
|
});
|
|
3481
4248
|
return Number(result2.rows[0]?.cnt) || 0;
|
|
@@ -3651,11 +4418,11 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
|
|
|
3651
4418
|
);
|
|
3652
4419
|
}
|
|
3653
4420
|
try {
|
|
3654
|
-
const cacheDir =
|
|
4421
|
+
const cacheDir = path13.join(EXE_AI_DIR, "session-cache");
|
|
3655
4422
|
if (existsSync11(cacheDir)) {
|
|
3656
4423
|
for (const f of readdirSync2(cacheDir)) {
|
|
3657
4424
|
if (f.startsWith("review-notified-")) {
|
|
3658
|
-
unlinkSync4(
|
|
4425
|
+
unlinkSync4(path13.join(cacheDir, f));
|
|
3659
4426
|
}
|
|
3660
4427
|
}
|
|
3661
4428
|
}
|
|
@@ -3676,7 +4443,7 @@ var init_tasks_review = __esm({
|
|
|
3676
4443
|
});
|
|
3677
4444
|
|
|
3678
4445
|
// src/lib/tasks-chain.ts
|
|
3679
|
-
import
|
|
4446
|
+
import path14 from "path";
|
|
3680
4447
|
import { readFile as readFile3, writeFile as writeFile4 } from "fs/promises";
|
|
3681
4448
|
async function cascadeUnblock(taskId, baseDir, now) {
|
|
3682
4449
|
const client = getClient();
|
|
@@ -3693,7 +4460,7 @@ async function cascadeUnblock(taskId, baseDir, now) {
|
|
|
3693
4460
|
});
|
|
3694
4461
|
for (const ur of unblockedRows.rows) {
|
|
3695
4462
|
try {
|
|
3696
|
-
const ubFile =
|
|
4463
|
+
const ubFile = path14.join(baseDir, String(ur.task_file));
|
|
3697
4464
|
let ubContent = await readFile3(ubFile, "utf-8");
|
|
3698
4465
|
ubContent = ubContent.replace(/\*\*Status:\*\* blocked/, "**Status:** open");
|
|
3699
4466
|
ubContent = ubContent.replace(/\n\*\*Blocked by:\*\*.*\n/, "\n");
|
|
@@ -3762,7 +4529,7 @@ var init_tasks_chain = __esm({
|
|
|
3762
4529
|
|
|
3763
4530
|
// src/lib/project-name.ts
|
|
3764
4531
|
import { execSync as execSync6 } from "child_process";
|
|
3765
|
-
import
|
|
4532
|
+
import path15 from "path";
|
|
3766
4533
|
function getProjectName(cwd) {
|
|
3767
4534
|
const dir = cwd ?? process.cwd();
|
|
3768
4535
|
if (_cached2 && _cachedCwd === dir) return _cached2;
|
|
@@ -3775,7 +4542,7 @@ function getProjectName(cwd) {
|
|
|
3775
4542
|
timeout: 2e3,
|
|
3776
4543
|
stdio: ["pipe", "pipe", "pipe"]
|
|
3777
4544
|
}).trim();
|
|
3778
|
-
repoRoot =
|
|
4545
|
+
repoRoot = path15.dirname(gitCommonDir);
|
|
3779
4546
|
} catch {
|
|
3780
4547
|
repoRoot = execSync6("git rev-parse --show-toplevel", {
|
|
3781
4548
|
cwd: dir,
|
|
@@ -3784,11 +4551,11 @@ function getProjectName(cwd) {
|
|
|
3784
4551
|
stdio: ["pipe", "pipe", "pipe"]
|
|
3785
4552
|
}).trim();
|
|
3786
4553
|
}
|
|
3787
|
-
_cached2 =
|
|
4554
|
+
_cached2 = path15.basename(repoRoot);
|
|
3788
4555
|
_cachedCwd = dir;
|
|
3789
4556
|
return _cached2;
|
|
3790
4557
|
} catch {
|
|
3791
|
-
_cached2 =
|
|
4558
|
+
_cached2 = path15.basename(dir);
|
|
3792
4559
|
_cachedCwd = dir;
|
|
3793
4560
|
return _cached2;
|
|
3794
4561
|
}
|
|
@@ -4323,7 +5090,7 @@ __export(tasks_exports, {
|
|
|
4323
5090
|
updateTaskStatus: () => updateTaskStatus,
|
|
4324
5091
|
writeCheckpoint: () => writeCheckpoint
|
|
4325
5092
|
});
|
|
4326
|
-
import
|
|
5093
|
+
import path16 from "path";
|
|
4327
5094
|
import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, unlinkSync as unlinkSync5 } from "fs";
|
|
4328
5095
|
async function createTask(input) {
|
|
4329
5096
|
const result = await createTaskCore(input);
|
|
@@ -4343,8 +5110,8 @@ async function updateTask(input) {
|
|
|
4343
5110
|
const { row, taskFile, now, taskId } = await updateTaskStatus(input);
|
|
4344
5111
|
try {
|
|
4345
5112
|
const agent = String(row.assigned_to);
|
|
4346
|
-
const cacheDir =
|
|
4347
|
-
const cachePath =
|
|
5113
|
+
const cacheDir = path16.join(EXE_AI_DIR, "session-cache");
|
|
5114
|
+
const cachePath = path16.join(cacheDir, `current-task-${agent}.json`);
|
|
4348
5115
|
if (input.status === "in_progress") {
|
|
4349
5116
|
mkdirSync5(cacheDir, { recursive: true });
|
|
4350
5117
|
writeFileSync6(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
|
|
@@ -4815,12 +5582,12 @@ __export(tmux_routing_exports, {
|
|
|
4815
5582
|
});
|
|
4816
5583
|
import { execFileSync as execFileSync2, execSync as execSync7 } from "child_process";
|
|
4817
5584
|
import { readFileSync as readFileSync11, writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, existsSync as existsSync12, appendFileSync, readdirSync as readdirSync3 } from "fs";
|
|
4818
|
-
import
|
|
4819
|
-
import
|
|
5585
|
+
import path17 from "path";
|
|
5586
|
+
import os10 from "os";
|
|
4820
5587
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
4821
5588
|
import { unlinkSync as unlinkSync6 } from "fs";
|
|
4822
5589
|
function spawnLockPath(sessionName) {
|
|
4823
|
-
return
|
|
5590
|
+
return path17.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
|
|
4824
5591
|
}
|
|
4825
5592
|
function isProcessAlive(pid) {
|
|
4826
5593
|
try {
|
|
@@ -4857,8 +5624,8 @@ function releaseSpawnLock2(sessionName) {
|
|
|
4857
5624
|
function resolveBehaviorsExporterScript() {
|
|
4858
5625
|
try {
|
|
4859
5626
|
const thisFile = fileURLToPath2(import.meta.url);
|
|
4860
|
-
const scriptPath =
|
|
4861
|
-
|
|
5627
|
+
const scriptPath = path17.join(
|
|
5628
|
+
path17.dirname(thisFile),
|
|
4862
5629
|
"..",
|
|
4863
5630
|
"bin",
|
|
4864
5631
|
"exe-export-behaviors.js"
|
|
@@ -4933,7 +5700,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
|
4933
5700
|
mkdirSync6(SESSION_CACHE, { recursive: true });
|
|
4934
5701
|
}
|
|
4935
5702
|
const rootExe = extractRootExe(parentExe) ?? parentExe;
|
|
4936
|
-
const filePath =
|
|
5703
|
+
const filePath = path17.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
|
|
4937
5704
|
writeFileSync7(filePath, JSON.stringify({
|
|
4938
5705
|
parentExe: rootExe,
|
|
4939
5706
|
dispatchedBy: dispatchedBy || rootExe,
|
|
@@ -4942,7 +5709,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
|
4942
5709
|
}
|
|
4943
5710
|
function getParentExe(sessionKey) {
|
|
4944
5711
|
try {
|
|
4945
|
-
const data = JSON.parse(readFileSync11(
|
|
5712
|
+
const data = JSON.parse(readFileSync11(path17.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
4946
5713
|
return data.parentExe || null;
|
|
4947
5714
|
} catch {
|
|
4948
5715
|
return null;
|
|
@@ -4951,7 +5718,7 @@ function getParentExe(sessionKey) {
|
|
|
4951
5718
|
function getDispatchedBy(sessionKey) {
|
|
4952
5719
|
try {
|
|
4953
5720
|
const data = JSON.parse(readFileSync11(
|
|
4954
|
-
|
|
5721
|
+
path17.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
|
|
4955
5722
|
"utf8"
|
|
4956
5723
|
));
|
|
4957
5724
|
return data.dispatchedBy ?? data.parentExe ?? null;
|
|
@@ -5137,7 +5904,7 @@ function sendIntercom(targetSession) {
|
|
|
5137
5904
|
try {
|
|
5138
5905
|
const rawAgent = targetSession.split("-")[0] ?? targetSession;
|
|
5139
5906
|
const agent = baseAgentName(rawAgent);
|
|
5140
|
-
const markerPath =
|
|
5907
|
+
const markerPath = path17.join(SESSION_CACHE, `current-task-${agent}.json`);
|
|
5141
5908
|
if (existsSync12(markerPath)) {
|
|
5142
5909
|
logIntercom(`SKIP \u2192 ${targetSession} (has in_progress task marker \u2014 will auto-chain)`);
|
|
5143
5910
|
return "debounced";
|
|
@@ -5147,7 +5914,7 @@ function sendIntercom(targetSession) {
|
|
|
5147
5914
|
try {
|
|
5148
5915
|
const rawAgent = targetSession.split("-")[0] ?? targetSession;
|
|
5149
5916
|
const agent = baseAgentName(rawAgent);
|
|
5150
|
-
const taskDir =
|
|
5917
|
+
const taskDir = path17.join(process.cwd(), "exe", agent);
|
|
5151
5918
|
if (existsSync12(taskDir)) {
|
|
5152
5919
|
const files = readdirSync3(taskDir).filter(
|
|
5153
5920
|
(f) => f.endsWith(".md") && f !== "DONE.txt"
|
|
@@ -5281,8 +6048,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
5281
6048
|
const transport = getTransport();
|
|
5282
6049
|
const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
|
|
5283
6050
|
const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
|
|
5284
|
-
const logDir =
|
|
5285
|
-
const logFile =
|
|
6051
|
+
const logDir = path17.join(os10.homedir(), ".exe-os", "session-logs");
|
|
6052
|
+
const logFile = path17.join(logDir, `${instanceLabel}-${Date.now()}.log`);
|
|
5286
6053
|
if (!existsSync12(logDir)) {
|
|
5287
6054
|
mkdirSync6(logDir, { recursive: true });
|
|
5288
6055
|
}
|
|
@@ -5290,14 +6057,14 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
5290
6057
|
let cleanupSuffix = "";
|
|
5291
6058
|
try {
|
|
5292
6059
|
const thisFile = fileURLToPath2(import.meta.url);
|
|
5293
|
-
const cleanupScript =
|
|
6060
|
+
const cleanupScript = path17.join(path17.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
|
|
5294
6061
|
if (existsSync12(cleanupScript)) {
|
|
5295
6062
|
cleanupSuffix = `; ${process.execPath} "${cleanupScript}" "${employeeName}" "${exeSession}"`;
|
|
5296
6063
|
}
|
|
5297
6064
|
} catch {
|
|
5298
6065
|
}
|
|
5299
6066
|
try {
|
|
5300
|
-
const claudeJsonPath =
|
|
6067
|
+
const claudeJsonPath = path17.join(os10.homedir(), ".claude.json");
|
|
5301
6068
|
let claudeJson = {};
|
|
5302
6069
|
try {
|
|
5303
6070
|
claudeJson = JSON.parse(readFileSync11(claudeJsonPath, "utf8"));
|
|
@@ -5312,10 +6079,10 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
5312
6079
|
} catch {
|
|
5313
6080
|
}
|
|
5314
6081
|
try {
|
|
5315
|
-
const settingsDir =
|
|
6082
|
+
const settingsDir = path17.join(os10.homedir(), ".claude", "projects");
|
|
5316
6083
|
const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
|
|
5317
|
-
const projSettingsDir =
|
|
5318
|
-
const settingsPath =
|
|
6084
|
+
const projSettingsDir = path17.join(settingsDir, normalizedKey);
|
|
6085
|
+
const settingsPath = path17.join(projSettingsDir, "settings.json");
|
|
5319
6086
|
let settings = {};
|
|
5320
6087
|
try {
|
|
5321
6088
|
settings = JSON.parse(readFileSync11(settingsPath, "utf8"));
|
|
@@ -5362,8 +6129,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
5362
6129
|
let behaviorsFlag = "";
|
|
5363
6130
|
let legacyFallbackWarned = false;
|
|
5364
6131
|
if (!useExeAgent && !useBinSymlink) {
|
|
5365
|
-
const identityPath =
|
|
5366
|
-
|
|
6132
|
+
const identityPath = path17.join(
|
|
6133
|
+
os10.homedir(),
|
|
5367
6134
|
".exe-os",
|
|
5368
6135
|
"identity",
|
|
5369
6136
|
`${employeeName}.md`
|
|
@@ -5378,7 +6145,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
5378
6145
|
}
|
|
5379
6146
|
const behaviorsFile = exportBehaviorsSync(
|
|
5380
6147
|
employeeName,
|
|
5381
|
-
|
|
6148
|
+
path17.basename(spawnCwd),
|
|
5382
6149
|
sessionName
|
|
5383
6150
|
);
|
|
5384
6151
|
if (behaviorsFile) {
|
|
@@ -5393,9 +6160,9 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
5393
6160
|
}
|
|
5394
6161
|
let sessionContextFlag = "";
|
|
5395
6162
|
try {
|
|
5396
|
-
const ctxDir =
|
|
6163
|
+
const ctxDir = path17.join(os10.homedir(), ".exe-os", "session-cache");
|
|
5397
6164
|
mkdirSync6(ctxDir, { recursive: true });
|
|
5398
|
-
const ctxFile =
|
|
6165
|
+
const ctxFile = path17.join(ctxDir, `session-context-${sessionName}.md`);
|
|
5399
6166
|
const ctxContent = [
|
|
5400
6167
|
`## Session Context`,
|
|
5401
6168
|
`You are running in tmux session: ${sessionName}.`,
|
|
@@ -5479,7 +6246,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
5479
6246
|
transport.pipeLog(sessionName, logFile);
|
|
5480
6247
|
try {
|
|
5481
6248
|
const mySession = getMySession();
|
|
5482
|
-
const dispatchInfo =
|
|
6249
|
+
const dispatchInfo = path17.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
|
|
5483
6250
|
writeFileSync7(dispatchInfo, JSON.stringify({
|
|
5484
6251
|
dispatchedBy: mySession,
|
|
5485
6252
|
rootExe: exeSession,
|
|
@@ -5554,15 +6321,15 @@ var init_tmux_routing = __esm({
|
|
|
5554
6321
|
init_intercom_queue();
|
|
5555
6322
|
init_plan_limits();
|
|
5556
6323
|
init_employees();
|
|
5557
|
-
SPAWN_LOCK_DIR =
|
|
5558
|
-
SESSION_CACHE =
|
|
6324
|
+
SPAWN_LOCK_DIR = path17.join(os10.homedir(), ".exe-os", "spawn-locks");
|
|
6325
|
+
SESSION_CACHE = path17.join(os10.homedir(), ".exe-os", "session-cache");
|
|
5559
6326
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
5560
6327
|
VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
|
|
5561
6328
|
VERIFY_PANE_LINES = 200;
|
|
5562
6329
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
5563
6330
|
CODEX_DEBOUNCE_MS = 12e4;
|
|
5564
|
-
INTERCOM_LOG2 =
|
|
5565
|
-
DEBOUNCE_FILE =
|
|
6331
|
+
INTERCOM_LOG2 = path17.join(os10.homedir(), ".exe-os", "intercom.log");
|
|
6332
|
+
DEBOUNCE_FILE = path17.join(SESSION_CACHE, "intercom-debounce.json");
|
|
5566
6333
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
5567
6334
|
BUSY_PATTERN = /[✻✽✶✳·].*…|Running…|• Working|• Ran |• Explored|• Called|esc to interrupt/;
|
|
5568
6335
|
}
|
|
@@ -5580,13 +6347,13 @@ var init_memory = __esm({
|
|
|
5580
6347
|
// src/lib/keychain.ts
|
|
5581
6348
|
import { readFile as readFile4, writeFile as writeFile5, unlink, mkdir as mkdir4, chmod as chmod2 } from "fs/promises";
|
|
5582
6349
|
import { existsSync as existsSync13 } from "fs";
|
|
5583
|
-
import
|
|
5584
|
-
import
|
|
6350
|
+
import path18 from "path";
|
|
6351
|
+
import os11 from "os";
|
|
5585
6352
|
function getKeyDir() {
|
|
5586
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ??
|
|
6353
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path18.join(os11.homedir(), ".exe-os");
|
|
5587
6354
|
}
|
|
5588
6355
|
function getKeyPath() {
|
|
5589
|
-
return
|
|
6356
|
+
return path18.join(getKeyDir(), "master.key");
|
|
5590
6357
|
}
|
|
5591
6358
|
async function tryKeytar() {
|
|
5592
6359
|
try {
|
|
@@ -5609,7 +6376,7 @@ async function getMasterKey() {
|
|
|
5609
6376
|
const keyPath = getKeyPath();
|
|
5610
6377
|
if (!existsSync13(keyPath)) {
|
|
5611
6378
|
process.stderr.write(
|
|
5612
|
-
`[keychain] Key not found at ${keyPath} (HOME=${
|
|
6379
|
+
`[keychain] Key not found at ${keyPath} (HOME=${os11.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
|
|
5613
6380
|
`
|
|
5614
6381
|
);
|
|
5615
6382
|
return null;
|
|
@@ -5647,7 +6414,7 @@ __export(shard_manager_exports, {
|
|
|
5647
6414
|
listShards: () => listShards,
|
|
5648
6415
|
shardExists: () => shardExists
|
|
5649
6416
|
});
|
|
5650
|
-
import
|
|
6417
|
+
import path19 from "path";
|
|
5651
6418
|
import { existsSync as existsSync14, mkdirSync as mkdirSync7, readdirSync as readdirSync4 } from "fs";
|
|
5652
6419
|
import { createClient as createClient2 } from "@libsql/client";
|
|
5653
6420
|
function initShardManager(encryptionKey) {
|
|
@@ -5673,7 +6440,7 @@ function getShardClient(projectName) {
|
|
|
5673
6440
|
}
|
|
5674
6441
|
const cached = _shards.get(safeName);
|
|
5675
6442
|
if (cached) return cached;
|
|
5676
|
-
const dbPath =
|
|
6443
|
+
const dbPath = path19.join(SHARDS_DIR, `${safeName}.db`);
|
|
5677
6444
|
const client = createClient2({
|
|
5678
6445
|
url: `file:${dbPath}`,
|
|
5679
6446
|
encryptionKey: _encryptionKey
|
|
@@ -5683,7 +6450,7 @@ function getShardClient(projectName) {
|
|
|
5683
6450
|
}
|
|
5684
6451
|
function shardExists(projectName) {
|
|
5685
6452
|
const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
5686
|
-
return existsSync14(
|
|
6453
|
+
return existsSync14(path19.join(SHARDS_DIR, `${safeName}.db`));
|
|
5687
6454
|
}
|
|
5688
6455
|
function listShards() {
|
|
5689
6456
|
if (!existsSync14(SHARDS_DIR)) return [];
|
|
@@ -5760,7 +6527,23 @@ async function ensureShardSchema(client) {
|
|
|
5760
6527
|
// MS-11: draft staging, MS-6a: memory_type, MS-7: trajectory
|
|
5761
6528
|
"ALTER TABLE memories ADD COLUMN draft INTEGER DEFAULT 0",
|
|
5762
6529
|
"ALTER TABLE memories ADD COLUMN memory_type TEXT DEFAULT 'raw'",
|
|
5763
|
-
"ALTER TABLE memories ADD COLUMN trajectory TEXT"
|
|
6530
|
+
"ALTER TABLE memories ADD COLUMN trajectory TEXT",
|
|
6531
|
+
// Metadata enrichment columns (must match database.ts)
|
|
6532
|
+
"ALTER TABLE memories ADD COLUMN intent TEXT",
|
|
6533
|
+
"ALTER TABLE memories ADD COLUMN outcome TEXT",
|
|
6534
|
+
"ALTER TABLE memories ADD COLUMN domain TEXT",
|
|
6535
|
+
"ALTER TABLE memories ADD COLUMN referenced_entities TEXT",
|
|
6536
|
+
"ALTER TABLE memories ADD COLUMN retrieval_count INTEGER DEFAULT 0",
|
|
6537
|
+
"ALTER TABLE memories ADD COLUMN chain_position TEXT",
|
|
6538
|
+
"ALTER TABLE memories ADD COLUMN review_status TEXT",
|
|
6539
|
+
"ALTER TABLE memories ADD COLUMN context_window_pct INTEGER",
|
|
6540
|
+
"ALTER TABLE memories ADD COLUMN file_paths TEXT",
|
|
6541
|
+
"ALTER TABLE memories ADD COLUMN commit_hash TEXT",
|
|
6542
|
+
"ALTER TABLE memories ADD COLUMN duration_ms INTEGER",
|
|
6543
|
+
"ALTER TABLE memories ADD COLUMN token_cost REAL",
|
|
6544
|
+
"ALTER TABLE memories ADD COLUMN audience TEXT",
|
|
6545
|
+
"ALTER TABLE memories ADD COLUMN language_type TEXT",
|
|
6546
|
+
"ALTER TABLE memories ADD COLUMN parent_memory_id TEXT"
|
|
5764
6547
|
]) {
|
|
5765
6548
|
try {
|
|
5766
6549
|
await client.execute(col);
|
|
@@ -5872,7 +6655,7 @@ var init_shard_manager = __esm({
|
|
|
5872
6655
|
"src/lib/shard-manager.ts"() {
|
|
5873
6656
|
"use strict";
|
|
5874
6657
|
init_config();
|
|
5875
|
-
SHARDS_DIR =
|
|
6658
|
+
SHARDS_DIR = path19.join(EXE_AI_DIR, "shards");
|
|
5876
6659
|
_shards = /* @__PURE__ */ new Map();
|
|
5877
6660
|
_encryptionKey = null;
|
|
5878
6661
|
_shardingEnabled = false;
|
|
@@ -6736,9 +7519,9 @@ function extractBash(input, response) {
|
|
|
6736
7519
|
}
|
|
6737
7520
|
function extractGrep(input, response) {
|
|
6738
7521
|
const pattern = String(input.pattern ?? "");
|
|
6739
|
-
const
|
|
7522
|
+
const path22 = input.path ? String(input.path) : "";
|
|
6740
7523
|
const output = String(response.text ?? response.content ?? JSON.stringify(response).slice(0, MAX_OUTPUT));
|
|
6741
|
-
return `Searched for "${pattern}"${
|
|
7524
|
+
return `Searched for "${pattern}"${path22 ? ` in ${path22}` : ""}
|
|
6742
7525
|
${output.slice(0, MAX_OUTPUT)}`;
|
|
6743
7526
|
}
|
|
6744
7527
|
function extractGlob(input, response) {
|
|
@@ -7277,8 +8060,8 @@ async function embedDirect(text) {
|
|
|
7277
8060
|
const llamaCpp = await import("node-llama-cpp");
|
|
7278
8061
|
const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
7279
8062
|
const { existsSync: existsSync16 } = await import("fs");
|
|
7280
|
-
const
|
|
7281
|
-
const modelPath =
|
|
8063
|
+
const path22 = await import("path");
|
|
8064
|
+
const modelPath = path22.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
|
|
7282
8065
|
if (!existsSync16(modelPath)) {
|
|
7283
8066
|
throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
|
|
7284
8067
|
}
|
|
@@ -7316,8 +8099,8 @@ __export(wiki_client_exports, {
|
|
|
7316
8099
|
listDocuments: () => listDocuments,
|
|
7317
8100
|
listWorkspaces: () => listWorkspaces
|
|
7318
8101
|
});
|
|
7319
|
-
async function wikiFetch(config2,
|
|
7320
|
-
const url = `${config2.baseUrl}/api/v1${
|
|
8102
|
+
async function wikiFetch(config2, path22, method = "GET", body) {
|
|
8103
|
+
const url = `${config2.baseUrl}/api/v1${path22}`;
|
|
7321
8104
|
const headers = {
|
|
7322
8105
|
Authorization: `Bearer ${config2.apiKey}`,
|
|
7323
8106
|
"Content-Type": "application/json"
|
|
@@ -7350,7 +8133,7 @@ async function wikiFetch(config2, path21, method = "GET", body) {
|
|
|
7350
8133
|
}
|
|
7351
8134
|
}
|
|
7352
8135
|
if (!response.ok) {
|
|
7353
|
-
throw new Error(`Wiki API ${method} ${
|
|
8136
|
+
throw new Error(`Wiki API ${method} ${path22}: ${response.status} ${response.statusText}`);
|
|
7354
8137
|
}
|
|
7355
8138
|
return response.json();
|
|
7356
8139
|
} finally {
|
|
@@ -13877,12 +14660,12 @@ var SlackAdapter = class {
|
|
|
13877
14660
|
// src/gateway/adapters/imessage.ts
|
|
13878
14661
|
import { execFile } from "child_process";
|
|
13879
14662
|
import { promisify } from "util";
|
|
13880
|
-
import
|
|
13881
|
-
import
|
|
14663
|
+
import os12 from "os";
|
|
14664
|
+
import path20 from "path";
|
|
13882
14665
|
var execFileAsync = promisify(execFile);
|
|
13883
14666
|
var POLL_INTERVAL_MS = 5e3;
|
|
13884
|
-
var MESSAGES_DB_PATH =
|
|
13885
|
-
process.env.HOME ??
|
|
14667
|
+
var MESSAGES_DB_PATH = path20.join(
|
|
14668
|
+
process.env.HOME ?? os12.homedir(),
|
|
13886
14669
|
"Library/Messages/chat.db"
|
|
13887
14670
|
);
|
|
13888
14671
|
var IMessageAdapter = class {
|
|
@@ -14727,9 +15510,9 @@ async function ensureCRMContact(info) {
|
|
|
14727
15510
|
// src/automation/trigger-engine.ts
|
|
14728
15511
|
import { readFileSync as readFileSync13, writeFileSync as writeFileSync8, existsSync as existsSync15, mkdirSync as mkdirSync9 } from "fs";
|
|
14729
15512
|
import { randomUUID as randomUUID15 } from "crypto";
|
|
14730
|
-
import
|
|
14731
|
-
import
|
|
14732
|
-
var TRIGGERS_PATH =
|
|
15513
|
+
import path21 from "path";
|
|
15514
|
+
import os13 from "os";
|
|
15515
|
+
var TRIGGERS_PATH = path21.join(os13.homedir(), ".exe-os", "triggers.json");
|
|
14733
15516
|
var GRAPH_API_VERSION = "v21.0";
|
|
14734
15517
|
function substituteTemplate(template, record) {
|
|
14735
15518
|
return template.replace(
|