@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
|
@@ -32,6 +32,44 @@ var init_db_retry = __esm({
|
|
|
32
32
|
}
|
|
33
33
|
});
|
|
34
34
|
|
|
35
|
+
// src/lib/secure-files.ts
|
|
36
|
+
import { chmodSync, existsSync, mkdirSync } from "fs";
|
|
37
|
+
import { chmod, mkdir } from "fs/promises";
|
|
38
|
+
async function ensurePrivateDir(dirPath) {
|
|
39
|
+
await mkdir(dirPath, { recursive: true, mode: PRIVATE_DIR_MODE });
|
|
40
|
+
try {
|
|
41
|
+
await chmod(dirPath, PRIVATE_DIR_MODE);
|
|
42
|
+
} catch {
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function ensurePrivateDirSync(dirPath) {
|
|
46
|
+
mkdirSync(dirPath, { recursive: true, mode: PRIVATE_DIR_MODE });
|
|
47
|
+
try {
|
|
48
|
+
chmodSync(dirPath, PRIVATE_DIR_MODE);
|
|
49
|
+
} catch {
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
async function enforcePrivateFile(filePath) {
|
|
53
|
+
try {
|
|
54
|
+
await chmod(filePath, PRIVATE_FILE_MODE);
|
|
55
|
+
} catch {
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function enforcePrivateFileSync(filePath) {
|
|
59
|
+
try {
|
|
60
|
+
if (existsSync(filePath)) chmodSync(filePath, PRIVATE_FILE_MODE);
|
|
61
|
+
} catch {
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
var PRIVATE_DIR_MODE, PRIVATE_FILE_MODE;
|
|
65
|
+
var init_secure_files = __esm({
|
|
66
|
+
"src/lib/secure-files.ts"() {
|
|
67
|
+
"use strict";
|
|
68
|
+
PRIVATE_DIR_MODE = 448;
|
|
69
|
+
PRIVATE_FILE_MODE = 384;
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
35
73
|
// src/lib/config.ts
|
|
36
74
|
var config_exports = {};
|
|
37
75
|
__export(config_exports, {
|
|
@@ -48,8 +86,8 @@ __export(config_exports, {
|
|
|
48
86
|
migrateConfig: () => migrateConfig,
|
|
49
87
|
saveConfig: () => saveConfig
|
|
50
88
|
});
|
|
51
|
-
import { readFile, writeFile
|
|
52
|
-
import { readFileSync, existsSync, renameSync } from "fs";
|
|
89
|
+
import { readFile, writeFile } from "fs/promises";
|
|
90
|
+
import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
|
|
53
91
|
import path from "path";
|
|
54
92
|
import os from "os";
|
|
55
93
|
function resolveDataDir() {
|
|
@@ -57,7 +95,7 @@ function resolveDataDir() {
|
|
|
57
95
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
58
96
|
const newDir = path.join(os.homedir(), ".exe-os");
|
|
59
97
|
const legacyDir = path.join(os.homedir(), ".exe-mem");
|
|
60
|
-
if (!
|
|
98
|
+
if (!existsSync2(newDir) && existsSync2(legacyDir)) {
|
|
61
99
|
try {
|
|
62
100
|
renameSync(legacyDir, newDir);
|
|
63
101
|
process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
|
|
@@ -120,9 +158,9 @@ function normalizeAutoUpdate(raw) {
|
|
|
120
158
|
}
|
|
121
159
|
async function loadConfig() {
|
|
122
160
|
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
123
|
-
await
|
|
161
|
+
await ensurePrivateDir(dir);
|
|
124
162
|
const configPath = path.join(dir, "config.json");
|
|
125
|
-
if (!
|
|
163
|
+
if (!existsSync2(configPath)) {
|
|
126
164
|
return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db") };
|
|
127
165
|
}
|
|
128
166
|
const raw = await readFile(configPath, "utf-8");
|
|
@@ -135,6 +173,7 @@ async function loadConfig() {
|
|
|
135
173
|
`);
|
|
136
174
|
try {
|
|
137
175
|
await writeFile(configPath, JSON.stringify(migratedCfg, null, 2) + "\n");
|
|
176
|
+
await enforcePrivateFile(configPath);
|
|
138
177
|
} catch {
|
|
139
178
|
}
|
|
140
179
|
}
|
|
@@ -153,7 +192,7 @@ async function loadConfig() {
|
|
|
153
192
|
function loadConfigSync() {
|
|
154
193
|
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
155
194
|
const configPath = path.join(dir, "config.json");
|
|
156
|
-
if (!
|
|
195
|
+
if (!existsSync2(configPath)) {
|
|
157
196
|
return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db") };
|
|
158
197
|
}
|
|
159
198
|
try {
|
|
@@ -171,12 +210,10 @@ function loadConfigSync() {
|
|
|
171
210
|
}
|
|
172
211
|
async function saveConfig(config) {
|
|
173
212
|
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
174
|
-
await
|
|
213
|
+
await ensurePrivateDir(dir);
|
|
175
214
|
const configPath = path.join(dir, "config.json");
|
|
176
215
|
await writeFile(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
177
|
-
|
|
178
|
-
await chmod(configPath, 384);
|
|
179
|
-
}
|
|
216
|
+
await enforcePrivateFile(configPath);
|
|
180
217
|
}
|
|
181
218
|
async function loadConfigFrom(configPath) {
|
|
182
219
|
const raw = await readFile(configPath, "utf-8");
|
|
@@ -196,6 +233,7 @@ var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CON
|
|
|
196
233
|
var init_config = __esm({
|
|
197
234
|
"src/lib/config.ts"() {
|
|
198
235
|
"use strict";
|
|
236
|
+
init_secure_files();
|
|
199
237
|
EXE_AI_DIR = resolveDataDir();
|
|
200
238
|
DB_PATH = path.join(EXE_AI_DIR, "memories.db");
|
|
201
239
|
MODELS_DIR = path.join(EXE_AI_DIR, "models");
|
|
@@ -312,10 +350,10 @@ __export(agent_config_exports, {
|
|
|
312
350
|
saveAgentConfig: () => saveAgentConfig,
|
|
313
351
|
setAgentRuntime: () => setAgentRuntime
|
|
314
352
|
});
|
|
315
|
-
import { readFileSync as readFileSync2, writeFileSync, existsSync as
|
|
353
|
+
import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync3 } from "fs";
|
|
316
354
|
import path2 from "path";
|
|
317
355
|
function loadAgentConfig() {
|
|
318
|
-
if (!
|
|
356
|
+
if (!existsSync3(AGENT_CONFIG_PATH)) return {};
|
|
319
357
|
try {
|
|
320
358
|
return JSON.parse(readFileSync2(AGENT_CONFIG_PATH, "utf-8"));
|
|
321
359
|
} catch {
|
|
@@ -324,8 +362,9 @@ function loadAgentConfig() {
|
|
|
324
362
|
}
|
|
325
363
|
function saveAgentConfig(config) {
|
|
326
364
|
const dir = path2.dirname(AGENT_CONFIG_PATH);
|
|
327
|
-
|
|
365
|
+
ensurePrivateDirSync(dir);
|
|
328
366
|
writeFileSync(AGENT_CONFIG_PATH, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
367
|
+
enforcePrivateFileSync(AGENT_CONFIG_PATH);
|
|
329
368
|
}
|
|
330
369
|
function getAgentRuntime(agentId) {
|
|
331
370
|
const config = loadAgentConfig();
|
|
@@ -365,6 +404,7 @@ var init_agent_config = __esm({
|
|
|
365
404
|
"use strict";
|
|
366
405
|
init_config();
|
|
367
406
|
init_runtime_table();
|
|
407
|
+
init_secure_files();
|
|
368
408
|
AGENT_CONFIG_PATH = path2.join(EXE_AI_DIR, "agent-config.json");
|
|
369
409
|
KNOWN_RUNTIMES = {
|
|
370
410
|
claude: ["claude-opus-4", "claude-sonnet-4", "claude-haiku-4.5"],
|
|
@@ -412,7 +452,7 @@ __export(employees_exports, {
|
|
|
412
452
|
validateEmployeeName: () => validateEmployeeName
|
|
413
453
|
});
|
|
414
454
|
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
415
|
-
import { existsSync as
|
|
455
|
+
import { existsSync as existsSync4, symlinkSync, readlinkSync, readFileSync as readFileSync3, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
|
|
416
456
|
import { execSync } from "child_process";
|
|
417
457
|
import path3 from "path";
|
|
418
458
|
import os2 from "os";
|
|
@@ -451,7 +491,7 @@ function validateEmployeeName(name) {
|
|
|
451
491
|
return { valid: true };
|
|
452
492
|
}
|
|
453
493
|
async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
|
|
454
|
-
if (!
|
|
494
|
+
if (!existsSync4(employeesPath)) {
|
|
455
495
|
return [];
|
|
456
496
|
}
|
|
457
497
|
const raw = await readFile2(employeesPath, "utf-8");
|
|
@@ -466,7 +506,7 @@ async function saveEmployees(employees, employeesPath = EMPLOYEES_PATH) {
|
|
|
466
506
|
await writeFile2(employeesPath, JSON.stringify(employees, null, 2) + "\n", "utf-8");
|
|
467
507
|
}
|
|
468
508
|
function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
|
|
469
|
-
if (!
|
|
509
|
+
if (!existsSync4(employeesPath)) return [];
|
|
470
510
|
try {
|
|
471
511
|
return JSON.parse(readFileSync3(employeesPath, "utf-8"));
|
|
472
512
|
} catch {
|
|
@@ -514,7 +554,7 @@ function appendToCoordinatorTeam(employee) {
|
|
|
514
554
|
const coordinator = getCoordinatorEmployee(loadEmployeesSync());
|
|
515
555
|
if (!coordinator) return;
|
|
516
556
|
const idPath = path3.join(IDENTITY_DIR, `${coordinator.name}.md`);
|
|
517
|
-
if (!
|
|
557
|
+
if (!existsSync4(idPath)) return;
|
|
518
558
|
const content = readFileSync3(idPath, "utf-8");
|
|
519
559
|
if (content.includes(`**${capitalize(employee.name)}`)) return;
|
|
520
560
|
const teamMatch = content.match(TEAM_SECTION_RE);
|
|
@@ -568,9 +608,9 @@ async function normalizeRosterCase(rosterPath) {
|
|
|
568
608
|
const identityDir = path3.join(os2.homedir(), ".exe-os", "identity");
|
|
569
609
|
const oldPath = path3.join(identityDir, `${oldName}.md`);
|
|
570
610
|
const newPath = path3.join(identityDir, `${emp.name}.md`);
|
|
571
|
-
if (
|
|
611
|
+
if (existsSync4(oldPath) && !existsSync4(newPath)) {
|
|
572
612
|
renameSync2(oldPath, newPath);
|
|
573
|
-
} else if (
|
|
613
|
+
} else if (existsSync4(oldPath) && oldPath !== newPath) {
|
|
574
614
|
const content = readFileSync3(oldPath, "utf-8");
|
|
575
615
|
writeFileSync2(newPath, content, "utf-8");
|
|
576
616
|
if (oldPath.toLowerCase() !== newPath.toLowerCase()) {
|
|
@@ -613,7 +653,7 @@ function registerBinSymlinks(name) {
|
|
|
613
653
|
for (const suffix of ["", "-opencode"]) {
|
|
614
654
|
const linkName = `${name}${suffix}`;
|
|
615
655
|
const linkPath = path3.join(binDir, linkName);
|
|
616
|
-
if (
|
|
656
|
+
if (existsSync4(linkPath)) {
|
|
617
657
|
skipped.push(linkName);
|
|
618
658
|
continue;
|
|
619
659
|
}
|
|
@@ -691,119 +731,12 @@ var init_database = __esm({
|
|
|
691
731
|
}
|
|
692
732
|
});
|
|
693
733
|
|
|
694
|
-
// src/lib/
|
|
695
|
-
import
|
|
734
|
+
// src/lib/session-registry.ts
|
|
735
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, mkdirSync as mkdirSync2, existsSync as existsSync5 } from "fs";
|
|
696
736
|
import path5 from "path";
|
|
697
737
|
import os4 from "os";
|
|
698
|
-
import {
|
|
699
|
-
readFileSync as readFileSync4,
|
|
700
|
-
readdirSync,
|
|
701
|
-
unlinkSync as unlinkSync2,
|
|
702
|
-
existsSync as existsSync4,
|
|
703
|
-
rmdirSync
|
|
704
|
-
} from "fs";
|
|
705
|
-
async function writeNotification(notification) {
|
|
706
|
-
try {
|
|
707
|
-
const client = getClient();
|
|
708
|
-
const id = crypto.randomUUID();
|
|
709
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
710
|
-
await client.execute({
|
|
711
|
-
sql: `INSERT INTO notifications (id, agent_id, agent_role, event, project, summary, task_file, read, created_at)
|
|
712
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, 0, ?)`,
|
|
713
|
-
args: [
|
|
714
|
-
id,
|
|
715
|
-
notification.agentId,
|
|
716
|
-
notification.agentRole,
|
|
717
|
-
notification.event,
|
|
718
|
-
notification.project,
|
|
719
|
-
notification.summary,
|
|
720
|
-
notification.taskFile ?? null,
|
|
721
|
-
now
|
|
722
|
-
]
|
|
723
|
-
});
|
|
724
|
-
} catch (err) {
|
|
725
|
-
process.stderr.write(`[notifications] WRITE FAILED: ${err instanceof Error ? err.message : String(err)}
|
|
726
|
-
`);
|
|
727
|
-
}
|
|
728
|
-
}
|
|
729
|
-
async function markAsReadByTaskFile(taskFile) {
|
|
730
|
-
try {
|
|
731
|
-
const client = getClient();
|
|
732
|
-
await client.execute({
|
|
733
|
-
sql: "UPDATE notifications SET read = 1 WHERE task_file = ? AND read = 0",
|
|
734
|
-
args: [taskFile]
|
|
735
|
-
});
|
|
736
|
-
} catch {
|
|
737
|
-
}
|
|
738
|
-
}
|
|
739
|
-
var init_notifications = __esm({
|
|
740
|
-
"src/lib/notifications.ts"() {
|
|
741
|
-
"use strict";
|
|
742
|
-
init_database();
|
|
743
|
-
}
|
|
744
|
-
});
|
|
745
|
-
|
|
746
|
-
// src/lib/state-bus.ts
|
|
747
|
-
var StateBus, orgBus;
|
|
748
|
-
var init_state_bus = __esm({
|
|
749
|
-
"src/lib/state-bus.ts"() {
|
|
750
|
-
"use strict";
|
|
751
|
-
StateBus = class {
|
|
752
|
-
handlers = /* @__PURE__ */ new Map();
|
|
753
|
-
globalHandlers = /* @__PURE__ */ new Set();
|
|
754
|
-
/** Emit an event to all subscribers */
|
|
755
|
-
emit(event) {
|
|
756
|
-
const typeHandlers = this.handlers.get(event.type);
|
|
757
|
-
if (typeHandlers) {
|
|
758
|
-
for (const handler of typeHandlers) {
|
|
759
|
-
try {
|
|
760
|
-
handler(event);
|
|
761
|
-
} catch {
|
|
762
|
-
}
|
|
763
|
-
}
|
|
764
|
-
}
|
|
765
|
-
for (const handler of this.globalHandlers) {
|
|
766
|
-
try {
|
|
767
|
-
handler(event);
|
|
768
|
-
} catch {
|
|
769
|
-
}
|
|
770
|
-
}
|
|
771
|
-
}
|
|
772
|
-
/** Subscribe to a specific event type */
|
|
773
|
-
on(type, handler) {
|
|
774
|
-
if (!this.handlers.has(type)) {
|
|
775
|
-
this.handlers.set(type, /* @__PURE__ */ new Set());
|
|
776
|
-
}
|
|
777
|
-
this.handlers.get(type).add(handler);
|
|
778
|
-
}
|
|
779
|
-
/** Subscribe to ALL events */
|
|
780
|
-
onAny(handler) {
|
|
781
|
-
this.globalHandlers.add(handler);
|
|
782
|
-
}
|
|
783
|
-
/** Unsubscribe from a specific event type */
|
|
784
|
-
off(type, handler) {
|
|
785
|
-
this.handlers.get(type)?.delete(handler);
|
|
786
|
-
}
|
|
787
|
-
/** Unsubscribe from ALL events */
|
|
788
|
-
offAny(handler) {
|
|
789
|
-
this.globalHandlers.delete(handler);
|
|
790
|
-
}
|
|
791
|
-
/** Remove all listeners */
|
|
792
|
-
clear() {
|
|
793
|
-
this.handlers.clear();
|
|
794
|
-
this.globalHandlers.clear();
|
|
795
|
-
}
|
|
796
|
-
};
|
|
797
|
-
orgBus = new StateBus();
|
|
798
|
-
}
|
|
799
|
-
});
|
|
800
|
-
|
|
801
|
-
// src/lib/session-registry.ts
|
|
802
|
-
import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, mkdirSync as mkdirSync2, existsSync as existsSync5 } from "fs";
|
|
803
|
-
import path6 from "path";
|
|
804
|
-
import os5 from "os";
|
|
805
738
|
function registerSession(entry) {
|
|
806
|
-
const dir =
|
|
739
|
+
const dir = path5.dirname(REGISTRY_PATH);
|
|
807
740
|
if (!existsSync5(dir)) {
|
|
808
741
|
mkdirSync2(dir, { recursive: true });
|
|
809
742
|
}
|
|
@@ -818,7 +751,7 @@ function registerSession(entry) {
|
|
|
818
751
|
}
|
|
819
752
|
function listSessions() {
|
|
820
753
|
try {
|
|
821
|
-
const raw =
|
|
754
|
+
const raw = readFileSync4(REGISTRY_PATH, "utf8");
|
|
822
755
|
return JSON.parse(raw);
|
|
823
756
|
} catch {
|
|
824
757
|
return [];
|
|
@@ -828,7 +761,7 @@ var REGISTRY_PATH;
|
|
|
828
761
|
var init_session_registry = __esm({
|
|
829
762
|
"src/lib/session-registry.ts"() {
|
|
830
763
|
"use strict";
|
|
831
|
-
REGISTRY_PATH =
|
|
764
|
+
REGISTRY_PATH = path5.join(os4.homedir(), ".exe-os", "session-registry.json");
|
|
832
765
|
}
|
|
833
766
|
});
|
|
834
767
|
|
|
@@ -1089,17 +1022,17 @@ __export(intercom_queue_exports, {
|
|
|
1089
1022
|
queueIntercom: () => queueIntercom,
|
|
1090
1023
|
readQueue: () => readQueue
|
|
1091
1024
|
});
|
|
1092
|
-
import { readFileSync as
|
|
1093
|
-
import
|
|
1094
|
-
import
|
|
1025
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, renameSync as renameSync3, existsSync as existsSync6, mkdirSync as mkdirSync3 } from "fs";
|
|
1026
|
+
import path6 from "path";
|
|
1027
|
+
import os5 from "os";
|
|
1095
1028
|
function ensureDir() {
|
|
1096
|
-
const dir =
|
|
1029
|
+
const dir = path6.dirname(QUEUE_PATH);
|
|
1097
1030
|
if (!existsSync6(dir)) mkdirSync3(dir, { recursive: true });
|
|
1098
1031
|
}
|
|
1099
1032
|
function readQueue() {
|
|
1100
1033
|
try {
|
|
1101
1034
|
if (!existsSync6(QUEUE_PATH)) return [];
|
|
1102
|
-
return JSON.parse(
|
|
1035
|
+
return JSON.parse(readFileSync5(QUEUE_PATH, "utf8"));
|
|
1103
1036
|
} catch {
|
|
1104
1037
|
return [];
|
|
1105
1038
|
}
|
|
@@ -1199,26 +1132,29 @@ var QUEUE_PATH, MAX_RETRIES, TTL_MS, INTERCOM_LOG;
|
|
|
1199
1132
|
var init_intercom_queue = __esm({
|
|
1200
1133
|
"src/lib/intercom-queue.ts"() {
|
|
1201
1134
|
"use strict";
|
|
1202
|
-
QUEUE_PATH =
|
|
1135
|
+
QUEUE_PATH = path6.join(os5.homedir(), ".exe-os", "intercom-queue.json");
|
|
1203
1136
|
MAX_RETRIES = 5;
|
|
1204
1137
|
TTL_MS = 60 * 60 * 1e3;
|
|
1205
|
-
INTERCOM_LOG =
|
|
1138
|
+
INTERCOM_LOG = path6.join(os5.homedir(), ".exe-os", "intercom.log");
|
|
1206
1139
|
}
|
|
1207
1140
|
});
|
|
1208
1141
|
|
|
1209
1142
|
// src/lib/license.ts
|
|
1210
|
-
import { readFileSync as
|
|
1143
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync5, existsSync as existsSync7, mkdirSync as mkdirSync4 } from "fs";
|
|
1211
1144
|
import { randomUUID } from "crypto";
|
|
1212
|
-
import
|
|
1145
|
+
import { createRequire as createRequire2 } from "module";
|
|
1146
|
+
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
1147
|
+
import os6 from "os";
|
|
1148
|
+
import path7 from "path";
|
|
1213
1149
|
import { jwtVerify, importSPKI } from "jose";
|
|
1214
1150
|
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, PLAN_LIMITS;
|
|
1215
1151
|
var init_license = __esm({
|
|
1216
1152
|
"src/lib/license.ts"() {
|
|
1217
1153
|
"use strict";
|
|
1218
1154
|
init_config();
|
|
1219
|
-
LICENSE_PATH =
|
|
1220
|
-
CACHE_PATH =
|
|
1221
|
-
DEVICE_ID_PATH =
|
|
1155
|
+
LICENSE_PATH = path7.join(EXE_AI_DIR, "license.key");
|
|
1156
|
+
CACHE_PATH = path7.join(EXE_AI_DIR, "license-cache.json");
|
|
1157
|
+
DEVICE_ID_PATH = path7.join(EXE_AI_DIR, "device-id");
|
|
1222
1158
|
PLAN_LIMITS = {
|
|
1223
1159
|
free: { devices: 1, employees: 1, memories: 5e3 },
|
|
1224
1160
|
pro: { devices: 3, employees: 5, memories: 1e5 },
|
|
@@ -1230,12 +1166,12 @@ var init_license = __esm({
|
|
|
1230
1166
|
});
|
|
1231
1167
|
|
|
1232
1168
|
// src/lib/plan-limits.ts
|
|
1233
|
-
import { readFileSync as
|
|
1234
|
-
import
|
|
1169
|
+
import { readFileSync as readFileSync7, existsSync as existsSync8 } from "fs";
|
|
1170
|
+
import path8 from "path";
|
|
1235
1171
|
function getLicenseSync() {
|
|
1236
1172
|
try {
|
|
1237
1173
|
if (!existsSync8(CACHE_PATH2)) return freeLicense();
|
|
1238
|
-
const raw = JSON.parse(
|
|
1174
|
+
const raw = JSON.parse(readFileSync7(CACHE_PATH2, "utf8"));
|
|
1239
1175
|
if (!raw.token || typeof raw.token !== "string") return freeLicense();
|
|
1240
1176
|
const parts = raw.token.split(".");
|
|
1241
1177
|
if (parts.length !== 3) return freeLicense();
|
|
@@ -1274,7 +1210,7 @@ function assertEmployeeLimitSync(rosterPath) {
|
|
|
1274
1210
|
let count = 0;
|
|
1275
1211
|
try {
|
|
1276
1212
|
if (existsSync8(filePath)) {
|
|
1277
|
-
const raw =
|
|
1213
|
+
const raw = readFileSync7(filePath, "utf8");
|
|
1278
1214
|
const employees = JSON.parse(raw);
|
|
1279
1215
|
count = Array.isArray(employees) ? employees.length : 0;
|
|
1280
1216
|
}
|
|
@@ -1303,12 +1239,12 @@ var init_plan_limits = __esm({
|
|
|
1303
1239
|
this.name = "PlanLimitError";
|
|
1304
1240
|
}
|
|
1305
1241
|
};
|
|
1306
|
-
CACHE_PATH2 =
|
|
1242
|
+
CACHE_PATH2 = path8.join(EXE_AI_DIR, "license-cache.json");
|
|
1307
1243
|
}
|
|
1308
1244
|
});
|
|
1309
1245
|
|
|
1310
1246
|
// src/lib/session-kill-telemetry.ts
|
|
1311
|
-
import
|
|
1247
|
+
import crypto from "crypto";
|
|
1312
1248
|
async function recordSessionKill(input) {
|
|
1313
1249
|
try {
|
|
1314
1250
|
const client = getClient();
|
|
@@ -1318,7 +1254,7 @@ async function recordSessionKill(input) {
|
|
|
1318
1254
|
ticks_idle, estimated_tokens_saved)
|
|
1319
1255
|
VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
|
1320
1256
|
args: [
|
|
1321
|
-
|
|
1257
|
+
crypto.randomUUID(),
|
|
1322
1258
|
input.sessionName,
|
|
1323
1259
|
input.agentId,
|
|
1324
1260
|
(/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -1641,6 +1577,7 @@ __export(tmux_routing_exports, {
|
|
|
1641
1577
|
isEmployeeAlive: () => isEmployeeAlive,
|
|
1642
1578
|
isExeSession: () => isExeSession,
|
|
1643
1579
|
isSessionBusy: () => isSessionBusy,
|
|
1580
|
+
notifyCoordinatorTaskCompletion: () => notifyCoordinatorTaskCompletion,
|
|
1644
1581
|
notifyParentExe: () => notifyParentExe,
|
|
1645
1582
|
parseParentExe: () => parseParentExe,
|
|
1646
1583
|
registerParentExe: () => registerParentExe,
|
|
@@ -1651,13 +1588,13 @@ __export(tmux_routing_exports, {
|
|
|
1651
1588
|
verifyPaneAtCapacity: () => verifyPaneAtCapacity
|
|
1652
1589
|
});
|
|
1653
1590
|
import { execFileSync as execFileSync2, execSync as execSync4 } from "child_process";
|
|
1654
|
-
import { readFileSync as
|
|
1655
|
-
import
|
|
1591
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, existsSync as existsSync9, appendFileSync, readdirSync } from "fs";
|
|
1592
|
+
import path9 from "path";
|
|
1656
1593
|
import os7 from "os";
|
|
1657
1594
|
import { fileURLToPath } from "url";
|
|
1658
|
-
import { unlinkSync as
|
|
1595
|
+
import { unlinkSync as unlinkSync2 } from "fs";
|
|
1659
1596
|
function spawnLockPath(sessionName) {
|
|
1660
|
-
return
|
|
1597
|
+
return path9.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
|
|
1661
1598
|
}
|
|
1662
1599
|
function isProcessAlive(pid) {
|
|
1663
1600
|
try {
|
|
@@ -1674,7 +1611,7 @@ function acquireSpawnLock(sessionName) {
|
|
|
1674
1611
|
const lockFile = spawnLockPath(sessionName);
|
|
1675
1612
|
if (existsSync9(lockFile)) {
|
|
1676
1613
|
try {
|
|
1677
|
-
const lock = JSON.parse(
|
|
1614
|
+
const lock = JSON.parse(readFileSync8(lockFile, "utf8"));
|
|
1678
1615
|
const age = Date.now() - lock.timestamp;
|
|
1679
1616
|
if (isProcessAlive(lock.pid) && age < 6e4) {
|
|
1680
1617
|
return false;
|
|
@@ -1687,15 +1624,15 @@ function acquireSpawnLock(sessionName) {
|
|
|
1687
1624
|
}
|
|
1688
1625
|
function releaseSpawnLock(sessionName) {
|
|
1689
1626
|
try {
|
|
1690
|
-
|
|
1627
|
+
unlinkSync2(spawnLockPath(sessionName));
|
|
1691
1628
|
} catch {
|
|
1692
1629
|
}
|
|
1693
1630
|
}
|
|
1694
1631
|
function resolveBehaviorsExporterScript() {
|
|
1695
1632
|
try {
|
|
1696
1633
|
const thisFile = fileURLToPath(import.meta.url);
|
|
1697
|
-
const scriptPath =
|
|
1698
|
-
|
|
1634
|
+
const scriptPath = path9.join(
|
|
1635
|
+
path9.dirname(thisFile),
|
|
1699
1636
|
"..",
|
|
1700
1637
|
"bin",
|
|
1701
1638
|
"exe-export-behaviors.js"
|
|
@@ -1770,7 +1707,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
|
1770
1707
|
mkdirSync5(SESSION_CACHE, { recursive: true });
|
|
1771
1708
|
}
|
|
1772
1709
|
const rootExe = extractRootExe(parentExe) ?? parentExe;
|
|
1773
|
-
const filePath =
|
|
1710
|
+
const filePath = path9.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
|
|
1774
1711
|
writeFileSync6(filePath, JSON.stringify({
|
|
1775
1712
|
parentExe: rootExe,
|
|
1776
1713
|
dispatchedBy: dispatchedBy || rootExe,
|
|
@@ -1779,7 +1716,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
|
1779
1716
|
}
|
|
1780
1717
|
function getParentExe(sessionKey) {
|
|
1781
1718
|
try {
|
|
1782
|
-
const data = JSON.parse(
|
|
1719
|
+
const data = JSON.parse(readFileSync8(path9.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
1783
1720
|
return data.parentExe || null;
|
|
1784
1721
|
} catch {
|
|
1785
1722
|
return null;
|
|
@@ -1787,8 +1724,8 @@ function getParentExe(sessionKey) {
|
|
|
1787
1724
|
}
|
|
1788
1725
|
function getDispatchedBy(sessionKey) {
|
|
1789
1726
|
try {
|
|
1790
|
-
const data = JSON.parse(
|
|
1791
|
-
|
|
1727
|
+
const data = JSON.parse(readFileSync8(
|
|
1728
|
+
path9.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
|
|
1792
1729
|
"utf8"
|
|
1793
1730
|
));
|
|
1794
1731
|
return data.dispatchedBy ?? data.parentExe ?? null;
|
|
@@ -1859,7 +1796,7 @@ async function verifyPaneAtCapacity(sessionName) {
|
|
|
1859
1796
|
function readDebounceState() {
|
|
1860
1797
|
try {
|
|
1861
1798
|
if (!existsSync9(DEBOUNCE_FILE)) return {};
|
|
1862
|
-
const raw = JSON.parse(
|
|
1799
|
+
const raw = JSON.parse(readFileSync8(DEBOUNCE_FILE, "utf8"));
|
|
1863
1800
|
const state = {};
|
|
1864
1801
|
for (const [key, val] of Object.entries(raw)) {
|
|
1865
1802
|
if (typeof val === "number") {
|
|
@@ -1974,7 +1911,7 @@ function sendIntercom(targetSession) {
|
|
|
1974
1911
|
try {
|
|
1975
1912
|
const rawAgent = targetSession.split("-")[0] ?? targetSession;
|
|
1976
1913
|
const agent = baseAgentName(rawAgent);
|
|
1977
|
-
const markerPath =
|
|
1914
|
+
const markerPath = path9.join(SESSION_CACHE, `current-task-${agent}.json`);
|
|
1978
1915
|
if (existsSync9(markerPath)) {
|
|
1979
1916
|
logIntercom(`SKIP \u2192 ${targetSession} (has in_progress task marker \u2014 will auto-chain)`);
|
|
1980
1917
|
return "debounced";
|
|
@@ -1984,9 +1921,9 @@ function sendIntercom(targetSession) {
|
|
|
1984
1921
|
try {
|
|
1985
1922
|
const rawAgent = targetSession.split("-")[0] ?? targetSession;
|
|
1986
1923
|
const agent = baseAgentName(rawAgent);
|
|
1987
|
-
const taskDir =
|
|
1924
|
+
const taskDir = path9.join(process.cwd(), "exe", agent);
|
|
1988
1925
|
if (existsSync9(taskDir)) {
|
|
1989
|
-
const files =
|
|
1926
|
+
const files = readdirSync(taskDir).filter(
|
|
1990
1927
|
(f) => f.endsWith(".md") && f !== "DONE.txt"
|
|
1991
1928
|
);
|
|
1992
1929
|
if (files.length === 0) {
|
|
@@ -2045,6 +1982,21 @@ function notifyParentExe(sessionKey) {
|
|
|
2045
1982
|
}
|
|
2046
1983
|
return true;
|
|
2047
1984
|
}
|
|
1985
|
+
function notifyCoordinatorTaskCompletion(coordinatorSession, agentName, taskTitle) {
|
|
1986
|
+
const transport = getTransport();
|
|
1987
|
+
try {
|
|
1988
|
+
const sessions = transport.listSessions();
|
|
1989
|
+
if (!sessions.includes(coordinatorSession)) return false;
|
|
1990
|
+
execSync4(
|
|
1991
|
+
`tmux send-keys -t ${JSON.stringify(coordinatorSession)} '/exe-intercom' Enter`,
|
|
1992
|
+
{ timeout: 3e3 }
|
|
1993
|
+
);
|
|
1994
|
+
logIntercom(`COMPLETION \u2192 ${coordinatorSession} (${agentName} completed "${taskTitle.slice(0, 50)}")`);
|
|
1995
|
+
return true;
|
|
1996
|
+
} catch {
|
|
1997
|
+
return false;
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
2048
2000
|
function ensureEmployee(employeeName, exeSession, projectDir, opts) {
|
|
2049
2001
|
if (isCoordinatorName(employeeName)) {
|
|
2050
2002
|
return { status: "failed", sessionName: "", error: "The COO is not a dispatchable employee" };
|
|
@@ -2118,8 +2070,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
2118
2070
|
const transport = getTransport();
|
|
2119
2071
|
const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
|
|
2120
2072
|
const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
|
|
2121
|
-
const logDir =
|
|
2122
|
-
const logFile =
|
|
2073
|
+
const logDir = path9.join(os7.homedir(), ".exe-os", "session-logs");
|
|
2074
|
+
const logFile = path9.join(logDir, `${instanceLabel}-${Date.now()}.log`);
|
|
2123
2075
|
if (!existsSync9(logDir)) {
|
|
2124
2076
|
mkdirSync5(logDir, { recursive: true });
|
|
2125
2077
|
}
|
|
@@ -2127,17 +2079,17 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
2127
2079
|
let cleanupSuffix = "";
|
|
2128
2080
|
try {
|
|
2129
2081
|
const thisFile = fileURLToPath(import.meta.url);
|
|
2130
|
-
const cleanupScript =
|
|
2082
|
+
const cleanupScript = path9.join(path9.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
|
|
2131
2083
|
if (existsSync9(cleanupScript)) {
|
|
2132
2084
|
cleanupSuffix = `; ${process.execPath} "${cleanupScript}" "${employeeName}" "${exeSession}"`;
|
|
2133
2085
|
}
|
|
2134
2086
|
} catch {
|
|
2135
2087
|
}
|
|
2136
2088
|
try {
|
|
2137
|
-
const claudeJsonPath =
|
|
2089
|
+
const claudeJsonPath = path9.join(os7.homedir(), ".claude.json");
|
|
2138
2090
|
let claudeJson = {};
|
|
2139
2091
|
try {
|
|
2140
|
-
claudeJson = JSON.parse(
|
|
2092
|
+
claudeJson = JSON.parse(readFileSync8(claudeJsonPath, "utf8"));
|
|
2141
2093
|
} catch {
|
|
2142
2094
|
}
|
|
2143
2095
|
if (!claudeJson.projects) claudeJson.projects = {};
|
|
@@ -2149,13 +2101,13 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
2149
2101
|
} catch {
|
|
2150
2102
|
}
|
|
2151
2103
|
try {
|
|
2152
|
-
const settingsDir =
|
|
2104
|
+
const settingsDir = path9.join(os7.homedir(), ".claude", "projects");
|
|
2153
2105
|
const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
|
|
2154
|
-
const projSettingsDir =
|
|
2155
|
-
const settingsPath =
|
|
2106
|
+
const projSettingsDir = path9.join(settingsDir, normalizedKey);
|
|
2107
|
+
const settingsPath = path9.join(projSettingsDir, "settings.json");
|
|
2156
2108
|
let settings = {};
|
|
2157
2109
|
try {
|
|
2158
|
-
settings = JSON.parse(
|
|
2110
|
+
settings = JSON.parse(readFileSync8(settingsPath, "utf8"));
|
|
2159
2111
|
} catch {
|
|
2160
2112
|
}
|
|
2161
2113
|
const perms = settings.permissions ?? {};
|
|
@@ -2199,7 +2151,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
2199
2151
|
let behaviorsFlag = "";
|
|
2200
2152
|
let legacyFallbackWarned = false;
|
|
2201
2153
|
if (!useExeAgent && !useBinSymlink) {
|
|
2202
|
-
const identityPath2 =
|
|
2154
|
+
const identityPath2 = path9.join(
|
|
2203
2155
|
os7.homedir(),
|
|
2204
2156
|
".exe-os",
|
|
2205
2157
|
"identity",
|
|
@@ -2215,7 +2167,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
2215
2167
|
}
|
|
2216
2168
|
const behaviorsFile = exportBehaviorsSync(
|
|
2217
2169
|
employeeName,
|
|
2218
|
-
|
|
2170
|
+
path9.basename(spawnCwd),
|
|
2219
2171
|
sessionName
|
|
2220
2172
|
);
|
|
2221
2173
|
if (behaviorsFile) {
|
|
@@ -2230,9 +2182,9 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
2230
2182
|
}
|
|
2231
2183
|
let sessionContextFlag = "";
|
|
2232
2184
|
try {
|
|
2233
|
-
const ctxDir =
|
|
2185
|
+
const ctxDir = path9.join(os7.homedir(), ".exe-os", "session-cache");
|
|
2234
2186
|
mkdirSync5(ctxDir, { recursive: true });
|
|
2235
|
-
const ctxFile =
|
|
2187
|
+
const ctxFile = path9.join(ctxDir, `session-context-${sessionName}.md`);
|
|
2236
2188
|
const ctxContent = [
|
|
2237
2189
|
`## Session Context`,
|
|
2238
2190
|
`You are running in tmux session: ${sessionName}.`,
|
|
@@ -2316,7 +2268,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
2316
2268
|
transport.pipeLog(sessionName, logFile);
|
|
2317
2269
|
try {
|
|
2318
2270
|
const mySession = getMySession();
|
|
2319
|
-
const dispatchInfo =
|
|
2271
|
+
const dispatchInfo = path9.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
|
|
2320
2272
|
writeFileSync6(dispatchInfo, JSON.stringify({
|
|
2321
2273
|
dispatchedBy: mySession,
|
|
2322
2274
|
rootExe: exeSession,
|
|
@@ -2391,15 +2343,15 @@ var init_tmux_routing = __esm({
|
|
|
2391
2343
|
init_intercom_queue();
|
|
2392
2344
|
init_plan_limits();
|
|
2393
2345
|
init_employees();
|
|
2394
|
-
SPAWN_LOCK_DIR =
|
|
2395
|
-
SESSION_CACHE =
|
|
2346
|
+
SPAWN_LOCK_DIR = path9.join(os7.homedir(), ".exe-os", "spawn-locks");
|
|
2347
|
+
SESSION_CACHE = path9.join(os7.homedir(), ".exe-os", "session-cache");
|
|
2396
2348
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
2397
2349
|
VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
|
|
2398
2350
|
VERIFY_PANE_LINES = 200;
|
|
2399
2351
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
2400
2352
|
CODEX_DEBOUNCE_MS = 12e4;
|
|
2401
|
-
INTERCOM_LOG2 =
|
|
2402
|
-
DEBOUNCE_FILE =
|
|
2353
|
+
INTERCOM_LOG2 = path9.join(os7.homedir(), ".exe-os", "intercom.log");
|
|
2354
|
+
DEBOUNCE_FILE = path9.join(SESSION_CACHE, "intercom-debounce.json");
|
|
2403
2355
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
2404
2356
|
BUSY_PATTERN = /[✻✽✶✳·].*…|Running…|• Working|• Ran |• Explored|• Called|esc to interrupt/;
|
|
2405
2357
|
}
|
|
@@ -2422,6 +2374,15 @@ function sessionScopeFilter(sessionScope, tableAlias) {
|
|
|
2422
2374
|
args: [scope]
|
|
2423
2375
|
};
|
|
2424
2376
|
}
|
|
2377
|
+
function strictSessionScopeFilter(sessionScope, tableAlias) {
|
|
2378
|
+
const scope = sessionScope !== void 0 ? sessionScope : getCurrentSessionScope();
|
|
2379
|
+
if (!scope) return { sql: "", args: [] };
|
|
2380
|
+
const col = tableAlias ? `${tableAlias}.session_scope` : "session_scope";
|
|
2381
|
+
return {
|
|
2382
|
+
sql: ` AND ${col} = ?`,
|
|
2383
|
+
args: [scope]
|
|
2384
|
+
};
|
|
2385
|
+
}
|
|
2425
2386
|
var init_task_scope = __esm({
|
|
2426
2387
|
"src/lib/task-scope.ts"() {
|
|
2427
2388
|
"use strict";
|
|
@@ -2429,13 +2390,125 @@ var init_task_scope = __esm({
|
|
|
2429
2390
|
}
|
|
2430
2391
|
});
|
|
2431
2392
|
|
|
2393
|
+
// src/lib/notifications.ts
|
|
2394
|
+
import crypto2 from "crypto";
|
|
2395
|
+
import path10 from "path";
|
|
2396
|
+
import os8 from "os";
|
|
2397
|
+
import {
|
|
2398
|
+
readFileSync as readFileSync9,
|
|
2399
|
+
readdirSync as readdirSync2,
|
|
2400
|
+
unlinkSync as unlinkSync3,
|
|
2401
|
+
existsSync as existsSync10,
|
|
2402
|
+
rmdirSync
|
|
2403
|
+
} from "fs";
|
|
2404
|
+
async function writeNotification(notification) {
|
|
2405
|
+
try {
|
|
2406
|
+
const client = getClient();
|
|
2407
|
+
const id = crypto2.randomUUID();
|
|
2408
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2409
|
+
const sessionScope = notification.sessionScope === void 0 ? getCurrentSessionScope() : notification.sessionScope;
|
|
2410
|
+
await client.execute({
|
|
2411
|
+
sql: `INSERT INTO notifications (id, agent_id, agent_role, event, project, summary, task_file, session_scope, read, created_at)
|
|
2412
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, 0, ?)`,
|
|
2413
|
+
args: [
|
|
2414
|
+
id,
|
|
2415
|
+
notification.agentId,
|
|
2416
|
+
notification.agentRole,
|
|
2417
|
+
notification.event,
|
|
2418
|
+
notification.project,
|
|
2419
|
+
notification.summary,
|
|
2420
|
+
notification.taskFile ?? null,
|
|
2421
|
+
sessionScope,
|
|
2422
|
+
now
|
|
2423
|
+
]
|
|
2424
|
+
});
|
|
2425
|
+
} catch (err) {
|
|
2426
|
+
process.stderr.write(`[notifications] WRITE FAILED: ${err instanceof Error ? err.message : String(err)}
|
|
2427
|
+
`);
|
|
2428
|
+
}
|
|
2429
|
+
}
|
|
2430
|
+
async function markAsReadByTaskFile(taskFile, sessionScope) {
|
|
2431
|
+
try {
|
|
2432
|
+
const client = getClient();
|
|
2433
|
+
const scope = strictSessionScopeFilter(sessionScope);
|
|
2434
|
+
await client.execute({
|
|
2435
|
+
sql: `UPDATE notifications SET read = 1
|
|
2436
|
+
WHERE task_file = ? AND read = 0${scope.sql}`,
|
|
2437
|
+
args: [taskFile, ...scope.args]
|
|
2438
|
+
});
|
|
2439
|
+
} catch {
|
|
2440
|
+
}
|
|
2441
|
+
}
|
|
2442
|
+
var init_notifications = __esm({
|
|
2443
|
+
"src/lib/notifications.ts"() {
|
|
2444
|
+
"use strict";
|
|
2445
|
+
init_database();
|
|
2446
|
+
init_task_scope();
|
|
2447
|
+
}
|
|
2448
|
+
});
|
|
2449
|
+
|
|
2450
|
+
// src/lib/state-bus.ts
|
|
2451
|
+
var StateBus, orgBus;
|
|
2452
|
+
var init_state_bus = __esm({
|
|
2453
|
+
"src/lib/state-bus.ts"() {
|
|
2454
|
+
"use strict";
|
|
2455
|
+
StateBus = class {
|
|
2456
|
+
handlers = /* @__PURE__ */ new Map();
|
|
2457
|
+
globalHandlers = /* @__PURE__ */ new Set();
|
|
2458
|
+
/** Emit an event to all subscribers */
|
|
2459
|
+
emit(event) {
|
|
2460
|
+
const typeHandlers = this.handlers.get(event.type);
|
|
2461
|
+
if (typeHandlers) {
|
|
2462
|
+
for (const handler of typeHandlers) {
|
|
2463
|
+
try {
|
|
2464
|
+
handler(event);
|
|
2465
|
+
} catch {
|
|
2466
|
+
}
|
|
2467
|
+
}
|
|
2468
|
+
}
|
|
2469
|
+
for (const handler of this.globalHandlers) {
|
|
2470
|
+
try {
|
|
2471
|
+
handler(event);
|
|
2472
|
+
} catch {
|
|
2473
|
+
}
|
|
2474
|
+
}
|
|
2475
|
+
}
|
|
2476
|
+
/** Subscribe to a specific event type */
|
|
2477
|
+
on(type, handler) {
|
|
2478
|
+
if (!this.handlers.has(type)) {
|
|
2479
|
+
this.handlers.set(type, /* @__PURE__ */ new Set());
|
|
2480
|
+
}
|
|
2481
|
+
this.handlers.get(type).add(handler);
|
|
2482
|
+
}
|
|
2483
|
+
/** Subscribe to ALL events */
|
|
2484
|
+
onAny(handler) {
|
|
2485
|
+
this.globalHandlers.add(handler);
|
|
2486
|
+
}
|
|
2487
|
+
/** Unsubscribe from a specific event type */
|
|
2488
|
+
off(type, handler) {
|
|
2489
|
+
this.handlers.get(type)?.delete(handler);
|
|
2490
|
+
}
|
|
2491
|
+
/** Unsubscribe from ALL events */
|
|
2492
|
+
offAny(handler) {
|
|
2493
|
+
this.globalHandlers.delete(handler);
|
|
2494
|
+
}
|
|
2495
|
+
/** Remove all listeners */
|
|
2496
|
+
clear() {
|
|
2497
|
+
this.handlers.clear();
|
|
2498
|
+
this.globalHandlers.clear();
|
|
2499
|
+
}
|
|
2500
|
+
};
|
|
2501
|
+
orgBus = new StateBus();
|
|
2502
|
+
}
|
|
2503
|
+
});
|
|
2504
|
+
|
|
2432
2505
|
// src/lib/tasks-crud.ts
|
|
2433
2506
|
import crypto3 from "crypto";
|
|
2434
2507
|
import path11 from "path";
|
|
2435
|
-
import
|
|
2508
|
+
import os9 from "os";
|
|
2436
2509
|
import { execSync as execSync5 } from "child_process";
|
|
2437
2510
|
import { mkdir as mkdir3, writeFile as writeFile3, appendFile } from "fs/promises";
|
|
2438
|
-
import { existsSync as
|
|
2511
|
+
import { existsSync as existsSync11, readFileSync as readFileSync10 } from "fs";
|
|
2439
2512
|
async function writeCheckpoint(input) {
|
|
2440
2513
|
const client = getClient();
|
|
2441
2514
|
const row = await resolveTask(client, input.taskId);
|
|
@@ -2647,13 +2720,19 @@ ${laneWarning}` : laneWarning;
|
|
|
2647
2720
|
});
|
|
2648
2721
|
if (input.baseDir) {
|
|
2649
2722
|
try {
|
|
2650
|
-
const EXE_OS_DIR = path11.join(
|
|
2723
|
+
const EXE_OS_DIR = path11.join(os9.homedir(), ".exe-os");
|
|
2651
2724
|
const mdPath = path11.join(EXE_OS_DIR, taskFile);
|
|
2652
2725
|
const mdDir = path11.dirname(mdPath);
|
|
2653
|
-
if (!
|
|
2726
|
+
if (!existsSync11(mdDir)) await mkdir3(mdDir, { recursive: true });
|
|
2654
2727
|
const reviewer = input.reviewer ?? input.assignedBy;
|
|
2655
2728
|
const mdContent = `# ${input.title}
|
|
2656
2729
|
|
|
2730
|
+
## MANDATORY: When done
|
|
2731
|
+
|
|
2732
|
+
You MUST call update_task with status "done" and a result summary when finished.
|
|
2733
|
+
If you skip this, your reviewer will not know you're done and your work won't be reviewed.
|
|
2734
|
+
Do NOT let a failed commit or any error prevent you from calling update_task(done).
|
|
2735
|
+
|
|
2657
2736
|
**ID:** ${id}
|
|
2658
2737
|
**Status:** ${initialStatus}
|
|
2659
2738
|
**Priority:** ${input.priority}
|
|
@@ -2667,12 +2746,6 @@ ${laneWarning}` : laneWarning;
|
|
|
2667
2746
|
## Context
|
|
2668
2747
|
|
|
2669
2748
|
${input.context}
|
|
2670
|
-
|
|
2671
|
-
## MANDATORY: When done
|
|
2672
|
-
|
|
2673
|
-
You MUST call update_task with status "done" and a result summary when finished.
|
|
2674
|
-
If you skip this, your reviewer will not know you're done and your work won't be reviewed.
|
|
2675
|
-
Do NOT let a failed commit or any error prevent you from calling update_task(done).
|
|
2676
2749
|
`;
|
|
2677
2750
|
await writeFile3(mdPath, mdContent, "utf-8");
|
|
2678
2751
|
} catch (err) {
|
|
@@ -2921,7 +2994,7 @@ ${input.result}` : `\u26A0\uFE0F ${warning}`;
|
|
|
2921
2994
|
await client.execute("PRAGMA wal_checkpoint(PASSIVE)");
|
|
2922
2995
|
} catch {
|
|
2923
2996
|
}
|
|
2924
|
-
if (input.status === "done" || input.status === "cancelled") {
|
|
2997
|
+
if (input.status === "done" || input.status === "cancelled" || input.status === "closed") {
|
|
2925
2998
|
try {
|
|
2926
2999
|
const { clearQueueForAgent: clearQueueForAgent2 } = await Promise.resolve().then(() => (init_intercom_queue(), intercom_queue_exports));
|
|
2927
3000
|
clearQueueForAgent2(String(row.assigned_to));
|
|
@@ -2952,7 +3025,7 @@ async function deleteTaskCore(taskId, _baseDir) {
|
|
|
2952
3025
|
async function ensureArchitectureDoc(baseDir, projectName) {
|
|
2953
3026
|
const archPath = path11.join(baseDir, "exe", "ARCHITECTURE.md");
|
|
2954
3027
|
try {
|
|
2955
|
-
if (
|
|
3028
|
+
if (existsSync11(archPath)) return;
|
|
2956
3029
|
const template = [
|
|
2957
3030
|
`# ${projectName} \u2014 System Architecture`,
|
|
2958
3031
|
"",
|
|
@@ -2987,7 +3060,7 @@ async function ensureArchitectureDoc(baseDir, projectName) {
|
|
|
2987
3060
|
async function ensureGitignoreExe(baseDir) {
|
|
2988
3061
|
const gitignorePath = path11.join(baseDir, ".gitignore");
|
|
2989
3062
|
try {
|
|
2990
|
-
if (
|
|
3063
|
+
if (existsSync11(gitignorePath)) {
|
|
2991
3064
|
const content = readFileSync10(gitignorePath, "utf-8");
|
|
2992
3065
|
if (/^\/?exe\/?$/m.test(content)) return;
|
|
2993
3066
|
await appendFile(gitignorePath, "\n# Employee task assignments (private)\n/exe/\n");
|
|
@@ -3020,57 +3093,41 @@ var init_tasks_crud = __esm({
|
|
|
3020
3093
|
|
|
3021
3094
|
// src/lib/tasks-review.ts
|
|
3022
3095
|
import path12 from "path";
|
|
3023
|
-
import { existsSync as
|
|
3096
|
+
import { existsSync as existsSync12, readdirSync as readdirSync3, unlinkSync as unlinkSync4 } from "fs";
|
|
3024
3097
|
async function countPendingReviews(sessionScope) {
|
|
3025
3098
|
const client = getClient();
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
args: [sessionScope]
|
|
3030
|
-
});
|
|
3031
|
-
return Number(result2.rows[0]?.cnt) || 0;
|
|
3032
|
-
}
|
|
3099
|
+
const scope = strictSessionScopeFilter(
|
|
3100
|
+
sessionScope === void 0 ? getCurrentSessionScope() : sessionScope
|
|
3101
|
+
);
|
|
3033
3102
|
const result = await client.execute({
|
|
3034
|
-
sql:
|
|
3035
|
-
|
|
3103
|
+
sql: `SELECT COUNT(*) as cnt FROM tasks
|
|
3104
|
+
WHERE status = 'needs_review'${scope.sql}`,
|
|
3105
|
+
args: [...scope.args]
|
|
3036
3106
|
});
|
|
3037
3107
|
return Number(result.rows[0]?.cnt) || 0;
|
|
3038
3108
|
}
|
|
3039
3109
|
async function countNewPendingReviewsSince(sinceIso, sessionScope) {
|
|
3040
3110
|
const client = getClient();
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
WHERE status = 'needs_review' AND updated_at > ?
|
|
3045
|
-
AND session_scope = ?`,
|
|
3046
|
-
args: [sinceIso, sessionScope]
|
|
3047
|
-
});
|
|
3048
|
-
return Number(result2.rows[0]?.cnt) || 0;
|
|
3049
|
-
}
|
|
3111
|
+
const scope = strictSessionScopeFilter(
|
|
3112
|
+
sessionScope === void 0 ? getCurrentSessionScope() : sessionScope
|
|
3113
|
+
);
|
|
3050
3114
|
const result = await client.execute({
|
|
3051
3115
|
sql: `SELECT COUNT(*) as cnt FROM tasks
|
|
3052
|
-
WHERE status = 'needs_review' AND updated_at >
|
|
3053
|
-
args: [sinceIso]
|
|
3116
|
+
WHERE status = 'needs_review' AND updated_at > ?${scope.sql}`,
|
|
3117
|
+
args: [sinceIso, ...scope.args]
|
|
3054
3118
|
});
|
|
3055
3119
|
return Number(result.rows[0]?.cnt) || 0;
|
|
3056
3120
|
}
|
|
3057
3121
|
async function listPendingReviews(limit, sessionScope) {
|
|
3058
3122
|
const client = getClient();
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
WHERE status = 'needs_review'
|
|
3063
|
-
AND session_scope = ?
|
|
3064
|
-
ORDER BY updated_at ASC LIMIT ?`,
|
|
3065
|
-
args: [sessionScope, limit]
|
|
3066
|
-
});
|
|
3067
|
-
return result2.rows;
|
|
3068
|
-
}
|
|
3123
|
+
const scope = strictSessionScopeFilter(
|
|
3124
|
+
sessionScope === void 0 ? getCurrentSessionScope() : sessionScope
|
|
3125
|
+
);
|
|
3069
3126
|
const result = await client.execute({
|
|
3070
3127
|
sql: `SELECT title, assigned_to, project_name, updated_at FROM tasks
|
|
3071
|
-
WHERE status = 'needs_review'
|
|
3128
|
+
WHERE status = 'needs_review'${scope.sql}
|
|
3072
3129
|
ORDER BY updated_at ASC LIMIT ?`,
|
|
3073
|
-
args: [limit]
|
|
3130
|
+
args: [...scope.args, limit]
|
|
3074
3131
|
});
|
|
3075
3132
|
return result.rows;
|
|
3076
3133
|
}
|
|
@@ -3082,7 +3139,7 @@ async function cleanupOrphanedReviews() {
|
|
|
3082
3139
|
WHERE status IN ('open', 'needs_review', 'in_progress')
|
|
3083
3140
|
AND assigned_by = 'system'
|
|
3084
3141
|
AND title LIKE 'Review:%'
|
|
3085
|
-
AND parent_task_id IN (SELECT id FROM tasks WHERE status IN ('done', 'cancelled'))`,
|
|
3142
|
+
AND parent_task_id IN (SELECT id FROM tasks WHERE status IN ('done', 'cancelled', 'closed'))`,
|
|
3086
3143
|
args: [now]
|
|
3087
3144
|
});
|
|
3088
3145
|
const r1b = await client.execute({
|
|
@@ -3202,7 +3259,7 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
|
|
|
3202
3259
|
}
|
|
3203
3260
|
try {
|
|
3204
3261
|
const cacheDir = path12.join(EXE_AI_DIR, "session-cache");
|
|
3205
|
-
if (
|
|
3262
|
+
if (existsSync12(cacheDir)) {
|
|
3206
3263
|
for (const f of readdirSync3(cacheDir)) {
|
|
3207
3264
|
if (f.startsWith("review-notified-")) {
|
|
3208
3265
|
unlinkSync4(path12.join(cacheDir, f));
|
|
@@ -3222,6 +3279,7 @@ var init_tasks_review = __esm({
|
|
|
3222
3279
|
init_tmux_routing();
|
|
3223
3280
|
init_session_key();
|
|
3224
3281
|
init_state_bus();
|
|
3282
|
+
init_task_scope();
|
|
3225
3283
|
}
|
|
3226
3284
|
});
|
|
3227
3285
|
|
|
@@ -3278,7 +3336,7 @@ async function checkSubtaskCompletion(parentTaskId, projectName) {
|
|
|
3278
3336
|
const scScope = sessionScopeFilter();
|
|
3279
3337
|
const remaining = await client.execute({
|
|
3280
3338
|
sql: `SELECT COUNT(*) as cnt FROM tasks
|
|
3281
|
-
WHERE parent_task_id = ? AND status NOT IN ('done', 'cancelled')${scScope.sql}`,
|
|
3339
|
+
WHERE parent_task_id = ? AND status NOT IN ('done', 'cancelled', 'closed')${scScope.sql}`,
|
|
3282
3340
|
args: [parentTaskId, ...scScope.args]
|
|
3283
3341
|
});
|
|
3284
3342
|
const cnt = Number(remaining.rows[0]?.cnt ?? 1);
|
|
@@ -3836,7 +3894,7 @@ async function updateTask(input) {
|
|
|
3836
3894
|
if (input.status === "in_progress") {
|
|
3837
3895
|
mkdirSync6(cacheDir, { recursive: true });
|
|
3838
3896
|
writeFileSync7(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
|
|
3839
|
-
} else if (input.status === "done" || input.status === "blocked" || input.status === "cancelled") {
|
|
3897
|
+
} else if (input.status === "done" || input.status === "blocked" || input.status === "cancelled" || input.status === "closed") {
|
|
3840
3898
|
try {
|
|
3841
3899
|
unlinkSync5(cachePath);
|
|
3842
3900
|
} catch {
|
|
@@ -3844,10 +3902,10 @@ async function updateTask(input) {
|
|
|
3844
3902
|
}
|
|
3845
3903
|
} catch {
|
|
3846
3904
|
}
|
|
3847
|
-
if (input.status === "done") {
|
|
3905
|
+
if (input.status === "done" || input.status === "closed") {
|
|
3848
3906
|
await cleanupReviewFile(row, taskFile, input.baseDir);
|
|
3849
3907
|
}
|
|
3850
|
-
if (input.status === "done" || input.status === "cancelled") {
|
|
3908
|
+
if (input.status === "done" || input.status === "cancelled" || input.status === "closed") {
|
|
3851
3909
|
try {
|
|
3852
3910
|
const client = getClient();
|
|
3853
3911
|
const taskTitle = String(row.title);
|
|
@@ -3863,7 +3921,7 @@ async function updateTask(input) {
|
|
|
3863
3921
|
if (!isCoordinatorName(assignedAgent)) {
|
|
3864
3922
|
try {
|
|
3865
3923
|
const draftClient = getClient();
|
|
3866
|
-
if (input.status === "done") {
|
|
3924
|
+
if (input.status === "done" || input.status === "closed") {
|
|
3867
3925
|
await draftClient.execute({
|
|
3868
3926
|
sql: `UPDATE memories SET draft = 0 WHERE agent_id = ? AND draft = 1`,
|
|
3869
3927
|
args: [assignedAgent]
|
|
@@ -3880,7 +3938,7 @@ async function updateTask(input) {
|
|
|
3880
3938
|
try {
|
|
3881
3939
|
const client = getClient();
|
|
3882
3940
|
const cascaded = await client.execute({
|
|
3883
|
-
sql: `UPDATE tasks SET status = '
|
|
3941
|
+
sql: `UPDATE tasks SET status = 'closed', updated_at = ?
|
|
3884
3942
|
WHERE parent_task_id = ? AND status = 'needs_review'`,
|
|
3885
3943
|
args: [now, taskId]
|
|
3886
3944
|
});
|
|
@@ -3893,14 +3951,14 @@ async function updateTask(input) {
|
|
|
3893
3951
|
} catch {
|
|
3894
3952
|
}
|
|
3895
3953
|
}
|
|
3896
|
-
const isTerminal = input.status === "done" || input.status === "needs_review";
|
|
3954
|
+
const isTerminal = input.status === "done" || input.status === "needs_review" || input.status === "closed";
|
|
3897
3955
|
if (isTerminal) {
|
|
3898
3956
|
const isCoordinator = isCoordinatorName(String(row.assigned_to));
|
|
3899
3957
|
if (!isCoordinator) {
|
|
3900
3958
|
notifyTaskDone();
|
|
3901
3959
|
}
|
|
3902
3960
|
await markTaskNotificationsRead(taskFile);
|
|
3903
|
-
if (input.status === "done") {
|
|
3961
|
+
if (input.status === "done" || input.status === "closed") {
|
|
3904
3962
|
try {
|
|
3905
3963
|
await cascadeUnblock(taskId, input.baseDir, now);
|
|
3906
3964
|
} catch {
|
|
@@ -3920,7 +3978,7 @@ async function updateTask(input) {
|
|
|
3920
3978
|
}
|
|
3921
3979
|
}
|
|
3922
3980
|
}
|
|
3923
|
-
if (input.status === "done" && !isCoordinatorName(String(row.assigned_to)) && !process.env.VITEST) {
|
|
3981
|
+
if ((input.status === "done" || input.status === "closed") && !isCoordinatorName(String(row.assigned_to)) && !process.env.VITEST) {
|
|
3924
3982
|
Promise.resolve().then(() => (init_skill_learning(), skill_learning_exports)).then(
|
|
3925
3983
|
({ captureAndLearn: captureAndLearn2 }) => captureAndLearn2({
|
|
3926
3984
|
taskId,
|
|
@@ -4001,12 +4059,12 @@ __export(identity_exports, {
|
|
|
4001
4059
|
listIdentities: () => listIdentities,
|
|
4002
4060
|
updateIdentity: () => updateIdentity
|
|
4003
4061
|
});
|
|
4004
|
-
import { existsSync as
|
|
4062
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync8, readFileSync as readFileSync12, writeFileSync as writeFileSync9 } from "fs";
|
|
4005
4063
|
import { readdirSync as readdirSync5 } from "fs";
|
|
4006
4064
|
import path17 from "path";
|
|
4007
4065
|
import { createHash } from "crypto";
|
|
4008
4066
|
function ensureDir2() {
|
|
4009
|
-
if (!
|
|
4067
|
+
if (!existsSync13(IDENTITY_DIR2)) {
|
|
4010
4068
|
mkdirSync8(IDENTITY_DIR2, { recursive: true });
|
|
4011
4069
|
}
|
|
4012
4070
|
}
|
|
@@ -4052,7 +4110,7 @@ function contentHash(content) {
|
|
|
4052
4110
|
}
|
|
4053
4111
|
function getIdentity(agentId) {
|
|
4054
4112
|
const filePath = identityPath(agentId);
|
|
4055
|
-
if (!
|
|
4113
|
+
if (!existsSync13(filePath)) return null;
|
|
4056
4114
|
const raw = readFileSync12(filePath, "utf-8");
|
|
4057
4115
|
const { frontmatter, body } = parseFrontmatter(raw);
|
|
4058
4116
|
return {
|
|
@@ -4828,10 +4886,10 @@ function registerCreateTask(server) {
|
|
|
4828
4886
|
skipDispatch: true
|
|
4829
4887
|
});
|
|
4830
4888
|
try {
|
|
4831
|
-
const { existsSync:
|
|
4889
|
+
const { existsSync: existsSync14, mkdirSync: mkdirSync9, writeFileSync: writeFileSync10 } = await import("fs");
|
|
4832
4890
|
const { identityPath: identityPath2 } = await Promise.resolve().then(() => (init_identity(), identity_exports));
|
|
4833
4891
|
const idPath = identityPath2(assigned_to);
|
|
4834
|
-
if (!
|
|
4892
|
+
if (!existsSync14(idPath)) {
|
|
4835
4893
|
const { loadEmployees: loadEmployees2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
|
|
4836
4894
|
const employees = await loadEmployees2();
|
|
4837
4895
|
const emp = employees.find((e) => e.name === assigned_to);
|
|
@@ -4840,7 +4898,7 @@ function registerCreateTask(server) {
|
|
|
4840
4898
|
const template = getTemplateForTitle2(emp.role);
|
|
4841
4899
|
if (template) {
|
|
4842
4900
|
const dir = (await import("path")).dirname(idPath);
|
|
4843
|
-
if (!
|
|
4901
|
+
if (!existsSync14(dir)) mkdirSync9(dir, { recursive: true });
|
|
4844
4902
|
writeFileSync10(idPath, template.replace(/^agent_id: \w+/m, `agent_id: ${assigned_to}`), "utf-8");
|
|
4845
4903
|
}
|
|
4846
4904
|
}
|