@askexenow/exe-os 0.8.37 → 0.8.38
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 +66 -60
- package/dist/bin/backfill-responses.js +7 -8
- package/dist/bin/backfill-vectors.js +1 -8
- package/dist/bin/cleanup-stale-review-tasks.js +1 -8
- package/dist/bin/cli.js +520 -325
- package/dist/bin/exe-assign.js +7 -8
- package/dist/bin/exe-boot.js +54 -21
- package/dist/bin/exe-call.js +9 -4
- package/dist/bin/exe-cloud.js +37 -3
- package/dist/bin/exe-doctor.js +1 -8
- package/dist/bin/exe-export-behaviors.js +4 -11
- package/dist/bin/exe-forget.js +1 -8
- package/dist/bin/exe-gateway.js +72 -30
- package/dist/bin/exe-heartbeat.js +4 -11
- package/dist/bin/exe-kill.js +1 -8
- package/dist/bin/exe-launch-agent.js +51 -14
- package/dist/bin/exe-link.js +13 -3
- package/dist/bin/exe-new-employee.js +35 -10
- package/dist/bin/exe-pending-messages.js +1 -8
- package/dist/bin/exe-pending-notifications.js +1 -8
- package/dist/bin/exe-pending-reviews.js +4 -11
- package/dist/bin/exe-review.js +7 -8
- package/dist/bin/exe-search.js +10 -11
- package/dist/bin/exe-session-cleanup.js +11 -12
- package/dist/bin/exe-status.js +1 -8
- package/dist/bin/exe-team.js +1 -8
- package/dist/bin/git-sweep.js +7 -8
- package/dist/bin/graph-backfill.js +1 -8
- package/dist/bin/graph-export.js +1 -8
- package/dist/bin/install.js +9 -0
- package/dist/bin/scan-tasks.js +7 -8
- package/dist/bin/setup.js +396 -245
- package/dist/bin/shard-migrate.js +1 -8
- package/dist/bin/wiki-sync.js +1 -8
- package/dist/gateway/index.js +30 -30
- package/dist/hooks/bug-report-worker.js +4 -11
- package/dist/hooks/commit-complete.js +7 -8
- package/dist/hooks/error-recall.js +11 -12
- package/dist/hooks/ingest-worker.js +24 -9
- package/dist/hooks/instructions-loaded.js +7 -8
- package/dist/hooks/notification.js +7 -8
- package/dist/hooks/post-compact.js +7 -8
- package/dist/hooks/pre-compact.js +7 -8
- package/dist/hooks/pre-tool-use.js +7 -8
- package/dist/hooks/prompt-ingest-worker.js +19 -4
- package/dist/hooks/prompt-submit.js +14 -9
- package/dist/hooks/response-ingest-worker.js +20 -5
- package/dist/hooks/session-end.js +11 -12
- package/dist/hooks/session-start.js +11 -12
- package/dist/hooks/stop.js +7 -8
- package/dist/hooks/subagent-stop.js +7 -8
- package/dist/hooks/summary-worker.js +24 -9
- package/dist/index.js +11 -5
- package/dist/lib/cloud-sync.js +19 -2
- package/dist/lib/employee-templates.js +5 -0
- package/dist/lib/exe-daemon.js +24 -8
- package/dist/lib/hybrid-search.js +10 -11
- package/dist/lib/identity-templates.js +16 -7
- package/dist/lib/license.js +43 -2
- package/dist/lib/schedules.js +1 -8
- package/dist/lib/store.js +7 -8
- package/dist/mcp/server.js +184 -113
- package/dist/mcp/tools/list-tasks.js +35 -27
- package/dist/runtime/index.js +7 -2
- package/dist/tui/App.js +44 -5
- package/package.json +4 -2
package/dist/lib/cloud-sync.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/cloud-sync.ts
|
|
2
9
|
import { readFileSync as readFileSync5, writeFileSync as writeFileSync2, existsSync as existsSync5, readdirSync, mkdirSync as mkdirSync2, appendFileSync } from "fs";
|
|
3
10
|
import path5 from "path";
|
|
@@ -351,14 +358,24 @@ async function validateLicense(apiKey, deviceId) {
|
|
|
351
358
|
} catch {
|
|
352
359
|
const cached = await getCachedLicense();
|
|
353
360
|
if (cached) return cached;
|
|
354
|
-
return FREE_LICENSE;
|
|
361
|
+
return { ...FREE_LICENSE, valid: false, error: "offline" };
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
var CACHE_MAX_AGE_MS = 36e5;
|
|
365
|
+
function getCacheAgeMs() {
|
|
366
|
+
try {
|
|
367
|
+
const { statSync } = __require("fs");
|
|
368
|
+
const s = statSync(CACHE_PATH);
|
|
369
|
+
return Date.now() - s.mtimeMs;
|
|
370
|
+
} catch {
|
|
371
|
+
return Infinity;
|
|
355
372
|
}
|
|
356
373
|
}
|
|
357
374
|
async function checkLicense() {
|
|
358
375
|
const key = loadLicense();
|
|
359
376
|
if (!key) return FREE_LICENSE;
|
|
360
377
|
const cached = await getCachedLicense();
|
|
361
|
-
if (cached) return cached;
|
|
378
|
+
if (cached && getCacheAgeMs() < CACHE_MAX_AGE_MS) return cached;
|
|
362
379
|
const deviceId = loadDeviceId();
|
|
363
380
|
return validateLicense(key, deviceId);
|
|
364
381
|
}
|
|
@@ -467,6 +467,10 @@ function buildCustomEmployeePrompt(name, role) {
|
|
|
467
467
|
function getTemplate(name) {
|
|
468
468
|
return TEMPLATES[name];
|
|
469
469
|
}
|
|
470
|
+
function getTemplateByRole(role) {
|
|
471
|
+
const lower = role.toLowerCase();
|
|
472
|
+
return Object.values(TEMPLATES).find((t) => t.role.toLowerCase() === lower);
|
|
473
|
+
}
|
|
470
474
|
function personalizePrompt(prompt, templateName, actualName) {
|
|
471
475
|
if (templateName === actualName) return prompt;
|
|
472
476
|
const escaped = templateName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -597,6 +601,7 @@ export {
|
|
|
597
601
|
buildCustomEmployeePrompt,
|
|
598
602
|
getSessionPrompt,
|
|
599
603
|
getTemplate,
|
|
604
|
+
getTemplateByRole,
|
|
600
605
|
personalizePrompt,
|
|
601
606
|
renderClientCOOTemplate
|
|
602
607
|
};
|
package/dist/lib/exe-daemon.js
CHANGED
|
@@ -1346,7 +1346,7 @@ __export(shard_manager_exports, {
|
|
|
1346
1346
|
shardExists: () => shardExists
|
|
1347
1347
|
});
|
|
1348
1348
|
import path3 from "path";
|
|
1349
|
-
import { existsSync as existsSync3, mkdirSync } from "fs";
|
|
1349
|
+
import { existsSync as existsSync3, mkdirSync, readdirSync } from "fs";
|
|
1350
1350
|
import { createClient as createClient2 } from "@libsql/client";
|
|
1351
1351
|
function initShardManager(encryptionKey) {
|
|
1352
1352
|
_encryptionKey = encryptionKey;
|
|
@@ -1385,8 +1385,7 @@ function shardExists(projectName) {
|
|
|
1385
1385
|
}
|
|
1386
1386
|
function listShards() {
|
|
1387
1387
|
if (!existsSync3(SHARDS_DIR)) return [];
|
|
1388
|
-
|
|
1389
|
-
return readdirSync3(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
1388
|
+
return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
1390
1389
|
}
|
|
1391
1390
|
async function ensureShardSchema(client) {
|
|
1392
1391
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
@@ -1669,6 +1668,12 @@ async function writeMemory(record) {
|
|
|
1669
1668
|
supersedes_id: record.supersedes_id ?? null
|
|
1670
1669
|
};
|
|
1671
1670
|
_pendingRecords.push(dbRow);
|
|
1671
|
+
const MAX_PENDING = 1e3;
|
|
1672
|
+
if (_pendingRecords.length > MAX_PENDING) {
|
|
1673
|
+
const dropped = _pendingRecords.length - MAX_PENDING;
|
|
1674
|
+
_pendingRecords = _pendingRecords.slice(-MAX_PENDING);
|
|
1675
|
+
console.warn(`[store] Dropped ${dropped} oldest pending records (overflow)`);
|
|
1676
|
+
}
|
|
1672
1677
|
if (_flushTimer === null) {
|
|
1673
1678
|
_flushTimer = setInterval(() => {
|
|
1674
1679
|
void flushBatch();
|
|
@@ -2566,7 +2571,7 @@ import path9 from "path";
|
|
|
2566
2571
|
import os4 from "os";
|
|
2567
2572
|
import {
|
|
2568
2573
|
readFileSync as readFileSync7,
|
|
2569
|
-
readdirSync,
|
|
2574
|
+
readdirSync as readdirSync2,
|
|
2570
2575
|
unlinkSync,
|
|
2571
2576
|
existsSync as existsSync9,
|
|
2572
2577
|
rmdirSync
|
|
@@ -3128,7 +3133,7 @@ __export(tasks_review_exports, {
|
|
|
3128
3133
|
listPendingReviews: () => listPendingReviews
|
|
3129
3134
|
});
|
|
3130
3135
|
import path11 from "path";
|
|
3131
|
-
import { existsSync as existsSync11, readdirSync as
|
|
3136
|
+
import { existsSync as existsSync11, readdirSync as readdirSync3, unlinkSync as unlinkSync2 } from "fs";
|
|
3132
3137
|
async function countPendingReviews() {
|
|
3133
3138
|
const client = getClient();
|
|
3134
3139
|
const result = await client.execute({
|
|
@@ -3340,7 +3345,7 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
|
|
|
3340
3345
|
try {
|
|
3341
3346
|
const cacheDir = path11.join(EXE_AI_DIR, "session-cache");
|
|
3342
3347
|
if (existsSync11(cacheDir)) {
|
|
3343
|
-
for (const f of
|
|
3348
|
+
for (const f of readdirSync3(cacheDir)) {
|
|
3344
3349
|
if (f.startsWith("review-notified-")) {
|
|
3345
3350
|
unlinkSync2(path11.join(cacheDir, f));
|
|
3346
3351
|
}
|
|
@@ -7952,13 +7957,24 @@ var REVIEW_POLL_INTERVAL_MS = 60 * 1e3;
|
|
|
7952
7957
|
var _context = null;
|
|
7953
7958
|
var _model = null;
|
|
7954
7959
|
var _llama = null;
|
|
7960
|
+
var MAX_QUEUE_SIZE = 1e3;
|
|
7955
7961
|
var highQueue = [];
|
|
7956
7962
|
var lowQueue = [];
|
|
7957
7963
|
var _processing = false;
|
|
7958
7964
|
var _activeConnections = 0;
|
|
7959
7965
|
var _idleTimer = null;
|
|
7960
7966
|
var _requestsServed = 0;
|
|
7967
|
+
var _droppedRequests = 0;
|
|
7961
7968
|
var _startedAt = Date.now();
|
|
7969
|
+
function enqueue(queue, entry) {
|
|
7970
|
+
if (queue.length >= MAX_QUEUE_SIZE) {
|
|
7971
|
+
queue.shift();
|
|
7972
|
+
_droppedRequests++;
|
|
7973
|
+
process.stderr.write(`[exed] Queue overflow \u2014 dropped oldest request (total dropped: ${_droppedRequests})
|
|
7974
|
+
`);
|
|
7975
|
+
}
|
|
7976
|
+
queue.push(entry);
|
|
7977
|
+
}
|
|
7962
7978
|
async function loadModel() {
|
|
7963
7979
|
const modelPath = path20.join(MODELS_DIR, MODEL_FILE);
|
|
7964
7980
|
if (!existsSync16(modelPath)) {
|
|
@@ -8125,9 +8141,9 @@ function startServer() {
|
|
|
8125
8141
|
}
|
|
8126
8142
|
const entry = { request, socket };
|
|
8127
8143
|
if (request.priority === "high") {
|
|
8128
|
-
highQueue
|
|
8144
|
+
enqueue(highQueue, entry);
|
|
8129
8145
|
} else {
|
|
8130
|
-
lowQueue
|
|
8146
|
+
enqueue(lowQueue, entry);
|
|
8131
8147
|
}
|
|
8132
8148
|
void processQueue();
|
|
8133
8149
|
} catch (err) {
|
|
@@ -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
|
};
|
|
@@ -1224,7 +1218,7 @@ __export(shard_manager_exports, {
|
|
|
1224
1218
|
shardExists: () => shardExists
|
|
1225
1219
|
});
|
|
1226
1220
|
import path3 from "path";
|
|
1227
|
-
import { existsSync as existsSync3, mkdirSync } from "fs";
|
|
1221
|
+
import { existsSync as existsSync3, mkdirSync, readdirSync } from "fs";
|
|
1228
1222
|
import { createClient as createClient2 } from "@libsql/client";
|
|
1229
1223
|
function initShardManager(encryptionKey) {
|
|
1230
1224
|
_encryptionKey = encryptionKey;
|
|
@@ -1263,8 +1257,7 @@ function shardExists(projectName) {
|
|
|
1263
1257
|
}
|
|
1264
1258
|
function listShards() {
|
|
1265
1259
|
if (!existsSync3(SHARDS_DIR)) return [];
|
|
1266
|
-
|
|
1267
|
-
return readdirSync2(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
1260
|
+
return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
1268
1261
|
}
|
|
1269
1262
|
async function ensureShardSchema(client) {
|
|
1270
1263
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
@@ -1547,6 +1540,12 @@ async function writeMemory(record) {
|
|
|
1547
1540
|
supersedes_id: record.supersedes_id ?? null
|
|
1548
1541
|
};
|
|
1549
1542
|
_pendingRecords.push(dbRow);
|
|
1543
|
+
const MAX_PENDING = 1e3;
|
|
1544
|
+
if (_pendingRecords.length > MAX_PENDING) {
|
|
1545
|
+
const dropped = _pendingRecords.length - MAX_PENDING;
|
|
1546
|
+
_pendingRecords = _pendingRecords.slice(-MAX_PENDING);
|
|
1547
|
+
console.warn(`[store] Dropped ${dropped} oldest pending records (overflow)`);
|
|
1548
|
+
}
|
|
1550
1549
|
if (_flushTimer === null) {
|
|
1551
1550
|
_flushTimer = setInterval(() => {
|
|
1552
1551
|
void flushBatch();
|
|
@@ -2445,7 +2444,7 @@ __export(file_grep_exports, {
|
|
|
2445
2444
|
grepProjectFiles: () => grepProjectFiles
|
|
2446
2445
|
});
|
|
2447
2446
|
import { execSync as execSync2 } from "child_process";
|
|
2448
|
-
import { readFileSync as readFileSync3, readdirSync, statSync as statSync2, existsSync as existsSync5 } from "fs";
|
|
2447
|
+
import { readFileSync as readFileSync3, readdirSync as readdirSync2, statSync as statSync2, existsSync as existsSync5 } from "fs";
|
|
2449
2448
|
import path6 from "path";
|
|
2450
2449
|
import crypto2 from "crypto";
|
|
2451
2450
|
function hasRipgrep() {
|
|
@@ -2590,7 +2589,7 @@ function collectFiles(root, patterns) {
|
|
|
2590
2589
|
const basename = path6.basename(dir);
|
|
2591
2590
|
if (EXCLUDE_DIRS.includes(basename)) return;
|
|
2592
2591
|
try {
|
|
2593
|
-
const entries =
|
|
2592
|
+
const entries = readdirSync2(dir, { withFileTypes: true });
|
|
2594
2593
|
for (const entry of entries) {
|
|
2595
2594
|
if (files.length >= MAX_FILES) return;
|
|
2596
2595
|
const rel = path6.join(relative, entry.name);
|
|
@@ -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/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";
|
|
@@ -239,14 +246,24 @@ async function validateLicense(apiKey, deviceId) {
|
|
|
239
246
|
} catch {
|
|
240
247
|
const cached = await getCachedLicense();
|
|
241
248
|
if (cached) return cached;
|
|
242
|
-
return FREE_LICENSE;
|
|
249
|
+
return { ...FREE_LICENSE, valid: false, error: "offline" };
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
var CACHE_MAX_AGE_MS = 36e5;
|
|
253
|
+
function getCacheAgeMs() {
|
|
254
|
+
try {
|
|
255
|
+
const { statSync } = __require("fs");
|
|
256
|
+
const s = statSync(CACHE_PATH);
|
|
257
|
+
return Date.now() - s.mtimeMs;
|
|
258
|
+
} catch {
|
|
259
|
+
return Infinity;
|
|
243
260
|
}
|
|
244
261
|
}
|
|
245
262
|
async function checkLicense() {
|
|
246
263
|
const key = loadLicense();
|
|
247
264
|
if (!key) return FREE_LICENSE;
|
|
248
265
|
const cached = await getCachedLicense();
|
|
249
|
-
if (cached) return cached;
|
|
266
|
+
if (cached && getCacheAgeMs() < CACHE_MAX_AGE_MS) return cached;
|
|
250
267
|
const deviceId = loadDeviceId();
|
|
251
268
|
return validateLicense(key, deviceId);
|
|
252
269
|
}
|
|
@@ -367,6 +384,28 @@ async function assertVpsLicense(opts) {
|
|
|
367
384
|
`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
385
|
);
|
|
369
386
|
}
|
|
387
|
+
var _revalTimer = null;
|
|
388
|
+
function startLicenseRevalidation(intervalMs = 36e5) {
|
|
389
|
+
if (_revalTimer) return;
|
|
390
|
+
_revalTimer = setInterval(async () => {
|
|
391
|
+
try {
|
|
392
|
+
const license = await checkLicense();
|
|
393
|
+
if (!license.valid) {
|
|
394
|
+
process.stderr.write("[exe-os] License expired or invalid \u2014 features may be restricted\n");
|
|
395
|
+
}
|
|
396
|
+
} catch {
|
|
397
|
+
}
|
|
398
|
+
}, intervalMs);
|
|
399
|
+
if (_revalTimer && typeof _revalTimer === "object" && "unref" in _revalTimer) {
|
|
400
|
+
_revalTimer.unref();
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
function stopLicenseRevalidation() {
|
|
404
|
+
if (_revalTimer) {
|
|
405
|
+
clearInterval(_revalTimer);
|
|
406
|
+
_revalTimer = null;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
370
409
|
export {
|
|
371
410
|
LICENSE_PUBLIC_KEY_PEM,
|
|
372
411
|
PLAN_LIMITS,
|
|
@@ -378,5 +417,7 @@ export {
|
|
|
378
417
|
loadLicense,
|
|
379
418
|
mirrorLicenseKey,
|
|
380
419
|
saveLicense,
|
|
420
|
+
startLicenseRevalidation,
|
|
421
|
+
stopLicenseRevalidation,
|
|
381
422
|
validateLicense
|
|
382
423
|
};
|
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
|
};
|
|
@@ -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) {
|
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
|
};
|
|
@@ -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) {
|
|
@@ -1461,6 +1454,12 @@ async function writeMemory(record) {
|
|
|
1461
1454
|
supersedes_id: record.supersedes_id ?? null
|
|
1462
1455
|
};
|
|
1463
1456
|
_pendingRecords.push(dbRow);
|
|
1457
|
+
const MAX_PENDING = 1e3;
|
|
1458
|
+
if (_pendingRecords.length > MAX_PENDING) {
|
|
1459
|
+
const dropped = _pendingRecords.length - MAX_PENDING;
|
|
1460
|
+
_pendingRecords = _pendingRecords.slice(-MAX_PENDING);
|
|
1461
|
+
console.warn(`[store] Dropped ${dropped} oldest pending records (overflow)`);
|
|
1462
|
+
}
|
|
1464
1463
|
if (_flushTimer === null) {
|
|
1465
1464
|
_flushTimer = setInterval(() => {
|
|
1466
1465
|
void flushBatch();
|