@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,4 +1,12 @@
|
|
|
1
1
|
// src/lib/identity-templates.ts
|
|
2
|
+
var PLAN_MODE_COMPAT = `
|
|
3
|
+
## Plan Mode Compatibility
|
|
4
|
+
If tool execution is unavailable (e.g., CC plan mode), switch to planning:
|
|
5
|
+
- Reason about the task and create a written plan
|
|
6
|
+
- Document what tools you would call and with what parameters
|
|
7
|
+
- Output structured text that can be acted on when tools become available
|
|
8
|
+
Do not repeatedly attempt tool calls that fail \u2014 switch to planning mode.
|
|
9
|
+
`;
|
|
2
10
|
var POST_WORK_CHECKLIST = `
|
|
3
11
|
5. Check for pending reviews (list_tasks status='needs_review' where you are reviewer) \u2014 reviews are work, process before new tasks
|
|
4
12
|
6. Check for blocked tasks (list_tasks status='blocked') \u2014 can you unblock it? Do it now. Can't? Escalate to exe immediately.
|
|
@@ -78,7 +86,7 @@ Never say "I have no memories" without first searching broadly. Your memory may
|
|
|
78
86
|
- **update_identity** \u2014 rewrite any agent's identity when role/responsibilities change (exe/founder only)
|
|
79
87
|
- **get_identity** \u2014 read any agent's identity for coordination
|
|
80
88
|
- **send_message** \u2014 direct intercom to employees
|
|
81
|
-
|
|
89
|
+
${PLAN_MODE_COMPAT}
|
|
82
90
|
## Completion Workflow
|
|
83
91
|
|
|
84
92
|
1. Read the task file and verify the deliverable matches the brief
|
|
@@ -149,7 +157,7 @@ You are \${agent_id}. CTO. You hold deep context on the entire codebase, archite
|
|
|
149
157
|
- **store_behavior** \u2014 record corrections for engineers (p0 = always injected)
|
|
150
158
|
- **get_identity** \u2014 read any agent's identity for review context
|
|
151
159
|
- **query_relationships** \u2014 GraphRAG entity connections for architecture analysis
|
|
152
|
-
|
|
160
|
+
${PLAN_MODE_COMPAT}
|
|
153
161
|
## Completion Workflow
|
|
154
162
|
|
|
155
163
|
1. Read ARCHITECTURE.md before starting work on any repo
|
|
@@ -216,7 +224,7 @@ You are \${agent_id}. CMO. You hold deep context on design, branding, storytelli
|
|
|
216
224
|
- **update_task** \u2014 mark tasks done with result summary
|
|
217
225
|
- **store_memory** \u2014 report completions with brand alignment notes, SEO considerations
|
|
218
226
|
- **get_identity** \u2014 read team identities for brand-consistent communication
|
|
219
|
-
|
|
227
|
+
${PLAN_MODE_COMPAT}
|
|
220
228
|
## Completion Workflow
|
|
221
229
|
|
|
222
230
|
1. Read the task file and understand the brief \u2014 tone, format, channel requirements
|
|
@@ -283,7 +291,7 @@ You are a principal engineer. You write production-grade code with zero shortcut
|
|
|
283
291
|
- **recall_my_memory** \u2014 check past work, patterns, gotchas in this project
|
|
284
292
|
- **store_memory** \u2014 report completions for org visibility
|
|
285
293
|
- **ask_team_memory** \u2014 pull context from colleagues when specs reference their work
|
|
286
|
-
|
|
294
|
+
${PLAN_MODE_COMPAT}
|
|
287
295
|
## Completion Workflow
|
|
288
296
|
|
|
289
297
|
1. Read ARCHITECTURE.md if it exists \u2014 understand architecture before changing anything
|
|
@@ -343,7 +351,7 @@ You are the content production specialist. You turn scripts and creative briefs
|
|
|
343
351
|
- **update_task** \u2014 mark tasks done with result summary
|
|
344
352
|
- **recall_my_memory** \u2014 check past work: which models worked, which prompts produced good results
|
|
345
353
|
- **store_memory** \u2014 report completions with production decisions for future reference
|
|
346
|
-
|
|
354
|
+
${PLAN_MODE_COMPAT}
|
|
347
355
|
## Completion Workflow
|
|
348
356
|
|
|
349
357
|
1. Read the task file \u2014 understand the brief, check budget constraints
|
|
@@ -415,7 +423,7 @@ You are the AI Product Lead \u2014 the competitive intelligence engine. You stud
|
|
|
415
423
|
- **update_task** \u2014 mark tasks done with analysis results
|
|
416
424
|
- **store_memory** \u2014 persist competitive analyses, evaluations, recommendations
|
|
417
425
|
- **create_task** \u2014 when a feature is worth building, spec it for the CTO
|
|
418
|
-
|
|
426
|
+
${PLAN_MODE_COMPAT}
|
|
419
427
|
## Completion Workflow
|
|
420
428
|
|
|
421
429
|
1. Read the task \u2014 understand what capability is needed
|
|
@@ -478,7 +486,7 @@ You are \${agent_id}. Staff Code Reviewer and System Auditor. Last line of defen
|
|
|
478
486
|
- **store_behavior** \u2014 record new patterns
|
|
479
487
|
- **update_task** \u2014 mark reviews done with structured findings
|
|
480
488
|
- **create_task** \u2014 assign fixes to the CTO
|
|
481
|
-
|
|
489
|
+
${PLAN_MODE_COMPAT}
|
|
482
490
|
## Completion Workflow
|
|
483
491
|
|
|
484
492
|
1. Read the task brief and understand the audit scope
|
|
@@ -507,6 +515,7 @@ function getTemplateForTitle(title) {
|
|
|
507
515
|
}
|
|
508
516
|
export {
|
|
509
517
|
IDENTITY_TEMPLATES,
|
|
518
|
+
PLAN_MODE_COMPAT,
|
|
510
519
|
POST_WORK_CHECKLIST,
|
|
511
520
|
getTemplate,
|
|
512
521
|
getTemplateForTitle
|
package/dist/lib/identity.js
CHANGED
|
@@ -5,7 +5,7 @@ import path2 from "path";
|
|
|
5
5
|
import { createHash } from "crypto";
|
|
6
6
|
|
|
7
7
|
// src/lib/config.ts
|
|
8
|
-
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
8
|
+
import { readFile, writeFile, mkdir, chmod } from "fs/promises";
|
|
9
9
|
import { readFileSync, existsSync, renameSync } from "fs";
|
|
10
10
|
import path from "path";
|
|
11
11
|
import os from "os";
|
package/dist/lib/keychain.js
CHANGED
|
@@ -9,11 +9,12 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
9
9
|
import { readFile, writeFile, unlink, mkdir, chmod } from "fs/promises";
|
|
10
10
|
import { existsSync } from "fs";
|
|
11
11
|
import path from "path";
|
|
12
|
+
import os from "os";
|
|
12
13
|
import crypto from "crypto";
|
|
13
14
|
var SERVICE = "exe-mem";
|
|
14
15
|
var ACCOUNT = "master-key";
|
|
15
16
|
function getKeyDir() {
|
|
16
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(
|
|
17
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(os.homedir(), ".exe-os");
|
|
17
18
|
}
|
|
18
19
|
function getKeyPath() {
|
|
19
20
|
return path.join(getKeyDir(), "master.key");
|
package/dist/lib/license.js
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
+
}) : x)(function(x) {
|
|
4
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
+
});
|
|
7
|
+
|
|
1
8
|
// src/lib/license.ts
|
|
2
9
|
import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync2, mkdirSync } from "fs";
|
|
3
10
|
import { randomUUID } from "crypto";
|
|
@@ -5,7 +12,7 @@ import path2 from "path";
|
|
|
5
12
|
import { jwtVerify, importSPKI } from "jose";
|
|
6
13
|
|
|
7
14
|
// src/lib/config.ts
|
|
8
|
-
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
15
|
+
import { readFile, writeFile, mkdir, chmod } from "fs/promises";
|
|
9
16
|
import { readFileSync, existsSync, renameSync } from "fs";
|
|
10
17
|
import path from "path";
|
|
11
18
|
import os from "os";
|
|
@@ -100,6 +107,15 @@ var LICENSE_PATH = path2.join(EXE_AI_DIR, "license.key");
|
|
|
100
107
|
var CACHE_PATH = path2.join(EXE_AI_DIR, "license-cache.json");
|
|
101
108
|
var DEVICE_ID_PATH = path2.join(EXE_AI_DIR, "device-id");
|
|
102
109
|
var API_BASE = "https://askexe.com/cloud";
|
|
110
|
+
var RETRY_DELAY_MS = 500;
|
|
111
|
+
async function fetchRetry(url, init) {
|
|
112
|
+
try {
|
|
113
|
+
return await fetch(url, init);
|
|
114
|
+
} catch {
|
|
115
|
+
await new Promise((r) => setTimeout(r, RETRY_DELAY_MS));
|
|
116
|
+
return fetch(url, { ...init, signal: AbortSignal.timeout(1e4) });
|
|
117
|
+
}
|
|
118
|
+
}
|
|
103
119
|
var LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
|
|
104
120
|
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
|
|
105
121
|
4uj+UqeKCcvtgNHKmOK278HJaJcANe9xAeji8AFYu27q3WtzCi04pHudow==
|
|
@@ -152,7 +168,7 @@ function loadLicense() {
|
|
|
152
168
|
}
|
|
153
169
|
function saveLicense(apiKey) {
|
|
154
170
|
mkdirSync(EXE_AI_DIR, { recursive: true });
|
|
155
|
-
writeFileSync(LICENSE_PATH, apiKey.trim(), "utf8");
|
|
171
|
+
writeFileSync(LICENSE_PATH, apiKey.trim(), { encoding: "utf8", mode: 384 });
|
|
156
172
|
}
|
|
157
173
|
async function verifyLicenseJwt(token) {
|
|
158
174
|
try {
|
|
@@ -204,7 +220,7 @@ function cacheResponse(token) {
|
|
|
204
220
|
async function validateLicense(apiKey, deviceId) {
|
|
205
221
|
const did = deviceId ?? loadDeviceId();
|
|
206
222
|
try {
|
|
207
|
-
const res = await
|
|
223
|
+
const res = await fetchRetry(`${API_BASE}/auth/activate`, {
|
|
208
224
|
method: "POST",
|
|
209
225
|
headers: { "Content-Type": "application/json" },
|
|
210
226
|
body: JSON.stringify({ apiKey, deviceId: did }),
|
|
@@ -239,14 +255,24 @@ async function validateLicense(apiKey, deviceId) {
|
|
|
239
255
|
} catch {
|
|
240
256
|
const cached = await getCachedLicense();
|
|
241
257
|
if (cached) return cached;
|
|
242
|
-
return FREE_LICENSE;
|
|
258
|
+
return { ...FREE_LICENSE, valid: false, error: "offline" };
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
var CACHE_MAX_AGE_MS = 36e5;
|
|
262
|
+
function getCacheAgeMs() {
|
|
263
|
+
try {
|
|
264
|
+
const { statSync } = __require("fs");
|
|
265
|
+
const s = statSync(CACHE_PATH);
|
|
266
|
+
return Date.now() - s.mtimeMs;
|
|
267
|
+
} catch {
|
|
268
|
+
return Infinity;
|
|
243
269
|
}
|
|
244
270
|
}
|
|
245
271
|
async function checkLicense() {
|
|
246
272
|
const key = loadLicense();
|
|
247
273
|
if (!key) return FREE_LICENSE;
|
|
248
274
|
const cached = await getCachedLicense();
|
|
249
|
-
if (cached) return cached;
|
|
275
|
+
if (cached && getCacheAgeMs() < CACHE_MAX_AGE_MS) return cached;
|
|
250
276
|
const deviceId = loadDeviceId();
|
|
251
277
|
return validateLicense(key, deviceId);
|
|
252
278
|
}
|
|
@@ -286,7 +312,7 @@ async function assertVpsLicense(opts) {
|
|
|
286
312
|
let explicitRejection = false;
|
|
287
313
|
let transientFailure = false;
|
|
288
314
|
try {
|
|
289
|
-
const res = await
|
|
315
|
+
const res = await fetchRetry(`${API_BASE}/auth/activate`, {
|
|
290
316
|
method: "POST",
|
|
291
317
|
headers: { "Content-Type": "application/json" },
|
|
292
318
|
body: JSON.stringify({ apiKey, deviceId }),
|
|
@@ -367,6 +393,28 @@ async function assertVpsLicense(opts) {
|
|
|
367
393
|
`License validation unreachable for more than ${graceDays} days. Restore network connectivity to https://askexe.com/cloud and retry. This VPS image refuses to boot after the offline grace window.`
|
|
368
394
|
);
|
|
369
395
|
}
|
|
396
|
+
var _revalTimer = null;
|
|
397
|
+
function startLicenseRevalidation(intervalMs = 36e5) {
|
|
398
|
+
if (_revalTimer) return;
|
|
399
|
+
_revalTimer = setInterval(async () => {
|
|
400
|
+
try {
|
|
401
|
+
const license = await checkLicense();
|
|
402
|
+
if (!license.valid) {
|
|
403
|
+
process.stderr.write("[exe-os] License expired or invalid \u2014 features may be restricted\n");
|
|
404
|
+
}
|
|
405
|
+
} catch {
|
|
406
|
+
}
|
|
407
|
+
}, intervalMs);
|
|
408
|
+
if (_revalTimer && typeof _revalTimer === "object" && "unref" in _revalTimer) {
|
|
409
|
+
_revalTimer.unref();
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
function stopLicenseRevalidation() {
|
|
413
|
+
if (_revalTimer) {
|
|
414
|
+
clearInterval(_revalTimer);
|
|
415
|
+
_revalTimer = null;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
370
418
|
export {
|
|
371
419
|
LICENSE_PUBLIC_KEY_PEM,
|
|
372
420
|
PLAN_LIMITS,
|
|
@@ -378,5 +426,7 @@ export {
|
|
|
378
426
|
loadLicense,
|
|
379
427
|
mirrorLicenseKey,
|
|
380
428
|
saveLicense,
|
|
429
|
+
startLicenseRevalidation,
|
|
430
|
+
stopLicenseRevalidation,
|
|
381
431
|
validateLicense
|
|
382
432
|
};
|
package/dist/lib/messaging.js
CHANGED
|
@@ -342,7 +342,7 @@ var init_intercom_queue = __esm({
|
|
|
342
342
|
});
|
|
343
343
|
|
|
344
344
|
// src/lib/config.ts
|
|
345
|
-
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
345
|
+
import { readFile, writeFile, mkdir, chmod } from "fs/promises";
|
|
346
346
|
import { readFileSync as readFileSync3, existsSync as existsSync3, renameSync as renameSync2 } from "fs";
|
|
347
347
|
import path3 from "path";
|
|
348
348
|
import os3 from "os";
|
package/dist/lib/reminders.js
CHANGED
|
@@ -24,7 +24,7 @@ async function createReminder(text, dueDate) {
|
|
|
24
24
|
}
|
|
25
25
|
async function listReminders(includeCompleted = false) {
|
|
26
26
|
const client = getClient();
|
|
27
|
-
const sql = includeCompleted ? `SELECT id, text, created_at, due_date, completed_at FROM reminders ORDER BY due_date ASC NULLS LAST` : `SELECT id, text, created_at, due_date, completed_at FROM reminders WHERE completed_at IS NULL ORDER BY due_date ASC NULLS LAST`;
|
|
27
|
+
const sql = includeCompleted ? `SELECT id, text, created_at, due_date, completed_at FROM reminders ORDER BY due_date ASC NULLS LAST LIMIT 500` : `SELECT id, text, created_at, due_date, completed_at FROM reminders WHERE completed_at IS NULL ORDER BY due_date ASC NULLS LAST LIMIT 500`;
|
|
28
28
|
const result = await client.execute(sql);
|
|
29
29
|
return result.rows.map((row) => ({
|
|
30
30
|
id: String(row.id),
|
|
@@ -43,7 +43,7 @@ async function completeReminder(idOrText) {
|
|
|
43
43
|
});
|
|
44
44
|
if (result.rows.length === 0) {
|
|
45
45
|
result = await client.execute({
|
|
46
|
-
sql: `SELECT id, text FROM reminders WHERE completed_at IS NULL AND text LIKE '%' || ? || '%'`,
|
|
46
|
+
sql: `SELECT id, text FROM reminders WHERE completed_at IS NULL AND text LIKE '%' || ? || '%' LIMIT 1`,
|
|
47
47
|
args: [idOrText]
|
|
48
48
|
});
|
|
49
49
|
}
|
package/dist/lib/schedules.js
CHANGED
|
@@ -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
|
};
|
|
@@ -15,15 +9,15 @@ var __export = (target, all) => {
|
|
|
15
9
|
};
|
|
16
10
|
|
|
17
11
|
// src/lib/config.ts
|
|
18
|
-
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
12
|
+
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
|
|
19
13
|
import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
|
|
20
14
|
import path2 from "path";
|
|
21
|
-
import
|
|
15
|
+
import os2 from "os";
|
|
22
16
|
function resolveDataDir() {
|
|
23
17
|
if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
|
|
24
18
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
25
|
-
const newDir = path2.join(
|
|
26
|
-
const legacyDir = path2.join(
|
|
19
|
+
const newDir = path2.join(os2.homedir(), ".exe-os");
|
|
20
|
+
const legacyDir = path2.join(os2.homedir(), ".exe-mem");
|
|
27
21
|
if (!existsSync2(newDir) && existsSync2(legacyDir)) {
|
|
28
22
|
try {
|
|
29
23
|
renameSync(legacyDir, newDir);
|
|
@@ -110,7 +104,7 @@ async function loadConfig() {
|
|
|
110
104
|
normalizeAutoUpdate(migratedCfg);
|
|
111
105
|
const config = { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db"), ...migratedCfg };
|
|
112
106
|
if (config.dbPath.startsWith("~")) {
|
|
113
|
-
config.dbPath = config.dbPath.replace(/^~/,
|
|
107
|
+
config.dbPath = config.dbPath.replace(/^~/, os2.homedir());
|
|
114
108
|
}
|
|
115
109
|
return config;
|
|
116
110
|
} catch {
|
|
@@ -217,7 +211,7 @@ __export(shard_manager_exports, {
|
|
|
217
211
|
shardExists: () => shardExists
|
|
218
212
|
});
|
|
219
213
|
import path3 from "path";
|
|
220
|
-
import { existsSync as existsSync3, mkdirSync } from "fs";
|
|
214
|
+
import { existsSync as existsSync3, mkdirSync, readdirSync } from "fs";
|
|
221
215
|
import { createClient as createClient2 } from "@libsql/client";
|
|
222
216
|
function initShardManager(encryptionKey) {
|
|
223
217
|
_encryptionKey = encryptionKey;
|
|
@@ -256,7 +250,6 @@ function shardExists(projectName) {
|
|
|
256
250
|
}
|
|
257
251
|
function listShards() {
|
|
258
252
|
if (!existsSync3(SHARDS_DIR)) return [];
|
|
259
|
-
const { readdirSync } = __require("fs");
|
|
260
253
|
return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
261
254
|
}
|
|
262
255
|
async function ensureShardSchema(client) {
|
|
@@ -539,6 +532,7 @@ async function ensureSchema() {
|
|
|
539
532
|
const client = getRawClient();
|
|
540
533
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
541
534
|
await client.execute("PRAGMA busy_timeout = 30000");
|
|
535
|
+
await client.execute("PRAGMA wal_autocheckpoint = 1000");
|
|
542
536
|
try {
|
|
543
537
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
544
538
|
} catch {
|
|
@@ -1332,11 +1326,12 @@ async function ensureSchema() {
|
|
|
1332
1326
|
import { readFile, writeFile, unlink, mkdir, chmod } from "fs/promises";
|
|
1333
1327
|
import { existsSync } from "fs";
|
|
1334
1328
|
import path from "path";
|
|
1329
|
+
import os from "os";
|
|
1335
1330
|
import crypto from "crypto";
|
|
1336
1331
|
var SERVICE = "exe-mem";
|
|
1337
1332
|
var ACCOUNT = "master-key";
|
|
1338
1333
|
function getKeyDir() {
|
|
1339
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(
|
|
1334
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(os.homedir(), ".exe-os");
|
|
1340
1335
|
}
|
|
1341
1336
|
function getKeyPath() {
|
|
1342
1337
|
return path.join(getKeyDir(), "master.key");
|
|
@@ -1373,6 +1368,30 @@ async function getMasterKey() {
|
|
|
1373
1368
|
|
|
1374
1369
|
// src/lib/store.ts
|
|
1375
1370
|
init_config();
|
|
1371
|
+
var INIT_MAX_RETRIES = 3;
|
|
1372
|
+
var INIT_RETRY_DELAY_MS = 1e3;
|
|
1373
|
+
function isBusyError2(err) {
|
|
1374
|
+
if (err instanceof Error) {
|
|
1375
|
+
const msg = err.message.toLowerCase();
|
|
1376
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
1377
|
+
}
|
|
1378
|
+
return false;
|
|
1379
|
+
}
|
|
1380
|
+
async function retryOnBusy2(fn, label) {
|
|
1381
|
+
for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
|
|
1382
|
+
try {
|
|
1383
|
+
return await fn();
|
|
1384
|
+
} catch (err) {
|
|
1385
|
+
if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
|
|
1386
|
+
process.stderr.write(
|
|
1387
|
+
`[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
|
|
1388
|
+
`
|
|
1389
|
+
);
|
|
1390
|
+
await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
throw new Error("unreachable");
|
|
1394
|
+
}
|
|
1376
1395
|
var _pendingRecords = [];
|
|
1377
1396
|
var _batchSize = 20;
|
|
1378
1397
|
var _flushIntervalMs = 1e4;
|
|
@@ -1407,14 +1426,17 @@ async function initStore(options) {
|
|
|
1407
1426
|
dbPath,
|
|
1408
1427
|
encryptionKey: hexKey
|
|
1409
1428
|
});
|
|
1410
|
-
await ensureSchema();
|
|
1429
|
+
await retryOnBusy2(() => ensureSchema(), "ensureSchema");
|
|
1411
1430
|
try {
|
|
1412
1431
|
const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
1413
1432
|
initShardManager2(hexKey);
|
|
1414
1433
|
} catch {
|
|
1415
1434
|
}
|
|
1416
1435
|
const client = getClient();
|
|
1417
|
-
const vResult = await
|
|
1436
|
+
const vResult = await retryOnBusy2(
|
|
1437
|
+
() => client.execute("SELECT MAX(version) as max_v FROM memories"),
|
|
1438
|
+
"version-query"
|
|
1439
|
+
);
|
|
1418
1440
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
1419
1441
|
}
|
|
1420
1442
|
|
|
@@ -26,7 +26,7 @@ async function storeBehavior(opts) {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
// src/lib/config.ts
|
|
29
|
-
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
29
|
+
import { readFile, writeFile, mkdir, chmod } from "fs/promises";
|
|
30
30
|
import { readFileSync, existsSync, renameSync } from "fs";
|
|
31
31
|
import path from "path";
|
|
32
32
|
import os from "os";
|
package/dist/lib/store.js
CHANGED
|
@@ -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
|
};
|
|
@@ -15,15 +9,15 @@ var __export = (target, all) => {
|
|
|
15
9
|
};
|
|
16
10
|
|
|
17
11
|
// src/lib/config.ts
|
|
18
|
-
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
12
|
+
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
|
|
19
13
|
import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
|
|
20
14
|
import path2 from "path";
|
|
21
|
-
import
|
|
15
|
+
import os2 from "os";
|
|
22
16
|
function resolveDataDir() {
|
|
23
17
|
if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
|
|
24
18
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
25
|
-
const newDir = path2.join(
|
|
26
|
-
const legacyDir = path2.join(
|
|
19
|
+
const newDir = path2.join(os2.homedir(), ".exe-os");
|
|
20
|
+
const legacyDir = path2.join(os2.homedir(), ".exe-mem");
|
|
27
21
|
if (!existsSync2(newDir) && existsSync2(legacyDir)) {
|
|
28
22
|
try {
|
|
29
23
|
renameSync(legacyDir, newDir);
|
|
@@ -110,7 +104,7 @@ async function loadConfig() {
|
|
|
110
104
|
normalizeAutoUpdate(migratedCfg);
|
|
111
105
|
const config = { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db"), ...migratedCfg };
|
|
112
106
|
if (config.dbPath.startsWith("~")) {
|
|
113
|
-
config.dbPath = config.dbPath.replace(/^~/,
|
|
107
|
+
config.dbPath = config.dbPath.replace(/^~/, os2.homedir());
|
|
114
108
|
}
|
|
115
109
|
return config;
|
|
116
110
|
} catch {
|
|
@@ -217,7 +211,7 @@ __export(shard_manager_exports, {
|
|
|
217
211
|
shardExists: () => shardExists
|
|
218
212
|
});
|
|
219
213
|
import path3 from "path";
|
|
220
|
-
import { existsSync as existsSync3, mkdirSync } from "fs";
|
|
214
|
+
import { existsSync as existsSync3, mkdirSync, readdirSync } from "fs";
|
|
221
215
|
import { createClient as createClient2 } from "@libsql/client";
|
|
222
216
|
function initShardManager(encryptionKey) {
|
|
223
217
|
_encryptionKey = encryptionKey;
|
|
@@ -256,7 +250,6 @@ function shardExists(projectName) {
|
|
|
256
250
|
}
|
|
257
251
|
function listShards() {
|
|
258
252
|
if (!existsSync3(SHARDS_DIR)) return [];
|
|
259
|
-
const { readdirSync } = __require("fs");
|
|
260
253
|
return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
261
254
|
}
|
|
262
255
|
async function ensureShardSchema(client) {
|
|
@@ -535,6 +528,7 @@ async function ensureSchema() {
|
|
|
535
528
|
const client = getRawClient();
|
|
536
529
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
537
530
|
await client.execute("PRAGMA busy_timeout = 30000");
|
|
531
|
+
await client.execute("PRAGMA wal_autocheckpoint = 1000");
|
|
538
532
|
try {
|
|
539
533
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
540
534
|
} catch {
|
|
@@ -1336,11 +1330,12 @@ async function disposeDatabase() {
|
|
|
1336
1330
|
import { readFile, writeFile, unlink, mkdir, chmod } from "fs/promises";
|
|
1337
1331
|
import { existsSync } from "fs";
|
|
1338
1332
|
import path from "path";
|
|
1333
|
+
import os from "os";
|
|
1339
1334
|
import crypto from "crypto";
|
|
1340
1335
|
var SERVICE = "exe-mem";
|
|
1341
1336
|
var ACCOUNT = "master-key";
|
|
1342
1337
|
function getKeyDir() {
|
|
1343
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(
|
|
1338
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(os.homedir(), ".exe-os");
|
|
1344
1339
|
}
|
|
1345
1340
|
function getKeyPath() {
|
|
1346
1341
|
return path.join(getKeyDir(), "master.key");
|
|
@@ -1377,6 +1372,30 @@ async function getMasterKey() {
|
|
|
1377
1372
|
|
|
1378
1373
|
// src/lib/store.ts
|
|
1379
1374
|
init_config();
|
|
1375
|
+
var INIT_MAX_RETRIES = 3;
|
|
1376
|
+
var INIT_RETRY_DELAY_MS = 1e3;
|
|
1377
|
+
function isBusyError2(err) {
|
|
1378
|
+
if (err instanceof Error) {
|
|
1379
|
+
const msg = err.message.toLowerCase();
|
|
1380
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
1381
|
+
}
|
|
1382
|
+
return false;
|
|
1383
|
+
}
|
|
1384
|
+
async function retryOnBusy2(fn, label) {
|
|
1385
|
+
for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
|
|
1386
|
+
try {
|
|
1387
|
+
return await fn();
|
|
1388
|
+
} catch (err) {
|
|
1389
|
+
if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
|
|
1390
|
+
process.stderr.write(
|
|
1391
|
+
`[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
|
|
1392
|
+
`
|
|
1393
|
+
);
|
|
1394
|
+
await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
throw new Error("unreachable");
|
|
1398
|
+
}
|
|
1380
1399
|
var _pendingRecords = [];
|
|
1381
1400
|
var _batchSize = 20;
|
|
1382
1401
|
var _flushIntervalMs = 1e4;
|
|
@@ -1411,14 +1430,17 @@ async function initStore(options) {
|
|
|
1411
1430
|
dbPath,
|
|
1412
1431
|
encryptionKey: hexKey
|
|
1413
1432
|
});
|
|
1414
|
-
await ensureSchema();
|
|
1433
|
+
await retryOnBusy2(() => ensureSchema(), "ensureSchema");
|
|
1415
1434
|
try {
|
|
1416
1435
|
const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
1417
1436
|
initShardManager2(hexKey);
|
|
1418
1437
|
} catch {
|
|
1419
1438
|
}
|
|
1420
1439
|
const client = getClient();
|
|
1421
|
-
const vResult = await
|
|
1440
|
+
const vResult = await retryOnBusy2(
|
|
1441
|
+
() => client.execute("SELECT MAX(version) as max_v FROM memories"),
|
|
1442
|
+
"version-query"
|
|
1443
|
+
);
|
|
1422
1444
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
1423
1445
|
}
|
|
1424
1446
|
function classifyTier(record) {
|
|
@@ -1461,6 +1483,12 @@ async function writeMemory(record) {
|
|
|
1461
1483
|
supersedes_id: record.supersedes_id ?? null
|
|
1462
1484
|
};
|
|
1463
1485
|
_pendingRecords.push(dbRow);
|
|
1486
|
+
const MAX_PENDING = 1e3;
|
|
1487
|
+
if (_pendingRecords.length > MAX_PENDING) {
|
|
1488
|
+
const dropped = _pendingRecords.length - MAX_PENDING;
|
|
1489
|
+
_pendingRecords = _pendingRecords.slice(-MAX_PENDING);
|
|
1490
|
+
console.warn(`[store] Dropped ${dropped} oldest pending records (overflow)`);
|
|
1491
|
+
}
|
|
1464
1492
|
if (_flushTimer === null) {
|
|
1465
1493
|
_flushTimer = setInterval(() => {
|
|
1466
1494
|
void flushBatch();
|
package/dist/lib/tasks.js
CHANGED
|
@@ -44,7 +44,7 @@ var init_database = __esm({
|
|
|
44
44
|
});
|
|
45
45
|
|
|
46
46
|
// src/lib/config.ts
|
|
47
|
-
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
47
|
+
import { readFile, writeFile, mkdir, chmod } from "fs/promises";
|
|
48
48
|
import { readFileSync, existsSync, renameSync } from "fs";
|
|
49
49
|
import path from "path";
|
|
50
50
|
import os from "os";
|
package/dist/lib/tmux-routing.js
CHANGED
|
@@ -342,7 +342,7 @@ var init_database = __esm({
|
|
|
342
342
|
});
|
|
343
343
|
|
|
344
344
|
// src/lib/config.ts
|
|
345
|
-
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
345
|
+
import { readFile, writeFile, mkdir, chmod } from "fs/promises";
|
|
346
346
|
import { readFileSync as readFileSync3, existsSync as existsSync3, renameSync as renameSync2 } from "fs";
|
|
347
347
|
import path3 from "path";
|
|
348
348
|
import os3 from "os";
|