@askexenow/exe-os 0.8.0 → 0.8.1
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/README.md +178 -79
- package/dist/bin/backfill-responses.js +160 -8
- package/dist/bin/backfill-vectors.js +130 -1
- package/dist/bin/cleanup-stale-review-tasks.js +130 -1
- package/dist/bin/cli.js +10111 -7540
- package/dist/bin/exe-agent.js +159 -1
- package/dist/bin/exe-assign.js +235 -16
- package/dist/bin/exe-boot.js +344 -472
- package/dist/bin/exe-call.js +145 -1
- package/dist/bin/exe-cloud.js +11 -0
- package/dist/bin/exe-dispatch.js +37 -24
- package/dist/bin/exe-doctor.js +130 -1
- package/dist/bin/exe-export-behaviors.js +150 -7
- package/dist/bin/exe-forget.js +822 -665
- package/dist/bin/exe-gateway.js +470 -62
- package/dist/bin/exe-heartbeat.js +133 -2
- package/dist/bin/exe-kill.js +150 -7
- package/dist/bin/exe-launch-agent.js +150 -7
- package/dist/bin/exe-new-employee.js +756 -224
- package/dist/bin/exe-pending-messages.js +132 -2
- package/dist/bin/exe-pending-notifications.js +130 -1
- package/dist/bin/exe-pending-reviews.js +132 -2
- package/dist/bin/exe-review.js +160 -8
- package/dist/bin/exe-search.js +2473 -2008
- package/dist/bin/exe-session-cleanup.js +238 -51
- package/dist/bin/exe-settings.js +11 -0
- package/dist/bin/exe-status.js +130 -1
- package/dist/bin/exe-team.js +130 -1
- package/dist/bin/git-sweep.js +272 -16
- package/dist/bin/graph-backfill.js +150 -7
- package/dist/bin/graph-export.js +150 -7
- package/dist/bin/install.js +5 -0
- package/dist/bin/scan-tasks.js +238 -19
- package/dist/bin/setup.js +1776 -10
- package/dist/bin/shard-migrate.js +150 -7
- package/dist/bin/update.js +9 -6
- package/dist/bin/wiki-sync.js +150 -7
- package/dist/gateway/index.js +470 -62
- package/dist/hooks/bug-report-worker.js +195 -35
- package/dist/hooks/commit-complete.js +272 -16
- package/dist/hooks/error-recall.js +2313 -1847
- package/dist/hooks/exe-heartbeat-hook.js +5 -0
- package/dist/hooks/ingest-worker.js +330 -58
- package/dist/hooks/ingest.js +11 -0
- package/dist/hooks/instructions-loaded.js +199 -10
- package/dist/hooks/notification.js +199 -10
- package/dist/hooks/post-compact.js +199 -10
- package/dist/hooks/pre-compact.js +199 -10
- package/dist/hooks/pre-tool-use.js +199 -10
- package/dist/hooks/prompt-ingest-worker.js +179 -14
- package/dist/hooks/prompt-submit.js +781 -285
- package/dist/hooks/response-ingest-worker.js +1900 -1405
- package/dist/hooks/session-end.js +456 -12
- package/dist/hooks/session-start.js +2188 -1724
- package/dist/hooks/stop.js +200 -10
- package/dist/hooks/subagent-stop.js +199 -10
- package/dist/hooks/summary-worker.js +604 -334
- package/dist/index.js +554 -61
- package/dist/lib/cloud-sync.js +5 -0
- package/dist/lib/config.js +13 -0
- package/dist/lib/consolidation.js +5 -0
- package/dist/lib/database.js +104 -0
- package/dist/lib/device-registry.js +109 -0
- package/dist/lib/embedder.js +13 -0
- package/dist/lib/employee-templates.js +53 -26
- package/dist/lib/employees.js +5 -0
- package/dist/lib/exe-daemon-client.js +5 -0
- package/dist/lib/exe-daemon.js +493 -79
- package/dist/lib/file-grep.js +20 -4
- package/dist/lib/hybrid-search.js +1435 -190
- package/dist/lib/identity-templates.js +126 -5
- package/dist/lib/identity.js +5 -0
- package/dist/lib/license.js +5 -0
- package/dist/lib/messaging.js +37 -24
- package/dist/lib/schedules.js +130 -1
- package/dist/lib/skill-learning.js +11 -0
- package/dist/lib/status-brief.js +5 -0
- package/dist/lib/store.js +199 -10
- package/dist/lib/task-router.js +72 -6
- package/dist/lib/tasks.js +179 -50
- package/dist/lib/tmux-routing.js +179 -46
- package/dist/mcp/server.js +2129 -1855
- package/dist/mcp/tools/create-task.js +86 -36
- package/dist/mcp/tools/deactivate-behavior.js +5 -0
- package/dist/mcp/tools/list-tasks.js +39 -11
- package/dist/mcp/tools/send-message.js +37 -24
- package/dist/mcp/tools/update-task.js +153 -38
- package/dist/runtime/index.js +451 -59
- package/dist/tui/App.js +454 -59
- package/package.json +1 -1
|
@@ -244,6 +244,27 @@ async function ensureSchema() {
|
|
|
244
244
|
});
|
|
245
245
|
} catch {
|
|
246
246
|
}
|
|
247
|
+
try {
|
|
248
|
+
await client.execute({
|
|
249
|
+
sql: `ALTER TABLE tasks ADD COLUMN checkpoint TEXT`,
|
|
250
|
+
args: []
|
|
251
|
+
});
|
|
252
|
+
} catch {
|
|
253
|
+
}
|
|
254
|
+
try {
|
|
255
|
+
await client.execute({
|
|
256
|
+
sql: `ALTER TABLE tasks ADD COLUMN checkpoint_count INTEGER NOT NULL DEFAULT 0`,
|
|
257
|
+
args: []
|
|
258
|
+
});
|
|
259
|
+
} catch {
|
|
260
|
+
}
|
|
261
|
+
try {
|
|
262
|
+
await client.execute({
|
|
263
|
+
sql: `ALTER TABLE tasks ADD COLUMN complexity TEXT NOT NULL DEFAULT 'standard'`,
|
|
264
|
+
args: []
|
|
265
|
+
});
|
|
266
|
+
} catch {
|
|
267
|
+
}
|
|
247
268
|
try {
|
|
248
269
|
await client.execute({
|
|
249
270
|
sql: `ALTER TABLE memories ADD COLUMN task_id TEXT`,
|
|
@@ -654,6 +675,15 @@ async function ensureSchema() {
|
|
|
654
675
|
} catch {
|
|
655
676
|
}
|
|
656
677
|
}
|
|
678
|
+
for (const col of [
|
|
679
|
+
"ALTER TABLE memories ADD COLUMN source_path TEXT",
|
|
680
|
+
"ALTER TABLE memories ADD COLUMN source_type TEXT DEFAULT 'text'"
|
|
681
|
+
]) {
|
|
682
|
+
try {
|
|
683
|
+
await client.execute(col);
|
|
684
|
+
} catch {
|
|
685
|
+
}
|
|
686
|
+
}
|
|
657
687
|
await client.executeMultiple(`
|
|
658
688
|
CREATE INDEX IF NOT EXISTS idx_memories_workspace
|
|
659
689
|
ON memories(workspace_id);
|
|
@@ -718,6 +748,34 @@ async function ensureSchema() {
|
|
|
718
748
|
CREATE INDEX IF NOT EXISTS idx_conversations_channel
|
|
719
749
|
ON conversations(channel_id);
|
|
720
750
|
`);
|
|
751
|
+
try {
|
|
752
|
+
await client.execute({
|
|
753
|
+
sql: `ALTER TABLE tasks ADD COLUMN budget_tokens INTEGER`,
|
|
754
|
+
args: []
|
|
755
|
+
});
|
|
756
|
+
} catch {
|
|
757
|
+
}
|
|
758
|
+
try {
|
|
759
|
+
await client.execute({
|
|
760
|
+
sql: `ALTER TABLE tasks ADD COLUMN budget_fallback_model TEXT`,
|
|
761
|
+
args: []
|
|
762
|
+
});
|
|
763
|
+
} catch {
|
|
764
|
+
}
|
|
765
|
+
try {
|
|
766
|
+
await client.execute({
|
|
767
|
+
sql: `ALTER TABLE tasks ADD COLUMN tokens_used INTEGER DEFAULT 0`,
|
|
768
|
+
args: []
|
|
769
|
+
});
|
|
770
|
+
} catch {
|
|
771
|
+
}
|
|
772
|
+
try {
|
|
773
|
+
await client.execute({
|
|
774
|
+
sql: `ALTER TABLE tasks ADD COLUMN tokens_warned_at INTEGER`,
|
|
775
|
+
args: []
|
|
776
|
+
});
|
|
777
|
+
} catch {
|
|
778
|
+
}
|
|
721
779
|
await client.executeMultiple(`
|
|
722
780
|
CREATE VIRTUAL TABLE IF NOT EXISTS conversations_fts USING fts5(
|
|
723
781
|
content_text,
|
|
@@ -744,6 +802,52 @@ async function ensureSchema() {
|
|
|
744
802
|
VALUES (new.rowid, new.content_text, new.sender_name, new.agent_response);
|
|
745
803
|
END;
|
|
746
804
|
`);
|
|
805
|
+
try {
|
|
806
|
+
await client.execute({
|
|
807
|
+
sql: `ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3`,
|
|
808
|
+
args: []
|
|
809
|
+
});
|
|
810
|
+
} catch {
|
|
811
|
+
}
|
|
812
|
+
try {
|
|
813
|
+
await client.execute(
|
|
814
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)`
|
|
815
|
+
);
|
|
816
|
+
} catch {
|
|
817
|
+
}
|
|
818
|
+
try {
|
|
819
|
+
await client.execute({
|
|
820
|
+
sql: `UPDATE memories SET tier = 1 WHERE tool_name = 'commit_to_long_term_memory' AND importance >= 8 AND tier = 3`,
|
|
821
|
+
args: []
|
|
822
|
+
});
|
|
823
|
+
await client.execute({
|
|
824
|
+
sql: `UPDATE memories SET tier = 2 WHERE tool_name IN ('store_memory', 'manual') AND importance >= 5 AND tier = 3`,
|
|
825
|
+
args: []
|
|
826
|
+
});
|
|
827
|
+
} catch {
|
|
828
|
+
}
|
|
829
|
+
try {
|
|
830
|
+
await client.execute({
|
|
831
|
+
sql: `ALTER TABLE memories ADD COLUMN supersedes_id TEXT`,
|
|
832
|
+
args: []
|
|
833
|
+
});
|
|
834
|
+
} catch {
|
|
835
|
+
}
|
|
836
|
+
try {
|
|
837
|
+
await client.execute(
|
|
838
|
+
`CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL`
|
|
839
|
+
);
|
|
840
|
+
} catch {
|
|
841
|
+
}
|
|
842
|
+
for (const col of [
|
|
843
|
+
"ALTER TABLE tasks ADD COLUMN checkpoint TEXT",
|
|
844
|
+
"ALTER TABLE tasks ADD COLUMN checkpoint_count INTEGER DEFAULT 0"
|
|
845
|
+
]) {
|
|
846
|
+
try {
|
|
847
|
+
await client.execute(col);
|
|
848
|
+
} catch {
|
|
849
|
+
}
|
|
850
|
+
}
|
|
747
851
|
}
|
|
748
852
|
async function disposeDatabase() {
|
|
749
853
|
if (_client) {
|
|
@@ -876,6 +980,11 @@ function normalizeSessionLifecycle(raw) {
|
|
|
876
980
|
const userSL = raw.sessionLifecycle ?? {};
|
|
877
981
|
raw.sessionLifecycle = { ...defaultSL, ...userSL };
|
|
878
982
|
}
|
|
983
|
+
function normalizeAutoUpdate(raw) {
|
|
984
|
+
const defaultAU = DEFAULT_CONFIG.autoUpdate;
|
|
985
|
+
const userAU = raw.autoUpdate ?? {};
|
|
986
|
+
raw.autoUpdate = { ...defaultAU, ...userAU };
|
|
987
|
+
}
|
|
879
988
|
async function loadConfig() {
|
|
880
989
|
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
881
990
|
await mkdir2(dir, { recursive: true });
|
|
@@ -898,6 +1007,7 @@ async function loadConfig() {
|
|
|
898
1007
|
}
|
|
899
1008
|
normalizeScalingRoadmap(migratedCfg);
|
|
900
1009
|
normalizeSessionLifecycle(migratedCfg);
|
|
1010
|
+
normalizeAutoUpdate(migratedCfg);
|
|
901
1011
|
const config = { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db"), ...migratedCfg };
|
|
902
1012
|
if (config.dbPath.startsWith("~")) {
|
|
903
1013
|
config.dbPath = config.dbPath.replace(/^~/, os.homedir());
|
|
@@ -973,6 +1083,11 @@ var init_config = __esm({
|
|
|
973
1083
|
idleKillTicksRequired: 3,
|
|
974
1084
|
idleKillIntercomAckWindowMs: 1e4,
|
|
975
1085
|
maxAutoInstances: 10
|
|
1086
|
+
},
|
|
1087
|
+
autoUpdate: {
|
|
1088
|
+
checkOnBoot: true,
|
|
1089
|
+
autoInstall: false,
|
|
1090
|
+
checkIntervalMs: 24 * 60 * 60 * 1e3
|
|
976
1091
|
}
|
|
977
1092
|
};
|
|
978
1093
|
CONFIG_MIGRATIONS = [
|
|
@@ -1106,13 +1221,27 @@ async function ensureShardSchema(client) {
|
|
|
1106
1221
|
"ALTER TABLE memories ADD COLUMN document_id TEXT",
|
|
1107
1222
|
"ALTER TABLE memories ADD COLUMN user_id TEXT",
|
|
1108
1223
|
"ALTER TABLE memories ADD COLUMN char_offset INTEGER",
|
|
1109
|
-
"ALTER TABLE memories ADD COLUMN page_number INTEGER"
|
|
1224
|
+
"ALTER TABLE memories ADD COLUMN page_number INTEGER",
|
|
1225
|
+
// Source provenance columns (must match database.ts)
|
|
1226
|
+
"ALTER TABLE memories ADD COLUMN source_path TEXT",
|
|
1227
|
+
"ALTER TABLE memories ADD COLUMN source_type TEXT DEFAULT 'text'",
|
|
1228
|
+
"ALTER TABLE memories ADD COLUMN tier INTEGER DEFAULT 3",
|
|
1229
|
+
"ALTER TABLE memories ADD COLUMN supersedes_id TEXT"
|
|
1110
1230
|
]) {
|
|
1111
1231
|
try {
|
|
1112
1232
|
await client.execute(col);
|
|
1113
1233
|
} catch {
|
|
1114
1234
|
}
|
|
1115
1235
|
}
|
|
1236
|
+
for (const idx of [
|
|
1237
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_tier ON memories(tier)",
|
|
1238
|
+
"CREATE INDEX IF NOT EXISTS idx_memories_supersedes ON memories(supersedes_id) WHERE supersedes_id IS NOT NULL"
|
|
1239
|
+
]) {
|
|
1240
|
+
try {
|
|
1241
|
+
await client.execute(idx);
|
|
1242
|
+
} catch {
|
|
1243
|
+
}
|
|
1244
|
+
}
|
|
1116
1245
|
try {
|
|
1117
1246
|
await client.execute("CREATE INDEX IF NOT EXISTS idx_memories_status ON memories(status)");
|
|
1118
1247
|
} catch {
|
|
@@ -1221,8 +1350,11 @@ var store_exports = {};
|
|
|
1221
1350
|
__export(store_exports, {
|
|
1222
1351
|
attachDocumentMetadata: () => attachDocumentMetadata,
|
|
1223
1352
|
buildWikiScopeFilter: () => buildWikiScopeFilter,
|
|
1353
|
+
classifyTier: () => classifyTier,
|
|
1224
1354
|
disposeStore: () => disposeStore,
|
|
1225
1355
|
flushBatch: () => flushBatch,
|
|
1356
|
+
flushTier3: () => flushTier3,
|
|
1357
|
+
getMemoryCardinality: () => getMemoryCardinality,
|
|
1226
1358
|
initStore: () => initStore,
|
|
1227
1359
|
reserveVersions: () => reserveVersions,
|
|
1228
1360
|
searchMemories: () => searchMemories,
|
|
@@ -1268,6 +1400,11 @@ async function initStore(options) {
|
|
|
1268
1400
|
const vResult = await client.execute("SELECT MAX(version) as max_v FROM memories");
|
|
1269
1401
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
1270
1402
|
}
|
|
1403
|
+
function classifyTier(record) {
|
|
1404
|
+
if (record.tool_name === "commit_to_long_term_memory" && (record.importance ?? 0) >= 8) return 1;
|
|
1405
|
+
if (["store_memory", "manual"].includes(record.tool_name ?? "") && (record.importance ?? 0) >= 5) return 2;
|
|
1406
|
+
return 3;
|
|
1407
|
+
}
|
|
1271
1408
|
async function writeMemory(record) {
|
|
1272
1409
|
if (record.vector !== null && record.vector.length !== EMBEDDING_DIM) {
|
|
1273
1410
|
throw new Error(
|
|
@@ -1295,7 +1432,11 @@ async function writeMemory(record) {
|
|
|
1295
1432
|
document_id: record.document_id ?? null,
|
|
1296
1433
|
user_id: record.user_id ?? null,
|
|
1297
1434
|
char_offset: record.char_offset ?? null,
|
|
1298
|
-
page_number: record.page_number ?? null
|
|
1435
|
+
page_number: record.page_number ?? null,
|
|
1436
|
+
source_path: record.source_path ?? null,
|
|
1437
|
+
source_type: record.source_type ?? null,
|
|
1438
|
+
tier: record.tier ?? classifyTier(record),
|
|
1439
|
+
supersedes_id: record.supersedes_id ?? null
|
|
1299
1440
|
};
|
|
1300
1441
|
_pendingRecords.push(dbRow);
|
|
1301
1442
|
if (_flushTimer === null) {
|
|
@@ -1327,20 +1468,26 @@ async function flushBatch() {
|
|
|
1327
1468
|
const userId = row.user_id ?? null;
|
|
1328
1469
|
const charOffset = row.char_offset ?? null;
|
|
1329
1470
|
const pageNumber = row.page_number ?? null;
|
|
1471
|
+
const sourcePath = row.source_path ?? null;
|
|
1472
|
+
const sourceType = row.source_type ?? null;
|
|
1473
|
+
const tier = row.tier ?? 3;
|
|
1474
|
+
const supersedesId = row.supersedes_id ?? null;
|
|
1330
1475
|
return {
|
|
1331
1476
|
sql: hasVector ? `INSERT OR IGNORE INTO memories
|
|
1332
1477
|
(id, agent_id, agent_role, session_id, timestamp,
|
|
1333
1478
|
tool_name, project_name,
|
|
1334
1479
|
has_error, raw_text, vector, version, task_id, importance, status,
|
|
1335
1480
|
confidence, last_accessed,
|
|
1336
|
-
workspace_id, document_id, user_id, char_offset, page_number
|
|
1337
|
-
|
|
1481
|
+
workspace_id, document_id, user_id, char_offset, page_number,
|
|
1482
|
+
source_path, source_type, tier, supersedes_id)
|
|
1483
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, vector32(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)` : `INSERT OR IGNORE INTO memories
|
|
1338
1484
|
(id, agent_id, agent_role, session_id, timestamp,
|
|
1339
1485
|
tool_name, project_name,
|
|
1340
1486
|
has_error, raw_text, vector, version, task_id, importance, status,
|
|
1341
1487
|
confidence, last_accessed,
|
|
1342
|
-
workspace_id, document_id, user_id, char_offset, page_number
|
|
1343
|
-
|
|
1488
|
+
workspace_id, document_id, user_id, char_offset, page_number,
|
|
1489
|
+
source_path, source_type, tier, supersedes_id)
|
|
1490
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
1344
1491
|
args: hasVector ? [
|
|
1345
1492
|
row.id,
|
|
1346
1493
|
row.agent_id,
|
|
@@ -1362,7 +1509,11 @@ async function flushBatch() {
|
|
|
1362
1509
|
documentId,
|
|
1363
1510
|
userId,
|
|
1364
1511
|
charOffset,
|
|
1365
|
-
pageNumber
|
|
1512
|
+
pageNumber,
|
|
1513
|
+
sourcePath,
|
|
1514
|
+
sourceType,
|
|
1515
|
+
tier,
|
|
1516
|
+
supersedesId
|
|
1366
1517
|
] : [
|
|
1367
1518
|
row.id,
|
|
1368
1519
|
row.agent_id,
|
|
@@ -1383,7 +1534,11 @@ async function flushBatch() {
|
|
|
1383
1534
|
documentId,
|
|
1384
1535
|
userId,
|
|
1385
1536
|
charOffset,
|
|
1386
|
-
pageNumber
|
|
1537
|
+
pageNumber,
|
|
1538
|
+
sourcePath,
|
|
1539
|
+
sourceType,
|
|
1540
|
+
tier,
|
|
1541
|
+
supersedesId
|
|
1387
1542
|
]
|
|
1388
1543
|
};
|
|
1389
1544
|
};
|
|
@@ -1457,7 +1612,8 @@ async function searchMemories(queryVector, agentId, options) {
|
|
|
1457
1612
|
has_error, raw_text, vector, importance, status,
|
|
1458
1613
|
confidence, last_accessed,
|
|
1459
1614
|
workspace_id, document_id, user_id,
|
|
1460
|
-
char_offset, page_number
|
|
1615
|
+
char_offset, page_number,
|
|
1616
|
+
source_path, source_type
|
|
1461
1617
|
FROM memories
|
|
1462
1618
|
WHERE agent_id = ?
|
|
1463
1619
|
AND vector IS NOT NULL${statusFilter}
|
|
@@ -1506,7 +1662,9 @@ async function searchMemories(queryVector, agentId, options) {
|
|
|
1506
1662
|
document_id: row.document_id ?? null,
|
|
1507
1663
|
user_id: row.user_id ?? null,
|
|
1508
1664
|
char_offset: row.char_offset ?? null,
|
|
1509
|
-
page_number: row.page_number ?? null
|
|
1665
|
+
page_number: row.page_number ?? null,
|
|
1666
|
+
source_path: row.source_path ?? null,
|
|
1667
|
+
source_type: row.source_type ?? null
|
|
1510
1668
|
}));
|
|
1511
1669
|
}
|
|
1512
1670
|
async function attachDocumentMetadata(records) {
|
|
@@ -1544,6 +1702,25 @@ async function attachDocumentMetadata(records) {
|
|
|
1544
1702
|
}
|
|
1545
1703
|
return records;
|
|
1546
1704
|
}
|
|
1705
|
+
async function flushTier3(agentId, options) {
|
|
1706
|
+
const client = getClient();
|
|
1707
|
+
const maxAge = options?.maxAgeHours ?? 72;
|
|
1708
|
+
const cutoff = new Date(Date.now() - maxAge * 36e5).toISOString();
|
|
1709
|
+
if (options?.dryRun) {
|
|
1710
|
+
const result2 = await client.execute({
|
|
1711
|
+
sql: `SELECT COUNT(*) as cnt FROM memories
|
|
1712
|
+
WHERE agent_id = ? AND tier = 3 AND status = 'active' AND timestamp < ?`,
|
|
1713
|
+
args: [agentId, cutoff]
|
|
1714
|
+
});
|
|
1715
|
+
return { archived: Number(result2.rows[0]?.cnt ?? 0) };
|
|
1716
|
+
}
|
|
1717
|
+
const result = await client.execute({
|
|
1718
|
+
sql: `UPDATE memories SET status = 'archived'
|
|
1719
|
+
WHERE agent_id = ? AND tier = 3 AND status = 'active' AND timestamp < ?`,
|
|
1720
|
+
args: [agentId, cutoff]
|
|
1721
|
+
});
|
|
1722
|
+
return { archived: result.rowsAffected };
|
|
1723
|
+
}
|
|
1547
1724
|
async function disposeStore() {
|
|
1548
1725
|
if (_flushTimer !== null) {
|
|
1549
1726
|
clearInterval(_flushTimer);
|
|
@@ -1574,6 +1751,18 @@ function reserveVersions(count) {
|
|
|
1574
1751
|
}
|
|
1575
1752
|
return reserved;
|
|
1576
1753
|
}
|
|
1754
|
+
async function getMemoryCardinality(agentId) {
|
|
1755
|
+
try {
|
|
1756
|
+
const client = getClient();
|
|
1757
|
+
const result = await client.execute({
|
|
1758
|
+
sql: `SELECT COUNT(*) as cnt FROM memories WHERE agent_id = ? AND COALESCE(status, 'active') = 'active'`,
|
|
1759
|
+
args: [agentId]
|
|
1760
|
+
});
|
|
1761
|
+
return Number(result.rows[0]?.cnt) || 0;
|
|
1762
|
+
} catch {
|
|
1763
|
+
return 0;
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1577
1766
|
var _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
|
|
1578
1767
|
var init_store = __esm({
|
|
1579
1768
|
"src/lib/store.ts"() {
|
|
@@ -1604,13 +1793,44 @@ __export(tasks_crud_exports, {
|
|
|
1604
1793
|
listTasks: () => listTasks,
|
|
1605
1794
|
resolveTask: () => resolveTask,
|
|
1606
1795
|
slugify: () => slugify,
|
|
1607
|
-
updateTaskStatus: () => updateTaskStatus
|
|
1796
|
+
updateTaskStatus: () => updateTaskStatus,
|
|
1797
|
+
writeCheckpoint: () => writeCheckpoint
|
|
1608
1798
|
});
|
|
1609
1799
|
import crypto2 from "crypto";
|
|
1610
1800
|
import path4 from "path";
|
|
1611
1801
|
import { execSync as execSync2 } from "child_process";
|
|
1612
1802
|
import { mkdir as mkdir3, writeFile as writeFile3, appendFile } from "fs/promises";
|
|
1613
1803
|
import { existsSync as existsSync4, readFileSync as readFileSync2 } from "fs";
|
|
1804
|
+
async function writeCheckpoint(input) {
|
|
1805
|
+
const client = getClient();
|
|
1806
|
+
const row = await resolveTask(client, input.taskId);
|
|
1807
|
+
const taskId = String(row.id);
|
|
1808
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1809
|
+
const blockedByIds = [];
|
|
1810
|
+
if (row.blocked_by) {
|
|
1811
|
+
blockedByIds.push(String(row.blocked_by));
|
|
1812
|
+
}
|
|
1813
|
+
const checkpoint = {
|
|
1814
|
+
step: input.step,
|
|
1815
|
+
context_summary: input.contextSummary,
|
|
1816
|
+
files_touched: input.filesTouched ?? [],
|
|
1817
|
+
blocked_by_ids: blockedByIds,
|
|
1818
|
+
last_checkpoint_at: now
|
|
1819
|
+
};
|
|
1820
|
+
const result = await client.execute({
|
|
1821
|
+
sql: `UPDATE tasks SET checkpoint = ?, checkpoint_count = checkpoint_count + 1, updated_at = ? WHERE id = ?`,
|
|
1822
|
+
args: [JSON.stringify(checkpoint), now, taskId]
|
|
1823
|
+
});
|
|
1824
|
+
if (result.rowsAffected === 0) {
|
|
1825
|
+
throw new Error(`Checkpoint write failed: task ${taskId} not found`);
|
|
1826
|
+
}
|
|
1827
|
+
const countResult = await client.execute({
|
|
1828
|
+
sql: "SELECT checkpoint_count FROM tasks WHERE id = ?",
|
|
1829
|
+
args: [taskId]
|
|
1830
|
+
});
|
|
1831
|
+
const checkpointCount = Number(countResult.rows[0]?.checkpoint_count ?? 1);
|
|
1832
|
+
return { checkpointCount };
|
|
1833
|
+
}
|
|
1614
1834
|
function extractParentFromContext(contextBody) {
|
|
1615
1835
|
if (!contextBody) return null;
|
|
1616
1836
|
const match = contextBody.match(
|
|
@@ -1717,9 +1937,10 @@ async function createTaskCore(input) {
|
|
|
1717
1937
|
} catch {
|
|
1718
1938
|
}
|
|
1719
1939
|
}
|
|
1940
|
+
const complexity = input.complexity ?? "standard";
|
|
1720
1941
|
await client.execute({
|
|
1721
|
-
sql: `INSERT INTO tasks (id, title, assigned_to, assigned_by, project_name, priority, status, task_file, blocked_by, parent_task_id, reviewer, context, created_at, updated_at)
|
|
1722
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
1942
|
+
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)
|
|
1943
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
1723
1944
|
args: [
|
|
1724
1945
|
id,
|
|
1725
1946
|
input.title,
|
|
@@ -1733,6 +1954,11 @@ async function createTaskCore(input) {
|
|
|
1733
1954
|
parentTaskId,
|
|
1734
1955
|
input.reviewer ?? null,
|
|
1735
1956
|
input.context,
|
|
1957
|
+
input.budgetTokens ?? null,
|
|
1958
|
+
input.budgetFallbackModel ?? null,
|
|
1959
|
+
0,
|
|
1960
|
+
null,
|
|
1961
|
+
complexity,
|
|
1736
1962
|
now,
|
|
1737
1963
|
now
|
|
1738
1964
|
]
|
|
@@ -1748,7 +1974,11 @@ async function createTaskCore(input) {
|
|
|
1748
1974
|
taskFile,
|
|
1749
1975
|
createdAt: now,
|
|
1750
1976
|
updatedAt: now,
|
|
1751
|
-
warning
|
|
1977
|
+
warning,
|
|
1978
|
+
budgetTokens: input.budgetTokens ?? null,
|
|
1979
|
+
budgetFallbackModel: input.budgetFallbackModel ?? null,
|
|
1980
|
+
tokensUsed: 0,
|
|
1981
|
+
tokensWarnedAt: null
|
|
1752
1982
|
};
|
|
1753
1983
|
}
|
|
1754
1984
|
async function listTasks(input) {
|
|
@@ -1788,7 +2018,12 @@ async function listTasks(input) {
|
|
|
1788
2018
|
status: String(r.status),
|
|
1789
2019
|
taskFile: String(r.task_file),
|
|
1790
2020
|
createdAt: String(r.created_at),
|
|
1791
|
-
updatedAt: String(r.updated_at)
|
|
2021
|
+
updatedAt: String(r.updated_at),
|
|
2022
|
+
checkpointCount: Number(r.checkpoint_count ?? 0),
|
|
2023
|
+
budgetTokens: r.budget_tokens !== null ? Number(r.budget_tokens) : null,
|
|
2024
|
+
budgetFallbackModel: r.budget_fallback_model !== null ? String(r.budget_fallback_model) : null,
|
|
2025
|
+
tokensUsed: Number(r.tokens_used ?? 0),
|
|
2026
|
+
tokensWarnedAt: r.tokens_warned_at !== null ? Number(r.tokens_warned_at) : null
|
|
1792
2027
|
}));
|
|
1793
2028
|
}
|
|
1794
2029
|
function checkStaleCompletion(taskContext, taskCreatedAt) {
|
|
@@ -1796,8 +2031,13 @@ function checkStaleCompletion(taskContext, taskCreatedAt) {
|
|
|
1796
2031
|
if (!DELEGATION_KEYWORDS.test(taskContext)) return null;
|
|
1797
2032
|
try {
|
|
1798
2033
|
const since = new Date(taskCreatedAt).toISOString();
|
|
2034
|
+
const branch = execSync2(
|
|
2035
|
+
"git rev-parse --abbrev-ref HEAD 2>/dev/null",
|
|
2036
|
+
{ encoding: "utf8", timeout: 3e3 }
|
|
2037
|
+
).trim();
|
|
2038
|
+
const branchArg = branch && branch !== "HEAD" ? branch : "";
|
|
1799
2039
|
const commitCount = execSync2(
|
|
1800
|
-
`git log --oneline --since="${since}" 2>/dev/null | wc -l`,
|
|
2040
|
+
`git log --oneline --since="${since}" ${branchArg} 2>/dev/null | wc -l`,
|
|
1801
2041
|
{ encoding: "utf8", timeout: 5e3 }
|
|
1802
2042
|
).trim();
|
|
1803
2043
|
const count = parseInt(commitCount, 10);
|
|
@@ -1856,6 +2096,14 @@ ${input.result}` : `\u26A0\uFE0F ${warning}`;
|
|
|
1856
2096
|
const claimedBy = cur?.assigned_tmux ? ` (claimed by ${cur.assigned_tmux})` : "";
|
|
1857
2097
|
throw new Error(`${TASK_ALREADY_CLAIMED_PREFIX}: task ${taskId} is ${status}${claimedBy}`);
|
|
1858
2098
|
}
|
|
2099
|
+
try {
|
|
2100
|
+
await writeCheckpoint({
|
|
2101
|
+
taskId,
|
|
2102
|
+
step: "claimed",
|
|
2103
|
+
contextSummary: `Task claimed by session. Transitioning open \u2192 in_progress.`
|
|
2104
|
+
});
|
|
2105
|
+
} catch {
|
|
2106
|
+
}
|
|
1859
2107
|
return { row, taskFile, now, taskId };
|
|
1860
2108
|
}
|
|
1861
2109
|
if (input.result) {
|
|
@@ -1869,6 +2117,14 @@ ${input.result}` : `\u26A0\uFE0F ${warning}`;
|
|
|
1869
2117
|
args: [input.status, now, taskId]
|
|
1870
2118
|
});
|
|
1871
2119
|
}
|
|
2120
|
+
try {
|
|
2121
|
+
await writeCheckpoint({
|
|
2122
|
+
taskId,
|
|
2123
|
+
step: `status_transition:${input.status}`,
|
|
2124
|
+
contextSummary: input.result ? `Transitioned to ${input.status}. Result: ${input.result.slice(0, 500)}` : `Transitioned to ${input.status}.`
|
|
2125
|
+
});
|
|
2126
|
+
} catch {
|
|
2127
|
+
}
|
|
1872
2128
|
return { row, taskFile, now, taskId };
|
|
1873
2129
|
}
|
|
1874
2130
|
async function deleteTaskCore(taskId, _baseDir) {
|