@askexenow/exe-os 0.9.7 → 0.9.9
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 +953 -105
- package/dist/bin/backfill-responses.js +952 -104
- package/dist/bin/backfill-vectors.js +956 -108
- package/dist/bin/cleanup-stale-review-tasks.js +802 -58
- package/dist/bin/cli.js +2292 -1070
- package/dist/bin/exe-agent-config.js +157 -101
- package/dist/bin/exe-agent.js +55 -29
- package/dist/bin/exe-assign.js +940 -92
- package/dist/bin/exe-boot.js +1424 -442
- package/dist/bin/exe-call.js +240 -141
- package/dist/bin/exe-cloud.js +198 -70
- package/dist/bin/exe-dispatch.js +951 -192
- package/dist/bin/exe-doctor.js +791 -51
- package/dist/bin/exe-export-behaviors.js +790 -42
- package/dist/bin/exe-forget.js +771 -31
- package/dist/bin/exe-gateway.js +1592 -521
- package/dist/bin/exe-heartbeat.js +850 -109
- package/dist/bin/exe-kill.js +783 -35
- package/dist/bin/exe-launch-agent.js +1030 -107
- package/dist/bin/exe-link.js +916 -110
- package/dist/bin/exe-new-employee.js +526 -217
- package/dist/bin/exe-pending-messages.js +1046 -62
- package/dist/bin/exe-pending-notifications.js +1318 -111
- package/dist/bin/exe-pending-reviews.js +1040 -72
- package/dist/bin/exe-rename.js +772 -59
- package/dist/bin/exe-review.js +772 -32
- package/dist/bin/exe-search.js +982 -128
- package/dist/bin/exe-session-cleanup.js +1180 -306
- package/dist/bin/exe-settings.js +185 -105
- package/dist/bin/exe-start-codex.js +886 -132
- package/dist/bin/exe-start-opencode.js +873 -119
- package/dist/bin/exe-status.js +803 -59
- package/dist/bin/exe-team.js +772 -32
- package/dist/bin/git-sweep.js +1046 -223
- package/dist/bin/graph-backfill.js +779 -31
- package/dist/bin/graph-export.js +785 -37
- package/dist/bin/install.js +632 -200
- package/dist/bin/scan-tasks.js +1055 -232
- package/dist/bin/setup.js +1419 -320
- package/dist/bin/shard-migrate.js +783 -35
- package/dist/bin/update.js +138 -49
- package/dist/bin/wiki-sync.js +782 -34
- package/dist/gateway/index.js +1444 -449
- package/dist/hooks/bug-report-worker.js +1141 -269
- package/dist/hooks/codex-stop-task-finalizer.js +4678 -0
- package/dist/hooks/commit-complete.js +1044 -221
- package/dist/hooks/error-recall.js +989 -135
- package/dist/hooks/exe-heartbeat-hook.js +99 -75
- package/dist/hooks/ingest-worker.js +4176 -3226
- package/dist/hooks/ingest.js +920 -168
- package/dist/hooks/instructions-loaded.js +874 -70
- package/dist/hooks/notification.js +860 -56
- package/dist/hooks/post-compact.js +881 -73
- package/dist/hooks/pre-compact.js +1050 -227
- package/dist/hooks/pre-tool-use.js +1084 -159
- package/dist/hooks/prompt-ingest-worker.js +1089 -164
- package/dist/hooks/prompt-submit.js +1469 -515
- package/dist/hooks/response-ingest-worker.js +1104 -179
- package/dist/hooks/session-end.js +1085 -251
- package/dist/hooks/session-start.js +1241 -231
- package/dist/hooks/stop.js +935 -109
- package/dist/hooks/subagent-stop.js +881 -73
- package/dist/hooks/summary-worker.js +1323 -307
- package/dist/index.js +1449 -452
- package/dist/lib/agent-config.js +28 -6
- package/dist/lib/cloud-sync.js +909 -115
- package/dist/lib/config.js +30 -10
- package/dist/lib/consolidation.js +42 -9
- package/dist/lib/database.js +739 -33
- package/dist/lib/db-daemon-client.js +73 -19
- package/dist/lib/db.js +2359 -0
- package/dist/lib/device-registry.js +760 -47
- package/dist/lib/embedder.js +201 -73
- package/dist/lib/employee-templates.js +30 -4
- package/dist/lib/employees.js +290 -86
- package/dist/lib/exe-daemon-client.js +187 -83
- package/dist/lib/exe-daemon.js +1696 -616
- package/dist/lib/hybrid-search.js +982 -128
- package/dist/lib/identity.js +43 -13
- package/dist/lib/license.js +133 -48
- package/dist/lib/messaging.js +167 -80
- package/dist/lib/reminders.js +35 -5
- package/dist/lib/schedules.js +772 -32
- package/dist/lib/skill-learning.js +54 -7
- package/dist/lib/store.js +779 -31
- package/dist/lib/task-router.js +94 -73
- package/dist/lib/tasks.js +298 -225
- package/dist/lib/tmux-routing.js +246 -172
- package/dist/lib/token-spend.js +52 -14
- package/dist/mcp/server.js +2893 -850
- package/dist/mcp/tools/complete-reminder.js +35 -5
- package/dist/mcp/tools/create-reminder.js +35 -5
- package/dist/mcp/tools/create-task.js +507 -323
- package/dist/mcp/tools/deactivate-behavior.js +40 -10
- package/dist/mcp/tools/list-reminders.js +35 -5
- package/dist/mcp/tools/list-tasks.js +277 -104
- package/dist/mcp/tools/send-message.js +129 -56
- package/dist/mcp/tools/update-task.js +1864 -188
- package/dist/runtime/index.js +1083 -259
- package/dist/tui/App.js +1501 -434
- package/package.json +3 -2
package/dist/lib/identity.js
CHANGED
|
@@ -3,9 +3,18 @@ var __esm = (fn, res) => function __init() {
|
|
|
3
3
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
4
4
|
};
|
|
5
5
|
|
|
6
|
+
// src/lib/secure-files.ts
|
|
7
|
+
import { chmodSync, existsSync, mkdirSync } from "fs";
|
|
8
|
+
import { chmod, mkdir } from "fs/promises";
|
|
9
|
+
var init_secure_files = __esm({
|
|
10
|
+
"src/lib/secure-files.ts"() {
|
|
11
|
+
"use strict";
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
|
|
6
15
|
// src/lib/config.ts
|
|
7
|
-
import { readFile, writeFile
|
|
8
|
-
import { readFileSync, existsSync, renameSync } from "fs";
|
|
16
|
+
import { readFile, writeFile } from "fs/promises";
|
|
17
|
+
import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
|
|
9
18
|
import path from "path";
|
|
10
19
|
import os from "os";
|
|
11
20
|
function resolveDataDir() {
|
|
@@ -13,7 +22,7 @@ function resolveDataDir() {
|
|
|
13
22
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
14
23
|
const newDir = path.join(os.homedir(), ".exe-os");
|
|
15
24
|
const legacyDir = path.join(os.homedir(), ".exe-mem");
|
|
16
|
-
if (!
|
|
25
|
+
if (!existsSync2(newDir) && existsSync2(legacyDir)) {
|
|
17
26
|
try {
|
|
18
27
|
renameSync(legacyDir, newDir);
|
|
19
28
|
process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
|
|
@@ -28,6 +37,7 @@ var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CON
|
|
|
28
37
|
var init_config = __esm({
|
|
29
38
|
"src/lib/config.ts"() {
|
|
30
39
|
"use strict";
|
|
40
|
+
init_secure_files();
|
|
31
41
|
EXE_AI_DIR = resolveDataDir();
|
|
32
42
|
DB_PATH = path.join(EXE_AI_DIR, "memories.db");
|
|
33
43
|
MODELS_DIR = path.join(EXE_AI_DIR, "models");
|
|
@@ -96,9 +106,9 @@ var init_config = __esm({
|
|
|
96
106
|
|
|
97
107
|
// src/lib/identity.ts
|
|
98
108
|
init_config();
|
|
99
|
-
import { existsSync as
|
|
109
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
100
110
|
import { readdirSync } from "fs";
|
|
101
|
-
import
|
|
111
|
+
import path4 from "path";
|
|
102
112
|
import { createHash } from "crypto";
|
|
103
113
|
|
|
104
114
|
// src/lib/database.ts
|
|
@@ -107,19 +117,39 @@ import { createClient } from "@libsql/client";
|
|
|
107
117
|
// src/lib/employees.ts
|
|
108
118
|
init_config();
|
|
109
119
|
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
110
|
-
import { existsSync as
|
|
120
|
+
import { existsSync as existsSync3, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
|
|
111
121
|
import { execSync } from "child_process";
|
|
112
122
|
import path2 from "path";
|
|
113
123
|
import os2 from "os";
|
|
114
124
|
var EMPLOYEES_PATH = path2.join(EXE_AI_DIR, "exe-employees.json");
|
|
125
|
+
var IDENTITY_DIR = path2.join(EXE_AI_DIR, "identity");
|
|
126
|
+
|
|
127
|
+
// src/lib/database-adapter.ts
|
|
128
|
+
import os3 from "os";
|
|
129
|
+
import path3 from "path";
|
|
130
|
+
import { createRequire } from "module";
|
|
131
|
+
import { pathToFileURL } from "url";
|
|
132
|
+
var BOOLEAN_COLUMNS_BY_TABLE = {
|
|
133
|
+
memories: /* @__PURE__ */ new Set(["has_error", "draft"]),
|
|
134
|
+
behaviors: /* @__PURE__ */ new Set(["active"]),
|
|
135
|
+
notifications: /* @__PURE__ */ new Set(["read"]),
|
|
136
|
+
users: /* @__PURE__ */ new Set(["has_personal_memory"])
|
|
137
|
+
};
|
|
138
|
+
var BOOLEAN_COLUMN_NAMES = new Set(
|
|
139
|
+
Object.values(BOOLEAN_COLUMNS_BY_TABLE).flatMap((cols) => [...cols])
|
|
140
|
+
);
|
|
115
141
|
|
|
116
142
|
// src/lib/database.ts
|
|
117
143
|
var _resilientClient = null;
|
|
118
144
|
var _daemonClient = null;
|
|
145
|
+
var _adapterClient = null;
|
|
119
146
|
function getClient() {
|
|
120
|
-
if (!
|
|
147
|
+
if (!_adapterClient) {
|
|
121
148
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
122
149
|
}
|
|
150
|
+
if (process.env.DATABASE_URL) {
|
|
151
|
+
return _adapterClient;
|
|
152
|
+
}
|
|
123
153
|
if (process.env.EXE_IS_DAEMON === "1") {
|
|
124
154
|
return _resilientClient;
|
|
125
155
|
}
|
|
@@ -130,14 +160,14 @@ function getClient() {
|
|
|
130
160
|
}
|
|
131
161
|
|
|
132
162
|
// src/lib/identity.ts
|
|
133
|
-
var
|
|
163
|
+
var IDENTITY_DIR2 = path4.join(EXE_AI_DIR, "identity");
|
|
134
164
|
function ensureDir() {
|
|
135
|
-
if (!
|
|
136
|
-
|
|
165
|
+
if (!existsSync4(IDENTITY_DIR2)) {
|
|
166
|
+
mkdirSync2(IDENTITY_DIR2, { recursive: true });
|
|
137
167
|
}
|
|
138
168
|
}
|
|
139
169
|
function identityPath(agentId) {
|
|
140
|
-
return
|
|
170
|
+
return path4.join(IDENTITY_DIR2, `${agentId}.md`);
|
|
141
171
|
}
|
|
142
172
|
function parseFrontmatter(raw) {
|
|
143
173
|
const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
@@ -178,7 +208,7 @@ function contentHash(content) {
|
|
|
178
208
|
}
|
|
179
209
|
function getIdentity(agentId) {
|
|
180
210
|
const filePath = identityPath(agentId);
|
|
181
|
-
if (!
|
|
211
|
+
if (!existsSync4(filePath)) return null;
|
|
182
212
|
const raw = readFileSync3(filePath, "utf-8");
|
|
183
213
|
const { frontmatter, body } = parseFrontmatter(raw);
|
|
184
214
|
return {
|
|
@@ -210,7 +240,7 @@ async function updateIdentity(agentId, content, updatedBy) {
|
|
|
210
240
|
}
|
|
211
241
|
function listIdentities() {
|
|
212
242
|
ensureDir();
|
|
213
|
-
const files = readdirSync(
|
|
243
|
+
const files = readdirSync(IDENTITY_DIR2).filter((f) => f.endsWith(".md"));
|
|
214
244
|
const results = [];
|
|
215
245
|
for (const file of files) {
|
|
216
246
|
const agentId = file.replace(".md", "");
|
package/dist/lib/license.js
CHANGED
|
@@ -6,22 +6,31 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
6
6
|
});
|
|
7
7
|
|
|
8
8
|
// src/lib/license.ts
|
|
9
|
-
import { readFileSync as readFileSync2, writeFileSync, existsSync as
|
|
9
|
+
import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync3, mkdirSync as mkdirSync2 } from "fs";
|
|
10
10
|
import { randomUUID } from "crypto";
|
|
11
|
+
import { createRequire } from "module";
|
|
12
|
+
import { pathToFileURL } from "url";
|
|
13
|
+
import os2 from "os";
|
|
11
14
|
import path2 from "path";
|
|
12
15
|
import { jwtVerify, importSPKI } from "jose";
|
|
13
16
|
|
|
14
17
|
// src/lib/config.ts
|
|
15
|
-
import { readFile, writeFile
|
|
16
|
-
import { readFileSync, existsSync, renameSync } from "fs";
|
|
18
|
+
import { readFile, writeFile } from "fs/promises";
|
|
19
|
+
import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
|
|
17
20
|
import path from "path";
|
|
18
21
|
import os from "os";
|
|
22
|
+
|
|
23
|
+
// src/lib/secure-files.ts
|
|
24
|
+
import { chmodSync, existsSync, mkdirSync } from "fs";
|
|
25
|
+
import { chmod, mkdir } from "fs/promises";
|
|
26
|
+
|
|
27
|
+
// src/lib/config.ts
|
|
19
28
|
function resolveDataDir() {
|
|
20
29
|
if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
|
|
21
30
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
22
31
|
const newDir = path.join(os.homedir(), ".exe-os");
|
|
23
32
|
const legacyDir = path.join(os.homedir(), ".exe-mem");
|
|
24
|
-
if (!
|
|
33
|
+
if (!existsSync2(newDir) && existsSync2(legacyDir)) {
|
|
25
34
|
try {
|
|
26
35
|
renameSync(legacyDir, newDir);
|
|
27
36
|
process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
|
|
@@ -134,34 +143,34 @@ var FREE_LICENSE = {
|
|
|
134
143
|
function loadDeviceId() {
|
|
135
144
|
const deviceJsonPath = path2.join(EXE_AI_DIR, "device.json");
|
|
136
145
|
try {
|
|
137
|
-
if (
|
|
146
|
+
if (existsSync3(deviceJsonPath)) {
|
|
138
147
|
const data = JSON.parse(readFileSync2(deviceJsonPath, "utf8"));
|
|
139
148
|
if (data.deviceId) return data.deviceId;
|
|
140
149
|
}
|
|
141
150
|
} catch {
|
|
142
151
|
}
|
|
143
152
|
try {
|
|
144
|
-
if (
|
|
153
|
+
if (existsSync3(DEVICE_ID_PATH)) {
|
|
145
154
|
const id2 = readFileSync2(DEVICE_ID_PATH, "utf8").trim();
|
|
146
155
|
if (id2) return id2;
|
|
147
156
|
}
|
|
148
157
|
} catch {
|
|
149
158
|
}
|
|
150
159
|
const id = randomUUID();
|
|
151
|
-
|
|
160
|
+
mkdirSync2(EXE_AI_DIR, { recursive: true });
|
|
152
161
|
writeFileSync(DEVICE_ID_PATH, id, "utf8");
|
|
153
162
|
return id;
|
|
154
163
|
}
|
|
155
164
|
function loadLicense() {
|
|
156
165
|
try {
|
|
157
|
-
if (!
|
|
166
|
+
if (!existsSync3(LICENSE_PATH)) return null;
|
|
158
167
|
return readFileSync2(LICENSE_PATH, "utf8").trim();
|
|
159
168
|
} catch {
|
|
160
169
|
return null;
|
|
161
170
|
}
|
|
162
171
|
}
|
|
163
172
|
function saveLicense(apiKey) {
|
|
164
|
-
|
|
173
|
+
mkdirSync2(EXE_AI_DIR, { recursive: true });
|
|
165
174
|
writeFileSync(LICENSE_PATH, apiKey.trim(), { encoding: "utf8", mode: 384 });
|
|
166
175
|
}
|
|
167
176
|
async function verifyLicenseJwt(token) {
|
|
@@ -188,7 +197,7 @@ async function verifyLicenseJwt(token) {
|
|
|
188
197
|
}
|
|
189
198
|
async function getCachedLicense() {
|
|
190
199
|
try {
|
|
191
|
-
if (!
|
|
200
|
+
if (!existsSync3(CACHE_PATH)) return null;
|
|
192
201
|
const raw = JSON.parse(readFileSync2(CACHE_PATH, "utf8"));
|
|
193
202
|
if (!raw.token || typeof raw.token !== "string") return null;
|
|
194
203
|
return await verifyLicenseJwt(raw.token);
|
|
@@ -198,7 +207,7 @@ async function getCachedLicense() {
|
|
|
198
207
|
}
|
|
199
208
|
function readCachedToken() {
|
|
200
209
|
try {
|
|
201
|
-
if (!
|
|
210
|
+
if (!existsSync3(CACHE_PATH)) return null;
|
|
202
211
|
const raw = JSON.parse(readFileSync2(CACHE_PATH, "utf8"));
|
|
203
212
|
return typeof raw.token === "string" ? raw.token : null;
|
|
204
213
|
} catch {
|
|
@@ -237,52 +246,128 @@ function cacheResponse(token) {
|
|
|
237
246
|
} catch {
|
|
238
247
|
}
|
|
239
248
|
}
|
|
240
|
-
|
|
241
|
-
|
|
249
|
+
var _prismaPromise = null;
|
|
250
|
+
var _prismaFailed = false;
|
|
251
|
+
function loadPrismaForLicense() {
|
|
252
|
+
if (_prismaFailed) return null;
|
|
253
|
+
const dbUrl = process.env.DATABASE_URL;
|
|
254
|
+
if (!dbUrl) {
|
|
255
|
+
const exeDbRoot = process.env.EXE_DB_ROOT ?? path2.join(os2.homedir(), "exe-db");
|
|
256
|
+
if (!existsSync3(path2.join(exeDbRoot, "package.json"))) {
|
|
257
|
+
_prismaFailed = true;
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
if (!_prismaPromise) {
|
|
262
|
+
_prismaPromise = (async () => {
|
|
263
|
+
const explicitPath = process.env.EXE_OS_PRISMA_CLIENT_PATH;
|
|
264
|
+
if (explicitPath) {
|
|
265
|
+
const mod2 = await import(pathToFileURL(explicitPath).href);
|
|
266
|
+
const Ctor2 = mod2.PrismaClient ?? mod2.default?.PrismaClient;
|
|
267
|
+
if (!Ctor2) throw new Error(`No PrismaClient at ${explicitPath}`);
|
|
268
|
+
return new Ctor2();
|
|
269
|
+
}
|
|
270
|
+
const exeDbRoot = process.env.EXE_DB_ROOT ?? path2.join(os2.homedir(), "exe-db");
|
|
271
|
+
const req = createRequire(path2.join(exeDbRoot, "package.json"));
|
|
272
|
+
const entry = req.resolve("@prisma/client");
|
|
273
|
+
const mod = await import(pathToFileURL(entry).href);
|
|
274
|
+
const Ctor = mod.PrismaClient ?? mod.default?.PrismaClient;
|
|
275
|
+
if (!Ctor) throw new Error(`No PrismaClient in ${entry}`);
|
|
276
|
+
return new Ctor();
|
|
277
|
+
})().catch((err) => {
|
|
278
|
+
_prismaFailed = true;
|
|
279
|
+
_prismaPromise = null;
|
|
280
|
+
throw err;
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
return _prismaPromise;
|
|
284
|
+
}
|
|
285
|
+
async function validateViaPostgres(apiKey) {
|
|
286
|
+
const loader = loadPrismaForLicense();
|
|
287
|
+
if (!loader) return null;
|
|
288
|
+
try {
|
|
289
|
+
const prisma = await loader;
|
|
290
|
+
const rows = await prisma.$queryRawUnsafe(
|
|
291
|
+
`SELECT plan, email, status, device_limit, employee_limit, memory_limit, expires_at
|
|
292
|
+
FROM billing.licenses WHERE key = $1 LIMIT 1`,
|
|
293
|
+
apiKey
|
|
294
|
+
);
|
|
295
|
+
if (!rows || rows.length === 0) return null;
|
|
296
|
+
const row = rows[0];
|
|
297
|
+
if (row.status !== "active") return null;
|
|
298
|
+
if (row.expires_at && new Date(row.expires_at) < /* @__PURE__ */ new Date()) return null;
|
|
299
|
+
const plan = row.plan;
|
|
300
|
+
const limits = PLAN_LIMITS[plan] ?? PLAN_LIMITS.free;
|
|
301
|
+
return {
|
|
302
|
+
valid: true,
|
|
303
|
+
plan,
|
|
304
|
+
email: row.email,
|
|
305
|
+
expiresAt: row.expires_at ? new Date(row.expires_at).toISOString() : null,
|
|
306
|
+
deviceLimit: row.device_limit ?? limits.devices,
|
|
307
|
+
employeeLimit: row.employee_limit ?? limits.employees,
|
|
308
|
+
memoryLimit: row.memory_limit ?? limits.memories
|
|
309
|
+
};
|
|
310
|
+
} catch {
|
|
311
|
+
return null;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
async function validateViaCFWorker(apiKey, deviceId) {
|
|
242
315
|
try {
|
|
243
316
|
const res = await fetchRetry(`${API_BASE}/auth/activate`, {
|
|
244
317
|
method: "POST",
|
|
245
318
|
headers: { "Content-Type": "application/json" },
|
|
246
|
-
body: JSON.stringify({ apiKey, deviceId
|
|
319
|
+
body: JSON.stringify({ apiKey, deviceId }),
|
|
247
320
|
signal: AbortSignal.timeout(1e4)
|
|
248
321
|
});
|
|
249
|
-
if (res.ok)
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
322
|
+
if (!res.ok) return null;
|
|
323
|
+
const data = await res.json();
|
|
324
|
+
if (data.error === "device_limit_exceeded") return null;
|
|
325
|
+
if (!data.valid) return null;
|
|
326
|
+
if (data.token) {
|
|
327
|
+
cacheResponse(data.token);
|
|
328
|
+
const verified = await verifyLicenseJwt(data.token);
|
|
329
|
+
if (verified) return verified;
|
|
330
|
+
}
|
|
331
|
+
const limits = PLAN_LIMITS[data.plan] ?? PLAN_LIMITS.free;
|
|
332
|
+
return {
|
|
333
|
+
valid: data.valid,
|
|
334
|
+
plan: data.plan,
|
|
335
|
+
email: data.email,
|
|
336
|
+
expiresAt: data.expiresAt,
|
|
337
|
+
deviceLimit: limits.devices,
|
|
338
|
+
employeeLimit: limits.employees,
|
|
339
|
+
memoryLimit: limits.memories
|
|
340
|
+
};
|
|
341
|
+
} catch {
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
async function validateLicense(apiKey, deviceId) {
|
|
346
|
+
const did = deviceId ?? loadDeviceId();
|
|
347
|
+
const pgResult = await validateViaPostgres(apiKey);
|
|
348
|
+
if (pgResult) {
|
|
349
|
+
try {
|
|
350
|
+
writeFileSync(CACHE_PATH, JSON.stringify({ pgLicense: pgResult, ts: Date.now() }), "utf8");
|
|
351
|
+
} catch {
|
|
352
|
+
}
|
|
353
|
+
return pgResult;
|
|
354
|
+
}
|
|
355
|
+
const cfResult = await validateViaCFWorker(apiKey, did);
|
|
356
|
+
if (cfResult) return cfResult;
|
|
357
|
+
const cached = await getCachedLicense();
|
|
358
|
+
if (cached) return cached;
|
|
359
|
+
try {
|
|
360
|
+
if (existsSync3(CACHE_PATH)) {
|
|
361
|
+
const raw = JSON.parse(readFileSync2(CACHE_PATH, "utf8"));
|
|
362
|
+
if (raw.pgLicense && raw.ts && Date.now() - raw.ts < 7 * 24 * 60 * 60 * 1e3) {
|
|
363
|
+
return raw.pgLicense;
|
|
262
364
|
}
|
|
263
|
-
const limits = PLAN_LIMITS[data.plan] ?? PLAN_LIMITS.free;
|
|
264
|
-
return {
|
|
265
|
-
valid: data.valid,
|
|
266
|
-
plan: data.plan,
|
|
267
|
-
email: data.email,
|
|
268
|
-
expiresAt: data.expiresAt,
|
|
269
|
-
deviceLimit: limits.devices,
|
|
270
|
-
employeeLimit: limits.employees,
|
|
271
|
-
memoryLimit: limits.memories
|
|
272
|
-
};
|
|
273
365
|
}
|
|
274
|
-
const cached = await getCachedLicense();
|
|
275
|
-
if (cached) return cached;
|
|
276
|
-
const raw = getRawCachedPlan();
|
|
277
|
-
if (raw) return raw;
|
|
278
|
-
return { ...FREE_LICENSE, valid: false, plan: "free" };
|
|
279
366
|
} catch {
|
|
280
|
-
const cached = await getCachedLicense();
|
|
281
|
-
if (cached) return cached;
|
|
282
|
-
const rawFallback = getRawCachedPlan();
|
|
283
|
-
if (rawFallback) return rawFallback;
|
|
284
|
-
return { ...FREE_LICENSE, valid: false, error: "offline" };
|
|
285
367
|
}
|
|
368
|
+
const rawFallback = getRawCachedPlan();
|
|
369
|
+
if (rawFallback) return rawFallback;
|
|
370
|
+
return { ...FREE_LICENSE, valid: false };
|
|
286
371
|
}
|
|
287
372
|
var CACHE_MAX_AGE_MS = 36e5;
|
|
288
373
|
function getCacheAgeMs() {
|
|
@@ -299,7 +384,7 @@ async function checkLicense() {
|
|
|
299
384
|
if (!key) {
|
|
300
385
|
try {
|
|
301
386
|
const configPath = path2.join(EXE_AI_DIR, "config.json");
|
|
302
|
-
if (
|
|
387
|
+
if (existsSync3(configPath)) {
|
|
303
388
|
const raw = JSON.parse(readFileSync2(configPath, "utf8"));
|
|
304
389
|
const cloud = raw.cloud;
|
|
305
390
|
if (cloud?.apiKey) {
|