@askexenow/exe-os 0.8.85 → 0.8.86
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/cleanup-stale-review-tasks.js +57 -19
- package/dist/bin/cli.js +507 -337
- package/dist/bin/exe-agent-config.js +242 -0
- package/dist/bin/exe-agent.js +3 -3
- package/dist/bin/exe-boot.js +344 -346
- package/dist/bin/exe-dispatch.js +375 -250
- package/dist/bin/exe-forget.js +5 -1
- package/dist/bin/exe-gateway.js +260 -135
- package/dist/bin/exe-healthcheck.js +133 -1
- package/dist/bin/exe-heartbeat.js +72 -31
- package/dist/bin/exe-link.js +25 -2
- package/dist/bin/exe-new-employee.js +22 -0
- package/dist/bin/exe-pending-messages.js +55 -17
- package/dist/bin/exe-pending-reviews.js +57 -19
- package/dist/bin/exe-search.js +6 -2
- package/dist/bin/exe-session-cleanup.js +260 -135
- package/dist/bin/exe-start-codex.js +2598 -0
- package/dist/bin/exe-start.sh +15 -3
- package/dist/bin/exe-status.js +57 -19
- package/dist/bin/git-sweep.js +391 -266
- package/dist/bin/install.js +22 -0
- package/dist/bin/scan-tasks.js +394 -269
- package/dist/bin/setup.js +47 -2
- package/dist/gateway/index.js +257 -132
- package/dist/hooks/bug-report-worker.js +242 -117
- package/dist/hooks/commit-complete.js +389 -264
- package/dist/hooks/error-recall.js +6 -2
- package/dist/hooks/ingest-worker.js +314 -193
- package/dist/hooks/post-compact.js +84 -46
- package/dist/hooks/pre-compact.js +272 -147
- package/dist/hooks/pre-tool-use.js +104 -66
- package/dist/hooks/prompt-submit.js +126 -66
- package/dist/hooks/session-end.js +277 -152
- package/dist/hooks/session-start.js +70 -28
- package/dist/hooks/stop.js +90 -52
- package/dist/hooks/subagent-stop.js +84 -46
- package/dist/hooks/summary-worker.js +175 -114
- package/dist/index.js +296 -171
- package/dist/lib/agent-config.js +167 -0
- package/dist/lib/cloud-sync.js +25 -2
- package/dist/lib/exe-daemon.js +338 -213
- package/dist/lib/hybrid-search.js +7 -2
- package/dist/lib/messaging.js +95 -39
- package/dist/lib/runtime-table.js +16 -0
- package/dist/lib/session-wrappers.js +22 -0
- package/dist/lib/tasks.js +242 -117
- package/dist/lib/tmux-routing.js +314 -189
- package/dist/mcp/server.js +573 -274
- package/dist/mcp/tools/create-task.js +260 -135
- package/dist/mcp/tools/list-tasks.js +68 -30
- package/dist/mcp/tools/send-message.js +100 -44
- package/dist/mcp/tools/update-task.js +123 -67
- package/dist/runtime/index.js +276 -151
- package/dist/tui/App.js +479 -354
- package/package.json +1 -1
- package/src/commands/exe/agent-config.md +27 -0
- package/src/commands/exe/cc-doctor.md +10 -0
|
@@ -2802,17 +2802,53 @@ var init_provider_table = __esm({
|
|
|
2802
2802
|
}
|
|
2803
2803
|
});
|
|
2804
2804
|
|
|
2805
|
-
// src/lib/
|
|
2806
|
-
|
|
2805
|
+
// src/lib/runtime-table.ts
|
|
2806
|
+
var RUNTIME_TABLE;
|
|
2807
|
+
var init_runtime_table = __esm({
|
|
2808
|
+
"src/lib/runtime-table.ts"() {
|
|
2809
|
+
"use strict";
|
|
2810
|
+
RUNTIME_TABLE = {
|
|
2811
|
+
codex: {
|
|
2812
|
+
binary: "codex",
|
|
2813
|
+
launchMode: "exec",
|
|
2814
|
+
autoApproveFlag: "--full-auto",
|
|
2815
|
+
inlineFlag: "--no-alt-screen",
|
|
2816
|
+
apiKeyEnv: "OPENAI_API_KEY",
|
|
2817
|
+
defaultModel: "gpt-5.4"
|
|
2818
|
+
}
|
|
2819
|
+
};
|
|
2820
|
+
}
|
|
2821
|
+
});
|
|
2822
|
+
|
|
2823
|
+
// src/lib/agent-config.ts
|
|
2824
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync2, existsSync as existsSync7, mkdirSync as mkdirSync2 } from "fs";
|
|
2807
2825
|
import path8 from "path";
|
|
2826
|
+
var AGENT_CONFIG_PATH, DEFAULT_MODELS;
|
|
2827
|
+
var init_agent_config = __esm({
|
|
2828
|
+
"src/lib/agent-config.ts"() {
|
|
2829
|
+
"use strict";
|
|
2830
|
+
init_config();
|
|
2831
|
+
init_runtime_table();
|
|
2832
|
+
AGENT_CONFIG_PATH = path8.join(EXE_AI_DIR, "agent-config.json");
|
|
2833
|
+
DEFAULT_MODELS = {
|
|
2834
|
+
claude: "claude-opus-4",
|
|
2835
|
+
codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
|
|
2836
|
+
opencode: "minimax-m2.7"
|
|
2837
|
+
};
|
|
2838
|
+
}
|
|
2839
|
+
});
|
|
2840
|
+
|
|
2841
|
+
// src/lib/intercom-queue.ts
|
|
2842
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync3, renameSync as renameSync3, existsSync as existsSync8, mkdirSync as mkdirSync3 } from "fs";
|
|
2843
|
+
import path9 from "path";
|
|
2808
2844
|
import os6 from "os";
|
|
2809
2845
|
var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
|
|
2810
2846
|
var init_intercom_queue = __esm({
|
|
2811
2847
|
"src/lib/intercom-queue.ts"() {
|
|
2812
2848
|
"use strict";
|
|
2813
|
-
QUEUE_PATH =
|
|
2849
|
+
QUEUE_PATH = path9.join(os6.homedir(), ".exe-os", "intercom-queue.json");
|
|
2814
2850
|
TTL_MS = 60 * 60 * 1e3;
|
|
2815
|
-
INTERCOM_LOG =
|
|
2851
|
+
INTERCOM_LOG = path9.join(os6.homedir(), ".exe-os", "intercom.log");
|
|
2816
2852
|
}
|
|
2817
2853
|
});
|
|
2818
2854
|
|
|
@@ -2833,9 +2869,9 @@ __export(license_exports, {
|
|
|
2833
2869
|
stopLicenseRevalidation: () => stopLicenseRevalidation,
|
|
2834
2870
|
validateLicense: () => validateLicense
|
|
2835
2871
|
});
|
|
2836
|
-
import { readFileSync as
|
|
2872
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync4, existsSync as existsSync9, mkdirSync as mkdirSync4 } from "fs";
|
|
2837
2873
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
2838
|
-
import
|
|
2874
|
+
import path10 from "path";
|
|
2839
2875
|
import { jwtVerify, importSPKI } from "jose";
|
|
2840
2876
|
async function fetchRetry(url, init) {
|
|
2841
2877
|
try {
|
|
@@ -2846,37 +2882,37 @@ async function fetchRetry(url, init) {
|
|
|
2846
2882
|
}
|
|
2847
2883
|
}
|
|
2848
2884
|
function loadDeviceId() {
|
|
2849
|
-
const deviceJsonPath =
|
|
2885
|
+
const deviceJsonPath = path10.join(EXE_AI_DIR, "device.json");
|
|
2850
2886
|
try {
|
|
2851
|
-
if (
|
|
2852
|
-
const data = JSON.parse(
|
|
2887
|
+
if (existsSync9(deviceJsonPath)) {
|
|
2888
|
+
const data = JSON.parse(readFileSync7(deviceJsonPath, "utf8"));
|
|
2853
2889
|
if (data.deviceId) return data.deviceId;
|
|
2854
2890
|
}
|
|
2855
2891
|
} catch {
|
|
2856
2892
|
}
|
|
2857
2893
|
try {
|
|
2858
|
-
if (
|
|
2859
|
-
const id2 =
|
|
2894
|
+
if (existsSync9(DEVICE_ID_PATH)) {
|
|
2895
|
+
const id2 = readFileSync7(DEVICE_ID_PATH, "utf8").trim();
|
|
2860
2896
|
if (id2) return id2;
|
|
2861
2897
|
}
|
|
2862
2898
|
} catch {
|
|
2863
2899
|
}
|
|
2864
2900
|
const id = randomUUID3();
|
|
2865
|
-
|
|
2866
|
-
|
|
2901
|
+
mkdirSync4(EXE_AI_DIR, { recursive: true });
|
|
2902
|
+
writeFileSync4(DEVICE_ID_PATH, id, "utf8");
|
|
2867
2903
|
return id;
|
|
2868
2904
|
}
|
|
2869
2905
|
function loadLicense() {
|
|
2870
2906
|
try {
|
|
2871
|
-
if (!
|
|
2872
|
-
return
|
|
2907
|
+
if (!existsSync9(LICENSE_PATH)) return null;
|
|
2908
|
+
return readFileSync7(LICENSE_PATH, "utf8").trim();
|
|
2873
2909
|
} catch {
|
|
2874
2910
|
return null;
|
|
2875
2911
|
}
|
|
2876
2912
|
}
|
|
2877
2913
|
function saveLicense(apiKey) {
|
|
2878
|
-
|
|
2879
|
-
|
|
2914
|
+
mkdirSync4(EXE_AI_DIR, { recursive: true });
|
|
2915
|
+
writeFileSync4(LICENSE_PATH, apiKey.trim(), { encoding: "utf8", mode: 384 });
|
|
2880
2916
|
}
|
|
2881
2917
|
async function verifyLicenseJwt(token) {
|
|
2882
2918
|
try {
|
|
@@ -2902,8 +2938,8 @@ async function verifyLicenseJwt(token) {
|
|
|
2902
2938
|
}
|
|
2903
2939
|
async function getCachedLicense() {
|
|
2904
2940
|
try {
|
|
2905
|
-
if (!
|
|
2906
|
-
const raw = JSON.parse(
|
|
2941
|
+
if (!existsSync9(CACHE_PATH)) return null;
|
|
2942
|
+
const raw = JSON.parse(readFileSync7(CACHE_PATH, "utf8"));
|
|
2907
2943
|
if (!raw.token || typeof raw.token !== "string") return null;
|
|
2908
2944
|
return await verifyLicenseJwt(raw.token);
|
|
2909
2945
|
} catch {
|
|
@@ -2912,8 +2948,8 @@ async function getCachedLicense() {
|
|
|
2912
2948
|
}
|
|
2913
2949
|
function readCachedToken() {
|
|
2914
2950
|
try {
|
|
2915
|
-
if (!
|
|
2916
|
-
const raw = JSON.parse(
|
|
2951
|
+
if (!existsSync9(CACHE_PATH)) return null;
|
|
2952
|
+
const raw = JSON.parse(readFileSync7(CACHE_PATH, "utf8"));
|
|
2917
2953
|
return typeof raw.token === "string" ? raw.token : null;
|
|
2918
2954
|
} catch {
|
|
2919
2955
|
return null;
|
|
@@ -2947,7 +2983,7 @@ function getRawCachedPlan() {
|
|
|
2947
2983
|
}
|
|
2948
2984
|
function cacheResponse(token) {
|
|
2949
2985
|
try {
|
|
2950
|
-
|
|
2986
|
+
writeFileSync4(CACHE_PATH, JSON.stringify({ token }), "utf8");
|
|
2951
2987
|
} catch {
|
|
2952
2988
|
}
|
|
2953
2989
|
}
|
|
@@ -3011,9 +3047,9 @@ async function checkLicense() {
|
|
|
3011
3047
|
let key = loadLicense();
|
|
3012
3048
|
if (!key) {
|
|
3013
3049
|
try {
|
|
3014
|
-
const configPath =
|
|
3015
|
-
if (
|
|
3016
|
-
const raw = JSON.parse(
|
|
3050
|
+
const configPath = path10.join(EXE_AI_DIR, "config.json");
|
|
3051
|
+
if (existsSync9(configPath)) {
|
|
3052
|
+
const raw = JSON.parse(readFileSync7(configPath, "utf8"));
|
|
3017
3053
|
const cloud = raw.cloud;
|
|
3018
3054
|
if (cloud?.apiKey) {
|
|
3019
3055
|
key = cloud.apiKey;
|
|
@@ -3172,9 +3208,9 @@ var init_license = __esm({
|
|
|
3172
3208
|
"src/lib/license.ts"() {
|
|
3173
3209
|
"use strict";
|
|
3174
3210
|
init_config();
|
|
3175
|
-
LICENSE_PATH =
|
|
3176
|
-
CACHE_PATH =
|
|
3177
|
-
DEVICE_ID_PATH =
|
|
3211
|
+
LICENSE_PATH = path10.join(EXE_AI_DIR, "license.key");
|
|
3212
|
+
CACHE_PATH = path10.join(EXE_AI_DIR, "license-cache.json");
|
|
3213
|
+
DEVICE_ID_PATH = path10.join(EXE_AI_DIR, "device-id");
|
|
3178
3214
|
API_BASE = "https://askexe.com/cloud";
|
|
3179
3215
|
RETRY_DELAY_MS = 500;
|
|
3180
3216
|
LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
|
|
@@ -3214,12 +3250,12 @@ __export(plan_limits_exports, {
|
|
|
3214
3250
|
countActiveMemories: () => countActiveMemories,
|
|
3215
3251
|
getLicenseSync: () => getLicenseSync
|
|
3216
3252
|
});
|
|
3217
|
-
import { readFileSync as
|
|
3218
|
-
import
|
|
3253
|
+
import { readFileSync as readFileSync8, existsSync as existsSync10 } from "fs";
|
|
3254
|
+
import path11 from "path";
|
|
3219
3255
|
function getLicenseSync() {
|
|
3220
3256
|
try {
|
|
3221
|
-
if (!
|
|
3222
|
-
const raw = JSON.parse(
|
|
3257
|
+
if (!existsSync10(CACHE_PATH2)) return freeLicense();
|
|
3258
|
+
const raw = JSON.parse(readFileSync8(CACHE_PATH2, "utf8"));
|
|
3223
3259
|
if (!raw.token || typeof raw.token !== "string") return freeLicense();
|
|
3224
3260
|
const parts = raw.token.split(".");
|
|
3225
3261
|
if (parts.length !== 3) return freeLicense();
|
|
@@ -3286,8 +3322,8 @@ function assertEmployeeLimitSync(rosterPath) {
|
|
|
3286
3322
|
const filePath = rosterPath ?? EMPLOYEES_PATH;
|
|
3287
3323
|
let count = 0;
|
|
3288
3324
|
try {
|
|
3289
|
-
if (
|
|
3290
|
-
const raw =
|
|
3325
|
+
if (existsSync10(filePath)) {
|
|
3326
|
+
const raw = readFileSync8(filePath, "utf8");
|
|
3291
3327
|
const employees = JSON.parse(raw);
|
|
3292
3328
|
count = Array.isArray(employees) ? employees.length : 0;
|
|
3293
3329
|
}
|
|
@@ -3324,13 +3360,13 @@ var init_plan_limits = __esm({
|
|
|
3324
3360
|
this.name = "PlanLimitError";
|
|
3325
3361
|
}
|
|
3326
3362
|
};
|
|
3327
|
-
CACHE_PATH2 =
|
|
3363
|
+
CACHE_PATH2 = path11.join(EXE_AI_DIR, "license-cache.json");
|
|
3328
3364
|
}
|
|
3329
3365
|
});
|
|
3330
3366
|
|
|
3331
3367
|
// src/lib/tmux-routing.ts
|
|
3332
|
-
import { readFileSync as
|
|
3333
|
-
import
|
|
3368
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync5, mkdirSync as mkdirSync5, existsSync as existsSync11, appendFileSync } from "fs";
|
|
3369
|
+
import path12 from "path";
|
|
3334
3370
|
import os7 from "os";
|
|
3335
3371
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
3336
3372
|
function getMySession() {
|
|
@@ -3344,7 +3380,7 @@ function extractRootExe(name) {
|
|
|
3344
3380
|
}
|
|
3345
3381
|
function getParentExe(sessionKey) {
|
|
3346
3382
|
try {
|
|
3347
|
-
const data = JSON.parse(
|
|
3383
|
+
const data = JSON.parse(readFileSync9(path12.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
3348
3384
|
return data.parentExe || null;
|
|
3349
3385
|
} catch {
|
|
3350
3386
|
return null;
|
|
@@ -3373,13 +3409,15 @@ var init_tmux_routing = __esm({
|
|
|
3373
3409
|
init_cc_agent_support();
|
|
3374
3410
|
init_mcp_prefix();
|
|
3375
3411
|
init_provider_table();
|
|
3412
|
+
init_agent_config();
|
|
3413
|
+
init_runtime_table();
|
|
3376
3414
|
init_intercom_queue();
|
|
3377
3415
|
init_plan_limits();
|
|
3378
3416
|
init_employees();
|
|
3379
|
-
SPAWN_LOCK_DIR =
|
|
3380
|
-
SESSION_CACHE =
|
|
3381
|
-
INTERCOM_LOG2 =
|
|
3382
|
-
DEBOUNCE_FILE =
|
|
3417
|
+
SPAWN_LOCK_DIR = path12.join(os7.homedir(), ".exe-os", "spawn-locks");
|
|
3418
|
+
SESSION_CACHE = path12.join(os7.homedir(), ".exe-os", "session-cache");
|
|
3419
|
+
INTERCOM_LOG2 = path12.join(os7.homedir(), ".exe-os", "intercom.log");
|
|
3420
|
+
DEBOUNCE_FILE = path12.join(SESSION_CACHE, "intercom-debounce.json");
|
|
3383
3421
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
3384
3422
|
}
|
|
3385
3423
|
});
|
|
@@ -3445,10 +3483,10 @@ async function disposeEmbedder() {
|
|
|
3445
3483
|
async function embedDirect(text) {
|
|
3446
3484
|
const llamaCpp = await import("node-llama-cpp");
|
|
3447
3485
|
const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
3448
|
-
const { existsSync:
|
|
3449
|
-
const
|
|
3450
|
-
const modelPath =
|
|
3451
|
-
if (!
|
|
3486
|
+
const { existsSync: existsSync16 } = await import("fs");
|
|
3487
|
+
const path17 = await import("path");
|
|
3488
|
+
const modelPath = path17.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
|
|
3489
|
+
if (!existsSync16(modelPath)) {
|
|
3452
3490
|
throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
|
|
3453
3491
|
}
|
|
3454
3492
|
const llama = await llamaCpp.getLlama();
|
|
@@ -3486,14 +3524,14 @@ __export(worker_gate_exports, {
|
|
|
3486
3524
|
tryAcquireBackfillLock: () => tryAcquireBackfillLock,
|
|
3487
3525
|
tryAcquireWorkerSlot: () => tryAcquireWorkerSlot
|
|
3488
3526
|
});
|
|
3489
|
-
import { readdirSync as readdirSync3, writeFileSync as
|
|
3490
|
-
import
|
|
3527
|
+
import { readdirSync as readdirSync3, writeFileSync as writeFileSync6, unlinkSync as unlinkSync4, mkdirSync as mkdirSync6, existsSync as existsSync12 } from "fs";
|
|
3528
|
+
import path13 from "path";
|
|
3491
3529
|
function tryAcquireWorkerSlot() {
|
|
3492
3530
|
try {
|
|
3493
|
-
|
|
3531
|
+
mkdirSync6(WORKER_PID_DIR, { recursive: true });
|
|
3494
3532
|
const reservationId = `res-${process.pid}-${Date.now()}`;
|
|
3495
|
-
const reservationPath =
|
|
3496
|
-
|
|
3533
|
+
const reservationPath = path13.join(WORKER_PID_DIR, `${reservationId}.pid`);
|
|
3534
|
+
writeFileSync6(reservationPath, String(process.pid));
|
|
3497
3535
|
const files = readdirSync3(WORKER_PID_DIR);
|
|
3498
3536
|
let alive = 0;
|
|
3499
3537
|
for (const f of files) {
|
|
@@ -3510,7 +3548,7 @@ function tryAcquireWorkerSlot() {
|
|
|
3510
3548
|
alive++;
|
|
3511
3549
|
} catch {
|
|
3512
3550
|
try {
|
|
3513
|
-
unlinkSync4(
|
|
3551
|
+
unlinkSync4(path13.join(WORKER_PID_DIR, f));
|
|
3514
3552
|
} catch {
|
|
3515
3553
|
}
|
|
3516
3554
|
}
|
|
@@ -3533,21 +3571,21 @@ function tryAcquireWorkerSlot() {
|
|
|
3533
3571
|
}
|
|
3534
3572
|
function registerWorkerPid(pid) {
|
|
3535
3573
|
try {
|
|
3536
|
-
|
|
3537
|
-
|
|
3574
|
+
mkdirSync6(WORKER_PID_DIR, { recursive: true });
|
|
3575
|
+
writeFileSync6(path13.join(WORKER_PID_DIR, `worker-${pid}.pid`), String(pid));
|
|
3538
3576
|
} catch {
|
|
3539
3577
|
}
|
|
3540
3578
|
}
|
|
3541
3579
|
function cleanupWorkerPid() {
|
|
3542
3580
|
try {
|
|
3543
|
-
unlinkSync4(
|
|
3581
|
+
unlinkSync4(path13.join(WORKER_PID_DIR, `worker-${process.pid}.pid`));
|
|
3544
3582
|
} catch {
|
|
3545
3583
|
}
|
|
3546
3584
|
}
|
|
3547
3585
|
function tryAcquireBackfillLock() {
|
|
3548
3586
|
try {
|
|
3549
|
-
|
|
3550
|
-
if (
|
|
3587
|
+
mkdirSync6(WORKER_PID_DIR, { recursive: true });
|
|
3588
|
+
if (existsSync12(BACKFILL_LOCK)) {
|
|
3551
3589
|
try {
|
|
3552
3590
|
const pid = parseInt(
|
|
3553
3591
|
__require("fs").readFileSync(BACKFILL_LOCK, "utf8").trim(),
|
|
@@ -3563,7 +3601,7 @@ function tryAcquireBackfillLock() {
|
|
|
3563
3601
|
} catch {
|
|
3564
3602
|
}
|
|
3565
3603
|
}
|
|
3566
|
-
|
|
3604
|
+
writeFileSync6(BACKFILL_LOCK, String(process.pid));
|
|
3567
3605
|
return true;
|
|
3568
3606
|
} catch {
|
|
3569
3607
|
return true;
|
|
@@ -3580,9 +3618,9 @@ var init_worker_gate = __esm({
|
|
|
3580
3618
|
"src/lib/worker-gate.ts"() {
|
|
3581
3619
|
"use strict";
|
|
3582
3620
|
init_config();
|
|
3583
|
-
WORKER_PID_DIR =
|
|
3621
|
+
WORKER_PID_DIR = path13.join(EXE_AI_DIR, "worker-pids");
|
|
3584
3622
|
MAX_CONCURRENT_WORKERS = 3;
|
|
3585
|
-
BACKFILL_LOCK =
|
|
3623
|
+
BACKFILL_LOCK = path13.join(WORKER_PID_DIR, "backfill.lock");
|
|
3586
3624
|
}
|
|
3587
3625
|
});
|
|
3588
3626
|
|
|
@@ -3684,8 +3722,8 @@ __export(crdt_sync_exports, {
|
|
|
3684
3722
|
rebuildFromDb: () => rebuildFromDb
|
|
3685
3723
|
});
|
|
3686
3724
|
import * as Y from "yjs";
|
|
3687
|
-
import { readFileSync as
|
|
3688
|
-
import
|
|
3725
|
+
import { readFileSync as readFileSync10, writeFileSync as writeFileSync7, existsSync as existsSync13, mkdirSync as mkdirSync7, unlinkSync as unlinkSync5 } from "fs";
|
|
3726
|
+
import path14 from "path";
|
|
3689
3727
|
import { homedir } from "os";
|
|
3690
3728
|
function getStatePath() {
|
|
3691
3729
|
return _statePathOverride ?? DEFAULT_STATE_PATH;
|
|
@@ -3697,9 +3735,9 @@ function initCrdtDoc() {
|
|
|
3697
3735
|
if (doc) return doc;
|
|
3698
3736
|
doc = new Y.Doc();
|
|
3699
3737
|
const sp = getStatePath();
|
|
3700
|
-
if (
|
|
3738
|
+
if (existsSync13(sp)) {
|
|
3701
3739
|
try {
|
|
3702
|
-
const state =
|
|
3740
|
+
const state = readFileSync10(sp);
|
|
3703
3741
|
Y.applyUpdate(doc, new Uint8Array(state));
|
|
3704
3742
|
} catch {
|
|
3705
3743
|
console.warn("[crdt-sync] WARN: corrupted state file, rebuilding from DB");
|
|
@@ -3841,10 +3879,10 @@ function persistState() {
|
|
|
3841
3879
|
if (!doc) return;
|
|
3842
3880
|
try {
|
|
3843
3881
|
const sp = getStatePath();
|
|
3844
|
-
const dir =
|
|
3845
|
-
if (!
|
|
3882
|
+
const dir = path14.dirname(sp);
|
|
3883
|
+
if (!existsSync13(dir)) mkdirSync7(dir, { recursive: true });
|
|
3846
3884
|
const state = Y.encodeStateAsUpdate(doc);
|
|
3847
|
-
|
|
3885
|
+
writeFileSync7(sp, Buffer.from(state));
|
|
3848
3886
|
} catch {
|
|
3849
3887
|
}
|
|
3850
3888
|
}
|
|
@@ -3885,7 +3923,7 @@ var DEFAULT_STATE_PATH, _statePathOverride, doc;
|
|
|
3885
3923
|
var init_crdt_sync = __esm({
|
|
3886
3924
|
"src/lib/crdt-sync.ts"() {
|
|
3887
3925
|
"use strict";
|
|
3888
|
-
DEFAULT_STATE_PATH =
|
|
3926
|
+
DEFAULT_STATE_PATH = path14.join(homedir(), ".exe-os", "crdt-state.bin");
|
|
3889
3927
|
_statePathOverride = null;
|
|
3890
3928
|
doc = null;
|
|
3891
3929
|
}
|
|
@@ -3919,16 +3957,16 @@ __export(cloud_sync_exports, {
|
|
|
3919
3957
|
mergeRosterFromRemote: () => mergeRosterFromRemote,
|
|
3920
3958
|
recordRosterDeletion: () => recordRosterDeletion
|
|
3921
3959
|
});
|
|
3922
|
-
import { readFileSync as
|
|
3960
|
+
import { readFileSync as readFileSync11, writeFileSync as writeFileSync8, existsSync as existsSync14, readdirSync as readdirSync4, mkdirSync as mkdirSync8, appendFileSync as appendFileSync2, unlinkSync as unlinkSync6, openSync as openSync2, closeSync as closeSync2 } from "fs";
|
|
3923
3961
|
import crypto3 from "crypto";
|
|
3924
|
-
import
|
|
3962
|
+
import path15 from "path";
|
|
3925
3963
|
import { homedir as homedir2 } from "os";
|
|
3926
3964
|
function sqlSafe(v) {
|
|
3927
3965
|
return v === void 0 ? null : v;
|
|
3928
3966
|
}
|
|
3929
3967
|
function logError(msg) {
|
|
3930
3968
|
try {
|
|
3931
|
-
const logPath =
|
|
3969
|
+
const logPath = path15.join(homedir2(), ".exe-os", "workers.log");
|
|
3932
3970
|
appendFileSync2(logPath, `${(/* @__PURE__ */ new Date()).toISOString()} ${msg}
|
|
3933
3971
|
`);
|
|
3934
3972
|
} catch {
|
|
@@ -3938,18 +3976,18 @@ async function withRosterLock(fn) {
|
|
|
3938
3976
|
try {
|
|
3939
3977
|
const fd = openSync2(ROSTER_LOCK_PATH, "wx");
|
|
3940
3978
|
closeSync2(fd);
|
|
3941
|
-
|
|
3979
|
+
writeFileSync8(ROSTER_LOCK_PATH, String(Date.now()));
|
|
3942
3980
|
} catch (err) {
|
|
3943
3981
|
if (err.code === "EEXIST") {
|
|
3944
3982
|
try {
|
|
3945
|
-
const ts = parseInt(
|
|
3983
|
+
const ts = parseInt(readFileSync11(ROSTER_LOCK_PATH, "utf-8"), 10);
|
|
3946
3984
|
if (Date.now() - ts < LOCK_STALE_MS) {
|
|
3947
3985
|
throw new Error("Roster merge already in progress \u2014 another sync is running");
|
|
3948
3986
|
}
|
|
3949
3987
|
unlinkSync6(ROSTER_LOCK_PATH);
|
|
3950
3988
|
const fd = openSync2(ROSTER_LOCK_PATH, "wx");
|
|
3951
3989
|
closeSync2(fd);
|
|
3952
|
-
|
|
3990
|
+
writeFileSync8(ROSTER_LOCK_PATH, String(Date.now()));
|
|
3953
3991
|
} catch (retryErr) {
|
|
3954
3992
|
if (retryErr instanceof Error && retryErr.message.includes("already in progress")) throw retryErr;
|
|
3955
3993
|
throw new Error("Roster merge already in progress \u2014 another sync is running");
|
|
@@ -4323,8 +4361,8 @@ async function cloudSync(config) {
|
|
|
4323
4361
|
try {
|
|
4324
4362
|
const employees = await loadEmployees();
|
|
4325
4363
|
rosterResult.employees = employees.length;
|
|
4326
|
-
const idDir =
|
|
4327
|
-
if (
|
|
4364
|
+
const idDir = path15.join(EXE_AI_DIR, "identity");
|
|
4365
|
+
if (existsSync14(idDir)) {
|
|
4328
4366
|
rosterResult.identities = readdirSync4(idDir).filter((f) => f.endsWith(".md")).length;
|
|
4329
4367
|
}
|
|
4330
4368
|
} catch {
|
|
@@ -4345,55 +4383,63 @@ async function cloudSync(config) {
|
|
|
4345
4383
|
function recordRosterDeletion(name) {
|
|
4346
4384
|
let deletions = [];
|
|
4347
4385
|
try {
|
|
4348
|
-
if (
|
|
4349
|
-
deletions = JSON.parse(
|
|
4386
|
+
if (existsSync14(ROSTER_DELETIONS_PATH)) {
|
|
4387
|
+
deletions = JSON.parse(readFileSync11(ROSTER_DELETIONS_PATH, "utf-8"));
|
|
4350
4388
|
}
|
|
4351
4389
|
} catch {
|
|
4352
4390
|
}
|
|
4353
4391
|
if (!deletions.includes(name)) deletions.push(name);
|
|
4354
|
-
|
|
4392
|
+
writeFileSync8(ROSTER_DELETIONS_PATH, JSON.stringify(deletions));
|
|
4355
4393
|
}
|
|
4356
4394
|
function consumeRosterDeletions() {
|
|
4357
4395
|
try {
|
|
4358
|
-
if (!
|
|
4359
|
-
const deletions = JSON.parse(
|
|
4360
|
-
|
|
4396
|
+
if (!existsSync14(ROSTER_DELETIONS_PATH)) return [];
|
|
4397
|
+
const deletions = JSON.parse(readFileSync11(ROSTER_DELETIONS_PATH, "utf-8"));
|
|
4398
|
+
writeFileSync8(ROSTER_DELETIONS_PATH, "[]");
|
|
4361
4399
|
return deletions;
|
|
4362
4400
|
} catch {
|
|
4363
4401
|
return [];
|
|
4364
4402
|
}
|
|
4365
4403
|
}
|
|
4366
4404
|
function buildRosterBlob(paths) {
|
|
4367
|
-
const rosterPath = paths?.rosterPath ??
|
|
4368
|
-
const identityDir = paths?.identityDir ??
|
|
4369
|
-
const configPath = paths?.configPath ??
|
|
4405
|
+
const rosterPath = paths?.rosterPath ?? path15.join(EXE_AI_DIR, "exe-employees.json");
|
|
4406
|
+
const identityDir = paths?.identityDir ?? path15.join(EXE_AI_DIR, "identity");
|
|
4407
|
+
const configPath = paths?.configPath ?? path15.join(EXE_AI_DIR, "config.json");
|
|
4370
4408
|
let roster = [];
|
|
4371
|
-
if (
|
|
4409
|
+
if (existsSync14(rosterPath)) {
|
|
4372
4410
|
try {
|
|
4373
|
-
roster = JSON.parse(
|
|
4411
|
+
roster = JSON.parse(readFileSync11(rosterPath, "utf-8"));
|
|
4374
4412
|
} catch {
|
|
4375
4413
|
}
|
|
4376
4414
|
}
|
|
4377
4415
|
const identities = {};
|
|
4378
|
-
if (
|
|
4416
|
+
if (existsSync14(identityDir)) {
|
|
4379
4417
|
for (const file of readdirSync4(identityDir).filter((f) => f.endsWith(".md"))) {
|
|
4380
4418
|
try {
|
|
4381
|
-
identities[file] =
|
|
4419
|
+
identities[file] = readFileSync11(path15.join(identityDir, file), "utf-8");
|
|
4382
4420
|
} catch {
|
|
4383
4421
|
}
|
|
4384
4422
|
}
|
|
4385
4423
|
}
|
|
4386
4424
|
let config;
|
|
4387
|
-
if (
|
|
4425
|
+
if (existsSync14(configPath)) {
|
|
4426
|
+
try {
|
|
4427
|
+
config = JSON.parse(readFileSync11(configPath, "utf-8"));
|
|
4428
|
+
} catch {
|
|
4429
|
+
}
|
|
4430
|
+
}
|
|
4431
|
+
let agentConfig;
|
|
4432
|
+
const agentConfigPath = path15.join(EXE_AI_DIR, "agent-config.json");
|
|
4433
|
+
if (existsSync14(agentConfigPath)) {
|
|
4388
4434
|
try {
|
|
4389
|
-
|
|
4435
|
+
agentConfig = JSON.parse(readFileSync11(agentConfigPath, "utf-8"));
|
|
4390
4436
|
} catch {
|
|
4391
4437
|
}
|
|
4392
4438
|
}
|
|
4393
4439
|
const deletedNames = consumeRosterDeletions();
|
|
4394
|
-
const content = JSON.stringify({ roster, identities, config, deletedNames });
|
|
4440
|
+
const content = JSON.stringify({ roster, identities, config, agentConfig, deletedNames });
|
|
4395
4441
|
const hash = crypto3.createHash("sha256").update(content).digest("hex").slice(0, 16);
|
|
4396
|
-
return { roster, identities, config, deletedNames, version: hash };
|
|
4442
|
+
return { roster, identities, config, agentConfig, deletedNames, version: hash };
|
|
4397
4443
|
}
|
|
4398
4444
|
async function cloudPushRoster(config) {
|
|
4399
4445
|
assertSecureEndpoint(config.endpoint);
|
|
@@ -4462,23 +4508,23 @@ async function cloudPullRoster(config) {
|
|
|
4462
4508
|
}
|
|
4463
4509
|
}
|
|
4464
4510
|
function mergeConfig(remoteConfig, configPath) {
|
|
4465
|
-
const cfgPath = configPath ??
|
|
4511
|
+
const cfgPath = configPath ?? path15.join(EXE_AI_DIR, "config.json");
|
|
4466
4512
|
let local = {};
|
|
4467
|
-
if (
|
|
4513
|
+
if (existsSync14(cfgPath)) {
|
|
4468
4514
|
try {
|
|
4469
|
-
local = JSON.parse(
|
|
4515
|
+
local = JSON.parse(readFileSync11(cfgPath, "utf-8"));
|
|
4470
4516
|
} catch {
|
|
4471
4517
|
}
|
|
4472
4518
|
}
|
|
4473
4519
|
const merged = { ...remoteConfig, ...local };
|
|
4474
|
-
const dir =
|
|
4475
|
-
if (!
|
|
4476
|
-
|
|
4520
|
+
const dir = path15.dirname(cfgPath);
|
|
4521
|
+
if (!existsSync14(dir)) mkdirSync8(dir, { recursive: true });
|
|
4522
|
+
writeFileSync8(cfgPath, JSON.stringify(merged, null, 2), "utf-8");
|
|
4477
4523
|
}
|
|
4478
4524
|
async function mergeRosterFromRemote(remote, paths) {
|
|
4479
4525
|
return withRosterLock(async () => {
|
|
4480
4526
|
const rosterPath = paths?.rosterPath ?? void 0;
|
|
4481
|
-
const identityDir = paths?.identityDir ??
|
|
4527
|
+
const identityDir = paths?.identityDir ?? path15.join(EXE_AI_DIR, "identity");
|
|
4482
4528
|
const localEmployees = await loadEmployees(rosterPath);
|
|
4483
4529
|
const localNames = new Set(localEmployees.map((e) => e.name));
|
|
4484
4530
|
let added = 0;
|
|
@@ -4499,15 +4545,15 @@ async function mergeRosterFromRemote(remote, paths) {
|
|
|
4499
4545
|
) ?? lookupKey;
|
|
4500
4546
|
const remoteIdentity = remote.identities[matchedKey];
|
|
4501
4547
|
if (remoteIdentity) {
|
|
4502
|
-
if (!
|
|
4503
|
-
const idPath =
|
|
4548
|
+
if (!existsSync14(identityDir)) mkdirSync8(identityDir, { recursive: true });
|
|
4549
|
+
const idPath = path15.join(identityDir, `${remoteEmp.name}.md`);
|
|
4504
4550
|
let localIdentity = null;
|
|
4505
4551
|
try {
|
|
4506
|
-
localIdentity =
|
|
4552
|
+
localIdentity = existsSync14(idPath) ? readFileSync11(idPath, "utf-8") : null;
|
|
4507
4553
|
} catch {
|
|
4508
4554
|
}
|
|
4509
4555
|
if (localIdentity !== remoteIdentity) {
|
|
4510
|
-
|
|
4556
|
+
writeFileSync8(idPath, remoteIdentity, "utf-8");
|
|
4511
4557
|
identitiesUpdated++;
|
|
4512
4558
|
}
|
|
4513
4559
|
}
|
|
@@ -4531,6 +4577,21 @@ async function mergeRosterFromRemote(remote, paths) {
|
|
|
4531
4577
|
} catch {
|
|
4532
4578
|
}
|
|
4533
4579
|
}
|
|
4580
|
+
if (remote.agentConfig && Object.keys(remote.agentConfig).length > 0) {
|
|
4581
|
+
try {
|
|
4582
|
+
const agentConfigPath = path15.join(EXE_AI_DIR, "agent-config.json");
|
|
4583
|
+
let local = {};
|
|
4584
|
+
if (existsSync14(agentConfigPath)) {
|
|
4585
|
+
try {
|
|
4586
|
+
local = JSON.parse(readFileSync11(agentConfigPath, "utf-8"));
|
|
4587
|
+
} catch {
|
|
4588
|
+
}
|
|
4589
|
+
}
|
|
4590
|
+
const merged = { ...remote.agentConfig, ...local };
|
|
4591
|
+
writeFileSync8(agentConfigPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
|
|
4592
|
+
} catch {
|
|
4593
|
+
}
|
|
4594
|
+
}
|
|
4534
4595
|
return { added, identitiesUpdated };
|
|
4535
4596
|
});
|
|
4536
4597
|
}
|
|
@@ -4965,9 +5026,9 @@ var init_cloud_sync = __esm({
|
|
|
4965
5026
|
LOCALHOST_PATTERNS = /^(localhost|127\.0\.0\.1|\[::1\])$/i;
|
|
4966
5027
|
FETCH_TIMEOUT_MS = 3e4;
|
|
4967
5028
|
PUSH_BATCH_SIZE = 5e3;
|
|
4968
|
-
ROSTER_LOCK_PATH =
|
|
5029
|
+
ROSTER_LOCK_PATH = path15.join(EXE_AI_DIR, "roster-merge.lock");
|
|
4969
5030
|
LOCK_STALE_MS = 3e4;
|
|
4970
|
-
ROSTER_DELETIONS_PATH =
|
|
5031
|
+
ROSTER_DELETIONS_PATH = path15.join(EXE_AI_DIR, "roster-deletions.json");
|
|
4971
5032
|
}
|
|
4972
5033
|
});
|
|
4973
5034
|
|
|
@@ -5334,8 +5395,8 @@ init_task_scope();
|
|
|
5334
5395
|
init_employees();
|
|
5335
5396
|
import crypto4 from "crypto";
|
|
5336
5397
|
import { execSync as execSync4 } from "child_process";
|
|
5337
|
-
import { existsSync as
|
|
5338
|
-
import
|
|
5398
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync9, openSync as openSync3, closeSync as closeSync3 } from "fs";
|
|
5399
|
+
import path16 from "path";
|
|
5339
5400
|
async function main() {
|
|
5340
5401
|
const agentId = process.env.AGENT_ID ?? "default";
|
|
5341
5402
|
const agentRole = process.env.AGENT_ROLE ?? "employee";
|
|
@@ -5470,8 +5531,8 @@ async function main() {
|
|
|
5470
5531
|
}
|
|
5471
5532
|
try {
|
|
5472
5533
|
const { EXE_AI_DIR: EXE_AI_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
5473
|
-
const flagPath =
|
|
5474
|
-
if (
|
|
5534
|
+
const flagPath = path16.join(EXE_AI_DIR2, "session-cache", "needs-backfill");
|
|
5535
|
+
if (existsSync15(flagPath)) {
|
|
5475
5536
|
const { tryAcquireWorkerSlot: tryAcquireWorkerSlot2, registerWorkerPid: registerWorkerPid2 } = await Promise.resolve().then(() => (init_worker_gate(), worker_gate_exports));
|
|
5476
5537
|
if (!tryAcquireWorkerSlot2()) {
|
|
5477
5538
|
process.stderr.write("[summary-worker] Backfill needed but worker gate full \u2014 skipping\n");
|
|
@@ -5479,11 +5540,11 @@ async function main() {
|
|
|
5479
5540
|
const { spawn: spawn2 } = await import("child_process");
|
|
5480
5541
|
const { fileURLToPath: fileURLToPath3 } = await import("url");
|
|
5481
5542
|
const thisFile = fileURLToPath3(import.meta.url);
|
|
5482
|
-
const backfillPath =
|
|
5483
|
-
if (
|
|
5543
|
+
const backfillPath = path16.resolve(path16.dirname(thisFile), "backfill-vectors.js");
|
|
5544
|
+
if (existsSync15(backfillPath)) {
|
|
5484
5545
|
const { EXE_AI_DIR: exeDir2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
5485
|
-
const bLogPath =
|
|
5486
|
-
|
|
5546
|
+
const bLogPath = path16.join(exeDir2, "workers.log");
|
|
5547
|
+
mkdirSync9(path16.dirname(bLogPath), { recursive: true });
|
|
5487
5548
|
const bLogFd = openSync3(bLogPath, "a");
|
|
5488
5549
|
const child = spawn2(process.execPath, [backfillPath], {
|
|
5489
5550
|
detached: true,
|