@askexenow/exe-os 0.8.41 → 0.8.43
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 +805 -642
- package/dist/bin/backfill-responses.js +804 -641
- package/dist/bin/backfill-vectors.js +791 -634
- package/dist/bin/cleanup-stale-review-tasks.js +788 -631
- package/dist/bin/cli.js +1345 -660
- package/dist/bin/exe-agent.js +20 -1
- package/dist/bin/exe-assign.js +1503 -1343
- package/dist/bin/exe-boot.js +2518 -1798
- package/dist/bin/exe-call.js +39 -1
- package/dist/bin/exe-cloud.js +15 -1
- package/dist/bin/exe-dispatch.js +39 -2
- package/dist/bin/exe-doctor.js +790 -633
- package/dist/bin/exe-export-behaviors.js +792 -637
- package/dist/bin/exe-forget.js +145 -0
- package/dist/bin/exe-gateway.js +2500 -1877
- package/dist/bin/exe-heartbeat.js +147 -1
- package/dist/bin/exe-kill.js +795 -640
- package/dist/bin/exe-launch-agent.js +2168 -2008
- package/dist/bin/exe-link.js +28 -2
- package/dist/bin/exe-new-employee.js +25 -3
- package/dist/bin/exe-pending-messages.js +146 -1
- package/dist/bin/exe-pending-notifications.js +788 -631
- package/dist/bin/exe-pending-reviews.js +147 -1
- package/dist/bin/exe-rename.js +23 -0
- package/dist/bin/exe-review.js +490 -327
- package/dist/bin/exe-search.js +154 -3
- package/dist/bin/exe-session-cleanup.js +2466 -413
- package/dist/bin/exe-status.js +474 -317
- package/dist/bin/exe-team.js +474 -317
- package/dist/bin/git-sweep.js +2690 -150
- package/dist/bin/graph-backfill.js +794 -637
- package/dist/bin/graph-export.js +798 -641
- package/dist/bin/scan-tasks.js +2951 -44
- package/dist/bin/setup.js +62 -26
- package/dist/bin/shard-migrate.js +792 -637
- package/dist/bin/wiki-sync.js +794 -637
- package/dist/gateway/index.js +2504 -1895
- package/dist/hooks/bug-report-worker.js +2118 -576
- package/dist/hooks/commit-complete.js +2689 -149
- package/dist/hooks/error-recall.js +154 -3
- package/dist/hooks/ingest-worker.js +1439 -815
- package/dist/hooks/instructions-loaded.js +151 -0
- package/dist/hooks/notification.js +153 -2
- package/dist/hooks/post-compact.js +164 -0
- package/dist/hooks/pre-compact.js +3073 -101
- package/dist/hooks/pre-tool-use.js +151 -0
- package/dist/hooks/prompt-ingest-worker.js +1714 -1537
- package/dist/hooks/prompt-submit.js +2658 -1113
- package/dist/hooks/response-ingest-worker.js +170 -6
- package/dist/hooks/session-end.js +153 -2
- package/dist/hooks/session-start.js +154 -3
- package/dist/hooks/stop.js +151 -0
- package/dist/hooks/subagent-stop.js +151 -0
- package/dist/hooks/summary-worker.js +179 -7
- package/dist/index.js +278 -100
- package/dist/lib/cloud-sync.js +28 -2
- package/dist/lib/consolidation.js +69 -2
- package/dist/lib/database.js +19 -0
- package/dist/lib/device-registry.js +19 -0
- package/dist/lib/employee-templates.js +20 -1
- package/dist/lib/exe-daemon.js +236 -16
- package/dist/lib/hybrid-search.js +154 -3
- package/dist/lib/license.js +15 -1
- package/dist/lib/messaging.js +39 -2
- package/dist/lib/schedules.js +792 -637
- package/dist/lib/store.js +796 -636
- package/dist/lib/tasks.js +1614 -1091
- package/dist/lib/tmux-routing.js +149 -9
- package/dist/mcp/server.js +1825 -1138
- package/dist/mcp/tools/create-task.js +2280 -828
- package/dist/mcp/tools/list-tasks.js +2788 -159
- package/dist/mcp/tools/send-message.js +39 -2
- package/dist/mcp/tools/update-task.js +64 -0
- package/dist/runtime/index.js +235 -67
- package/dist/tui/App.js +1452 -644
- package/package.json +3 -2
package/dist/lib/cloud-sync.js
CHANGED
|
@@ -297,6 +297,10 @@ function loadLicense() {
|
|
|
297
297
|
return null;
|
|
298
298
|
}
|
|
299
299
|
}
|
|
300
|
+
function saveLicense(apiKey) {
|
|
301
|
+
mkdirSync(EXE_AI_DIR, { recursive: true });
|
|
302
|
+
writeFileSync(LICENSE_PATH, apiKey.trim(), { encoding: "utf8", mode: 384 });
|
|
303
|
+
}
|
|
300
304
|
async function verifyLicenseJwt(token) {
|
|
301
305
|
try {
|
|
302
306
|
const key = await importSPKI(LICENSE_PUBLIC_KEY_PEM, LICENSE_JWT_ALG);
|
|
@@ -387,7 +391,21 @@ function getCacheAgeMs() {
|
|
|
387
391
|
}
|
|
388
392
|
}
|
|
389
393
|
async function checkLicense() {
|
|
390
|
-
|
|
394
|
+
let key = loadLicense();
|
|
395
|
+
if (!key) {
|
|
396
|
+
try {
|
|
397
|
+
const configPath = path3.join(EXE_AI_DIR, "config.json");
|
|
398
|
+
if (existsSync3(configPath)) {
|
|
399
|
+
const raw = JSON.parse(readFileSync3(configPath, "utf8"));
|
|
400
|
+
const cloud = raw.cloud;
|
|
401
|
+
if (cloud?.apiKey) {
|
|
402
|
+
key = cloud.apiKey;
|
|
403
|
+
saveLicense(key);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
} catch {
|
|
407
|
+
}
|
|
408
|
+
}
|
|
391
409
|
if (!key) return FREE_LICENSE;
|
|
392
410
|
const cached = await getCachedLicense();
|
|
393
411
|
if (cached && getCacheAgeMs() < CACHE_MAX_AGE_MS) return cached;
|
|
@@ -477,7 +495,7 @@ async function fetchWithRetry(url, init) {
|
|
|
477
495
|
try {
|
|
478
496
|
const signal = AbortSignal.timeout(FETCH_TIMEOUT_MS);
|
|
479
497
|
const resp = await fetch(url, { ...init, signal });
|
|
480
|
-
if (resp.status >= 500 && attempt < MAX_RETRIES) {
|
|
498
|
+
if (resp && resp.status >= 500 && attempt < MAX_RETRIES) {
|
|
481
499
|
await new Promise((r) => setTimeout(r, BASE_DELAY_MS * Math.pow(2, attempt)));
|
|
482
500
|
continue;
|
|
483
501
|
}
|
|
@@ -521,6 +539,10 @@ async function cloudPush(records, maxVersion, config) {
|
|
|
521
539
|
},
|
|
522
540
|
body: JSON.stringify({ version: maxVersion, blob })
|
|
523
541
|
});
|
|
542
|
+
if (resp == null) {
|
|
543
|
+
logError("[cloud-sync] PUSH FAILED: no response from server");
|
|
544
|
+
return false;
|
|
545
|
+
}
|
|
524
546
|
if (resp.status === 409) {
|
|
525
547
|
logError("[cloud-sync] PUSH VERSION CONFLICT \u2014 re-pull required before next push");
|
|
526
548
|
return false;
|
|
@@ -543,6 +565,10 @@ async function cloudPull(sinceVersion, config) {
|
|
|
543
565
|
},
|
|
544
566
|
body: JSON.stringify({ since_version: sinceVersion })
|
|
545
567
|
});
|
|
568
|
+
if (response == null) {
|
|
569
|
+
logError("[cloud-sync] PULL FAILED: no response from server");
|
|
570
|
+
return { records: [], maxVersion: sinceVersion };
|
|
571
|
+
}
|
|
546
572
|
if (!response.ok) return { records: [], maxVersion: sinceVersion };
|
|
547
573
|
const data = await response.json();
|
|
548
574
|
const allRecords = [];
|
|
@@ -3,6 +3,22 @@ var __esm = (fn, res) => function __init() {
|
|
|
3
3
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
4
4
|
};
|
|
5
5
|
|
|
6
|
+
// src/lib/db-retry.ts
|
|
7
|
+
var init_db_retry = __esm({
|
|
8
|
+
"src/lib/db-retry.ts"() {
|
|
9
|
+
"use strict";
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
// src/lib/database.ts
|
|
14
|
+
import { createClient } from "@libsql/client";
|
|
15
|
+
var init_database = __esm({
|
|
16
|
+
"src/lib/database.ts"() {
|
|
17
|
+
"use strict";
|
|
18
|
+
init_db_retry();
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
|
|
6
22
|
// src/lib/config.ts
|
|
7
23
|
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
|
|
8
24
|
import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
|
|
@@ -103,8 +119,8 @@ var init_config = __esm({
|
|
|
103
119
|
// src/lib/consolidation.ts
|
|
104
120
|
import { randomUUID } from "crypto";
|
|
105
121
|
|
|
106
|
-
// src/lib/
|
|
107
|
-
|
|
122
|
+
// src/lib/store.ts
|
|
123
|
+
init_database();
|
|
108
124
|
|
|
109
125
|
// src/lib/keychain.ts
|
|
110
126
|
import { readFile, writeFile, unlink, mkdir, chmod } from "fs/promises";
|
|
@@ -115,6 +131,57 @@ import crypto from "crypto";
|
|
|
115
131
|
|
|
116
132
|
// src/lib/store.ts
|
|
117
133
|
init_config();
|
|
134
|
+
|
|
135
|
+
// src/lib/state-bus.ts
|
|
136
|
+
var StateBus = class {
|
|
137
|
+
handlers = /* @__PURE__ */ new Map();
|
|
138
|
+
globalHandlers = /* @__PURE__ */ new Set();
|
|
139
|
+
/** Emit an event to all subscribers */
|
|
140
|
+
emit(event) {
|
|
141
|
+
const typeHandlers = this.handlers.get(event.type);
|
|
142
|
+
if (typeHandlers) {
|
|
143
|
+
for (const handler of typeHandlers) {
|
|
144
|
+
try {
|
|
145
|
+
handler(event);
|
|
146
|
+
} catch {
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
for (const handler of this.globalHandlers) {
|
|
151
|
+
try {
|
|
152
|
+
handler(event);
|
|
153
|
+
} catch {
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
/** Subscribe to a specific event type */
|
|
158
|
+
on(type, handler) {
|
|
159
|
+
if (!this.handlers.has(type)) {
|
|
160
|
+
this.handlers.set(type, /* @__PURE__ */ new Set());
|
|
161
|
+
}
|
|
162
|
+
this.handlers.get(type).add(handler);
|
|
163
|
+
}
|
|
164
|
+
/** Subscribe to ALL events */
|
|
165
|
+
onAny(handler) {
|
|
166
|
+
this.globalHandlers.add(handler);
|
|
167
|
+
}
|
|
168
|
+
/** Unsubscribe from a specific event type */
|
|
169
|
+
off(type, handler) {
|
|
170
|
+
this.handlers.get(type)?.delete(handler);
|
|
171
|
+
}
|
|
172
|
+
/** Unsubscribe from ALL events */
|
|
173
|
+
offAny(handler) {
|
|
174
|
+
this.globalHandlers.delete(handler);
|
|
175
|
+
}
|
|
176
|
+
/** Remove all listeners */
|
|
177
|
+
clear() {
|
|
178
|
+
this.handlers.clear();
|
|
179
|
+
this.globalHandlers.clear();
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
var orgBus = new StateBus();
|
|
183
|
+
|
|
184
|
+
// src/lib/store.ts
|
|
118
185
|
function vectorToBlob(vector) {
|
|
119
186
|
const f32 = vector instanceof Float32Array ? vector : new Float32Array(vector);
|
|
120
187
|
return JSON.stringify(Array.from(f32));
|
package/dist/lib/database.js
CHANGED
|
@@ -293,6 +293,13 @@ async function ensureSchema() {
|
|
|
293
293
|
});
|
|
294
294
|
} catch {
|
|
295
295
|
}
|
|
296
|
+
try {
|
|
297
|
+
await client.execute({
|
|
298
|
+
sql: `ALTER TABLE tasks ADD COLUMN session_scope TEXT`,
|
|
299
|
+
args: []
|
|
300
|
+
});
|
|
301
|
+
} catch {
|
|
302
|
+
}
|
|
296
303
|
try {
|
|
297
304
|
await client.execute({
|
|
298
305
|
sql: `ALTER TABLE memories ADD COLUMN task_id TEXT`,
|
|
@@ -739,6 +746,18 @@ async function ensureSchema() {
|
|
|
739
746
|
CREATE INDEX IF NOT EXISTS idx_session_kills_agent
|
|
740
747
|
ON session_kills(agent_id);
|
|
741
748
|
`);
|
|
749
|
+
await client.execute(`
|
|
750
|
+
CREATE TABLE IF NOT EXISTS global_procedures (
|
|
751
|
+
id TEXT PRIMARY KEY,
|
|
752
|
+
title TEXT NOT NULL,
|
|
753
|
+
content TEXT NOT NULL,
|
|
754
|
+
priority TEXT NOT NULL DEFAULT 'p0',
|
|
755
|
+
domain TEXT,
|
|
756
|
+
active INTEGER NOT NULL DEFAULT 1,
|
|
757
|
+
created_at TEXT NOT NULL,
|
|
758
|
+
updated_at TEXT NOT NULL
|
|
759
|
+
)
|
|
760
|
+
`);
|
|
742
761
|
await client.executeMultiple(`
|
|
743
762
|
CREATE TABLE IF NOT EXISTS conversations (
|
|
744
763
|
id TEXT PRIMARY KEY,
|
|
@@ -315,6 +315,13 @@ async function ensureSchema() {
|
|
|
315
315
|
});
|
|
316
316
|
} catch {
|
|
317
317
|
}
|
|
318
|
+
try {
|
|
319
|
+
await client.execute({
|
|
320
|
+
sql: `ALTER TABLE tasks ADD COLUMN session_scope TEXT`,
|
|
321
|
+
args: []
|
|
322
|
+
});
|
|
323
|
+
} catch {
|
|
324
|
+
}
|
|
318
325
|
try {
|
|
319
326
|
await client.execute({
|
|
320
327
|
sql: `ALTER TABLE memories ADD COLUMN task_id TEXT`,
|
|
@@ -761,6 +768,18 @@ async function ensureSchema() {
|
|
|
761
768
|
CREATE INDEX IF NOT EXISTS idx_session_kills_agent
|
|
762
769
|
ON session_kills(agent_id);
|
|
763
770
|
`);
|
|
771
|
+
await client.execute(`
|
|
772
|
+
CREATE TABLE IF NOT EXISTS global_procedures (
|
|
773
|
+
id TEXT PRIMARY KEY,
|
|
774
|
+
title TEXT NOT NULL,
|
|
775
|
+
content TEXT NOT NULL,
|
|
776
|
+
priority TEXT NOT NULL DEFAULT 'p0',
|
|
777
|
+
domain TEXT,
|
|
778
|
+
active INTEGER NOT NULL DEFAULT 1,
|
|
779
|
+
created_at TEXT NOT NULL,
|
|
780
|
+
updated_at TEXT NOT NULL
|
|
781
|
+
)
|
|
782
|
+
`);
|
|
764
783
|
await client.executeMultiple(`
|
|
765
784
|
CREATE TABLE IF NOT EXISTS conversations (
|
|
766
785
|
id TEXT PRIMARY KEY,
|
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
// src/lib/global-procedures.ts
|
|
2
|
+
import { randomUUID } from "crypto";
|
|
3
|
+
|
|
4
|
+
// src/lib/database.ts
|
|
5
|
+
import { createClient } from "@libsql/client";
|
|
6
|
+
|
|
7
|
+
// src/lib/global-procedures.ts
|
|
8
|
+
var _cache = "";
|
|
9
|
+
var _cacheLoaded = false;
|
|
10
|
+
function getGlobalProceduresBlock() {
|
|
11
|
+
if (!_cacheLoaded) return "";
|
|
12
|
+
if (!_cache) return "";
|
|
13
|
+
return `## Organization-Wide Procedures (MANDATORY \u2014 supersedes all other rules)
|
|
14
|
+
|
|
15
|
+
${_cache}
|
|
16
|
+
`;
|
|
17
|
+
}
|
|
18
|
+
|
|
1
19
|
// src/lib/employee-templates.ts
|
|
2
20
|
var BASE_OPERATING_PROCEDURES = `
|
|
3
21
|
EXE OS \u2014 VISION AND NON-NEGOTIABLE PRINCIPLES (above all work):
|
|
@@ -148,7 +166,8 @@ var PROCEDURES_MARKER = "EXE OS \u2014 VISION AND NON-NEGOTIABLE PRINCIPLES";
|
|
|
148
166
|
function getSessionPrompt(storedPrompt) {
|
|
149
167
|
const markerIndex = storedPrompt.indexOf(PROCEDURES_MARKER);
|
|
150
168
|
const rolePrompt = markerIndex >= 0 ? storedPrompt.slice(0, markerIndex).trimEnd() : storedPrompt;
|
|
151
|
-
|
|
169
|
+
const globalBlock = getGlobalProceduresBlock();
|
|
170
|
+
return `${globalBlock}${rolePrompt}
|
|
152
171
|
${BASE_OPERATING_PROCEDURES}`;
|
|
153
172
|
}
|
|
154
173
|
var TEMPLATES = {
|
package/dist/lib/exe-daemon.js
CHANGED
|
@@ -589,6 +589,13 @@ async function ensureSchema() {
|
|
|
589
589
|
});
|
|
590
590
|
} catch {
|
|
591
591
|
}
|
|
592
|
+
try {
|
|
593
|
+
await client.execute({
|
|
594
|
+
sql: `ALTER TABLE tasks ADD COLUMN session_scope TEXT`,
|
|
595
|
+
args: []
|
|
596
|
+
});
|
|
597
|
+
} catch {
|
|
598
|
+
}
|
|
592
599
|
try {
|
|
593
600
|
await client.execute({
|
|
594
601
|
sql: `ALTER TABLE memories ADD COLUMN task_id TEXT`,
|
|
@@ -1035,6 +1042,18 @@ async function ensureSchema() {
|
|
|
1035
1042
|
CREATE INDEX IF NOT EXISTS idx_session_kills_agent
|
|
1036
1043
|
ON session_kills(agent_id);
|
|
1037
1044
|
`);
|
|
1045
|
+
await client.execute(`
|
|
1046
|
+
CREATE TABLE IF NOT EXISTS global_procedures (
|
|
1047
|
+
id TEXT PRIMARY KEY,
|
|
1048
|
+
title TEXT NOT NULL,
|
|
1049
|
+
content TEXT NOT NULL,
|
|
1050
|
+
priority TEXT NOT NULL DEFAULT 'p0',
|
|
1051
|
+
domain TEXT,
|
|
1052
|
+
active INTEGER NOT NULL DEFAULT 1,
|
|
1053
|
+
created_at TEXT NOT NULL,
|
|
1054
|
+
updated_at TEXT NOT NULL
|
|
1055
|
+
)
|
|
1056
|
+
`);
|
|
1038
1057
|
await client.executeMultiple(`
|
|
1039
1058
|
CREATE TABLE IF NOT EXISTS conversations (
|
|
1040
1059
|
id TEXT PRIMARY KEY,
|
|
@@ -1339,6 +1358,61 @@ var init_keychain = __esm({
|
|
|
1339
1358
|
}
|
|
1340
1359
|
});
|
|
1341
1360
|
|
|
1361
|
+
// src/lib/state-bus.ts
|
|
1362
|
+
var StateBus, orgBus;
|
|
1363
|
+
var init_state_bus = __esm({
|
|
1364
|
+
"src/lib/state-bus.ts"() {
|
|
1365
|
+
"use strict";
|
|
1366
|
+
StateBus = class {
|
|
1367
|
+
handlers = /* @__PURE__ */ new Map();
|
|
1368
|
+
globalHandlers = /* @__PURE__ */ new Set();
|
|
1369
|
+
/** Emit an event to all subscribers */
|
|
1370
|
+
emit(event) {
|
|
1371
|
+
const typeHandlers = this.handlers.get(event.type);
|
|
1372
|
+
if (typeHandlers) {
|
|
1373
|
+
for (const handler of typeHandlers) {
|
|
1374
|
+
try {
|
|
1375
|
+
handler(event);
|
|
1376
|
+
} catch {
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
for (const handler of this.globalHandlers) {
|
|
1381
|
+
try {
|
|
1382
|
+
handler(event);
|
|
1383
|
+
} catch {
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
/** Subscribe to a specific event type */
|
|
1388
|
+
on(type, handler) {
|
|
1389
|
+
if (!this.handlers.has(type)) {
|
|
1390
|
+
this.handlers.set(type, /* @__PURE__ */ new Set());
|
|
1391
|
+
}
|
|
1392
|
+
this.handlers.get(type).add(handler);
|
|
1393
|
+
}
|
|
1394
|
+
/** Subscribe to ALL events */
|
|
1395
|
+
onAny(handler) {
|
|
1396
|
+
this.globalHandlers.add(handler);
|
|
1397
|
+
}
|
|
1398
|
+
/** Unsubscribe from a specific event type */
|
|
1399
|
+
off(type, handler) {
|
|
1400
|
+
this.handlers.get(type)?.delete(handler);
|
|
1401
|
+
}
|
|
1402
|
+
/** Unsubscribe from ALL events */
|
|
1403
|
+
offAny(handler) {
|
|
1404
|
+
this.globalHandlers.delete(handler);
|
|
1405
|
+
}
|
|
1406
|
+
/** Remove all listeners */
|
|
1407
|
+
clear() {
|
|
1408
|
+
this.handlers.clear();
|
|
1409
|
+
this.globalHandlers.clear();
|
|
1410
|
+
}
|
|
1411
|
+
};
|
|
1412
|
+
orgBus = new StateBus();
|
|
1413
|
+
}
|
|
1414
|
+
});
|
|
1415
|
+
|
|
1342
1416
|
// src/lib/shard-manager.ts
|
|
1343
1417
|
var shard_manager_exports = {};
|
|
1344
1418
|
__export(shard_manager_exports, {
|
|
@@ -1580,6 +1654,71 @@ var init_shard_manager = __esm({
|
|
|
1580
1654
|
}
|
|
1581
1655
|
});
|
|
1582
1656
|
|
|
1657
|
+
// src/lib/global-procedures.ts
|
|
1658
|
+
var global_procedures_exports = {};
|
|
1659
|
+
__export(global_procedures_exports, {
|
|
1660
|
+
deactivateGlobalProcedure: () => deactivateGlobalProcedure,
|
|
1661
|
+
getGlobalProceduresBlock: () => getGlobalProceduresBlock,
|
|
1662
|
+
loadGlobalProcedures: () => loadGlobalProcedures,
|
|
1663
|
+
storeGlobalProcedure: () => storeGlobalProcedure
|
|
1664
|
+
});
|
|
1665
|
+
import { randomUUID } from "crypto";
|
|
1666
|
+
async function loadGlobalProcedures() {
|
|
1667
|
+
const client = getClient();
|
|
1668
|
+
const result = await client.execute({
|
|
1669
|
+
sql: "SELECT * FROM global_procedures WHERE active = 1 ORDER BY priority ASC, created_at ASC",
|
|
1670
|
+
args: []
|
|
1671
|
+
});
|
|
1672
|
+
const procedures = result.rows;
|
|
1673
|
+
if (procedures.length > 0) {
|
|
1674
|
+
_cache = procedures.map((p) => `### ${p.title}
|
|
1675
|
+
${p.content}`).join("\n\n");
|
|
1676
|
+
} else {
|
|
1677
|
+
_cache = "";
|
|
1678
|
+
}
|
|
1679
|
+
_cacheLoaded = true;
|
|
1680
|
+
return procedures;
|
|
1681
|
+
}
|
|
1682
|
+
function getGlobalProceduresBlock() {
|
|
1683
|
+
if (!_cacheLoaded) return "";
|
|
1684
|
+
if (!_cache) return "";
|
|
1685
|
+
return `## Organization-Wide Procedures (MANDATORY \u2014 supersedes all other rules)
|
|
1686
|
+
|
|
1687
|
+
${_cache}
|
|
1688
|
+
`;
|
|
1689
|
+
}
|
|
1690
|
+
async function storeGlobalProcedure(input) {
|
|
1691
|
+
const id = randomUUID();
|
|
1692
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1693
|
+
const client = getClient();
|
|
1694
|
+
await client.execute({
|
|
1695
|
+
sql: `INSERT INTO global_procedures (id, title, content, priority, domain, active, created_at, updated_at)
|
|
1696
|
+
VALUES (?, ?, ?, ?, ?, 1, ?, ?)`,
|
|
1697
|
+
args: [id, input.title, input.content, input.priority ?? "p0", input.domain ?? null, now, now]
|
|
1698
|
+
});
|
|
1699
|
+
await loadGlobalProcedures();
|
|
1700
|
+
return id;
|
|
1701
|
+
}
|
|
1702
|
+
async function deactivateGlobalProcedure(id) {
|
|
1703
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1704
|
+
const client = getClient();
|
|
1705
|
+
const result = await client.execute({
|
|
1706
|
+
sql: "UPDATE global_procedures SET active = 0, updated_at = ? WHERE id = ?",
|
|
1707
|
+
args: [now, id]
|
|
1708
|
+
});
|
|
1709
|
+
await loadGlobalProcedures();
|
|
1710
|
+
return result.rowsAffected > 0;
|
|
1711
|
+
}
|
|
1712
|
+
var _cache, _cacheLoaded;
|
|
1713
|
+
var init_global_procedures = __esm({
|
|
1714
|
+
"src/lib/global-procedures.ts"() {
|
|
1715
|
+
"use strict";
|
|
1716
|
+
init_database();
|
|
1717
|
+
_cache = "";
|
|
1718
|
+
_cacheLoaded = false;
|
|
1719
|
+
}
|
|
1720
|
+
});
|
|
1721
|
+
|
|
1583
1722
|
// src/lib/store.ts
|
|
1584
1723
|
var store_exports = {};
|
|
1585
1724
|
__export(store_exports, {
|
|
@@ -1659,6 +1798,11 @@ async function initStore(options) {
|
|
|
1659
1798
|
"version-query"
|
|
1660
1799
|
);
|
|
1661
1800
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
1801
|
+
try {
|
|
1802
|
+
const { loadGlobalProcedures: loadGlobalProcedures2 } = await Promise.resolve().then(() => (init_global_procedures(), global_procedures_exports));
|
|
1803
|
+
await loadGlobalProcedures2();
|
|
1804
|
+
} catch {
|
|
1805
|
+
}
|
|
1662
1806
|
}
|
|
1663
1807
|
function classifyTier(record) {
|
|
1664
1808
|
if (record.tool_name === "commit_to_long_term_memory" && (record.importance ?? 0) >= 8) return 1;
|
|
@@ -1700,6 +1844,12 @@ async function writeMemory(record) {
|
|
|
1700
1844
|
supersedes_id: record.supersedes_id ?? null
|
|
1701
1845
|
};
|
|
1702
1846
|
_pendingRecords.push(dbRow);
|
|
1847
|
+
orgBus.emit({
|
|
1848
|
+
type: "memory_stored",
|
|
1849
|
+
agentId: record.agent_id,
|
|
1850
|
+
project: record.project_name,
|
|
1851
|
+
timestamp: record.timestamp
|
|
1852
|
+
});
|
|
1703
1853
|
const MAX_PENDING = 1e3;
|
|
1704
1854
|
if (_pendingRecords.length > MAX_PENDING) {
|
|
1705
1855
|
const dropped = _pendingRecords.length - MAX_PENDING;
|
|
@@ -2045,6 +2195,7 @@ var init_store = __esm({
|
|
|
2045
2195
|
init_database();
|
|
2046
2196
|
init_keychain();
|
|
2047
2197
|
init_config();
|
|
2198
|
+
init_state_bus();
|
|
2048
2199
|
INIT_MAX_RETRIES = 3;
|
|
2049
2200
|
INIT_RETRY_DELAY_MS = 1e3;
|
|
2050
2201
|
_pendingRecords = [];
|
|
@@ -2500,7 +2651,7 @@ var init_employees = __esm({
|
|
|
2500
2651
|
|
|
2501
2652
|
// src/lib/license.ts
|
|
2502
2653
|
import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, existsSync as existsSync7, mkdirSync as mkdirSync4 } from "fs";
|
|
2503
|
-
import { randomUUID } from "crypto";
|
|
2654
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
2504
2655
|
import path7 from "path";
|
|
2505
2656
|
import { jwtVerify, importSPKI } from "jose";
|
|
2506
2657
|
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, PLAN_LIMITS;
|
|
@@ -2898,9 +3049,15 @@ async function createTaskCore(input) {
|
|
|
2898
3049
|
}
|
|
2899
3050
|
}
|
|
2900
3051
|
const complexity = input.complexity ?? "standard";
|
|
3052
|
+
let sessionScope = null;
|
|
3053
|
+
try {
|
|
3054
|
+
const { resolveExeSession: resolveExeSession2 } = await Promise.resolve().then(() => (init_tmux_routing(), tmux_routing_exports));
|
|
3055
|
+
sessionScope = resolveExeSession2();
|
|
3056
|
+
} catch {
|
|
3057
|
+
}
|
|
2901
3058
|
await client.execute({
|
|
2902
|
-
sql: `INSERT INTO tasks (id, title, assigned_to, assigned_by, project_name, priority, status, task_file, blocked_by, parent_task_id, reviewer, context, complexity, budget_tokens, budget_fallback_model, tokens_used, tokens_warned_at, created_at, updated_at)
|
|
2903
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
3059
|
+
sql: `INSERT INTO tasks (id, title, assigned_to, assigned_by, project_name, priority, status, task_file, blocked_by, parent_task_id, reviewer, context, complexity, budget_tokens, budget_fallback_model, tokens_used, tokens_warned_at, session_scope, created_at, updated_at)
|
|
3060
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
2904
3061
|
args: [
|
|
2905
3062
|
id,
|
|
2906
3063
|
input.title,
|
|
@@ -2919,6 +3076,7 @@ async function createTaskCore(input) {
|
|
|
2919
3076
|
input.budgetFallbackModel ?? null,
|
|
2920
3077
|
0,
|
|
2921
3078
|
null,
|
|
3079
|
+
sessionScope,
|
|
2922
3080
|
now,
|
|
2923
3081
|
now
|
|
2924
3082
|
]
|
|
@@ -2963,6 +3121,15 @@ async function listTasks(input) {
|
|
|
2963
3121
|
conditions.push("priority = ?");
|
|
2964
3122
|
args.push(input.priority);
|
|
2965
3123
|
}
|
|
3124
|
+
try {
|
|
3125
|
+
const { resolveExeSession: resolveExeSession2 } = await Promise.resolve().then(() => (init_tmux_routing(), tmux_routing_exports));
|
|
3126
|
+
const session = resolveExeSession2();
|
|
3127
|
+
if (session) {
|
|
3128
|
+
conditions.push("(session_scope IS NULL OR session_scope = ?)");
|
|
3129
|
+
args.push(session);
|
|
3130
|
+
}
|
|
3131
|
+
} catch {
|
|
3132
|
+
}
|
|
2966
3133
|
const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
2967
3134
|
const result = await client.execute({
|
|
2968
3135
|
sql: `SELECT * FROM tasks ${where} ORDER BY CASE status WHEN 'blocked' THEN 0 WHEN 'in_progress' THEN 1 WHEN 'open' THEN 2 ELSE 3 END, priority ASC, created_at DESC LIMIT 1000`,
|
|
@@ -3331,6 +3498,13 @@ async function createReviewForCompletedTask(row, result, _baseDir, now) {
|
|
|
3331
3498
|
skipDispatch: true
|
|
3332
3499
|
});
|
|
3333
3500
|
const reviewId = reviewTask.id;
|
|
3501
|
+
orgBus.emit({
|
|
3502
|
+
type: "review_created",
|
|
3503
|
+
reviewId,
|
|
3504
|
+
employee: agent,
|
|
3505
|
+
reviewer,
|
|
3506
|
+
timestamp: now
|
|
3507
|
+
});
|
|
3334
3508
|
await writeNotification({
|
|
3335
3509
|
agentId: agent,
|
|
3336
3510
|
agentRole: String(row.assigned_to),
|
|
@@ -3427,6 +3601,7 @@ var init_tasks_review = __esm({
|
|
|
3427
3601
|
init_tasks_crud();
|
|
3428
3602
|
init_tmux_routing();
|
|
3429
3603
|
init_session_key();
|
|
3604
|
+
init_state_bus();
|
|
3430
3605
|
}
|
|
3431
3606
|
});
|
|
3432
3607
|
|
|
@@ -3591,13 +3766,12 @@ function assertSessionScope(actionType, targetProject) {
|
|
|
3591
3766
|
};
|
|
3592
3767
|
}
|
|
3593
3768
|
process.stderr.write(
|
|
3594
|
-
`[session-scope]
|
|
3769
|
+
`[session-scope] BLOCKED cross-project ${actionType}: session project="${currentProject}" \u2260 target project="${targetProject}"
|
|
3595
3770
|
`
|
|
3596
3771
|
);
|
|
3597
3772
|
return {
|
|
3598
|
-
allowed:
|
|
3599
|
-
|
|
3600
|
-
reason: "cross_session_granted",
|
|
3773
|
+
allowed: false,
|
|
3774
|
+
reason: "cross_session_denied",
|
|
3601
3775
|
currentProject,
|
|
3602
3776
|
targetProject,
|
|
3603
3777
|
targetSession: findSessionForProject(targetProject)?.windowName
|
|
@@ -3623,8 +3797,9 @@ async function dispatchTaskToEmployee(input) {
|
|
|
3623
3797
|
try {
|
|
3624
3798
|
const { assertSessionScope: assertSessionScope2 } = (init_session_scope(), __toCommonJS(session_scope_exports));
|
|
3625
3799
|
const check = assertSessionScope2("dispatch_task", input.projectName);
|
|
3626
|
-
if (check.reason === "
|
|
3800
|
+
if (check.reason === "cross_session_denied") {
|
|
3627
3801
|
crossProject = true;
|
|
3802
|
+
return { dispatched: "skipped", crossProject: true };
|
|
3628
3803
|
}
|
|
3629
3804
|
} catch {
|
|
3630
3805
|
}
|
|
@@ -4087,6 +4262,13 @@ async function updateTask(input) {
|
|
|
4087
4262
|
await cascadeUnblock(taskId, input.baseDir, now);
|
|
4088
4263
|
} catch {
|
|
4089
4264
|
}
|
|
4265
|
+
orgBus.emit({
|
|
4266
|
+
type: "task_completed",
|
|
4267
|
+
taskId,
|
|
4268
|
+
employee: String(row.assigned_to),
|
|
4269
|
+
result: input.result ?? "",
|
|
4270
|
+
timestamp: now
|
|
4271
|
+
});
|
|
4090
4272
|
if (row.parent_task_id) {
|
|
4091
4273
|
try {
|
|
4092
4274
|
await checkSubtaskCompletion(String(row.parent_task_id), String(row.project_name));
|
|
@@ -4154,6 +4336,7 @@ var init_tasks = __esm({
|
|
|
4154
4336
|
init_database();
|
|
4155
4337
|
init_config();
|
|
4156
4338
|
init_notifications();
|
|
4339
|
+
init_state_bus();
|
|
4157
4340
|
init_tasks_crud();
|
|
4158
4341
|
init_tasks_review();
|
|
4159
4342
|
init_tasks_crud();
|
|
@@ -4544,8 +4727,28 @@ function getMySession() {
|
|
|
4544
4727
|
return getTransport().getMySession();
|
|
4545
4728
|
}
|
|
4546
4729
|
function employeeSessionName(employee, exeSession, instance) {
|
|
4730
|
+
if (!/^exe\d+$/.test(exeSession)) {
|
|
4731
|
+
const root = extractRootExe(exeSession);
|
|
4732
|
+
if (root) {
|
|
4733
|
+
process.stderr.write(
|
|
4734
|
+
`[tmux-routing] WARN: exeSession="${exeSession}" is not a root exe session, using "${root}" instead
|
|
4735
|
+
`
|
|
4736
|
+
);
|
|
4737
|
+
exeSession = root;
|
|
4738
|
+
} else {
|
|
4739
|
+
throw new Error(
|
|
4740
|
+
`Invalid exeSession "${exeSession}" \u2014 must be a root exe session (e.g., "exe1"), not an agent session`
|
|
4741
|
+
);
|
|
4742
|
+
}
|
|
4743
|
+
}
|
|
4547
4744
|
const suffix = instance != null && instance > 0 ? String(instance) : "";
|
|
4548
|
-
|
|
4745
|
+
const name = `${employee}${suffix}-${exeSession}`;
|
|
4746
|
+
if (!VALID_SESSION_NAME.test(name)) {
|
|
4747
|
+
throw new Error(
|
|
4748
|
+
`Invalid session name "${name}" \u2014 must match {agent}-exe{N} or {agent}{instance}-exe{N}`
|
|
4749
|
+
);
|
|
4750
|
+
}
|
|
4751
|
+
return name;
|
|
4549
4752
|
}
|
|
4550
4753
|
function parseParentExe(sessionName, agentId) {
|
|
4551
4754
|
const escaped = agentId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -4785,6 +4988,22 @@ function ensureEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
4785
4988
|
error: `Error: pass employee name ('${bare}'), not session name ('${employeeName}')`
|
|
4786
4989
|
};
|
|
4787
4990
|
}
|
|
4991
|
+
if (!/^exe\d+$/.test(exeSession)) {
|
|
4992
|
+
const root = extractRootExe(exeSession);
|
|
4993
|
+
if (root) {
|
|
4994
|
+
process.stderr.write(
|
|
4995
|
+
`[ensureEmployee] WARN: caller passed exeSession="${exeSession}" (not a root exe). Auto-correcting to "${root}".
|
|
4996
|
+
`
|
|
4997
|
+
);
|
|
4998
|
+
exeSession = root;
|
|
4999
|
+
} else {
|
|
5000
|
+
return {
|
|
5001
|
+
status: "failed",
|
|
5002
|
+
sessionName: "",
|
|
5003
|
+
error: `Invalid exeSession "${exeSession}" \u2014 must be a root exe session (e.g., "exe1")`
|
|
5004
|
+
};
|
|
5005
|
+
}
|
|
5006
|
+
}
|
|
4788
5007
|
let effectiveInstance = opts?.instance;
|
|
4789
5008
|
if (effectiveInstance === void 0 && opts?.autoInstance) {
|
|
4790
5009
|
const free = findFreeInstance(
|
|
@@ -5031,7 +5250,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
5031
5250
|
releaseSpawnLock(sessionName);
|
|
5032
5251
|
return { sessionName };
|
|
5033
5252
|
}
|
|
5034
|
-
var SPAWN_LOCK_DIR, SESSION_CACHE, BEHAVIORS_EXPORT_TIMEOUT_MS, VERIFY_PANE_LINES, INTERCOM_DEBOUNCE_MS, INTERCOM_LOG2, DEBOUNCE_FILE, DEBOUNCE_CLEANUP_AGE_MS, BUSY_PATTERN;
|
|
5253
|
+
var SPAWN_LOCK_DIR, SESSION_CACHE, BEHAVIORS_EXPORT_TIMEOUT_MS, VALID_SESSION_NAME, VERIFY_PANE_LINES, INTERCOM_DEBOUNCE_MS, INTERCOM_LOG2, DEBOUNCE_FILE, DEBOUNCE_CLEANUP_AGE_MS, BUSY_PATTERN;
|
|
5035
5254
|
var init_tmux_routing = __esm({
|
|
5036
5255
|
"src/lib/tmux-routing.ts"() {
|
|
5037
5256
|
"use strict";
|
|
@@ -5046,6 +5265,7 @@ var init_tmux_routing = __esm({
|
|
|
5046
5265
|
SPAWN_LOCK_DIR = path15.join(os6.homedir(), ".exe-os", "spawn-locks");
|
|
5047
5266
|
SESSION_CACHE = path15.join(os6.homedir(), ".exe-os", "session-cache");
|
|
5048
5267
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
5268
|
+
VALID_SESSION_NAME = /^[a-z]+-exe\d+$|^[a-z]+\d+-exe\d+$/;
|
|
5049
5269
|
VERIFY_PANE_LINES = 200;
|
|
5050
5270
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
5051
5271
|
INTERCOM_LOG2 = path15.join(os6.homedir(), ".exe-os", "intercom.log");
|
|
@@ -5903,7 +6123,7 @@ __export(consolidation_exports, {
|
|
|
5903
6123
|
selectUnconsolidated: () => selectUnconsolidated,
|
|
5904
6124
|
storeConsolidation: () => storeConsolidation
|
|
5905
6125
|
});
|
|
5906
|
-
import { randomUUID as
|
|
6126
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
5907
6127
|
async function selectUnconsolidated(client, limit = 200) {
|
|
5908
6128
|
const result = await client.execute({
|
|
5909
6129
|
sql: `SELECT id, agent_id, project_name, tool_name, raw_text, timestamp
|
|
@@ -5999,7 +6219,7 @@ async function consolidateCluster(cluster, model) {
|
|
|
5999
6219
|
return textBlock?.text ?? "";
|
|
6000
6220
|
}
|
|
6001
6221
|
async function storeConsolidation(client, cluster, synthesisText, embedFn) {
|
|
6002
|
-
const consolidatedId =
|
|
6222
|
+
const consolidatedId = randomUUID3();
|
|
6003
6223
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
6004
6224
|
const rawText = `CONSOLIDATION [${cluster.dateRange}, ${cluster.projectName}]:
|
|
6005
6225
|
|
|
@@ -6024,7 +6244,7 @@ ${synthesisText}`;
|
|
|
6024
6244
|
const linkStmts = sourceIds.map((sourceId) => ({
|
|
6025
6245
|
sql: `INSERT INTO consolidations (id, consolidated_memory_id, source_memory_id, created_at)
|
|
6026
6246
|
VALUES (?, ?, ?, ?)`,
|
|
6027
|
-
args: [
|
|
6247
|
+
args: [randomUUID3(), consolidatedId, sourceId, now]
|
|
6028
6248
|
}));
|
|
6029
6249
|
const placeholders = sourceIds.map(() => "?").join(",");
|
|
6030
6250
|
const markStmt = {
|
|
@@ -6263,7 +6483,7 @@ var init_consolidation = __esm({
|
|
|
6263
6483
|
// src/lib/exe-daemon-client.ts
|
|
6264
6484
|
import net from "net";
|
|
6265
6485
|
import { spawn } from "child_process";
|
|
6266
|
-
import { randomUUID as
|
|
6486
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
6267
6487
|
import { existsSync as existsSync14, unlinkSync as unlinkSync5, readFileSync as readFileSync11, openSync, closeSync, statSync } from "fs";
|
|
6268
6488
|
import path17 from "path";
|
|
6269
6489
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
@@ -6455,7 +6675,7 @@ function sendRequest(texts, priority) {
|
|
|
6455
6675
|
resolve({ error: "Not connected" });
|
|
6456
6676
|
return;
|
|
6457
6677
|
}
|
|
6458
|
-
const id =
|
|
6678
|
+
const id = randomUUID4();
|
|
6459
6679
|
const timer = setTimeout(() => {
|
|
6460
6680
|
_pending.delete(id);
|
|
6461
6681
|
resolve({ error: "Request timeout" });
|
|
@@ -6473,7 +6693,7 @@ function sendRequest(texts, priority) {
|
|
|
6473
6693
|
async function pingDaemon() {
|
|
6474
6694
|
if (!_socket || !_connected) return null;
|
|
6475
6695
|
return new Promise((resolve) => {
|
|
6476
|
-
const id =
|
|
6696
|
+
const id = randomUUID4();
|
|
6477
6697
|
const timer = setTimeout(() => {
|
|
6478
6698
|
_pending.delete(id);
|
|
6479
6699
|
resolve(null);
|