@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/lib/tmux-routing.js
CHANGED
|
@@ -307,9 +307,34 @@ var init_provider_table = __esm({
|
|
|
307
307
|
}
|
|
308
308
|
});
|
|
309
309
|
|
|
310
|
+
// src/lib/secure-files.ts
|
|
311
|
+
import { chmodSync, existsSync as existsSync2, mkdirSync as mkdirSync2 } from "fs";
|
|
312
|
+
import { chmod, mkdir } from "fs/promises";
|
|
313
|
+
async function ensurePrivateDir(dirPath) {
|
|
314
|
+
await mkdir(dirPath, { recursive: true, mode: PRIVATE_DIR_MODE });
|
|
315
|
+
try {
|
|
316
|
+
await chmod(dirPath, PRIVATE_DIR_MODE);
|
|
317
|
+
} catch {
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
async function enforcePrivateFile(filePath) {
|
|
321
|
+
try {
|
|
322
|
+
await chmod(filePath, PRIVATE_FILE_MODE);
|
|
323
|
+
} catch {
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
var PRIVATE_DIR_MODE, PRIVATE_FILE_MODE;
|
|
327
|
+
var init_secure_files = __esm({
|
|
328
|
+
"src/lib/secure-files.ts"() {
|
|
329
|
+
"use strict";
|
|
330
|
+
PRIVATE_DIR_MODE = 448;
|
|
331
|
+
PRIVATE_FILE_MODE = 384;
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
|
|
310
335
|
// src/lib/config.ts
|
|
311
|
-
import { readFile, writeFile
|
|
312
|
-
import { readFileSync as readFileSync2, existsSync as
|
|
336
|
+
import { readFile, writeFile } from "fs/promises";
|
|
337
|
+
import { readFileSync as readFileSync2, existsSync as existsSync3, renameSync } from "fs";
|
|
313
338
|
import path2 from "path";
|
|
314
339
|
import os2 from "os";
|
|
315
340
|
function resolveDataDir() {
|
|
@@ -317,7 +342,7 @@ function resolveDataDir() {
|
|
|
317
342
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
318
343
|
const newDir = path2.join(os2.homedir(), ".exe-os");
|
|
319
344
|
const legacyDir = path2.join(os2.homedir(), ".exe-mem");
|
|
320
|
-
if (!
|
|
345
|
+
if (!existsSync3(newDir) && existsSync3(legacyDir)) {
|
|
321
346
|
try {
|
|
322
347
|
renameSync(legacyDir, newDir);
|
|
323
348
|
process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
|
|
@@ -380,9 +405,9 @@ function normalizeAutoUpdate(raw) {
|
|
|
380
405
|
}
|
|
381
406
|
async function loadConfig() {
|
|
382
407
|
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
383
|
-
await
|
|
408
|
+
await ensurePrivateDir(dir);
|
|
384
409
|
const configPath = path2.join(dir, "config.json");
|
|
385
|
-
if (!
|
|
410
|
+
if (!existsSync3(configPath)) {
|
|
386
411
|
return { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db") };
|
|
387
412
|
}
|
|
388
413
|
const raw = await readFile(configPath, "utf-8");
|
|
@@ -395,6 +420,7 @@ async function loadConfig() {
|
|
|
395
420
|
`);
|
|
396
421
|
try {
|
|
397
422
|
await writeFile(configPath, JSON.stringify(migratedCfg, null, 2) + "\n");
|
|
423
|
+
await enforcePrivateFile(configPath);
|
|
398
424
|
} catch {
|
|
399
425
|
}
|
|
400
426
|
}
|
|
@@ -414,6 +440,7 @@ var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CON
|
|
|
414
440
|
var init_config = __esm({
|
|
415
441
|
"src/lib/config.ts"() {
|
|
416
442
|
"use strict";
|
|
443
|
+
init_secure_files();
|
|
417
444
|
EXE_AI_DIR = resolveDataDir();
|
|
418
445
|
DB_PATH = path2.join(EXE_AI_DIR, "memories.db");
|
|
419
446
|
MODELS_DIR = path2.join(EXE_AI_DIR, "models");
|
|
@@ -518,10 +545,10 @@ var init_runtime_table = __esm({
|
|
|
518
545
|
});
|
|
519
546
|
|
|
520
547
|
// src/lib/agent-config.ts
|
|
521
|
-
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as
|
|
548
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync4 } from "fs";
|
|
522
549
|
import path3 from "path";
|
|
523
550
|
function loadAgentConfig() {
|
|
524
|
-
if (!
|
|
551
|
+
if (!existsSync4(AGENT_CONFIG_PATH)) return {};
|
|
525
552
|
try {
|
|
526
553
|
return JSON.parse(readFileSync3(AGENT_CONFIG_PATH, "utf-8"));
|
|
527
554
|
} catch {
|
|
@@ -542,6 +569,7 @@ var init_agent_config = __esm({
|
|
|
542
569
|
"use strict";
|
|
543
570
|
init_config();
|
|
544
571
|
init_runtime_table();
|
|
572
|
+
init_secure_files();
|
|
545
573
|
AGENT_CONFIG_PATH = path3.join(EXE_AI_DIR, "agent-config.json");
|
|
546
574
|
DEFAULT_MODELS = {
|
|
547
575
|
claude: "claude-opus-4",
|
|
@@ -560,16 +588,16 @@ __export(intercom_queue_exports, {
|
|
|
560
588
|
queueIntercom: () => queueIntercom,
|
|
561
589
|
readQueue: () => readQueue
|
|
562
590
|
});
|
|
563
|
-
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, renameSync as renameSync2, existsSync as
|
|
591
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, renameSync as renameSync2, existsSync as existsSync5, mkdirSync as mkdirSync3 } from "fs";
|
|
564
592
|
import path4 from "path";
|
|
565
593
|
import os3 from "os";
|
|
566
594
|
function ensureDir() {
|
|
567
595
|
const dir = path4.dirname(QUEUE_PATH);
|
|
568
|
-
if (!
|
|
596
|
+
if (!existsSync5(dir)) mkdirSync3(dir, { recursive: true });
|
|
569
597
|
}
|
|
570
598
|
function readQueue() {
|
|
571
599
|
try {
|
|
572
|
-
if (!
|
|
600
|
+
if (!existsSync5(QUEUE_PATH)) return [];
|
|
573
601
|
return JSON.parse(readFileSync4(QUEUE_PATH, "utf8"));
|
|
574
602
|
} catch {
|
|
575
603
|
return [];
|
|
@@ -686,7 +714,7 @@ var init_db_retry = __esm({
|
|
|
686
714
|
|
|
687
715
|
// src/lib/employees.ts
|
|
688
716
|
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
689
|
-
import { existsSync as
|
|
717
|
+
import { existsSync as existsSync6, symlinkSync, readlinkSync, readFileSync as readFileSync5, renameSync as renameSync3, unlinkSync, writeFileSync as writeFileSync4 } from "fs";
|
|
690
718
|
import { execSync as execSync3 } from "child_process";
|
|
691
719
|
import path5 from "path";
|
|
692
720
|
import os4 from "os";
|
|
@@ -707,7 +735,7 @@ function isCoordinatorName(agentName, employees = loadEmployeesSync()) {
|
|
|
707
735
|
return agentName.toLowerCase() === getCoordinatorName(employees).toLowerCase();
|
|
708
736
|
}
|
|
709
737
|
function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
|
|
710
|
-
if (!
|
|
738
|
+
if (!existsSync6(employeesPath)) return [];
|
|
711
739
|
try {
|
|
712
740
|
return JSON.parse(readFileSync5(employeesPath, "utf-8"));
|
|
713
741
|
} catch {
|
|
@@ -796,8 +824,11 @@ var init_database = __esm({
|
|
|
796
824
|
});
|
|
797
825
|
|
|
798
826
|
// src/lib/license.ts
|
|
799
|
-
import { readFileSync as readFileSync6, writeFileSync as writeFileSync5, existsSync as
|
|
827
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync5, existsSync as existsSync7, mkdirSync as mkdirSync4 } from "fs";
|
|
800
828
|
import { randomUUID } from "crypto";
|
|
829
|
+
import { createRequire as createRequire2 } from "module";
|
|
830
|
+
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
831
|
+
import os6 from "os";
|
|
801
832
|
import path7 from "path";
|
|
802
833
|
import { jwtVerify, importSPKI } from "jose";
|
|
803
834
|
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, PLAN_LIMITS;
|
|
@@ -819,11 +850,11 @@ var init_license = __esm({
|
|
|
819
850
|
});
|
|
820
851
|
|
|
821
852
|
// src/lib/plan-limits.ts
|
|
822
|
-
import { readFileSync as readFileSync7, existsSync as
|
|
853
|
+
import { readFileSync as readFileSync7, existsSync as existsSync8 } from "fs";
|
|
823
854
|
import path8 from "path";
|
|
824
855
|
function getLicenseSync() {
|
|
825
856
|
try {
|
|
826
|
-
if (!
|
|
857
|
+
if (!existsSync8(CACHE_PATH2)) return freeLicense();
|
|
827
858
|
const raw = JSON.parse(readFileSync7(CACHE_PATH2, "utf8"));
|
|
828
859
|
if (!raw.token || typeof raw.token !== "string") return freeLicense();
|
|
829
860
|
const parts = raw.token.split(".");
|
|
@@ -862,7 +893,7 @@ function assertEmployeeLimitSync(rosterPath) {
|
|
|
862
893
|
const filePath = rosterPath ?? EMPLOYEES_PATH;
|
|
863
894
|
let count = 0;
|
|
864
895
|
try {
|
|
865
|
-
if (
|
|
896
|
+
if (existsSync8(filePath)) {
|
|
866
897
|
const raw = readFileSync7(filePath, "utf8");
|
|
867
898
|
const employees = JSON.parse(raw);
|
|
868
899
|
count = Array.isArray(employees) ? employees.length : 0;
|
|
@@ -896,15 +927,48 @@ var init_plan_limits = __esm({
|
|
|
896
927
|
}
|
|
897
928
|
});
|
|
898
929
|
|
|
930
|
+
// src/lib/task-scope.ts
|
|
931
|
+
function getCurrentSessionScope() {
|
|
932
|
+
try {
|
|
933
|
+
return resolveExeSession();
|
|
934
|
+
} catch {
|
|
935
|
+
return null;
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
function sessionScopeFilter(sessionScope, tableAlias) {
|
|
939
|
+
const scope = sessionScope !== void 0 ? sessionScope : getCurrentSessionScope();
|
|
940
|
+
if (!scope) return { sql: "", args: [] };
|
|
941
|
+
const col = tableAlias ? `${tableAlias}.session_scope` : "session_scope";
|
|
942
|
+
return {
|
|
943
|
+
sql: ` AND (${col} IS NULL OR ${col} = ?)`,
|
|
944
|
+
args: [scope]
|
|
945
|
+
};
|
|
946
|
+
}
|
|
947
|
+
function strictSessionScopeFilter(sessionScope, tableAlias) {
|
|
948
|
+
const scope = sessionScope !== void 0 ? sessionScope : getCurrentSessionScope();
|
|
949
|
+
if (!scope) return { sql: "", args: [] };
|
|
950
|
+
const col = tableAlias ? `${tableAlias}.session_scope` : "session_scope";
|
|
951
|
+
return {
|
|
952
|
+
sql: ` AND ${col} = ?`,
|
|
953
|
+
args: [scope]
|
|
954
|
+
};
|
|
955
|
+
}
|
|
956
|
+
var init_task_scope = __esm({
|
|
957
|
+
"src/lib/task-scope.ts"() {
|
|
958
|
+
"use strict";
|
|
959
|
+
init_tmux_routing();
|
|
960
|
+
}
|
|
961
|
+
});
|
|
962
|
+
|
|
899
963
|
// src/lib/notifications.ts
|
|
900
964
|
import crypto from "crypto";
|
|
901
965
|
import path9 from "path";
|
|
902
|
-
import
|
|
966
|
+
import os7 from "os";
|
|
903
967
|
import {
|
|
904
968
|
readFileSync as readFileSync8,
|
|
905
969
|
readdirSync,
|
|
906
970
|
unlinkSync as unlinkSync2,
|
|
907
|
-
existsSync as
|
|
971
|
+
existsSync as existsSync9,
|
|
908
972
|
rmdirSync
|
|
909
973
|
} from "fs";
|
|
910
974
|
async function writeNotification(notification) {
|
|
@@ -912,9 +976,10 @@ async function writeNotification(notification) {
|
|
|
912
976
|
const client = getClient();
|
|
913
977
|
const id = crypto.randomUUID();
|
|
914
978
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
979
|
+
const sessionScope = notification.sessionScope === void 0 ? getCurrentSessionScope() : notification.sessionScope;
|
|
915
980
|
await client.execute({
|
|
916
|
-
sql: `INSERT INTO notifications (id, agent_id, agent_role, event, project, summary, task_file, read, created_at)
|
|
917
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, 0, ?)`,
|
|
981
|
+
sql: `INSERT INTO notifications (id, agent_id, agent_role, event, project, summary, task_file, session_scope, read, created_at)
|
|
982
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, 0, ?)`,
|
|
918
983
|
args: [
|
|
919
984
|
id,
|
|
920
985
|
notification.agentId,
|
|
@@ -923,6 +988,7 @@ async function writeNotification(notification) {
|
|
|
923
988
|
notification.project,
|
|
924
989
|
notification.summary,
|
|
925
990
|
notification.taskFile ?? null,
|
|
991
|
+
sessionScope,
|
|
926
992
|
now
|
|
927
993
|
]
|
|
928
994
|
});
|
|
@@ -931,12 +997,14 @@ async function writeNotification(notification) {
|
|
|
931
997
|
`);
|
|
932
998
|
}
|
|
933
999
|
}
|
|
934
|
-
async function markAsReadByTaskFile(taskFile) {
|
|
1000
|
+
async function markAsReadByTaskFile(taskFile, sessionScope) {
|
|
935
1001
|
try {
|
|
936
1002
|
const client = getClient();
|
|
1003
|
+
const scope = strictSessionScopeFilter(sessionScope);
|
|
937
1004
|
await client.execute({
|
|
938
|
-
sql:
|
|
939
|
-
|
|
1005
|
+
sql: `UPDATE notifications SET read = 1
|
|
1006
|
+
WHERE task_file = ? AND read = 0${scope.sql}`,
|
|
1007
|
+
args: [taskFile, ...scope.args]
|
|
940
1008
|
});
|
|
941
1009
|
} catch {
|
|
942
1010
|
}
|
|
@@ -945,6 +1013,7 @@ var init_notifications = __esm({
|
|
|
945
1013
|
"src/lib/notifications.ts"() {
|
|
946
1014
|
"use strict";
|
|
947
1015
|
init_database();
|
|
1016
|
+
init_task_scope();
|
|
948
1017
|
}
|
|
949
1018
|
});
|
|
950
1019
|
|
|
@@ -982,30 +1051,6 @@ var init_session_kill_telemetry = __esm({
|
|
|
982
1051
|
}
|
|
983
1052
|
});
|
|
984
1053
|
|
|
985
|
-
// src/lib/task-scope.ts
|
|
986
|
-
function getCurrentSessionScope() {
|
|
987
|
-
try {
|
|
988
|
-
return resolveExeSession();
|
|
989
|
-
} catch {
|
|
990
|
-
return null;
|
|
991
|
-
}
|
|
992
|
-
}
|
|
993
|
-
function sessionScopeFilter(sessionScope, tableAlias) {
|
|
994
|
-
const scope = sessionScope !== void 0 ? sessionScope : getCurrentSessionScope();
|
|
995
|
-
if (!scope) return { sql: "", args: [] };
|
|
996
|
-
const col = tableAlias ? `${tableAlias}.session_scope` : "session_scope";
|
|
997
|
-
return {
|
|
998
|
-
sql: ` AND (${col} IS NULL OR ${col} = ?)`,
|
|
999
|
-
args: [scope]
|
|
1000
|
-
};
|
|
1001
|
-
}
|
|
1002
|
-
var init_task_scope = __esm({
|
|
1003
|
-
"src/lib/task-scope.ts"() {
|
|
1004
|
-
"use strict";
|
|
1005
|
-
init_tmux_routing();
|
|
1006
|
-
}
|
|
1007
|
-
});
|
|
1008
|
-
|
|
1009
1054
|
// src/lib/state-bus.ts
|
|
1010
1055
|
var StateBus, orgBus;
|
|
1011
1056
|
var init_state_bus = __esm({
|
|
@@ -1064,10 +1109,10 @@ var init_state_bus = __esm({
|
|
|
1064
1109
|
// src/lib/tasks-crud.ts
|
|
1065
1110
|
import crypto3 from "crypto";
|
|
1066
1111
|
import path10 from "path";
|
|
1067
|
-
import
|
|
1112
|
+
import os8 from "os";
|
|
1068
1113
|
import { execSync as execSync4 } from "child_process";
|
|
1069
1114
|
import { mkdir as mkdir3, writeFile as writeFile3, appendFile } from "fs/promises";
|
|
1070
|
-
import { existsSync as
|
|
1115
|
+
import { existsSync as existsSync10, readFileSync as readFileSync9 } from "fs";
|
|
1071
1116
|
async function writeCheckpoint(input) {
|
|
1072
1117
|
const client = getClient();
|
|
1073
1118
|
const row = await resolveTask(client, input.taskId);
|
|
@@ -1279,13 +1324,19 @@ ${laneWarning}` : laneWarning;
|
|
|
1279
1324
|
});
|
|
1280
1325
|
if (input.baseDir) {
|
|
1281
1326
|
try {
|
|
1282
|
-
const EXE_OS_DIR = path10.join(
|
|
1327
|
+
const EXE_OS_DIR = path10.join(os8.homedir(), ".exe-os");
|
|
1283
1328
|
const mdPath = path10.join(EXE_OS_DIR, taskFile);
|
|
1284
1329
|
const mdDir = path10.dirname(mdPath);
|
|
1285
|
-
if (!
|
|
1330
|
+
if (!existsSync10(mdDir)) await mkdir3(mdDir, { recursive: true });
|
|
1286
1331
|
const reviewer = input.reviewer ?? input.assignedBy;
|
|
1287
1332
|
const mdContent = `# ${input.title}
|
|
1288
1333
|
|
|
1334
|
+
## MANDATORY: When done
|
|
1335
|
+
|
|
1336
|
+
You MUST call update_task with status "done" and a result summary when finished.
|
|
1337
|
+
If you skip this, your reviewer will not know you're done and your work won't be reviewed.
|
|
1338
|
+
Do NOT let a failed commit or any error prevent you from calling update_task(done).
|
|
1339
|
+
|
|
1289
1340
|
**ID:** ${id}
|
|
1290
1341
|
**Status:** ${initialStatus}
|
|
1291
1342
|
**Priority:** ${input.priority}
|
|
@@ -1299,12 +1350,6 @@ ${laneWarning}` : laneWarning;
|
|
|
1299
1350
|
## Context
|
|
1300
1351
|
|
|
1301
1352
|
${input.context}
|
|
1302
|
-
|
|
1303
|
-
## MANDATORY: When done
|
|
1304
|
-
|
|
1305
|
-
You MUST call update_task with status "done" and a result summary when finished.
|
|
1306
|
-
If you skip this, your reviewer will not know you're done and your work won't be reviewed.
|
|
1307
|
-
Do NOT let a failed commit or any error prevent you from calling update_task(done).
|
|
1308
1353
|
`;
|
|
1309
1354
|
await writeFile3(mdPath, mdContent, "utf-8");
|
|
1310
1355
|
} catch (err) {
|
|
@@ -1553,7 +1598,7 @@ ${input.result}` : `\u26A0\uFE0F ${warning}`;
|
|
|
1553
1598
|
await client.execute("PRAGMA wal_checkpoint(PASSIVE)");
|
|
1554
1599
|
} catch {
|
|
1555
1600
|
}
|
|
1556
|
-
if (input.status === "done" || input.status === "cancelled") {
|
|
1601
|
+
if (input.status === "done" || input.status === "cancelled" || input.status === "closed") {
|
|
1557
1602
|
try {
|
|
1558
1603
|
const { clearQueueForAgent: clearQueueForAgent2 } = await Promise.resolve().then(() => (init_intercom_queue(), intercom_queue_exports));
|
|
1559
1604
|
clearQueueForAgent2(String(row.assigned_to));
|
|
@@ -1584,7 +1629,7 @@ async function deleteTaskCore(taskId, _baseDir) {
|
|
|
1584
1629
|
async function ensureArchitectureDoc(baseDir, projectName) {
|
|
1585
1630
|
const archPath = path10.join(baseDir, "exe", "ARCHITECTURE.md");
|
|
1586
1631
|
try {
|
|
1587
|
-
if (
|
|
1632
|
+
if (existsSync10(archPath)) return;
|
|
1588
1633
|
const template = [
|
|
1589
1634
|
`# ${projectName} \u2014 System Architecture`,
|
|
1590
1635
|
"",
|
|
@@ -1619,7 +1664,7 @@ async function ensureArchitectureDoc(baseDir, projectName) {
|
|
|
1619
1664
|
async function ensureGitignoreExe(baseDir) {
|
|
1620
1665
|
const gitignorePath = path10.join(baseDir, ".gitignore");
|
|
1621
1666
|
try {
|
|
1622
|
-
if (
|
|
1667
|
+
if (existsSync10(gitignorePath)) {
|
|
1623
1668
|
const content = readFileSync9(gitignorePath, "utf-8");
|
|
1624
1669
|
if (/^\/?exe\/?$/m.test(content)) return;
|
|
1625
1670
|
await appendFile(gitignorePath, "\n# Employee task assignments (private)\n/exe/\n");
|
|
@@ -1652,57 +1697,41 @@ var init_tasks_crud = __esm({
|
|
|
1652
1697
|
|
|
1653
1698
|
// src/lib/tasks-review.ts
|
|
1654
1699
|
import path11 from "path";
|
|
1655
|
-
import { existsSync as
|
|
1700
|
+
import { existsSync as existsSync11, readdirSync as readdirSync2, unlinkSync as unlinkSync3 } from "fs";
|
|
1656
1701
|
async function countPendingReviews(sessionScope) {
|
|
1657
1702
|
const client = getClient();
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
args: [sessionScope]
|
|
1662
|
-
});
|
|
1663
|
-
return Number(result2.rows[0]?.cnt) || 0;
|
|
1664
|
-
}
|
|
1703
|
+
const scope = strictSessionScopeFilter(
|
|
1704
|
+
sessionScope === void 0 ? getCurrentSessionScope() : sessionScope
|
|
1705
|
+
);
|
|
1665
1706
|
const result = await client.execute({
|
|
1666
|
-
sql:
|
|
1667
|
-
|
|
1707
|
+
sql: `SELECT COUNT(*) as cnt FROM tasks
|
|
1708
|
+
WHERE status = 'needs_review'${scope.sql}`,
|
|
1709
|
+
args: [...scope.args]
|
|
1668
1710
|
});
|
|
1669
1711
|
return Number(result.rows[0]?.cnt) || 0;
|
|
1670
1712
|
}
|
|
1671
1713
|
async function countNewPendingReviewsSince(sinceIso, sessionScope) {
|
|
1672
1714
|
const client = getClient();
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
WHERE status = 'needs_review' AND updated_at > ?
|
|
1677
|
-
AND session_scope = ?`,
|
|
1678
|
-
args: [sinceIso, sessionScope]
|
|
1679
|
-
});
|
|
1680
|
-
return Number(result2.rows[0]?.cnt) || 0;
|
|
1681
|
-
}
|
|
1715
|
+
const scope = strictSessionScopeFilter(
|
|
1716
|
+
sessionScope === void 0 ? getCurrentSessionScope() : sessionScope
|
|
1717
|
+
);
|
|
1682
1718
|
const result = await client.execute({
|
|
1683
1719
|
sql: `SELECT COUNT(*) as cnt FROM tasks
|
|
1684
|
-
WHERE status = 'needs_review' AND updated_at >
|
|
1685
|
-
args: [sinceIso]
|
|
1720
|
+
WHERE status = 'needs_review' AND updated_at > ?${scope.sql}`,
|
|
1721
|
+
args: [sinceIso, ...scope.args]
|
|
1686
1722
|
});
|
|
1687
1723
|
return Number(result.rows[0]?.cnt) || 0;
|
|
1688
1724
|
}
|
|
1689
1725
|
async function listPendingReviews(limit, sessionScope) {
|
|
1690
1726
|
const client = getClient();
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
WHERE status = 'needs_review'
|
|
1695
|
-
AND session_scope = ?
|
|
1696
|
-
ORDER BY updated_at ASC LIMIT ?`,
|
|
1697
|
-
args: [sessionScope, limit]
|
|
1698
|
-
});
|
|
1699
|
-
return result2.rows;
|
|
1700
|
-
}
|
|
1727
|
+
const scope = strictSessionScopeFilter(
|
|
1728
|
+
sessionScope === void 0 ? getCurrentSessionScope() : sessionScope
|
|
1729
|
+
);
|
|
1701
1730
|
const result = await client.execute({
|
|
1702
1731
|
sql: `SELECT title, assigned_to, project_name, updated_at FROM tasks
|
|
1703
|
-
WHERE status = 'needs_review'
|
|
1732
|
+
WHERE status = 'needs_review'${scope.sql}
|
|
1704
1733
|
ORDER BY updated_at ASC LIMIT ?`,
|
|
1705
|
-
args: [limit]
|
|
1734
|
+
args: [...scope.args, limit]
|
|
1706
1735
|
});
|
|
1707
1736
|
return result.rows;
|
|
1708
1737
|
}
|
|
@@ -1714,7 +1743,7 @@ async function cleanupOrphanedReviews() {
|
|
|
1714
1743
|
WHERE status IN ('open', 'needs_review', 'in_progress')
|
|
1715
1744
|
AND assigned_by = 'system'
|
|
1716
1745
|
AND title LIKE 'Review:%'
|
|
1717
|
-
AND parent_task_id IN (SELECT id FROM tasks WHERE status IN ('done', 'cancelled'))`,
|
|
1746
|
+
AND parent_task_id IN (SELECT id FROM tasks WHERE status IN ('done', 'cancelled', 'closed'))`,
|
|
1718
1747
|
args: [now]
|
|
1719
1748
|
});
|
|
1720
1749
|
const r1b = await client.execute({
|
|
@@ -1834,7 +1863,7 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
|
|
|
1834
1863
|
}
|
|
1835
1864
|
try {
|
|
1836
1865
|
const cacheDir = path11.join(EXE_AI_DIR, "session-cache");
|
|
1837
|
-
if (
|
|
1866
|
+
if (existsSync11(cacheDir)) {
|
|
1838
1867
|
for (const f of readdirSync2(cacheDir)) {
|
|
1839
1868
|
if (f.startsWith("review-notified-")) {
|
|
1840
1869
|
unlinkSync3(path11.join(cacheDir, f));
|
|
@@ -1854,6 +1883,7 @@ var init_tasks_review = __esm({
|
|
|
1854
1883
|
init_tmux_routing();
|
|
1855
1884
|
init_session_key();
|
|
1856
1885
|
init_state_bus();
|
|
1886
|
+
init_task_scope();
|
|
1857
1887
|
}
|
|
1858
1888
|
});
|
|
1859
1889
|
|
|
@@ -1910,7 +1940,7 @@ async function checkSubtaskCompletion(parentTaskId, projectName) {
|
|
|
1910
1940
|
const scScope = sessionScopeFilter();
|
|
1911
1941
|
const remaining = await client.execute({
|
|
1912
1942
|
sql: `SELECT COUNT(*) as cnt FROM tasks
|
|
1913
|
-
WHERE parent_task_id = ? AND status NOT IN ('done', 'cancelled')${scScope.sql}`,
|
|
1943
|
+
WHERE parent_task_id = ? AND status NOT IN ('done', 'cancelled', 'closed')${scScope.sql}`,
|
|
1914
1944
|
args: [parentTaskId, ...scScope.args]
|
|
1915
1945
|
});
|
|
1916
1946
|
const cnt = Number(remaining.rows[0]?.cnt ?? 1);
|
|
@@ -2468,7 +2498,7 @@ async function updateTask(input) {
|
|
|
2468
2498
|
if (input.status === "in_progress") {
|
|
2469
2499
|
mkdirSync5(cacheDir, { recursive: true });
|
|
2470
2500
|
writeFileSync6(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
|
|
2471
|
-
} else if (input.status === "done" || input.status === "blocked" || input.status === "cancelled") {
|
|
2501
|
+
} else if (input.status === "done" || input.status === "blocked" || input.status === "cancelled" || input.status === "closed") {
|
|
2472
2502
|
try {
|
|
2473
2503
|
unlinkSync4(cachePath);
|
|
2474
2504
|
} catch {
|
|
@@ -2476,10 +2506,10 @@ async function updateTask(input) {
|
|
|
2476
2506
|
}
|
|
2477
2507
|
} catch {
|
|
2478
2508
|
}
|
|
2479
|
-
if (input.status === "done") {
|
|
2509
|
+
if (input.status === "done" || input.status === "closed") {
|
|
2480
2510
|
await cleanupReviewFile(row, taskFile, input.baseDir);
|
|
2481
2511
|
}
|
|
2482
|
-
if (input.status === "done" || input.status === "cancelled") {
|
|
2512
|
+
if (input.status === "done" || input.status === "cancelled" || input.status === "closed") {
|
|
2483
2513
|
try {
|
|
2484
2514
|
const client = getClient();
|
|
2485
2515
|
const taskTitle = String(row.title);
|
|
@@ -2495,7 +2525,7 @@ async function updateTask(input) {
|
|
|
2495
2525
|
if (!isCoordinatorName(assignedAgent)) {
|
|
2496
2526
|
try {
|
|
2497
2527
|
const draftClient = getClient();
|
|
2498
|
-
if (input.status === "done") {
|
|
2528
|
+
if (input.status === "done" || input.status === "closed") {
|
|
2499
2529
|
await draftClient.execute({
|
|
2500
2530
|
sql: `UPDATE memories SET draft = 0 WHERE agent_id = ? AND draft = 1`,
|
|
2501
2531
|
args: [assignedAgent]
|
|
@@ -2512,7 +2542,7 @@ async function updateTask(input) {
|
|
|
2512
2542
|
try {
|
|
2513
2543
|
const client = getClient();
|
|
2514
2544
|
const cascaded = await client.execute({
|
|
2515
|
-
sql: `UPDATE tasks SET status = '
|
|
2545
|
+
sql: `UPDATE tasks SET status = 'closed', updated_at = ?
|
|
2516
2546
|
WHERE parent_task_id = ? AND status = 'needs_review'`,
|
|
2517
2547
|
args: [now, taskId]
|
|
2518
2548
|
});
|
|
@@ -2525,14 +2555,14 @@ async function updateTask(input) {
|
|
|
2525
2555
|
} catch {
|
|
2526
2556
|
}
|
|
2527
2557
|
}
|
|
2528
|
-
const isTerminal = input.status === "done" || input.status === "needs_review";
|
|
2558
|
+
const isTerminal = input.status === "done" || input.status === "needs_review" || input.status === "closed";
|
|
2529
2559
|
if (isTerminal) {
|
|
2530
2560
|
const isCoordinator = isCoordinatorName(String(row.assigned_to));
|
|
2531
2561
|
if (!isCoordinator) {
|
|
2532
2562
|
notifyTaskDone();
|
|
2533
2563
|
}
|
|
2534
2564
|
await markTaskNotificationsRead(taskFile);
|
|
2535
|
-
if (input.status === "done") {
|
|
2565
|
+
if (input.status === "done" || input.status === "closed") {
|
|
2536
2566
|
try {
|
|
2537
2567
|
await cascadeUnblock(taskId, input.baseDir, now);
|
|
2538
2568
|
} catch {
|
|
@@ -2552,7 +2582,7 @@ async function updateTask(input) {
|
|
|
2552
2582
|
}
|
|
2553
2583
|
}
|
|
2554
2584
|
}
|
|
2555
|
-
if (input.status === "done" && !isCoordinatorName(String(row.assigned_to)) && !process.env.VITEST) {
|
|
2585
|
+
if ((input.status === "done" || input.status === "closed") && !isCoordinatorName(String(row.assigned_to)) && !process.env.VITEST) {
|
|
2556
2586
|
Promise.resolve().then(() => (init_skill_learning(), skill_learning_exports)).then(
|
|
2557
2587
|
({ captureAndLearn: captureAndLearn2 }) => captureAndLearn2({
|
|
2558
2588
|
taskId,
|
|
@@ -2924,6 +2954,7 @@ __export(tmux_routing_exports, {
|
|
|
2924
2954
|
isEmployeeAlive: () => isEmployeeAlive,
|
|
2925
2955
|
isExeSession: () => isExeSession,
|
|
2926
2956
|
isSessionBusy: () => isSessionBusy,
|
|
2957
|
+
notifyCoordinatorTaskCompletion: () => notifyCoordinatorTaskCompletion,
|
|
2927
2958
|
notifyParentExe: () => notifyParentExe,
|
|
2928
2959
|
parseParentExe: () => parseParentExe,
|
|
2929
2960
|
registerParentExe: () => registerParentExe,
|
|
@@ -2934,9 +2965,9 @@ __export(tmux_routing_exports, {
|
|
|
2934
2965
|
verifyPaneAtCapacity: () => verifyPaneAtCapacity
|
|
2935
2966
|
});
|
|
2936
2967
|
import { execFileSync as execFileSync2, execSync as execSync6 } from "child_process";
|
|
2937
|
-
import { readFileSync as readFileSync10, writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, existsSync as
|
|
2968
|
+
import { readFileSync as readFileSync10, writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, existsSync as existsSync12, appendFileSync, readdirSync as readdirSync3 } from "fs";
|
|
2938
2969
|
import path15 from "path";
|
|
2939
|
-
import
|
|
2970
|
+
import os9 from "os";
|
|
2940
2971
|
import { fileURLToPath } from "url";
|
|
2941
2972
|
import { unlinkSync as unlinkSync5 } from "fs";
|
|
2942
2973
|
function spawnLockPath(sessionName) {
|
|
@@ -2951,11 +2982,11 @@ function isProcessAlive(pid) {
|
|
|
2951
2982
|
}
|
|
2952
2983
|
}
|
|
2953
2984
|
function acquireSpawnLock(sessionName) {
|
|
2954
|
-
if (!
|
|
2985
|
+
if (!existsSync12(SPAWN_LOCK_DIR)) {
|
|
2955
2986
|
mkdirSync6(SPAWN_LOCK_DIR, { recursive: true });
|
|
2956
2987
|
}
|
|
2957
2988
|
const lockFile = spawnLockPath(sessionName);
|
|
2958
|
-
if (
|
|
2989
|
+
if (existsSync12(lockFile)) {
|
|
2959
2990
|
try {
|
|
2960
2991
|
const lock = JSON.parse(readFileSync10(lockFile, "utf8"));
|
|
2961
2992
|
const age = Date.now() - lock.timestamp;
|
|
@@ -2983,7 +3014,7 @@ function resolveBehaviorsExporterScript() {
|
|
|
2983
3014
|
"bin",
|
|
2984
3015
|
"exe-export-behaviors.js"
|
|
2985
3016
|
);
|
|
2986
|
-
return
|
|
3017
|
+
return existsSync12(scriptPath) ? scriptPath : null;
|
|
2987
3018
|
} catch {
|
|
2988
3019
|
return null;
|
|
2989
3020
|
}
|
|
@@ -3049,7 +3080,7 @@ function extractRootExe(name) {
|
|
|
3049
3080
|
return parts.length > 0 ? parts[parts.length - 1] : null;
|
|
3050
3081
|
}
|
|
3051
3082
|
function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
3052
|
-
if (!
|
|
3083
|
+
if (!existsSync12(SESSION_CACHE)) {
|
|
3053
3084
|
mkdirSync6(SESSION_CACHE, { recursive: true });
|
|
3054
3085
|
}
|
|
3055
3086
|
const rootExe = extractRootExe(parentExe) ?? parentExe;
|
|
@@ -3141,7 +3172,7 @@ async function verifyPaneAtCapacity(sessionName) {
|
|
|
3141
3172
|
}
|
|
3142
3173
|
function readDebounceState() {
|
|
3143
3174
|
try {
|
|
3144
|
-
if (!
|
|
3175
|
+
if (!existsSync12(DEBOUNCE_FILE)) return {};
|
|
3145
3176
|
const raw = JSON.parse(readFileSync10(DEBOUNCE_FILE, "utf8"));
|
|
3146
3177
|
const state = {};
|
|
3147
3178
|
for (const [key, val] of Object.entries(raw)) {
|
|
@@ -3158,7 +3189,7 @@ function readDebounceState() {
|
|
|
3158
3189
|
}
|
|
3159
3190
|
function writeDebounceState(state) {
|
|
3160
3191
|
try {
|
|
3161
|
-
if (!
|
|
3192
|
+
if (!existsSync12(SESSION_CACHE)) mkdirSync6(SESSION_CACHE, { recursive: true });
|
|
3162
3193
|
writeFileSync7(DEBOUNCE_FILE, JSON.stringify(state));
|
|
3163
3194
|
} catch {
|
|
3164
3195
|
}
|
|
@@ -3258,7 +3289,7 @@ function sendIntercom(targetSession) {
|
|
|
3258
3289
|
const rawAgent = targetSession.split("-")[0] ?? targetSession;
|
|
3259
3290
|
const agent = baseAgentName(rawAgent);
|
|
3260
3291
|
const markerPath = path15.join(SESSION_CACHE, `current-task-${agent}.json`);
|
|
3261
|
-
if (
|
|
3292
|
+
if (existsSync12(markerPath)) {
|
|
3262
3293
|
logIntercom(`SKIP \u2192 ${targetSession} (has in_progress task marker \u2014 will auto-chain)`);
|
|
3263
3294
|
return "debounced";
|
|
3264
3295
|
}
|
|
@@ -3268,7 +3299,7 @@ function sendIntercom(targetSession) {
|
|
|
3268
3299
|
const rawAgent = targetSession.split("-")[0] ?? targetSession;
|
|
3269
3300
|
const agent = baseAgentName(rawAgent);
|
|
3270
3301
|
const taskDir = path15.join(process.cwd(), "exe", agent);
|
|
3271
|
-
if (
|
|
3302
|
+
if (existsSync12(taskDir)) {
|
|
3272
3303
|
const files = readdirSync3(taskDir).filter(
|
|
3273
3304
|
(f) => f.endsWith(".md") && f !== "DONE.txt"
|
|
3274
3305
|
);
|
|
@@ -3328,6 +3359,21 @@ function notifyParentExe(sessionKey) {
|
|
|
3328
3359
|
}
|
|
3329
3360
|
return true;
|
|
3330
3361
|
}
|
|
3362
|
+
function notifyCoordinatorTaskCompletion(coordinatorSession, agentName, taskTitle) {
|
|
3363
|
+
const transport = getTransport();
|
|
3364
|
+
try {
|
|
3365
|
+
const sessions = transport.listSessions();
|
|
3366
|
+
if (!sessions.includes(coordinatorSession)) return false;
|
|
3367
|
+
execSync6(
|
|
3368
|
+
`tmux send-keys -t ${JSON.stringify(coordinatorSession)} '/exe-intercom' Enter`,
|
|
3369
|
+
{ timeout: 3e3 }
|
|
3370
|
+
);
|
|
3371
|
+
logIntercom(`COMPLETION \u2192 ${coordinatorSession} (${agentName} completed "${taskTitle.slice(0, 50)}")`);
|
|
3372
|
+
return true;
|
|
3373
|
+
} catch {
|
|
3374
|
+
return false;
|
|
3375
|
+
}
|
|
3376
|
+
}
|
|
3331
3377
|
function ensureEmployee(employeeName, exeSession, projectDir, opts) {
|
|
3332
3378
|
if (isCoordinatorName(employeeName)) {
|
|
3333
3379
|
return { status: "failed", sessionName: "", error: "The COO is not a dispatchable employee" };
|
|
@@ -3401,9 +3447,9 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3401
3447
|
const transport = getTransport();
|
|
3402
3448
|
const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
|
|
3403
3449
|
const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
|
|
3404
|
-
const logDir = path15.join(
|
|
3450
|
+
const logDir = path15.join(os9.homedir(), ".exe-os", "session-logs");
|
|
3405
3451
|
const logFile = path15.join(logDir, `${instanceLabel}-${Date.now()}.log`);
|
|
3406
|
-
if (!
|
|
3452
|
+
if (!existsSync12(logDir)) {
|
|
3407
3453
|
mkdirSync6(logDir, { recursive: true });
|
|
3408
3454
|
}
|
|
3409
3455
|
transport.kill(sessionName);
|
|
@@ -3411,13 +3457,13 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3411
3457
|
try {
|
|
3412
3458
|
const thisFile = fileURLToPath(import.meta.url);
|
|
3413
3459
|
const cleanupScript = path15.join(path15.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
|
|
3414
|
-
if (
|
|
3460
|
+
if (existsSync12(cleanupScript)) {
|
|
3415
3461
|
cleanupSuffix = `; ${process.execPath} "${cleanupScript}" "${employeeName}" "${exeSession}"`;
|
|
3416
3462
|
}
|
|
3417
3463
|
} catch {
|
|
3418
3464
|
}
|
|
3419
3465
|
try {
|
|
3420
|
-
const claudeJsonPath = path15.join(
|
|
3466
|
+
const claudeJsonPath = path15.join(os9.homedir(), ".claude.json");
|
|
3421
3467
|
let claudeJson = {};
|
|
3422
3468
|
try {
|
|
3423
3469
|
claudeJson = JSON.parse(readFileSync10(claudeJsonPath, "utf8"));
|
|
@@ -3432,7 +3478,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3432
3478
|
} catch {
|
|
3433
3479
|
}
|
|
3434
3480
|
try {
|
|
3435
|
-
const settingsDir = path15.join(
|
|
3481
|
+
const settingsDir = path15.join(os9.homedir(), ".claude", "projects");
|
|
3436
3482
|
const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
|
|
3437
3483
|
const projSettingsDir = path15.join(settingsDir, normalizedKey);
|
|
3438
3484
|
const settingsPath = path15.join(projSettingsDir, "settings.json");
|
|
@@ -3483,7 +3529,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3483
3529
|
let legacyFallbackWarned = false;
|
|
3484
3530
|
if (!useExeAgent && !useBinSymlink) {
|
|
3485
3531
|
const identityPath = path15.join(
|
|
3486
|
-
|
|
3532
|
+
os9.homedir(),
|
|
3487
3533
|
".exe-os",
|
|
3488
3534
|
"identity",
|
|
3489
3535
|
`${employeeName}.md`
|
|
@@ -3492,7 +3538,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3492
3538
|
const hasAgentFlag = claudeSupportsAgentFlag();
|
|
3493
3539
|
if (hasAgentFlag) {
|
|
3494
3540
|
identityFlag = ` --agent ${employeeName}`;
|
|
3495
|
-
} else if (
|
|
3541
|
+
} else if (existsSync12(identityPath)) {
|
|
3496
3542
|
identityFlag = ` --append-system-prompt-file ${identityPath}`;
|
|
3497
3543
|
legacyFallbackWarned = true;
|
|
3498
3544
|
}
|
|
@@ -3513,7 +3559,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3513
3559
|
}
|
|
3514
3560
|
let sessionContextFlag = "";
|
|
3515
3561
|
try {
|
|
3516
|
-
const ctxDir = path15.join(
|
|
3562
|
+
const ctxDir = path15.join(os9.homedir(), ".exe-os", "session-cache");
|
|
3517
3563
|
mkdirSync6(ctxDir, { recursive: true });
|
|
3518
3564
|
const ctxFile = path15.join(ctxDir, `session-context-${sessionName}.md`);
|
|
3519
3565
|
const ctxContent = [
|
|
@@ -3673,14 +3719,14 @@ var init_tmux_routing = __esm({
|
|
|
3673
3719
|
init_intercom_queue();
|
|
3674
3720
|
init_plan_limits();
|
|
3675
3721
|
init_employees();
|
|
3676
|
-
SPAWN_LOCK_DIR = path15.join(
|
|
3677
|
-
SESSION_CACHE = path15.join(
|
|
3722
|
+
SPAWN_LOCK_DIR = path15.join(os9.homedir(), ".exe-os", "spawn-locks");
|
|
3723
|
+
SESSION_CACHE = path15.join(os9.homedir(), ".exe-os", "session-cache");
|
|
3678
3724
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
3679
3725
|
VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
|
|
3680
3726
|
VERIFY_PANE_LINES = 200;
|
|
3681
3727
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
3682
3728
|
CODEX_DEBOUNCE_MS = 12e4;
|
|
3683
|
-
INTERCOM_LOG2 = path15.join(
|
|
3729
|
+
INTERCOM_LOG2 = path15.join(os9.homedir(), ".exe-os", "intercom.log");
|
|
3684
3730
|
DEBOUNCE_FILE = path15.join(SESSION_CACHE, "intercom-debounce.json");
|
|
3685
3731
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
3686
3732
|
BUSY_PATTERN = /[✻✽✶✳·].*…|Running…|• Working|• Ran |• Explored|• Called|esc to interrupt/;
|
|
@@ -3700,6 +3746,7 @@ export {
|
|
|
3700
3746
|
isEmployeeAlive,
|
|
3701
3747
|
isExeSession,
|
|
3702
3748
|
isSessionBusy,
|
|
3749
|
+
notifyCoordinatorTaskCompletion,
|
|
3703
3750
|
notifyParentExe,
|
|
3704
3751
|
parseParentExe,
|
|
3705
3752
|
registerParentExe,
|