@askexenow/exe-os 0.9.7 → 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 +953 -105
- package/dist/bin/backfill-responses.js +952 -104
- package/dist/bin/backfill-vectors.js +956 -108
- package/dist/bin/cleanup-stale-review-tasks.js +802 -58
- package/dist/bin/cli.js +2292 -1070
- package/dist/bin/exe-agent-config.js +157 -101
- package/dist/bin/exe-agent.js +55 -29
- package/dist/bin/exe-assign.js +940 -92
- package/dist/bin/exe-boot.js +1424 -442
- package/dist/bin/exe-call.js +240 -141
- package/dist/bin/exe-cloud.js +198 -70
- package/dist/bin/exe-dispatch.js +951 -192
- package/dist/bin/exe-doctor.js +791 -51
- package/dist/bin/exe-export-behaviors.js +790 -42
- package/dist/bin/exe-forget.js +771 -31
- package/dist/bin/exe-gateway.js +1592 -521
- package/dist/bin/exe-heartbeat.js +850 -109
- package/dist/bin/exe-kill.js +783 -35
- package/dist/bin/exe-launch-agent.js +1030 -107
- package/dist/bin/exe-link.js +916 -110
- package/dist/bin/exe-new-employee.js +526 -217
- package/dist/bin/exe-pending-messages.js +1046 -62
- package/dist/bin/exe-pending-notifications.js +1318 -111
- package/dist/bin/exe-pending-reviews.js +1040 -72
- package/dist/bin/exe-rename.js +772 -59
- package/dist/bin/exe-review.js +772 -32
- package/dist/bin/exe-search.js +982 -128
- package/dist/bin/exe-session-cleanup.js +1180 -306
- package/dist/bin/exe-settings.js +185 -105
- package/dist/bin/exe-start-codex.js +886 -132
- package/dist/bin/exe-start-opencode.js +873 -119
- package/dist/bin/exe-status.js +803 -59
- package/dist/bin/exe-team.js +772 -32
- package/dist/bin/git-sweep.js +1046 -223
- package/dist/bin/graph-backfill.js +779 -31
- package/dist/bin/graph-export.js +785 -37
- package/dist/bin/install.js +632 -200
- package/dist/bin/scan-tasks.js +1055 -232
- package/dist/bin/setup.js +1419 -320
- package/dist/bin/shard-migrate.js +783 -35
- package/dist/bin/update.js +138 -49
- package/dist/bin/wiki-sync.js +782 -34
- package/dist/gateway/index.js +1444 -449
- package/dist/hooks/bug-report-worker.js +1141 -269
- package/dist/hooks/codex-stop-task-finalizer.js +4678 -0
- package/dist/hooks/commit-complete.js +1044 -221
- package/dist/hooks/error-recall.js +989 -135
- package/dist/hooks/exe-heartbeat-hook.js +99 -75
- package/dist/hooks/ingest-worker.js +4176 -3226
- package/dist/hooks/ingest.js +920 -168
- package/dist/hooks/instructions-loaded.js +874 -70
- package/dist/hooks/notification.js +860 -56
- package/dist/hooks/post-compact.js +881 -73
- package/dist/hooks/pre-compact.js +1050 -227
- package/dist/hooks/pre-tool-use.js +1084 -159
- package/dist/hooks/prompt-ingest-worker.js +1089 -164
- package/dist/hooks/prompt-submit.js +1469 -515
- package/dist/hooks/response-ingest-worker.js +1104 -179
- package/dist/hooks/session-end.js +1085 -251
- package/dist/hooks/session-start.js +1241 -231
- package/dist/hooks/stop.js +935 -109
- package/dist/hooks/subagent-stop.js +881 -73
- package/dist/hooks/summary-worker.js +1323 -307
- package/dist/index.js +1449 -452
- package/dist/lib/agent-config.js +28 -6
- package/dist/lib/cloud-sync.js +909 -115
- package/dist/lib/config.js +30 -10
- package/dist/lib/consolidation.js +42 -9
- package/dist/lib/database.js +739 -33
- package/dist/lib/db-daemon-client.js +73 -19
- package/dist/lib/db.js +2359 -0
- package/dist/lib/device-registry.js +760 -47
- package/dist/lib/embedder.js +201 -73
- package/dist/lib/employee-templates.js +30 -4
- package/dist/lib/employees.js +290 -86
- package/dist/lib/exe-daemon-client.js +187 -83
- package/dist/lib/exe-daemon.js +1696 -616
- package/dist/lib/hybrid-search.js +982 -128
- package/dist/lib/identity.js +43 -13
- package/dist/lib/license.js +133 -48
- package/dist/lib/messaging.js +167 -80
- package/dist/lib/reminders.js +35 -5
- package/dist/lib/schedules.js +772 -32
- package/dist/lib/skill-learning.js +54 -7
- package/dist/lib/store.js +779 -31
- package/dist/lib/task-router.js +94 -73
- package/dist/lib/tasks.js +298 -225
- package/dist/lib/tmux-routing.js +246 -172
- package/dist/lib/token-spend.js +52 -14
- package/dist/mcp/server.js +2893 -850
- package/dist/mcp/tools/complete-reminder.js +35 -5
- package/dist/mcp/tools/create-reminder.js +35 -5
- package/dist/mcp/tools/create-task.js +507 -323
- package/dist/mcp/tools/deactivate-behavior.js +40 -10
- package/dist/mcp/tools/list-reminders.js +35 -5
- package/dist/mcp/tools/list-tasks.js +277 -104
- package/dist/mcp/tools/send-message.js +129 -56
- package/dist/mcp/tools/update-task.js +1864 -188
- package/dist/runtime/index.js +1083 -259
- package/dist/tui/App.js +1501 -434
- package/package.json +3 -2
|
@@ -26,9 +26,18 @@ var init_db_retry = __esm({
|
|
|
26
26
|
}
|
|
27
27
|
});
|
|
28
28
|
|
|
29
|
+
// src/lib/secure-files.ts
|
|
30
|
+
import { chmodSync, existsSync, mkdirSync } from "fs";
|
|
31
|
+
import { chmod, mkdir } from "fs/promises";
|
|
32
|
+
var init_secure_files = __esm({
|
|
33
|
+
"src/lib/secure-files.ts"() {
|
|
34
|
+
"use strict";
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
29
38
|
// src/lib/config.ts
|
|
30
|
-
import { readFile, writeFile
|
|
31
|
-
import { readFileSync, existsSync, renameSync } from "fs";
|
|
39
|
+
import { readFile, writeFile } from "fs/promises";
|
|
40
|
+
import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
|
|
32
41
|
import path from "path";
|
|
33
42
|
import os from "os";
|
|
34
43
|
function resolveDataDir() {
|
|
@@ -36,7 +45,7 @@ function resolveDataDir() {
|
|
|
36
45
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
37
46
|
const newDir = path.join(os.homedir(), ".exe-os");
|
|
38
47
|
const legacyDir = path.join(os.homedir(), ".exe-mem");
|
|
39
|
-
if (!
|
|
48
|
+
if (!existsSync2(newDir) && existsSync2(legacyDir)) {
|
|
40
49
|
try {
|
|
41
50
|
renameSync(legacyDir, newDir);
|
|
42
51
|
process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
|
|
@@ -51,6 +60,7 @@ var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CON
|
|
|
51
60
|
var init_config = __esm({
|
|
52
61
|
"src/lib/config.ts"() {
|
|
53
62
|
"use strict";
|
|
63
|
+
init_secure_files();
|
|
54
64
|
EXE_AI_DIR = resolveDataDir();
|
|
55
65
|
DB_PATH = path.join(EXE_AI_DIR, "memories.db");
|
|
56
66
|
MODELS_DIR = path.join(EXE_AI_DIR, "models");
|
|
@@ -119,25 +129,72 @@ var init_config = __esm({
|
|
|
119
129
|
|
|
120
130
|
// src/lib/employees.ts
|
|
121
131
|
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
122
|
-
import { existsSync as
|
|
132
|
+
import { existsSync as existsSync3, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
|
|
123
133
|
import { execSync } from "child_process";
|
|
124
134
|
import path2 from "path";
|
|
125
135
|
import os2 from "os";
|
|
126
|
-
|
|
136
|
+
function normalizeRole(role) {
|
|
137
|
+
return (role ?? "").trim().toLowerCase();
|
|
138
|
+
}
|
|
139
|
+
function isCoordinatorRole(role) {
|
|
140
|
+
return normalizeRole(role) === normalizeRole(COORDINATOR_ROLE);
|
|
141
|
+
}
|
|
142
|
+
function getCoordinatorEmployee(employees) {
|
|
143
|
+
return employees.find((e) => isCoordinatorRole(e.role));
|
|
144
|
+
}
|
|
145
|
+
function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
|
|
146
|
+
if (!existsSync3(employeesPath)) return [];
|
|
147
|
+
try {
|
|
148
|
+
return JSON.parse(readFileSync2(employeesPath, "utf-8"));
|
|
149
|
+
} catch {
|
|
150
|
+
return [];
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function getEmployee(employees, name) {
|
|
154
|
+
return employees.find((e) => e.name.toLowerCase() === name.toLowerCase());
|
|
155
|
+
}
|
|
156
|
+
var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, IDENTITY_DIR;
|
|
127
157
|
var init_employees = __esm({
|
|
128
158
|
"src/lib/employees.ts"() {
|
|
129
159
|
"use strict";
|
|
130
160
|
init_config();
|
|
131
161
|
EMPLOYEES_PATH = path2.join(EXE_AI_DIR, "exe-employees.json");
|
|
162
|
+
DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
|
|
163
|
+
COORDINATOR_ROLE = "COO";
|
|
164
|
+
IDENTITY_DIR = path2.join(EXE_AI_DIR, "identity");
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
// src/lib/database-adapter.ts
|
|
169
|
+
import os3 from "os";
|
|
170
|
+
import path3 from "path";
|
|
171
|
+
import { createRequire } from "module";
|
|
172
|
+
import { pathToFileURL } from "url";
|
|
173
|
+
var BOOLEAN_COLUMNS_BY_TABLE, BOOLEAN_COLUMN_NAMES;
|
|
174
|
+
var init_database_adapter = __esm({
|
|
175
|
+
"src/lib/database-adapter.ts"() {
|
|
176
|
+
"use strict";
|
|
177
|
+
BOOLEAN_COLUMNS_BY_TABLE = {
|
|
178
|
+
memories: /* @__PURE__ */ new Set(["has_error", "draft"]),
|
|
179
|
+
behaviors: /* @__PURE__ */ new Set(["active"]),
|
|
180
|
+
notifications: /* @__PURE__ */ new Set(["read"]),
|
|
181
|
+
users: /* @__PURE__ */ new Set(["has_personal_memory"])
|
|
182
|
+
};
|
|
183
|
+
BOOLEAN_COLUMN_NAMES = new Set(
|
|
184
|
+
Object.values(BOOLEAN_COLUMNS_BY_TABLE).flatMap((cols) => [...cols])
|
|
185
|
+
);
|
|
132
186
|
}
|
|
133
187
|
});
|
|
134
188
|
|
|
135
189
|
// src/lib/database.ts
|
|
136
190
|
import { createClient } from "@libsql/client";
|
|
137
191
|
function getClient() {
|
|
138
|
-
if (!
|
|
192
|
+
if (!_adapterClient) {
|
|
139
193
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
140
194
|
}
|
|
195
|
+
if (process.env.DATABASE_URL) {
|
|
196
|
+
return _adapterClient;
|
|
197
|
+
}
|
|
141
198
|
if (process.env.EXE_IS_DAEMON === "1") {
|
|
142
199
|
return _resilientClient;
|
|
143
200
|
}
|
|
@@ -146,87 +203,16 @@ function getClient() {
|
|
|
146
203
|
}
|
|
147
204
|
return _resilientClient;
|
|
148
205
|
}
|
|
149
|
-
var _resilientClient, _daemonClient;
|
|
206
|
+
var _resilientClient, _daemonClient, _adapterClient;
|
|
150
207
|
var init_database = __esm({
|
|
151
208
|
"src/lib/database.ts"() {
|
|
152
209
|
"use strict";
|
|
153
210
|
init_db_retry();
|
|
154
211
|
init_employees();
|
|
212
|
+
init_database_adapter();
|
|
155
213
|
_resilientClient = null;
|
|
156
214
|
_daemonClient = null;
|
|
157
|
-
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
// src/lib/notifications.ts
|
|
161
|
-
import crypto from "crypto";
|
|
162
|
-
import path3 from "path";
|
|
163
|
-
import os3 from "os";
|
|
164
|
-
import {
|
|
165
|
-
readFileSync as readFileSync3,
|
|
166
|
-
readdirSync,
|
|
167
|
-
unlinkSync as unlinkSync2,
|
|
168
|
-
existsSync as existsSync3,
|
|
169
|
-
rmdirSync
|
|
170
|
-
} from "fs";
|
|
171
|
-
var init_notifications = __esm({
|
|
172
|
-
"src/lib/notifications.ts"() {
|
|
173
|
-
"use strict";
|
|
174
|
-
init_database();
|
|
175
|
-
}
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
// src/lib/state-bus.ts
|
|
179
|
-
var StateBus, orgBus;
|
|
180
|
-
var init_state_bus = __esm({
|
|
181
|
-
"src/lib/state-bus.ts"() {
|
|
182
|
-
"use strict";
|
|
183
|
-
StateBus = class {
|
|
184
|
-
handlers = /* @__PURE__ */ new Map();
|
|
185
|
-
globalHandlers = /* @__PURE__ */ new Set();
|
|
186
|
-
/** Emit an event to all subscribers */
|
|
187
|
-
emit(event) {
|
|
188
|
-
const typeHandlers = this.handlers.get(event.type);
|
|
189
|
-
if (typeHandlers) {
|
|
190
|
-
for (const handler of typeHandlers) {
|
|
191
|
-
try {
|
|
192
|
-
handler(event);
|
|
193
|
-
} catch {
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
for (const handler of this.globalHandlers) {
|
|
198
|
-
try {
|
|
199
|
-
handler(event);
|
|
200
|
-
} catch {
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
/** Subscribe to a specific event type */
|
|
205
|
-
on(type, handler) {
|
|
206
|
-
if (!this.handlers.has(type)) {
|
|
207
|
-
this.handlers.set(type, /* @__PURE__ */ new Set());
|
|
208
|
-
}
|
|
209
|
-
this.handlers.get(type).add(handler);
|
|
210
|
-
}
|
|
211
|
-
/** Subscribe to ALL events */
|
|
212
|
-
onAny(handler) {
|
|
213
|
-
this.globalHandlers.add(handler);
|
|
214
|
-
}
|
|
215
|
-
/** Unsubscribe from a specific event type */
|
|
216
|
-
off(type, handler) {
|
|
217
|
-
this.handlers.get(type)?.delete(handler);
|
|
218
|
-
}
|
|
219
|
-
/** Unsubscribe from ALL events */
|
|
220
|
-
offAny(handler) {
|
|
221
|
-
this.globalHandlers.delete(handler);
|
|
222
|
-
}
|
|
223
|
-
/** Remove all listeners */
|
|
224
|
-
clear() {
|
|
225
|
-
this.handlers.clear();
|
|
226
|
-
this.globalHandlers.clear();
|
|
227
|
-
}
|
|
228
|
-
};
|
|
229
|
-
orgBus = new StateBus();
|
|
215
|
+
_adapterClient = null;
|
|
230
216
|
}
|
|
231
217
|
});
|
|
232
218
|
|
|
@@ -472,7 +458,7 @@ var init_runtime_table = __esm({
|
|
|
472
458
|
});
|
|
473
459
|
|
|
474
460
|
// src/lib/agent-config.ts
|
|
475
|
-
import { readFileSync as
|
|
461
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync4 } from "fs";
|
|
476
462
|
import path5 from "path";
|
|
477
463
|
var AGENT_CONFIG_PATH, DEFAULT_MODELS;
|
|
478
464
|
var init_agent_config = __esm({
|
|
@@ -480,6 +466,7 @@ var init_agent_config = __esm({
|
|
|
480
466
|
"use strict";
|
|
481
467
|
init_config();
|
|
482
468
|
init_runtime_table();
|
|
469
|
+
init_secure_files();
|
|
483
470
|
AGENT_CONFIG_PATH = path5.join(EXE_AI_DIR, "agent-config.json");
|
|
484
471
|
DEFAULT_MODELS = {
|
|
485
472
|
claude: "claude-opus-4",
|
|
@@ -490,7 +477,7 @@ var init_agent_config = __esm({
|
|
|
490
477
|
});
|
|
491
478
|
|
|
492
479
|
// src/lib/intercom-queue.ts
|
|
493
|
-
import { readFileSync as
|
|
480
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, renameSync as renameSync3, existsSync as existsSync5, mkdirSync as mkdirSync2 } from "fs";
|
|
494
481
|
import path6 from "path";
|
|
495
482
|
import os5 from "os";
|
|
496
483
|
var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
|
|
@@ -504,8 +491,11 @@ var init_intercom_queue = __esm({
|
|
|
504
491
|
});
|
|
505
492
|
|
|
506
493
|
// src/lib/license.ts
|
|
507
|
-
import { readFileSync as
|
|
494
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as existsSync6, mkdirSync as mkdirSync3 } from "fs";
|
|
508
495
|
import { randomUUID } from "crypto";
|
|
496
|
+
import { createRequire as createRequire2 } from "module";
|
|
497
|
+
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
498
|
+
import os6 from "os";
|
|
509
499
|
import path7 from "path";
|
|
510
500
|
import { jwtVerify, importSPKI } from "jose";
|
|
511
501
|
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH;
|
|
@@ -520,7 +510,7 @@ var init_license = __esm({
|
|
|
520
510
|
});
|
|
521
511
|
|
|
522
512
|
// src/lib/plan-limits.ts
|
|
523
|
-
import { readFileSync as
|
|
513
|
+
import { readFileSync as readFileSync6, existsSync as existsSync7 } from "fs";
|
|
524
514
|
import path8 from "path";
|
|
525
515
|
var CACHE_PATH2;
|
|
526
516
|
var init_plan_limits = __esm({
|
|
@@ -535,9 +525,9 @@ var init_plan_limits = __esm({
|
|
|
535
525
|
});
|
|
536
526
|
|
|
537
527
|
// src/lib/tmux-routing.ts
|
|
538
|
-
import { readFileSync as
|
|
528
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, existsSync as existsSync8, appendFileSync, readdirSync } from "fs";
|
|
539
529
|
import path9 from "path";
|
|
540
|
-
import
|
|
530
|
+
import os7 from "os";
|
|
541
531
|
import { fileURLToPath } from "url";
|
|
542
532
|
function getMySession() {
|
|
543
533
|
return getTransport().getMySession();
|
|
@@ -550,7 +540,7 @@ function extractRootExe(name) {
|
|
|
550
540
|
}
|
|
551
541
|
function getParentExe(sessionKey) {
|
|
552
542
|
try {
|
|
553
|
-
const data = JSON.parse(
|
|
543
|
+
const data = JSON.parse(readFileSync7(path9.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
554
544
|
return data.parentExe || null;
|
|
555
545
|
} catch {
|
|
556
546
|
return null;
|
|
@@ -593,9 +583,9 @@ var init_tmux_routing = __esm({
|
|
|
593
583
|
init_intercom_queue();
|
|
594
584
|
init_plan_limits();
|
|
595
585
|
init_employees();
|
|
596
|
-
SPAWN_LOCK_DIR = path9.join(
|
|
597
|
-
SESSION_CACHE = path9.join(
|
|
598
|
-
INTERCOM_LOG2 = path9.join(
|
|
586
|
+
SPAWN_LOCK_DIR = path9.join(os7.homedir(), ".exe-os", "spawn-locks");
|
|
587
|
+
SESSION_CACHE = path9.join(os7.homedir(), ".exe-os", "session-cache");
|
|
588
|
+
INTERCOM_LOG2 = path9.join(os7.homedir(), ".exe-os", "intercom.log");
|
|
599
589
|
DEBOUNCE_FILE = path9.join(SESSION_CACHE, "intercom-debounce.json");
|
|
600
590
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
601
591
|
}
|
|
@@ -625,13 +615,87 @@ var init_task_scope = __esm({
|
|
|
625
615
|
}
|
|
626
616
|
});
|
|
627
617
|
|
|
618
|
+
// src/lib/notifications.ts
|
|
619
|
+
import crypto from "crypto";
|
|
620
|
+
import path10 from "path";
|
|
621
|
+
import os8 from "os";
|
|
622
|
+
import {
|
|
623
|
+
readFileSync as readFileSync8,
|
|
624
|
+
readdirSync as readdirSync2,
|
|
625
|
+
unlinkSync as unlinkSync2,
|
|
626
|
+
existsSync as existsSync9,
|
|
627
|
+
rmdirSync
|
|
628
|
+
} from "fs";
|
|
629
|
+
var init_notifications = __esm({
|
|
630
|
+
"src/lib/notifications.ts"() {
|
|
631
|
+
"use strict";
|
|
632
|
+
init_database();
|
|
633
|
+
init_task_scope();
|
|
634
|
+
}
|
|
635
|
+
});
|
|
636
|
+
|
|
637
|
+
// src/lib/state-bus.ts
|
|
638
|
+
var StateBus, orgBus;
|
|
639
|
+
var init_state_bus = __esm({
|
|
640
|
+
"src/lib/state-bus.ts"() {
|
|
641
|
+
"use strict";
|
|
642
|
+
StateBus = class {
|
|
643
|
+
handlers = /* @__PURE__ */ new Map();
|
|
644
|
+
globalHandlers = /* @__PURE__ */ new Set();
|
|
645
|
+
/** Emit an event to all subscribers */
|
|
646
|
+
emit(event) {
|
|
647
|
+
const typeHandlers = this.handlers.get(event.type);
|
|
648
|
+
if (typeHandlers) {
|
|
649
|
+
for (const handler of typeHandlers) {
|
|
650
|
+
try {
|
|
651
|
+
handler(event);
|
|
652
|
+
} catch {
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
for (const handler of this.globalHandlers) {
|
|
657
|
+
try {
|
|
658
|
+
handler(event);
|
|
659
|
+
} catch {
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
/** Subscribe to a specific event type */
|
|
664
|
+
on(type, handler) {
|
|
665
|
+
if (!this.handlers.has(type)) {
|
|
666
|
+
this.handlers.set(type, /* @__PURE__ */ new Set());
|
|
667
|
+
}
|
|
668
|
+
this.handlers.get(type).add(handler);
|
|
669
|
+
}
|
|
670
|
+
/** Subscribe to ALL events */
|
|
671
|
+
onAny(handler) {
|
|
672
|
+
this.globalHandlers.add(handler);
|
|
673
|
+
}
|
|
674
|
+
/** Unsubscribe from a specific event type */
|
|
675
|
+
off(type, handler) {
|
|
676
|
+
this.handlers.get(type)?.delete(handler);
|
|
677
|
+
}
|
|
678
|
+
/** Unsubscribe from ALL events */
|
|
679
|
+
offAny(handler) {
|
|
680
|
+
this.globalHandlers.delete(handler);
|
|
681
|
+
}
|
|
682
|
+
/** Remove all listeners */
|
|
683
|
+
clear() {
|
|
684
|
+
this.handlers.clear();
|
|
685
|
+
this.globalHandlers.clear();
|
|
686
|
+
}
|
|
687
|
+
};
|
|
688
|
+
orgBus = new StateBus();
|
|
689
|
+
}
|
|
690
|
+
});
|
|
691
|
+
|
|
628
692
|
// src/lib/tasks-crud.ts
|
|
629
693
|
import crypto2 from "crypto";
|
|
630
|
-
import
|
|
631
|
-
import
|
|
694
|
+
import path11 from "path";
|
|
695
|
+
import os9 from "os";
|
|
632
696
|
import { execSync as execSync4 } from "child_process";
|
|
633
697
|
import { mkdir as mkdir3, writeFile as writeFile3, appendFile } from "fs/promises";
|
|
634
|
-
import { existsSync as
|
|
698
|
+
import { existsSync as existsSync10, readFileSync as readFileSync9 } from "fs";
|
|
635
699
|
function buildKeywordIndex() {
|
|
636
700
|
const idx = /* @__PURE__ */ new Map();
|
|
637
701
|
for (const [role, keywords] of Object.entries(LANE_KEYWORDS)) {
|
|
@@ -713,8 +777,8 @@ var init_tasks_crud = __esm({
|
|
|
713
777
|
});
|
|
714
778
|
|
|
715
779
|
// src/lib/tasks-review.ts
|
|
716
|
-
import
|
|
717
|
-
import { existsSync as
|
|
780
|
+
import path12 from "path";
|
|
781
|
+
import { existsSync as existsSync11, readdirSync as readdirSync3, unlinkSync as unlinkSync3 } from "fs";
|
|
718
782
|
var init_tasks_review = __esm({
|
|
719
783
|
"src/lib/tasks-review.ts"() {
|
|
720
784
|
"use strict";
|
|
@@ -725,11 +789,12 @@ var init_tasks_review = __esm({
|
|
|
725
789
|
init_tmux_routing();
|
|
726
790
|
init_session_key();
|
|
727
791
|
init_state_bus();
|
|
792
|
+
init_task_scope();
|
|
728
793
|
}
|
|
729
794
|
});
|
|
730
795
|
|
|
731
796
|
// src/lib/tasks-chain.ts
|
|
732
|
-
import
|
|
797
|
+
import path13 from "path";
|
|
733
798
|
import { readFile as readFile3, writeFile as writeFile4 } from "fs/promises";
|
|
734
799
|
var init_tasks_chain = __esm({
|
|
735
800
|
"src/lib/tasks-chain.ts"() {
|
|
@@ -753,7 +818,7 @@ var init_tasks_notify = __esm({
|
|
|
753
818
|
});
|
|
754
819
|
|
|
755
820
|
// src/lib/tasks.ts
|
|
756
|
-
import
|
|
821
|
+
import path14 from "path";
|
|
757
822
|
import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, unlinkSync as unlinkSync4 } from "fs";
|
|
758
823
|
var init_tasks = __esm({
|
|
759
824
|
"src/lib/tasks.ts"() {
|
|
@@ -774,7 +839,7 @@ var init_tasks = __esm({
|
|
|
774
839
|
|
|
775
840
|
// src/lib/project-name.ts
|
|
776
841
|
import { execSync as execSync5 } from "child_process";
|
|
777
|
-
import
|
|
842
|
+
import path15 from "path";
|
|
778
843
|
function getProjectName(cwd) {
|
|
779
844
|
const dir = cwd ?? process.cwd();
|
|
780
845
|
if (_cached2 && _cachedCwd === dir) return _cached2;
|
|
@@ -787,7 +852,7 @@ function getProjectName(cwd) {
|
|
|
787
852
|
timeout: 2e3,
|
|
788
853
|
stdio: ["pipe", "pipe", "pipe"]
|
|
789
854
|
}).trim();
|
|
790
|
-
repoRoot =
|
|
855
|
+
repoRoot = path15.dirname(gitCommonDir);
|
|
791
856
|
} catch {
|
|
792
857
|
repoRoot = execSync5("git rev-parse --show-toplevel", {
|
|
793
858
|
cwd: dir,
|
|
@@ -796,11 +861,11 @@ function getProjectName(cwd) {
|
|
|
796
861
|
stdio: ["pipe", "pipe", "pipe"]
|
|
797
862
|
}).trim();
|
|
798
863
|
}
|
|
799
|
-
_cached2 =
|
|
864
|
+
_cached2 = path15.basename(repoRoot);
|
|
800
865
|
_cachedCwd = dir;
|
|
801
866
|
return _cached2;
|
|
802
867
|
} catch {
|
|
803
|
-
_cached2 =
|
|
868
|
+
_cached2 = path15.basename(dir);
|
|
804
869
|
_cachedCwd = dir;
|
|
805
870
|
return _cached2;
|
|
806
871
|
}
|
|
@@ -818,22 +883,130 @@ var init_project_name = __esm({
|
|
|
818
883
|
init_tasks();
|
|
819
884
|
init_project_name();
|
|
820
885
|
import { z } from "zod";
|
|
886
|
+
|
|
887
|
+
// src/lib/active-agent.ts
|
|
888
|
+
init_config();
|
|
889
|
+
init_session_key();
|
|
890
|
+
init_employees();
|
|
891
|
+
import { readFileSync as readFileSync10, writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, unlinkSync as unlinkSync5, readdirSync as readdirSync4 } from "fs";
|
|
892
|
+
import { execSync as execSync6 } from "child_process";
|
|
893
|
+
import path16 from "path";
|
|
894
|
+
var CACHE_DIR = path16.join(EXE_AI_DIR, "session-cache");
|
|
895
|
+
var STALE_MS = 24 * 60 * 60 * 1e3;
|
|
896
|
+
function isNameWithOptionalInstance(candidate, baseName) {
|
|
897
|
+
if (candidate === baseName) return true;
|
|
898
|
+
if (!candidate.startsWith(baseName)) return false;
|
|
899
|
+
return /^\d+$/.test(candidate.slice(baseName.length));
|
|
900
|
+
}
|
|
901
|
+
function resolveEmployeeFromSessionPrefix(prefix, employees) {
|
|
902
|
+
const sorted = [...employees].sort((a, b) => b.name.length - a.name.length);
|
|
903
|
+
for (const employee of sorted) {
|
|
904
|
+
if (isNameWithOptionalInstance(prefix, employee.name)) {
|
|
905
|
+
return { agentId: employee.name, agentRole: employee.role };
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
return null;
|
|
909
|
+
}
|
|
910
|
+
function resolveActiveAgentFromTmuxSession(sessionName) {
|
|
911
|
+
const employees = loadEmployeesSync();
|
|
912
|
+
const coordinator = getCoordinatorEmployee(employees);
|
|
913
|
+
const coordinatorName = coordinator?.name ?? DEFAULT_COORDINATOR_TEMPLATE_NAME;
|
|
914
|
+
if (isNameWithOptionalInstance(sessionName, coordinatorName)) {
|
|
915
|
+
return {
|
|
916
|
+
agentId: coordinatorName,
|
|
917
|
+
agentRole: coordinator?.role ?? "COO"
|
|
918
|
+
};
|
|
919
|
+
}
|
|
920
|
+
if (isNameWithOptionalInstance(sessionName, DEFAULT_COORDINATOR_TEMPLATE_NAME)) {
|
|
921
|
+
return {
|
|
922
|
+
agentId: coordinator?.name ?? DEFAULT_COORDINATOR_TEMPLATE_NAME,
|
|
923
|
+
agentRole: coordinator?.role ?? "COO"
|
|
924
|
+
};
|
|
925
|
+
}
|
|
926
|
+
if (sessionName.includes("-")) {
|
|
927
|
+
const prefix = sessionName.split("-")[0] ?? "";
|
|
928
|
+
const employee = resolveEmployeeFromSessionPrefix(prefix, employees);
|
|
929
|
+
if (employee) return employee;
|
|
930
|
+
const legacy = prefix.match(/^([a-zA-Z]+)\d*$/);
|
|
931
|
+
if (legacy?.[1] && legacy[1] !== DEFAULT_COORDINATOR_TEMPLATE_NAME) {
|
|
932
|
+
const emp = getEmployee(employees, legacy[1]);
|
|
933
|
+
return { agentId: emp?.name ?? legacy[1], agentRole: emp?.role ?? "employee" };
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
return null;
|
|
937
|
+
}
|
|
938
|
+
function getMarkerPath() {
|
|
939
|
+
return path16.join(CACHE_DIR, `active-agent-${getSessionKey()}.json`);
|
|
940
|
+
}
|
|
941
|
+
function getActiveAgent() {
|
|
942
|
+
try {
|
|
943
|
+
const markerPath = getMarkerPath();
|
|
944
|
+
const raw = readFileSync10(markerPath, "utf8");
|
|
945
|
+
const data = JSON.parse(raw);
|
|
946
|
+
if (data.agentId) {
|
|
947
|
+
if (data.startedAt) {
|
|
948
|
+
const age = Date.now() - new Date(data.startedAt).getTime();
|
|
949
|
+
if (age > STALE_MS) {
|
|
950
|
+
try {
|
|
951
|
+
unlinkSync5(markerPath);
|
|
952
|
+
} catch {
|
|
953
|
+
}
|
|
954
|
+
} else {
|
|
955
|
+
return {
|
|
956
|
+
agentId: data.agentId,
|
|
957
|
+
agentRole: data.agentRole || "employee"
|
|
958
|
+
};
|
|
959
|
+
}
|
|
960
|
+
} else {
|
|
961
|
+
return {
|
|
962
|
+
agentId: data.agentId,
|
|
963
|
+
agentRole: data.agentRole || "employee"
|
|
964
|
+
};
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
} catch {
|
|
968
|
+
}
|
|
969
|
+
try {
|
|
970
|
+
const sessionName = execSync6(
|
|
971
|
+
"tmux display-message -p '#{session_name}' 2>/dev/null",
|
|
972
|
+
{ encoding: "utf8", timeout: 2e3 }
|
|
973
|
+
).trim();
|
|
974
|
+
const resolved = resolveActiveAgentFromTmuxSession(sessionName);
|
|
975
|
+
if (resolved) return resolved;
|
|
976
|
+
} catch {
|
|
977
|
+
}
|
|
978
|
+
return {
|
|
979
|
+
agentId: process.env.AGENT_ID || "default",
|
|
980
|
+
agentRole: process.env.AGENT_ROLE || "employee"
|
|
981
|
+
};
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
// src/mcp/tools/list-tasks.ts
|
|
821
985
|
function registerListTasks(server) {
|
|
822
986
|
server.registerTool(
|
|
823
987
|
"list_tasks",
|
|
824
988
|
{
|
|
825
989
|
title: "List Tasks",
|
|
826
|
-
description: "Query tasks by assignee, status, project, or priority. Defaults to current project. Pass project_name='all'
|
|
990
|
+
description: "Query tasks by assignee, status, project, or priority. Defaults to current project. Pass project_name='all' for all projects. When querying your own tasks, project filter is skipped automatically.",
|
|
827
991
|
inputSchema: {
|
|
828
992
|
assigned_to: z.string().optional().describe("Filter by employee name"),
|
|
829
|
-
status: z.enum(["open", "in_progress", "done", "blocked", "cancelled"]).optional().describe("Filter by status"),
|
|
993
|
+
status: z.enum(["open", "in_progress", "done", "needs_review", "blocked", "cancelled", "closed"]).optional().describe("Filter by status. Default: active tasks only (excludes closed/cancelled)"),
|
|
830
994
|
project_name: z.string().optional().describe("Project name. Defaults to current project. Pass 'all' for all projects."),
|
|
831
995
|
priority: z.enum(["p0", "p1", "p2"]).optional().describe("Filter by priority")
|
|
832
996
|
}
|
|
833
997
|
},
|
|
834
998
|
async ({ assigned_to, status, project_name, priority }) => {
|
|
835
999
|
try {
|
|
836
|
-
|
|
1000
|
+
let resolvedProject;
|
|
1001
|
+
if (project_name === "all") {
|
|
1002
|
+
resolvedProject = void 0;
|
|
1003
|
+
} else if (project_name) {
|
|
1004
|
+
resolvedProject = project_name;
|
|
1005
|
+
} else {
|
|
1006
|
+
const { agentId } = getActiveAgent();
|
|
1007
|
+
const queryingSelf = !assigned_to || assigned_to === agentId;
|
|
1008
|
+
resolvedProject = queryingSelf ? void 0 : getProjectName();
|
|
1009
|
+
}
|
|
837
1010
|
const tasks = await listTasks({
|
|
838
1011
|
assignedTo: assigned_to,
|
|
839
1012
|
status,
|