@askexenow/exe-os 0.9.211 → 0.9.214

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.
@@ -4,7 +4,7 @@ import {
4
4
  } from "../chunk-GMQKS5JD.js";
5
5
  import {
6
6
  lightweightSearch
7
- } from "../chunk-PTO7FEZG.js";
7
+ } from "../chunk-NVZODD7S.js";
8
8
  import "../chunk-E3Q4R3K6.js";
9
9
  import "../chunk-CHCA3ZM2.js";
10
10
  import "../chunk-XJQASQPO.js";
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  hybridSearch,
4
4
  lightweightSearch
5
- } from "../chunk-PTO7FEZG.js";
5
+ } from "../chunk-NVZODD7S.js";
6
6
  import {
7
7
  initStore
8
8
  } from "../chunk-E3Q4R3K6.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  lightweightSearch
3
- } from "./chunk-PTO7FEZG.js";
3
+ } from "./chunk-NVZODD7S.js";
4
4
  import "./chunk-E3Q4R3K6.js";
5
5
  import "./chunk-CHCA3ZM2.js";
6
6
  import "./chunk-XJQASQPO.js";
@@ -7,7 +7,7 @@ import {
7
7
  import {
8
8
  isRerankerAvailable,
9
9
  rerankWithScores
10
- } from "./chunk-G3JAB3O5.js";
10
+ } from "./chunk-UFOERR37.js";
11
11
  import {
12
12
  getEntityByName,
13
13
  getEntityNeighbors,
@@ -187,7 +187,7 @@ import {
187
187
  import {
188
188
  hybridSearch,
189
189
  recentRecords
190
- } from "./chunk-PTO7FEZG.js";
190
+ } from "./chunk-NVZODD7S.js";
191
191
  import {
192
192
  attachDocumentMetadata,
193
193
  flushBatch,
@@ -233,7 +233,7 @@ async function hybridSearch(queryText, agentId, options) {
233
233
  let rerankerAvailable = false;
234
234
  if (process.env.EXE_IS_DAEMON === "1") {
235
235
  try {
236
- const { isRerankerAvailable } = await import("./reranker-2D2XI6KV.js");
236
+ const { isRerankerAvailable } = await import("./reranker-AZN6MN2N.js");
237
237
  rerankerAvailable = isRerankerAvailable();
238
238
  } catch {
239
239
  }
@@ -397,7 +397,7 @@ async function hybridSearch(queryText, agentId, options) {
397
397
  try {
398
398
  let rerankedRecords;
399
399
  if (graphContextMap.size > 0) {
400
- const { rerankWithContext } = await import("./reranker-2D2XI6KV.js");
400
+ const { rerankWithContext } = await import("./reranker-AZN6MN2N.js");
401
401
  const candidates = merged.map((m) => ({
402
402
  text: m.raw_text,
403
403
  context: graphContextMap.get(m.id)
@@ -405,7 +405,7 @@ async function hybridSearch(queryText, agentId, options) {
405
405
  const scored = await rerankWithContext(effectiveQuery, candidates, rerankReturnLimit);
406
406
  rerankedRecords = scored.map((s) => merged[s.index]);
407
407
  } else {
408
- const { rerank } = await import("./reranker-2D2XI6KV.js");
408
+ const { rerank } = await import("./reranker-AZN6MN2N.js");
409
409
  rerankedRecords = await rerank(effectiveQuery, merged, rerankReturnLimit);
410
410
  }
411
411
  if (rerankedRecords.length > 0) {
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  hybridSearch,
6
6
  lightweightSearch
7
- } from "../chunk-PTO7FEZG.js";
7
+ } from "../chunk-NVZODD7S.js";
8
8
  import {
9
9
  initStore
10
10
  } from "../chunk-E3Q4R3K6.js";
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "version": 1,
3
- "generatedAt": "2026-06-03T16:14:41.007Z",
3
+ "generatedAt": "2026-06-04T08:59:34.433Z",
4
4
  "hashes": {
5
5
  "bug-report-worker.js": "0026604aac324e295b46bde719681de6800b2df144012cc2c2b349dcdbb082be",
6
6
  "codex-stop-task-finalizer.js": "f6188b6e85f247546996d138de58cd658e40c8175511e22b1b201a1379502632",
7
7
  "commit-complete.js": "1bc2e33e1d00daebc727c5c3e73ec8d5025ad08544e4cde2848d035ee5e21352",
8
- "error-recall.js": "6107ab1e85c829e15305c0a8e28b0a54265b2db212e15f960ef6ec077cec6cbd",
8
+ "error-recall.js": "b21822616521e68d752ac273a70c9e505fb3636379c31e66ab8609a95a87b02d",
9
9
  "exe-heartbeat-hook.js": "10688da0e9c9972fff33c3bb33923df4e743df9d48e744b96d227836c6270c4c",
10
10
  "ingest-worker.js": "df9693b3a590f313868019ab91dd2f7298750492f792c2b8055c4ad68a1c9d67",
11
11
  "ingest.js": "5af6b8a3a4e30c282d27a17a82d55337b7102d84e796198c6390315a39755404",
@@ -15,9 +15,9 @@
15
15
  "post-tool-combined.js": "19469891de74713eab9d5d9273c130d5fe5ad95a2b99618ac4bb9d60120b5c71",
16
16
  "pre-compact.js": "01761e0a404d9cc5fa2ef1788829bd62bbd426395703491906f4b255f32976f4",
17
17
  "pre-tool-use.js": "c2e10257f91ba7a759aa41db28e374b20780d7376eb17d3d167c3e7cbf0a226d",
18
- "prompt-submit.js": "5a195cae5742e4ab4b96a8c8e7aeca08b2204360d9233b41d260dc071bfc078c",
18
+ "prompt-submit.js": "5722df8ad7789f51bd37dbbd152209e2330952680c686460d393875c5b549072",
19
19
  "session-end.js": "2cfe3cbc196cb11bbe68ae23d128eacc99d1dbbbdd7b3698189922bf5645a71a",
20
- "session-start.js": "b76d1545d94ecab66f7d82e77e2b36ef643d3dd3cb4c9a4314d626af26e51ba1",
20
+ "session-start.js": "0416fc6b642529eb0125b02b892cb0014010294baaf5e864819a4fa745fddfa8",
21
21
  "stop.js": "9c784c10f1a8eddfec9f5dc66463d67a5b09eb21f340e0d92157e9e7befb367b",
22
22
  "subagent-stop.js": "a3d3a01d99dcdcebd5763e5974ce912d69c5f07ba254eb01c2f8c587903ec88c",
23
23
  "summary-worker.js": "f29f29e148ea34b38eab656131b2045e0e4020b526ab8bada9c693eb19dc690e"
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  hybridSearch,
3
3
  lightweightSearch
4
- } from "../chunk-PTO7FEZG.js";
4
+ } from "../chunk-NVZODD7S.js";
5
5
  import {
6
6
  initStore
7
7
  } from "../chunk-E3Q4R3K6.js";
@@ -158,7 +158,7 @@ You are **${ag.agentId}** (${ag.agentRole}). Daemon is degraded \u2014 memory un
158
158
  query = `last actions on ${projectName}`;
159
159
  header = "## Resuming Session\nHere's where you left off:";
160
160
  try {
161
- const { buildCatchupBrief } = await import("../catchup-brief-FIVK6YIX.js");
161
+ const { buildCatchupBrief } = await import("../catchup-brief-6AD7QQZB.js");
162
162
  const brief = await buildCatchupBrief(
163
163
  agentId,
164
164
  projectName,
@@ -407,12 +407,15 @@ var MAX_QUEUE_SIZE = 5e3;
407
407
  var _tmuxSessionCache = [];
408
408
  var _tmuxCacheTimestamp = 0;
409
409
  var TMUX_CACHE_TTL_MS = 5e3;
410
- function getTmuxSessions() {
410
+ async function getTmuxSessionsAsync() {
411
411
  const now = Date.now();
412
412
  if (now - _tmuxCacheTimestamp < TMUX_CACHE_TTL_MS) return _tmuxSessionCache;
413
413
  try {
414
- const efs = execFileSyncNode;
415
- _tmuxSessionCache = efs("tmux", ["list-sessions", "-F", "#{session_name}"], { timeout: 3e3 }).toString().trim().split("\n").filter(Boolean);
414
+ const { stdout } = await execFileAsync("tmux", ["list-sessions", "-F", "#{session_name}"], {
415
+ encoding: "utf8",
416
+ timeout: 3e3
417
+ });
418
+ _tmuxSessionCache = String(stdout ?? "").trim().split("\n").filter(Boolean);
416
419
  _tmuxCacheTimestamp = now;
417
420
  } catch {
418
421
  _tmuxSessionCache = [];
@@ -451,6 +454,48 @@ async function batchCapturePanes(sessions, lines = 20) {
451
454
  }
452
455
  return results;
453
456
  }
457
+ async function tmuxPaneAliveAsync(session) {
458
+ try {
459
+ const { stdout } = await execFileAsync(
460
+ "tmux",
461
+ ["list-panes", "-t", session, "-F", "#{pane_dead}"],
462
+ { encoding: "utf8", timeout: 3e3 }
463
+ );
464
+ return String(stdout ?? "").trim() !== "1";
465
+ } catch {
466
+ return false;
467
+ }
468
+ }
469
+ async function batchPaneAlive(sessions) {
470
+ const alive = /* @__PURE__ */ new Set();
471
+ const CONCURRENCY = 4;
472
+ for (let i = 0; i < sessions.length; i += CONCURRENCY) {
473
+ const batch = sessions.slice(i, i + CONCURRENCY);
474
+ const settled = await Promise.allSettled(
475
+ batch.map(async (session) => ({ session, alive: await tmuxPaneAliveAsync(session) }))
476
+ );
477
+ for (const result of settled) {
478
+ if (result.status === "fulfilled" && result.value.alive) {
479
+ alive.add(result.value.session);
480
+ }
481
+ }
482
+ }
483
+ return alive;
484
+ }
485
+ var CACHED_SESSION_BUSY_PATTERN = /[✻✽✶✳·].*…|Running…|• Working|• Ran |• Explored|• Called|esc to interrupt/;
486
+ function getCachedSessionState(sessionName, paneCache, aliveSessions) {
487
+ if (!aliveSessions.has(sessionName)) return "offline";
488
+ const pane = paneCache.get(sessionName);
489
+ if (!pane) return "offline";
490
+ if (!pane.includes("\u276F") && !pane.includes("Claude Code") && !CACHED_SESSION_BUSY_PATTERN.test(pane) && !/Running…/.test(pane)) {
491
+ if (/\$\s*$/.test(pane) || /% $/.test(pane.trimEnd())) {
492
+ return "no_claude";
493
+ }
494
+ }
495
+ if (/Running…/.test(pane)) return "tool";
496
+ if (CACHED_SESSION_BUSY_PATTERN.test(pane)) return "thinking";
497
+ return "idle";
498
+ }
454
499
  setInterval(() => {
455
500
  const now = Date.now();
456
501
  for (const [key, entry] of _paneCacheMap) {
@@ -480,6 +525,35 @@ var _idleTimer = null;
480
525
  var _requestsServed = 0;
481
526
  var _droppedRequests = 0;
482
527
  var _startedAt2 = Date.now();
528
+ var TIMER_TRACE_BOOT_WINDOW_MS = Number(process.env.EXE_TIMER_TRACE_BOOT_WINDOW_MS) || 10 * 60 * 1e3;
529
+ var TIMER_TRACE_SLOW_MS = Number(process.env.EXE_TIMER_TRACE_SLOW_MS) || 500;
530
+ function shouldTraceDaemonTimer(durationMs = 0) {
531
+ return Date.now() - _startedAt2 < TIMER_TRACE_BOOT_WINDOW_MS || durationMs >= TIMER_TRACE_SLOW_MS;
532
+ }
533
+ async function traceDaemonTimer(name, fn) {
534
+ const startedAt = Date.now();
535
+ const traceStart = shouldTraceDaemonTimer();
536
+ if (traceStart) {
537
+ process.stderr.write(`[exed] Timer start: ${name}
538
+ `);
539
+ }
540
+ try {
541
+ return await fn();
542
+ } finally {
543
+ const durationMs = Date.now() - startedAt;
544
+ if (shouldTraceDaemonTimer(durationMs)) {
545
+ const msg = `[exed] Timer duration: ${name} ${durationMs}ms`;
546
+ process.stderr.write(`${msg}
547
+ `);
548
+ logDaemonHealth({
549
+ event: "process_stats",
550
+ pid: process.pid,
551
+ message: msg,
552
+ data: { type: "timer_duration", timer: name, durationMs, uptimeMs: Date.now() - _startedAt2 }
553
+ });
554
+ }
555
+ }
556
+ }
483
557
  function enqueue(queue, entry) {
484
558
  if (queue.length >= MAX_QUEUE_SIZE) {
485
559
  queue.shift();
@@ -1200,7 +1274,7 @@ async function _writeMemoryRecordInner(entry) {
1200
1274
  }
1201
1275
  var MEMORY_DRAIN_INTERVAL_MS = 30 * 1e3;
1202
1276
  function startMemoryQueueDrain() {
1203
- const drain = async () => {
1277
+ const drain = async () => traceDaemonTimer("memory_queue_drain", async () => {
1204
1278
  fired("memory_queue_drain");
1205
1279
  if (!await ensureStoreForPolling()) return;
1206
1280
  try {
@@ -1237,7 +1311,7 @@ function startMemoryQueueDrain() {
1237
1311
  `
1238
1312
  );
1239
1313
  }
1240
- };
1314
+ });
1241
1315
  void drain();
1242
1316
  const timer = setInterval(() => void drain(), MEMORY_DRAIN_INTERVAL_MS);
1243
1317
  timer.unref();
@@ -1246,7 +1320,7 @@ function startMemoryQueueDrain() {
1246
1320
  }
1247
1321
  var MESSAGE_DRAIN_INTERVAL_MS = 3e4;
1248
1322
  function startMessageQueueDrain() {
1249
- const drain = async () => {
1323
+ const drain = async () => traceDaemonTimer("message_queue_drain", async () => {
1250
1324
  fired("message_queue_drain");
1251
1325
  if (!await ensureStoreForPolling()) return;
1252
1326
  try {
@@ -1290,7 +1364,7 @@ function startMessageQueueDrain() {
1290
1364
  `
1291
1365
  );
1292
1366
  }
1293
- };
1367
+ });
1294
1368
  void drain();
1295
1369
  const timer = setInterval(() => void drain(), MESSAGE_DRAIN_INTERVAL_MS);
1296
1370
  timer.unref();
@@ -2252,7 +2326,7 @@ async function startReviewPolling() {
2252
2326
  };
2253
2327
  const { pollReviewNudge, createReviewNudgeRealDeps, loadNudgeState } = await import("../daemon-orchestration-QVJ26DDN.js");
2254
2328
  const nudgeState = loadNudgeState();
2255
- const tick = async () => {
2329
+ const tick = async () => traceDaemonTimer("review_polling", async () => {
2256
2330
  fired("review_polling");
2257
2331
  if (!await ensureStoreForPolling()) return;
2258
2332
  try {
@@ -2279,7 +2353,7 @@ async function startReviewPolling() {
2279
2353
  process.stderr.write(`[exed] Review poll error: ${err instanceof Error ? err.message : String(err)}
2280
2354
  `);
2281
2355
  }
2282
- };
2356
+ });
2283
2357
  const timer = setInterval(() => void tick(), REVIEW_POLL_INTERVAL_MS);
2284
2358
  timer.unref();
2285
2359
  process.stderr.write(`[exed] Review polling started (every ${REVIEW_POLL_INTERVAL_MS / 6e4}m)
@@ -2287,7 +2361,7 @@ async function startReviewPolling() {
2287
2361
  }
2288
2362
  var SESSION_TTL_INTERVAL_MS = 5 * 60 * 1e3;
2289
2363
  function startSessionTTL() {
2290
- const tick = async () => {
2364
+ const tick = async () => traceDaemonTimer("session_ttl", async () => {
2291
2365
  fired("session_ttl");
2292
2366
  if (!await ensureStoreForPolling()) return;
2293
2367
  try {
@@ -2300,7 +2374,7 @@ function startSessionTTL() {
2300
2374
  process.stderr.write(`[exed] Session TTL error: ${err instanceof Error ? err.message : String(err)}
2301
2375
  `);
2302
2376
  }
2303
- };
2377
+ });
2304
2378
  const timer = setInterval(() => void tick(), SESSION_TTL_INTERVAL_MS);
2305
2379
  timer.unref();
2306
2380
  process.stderr.write(`[exed] Session TTL started (every ${SESSION_TTL_INTERVAL_MS / 6e4}m)
@@ -2310,7 +2384,7 @@ var COO_RESTART_COOLDOWN_MS = 5 * 6e4;
2310
2384
  var IDLE_KILL_INTERVAL_MS = 30 * 1e3;
2311
2385
  var _idleTickCounts = /* @__PURE__ */ new Map();
2312
2386
  function startIdleKill() {
2313
- const tick = async () => {
2387
+ const tick = async () => traceDaemonTimer("idle_kill", async () => {
2314
2388
  fired("idle_kill");
2315
2389
  if (!await ensureStoreForPolling()) return;
2316
2390
  try {
@@ -2321,7 +2395,7 @@ function startIdleKill() {
2321
2395
  const agentId = file.replace(".terminate", "");
2322
2396
  const signalPath = path3.join(signalDir, file);
2323
2397
  try {
2324
- const sessions = getTmuxSessions();
2398
+ const sessions = await getTmuxSessionsAsync();
2325
2399
  const match = sessions.find((s) => s.startsWith(`${agentId}-`) || s.startsWith(`${agentId}2-`) || s.startsWith(`${agentId}3-`));
2326
2400
  if (match) {
2327
2401
  execSyncNode(`tmux kill-session -t ${match} 2>/dev/null`, { timeout: 2e3 });
@@ -2342,10 +2416,20 @@ function startIdleKill() {
2342
2416
  if (!cfg) return;
2343
2417
  const { getClient } = await import("./database.js");
2344
2418
  const { pollIdleKill, createIdleKillRealDeps } = await import("../daemon-orchestration-QVJ26DDN.js");
2345
- const deps = createIdleKillRealDeps(
2419
+ const liveSessions = (await getTmuxSessionsAsync()).filter((s) => s.includes("-"));
2420
+ const [paneCache, aliveSessions] = await Promise.all([
2421
+ batchCapturePanes(liveSessions, 5),
2422
+ batchPaneAlive(liveSessions)
2423
+ ]);
2424
+ const realDeps = createIdleKillRealDeps(
2346
2425
  getClient,
2347
2426
  cfg.sessionLifecycle.idleKillIntercomAckWindowMs
2348
2427
  );
2428
+ const deps = {
2429
+ ...realDeps,
2430
+ listTmuxSessions: () => liveSessions,
2431
+ getSessionState: (sessionName) => getCachedSessionState(sessionName, paneCache, aliveSessions)
2432
+ };
2349
2433
  const killed = await pollIdleKill(deps, _idleTickCounts, {
2350
2434
  ticksRequired: cfg.sessionLifecycle.idleKillTicksRequired,
2351
2435
  enabled: cfg.sessionLifecycle.idleKillEnabled
@@ -2359,7 +2443,7 @@ function startIdleKill() {
2359
2443
  process.stderr.write(`[exed] Idle kill error: ${err instanceof Error ? err.message : String(err)}
2360
2444
  `);
2361
2445
  }
2362
- };
2446
+ });
2363
2447
  const timer = setInterval(() => void tick(), IDLE_KILL_INTERVAL_MS);
2364
2448
  timer.unref();
2365
2449
  process.stderr.write(`[exed] Idle kill started (every ${IDLE_KILL_INTERVAL_MS / 1e3}s)
@@ -2370,7 +2454,7 @@ function startConsolidation() {
2370
2454
  const { loadConfig: lc } = await import("./config.js");
2371
2455
  return lc();
2372
2456
  };
2373
- const tick = async () => {
2457
+ const tick = async () => traceDaemonTimer("consolidation_tick", async () => {
2374
2458
  fired("consolidation");
2375
2459
  try {
2376
2460
  const config = await loadConfig();
@@ -2421,8 +2505,9 @@ function startConsolidation() {
2421
2505
  process.stderr.write(`[exed] Consolidation error: ${err instanceof Error ? err.message : String(err)}
2422
2506
  `);
2423
2507
  }
2424
- };
2425
- loadConfig().then((config) => {
2508
+ });
2509
+ void traceDaemonTimer("consolidation_init", async () => {
2510
+ const config = await loadConfig();
2426
2511
  const intervalMs = config.consolidationIntervalMs;
2427
2512
  const timer = setInterval(() => void tick(), intervalMs);
2428
2513
  timer.unref();
@@ -2607,54 +2692,37 @@ function startGraphExtraction() {
2607
2692
  `);
2608
2693
  }
2609
2694
  var AGENT_STATS_INTERVAL_MS = 60 * 1e3;
2610
- var AGENT_STATS_SPEND_INTERVAL_MS = 10 * 60 * 1e3;
2611
2695
  var AGENT_STATS_PATH = path3.join(EXE_AI_DIR, "agent-stats.json");
2612
2696
  var _agentStatsInFlight = false;
2613
- var _agentSpendInFlight = false;
2614
- var _cachedSpend = null;
2697
+ var _cachedAgentData = null;
2615
2698
  async function writeAgentStats() {
2616
2699
  fired("agent_stats");
2617
2700
  if (_agentStatsInFlight) return;
2701
+ if (!_cachedAgentData) return;
2618
2702
  _agentStatsInFlight = true;
2619
- const started = Date.now();
2620
2703
  try {
2621
- if (!await ensureStoreForPolling()) return;
2622
2704
  acted("agent_stats");
2623
- const { getClient } = await import("./database.js");
2624
- const client = getClient();
2625
- const result = await client.execute({
2626
- sql: `SELECT agent_id,
2627
- COUNT(*) as total,
2628
- SUM(CASE WHEN timestamp > datetime('now', '-1 day') THEN 1 ELSE 0 END) as growth_24h,
2629
- SUM(CASE WHEN timestamp > datetime('now', '-7 days') THEN 1 ELSE 0 END) as growth_7d,
2630
- SUM(CASE WHEN timestamp > datetime('now', '-30 days') THEN 1 ELSE 0 END) as growth_30d
2631
- FROM memories
2632
- WHERE agent_id != 'default'
2633
- GROUP BY agent_id
2634
- ORDER BY total DESC`,
2635
- args: []
2636
- });
2637
- const agentsBase = result.rows.map((row) => {
2638
- const id = String(row.agent_id);
2639
- const s24 = _cachedSpend?.spend24h.get(id);
2640
- const s7 = _cachedSpend?.spend7d.get(id);
2641
- const s30 = _cachedSpend?.spend30d.get(id);
2705
+ const cache = _cachedAgentData;
2706
+ const agents = [...cache.counts.entries()].map(([id, c]) => {
2707
+ const s24 = cache.spend24h.get(id);
2708
+ const s7 = cache.spend7d.get(id);
2709
+ const s30 = cache.spend30d.get(id);
2642
2710
  return {
2643
2711
  id,
2644
- total: Number(row.total),
2645
- growth24h: Number(row.growth_24h),
2646
- growth7d: Number(row.growth_7d),
2647
- growth30d: Number(row.growth_30d),
2712
+ total: c.total,
2713
+ growth24h: c.growth24h,
2714
+ growth7d: c.growth7d,
2715
+ growth30d: c.growth30d,
2648
2716
  spend24h: s24 ?? { inputTokens: 0, outputTokens: 0, costUSD: 0, sessions: 0 },
2649
2717
  spend7d: s7 ?? { inputTokens: 0, outputTokens: 0, costUSD: 0, sessions: 0 },
2650
2718
  spend30d: s30 ?? { inputTokens: 0, outputTokens: 0, costUSD: 0, sessions: 0 }
2651
2719
  };
2652
2720
  });
2653
- const spendAge = _cachedSpend ? Math.round((Date.now() - _cachedSpend.refreshedAt) / 1e3) : null;
2721
+ const cacheAge = Math.round((Date.now() - cache.refreshedAt) / 1e3);
2654
2722
  const stats = {
2655
2723
  generated: (/* @__PURE__ */ new Date()).toISOString(),
2656
- spendStatus: _cachedSpend ? spendAge < AGENT_STATS_SPEND_INTERVAL_MS / 1e3 ? "fresh" : "stale" : "pending",
2657
- agents: agentsBase,
2724
+ dataStatus: cacheAge < AGENT_STATS_REFRESH_INTERVAL_MS / 1e3 ? "fresh" : "stale",
2725
+ agents,
2658
2726
  daemon: {
2659
2727
  uptime: Math.floor((Date.now() - _startedAt2) / 1e3),
2660
2728
  pid: process.pid
@@ -2666,55 +2734,82 @@ async function writeAgentStats() {
2666
2734
  `);
2667
2735
  } finally {
2668
2736
  _agentStatsInFlight = false;
2669
- const durationMs = Date.now() - started;
2670
- if (durationMs > 3e3) {
2671
- process.stderr.write(`[exed] Agent stats slow path: ${durationMs}ms
2672
- `);
2673
- logDaemonHealth({
2674
- event: "process_stats",
2675
- pid: process.pid,
2676
- message: `agent_stats took ${durationMs}ms`,
2677
- data: { type: "timer_slow", timer: "agent_stats", durationMs }
2678
- });
2679
- }
2680
2737
  }
2681
2738
  }
2682
- async function refreshAgentSpend() {
2683
- if (_agentSpendInFlight) return;
2684
- _agentSpendInFlight = true;
2739
+ var AGENT_STATS_REFRESH_INTERVAL_MS = 10 * 60 * 1e3;
2740
+ var _agentRefreshInFlight = false;
2741
+ async function refreshAgentData() {
2742
+ if (_agentRefreshInFlight) return;
2743
+ _agentRefreshInFlight = true;
2685
2744
  const started = Date.now();
2686
2745
  try {
2687
- const { getAgentSpend } = await import("./token-spend.js");
2688
- const spend24h = await getAgentSpend("24h");
2689
- const spend7d = await getAgentSpend("7d");
2690
- const spend30d = await getAgentSpend("30d");
2691
- _cachedSpend = {
2692
- spend24h: new Map(spend24h.map((s) => [s.agentId, { inputTokens: s.inputTokens, outputTokens: s.outputTokens, costUSD: s.costUSD, sessions: s.sessions }])),
2693
- spend7d: new Map(spend7d.map((s) => [s.agentId, { inputTokens: s.inputTokens, outputTokens: s.outputTokens, costUSD: s.costUSD, sessions: s.sessions }])),
2694
- spend30d: new Map(spend30d.map((s) => [s.agentId, { inputTokens: s.inputTokens, outputTokens: s.outputTokens, costUSD: s.costUSD, sessions: s.sessions }])),
2695
- refreshedAt: Date.now()
2696
- };
2746
+ if (!await ensureStoreForPolling()) return;
2747
+ const { getClient } = await import("./database.js");
2748
+ const client = getClient();
2749
+ const result = await client.execute({
2750
+ sql: `SELECT agent_id,
2751
+ COUNT(*) as total,
2752
+ SUM(CASE WHEN timestamp > datetime('now', '-1 day') THEN 1 ELSE 0 END) as growth_24h,
2753
+ SUM(CASE WHEN timestamp > datetime('now', '-7 days') THEN 1 ELSE 0 END) as growth_7d,
2754
+ SUM(CASE WHEN timestamp > datetime('now', '-30 days') THEN 1 ELSE 0 END) as growth_30d
2755
+ FROM memories
2756
+ WHERE agent_id != 'default'
2757
+ GROUP BY agent_id
2758
+ ORDER BY total DESC`,
2759
+ args: []
2760
+ });
2761
+ const counts = /* @__PURE__ */ new Map();
2762
+ for (const row of result.rows) {
2763
+ counts.set(String(row.agent_id), {
2764
+ total: Number(row.total),
2765
+ growth24h: Number(row.growth_24h),
2766
+ growth7d: Number(row.growth_7d),
2767
+ growth30d: Number(row.growth_30d)
2768
+ });
2769
+ }
2770
+ let spend24h = /* @__PURE__ */ new Map();
2771
+ let spend7d = /* @__PURE__ */ new Map();
2772
+ let spend30d = /* @__PURE__ */ new Map();
2773
+ try {
2774
+ const { getAgentSpend } = await import("./token-spend.js");
2775
+ const r24 = await getAgentSpend("24h");
2776
+ spend24h = new Map(r24.map((s) => [s.agentId, { inputTokens: s.inputTokens, outputTokens: s.outputTokens, costUSD: s.costUSD, sessions: s.sessions }]));
2777
+ const r7 = await getAgentSpend("7d");
2778
+ spend7d = new Map(r7.map((s) => [s.agentId, { inputTokens: s.inputTokens, outputTokens: s.outputTokens, costUSD: s.costUSD, sessions: s.sessions }]));
2779
+ const r30 = await getAgentSpend("30d");
2780
+ spend30d = new Map(r30.map((s) => [s.agentId, { inputTokens: s.inputTokens, outputTokens: s.outputTokens, costUSD: s.costUSD, sessions: s.sessions }]));
2781
+ } catch (err) {
2782
+ process.stderr.write(`[exed] Agent spend refresh error: ${err instanceof Error ? err.message : String(err)}
2783
+ `);
2784
+ }
2785
+ _cachedAgentData = { counts, spend24h, spend7d, spend30d, refreshedAt: Date.now() };
2697
2786
  const durationMs = Date.now() - started;
2698
2787
  if (durationMs > 5e3) {
2699
- process.stderr.write(`[exed] Agent spend refresh: ${durationMs}ms (${spend24h.length} agents)
2788
+ process.stderr.write(`[exed] Agent data refresh: ${durationMs}ms (${counts.size} agents)
2700
2789
  `);
2790
+ logDaemonHealth({
2791
+ event: "process_stats",
2792
+ pid: process.pid,
2793
+ message: `agent_data_refresh took ${durationMs}ms`,
2794
+ data: { type: "timer_slow", timer: "agent_data_refresh", durationMs }
2795
+ });
2701
2796
  }
2702
2797
  } catch (err) {
2703
- process.stderr.write(`[exed] Agent spend refresh error: ${err instanceof Error ? err.message : String(err)}
2798
+ process.stderr.write(`[exed] Agent data refresh error: ${err instanceof Error ? err.message : String(err)}
2704
2799
  `);
2705
2800
  } finally {
2706
- _agentSpendInFlight = false;
2801
+ _agentRefreshInFlight = false;
2707
2802
  }
2708
2803
  }
2709
2804
  function startAgentStats() {
2710
- const statsTimer = setInterval(() => void writeAgentStats(), AGENT_STATS_INTERVAL_MS);
2805
+ const statsTimer = setInterval(() => void traceDaemonTimer("agent_stats_write", () => writeAgentStats()), AGENT_STATS_INTERVAL_MS);
2711
2806
  statsTimer.unref();
2712
2807
  setTimeout(() => {
2713
- void refreshAgentSpend();
2714
- const spendTimer = setInterval(() => void refreshAgentSpend(), AGENT_STATS_SPEND_INTERVAL_MS);
2715
- spendTimer.unref();
2808
+ void traceDaemonTimer("agent_data_refresh", () => refreshAgentData());
2809
+ const refreshTimer = setInterval(() => void traceDaemonTimer("agent_data_refresh", () => refreshAgentData()), AGENT_STATS_REFRESH_INTERVAL_MS);
2810
+ refreshTimer.unref();
2716
2811
  }, 3 * 60 * 1e3);
2717
- process.stderr.write(`[exed] Agent stats started (counts every ${AGENT_STATS_INTERVAL_MS / 1e3}s, spend every ${AGENT_STATS_SPEND_INTERVAL_MS / 6e4}m, first spend at +3m)
2812
+ process.stderr.write(`[exed] Agent stats started (file every ${AGENT_STATS_INTERVAL_MS / 1e3}s, data refresh every ${AGENT_STATS_REFRESH_INTERVAL_MS / 6e4}m, first refresh at +3m)
2718
2813
  `);
2719
2814
  }
2720
2815
  var CONFIDENCE_DECAY_INTERVAL_MS = 24 * 60 * 60 * 1e3;
@@ -2781,7 +2876,7 @@ function startReflectionSweep() {
2781
2876
  `);
2782
2877
  }
2783
2878
  };
2784
- setTimeout(async () => {
2879
+ setTimeout(() => void traceDaemonTimer("memory_card_backfill", async () => {
2785
2880
  try {
2786
2881
  if (!await ensureStoreForPolling()) return;
2787
2882
  const { getClient: gc } = await import("./database.js");
@@ -2826,7 +2921,7 @@ function startReflectionSweep() {
2826
2921
  process.stderr.write("[exe-daemon] card backfill: " + (e instanceof Error ? e.message : String(e)) + "\n");
2827
2922
  }
2828
2923
  void tick();
2829
- }, 5 * 60 * 1e3);
2924
+ }), 5 * 60 * 1e3);
2830
2925
  const timer = setInterval(() => void tick(), REFLECTION_SWEEP_INTERVAL_MS);
2831
2926
  timer.unref();
2832
2927
  process.stderr.write(`[exed] Reflection sweep started (every 6h)
@@ -2896,7 +2991,7 @@ function startSoftDeletePurge() {
2896
2991
  }
2897
2992
  var QUEUE_DRAIN_INTERVAL_MS = 6e4;
2898
2993
  function startIntercomQueueDrain() {
2899
- const tick = async () => {
2994
+ const tick = async () => traceDaemonTimer("intercom_queue_drain", async () => {
2900
2995
  fired("intercom_queue_drain");
2901
2996
  try {
2902
2997
  const { drainQueue } = await import("../intercom-queue-RNM6EPGA.js");
@@ -2924,7 +3019,7 @@ function startIntercomQueueDrain() {
2924
3019
  } catch (e) {
2925
3020
  process.stderr.write("[exe-daemon] intercom queue drain: " + (e instanceof Error ? e.message : String(e)) + "\n");
2926
3021
  }
2927
- };
3022
+ });
2928
3023
  const timer = setInterval(tick, QUEUE_DRAIN_INTERVAL_MS);
2929
3024
  timer.unref();
2930
3025
  process.stderr.write(`[exed] Intercom queue drain started (every ${QUEUE_DRAIN_INTERVAL_MS / 1e3}s)
@@ -3075,7 +3170,7 @@ function getV8HeapLimitBytes() {
3075
3170
  }
3076
3171
  var TASK_ENFORCEMENT_INTERVAL_MS = 6e4;
3077
3172
  function startTaskEnforcementScanner() {
3078
- const tick = async () => {
3173
+ const tick = async () => traceDaemonTimer("task_enforcement", async () => {
3079
3174
  fired("task_enforcement");
3080
3175
  try {
3081
3176
  const { runTaskEnforcementTick } = await import("../task-enforcement-OSPCFH5T.js");
@@ -3085,10 +3180,20 @@ function startTaskEnforcementScanner() {
3085
3180
  const { loadEmployeesSync } = await import("./employees.js");
3086
3181
  const { sessionScopeFilter } = await import("../task-scope-4CBJ3QI2.js");
3087
3182
  const transport = getTransport();
3088
- const allSessions = getTmuxSessions().filter((s) => s.includes("-"));
3089
- const paneCache = await batchCapturePanes(allSessions, 20);
3183
+ const allSessions = (await getTmuxSessionsAsync()).filter((s) => s.includes("-"));
3184
+ const [paneCache, aliveSessions] = await Promise.all([
3185
+ batchCapturePanes(allSessions, 20),
3186
+ batchPaneAlive(allSessions)
3187
+ ]);
3188
+ const enforcementTransport = {
3189
+ listSessions: () => allSessions,
3190
+ capturePane: transport.capturePane.bind(transport),
3191
+ sendKeys: transport.sendKeys.bind(transport),
3192
+ sendKeysLiteral: transport.sendKeysLiteral?.bind(transport),
3193
+ isAlive: (session) => aliveSessions.has(session)
3194
+ };
3090
3195
  await runTaskEnforcementTick({
3091
- transport,
3196
+ transport: enforcementTransport,
3092
3197
  agentConfig: loadAgentConfig(),
3093
3198
  employees: loadEmployeesSync(),
3094
3199
  client: await getClient(),
@@ -3103,7 +3208,7 @@ function startTaskEnforcementScanner() {
3103
3208
  `
3104
3209
  );
3105
3210
  }
3106
- };
3211
+ });
3107
3212
  const timer = setInterval(tick, TASK_ENFORCEMENT_INTERVAL_MS);
3108
3213
  timer.unref();
3109
3214
  process.stderr.write(`[exed] Task enforcement scanner started (${TASK_ENFORCEMENT_INTERVAL_MS / 1e3}s interval)
@@ -3189,13 +3294,13 @@ var _apiWatchdogLastNudge = /* @__PURE__ */ new Map();
3189
3294
  var _apiWatchdogLastError = /* @__PURE__ */ new Map();
3190
3295
  var _apiWatchdogNudgeCounts = /* @__PURE__ */ new Map();
3191
3296
  function startApiWatchdog() {
3192
- const tick = async () => {
3297
+ const tick = async () => traceDaemonTimer("api_watchdog", async () => {
3193
3298
  fired("api_watchdog");
3194
3299
  try {
3195
3300
  const cfg = await getCachedConfig();
3196
3301
  if (!cfg?.apiWatchdog?.enabled) return;
3197
3302
  const cooldownMs = (cfg.apiWatchdog.cooldownMinutes ?? 10) * 6e4;
3198
- const sessions = getTmuxSessions();
3303
+ const sessions = await getTmuxSessionsAsync();
3199
3304
  if (sessions.length === 0) return;
3200
3305
  for (const session of sessions) {
3201
3306
  if (!session.includes("-")) continue;
@@ -3260,13 +3365,13 @@ function startApiWatchdog() {
3260
3365
  process.stderr.write(`[exed] API watchdog error: ${err instanceof Error ? err.message : String(err)}
3261
3366
  `);
3262
3367
  }
3263
- };
3368
+ });
3264
3369
  const timer = setInterval(() => void tick(), API_WATCHDOG_INTERVAL_MS);
3265
3370
  timer.unref();
3266
3371
  process.stderr.write("[exed] API watchdog started (30s scan, 10m cooldown per session)\n");
3267
3372
  }
3268
3373
  function startBackgroundJobGuardrails() {
3269
- const tick = async () => {
3374
+ const tick = async () => traceDaemonTimer("background_job_guardrails", async () => {
3270
3375
  fired("background_job_guardrails");
3271
3376
  try {
3272
3377
  const { enforceBackgroundJobGuardrails } = await import("../background-jobs-Q4S27FCN.js");
@@ -3285,7 +3390,7 @@ function startBackgroundJobGuardrails() {
3285
3390
  process.stderr.write(`[exed] Background job guardrail error: ${err instanceof Error ? err.message : String(err)}
3286
3391
  `);
3287
3392
  }
3288
- };
3393
+ });
3289
3394
  const timer = setInterval(() => void tick(), 6e4);
3290
3395
  timer.unref();
3291
3396
  process.stderr.write("[exed] Background job guardrails started (every 60s)\n");
@@ -3672,7 +3777,7 @@ try {
3672
3777
  startApiWatchdog();
3673
3778
  startRssWatchdog();
3674
3779
  setTimeout(startWalCheckpoint, 5e3);
3675
- setTimeout(async () => {
3780
+ setTimeout(() => void traceDaemonTimer("task_file_resync", async () => {
3676
3781
  try {
3677
3782
  if (!await ensureStoreForPolling()) return;
3678
3783
  const { readdir, readFile } = await import("fs/promises");
@@ -3740,17 +3845,17 @@ try {
3740
3845
  process.stderr.write(`[exed] Task re-sync error: ${e.message}
3741
3846
  `);
3742
3847
  }
3743
- }, 8e3);
3848
+ }), 8e3);
3744
3849
  setTimeout(startIdleKill, 1e4);
3745
3850
  setTimeout(startStuckTaskRelease, 15e3);
3746
3851
  setTimeout(startOrphanReaper, 2e4);
3747
3852
  setTimeout(startCloudSyncTimer, 25e3);
3748
3853
  setTimeout(startAgentStats, 3e4);
3749
- setTimeout(async () => {
3854
+ setTimeout(() => void traceDaemonTimer("session_registry_consistency", async () => {
3750
3855
  fired("session_registry_consistency");
3751
3856
  try {
3752
3857
  const { checkSessionRegistryConsistency } = await import("./session-registry.js");
3753
- const result = checkSessionRegistryConsistency();
3858
+ const result = checkSessionRegistryConsistency(await getTmuxSessionsAsync());
3754
3859
  if (result.missingTmux > 0 || result.missingRegistry > 0) {
3755
3860
  acted("session_registry_consistency");
3756
3861
  process.stderr.write(
@@ -3762,8 +3867,8 @@ try {
3762
3867
  process.stderr.write(`[exed] Session registry consistency error: ${err instanceof Error ? err.message : String(err)}
3763
3868
  `);
3764
3869
  }
3765
- }, 35e3);
3766
- setTimeout(startConsolidation, 6e4);
3870
+ }), 35e3);
3871
+ setTimeout(() => void traceDaemonTimer("consolidation_start", () => startConsolidation()), 6e4);
3767
3872
  setTimeout(startSkillSweep, 9e4);
3768
3873
  setTimeout(startSkillRefinement, 18e4);
3769
3874
  setTimeout(startGraphExtraction, 27e4);
@@ -3773,10 +3878,10 @@ try {
3773
3878
  setTimeout(startBugAutoFix, 24e4);
3774
3879
  setTimeout(startDatabaseBackup, 27e4);
3775
3880
  setTimeout(startAutoUpdateCheck, 3e5);
3776
- setTimeout(startBackgroundJobGuardrails, 6e4);
3881
+ setTimeout(() => void traceDaemonTimer("background_job_guardrails_start", () => startBackgroundJobGuardrails()), 6e4);
3777
3882
  setTimeout(startWorktreeReaper, 12e4);
3778
3883
  setTimeout(startZombieAgentReaper, 25e3);
3779
- setTimeout(async () => {
3884
+ setTimeout(() => void traceDaemonTimer("intercom_dedup_cleanup", async () => {
3780
3885
  fired("intercom_dedup_cleanup");
3781
3886
  try {
3782
3887
  if (!await ensureStoreForPolling()) return;
@@ -3792,8 +3897,8 @@ try {
3792
3897
  process.stderr.write(`[exed] Intercom dedup error: ${err instanceof Error ? err.message : String(err)}
3793
3898
  `);
3794
3899
  }
3795
- }, 3e4);
3796
- setTimeout(async () => {
3900
+ }), 3e4);
3901
+ setTimeout(() => void traceDaemonTimer("trace_ttl_sweep", async () => {
3797
3902
  fired("trace_ttl_sweep");
3798
3903
  try {
3799
3904
  if (!await ensureStoreForPolling()) return;
@@ -3809,8 +3914,8 @@ try {
3809
3914
  process.stderr.write(`[exed] Trace TTL error: ${err instanceof Error ? err.message : String(err)}
3810
3915
  `);
3811
3916
  }
3812
- }, 45e3);
3813
- setTimeout(async () => {
3917
+ }), 45e3);
3918
+ setTimeout(() => void traceDaemonTimer("orphan_task_cleanup", async () => {
3814
3919
  fired("orphan_task_cleanup");
3815
3920
  try {
3816
3921
  if (!await ensureStoreForPolling()) return;
@@ -3830,7 +3935,7 @@ try {
3830
3935
  process.stderr.write(`[exed] Orphan cleanup error: ${err instanceof Error ? err.message : String(err)}
3831
3936
  `);
3832
3937
  }
3833
- }, 45e3);
3938
+ }), 45e3);
3834
3939
  const HEALTH_HEARTBEAT_MS = 5 * 60 * 1e3;
3835
3940
  setInterval(() => {
3836
3941
  logHeartbeat();
@@ -5,7 +5,7 @@ import {
5
5
  recentRecords,
6
6
  rrfMerge,
7
7
  rrfMergeMulti
8
- } from "../chunk-PTO7FEZG.js";
8
+ } from "../chunk-NVZODD7S.js";
9
9
  import "../chunk-E3Q4R3K6.js";
10
10
  import "../chunk-CHCA3ZM2.js";
11
11
  import "../chunk-XJQASQPO.js";
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  registerAllTools
3
- } from "../chunk-4TQ3GE3G.js";
3
+ } from "../chunk-LSARQLX3.js";
4
4
  import "../chunk-557C2IGL.js";
5
5
  import "../chunk-3GFXV46R.js";
6
6
  import "../chunk-BO6HP63V.js";
7
- import "../chunk-G3JAB3O5.js";
7
+ import "../chunk-UFOERR37.js";
8
8
  import "../chunk-KH5Y6RR4.js";
9
9
  import "../chunk-GCMXBQ7Y.js";
10
10
  import "../chunk-IENYOYZ6.js";
@@ -56,7 +56,7 @@ import "../chunk-GMQKS5JD.js";
56
56
  import "../chunk-K5EXLDQD.js";
57
57
  import "../chunk-EF4PA3TY.js";
58
58
  import "../chunk-LMSRF47U.js";
59
- import "../chunk-PTO7FEZG.js";
59
+ import "../chunk-NVZODD7S.js";
60
60
  import "../chunk-E3Q4R3K6.js";
61
61
  import "../chunk-CHCA3ZM2.js";
62
62
  import "../chunk-XJQASQPO.js";
@@ -3,11 +3,11 @@ import {
3
3
  } from "../chunk-V4TZI6EO.js";
4
4
  import {
5
5
  registerAllTools
6
- } from "../chunk-4TQ3GE3G.js";
6
+ } from "../chunk-LSARQLX3.js";
7
7
  import "../chunk-557C2IGL.js";
8
8
  import "../chunk-3GFXV46R.js";
9
9
  import "../chunk-BO6HP63V.js";
10
- import "../chunk-G3JAB3O5.js";
10
+ import "../chunk-UFOERR37.js";
11
11
  import "../chunk-KH5Y6RR4.js";
12
12
  import {
13
13
  initLicenseGate
@@ -66,7 +66,7 @@ import "../chunk-GMQKS5JD.js";
66
66
  import "../chunk-K5EXLDQD.js";
67
67
  import "../chunk-EF4PA3TY.js";
68
68
  import "../chunk-LMSRF47U.js";
69
- import "../chunk-PTO7FEZG.js";
69
+ import "../chunk-NVZODD7S.js";
70
70
  import {
71
71
  disposeStore,
72
72
  initStore
@@ -5,7 +5,7 @@ import {
5
5
  rerank,
6
6
  rerankWithContext,
7
7
  rerankWithScores
8
- } from "./chunk-G3JAB3O5.js";
8
+ } from "./chunk-UFOERR37.js";
9
9
  import "./chunk-WXW3XGWX.js";
10
10
  import "./chunk-LYH5HE24.js";
11
11
  import "./chunk-MLKGABMK.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@askexenow/exe-os",
3
- "version": "0.9.211",
3
+ "version": "0.9.214",
4
4
  "description": "AI employee operating system — persistent memory, task management, and multi-agent coordination for Claude Code.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "type": "module",
@@ -1,9 +1,9 @@
1
1
  {
2
- "current": "0.9.211",
2
+ "current": "0.9.214",
3
3
  "notes": {
4
- "0.9.211": {
5
- "version": "0.9.211",
6
- "date": "2026-06-03",
4
+ "0.9.214": {
5
+ "version": "0.9.214",
6
+ "date": "2026-06-04",
7
7
  "features": [
8
8
  "free license telemetry is mandatory, paid can opt out",
9
9
  "add mcp-sessions CLI — rich status table for running sessions",
@@ -32,6 +32,11 @@
32
32
  "wire update.askexe.com — billing schema + non-fatal image credentials"
33
33
  ],
34
34
  "fixes": [
35
+ "remove failed DB warmup workaround",
36
+ "trace daemon timers and async tmux session checks",
37
+ "add scope comment to DB warmup task query (readiness gate)",
38
+ "add DB warmup at boot+5s to prevent 15s block on first query",
39
+ "move DB memory count query to slow path — fast path is cache-only",
35
40
  "split agent stats into fast path (60s) + slow path (10m)",
36
41
  "defer agent stats first tick + async file write",
37
42
  "Fix daemon agent stats event-loop stalls",
@@ -51,12 +56,7 @@
51
56
  "shard circuit breaker, event loop self-healing, heap cap, intercom reason",
52
57
  "add generate-hook-manifest to tsup entries — unblocks publish gate",
53
58
  "remove unused cleanupExpiredJars import — fixes TS6133 blocking publish",
54
- "remove dead actualRuntime variable — fixes TS6133 blocking publish",
55
- "isolate Metal/GPU ops in worker process — reranker dispose crash was killing daemon",
56
- "remove remaining /exe-intercom invocations + update tests",
57
- "replace /exe-intercom skill invocation with plain text prompt",
58
- "remove ALL --strict-mcp-config usage — was blocking /exe-intercom in session MCP config too",
59
- "tsup outputs to dist directly — kill dist-next migration shim"
59
+ "remove dead actualRuntime variable — fixes TS6133 blocking publish"
60
60
  ],
61
61
  "security": [
62
62
  "fix shell injection, SSRF, socket leaks, backup validation",
@@ -73,6 +73,9 @@
73
73
  "fix 4 pricing tier bypass vulnerabilities (audit F1-F4)"
74
74
  ],
75
75
  "other": [
76
+ "bump to v0.9.214",
77
+ "bump to v0.9.213",
78
+ "bump to v0.9.212",
76
79
  "bump to v0.9.211",
77
80
  "bump to v0.9.210",
78
81
  "bump to v0.9.209",
@@ -94,15 +97,12 @@
94
97
  "bump to v0.9.201",
95
98
  "bump to v0.9.200",
96
99
  "design orchestration measurement baseline",
97
- "capture tmux hardening path",
98
- "add orchestration counterargument",
99
- "audit tmux orchestration architecture",
100
- "bump to v0.9.199"
100
+ "capture tmux hardening path"
101
101
  ],
102
102
  "migration_notes": []
103
103
  },
104
- "0.9.210": {
105
- "version": "0.9.210",
104
+ "0.9.212": {
105
+ "version": "0.9.212",
106
106
  "date": "2026-06-03",
107
107
  "features": [
108
108
  "free license telemetry is mandatory, paid can opt out",
@@ -132,6 +132,8 @@
132
132
  "wire update.askexe.com — billing schema + non-fatal image credentials"
133
133
  ],
134
134
  "fixes": [
135
+ "move DB memory count query to slow path — fast path is cache-only",
136
+ "split agent stats into fast path (60s) + slow path (10m)",
135
137
  "defer agent stats first tick + async file write",
136
138
  "Fix daemon agent stats event-loop stalls",
137
139
  "async-ify task re-sync walk + git worktree list in daemon",
@@ -154,9 +156,7 @@
154
156
  "isolate Metal/GPU ops in worker process — reranker dispose crash was killing daemon",
155
157
  "remove remaining /exe-intercom invocations + update tests",
156
158
  "replace /exe-intercom skill invocation with plain text prompt",
157
- "remove ALL --strict-mcp-config usage — was blocking /exe-intercom in session MCP config too",
158
- "tsup outputs to dist directly — kill dist-next migration shim",
159
- "drop --strict-mcp-config from lean MCP — was blocking skill loading (/exe-intercom)"
159
+ "remove ALL --strict-mcp-config usage — was blocking /exe-intercom in session MCP config too"
160
160
  ],
161
161
  "security": [
162
162
  "fix shell injection, SSRF, socket leaks, backup validation",
@@ -173,6 +173,8 @@
173
173
  "fix 4 pricing tier bypass vulnerabilities (audit F1-F4)"
174
174
  ],
175
175
  "other": [
176
+ "bump to v0.9.212",
177
+ "bump to v0.9.211",
176
178
  "bump to v0.9.210",
177
179
  "bump to v0.9.209",
178
180
  "update release-notes.json",
@@ -195,14 +197,12 @@
195
197
  "design orchestration measurement baseline",
196
198
  "capture tmux hardening path",
197
199
  "add orchestration counterargument",
198
- "audit tmux orchestration architecture",
199
- "bump to v0.9.199",
200
- "remove registry.askexe.com references — fully consolidated to update.askexe.com"
200
+ "audit tmux orchestration architecture"
201
201
  ],
202
202
  "migration_notes": []
203
203
  },
204
- "0.9.209": {
205
- "version": "0.9.209",
204
+ "0.9.211": {
205
+ "version": "0.9.211",
206
206
  "date": "2026-06-03",
207
207
  "features": [
208
208
  "free license telemetry is mandatory, paid can opt out",
@@ -232,6 +232,8 @@
232
232
  "wire update.askexe.com — billing schema + non-fatal image credentials"
233
233
  ],
234
234
  "fixes": [
235
+ "split agent stats into fast path (60s) + slow path (10m)",
236
+ "defer agent stats first tick + async file write",
235
237
  "Fix daemon agent stats event-loop stalls",
236
238
  "async-ify task re-sync walk + git worktree list in daemon",
237
239
  "async worktree reaper — eliminates 30-min event loop blocks",
@@ -254,9 +256,7 @@
254
256
  "remove remaining /exe-intercom invocations + update tests",
255
257
  "replace /exe-intercom skill invocation with plain text prompt",
256
258
  "remove ALL --strict-mcp-config usage — was blocking /exe-intercom in session MCP config too",
257
- "tsup outputs to dist directly — kill dist-next migration shim",
258
- "drop --strict-mcp-config from lean MCP — was blocking skill loading (/exe-intercom)",
259
- "zombie agent reaper never kills coordinator/exe session processes"
259
+ "tsup outputs to dist directly — kill dist-next migration shim"
260
260
  ],
261
261
  "security": [
262
262
  "fix shell injection, SSRF, socket leaks, backup validation",
@@ -273,6 +273,8 @@
273
273
  "fix 4 pricing tier bypass vulnerabilities (audit F1-F4)"
274
274
  ],
275
275
  "other": [
276
+ "bump to v0.9.211",
277
+ "bump to v0.9.210",
276
278
  "bump to v0.9.209",
277
279
  "update release-notes.json",
278
280
  "Standardize task completion reports",
@@ -295,16 +297,16 @@
295
297
  "capture tmux hardening path",
296
298
  "add orchestration counterargument",
297
299
  "audit tmux orchestration architecture",
298
- "bump to v0.9.199",
299
- "remove registry.askexe.com references — fully consolidated to update.askexe.com",
300
- "bump to 0.9.198 — coordinator reaper guard"
300
+ "bump to v0.9.199"
301
301
  ],
302
302
  "migration_notes": []
303
303
  },
304
- "0.9.208": {
305
- "version": "0.9.208",
304
+ "0.9.210": {
305
+ "version": "0.9.210",
306
306
  "date": "2026-06-03",
307
307
  "features": [
308
+ "free license telemetry is mandatory, paid can opt out",
309
+ "add mcp-sessions CLI — rich status table for running sessions",
308
310
  "5-minute telemetry batching + per-tool-call usage in payload",
309
311
  "disk outbox for failed telemetry + remote killswitch",
310
312
  "auto-attach orchestration metrics to every bug report",
@@ -327,11 +329,10 @@
327
329
  "scale daemon heap to 25% of system RAM, support 10+ coordinators",
328
330
  "add query expansion + benchmark results to retrieval platform procedure",
329
331
  "3-mode BEAM benchmark — FTS vs FTS+Graph vs Hybrid",
330
- "wire update.askexe.com — billing schema + non-fatal image credentials",
331
- "add 'never defer' platform procedure — fix it now or assign it now",
332
- "BEAM multi-tier support — 100K, 1M, 10M token scales"
332
+ "wire update.askexe.com — billing schema + non-fatal image credentials"
333
333
  ],
334
334
  "fixes": [
335
+ "defer agent stats first tick + async file write",
335
336
  "Fix daemon agent stats event-loop stalls",
336
337
  "async-ify task re-sync walk + git worktree list in daemon",
337
338
  "async worktree reaper — eliminates 30-min event loop blocks",
@@ -355,8 +356,7 @@
355
356
  "replace /exe-intercom skill invocation with plain text prompt",
356
357
  "remove ALL --strict-mcp-config usage — was blocking /exe-intercom in session MCP config too",
357
358
  "tsup outputs to dist directly — kill dist-next migration shim",
358
- "drop --strict-mcp-config from lean MCP — was blocking skill loading (/exe-intercom)",
359
- "zombie agent reaper never kills coordinator/exe session processes"
359
+ "drop --strict-mcp-config from lean MCP — was blocking skill loading (/exe-intercom)"
360
360
  ],
361
361
  "security": [
362
362
  "fix shell injection, SSRF, socket leaks, backup validation",
@@ -373,12 +373,15 @@
373
373
  "fix 4 pricing tier bypass vulnerabilities (audit F1-F4)"
374
374
  ],
375
375
  "other": [
376
+ "bump to v0.9.210",
377
+ "bump to v0.9.209",
378
+ "update release-notes.json",
379
+ "Standardize task completion reports",
376
380
  "bump to v0.9.208",
377
381
  "bump to v0.9.207",
378
382
  "bump to v0.9.206",
379
383
  "bump to v0.9.205",
380
384
  "bump to v0.9.204",
381
- "update release-notes.json",
382
385
  "bump stack manifest to v0.9.12 — CRM v0.9.44, exe-os v0.9.199",
383
386
  "review full orchestration measurement coverage",
384
387
  "bump to v0.9.203",
@@ -394,17 +397,16 @@
394
397
  "add orchestration counterargument",
395
398
  "audit tmux orchestration architecture",
396
399
  "bump to v0.9.199",
397
- "remove registry.askexe.com references — fully consolidated to update.askexe.com",
398
- "bump to 0.9.198 — coordinator reaper guard",
399
- "bump to 0.9.197 — TTL fix + registry consolidation + TS fixes",
400
- "update all manifest images to update.askexe.com + compose + beam tuning"
400
+ "remove registry.askexe.com references — fully consolidated to update.askexe.com"
401
401
  ],
402
402
  "migration_notes": []
403
403
  },
404
- "0.9.207": {
405
- "version": "0.9.207",
404
+ "0.9.209": {
405
+ "version": "0.9.209",
406
406
  "date": "2026-06-03",
407
407
  "features": [
408
+ "free license telemetry is mandatory, paid can opt out",
409
+ "add mcp-sessions CLI — rich status table for running sessions",
408
410
  "5-minute telemetry batching + per-tool-call usage in payload",
409
411
  "disk outbox for failed telemetry + remote killswitch",
410
412
  "auto-attach orchestration metrics to every bug report",
@@ -427,11 +429,10 @@
427
429
  "scale daemon heap to 25% of system RAM, support 10+ coordinators",
428
430
  "add query expansion + benchmark results to retrieval platform procedure",
429
431
  "3-mode BEAM benchmark — FTS vs FTS+Graph vs Hybrid",
430
- "wire update.askexe.com — billing schema + non-fatal image credentials",
431
- "add 'never defer' platform procedure — fix it now or assign it now",
432
- "BEAM multi-tier support — 100K, 1M, 10M token scales"
432
+ "wire update.askexe.com — billing schema + non-fatal image credentials"
433
433
  ],
434
434
  "fixes": [
435
+ "Fix daemon agent stats event-loop stalls",
435
436
  "async-ify task re-sync walk + git worktree list in daemon",
436
437
  "async worktree reaper — eliminates 30-min event loop blocks",
437
438
  "simplify telemetry to once-per-day only",
@@ -455,8 +456,7 @@
455
456
  "remove ALL --strict-mcp-config usage — was blocking /exe-intercom in session MCP config too",
456
457
  "tsup outputs to dist directly — kill dist-next migration shim",
457
458
  "drop --strict-mcp-config from lean MCP — was blocking skill loading (/exe-intercom)",
458
- "zombie agent reaper never kills coordinator/exe session processes",
459
- "typecheck errors blocking publish — async embed alert + dead code cleanup"
459
+ "zombie agent reaper never kills coordinator/exe session processes"
460
460
  ],
461
461
  "security": [
462
462
  "fix shell injection, SSRF, socket leaks, backup validation",
@@ -473,11 +473,14 @@
473
473
  "fix 4 pricing tier bypass vulnerabilities (audit F1-F4)"
474
474
  ],
475
475
  "other": [
476
+ "bump to v0.9.209",
477
+ "update release-notes.json",
478
+ "Standardize task completion reports",
479
+ "bump to v0.9.208",
476
480
  "bump to v0.9.207",
477
481
  "bump to v0.9.206",
478
482
  "bump to v0.9.205",
479
483
  "bump to v0.9.204",
480
- "update release-notes.json",
481
484
  "bump stack manifest to v0.9.12 — CRM v0.9.44, exe-os v0.9.199",
482
485
  "review full orchestration measurement coverage",
483
486
  "bump to v0.9.203",
@@ -494,10 +497,7 @@
494
497
  "audit tmux orchestration architecture",
495
498
  "bump to v0.9.199",
496
499
  "remove registry.askexe.com references — fully consolidated to update.askexe.com",
497
- "bump to 0.9.198 — coordinator reaper guard",
498
- "bump to 0.9.197 — TTL fix + registry consolidation + TS fixes",
499
- "update all manifest images to update.askexe.com + compose + beam tuning",
500
- "bump to 0.9.196"
500
+ "bump to 0.9.198 — coordinator reaper guard"
501
501
  ],
502
502
  "migration_notes": []
503
503
  }
File without changes