@askexenow/exe-os 0.9.7 → 0.9.8
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 +754 -79
- package/dist/bin/backfill-responses.js +752 -77
- package/dist/bin/backfill-vectors.js +752 -77
- package/dist/bin/cleanup-stale-review-tasks.js +657 -35
- package/dist/bin/cli.js +1388 -605
- package/dist/bin/exe-agent-config.js +123 -95
- package/dist/bin/exe-agent.js +41 -25
- package/dist/bin/exe-assign.js +732 -57
- package/dist/bin/exe-boot.js +784 -153
- package/dist/bin/exe-call.js +209 -138
- package/dist/bin/exe-cloud.js +35 -12
- package/dist/bin/exe-dispatch.js +692 -70
- package/dist/bin/exe-doctor.js +648 -26
- package/dist/bin/exe-export-behaviors.js +650 -20
- package/dist/bin/exe-forget.js +635 -13
- package/dist/bin/exe-gateway.js +1053 -271
- package/dist/bin/exe-heartbeat.js +665 -43
- package/dist/bin/exe-kill.js +646 -16
- package/dist/bin/exe-launch-agent.js +887 -97
- package/dist/bin/exe-link.js +658 -43
- package/dist/bin/exe-new-employee.js +378 -177
- package/dist/bin/exe-pending-messages.js +656 -34
- package/dist/bin/exe-pending-notifications.js +635 -13
- package/dist/bin/exe-pending-reviews.js +659 -37
- package/dist/bin/exe-rename.js +645 -30
- package/dist/bin/exe-review.js +635 -13
- package/dist/bin/exe-search.js +771 -88
- package/dist/bin/exe-session-cleanup.js +834 -150
- package/dist/bin/exe-settings.js +127 -91
- package/dist/bin/exe-start-codex.js +729 -94
- package/dist/bin/exe-start-opencode.js +717 -82
- package/dist/bin/exe-status.js +657 -35
- package/dist/bin/exe-team.js +635 -13
- package/dist/bin/git-sweep.js +720 -89
- package/dist/bin/graph-backfill.js +643 -13
- package/dist/bin/graph-export.js +646 -16
- package/dist/bin/install.js +596 -193
- package/dist/bin/scan-tasks.js +724 -93
- package/dist/bin/setup.js +1038 -210
- package/dist/bin/shard-migrate.js +645 -15
- package/dist/bin/wiki-sync.js +646 -16
- package/dist/gateway/index.js +1027 -245
- package/dist/hooks/bug-report-worker.js +891 -170
- package/dist/hooks/commit-complete.js +718 -87
- package/dist/hooks/error-recall.js +776 -93
- package/dist/hooks/exe-heartbeat-hook.js +85 -71
- package/dist/hooks/ingest-worker.js +840 -156
- package/dist/hooks/ingest.js +90 -73
- package/dist/hooks/instructions-loaded.js +669 -38
- package/dist/hooks/notification.js +661 -30
- package/dist/hooks/post-compact.js +674 -43
- package/dist/hooks/pre-compact.js +718 -87
- package/dist/hooks/pre-tool-use.js +872 -125
- package/dist/hooks/prompt-ingest-worker.js +758 -83
- package/dist/hooks/prompt-submit.js +1060 -319
- package/dist/hooks/response-ingest-worker.js +758 -83
- package/dist/hooks/session-end.js +721 -90
- package/dist/hooks/session-start.js +1031 -207
- package/dist/hooks/stop.js +680 -49
- package/dist/hooks/subagent-stop.js +674 -43
- package/dist/hooks/summary-worker.js +816 -132
- package/dist/index.js +1015 -232
- package/dist/lib/cloud-sync.js +663 -48
- package/dist/lib/consolidation.js +26 -3
- package/dist/lib/database.js +626 -18
- package/dist/lib/db.js +2261 -0
- package/dist/lib/device-registry.js +640 -25
- package/dist/lib/embedder.js +96 -43
- package/dist/lib/employee-templates.js +16 -0
- package/dist/lib/employees.js +259 -83
- package/dist/lib/exe-daemon-client.js +101 -63
- package/dist/lib/exe-daemon.js +894 -162
- package/dist/lib/hybrid-search.js +771 -88
- package/dist/lib/identity.js +27 -7
- package/dist/lib/messaging.js +55 -28
- package/dist/lib/reminders.js +21 -1
- package/dist/lib/schedules.js +636 -14
- package/dist/lib/skill-learning.js +21 -1
- package/dist/lib/store.js +643 -13
- package/dist/lib/task-router.js +82 -71
- package/dist/lib/tasks.js +98 -71
- package/dist/lib/tmux-routing.js +87 -60
- package/dist/lib/token-spend.js +26 -6
- package/dist/mcp/server.js +1784 -458
- package/dist/mcp/tools/complete-reminder.js +21 -1
- package/dist/mcp/tools/create-reminder.js +21 -1
- package/dist/mcp/tools/create-task.js +290 -164
- package/dist/mcp/tools/deactivate-behavior.js +24 -4
- package/dist/mcp/tools/list-reminders.js +21 -1
- package/dist/mcp/tools/list-tasks.js +195 -38
- package/dist/mcp/tools/send-message.js +58 -31
- package/dist/mcp/tools/update-task.js +75 -48
- package/dist/runtime/index.js +720 -89
- package/dist/tui/App.js +853 -123
- package/package.json +3 -2
|
@@ -290,7 +290,7 @@ function baseAgentName(name, employees) {
|
|
|
290
290
|
if (getEmployee(roster, base)) return base;
|
|
291
291
|
return name;
|
|
292
292
|
}
|
|
293
|
-
var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE;
|
|
293
|
+
var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, IDENTITY_DIR;
|
|
294
294
|
var init_employees = __esm({
|
|
295
295
|
"src/lib/employees.ts"() {
|
|
296
296
|
"use strict";
|
|
@@ -298,12 +298,609 @@ var init_employees = __esm({
|
|
|
298
298
|
EMPLOYEES_PATH = path2.join(EXE_AI_DIR, "exe-employees.json");
|
|
299
299
|
DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
|
|
300
300
|
COORDINATOR_ROLE = "COO";
|
|
301
|
+
IDENTITY_DIR = path2.join(EXE_AI_DIR, "identity");
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
// src/lib/database-adapter.ts
|
|
306
|
+
import os3 from "os";
|
|
307
|
+
import path3 from "path";
|
|
308
|
+
import { createRequire } from "module";
|
|
309
|
+
import { pathToFileURL } from "url";
|
|
310
|
+
function quotedIdentifier(identifier) {
|
|
311
|
+
return `"${identifier.replace(/"/g, '""')}"`;
|
|
312
|
+
}
|
|
313
|
+
function unqualifiedTableName(name) {
|
|
314
|
+
const raw = name.trim().replace(/^"|"$/g, "");
|
|
315
|
+
const parts = raw.split(".");
|
|
316
|
+
return parts[parts.length - 1].replace(/^"|"$/g, "").toLowerCase();
|
|
317
|
+
}
|
|
318
|
+
function stripTrailingSemicolon(sql) {
|
|
319
|
+
return sql.trim().replace(/;+\s*$/u, "");
|
|
320
|
+
}
|
|
321
|
+
function appendClause(sql, clause) {
|
|
322
|
+
const trimmed = stripTrailingSemicolon(sql);
|
|
323
|
+
const returningMatch = /\sRETURNING\b[\s\S]*$/iu.exec(trimmed);
|
|
324
|
+
if (!returningMatch) {
|
|
325
|
+
return `${trimmed}${clause}`;
|
|
326
|
+
}
|
|
327
|
+
const idx = returningMatch.index;
|
|
328
|
+
return `${trimmed.slice(0, idx)}${clause}${trimmed.slice(idx)}`;
|
|
329
|
+
}
|
|
330
|
+
function normalizeStatement(stmt) {
|
|
331
|
+
if (typeof stmt === "string") {
|
|
332
|
+
return { kind: "positional", sql: stmt, args: [] };
|
|
333
|
+
}
|
|
334
|
+
const sql = stmt.sql;
|
|
335
|
+
if (Array.isArray(stmt.args) || stmt.args === void 0) {
|
|
336
|
+
return { kind: "positional", sql, args: stmt.args ?? [] };
|
|
337
|
+
}
|
|
338
|
+
return { kind: "named", sql, args: stmt.args };
|
|
339
|
+
}
|
|
340
|
+
function rewriteBooleanLiterals(sql) {
|
|
341
|
+
let out = sql;
|
|
342
|
+
for (const column of BOOLEAN_COLUMN_NAMES) {
|
|
343
|
+
const scoped = `((?:\\b[a-z_][a-z0-9_]*\\.)?${column})`;
|
|
344
|
+
out = out.replace(new RegExp(`${scoped}\\s*=\\s*0\\b`, "giu"), "$1 = FALSE");
|
|
345
|
+
out = out.replace(new RegExp(`${scoped}\\s*=\\s*1\\b`, "giu"), "$1 = TRUE");
|
|
346
|
+
out = out.replace(new RegExp(`${scoped}\\s*!=\\s*0\\b`, "giu"), "$1 != FALSE");
|
|
347
|
+
out = out.replace(new RegExp(`${scoped}\\s*!=\\s*1\\b`, "giu"), "$1 != TRUE");
|
|
348
|
+
out = out.replace(new RegExp(`${scoped}\\s*<>\\s*0\\b`, "giu"), "$1 <> FALSE");
|
|
349
|
+
out = out.replace(new RegExp(`${scoped}\\s*<>\\s*1\\b`, "giu"), "$1 <> TRUE");
|
|
350
|
+
}
|
|
351
|
+
return out;
|
|
352
|
+
}
|
|
353
|
+
function rewriteInsertOrIgnore(sql) {
|
|
354
|
+
if (!/^\s*INSERT\s+OR\s+IGNORE\s+INTO\b/iu.test(sql)) {
|
|
355
|
+
return sql;
|
|
356
|
+
}
|
|
357
|
+
const replaced = sql.replace(/^\s*INSERT\s+OR\s+IGNORE\s+INTO\b/iu, "INSERT INTO");
|
|
358
|
+
return /\bON\s+CONFLICT\b/iu.test(replaced) ? replaced : appendClause(replaced, " ON CONFLICT DO NOTHING");
|
|
359
|
+
}
|
|
360
|
+
function rewriteInsertOrReplace(sql) {
|
|
361
|
+
const match = /^\s*INSERT\s+OR\s+REPLACE\s+INTO\s+([A-Za-z0-9_."]+)\s*\(([^)]+)\)([\s\S]*)$/iu.exec(sql);
|
|
362
|
+
if (!match) {
|
|
363
|
+
return sql;
|
|
364
|
+
}
|
|
365
|
+
const rawTable = match[1];
|
|
366
|
+
const rawColumns = match[2];
|
|
367
|
+
const remainder = match[3];
|
|
368
|
+
const tableName = unqualifiedTableName(rawTable);
|
|
369
|
+
const conflictKeys = UPSERT_KEYS[tableName];
|
|
370
|
+
if (!conflictKeys?.length) {
|
|
371
|
+
return sql;
|
|
372
|
+
}
|
|
373
|
+
const columns = rawColumns.split(",").map((col) => col.trim().replace(/^"|"$/g, ""));
|
|
374
|
+
const updateColumns = columns.filter((col) => !conflictKeys.includes(col));
|
|
375
|
+
const conflictTarget = conflictKeys.map(quotedIdentifier).join(", ");
|
|
376
|
+
const updateClause = updateColumns.length === 0 ? " DO NOTHING" : ` DO UPDATE SET ${updateColumns.map((col) => `${quotedIdentifier(col)} = EXCLUDED.${quotedIdentifier(col)}`).join(", ")}`;
|
|
377
|
+
return `INSERT INTO ${rawTable} (${rawColumns})${appendClause(remainder, ` ON CONFLICT (${conflictTarget})${updateClause}`)}`;
|
|
378
|
+
}
|
|
379
|
+
function rewriteSql(sql) {
|
|
380
|
+
let out = sql;
|
|
381
|
+
out = out.replace(/\bdatetime\(\s*['"]now['"]\s*\)/giu, "CURRENT_TIMESTAMP");
|
|
382
|
+
out = out.replace(/\bvector32\s*\(\s*\?\s*\)/giu, "?");
|
|
383
|
+
out = rewriteBooleanLiterals(out);
|
|
384
|
+
out = rewriteInsertOrReplace(out);
|
|
385
|
+
out = rewriteInsertOrIgnore(out);
|
|
386
|
+
return stripTrailingSemicolon(out);
|
|
387
|
+
}
|
|
388
|
+
function toBoolean(value) {
|
|
389
|
+
if (value === null || value === void 0) return value;
|
|
390
|
+
if (typeof value === "boolean") return value;
|
|
391
|
+
if (typeof value === "number") return value !== 0;
|
|
392
|
+
if (typeof value === "bigint") return value !== 0n;
|
|
393
|
+
if (typeof value === "string") {
|
|
394
|
+
const normalized = value.trim().toLowerCase();
|
|
395
|
+
if (normalized === "0" || normalized === "false") return false;
|
|
396
|
+
if (normalized === "1" || normalized === "true") return true;
|
|
397
|
+
}
|
|
398
|
+
return Boolean(value);
|
|
399
|
+
}
|
|
400
|
+
function countQuestionMarks(sql, end) {
|
|
401
|
+
let count = 0;
|
|
402
|
+
let inSingle = false;
|
|
403
|
+
let inDouble = false;
|
|
404
|
+
let inLineComment = false;
|
|
405
|
+
let inBlockComment = false;
|
|
406
|
+
for (let i = 0; i < end; i++) {
|
|
407
|
+
const ch = sql[i];
|
|
408
|
+
const next = sql[i + 1];
|
|
409
|
+
if (inLineComment) {
|
|
410
|
+
if (ch === "\n") inLineComment = false;
|
|
411
|
+
continue;
|
|
412
|
+
}
|
|
413
|
+
if (inBlockComment) {
|
|
414
|
+
if (ch === "*" && next === "/") {
|
|
415
|
+
inBlockComment = false;
|
|
416
|
+
i += 1;
|
|
417
|
+
}
|
|
418
|
+
continue;
|
|
419
|
+
}
|
|
420
|
+
if (!inSingle && !inDouble && ch === "-" && next === "-") {
|
|
421
|
+
inLineComment = true;
|
|
422
|
+
i += 1;
|
|
423
|
+
continue;
|
|
424
|
+
}
|
|
425
|
+
if (!inSingle && !inDouble && ch === "/" && next === "*") {
|
|
426
|
+
inBlockComment = true;
|
|
427
|
+
i += 1;
|
|
428
|
+
continue;
|
|
429
|
+
}
|
|
430
|
+
if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
|
|
431
|
+
inSingle = !inSingle;
|
|
432
|
+
continue;
|
|
433
|
+
}
|
|
434
|
+
if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
|
|
435
|
+
inDouble = !inDouble;
|
|
436
|
+
continue;
|
|
437
|
+
}
|
|
438
|
+
if (!inSingle && !inDouble && ch === "?") {
|
|
439
|
+
count += 1;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
return count;
|
|
443
|
+
}
|
|
444
|
+
function findBooleanPlaceholderIndexes(sql) {
|
|
445
|
+
const indexes = /* @__PURE__ */ new Set();
|
|
446
|
+
for (const column of BOOLEAN_COLUMN_NAMES) {
|
|
447
|
+
const pattern = new RegExp(`(?:\\b[a-z_][a-z0-9_]*\\.)?${column}\\s*=\\s*\\?`, "giu");
|
|
448
|
+
for (const match of sql.matchAll(pattern)) {
|
|
449
|
+
const matchText = match[0];
|
|
450
|
+
const qIndex = match.index + matchText.lastIndexOf("?");
|
|
451
|
+
indexes.add(countQuestionMarks(sql, qIndex + 1));
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
return indexes;
|
|
455
|
+
}
|
|
456
|
+
function coerceInsertBooleanArgs(sql, args) {
|
|
457
|
+
const match = /^\s*INSERT(?:\s+OR\s+(?:IGNORE|REPLACE))?\s+INTO\s+([A-Za-z0-9_."]+)\s*\(([^)]+)\)/iu.exec(sql);
|
|
458
|
+
if (!match) return;
|
|
459
|
+
const rawTable = match[1];
|
|
460
|
+
const rawColumns = match[2];
|
|
461
|
+
const boolColumns = BOOLEAN_COLUMNS_BY_TABLE[unqualifiedTableName(rawTable)];
|
|
462
|
+
if (!boolColumns?.size) return;
|
|
463
|
+
const columns = rawColumns.split(",").map((col) => col.trim().replace(/^"|"$/g, ""));
|
|
464
|
+
for (const [index, column] of columns.entries()) {
|
|
465
|
+
if (boolColumns.has(column) && index < args.length) {
|
|
466
|
+
args[index] = toBoolean(args[index]);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
function coerceUpdateBooleanArgs(sql, args) {
|
|
471
|
+
const match = /^\s*UPDATE\s+([A-Za-z0-9_."]+)\s+SET\s+([\s\S]+?)(?:\s+WHERE\b|$)/iu.exec(sql);
|
|
472
|
+
if (!match) return;
|
|
473
|
+
const rawTable = match[1];
|
|
474
|
+
const setClause = match[2];
|
|
475
|
+
const boolColumns = BOOLEAN_COLUMNS_BY_TABLE[unqualifiedTableName(rawTable)];
|
|
476
|
+
if (!boolColumns?.size) return;
|
|
477
|
+
const assignments = setClause.split(",");
|
|
478
|
+
let placeholderIndex = 0;
|
|
479
|
+
for (const assignment of assignments) {
|
|
480
|
+
if (!assignment.includes("?")) continue;
|
|
481
|
+
placeholderIndex += 1;
|
|
482
|
+
const colMatch = /^\s*(?:[A-Za-z_][A-Za-z0-9_]*\.)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*\?/iu.exec(assignment);
|
|
483
|
+
if (colMatch && boolColumns.has(colMatch[1])) {
|
|
484
|
+
args[placeholderIndex - 1] = toBoolean(args[placeholderIndex - 1]);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
function coerceBooleanArgs(sql, args) {
|
|
489
|
+
const nextArgs = [...args];
|
|
490
|
+
coerceInsertBooleanArgs(sql, nextArgs);
|
|
491
|
+
coerceUpdateBooleanArgs(sql, nextArgs);
|
|
492
|
+
const placeholderIndexes = findBooleanPlaceholderIndexes(sql);
|
|
493
|
+
for (const index of placeholderIndexes) {
|
|
494
|
+
if (index > 0 && index <= nextArgs.length) {
|
|
495
|
+
nextArgs[index - 1] = toBoolean(nextArgs[index - 1]);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
return nextArgs;
|
|
499
|
+
}
|
|
500
|
+
function convertQuestionMarksToDollarParams(sql) {
|
|
501
|
+
let out = "";
|
|
502
|
+
let placeholder = 0;
|
|
503
|
+
let inSingle = false;
|
|
504
|
+
let inDouble = false;
|
|
505
|
+
let inLineComment = false;
|
|
506
|
+
let inBlockComment = false;
|
|
507
|
+
for (let i = 0; i < sql.length; i++) {
|
|
508
|
+
const ch = sql[i];
|
|
509
|
+
const next = sql[i + 1];
|
|
510
|
+
if (inLineComment) {
|
|
511
|
+
out += ch;
|
|
512
|
+
if (ch === "\n") inLineComment = false;
|
|
513
|
+
continue;
|
|
514
|
+
}
|
|
515
|
+
if (inBlockComment) {
|
|
516
|
+
out += ch;
|
|
517
|
+
if (ch === "*" && next === "/") {
|
|
518
|
+
out += next;
|
|
519
|
+
inBlockComment = false;
|
|
520
|
+
i += 1;
|
|
521
|
+
}
|
|
522
|
+
continue;
|
|
523
|
+
}
|
|
524
|
+
if (!inSingle && !inDouble && ch === "-" && next === "-") {
|
|
525
|
+
out += ch + next;
|
|
526
|
+
inLineComment = true;
|
|
527
|
+
i += 1;
|
|
528
|
+
continue;
|
|
529
|
+
}
|
|
530
|
+
if (!inSingle && !inDouble && ch === "/" && next === "*") {
|
|
531
|
+
out += ch + next;
|
|
532
|
+
inBlockComment = true;
|
|
533
|
+
i += 1;
|
|
534
|
+
continue;
|
|
535
|
+
}
|
|
536
|
+
if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
|
|
537
|
+
inSingle = !inSingle;
|
|
538
|
+
out += ch;
|
|
539
|
+
continue;
|
|
540
|
+
}
|
|
541
|
+
if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
|
|
542
|
+
inDouble = !inDouble;
|
|
543
|
+
out += ch;
|
|
544
|
+
continue;
|
|
545
|
+
}
|
|
546
|
+
if (!inSingle && !inDouble && ch === "?") {
|
|
547
|
+
placeholder += 1;
|
|
548
|
+
out += `$${placeholder}`;
|
|
549
|
+
continue;
|
|
550
|
+
}
|
|
551
|
+
out += ch;
|
|
552
|
+
}
|
|
553
|
+
return out;
|
|
554
|
+
}
|
|
555
|
+
function translateStatementForPostgres(stmt) {
|
|
556
|
+
const normalized = normalizeStatement(stmt);
|
|
557
|
+
if (normalized.kind === "named") {
|
|
558
|
+
throw new Error("Named SQL parameters are not supported by the Prisma adapter.");
|
|
559
|
+
}
|
|
560
|
+
const rewrittenSql = rewriteSql(normalized.sql);
|
|
561
|
+
const coercedArgs = coerceBooleanArgs(rewrittenSql, normalized.args);
|
|
562
|
+
return {
|
|
563
|
+
sql: convertQuestionMarksToDollarParams(rewrittenSql),
|
|
564
|
+
args: coercedArgs
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
function shouldBypassPostgres(stmt) {
|
|
568
|
+
const normalized = normalizeStatement(stmt);
|
|
569
|
+
if (normalized.kind === "named") {
|
|
570
|
+
return true;
|
|
571
|
+
}
|
|
572
|
+
return IMMEDIATE_FALLBACK_PATTERNS.some((pattern) => pattern.test(normalized.sql));
|
|
573
|
+
}
|
|
574
|
+
function shouldFallbackOnError(error) {
|
|
575
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
576
|
+
return /42P01|42883|42601|does not exist|syntax error|not supported|Named SQL parameters are not supported/iu.test(message);
|
|
577
|
+
}
|
|
578
|
+
function isReadQuery(sql) {
|
|
579
|
+
const trimmed = sql.trimStart();
|
|
580
|
+
return /^(SELECT|WITH|SHOW|EXPLAIN|VALUES)\b/iu.test(trimmed) || /\bRETURNING\b/iu.test(trimmed);
|
|
581
|
+
}
|
|
582
|
+
function buildRow(row, columns) {
|
|
583
|
+
const values = columns.map((column) => row[column]);
|
|
584
|
+
return Object.assign(values, row);
|
|
585
|
+
}
|
|
586
|
+
function buildResultSet(rows, rowsAffected = 0) {
|
|
587
|
+
const columns = rows[0] ? Object.keys(rows[0]) : [];
|
|
588
|
+
const resultRows = rows.map((row) => buildRow(row, columns));
|
|
589
|
+
return {
|
|
590
|
+
columns,
|
|
591
|
+
columnTypes: columns.map(() => ""),
|
|
592
|
+
rows: resultRows,
|
|
593
|
+
rowsAffected,
|
|
594
|
+
lastInsertRowid: void 0,
|
|
595
|
+
toJSON() {
|
|
596
|
+
return {
|
|
597
|
+
columns,
|
|
598
|
+
columnTypes: columns.map(() => ""),
|
|
599
|
+
rows,
|
|
600
|
+
rowsAffected,
|
|
601
|
+
lastInsertRowid: void 0
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
async function loadPrismaClient() {
|
|
607
|
+
if (!prismaClientPromise) {
|
|
608
|
+
prismaClientPromise = (async () => {
|
|
609
|
+
const explicitPath = process.env.EXE_OS_PRISMA_CLIENT_PATH;
|
|
610
|
+
if (explicitPath) {
|
|
611
|
+
const module2 = await import(pathToFileURL(explicitPath).href);
|
|
612
|
+
const PrismaClient2 = module2.PrismaClient ?? module2.default?.PrismaClient;
|
|
613
|
+
if (!PrismaClient2) {
|
|
614
|
+
throw new Error(`No PrismaClient export found at ${explicitPath}`);
|
|
615
|
+
}
|
|
616
|
+
return new PrismaClient2();
|
|
617
|
+
}
|
|
618
|
+
const exeDbRoot = process.env.EXE_DB_ROOT ?? path3.join(os3.homedir(), "exe-db");
|
|
619
|
+
const requireFromExeDb = createRequire(path3.join(exeDbRoot, "package.json"));
|
|
620
|
+
const prismaEntry = requireFromExeDb.resolve("@prisma/client");
|
|
621
|
+
const module = await import(pathToFileURL(prismaEntry).href);
|
|
622
|
+
const PrismaClient = module.PrismaClient ?? module.default?.PrismaClient;
|
|
623
|
+
if (!PrismaClient) {
|
|
624
|
+
throw new Error(`No PrismaClient export found in ${prismaEntry}`);
|
|
625
|
+
}
|
|
626
|
+
return new PrismaClient();
|
|
627
|
+
})();
|
|
628
|
+
}
|
|
629
|
+
return prismaClientPromise;
|
|
630
|
+
}
|
|
631
|
+
async function ensureCompatibilityViews(prisma) {
|
|
632
|
+
if (!compatibilityBootstrapPromise) {
|
|
633
|
+
compatibilityBootstrapPromise = (async () => {
|
|
634
|
+
for (const mapping of VIEW_MAPPINGS) {
|
|
635
|
+
const relation = mapping.source.replace(/"/g, "");
|
|
636
|
+
const rows = await prisma.$queryRawUnsafe(
|
|
637
|
+
"SELECT to_regclass($1) AS regclass",
|
|
638
|
+
relation
|
|
639
|
+
);
|
|
640
|
+
if (!rows[0]?.regclass) {
|
|
641
|
+
continue;
|
|
642
|
+
}
|
|
643
|
+
await prisma.$executeRawUnsafe(
|
|
644
|
+
`CREATE OR REPLACE VIEW public.${quotedIdentifier(mapping.view)} AS SELECT * FROM ${mapping.source}`
|
|
645
|
+
);
|
|
646
|
+
}
|
|
647
|
+
})();
|
|
648
|
+
}
|
|
649
|
+
return compatibilityBootstrapPromise;
|
|
650
|
+
}
|
|
651
|
+
async function executeOnPrisma(executor, stmt) {
|
|
652
|
+
const translated = translateStatementForPostgres(stmt);
|
|
653
|
+
if (isReadQuery(translated.sql)) {
|
|
654
|
+
const rows = await executor.$queryRawUnsafe(
|
|
655
|
+
translated.sql,
|
|
656
|
+
...translated.args
|
|
657
|
+
);
|
|
658
|
+
return buildResultSet(rows, /\bRETURNING\b/iu.test(translated.sql) ? rows.length : 0);
|
|
659
|
+
}
|
|
660
|
+
const rowsAffected = await executor.$executeRawUnsafe(translated.sql, ...translated.args);
|
|
661
|
+
return buildResultSet([], rowsAffected);
|
|
662
|
+
}
|
|
663
|
+
function splitSqlStatements(sql) {
|
|
664
|
+
const parts = [];
|
|
665
|
+
let current = "";
|
|
666
|
+
let inSingle = false;
|
|
667
|
+
let inDouble = false;
|
|
668
|
+
let inLineComment = false;
|
|
669
|
+
let inBlockComment = false;
|
|
670
|
+
for (let i = 0; i < sql.length; i++) {
|
|
671
|
+
const ch = sql[i];
|
|
672
|
+
const next = sql[i + 1];
|
|
673
|
+
if (inLineComment) {
|
|
674
|
+
current += ch;
|
|
675
|
+
if (ch === "\n") inLineComment = false;
|
|
676
|
+
continue;
|
|
677
|
+
}
|
|
678
|
+
if (inBlockComment) {
|
|
679
|
+
current += ch;
|
|
680
|
+
if (ch === "*" && next === "/") {
|
|
681
|
+
current += next;
|
|
682
|
+
inBlockComment = false;
|
|
683
|
+
i += 1;
|
|
684
|
+
}
|
|
685
|
+
continue;
|
|
686
|
+
}
|
|
687
|
+
if (!inSingle && !inDouble && ch === "-" && next === "-") {
|
|
688
|
+
current += ch + next;
|
|
689
|
+
inLineComment = true;
|
|
690
|
+
i += 1;
|
|
691
|
+
continue;
|
|
692
|
+
}
|
|
693
|
+
if (!inSingle && !inDouble && ch === "/" && next === "*") {
|
|
694
|
+
current += ch + next;
|
|
695
|
+
inBlockComment = true;
|
|
696
|
+
i += 1;
|
|
697
|
+
continue;
|
|
698
|
+
}
|
|
699
|
+
if (!inDouble && ch === "'" && sql[i - 1] !== "\\") {
|
|
700
|
+
inSingle = !inSingle;
|
|
701
|
+
current += ch;
|
|
702
|
+
continue;
|
|
703
|
+
}
|
|
704
|
+
if (!inSingle && ch === '"' && sql[i - 1] !== "\\") {
|
|
705
|
+
inDouble = !inDouble;
|
|
706
|
+
current += ch;
|
|
707
|
+
continue;
|
|
708
|
+
}
|
|
709
|
+
if (!inSingle && !inDouble && ch === ";") {
|
|
710
|
+
if (current.trim()) {
|
|
711
|
+
parts.push(current.trim());
|
|
712
|
+
}
|
|
713
|
+
current = "";
|
|
714
|
+
continue;
|
|
715
|
+
}
|
|
716
|
+
current += ch;
|
|
717
|
+
}
|
|
718
|
+
if (current.trim()) {
|
|
719
|
+
parts.push(current.trim());
|
|
720
|
+
}
|
|
721
|
+
return parts;
|
|
722
|
+
}
|
|
723
|
+
async function createPrismaDbAdapter(fallbackClient) {
|
|
724
|
+
const prisma = await loadPrismaClient();
|
|
725
|
+
await ensureCompatibilityViews(prisma);
|
|
726
|
+
let closed = false;
|
|
727
|
+
let adapter;
|
|
728
|
+
const fallbackExecute = async (stmt, error) => {
|
|
729
|
+
if (!fallbackClient) {
|
|
730
|
+
if (error) throw error;
|
|
731
|
+
throw new Error("No fallback SQLite client is available for this Prisma-routed query.");
|
|
732
|
+
}
|
|
733
|
+
if (error) {
|
|
734
|
+
process.stderr.write(
|
|
735
|
+
`[database-adapter] Falling back to SQLite: ${error instanceof Error ? error.message : String(error)}
|
|
736
|
+
`
|
|
737
|
+
);
|
|
738
|
+
}
|
|
739
|
+
return fallbackClient.execute(stmt);
|
|
740
|
+
};
|
|
741
|
+
adapter = {
|
|
742
|
+
async execute(stmt) {
|
|
743
|
+
if (shouldBypassPostgres(stmt)) {
|
|
744
|
+
return fallbackExecute(stmt);
|
|
745
|
+
}
|
|
746
|
+
try {
|
|
747
|
+
return await executeOnPrisma(prisma, stmt);
|
|
748
|
+
} catch (error) {
|
|
749
|
+
if (shouldFallbackOnError(error)) {
|
|
750
|
+
return fallbackExecute(stmt, error);
|
|
751
|
+
}
|
|
752
|
+
throw error;
|
|
753
|
+
}
|
|
754
|
+
},
|
|
755
|
+
async batch(stmts, mode) {
|
|
756
|
+
if (stmts.some((stmt) => shouldBypassPostgres(stmt))) {
|
|
757
|
+
if (!fallbackClient) {
|
|
758
|
+
throw new Error("Cannot batch unsupported SQLite-only statements without a fallback client.");
|
|
759
|
+
}
|
|
760
|
+
return fallbackClient.batch(stmts, mode);
|
|
761
|
+
}
|
|
762
|
+
try {
|
|
763
|
+
if (prisma.$transaction) {
|
|
764
|
+
return await prisma.$transaction(async (tx) => {
|
|
765
|
+
const results2 = [];
|
|
766
|
+
for (const stmt of stmts) {
|
|
767
|
+
results2.push(await executeOnPrisma(tx, stmt));
|
|
768
|
+
}
|
|
769
|
+
return results2;
|
|
770
|
+
});
|
|
771
|
+
}
|
|
772
|
+
const results = [];
|
|
773
|
+
for (const stmt of stmts) {
|
|
774
|
+
results.push(await executeOnPrisma(prisma, stmt));
|
|
775
|
+
}
|
|
776
|
+
return results;
|
|
777
|
+
} catch (error) {
|
|
778
|
+
if (fallbackClient && shouldFallbackOnError(error)) {
|
|
779
|
+
process.stderr.write(
|
|
780
|
+
`[database-adapter] Falling back batch to SQLite: ${error instanceof Error ? error.message : String(error)}
|
|
781
|
+
`
|
|
782
|
+
);
|
|
783
|
+
return fallbackClient.batch(stmts, mode);
|
|
784
|
+
}
|
|
785
|
+
throw error;
|
|
786
|
+
}
|
|
787
|
+
},
|
|
788
|
+
async migrate(stmts) {
|
|
789
|
+
if (fallbackClient) {
|
|
790
|
+
return fallbackClient.migrate(stmts);
|
|
791
|
+
}
|
|
792
|
+
return adapter.batch(stmts, "deferred");
|
|
793
|
+
},
|
|
794
|
+
async transaction(mode) {
|
|
795
|
+
if (!fallbackClient) {
|
|
796
|
+
throw new Error("Interactive transactions are only supported on the SQLite fallback client.");
|
|
797
|
+
}
|
|
798
|
+
return fallbackClient.transaction(mode);
|
|
799
|
+
},
|
|
800
|
+
async executeMultiple(sql) {
|
|
801
|
+
if (fallbackClient && shouldBypassPostgres(sql)) {
|
|
802
|
+
return fallbackClient.executeMultiple(sql);
|
|
803
|
+
}
|
|
804
|
+
for (const statement of splitSqlStatements(sql)) {
|
|
805
|
+
await adapter.execute(statement);
|
|
806
|
+
}
|
|
807
|
+
},
|
|
808
|
+
async sync() {
|
|
809
|
+
if (fallbackClient) {
|
|
810
|
+
return fallbackClient.sync();
|
|
811
|
+
}
|
|
812
|
+
return { frame_no: 0, frames_synced: 0 };
|
|
813
|
+
},
|
|
814
|
+
close() {
|
|
815
|
+
closed = true;
|
|
816
|
+
prismaClientPromise = null;
|
|
817
|
+
compatibilityBootstrapPromise = null;
|
|
818
|
+
void prisma.$disconnect?.();
|
|
819
|
+
},
|
|
820
|
+
get closed() {
|
|
821
|
+
return closed;
|
|
822
|
+
},
|
|
823
|
+
get protocol() {
|
|
824
|
+
return "prisma-postgres";
|
|
825
|
+
}
|
|
826
|
+
};
|
|
827
|
+
return adapter;
|
|
828
|
+
}
|
|
829
|
+
var VIEW_MAPPINGS, UPSERT_KEYS, BOOLEAN_COLUMNS_BY_TABLE, BOOLEAN_COLUMN_NAMES, IMMEDIATE_FALLBACK_PATTERNS, prismaClientPromise, compatibilityBootstrapPromise;
|
|
830
|
+
var init_database_adapter = __esm({
|
|
831
|
+
"src/lib/database-adapter.ts"() {
|
|
832
|
+
"use strict";
|
|
833
|
+
VIEW_MAPPINGS = [
|
|
834
|
+
{ view: "memories", source: "memory.memory_records" },
|
|
835
|
+
{ view: "tasks", source: "memory.tasks" },
|
|
836
|
+
{ view: "behaviors", source: "memory.behaviors" },
|
|
837
|
+
{ view: "entities", source: "memory.entities" },
|
|
838
|
+
{ view: "relationships", source: "memory.relationships" },
|
|
839
|
+
{ view: "entity_memories", source: "memory.entity_memories" },
|
|
840
|
+
{ view: "entity_aliases", source: "memory.entity_aliases" },
|
|
841
|
+
{ view: "notifications", source: "memory.notifications" },
|
|
842
|
+
{ view: "messages", source: "memory.messages" },
|
|
843
|
+
{ view: "users", source: "wiki.users" },
|
|
844
|
+
{ view: "workspaces", source: "wiki.workspaces" },
|
|
845
|
+
{ view: "workspace_users", source: "wiki.workspace_users" },
|
|
846
|
+
{ view: "documents", source: "wiki.workspace_documents" },
|
|
847
|
+
{ view: "chats", source: "wiki.workspace_chats" }
|
|
848
|
+
];
|
|
849
|
+
UPSERT_KEYS = {
|
|
850
|
+
memories: ["id"],
|
|
851
|
+
tasks: ["id"],
|
|
852
|
+
behaviors: ["id"],
|
|
853
|
+
entities: ["id"],
|
|
854
|
+
relationships: ["id"],
|
|
855
|
+
entity_aliases: ["alias"],
|
|
856
|
+
notifications: ["id"],
|
|
857
|
+
messages: ["id"],
|
|
858
|
+
users: ["id"],
|
|
859
|
+
workspaces: ["id"],
|
|
860
|
+
workspace_users: ["id"],
|
|
861
|
+
documents: ["id"],
|
|
862
|
+
chats: ["id"]
|
|
863
|
+
};
|
|
864
|
+
BOOLEAN_COLUMNS_BY_TABLE = {
|
|
865
|
+
memories: /* @__PURE__ */ new Set(["has_error", "draft"]),
|
|
866
|
+
behaviors: /* @__PURE__ */ new Set(["active"]),
|
|
867
|
+
notifications: /* @__PURE__ */ new Set(["read"]),
|
|
868
|
+
users: /* @__PURE__ */ new Set(["has_personal_memory"])
|
|
869
|
+
};
|
|
870
|
+
BOOLEAN_COLUMN_NAMES = new Set(
|
|
871
|
+
Object.values(BOOLEAN_COLUMNS_BY_TABLE).flatMap((cols) => [...cols])
|
|
872
|
+
);
|
|
873
|
+
IMMEDIATE_FALLBACK_PATTERNS = [
|
|
874
|
+
/\bPRAGMA\b/i,
|
|
875
|
+
/\bsqlite_master\b/i,
|
|
876
|
+
/(?:^|[.\s])(?:memories|conversations|entities)_fts\b/i,
|
|
877
|
+
/\bMATCH\b/i,
|
|
878
|
+
/\bvector_distance_cos\s*\(/i,
|
|
879
|
+
/\bjson_extract\s*\(/i,
|
|
880
|
+
/\bjulianday\s*\(/i,
|
|
881
|
+
/\bstrftime\s*\(/i,
|
|
882
|
+
/\blast_insert_rowid\s*\(/i
|
|
883
|
+
];
|
|
884
|
+
prismaClientPromise = null;
|
|
885
|
+
compatibilityBootstrapPromise = null;
|
|
301
886
|
}
|
|
302
887
|
});
|
|
303
888
|
|
|
304
889
|
// src/lib/database.ts
|
|
305
890
|
import { createClient } from "@libsql/client";
|
|
306
891
|
async function initDatabase(config) {
|
|
892
|
+
if (_walCheckpointTimer) {
|
|
893
|
+
clearInterval(_walCheckpointTimer);
|
|
894
|
+
_walCheckpointTimer = null;
|
|
895
|
+
}
|
|
896
|
+
if (_daemonClient) {
|
|
897
|
+
_daemonClient.close();
|
|
898
|
+
_daemonClient = null;
|
|
899
|
+
}
|
|
900
|
+
if (_adapterClient && _adapterClient !== _resilientClient) {
|
|
901
|
+
_adapterClient.close();
|
|
902
|
+
}
|
|
903
|
+
_adapterClient = null;
|
|
307
904
|
if (_client) {
|
|
308
905
|
_client.close();
|
|
309
906
|
_client = null;
|
|
@@ -317,6 +914,7 @@ async function initDatabase(config) {
|
|
|
317
914
|
}
|
|
318
915
|
_client = createClient(opts);
|
|
319
916
|
_resilientClient = wrapWithRetry(_client);
|
|
917
|
+
_adapterClient = _resilientClient;
|
|
320
918
|
_client.execute("PRAGMA busy_timeout = 30000").catch(() => {
|
|
321
919
|
});
|
|
322
920
|
_client.execute("PRAGMA journal_mode = WAL").catch(() => {
|
|
@@ -327,11 +925,17 @@ async function initDatabase(config) {
|
|
|
327
925
|
});
|
|
328
926
|
}, 3e4);
|
|
329
927
|
_walCheckpointTimer.unref();
|
|
928
|
+
if (process.env.DATABASE_URL) {
|
|
929
|
+
_adapterClient = await createPrismaDbAdapter(_resilientClient);
|
|
930
|
+
}
|
|
330
931
|
}
|
|
331
932
|
function getClient() {
|
|
332
|
-
if (!
|
|
933
|
+
if (!_adapterClient) {
|
|
333
934
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
334
935
|
}
|
|
936
|
+
if (process.env.DATABASE_URL) {
|
|
937
|
+
return _adapterClient;
|
|
938
|
+
}
|
|
335
939
|
if (process.env.EXE_IS_DAEMON === "1") {
|
|
336
940
|
return _resilientClient;
|
|
337
941
|
}
|
|
@@ -1272,26 +1876,36 @@ async function ensureSchema() {
|
|
|
1272
1876
|
}
|
|
1273
1877
|
}
|
|
1274
1878
|
async function disposeDatabase() {
|
|
1879
|
+
if (_walCheckpointTimer) {
|
|
1880
|
+
clearInterval(_walCheckpointTimer);
|
|
1881
|
+
_walCheckpointTimer = null;
|
|
1882
|
+
}
|
|
1275
1883
|
if (_daemonClient) {
|
|
1276
1884
|
_daemonClient.close();
|
|
1277
1885
|
_daemonClient = null;
|
|
1278
1886
|
}
|
|
1887
|
+
if (_adapterClient && _adapterClient !== _resilientClient) {
|
|
1888
|
+
_adapterClient.close();
|
|
1889
|
+
}
|
|
1890
|
+
_adapterClient = null;
|
|
1279
1891
|
if (_client) {
|
|
1280
1892
|
_client.close();
|
|
1281
1893
|
_client = null;
|
|
1282
1894
|
_resilientClient = null;
|
|
1283
1895
|
}
|
|
1284
1896
|
}
|
|
1285
|
-
var _client, _resilientClient, _walCheckpointTimer, _daemonClient, initTurso, disposeTurso;
|
|
1897
|
+
var _client, _resilientClient, _walCheckpointTimer, _daemonClient, _adapterClient, initTurso, disposeTurso;
|
|
1286
1898
|
var init_database = __esm({
|
|
1287
1899
|
"src/lib/database.ts"() {
|
|
1288
1900
|
"use strict";
|
|
1289
1901
|
init_db_retry();
|
|
1290
1902
|
init_employees();
|
|
1903
|
+
init_database_adapter();
|
|
1291
1904
|
_client = null;
|
|
1292
1905
|
_resilientClient = null;
|
|
1293
1906
|
_walCheckpointTimer = null;
|
|
1294
1907
|
_daemonClient = null;
|
|
1908
|
+
_adapterClient = null;
|
|
1295
1909
|
initTurso = initDatabase;
|
|
1296
1910
|
disposeTurso = disposeDatabase;
|
|
1297
1911
|
}
|
|
@@ -1310,7 +1924,7 @@ __export(shard_manager_exports, {
|
|
|
1310
1924
|
listShards: () => listShards,
|
|
1311
1925
|
shardExists: () => shardExists
|
|
1312
1926
|
});
|
|
1313
|
-
import
|
|
1927
|
+
import path5 from "path";
|
|
1314
1928
|
import { existsSync as existsSync4, mkdirSync, readdirSync } from "fs";
|
|
1315
1929
|
import { createClient as createClient2 } from "@libsql/client";
|
|
1316
1930
|
function initShardManager(encryptionKey) {
|
|
@@ -1336,7 +1950,7 @@ function getShardClient(projectName) {
|
|
|
1336
1950
|
}
|
|
1337
1951
|
const cached = _shards.get(safeName);
|
|
1338
1952
|
if (cached) return cached;
|
|
1339
|
-
const dbPath =
|
|
1953
|
+
const dbPath = path5.join(SHARDS_DIR, `${safeName}.db`);
|
|
1340
1954
|
const client = createClient2({
|
|
1341
1955
|
url: `file:${dbPath}`,
|
|
1342
1956
|
encryptionKey: _encryptionKey
|
|
@@ -1346,7 +1960,7 @@ function getShardClient(projectName) {
|
|
|
1346
1960
|
}
|
|
1347
1961
|
function shardExists(projectName) {
|
|
1348
1962
|
const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
1349
|
-
return existsSync4(
|
|
1963
|
+
return existsSync4(path5.join(SHARDS_DIR, `${safeName}.db`));
|
|
1350
1964
|
}
|
|
1351
1965
|
function listShards() {
|
|
1352
1966
|
if (!existsSync4(SHARDS_DIR)) return [];
|
|
@@ -1423,7 +2037,23 @@ async function ensureShardSchema(client) {
|
|
|
1423
2037
|
// MS-11: draft staging, MS-6a: memory_type, MS-7: trajectory
|
|
1424
2038
|
"ALTER TABLE memories ADD COLUMN draft INTEGER DEFAULT 0",
|
|
1425
2039
|
"ALTER TABLE memories ADD COLUMN memory_type TEXT DEFAULT 'raw'",
|
|
1426
|
-
"ALTER TABLE memories ADD COLUMN trajectory TEXT"
|
|
2040
|
+
"ALTER TABLE memories ADD COLUMN trajectory TEXT",
|
|
2041
|
+
// Metadata enrichment columns (must match database.ts)
|
|
2042
|
+
"ALTER TABLE memories ADD COLUMN intent TEXT",
|
|
2043
|
+
"ALTER TABLE memories ADD COLUMN outcome TEXT",
|
|
2044
|
+
"ALTER TABLE memories ADD COLUMN domain TEXT",
|
|
2045
|
+
"ALTER TABLE memories ADD COLUMN referenced_entities TEXT",
|
|
2046
|
+
"ALTER TABLE memories ADD COLUMN retrieval_count INTEGER DEFAULT 0",
|
|
2047
|
+
"ALTER TABLE memories ADD COLUMN chain_position TEXT",
|
|
2048
|
+
"ALTER TABLE memories ADD COLUMN review_status TEXT",
|
|
2049
|
+
"ALTER TABLE memories ADD COLUMN context_window_pct INTEGER",
|
|
2050
|
+
"ALTER TABLE memories ADD COLUMN file_paths TEXT",
|
|
2051
|
+
"ALTER TABLE memories ADD COLUMN commit_hash TEXT",
|
|
2052
|
+
"ALTER TABLE memories ADD COLUMN duration_ms INTEGER",
|
|
2053
|
+
"ALTER TABLE memories ADD COLUMN token_cost REAL",
|
|
2054
|
+
"ALTER TABLE memories ADD COLUMN audience TEXT",
|
|
2055
|
+
"ALTER TABLE memories ADD COLUMN language_type TEXT",
|
|
2056
|
+
"ALTER TABLE memories ADD COLUMN parent_memory_id TEXT"
|
|
1427
2057
|
]) {
|
|
1428
2058
|
try {
|
|
1429
2059
|
await client.execute(col);
|
|
@@ -1535,7 +2165,7 @@ var init_shard_manager = __esm({
|
|
|
1535
2165
|
"src/lib/shard-manager.ts"() {
|
|
1536
2166
|
"use strict";
|
|
1537
2167
|
init_config();
|
|
1538
|
-
SHARDS_DIR =
|
|
2168
|
+
SHARDS_DIR = path5.join(EXE_AI_DIR, "shards");
|
|
1539
2169
|
_shards = /* @__PURE__ */ new Map();
|
|
1540
2170
|
_encryptionKey = null;
|
|
1541
2171
|
_shardingEnabled = false;
|
|
@@ -1729,6 +2359,32 @@ ${p.content}`).join("\n\n");
|
|
|
1729
2359
|
}
|
|
1730
2360
|
});
|
|
1731
2361
|
|
|
2362
|
+
// src/lib/runtime-table.ts
|
|
2363
|
+
var RUNTIME_TABLE;
|
|
2364
|
+
var init_runtime_table = __esm({
|
|
2365
|
+
"src/lib/runtime-table.ts"() {
|
|
2366
|
+
"use strict";
|
|
2367
|
+
RUNTIME_TABLE = {
|
|
2368
|
+
codex: {
|
|
2369
|
+
binary: "codex",
|
|
2370
|
+
launchMode: "interactive",
|
|
2371
|
+
autoApproveFlag: "--dangerously-bypass-approvals-and-sandbox",
|
|
2372
|
+
inlineFlag: "--no-alt-screen",
|
|
2373
|
+
apiKeyEnv: "OPENAI_API_KEY",
|
|
2374
|
+
defaultModel: "gpt-5.4"
|
|
2375
|
+
},
|
|
2376
|
+
opencode: {
|
|
2377
|
+
binary: "opencode",
|
|
2378
|
+
launchMode: "exec",
|
|
2379
|
+
autoApproveFlag: "--dangerously-skip-permissions",
|
|
2380
|
+
inlineFlag: "",
|
|
2381
|
+
apiKeyEnv: "ANTHROPIC_API_KEY",
|
|
2382
|
+
defaultModel: "anthropic/claude-sonnet-4-6"
|
|
2383
|
+
}
|
|
2384
|
+
};
|
|
2385
|
+
}
|
|
2386
|
+
});
|
|
2387
|
+
|
|
1732
2388
|
// src/lib/session-key.ts
|
|
1733
2389
|
import { execSync as execSync2 } from "child_process";
|
|
1734
2390
|
function normalizeCommand(command) {
|
|
@@ -1809,7 +2465,7 @@ __export(active_agent_exports, {
|
|
|
1809
2465
|
});
|
|
1810
2466
|
import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3, unlinkSync as unlinkSync3, readdirSync as readdirSync3 } from "fs";
|
|
1811
2467
|
import { execSync as execSync3 } from "child_process";
|
|
1812
|
-
import
|
|
2468
|
+
import path7 from "path";
|
|
1813
2469
|
function isNameWithOptionalInstance(candidate, baseName) {
|
|
1814
2470
|
if (candidate === baseName) return true;
|
|
1815
2471
|
if (!candidate.startsWith(baseName)) return false;
|
|
@@ -1853,7 +2509,7 @@ function resolveActiveAgentFromTmuxSession(sessionName) {
|
|
|
1853
2509
|
return null;
|
|
1854
2510
|
}
|
|
1855
2511
|
function getMarkerPath() {
|
|
1856
|
-
return
|
|
2512
|
+
return path7.join(CACHE_DIR, `active-agent-${getSessionKey()}.json`);
|
|
1857
2513
|
}
|
|
1858
2514
|
function writeActiveAgent(agentId, agentRole) {
|
|
1859
2515
|
try {
|
|
@@ -1922,14 +2578,14 @@ function getAllActiveAgents() {
|
|
|
1922
2578
|
const key = file.slice("active-agent-".length, -".json".length);
|
|
1923
2579
|
if (key === "undefined") continue;
|
|
1924
2580
|
try {
|
|
1925
|
-
const raw = readFileSync3(
|
|
2581
|
+
const raw = readFileSync3(path7.join(CACHE_DIR, file), "utf8");
|
|
1926
2582
|
const data = JSON.parse(raw);
|
|
1927
2583
|
if (!data.agentId) continue;
|
|
1928
2584
|
if (data.startedAt) {
|
|
1929
2585
|
const age = Date.now() - new Date(data.startedAt).getTime();
|
|
1930
2586
|
if (age > STALE_MS) {
|
|
1931
2587
|
try {
|
|
1932
|
-
unlinkSync3(
|
|
2588
|
+
unlinkSync3(path7.join(CACHE_DIR, file));
|
|
1933
2589
|
} catch {
|
|
1934
2590
|
}
|
|
1935
2591
|
continue;
|
|
@@ -1952,11 +2608,11 @@ function getAllActiveAgents() {
|
|
|
1952
2608
|
function cleanupSessionMarkers() {
|
|
1953
2609
|
const key = getSessionKey();
|
|
1954
2610
|
try {
|
|
1955
|
-
unlinkSync3(
|
|
2611
|
+
unlinkSync3(path7.join(CACHE_DIR, `active-agent-${key}.json`));
|
|
1956
2612
|
} catch {
|
|
1957
2613
|
}
|
|
1958
2614
|
try {
|
|
1959
|
-
unlinkSync3(
|
|
2615
|
+
unlinkSync3(path7.join(CACHE_DIR, "active-agent-undefined.json"));
|
|
1960
2616
|
} catch {
|
|
1961
2617
|
}
|
|
1962
2618
|
}
|
|
@@ -1967,14 +2623,14 @@ var init_active_agent = __esm({
|
|
|
1967
2623
|
init_config();
|
|
1968
2624
|
init_session_key();
|
|
1969
2625
|
init_employees();
|
|
1970
|
-
CACHE_DIR =
|
|
2626
|
+
CACHE_DIR = path7.join(EXE_AI_DIR, "session-cache");
|
|
1971
2627
|
STALE_MS = 24 * 60 * 60 * 1e3;
|
|
1972
2628
|
}
|
|
1973
2629
|
});
|
|
1974
2630
|
|
|
1975
2631
|
// src/lib/agent-symlinks.ts
|
|
1976
|
-
import
|
|
1977
|
-
import
|
|
2632
|
+
import os6 from "os";
|
|
2633
|
+
import path8 from "path";
|
|
1978
2634
|
import {
|
|
1979
2635
|
existsSync as existsSync6,
|
|
1980
2636
|
lstatSync,
|
|
@@ -2005,10 +2661,10 @@ var init_mcp_prefix = __esm({
|
|
|
2005
2661
|
|
|
2006
2662
|
// src/lib/preferences.ts
|
|
2007
2663
|
import { existsSync as existsSync7, readFileSync as readFileSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync5 } from "fs";
|
|
2008
|
-
import
|
|
2009
|
-
import
|
|
2010
|
-
function loadPreferences(homeDir =
|
|
2011
|
-
const configPath =
|
|
2664
|
+
import path9 from "path";
|
|
2665
|
+
import os7 from "os";
|
|
2666
|
+
function loadPreferences(homeDir = os7.homedir()) {
|
|
2667
|
+
const configPath = path9.join(homeDir, ".exe-os", "config.json");
|
|
2012
2668
|
if (!existsSync7(configPath)) return {};
|
|
2013
2669
|
try {
|
|
2014
2670
|
const config = JSON.parse(readFileSync4(configPath, "utf-8"));
|
|
@@ -2026,16 +2682,16 @@ var init_preferences = __esm({
|
|
|
2026
2682
|
// src/adapters/claude/installer.ts
|
|
2027
2683
|
import { readFile as readFile4, writeFile as writeFile4, mkdir as mkdir4, readdir } from "fs/promises";
|
|
2028
2684
|
import { existsSync as existsSync8, readFileSync as readFileSync5, writeFileSync as writeFileSync5, copyFileSync, mkdirSync as mkdirSync6 } from "fs";
|
|
2029
|
-
import
|
|
2030
|
-
import
|
|
2685
|
+
import path10 from "path";
|
|
2686
|
+
import os8 from "os";
|
|
2031
2687
|
import { execSync as execSync4 } from "child_process";
|
|
2032
2688
|
import { fileURLToPath } from "url";
|
|
2033
2689
|
function resolvePackageRoot() {
|
|
2034
2690
|
const thisFile = fileURLToPath(import.meta.url);
|
|
2035
|
-
let dir =
|
|
2036
|
-
const root =
|
|
2691
|
+
let dir = path10.dirname(thisFile);
|
|
2692
|
+
const root = path10.parse(dir).root;
|
|
2037
2693
|
while (dir !== root) {
|
|
2038
|
-
const pkgPath =
|
|
2694
|
+
const pkgPath = path10.join(dir, "package.json");
|
|
2039
2695
|
if (existsSync8(pkgPath)) {
|
|
2040
2696
|
try {
|
|
2041
2697
|
const pkg = JSON.parse(readFileSync5(pkgPath, "utf-8"));
|
|
@@ -2043,9 +2699,9 @@ function resolvePackageRoot() {
|
|
|
2043
2699
|
} catch {
|
|
2044
2700
|
}
|
|
2045
2701
|
}
|
|
2046
|
-
dir =
|
|
2702
|
+
dir = path10.dirname(dir);
|
|
2047
2703
|
}
|
|
2048
|
-
return
|
|
2704
|
+
return path10.resolve(path10.dirname(thisFile), "..", "..", "..");
|
|
2049
2705
|
}
|
|
2050
2706
|
var EXE_SECTION_START, EXE_SECTION_END, ORCHESTRATION_RULES;
|
|
2051
2707
|
var init_installer = __esm({
|
|
@@ -2080,13 +2736,13 @@ __export(installer_exports, {
|
|
|
2080
2736
|
});
|
|
2081
2737
|
import { readFile as readFile5, writeFile as writeFile5, mkdir as mkdir5 } from "fs/promises";
|
|
2082
2738
|
import { existsSync as existsSync9 } from "fs";
|
|
2083
|
-
import
|
|
2084
|
-
import
|
|
2085
|
-
async function mergeCodexHooks(packageRoot, homeDir =
|
|
2086
|
-
const codexDir =
|
|
2087
|
-
const hooksPath =
|
|
2088
|
-
const logsDir =
|
|
2089
|
-
const hookLogPath =
|
|
2739
|
+
import path11 from "path";
|
|
2740
|
+
import os9 from "os";
|
|
2741
|
+
async function mergeCodexHooks(packageRoot, homeDir = os9.homedir()) {
|
|
2742
|
+
const codexDir = path11.join(homeDir, ".codex");
|
|
2743
|
+
const hooksPath = path11.join(codexDir, "hooks.json");
|
|
2744
|
+
const logsDir = path11.join(homeDir, ".exe-os", "logs");
|
|
2745
|
+
const hookLogPath = path11.join(logsDir, "hooks.log");
|
|
2090
2746
|
const logSuffix = ` 2>> "${hookLogPath}"`;
|
|
2091
2747
|
await mkdir5(codexDir, { recursive: true });
|
|
2092
2748
|
await mkdir5(logsDir, { recursive: true });
|
|
@@ -2108,7 +2764,7 @@ async function mergeCodexHooks(packageRoot, homeDir = os8.homedir()) {
|
|
|
2108
2764
|
hooks: [
|
|
2109
2765
|
{
|
|
2110
2766
|
type: "command",
|
|
2111
|
-
command: `node "${
|
|
2767
|
+
command: `node "${path11.join(packageRoot, "dist", "hooks", "session-start.js")}"${logSuffix}`,
|
|
2112
2768
|
timeout: 30,
|
|
2113
2769
|
statusMessage: "exe-os: loading memory brief"
|
|
2114
2770
|
}
|
|
@@ -2123,11 +2779,11 @@ async function mergeCodexHooks(packageRoot, homeDir = os8.homedir()) {
|
|
|
2123
2779
|
hooks: [
|
|
2124
2780
|
{
|
|
2125
2781
|
type: "command",
|
|
2126
|
-
command: `node "${
|
|
2782
|
+
command: `node "${path11.join(packageRoot, "dist", "hooks", "ingest.js")}"${logSuffix}`
|
|
2127
2783
|
},
|
|
2128
2784
|
{
|
|
2129
2785
|
type: "command",
|
|
2130
|
-
command: `node "${
|
|
2786
|
+
command: `node "${path11.join(packageRoot, "dist", "hooks", "error-recall.js")}"${logSuffix}`
|
|
2131
2787
|
}
|
|
2132
2788
|
]
|
|
2133
2789
|
},
|
|
@@ -2139,11 +2795,11 @@ async function mergeCodexHooks(packageRoot, homeDir = os8.homedir()) {
|
|
|
2139
2795
|
hooks: [
|
|
2140
2796
|
{
|
|
2141
2797
|
type: "command",
|
|
2142
|
-
command: `node "${
|
|
2798
|
+
command: `node "${path11.join(packageRoot, "dist", "hooks", "prompt-submit.js")}"${logSuffix}`
|
|
2143
2799
|
},
|
|
2144
2800
|
{
|
|
2145
2801
|
type: "command",
|
|
2146
|
-
command: `node "${
|
|
2802
|
+
command: `node "${path11.join(packageRoot, "dist", "hooks", "exe-heartbeat-hook.js")}"${logSuffix}`,
|
|
2147
2803
|
timeout: 5
|
|
2148
2804
|
}
|
|
2149
2805
|
]
|
|
@@ -2156,7 +2812,7 @@ async function mergeCodexHooks(packageRoot, homeDir = os8.homedir()) {
|
|
|
2156
2812
|
hooks: [
|
|
2157
2813
|
{
|
|
2158
2814
|
type: "command",
|
|
2159
|
-
command: `node "${
|
|
2815
|
+
command: `node "${path11.join(packageRoot, "dist", "hooks", "stop.js")}"${logSuffix}`
|
|
2160
2816
|
}
|
|
2161
2817
|
]
|
|
2162
2818
|
},
|
|
@@ -2169,7 +2825,7 @@ async function mergeCodexHooks(packageRoot, homeDir = os8.homedir()) {
|
|
|
2169
2825
|
hooks: [
|
|
2170
2826
|
{
|
|
2171
2827
|
type: "command",
|
|
2172
|
-
command: `node "${
|
|
2828
|
+
command: `node "${path11.join(packageRoot, "dist", "hooks", "pre-tool-use.js")}"${logSuffix}`
|
|
2173
2829
|
}
|
|
2174
2830
|
]
|
|
2175
2831
|
},
|
|
@@ -2200,15 +2856,15 @@ async function mergeCodexHooks(packageRoot, homeDir = os8.homedir()) {
|
|
|
2200
2856
|
await writeFile5(hooksPath, JSON.stringify(hooksJson, null, 2) + "\n");
|
|
2201
2857
|
return { added, skipped };
|
|
2202
2858
|
}
|
|
2203
|
-
function verifyCodexHooks(homeDir =
|
|
2204
|
-
const hooksPath =
|
|
2859
|
+
function verifyCodexHooks(homeDir = os9.homedir()) {
|
|
2860
|
+
const hooksPath = path11.join(homeDir, ".codex", "hooks.json");
|
|
2205
2861
|
if (!existsSync9(hooksPath)) return false;
|
|
2206
2862
|
try {
|
|
2207
2863
|
const hooksJson = JSON.parse(
|
|
2208
2864
|
__require("fs").readFileSync(hooksPath, "utf-8")
|
|
2209
2865
|
);
|
|
2210
2866
|
if (!hooksJson.hooks) return false;
|
|
2211
|
-
const required = ["SessionStart", "PostToolUse", "UserPromptSubmit", "Stop"];
|
|
2867
|
+
const required = ["SessionStart", "PostToolUse", "UserPromptSubmit", "Stop", "PreToolUse"];
|
|
2212
2868
|
for (const event of required) {
|
|
2213
2869
|
const groups = hooksJson.hooks[event];
|
|
2214
2870
|
if (!groups || !groups.some(
|
|
@@ -2222,11 +2878,11 @@ function verifyCodexHooks(homeDir = os8.homedir()) {
|
|
|
2222
2878
|
return false;
|
|
2223
2879
|
}
|
|
2224
2880
|
}
|
|
2225
|
-
async function installCodexStatusLine(homeDir =
|
|
2881
|
+
async function installCodexStatusLine(homeDir = os9.homedir()) {
|
|
2226
2882
|
const prefs = loadPreferences(homeDir);
|
|
2227
2883
|
if (prefs.codexStatusLine === false) return "opted-out";
|
|
2228
|
-
const codexDir =
|
|
2229
|
-
const configPath =
|
|
2884
|
+
const codexDir = path11.join(homeDir, ".codex");
|
|
2885
|
+
const configPath = path11.join(codexDir, "config.toml");
|
|
2230
2886
|
await mkdir5(codexDir, { recursive: true });
|
|
2231
2887
|
let content = "";
|
|
2232
2888
|
if (existsSync9(configPath)) {
|
|
@@ -2277,8 +2933,8 @@ var init_installer2 = __esm({
|
|
|
2277
2933
|
});
|
|
2278
2934
|
|
|
2279
2935
|
// src/bin/exe-start-codex.ts
|
|
2280
|
-
import
|
|
2281
|
-
import
|
|
2936
|
+
import os10 from "os";
|
|
2937
|
+
import path12 from "path";
|
|
2282
2938
|
import {
|
|
2283
2939
|
existsSync as existsSync10,
|
|
2284
2940
|
readFileSync as readFileSync6,
|
|
@@ -2295,15 +2951,15 @@ init_database();
|
|
|
2295
2951
|
// src/lib/keychain.ts
|
|
2296
2952
|
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
2297
2953
|
import { existsSync as existsSync3 } from "fs";
|
|
2298
|
-
import
|
|
2299
|
-
import
|
|
2954
|
+
import path4 from "path";
|
|
2955
|
+
import os4 from "os";
|
|
2300
2956
|
var SERVICE = "exe-mem";
|
|
2301
2957
|
var ACCOUNT = "master-key";
|
|
2302
2958
|
function getKeyDir() {
|
|
2303
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ??
|
|
2959
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path4.join(os4.homedir(), ".exe-os");
|
|
2304
2960
|
}
|
|
2305
2961
|
function getKeyPath() {
|
|
2306
|
-
return
|
|
2962
|
+
return path4.join(getKeyDir(), "master.key");
|
|
2307
2963
|
}
|
|
2308
2964
|
async function tryKeytar() {
|
|
2309
2965
|
try {
|
|
@@ -2326,7 +2982,7 @@ async function getMasterKey() {
|
|
|
2326
2982
|
const keyPath = getKeyPath();
|
|
2327
2983
|
if (!existsSync3(keyPath)) {
|
|
2328
2984
|
process.stderr.write(
|
|
2329
|
-
`[keychain] Key not found at ${keyPath} (HOME=${
|
|
2985
|
+
`[keychain] Key not found at ${keyPath} (HOME=${os4.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
|
|
2330
2986
|
`
|
|
2331
2987
|
);
|
|
2332
2988
|
return null;
|
|
@@ -2637,8 +3293,8 @@ function vectorToBlob(vector) {
|
|
|
2637
3293
|
}
|
|
2638
3294
|
|
|
2639
3295
|
// src/lib/behaviors-export.ts
|
|
2640
|
-
import
|
|
2641
|
-
import
|
|
3296
|
+
import os5 from "os";
|
|
3297
|
+
import path6 from "path";
|
|
2642
3298
|
import {
|
|
2643
3299
|
existsSync as existsSync5,
|
|
2644
3300
|
mkdirSync as mkdirSync2,
|
|
@@ -2680,8 +3336,8 @@ async function listBehaviors(agentId, projectName, limit = 30) {
|
|
|
2680
3336
|
}
|
|
2681
3337
|
|
|
2682
3338
|
// src/lib/behaviors-export.ts
|
|
2683
|
-
var BEHAVIORS_EXPORT_DIR =
|
|
2684
|
-
|
|
3339
|
+
var BEHAVIORS_EXPORT_DIR = path6.join(
|
|
3340
|
+
os5.homedir(),
|
|
2685
3341
|
".exe-os",
|
|
2686
3342
|
"behaviors-export"
|
|
2687
3343
|
);
|
|
@@ -2696,7 +3352,7 @@ function sweepStaleBehaviorExports(now = Date.now()) {
|
|
|
2696
3352
|
return;
|
|
2697
3353
|
}
|
|
2698
3354
|
for (const entry of entries) {
|
|
2699
|
-
const filePath =
|
|
3355
|
+
const filePath = path6.join(BEHAVIORS_EXPORT_DIR, entry);
|
|
2700
3356
|
try {
|
|
2701
3357
|
const stat = statSync(filePath);
|
|
2702
3358
|
if (now - stat.mtimeMs > STALE_EXPORT_AGE_MS) {
|
|
@@ -2729,10 +3385,10 @@ function renderBehaviorExport(behaviors) {
|
|
|
2729
3385
|
}
|
|
2730
3386
|
function exportFilePath(agentId, projectName, sessionKey) {
|
|
2731
3387
|
if (!sessionKey) {
|
|
2732
|
-
return
|
|
3388
|
+
return path6.join(BEHAVIORS_EXPORT_DIR, `${agentId}.md`);
|
|
2733
3389
|
}
|
|
2734
3390
|
const safeProject = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
2735
|
-
return
|
|
3391
|
+
return path6.join(
|
|
2736
3392
|
BEHAVIORS_EXPORT_DIR,
|
|
2737
3393
|
`${agentId}-${safeProject}-${sessionKey}.md`
|
|
2738
3394
|
);
|
|
@@ -2750,28 +3406,7 @@ async function exportBehaviorsForAgent(agentId, projectName, sessionKey) {
|
|
|
2750
3406
|
|
|
2751
3407
|
// src/bin/exe-start-codex.ts
|
|
2752
3408
|
init_employees();
|
|
2753
|
-
|
|
2754
|
-
// src/lib/runtime-table.ts
|
|
2755
|
-
var RUNTIME_TABLE = {
|
|
2756
|
-
codex: {
|
|
2757
|
-
binary: "codex",
|
|
2758
|
-
launchMode: "interactive",
|
|
2759
|
-
autoApproveFlag: "--dangerously-bypass-approvals-and-sandbox",
|
|
2760
|
-
inlineFlag: "--no-alt-screen",
|
|
2761
|
-
apiKeyEnv: "OPENAI_API_KEY",
|
|
2762
|
-
defaultModel: "gpt-5.4"
|
|
2763
|
-
},
|
|
2764
|
-
opencode: {
|
|
2765
|
-
binary: "opencode",
|
|
2766
|
-
launchMode: "exec",
|
|
2767
|
-
autoApproveFlag: "--dangerously-skip-permissions",
|
|
2768
|
-
inlineFlag: "",
|
|
2769
|
-
apiKeyEnv: "ANTHROPIC_API_KEY",
|
|
2770
|
-
defaultModel: "anthropic/claude-sonnet-4-6"
|
|
2771
|
-
}
|
|
2772
|
-
};
|
|
2773
|
-
|
|
2774
|
-
// src/bin/exe-start-codex.ts
|
|
3409
|
+
init_runtime_table();
|
|
2775
3410
|
var CODEX = RUNTIME_TABLE.codex;
|
|
2776
3411
|
var BOOT_INSTRUCTIONS = `
|
|
2777
3412
|
---
|
|
@@ -2782,7 +3417,7 @@ When done with a task: call update_task with status "done".
|
|
|
2782
3417
|
Always call store_memory to persist important findings.
|
|
2783
3418
|
`;
|
|
2784
3419
|
function resolveAgent(argv) {
|
|
2785
|
-
const invokedAs =
|
|
3420
|
+
const invokedAs = path12.basename(argv[1] ?? "");
|
|
2786
3421
|
if (invokedAs && invokedAs !== "exe-start-codex" && !invokedAs.endsWith(".js")) {
|
|
2787
3422
|
const agent2 = invokedAs.replace(/-codex$/, "").toLowerCase();
|
|
2788
3423
|
return { agent: agent2, passthrough: argv.slice(2) };
|
|
@@ -2808,8 +3443,8 @@ function resolveAgent(argv) {
|
|
|
2808
3443
|
return { agent, passthrough, sessionName };
|
|
2809
3444
|
}
|
|
2810
3445
|
function loadIdentity(agent) {
|
|
2811
|
-
const dir =
|
|
2812
|
-
const exact =
|
|
3446
|
+
const dir = path12.join(os10.homedir(), ".exe-os", "identity");
|
|
3447
|
+
const exact = path12.join(dir, `${agent}.md`);
|
|
2813
3448
|
if (existsSync10(exact)) {
|
|
2814
3449
|
const content = readFileSync6(exact, "utf-8").trim();
|
|
2815
3450
|
if (content) return content;
|
|
@@ -2818,13 +3453,13 @@ function loadIdentity(agent) {
|
|
|
2818
3453
|
const files = readdirSync4(dir);
|
|
2819
3454
|
const match = files.find((f) => f.toLowerCase() === `${agent.toLowerCase()}.md`);
|
|
2820
3455
|
if (match) {
|
|
2821
|
-
const content = readFileSync6(
|
|
3456
|
+
const content = readFileSync6(path12.join(dir, match), "utf-8").trim();
|
|
2822
3457
|
if (content) return content;
|
|
2823
3458
|
}
|
|
2824
3459
|
} catch {
|
|
2825
3460
|
}
|
|
2826
3461
|
try {
|
|
2827
|
-
const rosterPath =
|
|
3462
|
+
const rosterPath = path12.join(os10.homedir(), ".exe-os", "exe-employees.json");
|
|
2828
3463
|
const roster = JSON.parse(readFileSync6(rosterPath, "utf8"));
|
|
2829
3464
|
const emp = roster.find((e) => e.name.toLowerCase() === agent.toLowerCase());
|
|
2830
3465
|
if (emp?.systemPrompt && emp.systemPrompt.trim().length > 20) {
|
|
@@ -2835,7 +3470,7 @@ function loadIdentity(agent) {
|
|
|
2835
3470
|
return null;
|
|
2836
3471
|
}
|
|
2837
3472
|
function writePromptFile(agent, identity, behaviorsPath) {
|
|
2838
|
-
const promptDir =
|
|
3473
|
+
const promptDir = path12.join(os10.homedir(), ".exe-os", "codex-prompt");
|
|
2839
3474
|
mkdirSync7(promptDir, { recursive: true });
|
|
2840
3475
|
let prompt = identity;
|
|
2841
3476
|
if (behaviorsPath && existsSync10(behaviorsPath)) {
|
|
@@ -2845,7 +3480,7 @@ function writePromptFile(agent, identity, behaviorsPath) {
|
|
|
2845
3480
|
}
|
|
2846
3481
|
}
|
|
2847
3482
|
prompt += "\n" + BOOT_INSTRUCTIONS;
|
|
2848
|
-
const outPath =
|
|
3483
|
+
const outPath = path12.join(promptDir, `${agent}.md`);
|
|
2849
3484
|
writeFileSync6(outPath, prompt, "utf-8");
|
|
2850
3485
|
return outPath;
|
|
2851
3486
|
}
|
|
@@ -2926,7 +3561,7 @@ async function main() {
|
|
|
2926
3561
|
const empRole = (() => {
|
|
2927
3562
|
try {
|
|
2928
3563
|
const emps = readFileSync6(
|
|
2929
|
-
|
|
3564
|
+
path12.join(os10.homedir(), ".exe-os", "exe-employees.json"),
|
|
2930
3565
|
"utf-8"
|
|
2931
3566
|
);
|
|
2932
3567
|
const found = JSON.parse(emps).find(
|
|
@@ -2963,14 +3598,14 @@ async function main() {
|
|
|
2963
3598
|
if (WORKTREE_ROLES.has(empRole)) {
|
|
2964
3599
|
try {
|
|
2965
3600
|
const { execSync: es } = await import("child_process");
|
|
2966
|
-
const worktreeDir =
|
|
3601
|
+
const worktreeDir = path12.join(process.cwd(), ".worktrees", worktreeName);
|
|
2967
3602
|
const branchName = `${worktreeName}/codex-${Date.now()}`;
|
|
2968
3603
|
if (existsSync10(worktreeDir)) {
|
|
2969
3604
|
worktreePath = worktreeDir;
|
|
2970
3605
|
process.stderr.write(`[exe-start-codex] Reusing worktree at ${worktreeDir}
|
|
2971
3606
|
`);
|
|
2972
3607
|
} else {
|
|
2973
|
-
mkdirSync7(
|
|
3608
|
+
mkdirSync7(path12.dirname(worktreeDir), { recursive: true });
|
|
2974
3609
|
es(`git worktree add "${worktreeDir}" -b "${branchName}" HEAD`, {
|
|
2975
3610
|
encoding: "utf-8",
|
|
2976
3611
|
timeout: 3e4
|