@askexenow/exe-os 0.9.7 → 0.9.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/backfill-conversations.js +754 -79
- package/dist/bin/backfill-responses.js +752 -77
- package/dist/bin/backfill-vectors.js +752 -77
- package/dist/bin/cleanup-stale-review-tasks.js +657 -35
- package/dist/bin/cli.js +1388 -605
- package/dist/bin/exe-agent-config.js +123 -95
- package/dist/bin/exe-agent.js +41 -25
- package/dist/bin/exe-assign.js +732 -57
- package/dist/bin/exe-boot.js +784 -153
- package/dist/bin/exe-call.js +209 -138
- package/dist/bin/exe-cloud.js +35 -12
- package/dist/bin/exe-dispatch.js +692 -70
- package/dist/bin/exe-doctor.js +648 -26
- package/dist/bin/exe-export-behaviors.js +650 -20
- package/dist/bin/exe-forget.js +635 -13
- package/dist/bin/exe-gateway.js +1053 -271
- package/dist/bin/exe-heartbeat.js +665 -43
- package/dist/bin/exe-kill.js +646 -16
- package/dist/bin/exe-launch-agent.js +887 -97
- package/dist/bin/exe-link.js +658 -43
- package/dist/bin/exe-new-employee.js +378 -177
- package/dist/bin/exe-pending-messages.js +656 -34
- package/dist/bin/exe-pending-notifications.js +635 -13
- package/dist/bin/exe-pending-reviews.js +659 -37
- package/dist/bin/exe-rename.js +645 -30
- package/dist/bin/exe-review.js +635 -13
- package/dist/bin/exe-search.js +771 -88
- package/dist/bin/exe-session-cleanup.js +834 -150
- package/dist/bin/exe-settings.js +127 -91
- package/dist/bin/exe-start-codex.js +729 -94
- package/dist/bin/exe-start-opencode.js +717 -82
- package/dist/bin/exe-status.js +657 -35
- package/dist/bin/exe-team.js +635 -13
- package/dist/bin/git-sweep.js +720 -89
- package/dist/bin/graph-backfill.js +643 -13
- package/dist/bin/graph-export.js +646 -16
- package/dist/bin/install.js +596 -193
- package/dist/bin/scan-tasks.js +724 -93
- package/dist/bin/setup.js +1038 -210
- package/dist/bin/shard-migrate.js +645 -15
- package/dist/bin/wiki-sync.js +646 -16
- package/dist/gateway/index.js +1027 -245
- package/dist/hooks/bug-report-worker.js +891 -170
- package/dist/hooks/commit-complete.js +718 -87
- package/dist/hooks/error-recall.js +776 -93
- package/dist/hooks/exe-heartbeat-hook.js +85 -71
- package/dist/hooks/ingest-worker.js +840 -156
- package/dist/hooks/ingest.js +90 -73
- package/dist/hooks/instructions-loaded.js +669 -38
- package/dist/hooks/notification.js +661 -30
- package/dist/hooks/post-compact.js +674 -43
- package/dist/hooks/pre-compact.js +718 -87
- package/dist/hooks/pre-tool-use.js +872 -125
- package/dist/hooks/prompt-ingest-worker.js +758 -83
- package/dist/hooks/prompt-submit.js +1060 -319
- package/dist/hooks/response-ingest-worker.js +758 -83
- package/dist/hooks/session-end.js +721 -90
- package/dist/hooks/session-start.js +1031 -207
- package/dist/hooks/stop.js +680 -49
- package/dist/hooks/subagent-stop.js +674 -43
- package/dist/hooks/summary-worker.js +816 -132
- package/dist/index.js +1015 -232
- package/dist/lib/cloud-sync.js +663 -48
- package/dist/lib/consolidation.js +26 -3
- package/dist/lib/database.js +626 -18
- package/dist/lib/db.js +2261 -0
- package/dist/lib/device-registry.js +640 -25
- package/dist/lib/embedder.js +96 -43
- package/dist/lib/employee-templates.js +16 -0
- package/dist/lib/employees.js +259 -83
- package/dist/lib/exe-daemon-client.js +101 -63
- package/dist/lib/exe-daemon.js +894 -162
- package/dist/lib/hybrid-search.js +771 -88
- package/dist/lib/identity.js +27 -7
- package/dist/lib/messaging.js +55 -28
- package/dist/lib/reminders.js +21 -1
- package/dist/lib/schedules.js +636 -14
- package/dist/lib/skill-learning.js +21 -1
- package/dist/lib/store.js +643 -13
- package/dist/lib/task-router.js +82 -71
- package/dist/lib/tasks.js +98 -71
- package/dist/lib/tmux-routing.js +87 -60
- package/dist/lib/token-spend.js +26 -6
- package/dist/mcp/server.js +1784 -458
- package/dist/mcp/tools/complete-reminder.js +21 -1
- package/dist/mcp/tools/create-reminder.js +21 -1
- package/dist/mcp/tools/create-task.js +290 -164
- package/dist/mcp/tools/deactivate-behavior.js +24 -4
- package/dist/mcp/tools/list-reminders.js +21 -1
- package/dist/mcp/tools/list-tasks.js +195 -38
- package/dist/mcp/tools/send-message.js +58 -31
- package/dist/mcp/tools/update-task.js +75 -48
- package/dist/runtime/index.js +720 -89
- package/dist/tui/App.js +853 -123
- package/package.json +3 -2
package/dist/bin/exe-dispatch.js
CHANGED
|
@@ -780,7 +780,7 @@ function isMultiInstance(agentName, employees) {
|
|
|
780
780
|
if (!emp) return false;
|
|
781
781
|
return MULTI_INSTANCE_ROLES.has(emp.role.toLowerCase());
|
|
782
782
|
}
|
|
783
|
-
var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES;
|
|
783
|
+
var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES, IDENTITY_DIR;
|
|
784
784
|
var init_employees = __esm({
|
|
785
785
|
"src/lib/employees.ts"() {
|
|
786
786
|
"use strict";
|
|
@@ -789,12 +789,609 @@ var init_employees = __esm({
|
|
|
789
789
|
DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
|
|
790
790
|
COORDINATOR_ROLE = "COO";
|
|
791
791
|
MULTI_INSTANCE_ROLES = /* @__PURE__ */ new Set(["principal engineer", "content production specialist", "staff code reviewer"]);
|
|
792
|
+
IDENTITY_DIR = path5.join(EXE_AI_DIR, "identity");
|
|
793
|
+
}
|
|
794
|
+
});
|
|
795
|
+
|
|
796
|
+
// src/lib/database-adapter.ts
|
|
797
|
+
import os5 from "os";
|
|
798
|
+
import path6 from "path";
|
|
799
|
+
import { createRequire } from "module";
|
|
800
|
+
import { pathToFileURL } from "url";
|
|
801
|
+
function quotedIdentifier(identifier) {
|
|
802
|
+
return `"${identifier.replace(/"/g, '""')}"`;
|
|
803
|
+
}
|
|
804
|
+
function unqualifiedTableName(name) {
|
|
805
|
+
const raw = name.trim().replace(/^"|"$/g, "");
|
|
806
|
+
const parts = raw.split(".");
|
|
807
|
+
return parts[parts.length - 1].replace(/^"|"$/g, "").toLowerCase();
|
|
808
|
+
}
|
|
809
|
+
function stripTrailingSemicolon(sql) {
|
|
810
|
+
return sql.trim().replace(/;+\s*$/u, "");
|
|
811
|
+
}
|
|
812
|
+
function appendClause(sql, clause) {
|
|
813
|
+
const trimmed = stripTrailingSemicolon(sql);
|
|
814
|
+
const returningMatch = /\sRETURNING\b[\s\S]*$/iu.exec(trimmed);
|
|
815
|
+
if (!returningMatch) {
|
|
816
|
+
return `${trimmed}${clause}`;
|
|
817
|
+
}
|
|
818
|
+
const idx = returningMatch.index;
|
|
819
|
+
return `${trimmed.slice(0, idx)}${clause}${trimmed.slice(idx)}`;
|
|
820
|
+
}
|
|
821
|
+
function normalizeStatement(stmt) {
|
|
822
|
+
if (typeof stmt === "string") {
|
|
823
|
+
return { kind: "positional", sql: stmt, args: [] };
|
|
824
|
+
}
|
|
825
|
+
const sql = stmt.sql;
|
|
826
|
+
if (Array.isArray(stmt.args) || stmt.args === void 0) {
|
|
827
|
+
return { kind: "positional", sql, args: stmt.args ?? [] };
|
|
828
|
+
}
|
|
829
|
+
return { kind: "named", sql, args: stmt.args };
|
|
830
|
+
}
|
|
831
|
+
function rewriteBooleanLiterals(sql) {
|
|
832
|
+
let out = sql;
|
|
833
|
+
for (const column of BOOLEAN_COLUMN_NAMES) {
|
|
834
|
+
const scoped = `((?:\\b[a-z_][a-z0-9_]*\\.)?${column})`;
|
|
835
|
+
out = out.replace(new RegExp(`${scoped}\\s*=\\s*0\\b`, "giu"), "$1 = FALSE");
|
|
836
|
+
out = out.replace(new RegExp(`${scoped}\\s*=\\s*1\\b`, "giu"), "$1 = TRUE");
|
|
837
|
+
out = out.replace(new RegExp(`${scoped}\\s*!=\\s*0\\b`, "giu"), "$1 != FALSE");
|
|
838
|
+
out = out.replace(new RegExp(`${scoped}\\s*!=\\s*1\\b`, "giu"), "$1 != TRUE");
|
|
839
|
+
out = out.replace(new RegExp(`${scoped}\\s*<>\\s*0\\b`, "giu"), "$1 <> FALSE");
|
|
840
|
+
out = out.replace(new RegExp(`${scoped}\\s*<>\\s*1\\b`, "giu"), "$1 <> TRUE");
|
|
841
|
+
}
|
|
842
|
+
return out;
|
|
843
|
+
}
|
|
844
|
+
function rewriteInsertOrIgnore(sql) {
|
|
845
|
+
if (!/^\s*INSERT\s+OR\s+IGNORE\s+INTO\b/iu.test(sql)) {
|
|
846
|
+
return sql;
|
|
847
|
+
}
|
|
848
|
+
const replaced = sql.replace(/^\s*INSERT\s+OR\s+IGNORE\s+INTO\b/iu, "INSERT INTO");
|
|
849
|
+
return /\bON\s+CONFLICT\b/iu.test(replaced) ? replaced : appendClause(replaced, " ON CONFLICT DO NOTHING");
|
|
850
|
+
}
|
|
851
|
+
function rewriteInsertOrReplace(sql) {
|
|
852
|
+
const match = /^\s*INSERT\s+OR\s+REPLACE\s+INTO\s+([A-Za-z0-9_."]+)\s*\(([^)]+)\)([\s\S]*)$/iu.exec(sql);
|
|
853
|
+
if (!match) {
|
|
854
|
+
return sql;
|
|
855
|
+
}
|
|
856
|
+
const rawTable = match[1];
|
|
857
|
+
const rawColumns = match[2];
|
|
858
|
+
const remainder = match[3];
|
|
859
|
+
const tableName = unqualifiedTableName(rawTable);
|
|
860
|
+
const conflictKeys = UPSERT_KEYS[tableName];
|
|
861
|
+
if (!conflictKeys?.length) {
|
|
862
|
+
return sql;
|
|
863
|
+
}
|
|
864
|
+
const columns = rawColumns.split(",").map((col) => col.trim().replace(/^"|"$/g, ""));
|
|
865
|
+
const updateColumns = columns.filter((col) => !conflictKeys.includes(col));
|
|
866
|
+
const conflictTarget = conflictKeys.map(quotedIdentifier).join(", ");
|
|
867
|
+
const updateClause = updateColumns.length === 0 ? " DO NOTHING" : ` DO UPDATE SET ${updateColumns.map((col) => `${quotedIdentifier(col)} = EXCLUDED.${quotedIdentifier(col)}`).join(", ")}`;
|
|
868
|
+
return `INSERT INTO ${rawTable} (${rawColumns})${appendClause(remainder, ` ON CONFLICT (${conflictTarget})${updateClause}`)}`;
|
|
869
|
+
}
|
|
870
|
+
function rewriteSql(sql) {
|
|
871
|
+
let out = sql;
|
|
872
|
+
out = out.replace(/\bdatetime\(\s*['"]now['"]\s*\)/giu, "CURRENT_TIMESTAMP");
|
|
873
|
+
out = out.replace(/\bvector32\s*\(\s*\?\s*\)/giu, "?");
|
|
874
|
+
out = rewriteBooleanLiterals(out);
|
|
875
|
+
out = rewriteInsertOrReplace(out);
|
|
876
|
+
out = rewriteInsertOrIgnore(out);
|
|
877
|
+
return stripTrailingSemicolon(out);
|
|
878
|
+
}
|
|
879
|
+
function toBoolean(value) {
|
|
880
|
+
if (value === null || value === void 0) return value;
|
|
881
|
+
if (typeof value === "boolean") return value;
|
|
882
|
+
if (typeof value === "number") return value !== 0;
|
|
883
|
+
if (typeof value === "bigint") return value !== 0n;
|
|
884
|
+
if (typeof value === "string") {
|
|
885
|
+
const normalized = value.trim().toLowerCase();
|
|
886
|
+
if (normalized === "0" || normalized === "false") return false;
|
|
887
|
+
if (normalized === "1" || normalized === "true") return true;
|
|
888
|
+
}
|
|
889
|
+
return Boolean(value);
|
|
890
|
+
}
|
|
891
|
+
function countQuestionMarks(sql, end) {
|
|
892
|
+
let count = 0;
|
|
893
|
+
let inSingle = false;
|
|
894
|
+
let inDouble = false;
|
|
895
|
+
let inLineComment = false;
|
|
896
|
+
let inBlockComment = false;
|
|
897
|
+
for (let i = 0; i < end; i++) {
|
|
898
|
+
const ch = sql[i];
|
|
899
|
+
const next = sql[i + 1];
|
|
900
|
+
if (inLineComment) {
|
|
901
|
+
if (ch === "\n") inLineComment = false;
|
|
902
|
+
continue;
|
|
903
|
+
}
|
|
904
|
+
if (inBlockComment) {
|
|
905
|
+
if (ch === "*" && next === "/") {
|
|
906
|
+
inBlockComment = false;
|
|
907
|
+
i += 1;
|
|
908
|
+
}
|
|
909
|
+
continue;
|
|
910
|
+
}
|
|
911
|
+
if (!inSingle && !inDouble && ch === "-" && next === "-") {
|
|
912
|
+
inLineComment = true;
|
|
913
|
+
i += 1;
|
|
914
|
+
continue;
|
|
915
|
+
}
|
|
916
|
+
if (!inSingle && !inDouble && ch === "/" && next === "*") {
|
|
917
|
+
inBlockComment = true;
|
|
918
|
+
i += 1;
|
|
919
|
+
continue;
|
|
920
|
+
}
|
|
921
|
+
if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
|
|
922
|
+
inSingle = !inSingle;
|
|
923
|
+
continue;
|
|
924
|
+
}
|
|
925
|
+
if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
|
|
926
|
+
inDouble = !inDouble;
|
|
927
|
+
continue;
|
|
928
|
+
}
|
|
929
|
+
if (!inSingle && !inDouble && ch === "?") {
|
|
930
|
+
count += 1;
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
return count;
|
|
934
|
+
}
|
|
935
|
+
function findBooleanPlaceholderIndexes(sql) {
|
|
936
|
+
const indexes = /* @__PURE__ */ new Set();
|
|
937
|
+
for (const column of BOOLEAN_COLUMN_NAMES) {
|
|
938
|
+
const pattern = new RegExp(`(?:\\b[a-z_][a-z0-9_]*\\.)?${column}\\s*=\\s*\\?`, "giu");
|
|
939
|
+
for (const match of sql.matchAll(pattern)) {
|
|
940
|
+
const matchText = match[0];
|
|
941
|
+
const qIndex = match.index + matchText.lastIndexOf("?");
|
|
942
|
+
indexes.add(countQuestionMarks(sql, qIndex + 1));
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
return indexes;
|
|
946
|
+
}
|
|
947
|
+
function coerceInsertBooleanArgs(sql, args) {
|
|
948
|
+
const match = /^\s*INSERT(?:\s+OR\s+(?:IGNORE|REPLACE))?\s+INTO\s+([A-Za-z0-9_."]+)\s*\(([^)]+)\)/iu.exec(sql);
|
|
949
|
+
if (!match) return;
|
|
950
|
+
const rawTable = match[1];
|
|
951
|
+
const rawColumns = match[2];
|
|
952
|
+
const boolColumns = BOOLEAN_COLUMNS_BY_TABLE[unqualifiedTableName(rawTable)];
|
|
953
|
+
if (!boolColumns?.size) return;
|
|
954
|
+
const columns = rawColumns.split(",").map((col) => col.trim().replace(/^"|"$/g, ""));
|
|
955
|
+
for (const [index, column] of columns.entries()) {
|
|
956
|
+
if (boolColumns.has(column) && index < args.length) {
|
|
957
|
+
args[index] = toBoolean(args[index]);
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
function coerceUpdateBooleanArgs(sql, args) {
|
|
962
|
+
const match = /^\s*UPDATE\s+([A-Za-z0-9_."]+)\s+SET\s+([\s\S]+?)(?:\s+WHERE\b|$)/iu.exec(sql);
|
|
963
|
+
if (!match) return;
|
|
964
|
+
const rawTable = match[1];
|
|
965
|
+
const setClause = match[2];
|
|
966
|
+
const boolColumns = BOOLEAN_COLUMNS_BY_TABLE[unqualifiedTableName(rawTable)];
|
|
967
|
+
if (!boolColumns?.size) return;
|
|
968
|
+
const assignments = setClause.split(",");
|
|
969
|
+
let placeholderIndex = 0;
|
|
970
|
+
for (const assignment of assignments) {
|
|
971
|
+
if (!assignment.includes("?")) continue;
|
|
972
|
+
placeholderIndex += 1;
|
|
973
|
+
const colMatch = /^\s*(?:[A-Za-z_][A-Za-z0-9_]*\.)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*\?/iu.exec(assignment);
|
|
974
|
+
if (colMatch && boolColumns.has(colMatch[1])) {
|
|
975
|
+
args[placeholderIndex - 1] = toBoolean(args[placeholderIndex - 1]);
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
function coerceBooleanArgs(sql, args) {
|
|
980
|
+
const nextArgs = [...args];
|
|
981
|
+
coerceInsertBooleanArgs(sql, nextArgs);
|
|
982
|
+
coerceUpdateBooleanArgs(sql, nextArgs);
|
|
983
|
+
const placeholderIndexes = findBooleanPlaceholderIndexes(sql);
|
|
984
|
+
for (const index of placeholderIndexes) {
|
|
985
|
+
if (index > 0 && index <= nextArgs.length) {
|
|
986
|
+
nextArgs[index - 1] = toBoolean(nextArgs[index - 1]);
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
return nextArgs;
|
|
990
|
+
}
|
|
991
|
+
function convertQuestionMarksToDollarParams(sql) {
|
|
992
|
+
let out = "";
|
|
993
|
+
let placeholder = 0;
|
|
994
|
+
let inSingle = false;
|
|
995
|
+
let inDouble = false;
|
|
996
|
+
let inLineComment = false;
|
|
997
|
+
let inBlockComment = false;
|
|
998
|
+
for (let i = 0; i < sql.length; i++) {
|
|
999
|
+
const ch = sql[i];
|
|
1000
|
+
const next = sql[i + 1];
|
|
1001
|
+
if (inLineComment) {
|
|
1002
|
+
out += ch;
|
|
1003
|
+
if (ch === "\n") inLineComment = false;
|
|
1004
|
+
continue;
|
|
1005
|
+
}
|
|
1006
|
+
if (inBlockComment) {
|
|
1007
|
+
out += ch;
|
|
1008
|
+
if (ch === "*" && next === "/") {
|
|
1009
|
+
out += next;
|
|
1010
|
+
inBlockComment = false;
|
|
1011
|
+
i += 1;
|
|
1012
|
+
}
|
|
1013
|
+
continue;
|
|
1014
|
+
}
|
|
1015
|
+
if (!inSingle && !inDouble && ch === "-" && next === "-") {
|
|
1016
|
+
out += ch + next;
|
|
1017
|
+
inLineComment = true;
|
|
1018
|
+
i += 1;
|
|
1019
|
+
continue;
|
|
1020
|
+
}
|
|
1021
|
+
if (!inSingle && !inDouble && ch === "/" && next === "*") {
|
|
1022
|
+
out += ch + next;
|
|
1023
|
+
inBlockComment = true;
|
|
1024
|
+
i += 1;
|
|
1025
|
+
continue;
|
|
1026
|
+
}
|
|
1027
|
+
if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
|
|
1028
|
+
inSingle = !inSingle;
|
|
1029
|
+
out += ch;
|
|
1030
|
+
continue;
|
|
1031
|
+
}
|
|
1032
|
+
if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
|
|
1033
|
+
inDouble = !inDouble;
|
|
1034
|
+
out += ch;
|
|
1035
|
+
continue;
|
|
1036
|
+
}
|
|
1037
|
+
if (!inSingle && !inDouble && ch === "?") {
|
|
1038
|
+
placeholder += 1;
|
|
1039
|
+
out += `$${placeholder}`;
|
|
1040
|
+
continue;
|
|
1041
|
+
}
|
|
1042
|
+
out += ch;
|
|
1043
|
+
}
|
|
1044
|
+
return out;
|
|
1045
|
+
}
|
|
1046
|
+
function translateStatementForPostgres(stmt) {
|
|
1047
|
+
const normalized = normalizeStatement(stmt);
|
|
1048
|
+
if (normalized.kind === "named") {
|
|
1049
|
+
throw new Error("Named SQL parameters are not supported by the Prisma adapter.");
|
|
1050
|
+
}
|
|
1051
|
+
const rewrittenSql = rewriteSql(normalized.sql);
|
|
1052
|
+
const coercedArgs = coerceBooleanArgs(rewrittenSql, normalized.args);
|
|
1053
|
+
return {
|
|
1054
|
+
sql: convertQuestionMarksToDollarParams(rewrittenSql),
|
|
1055
|
+
args: coercedArgs
|
|
1056
|
+
};
|
|
1057
|
+
}
|
|
1058
|
+
function shouldBypassPostgres(stmt) {
|
|
1059
|
+
const normalized = normalizeStatement(stmt);
|
|
1060
|
+
if (normalized.kind === "named") {
|
|
1061
|
+
return true;
|
|
1062
|
+
}
|
|
1063
|
+
return IMMEDIATE_FALLBACK_PATTERNS.some((pattern) => pattern.test(normalized.sql));
|
|
1064
|
+
}
|
|
1065
|
+
function shouldFallbackOnError(error) {
|
|
1066
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1067
|
+
return /42P01|42883|42601|does not exist|syntax error|not supported|Named SQL parameters are not supported/iu.test(message);
|
|
1068
|
+
}
|
|
1069
|
+
function isReadQuery(sql) {
|
|
1070
|
+
const trimmed = sql.trimStart();
|
|
1071
|
+
return /^(SELECT|WITH|SHOW|EXPLAIN|VALUES)\b/iu.test(trimmed) || /\bRETURNING\b/iu.test(trimmed);
|
|
1072
|
+
}
|
|
1073
|
+
function buildRow(row, columns) {
|
|
1074
|
+
const values = columns.map((column) => row[column]);
|
|
1075
|
+
return Object.assign(values, row);
|
|
1076
|
+
}
|
|
1077
|
+
function buildResultSet(rows, rowsAffected = 0) {
|
|
1078
|
+
const columns = rows[0] ? Object.keys(rows[0]) : [];
|
|
1079
|
+
const resultRows = rows.map((row) => buildRow(row, columns));
|
|
1080
|
+
return {
|
|
1081
|
+
columns,
|
|
1082
|
+
columnTypes: columns.map(() => ""),
|
|
1083
|
+
rows: resultRows,
|
|
1084
|
+
rowsAffected,
|
|
1085
|
+
lastInsertRowid: void 0,
|
|
1086
|
+
toJSON() {
|
|
1087
|
+
return {
|
|
1088
|
+
columns,
|
|
1089
|
+
columnTypes: columns.map(() => ""),
|
|
1090
|
+
rows,
|
|
1091
|
+
rowsAffected,
|
|
1092
|
+
lastInsertRowid: void 0
|
|
1093
|
+
};
|
|
1094
|
+
}
|
|
1095
|
+
};
|
|
1096
|
+
}
|
|
1097
|
+
async function loadPrismaClient() {
|
|
1098
|
+
if (!prismaClientPromise) {
|
|
1099
|
+
prismaClientPromise = (async () => {
|
|
1100
|
+
const explicitPath = process.env.EXE_OS_PRISMA_CLIENT_PATH;
|
|
1101
|
+
if (explicitPath) {
|
|
1102
|
+
const module2 = await import(pathToFileURL(explicitPath).href);
|
|
1103
|
+
const PrismaClient2 = module2.PrismaClient ?? module2.default?.PrismaClient;
|
|
1104
|
+
if (!PrismaClient2) {
|
|
1105
|
+
throw new Error(`No PrismaClient export found at ${explicitPath}`);
|
|
1106
|
+
}
|
|
1107
|
+
return new PrismaClient2();
|
|
1108
|
+
}
|
|
1109
|
+
const exeDbRoot = process.env.EXE_DB_ROOT ?? path6.join(os5.homedir(), "exe-db");
|
|
1110
|
+
const requireFromExeDb = createRequire(path6.join(exeDbRoot, "package.json"));
|
|
1111
|
+
const prismaEntry = requireFromExeDb.resolve("@prisma/client");
|
|
1112
|
+
const module = await import(pathToFileURL(prismaEntry).href);
|
|
1113
|
+
const PrismaClient = module.PrismaClient ?? module.default?.PrismaClient;
|
|
1114
|
+
if (!PrismaClient) {
|
|
1115
|
+
throw new Error(`No PrismaClient export found in ${prismaEntry}`);
|
|
1116
|
+
}
|
|
1117
|
+
return new PrismaClient();
|
|
1118
|
+
})();
|
|
1119
|
+
}
|
|
1120
|
+
return prismaClientPromise;
|
|
1121
|
+
}
|
|
1122
|
+
async function ensureCompatibilityViews(prisma) {
|
|
1123
|
+
if (!compatibilityBootstrapPromise) {
|
|
1124
|
+
compatibilityBootstrapPromise = (async () => {
|
|
1125
|
+
for (const mapping of VIEW_MAPPINGS) {
|
|
1126
|
+
const relation = mapping.source.replace(/"/g, "");
|
|
1127
|
+
const rows = await prisma.$queryRawUnsafe(
|
|
1128
|
+
"SELECT to_regclass($1) AS regclass",
|
|
1129
|
+
relation
|
|
1130
|
+
);
|
|
1131
|
+
if (!rows[0]?.regclass) {
|
|
1132
|
+
continue;
|
|
1133
|
+
}
|
|
1134
|
+
await prisma.$executeRawUnsafe(
|
|
1135
|
+
`CREATE OR REPLACE VIEW public.${quotedIdentifier(mapping.view)} AS SELECT * FROM ${mapping.source}`
|
|
1136
|
+
);
|
|
1137
|
+
}
|
|
1138
|
+
})();
|
|
1139
|
+
}
|
|
1140
|
+
return compatibilityBootstrapPromise;
|
|
1141
|
+
}
|
|
1142
|
+
async function executeOnPrisma(executor, stmt) {
|
|
1143
|
+
const translated = translateStatementForPostgres(stmt);
|
|
1144
|
+
if (isReadQuery(translated.sql)) {
|
|
1145
|
+
const rows = await executor.$queryRawUnsafe(
|
|
1146
|
+
translated.sql,
|
|
1147
|
+
...translated.args
|
|
1148
|
+
);
|
|
1149
|
+
return buildResultSet(rows, /\bRETURNING\b/iu.test(translated.sql) ? rows.length : 0);
|
|
1150
|
+
}
|
|
1151
|
+
const rowsAffected = await executor.$executeRawUnsafe(translated.sql, ...translated.args);
|
|
1152
|
+
return buildResultSet([], rowsAffected);
|
|
1153
|
+
}
|
|
1154
|
+
function splitSqlStatements(sql) {
|
|
1155
|
+
const parts = [];
|
|
1156
|
+
let current = "";
|
|
1157
|
+
let inSingle = false;
|
|
1158
|
+
let inDouble = false;
|
|
1159
|
+
let inLineComment = false;
|
|
1160
|
+
let inBlockComment = false;
|
|
1161
|
+
for (let i = 0; i < sql.length; i++) {
|
|
1162
|
+
const ch = sql[i];
|
|
1163
|
+
const next = sql[i + 1];
|
|
1164
|
+
if (inLineComment) {
|
|
1165
|
+
current += ch;
|
|
1166
|
+
if (ch === "\n") inLineComment = false;
|
|
1167
|
+
continue;
|
|
1168
|
+
}
|
|
1169
|
+
if (inBlockComment) {
|
|
1170
|
+
current += ch;
|
|
1171
|
+
if (ch === "*" && next === "/") {
|
|
1172
|
+
current += next;
|
|
1173
|
+
inBlockComment = false;
|
|
1174
|
+
i += 1;
|
|
1175
|
+
}
|
|
1176
|
+
continue;
|
|
1177
|
+
}
|
|
1178
|
+
if (!inSingle && !inDouble && ch === "-" && next === "-") {
|
|
1179
|
+
current += ch + next;
|
|
1180
|
+
inLineComment = true;
|
|
1181
|
+
i += 1;
|
|
1182
|
+
continue;
|
|
1183
|
+
}
|
|
1184
|
+
if (!inSingle && !inDouble && ch === "/" && next === "*") {
|
|
1185
|
+
current += ch + next;
|
|
1186
|
+
inBlockComment = true;
|
|
1187
|
+
i += 1;
|
|
1188
|
+
continue;
|
|
1189
|
+
}
|
|
1190
|
+
if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
|
|
1191
|
+
inSingle = !inSingle;
|
|
1192
|
+
current += ch;
|
|
1193
|
+
continue;
|
|
1194
|
+
}
|
|
1195
|
+
if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
|
|
1196
|
+
inDouble = !inDouble;
|
|
1197
|
+
current += ch;
|
|
1198
|
+
continue;
|
|
1199
|
+
}
|
|
1200
|
+
if (!inSingle && !inDouble && ch === ";") {
|
|
1201
|
+
if (current.trim()) {
|
|
1202
|
+
parts.push(current.trim());
|
|
1203
|
+
}
|
|
1204
|
+
current = "";
|
|
1205
|
+
continue;
|
|
1206
|
+
}
|
|
1207
|
+
current += ch;
|
|
1208
|
+
}
|
|
1209
|
+
if (current.trim()) {
|
|
1210
|
+
parts.push(current.trim());
|
|
1211
|
+
}
|
|
1212
|
+
return parts;
|
|
1213
|
+
}
|
|
1214
|
+
async function createPrismaDbAdapter(fallbackClient) {
|
|
1215
|
+
const prisma = await loadPrismaClient();
|
|
1216
|
+
await ensureCompatibilityViews(prisma);
|
|
1217
|
+
let closed = false;
|
|
1218
|
+
let adapter;
|
|
1219
|
+
const fallbackExecute = async (stmt, error) => {
|
|
1220
|
+
if (!fallbackClient) {
|
|
1221
|
+
if (error) throw error;
|
|
1222
|
+
throw new Error("No fallback SQLite client is available for this Prisma-routed query.");
|
|
1223
|
+
}
|
|
1224
|
+
if (error) {
|
|
1225
|
+
process.stderr.write(
|
|
1226
|
+
`[database-adapter] Falling back to SQLite: ${error instanceof Error ? error.message : String(error)}
|
|
1227
|
+
`
|
|
1228
|
+
);
|
|
1229
|
+
}
|
|
1230
|
+
return fallbackClient.execute(stmt);
|
|
1231
|
+
};
|
|
1232
|
+
adapter = {
|
|
1233
|
+
async execute(stmt) {
|
|
1234
|
+
if (shouldBypassPostgres(stmt)) {
|
|
1235
|
+
return fallbackExecute(stmt);
|
|
1236
|
+
}
|
|
1237
|
+
try {
|
|
1238
|
+
return await executeOnPrisma(prisma, stmt);
|
|
1239
|
+
} catch (error) {
|
|
1240
|
+
if (shouldFallbackOnError(error)) {
|
|
1241
|
+
return fallbackExecute(stmt, error);
|
|
1242
|
+
}
|
|
1243
|
+
throw error;
|
|
1244
|
+
}
|
|
1245
|
+
},
|
|
1246
|
+
async batch(stmts, mode) {
|
|
1247
|
+
if (stmts.some((stmt) => shouldBypassPostgres(stmt))) {
|
|
1248
|
+
if (!fallbackClient) {
|
|
1249
|
+
throw new Error("Cannot batch unsupported SQLite-only statements without a fallback client.");
|
|
1250
|
+
}
|
|
1251
|
+
return fallbackClient.batch(stmts, mode);
|
|
1252
|
+
}
|
|
1253
|
+
try {
|
|
1254
|
+
if (prisma.$transaction) {
|
|
1255
|
+
return await prisma.$transaction(async (tx) => {
|
|
1256
|
+
const results2 = [];
|
|
1257
|
+
for (const stmt of stmts) {
|
|
1258
|
+
results2.push(await executeOnPrisma(tx, stmt));
|
|
1259
|
+
}
|
|
1260
|
+
return results2;
|
|
1261
|
+
});
|
|
1262
|
+
}
|
|
1263
|
+
const results = [];
|
|
1264
|
+
for (const stmt of stmts) {
|
|
1265
|
+
results.push(await executeOnPrisma(prisma, stmt));
|
|
1266
|
+
}
|
|
1267
|
+
return results;
|
|
1268
|
+
} catch (error) {
|
|
1269
|
+
if (fallbackClient && shouldFallbackOnError(error)) {
|
|
1270
|
+
process.stderr.write(
|
|
1271
|
+
`[database-adapter] Falling back batch to SQLite: ${error instanceof Error ? error.message : String(error)}
|
|
1272
|
+
`
|
|
1273
|
+
);
|
|
1274
|
+
return fallbackClient.batch(stmts, mode);
|
|
1275
|
+
}
|
|
1276
|
+
throw error;
|
|
1277
|
+
}
|
|
1278
|
+
},
|
|
1279
|
+
async migrate(stmts) {
|
|
1280
|
+
if (fallbackClient) {
|
|
1281
|
+
return fallbackClient.migrate(stmts);
|
|
1282
|
+
}
|
|
1283
|
+
return adapter.batch(stmts, "deferred");
|
|
1284
|
+
},
|
|
1285
|
+
async transaction(mode) {
|
|
1286
|
+
if (!fallbackClient) {
|
|
1287
|
+
throw new Error("Interactive transactions are only supported on the SQLite fallback client.");
|
|
1288
|
+
}
|
|
1289
|
+
return fallbackClient.transaction(mode);
|
|
1290
|
+
},
|
|
1291
|
+
async executeMultiple(sql) {
|
|
1292
|
+
if (fallbackClient && shouldBypassPostgres(sql)) {
|
|
1293
|
+
return fallbackClient.executeMultiple(sql);
|
|
1294
|
+
}
|
|
1295
|
+
for (const statement of splitSqlStatements(sql)) {
|
|
1296
|
+
await adapter.execute(statement);
|
|
1297
|
+
}
|
|
1298
|
+
},
|
|
1299
|
+
async sync() {
|
|
1300
|
+
if (fallbackClient) {
|
|
1301
|
+
return fallbackClient.sync();
|
|
1302
|
+
}
|
|
1303
|
+
return { frame_no: 0, frames_synced: 0 };
|
|
1304
|
+
},
|
|
1305
|
+
close() {
|
|
1306
|
+
closed = true;
|
|
1307
|
+
prismaClientPromise = null;
|
|
1308
|
+
compatibilityBootstrapPromise = null;
|
|
1309
|
+
void prisma.$disconnect?.();
|
|
1310
|
+
},
|
|
1311
|
+
get closed() {
|
|
1312
|
+
return closed;
|
|
1313
|
+
},
|
|
1314
|
+
get protocol() {
|
|
1315
|
+
return "prisma-postgres";
|
|
1316
|
+
}
|
|
1317
|
+
};
|
|
1318
|
+
return adapter;
|
|
1319
|
+
}
|
|
1320
|
+
var VIEW_MAPPINGS, UPSERT_KEYS, BOOLEAN_COLUMNS_BY_TABLE, BOOLEAN_COLUMN_NAMES, IMMEDIATE_FALLBACK_PATTERNS, prismaClientPromise, compatibilityBootstrapPromise;
|
|
1321
|
+
var init_database_adapter = __esm({
|
|
1322
|
+
"src/lib/database-adapter.ts"() {
|
|
1323
|
+
"use strict";
|
|
1324
|
+
VIEW_MAPPINGS = [
|
|
1325
|
+
{ view: "memories", source: "memory.memory_records" },
|
|
1326
|
+
{ view: "tasks", source: "memory.tasks" },
|
|
1327
|
+
{ view: "behaviors", source: "memory.behaviors" },
|
|
1328
|
+
{ view: "entities", source: "memory.entities" },
|
|
1329
|
+
{ view: "relationships", source: "memory.relationships" },
|
|
1330
|
+
{ view: "entity_memories", source: "memory.entity_memories" },
|
|
1331
|
+
{ view: "entity_aliases", source: "memory.entity_aliases" },
|
|
1332
|
+
{ view: "notifications", source: "memory.notifications" },
|
|
1333
|
+
{ view: "messages", source: "memory.messages" },
|
|
1334
|
+
{ view: "users", source: "wiki.users" },
|
|
1335
|
+
{ view: "workspaces", source: "wiki.workspaces" },
|
|
1336
|
+
{ view: "workspace_users", source: "wiki.workspace_users" },
|
|
1337
|
+
{ view: "documents", source: "wiki.workspace_documents" },
|
|
1338
|
+
{ view: "chats", source: "wiki.workspace_chats" }
|
|
1339
|
+
];
|
|
1340
|
+
UPSERT_KEYS = {
|
|
1341
|
+
memories: ["id"],
|
|
1342
|
+
tasks: ["id"],
|
|
1343
|
+
behaviors: ["id"],
|
|
1344
|
+
entities: ["id"],
|
|
1345
|
+
relationships: ["id"],
|
|
1346
|
+
entity_aliases: ["alias"],
|
|
1347
|
+
notifications: ["id"],
|
|
1348
|
+
messages: ["id"],
|
|
1349
|
+
users: ["id"],
|
|
1350
|
+
workspaces: ["id"],
|
|
1351
|
+
workspace_users: ["id"],
|
|
1352
|
+
documents: ["id"],
|
|
1353
|
+
chats: ["id"]
|
|
1354
|
+
};
|
|
1355
|
+
BOOLEAN_COLUMNS_BY_TABLE = {
|
|
1356
|
+
memories: /* @__PURE__ */ new Set(["has_error", "draft"]),
|
|
1357
|
+
behaviors: /* @__PURE__ */ new Set(["active"]),
|
|
1358
|
+
notifications: /* @__PURE__ */ new Set(["read"]),
|
|
1359
|
+
users: /* @__PURE__ */ new Set(["has_personal_memory"])
|
|
1360
|
+
};
|
|
1361
|
+
BOOLEAN_COLUMN_NAMES = new Set(
|
|
1362
|
+
Object.values(BOOLEAN_COLUMNS_BY_TABLE).flatMap((cols) => [...cols])
|
|
1363
|
+
);
|
|
1364
|
+
IMMEDIATE_FALLBACK_PATTERNS = [
|
|
1365
|
+
/\bPRAGMA\b/i,
|
|
1366
|
+
/\bsqlite_master\b/i,
|
|
1367
|
+
/(?:^|[.\s])(?:memories|conversations|entities)_fts\b/i,
|
|
1368
|
+
/\bMATCH\b/i,
|
|
1369
|
+
/\bvector_distance_cos\s*\(/i,
|
|
1370
|
+
/\bjson_extract\s*\(/i,
|
|
1371
|
+
/\bjulianday\s*\(/i,
|
|
1372
|
+
/\bstrftime\s*\(/i,
|
|
1373
|
+
/\blast_insert_rowid\s*\(/i
|
|
1374
|
+
];
|
|
1375
|
+
prismaClientPromise = null;
|
|
1376
|
+
compatibilityBootstrapPromise = null;
|
|
792
1377
|
}
|
|
793
1378
|
});
|
|
794
1379
|
|
|
795
1380
|
// src/lib/database.ts
|
|
796
1381
|
import { createClient } from "@libsql/client";
|
|
797
1382
|
async function initDatabase(config) {
|
|
1383
|
+
if (_walCheckpointTimer) {
|
|
1384
|
+
clearInterval(_walCheckpointTimer);
|
|
1385
|
+
_walCheckpointTimer = null;
|
|
1386
|
+
}
|
|
1387
|
+
if (_daemonClient) {
|
|
1388
|
+
_daemonClient.close();
|
|
1389
|
+
_daemonClient = null;
|
|
1390
|
+
}
|
|
1391
|
+
if (_adapterClient && _adapterClient !== _resilientClient) {
|
|
1392
|
+
_adapterClient.close();
|
|
1393
|
+
}
|
|
1394
|
+
_adapterClient = null;
|
|
798
1395
|
if (_client) {
|
|
799
1396
|
_client.close();
|
|
800
1397
|
_client = null;
|
|
@@ -808,6 +1405,7 @@ async function initDatabase(config) {
|
|
|
808
1405
|
}
|
|
809
1406
|
_client = createClient(opts);
|
|
810
1407
|
_resilientClient = wrapWithRetry(_client);
|
|
1408
|
+
_adapterClient = _resilientClient;
|
|
811
1409
|
_client.execute("PRAGMA busy_timeout = 30000").catch(() => {
|
|
812
1410
|
});
|
|
813
1411
|
_client.execute("PRAGMA journal_mode = WAL").catch(() => {
|
|
@@ -818,11 +1416,17 @@ async function initDatabase(config) {
|
|
|
818
1416
|
});
|
|
819
1417
|
}, 3e4);
|
|
820
1418
|
_walCheckpointTimer.unref();
|
|
1419
|
+
if (process.env.DATABASE_URL) {
|
|
1420
|
+
_adapterClient = await createPrismaDbAdapter(_resilientClient);
|
|
1421
|
+
}
|
|
821
1422
|
}
|
|
822
1423
|
function getClient() {
|
|
823
|
-
if (!
|
|
1424
|
+
if (!_adapterClient) {
|
|
824
1425
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
825
1426
|
}
|
|
1427
|
+
if (process.env.DATABASE_URL) {
|
|
1428
|
+
return _adapterClient;
|
|
1429
|
+
}
|
|
826
1430
|
if (process.env.EXE_IS_DAEMON === "1") {
|
|
827
1431
|
return _resilientClient;
|
|
828
1432
|
}
|
|
@@ -1762,16 +2366,18 @@ async function ensureSchema() {
|
|
|
1762
2366
|
}
|
|
1763
2367
|
}
|
|
1764
2368
|
}
|
|
1765
|
-
var _client, _resilientClient, _walCheckpointTimer, _daemonClient, initTurso;
|
|
2369
|
+
var _client, _resilientClient, _walCheckpointTimer, _daemonClient, _adapterClient, initTurso;
|
|
1766
2370
|
var init_database = __esm({
|
|
1767
2371
|
"src/lib/database.ts"() {
|
|
1768
2372
|
"use strict";
|
|
1769
2373
|
init_db_retry();
|
|
1770
2374
|
init_employees();
|
|
2375
|
+
init_database_adapter();
|
|
1771
2376
|
_client = null;
|
|
1772
2377
|
_resilientClient = null;
|
|
1773
2378
|
_walCheckpointTimer = null;
|
|
1774
2379
|
_daemonClient = null;
|
|
2380
|
+
_adapterClient = null;
|
|
1775
2381
|
initTurso = initDatabase;
|
|
1776
2382
|
}
|
|
1777
2383
|
});
|
|
@@ -1779,16 +2385,16 @@ var init_database = __esm({
|
|
|
1779
2385
|
// src/lib/license.ts
|
|
1780
2386
|
import { readFileSync as readFileSync6, writeFileSync as writeFileSync5, existsSync as existsSync6, mkdirSync as mkdirSync4 } from "fs";
|
|
1781
2387
|
import { randomUUID } from "crypto";
|
|
1782
|
-
import
|
|
2388
|
+
import path7 from "path";
|
|
1783
2389
|
import { jwtVerify, importSPKI } from "jose";
|
|
1784
2390
|
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, PLAN_LIMITS;
|
|
1785
2391
|
var init_license = __esm({
|
|
1786
2392
|
"src/lib/license.ts"() {
|
|
1787
2393
|
"use strict";
|
|
1788
2394
|
init_config();
|
|
1789
|
-
LICENSE_PATH =
|
|
1790
|
-
CACHE_PATH =
|
|
1791
|
-
DEVICE_ID_PATH =
|
|
2395
|
+
LICENSE_PATH = path7.join(EXE_AI_DIR, "license.key");
|
|
2396
|
+
CACHE_PATH = path7.join(EXE_AI_DIR, "license-cache.json");
|
|
2397
|
+
DEVICE_ID_PATH = path7.join(EXE_AI_DIR, "device-id");
|
|
1792
2398
|
PLAN_LIMITS = {
|
|
1793
2399
|
free: { devices: 1, employees: 1, memories: 5e3 },
|
|
1794
2400
|
pro: { devices: 3, employees: 5, memories: 1e5 },
|
|
@@ -1801,7 +2407,7 @@ var init_license = __esm({
|
|
|
1801
2407
|
|
|
1802
2408
|
// src/lib/plan-limits.ts
|
|
1803
2409
|
import { readFileSync as readFileSync7, existsSync as existsSync7 } from "fs";
|
|
1804
|
-
import
|
|
2410
|
+
import path8 from "path";
|
|
1805
2411
|
function getLicenseSync() {
|
|
1806
2412
|
try {
|
|
1807
2413
|
if (!existsSync7(CACHE_PATH2)) return freeLicense();
|
|
@@ -1873,14 +2479,14 @@ var init_plan_limits = __esm({
|
|
|
1873
2479
|
this.name = "PlanLimitError";
|
|
1874
2480
|
}
|
|
1875
2481
|
};
|
|
1876
|
-
CACHE_PATH2 =
|
|
2482
|
+
CACHE_PATH2 = path8.join(EXE_AI_DIR, "license-cache.json");
|
|
1877
2483
|
}
|
|
1878
2484
|
});
|
|
1879
2485
|
|
|
1880
2486
|
// src/lib/notifications.ts
|
|
1881
2487
|
import crypto from "crypto";
|
|
1882
|
-
import
|
|
1883
|
-
import
|
|
2488
|
+
import path9 from "path";
|
|
2489
|
+
import os6 from "os";
|
|
1884
2490
|
import {
|
|
1885
2491
|
readFileSync as readFileSync8,
|
|
1886
2492
|
readdirSync,
|
|
@@ -2044,8 +2650,8 @@ var init_state_bus = __esm({
|
|
|
2044
2650
|
|
|
2045
2651
|
// src/lib/tasks-crud.ts
|
|
2046
2652
|
import crypto3 from "crypto";
|
|
2047
|
-
import
|
|
2048
|
-
import
|
|
2653
|
+
import path10 from "path";
|
|
2654
|
+
import os7 from "os";
|
|
2049
2655
|
import { execSync as execSync4 } from "child_process";
|
|
2050
2656
|
import { mkdir as mkdir3, writeFile as writeFile3, appendFile } from "fs/promises";
|
|
2051
2657
|
import { existsSync as existsSync9, readFileSync as readFileSync9 } from "fs";
|
|
@@ -2223,8 +2829,8 @@ ${laneWarning}` : laneWarning;
|
|
|
2223
2829
|
}
|
|
2224
2830
|
if (input.baseDir) {
|
|
2225
2831
|
try {
|
|
2226
|
-
await mkdir3(
|
|
2227
|
-
await mkdir3(
|
|
2832
|
+
await mkdir3(path10.join(input.baseDir, "exe", "output"), { recursive: true });
|
|
2833
|
+
await mkdir3(path10.join(input.baseDir, "exe", "research"), { recursive: true });
|
|
2228
2834
|
await ensureArchitectureDoc(input.baseDir, input.projectName);
|
|
2229
2835
|
await ensureGitignoreExe(input.baseDir);
|
|
2230
2836
|
} catch {
|
|
@@ -2260,9 +2866,9 @@ ${laneWarning}` : laneWarning;
|
|
|
2260
2866
|
});
|
|
2261
2867
|
if (input.baseDir) {
|
|
2262
2868
|
try {
|
|
2263
|
-
const EXE_OS_DIR =
|
|
2264
|
-
const mdPath =
|
|
2265
|
-
const mdDir =
|
|
2869
|
+
const EXE_OS_DIR = path10.join(os7.homedir(), ".exe-os");
|
|
2870
|
+
const mdPath = path10.join(EXE_OS_DIR, taskFile);
|
|
2871
|
+
const mdDir = path10.dirname(mdPath);
|
|
2266
2872
|
if (!existsSync9(mdDir)) await mkdir3(mdDir, { recursive: true });
|
|
2267
2873
|
const reviewer = input.reviewer ?? input.assignedBy;
|
|
2268
2874
|
const mdContent = `# ${input.title}
|
|
@@ -2563,7 +3169,7 @@ async function deleteTaskCore(taskId, _baseDir) {
|
|
|
2563
3169
|
return { taskFile, assignedTo, assignedBy, taskSlug };
|
|
2564
3170
|
}
|
|
2565
3171
|
async function ensureArchitectureDoc(baseDir, projectName) {
|
|
2566
|
-
const archPath =
|
|
3172
|
+
const archPath = path10.join(baseDir, "exe", "ARCHITECTURE.md");
|
|
2567
3173
|
try {
|
|
2568
3174
|
if (existsSync9(archPath)) return;
|
|
2569
3175
|
const template = [
|
|
@@ -2598,7 +3204,7 @@ async function ensureArchitectureDoc(baseDir, projectName) {
|
|
|
2598
3204
|
}
|
|
2599
3205
|
}
|
|
2600
3206
|
async function ensureGitignoreExe(baseDir) {
|
|
2601
|
-
const gitignorePath =
|
|
3207
|
+
const gitignorePath = path10.join(baseDir, ".gitignore");
|
|
2602
3208
|
try {
|
|
2603
3209
|
if (existsSync9(gitignorePath)) {
|
|
2604
3210
|
const content = readFileSync9(gitignorePath, "utf-8");
|
|
@@ -2632,13 +3238,13 @@ var init_tasks_crud = __esm({
|
|
|
2632
3238
|
});
|
|
2633
3239
|
|
|
2634
3240
|
// src/lib/tasks-review.ts
|
|
2635
|
-
import
|
|
3241
|
+
import path11 from "path";
|
|
2636
3242
|
import { existsSync as existsSync10, readdirSync as readdirSync2, unlinkSync as unlinkSync3 } from "fs";
|
|
2637
3243
|
async function countPendingReviews(sessionScope) {
|
|
2638
3244
|
const client = getClient();
|
|
2639
3245
|
if (sessionScope) {
|
|
2640
3246
|
const result3 = await client.execute({
|
|
2641
|
-
sql: "SELECT COUNT(*) as cnt FROM tasks WHERE status = 'needs_review' AND
|
|
3247
|
+
sql: "SELECT COUNT(*) as cnt FROM tasks WHERE status = 'needs_review' AND session_scope = ?",
|
|
2642
3248
|
args: [sessionScope]
|
|
2643
3249
|
});
|
|
2644
3250
|
return Number(result3.rows[0]?.cnt) || 0;
|
|
@@ -2814,11 +3420,11 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
|
|
|
2814
3420
|
);
|
|
2815
3421
|
}
|
|
2816
3422
|
try {
|
|
2817
|
-
const cacheDir =
|
|
3423
|
+
const cacheDir = path11.join(EXE_AI_DIR, "session-cache");
|
|
2818
3424
|
if (existsSync10(cacheDir)) {
|
|
2819
3425
|
for (const f of readdirSync2(cacheDir)) {
|
|
2820
3426
|
if (f.startsWith("review-notified-")) {
|
|
2821
|
-
unlinkSync3(
|
|
3427
|
+
unlinkSync3(path11.join(cacheDir, f));
|
|
2822
3428
|
}
|
|
2823
3429
|
}
|
|
2824
3430
|
}
|
|
@@ -2839,7 +3445,7 @@ var init_tasks_review = __esm({
|
|
|
2839
3445
|
});
|
|
2840
3446
|
|
|
2841
3447
|
// src/lib/tasks-chain.ts
|
|
2842
|
-
import
|
|
3448
|
+
import path12 from "path";
|
|
2843
3449
|
import { readFile as readFile3, writeFile as writeFile4 } from "fs/promises";
|
|
2844
3450
|
async function cascadeUnblock(taskId, baseDir, now) {
|
|
2845
3451
|
const client = getClient();
|
|
@@ -2856,7 +3462,7 @@ async function cascadeUnblock(taskId, baseDir, now) {
|
|
|
2856
3462
|
});
|
|
2857
3463
|
for (const ur of unblockedRows.rows) {
|
|
2858
3464
|
try {
|
|
2859
|
-
const ubFile =
|
|
3465
|
+
const ubFile = path12.join(baseDir, String(ur.task_file));
|
|
2860
3466
|
let ubContent = await readFile3(ubFile, "utf-8");
|
|
2861
3467
|
ubContent = ubContent.replace(/\*\*Status:\*\* blocked/, "**Status:** open");
|
|
2862
3468
|
ubContent = ubContent.replace(/\n\*\*Blocked by:\*\*.*\n/, "\n");
|
|
@@ -2925,7 +3531,7 @@ var init_tasks_chain = __esm({
|
|
|
2925
3531
|
|
|
2926
3532
|
// src/lib/project-name.ts
|
|
2927
3533
|
import { execSync as execSync5 } from "child_process";
|
|
2928
|
-
import
|
|
3534
|
+
import path13 from "path";
|
|
2929
3535
|
function getProjectName(cwd) {
|
|
2930
3536
|
const dir = cwd ?? process.cwd();
|
|
2931
3537
|
if (_cached2 && _cachedCwd === dir) return _cached2;
|
|
@@ -2938,7 +3544,7 @@ function getProjectName(cwd) {
|
|
|
2938
3544
|
timeout: 2e3,
|
|
2939
3545
|
stdio: ["pipe", "pipe", "pipe"]
|
|
2940
3546
|
}).trim();
|
|
2941
|
-
repoRoot =
|
|
3547
|
+
repoRoot = path13.dirname(gitCommonDir);
|
|
2942
3548
|
} catch {
|
|
2943
3549
|
repoRoot = execSync5("git rev-parse --show-toplevel", {
|
|
2944
3550
|
cwd: dir,
|
|
@@ -2947,11 +3553,11 @@ function getProjectName(cwd) {
|
|
|
2947
3553
|
stdio: ["pipe", "pipe", "pipe"]
|
|
2948
3554
|
}).trim();
|
|
2949
3555
|
}
|
|
2950
|
-
_cached2 =
|
|
3556
|
+
_cached2 = path13.basename(repoRoot);
|
|
2951
3557
|
_cachedCwd = dir;
|
|
2952
3558
|
return _cached2;
|
|
2953
3559
|
} catch {
|
|
2954
|
-
_cached2 =
|
|
3560
|
+
_cached2 = path13.basename(dir);
|
|
2955
3561
|
_cachedCwd = dir;
|
|
2956
3562
|
return _cached2;
|
|
2957
3563
|
}
|
|
@@ -3424,7 +4030,7 @@ __export(tasks_exports, {
|
|
|
3424
4030
|
updateTaskStatus: () => updateTaskStatus,
|
|
3425
4031
|
writeCheckpoint: () => writeCheckpoint
|
|
3426
4032
|
});
|
|
3427
|
-
import
|
|
4033
|
+
import path14 from "path";
|
|
3428
4034
|
import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, unlinkSync as unlinkSync4 } from "fs";
|
|
3429
4035
|
async function createTask(input) {
|
|
3430
4036
|
const result2 = await createTaskCore(input);
|
|
@@ -3444,8 +4050,8 @@ async function updateTask(input) {
|
|
|
3444
4050
|
const { row, taskFile, now, taskId } = await updateTaskStatus(input);
|
|
3445
4051
|
try {
|
|
3446
4052
|
const agent = String(row.assigned_to);
|
|
3447
|
-
const cacheDir =
|
|
3448
|
-
const cachePath =
|
|
4053
|
+
const cacheDir = path14.join(EXE_AI_DIR, "session-cache");
|
|
4054
|
+
const cachePath = path14.join(cacheDir, `current-task-${agent}.json`);
|
|
3449
4055
|
if (input.status === "in_progress") {
|
|
3450
4056
|
mkdirSync5(cacheDir, { recursive: true });
|
|
3451
4057
|
writeFileSync6(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
|
|
@@ -3916,12 +4522,12 @@ __export(tmux_routing_exports, {
|
|
|
3916
4522
|
});
|
|
3917
4523
|
import { execFileSync as execFileSync2, execSync as execSync6 } from "child_process";
|
|
3918
4524
|
import { readFileSync as readFileSync10, writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, existsSync as existsSync11, appendFileSync, readdirSync as readdirSync3 } from "fs";
|
|
3919
|
-
import
|
|
3920
|
-
import
|
|
4525
|
+
import path15 from "path";
|
|
4526
|
+
import os8 from "os";
|
|
3921
4527
|
import { fileURLToPath } from "url";
|
|
3922
4528
|
import { unlinkSync as unlinkSync5 } from "fs";
|
|
3923
4529
|
function spawnLockPath(sessionName) {
|
|
3924
|
-
return
|
|
4530
|
+
return path15.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
|
|
3925
4531
|
}
|
|
3926
4532
|
function isProcessAlive(pid) {
|
|
3927
4533
|
try {
|
|
@@ -3958,8 +4564,8 @@ function releaseSpawnLock(sessionName) {
|
|
|
3958
4564
|
function resolveBehaviorsExporterScript() {
|
|
3959
4565
|
try {
|
|
3960
4566
|
const thisFile = fileURLToPath(import.meta.url);
|
|
3961
|
-
const scriptPath =
|
|
3962
|
-
|
|
4567
|
+
const scriptPath = path15.join(
|
|
4568
|
+
path15.dirname(thisFile),
|
|
3963
4569
|
"..",
|
|
3964
4570
|
"bin",
|
|
3965
4571
|
"exe-export-behaviors.js"
|
|
@@ -4034,7 +4640,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
|
4034
4640
|
mkdirSync6(SESSION_CACHE, { recursive: true });
|
|
4035
4641
|
}
|
|
4036
4642
|
const rootExe = extractRootExe(parentExe) ?? parentExe;
|
|
4037
|
-
const filePath =
|
|
4643
|
+
const filePath = path15.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
|
|
4038
4644
|
writeFileSync7(filePath, JSON.stringify({
|
|
4039
4645
|
parentExe: rootExe,
|
|
4040
4646
|
dispatchedBy: dispatchedBy || rootExe,
|
|
@@ -4043,7 +4649,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
|
4043
4649
|
}
|
|
4044
4650
|
function getParentExe(sessionKey) {
|
|
4045
4651
|
try {
|
|
4046
|
-
const data = JSON.parse(readFileSync10(
|
|
4652
|
+
const data = JSON.parse(readFileSync10(path15.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
4047
4653
|
return data.parentExe || null;
|
|
4048
4654
|
} catch {
|
|
4049
4655
|
return null;
|
|
@@ -4052,7 +4658,7 @@ function getParentExe(sessionKey) {
|
|
|
4052
4658
|
function getDispatchedBy(sessionKey) {
|
|
4053
4659
|
try {
|
|
4054
4660
|
const data = JSON.parse(readFileSync10(
|
|
4055
|
-
|
|
4661
|
+
path15.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
|
|
4056
4662
|
"utf8"
|
|
4057
4663
|
));
|
|
4058
4664
|
return data.dispatchedBy ?? data.parentExe ?? null;
|
|
@@ -4238,7 +4844,7 @@ function sendIntercom(targetSession) {
|
|
|
4238
4844
|
try {
|
|
4239
4845
|
const rawAgent = targetSession.split("-")[0] ?? targetSession;
|
|
4240
4846
|
const agent = baseAgentName(rawAgent);
|
|
4241
|
-
const markerPath =
|
|
4847
|
+
const markerPath = path15.join(SESSION_CACHE, `current-task-${agent}.json`);
|
|
4242
4848
|
if (existsSync11(markerPath)) {
|
|
4243
4849
|
logIntercom(`SKIP \u2192 ${targetSession} (has in_progress task marker \u2014 will auto-chain)`);
|
|
4244
4850
|
return "debounced";
|
|
@@ -4248,7 +4854,7 @@ function sendIntercom(targetSession) {
|
|
|
4248
4854
|
try {
|
|
4249
4855
|
const rawAgent = targetSession.split("-")[0] ?? targetSession;
|
|
4250
4856
|
const agent = baseAgentName(rawAgent);
|
|
4251
|
-
const taskDir =
|
|
4857
|
+
const taskDir = path15.join(process.cwd(), "exe", agent);
|
|
4252
4858
|
if (existsSync11(taskDir)) {
|
|
4253
4859
|
const files = readdirSync3(taskDir).filter(
|
|
4254
4860
|
(f) => f.endsWith(".md") && f !== "DONE.txt"
|
|
@@ -4382,8 +4988,8 @@ function spawnEmployee(employeeName2, exeSession2, projectDir2, opts) {
|
|
|
4382
4988
|
const transport = getTransport();
|
|
4383
4989
|
const sessionName = employeeSessionName(employeeName2, exeSession2, opts?.instance);
|
|
4384
4990
|
const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName2}${opts.instance}` : employeeName2;
|
|
4385
|
-
const logDir =
|
|
4386
|
-
const logFile =
|
|
4991
|
+
const logDir = path15.join(os8.homedir(), ".exe-os", "session-logs");
|
|
4992
|
+
const logFile = path15.join(logDir, `${instanceLabel}-${Date.now()}.log`);
|
|
4387
4993
|
if (!existsSync11(logDir)) {
|
|
4388
4994
|
mkdirSync6(logDir, { recursive: true });
|
|
4389
4995
|
}
|
|
@@ -4391,14 +4997,14 @@ function spawnEmployee(employeeName2, exeSession2, projectDir2, opts) {
|
|
|
4391
4997
|
let cleanupSuffix = "";
|
|
4392
4998
|
try {
|
|
4393
4999
|
const thisFile = fileURLToPath(import.meta.url);
|
|
4394
|
-
const cleanupScript =
|
|
5000
|
+
const cleanupScript = path15.join(path15.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
|
|
4395
5001
|
if (existsSync11(cleanupScript)) {
|
|
4396
5002
|
cleanupSuffix = `; ${process.execPath} "${cleanupScript}" "${employeeName2}" "${exeSession2}"`;
|
|
4397
5003
|
}
|
|
4398
5004
|
} catch {
|
|
4399
5005
|
}
|
|
4400
5006
|
try {
|
|
4401
|
-
const claudeJsonPath =
|
|
5007
|
+
const claudeJsonPath = path15.join(os8.homedir(), ".claude.json");
|
|
4402
5008
|
let claudeJson = {};
|
|
4403
5009
|
try {
|
|
4404
5010
|
claudeJson = JSON.parse(readFileSync10(claudeJsonPath, "utf8"));
|
|
@@ -4413,10 +5019,10 @@ function spawnEmployee(employeeName2, exeSession2, projectDir2, opts) {
|
|
|
4413
5019
|
} catch {
|
|
4414
5020
|
}
|
|
4415
5021
|
try {
|
|
4416
|
-
const settingsDir =
|
|
5022
|
+
const settingsDir = path15.join(os8.homedir(), ".claude", "projects");
|
|
4417
5023
|
const normalizedKey = (opts?.cwd ?? projectDir2).replace(/\//g, "-").replace(/^-/, "");
|
|
4418
|
-
const projSettingsDir =
|
|
4419
|
-
const settingsPath =
|
|
5024
|
+
const projSettingsDir = path15.join(settingsDir, normalizedKey);
|
|
5025
|
+
const settingsPath = path15.join(projSettingsDir, "settings.json");
|
|
4420
5026
|
let settings = {};
|
|
4421
5027
|
try {
|
|
4422
5028
|
settings = JSON.parse(readFileSync10(settingsPath, "utf8"));
|
|
@@ -4463,8 +5069,8 @@ function spawnEmployee(employeeName2, exeSession2, projectDir2, opts) {
|
|
|
4463
5069
|
let behaviorsFlag = "";
|
|
4464
5070
|
let legacyFallbackWarned = false;
|
|
4465
5071
|
if (!useExeAgent && !useBinSymlink) {
|
|
4466
|
-
const identityPath =
|
|
4467
|
-
|
|
5072
|
+
const identityPath = path15.join(
|
|
5073
|
+
os8.homedir(),
|
|
4468
5074
|
".exe-os",
|
|
4469
5075
|
"identity",
|
|
4470
5076
|
`${employeeName2}.md`
|
|
@@ -4479,7 +5085,7 @@ function spawnEmployee(employeeName2, exeSession2, projectDir2, opts) {
|
|
|
4479
5085
|
}
|
|
4480
5086
|
const behaviorsFile = exportBehaviorsSync(
|
|
4481
5087
|
employeeName2,
|
|
4482
|
-
|
|
5088
|
+
path15.basename(spawnCwd),
|
|
4483
5089
|
sessionName
|
|
4484
5090
|
);
|
|
4485
5091
|
if (behaviorsFile) {
|
|
@@ -4494,9 +5100,9 @@ function spawnEmployee(employeeName2, exeSession2, projectDir2, opts) {
|
|
|
4494
5100
|
}
|
|
4495
5101
|
let sessionContextFlag = "";
|
|
4496
5102
|
try {
|
|
4497
|
-
const ctxDir =
|
|
5103
|
+
const ctxDir = path15.join(os8.homedir(), ".exe-os", "session-cache");
|
|
4498
5104
|
mkdirSync6(ctxDir, { recursive: true });
|
|
4499
|
-
const ctxFile =
|
|
5105
|
+
const ctxFile = path15.join(ctxDir, `session-context-${sessionName}.md`);
|
|
4500
5106
|
const ctxContent = [
|
|
4501
5107
|
`## Session Context`,
|
|
4502
5108
|
`You are running in tmux session: ${sessionName}.`,
|
|
@@ -4580,7 +5186,7 @@ function spawnEmployee(employeeName2, exeSession2, projectDir2, opts) {
|
|
|
4580
5186
|
transport.pipeLog(sessionName, logFile);
|
|
4581
5187
|
try {
|
|
4582
5188
|
const mySession = getMySession();
|
|
4583
|
-
const dispatchInfo =
|
|
5189
|
+
const dispatchInfo = path15.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
|
|
4584
5190
|
writeFileSync7(dispatchInfo, JSON.stringify({
|
|
4585
5191
|
dispatchedBy: mySession,
|
|
4586
5192
|
rootExe: exeSession2,
|
|
@@ -4655,15 +5261,15 @@ var init_tmux_routing = __esm({
|
|
|
4655
5261
|
init_intercom_queue();
|
|
4656
5262
|
init_plan_limits();
|
|
4657
5263
|
init_employees();
|
|
4658
|
-
SPAWN_LOCK_DIR =
|
|
4659
|
-
SESSION_CACHE =
|
|
5264
|
+
SPAWN_LOCK_DIR = path15.join(os8.homedir(), ".exe-os", "spawn-locks");
|
|
5265
|
+
SESSION_CACHE = path15.join(os8.homedir(), ".exe-os", "session-cache");
|
|
4660
5266
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
4661
5267
|
VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
|
|
4662
5268
|
VERIFY_PANE_LINES = 200;
|
|
4663
5269
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
4664
5270
|
CODEX_DEBOUNCE_MS = 12e4;
|
|
4665
|
-
INTERCOM_LOG2 =
|
|
4666
|
-
DEBOUNCE_FILE =
|
|
5271
|
+
INTERCOM_LOG2 = path15.join(os8.homedir(), ".exe-os", "intercom.log");
|
|
5272
|
+
DEBOUNCE_FILE = path15.join(SESSION_CACHE, "intercom-debounce.json");
|
|
4667
5273
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
4668
5274
|
BUSY_PATTERN = /[✻✽✶✳·].*…|Running…|• Working|• Ran |• Explored|• Called|esc to interrupt/;
|
|
4669
5275
|
}
|
|
@@ -4682,7 +5288,7 @@ __export(shard_manager_exports, {
|
|
|
4682
5288
|
listShards: () => listShards,
|
|
4683
5289
|
shardExists: () => shardExists
|
|
4684
5290
|
});
|
|
4685
|
-
import
|
|
5291
|
+
import path17 from "path";
|
|
4686
5292
|
import { existsSync as existsSync13, mkdirSync as mkdirSync7, readdirSync as readdirSync4 } from "fs";
|
|
4687
5293
|
import { createClient as createClient2 } from "@libsql/client";
|
|
4688
5294
|
function initShardManager(encryptionKey) {
|
|
@@ -4708,7 +5314,7 @@ function getShardClient(projectName) {
|
|
|
4708
5314
|
}
|
|
4709
5315
|
const cached = _shards.get(safeName);
|
|
4710
5316
|
if (cached) return cached;
|
|
4711
|
-
const dbPath =
|
|
5317
|
+
const dbPath = path17.join(SHARDS_DIR, `${safeName}.db`);
|
|
4712
5318
|
const client = createClient2({
|
|
4713
5319
|
url: `file:${dbPath}`,
|
|
4714
5320
|
encryptionKey: _encryptionKey
|
|
@@ -4718,7 +5324,7 @@ function getShardClient(projectName) {
|
|
|
4718
5324
|
}
|
|
4719
5325
|
function shardExists(projectName) {
|
|
4720
5326
|
const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
4721
|
-
return existsSync13(
|
|
5327
|
+
return existsSync13(path17.join(SHARDS_DIR, `${safeName}.db`));
|
|
4722
5328
|
}
|
|
4723
5329
|
function listShards() {
|
|
4724
5330
|
if (!existsSync13(SHARDS_DIR)) return [];
|
|
@@ -4795,7 +5401,23 @@ async function ensureShardSchema(client) {
|
|
|
4795
5401
|
// MS-11: draft staging, MS-6a: memory_type, MS-7: trajectory
|
|
4796
5402
|
"ALTER TABLE memories ADD COLUMN draft INTEGER DEFAULT 0",
|
|
4797
5403
|
"ALTER TABLE memories ADD COLUMN memory_type TEXT DEFAULT 'raw'",
|
|
4798
|
-
"ALTER TABLE memories ADD COLUMN trajectory TEXT"
|
|
5404
|
+
"ALTER TABLE memories ADD COLUMN trajectory TEXT",
|
|
5405
|
+
// Metadata enrichment columns (must match database.ts)
|
|
5406
|
+
"ALTER TABLE memories ADD COLUMN intent TEXT",
|
|
5407
|
+
"ALTER TABLE memories ADD COLUMN outcome TEXT",
|
|
5408
|
+
"ALTER TABLE memories ADD COLUMN domain TEXT",
|
|
5409
|
+
"ALTER TABLE memories ADD COLUMN referenced_entities TEXT",
|
|
5410
|
+
"ALTER TABLE memories ADD COLUMN retrieval_count INTEGER DEFAULT 0",
|
|
5411
|
+
"ALTER TABLE memories ADD COLUMN chain_position TEXT",
|
|
5412
|
+
"ALTER TABLE memories ADD COLUMN review_status TEXT",
|
|
5413
|
+
"ALTER TABLE memories ADD COLUMN context_window_pct INTEGER",
|
|
5414
|
+
"ALTER TABLE memories ADD COLUMN file_paths TEXT",
|
|
5415
|
+
"ALTER TABLE memories ADD COLUMN commit_hash TEXT",
|
|
5416
|
+
"ALTER TABLE memories ADD COLUMN duration_ms INTEGER",
|
|
5417
|
+
"ALTER TABLE memories ADD COLUMN token_cost REAL",
|
|
5418
|
+
"ALTER TABLE memories ADD COLUMN audience TEXT",
|
|
5419
|
+
"ALTER TABLE memories ADD COLUMN language_type TEXT",
|
|
5420
|
+
"ALTER TABLE memories ADD COLUMN parent_memory_id TEXT"
|
|
4799
5421
|
]) {
|
|
4800
5422
|
try {
|
|
4801
5423
|
await client.execute(col);
|
|
@@ -4907,7 +5529,7 @@ var init_shard_manager = __esm({
|
|
|
4907
5529
|
"src/lib/shard-manager.ts"() {
|
|
4908
5530
|
"use strict";
|
|
4909
5531
|
init_config();
|
|
4910
|
-
SHARDS_DIR =
|
|
5532
|
+
SHARDS_DIR = path17.join(EXE_AI_DIR, "shards");
|
|
4911
5533
|
_shards = /* @__PURE__ */ new Map();
|
|
4912
5534
|
_encryptionKey = null;
|
|
4913
5535
|
_shardingEnabled = false;
|
|
@@ -5112,15 +5734,15 @@ init_database();
|
|
|
5112
5734
|
// src/lib/keychain.ts
|
|
5113
5735
|
import { readFile as readFile4, writeFile as writeFile5, unlink, mkdir as mkdir4, chmod as chmod2 } from "fs/promises";
|
|
5114
5736
|
import { existsSync as existsSync12 } from "fs";
|
|
5115
|
-
import
|
|
5116
|
-
import
|
|
5737
|
+
import path16 from "path";
|
|
5738
|
+
import os9 from "os";
|
|
5117
5739
|
var SERVICE = "exe-mem";
|
|
5118
5740
|
var ACCOUNT = "master-key";
|
|
5119
5741
|
function getKeyDir() {
|
|
5120
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ??
|
|
5742
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path16.join(os9.homedir(), ".exe-os");
|
|
5121
5743
|
}
|
|
5122
5744
|
function getKeyPath() {
|
|
5123
|
-
return
|
|
5745
|
+
return path16.join(getKeyDir(), "master.key");
|
|
5124
5746
|
}
|
|
5125
5747
|
async function tryKeytar() {
|
|
5126
5748
|
try {
|
|
@@ -5143,7 +5765,7 @@ async function getMasterKey() {
|
|
|
5143
5765
|
const keyPath = getKeyPath();
|
|
5144
5766
|
if (!existsSync12(keyPath)) {
|
|
5145
5767
|
process.stderr.write(
|
|
5146
|
-
`[keychain] Key not found at ${keyPath} (HOME=${
|
|
5768
|
+
`[keychain] Key not found at ${keyPath} (HOME=${os9.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
|
|
5147
5769
|
`
|
|
5148
5770
|
);
|
|
5149
5771
|
return null;
|