@askexenow/exe-os 0.9.113 → 0.9.115
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/agentic-ontology-backfill.js +36 -12
- package/dist/bin/agentic-reflection-backfill.js +36 -12
- package/dist/bin/agentic-semantic-label.js +36 -12
- package/dist/bin/backfill-conversations.js +36 -12
- package/dist/bin/backfill-responses.js +36 -12
- package/dist/bin/backfill-vectors.js +36 -12
- package/dist/bin/bulk-sync-postgres.js +36 -12
- package/dist/bin/cleanup-stale-review-tasks.js +470 -113
- package/dist/bin/cli.js +413 -62
- package/dist/bin/exe-agent.js +27 -0
- package/dist/bin/exe-assign.js +36 -12
- package/dist/bin/exe-boot.js +246 -54
- package/dist/bin/exe-call.js +8 -0
- package/dist/bin/exe-cloud.js +47 -12
- package/dist/bin/exe-dispatch.js +348 -53
- package/dist/bin/exe-doctor.js +51 -13
- package/dist/bin/exe-export-behaviors.js +37 -12
- package/dist/bin/exe-forget.js +36 -12
- package/dist/bin/exe-gateway.js +348 -53
- package/dist/bin/exe-heartbeat.js +471 -113
- package/dist/bin/exe-kill.js +36 -12
- package/dist/bin/exe-launch-agent.js +117 -18
- package/dist/bin/exe-new-employee.js +9 -1
- package/dist/bin/exe-pending-messages.js +452 -95
- package/dist/bin/exe-pending-notifications.js +452 -95
- package/dist/bin/exe-pending-reviews.js +452 -95
- package/dist/bin/exe-rename.js +36 -12
- package/dist/bin/exe-review.js +36 -12
- package/dist/bin/exe-search.js +37 -12
- package/dist/bin/exe-session-cleanup.js +348 -53
- package/dist/bin/exe-settings.js +12 -0
- package/dist/bin/exe-start-codex.js +46 -13
- package/dist/bin/exe-start-opencode.js +46 -13
- package/dist/bin/exe-status.js +460 -114
- package/dist/bin/exe-support.js +12 -0
- package/dist/bin/exe-team.js +36 -12
- package/dist/bin/git-sweep.js +348 -53
- package/dist/bin/graph-backfill.js +36 -12
- package/dist/bin/graph-export.js +36 -12
- package/dist/bin/install.js +9 -1
- package/dist/bin/intercom-check.js +255 -53
- package/dist/bin/scan-tasks.js +348 -53
- package/dist/bin/setup.js +74 -12
- package/dist/bin/shard-migrate.js +36 -12
- package/dist/gateway/index.js +348 -53
- package/dist/hooks/bug-report-worker.js +348 -53
- package/dist/hooks/codex-stop-task-finalizer.js +308 -37
- package/dist/hooks/commit-complete.js +348 -53
- package/dist/hooks/error-recall.js +37 -12
- package/dist/hooks/ingest.js +363 -54
- package/dist/hooks/instructions-loaded.js +36 -12
- package/dist/hooks/notification.js +36 -12
- package/dist/hooks/post-compact.js +426 -72
- package/dist/hooks/post-tool-combined.js +501 -146
- package/dist/hooks/pre-compact.js +348 -53
- package/dist/hooks/pre-tool-use.js +92 -13
- package/dist/hooks/prompt-submit.js +348 -53
- package/dist/hooks/session-end.js +158 -53
- package/dist/hooks/session-start.js +66 -13
- package/dist/hooks/stop.js +420 -72
- package/dist/hooks/subagent-stop.js +419 -72
- package/dist/hooks/summary-worker.js +442 -121
- package/dist/index.js +375 -53
- package/dist/lib/agent-config.js +8 -0
- package/dist/lib/cloud-sync.js +35 -12
- package/dist/lib/config.js +13 -0
- package/dist/lib/consolidation.js +9 -1
- package/dist/lib/embedder.js +13 -0
- package/dist/lib/employees.js +8 -0
- package/dist/lib/exe-daemon.js +524 -60
- package/dist/lib/hybrid-search.js +37 -12
- package/dist/lib/keychain.js +25 -13
- package/dist/lib/messaging.js +395 -74
- package/dist/lib/schedules.js +36 -12
- package/dist/lib/skill-learning.js +21 -0
- package/dist/lib/store.js +36 -12
- package/dist/lib/tasks.js +324 -41
- package/dist/lib/tmux-routing.js +324 -41
- package/dist/mcp/server.js +374 -54
- package/dist/mcp/tools/create-task.js +324 -41
- package/dist/mcp/tools/list-tasks.js +406 -57
- package/dist/mcp/tools/send-message.js +395 -74
- package/dist/mcp/tools/update-task.js +324 -41
- package/dist/runtime/index.js +375 -53
- package/dist/tui/App.js +377 -55
- package/package.json +1 -1
|
@@ -193,6 +193,17 @@ function normalizeOrchestration(raw) {
|
|
|
193
193
|
const userOrg = raw.orchestration ?? {};
|
|
194
194
|
raw.orchestration = { ...defaultOrg, ...userOrg };
|
|
195
195
|
}
|
|
196
|
+
function normalizeCloudEndpoint(raw) {
|
|
197
|
+
const cloud = raw.cloud;
|
|
198
|
+
if (!cloud?.endpoint) return;
|
|
199
|
+
const ep = String(cloud.endpoint);
|
|
200
|
+
if (ep === "https://askexe.com/cloud" || ep === "https://askexe.com/cloud/") {
|
|
201
|
+
cloud.endpoint = "https://cloud.askexe.com";
|
|
202
|
+
process.stderr.write(
|
|
203
|
+
"[config] Auto-migrated cloud endpoint: askexe.com/cloud \u2192 cloud.askexe.com\n"
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
196
207
|
async function loadConfig() {
|
|
197
208
|
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
198
209
|
await ensurePrivateDir(dir);
|
|
@@ -218,6 +229,7 @@ async function loadConfig() {
|
|
|
218
229
|
normalizeSessionLifecycle(migratedCfg);
|
|
219
230
|
normalizeAutoUpdate(migratedCfg);
|
|
220
231
|
normalizeOrchestration(migratedCfg);
|
|
232
|
+
normalizeCloudEndpoint(migratedCfg);
|
|
221
233
|
const config = { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db"), ...migratedCfg };
|
|
222
234
|
if (config.dbPath.startsWith("~")) {
|
|
223
235
|
config.dbPath = config.dbPath.replace(/^~/, os.homedir());
|
|
@@ -4385,7 +4397,7 @@ init_memory();
|
|
|
4385
4397
|
init_database();
|
|
4386
4398
|
|
|
4387
4399
|
// src/lib/keychain.ts
|
|
4388
|
-
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
4400
|
+
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2, rename, copyFile } from "fs/promises";
|
|
4389
4401
|
import { existsSync as existsSync7, statSync as statSync3 } from "fs";
|
|
4390
4402
|
import { execSync as execSync3 } from "child_process";
|
|
4391
4403
|
import path6 from "path";
|
|
@@ -4424,12 +4436,14 @@ function linuxSecretAvailable() {
|
|
|
4424
4436
|
function isRootOnlyTrustedServerKeyFile(keyPath) {
|
|
4425
4437
|
if (process.platform !== "linux") return false;
|
|
4426
4438
|
try {
|
|
4427
|
-
const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
|
|
4428
4439
|
const st = statSync3(keyPath);
|
|
4429
4440
|
if (!st.isFile() || (st.mode & 63) !== 0) return false;
|
|
4441
|
+
const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
|
|
4430
4442
|
if (uid === 0) return true;
|
|
4431
4443
|
const exeOsDir = process.env.EXE_OS_DIR;
|
|
4432
|
-
|
|
4444
|
+
if (exeOsDir && path6.resolve(keyPath).startsWith(path6.resolve(exeOsDir) + path6.sep)) return true;
|
|
4445
|
+
if (!linuxSecretAvailable()) return true;
|
|
4446
|
+
return false;
|
|
4433
4447
|
} catch {
|
|
4434
4448
|
return false;
|
|
4435
4449
|
}
|
|
@@ -4580,15 +4594,25 @@ async function writeMachineBoundFileFallback(b64) {
|
|
|
4580
4594
|
await mkdir3(dir, { recursive: true });
|
|
4581
4595
|
const keyPath = getKeyPath();
|
|
4582
4596
|
const machineKey = deriveMachineKey();
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
|
|
4597
|
+
const content = machineKey ? encryptWithMachineKey(b64, machineKey) + "\n" : b64 + "\n";
|
|
4598
|
+
const result = machineKey ? "encrypted" : "plaintext";
|
|
4599
|
+
const tmpPath = keyPath + ".tmp";
|
|
4600
|
+
try {
|
|
4601
|
+
if (existsSync7(keyPath)) {
|
|
4602
|
+
await copyFile(keyPath, keyPath + ".bak").catch(() => {
|
|
4603
|
+
});
|
|
4604
|
+
}
|
|
4605
|
+
await writeFile3(tmpPath, content, "utf-8");
|
|
4606
|
+
await chmod2(tmpPath, 384);
|
|
4607
|
+
await rename(tmpPath, keyPath);
|
|
4608
|
+
} catch (err) {
|
|
4609
|
+
try {
|
|
4610
|
+
await unlink(tmpPath);
|
|
4611
|
+
} catch {
|
|
4612
|
+
}
|
|
4613
|
+
throw err;
|
|
4588
4614
|
}
|
|
4589
|
-
|
|
4590
|
-
await chmod2(keyPath, 384);
|
|
4591
|
-
return "plaintext";
|
|
4615
|
+
return result;
|
|
4592
4616
|
}
|
|
4593
4617
|
async function getMasterKey() {
|
|
4594
4618
|
let nativeValue = macKeychainGet() ?? linuxSecretGet();
|
|
@@ -4655,7 +4679,7 @@ async function getMasterKey() {
|
|
|
4655
4679
|
b64Value = content;
|
|
4656
4680
|
}
|
|
4657
4681
|
const key = Buffer.from(b64Value, "base64");
|
|
4658
|
-
if (
|
|
4682
|
+
if (isRootOnlyTrustedServerKeyFile(keyPath)) {
|
|
4659
4683
|
return key;
|
|
4660
4684
|
}
|
|
4661
4685
|
const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
|
|
@@ -193,6 +193,17 @@ function normalizeOrchestration(raw) {
|
|
|
193
193
|
const userOrg = raw.orchestration ?? {};
|
|
194
194
|
raw.orchestration = { ...defaultOrg, ...userOrg };
|
|
195
195
|
}
|
|
196
|
+
function normalizeCloudEndpoint(raw) {
|
|
197
|
+
const cloud = raw.cloud;
|
|
198
|
+
if (!cloud?.endpoint) return;
|
|
199
|
+
const ep = String(cloud.endpoint);
|
|
200
|
+
if (ep === "https://askexe.com/cloud" || ep === "https://askexe.com/cloud/") {
|
|
201
|
+
cloud.endpoint = "https://cloud.askexe.com";
|
|
202
|
+
process.stderr.write(
|
|
203
|
+
"[config] Auto-migrated cloud endpoint: askexe.com/cloud \u2192 cloud.askexe.com\n"
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
196
207
|
async function loadConfig() {
|
|
197
208
|
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
198
209
|
await ensurePrivateDir(dir);
|
|
@@ -218,6 +229,7 @@ async function loadConfig() {
|
|
|
218
229
|
normalizeSessionLifecycle(migratedCfg);
|
|
219
230
|
normalizeAutoUpdate(migratedCfg);
|
|
220
231
|
normalizeOrchestration(migratedCfg);
|
|
232
|
+
normalizeCloudEndpoint(migratedCfg);
|
|
221
233
|
const config = { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db"), ...migratedCfg };
|
|
222
234
|
if (config.dbPath.startsWith("~")) {
|
|
223
235
|
config.dbPath = config.dbPath.replace(/^~/, os.homedir());
|
|
@@ -3958,7 +3970,7 @@ init_memory();
|
|
|
3958
3970
|
init_database();
|
|
3959
3971
|
|
|
3960
3972
|
// src/lib/keychain.ts
|
|
3961
|
-
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
3973
|
+
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2, rename, copyFile } from "fs/promises";
|
|
3962
3974
|
import { existsSync as existsSync7, statSync as statSync3 } from "fs";
|
|
3963
3975
|
import { execSync as execSync3 } from "child_process";
|
|
3964
3976
|
import path6 from "path";
|
|
@@ -3997,12 +4009,14 @@ function linuxSecretAvailable() {
|
|
|
3997
4009
|
function isRootOnlyTrustedServerKeyFile(keyPath) {
|
|
3998
4010
|
if (process.platform !== "linux") return false;
|
|
3999
4011
|
try {
|
|
4000
|
-
const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
|
|
4001
4012
|
const st = statSync3(keyPath);
|
|
4002
4013
|
if (!st.isFile() || (st.mode & 63) !== 0) return false;
|
|
4014
|
+
const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
|
|
4003
4015
|
if (uid === 0) return true;
|
|
4004
4016
|
const exeOsDir = process.env.EXE_OS_DIR;
|
|
4005
|
-
|
|
4017
|
+
if (exeOsDir && path6.resolve(keyPath).startsWith(path6.resolve(exeOsDir) + path6.sep)) return true;
|
|
4018
|
+
if (!linuxSecretAvailable()) return true;
|
|
4019
|
+
return false;
|
|
4006
4020
|
} catch {
|
|
4007
4021
|
return false;
|
|
4008
4022
|
}
|
|
@@ -4153,15 +4167,25 @@ async function writeMachineBoundFileFallback(b64) {
|
|
|
4153
4167
|
await mkdir3(dir, { recursive: true });
|
|
4154
4168
|
const keyPath = getKeyPath();
|
|
4155
4169
|
const machineKey = deriveMachineKey();
|
|
4156
|
-
|
|
4157
|
-
|
|
4158
|
-
|
|
4159
|
-
|
|
4160
|
-
|
|
4170
|
+
const content = machineKey ? encryptWithMachineKey(b64, machineKey) + "\n" : b64 + "\n";
|
|
4171
|
+
const result = machineKey ? "encrypted" : "plaintext";
|
|
4172
|
+
const tmpPath = keyPath + ".tmp";
|
|
4173
|
+
try {
|
|
4174
|
+
if (existsSync7(keyPath)) {
|
|
4175
|
+
await copyFile(keyPath, keyPath + ".bak").catch(() => {
|
|
4176
|
+
});
|
|
4177
|
+
}
|
|
4178
|
+
await writeFile3(tmpPath, content, "utf-8");
|
|
4179
|
+
await chmod2(tmpPath, 384);
|
|
4180
|
+
await rename(tmpPath, keyPath);
|
|
4181
|
+
} catch (err) {
|
|
4182
|
+
try {
|
|
4183
|
+
await unlink(tmpPath);
|
|
4184
|
+
} catch {
|
|
4185
|
+
}
|
|
4186
|
+
throw err;
|
|
4161
4187
|
}
|
|
4162
|
-
|
|
4163
|
-
await chmod2(keyPath, 384);
|
|
4164
|
-
return "plaintext";
|
|
4188
|
+
return result;
|
|
4165
4189
|
}
|
|
4166
4190
|
async function getMasterKey() {
|
|
4167
4191
|
let nativeValue = macKeychainGet() ?? linuxSecretGet();
|
|
@@ -4228,7 +4252,7 @@ async function getMasterKey() {
|
|
|
4228
4252
|
b64Value = content;
|
|
4229
4253
|
}
|
|
4230
4254
|
const key = Buffer.from(b64Value, "base64");
|
|
4231
|
-
if (
|
|
4255
|
+
if (isRootOnlyTrustedServerKeyFile(keyPath)) {
|
|
4232
4256
|
return key;
|
|
4233
4257
|
}
|
|
4234
4258
|
const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
|
|
@@ -193,6 +193,17 @@ function normalizeOrchestration(raw) {
|
|
|
193
193
|
const userOrg = raw.orchestration ?? {};
|
|
194
194
|
raw.orchestration = { ...defaultOrg, ...userOrg };
|
|
195
195
|
}
|
|
196
|
+
function normalizeCloudEndpoint(raw) {
|
|
197
|
+
const cloud = raw.cloud;
|
|
198
|
+
if (!cloud?.endpoint) return;
|
|
199
|
+
const ep = String(cloud.endpoint);
|
|
200
|
+
if (ep === "https://askexe.com/cloud" || ep === "https://askexe.com/cloud/") {
|
|
201
|
+
cloud.endpoint = "https://cloud.askexe.com";
|
|
202
|
+
process.stderr.write(
|
|
203
|
+
"[config] Auto-migrated cloud endpoint: askexe.com/cloud \u2192 cloud.askexe.com\n"
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
196
207
|
async function loadConfig() {
|
|
197
208
|
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
198
209
|
await ensurePrivateDir(dir);
|
|
@@ -218,6 +229,7 @@ async function loadConfig() {
|
|
|
218
229
|
normalizeSessionLifecycle(migratedCfg);
|
|
219
230
|
normalizeAutoUpdate(migratedCfg);
|
|
220
231
|
normalizeOrchestration(migratedCfg);
|
|
232
|
+
normalizeCloudEndpoint(migratedCfg);
|
|
221
233
|
const config = { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db"), ...migratedCfg };
|
|
222
234
|
if (config.dbPath.startsWith("~")) {
|
|
223
235
|
config.dbPath = config.dbPath.replace(/^~/, os.homedir());
|
|
@@ -4082,7 +4094,7 @@ init_memory();
|
|
|
4082
4094
|
init_database();
|
|
4083
4095
|
|
|
4084
4096
|
// src/lib/keychain.ts
|
|
4085
|
-
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
4097
|
+
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2, rename, copyFile } from "fs/promises";
|
|
4086
4098
|
import { existsSync as existsSync7, statSync as statSync3 } from "fs";
|
|
4087
4099
|
import { execSync as execSync3 } from "child_process";
|
|
4088
4100
|
import path6 from "path";
|
|
@@ -4121,12 +4133,14 @@ function linuxSecretAvailable() {
|
|
|
4121
4133
|
function isRootOnlyTrustedServerKeyFile(keyPath) {
|
|
4122
4134
|
if (process.platform !== "linux") return false;
|
|
4123
4135
|
try {
|
|
4124
|
-
const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
|
|
4125
4136
|
const st = statSync3(keyPath);
|
|
4126
4137
|
if (!st.isFile() || (st.mode & 63) !== 0) return false;
|
|
4138
|
+
const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
|
|
4127
4139
|
if (uid === 0) return true;
|
|
4128
4140
|
const exeOsDir = process.env.EXE_OS_DIR;
|
|
4129
|
-
|
|
4141
|
+
if (exeOsDir && path6.resolve(keyPath).startsWith(path6.resolve(exeOsDir) + path6.sep)) return true;
|
|
4142
|
+
if (!linuxSecretAvailable()) return true;
|
|
4143
|
+
return false;
|
|
4130
4144
|
} catch {
|
|
4131
4145
|
return false;
|
|
4132
4146
|
}
|
|
@@ -4277,15 +4291,25 @@ async function writeMachineBoundFileFallback(b64) {
|
|
|
4277
4291
|
await mkdir3(dir, { recursive: true });
|
|
4278
4292
|
const keyPath = getKeyPath();
|
|
4279
4293
|
const machineKey = deriveMachineKey();
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
4284
|
-
|
|
4294
|
+
const content = machineKey ? encryptWithMachineKey(b64, machineKey) + "\n" : b64 + "\n";
|
|
4295
|
+
const result = machineKey ? "encrypted" : "plaintext";
|
|
4296
|
+
const tmpPath = keyPath + ".tmp";
|
|
4297
|
+
try {
|
|
4298
|
+
if (existsSync7(keyPath)) {
|
|
4299
|
+
await copyFile(keyPath, keyPath + ".bak").catch(() => {
|
|
4300
|
+
});
|
|
4301
|
+
}
|
|
4302
|
+
await writeFile3(tmpPath, content, "utf-8");
|
|
4303
|
+
await chmod2(tmpPath, 384);
|
|
4304
|
+
await rename(tmpPath, keyPath);
|
|
4305
|
+
} catch (err) {
|
|
4306
|
+
try {
|
|
4307
|
+
await unlink(tmpPath);
|
|
4308
|
+
} catch {
|
|
4309
|
+
}
|
|
4310
|
+
throw err;
|
|
4285
4311
|
}
|
|
4286
|
-
|
|
4287
|
-
await chmod2(keyPath, 384);
|
|
4288
|
-
return "plaintext";
|
|
4312
|
+
return result;
|
|
4289
4313
|
}
|
|
4290
4314
|
async function getMasterKey() {
|
|
4291
4315
|
let nativeValue = macKeychainGet() ?? linuxSecretGet();
|
|
@@ -4352,7 +4376,7 @@ async function getMasterKey() {
|
|
|
4352
4376
|
b64Value = content;
|
|
4353
4377
|
}
|
|
4354
4378
|
const key = Buffer.from(b64Value, "base64");
|
|
4355
|
-
if (
|
|
4379
|
+
if (isRootOnlyTrustedServerKeyFile(keyPath)) {
|
|
4356
4380
|
return key;
|
|
4357
4381
|
}
|
|
4358
4382
|
const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
|
|
@@ -193,6 +193,17 @@ function normalizeOrchestration(raw) {
|
|
|
193
193
|
const userOrg = raw.orchestration ?? {};
|
|
194
194
|
raw.orchestration = { ...defaultOrg, ...userOrg };
|
|
195
195
|
}
|
|
196
|
+
function normalizeCloudEndpoint(raw) {
|
|
197
|
+
const cloud = raw.cloud;
|
|
198
|
+
if (!cloud?.endpoint) return;
|
|
199
|
+
const ep = String(cloud.endpoint);
|
|
200
|
+
if (ep === "https://askexe.com/cloud" || ep === "https://askexe.com/cloud/") {
|
|
201
|
+
cloud.endpoint = "https://cloud.askexe.com";
|
|
202
|
+
process.stderr.write(
|
|
203
|
+
"[config] Auto-migrated cloud endpoint: askexe.com/cloud \u2192 cloud.askexe.com\n"
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
196
207
|
async function loadConfig() {
|
|
197
208
|
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
198
209
|
await ensurePrivateDir(dir);
|
|
@@ -218,6 +229,7 @@ async function loadConfig() {
|
|
|
218
229
|
normalizeSessionLifecycle(migratedCfg);
|
|
219
230
|
normalizeAutoUpdate(migratedCfg);
|
|
220
231
|
normalizeOrchestration(migratedCfg);
|
|
232
|
+
normalizeCloudEndpoint(migratedCfg);
|
|
221
233
|
const config = { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db"), ...migratedCfg };
|
|
222
234
|
if (config.dbPath.startsWith("~")) {
|
|
223
235
|
config.dbPath = config.dbPath.replace(/^~/, os.homedir());
|
|
@@ -4534,7 +4546,7 @@ init_memory();
|
|
|
4534
4546
|
init_database();
|
|
4535
4547
|
|
|
4536
4548
|
// src/lib/keychain.ts
|
|
4537
|
-
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
4549
|
+
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2, rename, copyFile } from "fs/promises";
|
|
4538
4550
|
import { existsSync as existsSync7, statSync as statSync3 } from "fs";
|
|
4539
4551
|
import { execSync as execSync3 } from "child_process";
|
|
4540
4552
|
import path6 from "path";
|
|
@@ -4573,12 +4585,14 @@ function linuxSecretAvailable() {
|
|
|
4573
4585
|
function isRootOnlyTrustedServerKeyFile(keyPath) {
|
|
4574
4586
|
if (process.platform !== "linux") return false;
|
|
4575
4587
|
try {
|
|
4576
|
-
const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
|
|
4577
4588
|
const st = statSync3(keyPath);
|
|
4578
4589
|
if (!st.isFile() || (st.mode & 63) !== 0) return false;
|
|
4590
|
+
const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
|
|
4579
4591
|
if (uid === 0) return true;
|
|
4580
4592
|
const exeOsDir = process.env.EXE_OS_DIR;
|
|
4581
|
-
|
|
4593
|
+
if (exeOsDir && path6.resolve(keyPath).startsWith(path6.resolve(exeOsDir) + path6.sep)) return true;
|
|
4594
|
+
if (!linuxSecretAvailable()) return true;
|
|
4595
|
+
return false;
|
|
4582
4596
|
} catch {
|
|
4583
4597
|
return false;
|
|
4584
4598
|
}
|
|
@@ -4729,15 +4743,25 @@ async function writeMachineBoundFileFallback(b64) {
|
|
|
4729
4743
|
await mkdir3(dir, { recursive: true });
|
|
4730
4744
|
const keyPath = getKeyPath();
|
|
4731
4745
|
const machineKey = deriveMachineKey();
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
|
|
4736
|
-
|
|
4746
|
+
const content = machineKey ? encryptWithMachineKey(b64, machineKey) + "\n" : b64 + "\n";
|
|
4747
|
+
const result = machineKey ? "encrypted" : "plaintext";
|
|
4748
|
+
const tmpPath = keyPath + ".tmp";
|
|
4749
|
+
try {
|
|
4750
|
+
if (existsSync7(keyPath)) {
|
|
4751
|
+
await copyFile(keyPath, keyPath + ".bak").catch(() => {
|
|
4752
|
+
});
|
|
4753
|
+
}
|
|
4754
|
+
await writeFile3(tmpPath, content, "utf-8");
|
|
4755
|
+
await chmod2(tmpPath, 384);
|
|
4756
|
+
await rename(tmpPath, keyPath);
|
|
4757
|
+
} catch (err) {
|
|
4758
|
+
try {
|
|
4759
|
+
await unlink(tmpPath);
|
|
4760
|
+
} catch {
|
|
4761
|
+
}
|
|
4762
|
+
throw err;
|
|
4737
4763
|
}
|
|
4738
|
-
|
|
4739
|
-
await chmod2(keyPath, 384);
|
|
4740
|
-
return "plaintext";
|
|
4764
|
+
return result;
|
|
4741
4765
|
}
|
|
4742
4766
|
async function getMasterKey() {
|
|
4743
4767
|
let nativeValue = macKeychainGet() ?? linuxSecretGet();
|
|
@@ -4804,7 +4828,7 @@ async function getMasterKey() {
|
|
|
4804
4828
|
b64Value = content;
|
|
4805
4829
|
}
|
|
4806
4830
|
const key = Buffer.from(b64Value, "base64");
|
|
4807
|
-
if (
|
|
4831
|
+
if (isRootOnlyTrustedServerKeyFile(keyPath)) {
|
|
4808
4832
|
return key;
|
|
4809
4833
|
}
|
|
4810
4834
|
const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
|
|
@@ -193,6 +193,17 @@ function normalizeOrchestration(raw) {
|
|
|
193
193
|
const userOrg = raw.orchestration ?? {};
|
|
194
194
|
raw.orchestration = { ...defaultOrg, ...userOrg };
|
|
195
195
|
}
|
|
196
|
+
function normalizeCloudEndpoint(raw) {
|
|
197
|
+
const cloud = raw.cloud;
|
|
198
|
+
if (!cloud?.endpoint) return;
|
|
199
|
+
const ep = String(cloud.endpoint);
|
|
200
|
+
if (ep === "https://askexe.com/cloud" || ep === "https://askexe.com/cloud/") {
|
|
201
|
+
cloud.endpoint = "https://cloud.askexe.com";
|
|
202
|
+
process.stderr.write(
|
|
203
|
+
"[config] Auto-migrated cloud endpoint: askexe.com/cloud \u2192 cloud.askexe.com\n"
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
196
207
|
async function loadConfig() {
|
|
197
208
|
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
198
209
|
await ensurePrivateDir(dir);
|
|
@@ -218,6 +229,7 @@ async function loadConfig() {
|
|
|
218
229
|
normalizeSessionLifecycle(migratedCfg);
|
|
219
230
|
normalizeAutoUpdate(migratedCfg);
|
|
220
231
|
normalizeOrchestration(migratedCfg);
|
|
232
|
+
normalizeCloudEndpoint(migratedCfg);
|
|
221
233
|
const config = { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db"), ...migratedCfg };
|
|
222
234
|
if (config.dbPath.startsWith("~")) {
|
|
223
235
|
config.dbPath = config.dbPath.replace(/^~/, os.homedir());
|
|
@@ -4533,7 +4545,7 @@ init_memory();
|
|
|
4533
4545
|
init_database();
|
|
4534
4546
|
|
|
4535
4547
|
// src/lib/keychain.ts
|
|
4536
|
-
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
4548
|
+
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2, rename, copyFile } from "fs/promises";
|
|
4537
4549
|
import { existsSync as existsSync7, statSync as statSync3 } from "fs";
|
|
4538
4550
|
import { execSync as execSync3 } from "child_process";
|
|
4539
4551
|
import path6 from "path";
|
|
@@ -4572,12 +4584,14 @@ function linuxSecretAvailable() {
|
|
|
4572
4584
|
function isRootOnlyTrustedServerKeyFile(keyPath) {
|
|
4573
4585
|
if (process.platform !== "linux") return false;
|
|
4574
4586
|
try {
|
|
4575
|
-
const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
|
|
4576
4587
|
const st = statSync3(keyPath);
|
|
4577
4588
|
if (!st.isFile() || (st.mode & 63) !== 0) return false;
|
|
4589
|
+
const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
|
|
4578
4590
|
if (uid === 0) return true;
|
|
4579
4591
|
const exeOsDir = process.env.EXE_OS_DIR;
|
|
4580
|
-
|
|
4592
|
+
if (exeOsDir && path6.resolve(keyPath).startsWith(path6.resolve(exeOsDir) + path6.sep)) return true;
|
|
4593
|
+
if (!linuxSecretAvailable()) return true;
|
|
4594
|
+
return false;
|
|
4581
4595
|
} catch {
|
|
4582
4596
|
return false;
|
|
4583
4597
|
}
|
|
@@ -4728,15 +4742,25 @@ async function writeMachineBoundFileFallback(b64) {
|
|
|
4728
4742
|
await mkdir3(dir, { recursive: true });
|
|
4729
4743
|
const keyPath = getKeyPath();
|
|
4730
4744
|
const machineKey = deriveMachineKey();
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
|
|
4745
|
+
const content = machineKey ? encryptWithMachineKey(b64, machineKey) + "\n" : b64 + "\n";
|
|
4746
|
+
const result = machineKey ? "encrypted" : "plaintext";
|
|
4747
|
+
const tmpPath = keyPath + ".tmp";
|
|
4748
|
+
try {
|
|
4749
|
+
if (existsSync7(keyPath)) {
|
|
4750
|
+
await copyFile(keyPath, keyPath + ".bak").catch(() => {
|
|
4751
|
+
});
|
|
4752
|
+
}
|
|
4753
|
+
await writeFile3(tmpPath, content, "utf-8");
|
|
4754
|
+
await chmod2(tmpPath, 384);
|
|
4755
|
+
await rename(tmpPath, keyPath);
|
|
4756
|
+
} catch (err) {
|
|
4757
|
+
try {
|
|
4758
|
+
await unlink(tmpPath);
|
|
4759
|
+
} catch {
|
|
4760
|
+
}
|
|
4761
|
+
throw err;
|
|
4736
4762
|
}
|
|
4737
|
-
|
|
4738
|
-
await chmod2(keyPath, 384);
|
|
4739
|
-
return "plaintext";
|
|
4763
|
+
return result;
|
|
4740
4764
|
}
|
|
4741
4765
|
async function getMasterKey() {
|
|
4742
4766
|
let nativeValue = macKeychainGet() ?? linuxSecretGet();
|
|
@@ -4803,7 +4827,7 @@ async function getMasterKey() {
|
|
|
4803
4827
|
b64Value = content;
|
|
4804
4828
|
}
|
|
4805
4829
|
const key = Buffer.from(b64Value, "base64");
|
|
4806
|
-
if (
|
|
4830
|
+
if (isRootOnlyTrustedServerKeyFile(keyPath)) {
|
|
4807
4831
|
return key;
|
|
4808
4832
|
}
|
|
4809
4833
|
const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
|
|
@@ -193,6 +193,17 @@ function normalizeOrchestration(raw) {
|
|
|
193
193
|
const userOrg = raw.orchestration ?? {};
|
|
194
194
|
raw.orchestration = { ...defaultOrg, ...userOrg };
|
|
195
195
|
}
|
|
196
|
+
function normalizeCloudEndpoint(raw) {
|
|
197
|
+
const cloud = raw.cloud;
|
|
198
|
+
if (!cloud?.endpoint) return;
|
|
199
|
+
const ep = String(cloud.endpoint);
|
|
200
|
+
if (ep === "https://askexe.com/cloud" || ep === "https://askexe.com/cloud/") {
|
|
201
|
+
cloud.endpoint = "https://cloud.askexe.com";
|
|
202
|
+
process.stderr.write(
|
|
203
|
+
"[config] Auto-migrated cloud endpoint: askexe.com/cloud \u2192 cloud.askexe.com\n"
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
196
207
|
async function loadConfig() {
|
|
197
208
|
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
198
209
|
await ensurePrivateDir(dir);
|
|
@@ -218,6 +229,7 @@ async function loadConfig() {
|
|
|
218
229
|
normalizeSessionLifecycle(migratedCfg);
|
|
219
230
|
normalizeAutoUpdate(migratedCfg);
|
|
220
231
|
normalizeOrchestration(migratedCfg);
|
|
232
|
+
normalizeCloudEndpoint(migratedCfg);
|
|
221
233
|
const config = { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db"), ...migratedCfg };
|
|
222
234
|
if (config.dbPath.startsWith("~")) {
|
|
223
235
|
config.dbPath = config.dbPath.replace(/^~/, os.homedir());
|
|
@@ -4080,7 +4092,7 @@ init_memory();
|
|
|
4080
4092
|
init_database();
|
|
4081
4093
|
|
|
4082
4094
|
// src/lib/keychain.ts
|
|
4083
|
-
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
4095
|
+
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2, rename, copyFile } from "fs/promises";
|
|
4084
4096
|
import { existsSync as existsSync7, statSync as statSync3 } from "fs";
|
|
4085
4097
|
import { execSync as execSync3 } from "child_process";
|
|
4086
4098
|
import path6 from "path";
|
|
@@ -4119,12 +4131,14 @@ function linuxSecretAvailable() {
|
|
|
4119
4131
|
function isRootOnlyTrustedServerKeyFile(keyPath) {
|
|
4120
4132
|
if (process.platform !== "linux") return false;
|
|
4121
4133
|
try {
|
|
4122
|
-
const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
|
|
4123
4134
|
const st = statSync3(keyPath);
|
|
4124
4135
|
if (!st.isFile() || (st.mode & 63) !== 0) return false;
|
|
4136
|
+
const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
|
|
4125
4137
|
if (uid === 0) return true;
|
|
4126
4138
|
const exeOsDir = process.env.EXE_OS_DIR;
|
|
4127
|
-
|
|
4139
|
+
if (exeOsDir && path6.resolve(keyPath).startsWith(path6.resolve(exeOsDir) + path6.sep)) return true;
|
|
4140
|
+
if (!linuxSecretAvailable()) return true;
|
|
4141
|
+
return false;
|
|
4128
4142
|
} catch {
|
|
4129
4143
|
return false;
|
|
4130
4144
|
}
|
|
@@ -4275,15 +4289,25 @@ async function writeMachineBoundFileFallback(b64) {
|
|
|
4275
4289
|
await mkdir3(dir, { recursive: true });
|
|
4276
4290
|
const keyPath = getKeyPath();
|
|
4277
4291
|
const machineKey = deriveMachineKey();
|
|
4278
|
-
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
|
|
4292
|
+
const content = machineKey ? encryptWithMachineKey(b64, machineKey) + "\n" : b64 + "\n";
|
|
4293
|
+
const result = machineKey ? "encrypted" : "plaintext";
|
|
4294
|
+
const tmpPath = keyPath + ".tmp";
|
|
4295
|
+
try {
|
|
4296
|
+
if (existsSync7(keyPath)) {
|
|
4297
|
+
await copyFile(keyPath, keyPath + ".bak").catch(() => {
|
|
4298
|
+
});
|
|
4299
|
+
}
|
|
4300
|
+
await writeFile3(tmpPath, content, "utf-8");
|
|
4301
|
+
await chmod2(tmpPath, 384);
|
|
4302
|
+
await rename(tmpPath, keyPath);
|
|
4303
|
+
} catch (err) {
|
|
4304
|
+
try {
|
|
4305
|
+
await unlink(tmpPath);
|
|
4306
|
+
} catch {
|
|
4307
|
+
}
|
|
4308
|
+
throw err;
|
|
4283
4309
|
}
|
|
4284
|
-
|
|
4285
|
-
await chmod2(keyPath, 384);
|
|
4286
|
-
return "plaintext";
|
|
4310
|
+
return result;
|
|
4287
4311
|
}
|
|
4288
4312
|
async function getMasterKey() {
|
|
4289
4313
|
let nativeValue = macKeychainGet() ?? linuxSecretGet();
|
|
@@ -4350,7 +4374,7 @@ async function getMasterKey() {
|
|
|
4350
4374
|
b64Value = content;
|
|
4351
4375
|
}
|
|
4352
4376
|
const key = Buffer.from(b64Value, "base64");
|
|
4353
|
-
if (
|
|
4377
|
+
if (isRootOnlyTrustedServerKeyFile(keyPath)) {
|
|
4354
4378
|
return key;
|
|
4355
4379
|
}
|
|
4356
4380
|
const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
|
|
@@ -193,6 +193,17 @@ function normalizeOrchestration(raw) {
|
|
|
193
193
|
const userOrg = raw.orchestration ?? {};
|
|
194
194
|
raw.orchestration = { ...defaultOrg, ...userOrg };
|
|
195
195
|
}
|
|
196
|
+
function normalizeCloudEndpoint(raw) {
|
|
197
|
+
const cloud = raw.cloud;
|
|
198
|
+
if (!cloud?.endpoint) return;
|
|
199
|
+
const ep = String(cloud.endpoint);
|
|
200
|
+
if (ep === "https://askexe.com/cloud" || ep === "https://askexe.com/cloud/") {
|
|
201
|
+
cloud.endpoint = "https://cloud.askexe.com";
|
|
202
|
+
process.stderr.write(
|
|
203
|
+
"[config] Auto-migrated cloud endpoint: askexe.com/cloud \u2192 cloud.askexe.com\n"
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
196
207
|
async function loadConfig() {
|
|
197
208
|
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
198
209
|
await ensurePrivateDir(dir);
|
|
@@ -218,6 +229,7 @@ async function loadConfig() {
|
|
|
218
229
|
normalizeSessionLifecycle(migratedCfg);
|
|
219
230
|
normalizeAutoUpdate(migratedCfg);
|
|
220
231
|
normalizeOrchestration(migratedCfg);
|
|
232
|
+
normalizeCloudEndpoint(migratedCfg);
|
|
221
233
|
const config = { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db"), ...migratedCfg };
|
|
222
234
|
if (config.dbPath.startsWith("~")) {
|
|
223
235
|
config.dbPath = config.dbPath.replace(/^~/, os.homedir());
|
|
@@ -3101,7 +3113,7 @@ var init_database = __esm({
|
|
|
3101
3113
|
});
|
|
3102
3114
|
|
|
3103
3115
|
// src/lib/keychain.ts
|
|
3104
|
-
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
3116
|
+
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2, rename, copyFile } from "fs/promises";
|
|
3105
3117
|
import { existsSync as existsSync7, statSync as statSync3 } from "fs";
|
|
3106
3118
|
import { execSync as execSync3 } from "child_process";
|
|
3107
3119
|
import path6 from "path";
|
|
@@ -3136,12 +3148,14 @@ function linuxSecretAvailable() {
|
|
|
3136
3148
|
function isRootOnlyTrustedServerKeyFile(keyPath) {
|
|
3137
3149
|
if (process.platform !== "linux") return false;
|
|
3138
3150
|
try {
|
|
3139
|
-
const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
|
|
3140
3151
|
const st = statSync3(keyPath);
|
|
3141
3152
|
if (!st.isFile() || (st.mode & 63) !== 0) return false;
|
|
3153
|
+
const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
|
|
3142
3154
|
if (uid === 0) return true;
|
|
3143
3155
|
const exeOsDir = process.env.EXE_OS_DIR;
|
|
3144
|
-
|
|
3156
|
+
if (exeOsDir && path6.resolve(keyPath).startsWith(path6.resolve(exeOsDir) + path6.sep)) return true;
|
|
3157
|
+
if (!linuxSecretAvailable()) return true;
|
|
3158
|
+
return false;
|
|
3145
3159
|
} catch {
|
|
3146
3160
|
return false;
|
|
3147
3161
|
}
|
|
@@ -3291,15 +3305,25 @@ async function writeMachineBoundFileFallback(b64) {
|
|
|
3291
3305
|
await mkdir3(dir, { recursive: true });
|
|
3292
3306
|
const keyPath = getKeyPath();
|
|
3293
3307
|
const machineKey = deriveMachineKey();
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3308
|
+
const content = machineKey ? encryptWithMachineKey(b64, machineKey) + "\n" : b64 + "\n";
|
|
3309
|
+
const result = machineKey ? "encrypted" : "plaintext";
|
|
3310
|
+
const tmpPath = keyPath + ".tmp";
|
|
3311
|
+
try {
|
|
3312
|
+
if (existsSync7(keyPath)) {
|
|
3313
|
+
await copyFile(keyPath, keyPath + ".bak").catch(() => {
|
|
3314
|
+
});
|
|
3315
|
+
}
|
|
3316
|
+
await writeFile3(tmpPath, content, "utf-8");
|
|
3317
|
+
await chmod2(tmpPath, 384);
|
|
3318
|
+
await rename(tmpPath, keyPath);
|
|
3319
|
+
} catch (err) {
|
|
3320
|
+
try {
|
|
3321
|
+
await unlink(tmpPath);
|
|
3322
|
+
} catch {
|
|
3323
|
+
}
|
|
3324
|
+
throw err;
|
|
3299
3325
|
}
|
|
3300
|
-
|
|
3301
|
-
await chmod2(keyPath, 384);
|
|
3302
|
-
return "plaintext";
|
|
3326
|
+
return result;
|
|
3303
3327
|
}
|
|
3304
3328
|
async function getMasterKey() {
|
|
3305
3329
|
let nativeValue = macKeychainGet() ?? linuxSecretGet();
|
|
@@ -3366,7 +3390,7 @@ async function getMasterKey() {
|
|
|
3366
3390
|
b64Value = content;
|
|
3367
3391
|
}
|
|
3368
3392
|
const key = Buffer.from(b64Value, "base64");
|
|
3369
|
-
if (
|
|
3393
|
+
if (isRootOnlyTrustedServerKeyFile(keyPath)) {
|
|
3370
3394
|
return key;
|
|
3371
3395
|
}
|
|
3372
3396
|
const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
|