@askexenow/exe-os 0.9.8 → 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 +222 -49
- package/dist/bin/backfill-responses.js +221 -48
- package/dist/bin/backfill-vectors.js +225 -52
- package/dist/bin/cleanup-stale-review-tasks.js +150 -28
- package/dist/bin/cli.js +1295 -856
- package/dist/bin/exe-agent-config.js +36 -8
- package/dist/bin/exe-agent.js +14 -4
- package/dist/bin/exe-assign.js +221 -48
- package/dist/bin/exe-boot.js +778 -427
- package/dist/bin/exe-call.js +41 -13
- package/dist/bin/exe-cloud.js +163 -58
- package/dist/bin/exe-dispatch.js +276 -139
- package/dist/bin/exe-doctor.js +145 -27
- package/dist/bin/exe-export-behaviors.js +141 -23
- package/dist/bin/exe-forget.js +137 -19
- package/dist/bin/exe-gateway.js +677 -388
- package/dist/bin/exe-heartbeat.js +227 -108
- package/dist/bin/exe-kill.js +138 -20
- package/dist/bin/exe-launch-agent.js +172 -39
- package/dist/bin/exe-link.js +291 -100
- package/dist/bin/exe-new-employee.js +214 -106
- package/dist/bin/exe-pending-messages.js +395 -33
- package/dist/bin/exe-pending-notifications.js +684 -99
- package/dist/bin/exe-pending-reviews.js +420 -74
- package/dist/bin/exe-rename.js +147 -49
- package/dist/bin/exe-review.js +138 -20
- package/dist/bin/exe-search.js +240 -69
- package/dist/bin/exe-session-cleanup.js +440 -250
- package/dist/bin/exe-settings.js +61 -17
- package/dist/bin/exe-start-codex.js +158 -39
- package/dist/bin/exe-start-opencode.js +157 -38
- package/dist/bin/exe-status.js +151 -29
- package/dist/bin/exe-team.js +138 -20
- package/dist/bin/git-sweep.js +404 -212
- package/dist/bin/graph-backfill.js +137 -19
- package/dist/bin/graph-export.js +140 -22
- package/dist/bin/install.js +90 -61
- package/dist/bin/scan-tasks.js +412 -220
- package/dist/bin/setup.js +564 -293
- package/dist/bin/shard-migrate.js +139 -21
- package/dist/bin/update.js +138 -49
- package/dist/bin/wiki-sync.js +137 -19
- package/dist/gateway/index.js +533 -320
- package/dist/hooks/bug-report-worker.js +344 -193
- package/dist/hooks/codex-stop-task-finalizer.js +4678 -0
- package/dist/hooks/commit-complete.js +402 -210
- package/dist/hooks/error-recall.js +245 -74
- package/dist/hooks/exe-heartbeat-hook.js +16 -6
- package/dist/hooks/ingest-worker.js +3423 -3157
- package/dist/hooks/ingest.js +832 -97
- package/dist/hooks/instructions-loaded.js +227 -54
- package/dist/hooks/notification.js +216 -43
- package/dist/hooks/post-compact.js +239 -62
- package/dist/hooks/pre-compact.js +408 -216
- package/dist/hooks/pre-tool-use.js +268 -90
- package/dist/hooks/prompt-ingest-worker.js +352 -102
- package/dist/hooks/prompt-submit.js +541 -328
- package/dist/hooks/response-ingest-worker.js +372 -122
- package/dist/hooks/session-end.js +443 -240
- package/dist/hooks/session-start.js +313 -127
- package/dist/hooks/stop.js +293 -98
- package/dist/hooks/subagent-stop.js +239 -62
- package/dist/hooks/summary-worker.js +568 -236
- package/dist/index.js +538 -324
- package/dist/lib/agent-config.js +28 -6
- package/dist/lib/cloud-sync.js +284 -105
- package/dist/lib/config.js +30 -10
- package/dist/lib/consolidation.js +16 -6
- package/dist/lib/database.js +123 -25
- package/dist/lib/db-daemon-client.js +73 -19
- package/dist/lib/db.js +123 -25
- package/dist/lib/device-registry.js +133 -35
- package/dist/lib/embedder.js +107 -32
- package/dist/lib/employee-templates.js +14 -4
- package/dist/lib/employees.js +41 -13
- package/dist/lib/exe-daemon-client.js +88 -22
- package/dist/lib/exe-daemon.js +935 -587
- package/dist/lib/hybrid-search.js +240 -69
- package/dist/lib/identity.js +18 -8
- package/dist/lib/license.js +133 -48
- package/dist/lib/messaging.js +116 -56
- package/dist/lib/reminders.js +14 -4
- package/dist/lib/schedules.js +137 -19
- package/dist/lib/skill-learning.js +33 -6
- package/dist/lib/store.js +137 -19
- package/dist/lib/task-router.js +14 -4
- package/dist/lib/tasks.js +280 -234
- package/dist/lib/tmux-routing.js +172 -125
- package/dist/lib/token-spend.js +26 -8
- package/dist/mcp/server.js +1326 -609
- package/dist/mcp/tools/complete-reminder.js +14 -4
- package/dist/mcp/tools/create-reminder.js +14 -4
- package/dist/mcp/tools/create-task.js +306 -248
- package/dist/mcp/tools/deactivate-behavior.js +16 -6
- package/dist/mcp/tools/list-reminders.js +14 -4
- package/dist/mcp/tools/list-tasks.js +123 -107
- package/dist/mcp/tools/send-message.js +75 -29
- package/dist/mcp/tools/update-task.js +1848 -199
- package/dist/runtime/index.js +441 -248
- package/dist/tui/App.js +761 -424
- package/package.json +1 -1
|
@@ -15,9 +15,34 @@ var __export = (target, all) => {
|
|
|
15
15
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
+
// src/lib/secure-files.ts
|
|
19
|
+
import { chmodSync as chmodSync2, existsSync as existsSync2, mkdirSync as mkdirSync2 } from "fs";
|
|
20
|
+
import { chmod, mkdir } from "fs/promises";
|
|
21
|
+
function ensurePrivateDirSync(dirPath) {
|
|
22
|
+
mkdirSync2(dirPath, { recursive: true, mode: PRIVATE_DIR_MODE });
|
|
23
|
+
try {
|
|
24
|
+
chmodSync2(dirPath, PRIVATE_DIR_MODE);
|
|
25
|
+
} catch {
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function enforcePrivateFileSync(filePath) {
|
|
29
|
+
try {
|
|
30
|
+
if (existsSync2(filePath)) chmodSync2(filePath, PRIVATE_FILE_MODE);
|
|
31
|
+
} catch {
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
var PRIVATE_DIR_MODE, PRIVATE_FILE_MODE;
|
|
35
|
+
var init_secure_files = __esm({
|
|
36
|
+
"src/lib/secure-files.ts"() {
|
|
37
|
+
"use strict";
|
|
38
|
+
PRIVATE_DIR_MODE = 448;
|
|
39
|
+
PRIVATE_FILE_MODE = 384;
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
18
43
|
// src/lib/config.ts
|
|
19
|
-
import { readFile, writeFile
|
|
20
|
-
import { readFileSync as readFileSync2, existsSync as
|
|
44
|
+
import { readFile, writeFile } from "fs/promises";
|
|
45
|
+
import { readFileSync as readFileSync2, existsSync as existsSync3, renameSync } from "fs";
|
|
21
46
|
import path2 from "path";
|
|
22
47
|
import os from "os";
|
|
23
48
|
function resolveDataDir() {
|
|
@@ -25,7 +50,7 @@ function resolveDataDir() {
|
|
|
25
50
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
26
51
|
const newDir = path2.join(os.homedir(), ".exe-os");
|
|
27
52
|
const legacyDir = path2.join(os.homedir(), ".exe-mem");
|
|
28
|
-
if (!
|
|
53
|
+
if (!existsSync3(newDir) && existsSync3(legacyDir)) {
|
|
29
54
|
try {
|
|
30
55
|
renameSync(legacyDir, newDir);
|
|
31
56
|
process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
|
|
@@ -40,6 +65,7 @@ var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CON
|
|
|
40
65
|
var init_config = __esm({
|
|
41
66
|
"src/lib/config.ts"() {
|
|
42
67
|
"use strict";
|
|
68
|
+
init_secure_files();
|
|
43
69
|
EXE_AI_DIR = resolveDataDir();
|
|
44
70
|
DB_PATH = path2.join(EXE_AI_DIR, "memories.db");
|
|
45
71
|
MODELS_DIR = path2.join(EXE_AI_DIR, "models");
|
|
@@ -146,10 +172,10 @@ __export(agent_config_exports, {
|
|
|
146
172
|
saveAgentConfig: () => saveAgentConfig,
|
|
147
173
|
setAgentRuntime: () => setAgentRuntime
|
|
148
174
|
});
|
|
149
|
-
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as
|
|
175
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync4 } from "fs";
|
|
150
176
|
import path3 from "path";
|
|
151
177
|
function loadAgentConfig() {
|
|
152
|
-
if (!
|
|
178
|
+
if (!existsSync4(AGENT_CONFIG_PATH)) return {};
|
|
153
179
|
try {
|
|
154
180
|
return JSON.parse(readFileSync3(AGENT_CONFIG_PATH, "utf-8"));
|
|
155
181
|
} catch {
|
|
@@ -158,8 +184,9 @@ function loadAgentConfig() {
|
|
|
158
184
|
}
|
|
159
185
|
function saveAgentConfig(config) {
|
|
160
186
|
const dir = path3.dirname(AGENT_CONFIG_PATH);
|
|
161
|
-
|
|
187
|
+
ensurePrivateDirSync(dir);
|
|
162
188
|
writeFileSync2(AGENT_CONFIG_PATH, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
189
|
+
enforcePrivateFileSync(AGENT_CONFIG_PATH);
|
|
163
190
|
}
|
|
164
191
|
function getAgentRuntime(agentId) {
|
|
165
192
|
const config = loadAgentConfig();
|
|
@@ -199,6 +226,7 @@ var init_agent_config = __esm({
|
|
|
199
226
|
"use strict";
|
|
200
227
|
init_config();
|
|
201
228
|
init_runtime_table();
|
|
229
|
+
init_secure_files();
|
|
202
230
|
AGENT_CONFIG_PATH = path3.join(EXE_AI_DIR, "agent-config.json");
|
|
203
231
|
KNOWN_RUNTIMES = {
|
|
204
232
|
claude: ["claude-opus-4", "claude-sonnet-4", "claude-haiku-4.5"],
|
|
@@ -220,7 +248,7 @@ var init_agent_config = __esm({
|
|
|
220
248
|
|
|
221
249
|
// src/lib/employees.ts
|
|
222
250
|
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
223
|
-
import { existsSync as
|
|
251
|
+
import { existsSync as existsSync5, symlinkSync, readlinkSync, readFileSync as readFileSync4, renameSync as renameSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
224
252
|
import { execSync } from "child_process";
|
|
225
253
|
import path4 from "path";
|
|
226
254
|
import os2 from "os";
|
|
@@ -249,7 +277,7 @@ function validateEmployeeName(name) {
|
|
|
249
277
|
return { valid: true };
|
|
250
278
|
}
|
|
251
279
|
async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
|
|
252
|
-
if (!
|
|
280
|
+
if (!existsSync5(employeesPath)) {
|
|
253
281
|
return [];
|
|
254
282
|
}
|
|
255
283
|
const raw = await readFile2(employeesPath, "utf-8");
|
|
@@ -264,7 +292,7 @@ async function saveEmployees(employees, employeesPath = EMPLOYEES_PATH) {
|
|
|
264
292
|
await writeFile2(employeesPath, JSON.stringify(employees, null, 2) + "\n", "utf-8");
|
|
265
293
|
}
|
|
266
294
|
function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
|
|
267
|
-
if (!
|
|
295
|
+
if (!existsSync5(employeesPath)) return [];
|
|
268
296
|
try {
|
|
269
297
|
return JSON.parse(readFileSync4(employeesPath, "utf-8"));
|
|
270
298
|
} catch {
|
|
@@ -282,7 +310,7 @@ function appendToCoordinatorTeam(employee) {
|
|
|
282
310
|
const coordinator = getCoordinatorEmployee(loadEmployeesSync());
|
|
283
311
|
if (!coordinator) return;
|
|
284
312
|
const idPath = path4.join(IDENTITY_DIR, `${coordinator.name}.md`);
|
|
285
|
-
if (!
|
|
313
|
+
if (!existsSync5(idPath)) return;
|
|
286
314
|
const content = readFileSync4(idPath, "utf-8");
|
|
287
315
|
if (content.includes(`**${capitalize(employee.name)}`)) return;
|
|
288
316
|
const teamMatch = content.match(TEAM_SECTION_RE);
|
|
@@ -351,7 +379,7 @@ function registerBinSymlinks(name) {
|
|
|
351
379
|
for (const suffix of ["", "-opencode"]) {
|
|
352
380
|
const linkName = `${name}${suffix}`;
|
|
353
381
|
const linkPath = path4.join(binDir, linkName);
|
|
354
|
-
if (
|
|
382
|
+
if (existsSync5(linkPath)) {
|
|
355
383
|
skipped.push(linkName);
|
|
356
384
|
continue;
|
|
357
385
|
}
|
|
@@ -984,12 +1012,12 @@ __export(identity_exports, {
|
|
|
984
1012
|
listIdentities: () => listIdentities,
|
|
985
1013
|
updateIdentity: () => updateIdentity
|
|
986
1014
|
});
|
|
987
|
-
import { existsSync as
|
|
1015
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync4, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "fs";
|
|
988
1016
|
import { readdirSync as readdirSync2 } from "fs";
|
|
989
1017
|
import path8 from "path";
|
|
990
1018
|
import { createHash } from "crypto";
|
|
991
1019
|
function ensureDir() {
|
|
992
|
-
if (!
|
|
1020
|
+
if (!existsSync8(IDENTITY_DIR2)) {
|
|
993
1021
|
mkdirSync4(IDENTITY_DIR2, { recursive: true });
|
|
994
1022
|
}
|
|
995
1023
|
}
|
|
@@ -1035,7 +1063,7 @@ function contentHash(content) {
|
|
|
1035
1063
|
}
|
|
1036
1064
|
function getIdentity(agentId) {
|
|
1037
1065
|
const filePath = identityPath(agentId);
|
|
1038
|
-
if (!
|
|
1066
|
+
if (!existsSync8(filePath)) return null;
|
|
1039
1067
|
const raw = readFileSync7(filePath, "utf-8");
|
|
1040
1068
|
const { frontmatter, body } = parseFrontmatter(raw);
|
|
1041
1069
|
return {
|
|
@@ -1111,10 +1139,10 @@ var init_identity = __esm({
|
|
|
1111
1139
|
});
|
|
1112
1140
|
|
|
1113
1141
|
// src/lib/agent-symlinks.ts
|
|
1114
|
-
import
|
|
1142
|
+
import os5 from "os";
|
|
1115
1143
|
import path9 from "path";
|
|
1116
1144
|
import {
|
|
1117
|
-
existsSync as
|
|
1145
|
+
existsSync as existsSync9,
|
|
1118
1146
|
lstatSync,
|
|
1119
1147
|
mkdirSync as mkdirSync5,
|
|
1120
1148
|
readlinkSync as readlinkSync2,
|
|
@@ -1129,11 +1157,11 @@ function identitySourcePath(homeDir, agentId) {
|
|
|
1129
1157
|
function claudeAgentLinkPath(homeDir, agentId) {
|
|
1130
1158
|
return path9.join(claudeAgentsDir(homeDir), `${agentId}.md`);
|
|
1131
1159
|
}
|
|
1132
|
-
function ensureAgentSymlink(agentId, homeDir =
|
|
1160
|
+
function ensureAgentSymlink(agentId, homeDir = os5.homedir()) {
|
|
1133
1161
|
const target = identitySourcePath(homeDir, agentId);
|
|
1134
1162
|
const link = claudeAgentLinkPath(homeDir, agentId);
|
|
1135
1163
|
mkdirSync5(claudeAgentsDir(homeDir), { recursive: true });
|
|
1136
|
-
if (
|
|
1164
|
+
if (existsSync9(link)) {
|
|
1137
1165
|
let stat;
|
|
1138
1166
|
try {
|
|
1139
1167
|
stat = lstatSync(link);
|
|
@@ -1167,7 +1195,7 @@ function ensureAgentSymlink(agentId, homeDir = os4.homedir()) {
|
|
|
1167
1195
|
}
|
|
1168
1196
|
return { agentId, action: "created", target, link };
|
|
1169
1197
|
}
|
|
1170
|
-
async function ensureAllAgentSymlinks(homeDir =
|
|
1198
|
+
async function ensureAllAgentSymlinks(homeDir = os5.homedir()) {
|
|
1171
1199
|
const employees = await loadEmployees();
|
|
1172
1200
|
return employees.map((emp) => ensureAgentSymlink(emp.name, homeDir));
|
|
1173
1201
|
}
|
|
@@ -1202,12 +1230,12 @@ var init_mcp_prefix = __esm({
|
|
|
1202
1230
|
});
|
|
1203
1231
|
|
|
1204
1232
|
// src/lib/preferences.ts
|
|
1205
|
-
import { existsSync as
|
|
1233
|
+
import { existsSync as existsSync10, readFileSync as readFileSync8, writeFileSync as writeFileSync6 } from "fs";
|
|
1206
1234
|
import path10 from "path";
|
|
1207
|
-
import
|
|
1208
|
-
function loadPreferences(homeDir =
|
|
1235
|
+
import os6 from "os";
|
|
1236
|
+
function loadPreferences(homeDir = os6.homedir()) {
|
|
1209
1237
|
const configPath = path10.join(homeDir, ".exe-os", "config.json");
|
|
1210
|
-
if (!
|
|
1238
|
+
if (!existsSync10(configPath)) return {};
|
|
1211
1239
|
try {
|
|
1212
1240
|
const config = JSON.parse(readFileSync8(configPath, "utf-8"));
|
|
1213
1241
|
return config.preferences ?? {};
|
|
@@ -1218,6 +1246,7 @@ function loadPreferences(homeDir = os5.homedir()) {
|
|
|
1218
1246
|
var init_preferences = __esm({
|
|
1219
1247
|
"src/lib/preferences.ts"() {
|
|
1220
1248
|
"use strict";
|
|
1249
|
+
init_secure_files();
|
|
1221
1250
|
}
|
|
1222
1251
|
});
|
|
1223
1252
|
|
|
@@ -1235,9 +1264,9 @@ __export(installer_exports, {
|
|
|
1235
1264
|
setupTmux: () => setupTmux
|
|
1236
1265
|
});
|
|
1237
1266
|
import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3, readdir } from "fs/promises";
|
|
1238
|
-
import { existsSync as
|
|
1267
|
+
import { existsSync as existsSync11, readFileSync as readFileSync9, writeFileSync as writeFileSync7, copyFileSync, mkdirSync as mkdirSync6 } from "fs";
|
|
1239
1268
|
import path11 from "path";
|
|
1240
|
-
import
|
|
1269
|
+
import os7 from "os";
|
|
1241
1270
|
import { execSync as execSync2 } from "child_process";
|
|
1242
1271
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1243
1272
|
function resolvePackageRoot() {
|
|
@@ -1246,7 +1275,7 @@ function resolvePackageRoot() {
|
|
|
1246
1275
|
const root = path11.parse(dir).root;
|
|
1247
1276
|
while (dir !== root) {
|
|
1248
1277
|
const pkgPath = path11.join(dir, "package.json");
|
|
1249
|
-
if (
|
|
1278
|
+
if (existsSync11(pkgPath)) {
|
|
1250
1279
|
try {
|
|
1251
1280
|
const pkg = JSON.parse(readFileSync9(pkgPath, "utf-8"));
|
|
1252
1281
|
if (pkg.name === "@askexenow/exe-os" || pkg.name === "exe-os") return dir;
|
|
@@ -1257,12 +1286,12 @@ function resolvePackageRoot() {
|
|
|
1257
1286
|
}
|
|
1258
1287
|
return path11.resolve(path11.dirname(thisFile), "..", "..", "..");
|
|
1259
1288
|
}
|
|
1260
|
-
async function copySlashCommands(packageRoot, homeDir =
|
|
1289
|
+
async function copySlashCommands(packageRoot, homeDir = os7.homedir()) {
|
|
1261
1290
|
let copied = 0;
|
|
1262
1291
|
let skipped = 0;
|
|
1263
1292
|
const skillsBase = path11.join(homeDir, ".claude", "skills");
|
|
1264
1293
|
const exeDir = path11.join(packageRoot, "src", "commands", "exe");
|
|
1265
|
-
if (
|
|
1294
|
+
if (existsSync11(exeDir)) {
|
|
1266
1295
|
const entries = await readdir(exeDir);
|
|
1267
1296
|
const mdFiles = entries.filter((f) => f.endsWith(".md"));
|
|
1268
1297
|
for (const file of mdFiles) {
|
|
@@ -1277,7 +1306,7 @@ async function copySlashCommands(packageRoot, homeDir = os6.homedir()) {
|
|
|
1277
1306
|
}
|
|
1278
1307
|
}
|
|
1279
1308
|
const topLevelSrc = path11.join(packageRoot, "src", "commands", "exe.md");
|
|
1280
|
-
if (
|
|
1309
|
+
if (existsSync11(topLevelSrc)) {
|
|
1281
1310
|
const destDir = path11.join(skillsBase, "exe");
|
|
1282
1311
|
await mkdir3(destDir, { recursive: true });
|
|
1283
1312
|
const destPath = path11.join(destDir, "SKILL.md");
|
|
@@ -1303,17 +1332,17 @@ name: ${skillName}
|
|
|
1303
1332
|
`);
|
|
1304
1333
|
}
|
|
1305
1334
|
}
|
|
1306
|
-
if (
|
|
1335
|
+
if (existsSync11(destPath)) {
|
|
1307
1336
|
const existing = await readFile3(destPath, "utf-8");
|
|
1308
1337
|
if (existing === content) return false;
|
|
1309
1338
|
}
|
|
1310
1339
|
await writeFile3(destPath, content);
|
|
1311
1340
|
return true;
|
|
1312
1341
|
}
|
|
1313
|
-
async function registerMcpServer(packageRoot, homeDir =
|
|
1342
|
+
async function registerMcpServer(packageRoot, homeDir = os7.homedir()) {
|
|
1314
1343
|
const claudeJsonPath = path11.join(homeDir, ".claude.json");
|
|
1315
1344
|
let claudeJson = {};
|
|
1316
|
-
if (
|
|
1345
|
+
if (existsSync11(claudeJsonPath)) {
|
|
1317
1346
|
try {
|
|
1318
1347
|
claudeJson = JSON.parse(await readFile3(claudeJsonPath, "utf-8"));
|
|
1319
1348
|
} catch {
|
|
@@ -1330,21 +1359,21 @@ async function registerMcpServer(packageRoot, homeDir = os6.homedir()) {
|
|
|
1330
1359
|
env: {}
|
|
1331
1360
|
};
|
|
1332
1361
|
const currentMem = claudeJson.mcpServers[MCP_LEGACY_KEY];
|
|
1333
|
-
const currentOs = claudeJson.mcpServers[MCP_PRIMARY_KEY];
|
|
1334
1362
|
const memMatches = currentMem && JSON.stringify(currentMem) === JSON.stringify(newEntry);
|
|
1335
|
-
|
|
1336
|
-
|
|
1363
|
+
if (claudeJson.mcpServers[MCP_PRIMARY_KEY]) {
|
|
1364
|
+
delete claudeJson.mcpServers[MCP_PRIMARY_KEY];
|
|
1365
|
+
}
|
|
1366
|
+
if (memMatches && !claudeJson.mcpServers[MCP_PRIMARY_KEY]) {
|
|
1337
1367
|
await cleanSettingsJsonMcp(path11.join(homeDir, ".claude", "settings.json"));
|
|
1338
1368
|
return false;
|
|
1339
1369
|
}
|
|
1340
1370
|
claudeJson.mcpServers[MCP_LEGACY_KEY] = newEntry;
|
|
1341
|
-
claudeJson.mcpServers[MCP_PRIMARY_KEY] = newEntry;
|
|
1342
1371
|
await writeFile3(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
|
|
1343
1372
|
await cleanSettingsJsonMcp(path11.join(homeDir, ".claude", "settings.json"));
|
|
1344
1373
|
return true;
|
|
1345
1374
|
}
|
|
1346
1375
|
async function cleanSettingsJsonMcp(settingsPath) {
|
|
1347
|
-
if (!
|
|
1376
|
+
if (!existsSync11(settingsPath)) return;
|
|
1348
1377
|
try {
|
|
1349
1378
|
const settings = JSON.parse(await readFile3(settingsPath, "utf-8"));
|
|
1350
1379
|
const servers = settings.mcpServers;
|
|
@@ -1364,14 +1393,14 @@ async function cleanSettingsJsonMcp(settingsPath) {
|
|
|
1364
1393
|
} catch {
|
|
1365
1394
|
}
|
|
1366
1395
|
}
|
|
1367
|
-
async function mergeHooks(packageRoot, homeDir =
|
|
1396
|
+
async function mergeHooks(packageRoot, homeDir = os7.homedir()) {
|
|
1368
1397
|
const settingsPath = path11.join(homeDir, ".claude", "settings.json");
|
|
1369
1398
|
const logsDir = path11.join(homeDir, ".exe-os", "logs");
|
|
1370
1399
|
const hookLogPath = path11.join(logsDir, "hooks.log");
|
|
1371
1400
|
const logSuffix = ` 2>> "${hookLogPath}"`;
|
|
1372
1401
|
await mkdir3(logsDir, { recursive: true });
|
|
1373
1402
|
let settings = {};
|
|
1374
|
-
if (
|
|
1403
|
+
if (existsSync11(settingsPath)) {
|
|
1375
1404
|
try {
|
|
1376
1405
|
settings = JSON.parse(await readFile3(settingsPath, "utf-8"));
|
|
1377
1406
|
} catch {
|
|
@@ -1637,9 +1666,9 @@ async function mergeHooks(packageRoot, homeDir = os6.homedir()) {
|
|
|
1637
1666
|
await writeFile3(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
1638
1667
|
return { added, skipped };
|
|
1639
1668
|
}
|
|
1640
|
-
async function cleanOldShellFunctions(homeDir =
|
|
1669
|
+
async function cleanOldShellFunctions(homeDir = os7.homedir()) {
|
|
1641
1670
|
const rosterPath = path11.join(homeDir, ".exe-os", "exe-employees.json");
|
|
1642
|
-
if (!
|
|
1671
|
+
if (!existsSync11(rosterPath)) return 0;
|
|
1643
1672
|
let employees;
|
|
1644
1673
|
try {
|
|
1645
1674
|
employees = JSON.parse(await readFile3(rosterPath, "utf-8"));
|
|
@@ -1660,7 +1689,7 @@ async function cleanOldShellFunctions(homeDir = os6.homedir()) {
|
|
|
1660
1689
|
const REMOVED_MARKER = "# Removed by exe-os \u2014 wrappers now at ~/.exe-os/bin/";
|
|
1661
1690
|
let totalRemoved = 0;
|
|
1662
1691
|
for (const rcPath of rcFiles) {
|
|
1663
|
-
if (!
|
|
1692
|
+
if (!existsSync11(rcPath)) continue;
|
|
1664
1693
|
let content;
|
|
1665
1694
|
try {
|
|
1666
1695
|
content = await readFile3(rcPath, "utf-8");
|
|
@@ -1787,19 +1816,19 @@ async function injectOrchestrationRules(homeDir) {
|
|
|
1787
1816
|
await writeFile3(claudeMdPath, existing + separator + ORCHESTRATION_RULES + "\n", "utf-8");
|
|
1788
1817
|
return "injected";
|
|
1789
1818
|
}
|
|
1790
|
-
async function installStatusLine(packageRoot, homeDir =
|
|
1819
|
+
async function installStatusLine(packageRoot, homeDir = os7.homedir()) {
|
|
1791
1820
|
const prefs = loadPreferences(homeDir);
|
|
1792
1821
|
if (prefs.ccStatusLine === false) return "opted-out";
|
|
1793
1822
|
const claudeDir = path11.join(homeDir, ".claude");
|
|
1794
1823
|
await mkdir3(claudeDir, { recursive: true });
|
|
1795
1824
|
const assetPath = path11.join(packageRoot, "dist", "assets", "statusline-command.sh");
|
|
1796
|
-
if (!
|
|
1825
|
+
if (!existsSync11(assetPath)) return "asset-missing";
|
|
1797
1826
|
const destScript = path11.join(claudeDir, "statusline-command.sh");
|
|
1798
1827
|
const assetContent = await readFile3(assetPath, "utf-8");
|
|
1799
1828
|
await writeFile3(destScript, assetContent, { mode: 493 });
|
|
1800
1829
|
const settingsPath = path11.join(claudeDir, "settings.json");
|
|
1801
1830
|
let settings = {};
|
|
1802
|
-
if (
|
|
1831
|
+
if (existsSync11(settingsPath)) {
|
|
1803
1832
|
try {
|
|
1804
1833
|
settings = JSON.parse(await readFile3(settingsPath, "utf-8"));
|
|
1805
1834
|
} catch {
|
|
@@ -1836,9 +1865,9 @@ async function runInstaller(homeDir) {
|
|
|
1836
1865
|
`Hooks: ${hookResult.added} added, ${hookResult.skipped} unchanged
|
|
1837
1866
|
`
|
|
1838
1867
|
);
|
|
1839
|
-
const resolvedHome = homeDir ??
|
|
1868
|
+
const resolvedHome = homeDir ?? os7.homedir();
|
|
1840
1869
|
const exeWorkspace = path11.join(resolvedHome, "exe");
|
|
1841
|
-
if (!
|
|
1870
|
+
if (!existsSync11(exeWorkspace)) {
|
|
1842
1871
|
try {
|
|
1843
1872
|
await mkdir3(path11.join(exeWorkspace, "content"), { recursive: true });
|
|
1844
1873
|
await mkdir3(path11.join(exeWorkspace, "operations"), { recursive: true });
|
|
@@ -1877,7 +1906,7 @@ exe-os installed successfully.
|
|
|
1877
1906
|
`);
|
|
1878
1907
|
}
|
|
1879
1908
|
function setupTmux(home) {
|
|
1880
|
-
const homeDir = home ??
|
|
1909
|
+
const homeDir = home ?? os7.homedir();
|
|
1881
1910
|
const exeDir = path11.join(homeDir, ".exe-os");
|
|
1882
1911
|
const exeTmuxConf = path11.join(exeDir, "tmux.conf");
|
|
1883
1912
|
const userTmuxConf = path11.join(homeDir, ".tmux.conf");
|
|
@@ -1885,17 +1914,17 @@ function setupTmux(home) {
|
|
|
1885
1914
|
const sourceLine = "source-file ~/.exe-os/tmux.conf";
|
|
1886
1915
|
const pkgRoot = resolvePackageRoot();
|
|
1887
1916
|
const assetPath = path11.join(pkgRoot, "dist", "assets", "tmux.conf");
|
|
1888
|
-
if (!
|
|
1917
|
+
if (!existsSync11(assetPath)) {
|
|
1889
1918
|
process.stderr.write(`exe-os: tmux.conf asset not found at ${assetPath} \u2014 skipping tmux setup
|
|
1890
1919
|
`);
|
|
1891
1920
|
return;
|
|
1892
1921
|
}
|
|
1893
|
-
|
|
1922
|
+
mkdirSync6(exeDir, { recursive: true });
|
|
1894
1923
|
copyFileSync(assetPath, exeTmuxConf);
|
|
1895
|
-
if (
|
|
1924
|
+
if (existsSync11(userTmuxConf)) {
|
|
1896
1925
|
const existing = readFileSync9(userTmuxConf, "utf8");
|
|
1897
1926
|
if (!existing.includes(sourceLine)) {
|
|
1898
|
-
if (!
|
|
1927
|
+
if (!existsSync11(backupPath)) {
|
|
1899
1928
|
copyFileSync(userTmuxConf, backupPath);
|
|
1900
1929
|
process.stderr.write(`exe-os: backed up existing tmux config to ${backupPath}
|
|
1901
1930
|
`);
|
|
@@ -1915,10 +1944,10 @@ ${sourceLine}
|
|
|
1915
1944
|
process.stderr.write("exe-os: tmux config installed\n");
|
|
1916
1945
|
}
|
|
1917
1946
|
function setupGhostty(home) {
|
|
1918
|
-
const homeDir = home ??
|
|
1947
|
+
const homeDir = home ?? os7.homedir();
|
|
1919
1948
|
const xdgConfig = path11.join(homeDir, ".config", "ghostty");
|
|
1920
1949
|
const macConfig = path11.join(homeDir, "Library", "Application Support", "com.mitchellh.ghostty");
|
|
1921
|
-
const ghosttyInstalled =
|
|
1950
|
+
const ghosttyInstalled = existsSync11(xdgConfig) || existsSync11(macConfig) || (() => {
|
|
1922
1951
|
try {
|
|
1923
1952
|
execSync2("which ghostty 2>/dev/null");
|
|
1924
1953
|
return true;
|
|
@@ -1931,28 +1960,28 @@ function setupGhostty(home) {
|
|
|
1931
1960
|
}
|
|
1932
1961
|
const pkgRoot = resolvePackageRoot();
|
|
1933
1962
|
const assetPath = path11.join(pkgRoot, "dist", "assets", "ghostty.conf");
|
|
1934
|
-
if (!
|
|
1963
|
+
if (!existsSync11(assetPath)) {
|
|
1935
1964
|
process.stderr.write("exe-os: ghostty.conf asset not found \u2014 skipping Ghostty setup\n");
|
|
1936
1965
|
return;
|
|
1937
1966
|
}
|
|
1938
1967
|
const configDir = xdgConfig;
|
|
1939
1968
|
const configPath = path11.join(configDir, "config");
|
|
1940
1969
|
const backupPath = path11.join(configDir, "config.backup");
|
|
1941
|
-
|
|
1970
|
+
mkdirSync6(configDir, { recursive: true });
|
|
1942
1971
|
const START_MARKER = "# \u2500\u2500 exe-os:ghostty-start \u2500\u2500";
|
|
1943
1972
|
const END_MARKER = "# \u2500\u2500 exe-os:ghostty-end \u2500\u2500";
|
|
1944
1973
|
const assetContent = readFileSync9(assetPath, "utf8").trim();
|
|
1945
1974
|
const markedSection = `${START_MARKER}
|
|
1946
1975
|
${assetContent}
|
|
1947
1976
|
${END_MARKER}`;
|
|
1948
|
-
if (
|
|
1977
|
+
if (existsSync11(configPath)) {
|
|
1949
1978
|
const existing = readFileSync9(configPath, "utf8");
|
|
1950
1979
|
if (existing.includes(START_MARKER) && existing.includes(END_MARKER)) {
|
|
1951
1980
|
const before = existing.slice(0, existing.indexOf(START_MARKER));
|
|
1952
1981
|
const after = existing.slice(existing.indexOf(END_MARKER) + END_MARKER.length);
|
|
1953
1982
|
writeFileSync7(configPath, `${before}${markedSection}${after}`);
|
|
1954
1983
|
} else if (existing.includes("Exe OS")) {
|
|
1955
|
-
if (!
|
|
1984
|
+
if (!existsSync11(backupPath)) {
|
|
1956
1985
|
copyFileSync(configPath, backupPath);
|
|
1957
1986
|
process.stderr.write(`exe-os: backed up existing Ghostty config to ${backupPath}
|
|
1958
1987
|
`);
|
|
@@ -1960,7 +1989,7 @@ ${END_MARKER}`;
|
|
|
1960
1989
|
writeFileSync7(configPath, `${markedSection}
|
|
1961
1990
|
`);
|
|
1962
1991
|
} else {
|
|
1963
|
-
if (!
|
|
1992
|
+
if (!existsSync11(backupPath)) {
|
|
1964
1993
|
copyFileSync(configPath, backupPath);
|
|
1965
1994
|
process.stderr.write(`exe-os: backed up existing Ghostty config to ${backupPath}
|
|
1966
1995
|
`);
|
|
@@ -2011,7 +2040,7 @@ ${EXE_SECTION_END}`;
|
|
|
2011
2040
|
});
|
|
2012
2041
|
|
|
2013
2042
|
// src/bin/exe-new-employee.ts
|
|
2014
|
-
import { existsSync as
|
|
2043
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync7 } from "fs";
|
|
2015
2044
|
import path12 from "path";
|
|
2016
2045
|
|
|
2017
2046
|
// src/lib/session-wrappers.ts
|
|
@@ -2604,13 +2633,16 @@ function isMainModule(importMetaUrl) {
|
|
|
2604
2633
|
// src/lib/plan-limits.ts
|
|
2605
2634
|
init_database();
|
|
2606
2635
|
init_employees();
|
|
2607
|
-
import { readFileSync as readFileSync6, existsSync as
|
|
2636
|
+
import { readFileSync as readFileSync6, existsSync as existsSync7 } from "fs";
|
|
2608
2637
|
import path7 from "path";
|
|
2609
2638
|
|
|
2610
2639
|
// src/lib/license.ts
|
|
2611
2640
|
init_config();
|
|
2612
|
-
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as
|
|
2641
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as existsSync6, mkdirSync as mkdirSync3 } from "fs";
|
|
2613
2642
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
2643
|
+
import { createRequire as createRequire2 } from "module";
|
|
2644
|
+
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
2645
|
+
import os4 from "os";
|
|
2614
2646
|
import path6 from "path";
|
|
2615
2647
|
import { jwtVerify, importSPKI } from "jose";
|
|
2616
2648
|
var LICENSE_PATH = path6.join(EXE_AI_DIR, "license.key");
|
|
@@ -2650,14 +2682,14 @@ var FREE_LICENSE = {
|
|
|
2650
2682
|
function loadDeviceId() {
|
|
2651
2683
|
const deviceJsonPath = path6.join(EXE_AI_DIR, "device.json");
|
|
2652
2684
|
try {
|
|
2653
|
-
if (
|
|
2685
|
+
if (existsSync6(deviceJsonPath)) {
|
|
2654
2686
|
const data = JSON.parse(readFileSync5(deviceJsonPath, "utf8"));
|
|
2655
2687
|
if (data.deviceId) return data.deviceId;
|
|
2656
2688
|
}
|
|
2657
2689
|
} catch {
|
|
2658
2690
|
}
|
|
2659
2691
|
try {
|
|
2660
|
-
if (
|
|
2692
|
+
if (existsSync6(DEVICE_ID_PATH)) {
|
|
2661
2693
|
const id2 = readFileSync5(DEVICE_ID_PATH, "utf8").trim();
|
|
2662
2694
|
if (id2) return id2;
|
|
2663
2695
|
}
|
|
@@ -2670,7 +2702,7 @@ function loadDeviceId() {
|
|
|
2670
2702
|
}
|
|
2671
2703
|
function loadLicense() {
|
|
2672
2704
|
try {
|
|
2673
|
-
if (!
|
|
2705
|
+
if (!existsSync6(LICENSE_PATH)) return null;
|
|
2674
2706
|
return readFileSync5(LICENSE_PATH, "utf8").trim();
|
|
2675
2707
|
} catch {
|
|
2676
2708
|
return null;
|
|
@@ -2704,7 +2736,7 @@ async function verifyLicenseJwt(token) {
|
|
|
2704
2736
|
}
|
|
2705
2737
|
async function getCachedLicense() {
|
|
2706
2738
|
try {
|
|
2707
|
-
if (!
|
|
2739
|
+
if (!existsSync6(CACHE_PATH)) return null;
|
|
2708
2740
|
const raw = JSON.parse(readFileSync5(CACHE_PATH, "utf8"));
|
|
2709
2741
|
if (!raw.token || typeof raw.token !== "string") return null;
|
|
2710
2742
|
return await verifyLicenseJwt(raw.token);
|
|
@@ -2714,7 +2746,7 @@ async function getCachedLicense() {
|
|
|
2714
2746
|
}
|
|
2715
2747
|
function readCachedToken() {
|
|
2716
2748
|
try {
|
|
2717
|
-
if (!
|
|
2749
|
+
if (!existsSync6(CACHE_PATH)) return null;
|
|
2718
2750
|
const raw = JSON.parse(readFileSync5(CACHE_PATH, "utf8"));
|
|
2719
2751
|
return typeof raw.token === "string" ? raw.token : null;
|
|
2720
2752
|
} catch {
|
|
@@ -2753,52 +2785,128 @@ function cacheResponse(token) {
|
|
|
2753
2785
|
} catch {
|
|
2754
2786
|
}
|
|
2755
2787
|
}
|
|
2756
|
-
|
|
2757
|
-
|
|
2788
|
+
var _prismaPromise = null;
|
|
2789
|
+
var _prismaFailed = false;
|
|
2790
|
+
function loadPrismaForLicense() {
|
|
2791
|
+
if (_prismaFailed) return null;
|
|
2792
|
+
const dbUrl = process.env.DATABASE_URL;
|
|
2793
|
+
if (!dbUrl) {
|
|
2794
|
+
const exeDbRoot = process.env.EXE_DB_ROOT ?? path6.join(os4.homedir(), "exe-db");
|
|
2795
|
+
if (!existsSync6(path6.join(exeDbRoot, "package.json"))) {
|
|
2796
|
+
_prismaFailed = true;
|
|
2797
|
+
return null;
|
|
2798
|
+
}
|
|
2799
|
+
}
|
|
2800
|
+
if (!_prismaPromise) {
|
|
2801
|
+
_prismaPromise = (async () => {
|
|
2802
|
+
const explicitPath = process.env.EXE_OS_PRISMA_CLIENT_PATH;
|
|
2803
|
+
if (explicitPath) {
|
|
2804
|
+
const mod2 = await import(pathToFileURL2(explicitPath).href);
|
|
2805
|
+
const Ctor2 = mod2.PrismaClient ?? mod2.default?.PrismaClient;
|
|
2806
|
+
if (!Ctor2) throw new Error(`No PrismaClient at ${explicitPath}`);
|
|
2807
|
+
return new Ctor2();
|
|
2808
|
+
}
|
|
2809
|
+
const exeDbRoot = process.env.EXE_DB_ROOT ?? path6.join(os4.homedir(), "exe-db");
|
|
2810
|
+
const req = createRequire2(path6.join(exeDbRoot, "package.json"));
|
|
2811
|
+
const entry = req.resolve("@prisma/client");
|
|
2812
|
+
const mod = await import(pathToFileURL2(entry).href);
|
|
2813
|
+
const Ctor = mod.PrismaClient ?? mod.default?.PrismaClient;
|
|
2814
|
+
if (!Ctor) throw new Error(`No PrismaClient in ${entry}`);
|
|
2815
|
+
return new Ctor();
|
|
2816
|
+
})().catch((err) => {
|
|
2817
|
+
_prismaFailed = true;
|
|
2818
|
+
_prismaPromise = null;
|
|
2819
|
+
throw err;
|
|
2820
|
+
});
|
|
2821
|
+
}
|
|
2822
|
+
return _prismaPromise;
|
|
2823
|
+
}
|
|
2824
|
+
async function validateViaPostgres(apiKey) {
|
|
2825
|
+
const loader = loadPrismaForLicense();
|
|
2826
|
+
if (!loader) return null;
|
|
2827
|
+
try {
|
|
2828
|
+
const prisma = await loader;
|
|
2829
|
+
const rows = await prisma.$queryRawUnsafe(
|
|
2830
|
+
`SELECT plan, email, status, device_limit, employee_limit, memory_limit, expires_at
|
|
2831
|
+
FROM billing.licenses WHERE key = $1 LIMIT 1`,
|
|
2832
|
+
apiKey
|
|
2833
|
+
);
|
|
2834
|
+
if (!rows || rows.length === 0) return null;
|
|
2835
|
+
const row = rows[0];
|
|
2836
|
+
if (row.status !== "active") return null;
|
|
2837
|
+
if (row.expires_at && new Date(row.expires_at) < /* @__PURE__ */ new Date()) return null;
|
|
2838
|
+
const plan = row.plan;
|
|
2839
|
+
const limits = PLAN_LIMITS[plan] ?? PLAN_LIMITS.free;
|
|
2840
|
+
return {
|
|
2841
|
+
valid: true,
|
|
2842
|
+
plan,
|
|
2843
|
+
email: row.email,
|
|
2844
|
+
expiresAt: row.expires_at ? new Date(row.expires_at).toISOString() : null,
|
|
2845
|
+
deviceLimit: row.device_limit ?? limits.devices,
|
|
2846
|
+
employeeLimit: row.employee_limit ?? limits.employees,
|
|
2847
|
+
memoryLimit: row.memory_limit ?? limits.memories
|
|
2848
|
+
};
|
|
2849
|
+
} catch {
|
|
2850
|
+
return null;
|
|
2851
|
+
}
|
|
2852
|
+
}
|
|
2853
|
+
async function validateViaCFWorker(apiKey, deviceId) {
|
|
2758
2854
|
try {
|
|
2759
2855
|
const res = await fetchRetry(`${API_BASE}/auth/activate`, {
|
|
2760
2856
|
method: "POST",
|
|
2761
2857
|
headers: { "Content-Type": "application/json" },
|
|
2762
|
-
body: JSON.stringify({ apiKey, deviceId
|
|
2858
|
+
body: JSON.stringify({ apiKey, deviceId }),
|
|
2763
2859
|
signal: AbortSignal.timeout(1e4)
|
|
2764
2860
|
});
|
|
2765
|
-
if (res.ok)
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2861
|
+
if (!res.ok) return null;
|
|
2862
|
+
const data = await res.json();
|
|
2863
|
+
if (data.error === "device_limit_exceeded") return null;
|
|
2864
|
+
if (!data.valid) return null;
|
|
2865
|
+
if (data.token) {
|
|
2866
|
+
cacheResponse(data.token);
|
|
2867
|
+
const verified = await verifyLicenseJwt(data.token);
|
|
2868
|
+
if (verified) return verified;
|
|
2869
|
+
}
|
|
2870
|
+
const limits = PLAN_LIMITS[data.plan] ?? PLAN_LIMITS.free;
|
|
2871
|
+
return {
|
|
2872
|
+
valid: data.valid,
|
|
2873
|
+
plan: data.plan,
|
|
2874
|
+
email: data.email,
|
|
2875
|
+
expiresAt: data.expiresAt,
|
|
2876
|
+
deviceLimit: limits.devices,
|
|
2877
|
+
employeeLimit: limits.employees,
|
|
2878
|
+
memoryLimit: limits.memories
|
|
2879
|
+
};
|
|
2880
|
+
} catch {
|
|
2881
|
+
return null;
|
|
2882
|
+
}
|
|
2883
|
+
}
|
|
2884
|
+
async function validateLicense(apiKey, deviceId) {
|
|
2885
|
+
const did = deviceId ?? loadDeviceId();
|
|
2886
|
+
const pgResult = await validateViaPostgres(apiKey);
|
|
2887
|
+
if (pgResult) {
|
|
2888
|
+
try {
|
|
2889
|
+
writeFileSync4(CACHE_PATH, JSON.stringify({ pgLicense: pgResult, ts: Date.now() }), "utf8");
|
|
2890
|
+
} catch {
|
|
2891
|
+
}
|
|
2892
|
+
return pgResult;
|
|
2893
|
+
}
|
|
2894
|
+
const cfResult = await validateViaCFWorker(apiKey, did);
|
|
2895
|
+
if (cfResult) return cfResult;
|
|
2896
|
+
const cached = await getCachedLicense();
|
|
2897
|
+
if (cached) return cached;
|
|
2898
|
+
try {
|
|
2899
|
+
if (existsSync6(CACHE_PATH)) {
|
|
2900
|
+
const raw = JSON.parse(readFileSync5(CACHE_PATH, "utf8"));
|
|
2901
|
+
if (raw.pgLicense && raw.ts && Date.now() - raw.ts < 7 * 24 * 60 * 60 * 1e3) {
|
|
2902
|
+
return raw.pgLicense;
|
|
2778
2903
|
}
|
|
2779
|
-
const limits = PLAN_LIMITS[data.plan] ?? PLAN_LIMITS.free;
|
|
2780
|
-
return {
|
|
2781
|
-
valid: data.valid,
|
|
2782
|
-
plan: data.plan,
|
|
2783
|
-
email: data.email,
|
|
2784
|
-
expiresAt: data.expiresAt,
|
|
2785
|
-
deviceLimit: limits.devices,
|
|
2786
|
-
employeeLimit: limits.employees,
|
|
2787
|
-
memoryLimit: limits.memories
|
|
2788
|
-
};
|
|
2789
2904
|
}
|
|
2790
|
-
const cached = await getCachedLicense();
|
|
2791
|
-
if (cached) return cached;
|
|
2792
|
-
const raw = getRawCachedPlan();
|
|
2793
|
-
if (raw) return raw;
|
|
2794
|
-
return { ...FREE_LICENSE, valid: false, plan: "free" };
|
|
2795
2905
|
} catch {
|
|
2796
|
-
const cached = await getCachedLicense();
|
|
2797
|
-
if (cached) return cached;
|
|
2798
|
-
const rawFallback = getRawCachedPlan();
|
|
2799
|
-
if (rawFallback) return rawFallback;
|
|
2800
|
-
return { ...FREE_LICENSE, valid: false, error: "offline" };
|
|
2801
2906
|
}
|
|
2907
|
+
const rawFallback = getRawCachedPlan();
|
|
2908
|
+
if (rawFallback) return rawFallback;
|
|
2909
|
+
return { ...FREE_LICENSE, valid: false };
|
|
2802
2910
|
}
|
|
2803
2911
|
var CACHE_MAX_AGE_MS = 36e5;
|
|
2804
2912
|
function getCacheAgeMs() {
|
|
@@ -2815,7 +2923,7 @@ async function checkLicense() {
|
|
|
2815
2923
|
if (!key) {
|
|
2816
2924
|
try {
|
|
2817
2925
|
const configPath = path6.join(EXE_AI_DIR, "config.json");
|
|
2818
|
-
if (
|
|
2926
|
+
if (existsSync6(configPath)) {
|
|
2819
2927
|
const raw = JSON.parse(readFileSync5(configPath, "utf8"));
|
|
2820
2928
|
const cloud = raw.cloud;
|
|
2821
2929
|
if (cloud?.apiKey) {
|
|
@@ -2943,8 +3051,8 @@ async function main() {
|
|
|
2943
3051
|
} catch {
|
|
2944
3052
|
}
|
|
2945
3053
|
const taskDir = path12.join(process.cwd(), "exe", name);
|
|
2946
|
-
if (!
|
|
2947
|
-
|
|
3054
|
+
if (!existsSync12(taskDir)) {
|
|
3055
|
+
mkdirSync7(taskDir, { recursive: true });
|
|
2948
3056
|
}
|
|
2949
3057
|
const bins = registerBinSymlinks(newEmployee.name);
|
|
2950
3058
|
if (bins.created.length > 0) {
|