@askexenow/exe-os 0.8.37 → 0.8.39
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/README.md +17 -8
- package/dist/bin/backfill-conversations.js +112 -70
- package/dist/bin/backfill-responses.js +53 -18
- package/dist/bin/backfill-vectors.js +43 -16
- package/dist/bin/cleanup-stale-review-tasks.js +38 -16
- package/dist/bin/cli.js +790 -468
- package/dist/bin/exe-agent.js +19 -4
- package/dist/bin/exe-assign.js +46 -13
- package/dist/bin/exe-boot.js +288 -129
- package/dist/bin/exe-call.js +20 -10
- package/dist/bin/exe-cloud.js +135 -30
- package/dist/bin/exe-dispatch.js +1 -1
- package/dist/bin/exe-doctor.js +38 -16
- package/dist/bin/exe-export-behaviors.js +43 -21
- package/dist/bin/exe-forget.js +39 -17
- package/dist/bin/exe-gateway.js +159 -50
- package/dist/bin/exe-heartbeat.js +53 -31
- package/dist/bin/exe-kill.js +40 -18
- package/dist/bin/exe-launch-agent.js +109 -36
- package/dist/bin/exe-link.js +196 -87
- package/dist/bin/exe-new-employee.js +56 -17
- package/dist/bin/exe-pending-messages.js +47 -25
- package/dist/bin/exe-pending-notifications.js +38 -16
- package/dist/bin/exe-pending-reviews.js +51 -29
- package/dist/bin/exe-rename.js +21 -7
- package/dist/bin/exe-review.js +41 -13
- package/dist/bin/exe-search.js +57 -21
- package/dist/bin/exe-session-cleanup.js +67 -31
- package/dist/bin/exe-settings.js +63 -2
- package/dist/bin/exe-status.js +35 -13
- package/dist/bin/exe-team.js +35 -13
- package/dist/bin/git-sweep.js +45 -17
- package/dist/bin/graph-backfill.js +38 -16
- package/dist/bin/graph-export.js +38 -16
- package/dist/bin/install.js +10 -1
- package/dist/bin/scan-tasks.js +47 -19
- package/dist/bin/setup.js +444 -259
- package/dist/bin/shard-migrate.js +38 -16
- package/dist/bin/wiki-sync.js +40 -17
- package/dist/gateway/index.js +113 -48
- package/dist/hooks/bug-report-worker.js +66 -39
- package/dist/hooks/commit-complete.js +45 -17
- package/dist/hooks/error-recall.js +60 -20
- package/dist/hooks/exe-heartbeat-hook.js +3 -2
- package/dist/hooks/ingest-worker.js +174 -45
- package/dist/hooks/ingest.js +74 -28
- package/dist/hooks/instructions-loaded.js +46 -17
- package/dist/hooks/notification.js +44 -15
- package/dist/hooks/post-compact.js +44 -15
- package/dist/hooks/pre-compact.js +42 -14
- package/dist/hooks/pre-tool-use.js +59 -22
- package/dist/hooks/prompt-ingest-worker.js +75 -14
- package/dist/hooks/prompt-submit.js +75 -32
- package/dist/hooks/response-ingest-worker.js +76 -15
- package/dist/hooks/session-end.js +54 -22
- package/dist/hooks/session-start.js +57 -20
- package/dist/hooks/stop.js +44 -15
- package/dist/hooks/subagent-stop.js +44 -15
- package/dist/hooks/summary-worker.js +339 -106
- package/dist/index.js +94 -23
- package/dist/lib/cloud-sync.js +191 -80
- package/dist/lib/config.js +4 -1
- package/dist/lib/consolidation.js +5 -4
- package/dist/lib/database.js +1 -0
- package/dist/lib/device-registry.js +2 -1
- package/dist/lib/embedder.js +9 -1
- package/dist/lib/employee-templates.js +5 -0
- package/dist/lib/employees.js +11 -6
- package/dist/lib/exe-daemon-client.js +6 -1
- package/dist/lib/exe-daemon.js +95 -36
- package/dist/lib/hybrid-search.js +57 -21
- package/dist/lib/identity-templates.js +16 -7
- package/dist/lib/identity.js +1 -1
- package/dist/lib/keychain.js +2 -1
- package/dist/lib/license.js +56 -6
- package/dist/lib/messaging.js +1 -1
- package/dist/lib/reminders.js +2 -2
- package/dist/lib/schedules.js +38 -16
- package/dist/lib/skill-learning.js +1 -1
- package/dist/lib/store.js +44 -16
- package/dist/lib/tasks.js +1 -1
- package/dist/lib/tmux-routing.js +1 -1
- package/dist/mcp/server.js +280 -155
- package/dist/mcp/tools/complete-reminder.js +1 -1
- package/dist/mcp/tools/create-task.js +14 -6
- package/dist/mcp/tools/deactivate-behavior.js +2 -2
- package/dist/mcp/tools/list-reminders.js +1 -1
- package/dist/mcp/tools/list-tasks.js +36 -28
- package/dist/mcp/tools/send-message.js +1 -1
- package/dist/mcp/tools/update-task.js +1 -1
- package/dist/runtime/index.js +42 -8
- package/dist/tui/App.js +220 -99
- package/package.json +5 -3
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
var __defProp = Object.defineProperty;
|
|
3
3
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
5
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
6
|
+
}) : x)(function(x) {
|
|
7
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
8
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
9
|
+
});
|
|
4
10
|
var __esm = (fn, res) => function __init() {
|
|
5
11
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
6
12
|
};
|
|
@@ -10,7 +16,7 @@ var __export = (target, all) => {
|
|
|
10
16
|
};
|
|
11
17
|
|
|
12
18
|
// src/lib/config.ts
|
|
13
|
-
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
19
|
+
import { readFile, writeFile, mkdir, chmod } from "fs/promises";
|
|
14
20
|
import { readFileSync, existsSync, renameSync } from "fs";
|
|
15
21
|
import path from "path";
|
|
16
22
|
import os from "os";
|
|
@@ -134,6 +140,7 @@ var init_database = __esm({
|
|
|
134
140
|
var identity_templates_exports = {};
|
|
135
141
|
__export(identity_templates_exports, {
|
|
136
142
|
IDENTITY_TEMPLATES: () => IDENTITY_TEMPLATES,
|
|
143
|
+
PLAN_MODE_COMPAT: () => PLAN_MODE_COMPAT,
|
|
137
144
|
POST_WORK_CHECKLIST: () => POST_WORK_CHECKLIST,
|
|
138
145
|
getTemplate: () => getTemplate2,
|
|
139
146
|
getTemplateForTitle: () => getTemplateForTitle
|
|
@@ -153,10 +160,18 @@ function getTemplateForTitle(title) {
|
|
|
153
160
|
if (t.includes("review") || t.includes("audit") || t.includes("qa")) return IDENTITY_TEMPLATES["staff-code-reviewer"];
|
|
154
161
|
return null;
|
|
155
162
|
}
|
|
156
|
-
var POST_WORK_CHECKLIST, IDENTITY_TEMPLATES;
|
|
163
|
+
var PLAN_MODE_COMPAT, POST_WORK_CHECKLIST, IDENTITY_TEMPLATES;
|
|
157
164
|
var init_identity_templates = __esm({
|
|
158
165
|
"src/lib/identity-templates.ts"() {
|
|
159
166
|
"use strict";
|
|
167
|
+
PLAN_MODE_COMPAT = `
|
|
168
|
+
## Plan Mode Compatibility
|
|
169
|
+
If tool execution is unavailable (e.g., CC plan mode), switch to planning:
|
|
170
|
+
- Reason about the task and create a written plan
|
|
171
|
+
- Document what tools you would call and with what parameters
|
|
172
|
+
- Output structured text that can be acted on when tools become available
|
|
173
|
+
Do not repeatedly attempt tool calls that fail \u2014 switch to planning mode.
|
|
174
|
+
`;
|
|
160
175
|
POST_WORK_CHECKLIST = `
|
|
161
176
|
5. Check for pending reviews (list_tasks status='needs_review' where you are reviewer) \u2014 reviews are work, process before new tasks
|
|
162
177
|
6. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to exe immediately.
|
|
@@ -236,7 +251,7 @@ Never say "I have no memories" without first searching broadly. Your memory may
|
|
|
236
251
|
- **update_identity** \u2014 rewrite any agent's identity when role/responsibilities change (exe/founder only)
|
|
237
252
|
- **get_identity** \u2014 read any agent's identity for coordination
|
|
238
253
|
- **send_message** \u2014 direct intercom to employees
|
|
239
|
-
|
|
254
|
+
${PLAN_MODE_COMPAT}
|
|
240
255
|
## Completion Workflow
|
|
241
256
|
|
|
242
257
|
1. Read the task file and verify the deliverable matches the brief
|
|
@@ -307,7 +322,7 @@ You are \${agent_id}. CTO. You hold deep context on the entire codebase, archite
|
|
|
307
322
|
- **store_behavior** \u2014 record corrections for engineers (p0 = always injected)
|
|
308
323
|
- **get_identity** \u2014 read any agent's identity for review context
|
|
309
324
|
- **query_relationships** \u2014 GraphRAG entity connections for architecture analysis
|
|
310
|
-
|
|
325
|
+
${PLAN_MODE_COMPAT}
|
|
311
326
|
## Completion Workflow
|
|
312
327
|
|
|
313
328
|
1. Read ARCHITECTURE.md before starting work on any repo
|
|
@@ -374,7 +389,7 @@ You are \${agent_id}. CMO. You hold deep context on design, branding, storytelli
|
|
|
374
389
|
- **update_task** \u2014 mark tasks done with result summary
|
|
375
390
|
- **store_memory** \u2014 report completions with brand alignment notes, SEO considerations
|
|
376
391
|
- **get_identity** \u2014 read team identities for brand-consistent communication
|
|
377
|
-
|
|
392
|
+
${PLAN_MODE_COMPAT}
|
|
378
393
|
## Completion Workflow
|
|
379
394
|
|
|
380
395
|
1. Read the task file and understand the brief \u2014 tone, format, channel requirements
|
|
@@ -441,7 +456,7 @@ You are a principal engineer. You write production-grade code with zero shortcut
|
|
|
441
456
|
- **recall_my_memory** \u2014 check past work, patterns, gotchas in this project
|
|
442
457
|
- **store_memory** \u2014 report completions for org visibility
|
|
443
458
|
- **ask_team_memory** \u2014 pull context from colleagues when specs reference their work
|
|
444
|
-
|
|
459
|
+
${PLAN_MODE_COMPAT}
|
|
445
460
|
## Completion Workflow
|
|
446
461
|
|
|
447
462
|
1. Read ARCHITECTURE.md if it exists \u2014 understand architecture before changing anything
|
|
@@ -501,7 +516,7 @@ You are the content production specialist. You turn scripts and creative briefs
|
|
|
501
516
|
- **update_task** \u2014 mark tasks done with result summary
|
|
502
517
|
- **recall_my_memory** \u2014 check past work: which models worked, which prompts produced good results
|
|
503
518
|
- **store_memory** \u2014 report completions with production decisions for future reference
|
|
504
|
-
|
|
519
|
+
${PLAN_MODE_COMPAT}
|
|
505
520
|
## Completion Workflow
|
|
506
521
|
|
|
507
522
|
1. Read the task file \u2014 understand the brief, check budget constraints
|
|
@@ -573,7 +588,7 @@ You are the AI Product Lead \u2014 the competitive intelligence engine. You stud
|
|
|
573
588
|
- **update_task** \u2014 mark tasks done with analysis results
|
|
574
589
|
- **store_memory** \u2014 persist competitive analyses, evaluations, recommendations
|
|
575
590
|
- **create_task** \u2014 when a feature is worth building, spec it for the CTO
|
|
576
|
-
|
|
591
|
+
${PLAN_MODE_COMPAT}
|
|
577
592
|
## Completion Workflow
|
|
578
593
|
|
|
579
594
|
1. Read the task \u2014 understand what capability is needed
|
|
@@ -636,7 +651,7 @@ You are \${agent_id}. Staff Code Reviewer and System Auditor. Last line of defen
|
|
|
636
651
|
- **store_behavior** \u2014 record new patterns
|
|
637
652
|
- **update_task** \u2014 mark reviews done with structured findings
|
|
638
653
|
- **create_task** \u2014 assign fixes to the CTO
|
|
639
|
-
|
|
654
|
+
${PLAN_MODE_COMPAT}
|
|
640
655
|
## Completion Workflow
|
|
641
656
|
|
|
642
657
|
1. Read the task brief and understand the audit scope
|
|
@@ -834,15 +849,20 @@ function addEmployee(employees, employee) {
|
|
|
834
849
|
}
|
|
835
850
|
return [...employees, normalized];
|
|
836
851
|
}
|
|
852
|
+
function findExeBin() {
|
|
853
|
+
try {
|
|
854
|
+
return execSync(process.platform === "win32" ? "where exe-os" : "which exe-os", { encoding: "utf8" }).trim();
|
|
855
|
+
} catch {
|
|
856
|
+
return null;
|
|
857
|
+
}
|
|
858
|
+
}
|
|
837
859
|
function registerBinSymlinks(name) {
|
|
838
860
|
const created = [];
|
|
839
861
|
const skipped = [];
|
|
840
862
|
const errors = [];
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
} catch {
|
|
845
|
-
errors.push("Could not find 'exe' in PATH");
|
|
863
|
+
const exeBinPath = findExeBin();
|
|
864
|
+
if (!exeBinPath) {
|
|
865
|
+
errors.push("Could not find 'exe-os' in PATH");
|
|
846
866
|
return { created, skipped, errors };
|
|
847
867
|
}
|
|
848
868
|
const binDir = path2.dirname(exeBinPath);
|
|
@@ -1223,6 +1243,15 @@ var LICENSE_PATH = path3.join(EXE_AI_DIR, "license.key");
|
|
|
1223
1243
|
var CACHE_PATH = path3.join(EXE_AI_DIR, "license-cache.json");
|
|
1224
1244
|
var DEVICE_ID_PATH = path3.join(EXE_AI_DIR, "device-id");
|
|
1225
1245
|
var API_BASE = "https://askexe.com/cloud";
|
|
1246
|
+
var RETRY_DELAY_MS = 500;
|
|
1247
|
+
async function fetchRetry(url, init) {
|
|
1248
|
+
try {
|
|
1249
|
+
return await fetch(url, init);
|
|
1250
|
+
} catch {
|
|
1251
|
+
await new Promise((r) => setTimeout(r, RETRY_DELAY_MS));
|
|
1252
|
+
return fetch(url, { ...init, signal: AbortSignal.timeout(1e4) });
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1226
1255
|
var LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
|
|
1227
1256
|
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
|
|
1228
1257
|
4uj+UqeKCcvtgNHKmOK278HJaJcANe9xAeji8AFYu27q3WtzCi04pHudow==
|
|
@@ -1314,7 +1343,7 @@ function cacheResponse(token) {
|
|
|
1314
1343
|
async function validateLicense(apiKey, deviceId) {
|
|
1315
1344
|
const did = deviceId ?? loadDeviceId();
|
|
1316
1345
|
try {
|
|
1317
|
-
const res = await
|
|
1346
|
+
const res = await fetchRetry(`${API_BASE}/auth/activate`, {
|
|
1318
1347
|
method: "POST",
|
|
1319
1348
|
headers: { "Content-Type": "application/json" },
|
|
1320
1349
|
body: JSON.stringify({ apiKey, deviceId: did }),
|
|
@@ -1349,14 +1378,24 @@ async function validateLicense(apiKey, deviceId) {
|
|
|
1349
1378
|
} catch {
|
|
1350
1379
|
const cached = await getCachedLicense();
|
|
1351
1380
|
if (cached) return cached;
|
|
1352
|
-
return FREE_LICENSE;
|
|
1381
|
+
return { ...FREE_LICENSE, valid: false, error: "offline" };
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
var CACHE_MAX_AGE_MS = 36e5;
|
|
1385
|
+
function getCacheAgeMs() {
|
|
1386
|
+
try {
|
|
1387
|
+
const { statSync } = __require("fs");
|
|
1388
|
+
const s = statSync(CACHE_PATH);
|
|
1389
|
+
return Date.now() - s.mtimeMs;
|
|
1390
|
+
} catch {
|
|
1391
|
+
return Infinity;
|
|
1353
1392
|
}
|
|
1354
1393
|
}
|
|
1355
1394
|
async function checkLicense() {
|
|
1356
1395
|
const key = loadLicense();
|
|
1357
1396
|
if (!key) return FREE_LICENSE;
|
|
1358
1397
|
const cached = await getCachedLicense();
|
|
1359
|
-
if (cached) return cached;
|
|
1398
|
+
if (cached && getCacheAgeMs() < CACHE_MAX_AGE_MS) return cached;
|
|
1360
1399
|
const deviceId = loadDeviceId();
|
|
1361
1400
|
return validateLicense(key, deviceId);
|
|
1362
1401
|
}
|
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
4
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
5
|
-
}) : x)(function(x) {
|
|
6
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
7
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
8
|
-
});
|
|
9
3
|
var __esm = (fn, res) => function __init() {
|
|
10
4
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
11
5
|
};
|
|
@@ -102,6 +96,7 @@ async function ensureSchema() {
|
|
|
102
96
|
const client = getRawClient();
|
|
103
97
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
104
98
|
await client.execute("PRAGMA busy_timeout = 30000");
|
|
99
|
+
await client.execute("PRAGMA wal_autocheckpoint = 1000");
|
|
105
100
|
try {
|
|
106
101
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
107
102
|
} catch {
|
|
@@ -902,15 +897,15 @@ var init_database = __esm({
|
|
|
902
897
|
});
|
|
903
898
|
|
|
904
899
|
// src/lib/config.ts
|
|
905
|
-
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
900
|
+
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
|
|
906
901
|
import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
|
|
907
902
|
import path2 from "path";
|
|
908
|
-
import
|
|
903
|
+
import os2 from "os";
|
|
909
904
|
function resolveDataDir() {
|
|
910
905
|
if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
|
|
911
906
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
912
|
-
const newDir = path2.join(
|
|
913
|
-
const legacyDir = path2.join(
|
|
907
|
+
const newDir = path2.join(os2.homedir(), ".exe-os");
|
|
908
|
+
const legacyDir = path2.join(os2.homedir(), ".exe-mem");
|
|
914
909
|
if (!existsSync2(newDir) && existsSync2(legacyDir)) {
|
|
915
910
|
try {
|
|
916
911
|
renameSync(legacyDir, newDir);
|
|
@@ -997,7 +992,7 @@ async function loadConfig() {
|
|
|
997
992
|
normalizeAutoUpdate(migratedCfg);
|
|
998
993
|
const config = { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db"), ...migratedCfg };
|
|
999
994
|
if (config.dbPath.startsWith("~")) {
|
|
1000
|
-
config.dbPath = config.dbPath.replace(/^~/,
|
|
995
|
+
config.dbPath = config.dbPath.replace(/^~/, os2.homedir());
|
|
1001
996
|
}
|
|
1002
997
|
return config;
|
|
1003
998
|
} catch {
|
|
@@ -1104,7 +1099,7 @@ __export(shard_manager_exports, {
|
|
|
1104
1099
|
shardExists: () => shardExists
|
|
1105
1100
|
});
|
|
1106
1101
|
import path3 from "path";
|
|
1107
|
-
import { existsSync as existsSync3, mkdirSync } from "fs";
|
|
1102
|
+
import { existsSync as existsSync3, mkdirSync, readdirSync } from "fs";
|
|
1108
1103
|
import { createClient as createClient2 } from "@libsql/client";
|
|
1109
1104
|
function initShardManager(encryptionKey) {
|
|
1110
1105
|
_encryptionKey = encryptionKey;
|
|
@@ -1143,7 +1138,6 @@ function shardExists(projectName) {
|
|
|
1143
1138
|
}
|
|
1144
1139
|
function listShards() {
|
|
1145
1140
|
if (!existsSync3(SHARDS_DIR)) return [];
|
|
1146
|
-
const { readdirSync } = __require("fs");
|
|
1147
1141
|
return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
1148
1142
|
}
|
|
1149
1143
|
async function ensureShardSchema(client) {
|
|
@@ -1334,12 +1328,12 @@ var init_shard_manager = __esm({
|
|
|
1334
1328
|
|
|
1335
1329
|
// src/lib/session-registry.ts
|
|
1336
1330
|
import path4 from "path";
|
|
1337
|
-
import
|
|
1331
|
+
import os3 from "os";
|
|
1338
1332
|
var REGISTRY_PATH;
|
|
1339
1333
|
var init_session_registry = __esm({
|
|
1340
1334
|
"src/lib/session-registry.ts"() {
|
|
1341
1335
|
"use strict";
|
|
1342
|
-
REGISTRY_PATH = path4.join(
|
|
1336
|
+
REGISTRY_PATH = path4.join(os3.homedir(), ".exe-os", "session-registry.json");
|
|
1343
1337
|
}
|
|
1344
1338
|
});
|
|
1345
1339
|
|
|
@@ -1390,14 +1384,14 @@ var init_provider_table = __esm({
|
|
|
1390
1384
|
// src/lib/intercom-queue.ts
|
|
1391
1385
|
import { readFileSync as readFileSync2, writeFileSync, renameSync as renameSync2, existsSync as existsSync4, mkdirSync as mkdirSync2 } from "fs";
|
|
1392
1386
|
import path5 from "path";
|
|
1393
|
-
import
|
|
1387
|
+
import os4 from "os";
|
|
1394
1388
|
var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
|
|
1395
1389
|
var init_intercom_queue = __esm({
|
|
1396
1390
|
"src/lib/intercom-queue.ts"() {
|
|
1397
1391
|
"use strict";
|
|
1398
|
-
QUEUE_PATH = path5.join(
|
|
1392
|
+
QUEUE_PATH = path5.join(os4.homedir(), ".exe-os", "intercom-queue.json");
|
|
1399
1393
|
TTL_MS = 60 * 60 * 1e3;
|
|
1400
|
-
INTERCOM_LOG = path5.join(
|
|
1394
|
+
INTERCOM_LOG = path5.join(os4.homedir(), ".exe-os", "intercom.log");
|
|
1401
1395
|
}
|
|
1402
1396
|
});
|
|
1403
1397
|
|
|
@@ -1448,7 +1442,7 @@ var init_plan_limits = __esm({
|
|
|
1448
1442
|
|
|
1449
1443
|
// src/lib/tmux-routing.ts
|
|
1450
1444
|
import path9 from "path";
|
|
1451
|
-
import
|
|
1445
|
+
import os5 from "os";
|
|
1452
1446
|
import { fileURLToPath } from "url";
|
|
1453
1447
|
var SPAWN_LOCK_DIR, SESSION_CACHE, INTERCOM_LOG2, DEBOUNCE_FILE, DEBOUNCE_CLEANUP_AGE_MS;
|
|
1454
1448
|
var init_tmux_routing = __esm({
|
|
@@ -1462,9 +1456,9 @@ var init_tmux_routing = __esm({
|
|
|
1462
1456
|
init_provider_table();
|
|
1463
1457
|
init_intercom_queue();
|
|
1464
1458
|
init_plan_limits();
|
|
1465
|
-
SPAWN_LOCK_DIR = path9.join(
|
|
1466
|
-
SESSION_CACHE = path9.join(
|
|
1467
|
-
INTERCOM_LOG2 = path9.join(
|
|
1459
|
+
SPAWN_LOCK_DIR = path9.join(os5.homedir(), ".exe-os", "spawn-locks");
|
|
1460
|
+
SESSION_CACHE = path9.join(os5.homedir(), ".exe-os", "session-cache");
|
|
1461
|
+
INTERCOM_LOG2 = path9.join(os5.homedir(), ".exe-os", "intercom.log");
|
|
1468
1462
|
DEBOUNCE_FILE = path9.join(SESSION_CACHE, "intercom-debounce.json");
|
|
1469
1463
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
1470
1464
|
}
|
|
@@ -1477,11 +1471,12 @@ init_database();
|
|
|
1477
1471
|
import { readFile, writeFile, unlink, mkdir, chmod } from "fs/promises";
|
|
1478
1472
|
import { existsSync } from "fs";
|
|
1479
1473
|
import path from "path";
|
|
1474
|
+
import os from "os";
|
|
1480
1475
|
import crypto from "crypto";
|
|
1481
1476
|
var SERVICE = "exe-mem";
|
|
1482
1477
|
var ACCOUNT = "master-key";
|
|
1483
1478
|
function getKeyDir() {
|
|
1484
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(
|
|
1479
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(os.homedir(), ".exe-os");
|
|
1485
1480
|
}
|
|
1486
1481
|
function getKeyPath() {
|
|
1487
1482
|
return path.join(getKeyDir(), "master.key");
|
|
@@ -1518,6 +1513,30 @@ async function getMasterKey() {
|
|
|
1518
1513
|
|
|
1519
1514
|
// src/lib/store.ts
|
|
1520
1515
|
init_config();
|
|
1516
|
+
var INIT_MAX_RETRIES = 3;
|
|
1517
|
+
var INIT_RETRY_DELAY_MS = 1e3;
|
|
1518
|
+
function isBusyError2(err) {
|
|
1519
|
+
if (err instanceof Error) {
|
|
1520
|
+
const msg = err.message.toLowerCase();
|
|
1521
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
1522
|
+
}
|
|
1523
|
+
return false;
|
|
1524
|
+
}
|
|
1525
|
+
async function retryOnBusy2(fn, label) {
|
|
1526
|
+
for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
|
|
1527
|
+
try {
|
|
1528
|
+
return await fn();
|
|
1529
|
+
} catch (err) {
|
|
1530
|
+
if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
|
|
1531
|
+
process.stderr.write(
|
|
1532
|
+
`[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
|
|
1533
|
+
`
|
|
1534
|
+
);
|
|
1535
|
+
await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
|
|
1536
|
+
}
|
|
1537
|
+
}
|
|
1538
|
+
throw new Error("unreachable");
|
|
1539
|
+
}
|
|
1521
1540
|
var _pendingRecords = [];
|
|
1522
1541
|
var _batchSize = 20;
|
|
1523
1542
|
var _flushIntervalMs = 1e4;
|
|
@@ -1552,14 +1571,17 @@ async function initStore(options) {
|
|
|
1552
1571
|
dbPath,
|
|
1553
1572
|
encryptionKey: hexKey
|
|
1554
1573
|
});
|
|
1555
|
-
await ensureSchema();
|
|
1574
|
+
await retryOnBusy2(() => ensureSchema(), "ensureSchema");
|
|
1556
1575
|
try {
|
|
1557
1576
|
const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
1558
1577
|
initShardManager2(hexKey);
|
|
1559
1578
|
} catch {
|
|
1560
1579
|
}
|
|
1561
1580
|
const client = getClient();
|
|
1562
|
-
const vResult = await
|
|
1581
|
+
const vResult = await retryOnBusy2(
|
|
1582
|
+
() => client.execute("SELECT MAX(version) as max_v FROM memories"),
|
|
1583
|
+
"version-query"
|
|
1584
|
+
);
|
|
1563
1585
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
1564
1586
|
}
|
|
1565
1587
|
|
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
var __defProp = Object.defineProperty;
|
|
3
3
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
5
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
6
|
-
}) : x)(function(x) {
|
|
7
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
8
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
9
|
-
});
|
|
10
4
|
var __esm = (fn, res) => function __init() {
|
|
11
5
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
12
6
|
};
|
|
@@ -16,15 +10,15 @@ var __export = (target, all) => {
|
|
|
16
10
|
};
|
|
17
11
|
|
|
18
12
|
// src/lib/config.ts
|
|
19
|
-
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
13
|
+
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
|
|
20
14
|
import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
|
|
21
15
|
import path2 from "path";
|
|
22
|
-
import
|
|
16
|
+
import os2 from "os";
|
|
23
17
|
function resolveDataDir() {
|
|
24
18
|
if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
|
|
25
19
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
26
|
-
const newDir = path2.join(
|
|
27
|
-
const legacyDir = path2.join(
|
|
20
|
+
const newDir = path2.join(os2.homedir(), ".exe-os");
|
|
21
|
+
const legacyDir = path2.join(os2.homedir(), ".exe-mem");
|
|
28
22
|
if (!existsSync2(newDir) && existsSync2(legacyDir)) {
|
|
29
23
|
try {
|
|
30
24
|
renameSync(legacyDir, newDir);
|
|
@@ -111,7 +105,7 @@ async function loadConfig() {
|
|
|
111
105
|
normalizeAutoUpdate(migratedCfg);
|
|
112
106
|
const config = { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db"), ...migratedCfg };
|
|
113
107
|
if (config.dbPath.startsWith("~")) {
|
|
114
|
-
config.dbPath = config.dbPath.replace(/^~/,
|
|
108
|
+
config.dbPath = config.dbPath.replace(/^~/, os2.homedir());
|
|
115
109
|
}
|
|
116
110
|
return config;
|
|
117
111
|
} catch {
|
|
@@ -218,7 +212,7 @@ __export(shard_manager_exports, {
|
|
|
218
212
|
shardExists: () => shardExists
|
|
219
213
|
});
|
|
220
214
|
import path3 from "path";
|
|
221
|
-
import { existsSync as existsSync3, mkdirSync } from "fs";
|
|
215
|
+
import { existsSync as existsSync3, mkdirSync, readdirSync } from "fs";
|
|
222
216
|
import { createClient as createClient2 } from "@libsql/client";
|
|
223
217
|
function initShardManager(encryptionKey) {
|
|
224
218
|
_encryptionKey = encryptionKey;
|
|
@@ -257,7 +251,6 @@ function shardExists(projectName) {
|
|
|
257
251
|
}
|
|
258
252
|
function listShards() {
|
|
259
253
|
if (!existsSync3(SHARDS_DIR)) return [];
|
|
260
|
-
const { readdirSync } = __require("fs");
|
|
261
254
|
return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
262
255
|
}
|
|
263
256
|
async function ensureShardSchema(client) {
|
|
@@ -533,6 +526,7 @@ async function ensureSchema() {
|
|
|
533
526
|
const client = getRawClient();
|
|
534
527
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
535
528
|
await client.execute("PRAGMA busy_timeout = 30000");
|
|
529
|
+
await client.execute("PRAGMA wal_autocheckpoint = 1000");
|
|
536
530
|
try {
|
|
537
531
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
538
532
|
} catch {
|
|
@@ -1326,11 +1320,12 @@ async function ensureSchema() {
|
|
|
1326
1320
|
import { readFile, writeFile, unlink, mkdir, chmod } from "fs/promises";
|
|
1327
1321
|
import { existsSync } from "fs";
|
|
1328
1322
|
import path from "path";
|
|
1323
|
+
import os from "os";
|
|
1329
1324
|
import crypto from "crypto";
|
|
1330
1325
|
var SERVICE = "exe-mem";
|
|
1331
1326
|
var ACCOUNT = "master-key";
|
|
1332
1327
|
function getKeyDir() {
|
|
1333
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(
|
|
1328
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(os.homedir(), ".exe-os");
|
|
1334
1329
|
}
|
|
1335
1330
|
function getKeyPath() {
|
|
1336
1331
|
return path.join(getKeyDir(), "master.key");
|
|
@@ -1367,6 +1362,30 @@ async function getMasterKey() {
|
|
|
1367
1362
|
|
|
1368
1363
|
// src/lib/store.ts
|
|
1369
1364
|
init_config();
|
|
1365
|
+
var INIT_MAX_RETRIES = 3;
|
|
1366
|
+
var INIT_RETRY_DELAY_MS = 1e3;
|
|
1367
|
+
function isBusyError2(err) {
|
|
1368
|
+
if (err instanceof Error) {
|
|
1369
|
+
const msg = err.message.toLowerCase();
|
|
1370
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
1371
|
+
}
|
|
1372
|
+
return false;
|
|
1373
|
+
}
|
|
1374
|
+
async function retryOnBusy2(fn, label) {
|
|
1375
|
+
for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
|
|
1376
|
+
try {
|
|
1377
|
+
return await fn();
|
|
1378
|
+
} catch (err) {
|
|
1379
|
+
if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
|
|
1380
|
+
process.stderr.write(
|
|
1381
|
+
`[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
|
|
1382
|
+
`
|
|
1383
|
+
);
|
|
1384
|
+
await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
throw new Error("unreachable");
|
|
1388
|
+
}
|
|
1370
1389
|
var _pendingRecords = [];
|
|
1371
1390
|
var _batchSize = 20;
|
|
1372
1391
|
var _flushIntervalMs = 1e4;
|
|
@@ -1401,14 +1420,17 @@ async function initStore(options) {
|
|
|
1401
1420
|
dbPath,
|
|
1402
1421
|
encryptionKey: hexKey
|
|
1403
1422
|
});
|
|
1404
|
-
await ensureSchema();
|
|
1423
|
+
await retryOnBusy2(() => ensureSchema(), "ensureSchema");
|
|
1405
1424
|
try {
|
|
1406
1425
|
const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
1407
1426
|
initShardManager2(hexKey);
|
|
1408
1427
|
} catch {
|
|
1409
1428
|
}
|
|
1410
1429
|
const client = getClient();
|
|
1411
|
-
const vResult = await
|
|
1430
|
+
const vResult = await retryOnBusy2(
|
|
1431
|
+
() => client.execute("SELECT MAX(version) as max_v FROM memories"),
|
|
1432
|
+
"version-query"
|
|
1433
|
+
);
|
|
1412
1434
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
1413
1435
|
}
|
|
1414
1436
|
|