@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/exe-boot.js
CHANGED
|
@@ -368,7 +368,7 @@ function registerBinSymlinks(name) {
|
|
|
368
368
|
}
|
|
369
369
|
return { created, skipped, errors };
|
|
370
370
|
}
|
|
371
|
-
var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES;
|
|
371
|
+
var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES, IDENTITY_DIR;
|
|
372
372
|
var init_employees = __esm({
|
|
373
373
|
"src/lib/employees.ts"() {
|
|
374
374
|
"use strict";
|
|
@@ -377,6 +377,7 @@ var init_employees = __esm({
|
|
|
377
377
|
DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
|
|
378
378
|
COORDINATOR_ROLE = "COO";
|
|
379
379
|
MULTI_INSTANCE_ROLES = /* @__PURE__ */ new Set(["principal engineer", "content production specialist", "staff code reviewer"]);
|
|
380
|
+
IDENTITY_DIR = path2.join(EXE_AI_DIR, "identity");
|
|
380
381
|
}
|
|
381
382
|
});
|
|
382
383
|
|
|
@@ -435,13 +436,597 @@ var init_db_retry = __esm({
|
|
|
435
436
|
}
|
|
436
437
|
});
|
|
437
438
|
|
|
439
|
+
// src/lib/database-adapter.ts
|
|
440
|
+
import os3 from "os";
|
|
441
|
+
import path3 from "path";
|
|
442
|
+
import { createRequire } from "module";
|
|
443
|
+
import { pathToFileURL } from "url";
|
|
444
|
+
function quotedIdentifier(identifier) {
|
|
445
|
+
return `"${identifier.replace(/"/g, '""')}"`;
|
|
446
|
+
}
|
|
447
|
+
function unqualifiedTableName(name) {
|
|
448
|
+
const raw = name.trim().replace(/^"|"$/g, "");
|
|
449
|
+
const parts = raw.split(".");
|
|
450
|
+
return parts[parts.length - 1].replace(/^"|"$/g, "").toLowerCase();
|
|
451
|
+
}
|
|
452
|
+
function stripTrailingSemicolon(sql) {
|
|
453
|
+
return sql.trim().replace(/;+\s*$/u, "");
|
|
454
|
+
}
|
|
455
|
+
function appendClause(sql, clause) {
|
|
456
|
+
const trimmed = stripTrailingSemicolon(sql);
|
|
457
|
+
const returningMatch = /\sRETURNING\b[\s\S]*$/iu.exec(trimmed);
|
|
458
|
+
if (!returningMatch) {
|
|
459
|
+
return `${trimmed}${clause}`;
|
|
460
|
+
}
|
|
461
|
+
const idx = returningMatch.index;
|
|
462
|
+
return `${trimmed.slice(0, idx)}${clause}${trimmed.slice(idx)}`;
|
|
463
|
+
}
|
|
464
|
+
function normalizeStatement(stmt) {
|
|
465
|
+
if (typeof stmt === "string") {
|
|
466
|
+
return { kind: "positional", sql: stmt, args: [] };
|
|
467
|
+
}
|
|
468
|
+
const sql = stmt.sql;
|
|
469
|
+
if (Array.isArray(stmt.args) || stmt.args === void 0) {
|
|
470
|
+
return { kind: "positional", sql, args: stmt.args ?? [] };
|
|
471
|
+
}
|
|
472
|
+
return { kind: "named", sql, args: stmt.args };
|
|
473
|
+
}
|
|
474
|
+
function rewriteBooleanLiterals(sql) {
|
|
475
|
+
let out = sql;
|
|
476
|
+
for (const column of BOOLEAN_COLUMN_NAMES) {
|
|
477
|
+
const scoped = `((?:\\b[a-z_][a-z0-9_]*\\.)?${column})`;
|
|
478
|
+
out = out.replace(new RegExp(`${scoped}\\s*=\\s*0\\b`, "giu"), "$1 = FALSE");
|
|
479
|
+
out = out.replace(new RegExp(`${scoped}\\s*=\\s*1\\b`, "giu"), "$1 = TRUE");
|
|
480
|
+
out = out.replace(new RegExp(`${scoped}\\s*!=\\s*0\\b`, "giu"), "$1 != FALSE");
|
|
481
|
+
out = out.replace(new RegExp(`${scoped}\\s*!=\\s*1\\b`, "giu"), "$1 != TRUE");
|
|
482
|
+
out = out.replace(new RegExp(`${scoped}\\s*<>\\s*0\\b`, "giu"), "$1 <> FALSE");
|
|
483
|
+
out = out.replace(new RegExp(`${scoped}\\s*<>\\s*1\\b`, "giu"), "$1 <> TRUE");
|
|
484
|
+
}
|
|
485
|
+
return out;
|
|
486
|
+
}
|
|
487
|
+
function rewriteInsertOrIgnore(sql) {
|
|
488
|
+
if (!/^\s*INSERT\s+OR\s+IGNORE\s+INTO\b/iu.test(sql)) {
|
|
489
|
+
return sql;
|
|
490
|
+
}
|
|
491
|
+
const replaced = sql.replace(/^\s*INSERT\s+OR\s+IGNORE\s+INTO\b/iu, "INSERT INTO");
|
|
492
|
+
return /\bON\s+CONFLICT\b/iu.test(replaced) ? replaced : appendClause(replaced, " ON CONFLICT DO NOTHING");
|
|
493
|
+
}
|
|
494
|
+
function rewriteInsertOrReplace(sql) {
|
|
495
|
+
const match = /^\s*INSERT\s+OR\s+REPLACE\s+INTO\s+([A-Za-z0-9_."]+)\s*\(([^)]+)\)([\s\S]*)$/iu.exec(sql);
|
|
496
|
+
if (!match) {
|
|
497
|
+
return sql;
|
|
498
|
+
}
|
|
499
|
+
const rawTable = match[1];
|
|
500
|
+
const rawColumns = match[2];
|
|
501
|
+
const remainder = match[3];
|
|
502
|
+
const tableName = unqualifiedTableName(rawTable);
|
|
503
|
+
const conflictKeys = UPSERT_KEYS[tableName];
|
|
504
|
+
if (!conflictKeys?.length) {
|
|
505
|
+
return sql;
|
|
506
|
+
}
|
|
507
|
+
const columns = rawColumns.split(",").map((col) => col.trim().replace(/^"|"$/g, ""));
|
|
508
|
+
const updateColumns = columns.filter((col) => !conflictKeys.includes(col));
|
|
509
|
+
const conflictTarget = conflictKeys.map(quotedIdentifier).join(", ");
|
|
510
|
+
const updateClause = updateColumns.length === 0 ? " DO NOTHING" : ` DO UPDATE SET ${updateColumns.map((col) => `${quotedIdentifier(col)} = EXCLUDED.${quotedIdentifier(col)}`).join(", ")}`;
|
|
511
|
+
return `INSERT INTO ${rawTable} (${rawColumns})${appendClause(remainder, ` ON CONFLICT (${conflictTarget})${updateClause}`)}`;
|
|
512
|
+
}
|
|
513
|
+
function rewriteSql(sql) {
|
|
514
|
+
let out = sql;
|
|
515
|
+
out = out.replace(/\bdatetime\(\s*['"]now['"]\s*\)/giu, "CURRENT_TIMESTAMP");
|
|
516
|
+
out = out.replace(/\bvector32\s*\(\s*\?\s*\)/giu, "?");
|
|
517
|
+
out = rewriteBooleanLiterals(out);
|
|
518
|
+
out = rewriteInsertOrReplace(out);
|
|
519
|
+
out = rewriteInsertOrIgnore(out);
|
|
520
|
+
return stripTrailingSemicolon(out);
|
|
521
|
+
}
|
|
522
|
+
function toBoolean(value) {
|
|
523
|
+
if (value === null || value === void 0) return value;
|
|
524
|
+
if (typeof value === "boolean") return value;
|
|
525
|
+
if (typeof value === "number") return value !== 0;
|
|
526
|
+
if (typeof value === "bigint") return value !== 0n;
|
|
527
|
+
if (typeof value === "string") {
|
|
528
|
+
const normalized = value.trim().toLowerCase();
|
|
529
|
+
if (normalized === "0" || normalized === "false") return false;
|
|
530
|
+
if (normalized === "1" || normalized === "true") return true;
|
|
531
|
+
}
|
|
532
|
+
return Boolean(value);
|
|
533
|
+
}
|
|
534
|
+
function countQuestionMarks(sql, end) {
|
|
535
|
+
let count = 0;
|
|
536
|
+
let inSingle = false;
|
|
537
|
+
let inDouble = false;
|
|
538
|
+
let inLineComment = false;
|
|
539
|
+
let inBlockComment = false;
|
|
540
|
+
for (let i = 0; i < end; i++) {
|
|
541
|
+
const ch = sql[i];
|
|
542
|
+
const next = sql[i + 1];
|
|
543
|
+
if (inLineComment) {
|
|
544
|
+
if (ch === "\n") inLineComment = false;
|
|
545
|
+
continue;
|
|
546
|
+
}
|
|
547
|
+
if (inBlockComment) {
|
|
548
|
+
if (ch === "*" && next === "/") {
|
|
549
|
+
inBlockComment = false;
|
|
550
|
+
i += 1;
|
|
551
|
+
}
|
|
552
|
+
continue;
|
|
553
|
+
}
|
|
554
|
+
if (!inSingle && !inDouble && ch === "-" && next === "-") {
|
|
555
|
+
inLineComment = true;
|
|
556
|
+
i += 1;
|
|
557
|
+
continue;
|
|
558
|
+
}
|
|
559
|
+
if (!inSingle && !inDouble && ch === "/" && next === "*") {
|
|
560
|
+
inBlockComment = true;
|
|
561
|
+
i += 1;
|
|
562
|
+
continue;
|
|
563
|
+
}
|
|
564
|
+
if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
|
|
565
|
+
inSingle = !inSingle;
|
|
566
|
+
continue;
|
|
567
|
+
}
|
|
568
|
+
if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
|
|
569
|
+
inDouble = !inDouble;
|
|
570
|
+
continue;
|
|
571
|
+
}
|
|
572
|
+
if (!inSingle && !inDouble && ch === "?") {
|
|
573
|
+
count += 1;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
return count;
|
|
577
|
+
}
|
|
578
|
+
function findBooleanPlaceholderIndexes(sql) {
|
|
579
|
+
const indexes = /* @__PURE__ */ new Set();
|
|
580
|
+
for (const column of BOOLEAN_COLUMN_NAMES) {
|
|
581
|
+
const pattern = new RegExp(`(?:\\b[a-z_][a-z0-9_]*\\.)?${column}\\s*=\\s*\\?`, "giu");
|
|
582
|
+
for (const match of sql.matchAll(pattern)) {
|
|
583
|
+
const matchText = match[0];
|
|
584
|
+
const qIndex = match.index + matchText.lastIndexOf("?");
|
|
585
|
+
indexes.add(countQuestionMarks(sql, qIndex + 1));
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
return indexes;
|
|
589
|
+
}
|
|
590
|
+
function coerceInsertBooleanArgs(sql, args) {
|
|
591
|
+
const match = /^\s*INSERT(?:\s+OR\s+(?:IGNORE|REPLACE))?\s+INTO\s+([A-Za-z0-9_."]+)\s*\(([^)]+)\)/iu.exec(sql);
|
|
592
|
+
if (!match) return;
|
|
593
|
+
const rawTable = match[1];
|
|
594
|
+
const rawColumns = match[2];
|
|
595
|
+
const boolColumns = BOOLEAN_COLUMNS_BY_TABLE[unqualifiedTableName(rawTable)];
|
|
596
|
+
if (!boolColumns?.size) return;
|
|
597
|
+
const columns = rawColumns.split(",").map((col) => col.trim().replace(/^"|"$/g, ""));
|
|
598
|
+
for (const [index, column] of columns.entries()) {
|
|
599
|
+
if (boolColumns.has(column) && index < args.length) {
|
|
600
|
+
args[index] = toBoolean(args[index]);
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
function coerceUpdateBooleanArgs(sql, args) {
|
|
605
|
+
const match = /^\s*UPDATE\s+([A-Za-z0-9_."]+)\s+SET\s+([\s\S]+?)(?:\s+WHERE\b|$)/iu.exec(sql);
|
|
606
|
+
if (!match) return;
|
|
607
|
+
const rawTable = match[1];
|
|
608
|
+
const setClause = match[2];
|
|
609
|
+
const boolColumns = BOOLEAN_COLUMNS_BY_TABLE[unqualifiedTableName(rawTable)];
|
|
610
|
+
if (!boolColumns?.size) return;
|
|
611
|
+
const assignments = setClause.split(",");
|
|
612
|
+
let placeholderIndex = 0;
|
|
613
|
+
for (const assignment of assignments) {
|
|
614
|
+
if (!assignment.includes("?")) continue;
|
|
615
|
+
placeholderIndex += 1;
|
|
616
|
+
const colMatch = /^\s*(?:[A-Za-z_][A-Za-z0-9_]*\.)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*\?/iu.exec(assignment);
|
|
617
|
+
if (colMatch && boolColumns.has(colMatch[1])) {
|
|
618
|
+
args[placeholderIndex - 1] = toBoolean(args[placeholderIndex - 1]);
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
function coerceBooleanArgs(sql, args) {
|
|
623
|
+
const nextArgs = [...args];
|
|
624
|
+
coerceInsertBooleanArgs(sql, nextArgs);
|
|
625
|
+
coerceUpdateBooleanArgs(sql, nextArgs);
|
|
626
|
+
const placeholderIndexes = findBooleanPlaceholderIndexes(sql);
|
|
627
|
+
for (const index of placeholderIndexes) {
|
|
628
|
+
if (index > 0 && index <= nextArgs.length) {
|
|
629
|
+
nextArgs[index - 1] = toBoolean(nextArgs[index - 1]);
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
return nextArgs;
|
|
633
|
+
}
|
|
634
|
+
function convertQuestionMarksToDollarParams(sql) {
|
|
635
|
+
let out = "";
|
|
636
|
+
let placeholder = 0;
|
|
637
|
+
let inSingle = false;
|
|
638
|
+
let inDouble = false;
|
|
639
|
+
let inLineComment = false;
|
|
640
|
+
let inBlockComment = false;
|
|
641
|
+
for (let i = 0; i < sql.length; i++) {
|
|
642
|
+
const ch = sql[i];
|
|
643
|
+
const next = sql[i + 1];
|
|
644
|
+
if (inLineComment) {
|
|
645
|
+
out += ch;
|
|
646
|
+
if (ch === "\n") inLineComment = false;
|
|
647
|
+
continue;
|
|
648
|
+
}
|
|
649
|
+
if (inBlockComment) {
|
|
650
|
+
out += ch;
|
|
651
|
+
if (ch === "*" && next === "/") {
|
|
652
|
+
out += next;
|
|
653
|
+
inBlockComment = false;
|
|
654
|
+
i += 1;
|
|
655
|
+
}
|
|
656
|
+
continue;
|
|
657
|
+
}
|
|
658
|
+
if (!inSingle && !inDouble && ch === "-" && next === "-") {
|
|
659
|
+
out += ch + next;
|
|
660
|
+
inLineComment = true;
|
|
661
|
+
i += 1;
|
|
662
|
+
continue;
|
|
663
|
+
}
|
|
664
|
+
if (!inSingle && !inDouble && ch === "/" && next === "*") {
|
|
665
|
+
out += ch + next;
|
|
666
|
+
inBlockComment = true;
|
|
667
|
+
i += 1;
|
|
668
|
+
continue;
|
|
669
|
+
}
|
|
670
|
+
if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
|
|
671
|
+
inSingle = !inSingle;
|
|
672
|
+
out += ch;
|
|
673
|
+
continue;
|
|
674
|
+
}
|
|
675
|
+
if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
|
|
676
|
+
inDouble = !inDouble;
|
|
677
|
+
out += ch;
|
|
678
|
+
continue;
|
|
679
|
+
}
|
|
680
|
+
if (!inSingle && !inDouble && ch === "?") {
|
|
681
|
+
placeholder += 1;
|
|
682
|
+
out += `$${placeholder}`;
|
|
683
|
+
continue;
|
|
684
|
+
}
|
|
685
|
+
out += ch;
|
|
686
|
+
}
|
|
687
|
+
return out;
|
|
688
|
+
}
|
|
689
|
+
function translateStatementForPostgres(stmt) {
|
|
690
|
+
const normalized = normalizeStatement(stmt);
|
|
691
|
+
if (normalized.kind === "named") {
|
|
692
|
+
throw new Error("Named SQL parameters are not supported by the Prisma adapter.");
|
|
693
|
+
}
|
|
694
|
+
const rewrittenSql = rewriteSql(normalized.sql);
|
|
695
|
+
const coercedArgs = coerceBooleanArgs(rewrittenSql, normalized.args);
|
|
696
|
+
return {
|
|
697
|
+
sql: convertQuestionMarksToDollarParams(rewrittenSql),
|
|
698
|
+
args: coercedArgs
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
function shouldBypassPostgres(stmt) {
|
|
702
|
+
const normalized = normalizeStatement(stmt);
|
|
703
|
+
if (normalized.kind === "named") {
|
|
704
|
+
return true;
|
|
705
|
+
}
|
|
706
|
+
return IMMEDIATE_FALLBACK_PATTERNS.some((pattern) => pattern.test(normalized.sql));
|
|
707
|
+
}
|
|
708
|
+
function shouldFallbackOnError(error) {
|
|
709
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
710
|
+
return /42P01|42883|42601|does not exist|syntax error|not supported|Named SQL parameters are not supported/iu.test(message);
|
|
711
|
+
}
|
|
712
|
+
function isReadQuery(sql) {
|
|
713
|
+
const trimmed = sql.trimStart();
|
|
714
|
+
return /^(SELECT|WITH|SHOW|EXPLAIN|VALUES)\b/iu.test(trimmed) || /\bRETURNING\b/iu.test(trimmed);
|
|
715
|
+
}
|
|
716
|
+
function buildRow(row, columns) {
|
|
717
|
+
const values = columns.map((column) => row[column]);
|
|
718
|
+
return Object.assign(values, row);
|
|
719
|
+
}
|
|
720
|
+
function buildResultSet(rows, rowsAffected = 0) {
|
|
721
|
+
const columns = rows[0] ? Object.keys(rows[0]) : [];
|
|
722
|
+
const resultRows = rows.map((row) => buildRow(row, columns));
|
|
723
|
+
return {
|
|
724
|
+
columns,
|
|
725
|
+
columnTypes: columns.map(() => ""),
|
|
726
|
+
rows: resultRows,
|
|
727
|
+
rowsAffected,
|
|
728
|
+
lastInsertRowid: void 0,
|
|
729
|
+
toJSON() {
|
|
730
|
+
return {
|
|
731
|
+
columns,
|
|
732
|
+
columnTypes: columns.map(() => ""),
|
|
733
|
+
rows,
|
|
734
|
+
rowsAffected,
|
|
735
|
+
lastInsertRowid: void 0
|
|
736
|
+
};
|
|
737
|
+
}
|
|
738
|
+
};
|
|
739
|
+
}
|
|
740
|
+
async function loadPrismaClient() {
|
|
741
|
+
if (!prismaClientPromise) {
|
|
742
|
+
prismaClientPromise = (async () => {
|
|
743
|
+
const explicitPath = process.env.EXE_OS_PRISMA_CLIENT_PATH;
|
|
744
|
+
if (explicitPath) {
|
|
745
|
+
const module2 = await import(pathToFileURL(explicitPath).href);
|
|
746
|
+
const PrismaClient2 = module2.PrismaClient ?? module2.default?.PrismaClient;
|
|
747
|
+
if (!PrismaClient2) {
|
|
748
|
+
throw new Error(`No PrismaClient export found at ${explicitPath}`);
|
|
749
|
+
}
|
|
750
|
+
return new PrismaClient2();
|
|
751
|
+
}
|
|
752
|
+
const exeDbRoot = process.env.EXE_DB_ROOT ?? path3.join(os3.homedir(), "exe-db");
|
|
753
|
+
const requireFromExeDb = createRequire(path3.join(exeDbRoot, "package.json"));
|
|
754
|
+
const prismaEntry = requireFromExeDb.resolve("@prisma/client");
|
|
755
|
+
const module = await import(pathToFileURL(prismaEntry).href);
|
|
756
|
+
const PrismaClient = module.PrismaClient ?? module.default?.PrismaClient;
|
|
757
|
+
if (!PrismaClient) {
|
|
758
|
+
throw new Error(`No PrismaClient export found in ${prismaEntry}`);
|
|
759
|
+
}
|
|
760
|
+
return new PrismaClient();
|
|
761
|
+
})();
|
|
762
|
+
}
|
|
763
|
+
return prismaClientPromise;
|
|
764
|
+
}
|
|
765
|
+
async function ensureCompatibilityViews(prisma) {
|
|
766
|
+
if (!compatibilityBootstrapPromise) {
|
|
767
|
+
compatibilityBootstrapPromise = (async () => {
|
|
768
|
+
for (const mapping of VIEW_MAPPINGS) {
|
|
769
|
+
const relation = mapping.source.replace(/"/g, "");
|
|
770
|
+
const rows = await prisma.$queryRawUnsafe(
|
|
771
|
+
"SELECT to_regclass($1) AS regclass",
|
|
772
|
+
relation
|
|
773
|
+
);
|
|
774
|
+
if (!rows[0]?.regclass) {
|
|
775
|
+
continue;
|
|
776
|
+
}
|
|
777
|
+
await prisma.$executeRawUnsafe(
|
|
778
|
+
`CREATE OR REPLACE VIEW public.${quotedIdentifier(mapping.view)} AS SELECT * FROM ${mapping.source}`
|
|
779
|
+
);
|
|
780
|
+
}
|
|
781
|
+
})();
|
|
782
|
+
}
|
|
783
|
+
return compatibilityBootstrapPromise;
|
|
784
|
+
}
|
|
785
|
+
async function executeOnPrisma(executor, stmt) {
|
|
786
|
+
const translated = translateStatementForPostgres(stmt);
|
|
787
|
+
if (isReadQuery(translated.sql)) {
|
|
788
|
+
const rows = await executor.$queryRawUnsafe(
|
|
789
|
+
translated.sql,
|
|
790
|
+
...translated.args
|
|
791
|
+
);
|
|
792
|
+
return buildResultSet(rows, /\bRETURNING\b/iu.test(translated.sql) ? rows.length : 0);
|
|
793
|
+
}
|
|
794
|
+
const rowsAffected = await executor.$executeRawUnsafe(translated.sql, ...translated.args);
|
|
795
|
+
return buildResultSet([], rowsAffected);
|
|
796
|
+
}
|
|
797
|
+
function splitSqlStatements(sql) {
|
|
798
|
+
const parts = [];
|
|
799
|
+
let current = "";
|
|
800
|
+
let inSingle = false;
|
|
801
|
+
let inDouble = false;
|
|
802
|
+
let inLineComment = false;
|
|
803
|
+
let inBlockComment = false;
|
|
804
|
+
for (let i = 0; i < sql.length; i++) {
|
|
805
|
+
const ch = sql[i];
|
|
806
|
+
const next = sql[i + 1];
|
|
807
|
+
if (inLineComment) {
|
|
808
|
+
current += ch;
|
|
809
|
+
if (ch === "\n") inLineComment = false;
|
|
810
|
+
continue;
|
|
811
|
+
}
|
|
812
|
+
if (inBlockComment) {
|
|
813
|
+
current += ch;
|
|
814
|
+
if (ch === "*" && next === "/") {
|
|
815
|
+
current += next;
|
|
816
|
+
inBlockComment = false;
|
|
817
|
+
i += 1;
|
|
818
|
+
}
|
|
819
|
+
continue;
|
|
820
|
+
}
|
|
821
|
+
if (!inSingle && !inDouble && ch === "-" && next === "-") {
|
|
822
|
+
current += ch + next;
|
|
823
|
+
inLineComment = true;
|
|
824
|
+
i += 1;
|
|
825
|
+
continue;
|
|
826
|
+
}
|
|
827
|
+
if (!inSingle && !inDouble && ch === "/" && next === "*") {
|
|
828
|
+
current += ch + next;
|
|
829
|
+
inBlockComment = true;
|
|
830
|
+
i += 1;
|
|
831
|
+
continue;
|
|
832
|
+
}
|
|
833
|
+
if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
|
|
834
|
+
inSingle = !inSingle;
|
|
835
|
+
current += ch;
|
|
836
|
+
continue;
|
|
837
|
+
}
|
|
838
|
+
if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
|
|
839
|
+
inDouble = !inDouble;
|
|
840
|
+
current += ch;
|
|
841
|
+
continue;
|
|
842
|
+
}
|
|
843
|
+
if (!inSingle && !inDouble && ch === ";") {
|
|
844
|
+
if (current.trim()) {
|
|
845
|
+
parts.push(current.trim());
|
|
846
|
+
}
|
|
847
|
+
current = "";
|
|
848
|
+
continue;
|
|
849
|
+
}
|
|
850
|
+
current += ch;
|
|
851
|
+
}
|
|
852
|
+
if (current.trim()) {
|
|
853
|
+
parts.push(current.trim());
|
|
854
|
+
}
|
|
855
|
+
return parts;
|
|
856
|
+
}
|
|
857
|
+
async function createPrismaDbAdapter(fallbackClient) {
|
|
858
|
+
const prisma = await loadPrismaClient();
|
|
859
|
+
await ensureCompatibilityViews(prisma);
|
|
860
|
+
let closed = false;
|
|
861
|
+
let adapter;
|
|
862
|
+
const fallbackExecute = async (stmt, error) => {
|
|
863
|
+
if (!fallbackClient) {
|
|
864
|
+
if (error) throw error;
|
|
865
|
+
throw new Error("No fallback SQLite client is available for this Prisma-routed query.");
|
|
866
|
+
}
|
|
867
|
+
if (error) {
|
|
868
|
+
process.stderr.write(
|
|
869
|
+
`[database-adapter] Falling back to SQLite: ${error instanceof Error ? error.message : String(error)}
|
|
870
|
+
`
|
|
871
|
+
);
|
|
872
|
+
}
|
|
873
|
+
return fallbackClient.execute(stmt);
|
|
874
|
+
};
|
|
875
|
+
adapter = {
|
|
876
|
+
async execute(stmt) {
|
|
877
|
+
if (shouldBypassPostgres(stmt)) {
|
|
878
|
+
return fallbackExecute(stmt);
|
|
879
|
+
}
|
|
880
|
+
try {
|
|
881
|
+
return await executeOnPrisma(prisma, stmt);
|
|
882
|
+
} catch (error) {
|
|
883
|
+
if (shouldFallbackOnError(error)) {
|
|
884
|
+
return fallbackExecute(stmt, error);
|
|
885
|
+
}
|
|
886
|
+
throw error;
|
|
887
|
+
}
|
|
888
|
+
},
|
|
889
|
+
async batch(stmts, mode) {
|
|
890
|
+
if (stmts.some((stmt) => shouldBypassPostgres(stmt))) {
|
|
891
|
+
if (!fallbackClient) {
|
|
892
|
+
throw new Error("Cannot batch unsupported SQLite-only statements without a fallback client.");
|
|
893
|
+
}
|
|
894
|
+
return fallbackClient.batch(stmts, mode);
|
|
895
|
+
}
|
|
896
|
+
try {
|
|
897
|
+
if (prisma.$transaction) {
|
|
898
|
+
return await prisma.$transaction(async (tx) => {
|
|
899
|
+
const results2 = [];
|
|
900
|
+
for (const stmt of stmts) {
|
|
901
|
+
results2.push(await executeOnPrisma(tx, stmt));
|
|
902
|
+
}
|
|
903
|
+
return results2;
|
|
904
|
+
});
|
|
905
|
+
}
|
|
906
|
+
const results = [];
|
|
907
|
+
for (const stmt of stmts) {
|
|
908
|
+
results.push(await executeOnPrisma(prisma, stmt));
|
|
909
|
+
}
|
|
910
|
+
return results;
|
|
911
|
+
} catch (error) {
|
|
912
|
+
if (fallbackClient && shouldFallbackOnError(error)) {
|
|
913
|
+
process.stderr.write(
|
|
914
|
+
`[database-adapter] Falling back batch to SQLite: ${error instanceof Error ? error.message : String(error)}
|
|
915
|
+
`
|
|
916
|
+
);
|
|
917
|
+
return fallbackClient.batch(stmts, mode);
|
|
918
|
+
}
|
|
919
|
+
throw error;
|
|
920
|
+
}
|
|
921
|
+
},
|
|
922
|
+
async migrate(stmts) {
|
|
923
|
+
if (fallbackClient) {
|
|
924
|
+
return fallbackClient.migrate(stmts);
|
|
925
|
+
}
|
|
926
|
+
return adapter.batch(stmts, "deferred");
|
|
927
|
+
},
|
|
928
|
+
async transaction(mode) {
|
|
929
|
+
if (!fallbackClient) {
|
|
930
|
+
throw new Error("Interactive transactions are only supported on the SQLite fallback client.");
|
|
931
|
+
}
|
|
932
|
+
return fallbackClient.transaction(mode);
|
|
933
|
+
},
|
|
934
|
+
async executeMultiple(sql) {
|
|
935
|
+
if (fallbackClient && shouldBypassPostgres(sql)) {
|
|
936
|
+
return fallbackClient.executeMultiple(sql);
|
|
937
|
+
}
|
|
938
|
+
for (const statement of splitSqlStatements(sql)) {
|
|
939
|
+
await adapter.execute(statement);
|
|
940
|
+
}
|
|
941
|
+
},
|
|
942
|
+
async sync() {
|
|
943
|
+
if (fallbackClient) {
|
|
944
|
+
return fallbackClient.sync();
|
|
945
|
+
}
|
|
946
|
+
return { frame_no: 0, frames_synced: 0 };
|
|
947
|
+
},
|
|
948
|
+
close() {
|
|
949
|
+
closed = true;
|
|
950
|
+
prismaClientPromise = null;
|
|
951
|
+
compatibilityBootstrapPromise = null;
|
|
952
|
+
void prisma.$disconnect?.();
|
|
953
|
+
},
|
|
954
|
+
get closed() {
|
|
955
|
+
return closed;
|
|
956
|
+
},
|
|
957
|
+
get protocol() {
|
|
958
|
+
return "prisma-postgres";
|
|
959
|
+
}
|
|
960
|
+
};
|
|
961
|
+
return adapter;
|
|
962
|
+
}
|
|
963
|
+
var VIEW_MAPPINGS, UPSERT_KEYS, BOOLEAN_COLUMNS_BY_TABLE, BOOLEAN_COLUMN_NAMES, IMMEDIATE_FALLBACK_PATTERNS, prismaClientPromise, compatibilityBootstrapPromise;
|
|
964
|
+
var init_database_adapter = __esm({
|
|
965
|
+
"src/lib/database-adapter.ts"() {
|
|
966
|
+
"use strict";
|
|
967
|
+
VIEW_MAPPINGS = [
|
|
968
|
+
{ view: "memories", source: "memory.memory_records" },
|
|
969
|
+
{ view: "tasks", source: "memory.tasks" },
|
|
970
|
+
{ view: "behaviors", source: "memory.behaviors" },
|
|
971
|
+
{ view: "entities", source: "memory.entities" },
|
|
972
|
+
{ view: "relationships", source: "memory.relationships" },
|
|
973
|
+
{ view: "entity_memories", source: "memory.entity_memories" },
|
|
974
|
+
{ view: "entity_aliases", source: "memory.entity_aliases" },
|
|
975
|
+
{ view: "notifications", source: "memory.notifications" },
|
|
976
|
+
{ view: "messages", source: "memory.messages" },
|
|
977
|
+
{ view: "users", source: "wiki.users" },
|
|
978
|
+
{ view: "workspaces", source: "wiki.workspaces" },
|
|
979
|
+
{ view: "workspace_users", source: "wiki.workspace_users" },
|
|
980
|
+
{ view: "documents", source: "wiki.workspace_documents" },
|
|
981
|
+
{ view: "chats", source: "wiki.workspace_chats" }
|
|
982
|
+
];
|
|
983
|
+
UPSERT_KEYS = {
|
|
984
|
+
memories: ["id"],
|
|
985
|
+
tasks: ["id"],
|
|
986
|
+
behaviors: ["id"],
|
|
987
|
+
entities: ["id"],
|
|
988
|
+
relationships: ["id"],
|
|
989
|
+
entity_aliases: ["alias"],
|
|
990
|
+
notifications: ["id"],
|
|
991
|
+
messages: ["id"],
|
|
992
|
+
users: ["id"],
|
|
993
|
+
workspaces: ["id"],
|
|
994
|
+
workspace_users: ["id"],
|
|
995
|
+
documents: ["id"],
|
|
996
|
+
chats: ["id"]
|
|
997
|
+
};
|
|
998
|
+
BOOLEAN_COLUMNS_BY_TABLE = {
|
|
999
|
+
memories: /* @__PURE__ */ new Set(["has_error", "draft"]),
|
|
1000
|
+
behaviors: /* @__PURE__ */ new Set(["active"]),
|
|
1001
|
+
notifications: /* @__PURE__ */ new Set(["read"]),
|
|
1002
|
+
users: /* @__PURE__ */ new Set(["has_personal_memory"])
|
|
1003
|
+
};
|
|
1004
|
+
BOOLEAN_COLUMN_NAMES = new Set(
|
|
1005
|
+
Object.values(BOOLEAN_COLUMNS_BY_TABLE).flatMap((cols) => [...cols])
|
|
1006
|
+
);
|
|
1007
|
+
IMMEDIATE_FALLBACK_PATTERNS = [
|
|
1008
|
+
/\bPRAGMA\b/i,
|
|
1009
|
+
/\bsqlite_master\b/i,
|
|
1010
|
+
/(?:^|[.\s])(?:memories|conversations|entities)_fts\b/i,
|
|
1011
|
+
/\bMATCH\b/i,
|
|
1012
|
+
/\bvector_distance_cos\s*\(/i,
|
|
1013
|
+
/\bjson_extract\s*\(/i,
|
|
1014
|
+
/\bjulianday\s*\(/i,
|
|
1015
|
+
/\bstrftime\s*\(/i,
|
|
1016
|
+
/\blast_insert_rowid\s*\(/i
|
|
1017
|
+
];
|
|
1018
|
+
prismaClientPromise = null;
|
|
1019
|
+
compatibilityBootstrapPromise = null;
|
|
1020
|
+
}
|
|
1021
|
+
});
|
|
1022
|
+
|
|
438
1023
|
// src/lib/exe-daemon-client.ts
|
|
439
1024
|
import net from "net";
|
|
440
|
-
import
|
|
1025
|
+
import os4 from "os";
|
|
441
1026
|
import { spawn } from "child_process";
|
|
442
1027
|
import { randomUUID } from "crypto";
|
|
443
1028
|
import { existsSync as existsSync3, unlinkSync as unlinkSync2, readFileSync as readFileSync3, openSync, closeSync, statSync } from "fs";
|
|
444
|
-
import
|
|
1029
|
+
import path4 from "path";
|
|
445
1030
|
import { fileURLToPath } from "url";
|
|
446
1031
|
function handleData(chunk) {
|
|
447
1032
|
_buffer += chunk.toString();
|
|
@@ -492,17 +1077,17 @@ function cleanupStaleFiles() {
|
|
|
492
1077
|
}
|
|
493
1078
|
}
|
|
494
1079
|
function findPackageRoot() {
|
|
495
|
-
let dir =
|
|
496
|
-
const { root } =
|
|
1080
|
+
let dir = path4.dirname(fileURLToPath(import.meta.url));
|
|
1081
|
+
const { root } = path4.parse(dir);
|
|
497
1082
|
while (dir !== root) {
|
|
498
|
-
if (existsSync3(
|
|
499
|
-
dir =
|
|
1083
|
+
if (existsSync3(path4.join(dir, "package.json"))) return dir;
|
|
1084
|
+
dir = path4.dirname(dir);
|
|
500
1085
|
}
|
|
501
1086
|
return null;
|
|
502
1087
|
}
|
|
503
1088
|
function spawnDaemon() {
|
|
504
|
-
const freeGB =
|
|
505
|
-
const totalGB =
|
|
1089
|
+
const freeGB = os4.freemem() / (1024 * 1024 * 1024);
|
|
1090
|
+
const totalGB = os4.totalmem() / (1024 * 1024 * 1024);
|
|
506
1091
|
if (totalGB <= 8) {
|
|
507
1092
|
process.stderr.write(
|
|
508
1093
|
`[exed-client] SKIP: ${totalGB.toFixed(0)}GB system \u2014 embedding daemon disabled. Using keyword search only. Minimum 16GB recommended for vector search.
|
|
@@ -522,7 +1107,7 @@ function spawnDaemon() {
|
|
|
522
1107
|
process.stderr.write("[exed-client] WARN: cannot find package root\n");
|
|
523
1108
|
return;
|
|
524
1109
|
}
|
|
525
|
-
const daemonPath =
|
|
1110
|
+
const daemonPath = path4.join(pkgRoot, "dist", "lib", "exe-daemon.js");
|
|
526
1111
|
if (!existsSync3(daemonPath)) {
|
|
527
1112
|
process.stderr.write(`[exed-client] WARN: daemon script not found at ${daemonPath}
|
|
528
1113
|
`);
|
|
@@ -531,7 +1116,7 @@ function spawnDaemon() {
|
|
|
531
1116
|
const resolvedPath = daemonPath;
|
|
532
1117
|
process.stderr.write(`[exed-client] Spawning daemon: ${resolvedPath}
|
|
533
1118
|
`);
|
|
534
|
-
const logPath =
|
|
1119
|
+
const logPath = path4.join(path4.dirname(SOCKET_PATH), "exed.log");
|
|
535
1120
|
let stderrFd = "ignore";
|
|
536
1121
|
try {
|
|
537
1122
|
stderrFd = openSync(logPath, "a");
|
|
@@ -678,9 +1263,9 @@ var init_exe_daemon_client = __esm({
|
|
|
678
1263
|
"src/lib/exe-daemon-client.ts"() {
|
|
679
1264
|
"use strict";
|
|
680
1265
|
init_config();
|
|
681
|
-
SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ??
|
|
682
|
-
PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ??
|
|
683
|
-
SPAWN_LOCK_PATH =
|
|
1266
|
+
SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path4.join(EXE_AI_DIR, "exed.sock");
|
|
1267
|
+
PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path4.join(EXE_AI_DIR, "exed.pid");
|
|
1268
|
+
SPAWN_LOCK_PATH = path4.join(EXE_AI_DIR, "exed-spawn.lock");
|
|
684
1269
|
SPAWN_LOCK_STALE_MS = 3e4;
|
|
685
1270
|
CONNECT_TIMEOUT_MS = 15e3;
|
|
686
1271
|
REQUEST_TIMEOUT_MS = 3e4;
|
|
@@ -762,7 +1347,7 @@ __export(db_daemon_client_exports, {
|
|
|
762
1347
|
createDaemonDbClient: () => createDaemonDbClient,
|
|
763
1348
|
initDaemonDbClient: () => initDaemonDbClient
|
|
764
1349
|
});
|
|
765
|
-
function
|
|
1350
|
+
function normalizeStatement2(stmt) {
|
|
766
1351
|
if (typeof stmt === "string") {
|
|
767
1352
|
return { sql: stmt, args: [] };
|
|
768
1353
|
}
|
|
@@ -786,7 +1371,7 @@ function createDaemonDbClient(fallbackClient) {
|
|
|
786
1371
|
if (!_useDaemon || !isClientConnected()) {
|
|
787
1372
|
return fallbackClient.execute(stmt);
|
|
788
1373
|
}
|
|
789
|
-
const { sql, args } =
|
|
1374
|
+
const { sql, args } = normalizeStatement2(stmt);
|
|
790
1375
|
const response = await sendDaemonRequest({
|
|
791
1376
|
type: "db-execute",
|
|
792
1377
|
sql,
|
|
@@ -811,7 +1396,7 @@ function createDaemonDbClient(fallbackClient) {
|
|
|
811
1396
|
if (!_useDaemon || !isClientConnected()) {
|
|
812
1397
|
return fallbackClient.batch(stmts, mode);
|
|
813
1398
|
}
|
|
814
|
-
const statements = stmts.map(
|
|
1399
|
+
const statements = stmts.map(normalizeStatement2);
|
|
815
1400
|
const response = await sendDaemonRequest({
|
|
816
1401
|
type: "db-batch",
|
|
817
1402
|
statements,
|
|
@@ -906,6 +1491,18 @@ __export(database_exports, {
|
|
|
906
1491
|
});
|
|
907
1492
|
import { createClient } from "@libsql/client";
|
|
908
1493
|
async function initDatabase(config) {
|
|
1494
|
+
if (_walCheckpointTimer) {
|
|
1495
|
+
clearInterval(_walCheckpointTimer);
|
|
1496
|
+
_walCheckpointTimer = null;
|
|
1497
|
+
}
|
|
1498
|
+
if (_daemonClient) {
|
|
1499
|
+
_daemonClient.close();
|
|
1500
|
+
_daemonClient = null;
|
|
1501
|
+
}
|
|
1502
|
+
if (_adapterClient && _adapterClient !== _resilientClient) {
|
|
1503
|
+
_adapterClient.close();
|
|
1504
|
+
}
|
|
1505
|
+
_adapterClient = null;
|
|
909
1506
|
if (_client) {
|
|
910
1507
|
_client.close();
|
|
911
1508
|
_client = null;
|
|
@@ -919,6 +1516,7 @@ async function initDatabase(config) {
|
|
|
919
1516
|
}
|
|
920
1517
|
_client = createClient(opts);
|
|
921
1518
|
_resilientClient = wrapWithRetry(_client);
|
|
1519
|
+
_adapterClient = _resilientClient;
|
|
922
1520
|
_client.execute("PRAGMA busy_timeout = 30000").catch(() => {
|
|
923
1521
|
});
|
|
924
1522
|
_client.execute("PRAGMA journal_mode = WAL").catch(() => {
|
|
@@ -929,14 +1527,20 @@ async function initDatabase(config) {
|
|
|
929
1527
|
});
|
|
930
1528
|
}, 3e4);
|
|
931
1529
|
_walCheckpointTimer.unref();
|
|
1530
|
+
if (process.env.DATABASE_URL) {
|
|
1531
|
+
_adapterClient = await createPrismaDbAdapter(_resilientClient);
|
|
1532
|
+
}
|
|
932
1533
|
}
|
|
933
1534
|
function isInitialized() {
|
|
934
|
-
return _client !== null;
|
|
1535
|
+
return _adapterClient !== null || _client !== null;
|
|
935
1536
|
}
|
|
936
1537
|
function getClient() {
|
|
937
|
-
if (!
|
|
1538
|
+
if (!_adapterClient) {
|
|
938
1539
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
939
1540
|
}
|
|
1541
|
+
if (process.env.DATABASE_URL) {
|
|
1542
|
+
return _adapterClient;
|
|
1543
|
+
}
|
|
940
1544
|
if (process.env.EXE_IS_DAEMON === "1") {
|
|
941
1545
|
return _resilientClient;
|
|
942
1546
|
}
|
|
@@ -946,6 +1550,7 @@ function getClient() {
|
|
|
946
1550
|
return _resilientClient;
|
|
947
1551
|
}
|
|
948
1552
|
async function initDaemonClient() {
|
|
1553
|
+
if (process.env.DATABASE_URL) return;
|
|
949
1554
|
if (process.env.EXE_IS_DAEMON === "1") return;
|
|
950
1555
|
if (!_resilientClient) return;
|
|
951
1556
|
try {
|
|
@@ -1890,26 +2495,36 @@ async function ensureSchema() {
|
|
|
1890
2495
|
}
|
|
1891
2496
|
}
|
|
1892
2497
|
async function disposeDatabase() {
|
|
2498
|
+
if (_walCheckpointTimer) {
|
|
2499
|
+
clearInterval(_walCheckpointTimer);
|
|
2500
|
+
_walCheckpointTimer = null;
|
|
2501
|
+
}
|
|
1893
2502
|
if (_daemonClient) {
|
|
1894
2503
|
_daemonClient.close();
|
|
1895
2504
|
_daemonClient = null;
|
|
1896
2505
|
}
|
|
2506
|
+
if (_adapterClient && _adapterClient !== _resilientClient) {
|
|
2507
|
+
_adapterClient.close();
|
|
2508
|
+
}
|
|
2509
|
+
_adapterClient = null;
|
|
1897
2510
|
if (_client) {
|
|
1898
2511
|
_client.close();
|
|
1899
2512
|
_client = null;
|
|
1900
2513
|
_resilientClient = null;
|
|
1901
2514
|
}
|
|
1902
2515
|
}
|
|
1903
|
-
var _client, _resilientClient, _walCheckpointTimer, _daemonClient, initTurso, disposeTurso;
|
|
2516
|
+
var _client, _resilientClient, _walCheckpointTimer, _daemonClient, _adapterClient, initTurso, disposeTurso;
|
|
1904
2517
|
var init_database = __esm({
|
|
1905
2518
|
"src/lib/database.ts"() {
|
|
1906
2519
|
"use strict";
|
|
1907
2520
|
init_db_retry();
|
|
1908
2521
|
init_employees();
|
|
2522
|
+
init_database_adapter();
|
|
1909
2523
|
_client = null;
|
|
1910
2524
|
_resilientClient = null;
|
|
1911
2525
|
_walCheckpointTimer = null;
|
|
1912
2526
|
_daemonClient = null;
|
|
2527
|
+
_adapterClient = null;
|
|
1913
2528
|
initTurso = initDatabase;
|
|
1914
2529
|
disposeTurso = disposeDatabase;
|
|
1915
2530
|
}
|
|
@@ -2120,13 +2735,13 @@ __export(keychain_exports, {
|
|
|
2120
2735
|
});
|
|
2121
2736
|
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
2122
2737
|
import { existsSync as existsSync4 } from "fs";
|
|
2123
|
-
import
|
|
2124
|
-
import
|
|
2738
|
+
import path5 from "path";
|
|
2739
|
+
import os5 from "os";
|
|
2125
2740
|
function getKeyDir() {
|
|
2126
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ??
|
|
2741
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path5.join(os5.homedir(), ".exe-os");
|
|
2127
2742
|
}
|
|
2128
2743
|
function getKeyPath() {
|
|
2129
|
-
return
|
|
2744
|
+
return path5.join(getKeyDir(), "master.key");
|
|
2130
2745
|
}
|
|
2131
2746
|
async function tryKeytar() {
|
|
2132
2747
|
try {
|
|
@@ -2149,7 +2764,7 @@ async function getMasterKey() {
|
|
|
2149
2764
|
const keyPath = getKeyPath();
|
|
2150
2765
|
if (!existsSync4(keyPath)) {
|
|
2151
2766
|
process.stderr.write(
|
|
2152
|
-
`[keychain] Key not found at ${keyPath} (HOME=${
|
|
2767
|
+
`[keychain] Key not found at ${keyPath} (HOME=${os5.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
|
|
2153
2768
|
`
|
|
2154
2769
|
);
|
|
2155
2770
|
return null;
|
|
@@ -2300,7 +2915,7 @@ __export(shard_manager_exports, {
|
|
|
2300
2915
|
listShards: () => listShards,
|
|
2301
2916
|
shardExists: () => shardExists
|
|
2302
2917
|
});
|
|
2303
|
-
import
|
|
2918
|
+
import path6 from "path";
|
|
2304
2919
|
import { existsSync as existsSync5, mkdirSync, readdirSync } from "fs";
|
|
2305
2920
|
import { createClient as createClient2 } from "@libsql/client";
|
|
2306
2921
|
function initShardManager(encryptionKey) {
|
|
@@ -2326,7 +2941,7 @@ function getShardClient(projectName) {
|
|
|
2326
2941
|
}
|
|
2327
2942
|
const cached = _shards.get(safeName);
|
|
2328
2943
|
if (cached) return cached;
|
|
2329
|
-
const dbPath =
|
|
2944
|
+
const dbPath = path6.join(SHARDS_DIR, `${safeName}.db`);
|
|
2330
2945
|
const client = createClient2({
|
|
2331
2946
|
url: `file:${dbPath}`,
|
|
2332
2947
|
encryptionKey: _encryptionKey
|
|
@@ -2336,7 +2951,7 @@ function getShardClient(projectName) {
|
|
|
2336
2951
|
}
|
|
2337
2952
|
function shardExists(projectName) {
|
|
2338
2953
|
const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
2339
|
-
return existsSync5(
|
|
2954
|
+
return existsSync5(path6.join(SHARDS_DIR, `${safeName}.db`));
|
|
2340
2955
|
}
|
|
2341
2956
|
function listShards() {
|
|
2342
2957
|
if (!existsSync5(SHARDS_DIR)) return [];
|
|
@@ -2413,7 +3028,23 @@ async function ensureShardSchema(client) {
|
|
|
2413
3028
|
// MS-11: draft staging, MS-6a: memory_type, MS-7: trajectory
|
|
2414
3029
|
"ALTER TABLE memories ADD COLUMN draft INTEGER DEFAULT 0",
|
|
2415
3030
|
"ALTER TABLE memories ADD COLUMN memory_type TEXT DEFAULT 'raw'",
|
|
2416
|
-
"ALTER TABLE memories ADD COLUMN trajectory TEXT"
|
|
3031
|
+
"ALTER TABLE memories ADD COLUMN trajectory TEXT",
|
|
3032
|
+
// Metadata enrichment columns (must match database.ts)
|
|
3033
|
+
"ALTER TABLE memories ADD COLUMN intent TEXT",
|
|
3034
|
+
"ALTER TABLE memories ADD COLUMN outcome TEXT",
|
|
3035
|
+
"ALTER TABLE memories ADD COLUMN domain TEXT",
|
|
3036
|
+
"ALTER TABLE memories ADD COLUMN referenced_entities TEXT",
|
|
3037
|
+
"ALTER TABLE memories ADD COLUMN retrieval_count INTEGER DEFAULT 0",
|
|
3038
|
+
"ALTER TABLE memories ADD COLUMN chain_position TEXT",
|
|
3039
|
+
"ALTER TABLE memories ADD COLUMN review_status TEXT",
|
|
3040
|
+
"ALTER TABLE memories ADD COLUMN context_window_pct INTEGER",
|
|
3041
|
+
"ALTER TABLE memories ADD COLUMN file_paths TEXT",
|
|
3042
|
+
"ALTER TABLE memories ADD COLUMN commit_hash TEXT",
|
|
3043
|
+
"ALTER TABLE memories ADD COLUMN duration_ms INTEGER",
|
|
3044
|
+
"ALTER TABLE memories ADD COLUMN token_cost REAL",
|
|
3045
|
+
"ALTER TABLE memories ADD COLUMN audience TEXT",
|
|
3046
|
+
"ALTER TABLE memories ADD COLUMN language_type TEXT",
|
|
3047
|
+
"ALTER TABLE memories ADD COLUMN parent_memory_id TEXT"
|
|
2417
3048
|
]) {
|
|
2418
3049
|
try {
|
|
2419
3050
|
await client.execute(col);
|
|
@@ -2525,7 +3156,7 @@ var init_shard_manager = __esm({
|
|
|
2525
3156
|
"src/lib/shard-manager.ts"() {
|
|
2526
3157
|
"use strict";
|
|
2527
3158
|
init_config();
|
|
2528
|
-
SHARDS_DIR =
|
|
3159
|
+
SHARDS_DIR = path6.join(EXE_AI_DIR, "shards");
|
|
2529
3160
|
_shards = /* @__PURE__ */ new Map();
|
|
2530
3161
|
_encryptionKey = null;
|
|
2531
3162
|
_shardingEnabled = false;
|
|
@@ -2633,10 +3264,10 @@ __export(session_registry_exports, {
|
|
|
2633
3264
|
});
|
|
2634
3265
|
import { readFileSync as readFileSync4, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, existsSync as existsSync6 } from "fs";
|
|
2635
3266
|
import { execSync as execSync2 } from "child_process";
|
|
2636
|
-
import
|
|
2637
|
-
import
|
|
3267
|
+
import path7 from "path";
|
|
3268
|
+
import os6 from "os";
|
|
2638
3269
|
function registerSession(entry) {
|
|
2639
|
-
const dir =
|
|
3270
|
+
const dir = path7.dirname(REGISTRY_PATH);
|
|
2640
3271
|
if (!existsSync6(dir)) {
|
|
2641
3272
|
mkdirSync2(dir, { recursive: true });
|
|
2642
3273
|
}
|
|
@@ -2680,7 +3311,7 @@ var REGISTRY_PATH;
|
|
|
2680
3311
|
var init_session_registry = __esm({
|
|
2681
3312
|
"src/lib/session-registry.ts"() {
|
|
2682
3313
|
"use strict";
|
|
2683
|
-
REGISTRY_PATH =
|
|
3314
|
+
REGISTRY_PATH = path7.join(os6.homedir(), ".exe-os", "session-registry.json");
|
|
2684
3315
|
}
|
|
2685
3316
|
});
|
|
2686
3317
|
|
|
@@ -2961,7 +3592,7 @@ var init_runtime_table = __esm({
|
|
|
2961
3592
|
|
|
2962
3593
|
// src/lib/agent-config.ts
|
|
2963
3594
|
import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, existsSync as existsSync7, mkdirSync as mkdirSync3 } from "fs";
|
|
2964
|
-
import
|
|
3595
|
+
import path8 from "path";
|
|
2965
3596
|
function loadAgentConfig() {
|
|
2966
3597
|
if (!existsSync7(AGENT_CONFIG_PATH)) return {};
|
|
2967
3598
|
try {
|
|
@@ -2984,7 +3615,7 @@ var init_agent_config = __esm({
|
|
|
2984
3615
|
"use strict";
|
|
2985
3616
|
init_config();
|
|
2986
3617
|
init_runtime_table();
|
|
2987
|
-
AGENT_CONFIG_PATH =
|
|
3618
|
+
AGENT_CONFIG_PATH = path8.join(EXE_AI_DIR, "agent-config.json");
|
|
2988
3619
|
DEFAULT_MODELS = {
|
|
2989
3620
|
claude: "claude-opus-4",
|
|
2990
3621
|
codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
|
|
@@ -3003,10 +3634,10 @@ __export(intercom_queue_exports, {
|
|
|
3003
3634
|
readQueue: () => readQueue
|
|
3004
3635
|
});
|
|
3005
3636
|
import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, renameSync as renameSync3, existsSync as existsSync8, mkdirSync as mkdirSync4 } from "fs";
|
|
3006
|
-
import
|
|
3007
|
-
import
|
|
3637
|
+
import path9 from "path";
|
|
3638
|
+
import os7 from "os";
|
|
3008
3639
|
function ensureDir() {
|
|
3009
|
-
const dir =
|
|
3640
|
+
const dir = path9.dirname(QUEUE_PATH);
|
|
3010
3641
|
if (!existsSync8(dir)) mkdirSync4(dir, { recursive: true });
|
|
3011
3642
|
}
|
|
3012
3643
|
function readQueue() {
|
|
@@ -3112,10 +3743,10 @@ var QUEUE_PATH, MAX_RETRIES2, TTL_MS, INTERCOM_LOG;
|
|
|
3112
3743
|
var init_intercom_queue = __esm({
|
|
3113
3744
|
"src/lib/intercom-queue.ts"() {
|
|
3114
3745
|
"use strict";
|
|
3115
|
-
QUEUE_PATH =
|
|
3746
|
+
QUEUE_PATH = path9.join(os7.homedir(), ".exe-os", "intercom-queue.json");
|
|
3116
3747
|
MAX_RETRIES2 = 5;
|
|
3117
3748
|
TTL_MS = 60 * 60 * 1e3;
|
|
3118
|
-
INTERCOM_LOG =
|
|
3749
|
+
INTERCOM_LOG = path9.join(os7.homedir(), ".exe-os", "intercom.log");
|
|
3119
3750
|
}
|
|
3120
3751
|
});
|
|
3121
3752
|
|
|
@@ -3138,7 +3769,7 @@ __export(license_exports, {
|
|
|
3138
3769
|
});
|
|
3139
3770
|
import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, existsSync as existsSync9, mkdirSync as mkdirSync5 } from "fs";
|
|
3140
3771
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
3141
|
-
import
|
|
3772
|
+
import path10 from "path";
|
|
3142
3773
|
import { jwtVerify, importSPKI } from "jose";
|
|
3143
3774
|
async function fetchRetry(url, init) {
|
|
3144
3775
|
try {
|
|
@@ -3149,7 +3780,7 @@ async function fetchRetry(url, init) {
|
|
|
3149
3780
|
}
|
|
3150
3781
|
}
|
|
3151
3782
|
function loadDeviceId() {
|
|
3152
|
-
const deviceJsonPath =
|
|
3783
|
+
const deviceJsonPath = path10.join(EXE_AI_DIR, "device.json");
|
|
3153
3784
|
try {
|
|
3154
3785
|
if (existsSync9(deviceJsonPath)) {
|
|
3155
3786
|
const data = JSON.parse(readFileSync7(deviceJsonPath, "utf8"));
|
|
@@ -3314,7 +3945,7 @@ async function checkLicense() {
|
|
|
3314
3945
|
let key = loadLicense();
|
|
3315
3946
|
if (!key) {
|
|
3316
3947
|
try {
|
|
3317
|
-
const configPath =
|
|
3948
|
+
const configPath = path10.join(EXE_AI_DIR, "config.json");
|
|
3318
3949
|
if (existsSync9(configPath)) {
|
|
3319
3950
|
const raw = JSON.parse(readFileSync7(configPath, "utf8"));
|
|
3320
3951
|
const cloud = raw.cloud;
|
|
@@ -3475,9 +4106,9 @@ var init_license = __esm({
|
|
|
3475
4106
|
"src/lib/license.ts"() {
|
|
3476
4107
|
"use strict";
|
|
3477
4108
|
init_config();
|
|
3478
|
-
LICENSE_PATH =
|
|
3479
|
-
CACHE_PATH =
|
|
3480
|
-
DEVICE_ID_PATH =
|
|
4109
|
+
LICENSE_PATH = path10.join(EXE_AI_DIR, "license.key");
|
|
4110
|
+
CACHE_PATH = path10.join(EXE_AI_DIR, "license-cache.json");
|
|
4111
|
+
DEVICE_ID_PATH = path10.join(EXE_AI_DIR, "device-id");
|
|
3481
4112
|
API_BASE = "https://askexe.com/cloud";
|
|
3482
4113
|
RETRY_DELAY_MS = 500;
|
|
3483
4114
|
LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
|
|
@@ -3508,7 +4139,7 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
|
|
|
3508
4139
|
|
|
3509
4140
|
// src/lib/plan-limits.ts
|
|
3510
4141
|
import { readFileSync as readFileSync8, existsSync as existsSync10 } from "fs";
|
|
3511
|
-
import
|
|
4142
|
+
import path11 from "path";
|
|
3512
4143
|
function getLicenseSync() {
|
|
3513
4144
|
try {
|
|
3514
4145
|
if (!existsSync10(CACHE_PATH2)) return freeLicense();
|
|
@@ -3580,14 +4211,14 @@ var init_plan_limits = __esm({
|
|
|
3580
4211
|
this.name = "PlanLimitError";
|
|
3581
4212
|
}
|
|
3582
4213
|
};
|
|
3583
|
-
CACHE_PATH2 =
|
|
4214
|
+
CACHE_PATH2 = path11.join(EXE_AI_DIR, "license-cache.json");
|
|
3584
4215
|
}
|
|
3585
4216
|
});
|
|
3586
4217
|
|
|
3587
4218
|
// src/lib/notifications.ts
|
|
3588
4219
|
import crypto from "crypto";
|
|
3589
|
-
import
|
|
3590
|
-
import
|
|
4220
|
+
import path12 from "path";
|
|
4221
|
+
import os8 from "os";
|
|
3591
4222
|
import {
|
|
3592
4223
|
readFileSync as readFileSync9,
|
|
3593
4224
|
readdirSync as readdirSync2,
|
|
@@ -3705,8 +4336,8 @@ async function markDoneTaskNotificationsAsRead() {
|
|
|
3705
4336
|
}
|
|
3706
4337
|
}
|
|
3707
4338
|
async function migrateJsonNotifications() {
|
|
3708
|
-
const base = process.env.EXE_OS_DIR || process.env.EXE_MEM_DIR ||
|
|
3709
|
-
const notifDir =
|
|
4339
|
+
const base = process.env.EXE_OS_DIR || process.env.EXE_MEM_DIR || path12.join(os8.homedir(), ".exe-os");
|
|
4340
|
+
const notifDir = path12.join(base, "notifications");
|
|
3710
4341
|
if (!existsSync11(notifDir)) return 0;
|
|
3711
4342
|
let migrated = 0;
|
|
3712
4343
|
try {
|
|
@@ -3715,7 +4346,7 @@ async function migrateJsonNotifications() {
|
|
|
3715
4346
|
const client = getClient();
|
|
3716
4347
|
for (const file of files) {
|
|
3717
4348
|
try {
|
|
3718
|
-
const filePath =
|
|
4349
|
+
const filePath = path12.join(notifDir, file);
|
|
3719
4350
|
const data = JSON.parse(readFileSync9(filePath, "utf8"));
|
|
3720
4351
|
await client.execute({
|
|
3721
4352
|
sql: `INSERT OR IGNORE INTO notifications (id, agent_id, agent_role, event, project, summary, task_file, read, created_at)
|
|
@@ -3863,8 +4494,8 @@ var init_session_kill_telemetry = __esm({
|
|
|
3863
4494
|
|
|
3864
4495
|
// src/lib/tasks-crud.ts
|
|
3865
4496
|
import crypto3 from "crypto";
|
|
3866
|
-
import
|
|
3867
|
-
import
|
|
4497
|
+
import path13 from "path";
|
|
4498
|
+
import os9 from "os";
|
|
3868
4499
|
import { execSync as execSync5 } from "child_process";
|
|
3869
4500
|
import { mkdir as mkdir4, writeFile as writeFile4, appendFile } from "fs/promises";
|
|
3870
4501
|
import { existsSync as existsSync12, readFileSync as readFileSync10 } from "fs";
|
|
@@ -4042,8 +4673,8 @@ ${laneWarning}` : laneWarning;
|
|
|
4042
4673
|
}
|
|
4043
4674
|
if (input.baseDir) {
|
|
4044
4675
|
try {
|
|
4045
|
-
await mkdir4(
|
|
4046
|
-
await mkdir4(
|
|
4676
|
+
await mkdir4(path13.join(input.baseDir, "exe", "output"), { recursive: true });
|
|
4677
|
+
await mkdir4(path13.join(input.baseDir, "exe", "research"), { recursive: true });
|
|
4047
4678
|
await ensureArchitectureDoc(input.baseDir, input.projectName);
|
|
4048
4679
|
await ensureGitignoreExe(input.baseDir);
|
|
4049
4680
|
} catch {
|
|
@@ -4079,9 +4710,9 @@ ${laneWarning}` : laneWarning;
|
|
|
4079
4710
|
});
|
|
4080
4711
|
if (input.baseDir) {
|
|
4081
4712
|
try {
|
|
4082
|
-
const EXE_OS_DIR =
|
|
4083
|
-
const mdPath =
|
|
4084
|
-
const mdDir =
|
|
4713
|
+
const EXE_OS_DIR = path13.join(os9.homedir(), ".exe-os");
|
|
4714
|
+
const mdPath = path13.join(EXE_OS_DIR, taskFile);
|
|
4715
|
+
const mdDir = path13.dirname(mdPath);
|
|
4085
4716
|
if (!existsSync12(mdDir)) await mkdir4(mdDir, { recursive: true });
|
|
4086
4717
|
const reviewer = input.reviewer ?? input.assignedBy;
|
|
4087
4718
|
const mdContent = `# ${input.title}
|
|
@@ -4382,7 +5013,7 @@ async function deleteTaskCore(taskId, _baseDir) {
|
|
|
4382
5013
|
return { taskFile, assignedTo, assignedBy, taskSlug };
|
|
4383
5014
|
}
|
|
4384
5015
|
async function ensureArchitectureDoc(baseDir, projectName) {
|
|
4385
|
-
const archPath =
|
|
5016
|
+
const archPath = path13.join(baseDir, "exe", "ARCHITECTURE.md");
|
|
4386
5017
|
try {
|
|
4387
5018
|
if (existsSync12(archPath)) return;
|
|
4388
5019
|
const template = [
|
|
@@ -4417,7 +5048,7 @@ async function ensureArchitectureDoc(baseDir, projectName) {
|
|
|
4417
5048
|
}
|
|
4418
5049
|
}
|
|
4419
5050
|
async function ensureGitignoreExe(baseDir) {
|
|
4420
|
-
const gitignorePath =
|
|
5051
|
+
const gitignorePath = path13.join(baseDir, ".gitignore");
|
|
4421
5052
|
try {
|
|
4422
5053
|
if (existsSync12(gitignorePath)) {
|
|
4423
5054
|
const content = readFileSync10(gitignorePath, "utf-8");
|
|
@@ -4451,13 +5082,13 @@ var init_tasks_crud = __esm({
|
|
|
4451
5082
|
});
|
|
4452
5083
|
|
|
4453
5084
|
// src/lib/tasks-review.ts
|
|
4454
|
-
import
|
|
5085
|
+
import path14 from "path";
|
|
4455
5086
|
import { existsSync as existsSync13, readdirSync as readdirSync3, unlinkSync as unlinkSync4 } from "fs";
|
|
4456
5087
|
async function countPendingReviews(sessionScope) {
|
|
4457
5088
|
const client = getClient();
|
|
4458
5089
|
if (sessionScope) {
|
|
4459
5090
|
const result2 = await client.execute({
|
|
4460
|
-
sql: "SELECT COUNT(*) as cnt FROM tasks WHERE status = 'needs_review' AND
|
|
5091
|
+
sql: "SELECT COUNT(*) as cnt FROM tasks WHERE status = 'needs_review' AND session_scope = ?",
|
|
4461
5092
|
args: [sessionScope]
|
|
4462
5093
|
});
|
|
4463
5094
|
return Number(result2.rows[0]?.cnt) || 0;
|
|
@@ -4633,11 +5264,11 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
|
|
|
4633
5264
|
);
|
|
4634
5265
|
}
|
|
4635
5266
|
try {
|
|
4636
|
-
const cacheDir =
|
|
5267
|
+
const cacheDir = path14.join(EXE_AI_DIR, "session-cache");
|
|
4637
5268
|
if (existsSync13(cacheDir)) {
|
|
4638
5269
|
for (const f of readdirSync3(cacheDir)) {
|
|
4639
5270
|
if (f.startsWith("review-notified-")) {
|
|
4640
|
-
unlinkSync4(
|
|
5271
|
+
unlinkSync4(path14.join(cacheDir, f));
|
|
4641
5272
|
}
|
|
4642
5273
|
}
|
|
4643
5274
|
}
|
|
@@ -4658,7 +5289,7 @@ var init_tasks_review = __esm({
|
|
|
4658
5289
|
});
|
|
4659
5290
|
|
|
4660
5291
|
// src/lib/tasks-chain.ts
|
|
4661
|
-
import
|
|
5292
|
+
import path15 from "path";
|
|
4662
5293
|
import { readFile as readFile4, writeFile as writeFile5 } from "fs/promises";
|
|
4663
5294
|
async function cascadeUnblock(taskId, baseDir, now) {
|
|
4664
5295
|
const client = getClient();
|
|
@@ -4675,7 +5306,7 @@ async function cascadeUnblock(taskId, baseDir, now) {
|
|
|
4675
5306
|
});
|
|
4676
5307
|
for (const ur of unblockedRows.rows) {
|
|
4677
5308
|
try {
|
|
4678
|
-
const ubFile =
|
|
5309
|
+
const ubFile = path15.join(baseDir, String(ur.task_file));
|
|
4679
5310
|
let ubContent = await readFile4(ubFile, "utf-8");
|
|
4680
5311
|
ubContent = ubContent.replace(/\*\*Status:\*\* blocked/, "**Status:** open");
|
|
4681
5312
|
ubContent = ubContent.replace(/\n\*\*Blocked by:\*\*.*\n/, "\n");
|
|
@@ -4749,7 +5380,7 @@ __export(project_name_exports, {
|
|
|
4749
5380
|
getProjectName: () => getProjectName
|
|
4750
5381
|
});
|
|
4751
5382
|
import { execSync as execSync6 } from "child_process";
|
|
4752
|
-
import
|
|
5383
|
+
import path16 from "path";
|
|
4753
5384
|
function getProjectName(cwd) {
|
|
4754
5385
|
const dir = cwd ?? process.cwd();
|
|
4755
5386
|
if (_cached2 && _cachedCwd === dir) return _cached2;
|
|
@@ -4762,7 +5393,7 @@ function getProjectName(cwd) {
|
|
|
4762
5393
|
timeout: 2e3,
|
|
4763
5394
|
stdio: ["pipe", "pipe", "pipe"]
|
|
4764
5395
|
}).trim();
|
|
4765
|
-
repoRoot =
|
|
5396
|
+
repoRoot = path16.dirname(gitCommonDir);
|
|
4766
5397
|
} catch {
|
|
4767
5398
|
repoRoot = execSync6("git rev-parse --show-toplevel", {
|
|
4768
5399
|
cwd: dir,
|
|
@@ -4771,11 +5402,11 @@ function getProjectName(cwd) {
|
|
|
4771
5402
|
stdio: ["pipe", "pipe", "pipe"]
|
|
4772
5403
|
}).trim();
|
|
4773
5404
|
}
|
|
4774
|
-
_cached2 =
|
|
5405
|
+
_cached2 = path16.basename(repoRoot);
|
|
4775
5406
|
_cachedCwd = dir;
|
|
4776
5407
|
return _cached2;
|
|
4777
5408
|
} catch {
|
|
4778
|
-
_cached2 =
|
|
5409
|
+
_cached2 = path16.basename(dir);
|
|
4779
5410
|
_cachedCwd = dir;
|
|
4780
5411
|
return _cached2;
|
|
4781
5412
|
}
|
|
@@ -5252,7 +5883,7 @@ __export(tasks_exports, {
|
|
|
5252
5883
|
updateTaskStatus: () => updateTaskStatus,
|
|
5253
5884
|
writeCheckpoint: () => writeCheckpoint
|
|
5254
5885
|
});
|
|
5255
|
-
import
|
|
5886
|
+
import path17 from "path";
|
|
5256
5887
|
import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync6, unlinkSync as unlinkSync5 } from "fs";
|
|
5257
5888
|
async function createTask(input) {
|
|
5258
5889
|
const result = await createTaskCore(input);
|
|
@@ -5272,8 +5903,8 @@ async function updateTask(input) {
|
|
|
5272
5903
|
const { row, taskFile, now, taskId } = await updateTaskStatus(input);
|
|
5273
5904
|
try {
|
|
5274
5905
|
const agent = String(row.assigned_to);
|
|
5275
|
-
const cacheDir =
|
|
5276
|
-
const cachePath =
|
|
5906
|
+
const cacheDir = path17.join(EXE_AI_DIR, "session-cache");
|
|
5907
|
+
const cachePath = path17.join(cacheDir, `current-task-${agent}.json`);
|
|
5277
5908
|
if (input.status === "in_progress") {
|
|
5278
5909
|
mkdirSync6(cacheDir, { recursive: true });
|
|
5279
5910
|
writeFileSync6(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
|
|
@@ -5744,12 +6375,12 @@ __export(tmux_routing_exports, {
|
|
|
5744
6375
|
});
|
|
5745
6376
|
import { execFileSync as execFileSync2, execSync as execSync7 } from "child_process";
|
|
5746
6377
|
import { readFileSync as readFileSync11, writeFileSync as writeFileSync7, mkdirSync as mkdirSync7, existsSync as existsSync14, appendFileSync, readdirSync as readdirSync4 } from "fs";
|
|
5747
|
-
import
|
|
5748
|
-
import
|
|
6378
|
+
import path18 from "path";
|
|
6379
|
+
import os10 from "os";
|
|
5749
6380
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
5750
6381
|
import { unlinkSync as unlinkSync6 } from "fs";
|
|
5751
6382
|
function spawnLockPath(sessionName) {
|
|
5752
|
-
return
|
|
6383
|
+
return path18.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
|
|
5753
6384
|
}
|
|
5754
6385
|
function isProcessAlive(pid) {
|
|
5755
6386
|
try {
|
|
@@ -5786,8 +6417,8 @@ function releaseSpawnLock2(sessionName) {
|
|
|
5786
6417
|
function resolveBehaviorsExporterScript() {
|
|
5787
6418
|
try {
|
|
5788
6419
|
const thisFile = fileURLToPath2(import.meta.url);
|
|
5789
|
-
const scriptPath =
|
|
5790
|
-
|
|
6420
|
+
const scriptPath = path18.join(
|
|
6421
|
+
path18.dirname(thisFile),
|
|
5791
6422
|
"..",
|
|
5792
6423
|
"bin",
|
|
5793
6424
|
"exe-export-behaviors.js"
|
|
@@ -5862,7 +6493,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
|
5862
6493
|
mkdirSync7(SESSION_CACHE, { recursive: true });
|
|
5863
6494
|
}
|
|
5864
6495
|
const rootExe = extractRootExe(parentExe) ?? parentExe;
|
|
5865
|
-
const filePath =
|
|
6496
|
+
const filePath = path18.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
|
|
5866
6497
|
writeFileSync7(filePath, JSON.stringify({
|
|
5867
6498
|
parentExe: rootExe,
|
|
5868
6499
|
dispatchedBy: dispatchedBy || rootExe,
|
|
@@ -5871,7 +6502,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
|
5871
6502
|
}
|
|
5872
6503
|
function getParentExe(sessionKey) {
|
|
5873
6504
|
try {
|
|
5874
|
-
const data = JSON.parse(readFileSync11(
|
|
6505
|
+
const data = JSON.parse(readFileSync11(path18.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
5875
6506
|
return data.parentExe || null;
|
|
5876
6507
|
} catch {
|
|
5877
6508
|
return null;
|
|
@@ -5880,7 +6511,7 @@ function getParentExe(sessionKey) {
|
|
|
5880
6511
|
function getDispatchedBy(sessionKey) {
|
|
5881
6512
|
try {
|
|
5882
6513
|
const data = JSON.parse(readFileSync11(
|
|
5883
|
-
|
|
6514
|
+
path18.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
|
|
5884
6515
|
"utf8"
|
|
5885
6516
|
));
|
|
5886
6517
|
return data.dispatchedBy ?? data.parentExe ?? null;
|
|
@@ -5891,15 +6522,24 @@ function getDispatchedBy(sessionKey) {
|
|
|
5891
6522
|
function resolveExeSession() {
|
|
5892
6523
|
const mySession = getMySession();
|
|
5893
6524
|
if (!mySession) return null;
|
|
6525
|
+
const fromSessionName = extractRootExe(mySession);
|
|
5894
6526
|
try {
|
|
5895
6527
|
const key = getSessionKey();
|
|
5896
6528
|
const parentExe = getParentExe(key);
|
|
5897
6529
|
if (parentExe) {
|
|
5898
|
-
|
|
6530
|
+
const fromCache = extractRootExe(parentExe) ?? parentExe;
|
|
6531
|
+
if (fromSessionName && fromCache !== fromSessionName) {
|
|
6532
|
+
process.stderr.write(
|
|
6533
|
+
`[tmux-routing] WARN: cache says "${fromCache}" but session name says "${fromSessionName}". Trusting session name.
|
|
6534
|
+
`
|
|
6535
|
+
);
|
|
6536
|
+
return fromSessionName;
|
|
6537
|
+
}
|
|
6538
|
+
return fromCache;
|
|
5899
6539
|
}
|
|
5900
6540
|
} catch {
|
|
5901
6541
|
}
|
|
5902
|
-
return
|
|
6542
|
+
return fromSessionName ?? mySession;
|
|
5903
6543
|
}
|
|
5904
6544
|
function isEmployeeAlive(sessionName) {
|
|
5905
6545
|
return getTransport().isAlive(sessionName);
|
|
@@ -6057,7 +6697,7 @@ function sendIntercom(targetSession) {
|
|
|
6057
6697
|
try {
|
|
6058
6698
|
const rawAgent = targetSession.split("-")[0] ?? targetSession;
|
|
6059
6699
|
const agent = baseAgentName(rawAgent);
|
|
6060
|
-
const markerPath =
|
|
6700
|
+
const markerPath = path18.join(SESSION_CACHE, `current-task-${agent}.json`);
|
|
6061
6701
|
if (existsSync14(markerPath)) {
|
|
6062
6702
|
logIntercom(`SKIP \u2192 ${targetSession} (has in_progress task marker \u2014 will auto-chain)`);
|
|
6063
6703
|
return "debounced";
|
|
@@ -6067,7 +6707,7 @@ function sendIntercom(targetSession) {
|
|
|
6067
6707
|
try {
|
|
6068
6708
|
const rawAgent = targetSession.split("-")[0] ?? targetSession;
|
|
6069
6709
|
const agent = baseAgentName(rawAgent);
|
|
6070
|
-
const taskDir =
|
|
6710
|
+
const taskDir = path18.join(process.cwd(), "exe", agent);
|
|
6071
6711
|
if (existsSync14(taskDir)) {
|
|
6072
6712
|
const files = readdirSync4(taskDir).filter(
|
|
6073
6713
|
(f) => f.endsWith(".md") && f !== "DONE.txt"
|
|
@@ -6201,8 +6841,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
6201
6841
|
const transport = getTransport();
|
|
6202
6842
|
const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
|
|
6203
6843
|
const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
|
|
6204
|
-
const logDir =
|
|
6205
|
-
const logFile =
|
|
6844
|
+
const logDir = path18.join(os10.homedir(), ".exe-os", "session-logs");
|
|
6845
|
+
const logFile = path18.join(logDir, `${instanceLabel}-${Date.now()}.log`);
|
|
6206
6846
|
if (!existsSync14(logDir)) {
|
|
6207
6847
|
mkdirSync7(logDir, { recursive: true });
|
|
6208
6848
|
}
|
|
@@ -6210,14 +6850,14 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
6210
6850
|
let cleanupSuffix = "";
|
|
6211
6851
|
try {
|
|
6212
6852
|
const thisFile = fileURLToPath2(import.meta.url);
|
|
6213
|
-
const cleanupScript =
|
|
6853
|
+
const cleanupScript = path18.join(path18.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
|
|
6214
6854
|
if (existsSync14(cleanupScript)) {
|
|
6215
6855
|
cleanupSuffix = `; ${process.execPath} "${cleanupScript}" "${employeeName}" "${exeSession}"`;
|
|
6216
6856
|
}
|
|
6217
6857
|
} catch {
|
|
6218
6858
|
}
|
|
6219
6859
|
try {
|
|
6220
|
-
const claudeJsonPath =
|
|
6860
|
+
const claudeJsonPath = path18.join(os10.homedir(), ".claude.json");
|
|
6221
6861
|
let claudeJson = {};
|
|
6222
6862
|
try {
|
|
6223
6863
|
claudeJson = JSON.parse(readFileSync11(claudeJsonPath, "utf8"));
|
|
@@ -6232,10 +6872,10 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
6232
6872
|
} catch {
|
|
6233
6873
|
}
|
|
6234
6874
|
try {
|
|
6235
|
-
const settingsDir =
|
|
6875
|
+
const settingsDir = path18.join(os10.homedir(), ".claude", "projects");
|
|
6236
6876
|
const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
|
|
6237
|
-
const projSettingsDir =
|
|
6238
|
-
const settingsPath =
|
|
6877
|
+
const projSettingsDir = path18.join(settingsDir, normalizedKey);
|
|
6878
|
+
const settingsPath = path18.join(projSettingsDir, "settings.json");
|
|
6239
6879
|
let settings = {};
|
|
6240
6880
|
try {
|
|
6241
6881
|
settings = JSON.parse(readFileSync11(settingsPath, "utf8"));
|
|
@@ -6282,8 +6922,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
6282
6922
|
let behaviorsFlag = "";
|
|
6283
6923
|
let legacyFallbackWarned = false;
|
|
6284
6924
|
if (!useExeAgent && !useBinSymlink) {
|
|
6285
|
-
const identityPath =
|
|
6286
|
-
|
|
6925
|
+
const identityPath = path18.join(
|
|
6926
|
+
os10.homedir(),
|
|
6287
6927
|
".exe-os",
|
|
6288
6928
|
"identity",
|
|
6289
6929
|
`${employeeName}.md`
|
|
@@ -6298,7 +6938,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
6298
6938
|
}
|
|
6299
6939
|
const behaviorsFile = exportBehaviorsSync(
|
|
6300
6940
|
employeeName,
|
|
6301
|
-
|
|
6941
|
+
path18.basename(spawnCwd),
|
|
6302
6942
|
sessionName
|
|
6303
6943
|
);
|
|
6304
6944
|
if (behaviorsFile) {
|
|
@@ -6313,9 +6953,9 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
6313
6953
|
}
|
|
6314
6954
|
let sessionContextFlag = "";
|
|
6315
6955
|
try {
|
|
6316
|
-
const ctxDir =
|
|
6956
|
+
const ctxDir = path18.join(os10.homedir(), ".exe-os", "session-cache");
|
|
6317
6957
|
mkdirSync7(ctxDir, { recursive: true });
|
|
6318
|
-
const ctxFile =
|
|
6958
|
+
const ctxFile = path18.join(ctxDir, `session-context-${sessionName}.md`);
|
|
6319
6959
|
const ctxContent = [
|
|
6320
6960
|
`## Session Context`,
|
|
6321
6961
|
`You are running in tmux session: ${sessionName}.`,
|
|
@@ -6399,7 +7039,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
6399
7039
|
transport.pipeLog(sessionName, logFile);
|
|
6400
7040
|
try {
|
|
6401
7041
|
const mySession = getMySession();
|
|
6402
|
-
const dispatchInfo =
|
|
7042
|
+
const dispatchInfo = path18.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
|
|
6403
7043
|
writeFileSync7(dispatchInfo, JSON.stringify({
|
|
6404
7044
|
dispatchedBy: mySession,
|
|
6405
7045
|
rootExe: exeSession,
|
|
@@ -6474,15 +7114,15 @@ var init_tmux_routing = __esm({
|
|
|
6474
7114
|
init_intercom_queue();
|
|
6475
7115
|
init_plan_limits();
|
|
6476
7116
|
init_employees();
|
|
6477
|
-
SPAWN_LOCK_DIR =
|
|
6478
|
-
SESSION_CACHE =
|
|
7117
|
+
SPAWN_LOCK_DIR = path18.join(os10.homedir(), ".exe-os", "spawn-locks");
|
|
7118
|
+
SESSION_CACHE = path18.join(os10.homedir(), ".exe-os", "session-cache");
|
|
6479
7119
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
6480
7120
|
VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
|
|
6481
7121
|
VERIFY_PANE_LINES = 200;
|
|
6482
7122
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
6483
7123
|
CODEX_DEBOUNCE_MS = 12e4;
|
|
6484
|
-
INTERCOM_LOG2 =
|
|
6485
|
-
DEBOUNCE_FILE =
|
|
7124
|
+
INTERCOM_LOG2 = path18.join(os10.homedir(), ".exe-os", "intercom.log");
|
|
7125
|
+
DEBOUNCE_FILE = path18.join(SESSION_CACHE, "intercom-debounce.json");
|
|
6486
7126
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
6487
7127
|
BUSY_PATTERN = /[✻✽✶✳·].*…|Running…|• Working|• Ran |• Explored|• Called|esc to interrupt/;
|
|
6488
7128
|
}
|
|
@@ -6540,12 +7180,12 @@ __export(worker_gate_exports, {
|
|
|
6540
7180
|
tryAcquireWorkerSlot: () => tryAcquireWorkerSlot
|
|
6541
7181
|
});
|
|
6542
7182
|
import { readdirSync as readdirSync6, writeFileSync as writeFileSync9, unlinkSync as unlinkSync8, mkdirSync as mkdirSync9, existsSync as existsSync15 } from "fs";
|
|
6543
|
-
import
|
|
7183
|
+
import path20 from "path";
|
|
6544
7184
|
function tryAcquireWorkerSlot() {
|
|
6545
7185
|
try {
|
|
6546
7186
|
mkdirSync9(WORKER_PID_DIR, { recursive: true });
|
|
6547
7187
|
const reservationId = `res-${process.pid}-${Date.now()}`;
|
|
6548
|
-
const reservationPath =
|
|
7188
|
+
const reservationPath = path20.join(WORKER_PID_DIR, `${reservationId}.pid`);
|
|
6549
7189
|
writeFileSync9(reservationPath, String(process.pid));
|
|
6550
7190
|
const files = readdirSync6(WORKER_PID_DIR);
|
|
6551
7191
|
let alive = 0;
|
|
@@ -6563,7 +7203,7 @@ function tryAcquireWorkerSlot() {
|
|
|
6563
7203
|
alive++;
|
|
6564
7204
|
} catch {
|
|
6565
7205
|
try {
|
|
6566
|
-
unlinkSync8(
|
|
7206
|
+
unlinkSync8(path20.join(WORKER_PID_DIR, f));
|
|
6567
7207
|
} catch {
|
|
6568
7208
|
}
|
|
6569
7209
|
}
|
|
@@ -6587,13 +7227,13 @@ function tryAcquireWorkerSlot() {
|
|
|
6587
7227
|
function registerWorkerPid(pid) {
|
|
6588
7228
|
try {
|
|
6589
7229
|
mkdirSync9(WORKER_PID_DIR, { recursive: true });
|
|
6590
|
-
writeFileSync9(
|
|
7230
|
+
writeFileSync9(path20.join(WORKER_PID_DIR, `worker-${pid}.pid`), String(pid));
|
|
6591
7231
|
} catch {
|
|
6592
7232
|
}
|
|
6593
7233
|
}
|
|
6594
7234
|
function cleanupWorkerPid() {
|
|
6595
7235
|
try {
|
|
6596
|
-
unlinkSync8(
|
|
7236
|
+
unlinkSync8(path20.join(WORKER_PID_DIR, `worker-${process.pid}.pid`));
|
|
6597
7237
|
} catch {
|
|
6598
7238
|
}
|
|
6599
7239
|
}
|
|
@@ -6633,9 +7273,9 @@ var init_worker_gate = __esm({
|
|
|
6633
7273
|
"src/lib/worker-gate.ts"() {
|
|
6634
7274
|
"use strict";
|
|
6635
7275
|
init_config();
|
|
6636
|
-
WORKER_PID_DIR =
|
|
7276
|
+
WORKER_PID_DIR = path20.join(EXE_AI_DIR, "worker-pids");
|
|
6637
7277
|
MAX_CONCURRENT_WORKERS = 3;
|
|
6638
|
-
BACKFILL_LOCK =
|
|
7278
|
+
BACKFILL_LOCK = path20.join(WORKER_PID_DIR, "backfill.lock");
|
|
6639
7279
|
}
|
|
6640
7280
|
});
|
|
6641
7281
|
|
|
@@ -6738,7 +7378,7 @@ __export(crdt_sync_exports, {
|
|
|
6738
7378
|
});
|
|
6739
7379
|
import * as Y from "yjs";
|
|
6740
7380
|
import { readFileSync as readFileSync13, writeFileSync as writeFileSync10, existsSync as existsSync16, mkdirSync as mkdirSync10, unlinkSync as unlinkSync9 } from "fs";
|
|
6741
|
-
import
|
|
7381
|
+
import path21 from "path";
|
|
6742
7382
|
import { homedir } from "os";
|
|
6743
7383
|
function getStatePath() {
|
|
6744
7384
|
return _statePathOverride ?? DEFAULT_STATE_PATH;
|
|
@@ -6894,7 +7534,7 @@ function persistState() {
|
|
|
6894
7534
|
if (!doc) return;
|
|
6895
7535
|
try {
|
|
6896
7536
|
const sp = getStatePath();
|
|
6897
|
-
const dir =
|
|
7537
|
+
const dir = path21.dirname(sp);
|
|
6898
7538
|
if (!existsSync16(dir)) mkdirSync10(dir, { recursive: true });
|
|
6899
7539
|
const state = Y.encodeStateAsUpdate(doc);
|
|
6900
7540
|
writeFileSync10(sp, Buffer.from(state));
|
|
@@ -6938,7 +7578,7 @@ var DEFAULT_STATE_PATH, _statePathOverride, doc;
|
|
|
6938
7578
|
var init_crdt_sync = __esm({
|
|
6939
7579
|
"src/lib/crdt-sync.ts"() {
|
|
6940
7580
|
"use strict";
|
|
6941
|
-
DEFAULT_STATE_PATH =
|
|
7581
|
+
DEFAULT_STATE_PATH = path21.join(homedir(), ".exe-os", "crdt-state.bin");
|
|
6942
7582
|
_statePathOverride = null;
|
|
6943
7583
|
doc = null;
|
|
6944
7584
|
}
|
|
@@ -6974,14 +7614,14 @@ __export(cloud_sync_exports, {
|
|
|
6974
7614
|
});
|
|
6975
7615
|
import { readFileSync as readFileSync14, writeFileSync as writeFileSync11, existsSync as existsSync17, readdirSync as readdirSync7, mkdirSync as mkdirSync11, appendFileSync as appendFileSync2, unlinkSync as unlinkSync10, openSync as openSync2, closeSync as closeSync2 } from "fs";
|
|
6976
7616
|
import crypto7 from "crypto";
|
|
6977
|
-
import
|
|
7617
|
+
import path22 from "path";
|
|
6978
7618
|
import { homedir as homedir2 } from "os";
|
|
6979
7619
|
function sqlSafe(v) {
|
|
6980
7620
|
return v === void 0 ? null : v;
|
|
6981
7621
|
}
|
|
6982
7622
|
function logError(msg) {
|
|
6983
7623
|
try {
|
|
6984
|
-
const logPath =
|
|
7624
|
+
const logPath = path22.join(homedir2(), ".exe-os", "workers.log");
|
|
6985
7625
|
appendFileSync2(logPath, `${(/* @__PURE__ */ new Date()).toISOString()} ${msg}
|
|
6986
7626
|
`);
|
|
6987
7627
|
} catch {
|
|
@@ -7376,7 +8016,7 @@ async function cloudSync(config) {
|
|
|
7376
8016
|
try {
|
|
7377
8017
|
const employees = await loadEmployees();
|
|
7378
8018
|
rosterResult.employees = employees.length;
|
|
7379
|
-
const idDir =
|
|
8019
|
+
const idDir = path22.join(EXE_AI_DIR, "identity");
|
|
7380
8020
|
if (existsSync17(idDir)) {
|
|
7381
8021
|
rosterResult.identities = readdirSync7(idDir).filter((f) => f.endsWith(".md")).length;
|
|
7382
8022
|
}
|
|
@@ -7417,9 +8057,9 @@ function consumeRosterDeletions() {
|
|
|
7417
8057
|
}
|
|
7418
8058
|
}
|
|
7419
8059
|
function buildRosterBlob(paths) {
|
|
7420
|
-
const rosterPath = paths?.rosterPath ??
|
|
7421
|
-
const identityDir = paths?.identityDir ??
|
|
7422
|
-
const configPath = paths?.configPath ??
|
|
8060
|
+
const rosterPath = paths?.rosterPath ?? path22.join(EXE_AI_DIR, "exe-employees.json");
|
|
8061
|
+
const identityDir = paths?.identityDir ?? path22.join(EXE_AI_DIR, "identity");
|
|
8062
|
+
const configPath = paths?.configPath ?? path22.join(EXE_AI_DIR, "config.json");
|
|
7423
8063
|
let roster = [];
|
|
7424
8064
|
if (existsSync17(rosterPath)) {
|
|
7425
8065
|
try {
|
|
@@ -7431,7 +8071,7 @@ function buildRosterBlob(paths) {
|
|
|
7431
8071
|
if (existsSync17(identityDir)) {
|
|
7432
8072
|
for (const file of readdirSync7(identityDir).filter((f) => f.endsWith(".md"))) {
|
|
7433
8073
|
try {
|
|
7434
|
-
identities[file] = readFileSync14(
|
|
8074
|
+
identities[file] = readFileSync14(path22.join(identityDir, file), "utf-8");
|
|
7435
8075
|
} catch {
|
|
7436
8076
|
}
|
|
7437
8077
|
}
|
|
@@ -7444,7 +8084,7 @@ function buildRosterBlob(paths) {
|
|
|
7444
8084
|
}
|
|
7445
8085
|
}
|
|
7446
8086
|
let agentConfig;
|
|
7447
|
-
const agentConfigPath =
|
|
8087
|
+
const agentConfigPath = path22.join(EXE_AI_DIR, "agent-config.json");
|
|
7448
8088
|
if (existsSync17(agentConfigPath)) {
|
|
7449
8089
|
try {
|
|
7450
8090
|
agentConfig = JSON.parse(readFileSync14(agentConfigPath, "utf-8"));
|
|
@@ -7523,7 +8163,7 @@ async function cloudPullRoster(config) {
|
|
|
7523
8163
|
}
|
|
7524
8164
|
}
|
|
7525
8165
|
function mergeConfig(remoteConfig, configPath) {
|
|
7526
|
-
const cfgPath = configPath ??
|
|
8166
|
+
const cfgPath = configPath ?? path22.join(EXE_AI_DIR, "config.json");
|
|
7527
8167
|
let local = {};
|
|
7528
8168
|
if (existsSync17(cfgPath)) {
|
|
7529
8169
|
try {
|
|
@@ -7532,14 +8172,14 @@ function mergeConfig(remoteConfig, configPath) {
|
|
|
7532
8172
|
}
|
|
7533
8173
|
}
|
|
7534
8174
|
const merged = { ...remoteConfig, ...local };
|
|
7535
|
-
const dir =
|
|
8175
|
+
const dir = path22.dirname(cfgPath);
|
|
7536
8176
|
if (!existsSync17(dir)) mkdirSync11(dir, { recursive: true });
|
|
7537
8177
|
writeFileSync11(cfgPath, JSON.stringify(merged, null, 2), "utf-8");
|
|
7538
8178
|
}
|
|
7539
8179
|
async function mergeRosterFromRemote(remote, paths) {
|
|
7540
8180
|
return withRosterLock(async () => {
|
|
7541
8181
|
const rosterPath = paths?.rosterPath ?? void 0;
|
|
7542
|
-
const identityDir = paths?.identityDir ??
|
|
8182
|
+
const identityDir = paths?.identityDir ?? path22.join(EXE_AI_DIR, "identity");
|
|
7543
8183
|
const localEmployees = await loadEmployees(rosterPath);
|
|
7544
8184
|
const localNames = new Set(localEmployees.map((e) => e.name));
|
|
7545
8185
|
let added = 0;
|
|
@@ -7561,7 +8201,7 @@ async function mergeRosterFromRemote(remote, paths) {
|
|
|
7561
8201
|
const remoteIdentity = remote.identities[matchedKey];
|
|
7562
8202
|
if (remoteIdentity) {
|
|
7563
8203
|
if (!existsSync17(identityDir)) mkdirSync11(identityDir, { recursive: true });
|
|
7564
|
-
const idPath =
|
|
8204
|
+
const idPath = path22.join(identityDir, `${remoteEmp.name}.md`);
|
|
7565
8205
|
let localIdentity = null;
|
|
7566
8206
|
try {
|
|
7567
8207
|
localIdentity = existsSync17(idPath) ? readFileSync14(idPath, "utf-8") : null;
|
|
@@ -7594,7 +8234,7 @@ async function mergeRosterFromRemote(remote, paths) {
|
|
|
7594
8234
|
}
|
|
7595
8235
|
if (remote.agentConfig && Object.keys(remote.agentConfig).length > 0) {
|
|
7596
8236
|
try {
|
|
7597
|
-
const agentConfigPath =
|
|
8237
|
+
const agentConfigPath = path22.join(EXE_AI_DIR, "agent-config.json");
|
|
7598
8238
|
let local = {};
|
|
7599
8239
|
if (existsSync17(agentConfigPath)) {
|
|
7600
8240
|
try {
|
|
@@ -8041,9 +8681,9 @@ var init_cloud_sync = __esm({
|
|
|
8041
8681
|
LOCALHOST_PATTERNS = /^(localhost|127\.0\.0\.1|\[::1\])$/i;
|
|
8042
8682
|
FETCH_TIMEOUT_MS = 3e4;
|
|
8043
8683
|
PUSH_BATCH_SIZE = 5e3;
|
|
8044
|
-
ROSTER_LOCK_PATH =
|
|
8684
|
+
ROSTER_LOCK_PATH = path22.join(EXE_AI_DIR, "roster-merge.lock");
|
|
8045
8685
|
LOCK_STALE_MS = 3e4;
|
|
8046
|
-
ROSTER_DELETIONS_PATH =
|
|
8686
|
+
ROSTER_DELETIONS_PATH = path22.join(EXE_AI_DIR, "roster-deletions.json");
|
|
8047
8687
|
}
|
|
8048
8688
|
});
|
|
8049
8689
|
|
|
@@ -8225,10 +8865,10 @@ var init_schedules = __esm({
|
|
|
8225
8865
|
|
|
8226
8866
|
// src/bin/exe-boot.ts
|
|
8227
8867
|
init_employees();
|
|
8228
|
-
import
|
|
8868
|
+
import path23 from "path";
|
|
8229
8869
|
import { mkdir as mkdir5, writeFile as writeFile6 } from "fs/promises";
|
|
8230
8870
|
import { existsSync as existsSync18, readFileSync as readFileSync15, readdirSync as readdirSync8, unlinkSync as unlinkSync11 } from "fs";
|
|
8231
|
-
import
|
|
8871
|
+
import os11 from "os";
|
|
8232
8872
|
|
|
8233
8873
|
// src/lib/employee-templates.ts
|
|
8234
8874
|
init_global_procedures();
|
|
@@ -8732,11 +9372,11 @@ init_session_key();
|
|
|
8732
9372
|
init_employees();
|
|
8733
9373
|
import { readFileSync as readFileSync12, writeFileSync as writeFileSync8, mkdirSync as mkdirSync8, unlinkSync as unlinkSync7, readdirSync as readdirSync5 } from "fs";
|
|
8734
9374
|
import { execSync as execSync8 } from "child_process";
|
|
8735
|
-
import
|
|
8736
|
-
var CACHE_DIR =
|
|
9375
|
+
import path19 from "path";
|
|
9376
|
+
var CACHE_DIR = path19.join(EXE_AI_DIR, "session-cache");
|
|
8737
9377
|
var STALE_MS = 24 * 60 * 60 * 1e3;
|
|
8738
9378
|
function getMarkerPath() {
|
|
8739
|
-
return
|
|
9379
|
+
return path19.join(CACHE_DIR, `active-agent-${getSessionKey()}.json`);
|
|
8740
9380
|
}
|
|
8741
9381
|
function writeActiveAgent(agentId, agentRole) {
|
|
8742
9382
|
try {
|
|
@@ -8751,11 +9391,11 @@ function writeActiveAgent(agentId, agentRole) {
|
|
|
8751
9391
|
function cleanupSessionMarkers() {
|
|
8752
9392
|
const key = getSessionKey();
|
|
8753
9393
|
try {
|
|
8754
|
-
unlinkSync7(
|
|
9394
|
+
unlinkSync7(path19.join(CACHE_DIR, `active-agent-${key}.json`));
|
|
8755
9395
|
} catch {
|
|
8756
9396
|
}
|
|
8757
9397
|
try {
|
|
8758
|
-
unlinkSync7(
|
|
9398
|
+
unlinkSync7(path19.join(CACHE_DIR, "active-agent-undefined.json"));
|
|
8759
9399
|
} catch {
|
|
8760
9400
|
}
|
|
8761
9401
|
}
|
|
@@ -8845,7 +9485,7 @@ async function boot(options) {
|
|
|
8845
9485
|
const employeeDirs = entries.filter((e) => e.isDirectory() && !["output", "research"].includes(e.name));
|
|
8846
9486
|
for (const dir of employeeDirs) {
|
|
8847
9487
|
const employee = dir.name;
|
|
8848
|
-
const taskDir =
|
|
9488
|
+
const taskDir = path23.join(exeDir, employee);
|
|
8849
9489
|
let files;
|
|
8850
9490
|
try {
|
|
8851
9491
|
files = readdirSync9(taskDir).filter((f) => f.endsWith(".md"));
|
|
@@ -8856,7 +9496,7 @@ async function boot(options) {
|
|
|
8856
9496
|
const taskFilePath = `exe/${employee}/${file}`;
|
|
8857
9497
|
let content;
|
|
8858
9498
|
try {
|
|
8859
|
-
content = readFs(
|
|
9499
|
+
content = readFs(path23.join(taskDir, file), "utf8");
|
|
8860
9500
|
} catch {
|
|
8861
9501
|
continue;
|
|
8862
9502
|
}
|
|
@@ -8942,12 +9582,12 @@ async function boot(options) {
|
|
|
8942
9582
|
}
|
|
8943
9583
|
try {
|
|
8944
9584
|
for (const reviewDirName of /* @__PURE__ */ new Set(["exe", coordinatorName])) {
|
|
8945
|
-
const reviewDir =
|
|
9585
|
+
const reviewDir = path23.join(process.cwd(), "exe", reviewDirName);
|
|
8946
9586
|
if (existsSync18(reviewDir)) {
|
|
8947
9587
|
for (const f of readdirSync8(reviewDir)) {
|
|
8948
9588
|
if (f.startsWith("review-") && f.endsWith(".md")) {
|
|
8949
9589
|
try {
|
|
8950
|
-
unlinkSync11(
|
|
9590
|
+
unlinkSync11(path23.join(reviewDir, f));
|
|
8951
9591
|
} catch {
|
|
8952
9592
|
}
|
|
8953
9593
|
}
|
|
@@ -8993,7 +9633,7 @@ async function boot(options) {
|
|
|
8993
9633
|
});
|
|
8994
9634
|
const taskFile = String(r.task_file);
|
|
8995
9635
|
try {
|
|
8996
|
-
const filePath =
|
|
9636
|
+
const filePath = path23.join(process.cwd(), taskFile);
|
|
8997
9637
|
if (existsSync18(filePath)) {
|
|
8998
9638
|
let content = readFileSync15(filePath, "utf8");
|
|
8999
9639
|
content = content.replace(/\*\*Status:\*\* needs_review/, "**Status:** done");
|
|
@@ -9492,8 +10132,8 @@ async function boot(options) {
|
|
|
9492
10132
|
})()
|
|
9493
10133
|
]);
|
|
9494
10134
|
try {
|
|
9495
|
-
const configPath =
|
|
9496
|
-
process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ??
|
|
10135
|
+
const configPath = path23.join(
|
|
10136
|
+
process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path23.join(os11.homedir(), ".exe-os"),
|
|
9497
10137
|
"config.json"
|
|
9498
10138
|
);
|
|
9499
10139
|
if (existsSync18(configPath)) {
|
|
@@ -9503,7 +10143,7 @@ async function boot(options) {
|
|
|
9503
10143
|
} catch {
|
|
9504
10144
|
}
|
|
9505
10145
|
try {
|
|
9506
|
-
const backfillFlagPath =
|
|
10146
|
+
const backfillFlagPath = path23.join(EXE_AI_DIR, "session-cache", "needs-backfill");
|
|
9507
10147
|
const isBackfillNeeded = () => existsSync18(backfillFlagPath);
|
|
9508
10148
|
const coverageResult = await client.execute({
|
|
9509
10149
|
sql: `SELECT COUNT(*) as total,
|
|
@@ -9526,7 +10166,7 @@ async function boot(options) {
|
|
|
9526
10166
|
let daemonRunning = false;
|
|
9527
10167
|
let daemonUptime;
|
|
9528
10168
|
let daemonRequestsServed;
|
|
9529
|
-
const socketPath =
|
|
10169
|
+
const socketPath = path23.join(EXE_AI_DIR, "exed.sock");
|
|
9530
10170
|
if (existsSync18(socketPath)) {
|
|
9531
10171
|
try {
|
|
9532
10172
|
const net2 = await import("net");
|
|
@@ -9569,7 +10209,7 @@ async function boot(options) {
|
|
|
9569
10209
|
}
|
|
9570
10210
|
}
|
|
9571
10211
|
if (!daemonRunning) {
|
|
9572
|
-
const pidPath =
|
|
10212
|
+
const pidPath = path23.join(EXE_AI_DIR, "exed.pid");
|
|
9573
10213
|
if (existsSync18(pidPath)) {
|
|
9574
10214
|
try {
|
|
9575
10215
|
const pid = parseInt(readFileSync15(pidPath, "utf8").trim(), 10);
|
|
@@ -9583,7 +10223,7 @@ async function boot(options) {
|
|
|
9583
10223
|
}
|
|
9584
10224
|
if (nullCount === 0) {
|
|
9585
10225
|
try {
|
|
9586
|
-
const flagPath =
|
|
10226
|
+
const flagPath = path23.join(EXE_AI_DIR, "session-cache", "needs-backfill");
|
|
9587
10227
|
if (existsSync18(flagPath)) {
|
|
9588
10228
|
const { unlinkSync: unlinkSync12 } = await import("fs");
|
|
9589
10229
|
unlinkSync12(flagPath);
|
|
@@ -9610,10 +10250,10 @@ async function boot(options) {
|
|
|
9610
10250
|
const { spawn: spawn2 } = await import("child_process");
|
|
9611
10251
|
const { fileURLToPath: fileURLToPath4 } = await import("url");
|
|
9612
10252
|
const thisFile = fileURLToPath4(import.meta.url);
|
|
9613
|
-
const backfillPath =
|
|
10253
|
+
const backfillPath = path23.resolve(path23.dirname(thisFile), "backfill-vectors.js");
|
|
9614
10254
|
if (existsSync18(backfillPath)) {
|
|
9615
10255
|
const { openSync: openSync3, closeSync: closeSync3 } = await import("fs");
|
|
9616
|
-
const workerLogPath =
|
|
10256
|
+
const workerLogPath = path23.join(EXE_AI_DIR, "workers.log");
|
|
9617
10257
|
let stderrFd = "ignore";
|
|
9618
10258
|
try {
|
|
9619
10259
|
stderrFd = openSync3(workerLogPath, "a");
|
|
@@ -9643,7 +10283,7 @@ async function boot(options) {
|
|
|
9643
10283
|
const criticalBinaries = ["backfill-vectors.js", "scan-tasks.js"];
|
|
9644
10284
|
const missing = [];
|
|
9645
10285
|
for (const bin of criticalBinaries) {
|
|
9646
|
-
const binPath =
|
|
10286
|
+
const binPath = path23.resolve(path23.dirname(thisFile), bin);
|
|
9647
10287
|
if (!existsSync18(binPath)) {
|
|
9648
10288
|
missing.push(`dist/bin/${bin}`);
|
|
9649
10289
|
}
|
|
@@ -9673,7 +10313,7 @@ async function boot(options) {
|
|
|
9673
10313
|
console.log(brief);
|
|
9674
10314
|
return;
|
|
9675
10315
|
}
|
|
9676
|
-
const sessionDir =
|
|
10316
|
+
const sessionDir = path23.join(EXE_AI_DIR, "sessions", coordinatorName);
|
|
9677
10317
|
await mkdir5(sessionDir, { recursive: true });
|
|
9678
10318
|
const claudeMdContent = `${getSessionPrompt(coordinatorEmployee.systemPrompt)}
|
|
9679
10319
|
|
|
@@ -9682,7 +10322,7 @@ async function boot(options) {
|
|
|
9682
10322
|
# Status Brief
|
|
9683
10323
|
|
|
9684
10324
|
${brief}`;
|
|
9685
|
-
await writeFile6(
|
|
10325
|
+
await writeFile6(path23.join(sessionDir, "CLAUDE.md"), claudeMdContent, "utf-8");
|
|
9686
10326
|
const unread = await readUnreadNotifications();
|
|
9687
10327
|
if (unread.length > 0) {
|
|
9688
10328
|
console.log(`\u{1F4EC} ${unread.length} unread notification${unread.length === 1 ? "" : "s"}`);
|
|
@@ -9691,8 +10331,8 @@ ${brief}`;
|
|
|
9691
10331
|
await cleanupOldNotifications();
|
|
9692
10332
|
console.log(brief);
|
|
9693
10333
|
try {
|
|
9694
|
-
const configPath2 =
|
|
9695
|
-
process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ??
|
|
10334
|
+
const configPath2 = path23.join(
|
|
10335
|
+
process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path23.join(os11.homedir(), ".exe-os"),
|
|
9696
10336
|
"config.json"
|
|
9697
10337
|
);
|
|
9698
10338
|
if (existsSync18(configPath2)) {
|