@askexenow/exe-os 0.8.104 → 0.8.105
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 +12 -1
- package/dist/bin/backfill-responses.js +12 -1
- package/dist/bin/backfill-vectors.js +12 -1
- package/dist/bin/cleanup-stale-review-tasks.js +12 -1
- package/dist/bin/cli.js +32 -7
- package/dist/bin/exe-assign.js +12 -1
- package/dist/bin/exe-boot.js +84 -10
- package/dist/bin/exe-call.js +138 -10
- package/dist/bin/exe-dispatch.js +31 -6
- package/dist/bin/exe-doctor.js +12 -1
- package/dist/bin/exe-export-behaviors.js +12 -1
- package/dist/bin/exe-forget.js +65 -3
- package/dist/bin/exe-gateway.js +31 -6
- package/dist/bin/exe-heartbeat.js +16 -5
- package/dist/bin/exe-kill.js +12 -1
- package/dist/bin/exe-launch-agent.js +12 -1
- package/dist/bin/exe-link.js +12 -1
- package/dist/bin/exe-pending-messages.js +12 -1
- package/dist/bin/exe-pending-notifications.js +12 -1
- package/dist/bin/exe-pending-reviews.js +39 -6
- package/dist/bin/exe-rename.js +12 -1
- package/dist/bin/exe-review.js +12 -1
- package/dist/bin/exe-search.js +65 -3
- package/dist/bin/exe-session-cleanup.js +50 -8
- package/dist/bin/exe-start-codex.js +13 -2
- package/dist/bin/exe-start-opencode.js +12 -1
- package/dist/bin/exe-status.js +12 -1
- package/dist/bin/exe-team.js +12 -1
- package/dist/bin/git-sweep.js +31 -6
- package/dist/bin/graph-backfill.js +12 -1
- package/dist/bin/graph-export.js +12 -1
- package/dist/bin/scan-tasks.js +31 -6
- package/dist/bin/setup.js +12 -1
- package/dist/bin/shard-migrate.js +12 -1
- package/dist/bin/wiki-sync.js +12 -1
- package/dist/gateway/index.js +31 -6
- package/dist/hooks/bug-report-worker.js +31 -6
- package/dist/hooks/commit-complete.js +31 -6
- package/dist/hooks/error-recall.js +65 -3
- package/dist/hooks/ingest-worker.js +31 -6
- package/dist/hooks/instructions-loaded.js +12 -1
- package/dist/hooks/notification.js +12 -1
- package/dist/hooks/post-compact.js +12 -1
- package/dist/hooks/pre-compact.js +31 -6
- package/dist/hooks/pre-tool-use.js +12 -1
- package/dist/hooks/prompt-ingest-worker.js +12 -1
- package/dist/hooks/prompt-submit.js +120 -13
- package/dist/hooks/response-ingest-worker.js +12 -1
- package/dist/hooks/session-end.js +31 -6
- package/dist/hooks/session-start.js +65 -3
- package/dist/hooks/stop.js +12 -1
- package/dist/hooks/subagent-stop.js +12 -1
- package/dist/hooks/summary-worker.js +12 -1
- package/dist/index.js +31 -6
- package/dist/lib/cloud-sync.js +12 -1
- package/dist/lib/database.js +11 -0
- package/dist/lib/device-registry.js +12 -1
- package/dist/lib/exe-daemon.js +48 -6
- package/dist/lib/hybrid-search.js +65 -3
- package/dist/lib/messaging.js +30 -2
- package/dist/lib/schedules.js +12 -1
- package/dist/lib/status-brief.js +24 -0
- package/dist/lib/store.js +12 -1
- package/dist/lib/tasks.js +19 -5
- package/dist/lib/tmux-routing.js +19 -5
- package/dist/mcp/server.js +84 -8
- package/dist/mcp/tools/create-task.js +19 -5
- package/dist/mcp/tools/send-message.js +32 -4
- package/dist/mcp/tools/update-task.js +42 -10
- package/dist/runtime/index.js +31 -6
- package/dist/tui/App.js +31 -6
- package/package.json +4 -2
|
@@ -304,6 +304,16 @@ async function initDatabase(config) {
|
|
|
304
304
|
}
|
|
305
305
|
_client = createClient(opts);
|
|
306
306
|
_resilientClient = wrapWithRetry(_client);
|
|
307
|
+
_client.execute("PRAGMA busy_timeout = 30000").catch(() => {
|
|
308
|
+
});
|
|
309
|
+
_client.execute("PRAGMA journal_mode = WAL").catch(() => {
|
|
310
|
+
});
|
|
311
|
+
if (_walCheckpointTimer) clearInterval(_walCheckpointTimer);
|
|
312
|
+
_walCheckpointTimer = setInterval(() => {
|
|
313
|
+
_client?.execute("PRAGMA wal_checkpoint(PASSIVE)").catch(() => {
|
|
314
|
+
});
|
|
315
|
+
}, 3e4);
|
|
316
|
+
_walCheckpointTimer.unref();
|
|
307
317
|
}
|
|
308
318
|
function getClient() {
|
|
309
319
|
if (!_resilientClient) {
|
|
@@ -1248,7 +1258,7 @@ async function ensureSchema() {
|
|
|
1248
1258
|
}
|
|
1249
1259
|
}
|
|
1250
1260
|
}
|
|
1251
|
-
var _client, _resilientClient, _daemonClient, initTurso;
|
|
1261
|
+
var _client, _resilientClient, _walCheckpointTimer, _daemonClient, initTurso;
|
|
1252
1262
|
var init_database = __esm({
|
|
1253
1263
|
"src/lib/database.ts"() {
|
|
1254
1264
|
"use strict";
|
|
@@ -1256,6 +1266,7 @@ var init_database = __esm({
|
|
|
1256
1266
|
init_employees();
|
|
1257
1267
|
_client = null;
|
|
1258
1268
|
_resilientClient = null;
|
|
1269
|
+
_walCheckpointTimer = null;
|
|
1259
1270
|
_daemonClient = null;
|
|
1260
1271
|
initTurso = initDatabase;
|
|
1261
1272
|
}
|
|
@@ -304,6 +304,16 @@ async function initDatabase(config) {
|
|
|
304
304
|
}
|
|
305
305
|
_client = createClient(opts);
|
|
306
306
|
_resilientClient = wrapWithRetry(_client);
|
|
307
|
+
_client.execute("PRAGMA busy_timeout = 30000").catch(() => {
|
|
308
|
+
});
|
|
309
|
+
_client.execute("PRAGMA journal_mode = WAL").catch(() => {
|
|
310
|
+
});
|
|
311
|
+
if (_walCheckpointTimer) clearInterval(_walCheckpointTimer);
|
|
312
|
+
_walCheckpointTimer = setInterval(() => {
|
|
313
|
+
_client?.execute("PRAGMA wal_checkpoint(PASSIVE)").catch(() => {
|
|
314
|
+
});
|
|
315
|
+
}, 3e4);
|
|
316
|
+
_walCheckpointTimer.unref();
|
|
307
317
|
}
|
|
308
318
|
function getClient() {
|
|
309
319
|
if (!_resilientClient) {
|
|
@@ -1248,7 +1258,7 @@ async function ensureSchema() {
|
|
|
1248
1258
|
}
|
|
1249
1259
|
}
|
|
1250
1260
|
}
|
|
1251
|
-
var _client, _resilientClient, _daemonClient, initTurso;
|
|
1261
|
+
var _client, _resilientClient, _walCheckpointTimer, _daemonClient, initTurso;
|
|
1252
1262
|
var init_database = __esm({
|
|
1253
1263
|
"src/lib/database.ts"() {
|
|
1254
1264
|
"use strict";
|
|
@@ -1256,6 +1266,7 @@ var init_database = __esm({
|
|
|
1256
1266
|
init_employees();
|
|
1257
1267
|
_client = null;
|
|
1258
1268
|
_resilientClient = null;
|
|
1269
|
+
_walCheckpointTimer = null;
|
|
1259
1270
|
_daemonClient = null;
|
|
1260
1271
|
initTurso = initDatabase;
|
|
1261
1272
|
}
|
|
@@ -306,6 +306,16 @@ async function initDatabase(config) {
|
|
|
306
306
|
}
|
|
307
307
|
_client = createClient(opts);
|
|
308
308
|
_resilientClient = wrapWithRetry(_client);
|
|
309
|
+
_client.execute("PRAGMA busy_timeout = 30000").catch(() => {
|
|
310
|
+
});
|
|
311
|
+
_client.execute("PRAGMA journal_mode = WAL").catch(() => {
|
|
312
|
+
});
|
|
313
|
+
if (_walCheckpointTimer) clearInterval(_walCheckpointTimer);
|
|
314
|
+
_walCheckpointTimer = setInterval(() => {
|
|
315
|
+
_client?.execute("PRAGMA wal_checkpoint(PASSIVE)").catch(() => {
|
|
316
|
+
});
|
|
317
|
+
}, 3e4);
|
|
318
|
+
_walCheckpointTimer.unref();
|
|
309
319
|
}
|
|
310
320
|
function getClient() {
|
|
311
321
|
if (!_resilientClient) {
|
|
@@ -1250,7 +1260,7 @@ async function ensureSchema() {
|
|
|
1250
1260
|
}
|
|
1251
1261
|
}
|
|
1252
1262
|
}
|
|
1253
|
-
var _client, _resilientClient, _daemonClient, initTurso;
|
|
1263
|
+
var _client, _resilientClient, _walCheckpointTimer, _daemonClient, initTurso;
|
|
1254
1264
|
var init_database = __esm({
|
|
1255
1265
|
"src/lib/database.ts"() {
|
|
1256
1266
|
"use strict";
|
|
@@ -1258,6 +1268,7 @@ var init_database = __esm({
|
|
|
1258
1268
|
init_employees();
|
|
1259
1269
|
_client = null;
|
|
1260
1270
|
_resilientClient = null;
|
|
1271
|
+
_walCheckpointTimer = null;
|
|
1261
1272
|
_daemonClient = null;
|
|
1262
1273
|
initTurso = initDatabase;
|
|
1263
1274
|
}
|
|
@@ -311,6 +311,16 @@ async function initDatabase(config) {
|
|
|
311
311
|
}
|
|
312
312
|
_client = createClient(opts);
|
|
313
313
|
_resilientClient = wrapWithRetry(_client);
|
|
314
|
+
_client.execute("PRAGMA busy_timeout = 30000").catch(() => {
|
|
315
|
+
});
|
|
316
|
+
_client.execute("PRAGMA journal_mode = WAL").catch(() => {
|
|
317
|
+
});
|
|
318
|
+
if (_walCheckpointTimer) clearInterval(_walCheckpointTimer);
|
|
319
|
+
_walCheckpointTimer = setInterval(() => {
|
|
320
|
+
_client?.execute("PRAGMA wal_checkpoint(PASSIVE)").catch(() => {
|
|
321
|
+
});
|
|
322
|
+
}, 3e4);
|
|
323
|
+
_walCheckpointTimer.unref();
|
|
314
324
|
}
|
|
315
325
|
function getClient() {
|
|
316
326
|
if (!_resilientClient) {
|
|
@@ -1255,7 +1265,7 @@ async function ensureSchema() {
|
|
|
1255
1265
|
}
|
|
1256
1266
|
}
|
|
1257
1267
|
}
|
|
1258
|
-
var _client, _resilientClient, _daemonClient, initTurso;
|
|
1268
|
+
var _client, _resilientClient, _walCheckpointTimer, _daemonClient, initTurso;
|
|
1259
1269
|
var init_database = __esm({
|
|
1260
1270
|
"src/lib/database.ts"() {
|
|
1261
1271
|
"use strict";
|
|
@@ -1263,6 +1273,7 @@ var init_database = __esm({
|
|
|
1263
1273
|
init_employees();
|
|
1264
1274
|
_client = null;
|
|
1265
1275
|
_resilientClient = null;
|
|
1276
|
+
_walCheckpointTimer = null;
|
|
1266
1277
|
_daemonClient = null;
|
|
1267
1278
|
initTurso = initDatabase;
|
|
1268
1279
|
}
|
package/dist/bin/cli.js
CHANGED
|
@@ -1967,6 +1967,16 @@ async function initDatabase(config) {
|
|
|
1967
1967
|
}
|
|
1968
1968
|
_client = createClient(opts);
|
|
1969
1969
|
_resilientClient = wrapWithRetry(_client);
|
|
1970
|
+
_client.execute("PRAGMA busy_timeout = 30000").catch(() => {
|
|
1971
|
+
});
|
|
1972
|
+
_client.execute("PRAGMA journal_mode = WAL").catch(() => {
|
|
1973
|
+
});
|
|
1974
|
+
if (_walCheckpointTimer) clearInterval(_walCheckpointTimer);
|
|
1975
|
+
_walCheckpointTimer = setInterval(() => {
|
|
1976
|
+
_client?.execute("PRAGMA wal_checkpoint(PASSIVE)").catch(() => {
|
|
1977
|
+
});
|
|
1978
|
+
}, 3e4);
|
|
1979
|
+
_walCheckpointTimer.unref();
|
|
1970
1980
|
}
|
|
1971
1981
|
function isInitialized() {
|
|
1972
1982
|
return _client !== null;
|
|
@@ -2938,7 +2948,7 @@ async function disposeDatabase() {
|
|
|
2938
2948
|
_resilientClient = null;
|
|
2939
2949
|
}
|
|
2940
2950
|
}
|
|
2941
|
-
var _client, _resilientClient, _daemonClient, initTurso, disposeTurso;
|
|
2951
|
+
var _client, _resilientClient, _walCheckpointTimer, _daemonClient, initTurso, disposeTurso;
|
|
2942
2952
|
var init_database = __esm({
|
|
2943
2953
|
"src/lib/database.ts"() {
|
|
2944
2954
|
"use strict";
|
|
@@ -2946,6 +2956,7 @@ var init_database = __esm({
|
|
|
2946
2956
|
init_employees();
|
|
2947
2957
|
_client = null;
|
|
2948
2958
|
_resilientClient = null;
|
|
2959
|
+
_walCheckpointTimer = null;
|
|
2949
2960
|
_daemonClient = null;
|
|
2950
2961
|
initTurso = initDatabase;
|
|
2951
2962
|
disposeTurso = disposeDatabase;
|
|
@@ -8054,6 +8065,10 @@ ${input.result}` : `\u26A0\uFE0F ${warning}`;
|
|
|
8054
8065
|
args: [input.status, now, taskId]
|
|
8055
8066
|
});
|
|
8056
8067
|
}
|
|
8068
|
+
try {
|
|
8069
|
+
await client.execute("PRAGMA wal_checkpoint(PASSIVE)");
|
|
8070
|
+
} catch {
|
|
8071
|
+
}
|
|
8057
8072
|
try {
|
|
8058
8073
|
await writeCheckpoint({
|
|
8059
8074
|
taskId,
|
|
@@ -8184,18 +8199,18 @@ async function listPendingReviews(limit, sessionScope) {
|
|
|
8184
8199
|
const client = getClient();
|
|
8185
8200
|
if (sessionScope) {
|
|
8186
8201
|
const result2 = await client.execute({
|
|
8187
|
-
sql: `SELECT title, assigned_to, project_name FROM tasks
|
|
8202
|
+
sql: `SELECT title, assigned_to, project_name, updated_at FROM tasks
|
|
8188
8203
|
WHERE status = 'needs_review'
|
|
8189
8204
|
AND session_scope = ?
|
|
8190
|
-
ORDER BY
|
|
8205
|
+
ORDER BY updated_at ASC LIMIT ?`,
|
|
8191
8206
|
args: [sessionScope, limit]
|
|
8192
8207
|
});
|
|
8193
8208
|
return result2.rows;
|
|
8194
8209
|
}
|
|
8195
8210
|
const result = await client.execute({
|
|
8196
|
-
sql: `SELECT title, assigned_to, project_name FROM tasks
|
|
8211
|
+
sql: `SELECT title, assigned_to, project_name, updated_at FROM tasks
|
|
8197
8212
|
WHERE status = 'needs_review'
|
|
8198
|
-
ORDER BY
|
|
8213
|
+
ORDER BY updated_at ASC LIMIT ?`,
|
|
8199
8214
|
args: [limit]
|
|
8200
8215
|
});
|
|
8201
8216
|
return result.rows;
|
|
@@ -9740,7 +9755,17 @@ function sendIntercom(targetSession) {
|
|
|
9740
9755
|
logIntercom(`COPY_MODE \u2192 ${targetSession} (exiting copy mode first)`);
|
|
9741
9756
|
transport.sendKeys(targetSession, "q");
|
|
9742
9757
|
}
|
|
9743
|
-
|
|
9758
|
+
const agentName = targetSession.split("-")[0] ?? targetSession;
|
|
9759
|
+
const rtConfig = getAgentRuntime(agentName);
|
|
9760
|
+
if (rtConfig.runtime === "codex" || rtConfig.runtime === "opencode") {
|
|
9761
|
+
transport.sendKeys(targetSession, "You have a new task assigned. Call list_tasks to see your open tasks, then get_task to read the highest priority one. Start working now.");
|
|
9762
|
+
try {
|
|
9763
|
+
execSync8(`tmux send-keys -t ${targetSession} Tab`, { timeout: 2e3 });
|
|
9764
|
+
} catch {
|
|
9765
|
+
}
|
|
9766
|
+
} else {
|
|
9767
|
+
transport.sendKeys(targetSession, "/exe-intercom");
|
|
9768
|
+
}
|
|
9744
9769
|
const batched = recordDebounce(targetSession);
|
|
9745
9770
|
logIntercom(`DELIVERED \u2192 ${targetSession}${batched > 0 ? ` [${batched} nudges batched during debounce]` : ""} (fire-and-forget)`);
|
|
9746
9771
|
return "delivered";
|
|
@@ -27521,7 +27546,7 @@ async function mergeCodexHooks(packageRoot, homeDir = os15.homedir()) {
|
|
|
27521
27546
|
{
|
|
27522
27547
|
type: "command",
|
|
27523
27548
|
command: `node "${path39.join(packageRoot, "dist", "hooks", "session-start.js")}"`,
|
|
27524
|
-
timeout:
|
|
27549
|
+
timeout: 30,
|
|
27525
27550
|
statusMessage: "exe-os: loading memory brief"
|
|
27526
27551
|
}
|
|
27527
27552
|
]
|
package/dist/bin/exe-assign.js
CHANGED
|
@@ -651,6 +651,16 @@ async function initDatabase(config) {
|
|
|
651
651
|
}
|
|
652
652
|
_client = createClient(opts);
|
|
653
653
|
_resilientClient = wrapWithRetry(_client);
|
|
654
|
+
_client.execute("PRAGMA busy_timeout = 30000").catch(() => {
|
|
655
|
+
});
|
|
656
|
+
_client.execute("PRAGMA journal_mode = WAL").catch(() => {
|
|
657
|
+
});
|
|
658
|
+
if (_walCheckpointTimer) clearInterval(_walCheckpointTimer);
|
|
659
|
+
_walCheckpointTimer = setInterval(() => {
|
|
660
|
+
_client?.execute("PRAGMA wal_checkpoint(PASSIVE)").catch(() => {
|
|
661
|
+
});
|
|
662
|
+
}, 3e4);
|
|
663
|
+
_walCheckpointTimer.unref();
|
|
654
664
|
}
|
|
655
665
|
function getClient() {
|
|
656
666
|
if (!_resilientClient) {
|
|
@@ -1595,7 +1605,7 @@ async function ensureSchema() {
|
|
|
1595
1605
|
}
|
|
1596
1606
|
}
|
|
1597
1607
|
}
|
|
1598
|
-
var _client, _resilientClient, _daemonClient, initTurso;
|
|
1608
|
+
var _client, _resilientClient, _walCheckpointTimer, _daemonClient, initTurso;
|
|
1599
1609
|
var init_database = __esm({
|
|
1600
1610
|
"src/lib/database.ts"() {
|
|
1601
1611
|
"use strict";
|
|
@@ -1603,6 +1613,7 @@ var init_database = __esm({
|
|
|
1603
1613
|
init_employees();
|
|
1604
1614
|
_client = null;
|
|
1605
1615
|
_resilientClient = null;
|
|
1616
|
+
_walCheckpointTimer = null;
|
|
1606
1617
|
_daemonClient = null;
|
|
1607
1618
|
initTurso = initDatabase;
|
|
1608
1619
|
}
|
package/dist/bin/exe-boot.js
CHANGED
|
@@ -911,6 +911,16 @@ async function initDatabase(config) {
|
|
|
911
911
|
}
|
|
912
912
|
_client = createClient(opts);
|
|
913
913
|
_resilientClient = wrapWithRetry(_client);
|
|
914
|
+
_client.execute("PRAGMA busy_timeout = 30000").catch(() => {
|
|
915
|
+
});
|
|
916
|
+
_client.execute("PRAGMA journal_mode = WAL").catch(() => {
|
|
917
|
+
});
|
|
918
|
+
if (_walCheckpointTimer) clearInterval(_walCheckpointTimer);
|
|
919
|
+
_walCheckpointTimer = setInterval(() => {
|
|
920
|
+
_client?.execute("PRAGMA wal_checkpoint(PASSIVE)").catch(() => {
|
|
921
|
+
});
|
|
922
|
+
}, 3e4);
|
|
923
|
+
_walCheckpointTimer.unref();
|
|
914
924
|
}
|
|
915
925
|
function isInitialized() {
|
|
916
926
|
return _client !== null;
|
|
@@ -1882,7 +1892,7 @@ async function disposeDatabase() {
|
|
|
1882
1892
|
_resilientClient = null;
|
|
1883
1893
|
}
|
|
1884
1894
|
}
|
|
1885
|
-
var _client, _resilientClient, _daemonClient, initTurso, disposeTurso;
|
|
1895
|
+
var _client, _resilientClient, _walCheckpointTimer, _daemonClient, initTurso, disposeTurso;
|
|
1886
1896
|
var init_database = __esm({
|
|
1887
1897
|
"src/lib/database.ts"() {
|
|
1888
1898
|
"use strict";
|
|
@@ -1890,6 +1900,7 @@ var init_database = __esm({
|
|
|
1890
1900
|
init_employees();
|
|
1891
1901
|
_client = null;
|
|
1892
1902
|
_resilientClient = null;
|
|
1903
|
+
_walCheckpointTimer = null;
|
|
1893
1904
|
_daemonClient = null;
|
|
1894
1905
|
initTurso = initDatabase;
|
|
1895
1906
|
disposeTurso = disposeDatabase;
|
|
@@ -4218,6 +4229,10 @@ ${input.result}` : `\u26A0\uFE0F ${warning}`;
|
|
|
4218
4229
|
args: [input.status, now, taskId]
|
|
4219
4230
|
});
|
|
4220
4231
|
}
|
|
4232
|
+
try {
|
|
4233
|
+
await client.execute("PRAGMA wal_checkpoint(PASSIVE)");
|
|
4234
|
+
} catch {
|
|
4235
|
+
}
|
|
4221
4236
|
try {
|
|
4222
4237
|
await writeCheckpoint({
|
|
4223
4238
|
taskId,
|
|
@@ -4348,18 +4363,18 @@ async function listPendingReviews(limit, sessionScope) {
|
|
|
4348
4363
|
const client = getClient();
|
|
4349
4364
|
if (sessionScope) {
|
|
4350
4365
|
const result2 = await client.execute({
|
|
4351
|
-
sql: `SELECT title, assigned_to, project_name FROM tasks
|
|
4366
|
+
sql: `SELECT title, assigned_to, project_name, updated_at FROM tasks
|
|
4352
4367
|
WHERE status = 'needs_review'
|
|
4353
4368
|
AND session_scope = ?
|
|
4354
|
-
ORDER BY
|
|
4369
|
+
ORDER BY updated_at ASC LIMIT ?`,
|
|
4355
4370
|
args: [sessionScope, limit]
|
|
4356
4371
|
});
|
|
4357
4372
|
return result2.rows;
|
|
4358
4373
|
}
|
|
4359
4374
|
const result = await client.execute({
|
|
4360
|
-
sql: `SELECT title, assigned_to, project_name FROM tasks
|
|
4375
|
+
sql: `SELECT title, assigned_to, project_name, updated_at FROM tasks
|
|
4361
4376
|
WHERE status = 'needs_review'
|
|
4362
|
-
ORDER BY
|
|
4377
|
+
ORDER BY updated_at ASC LIMIT ?`,
|
|
4363
4378
|
args: [limit]
|
|
4364
4379
|
});
|
|
4365
4380
|
return result.rows;
|
|
@@ -5913,7 +5928,17 @@ function sendIntercom(targetSession) {
|
|
|
5913
5928
|
logIntercom(`COPY_MODE \u2192 ${targetSession} (exiting copy mode first)`);
|
|
5914
5929
|
transport.sendKeys(targetSession, "q");
|
|
5915
5930
|
}
|
|
5916
|
-
|
|
5931
|
+
const agentName = targetSession.split("-")[0] ?? targetSession;
|
|
5932
|
+
const rtConfig = getAgentRuntime(agentName);
|
|
5933
|
+
if (rtConfig.runtime === "codex" || rtConfig.runtime === "opencode") {
|
|
5934
|
+
transport.sendKeys(targetSession, "You have a new task assigned. Call list_tasks to see your open tasks, then get_task to read the highest priority one. Start working now.");
|
|
5935
|
+
try {
|
|
5936
|
+
execSync7(`tmux send-keys -t ${targetSession} Tab`, { timeout: 2e3 });
|
|
5937
|
+
} catch {
|
|
5938
|
+
}
|
|
5939
|
+
} else {
|
|
5940
|
+
transport.sendKeys(targetSession, "/exe-intercom");
|
|
5941
|
+
}
|
|
5917
5942
|
const batched = recordDebounce(targetSession);
|
|
5918
5943
|
logIntercom(`DELIVERED \u2192 ${targetSession}${batched > 0 ? ` [${batched} nudges batched during debounce]` : ""} (fire-and-forget)`);
|
|
5919
5944
|
return "delivered";
|
|
@@ -8337,6 +8362,30 @@ function buildReminders(data) {
|
|
|
8337
8362
|
function buildActionRequired(data) {
|
|
8338
8363
|
const lines = [];
|
|
8339
8364
|
let hasIssues = false;
|
|
8365
|
+
const STALE_REVIEW_MS = 24 * 60 * 60 * 1e3;
|
|
8366
|
+
const staleReviews = data.pendingReviews.filter(
|
|
8367
|
+
(r) => r.updatedAt && Date.now() - new Date(r.updatedAt).getTime() > STALE_REVIEW_MS
|
|
8368
|
+
);
|
|
8369
|
+
if (staleReviews.length > 0) {
|
|
8370
|
+
hasIssues = true;
|
|
8371
|
+
const oldest = staleReviews.reduce(
|
|
8372
|
+
(a, b) => new Date(a.updatedAt).getTime() < new Date(b.updatedAt).getTime() ? a : b
|
|
8373
|
+
);
|
|
8374
|
+
const oldestAge = ((Date.now() - new Date(oldest.updatedAt).getTime()) / 36e5).toFixed(0);
|
|
8375
|
+
lines.push(` \u{1F534} ${staleReviews.length} STALE REVIEW${staleReviews.length === 1 ? "" : "S"} (>24h, oldest: ${oldestAge}h) \u2014 run /exe-review`);
|
|
8376
|
+
}
|
|
8377
|
+
if (data.pendingReviews.length > 0 && staleReviews.length === 0) {
|
|
8378
|
+
const oldest = data.pendingReviews.reduce((a, b) => {
|
|
8379
|
+
if (!a.updatedAt || !b.updatedAt) return a;
|
|
8380
|
+
return new Date(a.updatedAt).getTime() < new Date(b.updatedAt).getTime() ? a : b;
|
|
8381
|
+
});
|
|
8382
|
+
const ageStr = oldest.updatedAt ? (() => {
|
|
8383
|
+
const hrs = (Date.now() - new Date(oldest.updatedAt).getTime()) / 36e5;
|
|
8384
|
+
return hrs < 1 ? `${Math.floor(hrs * 60)}m` : `${hrs.toFixed(0)}h`;
|
|
8385
|
+
})() : "";
|
|
8386
|
+
lines.push(` \u{1F4CB} ${data.pendingReviews.length} review${data.pendingReviews.length === 1 ? "" : "s"} pending${ageStr ? ` (oldest: ${ageStr})` : ""}`);
|
|
8387
|
+
hasIssues = true;
|
|
8388
|
+
}
|
|
8340
8389
|
const blockedTasks = data.globalTasks.filter((t) => t.status === "blocked");
|
|
8341
8390
|
if (blockedTasks.length > 0) {
|
|
8342
8391
|
hasIssues = true;
|
|
@@ -8829,7 +8878,7 @@ async function boot(options) {
|
|
|
8829
8878
|
const revScope = sessionScopeFilter();
|
|
8830
8879
|
try {
|
|
8831
8880
|
const result = await client.execute({
|
|
8832
|
-
sql: `SELECT t.title, t.priority, t.created_at,
|
|
8881
|
+
sql: `SELECT t.title, t.priority, t.created_at, t.updated_at,
|
|
8833
8882
|
COALESCE(
|
|
8834
8883
|
(SELECT orig.assigned_to FROM tasks orig WHERE orig.task_file = REPLACE(REPLACE(t.task_file, 'review-', ''), 'exe/exe/', 'exe/' || orig.assigned_to || '/')),
|
|
8835
8884
|
REPLACE(SUBSTR(t.title, INSTR(t.title, 'review-') + 7), SUBSTR(t.title, INSTR(t.title, '-')), '')
|
|
@@ -8844,12 +8893,13 @@ async function boot(options) {
|
|
|
8844
8893
|
title: String(row.title),
|
|
8845
8894
|
priority: String(row.priority),
|
|
8846
8895
|
originalAssignee: String(row.original_assignee || "unknown"),
|
|
8847
|
-
createdAt: String(row.created_at || "")
|
|
8896
|
+
createdAt: String(row.created_at || ""),
|
|
8897
|
+
updatedAt: String(row.updated_at || row.created_at || "")
|
|
8848
8898
|
}));
|
|
8849
8899
|
} catch {
|
|
8850
8900
|
try {
|
|
8851
8901
|
const result = await client.execute({
|
|
8852
|
-
sql: `SELECT title, priority, created_at
|
|
8902
|
+
sql: `SELECT title, priority, created_at, updated_at
|
|
8853
8903
|
FROM tasks
|
|
8854
8904
|
WHERE (assigned_to = ? OR assigned_to = 'exe') AND status IN ('open', 'in_progress')
|
|
8855
8905
|
AND task_file LIKE '%review-%'${revScope.sql}
|
|
@@ -8863,13 +8913,37 @@ async function boot(options) {
|
|
|
8863
8913
|
title,
|
|
8864
8914
|
priority: String(row.priority),
|
|
8865
8915
|
originalAssignee: match?.[1] ?? "unknown",
|
|
8866
|
-
createdAt: String(row.created_at || "")
|
|
8916
|
+
createdAt: String(row.created_at || ""),
|
|
8917
|
+
updatedAt: String(row.updated_at || row.created_at || "")
|
|
8867
8918
|
};
|
|
8868
8919
|
});
|
|
8869
8920
|
} catch {
|
|
8870
8921
|
briefData.pendingReviews = [];
|
|
8871
8922
|
}
|
|
8872
8923
|
}
|
|
8924
|
+
try {
|
|
8925
|
+
const nrScope = sessionScopeFilter();
|
|
8926
|
+
const nrResult = await client.execute({
|
|
8927
|
+
sql: `SELECT title, priority, assigned_to, created_at, updated_at
|
|
8928
|
+
FROM tasks WHERE status = 'needs_review'${nrScope.sql}
|
|
8929
|
+
ORDER BY updated_at ASC`,
|
|
8930
|
+
args: [...nrScope.args]
|
|
8931
|
+
});
|
|
8932
|
+
const existingTitles = new Set(briefData.pendingReviews.map((r) => r.title));
|
|
8933
|
+
for (const row of nrResult.rows) {
|
|
8934
|
+
const title = String(row.title);
|
|
8935
|
+
if (!existingTitles.has(title)) {
|
|
8936
|
+
briefData.pendingReviews.push({
|
|
8937
|
+
title,
|
|
8938
|
+
priority: String(row.priority),
|
|
8939
|
+
originalAssignee: String(row.assigned_to || "unknown"),
|
|
8940
|
+
createdAt: String(row.created_at || ""),
|
|
8941
|
+
updatedAt: String(row.updated_at || row.created_at || "")
|
|
8942
|
+
});
|
|
8943
|
+
}
|
|
8944
|
+
}
|
|
8945
|
+
} catch {
|
|
8946
|
+
}
|
|
8873
8947
|
})(),
|
|
8874
8948
|
// Global task queue — all open/in_progress/blocked tasks
|
|
8875
8949
|
(async () => {
|
package/dist/bin/exe-call.js
CHANGED
|
@@ -1082,10 +1082,122 @@ All memory, tasks, behaviors, documents, and wiki content belonging to {{company
|
|
|
1082
1082
|
}
|
|
1083
1083
|
});
|
|
1084
1084
|
|
|
1085
|
+
// src/lib/runtime-table.ts
|
|
1086
|
+
var RUNTIME_TABLE, DEFAULT_RUNTIME;
|
|
1087
|
+
var init_runtime_table = __esm({
|
|
1088
|
+
"src/lib/runtime-table.ts"() {
|
|
1089
|
+
"use strict";
|
|
1090
|
+
RUNTIME_TABLE = {
|
|
1091
|
+
codex: {
|
|
1092
|
+
binary: "codex",
|
|
1093
|
+
launchMode: "interactive",
|
|
1094
|
+
autoApproveFlag: "--dangerously-bypass-approvals-and-sandbox",
|
|
1095
|
+
inlineFlag: "--no-alt-screen",
|
|
1096
|
+
apiKeyEnv: "OPENAI_API_KEY",
|
|
1097
|
+
defaultModel: "gpt-5.4"
|
|
1098
|
+
},
|
|
1099
|
+
opencode: {
|
|
1100
|
+
binary: "opencode",
|
|
1101
|
+
launchMode: "exec",
|
|
1102
|
+
autoApproveFlag: "--dangerously-skip-permissions",
|
|
1103
|
+
inlineFlag: "",
|
|
1104
|
+
apiKeyEnv: "ANTHROPIC_API_KEY",
|
|
1105
|
+
defaultModel: "anthropic/claude-sonnet-4-6"
|
|
1106
|
+
}
|
|
1107
|
+
};
|
|
1108
|
+
DEFAULT_RUNTIME = "claude";
|
|
1109
|
+
}
|
|
1110
|
+
});
|
|
1111
|
+
|
|
1112
|
+
// src/lib/agent-config.ts
|
|
1113
|
+
var agent_config_exports = {};
|
|
1114
|
+
__export(agent_config_exports, {
|
|
1115
|
+
AGENT_CONFIG_PATH: () => AGENT_CONFIG_PATH,
|
|
1116
|
+
DEFAULT_MODELS: () => DEFAULT_MODELS,
|
|
1117
|
+
KNOWN_RUNTIMES: () => KNOWN_RUNTIMES,
|
|
1118
|
+
RUNTIME_LABELS: () => RUNTIME_LABELS,
|
|
1119
|
+
clearAgentRuntime: () => clearAgentRuntime,
|
|
1120
|
+
getAgentRuntime: () => getAgentRuntime,
|
|
1121
|
+
loadAgentConfig: () => loadAgentConfig,
|
|
1122
|
+
saveAgentConfig: () => saveAgentConfig,
|
|
1123
|
+
setAgentRuntime: () => setAgentRuntime
|
|
1124
|
+
});
|
|
1125
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync3, mkdirSync } from "fs";
|
|
1126
|
+
import path3 from "path";
|
|
1127
|
+
function loadAgentConfig() {
|
|
1128
|
+
if (!existsSync3(AGENT_CONFIG_PATH)) return {};
|
|
1129
|
+
try {
|
|
1130
|
+
return JSON.parse(readFileSync3(AGENT_CONFIG_PATH, "utf-8"));
|
|
1131
|
+
} catch {
|
|
1132
|
+
return {};
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
function saveAgentConfig(config) {
|
|
1136
|
+
const dir = path3.dirname(AGENT_CONFIG_PATH);
|
|
1137
|
+
if (!existsSync3(dir)) mkdirSync(dir, { recursive: true });
|
|
1138
|
+
writeFileSync2(AGENT_CONFIG_PATH, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
1139
|
+
}
|
|
1140
|
+
function getAgentRuntime(agentId) {
|
|
1141
|
+
const config = loadAgentConfig();
|
|
1142
|
+
const entry = config[agentId];
|
|
1143
|
+
if (entry) return entry;
|
|
1144
|
+
const orgDefault = config["default"];
|
|
1145
|
+
if (orgDefault) return orgDefault;
|
|
1146
|
+
return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
|
|
1147
|
+
}
|
|
1148
|
+
function setAgentRuntime(agentId, runtime, model) {
|
|
1149
|
+
const knownModels = KNOWN_RUNTIMES[runtime];
|
|
1150
|
+
if (!knownModels) {
|
|
1151
|
+
return {
|
|
1152
|
+
ok: false,
|
|
1153
|
+
error: `Unknown runtime "${runtime}". Valid: ${Object.keys(KNOWN_RUNTIMES).join(", ")}`
|
|
1154
|
+
};
|
|
1155
|
+
}
|
|
1156
|
+
if (!knownModels.includes(model)) {
|
|
1157
|
+
return {
|
|
1158
|
+
ok: false,
|
|
1159
|
+
error: `Unknown model "${model}" for runtime "${runtime}". Valid: ${knownModels.join(", ")}`
|
|
1160
|
+
};
|
|
1161
|
+
}
|
|
1162
|
+
const config = loadAgentConfig();
|
|
1163
|
+
config[agentId] = { runtime, model };
|
|
1164
|
+
saveAgentConfig(config);
|
|
1165
|
+
return { ok: true };
|
|
1166
|
+
}
|
|
1167
|
+
function clearAgentRuntime(agentId) {
|
|
1168
|
+
const config = loadAgentConfig();
|
|
1169
|
+
delete config[agentId];
|
|
1170
|
+
saveAgentConfig(config);
|
|
1171
|
+
}
|
|
1172
|
+
var AGENT_CONFIG_PATH, KNOWN_RUNTIMES, RUNTIME_LABELS, DEFAULT_MODELS;
|
|
1173
|
+
var init_agent_config = __esm({
|
|
1174
|
+
"src/lib/agent-config.ts"() {
|
|
1175
|
+
"use strict";
|
|
1176
|
+
init_config();
|
|
1177
|
+
init_runtime_table();
|
|
1178
|
+
AGENT_CONFIG_PATH = path3.join(EXE_AI_DIR, "agent-config.json");
|
|
1179
|
+
KNOWN_RUNTIMES = {
|
|
1180
|
+
claude: ["claude-opus-4", "claude-sonnet-4", "claude-haiku-4.5"],
|
|
1181
|
+
codex: ["gpt-5.4", "gpt-5.5", "o3", "o4-mini"],
|
|
1182
|
+
opencode: ["anthropic/claude-sonnet-4-6", "openai/gpt-5.4", "google/gemini-2.5-pro", "deepseek/deepseek-r3", "minimax/minimax-m2.5"]
|
|
1183
|
+
};
|
|
1184
|
+
RUNTIME_LABELS = {
|
|
1185
|
+
claude: "Claude Code (Anthropic)",
|
|
1186
|
+
codex: "Codex (OpenAI)",
|
|
1187
|
+
opencode: "OpenCode (open source)"
|
|
1188
|
+
};
|
|
1189
|
+
DEFAULT_MODELS = {
|
|
1190
|
+
claude: "claude-opus-4",
|
|
1191
|
+
codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
|
|
1192
|
+
opencode: RUNTIME_TABLE.opencode?.defaultModel ?? "anthropic/claude-sonnet-4-6"
|
|
1193
|
+
};
|
|
1194
|
+
}
|
|
1195
|
+
});
|
|
1196
|
+
|
|
1085
1197
|
// src/bin/exe-call.ts
|
|
1086
1198
|
init_employees();
|
|
1087
1199
|
init_config();
|
|
1088
|
-
import
|
|
1200
|
+
import path4 from "path";
|
|
1089
1201
|
import { mkdir as mkdir3, writeFile as writeFile3 } from "fs/promises";
|
|
1090
1202
|
import { execSync as execSync2 } from "child_process";
|
|
1091
1203
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
@@ -1129,10 +1241,10 @@ function buildSessionEnv(employee, sessionDir) {
|
|
|
1129
1241
|
env["AGENT_ROLE"] = employee.role;
|
|
1130
1242
|
return env;
|
|
1131
1243
|
}
|
|
1132
|
-
async function prepareSessionDir(name, systemPrompt, sessionsBase =
|
|
1133
|
-
const sessionDir =
|
|
1244
|
+
async function prepareSessionDir(name, systemPrompt, sessionsBase = path4.join(EXE_AI_DIR, "sessions")) {
|
|
1245
|
+
const sessionDir = path4.join(sessionsBase, name);
|
|
1134
1246
|
await mkdir3(sessionDir, { recursive: true });
|
|
1135
|
-
await writeFile3(
|
|
1247
|
+
await writeFile3(path4.join(sessionDir, "CLAUDE.md"), systemPrompt, "utf-8");
|
|
1136
1248
|
return sessionDir;
|
|
1137
1249
|
}
|
|
1138
1250
|
if (isMainModule(import.meta.url)) {
|
|
@@ -1140,8 +1252,8 @@ if (isMainModule(import.meta.url)) {
|
|
|
1140
1252
|
const employees = await loadEmployees();
|
|
1141
1253
|
const coordinatorName = getCoordinatorName(employees);
|
|
1142
1254
|
if (!name || name === coordinatorName) {
|
|
1143
|
-
const __dirname =
|
|
1144
|
-
const bootPath =
|
|
1255
|
+
const __dirname = path4.dirname(fileURLToPath2(import.meta.url));
|
|
1256
|
+
const bootPath = path4.join(__dirname, "exe-boot.js");
|
|
1145
1257
|
try {
|
|
1146
1258
|
execSync2(`node "${bootPath}"`, { stdio: "inherit" });
|
|
1147
1259
|
} catch (err) {
|
|
@@ -1176,10 +1288,26 @@ if (isMainModule(import.meta.url)) {
|
|
|
1176
1288
|
}
|
|
1177
1289
|
const sessionDir = await prepareSessionDir(name, getSessionPrompt(prompt));
|
|
1178
1290
|
const env = buildSessionEnv(employee, sessionDir);
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
)
|
|
1182
|
-
|
|
1291
|
+
const { getAgentRuntime: getAgentRuntime2 } = await Promise.resolve().then(() => (init_agent_config(), agent_config_exports));
|
|
1292
|
+
const rtConfig = getAgentRuntime2(employee.name);
|
|
1293
|
+
if (rtConfig.runtime === "codex") {
|
|
1294
|
+
console.log(
|
|
1295
|
+
`Launching ${employee.name} (${employee.role}) on Codex (${rtConfig.model})...`
|
|
1296
|
+
);
|
|
1297
|
+
const codexLauncher = path4.join(path4.dirname(fileURLToPath2(import.meta.url)), "exe-start-codex.js");
|
|
1298
|
+
execSync2(`node "${codexLauncher}" --agent ${employee.name}`, { stdio: "inherit", env });
|
|
1299
|
+
} else if (rtConfig.runtime === "opencode") {
|
|
1300
|
+
console.log(
|
|
1301
|
+
`Launching ${employee.name} (${employee.role}) on OpenCode (${rtConfig.model})...`
|
|
1302
|
+
);
|
|
1303
|
+
const opencodeLauncher = path4.join(path4.dirname(fileURLToPath2(import.meta.url)), "exe-start-opencode.js");
|
|
1304
|
+
execSync2(`node "${opencodeLauncher}" --agent ${employee.name}`, { stdio: "inherit", env });
|
|
1305
|
+
} else {
|
|
1306
|
+
console.log(
|
|
1307
|
+
`Launching ${employee.name} (${employee.role}) on Claude Code...`
|
|
1308
|
+
);
|
|
1309
|
+
execSync2("claude --dangerously-skip-permissions", { stdio: "inherit", env });
|
|
1310
|
+
}
|
|
1183
1311
|
} catch (err) {
|
|
1184
1312
|
console.error(`Failed to launch employee session: ${err instanceof Error ? err.message : String(err)}`);
|
|
1185
1313
|
console.error("Try running: exe-os team");
|