@askexenow/exe-os 0.9.8 → 0.9.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/backfill-conversations.js +222 -49
- package/dist/bin/backfill-responses.js +221 -48
- package/dist/bin/backfill-vectors.js +225 -52
- package/dist/bin/cleanup-stale-review-tasks.js +150 -28
- package/dist/bin/cli.js +1295 -856
- package/dist/bin/exe-agent-config.js +36 -8
- package/dist/bin/exe-agent.js +14 -4
- package/dist/bin/exe-assign.js +221 -48
- package/dist/bin/exe-boot.js +778 -427
- package/dist/bin/exe-call.js +41 -13
- package/dist/bin/exe-cloud.js +163 -58
- package/dist/bin/exe-dispatch.js +276 -139
- package/dist/bin/exe-doctor.js +145 -27
- package/dist/bin/exe-export-behaviors.js +141 -23
- package/dist/bin/exe-forget.js +137 -19
- package/dist/bin/exe-gateway.js +677 -388
- package/dist/bin/exe-heartbeat.js +227 -108
- package/dist/bin/exe-kill.js +138 -20
- package/dist/bin/exe-launch-agent.js +172 -39
- package/dist/bin/exe-link.js +291 -100
- package/dist/bin/exe-new-employee.js +214 -106
- package/dist/bin/exe-pending-messages.js +395 -33
- package/dist/bin/exe-pending-notifications.js +684 -99
- package/dist/bin/exe-pending-reviews.js +420 -74
- package/dist/bin/exe-rename.js +147 -49
- package/dist/bin/exe-review.js +138 -20
- package/dist/bin/exe-search.js +240 -69
- package/dist/bin/exe-session-cleanup.js +440 -250
- package/dist/bin/exe-settings.js +61 -17
- package/dist/bin/exe-start-codex.js +158 -39
- package/dist/bin/exe-start-opencode.js +157 -38
- package/dist/bin/exe-status.js +151 -29
- package/dist/bin/exe-team.js +138 -20
- package/dist/bin/git-sweep.js +404 -212
- package/dist/bin/graph-backfill.js +137 -19
- package/dist/bin/graph-export.js +140 -22
- package/dist/bin/install.js +90 -61
- package/dist/bin/scan-tasks.js +412 -220
- package/dist/bin/setup.js +564 -293
- package/dist/bin/shard-migrate.js +139 -21
- package/dist/bin/update.js +138 -49
- package/dist/bin/wiki-sync.js +137 -19
- package/dist/gateway/index.js +533 -320
- package/dist/hooks/bug-report-worker.js +344 -193
- package/dist/hooks/codex-stop-task-finalizer.js +4678 -0
- package/dist/hooks/commit-complete.js +402 -210
- package/dist/hooks/error-recall.js +245 -74
- package/dist/hooks/exe-heartbeat-hook.js +16 -6
- package/dist/hooks/ingest-worker.js +3423 -3157
- package/dist/hooks/ingest.js +832 -97
- package/dist/hooks/instructions-loaded.js +227 -54
- package/dist/hooks/notification.js +216 -43
- package/dist/hooks/post-compact.js +239 -62
- package/dist/hooks/pre-compact.js +408 -216
- package/dist/hooks/pre-tool-use.js +268 -90
- package/dist/hooks/prompt-ingest-worker.js +352 -102
- package/dist/hooks/prompt-submit.js +541 -328
- package/dist/hooks/response-ingest-worker.js +372 -122
- package/dist/hooks/session-end.js +443 -240
- package/dist/hooks/session-start.js +313 -127
- package/dist/hooks/stop.js +293 -98
- package/dist/hooks/subagent-stop.js +239 -62
- package/dist/hooks/summary-worker.js +568 -236
- package/dist/index.js +538 -324
- package/dist/lib/agent-config.js +28 -6
- package/dist/lib/cloud-sync.js +284 -105
- package/dist/lib/config.js +30 -10
- package/dist/lib/consolidation.js +16 -6
- package/dist/lib/database.js +123 -25
- package/dist/lib/db-daemon-client.js +73 -19
- package/dist/lib/db.js +123 -25
- package/dist/lib/device-registry.js +133 -35
- package/dist/lib/embedder.js +107 -32
- package/dist/lib/employee-templates.js +14 -4
- package/dist/lib/employees.js +41 -13
- package/dist/lib/exe-daemon-client.js +88 -22
- package/dist/lib/exe-daemon.js +935 -587
- package/dist/lib/hybrid-search.js +240 -69
- package/dist/lib/identity.js +18 -8
- package/dist/lib/license.js +133 -48
- package/dist/lib/messaging.js +116 -56
- package/dist/lib/reminders.js +14 -4
- package/dist/lib/schedules.js +137 -19
- package/dist/lib/skill-learning.js +33 -6
- package/dist/lib/store.js +137 -19
- package/dist/lib/task-router.js +14 -4
- package/dist/lib/tasks.js +280 -234
- package/dist/lib/tmux-routing.js +172 -125
- package/dist/lib/token-spend.js +26 -8
- package/dist/mcp/server.js +1326 -609
- package/dist/mcp/tools/complete-reminder.js +14 -4
- package/dist/mcp/tools/create-reminder.js +14 -4
- package/dist/mcp/tools/create-task.js +306 -248
- package/dist/mcp/tools/deactivate-behavior.js +16 -6
- package/dist/mcp/tools/list-reminders.js +14 -4
- package/dist/mcp/tools/list-tasks.js +123 -107
- package/dist/mcp/tools/send-message.js +75 -29
- package/dist/mcp/tools/update-task.js +1848 -199
- package/dist/runtime/index.js +441 -248
- package/dist/tui/App.js +761 -424
- package/package.json +1 -1
package/dist/hooks/ingest.js
CHANGED
|
@@ -1,11 +1,47 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
1
2
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
4
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
5
|
+
}) : x)(function(x) {
|
|
6
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
7
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
8
|
+
});
|
|
2
9
|
var __esm = (fn, res) => function __init() {
|
|
3
10
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
4
11
|
};
|
|
12
|
+
var __export = (target, all) => {
|
|
13
|
+
for (var name in all)
|
|
14
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
// src/lib/secure-files.ts
|
|
18
|
+
import { chmodSync, existsSync, mkdirSync } from "fs";
|
|
19
|
+
import { chmod, mkdir } from "fs/promises";
|
|
20
|
+
function ensurePrivateDirSync(dirPath) {
|
|
21
|
+
mkdirSync(dirPath, { recursive: true, mode: PRIVATE_DIR_MODE });
|
|
22
|
+
try {
|
|
23
|
+
chmodSync(dirPath, PRIVATE_DIR_MODE);
|
|
24
|
+
} catch {
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function enforcePrivateFileSync(filePath) {
|
|
28
|
+
try {
|
|
29
|
+
if (existsSync(filePath)) chmodSync(filePath, PRIVATE_FILE_MODE);
|
|
30
|
+
} catch {
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
var PRIVATE_DIR_MODE, PRIVATE_FILE_MODE;
|
|
34
|
+
var init_secure_files = __esm({
|
|
35
|
+
"src/lib/secure-files.ts"() {
|
|
36
|
+
"use strict";
|
|
37
|
+
PRIVATE_DIR_MODE = 448;
|
|
38
|
+
PRIVATE_FILE_MODE = 384;
|
|
39
|
+
}
|
|
40
|
+
});
|
|
5
41
|
|
|
6
42
|
// src/lib/config.ts
|
|
7
|
-
import { readFile, writeFile
|
|
8
|
-
import { readFileSync, existsSync, renameSync } from "fs";
|
|
43
|
+
import { readFile, writeFile } from "fs/promises";
|
|
44
|
+
import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
|
|
9
45
|
import path from "path";
|
|
10
46
|
import os from "os";
|
|
11
47
|
function resolveDataDir() {
|
|
@@ -13,7 +49,7 @@ function resolveDataDir() {
|
|
|
13
49
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
14
50
|
const newDir = path.join(os.homedir(), ".exe-os");
|
|
15
51
|
const legacyDir = path.join(os.homedir(), ".exe-mem");
|
|
16
|
-
if (!
|
|
52
|
+
if (!existsSync2(newDir) && existsSync2(legacyDir)) {
|
|
17
53
|
try {
|
|
18
54
|
renameSync(legacyDir, newDir);
|
|
19
55
|
process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
|
|
@@ -77,7 +113,7 @@ function normalizeAutoUpdate(raw) {
|
|
|
77
113
|
function loadConfigSync() {
|
|
78
114
|
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
79
115
|
const configPath = path.join(dir, "config.json");
|
|
80
|
-
if (!
|
|
116
|
+
if (!existsSync2(configPath)) {
|
|
81
117
|
return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db") };
|
|
82
118
|
}
|
|
83
119
|
try {
|
|
@@ -97,6 +133,7 @@ var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CON
|
|
|
97
133
|
var init_config = __esm({
|
|
98
134
|
"src/lib/config.ts"() {
|
|
99
135
|
"use strict";
|
|
136
|
+
init_secure_files();
|
|
100
137
|
EXE_AI_DIR = resolveDataDir();
|
|
101
138
|
DB_PATH = path.join(EXE_AI_DIR, "memories.db");
|
|
102
139
|
MODELS_DIR = path.join(EXE_AI_DIR, "models");
|
|
@@ -173,19 +210,703 @@ var init_config = __esm({
|
|
|
173
210
|
}
|
|
174
211
|
});
|
|
175
212
|
|
|
213
|
+
// src/lib/runtime-table.ts
|
|
214
|
+
var RUNTIME_TABLE, DEFAULT_RUNTIME;
|
|
215
|
+
var init_runtime_table = __esm({
|
|
216
|
+
"src/lib/runtime-table.ts"() {
|
|
217
|
+
"use strict";
|
|
218
|
+
RUNTIME_TABLE = {
|
|
219
|
+
codex: {
|
|
220
|
+
binary: "codex",
|
|
221
|
+
launchMode: "interactive",
|
|
222
|
+
autoApproveFlag: "--dangerously-bypass-approvals-and-sandbox",
|
|
223
|
+
inlineFlag: "--no-alt-screen",
|
|
224
|
+
apiKeyEnv: "OPENAI_API_KEY",
|
|
225
|
+
defaultModel: "gpt-5.4"
|
|
226
|
+
},
|
|
227
|
+
opencode: {
|
|
228
|
+
binary: "opencode",
|
|
229
|
+
launchMode: "exec",
|
|
230
|
+
autoApproveFlag: "--dangerously-skip-permissions",
|
|
231
|
+
inlineFlag: "",
|
|
232
|
+
apiKeyEnv: "ANTHROPIC_API_KEY",
|
|
233
|
+
defaultModel: "anthropic/claude-sonnet-4-6"
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
DEFAULT_RUNTIME = "claude";
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
// src/lib/agent-config.ts
|
|
241
|
+
var agent_config_exports = {};
|
|
242
|
+
__export(agent_config_exports, {
|
|
243
|
+
AGENT_CONFIG_PATH: () => AGENT_CONFIG_PATH,
|
|
244
|
+
DEFAULT_MODELS: () => DEFAULT_MODELS,
|
|
245
|
+
KNOWN_RUNTIMES: () => KNOWN_RUNTIMES,
|
|
246
|
+
RUNTIME_LABELS: () => RUNTIME_LABELS,
|
|
247
|
+
clearAgentRuntime: () => clearAgentRuntime,
|
|
248
|
+
getAgentRuntime: () => getAgentRuntime,
|
|
249
|
+
loadAgentConfig: () => loadAgentConfig,
|
|
250
|
+
saveAgentConfig: () => saveAgentConfig,
|
|
251
|
+
setAgentRuntime: () => setAgentRuntime
|
|
252
|
+
});
|
|
253
|
+
import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync3 } from "fs";
|
|
254
|
+
import path2 from "path";
|
|
255
|
+
function loadAgentConfig() {
|
|
256
|
+
if (!existsSync3(AGENT_CONFIG_PATH)) return {};
|
|
257
|
+
try {
|
|
258
|
+
return JSON.parse(readFileSync2(AGENT_CONFIG_PATH, "utf-8"));
|
|
259
|
+
} catch {
|
|
260
|
+
return {};
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
function saveAgentConfig(config) {
|
|
264
|
+
const dir = path2.dirname(AGENT_CONFIG_PATH);
|
|
265
|
+
ensurePrivateDirSync(dir);
|
|
266
|
+
writeFileSync(AGENT_CONFIG_PATH, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
267
|
+
enforcePrivateFileSync(AGENT_CONFIG_PATH);
|
|
268
|
+
}
|
|
269
|
+
function getAgentRuntime(agentId) {
|
|
270
|
+
const config = loadAgentConfig();
|
|
271
|
+
const entry = config[agentId];
|
|
272
|
+
if (entry) return entry;
|
|
273
|
+
const orgDefault = config["default"];
|
|
274
|
+
if (orgDefault) return orgDefault;
|
|
275
|
+
return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
|
|
276
|
+
}
|
|
277
|
+
function setAgentRuntime(agentId, runtime, model) {
|
|
278
|
+
const knownModels = KNOWN_RUNTIMES[runtime];
|
|
279
|
+
if (!knownModels) {
|
|
280
|
+
return {
|
|
281
|
+
ok: false,
|
|
282
|
+
error: `Unknown runtime "${runtime}". Valid: ${Object.keys(KNOWN_RUNTIMES).join(", ")}`
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
if (!knownModels.includes(model)) {
|
|
286
|
+
return {
|
|
287
|
+
ok: false,
|
|
288
|
+
error: `Unknown model "${model}" for runtime "${runtime}". Valid: ${knownModels.join(", ")}`
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
const config = loadAgentConfig();
|
|
292
|
+
config[agentId] = { runtime, model };
|
|
293
|
+
saveAgentConfig(config);
|
|
294
|
+
return { ok: true };
|
|
295
|
+
}
|
|
296
|
+
function clearAgentRuntime(agentId) {
|
|
297
|
+
const config = loadAgentConfig();
|
|
298
|
+
delete config[agentId];
|
|
299
|
+
saveAgentConfig(config);
|
|
300
|
+
}
|
|
301
|
+
var AGENT_CONFIG_PATH, KNOWN_RUNTIMES, RUNTIME_LABELS, DEFAULT_MODELS;
|
|
302
|
+
var init_agent_config = __esm({
|
|
303
|
+
"src/lib/agent-config.ts"() {
|
|
304
|
+
"use strict";
|
|
305
|
+
init_config();
|
|
306
|
+
init_runtime_table();
|
|
307
|
+
init_secure_files();
|
|
308
|
+
AGENT_CONFIG_PATH = path2.join(EXE_AI_DIR, "agent-config.json");
|
|
309
|
+
KNOWN_RUNTIMES = {
|
|
310
|
+
claude: ["claude-opus-4", "claude-sonnet-4", "claude-haiku-4.5"],
|
|
311
|
+
codex: ["gpt-5.4", "gpt-5.5", "gpt-5.3-codex-spark", "o3", "o4-mini"],
|
|
312
|
+
opencode: ["anthropic/claude-sonnet-4-6", "openai/gpt-5.4", "google/gemini-2.5-pro", "deepseek/deepseek-r3", "minimax/minimax-m2.5"]
|
|
313
|
+
};
|
|
314
|
+
RUNTIME_LABELS = {
|
|
315
|
+
claude: "Claude Code (Anthropic)",
|
|
316
|
+
codex: "Codex (OpenAI)",
|
|
317
|
+
opencode: "OpenCode (open source)"
|
|
318
|
+
};
|
|
319
|
+
DEFAULT_MODELS = {
|
|
320
|
+
claude: "claude-opus-4",
|
|
321
|
+
codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
|
|
322
|
+
opencode: RUNTIME_TABLE.opencode?.defaultModel ?? "anthropic/claude-sonnet-4-6"
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
// src/lib/employees.ts
|
|
328
|
+
var employees_exports = {};
|
|
329
|
+
__export(employees_exports, {
|
|
330
|
+
COORDINATOR_ROLE: () => COORDINATOR_ROLE,
|
|
331
|
+
DEFAULT_COORDINATOR_TEMPLATE_NAME: () => DEFAULT_COORDINATOR_TEMPLATE_NAME,
|
|
332
|
+
EMPLOYEES_PATH: () => EMPLOYEES_PATH,
|
|
333
|
+
addEmployee: () => addEmployee,
|
|
334
|
+
baseAgentName: () => baseAgentName,
|
|
335
|
+
canCoordinate: () => canCoordinate,
|
|
336
|
+
getCoordinatorEmployee: () => getCoordinatorEmployee,
|
|
337
|
+
getCoordinatorName: () => getCoordinatorName,
|
|
338
|
+
getEmployee: () => getEmployee,
|
|
339
|
+
getEmployeeByRole: () => getEmployeeByRole,
|
|
340
|
+
getEmployeeNamesByRole: () => getEmployeeNamesByRole,
|
|
341
|
+
hasRole: () => hasRole,
|
|
342
|
+
hireEmployee: () => hireEmployee,
|
|
343
|
+
isCoordinatorName: () => isCoordinatorName,
|
|
344
|
+
isCoordinatorRole: () => isCoordinatorRole,
|
|
345
|
+
isMultiInstance: () => isMultiInstance,
|
|
346
|
+
loadEmployees: () => loadEmployees,
|
|
347
|
+
loadEmployeesSync: () => loadEmployeesSync,
|
|
348
|
+
normalizeRole: () => normalizeRole,
|
|
349
|
+
normalizeRosterCase: () => normalizeRosterCase,
|
|
350
|
+
registerBinSymlinks: () => registerBinSymlinks,
|
|
351
|
+
saveEmployees: () => saveEmployees,
|
|
352
|
+
validateEmployeeName: () => validateEmployeeName
|
|
353
|
+
});
|
|
354
|
+
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
355
|
+
import { existsSync as existsSync4, symlinkSync, readlinkSync, readFileSync as readFileSync3, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
|
|
356
|
+
import { execSync as execSync2 } from "child_process";
|
|
357
|
+
import path3 from "path";
|
|
358
|
+
import os2 from "os";
|
|
359
|
+
function normalizeRole(role) {
|
|
360
|
+
return (role ?? "").trim().toLowerCase();
|
|
361
|
+
}
|
|
362
|
+
function isCoordinatorRole(role) {
|
|
363
|
+
return normalizeRole(role) === normalizeRole(COORDINATOR_ROLE);
|
|
364
|
+
}
|
|
365
|
+
function getCoordinatorEmployee(employees) {
|
|
366
|
+
return employees.find((e) => isCoordinatorRole(e.role));
|
|
367
|
+
}
|
|
368
|
+
function getCoordinatorName(employees = loadEmployeesSync()) {
|
|
369
|
+
return getCoordinatorEmployee(employees)?.name ?? DEFAULT_COORDINATOR_TEMPLATE_NAME;
|
|
370
|
+
}
|
|
371
|
+
function isCoordinatorName(agentName, employees = loadEmployeesSync()) {
|
|
372
|
+
if (!agentName) return false;
|
|
373
|
+
return agentName.toLowerCase() === getCoordinatorName(employees).toLowerCase();
|
|
374
|
+
}
|
|
375
|
+
function canCoordinate(agentName, agentRole, employees = loadEmployeesSync()) {
|
|
376
|
+
return agentName === "default" || isCoordinatorRole(agentRole) || isCoordinatorName(agentName, employees);
|
|
377
|
+
}
|
|
378
|
+
function validateEmployeeName(name) {
|
|
379
|
+
if (!name) {
|
|
380
|
+
return { valid: false, error: "Name is required" };
|
|
381
|
+
}
|
|
382
|
+
if (name.length > 32) {
|
|
383
|
+
return { valid: false, error: "Name must be 32 characters or fewer" };
|
|
384
|
+
}
|
|
385
|
+
if (!/^[a-z][a-z0-9]*$/.test(name)) {
|
|
386
|
+
return {
|
|
387
|
+
valid: false,
|
|
388
|
+
error: "Name must start with a letter and contain only lowercase alphanumeric characters"
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
return { valid: true };
|
|
392
|
+
}
|
|
393
|
+
async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
|
|
394
|
+
if (!existsSync4(employeesPath)) {
|
|
395
|
+
return [];
|
|
396
|
+
}
|
|
397
|
+
const raw = await readFile2(employeesPath, "utf-8");
|
|
398
|
+
try {
|
|
399
|
+
return JSON.parse(raw);
|
|
400
|
+
} catch {
|
|
401
|
+
return [];
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
async function saveEmployees(employees, employeesPath = EMPLOYEES_PATH) {
|
|
405
|
+
await mkdir2(path3.dirname(employeesPath), { recursive: true });
|
|
406
|
+
await writeFile2(employeesPath, JSON.stringify(employees, null, 2) + "\n", "utf-8");
|
|
407
|
+
}
|
|
408
|
+
function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
|
|
409
|
+
if (!existsSync4(employeesPath)) return [];
|
|
410
|
+
try {
|
|
411
|
+
return JSON.parse(readFileSync3(employeesPath, "utf-8"));
|
|
412
|
+
} catch {
|
|
413
|
+
return [];
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
function getEmployee(employees, name) {
|
|
417
|
+
return employees.find((e) => e.name.toLowerCase() === name.toLowerCase());
|
|
418
|
+
}
|
|
419
|
+
function getEmployeeByRole(employees, role) {
|
|
420
|
+
const lower = role.toLowerCase();
|
|
421
|
+
return employees.find((e) => e.role.toLowerCase() === lower);
|
|
422
|
+
}
|
|
423
|
+
function getEmployeeNamesByRole(employees, role) {
|
|
424
|
+
const lower = role.toLowerCase();
|
|
425
|
+
return employees.filter((e) => e.role.toLowerCase() === lower).map((e) => e.name);
|
|
426
|
+
}
|
|
427
|
+
function hasRole(agentName, role) {
|
|
428
|
+
const employees = loadEmployeesSync();
|
|
429
|
+
const emp = getEmployee(employees, agentName);
|
|
430
|
+
return emp ? emp.role.toLowerCase() === role.toLowerCase() : false;
|
|
431
|
+
}
|
|
432
|
+
function baseAgentName(name, employees) {
|
|
433
|
+
const match = name.match(/^([a-zA-Z]+)\d+$/);
|
|
434
|
+
if (!match) return name;
|
|
435
|
+
const base = match[1];
|
|
436
|
+
const roster = employees ?? loadEmployeesSync();
|
|
437
|
+
if (getEmployee(roster, base)) return base;
|
|
438
|
+
return name;
|
|
439
|
+
}
|
|
440
|
+
function isMultiInstance(agentName, employees) {
|
|
441
|
+
const roster = employees ?? loadEmployeesSync();
|
|
442
|
+
const emp = getEmployee(roster, agentName);
|
|
443
|
+
if (!emp) return false;
|
|
444
|
+
return MULTI_INSTANCE_ROLES.has(emp.role.toLowerCase());
|
|
445
|
+
}
|
|
446
|
+
function addEmployee(employees, employee) {
|
|
447
|
+
const normalized = { ...employee, name: employee.name.toLowerCase() };
|
|
448
|
+
if (employees.some((e) => e.name.toLowerCase() === normalized.name)) {
|
|
449
|
+
throw new Error(`Employee '${normalized.name}' already exists`);
|
|
450
|
+
}
|
|
451
|
+
return [...employees, normalized];
|
|
452
|
+
}
|
|
453
|
+
function appendToCoordinatorTeam(employee) {
|
|
454
|
+
const coordinator = getCoordinatorEmployee(loadEmployeesSync());
|
|
455
|
+
if (!coordinator) return;
|
|
456
|
+
const idPath = path3.join(IDENTITY_DIR, `${coordinator.name}.md`);
|
|
457
|
+
if (!existsSync4(idPath)) return;
|
|
458
|
+
const content = readFileSync3(idPath, "utf-8");
|
|
459
|
+
if (content.includes(`**${capitalize(employee.name)}`)) return;
|
|
460
|
+
const teamMatch = content.match(TEAM_SECTION_RE);
|
|
461
|
+
if (!teamMatch || teamMatch.index === void 0) return;
|
|
462
|
+
const afterTeam = content.slice(teamMatch.index + teamMatch[0].length);
|
|
463
|
+
const nextHeading = afterTeam.match(/\n## /);
|
|
464
|
+
const entry = `
|
|
465
|
+
**${capitalize(employee.name)} (${employee.role}):** Newly hired. Update this description as the role develops.
|
|
466
|
+
`;
|
|
467
|
+
let updated;
|
|
468
|
+
if (nextHeading && nextHeading.index !== void 0) {
|
|
469
|
+
const insertAt = teamMatch.index + teamMatch[0].length + nextHeading.index;
|
|
470
|
+
updated = content.slice(0, insertAt) + entry + content.slice(insertAt);
|
|
471
|
+
} else {
|
|
472
|
+
updated = content.trimEnd() + "\n" + entry;
|
|
473
|
+
}
|
|
474
|
+
writeFileSync2(idPath, updated, "utf-8");
|
|
475
|
+
}
|
|
476
|
+
function capitalize(s) {
|
|
477
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
478
|
+
}
|
|
479
|
+
async function hireEmployee(employee) {
|
|
480
|
+
const employees = await loadEmployees();
|
|
481
|
+
const updated = addEmployee(employees, employee);
|
|
482
|
+
await saveEmployees(updated);
|
|
483
|
+
try {
|
|
484
|
+
appendToCoordinatorTeam(employee);
|
|
485
|
+
} catch {
|
|
486
|
+
}
|
|
487
|
+
try {
|
|
488
|
+
const { loadAgentConfig: loadAgentConfig2, saveAgentConfig: saveAgentConfig2 } = await Promise.resolve().then(() => (init_agent_config(), agent_config_exports));
|
|
489
|
+
const config = loadAgentConfig2();
|
|
490
|
+
const name = employee.name.toLowerCase();
|
|
491
|
+
if (!config[name] && config["default"]) {
|
|
492
|
+
config[name] = { ...config["default"] };
|
|
493
|
+
saveAgentConfig2(config);
|
|
494
|
+
}
|
|
495
|
+
} catch {
|
|
496
|
+
}
|
|
497
|
+
return updated;
|
|
498
|
+
}
|
|
499
|
+
async function normalizeRosterCase(rosterPath) {
|
|
500
|
+
const employees = await loadEmployees(rosterPath);
|
|
501
|
+
let changed = false;
|
|
502
|
+
for (const emp of employees) {
|
|
503
|
+
if (emp.name !== emp.name.toLowerCase()) {
|
|
504
|
+
const oldName = emp.name;
|
|
505
|
+
emp.name = emp.name.toLowerCase();
|
|
506
|
+
changed = true;
|
|
507
|
+
try {
|
|
508
|
+
const identityDir = path3.join(os2.homedir(), ".exe-os", "identity");
|
|
509
|
+
const oldPath = path3.join(identityDir, `${oldName}.md`);
|
|
510
|
+
const newPath = path3.join(identityDir, `${emp.name}.md`);
|
|
511
|
+
if (existsSync4(oldPath) && !existsSync4(newPath)) {
|
|
512
|
+
renameSync2(oldPath, newPath);
|
|
513
|
+
} else if (existsSync4(oldPath) && oldPath !== newPath) {
|
|
514
|
+
const content = readFileSync3(oldPath, "utf-8");
|
|
515
|
+
writeFileSync2(newPath, content, "utf-8");
|
|
516
|
+
if (oldPath.toLowerCase() !== newPath.toLowerCase()) {
|
|
517
|
+
unlinkSync(oldPath);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
} catch {
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
if (changed) {
|
|
525
|
+
await saveEmployees(employees, rosterPath);
|
|
526
|
+
}
|
|
527
|
+
return changed;
|
|
528
|
+
}
|
|
529
|
+
function findExeBin() {
|
|
530
|
+
try {
|
|
531
|
+
return execSync2(process.platform === "win32" ? "where exe-os" : "which exe-os", { encoding: "utf8" }).trim();
|
|
532
|
+
} catch {
|
|
533
|
+
return null;
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
function registerBinSymlinks(name) {
|
|
537
|
+
const created = [];
|
|
538
|
+
const skipped = [];
|
|
539
|
+
const errors = [];
|
|
540
|
+
const exeBinPath = findExeBin();
|
|
541
|
+
if (!exeBinPath) {
|
|
542
|
+
errors.push("Could not find 'exe-os' in PATH");
|
|
543
|
+
return { created, skipped, errors };
|
|
544
|
+
}
|
|
545
|
+
const binDir = path3.dirname(exeBinPath);
|
|
546
|
+
let target;
|
|
547
|
+
try {
|
|
548
|
+
target = readlinkSync(exeBinPath);
|
|
549
|
+
} catch {
|
|
550
|
+
errors.push("Could not read 'exe' symlink");
|
|
551
|
+
return { created, skipped, errors };
|
|
552
|
+
}
|
|
553
|
+
for (const suffix of ["", "-opencode"]) {
|
|
554
|
+
const linkName = `${name}${suffix}`;
|
|
555
|
+
const linkPath = path3.join(binDir, linkName);
|
|
556
|
+
if (existsSync4(linkPath)) {
|
|
557
|
+
skipped.push(linkName);
|
|
558
|
+
continue;
|
|
559
|
+
}
|
|
560
|
+
try {
|
|
561
|
+
symlinkSync(target, linkPath);
|
|
562
|
+
created.push(linkName);
|
|
563
|
+
} catch (err) {
|
|
564
|
+
errors.push(`${linkName}: ${err instanceof Error ? err.message : String(err)}`);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
return { created, skipped, errors };
|
|
568
|
+
}
|
|
569
|
+
var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES, IDENTITY_DIR, TEAM_SECTION_RE;
|
|
570
|
+
var init_employees = __esm({
|
|
571
|
+
"src/lib/employees.ts"() {
|
|
572
|
+
"use strict";
|
|
573
|
+
init_config();
|
|
574
|
+
EMPLOYEES_PATH = path3.join(EXE_AI_DIR, "exe-employees.json");
|
|
575
|
+
DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
|
|
576
|
+
COORDINATOR_ROLE = "COO";
|
|
577
|
+
MULTI_INSTANCE_ROLES = /* @__PURE__ */ new Set(["principal engineer", "content production specialist", "staff code reviewer"]);
|
|
578
|
+
IDENTITY_DIR = path3.join(EXE_AI_DIR, "identity");
|
|
579
|
+
TEAM_SECTION_RE = /^## Team\b.*$/m;
|
|
580
|
+
}
|
|
581
|
+
});
|
|
582
|
+
|
|
583
|
+
// src/lib/mcp-prefix.ts
|
|
584
|
+
function isExeMcpTool(toolName) {
|
|
585
|
+
if (!toolName) return false;
|
|
586
|
+
return MCP_TOOL_PREFIXES.some((p) => toolName.startsWith(p));
|
|
587
|
+
}
|
|
588
|
+
function stripExeMcpPrefix(toolName) {
|
|
589
|
+
for (const p of MCP_TOOL_PREFIXES) {
|
|
590
|
+
if (toolName.startsWith(p)) return toolName.slice(p.length);
|
|
591
|
+
}
|
|
592
|
+
return toolName;
|
|
593
|
+
}
|
|
594
|
+
var MCP_PRIMARY_KEY, MCP_LEGACY_KEY, MCP_TOOL_PREFIXES;
|
|
595
|
+
var init_mcp_prefix = __esm({
|
|
596
|
+
"src/lib/mcp-prefix.ts"() {
|
|
597
|
+
"use strict";
|
|
598
|
+
MCP_PRIMARY_KEY = "exe-os";
|
|
599
|
+
MCP_LEGACY_KEY = "exe-mem";
|
|
600
|
+
MCP_TOOL_PREFIXES = [
|
|
601
|
+
`mcp__${MCP_PRIMARY_KEY}__`,
|
|
602
|
+
`mcp__${MCP_LEGACY_KEY}__`
|
|
603
|
+
];
|
|
604
|
+
}
|
|
605
|
+
});
|
|
606
|
+
|
|
607
|
+
// src/lib/content-extractor.ts
|
|
608
|
+
var content_extractor_exports = {};
|
|
609
|
+
__export(content_extractor_exports, {
|
|
610
|
+
extractSemanticText: () => extractSemanticText
|
|
611
|
+
});
|
|
612
|
+
function extractSemanticText(toolName, toolInput, toolResponse) {
|
|
613
|
+
switch (toolName) {
|
|
614
|
+
case "Write":
|
|
615
|
+
return extractWrite(toolInput);
|
|
616
|
+
case "Edit":
|
|
617
|
+
return extractEdit(toolInput);
|
|
618
|
+
case "Read":
|
|
619
|
+
return extractRead(toolInput, toolResponse);
|
|
620
|
+
case "Bash":
|
|
621
|
+
return extractBash(toolInput, toolResponse);
|
|
622
|
+
case "Grep":
|
|
623
|
+
return extractGrep(toolInput, toolResponse);
|
|
624
|
+
case "Glob":
|
|
625
|
+
return extractGlob(toolInput, toolResponse);
|
|
626
|
+
default:
|
|
627
|
+
if (isExeMcpTool(toolName)) {
|
|
628
|
+
return extractExeMemMcp(toolName, toolInput, toolResponse);
|
|
629
|
+
}
|
|
630
|
+
if (toolName.startsWith("mcp__")) {
|
|
631
|
+
return extractGenericMcp(toolName, toolInput, toolResponse);
|
|
632
|
+
}
|
|
633
|
+
return extractDefault(toolName, toolInput, toolResponse);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
function findContainingChunk(filePath, snippet) {
|
|
637
|
+
try {
|
|
638
|
+
const ext = filePath.split(".").pop()?.toLowerCase();
|
|
639
|
+
if (ext !== "ts" && ext !== "tsx" && ext !== "js" && ext !== "jsx") return "";
|
|
640
|
+
const { readFileSync: readFileSync7 } = __require("fs");
|
|
641
|
+
const source = readFileSync7(filePath, "utf8");
|
|
642
|
+
const lines = source.split("\n");
|
|
643
|
+
const lowerSnippet = snippet.toLowerCase().slice(0, 80);
|
|
644
|
+
let matchLine = -1;
|
|
645
|
+
for (let i = 0; i < lines.length; i++) {
|
|
646
|
+
if (lines[i].toLowerCase().includes(lowerSnippet)) {
|
|
647
|
+
matchLine = i;
|
|
648
|
+
break;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
if (matchLine === -1) return "";
|
|
652
|
+
for (let i = matchLine; i >= 0; i--) {
|
|
653
|
+
const line = lines[i];
|
|
654
|
+
const fnMatch = line.match(/(?:export\s+)?(?:async\s+)?function\s+(\w+)/);
|
|
655
|
+
if (fnMatch) return `Function ${fnMatch[1]} in ${filePath}:${i + 1}`;
|
|
656
|
+
const classMatch = line.match(/(?:export\s+)?class\s+(\w+)/);
|
|
657
|
+
if (classMatch) return `Class ${classMatch[1]} in ${filePath}:${i + 1}`;
|
|
658
|
+
const arrowMatch = line.match(/(?:export\s+)?(?:const|let)\s+(\w+)\s*=\s*(?:async\s+)?\(/);
|
|
659
|
+
if (arrowMatch) return `Function ${arrowMatch[1]} in ${filePath}:${i + 1}`;
|
|
660
|
+
}
|
|
661
|
+
} catch {
|
|
662
|
+
}
|
|
663
|
+
return "";
|
|
664
|
+
}
|
|
665
|
+
function extractWrite(input2) {
|
|
666
|
+
const filePath = String(input2.file_path ?? "");
|
|
667
|
+
const content = String(input2.content ?? "");
|
|
668
|
+
const chunkContext = findContainingChunk(filePath, content.slice(0, 200));
|
|
669
|
+
const prefix = chunkContext ? `Wrote ${filePath} (${chunkContext})` : `Wrote ${filePath}`;
|
|
670
|
+
return `${prefix}
|
|
671
|
+
${content.slice(0, MAX_CONTENT)}`;
|
|
672
|
+
}
|
|
673
|
+
function extractEdit(input2) {
|
|
674
|
+
const filePath = String(input2.file_path ?? "");
|
|
675
|
+
const oldStr = String(input2.old_string ?? "");
|
|
676
|
+
const newStr = String(input2.new_string ?? "");
|
|
677
|
+
const chunkContext = findContainingChunk(filePath, oldStr.slice(0, 200));
|
|
678
|
+
const prefix = chunkContext ? `Edited ${filePath} (${chunkContext})` : `Edited ${filePath}`;
|
|
679
|
+
return `${prefix}
|
|
680
|
+
Removed: ${oldStr.slice(0, MAX_CONTENT / 2)}
|
|
681
|
+
Added: ${newStr.slice(0, MAX_CONTENT / 2)}`;
|
|
682
|
+
}
|
|
683
|
+
function extractRead(input2, response) {
|
|
684
|
+
const filePath = String(input2.file_path ?? "");
|
|
685
|
+
const file = response.file;
|
|
686
|
+
const content = file ? String(file.content ?? "") : "";
|
|
687
|
+
if (!content) {
|
|
688
|
+
const text = String(response.text ?? response.content ?? "");
|
|
689
|
+
return `Read ${filePath}
|
|
690
|
+
${text.slice(0, MAX_CONTENT)}`;
|
|
691
|
+
}
|
|
692
|
+
return `Read ${filePath}
|
|
693
|
+
${content.slice(0, MAX_CONTENT)}`;
|
|
694
|
+
}
|
|
695
|
+
function extractBash(input2, response) {
|
|
696
|
+
const command = String(input2.command ?? "");
|
|
697
|
+
const description = input2.description ? String(input2.description) : "";
|
|
698
|
+
const stdout = String(response.stdout ?? response.text ?? "");
|
|
699
|
+
const stderr = String(response.stderr ?? "");
|
|
700
|
+
const parts = [description ? `${description}: ${command}` : `Ran: ${command}`];
|
|
701
|
+
if (stdout) parts.push(`Output: ${stdout.slice(0, MAX_OUTPUT)}`);
|
|
702
|
+
if (stderr && !stdout) parts.push(`Error: ${stderr.slice(0, MAX_OUTPUT)}`);
|
|
703
|
+
return parts.join("\n");
|
|
704
|
+
}
|
|
705
|
+
function extractGrep(input2, response) {
|
|
706
|
+
const pattern = String(input2.pattern ?? "");
|
|
707
|
+
const path9 = input2.path ? String(input2.path) : "";
|
|
708
|
+
const output = String(response.text ?? response.content ?? JSON.stringify(response).slice(0, MAX_OUTPUT));
|
|
709
|
+
return `Searched for "${pattern}"${path9 ? ` in ${path9}` : ""}
|
|
710
|
+
${output.slice(0, MAX_OUTPUT)}`;
|
|
711
|
+
}
|
|
712
|
+
function extractGlob(input2, response) {
|
|
713
|
+
const pattern = String(input2.pattern ?? "");
|
|
714
|
+
const output = String(response.text ?? response.content ?? JSON.stringify(response).slice(0, MAX_OUTPUT));
|
|
715
|
+
return `Found files matching "${pattern}"
|
|
716
|
+
${output.slice(0, MAX_OUTPUT)}`;
|
|
717
|
+
}
|
|
718
|
+
function extractExeMemMcp(toolName, input2, response) {
|
|
719
|
+
const shortName = stripExeMcpPrefix(toolName);
|
|
720
|
+
switch (shortName) {
|
|
721
|
+
case "store_memory": {
|
|
722
|
+
const text = String(input2.text ?? input2.query ?? "");
|
|
723
|
+
return `Stored memory: ${text.slice(0, MAX_CONTENT)}`;
|
|
724
|
+
}
|
|
725
|
+
case "recall_my_memory":
|
|
726
|
+
case "ask_team_memory": {
|
|
727
|
+
const query = String(input2.query ?? "");
|
|
728
|
+
const member = input2.team_member ? ` (from ${input2.team_member})` : "";
|
|
729
|
+
const resultText = extractResponseText(response);
|
|
730
|
+
return `Memory search${member}: "${query}"
|
|
731
|
+
${resultText.slice(0, MAX_OUTPUT)}`;
|
|
732
|
+
}
|
|
733
|
+
case "create_task": {
|
|
734
|
+
const title = String(input2.title ?? "");
|
|
735
|
+
const assignedTo = String(input2.assigned_to ?? "");
|
|
736
|
+
const priority = String(input2.priority ?? "p1");
|
|
737
|
+
const context = String(input2.context ?? "");
|
|
738
|
+
return `Task created: "${title}" assigned to ${assignedTo} [${priority}]
|
|
739
|
+
${context.slice(0, MAX_CONTENT)}`;
|
|
740
|
+
}
|
|
741
|
+
case "update_task": {
|
|
742
|
+
const taskId = String(input2.task_id ?? "");
|
|
743
|
+
const status = String(input2.status ?? "");
|
|
744
|
+
const result = input2.result ? String(input2.result) : "";
|
|
745
|
+
return `Task updated: ${taskId} \u2192 ${status}${result ? `
|
|
746
|
+
Result: ${result.slice(0, MAX_CONTENT)}` : ""}`;
|
|
747
|
+
}
|
|
748
|
+
case "list_tasks": {
|
|
749
|
+
const resultText = extractResponseText(response);
|
|
750
|
+
return `Listed tasks
|
|
751
|
+
${resultText.slice(0, MAX_OUTPUT)}`;
|
|
752
|
+
}
|
|
753
|
+
default: {
|
|
754
|
+
return extractGenericMcp(toolName, input2, response);
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
function extractGenericMcp(toolName, input2, response) {
|
|
759
|
+
const shortName = toolName.replace(/^mcp__[^_]+__/, "");
|
|
760
|
+
const inputParts = Object.entries(input2).filter(([, v]) => v != null && String(v).length > 0).map(([k, v]) => `${k}: ${String(v).slice(0, 200)}`).join(", ");
|
|
761
|
+
const resultText = extractResponseText(response);
|
|
762
|
+
return `${shortName}(${inputParts})
|
|
763
|
+
${resultText.slice(0, MAX_OUTPUT)}`;
|
|
764
|
+
}
|
|
765
|
+
function extractDefault(toolName, input2, response) {
|
|
766
|
+
const inputStr = JSON.stringify(input2);
|
|
767
|
+
const resultText = extractResponseText(response);
|
|
768
|
+
return `Tool: ${toolName}
|
|
769
|
+
${inputStr.slice(0, MAX_CONTENT / 2)}
|
|
770
|
+
${resultText.slice(0, MAX_OUTPUT)}`;
|
|
771
|
+
}
|
|
772
|
+
function extractResponseText(response) {
|
|
773
|
+
if (typeof response.text === "string") return response.text;
|
|
774
|
+
if (typeof response.content === "string") return response.content;
|
|
775
|
+
if (Array.isArray(response.content)) {
|
|
776
|
+
return response.content.map((block) => {
|
|
777
|
+
if (typeof block === "object" && block !== null && "text" in block) {
|
|
778
|
+
return String(block.text);
|
|
779
|
+
}
|
|
780
|
+
return "";
|
|
781
|
+
}).filter(Boolean).join("\n");
|
|
782
|
+
}
|
|
783
|
+
if (Array.isArray(response)) {
|
|
784
|
+
return response.map((item) => {
|
|
785
|
+
if (typeof item === "object" && item !== null && "text" in item) {
|
|
786
|
+
return String(item.text);
|
|
787
|
+
}
|
|
788
|
+
return "";
|
|
789
|
+
}).filter(Boolean).join("\n");
|
|
790
|
+
}
|
|
791
|
+
return JSON.stringify(response).slice(0, MAX_OUTPUT);
|
|
792
|
+
}
|
|
793
|
+
var MAX_CONTENT, MAX_OUTPUT;
|
|
794
|
+
var init_content_extractor = __esm({
|
|
795
|
+
"src/lib/content-extractor.ts"() {
|
|
796
|
+
"use strict";
|
|
797
|
+
init_mcp_prefix();
|
|
798
|
+
MAX_CONTENT = 2e3;
|
|
799
|
+
MAX_OUTPUT = 1e3;
|
|
800
|
+
}
|
|
801
|
+
});
|
|
802
|
+
|
|
803
|
+
// src/lib/project-name.ts
|
|
804
|
+
var project_name_exports = {};
|
|
805
|
+
__export(project_name_exports, {
|
|
806
|
+
_resetCache: () => _resetCache,
|
|
807
|
+
getProjectName: () => getProjectName
|
|
808
|
+
});
|
|
809
|
+
import { execSync as execSync4 } from "child_process";
|
|
810
|
+
import path6 from "path";
|
|
811
|
+
function getProjectName(cwd) {
|
|
812
|
+
const dir = cwd ?? process.cwd();
|
|
813
|
+
if (_cached2 && _cachedCwd === dir) return _cached2;
|
|
814
|
+
try {
|
|
815
|
+
let repoRoot;
|
|
816
|
+
try {
|
|
817
|
+
const gitCommonDir = execSync4("git rev-parse --path-format=absolute --git-common-dir", {
|
|
818
|
+
cwd: dir,
|
|
819
|
+
encoding: "utf8",
|
|
820
|
+
timeout: 2e3,
|
|
821
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
822
|
+
}).trim();
|
|
823
|
+
repoRoot = path6.dirname(gitCommonDir);
|
|
824
|
+
} catch {
|
|
825
|
+
repoRoot = execSync4("git rev-parse --show-toplevel", {
|
|
826
|
+
cwd: dir,
|
|
827
|
+
encoding: "utf8",
|
|
828
|
+
timeout: 2e3,
|
|
829
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
830
|
+
}).trim();
|
|
831
|
+
}
|
|
832
|
+
_cached2 = path6.basename(repoRoot);
|
|
833
|
+
_cachedCwd = dir;
|
|
834
|
+
return _cached2;
|
|
835
|
+
} catch {
|
|
836
|
+
_cached2 = path6.basename(dir);
|
|
837
|
+
_cachedCwd = dir;
|
|
838
|
+
return _cached2;
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
function _resetCache() {
|
|
842
|
+
_cached2 = null;
|
|
843
|
+
_cachedCwd = null;
|
|
844
|
+
}
|
|
845
|
+
var _cached2, _cachedCwd;
|
|
846
|
+
var init_project_name = __esm({
|
|
847
|
+
"src/lib/project-name.ts"() {
|
|
848
|
+
"use strict";
|
|
849
|
+
_cached2 = null;
|
|
850
|
+
_cachedCwd = null;
|
|
851
|
+
}
|
|
852
|
+
});
|
|
853
|
+
|
|
854
|
+
// src/lib/daemon-auth.ts
|
|
855
|
+
var daemon_auth_exports = {};
|
|
856
|
+
__export(daemon_auth_exports, {
|
|
857
|
+
DAEMON_TOKEN_PATH: () => DAEMON_TOKEN_PATH,
|
|
858
|
+
ensureDaemonToken: () => ensureDaemonToken,
|
|
859
|
+
readDaemonToken: () => readDaemonToken
|
|
860
|
+
});
|
|
861
|
+
import crypto2 from "crypto";
|
|
862
|
+
import path7 from "path";
|
|
863
|
+
import { existsSync as existsSync6, readFileSync as readFileSync5, writeFileSync as writeFileSync5 } from "fs";
|
|
864
|
+
function normalizeToken(token) {
|
|
865
|
+
if (!token) return null;
|
|
866
|
+
const trimmed = token.trim();
|
|
867
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
868
|
+
}
|
|
869
|
+
function readDaemonToken() {
|
|
870
|
+
try {
|
|
871
|
+
if (!existsSync6(DAEMON_TOKEN_PATH)) return null;
|
|
872
|
+
return normalizeToken(readFileSync5(DAEMON_TOKEN_PATH, "utf8"));
|
|
873
|
+
} catch {
|
|
874
|
+
return null;
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
function ensureDaemonToken(seed) {
|
|
878
|
+
const existing = readDaemonToken();
|
|
879
|
+
if (existing) return existing;
|
|
880
|
+
const token = normalizeToken(seed) ?? crypto2.randomBytes(32).toString("hex");
|
|
881
|
+
ensurePrivateDirSync(EXE_AI_DIR);
|
|
882
|
+
writeFileSync5(DAEMON_TOKEN_PATH, `${token}
|
|
883
|
+
`, "utf8");
|
|
884
|
+
enforcePrivateFileSync(DAEMON_TOKEN_PATH);
|
|
885
|
+
return token;
|
|
886
|
+
}
|
|
887
|
+
var DAEMON_TOKEN_PATH;
|
|
888
|
+
var init_daemon_auth = __esm({
|
|
889
|
+
"src/lib/daemon-auth.ts"() {
|
|
890
|
+
"use strict";
|
|
891
|
+
init_config();
|
|
892
|
+
init_secure_files();
|
|
893
|
+
DAEMON_TOKEN_PATH = path7.join(EXE_AI_DIR, "exed.token");
|
|
894
|
+
}
|
|
895
|
+
});
|
|
896
|
+
|
|
176
897
|
// src/adapters/claude/hooks/ingest.ts
|
|
177
898
|
init_config();
|
|
178
899
|
init_config();
|
|
179
900
|
import { spawn } from "child_process";
|
|
180
|
-
import { readFileSync as
|
|
181
|
-
import
|
|
901
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync6, mkdirSync as mkdirSync4, existsSync as existsSync7, openSync, closeSync } from "fs";
|
|
902
|
+
import path8 from "path";
|
|
182
903
|
import { fileURLToPath } from "url";
|
|
183
904
|
|
|
184
905
|
// src/lib/active-agent.ts
|
|
185
906
|
init_config();
|
|
186
|
-
import { readFileSync as
|
|
907
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, mkdirSync as mkdirSync2, unlinkSync as unlinkSync2, readdirSync } from "fs";
|
|
187
908
|
import { execSync as execSync3 } from "child_process";
|
|
188
|
-
import
|
|
909
|
+
import path4 from "path";
|
|
189
910
|
|
|
190
911
|
// src/lib/session-key.ts
|
|
191
912
|
import { execSync } from "child_process";
|
|
@@ -249,43 +970,9 @@ function getSessionKey() {
|
|
|
249
970
|
return _cached;
|
|
250
971
|
}
|
|
251
972
|
|
|
252
|
-
// src/lib/employees.ts
|
|
253
|
-
init_config();
|
|
254
|
-
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
255
|
-
import { existsSync as existsSync2, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
|
|
256
|
-
import { execSync as execSync2 } from "child_process";
|
|
257
|
-
import path2 from "path";
|
|
258
|
-
import os2 from "os";
|
|
259
|
-
var EMPLOYEES_PATH = path2.join(EXE_AI_DIR, "exe-employees.json");
|
|
260
|
-
var DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
|
|
261
|
-
var COORDINATOR_ROLE = "COO";
|
|
262
|
-
function normalizeRole(role) {
|
|
263
|
-
return (role ?? "").trim().toLowerCase();
|
|
264
|
-
}
|
|
265
|
-
function isCoordinatorRole(role) {
|
|
266
|
-
return normalizeRole(role) === normalizeRole(COORDINATOR_ROLE);
|
|
267
|
-
}
|
|
268
|
-
function getCoordinatorEmployee(employees) {
|
|
269
|
-
return employees.find((e) => isCoordinatorRole(e.role));
|
|
270
|
-
}
|
|
271
|
-
function getCoordinatorName(employees = loadEmployeesSync()) {
|
|
272
|
-
return getCoordinatorEmployee(employees)?.name ?? DEFAULT_COORDINATOR_TEMPLATE_NAME;
|
|
273
|
-
}
|
|
274
|
-
function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
|
|
275
|
-
if (!existsSync2(employeesPath)) return [];
|
|
276
|
-
try {
|
|
277
|
-
return JSON.parse(readFileSync2(employeesPath, "utf-8"));
|
|
278
|
-
} catch {
|
|
279
|
-
return [];
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
function getEmployee(employees, name) {
|
|
283
|
-
return employees.find((e) => e.name.toLowerCase() === name.toLowerCase());
|
|
284
|
-
}
|
|
285
|
-
var IDENTITY_DIR = path2.join(EXE_AI_DIR, "identity");
|
|
286
|
-
|
|
287
973
|
// src/lib/active-agent.ts
|
|
288
|
-
|
|
974
|
+
init_employees();
|
|
975
|
+
var CACHE_DIR = path4.join(EXE_AI_DIR, "session-cache");
|
|
289
976
|
var STALE_MS = 24 * 60 * 60 * 1e3;
|
|
290
977
|
function isNameWithOptionalInstance(candidate, baseName) {
|
|
291
978
|
if (candidate === baseName) return true;
|
|
@@ -330,12 +1017,12 @@ function resolveActiveAgentFromTmuxSession(sessionName) {
|
|
|
330
1017
|
return null;
|
|
331
1018
|
}
|
|
332
1019
|
function getMarkerPath() {
|
|
333
|
-
return
|
|
1020
|
+
return path4.join(CACHE_DIR, `active-agent-${getSessionKey()}.json`);
|
|
334
1021
|
}
|
|
335
1022
|
function getActiveAgent() {
|
|
336
1023
|
try {
|
|
337
1024
|
const markerPath = getMarkerPath();
|
|
338
|
-
const raw =
|
|
1025
|
+
const raw = readFileSync4(markerPath, "utf8");
|
|
339
1026
|
const data = JSON.parse(raw);
|
|
340
1027
|
if (data.agentId) {
|
|
341
1028
|
if (data.startedAt) {
|
|
@@ -376,21 +1063,8 @@ function getActiveAgent() {
|
|
|
376
1063
|
}
|
|
377
1064
|
|
|
378
1065
|
// src/lib/error-detector.ts
|
|
1066
|
+
init_mcp_prefix();
|
|
379
1067
|
import crypto from "crypto";
|
|
380
|
-
|
|
381
|
-
// src/lib/mcp-prefix.ts
|
|
382
|
-
var MCP_PRIMARY_KEY = "exe-os";
|
|
383
|
-
var MCP_LEGACY_KEY = "exe-mem";
|
|
384
|
-
var MCP_TOOL_PREFIXES = [
|
|
385
|
-
`mcp__${MCP_PRIMARY_KEY}__`,
|
|
386
|
-
`mcp__${MCP_LEGACY_KEY}__`
|
|
387
|
-
];
|
|
388
|
-
function isExeMcpTool(toolName) {
|
|
389
|
-
if (!toolName) return false;
|
|
390
|
-
return MCP_TOOL_PREFIXES.some((p) => toolName.startsWith(p));
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
// src/lib/error-detector.ts
|
|
394
1068
|
var ERROR_PATTERNS = [
|
|
395
1069
|
/\bError\b/i,
|
|
396
1070
|
/\bERR!\b/,
|
|
@@ -527,16 +1201,16 @@ function errorFingerprint(toolName, errorText) {
|
|
|
527
1201
|
|
|
528
1202
|
// src/lib/worker-gate.ts
|
|
529
1203
|
init_config();
|
|
530
|
-
import { readdirSync as readdirSync2, writeFileSync as
|
|
531
|
-
import
|
|
532
|
-
var WORKER_PID_DIR =
|
|
1204
|
+
import { readdirSync as readdirSync2, writeFileSync as writeFileSync4, unlinkSync as unlinkSync3, mkdirSync as mkdirSync3, existsSync as existsSync5 } from "fs";
|
|
1205
|
+
import path5 from "path";
|
|
1206
|
+
var WORKER_PID_DIR = path5.join(EXE_AI_DIR, "worker-pids");
|
|
533
1207
|
var MAX_CONCURRENT_WORKERS = 3;
|
|
534
1208
|
function tryAcquireWorkerSlot() {
|
|
535
1209
|
try {
|
|
536
|
-
|
|
1210
|
+
mkdirSync3(WORKER_PID_DIR, { recursive: true });
|
|
537
1211
|
const reservationId = `res-${process.pid}-${Date.now()}`;
|
|
538
|
-
const reservationPath =
|
|
539
|
-
|
|
1212
|
+
const reservationPath = path5.join(WORKER_PID_DIR, `${reservationId}.pid`);
|
|
1213
|
+
writeFileSync4(reservationPath, String(process.pid));
|
|
540
1214
|
const files = readdirSync2(WORKER_PID_DIR);
|
|
541
1215
|
let alive = 0;
|
|
542
1216
|
for (const f of files) {
|
|
@@ -553,7 +1227,7 @@ function tryAcquireWorkerSlot() {
|
|
|
553
1227
|
alive++;
|
|
554
1228
|
} catch {
|
|
555
1229
|
try {
|
|
556
|
-
unlinkSync3(
|
|
1230
|
+
unlinkSync3(path5.join(WORKER_PID_DIR, f));
|
|
557
1231
|
} catch {
|
|
558
1232
|
}
|
|
559
1233
|
}
|
|
@@ -576,14 +1250,15 @@ function tryAcquireWorkerSlot() {
|
|
|
576
1250
|
}
|
|
577
1251
|
function registerWorkerPid(pid) {
|
|
578
1252
|
try {
|
|
579
|
-
|
|
580
|
-
|
|
1253
|
+
mkdirSync3(WORKER_PID_DIR, { recursive: true });
|
|
1254
|
+
writeFileSync4(path5.join(WORKER_PID_DIR, `worker-${pid}.pid`), String(pid));
|
|
581
1255
|
} catch {
|
|
582
1256
|
}
|
|
583
1257
|
}
|
|
584
|
-
var BACKFILL_LOCK =
|
|
1258
|
+
var BACKFILL_LOCK = path5.join(WORKER_PID_DIR, "backfill.lock");
|
|
585
1259
|
|
|
586
1260
|
// src/adapters/claude/hooks/ingest.ts
|
|
1261
|
+
init_employees();
|
|
587
1262
|
if (!process.env.AGENT_ID) {
|
|
588
1263
|
process.env.AGENT_ID = "default";
|
|
589
1264
|
process.env.AGENT_ROLE = "employee";
|
|
@@ -594,7 +1269,7 @@ if (!loadConfigSync().autoIngestion) {
|
|
|
594
1269
|
if (!process.env.EXE_OS_DIR) {
|
|
595
1270
|
process.env.EXE_OS_DIR = EXE_AI_DIR;
|
|
596
1271
|
}
|
|
597
|
-
var WORKER_LOG_PATH =
|
|
1272
|
+
var WORKER_LOG_PATH = path8.join(EXE_AI_DIR, "workers.log");
|
|
598
1273
|
function openWorkerLog() {
|
|
599
1274
|
try {
|
|
600
1275
|
return openSync(WORKER_LOG_PATH, "a");
|
|
@@ -606,13 +1281,13 @@ var ALLOWED_TOOL_RE = /^(Bash|Edit|Write|Read|Glob|Grep|Agent|apply_patch|mcp__.
|
|
|
606
1281
|
var WRITE_TOOL_RE = /^(Bash|Edit|Write|apply_patch)$/;
|
|
607
1282
|
var SUMMARY_INTERVAL = 25;
|
|
608
1283
|
var MIN_WRITES_FOR_SUMMARY = 3;
|
|
609
|
-
var COUNTER_DIR =
|
|
1284
|
+
var COUNTER_DIR = path8.join(EXE_AI_DIR, "session-cache");
|
|
610
1285
|
function getCounterPath(sessionId) {
|
|
611
|
-
return
|
|
1286
|
+
return path8.join(COUNTER_DIR, `counter-${sessionId}.json`);
|
|
612
1287
|
}
|
|
613
1288
|
function loadCounter(sessionId) {
|
|
614
1289
|
try {
|
|
615
|
-
const raw =
|
|
1290
|
+
const raw = readFileSync6(getCounterPath(sessionId), "utf8");
|
|
616
1291
|
return JSON.parse(raw);
|
|
617
1292
|
} catch {
|
|
618
1293
|
return { total: 0, writes: 0, pipelineWrites: 0, lastSummaryAt: 0, pipelineDetected: false };
|
|
@@ -620,8 +1295,8 @@ function loadCounter(sessionId) {
|
|
|
620
1295
|
}
|
|
621
1296
|
function saveCounter(sessionId, counter) {
|
|
622
1297
|
try {
|
|
623
|
-
|
|
624
|
-
|
|
1298
|
+
mkdirSync4(COUNTER_DIR, { recursive: true });
|
|
1299
|
+
writeFileSync6(getCounterPath(sessionId), JSON.stringify(counter));
|
|
625
1300
|
} catch {
|
|
626
1301
|
}
|
|
627
1302
|
}
|
|
@@ -633,15 +1308,15 @@ process.stdin.on("data", (chunk) => {
|
|
|
633
1308
|
input += chunk;
|
|
634
1309
|
}
|
|
635
1310
|
});
|
|
636
|
-
process.stdin.on("end", () => {
|
|
1311
|
+
process.stdin.on("end", async () => {
|
|
637
1312
|
try {
|
|
638
1313
|
if (process.env.EXE_DEBUG_HOOKS) {
|
|
639
1314
|
try {
|
|
640
|
-
const debugPath =
|
|
641
|
-
|
|
1315
|
+
const debugPath = path8.join(EXE_AI_DIR, "logs", "hook-stdin-ingest.log");
|
|
1316
|
+
mkdirSync4(path8.dirname(debugPath), { recursive: true });
|
|
642
1317
|
const ts = (/* @__PURE__ */ new Date()).toISOString();
|
|
643
1318
|
const snippet = input.length > 2e3 ? input.slice(0, 2e3) + "...[truncated]" : input;
|
|
644
|
-
|
|
1319
|
+
writeFileSync6(debugPath, `[${ts}] ${snippet}
|
|
645
1320
|
`, { flag: "a" });
|
|
646
1321
|
} catch {
|
|
647
1322
|
}
|
|
@@ -708,14 +1383,14 @@ Your output files must start with: exe/output/${agent.agentId}-`
|
|
|
708
1383
|
const classification = classifyError(errorText);
|
|
709
1384
|
if (classification === "system" && data.session_id) {
|
|
710
1385
|
const fp = errorFingerprint(data.tool_name, errorText);
|
|
711
|
-
const fpFilePath =
|
|
1386
|
+
const fpFilePath = path8.join(COUNTER_DIR, `bug-fingerprints-${data.session_id}.json`);
|
|
712
1387
|
let fpData = {
|
|
713
1388
|
seen: {},
|
|
714
1389
|
taskCount: 0,
|
|
715
1390
|
lastTaskAt: ""
|
|
716
1391
|
};
|
|
717
1392
|
try {
|
|
718
|
-
fpData = JSON.parse(
|
|
1393
|
+
fpData = JSON.parse(readFileSync6(fpFilePath, "utf8"));
|
|
719
1394
|
} catch {
|
|
720
1395
|
}
|
|
721
1396
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -733,13 +1408,13 @@ Your output files must start with: exe/output/${agent.agentId}-`
|
|
|
733
1408
|
fpData.seen[fp] = { count: 1, firstAt: now, lastAt: now };
|
|
734
1409
|
fpData.taskCount++;
|
|
735
1410
|
fpData.lastTaskAt = now;
|
|
736
|
-
const bugWorkerPath =
|
|
737
|
-
|
|
1411
|
+
const bugWorkerPath = path8.resolve(
|
|
1412
|
+
path8.dirname(fileURLToPath(import.meta.url)),
|
|
738
1413
|
"bug-report-worker.js"
|
|
739
1414
|
);
|
|
740
|
-
if (
|
|
1415
|
+
if (existsSync7(bugWorkerPath) && tryAcquireWorkerSlot()) {
|
|
741
1416
|
const stderrFd2 = openWorkerLog();
|
|
742
|
-
const projectName = process.cwd().split(
|
|
1417
|
+
const projectName = process.cwd().split(path8.sep).pop() ?? "unknown";
|
|
743
1418
|
const bugToolInput = data.tool_input ?? {};
|
|
744
1419
|
const bugWorker = spawn(process.execPath, [bugWorkerPath], {
|
|
745
1420
|
detached: true,
|
|
@@ -767,8 +1442,8 @@ Your output files must start with: exe/output/${agent.agentId}-`
|
|
|
767
1442
|
}
|
|
768
1443
|
}
|
|
769
1444
|
try {
|
|
770
|
-
|
|
771
|
-
|
|
1445
|
+
mkdirSync4(COUNTER_DIR, { recursive: true });
|
|
1446
|
+
writeFileSync6(fpFilePath, JSON.stringify(fpData));
|
|
772
1447
|
} catch {
|
|
773
1448
|
}
|
|
774
1449
|
}
|
|
@@ -785,11 +1460,11 @@ Your output files must start with: exe/output/${agent.agentId}-`
|
|
|
785
1460
|
}
|
|
786
1461
|
const callsSinceLastSummary = counter.total - counter.lastSummaryAt;
|
|
787
1462
|
if (callsSinceLastSummary >= SUMMARY_INTERVAL && counter.writes >= MIN_WRITES_FOR_SUMMARY) {
|
|
788
|
-
const summaryWorkerPath =
|
|
789
|
-
|
|
1463
|
+
const summaryWorkerPath = path8.resolve(
|
|
1464
|
+
path8.dirname(fileURLToPath(import.meta.url)),
|
|
790
1465
|
"summary-worker.js"
|
|
791
1466
|
);
|
|
792
|
-
if (
|
|
1467
|
+
if (existsSync7(summaryWorkerPath) && tryAcquireWorkerSlot()) {
|
|
793
1468
|
const stderrFd2 = openWorkerLog();
|
|
794
1469
|
const summaryWorker = spawn(process.execPath, [summaryWorkerPath], {
|
|
795
1470
|
detached: true,
|
|
@@ -835,13 +1510,13 @@ WARNING: You are writing code without running the build pipeline. If this task a
|
|
|
835
1510
|
const bashOutput = typeof data.tool_response === "string" ? data.tool_response : JSON.stringify(data.tool_response ?? "");
|
|
836
1511
|
const commitMatch = bashOutput.match(/\[(\S+)\s+([a-f0-9]{7,40})\]\s+(.+)/);
|
|
837
1512
|
if (commitMatch) {
|
|
838
|
-
const commitWorkerPath =
|
|
839
|
-
|
|
1513
|
+
const commitWorkerPath = path8.resolve(
|
|
1514
|
+
path8.dirname(fileURLToPath(import.meta.url)),
|
|
840
1515
|
"commit-complete.js"
|
|
841
1516
|
);
|
|
842
|
-
if (
|
|
1517
|
+
if (existsSync7(commitWorkerPath) && tryAcquireWorkerSlot()) {
|
|
843
1518
|
const stderrFd2 = openWorkerLog();
|
|
844
|
-
const projectName = process.cwd().split(
|
|
1519
|
+
const projectName = process.cwd().split(path8.sep).pop() ?? "unknown";
|
|
845
1520
|
const commitWorker = spawn(process.execPath, [commitWorkerPath], {
|
|
846
1521
|
detached: true,
|
|
847
1522
|
stdio: ["ignore", "ignore", stderrFd2],
|
|
@@ -865,8 +1540,68 @@ WARNING: You are writing code without running the build pipeline. If this task a
|
|
|
865
1540
|
if (!ALLOWED_TOOL_RE.test(data.tool_name)) {
|
|
866
1541
|
process.exit(0);
|
|
867
1542
|
}
|
|
868
|
-
|
|
869
|
-
|
|
1543
|
+
let sentViaDaemon = false;
|
|
1544
|
+
try {
|
|
1545
|
+
const socketPath = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path8.join(EXE_AI_DIR, "exed.sock");
|
|
1546
|
+
if (existsSync7(socketPath)) {
|
|
1547
|
+
const { extractSemanticText: extractSemanticText2 } = await Promise.resolve().then(() => (init_content_extractor(), content_extractor_exports));
|
|
1548
|
+
const { getProjectName: getProjectName2 } = await Promise.resolve().then(() => (init_project_name(), project_name_exports));
|
|
1549
|
+
const { canCoordinate: canCoordinate2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
1550
|
+
const { readDaemonToken: readDaemonToken2 } = await Promise.resolve().then(() => (init_daemon_auth(), daemon_auth_exports));
|
|
1551
|
+
const rawText = extractSemanticText2(data.tool_name, data.tool_input ?? {}, data.tool_response ?? {});
|
|
1552
|
+
if (rawText.length >= 50) {
|
|
1553
|
+
let taskId = null;
|
|
1554
|
+
try {
|
|
1555
|
+
const cachePath = path8.join(EXE_AI_DIR, "session-cache", `current-task-${agent.agentId}.json`);
|
|
1556
|
+
if (existsSync7(cachePath)) {
|
|
1557
|
+
const cached = JSON.parse(readFileSync6(cachePath, "utf8"));
|
|
1558
|
+
taskId = cached.taskId ?? null;
|
|
1559
|
+
}
|
|
1560
|
+
} catch {
|
|
1561
|
+
}
|
|
1562
|
+
const detectData2 = { tool_name: data.tool_name, tool_response: data.tool_response };
|
|
1563
|
+
const hasError = detectError(detectData2);
|
|
1564
|
+
const isDraft = taskId !== null && !canCoordinate2(agent.agentId, agent.agentRole);
|
|
1565
|
+
const toolInputStr = JSON.stringify(data.tool_input ?? "").slice(0, 200);
|
|
1566
|
+
const toolOutputStr = JSON.stringify(data.tool_response ?? "").slice(0, 200);
|
|
1567
|
+
const token = process.env.EXE_DAEMON_TOKEN ?? readDaemonToken2();
|
|
1568
|
+
const projectName = getProjectName2(data.cwd ?? process.cwd());
|
|
1569
|
+
const payload = JSON.stringify({
|
|
1570
|
+
id: `ingest-${Date.now()}`,
|
|
1571
|
+
token,
|
|
1572
|
+
type: "ingest",
|
|
1573
|
+
rawText,
|
|
1574
|
+
agentId: agent.agentId,
|
|
1575
|
+
agentRole: agent.agentRole,
|
|
1576
|
+
sessionId: data.session_id ?? "",
|
|
1577
|
+
toolName: data.tool_name,
|
|
1578
|
+
projectName,
|
|
1579
|
+
hasError,
|
|
1580
|
+
taskId,
|
|
1581
|
+
confidence: agent.agentId === "default" ? 0.9 : 0.7,
|
|
1582
|
+
draft: isDraft,
|
|
1583
|
+
trajectory: { input: toolInputStr, tool: data.tool_name, output: toolOutputStr, result_type: hasError ? "error" : "success" }
|
|
1584
|
+
}) + "\n";
|
|
1585
|
+
const net = await import("net");
|
|
1586
|
+
const sock = net.connect(socketPath);
|
|
1587
|
+
sock.on("error", () => {
|
|
1588
|
+
});
|
|
1589
|
+
sock.write(payload, () => {
|
|
1590
|
+
sock.destroy();
|
|
1591
|
+
});
|
|
1592
|
+
sentViaDaemon = true;
|
|
1593
|
+
} else {
|
|
1594
|
+
sentViaDaemon = true;
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
} catch {
|
|
1598
|
+
}
|
|
1599
|
+
if (sentViaDaemon) {
|
|
1600
|
+
setTimeout(() => process.exit(0), 10);
|
|
1601
|
+
return;
|
|
1602
|
+
}
|
|
1603
|
+
const workerPath = path8.resolve(
|
|
1604
|
+
path8.dirname(fileURLToPath(import.meta.url)),
|
|
870
1605
|
"ingest-worker.js"
|
|
871
1606
|
);
|
|
872
1607
|
if (!tryAcquireWorkerSlot()) {
|