@askexenow/exe-os 0.8.38 → 0.8.39
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/README.md +17 -8
- package/dist/bin/backfill-conversations.js +46 -10
- package/dist/bin/backfill-responses.js +46 -10
- package/dist/bin/backfill-vectors.js +42 -8
- package/dist/bin/cleanup-stale-review-tasks.js +37 -8
- package/dist/bin/cli.js +281 -154
- package/dist/bin/exe-agent.js +19 -4
- package/dist/bin/exe-assign.js +39 -5
- package/dist/bin/exe-boot.js +237 -111
- package/dist/bin/exe-call.js +11 -6
- package/dist/bin/exe-cloud.js +99 -28
- package/dist/bin/exe-dispatch.js +1 -1
- package/dist/bin/exe-doctor.js +37 -8
- package/dist/bin/exe-export-behaviors.js +39 -10
- package/dist/bin/exe-forget.js +38 -9
- package/dist/bin/exe-gateway.js +109 -42
- package/dist/bin/exe-heartbeat.js +49 -20
- package/dist/bin/exe-kill.js +39 -10
- package/dist/bin/exe-launch-agent.js +58 -22
- package/dist/bin/exe-link.js +184 -85
- package/dist/bin/exe-new-employee.js +21 -7
- package/dist/bin/exe-pending-messages.js +46 -17
- package/dist/bin/exe-pending-notifications.js +37 -8
- package/dist/bin/exe-pending-reviews.js +47 -18
- package/dist/bin/exe-rename.js +21 -7
- package/dist/bin/exe-review.js +34 -5
- package/dist/bin/exe-search.js +47 -10
- package/dist/bin/exe-session-cleanup.js +56 -19
- package/dist/bin/exe-settings.js +63 -2
- package/dist/bin/exe-status.js +34 -5
- package/dist/bin/exe-team.js +34 -5
- package/dist/bin/git-sweep.js +38 -9
- package/dist/bin/graph-backfill.js +37 -8
- package/dist/bin/graph-export.js +37 -8
- package/dist/bin/install.js +1 -1
- package/dist/bin/scan-tasks.js +40 -11
- package/dist/bin/setup.js +58 -24
- package/dist/bin/shard-migrate.js +37 -8
- package/dist/bin/wiki-sync.js +39 -9
- package/dist/gateway/index.js +102 -37
- package/dist/hooks/bug-report-worker.js +62 -28
- package/dist/hooks/commit-complete.js +38 -9
- package/dist/hooks/error-recall.js +49 -8
- package/dist/hooks/exe-heartbeat-hook.js +3 -2
- package/dist/hooks/ingest-worker.js +151 -37
- package/dist/hooks/ingest.js +74 -28
- package/dist/hooks/instructions-loaded.js +39 -9
- package/dist/hooks/notification.js +37 -7
- package/dist/hooks/post-compact.js +37 -7
- package/dist/hooks/pre-compact.js +35 -6
- package/dist/hooks/pre-tool-use.js +52 -14
- package/dist/hooks/prompt-ingest-worker.js +56 -10
- package/dist/hooks/prompt-submit.js +61 -23
- package/dist/hooks/response-ingest-worker.js +57 -11
- package/dist/hooks/session-end.js +43 -10
- package/dist/hooks/session-start.js +46 -8
- package/dist/hooks/stop.js +37 -7
- package/dist/hooks/subagent-stop.js +37 -7
- package/dist/hooks/summary-worker.js +317 -99
- package/dist/index.js +87 -22
- package/dist/lib/cloud-sync.js +172 -78
- package/dist/lib/config.js +4 -1
- package/dist/lib/consolidation.js +5 -4
- package/dist/lib/database.js +1 -0
- package/dist/lib/device-registry.js +2 -1
- package/dist/lib/embedder.js +9 -1
- package/dist/lib/employees.js +11 -6
- package/dist/lib/exe-daemon-client.js +6 -1
- package/dist/lib/exe-daemon.js +71 -28
- package/dist/lib/hybrid-search.js +47 -10
- package/dist/lib/identity.js +1 -1
- package/dist/lib/keychain.js +2 -1
- package/dist/lib/license.js +13 -4
- package/dist/lib/messaging.js +1 -1
- package/dist/lib/reminders.js +2 -2
- package/dist/lib/schedules.js +37 -8
- package/dist/lib/skill-learning.js +1 -1
- package/dist/lib/store.js +37 -8
- package/dist/lib/tasks.js +1 -1
- package/dist/lib/tmux-routing.js +1 -1
- package/dist/mcp/server.js +97 -43
- package/dist/mcp/tools/complete-reminder.js +1 -1
- package/dist/mcp/tools/create-task.js +14 -6
- package/dist/mcp/tools/deactivate-behavior.js +2 -2
- package/dist/mcp/tools/list-reminders.js +1 -1
- package/dist/mcp/tools/list-tasks.js +1 -1
- package/dist/mcp/tools/send-message.js +1 -1
- package/dist/mcp/tools/update-task.js +1 -1
- package/dist/runtime/index.js +35 -6
- package/dist/tui/App.js +177 -95
- package/package.json +3 -3
|
@@ -211,6 +211,7 @@ async function ensureSchema() {
|
|
|
211
211
|
const client = getRawClient();
|
|
212
212
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
213
213
|
await client.execute("PRAGMA busy_timeout = 30000");
|
|
214
|
+
await client.execute("PRAGMA wal_autocheckpoint = 1000");
|
|
214
215
|
try {
|
|
215
216
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
216
217
|
} catch {
|
|
@@ -1034,15 +1035,15 @@ __export(config_exports, {
|
|
|
1034
1035
|
migrateConfig: () => migrateConfig,
|
|
1035
1036
|
saveConfig: () => saveConfig
|
|
1036
1037
|
});
|
|
1037
|
-
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
1038
|
+
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
|
|
1038
1039
|
import { readFileSync as readFileSync2, existsSync as existsSync3, renameSync } from "fs";
|
|
1039
1040
|
import path4 from "path";
|
|
1040
|
-
import
|
|
1041
|
+
import os2 from "os";
|
|
1041
1042
|
function resolveDataDir() {
|
|
1042
1043
|
if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
|
|
1043
1044
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
1044
|
-
const newDir = path4.join(
|
|
1045
|
-
const legacyDir = path4.join(
|
|
1045
|
+
const newDir = path4.join(os2.homedir(), ".exe-os");
|
|
1046
|
+
const legacyDir = path4.join(os2.homedir(), ".exe-mem");
|
|
1046
1047
|
if (!existsSync3(newDir) && existsSync3(legacyDir)) {
|
|
1047
1048
|
try {
|
|
1048
1049
|
renameSync(legacyDir, newDir);
|
|
@@ -1129,7 +1130,7 @@ async function loadConfig() {
|
|
|
1129
1130
|
normalizeAutoUpdate(migratedCfg);
|
|
1130
1131
|
const config = { ...DEFAULT_CONFIG, dbPath: path4.join(dir, "memories.db"), ...migratedCfg };
|
|
1131
1132
|
if (config.dbPath.startsWith("~")) {
|
|
1132
|
-
config.dbPath = config.dbPath.replace(/^~/,
|
|
1133
|
+
config.dbPath = config.dbPath.replace(/^~/, os2.homedir());
|
|
1133
1134
|
}
|
|
1134
1135
|
return config;
|
|
1135
1136
|
} catch {
|
|
@@ -1160,6 +1161,9 @@ async function saveConfig(config) {
|
|
|
1160
1161
|
await mkdir2(dir, { recursive: true });
|
|
1161
1162
|
const configPath = path4.join(dir, "config.json");
|
|
1162
1163
|
await writeFile2(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
1164
|
+
if (config.cloud?.apiKey) {
|
|
1165
|
+
await chmod2(configPath, 384);
|
|
1166
|
+
}
|
|
1163
1167
|
}
|
|
1164
1168
|
async function loadConfigFrom(configPath) {
|
|
1165
1169
|
const raw = await readFile2(configPath, "utf-8");
|
|
@@ -1505,7 +1509,7 @@ var init_shard_manager = __esm({
|
|
|
1505
1509
|
// src/lib/notifications.ts
|
|
1506
1510
|
import crypto3 from "crypto";
|
|
1507
1511
|
import path6 from "path";
|
|
1508
|
-
import
|
|
1512
|
+
import os3 from "os";
|
|
1509
1513
|
import {
|
|
1510
1514
|
readFileSync as readFileSync3,
|
|
1511
1515
|
readdirSync as readdirSync3,
|
|
@@ -1591,6 +1595,14 @@ import { readFileSync as readFileSync5, writeFileSync, existsSync as existsSync7
|
|
|
1591
1595
|
import { randomUUID } from "crypto";
|
|
1592
1596
|
import path8 from "path";
|
|
1593
1597
|
import { jwtVerify, importSPKI } from "jose";
|
|
1598
|
+
async function fetchRetry(url, init) {
|
|
1599
|
+
try {
|
|
1600
|
+
return await fetch(url, init);
|
|
1601
|
+
} catch {
|
|
1602
|
+
await new Promise((r) => setTimeout(r, RETRY_DELAY_MS));
|
|
1603
|
+
return fetch(url, { ...init, signal: AbortSignal.timeout(1e4) });
|
|
1604
|
+
}
|
|
1605
|
+
}
|
|
1594
1606
|
function loadDeviceId() {
|
|
1595
1607
|
const deviceJsonPath = path8.join(EXE_AI_DIR, "device.json");
|
|
1596
1608
|
try {
|
|
@@ -1661,7 +1673,7 @@ function cacheResponse(token) {
|
|
|
1661
1673
|
async function validateLicense(apiKey, deviceId) {
|
|
1662
1674
|
const did = deviceId ?? loadDeviceId();
|
|
1663
1675
|
try {
|
|
1664
|
-
const res = await
|
|
1676
|
+
const res = await fetchRetry(`${API_BASE}/auth/activate`, {
|
|
1665
1677
|
method: "POST",
|
|
1666
1678
|
headers: { "Content-Type": "application/json" },
|
|
1667
1679
|
body: JSON.stringify({ apiKey, deviceId: did }),
|
|
@@ -1716,7 +1728,7 @@ async function checkLicense() {
|
|
|
1716
1728
|
const deviceId = loadDeviceId();
|
|
1717
1729
|
return validateLicense(key, deviceId);
|
|
1718
1730
|
}
|
|
1719
|
-
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, API_BASE, LICENSE_PUBLIC_KEY_PEM, LICENSE_JWT_ALG, PLAN_LIMITS, FREE_LICENSE, CACHE_MAX_AGE_MS;
|
|
1731
|
+
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, API_BASE, RETRY_DELAY_MS, LICENSE_PUBLIC_KEY_PEM, LICENSE_JWT_ALG, PLAN_LIMITS, FREE_LICENSE, CACHE_MAX_AGE_MS;
|
|
1720
1732
|
var init_license = __esm({
|
|
1721
1733
|
"src/lib/license.ts"() {
|
|
1722
1734
|
"use strict";
|
|
@@ -1725,6 +1737,7 @@ var init_license = __esm({
|
|
|
1725
1737
|
CACHE_PATH = path8.join(EXE_AI_DIR, "license-cache.json");
|
|
1726
1738
|
DEVICE_ID_PATH = path8.join(EXE_AI_DIR, "device-id");
|
|
1727
1739
|
API_BASE = "https://askexe.com/cloud";
|
|
1740
|
+
RETRY_DELAY_MS = 500;
|
|
1728
1741
|
LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
|
|
1729
1742
|
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
|
|
1730
1743
|
4uj+UqeKCcvtgNHKmOK278HJaJcANe9xAeji8AFYu27q3WtzCi04pHudow==
|
|
@@ -1856,6 +1869,10 @@ import path10 from "path";
|
|
|
1856
1869
|
import { fileURLToPath } from "url";
|
|
1857
1870
|
function handleData(chunk) {
|
|
1858
1871
|
_buffer += chunk.toString();
|
|
1872
|
+
if (_buffer.length > MAX_BUFFER) {
|
|
1873
|
+
_buffer = "";
|
|
1874
|
+
return;
|
|
1875
|
+
}
|
|
1859
1876
|
let newlineIdx;
|
|
1860
1877
|
while ((newlineIdx = _buffer.indexOf("\n")) !== -1) {
|
|
1861
1878
|
const line = _buffer.slice(0, newlineIdx).trim();
|
|
@@ -2163,7 +2180,7 @@ function disconnectClient() {
|
|
|
2163
2180
|
entry.resolve({ error: "Client disconnected" });
|
|
2164
2181
|
}
|
|
2165
2182
|
}
|
|
2166
|
-
var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, _socket, _connected, _buffer, _requestCount, HEALTH_CHECK_INTERVAL, _pending;
|
|
2183
|
+
var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, _socket, _connected, _buffer, _requestCount, HEALTH_CHECK_INTERVAL, _pending, MAX_BUFFER;
|
|
2167
2184
|
var init_exe_daemon_client = __esm({
|
|
2168
2185
|
"src/lib/exe-daemon-client.ts"() {
|
|
2169
2186
|
"use strict";
|
|
@@ -2180,6 +2197,7 @@ var init_exe_daemon_client = __esm({
|
|
|
2180
2197
|
_requestCount = 0;
|
|
2181
2198
|
HEALTH_CHECK_INTERVAL = 100;
|
|
2182
2199
|
_pending = /* @__PURE__ */ new Map();
|
|
2200
|
+
MAX_BUFFER = 1e7;
|
|
2183
2201
|
}
|
|
2184
2202
|
});
|
|
2185
2203
|
|
|
@@ -2221,8 +2239,8 @@ async function embedDirect(text) {
|
|
|
2221
2239
|
const llamaCpp = await import("node-llama-cpp");
|
|
2222
2240
|
const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
2223
2241
|
const { existsSync: existsSync15 } = await import("fs");
|
|
2224
|
-
const
|
|
2225
|
-
const modelPath =
|
|
2242
|
+
const path20 = await import("path");
|
|
2243
|
+
const modelPath = path20.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
|
|
2226
2244
|
if (!existsSync15(modelPath)) {
|
|
2227
2245
|
throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
|
|
2228
2246
|
}
|
|
@@ -2655,7 +2673,7 @@ var init_tasks_crud = __esm({
|
|
|
2655
2673
|
// src/lib/session-registry.ts
|
|
2656
2674
|
import { readFileSync as readFileSync9, writeFileSync as writeFileSync2, mkdirSync as mkdirSync3, existsSync as existsSync11 } from "fs";
|
|
2657
2675
|
import path12 from "path";
|
|
2658
|
-
import
|
|
2676
|
+
import os4 from "os";
|
|
2659
2677
|
function registerSession(entry) {
|
|
2660
2678
|
const dir = path12.dirname(REGISTRY_PATH);
|
|
2661
2679
|
if (!existsSync11(dir)) {
|
|
@@ -2682,7 +2700,7 @@ var REGISTRY_PATH;
|
|
|
2682
2700
|
var init_session_registry = __esm({
|
|
2683
2701
|
"src/lib/session-registry.ts"() {
|
|
2684
2702
|
"use strict";
|
|
2685
|
-
REGISTRY_PATH = path12.join(
|
|
2703
|
+
REGISTRY_PATH = path12.join(os4.homedir(), ".exe-os", "session-registry.json");
|
|
2686
2704
|
}
|
|
2687
2705
|
});
|
|
2688
2706
|
|
|
@@ -2881,7 +2899,7 @@ var init_provider_table = __esm({
|
|
|
2881
2899
|
// src/lib/intercom-queue.ts
|
|
2882
2900
|
import { readFileSync as readFileSync10, writeFileSync as writeFileSync3, renameSync as renameSync2, existsSync as existsSync12, mkdirSync as mkdirSync4 } from "fs";
|
|
2883
2901
|
import path13 from "path";
|
|
2884
|
-
import
|
|
2902
|
+
import os5 from "os";
|
|
2885
2903
|
function ensureDir() {
|
|
2886
2904
|
const dir = path13.dirname(QUEUE_PATH);
|
|
2887
2905
|
if (!existsSync12(dir)) mkdirSync4(dir, { recursive: true });
|
|
@@ -2921,9 +2939,9 @@ var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
|
|
|
2921
2939
|
var init_intercom_queue = __esm({
|
|
2922
2940
|
"src/lib/intercom-queue.ts"() {
|
|
2923
2941
|
"use strict";
|
|
2924
|
-
QUEUE_PATH = path13.join(
|
|
2942
|
+
QUEUE_PATH = path13.join(os5.homedir(), ".exe-os", "intercom-queue.json");
|
|
2925
2943
|
TTL_MS = 60 * 60 * 1e3;
|
|
2926
|
-
INTERCOM_LOG = path13.join(
|
|
2944
|
+
INTERCOM_LOG = path13.join(os5.homedir(), ".exe-os", "intercom.log");
|
|
2927
2945
|
}
|
|
2928
2946
|
});
|
|
2929
2947
|
|
|
@@ -2931,7 +2949,7 @@ var init_intercom_queue = __esm({
|
|
|
2931
2949
|
import { execFileSync as execFileSync2, execSync as execSync7 } from "child_process";
|
|
2932
2950
|
import { readFileSync as readFileSync11, writeFileSync as writeFileSync4, mkdirSync as mkdirSync5, existsSync as existsSync13, appendFileSync } from "fs";
|
|
2933
2951
|
import path14 from "path";
|
|
2934
|
-
import
|
|
2952
|
+
import os6 from "os";
|
|
2935
2953
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2936
2954
|
import { unlinkSync as unlinkSync3 } from "fs";
|
|
2937
2955
|
function spawnLockPath(sessionName) {
|
|
@@ -3236,7 +3254,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3236
3254
|
const transport = getTransport();
|
|
3237
3255
|
const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
|
|
3238
3256
|
const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
|
|
3239
|
-
const logDir = path14.join(
|
|
3257
|
+
const logDir = path14.join(os6.homedir(), ".exe-os", "session-logs");
|
|
3240
3258
|
const logFile = path14.join(logDir, `${instanceLabel}-${Date.now()}.log`);
|
|
3241
3259
|
if (!existsSync13(logDir)) {
|
|
3242
3260
|
mkdirSync5(logDir, { recursive: true });
|
|
@@ -3252,7 +3270,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3252
3270
|
} catch {
|
|
3253
3271
|
}
|
|
3254
3272
|
try {
|
|
3255
|
-
const claudeJsonPath = path14.join(
|
|
3273
|
+
const claudeJsonPath = path14.join(os6.homedir(), ".claude.json");
|
|
3256
3274
|
let claudeJson = {};
|
|
3257
3275
|
try {
|
|
3258
3276
|
claudeJson = JSON.parse(readFileSync11(claudeJsonPath, "utf8"));
|
|
@@ -3267,7 +3285,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3267
3285
|
} catch {
|
|
3268
3286
|
}
|
|
3269
3287
|
try {
|
|
3270
|
-
const settingsDir = path14.join(
|
|
3288
|
+
const settingsDir = path14.join(os6.homedir(), ".claude", "projects");
|
|
3271
3289
|
const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
|
|
3272
3290
|
const projSettingsDir = path14.join(settingsDir, normalizedKey);
|
|
3273
3291
|
const settingsPath = path14.join(projSettingsDir, "settings.json");
|
|
@@ -3315,7 +3333,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3315
3333
|
let legacyFallbackWarned = false;
|
|
3316
3334
|
if (!useExeAgent && !useBinSymlink) {
|
|
3317
3335
|
const identityPath = path14.join(
|
|
3318
|
-
|
|
3336
|
+
os6.homedir(),
|
|
3319
3337
|
".exe-os",
|
|
3320
3338
|
"identity",
|
|
3321
3339
|
`${employeeName}.md`
|
|
@@ -3345,7 +3363,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3345
3363
|
}
|
|
3346
3364
|
let sessionContextFlag = "";
|
|
3347
3365
|
try {
|
|
3348
|
-
const ctxDir = path14.join(
|
|
3366
|
+
const ctxDir = path14.join(os6.homedir(), ".exe-os", "session-cache");
|
|
3349
3367
|
mkdirSync5(ctxDir, { recursive: true });
|
|
3350
3368
|
const ctxFile = path14.join(ctxDir, `session-context-${sessionName}.md`);
|
|
3351
3369
|
const ctxContent = [
|
|
@@ -3456,11 +3474,11 @@ var init_tmux_routing = __esm({
|
|
|
3456
3474
|
init_provider_table();
|
|
3457
3475
|
init_intercom_queue();
|
|
3458
3476
|
init_plan_limits();
|
|
3459
|
-
SPAWN_LOCK_DIR = path14.join(
|
|
3460
|
-
SESSION_CACHE = path14.join(
|
|
3477
|
+
SPAWN_LOCK_DIR = path14.join(os6.homedir(), ".exe-os", "spawn-locks");
|
|
3478
|
+
SESSION_CACHE = path14.join(os6.homedir(), ".exe-os", "session-cache");
|
|
3461
3479
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
3462
3480
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
3463
|
-
INTERCOM_LOG2 = path14.join(
|
|
3481
|
+
INTERCOM_LOG2 = path14.join(os6.homedir(), ".exe-os", "intercom.log");
|
|
3464
3482
|
DEBOUNCE_FILE = path14.join(SESSION_CACHE, "intercom-debounce.json");
|
|
3465
3483
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
3466
3484
|
BUSY_PATTERN = /[✻✽✶✳·].*…|Running…/;
|
|
@@ -4288,11 +4306,69 @@ var init_tasks = __esm({
|
|
|
4288
4306
|
}
|
|
4289
4307
|
});
|
|
4290
4308
|
|
|
4309
|
+
// src/lib/worker-gate.ts
|
|
4310
|
+
var worker_gate_exports = {};
|
|
4311
|
+
__export(worker_gate_exports, {
|
|
4312
|
+
MAX_CONCURRENT_WORKERS: () => MAX_CONCURRENT_WORKERS,
|
|
4313
|
+
cleanupWorkerPid: () => cleanupWorkerPid,
|
|
4314
|
+
registerWorkerPid: () => registerWorkerPid,
|
|
4315
|
+
tryAcquireWorkerSlot: () => tryAcquireWorkerSlot
|
|
4316
|
+
});
|
|
4317
|
+
import { readdirSync as readdirSync5, writeFileSync as writeFileSync6, unlinkSync as unlinkSync6, mkdirSync as mkdirSync7 } from "fs";
|
|
4318
|
+
import path18 from "path";
|
|
4319
|
+
function tryAcquireWorkerSlot() {
|
|
4320
|
+
try {
|
|
4321
|
+
mkdirSync7(WORKER_PID_DIR, { recursive: true });
|
|
4322
|
+
const files = readdirSync5(WORKER_PID_DIR);
|
|
4323
|
+
let alive = 0;
|
|
4324
|
+
for (const f of files) {
|
|
4325
|
+
if (!f.endsWith(".pid")) continue;
|
|
4326
|
+
const dashIdx = f.lastIndexOf("-");
|
|
4327
|
+
const pid = parseInt(f.slice(dashIdx + 1).replace(".pid", ""), 10);
|
|
4328
|
+
if (isNaN(pid)) continue;
|
|
4329
|
+
try {
|
|
4330
|
+
process.kill(pid, 0);
|
|
4331
|
+
alive++;
|
|
4332
|
+
} catch {
|
|
4333
|
+
try {
|
|
4334
|
+
unlinkSync6(path18.join(WORKER_PID_DIR, f));
|
|
4335
|
+
} catch {
|
|
4336
|
+
}
|
|
4337
|
+
}
|
|
4338
|
+
}
|
|
4339
|
+
return alive < MAX_CONCURRENT_WORKERS;
|
|
4340
|
+
} catch {
|
|
4341
|
+
return true;
|
|
4342
|
+
}
|
|
4343
|
+
}
|
|
4344
|
+
function registerWorkerPid(pid) {
|
|
4345
|
+
try {
|
|
4346
|
+
mkdirSync7(WORKER_PID_DIR, { recursive: true });
|
|
4347
|
+
writeFileSync6(path18.join(WORKER_PID_DIR, `worker-${pid}.pid`), String(pid));
|
|
4348
|
+
} catch {
|
|
4349
|
+
}
|
|
4350
|
+
}
|
|
4351
|
+
function cleanupWorkerPid() {
|
|
4352
|
+
try {
|
|
4353
|
+
unlinkSync6(path18.join(WORKER_PID_DIR, `worker-${process.pid}.pid`));
|
|
4354
|
+
} catch {
|
|
4355
|
+
}
|
|
4356
|
+
}
|
|
4357
|
+
var WORKER_PID_DIR, MAX_CONCURRENT_WORKERS;
|
|
4358
|
+
var init_worker_gate = __esm({
|
|
4359
|
+
"src/lib/worker-gate.ts"() {
|
|
4360
|
+
"use strict";
|
|
4361
|
+
init_config();
|
|
4362
|
+
WORKER_PID_DIR = path18.join(EXE_AI_DIR, "worker-pids");
|
|
4363
|
+
MAX_CONCURRENT_WORKERS = 3;
|
|
4364
|
+
}
|
|
4365
|
+
});
|
|
4366
|
+
|
|
4291
4367
|
// src/adapters/claude/hooks/ingest-worker.ts
|
|
4292
4368
|
import crypto7 from "crypto";
|
|
4293
4369
|
import { execSync as execSync8 } from "child_process";
|
|
4294
|
-
import { mkdirSync as
|
|
4295
|
-
import
|
|
4370
|
+
import { mkdirSync as mkdirSync8, writeFileSync as writeFileSync7 } from "fs";
|
|
4371
|
+
import path19 from "path";
|
|
4296
4372
|
|
|
4297
4373
|
// src/lib/error-detector.ts
|
|
4298
4374
|
init_mcp_prefix();
|
|
@@ -4406,11 +4482,12 @@ init_database();
|
|
|
4406
4482
|
import { readFile, writeFile, unlink, mkdir, chmod } from "fs/promises";
|
|
4407
4483
|
import { existsSync as existsSync2 } from "fs";
|
|
4408
4484
|
import path3 from "path";
|
|
4485
|
+
import os from "os";
|
|
4409
4486
|
import crypto2 from "crypto";
|
|
4410
4487
|
var SERVICE = "exe-mem";
|
|
4411
4488
|
var ACCOUNT = "master-key";
|
|
4412
4489
|
function getKeyDir() {
|
|
4413
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path3.join(
|
|
4490
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path3.join(os.homedir(), ".exe-os");
|
|
4414
4491
|
}
|
|
4415
4492
|
function getKeyPath() {
|
|
4416
4493
|
return path3.join(getKeyDir(), "master.key");
|
|
@@ -4447,6 +4524,30 @@ async function getMasterKey() {
|
|
|
4447
4524
|
|
|
4448
4525
|
// src/lib/store.ts
|
|
4449
4526
|
init_config();
|
|
4527
|
+
var INIT_MAX_RETRIES = 3;
|
|
4528
|
+
var INIT_RETRY_DELAY_MS = 1e3;
|
|
4529
|
+
function isBusyError2(err) {
|
|
4530
|
+
if (err instanceof Error) {
|
|
4531
|
+
const msg = err.message.toLowerCase();
|
|
4532
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
4533
|
+
}
|
|
4534
|
+
return false;
|
|
4535
|
+
}
|
|
4536
|
+
async function retryOnBusy2(fn, label) {
|
|
4537
|
+
for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
|
|
4538
|
+
try {
|
|
4539
|
+
return await fn();
|
|
4540
|
+
} catch (err) {
|
|
4541
|
+
if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
|
|
4542
|
+
process.stderr.write(
|
|
4543
|
+
`[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
|
|
4544
|
+
`
|
|
4545
|
+
);
|
|
4546
|
+
await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
|
|
4547
|
+
}
|
|
4548
|
+
}
|
|
4549
|
+
throw new Error("unreachable");
|
|
4550
|
+
}
|
|
4450
4551
|
var _pendingRecords = [];
|
|
4451
4552
|
var _batchSize = 20;
|
|
4452
4553
|
var _flushIntervalMs = 1e4;
|
|
@@ -4481,14 +4582,17 @@ async function initStore(options) {
|
|
|
4481
4582
|
dbPath,
|
|
4482
4583
|
encryptionKey: hexKey
|
|
4483
4584
|
});
|
|
4484
|
-
await ensureSchema();
|
|
4585
|
+
await retryOnBusy2(() => ensureSchema(), "ensureSchema");
|
|
4485
4586
|
try {
|
|
4486
4587
|
const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
4487
4588
|
initShardManager2(hexKey);
|
|
4488
4589
|
} catch {
|
|
4489
4590
|
}
|
|
4490
4591
|
const client = getClient();
|
|
4491
|
-
const vResult = await
|
|
4592
|
+
const vResult = await retryOnBusy2(
|
|
4593
|
+
() => client.execute("SELECT MAX(version) as max_v FROM memories"),
|
|
4594
|
+
"version-query"
|
|
4595
|
+
);
|
|
4492
4596
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
4493
4597
|
}
|
|
4494
4598
|
function classifyTier(record) {
|
|
@@ -4787,9 +4891,9 @@ function extractBash(input2, response) {
|
|
|
4787
4891
|
}
|
|
4788
4892
|
function extractGrep(input2, response) {
|
|
4789
4893
|
const pattern = String(input2.pattern ?? "");
|
|
4790
|
-
const
|
|
4894
|
+
const path20 = input2.path ? String(input2.path) : "";
|
|
4791
4895
|
const output = String(response.text ?? response.content ?? JSON.stringify(response).slice(0, MAX_OUTPUT));
|
|
4792
|
-
return `Searched for "${pattern}"${
|
|
4896
|
+
return `Searched for "${pattern}"${path20 ? ` in ${path20}` : ""}
|
|
4793
4897
|
${output.slice(0, MAX_OUTPUT)}`;
|
|
4794
4898
|
}
|
|
4795
4899
|
function extractGlob(input2, response) {
|
|
@@ -4924,7 +5028,7 @@ process.stdin.on("end", async () => {
|
|
|
4924
5028
|
try {
|
|
4925
5029
|
const { EXE_AI_DIR: exeDir } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
4926
5030
|
const agentId2 = process.env.AGENT_ID;
|
|
4927
|
-
const cachePath =
|
|
5031
|
+
const cachePath = path19.join(exeDir, "session-cache", `current-task-${agentId2}.json`);
|
|
4928
5032
|
const { readFileSync: rf } = await import("fs");
|
|
4929
5033
|
const cached = JSON.parse(rf(cachePath, "utf8"));
|
|
4930
5034
|
taskId = cached.taskId ?? null;
|
|
@@ -4949,8 +5053,8 @@ process.stdin.on("end", async () => {
|
|
|
4949
5053
|
if (needsBackfill) {
|
|
4950
5054
|
try {
|
|
4951
5055
|
const { EXE_AI_DIR: exeDir } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
4952
|
-
const flagPath =
|
|
4953
|
-
|
|
5056
|
+
const flagPath = path19.join(exeDir, "session-cache", "needs-backfill");
|
|
5057
|
+
writeFileSync7(flagPath, "1");
|
|
4954
5058
|
} catch (err) {
|
|
4955
5059
|
process.stderr.write(`[ingest-worker] backfill flag write failed: ${err instanceof Error ? err.message : String(err)}
|
|
4956
5060
|
`);
|
|
@@ -5062,8 +5166,8 @@ process.stdin.on("end", async () => {
|
|
|
5062
5166
|
}
|
|
5063
5167
|
const cwd = data.cwd ?? process.cwd();
|
|
5064
5168
|
try {
|
|
5065
|
-
|
|
5066
|
-
|
|
5169
|
+
mkdirSync8(path19.join(cwd, "exe/output"), { recursive: true });
|
|
5170
|
+
mkdirSync8(path19.join(cwd, "exe/research"), { recursive: true });
|
|
5067
5171
|
const { ensureGitignoreExe: ensureGitignoreExe2 } = await Promise.resolve().then(() => (init_tasks(), tasks_exports));
|
|
5068
5172
|
await ensureGitignoreExe2(cwd);
|
|
5069
5173
|
} catch (err) {
|
|
@@ -5073,9 +5177,19 @@ process.stdin.on("end", async () => {
|
|
|
5073
5177
|
}
|
|
5074
5178
|
}
|
|
5075
5179
|
}
|
|
5180
|
+
try {
|
|
5181
|
+
const { getRawClient: getRawClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
5182
|
+
await getRawClient2().execute("PRAGMA wal_checkpoint(PASSIVE)");
|
|
5183
|
+
} catch {
|
|
5184
|
+
}
|
|
5076
5185
|
} catch (err) {
|
|
5077
5186
|
process.stderr.write(`[ingest-worker] FATAL: ${err instanceof Error ? err.message : String(err)}
|
|
5078
5187
|
`);
|
|
5188
|
+
}
|
|
5189
|
+
try {
|
|
5190
|
+
const { cleanupWorkerPid: cleanupWorkerPid2 } = await Promise.resolve().then(() => (init_worker_gate(), worker_gate_exports));
|
|
5191
|
+
cleanupWorkerPid2();
|
|
5192
|
+
} catch {
|
|
5079
5193
|
}
|
|
5080
5194
|
process.exit(0);
|
|
5081
5195
|
});
|
package/dist/hooks/ingest.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/lib/config.ts
|
|
2
|
-
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
2
|
+
import { readFile, writeFile, mkdir, chmod } from "fs/promises";
|
|
3
3
|
import { readFileSync, existsSync, renameSync } from "fs";
|
|
4
4
|
import path from "path";
|
|
5
5
|
import os from "os";
|
|
@@ -170,8 +170,8 @@ function loadConfigSync() {
|
|
|
170
170
|
|
|
171
171
|
// src/adapters/claude/hooks/ingest.ts
|
|
172
172
|
import { spawn } from "child_process";
|
|
173
|
-
import { readFileSync as readFileSync3, writeFileSync as
|
|
174
|
-
import
|
|
173
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3, existsSync as existsSync2, openSync, closeSync } from "fs";
|
|
174
|
+
import path4 from "path";
|
|
175
175
|
import { fileURLToPath } from "url";
|
|
176
176
|
|
|
177
177
|
// src/adapters/claude/active-agent.ts
|
|
@@ -412,6 +412,44 @@ function errorFingerprint(toolName, errorText) {
|
|
|
412
412
|
return crypto.createHash("sha256").update(`${toolName}:${normalized}`).digest("hex").slice(0, 16);
|
|
413
413
|
}
|
|
414
414
|
|
|
415
|
+
// src/lib/worker-gate.ts
|
|
416
|
+
import { readdirSync as readdirSync2, writeFileSync as writeFileSync2, unlinkSync as unlinkSync2, mkdirSync as mkdirSync2 } from "fs";
|
|
417
|
+
import path3 from "path";
|
|
418
|
+
var WORKER_PID_DIR = path3.join(EXE_AI_DIR, "worker-pids");
|
|
419
|
+
var MAX_CONCURRENT_WORKERS = 3;
|
|
420
|
+
function tryAcquireWorkerSlot() {
|
|
421
|
+
try {
|
|
422
|
+
mkdirSync2(WORKER_PID_DIR, { recursive: true });
|
|
423
|
+
const files = readdirSync2(WORKER_PID_DIR);
|
|
424
|
+
let alive = 0;
|
|
425
|
+
for (const f of files) {
|
|
426
|
+
if (!f.endsWith(".pid")) continue;
|
|
427
|
+
const dashIdx = f.lastIndexOf("-");
|
|
428
|
+
const pid = parseInt(f.slice(dashIdx + 1).replace(".pid", ""), 10);
|
|
429
|
+
if (isNaN(pid)) continue;
|
|
430
|
+
try {
|
|
431
|
+
process.kill(pid, 0);
|
|
432
|
+
alive++;
|
|
433
|
+
} catch {
|
|
434
|
+
try {
|
|
435
|
+
unlinkSync2(path3.join(WORKER_PID_DIR, f));
|
|
436
|
+
} catch {
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
return alive < MAX_CONCURRENT_WORKERS;
|
|
441
|
+
} catch {
|
|
442
|
+
return true;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
function registerWorkerPid(pid) {
|
|
446
|
+
try {
|
|
447
|
+
mkdirSync2(WORKER_PID_DIR, { recursive: true });
|
|
448
|
+
writeFileSync2(path3.join(WORKER_PID_DIR, `worker-${pid}.pid`), String(pid));
|
|
449
|
+
} catch {
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
415
453
|
// src/adapters/claude/hooks/ingest.ts
|
|
416
454
|
if (!process.env.AGENT_ID) {
|
|
417
455
|
process.env.AGENT_ID = "default";
|
|
@@ -420,7 +458,7 @@ if (!process.env.AGENT_ID) {
|
|
|
420
458
|
if (!loadConfigSync().autoIngestion) {
|
|
421
459
|
process.exit(0);
|
|
422
460
|
}
|
|
423
|
-
var WORKER_LOG_PATH =
|
|
461
|
+
var WORKER_LOG_PATH = path4.join(EXE_AI_DIR, "workers.log");
|
|
424
462
|
function openWorkerLog() {
|
|
425
463
|
try {
|
|
426
464
|
return openSync(WORKER_LOG_PATH, "a");
|
|
@@ -432,9 +470,9 @@ var ALLOWED_TOOL_RE = /^(Bash|Edit|Write|Read|Glob|Grep|Agent|mcp__.*)$/;
|
|
|
432
470
|
var WRITE_TOOL_RE = /^(Bash|Edit|Write)$/;
|
|
433
471
|
var SUMMARY_INTERVAL = 25;
|
|
434
472
|
var MIN_WRITES_FOR_SUMMARY = 3;
|
|
435
|
-
var COUNTER_DIR =
|
|
473
|
+
var COUNTER_DIR = path4.join(EXE_AI_DIR, "session-cache");
|
|
436
474
|
function getCounterPath(sessionId) {
|
|
437
|
-
return
|
|
475
|
+
return path4.join(COUNTER_DIR, `counter-${sessionId}.json`);
|
|
438
476
|
}
|
|
439
477
|
function loadCounter(sessionId) {
|
|
440
478
|
try {
|
|
@@ -446,8 +484,8 @@ function loadCounter(sessionId) {
|
|
|
446
484
|
}
|
|
447
485
|
function saveCounter(sessionId, counter) {
|
|
448
486
|
try {
|
|
449
|
-
|
|
450
|
-
|
|
487
|
+
mkdirSync3(COUNTER_DIR, { recursive: true });
|
|
488
|
+
writeFileSync3(getCounterPath(sessionId), JSON.stringify(counter));
|
|
451
489
|
} catch {
|
|
452
490
|
}
|
|
453
491
|
}
|
|
@@ -466,7 +504,7 @@ process.stdin.on("end", () => {
|
|
|
466
504
|
process.exit(0);
|
|
467
505
|
}
|
|
468
506
|
const agent = getActiveAgent();
|
|
469
|
-
if (/^(Read|Write|Edit)$/.test(data.tool_name) && agent.
|
|
507
|
+
if (/^(Read|Write|Edit)$/.test(data.tool_name) && agent.agentRole !== "COO" && agent.agentId !== "default") {
|
|
470
508
|
const filePath = data.tool_input?.file_path ?? "";
|
|
471
509
|
const exeMatch = filePath.match(/exe\/([^/]+)\//);
|
|
472
510
|
if (exeMatch && exeMatch[1] !== agent.agentId) {
|
|
@@ -483,7 +521,7 @@ Do NOT read, write, or modify files in another employee's folder.`
|
|
|
483
521
|
process.stdout.write(warning);
|
|
484
522
|
}
|
|
485
523
|
}
|
|
486
|
-
if (/^(Read|Glob|Grep|Bash)$/.test(data.tool_name) && agent.
|
|
524
|
+
if (/^(Read|Glob|Grep|Bash)$/.test(data.tool_name) && agent.agentRole === "COO") {
|
|
487
525
|
const target = data.tool_input?.file_path ?? data.tool_input?.path ?? data.tool_input?.pattern ?? String(data.tool_input?.command ?? "");
|
|
488
526
|
if (/exe\/exe\//.test(target)) {
|
|
489
527
|
const warning = JSON.stringify({
|
|
@@ -498,7 +536,7 @@ Open reviews are tracked in the tasks table: SELECT COUNT(*) FROM tasks WHERE as
|
|
|
498
536
|
process.stdout.write(warning);
|
|
499
537
|
}
|
|
500
538
|
}
|
|
501
|
-
if (/^(Write|Bash)$/.test(data.tool_name) && agent.
|
|
539
|
+
if (/^(Write|Bash)$/.test(data.tool_name) && agent.agentRole !== "COO" && agent.agentId !== "default") {
|
|
502
540
|
const filePath = data.tool_input?.file_path ?? String(data.tool_input?.command ?? "");
|
|
503
541
|
const outputMatch = filePath.match(/exe\/output\/([^/\-]+)-([^/]+)/);
|
|
504
542
|
if (outputMatch) {
|
|
@@ -522,7 +560,7 @@ Your output files must start with: exe/output/${agent.agentId}-`
|
|
|
522
560
|
const classification = classifyError(errorText);
|
|
523
561
|
if (classification === "system" && data.session_id) {
|
|
524
562
|
const fp = errorFingerprint(data.tool_name, errorText);
|
|
525
|
-
const fpFilePath =
|
|
563
|
+
const fpFilePath = path4.join(COUNTER_DIR, `bug-fingerprints-${data.session_id}.json`);
|
|
526
564
|
let fpData = {
|
|
527
565
|
seen: {},
|
|
528
566
|
taskCount: 0,
|
|
@@ -547,13 +585,13 @@ Your output files must start with: exe/output/${agent.agentId}-`
|
|
|
547
585
|
fpData.seen[fp] = { count: 1, firstAt: now, lastAt: now };
|
|
548
586
|
fpData.taskCount++;
|
|
549
587
|
fpData.lastTaskAt = now;
|
|
550
|
-
const bugWorkerPath =
|
|
551
|
-
|
|
588
|
+
const bugWorkerPath = path4.resolve(
|
|
589
|
+
path4.dirname(fileURLToPath(import.meta.url)),
|
|
552
590
|
"bug-report-worker.js"
|
|
553
591
|
);
|
|
554
|
-
if (existsSync2(bugWorkerPath)) {
|
|
592
|
+
if (existsSync2(bugWorkerPath) && tryAcquireWorkerSlot()) {
|
|
555
593
|
const stderrFd2 = openWorkerLog();
|
|
556
|
-
const projectName = process.cwd().split(
|
|
594
|
+
const projectName = process.cwd().split(path4.sep).pop() ?? "unknown";
|
|
557
595
|
const bugToolInput = data.tool_input ?? {};
|
|
558
596
|
const bugWorker = spawn(process.execPath, [bugWorkerPath], {
|
|
559
597
|
detached: true,
|
|
@@ -569,6 +607,7 @@ Your output files must start with: exe/output/${agent.agentId}-`
|
|
|
569
607
|
BUG_PROJECT_NAME: projectName
|
|
570
608
|
}
|
|
571
609
|
});
|
|
610
|
+
if (bugWorker.pid) registerWorkerPid(bugWorker.pid);
|
|
572
611
|
bugWorker.unref();
|
|
573
612
|
if (typeof stderrFd2 === "number") try {
|
|
574
613
|
closeSync(stderrFd2);
|
|
@@ -580,13 +619,13 @@ Your output files must start with: exe/output/${agent.agentId}-`
|
|
|
580
619
|
}
|
|
581
620
|
}
|
|
582
621
|
try {
|
|
583
|
-
|
|
584
|
-
|
|
622
|
+
mkdirSync3(COUNTER_DIR, { recursive: true });
|
|
623
|
+
writeFileSync3(fpFilePath, JSON.stringify(fpData));
|
|
585
624
|
} catch {
|
|
586
625
|
}
|
|
587
626
|
}
|
|
588
627
|
}
|
|
589
|
-
if (data.session_id && agent.
|
|
628
|
+
if (data.session_id && agent.agentRole !== "COO" && agent.agentId !== "default") {
|
|
590
629
|
const counter = loadCounter(data.session_id);
|
|
591
630
|
counter.total++;
|
|
592
631
|
if (WRITE_TOOL_RE.test(data.tool_name)) {
|
|
@@ -598,11 +637,11 @@ Your output files must start with: exe/output/${agent.agentId}-`
|
|
|
598
637
|
}
|
|
599
638
|
const callsSinceLastSummary = counter.total - counter.lastSummaryAt;
|
|
600
639
|
if (callsSinceLastSummary >= SUMMARY_INTERVAL && counter.writes >= MIN_WRITES_FOR_SUMMARY) {
|
|
601
|
-
const summaryWorkerPath =
|
|
602
|
-
|
|
640
|
+
const summaryWorkerPath = path4.resolve(
|
|
641
|
+
path4.dirname(fileURLToPath(import.meta.url)),
|
|
603
642
|
"summary-worker.js"
|
|
604
643
|
);
|
|
605
|
-
if (existsSync2(summaryWorkerPath)) {
|
|
644
|
+
if (existsSync2(summaryWorkerPath) && tryAcquireWorkerSlot()) {
|
|
606
645
|
const stderrFd2 = openWorkerLog();
|
|
607
646
|
const summaryWorker = spawn(process.execPath, [summaryWorkerPath], {
|
|
608
647
|
detached: true,
|
|
@@ -616,6 +655,7 @@ Your output files must start with: exe/output/${agent.agentId}-`
|
|
|
616
655
|
EXE_SUMMARY_WRITES: String(counter.writes)
|
|
617
656
|
}
|
|
618
657
|
});
|
|
658
|
+
if (summaryWorker.pid) registerWorkerPid(summaryWorker.pid);
|
|
619
659
|
summaryWorker.unref();
|
|
620
660
|
if (typeof stderrFd2 === "number") try {
|
|
621
661
|
closeSync(stderrFd2);
|
|
@@ -643,13 +683,13 @@ Your output files must start with: exe/output/${agent.agentId}-`
|
|
|
643
683
|
const bashOutput = typeof data.tool_response === "string" ? data.tool_response : JSON.stringify(data.tool_response ?? "");
|
|
644
684
|
const commitMatch = bashOutput.match(/\[(\S+)\s+([a-f0-9]{7,40})\]\s+(.+)/);
|
|
645
685
|
if (commitMatch) {
|
|
646
|
-
const commitWorkerPath =
|
|
647
|
-
|
|
686
|
+
const commitWorkerPath = path4.resolve(
|
|
687
|
+
path4.dirname(fileURLToPath(import.meta.url)),
|
|
648
688
|
"commit-complete.js"
|
|
649
689
|
);
|
|
650
|
-
if (existsSync2(commitWorkerPath)) {
|
|
690
|
+
if (existsSync2(commitWorkerPath) && tryAcquireWorkerSlot()) {
|
|
651
691
|
const stderrFd2 = openWorkerLog();
|
|
652
|
-
const projectName = process.cwd().split(
|
|
692
|
+
const projectName = process.cwd().split(path4.sep).pop() ?? "unknown";
|
|
653
693
|
const commitWorker = spawn(process.execPath, [commitWorkerPath], {
|
|
654
694
|
detached: true,
|
|
655
695
|
stdio: ["ignore", "ignore", stderrFd2],
|
|
@@ -661,6 +701,7 @@ Your output files must start with: exe/output/${agent.agentId}-`
|
|
|
661
701
|
PROJECT_NAME: projectName
|
|
662
702
|
}
|
|
663
703
|
});
|
|
704
|
+
if (commitWorker.pid) registerWorkerPid(commitWorker.pid);
|
|
664
705
|
commitWorker.unref();
|
|
665
706
|
if (typeof stderrFd2 === "number") try {
|
|
666
707
|
closeSync(stderrFd2);
|
|
@@ -672,16 +713,21 @@ Your output files must start with: exe/output/${agent.agentId}-`
|
|
|
672
713
|
if (!ALLOWED_TOOL_RE.test(data.tool_name)) {
|
|
673
714
|
process.exit(0);
|
|
674
715
|
}
|
|
675
|
-
const workerPath =
|
|
676
|
-
|
|
716
|
+
const workerPath = path4.resolve(
|
|
717
|
+
path4.dirname(fileURLToPath(import.meta.url)),
|
|
677
718
|
"ingest-worker.js"
|
|
678
719
|
);
|
|
720
|
+
if (!tryAcquireWorkerSlot()) {
|
|
721
|
+
process.stderr.write("[ingest] Worker concurrency limit reached, skipping ingestion\n");
|
|
722
|
+
process.exit(0);
|
|
723
|
+
}
|
|
679
724
|
const stderrFd = openWorkerLog();
|
|
680
725
|
const worker = spawn(process.execPath, [workerPath], {
|
|
681
726
|
detached: true,
|
|
682
727
|
stdio: ["pipe", "ignore", stderrFd],
|
|
683
728
|
env: { ...process.env, AGENT_ID: agent.agentId, AGENT_ROLE: agent.agentRole }
|
|
684
729
|
});
|
|
730
|
+
if (worker.pid) registerWorkerPid(worker.pid);
|
|
685
731
|
worker.stdin.write(input);
|
|
686
732
|
worker.stdin.end();
|
|
687
733
|
worker.unref();
|