@askexenow/exe-os 0.9.350 → 0.9.352

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/cli.js CHANGED
@@ -201,7 +201,7 @@ if (args.includes("--global")) {
201
201
  process.exit(1);
202
202
  }
203
203
  } else if (args[0] === "key") {
204
- const { main: runKey } = await import("../exe-key-GYNPBQDF.js");
204
+ const { main: runKey } = await import("../exe-key-5R6XAPHS.js");
205
205
  await runKey(args.slice(1));
206
206
  } else if (args[0] === "grant") {
207
207
  const { main: runGrant } = await import("./exe-grant.js");
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  computeMcpSurfaceHash
4
- } from "../chunk-RYKHPC3Y.js";
4
+ } from "../chunk-XKA343SE.js";
5
5
  import "../chunk-WCGNCH3Q.js";
6
- import "../chunk-FUOXMZUZ.js";
6
+ import "../chunk-HKXNF72F.js";
7
7
  import "../chunk-557C2IGL.js";
8
8
  import "../chunk-PELEK2IT.js";
9
9
  import "../chunk-L3DKZC4R.js";
@@ -15,9 +15,9 @@ import "../chunk-MBULOZJF.js";
15
15
  import "../chunk-KBFHODXV.js";
16
16
  import "../chunk-OPDZ62TW.js";
17
17
  import "../chunk-YJBBW6OT.js";
18
- import "../chunk-4NPP7ASA.js";
18
+ import "../chunk-AD42TL2C.js";
19
19
  import "../chunk-CRCB5S7I.js";
20
- import "../chunk-EDEVSNAF.js";
20
+ import "../chunk-P5C7JCIZ.js";
21
21
  import "../chunk-KES3SNOH.js";
22
22
  import "../chunk-E6ORBQHP.js";
23
23
  import "../chunk-WAVZDYXS.js";
@@ -75,7 +75,7 @@ import "../chunk-S3THSOWV.js";
75
75
  import "../chunk-IOEUAQWP.js";
76
76
  import "../chunk-I5AVZOL2.js";
77
77
  import "../chunk-APRVAUOR.js";
78
- import "../chunk-EGYDW57S.js";
78
+ import "../chunk-H2BE7ZPC.js";
79
79
  import "../chunk-AB4PAQYK.js";
80
80
  import "../chunk-LVG5ATTU.js";
81
81
  import "../chunk-PENPH5AG.js";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  lightweightSearch
4
- } from "../chunk-EGYDW57S.js";
4
+ } from "../chunk-H2BE7ZPC.js";
5
5
  import "../chunk-AB4PAQYK.js";
6
6
  import "../chunk-LVG5ATTU.js";
7
7
  import "../chunk-PENPH5AG.js";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  hybridSearch
4
- } from "../chunk-EGYDW57S.js";
4
+ } from "../chunk-H2BE7ZPC.js";
5
5
  import "../chunk-AB4PAQYK.js";
6
6
  import {
7
7
  initStore
@@ -12,7 +12,7 @@ import {
12
12
  import "../chunk-XBOLFVMD.js";
13
13
  import {
14
14
  computeMcpSurfaceHash
15
- } from "../chunk-RYKHPC3Y.js";
15
+ } from "../chunk-XKA343SE.js";
16
16
  import {
17
17
  buildDaemonLaunchdPlist,
18
18
  buildWatchdogLaunchdPlist,
@@ -24,7 +24,7 @@ import {
24
24
  generateSessionWrappers
25
25
  } from "../chunk-CVTWQZOR.js";
26
26
  import "../chunk-WCGNCH3Q.js";
27
- import "../chunk-FUOXMZUZ.js";
27
+ import "../chunk-HKXNF72F.js";
28
28
  import "../chunk-557C2IGL.js";
29
29
  import "../chunk-PELEK2IT.js";
30
30
  import "../chunk-L3DKZC4R.js";
@@ -36,9 +36,9 @@ import "../chunk-MBULOZJF.js";
36
36
  import "../chunk-KBFHODXV.js";
37
37
  import "../chunk-OPDZ62TW.js";
38
38
  import "../chunk-YJBBW6OT.js";
39
- import "../chunk-4NPP7ASA.js";
39
+ import "../chunk-AD42TL2C.js";
40
40
  import "../chunk-CRCB5S7I.js";
41
- import "../chunk-EDEVSNAF.js";
41
+ import "../chunk-P5C7JCIZ.js";
42
42
  import "../chunk-KES3SNOH.js";
43
43
  import "../chunk-E6ORBQHP.js";
44
44
  import "../chunk-WAVZDYXS.js";
@@ -99,7 +99,7 @@ import "../chunk-APRVAUOR.js";
99
99
  import {
100
100
  resolveEmbeddingsEnabled
101
101
  } from "../chunk-KWOAM7TA.js";
102
- import "../chunk-EGYDW57S.js";
102
+ import "../chunk-H2BE7ZPC.js";
103
103
  import "../chunk-AB4PAQYK.js";
104
104
  import "../chunk-LVG5ATTU.js";
105
105
  import "../chunk-PENPH5AG.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  lightweightSearch
3
- } from "./chunk-EGYDW57S.js";
3
+ } from "./chunk-H2BE7ZPC.js";
4
4
  import "./chunk-AB4PAQYK.js";
5
5
  import "./chunk-LVG5ATTU.js";
6
6
  import "./chunk-PENPH5AG.js";
@@ -564,7 +564,7 @@ async function hybridSearch(queryText, agentId, options) {
564
564
  let rerankerAvailable = false;
565
565
  if (process.env.EXE_IS_DAEMON === "1") {
566
566
  try {
567
- const { isRerankerAvailable } = await import("./reranker-GJEC7PVT.js");
567
+ const { isRerankerAvailable } = await import("./reranker-N4QIAVEZ.js");
568
568
  rerankerAvailable = isRerankerAvailable();
569
569
  } catch {
570
570
  }
@@ -767,7 +767,7 @@ async function hybridSearch(queryText, agentId, options) {
767
767
  try {
768
768
  let rerankedRecords;
769
769
  if (graphContextMap.size > 0) {
770
- const { rerankWithContext } = await import("./reranker-GJEC7PVT.js");
770
+ const { rerankWithContext } = await import("./reranker-N4QIAVEZ.js");
771
771
  const candidates = merged.map((m) => ({
772
772
  text: m.raw_text,
773
773
  context: graphContextMap.get(m.id)
@@ -775,7 +775,7 @@ async function hybridSearch(queryText, agentId, options) {
775
775
  const scored = await rerankWithContext(effectiveQuery, candidates, rerankReturnLimit);
776
776
  rerankedRecords = scored.map((s) => merged[s.index]);
777
777
  } else {
778
- const { rerank } = await import("./reranker-GJEC7PVT.js");
778
+ const { rerank } = await import("./reranker-N4QIAVEZ.js");
779
779
  rerankedRecords = await rerank(effectiveQuery, merged, rerankReturnLimit);
780
780
  }
781
781
  if (rerankedRecords.length > 0) {
@@ -59,7 +59,7 @@ import {
59
59
  import {
60
60
  isRerankerAvailable,
61
61
  rerankWithScores
62
- } from "./chunk-4NPP7ASA.js";
62
+ } from "./chunk-AD42TL2C.js";
63
63
  import {
64
64
  getEntityByName,
65
65
  getEntityNeighbors,
@@ -70,7 +70,7 @@ import {
70
70
  } from "./chunk-CRCB5S7I.js";
71
71
  import {
72
72
  AUTO_WAKE_MAX_RETRIES
73
- } from "./chunk-EDEVSNAF.js";
73
+ } from "./chunk-P5C7JCIZ.js";
74
74
  import {
75
75
  listRecentSessionEvents
76
76
  } from "./chunk-KES3SNOH.js";
@@ -242,7 +242,7 @@ import {
242
242
  import {
243
243
  hybridSearch,
244
244
  recentRecords
245
- } from "./chunk-EGYDW57S.js";
245
+ } from "./chunk-H2BE7ZPC.js";
246
246
  import {
247
247
  buildFtsMatch,
248
248
  tokenizeForFts
@@ -2837,11 +2837,13 @@ function registerResumeEmployee(server) {
2837
2837
  }
2838
2838
  },
2839
2839
  async ({ agent_id, project_name }) => {
2840
+ let client;
2840
2841
  if (!isInitialized()) {
2841
2842
  const { fastDbInit: fastDbInit2 } = await import("./fast-db-init-5HF3TLAF.js");
2842
- await fastDbInit2();
2843
+ client = await fastDbInit2();
2844
+ } else {
2845
+ client = getClient();
2843
2846
  }
2844
- const client = getClient();
2845
2847
  const reScope = sessionScopeFilter();
2846
2848
  const openTasks = await client.execute({
2847
2849
  sql: `SELECT id, title, priority, task_file, status, assigned_tmux,
@@ -1982,6 +1982,134 @@ function createStuckTaskRealDeps(getClient) {
1982
1982
  }
1983
1983
  };
1984
1984
  }
1985
+ async function releaseStaleClaims(deps, nowMs = Date.now()) {
1986
+ let liveSessions;
1987
+ try {
1988
+ liveSessions = deps.listTmuxSessionsAsync ? await deps.listTmuxSessionsAsync() : deps.listTmuxSessions();
1989
+ } catch (e) {
1990
+ process.stderr.write("[stale-claim] list tmux sessions: " + (e instanceof Error ? e.message : String(e)) + "\n");
1991
+ return [];
1992
+ }
1993
+ if (liveSessions.length === 0 && deps.tmuxSessionsVerified?.() === false) {
1994
+ process.stderr.write("[stale-claim] Skipping claim release: tmux session list was not verified (probe failed/timeout). Preserving claims.\n");
1995
+ return [];
1996
+ }
1997
+ const liveSessionSet = new Set(liveSessions);
1998
+ let tasks;
1999
+ try {
2000
+ tasks = await deps.queryClaimedOpenBlockedTasks();
2001
+ } catch (e) {
2002
+ process.stderr.write("[stale-claim] query claimed tasks: " + (e instanceof Error ? e.message : String(e)) + "\n");
2003
+ return [];
2004
+ }
2005
+ const released = [];
2006
+ for (const t of tasks) {
2007
+ if (!t.claimedSession || t.claimedSession === "unknown") continue;
2008
+ if (liveSessionSet.has(t.claimedSession)) continue;
2009
+ const updatedMs = new Date(t.updatedAt).getTime();
2010
+ if (!Number.isNaN(updatedMs) && nowMs - updatedMs < STUCK_TASK_GRACE_MS) continue;
2011
+ try {
2012
+ await deps.releaseClaim(t.taskId, t.claimedSession);
2013
+ released.push(t.taskId);
2014
+ process.stderr.write(
2015
+ `[stale-claim] Task ${t.taskId.slice(0, 8)} (${t.agentId}) \u2014 claim holder session ${t.claimedSession}` + (t.claimInstanceId ? ` (${t.claimInstanceId})` : "") + ` is gone; released claim so the owner can re-claim.
2016
+ `
2017
+ );
2018
+ } catch (err) {
2019
+ process.stderr.write(`[stale-claim] Failed to release claim on ${t.taskId}: ${err instanceof Error ? err.message : String(err)}
2020
+ `);
2021
+ }
2022
+ }
2023
+ return released;
2024
+ }
2025
+ function createStaleClaimRealDeps(getClient) {
2026
+ let lastTmuxListVerified = false;
2027
+ const listSync = () => {
2028
+ try {
2029
+ const socket = process.env.EXE_TMUX_SOCKET;
2030
+ const socketArgs = socket ? ["-L", socket] : [];
2031
+ const out = execFileSync("tmux", [...socketArgs, "list-sessions", "-F", "#{session_name}"], {
2032
+ encoding: "utf8",
2033
+ stdio: ["pipe", "pipe", "pipe"],
2034
+ timeout: 3e3
2035
+ });
2036
+ lastTmuxListVerified = true;
2037
+ return out.trim().split("\n").filter(Boolean);
2038
+ } catch {
2039
+ lastTmuxListVerified = false;
2040
+ return [];
2041
+ }
2042
+ };
2043
+ return {
2044
+ listTmuxSessions: listSync,
2045
+ listTmuxSessionsAsync: async () => {
2046
+ try {
2047
+ const socket = process.env.EXE_TMUX_SOCKET;
2048
+ const socketArgs = socket ? ["-L", socket] : [];
2049
+ const { stdout } = await execFileAsync("tmux", [...socketArgs, "list-sessions", "-F", "#{session_name}"], {
2050
+ encoding: "utf8",
2051
+ timeout: 3e3
2052
+ });
2053
+ lastTmuxListVerified = true;
2054
+ return (stdout ?? "").trim().split("\n").filter(Boolean);
2055
+ } catch {
2056
+ lastTmuxListVerified = false;
2057
+ return [];
2058
+ }
2059
+ },
2060
+ tmuxSessionsVerified: () => lastTmuxListVerified,
2061
+ queryClaimedOpenBlockedTasks: async () => {
2062
+ const { loadDeviceId } = await import("./lib/license.js");
2063
+ const deviceId = loadDeviceId();
2064
+ const client = getClient();
2065
+ const rows = await client.execute({
2066
+ sql: `SELECT id, assigned_to, assigned_tmux, claim_session_instance_id, updated_at
2067
+ FROM tasks
2068
+ WHERE status IN ('open', 'blocked')
2069
+ AND assigned_tmux IS NOT NULL
2070
+ AND assigned_tmux != 'unknown'
2071
+ AND (device_id = ? OR device_id IS NULL)
2072
+ ORDER BY updated_at ASC
2073
+ LIMIT 1000`,
2074
+ args: [deviceId]
2075
+ });
2076
+ return rows.rows.map((r) => ({
2077
+ taskId: String(r.id),
2078
+ agentId: String(r.assigned_to ?? "unknown"),
2079
+ claimedSession: r.assigned_tmux ? String(r.assigned_tmux) : "",
2080
+ claimInstanceId: r.claim_session_instance_id ? String(r.claim_session_instance_id) : null,
2081
+ updatedAt: String(r.updated_at)
2082
+ }));
2083
+ },
2084
+ releaseClaim: async (taskId, holderSession) => {
2085
+ const client = getClient();
2086
+ const nowIso = (/* @__PURE__ */ new Date()).toISOString();
2087
+ await client.execute({
2088
+ sql: `UPDATE tasks
2089
+ SET assigned_tmux = NULL,
2090
+ instance_id = NULL,
2091
+ claimed_by = NULL,
2092
+ claimed_at = NULL,
2093
+ last_heartbeat_at = NULL,
2094
+ claim_session_instance_id = NULL,
2095
+ lease_expires_at = NULL,
2096
+ updated_at = ?
2097
+ WHERE id = ?
2098
+ AND status IN ('open', 'blocked')
2099
+ AND assigned_tmux = ?`,
2100
+ args: [nowIso, taskId, holderSession]
2101
+ });
2102
+ recordOrchestrationEventBestEffort({
2103
+ eventType: "task.claim_released",
2104
+ source: "daemon-orchestration.releaseStaleClaims",
2105
+ severity: "warn",
2106
+ taskId,
2107
+ result: "dead_holder_session",
2108
+ payload: { holderSession }
2109
+ });
2110
+ }
2111
+ };
2112
+ }
1985
2113
  var DEFAULT_STALE_REVIEW_DAYS = 7;
1986
2114
  async function cleanupStaleReviews(deps) {
1987
2115
  const thresholdDays = deps.getStaleReviewThreshold();
@@ -3411,6 +3539,8 @@ export {
3411
3539
  releaseStuckTasks,
3412
3540
  paneShowsBackgroundSubagentWait,
3413
3541
  createStuckTaskRealDeps,
3542
+ releaseStaleClaims,
3543
+ createStaleClaimRealDeps,
3414
3544
  cleanupStaleReviews,
3415
3545
  createStaleReviewRealDeps,
3416
3546
  ESCALATE_AFTER_MS,
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-WCGNCH3Q.js";
4
4
  import {
5
5
  registerAllTools
6
- } from "./chunk-FUOXMZUZ.js";
6
+ } from "./chunk-HKXNF72F.js";
7
7
 
8
8
  // src/mcp/mcp-surface-hash.ts
9
9
  function computeMcpSurfaceHash() {
@@ -41,6 +41,7 @@ import {
41
41
  createOrphanReaperRealDepsAsync,
42
42
  createReviewNudgeRealDeps,
43
43
  createSessionTTLRealDeps,
44
+ createStaleClaimRealDeps,
44
45
  createStaleReviewRealDeps,
45
46
  createStuckBlockedRealDeps,
46
47
  createStuckTaskRealDeps,
@@ -66,6 +67,7 @@ import {
66
67
  reapOrphanedMcpProcesses,
67
68
  reapOrphanedWorktrees,
68
69
  reapZombieAgentProcesses,
70
+ releaseStaleClaims,
69
71
  releaseStuckTasks,
70
72
  saveNudgeState,
71
73
  saveStuckBlockedState,
@@ -73,7 +75,7 @@ import {
73
75
  shouldKillIdleSession,
74
76
  shouldKillSession,
75
77
  shouldNudgeEmployee
76
- } from "./chunk-EDEVSNAF.js";
78
+ } from "./chunk-P5C7JCIZ.js";
77
79
  import "./chunk-WAVZDYXS.js";
78
80
  import "./chunk-MFX2RWJZ.js";
79
81
  import "./chunk-APRVAUOR.js";
@@ -166,6 +168,7 @@ export {
166
168
  createOrphanReaperRealDepsAsync,
167
169
  createReviewNudgeRealDeps,
168
170
  createSessionTTLRealDeps,
171
+ createStaleClaimRealDeps,
169
172
  createStaleReviewRealDeps,
170
173
  createStuckBlockedRealDeps,
171
174
  createStuckTaskRealDeps,
@@ -191,6 +194,7 @@ export {
191
194
  reapOrphanedMcpProcesses,
192
195
  reapOrphanedWorktrees,
193
196
  reapZombieAgentProcesses,
197
+ releaseStaleClaims,
194
198
  releaseStuckTasks,
195
199
  saveNudgeState,
196
200
  saveStuckBlockedState,
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  computeMcpSurfaceHash
4
- } from "./chunk-RYKHPC3Y.js";
4
+ } from "./chunk-XKA343SE.js";
5
5
  import "./chunk-WCGNCH3Q.js";
6
- import "./chunk-FUOXMZUZ.js";
6
+ import "./chunk-HKXNF72F.js";
7
7
  import "./chunk-557C2IGL.js";
8
8
  import "./chunk-PELEK2IT.js";
9
9
  import "./chunk-L3DKZC4R.js";
@@ -15,9 +15,9 @@ import "./chunk-MBULOZJF.js";
15
15
  import "./chunk-KBFHODXV.js";
16
16
  import "./chunk-OPDZ62TW.js";
17
17
  import "./chunk-YJBBW6OT.js";
18
- import "./chunk-4NPP7ASA.js";
18
+ import "./chunk-AD42TL2C.js";
19
19
  import "./chunk-CRCB5S7I.js";
20
- import "./chunk-EDEVSNAF.js";
20
+ import "./chunk-P5C7JCIZ.js";
21
21
  import "./chunk-KES3SNOH.js";
22
22
  import "./chunk-E6ORBQHP.js";
23
23
  import "./chunk-WAVZDYXS.js";
@@ -75,7 +75,7 @@ import "./chunk-S3THSOWV.js";
75
75
  import "./chunk-IOEUAQWP.js";
76
76
  import "./chunk-I5AVZOL2.js";
77
77
  import "./chunk-APRVAUOR.js";
78
- import "./chunk-EGYDW57S.js";
78
+ import "./chunk-H2BE7ZPC.js";
79
79
  import "./chunk-AB4PAQYK.js";
80
80
  import "./chunk-LVG5ATTU.js";
81
81
  import "./chunk-PENPH5AG.js";
@@ -8,7 +8,7 @@ import {
8
8
  import {
9
9
  hybridSearch,
10
10
  lightweightSearch
11
- } from "../chunk-EGYDW57S.js";
11
+ } from "../chunk-H2BE7ZPC.js";
12
12
  import "../chunk-AB4PAQYK.js";
13
13
  import {
14
14
  buildSystemStateMemoryTypeExclusion,
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "version": 1,
3
- "generatedAt": "2026-07-24T09:13:08.736Z",
3
+ "generatedAt": "2026-07-25T04:38:45.093Z",
4
4
  "hashes": {
5
5
  "bug-report-worker.js": "b9bcde949c60c3d57ba3f6a66f0fd7c0c24dcbd6314422a0544e38e0687067a9",
6
6
  "codex-stop-task-finalizer.js": "6f80ca6d60a73244bbe2d0e347cf1c7eb59f8296388f932d2fe34ca69dc5c0a5",
7
7
  "commit-complete.js": "744cd477da753aeb82063c2f8219a3fe9af93681e66e41d5f96d0779027b3aeb",
8
- "error-recall.js": "2320fe3f6efd163ae03be9d27c63579e3e8c4188bfafd6633c872b1f00b87053",
8
+ "error-recall.js": "3f27b6841fd86675b604485a548e5d97d7dbbfdb06afa18701708e0782dae6e0",
9
9
  "exe-heartbeat-hook.js": "f8f18927a4397e7c497ec4e4fc79b571b87b73eec5809ee3a7425cffa49b3112",
10
10
  "ingest-worker.js": "e194c2237bf431941c27cb213bc793d136b74b04a3e7bf9262371784c999e4b0",
11
11
  "ingest.js": "955a231c1dd63fb75843531d2b58dff5b84d73770b9c3ebf5d5e35d6989e9284",
@@ -15,9 +15,9 @@
15
15
  "post-tool-combined.js": "ef91564fcfb1560e39a612eb91dcda1b2e4ab3cc9338c27ab7f92b390b03b7fa",
16
16
  "pre-compact.js": "933f9817f66f4e7d28d903ab40b86478ecfc6f9972e9e447838772d5176ccabf",
17
17
  "pre-tool-use.js": "1da521b7fa580ea0a8b3f7722d48ead1fde758e24fd628019f24ee56842dfe46",
18
- "prompt-submit.js": "8a8137433da871ba6d5967e8c015ceced43b689c1e8d769d9230f79ecc72aedd",
18
+ "prompt-submit.js": "ce4c63dcebe9bde6f9034576da54f1917882a920f74f539907641b2c0f2f7f23",
19
19
  "session-end.js": "0eb2bdedb37806e8fa352aad5cb006aa2af12c213169f1cad4157ee6e1737cf5",
20
- "session-start.js": "03954c72a26aa86062cccabc831ab5460705a7c8b8c4304cc7e3ab1955140f95",
20
+ "session-start.js": "6931cfa741ad0932c75b15752a7aa941aac58c6d8153dd254becee7cd48a4a70",
21
21
  "stop.js": "901df128a49816c84208badd1f6a564bb2094d39180212e304b8610fbd3fd85f",
22
22
  "subagent-stop.js": "8483c06cfd5c0441cee1b5f1156a9a9ad22862735aa5579010735fce3ed32c0c",
23
23
  "summary-worker.js": "3c4ea227f43b94b1c4ce01207dddf55d0c252ace2a53541399a7078519dc19e6"
@@ -20,7 +20,7 @@ import {
20
20
  import {
21
21
  hybridSearch,
22
22
  lightweightSearch
23
- } from "../chunk-EGYDW57S.js";
23
+ } from "../chunk-H2BE7ZPC.js";
24
24
  import "../chunk-AB4PAQYK.js";
25
25
  import "../chunk-LVG5ATTU.js";
26
26
  import "../chunk-PENPH5AG.js";
@@ -35,6 +35,7 @@ import "../chunk-4QCFFW2H.js";
35
35
  import "../chunk-76CJBM36.js";
36
36
  import {
37
37
  decideQueuedNudgeDrain,
38
+ getMySession,
38
39
  getSessionState,
39
40
  isExeSession
40
41
  } from "../chunk-LOYK2BRY.js";
@@ -344,6 +345,16 @@ process.stdin.on("end", async () => {
344
345
  let _cachedSessionName = null;
345
346
  const getCurrentSessionName = () => {
346
347
  if (_cachedSessionName !== null) return _cachedSessionName;
348
+ if (inTmux) {
349
+ try {
350
+ const live = getMySession();
351
+ if (live) {
352
+ _cachedSessionName = live;
353
+ return live;
354
+ }
355
+ } catch {
356
+ }
357
+ }
347
358
  const ownSession = process.env.EXE_SESSION_NAME?.trim();
348
359
  if (ownSession) {
349
360
  _cachedSessionName = ownSession;
@@ -207,7 +207,7 @@ You are **${ag.agentId}**. The daemon was degraded at boot \u2014 memory context
207
207
  query = `last actions on ${projectName}`;
208
208
  header = "## Resuming Session\nHere's where you left off:";
209
209
  try {
210
- const { buildCatchupBrief } = await import("../catchup-brief-HPB5CL7R.js");
210
+ const { buildCatchupBrief } = await import("../catchup-brief-7WCQGC2Z.js");
211
211
  const brief = await buildCatchupBrief(
212
212
  agentId,
213
213
  projectName,
@@ -544,28 +544,80 @@ function shouldWarnSlowTimer(durationMs, slept, thresholdMs) {
544
544
  }
545
545
 
546
546
  // src/lib/daemon-timer-watchdog.ts
547
+ var DEFAULT_LAG_PROBE_INTERVAL_MS = 200;
548
+ function defaultLagThresholdMs(timeoutMs) {
549
+ return Math.max(1e3, timeoutMs * 0.1);
550
+ }
551
+ function normalizeLagProbeIntervalMs(intervalMs) {
552
+ return Number.isFinite(intervalMs) && intervalMs !== void 0 && intervalMs > 0 ? intervalMs : DEFAULT_LAG_PROBE_INTERVAL_MS;
553
+ }
554
+ function validNonNegativeMs(value) {
555
+ return Number.isFinite(value) && value > 0 ? value : 0;
556
+ }
547
557
  function startTimerTimeoutWatchdog(options) {
548
558
  const now = options.now ?? Date.now;
549
559
  const setTimer = options.setTimeoutFn ?? setTimeout;
550
560
  const clearTimer = options.clearTimeoutFn ?? clearTimeout;
561
+ const setLagProbeTimer = options.setLagProbeTimeoutFn ?? setTimer;
562
+ const clearLagProbeTimer = options.clearLagProbeTimeoutFn ?? clearTimer;
563
+ const lagProbeIntervalMs = normalizeLagProbeIntervalMs(options.lagProbeIntervalMs);
564
+ const lagThresholdMs = options.lagThresholdMs ?? defaultLagThresholdMs(options.timeoutMs);
551
565
  let stopped = false;
552
566
  let handle = null;
567
+ let lagProbeHandle = null;
568
+ let nextLagProbeDueMs = now() + lagProbeIntervalMs;
569
+ let maxLagMs = 0;
570
+ const recordLag = (lagMs) => {
571
+ maxLagMs = Math.max(maxLagMs, validNonNegativeMs(lagMs));
572
+ };
573
+ const currentMaxLagMs = () => {
574
+ if (options.eventLoopLagSource) {
575
+ recordLag(options.eventLoopLagSource());
576
+ } else {
577
+ recordLag(now() - nextLagProbeDueMs);
578
+ }
579
+ return maxLagMs;
580
+ };
581
+ const armLagProbe = () => {
582
+ if (stopped || options.eventLoopLagSource) return;
583
+ nextLagProbeDueMs = now() + lagProbeIntervalMs;
584
+ lagProbeHandle = setLagProbeTimer(() => {
585
+ lagProbeHandle = null;
586
+ recordLag(now() - nextLagProbeDueMs);
587
+ armLagProbe();
588
+ }, lagProbeIntervalMs);
589
+ lagProbeHandle.unref?.();
590
+ };
553
591
  const arm = () => {
554
592
  if (stopped) return;
555
593
  handle = setTimer(() => {
556
594
  handle = null;
557
595
  const pausedMs = Math.max(0, options.pauseTotalMs() - options.pauseSnapshotMs);
558
596
  const busyMs = now() - options.startedAtMs - pausedMs;
559
- if (busyMs >= options.timeoutMs) options.onTimeout(busyMs);
597
+ if (busyMs >= options.timeoutMs) {
598
+ const windowMaxLagMs = currentMaxLagMs();
599
+ if (windowMaxLagMs >= lagThresholdMs) {
600
+ options.onTimeout(busyMs);
601
+ } else if (options.onSlowAwait) {
602
+ options.onSlowAwait(busyMs, windowMaxLagMs);
603
+ } else {
604
+ options.onTimeout(busyMs);
605
+ }
606
+ maxLagMs = 0;
607
+ nextLagProbeDueMs = now() + lagProbeIntervalMs;
608
+ }
560
609
  arm();
561
610
  }, options.timeoutMs);
562
611
  handle.unref?.();
563
612
  };
613
+ armLagProbe();
564
614
  arm();
565
615
  return () => {
566
616
  stopped = true;
567
617
  if (handle) clearTimer(handle);
618
+ if (lagProbeHandle) clearLagProbeTimer(lagProbeHandle);
568
619
  handle = null;
620
+ lagProbeHandle = null;
569
621
  };
570
622
  }
571
623
 
@@ -1650,12 +1702,14 @@ async function traceDaemonTimer(name, fn) {
1650
1702
  `);
1651
1703
  }
1652
1704
  const watchdogStart = Date.now();
1705
+ let timeoutWatchdogSawBlocking = false;
1653
1706
  const stopTimeoutWatchdog = startTimerTimeoutWatchdog({
1654
1707
  timeoutMs: TIMER_TIMEOUT_MS,
1655
1708
  startedAtMs: watchdogStart,
1656
1709
  pauseSnapshotMs: pauseSnapshot,
1657
1710
  pauseTotalMs: () => sweepPauseTotalMs(name),
1658
1711
  onTimeout: () => {
1712
+ timeoutWatchdogSawBlocking = true;
1659
1713
  _lastBlockingTimer = { name, durationMs: TIMER_TIMEOUT_MS, ts: Date.now() };
1660
1714
  process.stderr.write(
1661
1715
  `[exed] Timer TIMEOUT WARNING: ${name} has been running for >${TIMER_TIMEOUT_MS / 1e3}s \u2014 likely blocking the event loop
@@ -1667,6 +1721,23 @@ async function traceDaemonTimer(name, fn) {
1667
1721
  message: `Timer ${name} exceeded ${TIMER_TIMEOUT_MS / 1e3}s budget`,
1668
1722
  data: { timer: name, timeoutMs: TIMER_TIMEOUT_MS }
1669
1723
  });
1724
+ },
1725
+ onSlowAwait: (busyMs, maxLagMs) => {
1726
+ const msg = `[exed] Timer LONG (awaiting I/O, loop responsive): ${name} busy ${Math.round(busyMs)}ms (max event-loop lag ${Math.round(maxLagMs)}ms)`;
1727
+ process.stderr.write(`${msg}
1728
+ `);
1729
+ logDaemonHealth({
1730
+ event: "process_stats",
1731
+ pid: process.pid,
1732
+ message: msg,
1733
+ data: {
1734
+ type: "timer_long_await",
1735
+ timer: name,
1736
+ busyMs: Math.round(busyMs),
1737
+ maxEventLoopLagMs: Math.round(maxLagMs),
1738
+ timeoutMs: TIMER_TIMEOUT_MS
1739
+ }
1740
+ });
1670
1741
  }
1671
1742
  });
1672
1743
  try {
@@ -1679,7 +1750,7 @@ async function traceDaemonTimer(name, fn) {
1679
1750
  const slept = span.sleptMs > 1e3;
1680
1751
  const sweepPausedMs = Math.max(0, sweepPauseTotalMs(name) - pauseSnapshot);
1681
1752
  const busyMs = Math.max(0, durationMs - sweepPausedMs);
1682
- if (!slept && busyMs >= TIMER_TIMEOUT_MS) {
1753
+ if (timeoutWatchdogSawBlocking && !slept && busyMs >= TIMER_TIMEOUT_MS) {
1683
1754
  _lastBlockingTimer = { name, durationMs: busyMs, ts: Date.now() };
1684
1755
  }
1685
1756
  if (shouldWarnSlowTimer(busyMs, slept, TIMER_SLOW_WARN_MS)) {
@@ -2717,6 +2788,17 @@ async function handleHealthCheck(socket, requestId) {
2717
2788
  }
2718
2789
  }
2719
2790
  var _dbRequestsServed = 0;
2791
+ async function runDaemonTimerRead(sql, args = []) {
2792
+ try {
2793
+ const { isDbReadWorkerReady, runReadQueryInWorker } = await import("./db-read-worker-client.js");
2794
+ if (isDbReadWorkerReady()) {
2795
+ return await runReadQueryInWorker(sql, args);
2796
+ }
2797
+ } catch {
2798
+ }
2799
+ const { getClient } = await import("./database.js");
2800
+ return getClient().execute({ sql, args });
2801
+ }
2720
2802
  async function handleDbExecute(socket, requestId, sql, args) {
2721
2803
  if (_drainingWrites) {
2722
2804
  sendResponse(socket, { id: requestId, error: "Server shutting down" });
@@ -5113,7 +5195,7 @@ async function startReviewPolling() {
5113
5195
  lastNudgeSent: /* @__PURE__ */ new Map(),
5114
5196
  intervalMs: REVIEW_POLL_INTERVAL_MS
5115
5197
  };
5116
- const { pollReviewNudge, createReviewNudgeRealDeps, loadNudgeState } = await import("../daemon-orchestration-WHGMXCZW.js");
5198
+ const { pollReviewNudge, createReviewNudgeRealDeps, loadNudgeState } = await import("../daemon-orchestration-X7UPV6VU.js");
5117
5199
  const nudgeState = loadNudgeState();
5118
5200
  const tick = async () => traceDaemonTimer("review_polling", async () => {
5119
5201
  fired("review_polling");
@@ -5121,6 +5203,47 @@ async function startReviewPolling() {
5121
5203
  try {
5122
5204
  const { getClient } = await import("./database.js");
5123
5205
  const deps = polling.createRealDeps(getClient);
5206
+ const { strictSessionScopeFilter } = await import("../task-scope-3F3MSGSX.js");
5207
+ const { getCoordinatorName, DEFAULT_COORDINATOR_TEMPLATE_NAME } = await import("./employees.js");
5208
+ deps.findOrphanedDoneTasks = async (sessionScope) => {
5209
+ const coordinatorName = getCoordinatorName();
5210
+ const odScope = strictSessionScopeFilter(sessionScope, "t");
5211
+ const result = await runDaemonTimerRead(
5212
+ `SELECT t.id, t.title, t.assigned_to, t.assigned_by,
5213
+ t.project_name, t.task_file, t.result, t.status
5214
+ FROM tasks t
5215
+ WHERE t.status = 'needs_review'
5216
+ AND t.assigned_to != ?
5217
+ AND t.assigned_to != ?${odScope.sql}
5218
+ AND (t.result IS NULL OR t.result NOT LIKE '%## Review notes%')`,
5219
+ [coordinatorName, DEFAULT_COORDINATOR_TEMPLATE_NAME, ...odScope.args]
5220
+ );
5221
+ return result.rows;
5222
+ };
5223
+ deps.findTieredReviewCandidates = async (sessionScope) => {
5224
+ let project = null;
5225
+ try {
5226
+ const { getProjectName } = await import("../project-name-EWG5KAZP.js");
5227
+ project = getProjectName() || null;
5228
+ } catch {
5229
+ project = null;
5230
+ }
5231
+ if (!project) return [];
5232
+ const trScope = strictSessionScopeFilter(sessionScope, "t");
5233
+ const result = await runDaemonTimerRead(
5234
+ `SELECT t.id, t.title, t.priority, t.complexity, t.context,
5235
+ t.project_name, t.session_scope, t.assigned_to, t.reviewer,
5236
+ t.verification_receipts
5237
+ FROM tasks t
5238
+ WHERE t.status = 'needs_review'
5239
+ AND t.project_name = ?
5240
+ AND COALESCE(t.review_sampled, 0) = 0${trScope.sql}
5241
+ ORDER BY t.updated_at ASC
5242
+ LIMIT 100`,
5243
+ [project, ...trScope.args]
5244
+ );
5245
+ return result.rows;
5246
+ };
5124
5247
  const { sessions: sharedSessions } = await getSharedOrchestrationCaches();
5125
5248
  deps.listTmuxSessions = () => sharedSessions;
5126
5249
  const sent = await polling.pollPendingReviews(deps, state);
@@ -5159,7 +5282,7 @@ function startSessionTTL() {
5159
5282
  if (!await ensureStoreForPolling()) return;
5160
5283
  if (inPostRestartDestructiveGrace("session_ttl")) return;
5161
5284
  const { getClient } = await import("./database.js");
5162
- const { checkSessionTTL, createSessionTTLRealDeps } = await import("../daemon-orchestration-WHGMXCZW.js");
5285
+ const { checkSessionTTL, createSessionTTLRealDeps } = await import("../daemon-orchestration-X7UPV6VU.js");
5163
5286
  const deps = createSessionTTLRealDeps(getClient);
5164
5287
  const killed = await checkSessionTTL(deps, _wedgeObservations);
5165
5288
  if (killed.length > 0) acted("session_ttl");
@@ -5211,7 +5334,7 @@ function startIdleKill() {
5211
5334
  const cfg = await getCachedConfig();
5212
5335
  if (!cfg) return;
5213
5336
  const { getClient } = await import("./database.js");
5214
- const { pollIdleKill, createIdleKillRealDeps } = await import("../daemon-orchestration-WHGMXCZW.js");
5337
+ const { pollIdleKill, createIdleKillRealDeps } = await import("../daemon-orchestration-X7UPV6VU.js");
5215
5338
  const { sessions: liveSessions, paneCache, aliveSessions } = await getSharedOrchestrationCaches();
5216
5339
  const realDeps = createIdleKillRealDeps(
5217
5340
  getClient,
@@ -6040,8 +6163,7 @@ async function refreshAgentData() {
6040
6163
  const started = Date.now();
6041
6164
  try {
6042
6165
  if (!await ensureStoreForPolling()) return;
6043
- const { offloadReadQuery } = await import("./database.js");
6044
- const result = await offloadReadQuery(
6166
+ const result = await runDaemonTimerRead(
6045
6167
  `SELECT agent_id,
6046
6168
  COUNT(*) as total,
6047
6169
  SUM(CASE WHEN timestamp > datetime('now', '-1 day') THEN 1 ELSE 0 END) as growth_24h,
@@ -6568,7 +6690,7 @@ function startOrphanReaper() {
6568
6690
  const tick = async () => traceDaemonTimer("orphan_reaper", async () => {
6569
6691
  fired("orphan_reaper");
6570
6692
  try {
6571
- const { reapOrphanedMcpProcesses, createOrphanReaperRealDepsAsync } = await import("../daemon-orchestration-WHGMXCZW.js");
6693
+ const { reapOrphanedMcpProcesses, createOrphanReaperRealDepsAsync } = await import("../daemon-orchestration-X7UPV6VU.js");
6572
6694
  const deps = await createOrphanReaperRealDepsAsync();
6573
6695
  const reaped = await reapOrphanedMcpProcesses(deps);
6574
6696
  if (reaped.length > 0) acted("orphan_reaper");
@@ -6593,7 +6715,7 @@ function startZombieAgentReaper() {
6593
6715
  const tick = async () => traceDaemonTimer("zombie_agent_reaper", async () => {
6594
6716
  fired("zombie_agent_reaper");
6595
6717
  try {
6596
- const { reapZombieAgentProcesses, createZombieAgentReaperRealDepsAsync } = await import("../daemon-orchestration-WHGMXCZW.js");
6718
+ const { reapZombieAgentProcesses, createZombieAgentReaperRealDepsAsync } = await import("../daemon-orchestration-X7UPV6VU.js");
6597
6719
  const deps = await createZombieAgentReaperRealDepsAsync();
6598
6720
  const reaped = reapZombieAgentProcesses(deps);
6599
6721
  if (reaped.length > 0) acted("zombie_agent_reaper");
@@ -6648,7 +6770,7 @@ function startWorktreeReaper() {
6648
6770
  const tick = async () => traceDaemonTimer("worktree_reaper", async () => {
6649
6771
  fired("worktree_reaper");
6650
6772
  try {
6651
- const { reapOrphanedWorktrees, createWorktreeReaperRealDeps } = await import("../daemon-orchestration-WHGMXCZW.js");
6773
+ const { reapOrphanedWorktrees, createWorktreeReaperRealDeps } = await import("../daemon-orchestration-X7UPV6VU.js");
6652
6774
  const deps = await createWorktreeReaperRealDeps();
6653
6775
  const result = await reapOrphanedWorktrees(deps);
6654
6776
  if (result.pruned.length > 0) {
@@ -6722,7 +6844,7 @@ function startAutoWake() {
6722
6844
  if (!await ensureStoreForPolling()) return;
6723
6845
  try {
6724
6846
  const { getClient } = await import("./database.js");
6725
- const { pollOrphanedTasks, createAutoWakeRealDeps } = await import("../daemon-orchestration-WHGMXCZW.js");
6847
+ const { pollOrphanedTasks, createAutoWakeRealDeps } = await import("../daemon-orchestration-X7UPV6VU.js");
6726
6848
  const deps = createAutoWakeRealDeps(getClient, process.cwd(), getTmuxSessionsAsync);
6727
6849
  const woken = await pollOrphanedTasks(deps);
6728
6850
  if (woken.length > 0) acted("auto_wake");
@@ -6917,14 +7039,22 @@ function startStuckTaskRelease() {
6917
7039
  const {
6918
7040
  releaseStuckTasks,
6919
7041
  createStuckTaskRealDeps,
7042
+ releaseStaleClaims,
7043
+ createStaleClaimRealDeps,
6920
7044
  escalateStuckBlockedTasks,
6921
7045
  createStuckBlockedRealDeps
6922
- } = await import("../daemon-orchestration-WHGMXCZW.js");
7046
+ } = await import("../daemon-orchestration-X7UPV6VU.js");
6923
7047
  const deps = createStuckTaskRealDeps(getClient);
6924
7048
  const released = await releaseStuckTasks(deps);
6925
7049
  if (released.length > 0) {
6926
7050
  acted("stuck_task_release");
6927
7051
  process.stderr.write(`[exed] Stuck-release: ${released.length} task(s) moved to blocked
7052
+ `);
7053
+ }
7054
+ const claimsReleased = await releaseStaleClaims(createStaleClaimRealDeps(getClient));
7055
+ if (claimsReleased.length > 0) {
7056
+ acted("stuck_task_release");
7057
+ process.stderr.write(`[exed] Stale-claim release: ${claimsReleased.length} dead-holder claim(s) cleared
6928
7058
  `);
6929
7059
  }
6930
7060
  const blockedResult = await escalateStuckBlockedTasks(createStuckBlockedRealDeps(getClient));
@@ -7130,7 +7260,7 @@ function startTaskEnforcementScanner() {
7130
7260
  sendKeysLiteral: transport.sendKeysLiteral?.bind(transport),
7131
7261
  isAlive: (session) => aliveSessions.has(session)
7132
7262
  };
7133
- const { checkAutoWakeGates } = await import("../daemon-orchestration-WHGMXCZW.js");
7263
+ const { checkAutoWakeGates } = await import("../daemon-orchestration-X7UPV6VU.js");
7134
7264
  const { ensureEmployeeAsync, employeeSessionName, sendIntercomAsync } = await import("./tmux-routing.js");
7135
7265
  const { shouldAutoInstance } = await import("./employees.js");
7136
7266
  const { recordOrchestrationEventBestEffort } = await import("../orchestration-events-EXQRGVEJ.js");
@@ -7446,6 +7576,43 @@ function startBackgroundJobGuardrails() {
7446
7576
  timer.unref();
7447
7577
  process.stderr.write("[exed] Background job guardrails started (every 60s)\n");
7448
7578
  }
7579
+ var TRACE_TTL_SWEEP_TOOLS = ["Bash", "Read", "Edit", "Grep", "Write", "Glob", "apply_patch"];
7580
+ async function sweepExpiredTracesFromDaemonTimer() {
7581
+ const placeholders = TRACE_TTL_SWEEP_TOOLS.map(() => "?").join(",");
7582
+ const idsResult = await runDaemonTimerRead(
7583
+ `SELECT id FROM memories
7584
+ WHERE tool_name IN (${placeholders})
7585
+ AND COALESCE(memory_type, 'raw') = 'raw'
7586
+ AND timestamp < datetime('now', '-7 days')
7587
+ AND COALESCE(importance, 0) < 7`,
7588
+ TRACE_TTL_SWEEP_TOOLS
7589
+ );
7590
+ const memoryIds = idsResult.rows.map((r) => String(r.id)).filter(Boolean);
7591
+ if (memoryIds.length === 0) return 0;
7592
+ const { getClient } = await import("./database.js");
7593
+ const { cleanupGraphLinksForMemories, cleanupCardsForMemories } = await import("../graph-rag-P3PSYW7P.js");
7594
+ const client = getClient();
7595
+ await cleanupGraphLinksForMemories(client, memoryIds);
7596
+ await cleanupCardsForMemories(client, memoryIds);
7597
+ let deleted = 0;
7598
+ const batchSize = 500;
7599
+ for (let i = 0; i < memoryIds.length; i += batchSize) {
7600
+ const batch = memoryIds.slice(i, i + batchSize);
7601
+ const idPlaceholders = batch.map(() => "?").join(",");
7602
+ const result = await client.execute({
7603
+ sql: `DELETE FROM memories
7604
+ WHERE id IN (${idPlaceholders})
7605
+ AND tool_name IN (${placeholders})
7606
+ AND COALESCE(memory_type, 'raw') = 'raw'
7607
+ AND timestamp < datetime('now', '-7 days')
7608
+ AND COALESCE(importance, 0) < 7`,
7609
+ args: [...batch, ...TRACE_TTL_SWEEP_TOOLS]
7610
+ });
7611
+ deleted += Number(result.rowsAffected ?? 0);
7612
+ await yieldToEventLoop();
7613
+ }
7614
+ return deleted;
7615
+ }
7449
7616
  function handleSignalShutdown() {
7450
7617
  if (_shuttingDown) return;
7451
7618
  const { intent: restartIntent, reason } = consumeRestartIntentDetail();
@@ -8341,7 +8508,7 @@ function startTaskGroupBarriers() {
8341
8508
  fired("task_group_barriers");
8342
8509
  if (!await ensureStoreForPolling()) return;
8343
8510
  try {
8344
- const { pollTaskGroupBarriers } = await import("../daemon-orchestration-WHGMXCZW.js");
8511
+ const { pollTaskGroupBarriers } = await import("../daemon-orchestration-X7UPV6VU.js");
8345
8512
  const firedCount = await pollTaskGroupBarriers();
8346
8513
  if (firedCount > 0) {
8347
8514
  acted("task_group_barriers");
@@ -8363,7 +8530,7 @@ function startCheckpointGc() {
8363
8530
  fired("checkpoint_gc");
8364
8531
  if (!await ensureStoreForPolling()) return;
8365
8532
  try {
8366
- const { gcStaleCheckpoints } = await import("../daemon-orchestration-WHGMXCZW.js");
8533
+ const { gcStaleCheckpoints } = await import("../daemon-orchestration-X7UPV6VU.js");
8367
8534
  const cleared = await gcStaleCheckpoints();
8368
8535
  if (cleared > 0) {
8369
8536
  acted("checkpoint_gc");
@@ -8563,9 +8730,7 @@ function startLocalFirstTimers() {
8563
8730
  fired("trace_ttl_sweep");
8564
8731
  try {
8565
8732
  if (!await ensureStoreForPolling()) return;
8566
- const { getClient } = await import("./database.js");
8567
- const { sweepExpiredTraces } = await import("./consolidation.js");
8568
- const count = await sweepExpiredTraces(getClient());
8733
+ const count = await sweepExpiredTracesFromDaemonTimer();
8569
8734
  if (count > 0) {
8570
8735
  acted("trace_ttl_sweep");
8571
8736
  process.stderr.write(`[exed] Trace TTL: deleted ${count} expired raw tool traces (>7d, importance<7)
@@ -5,7 +5,7 @@ import {
5
5
  recentRecords,
6
6
  rrfMerge,
7
7
  rrfMergeMulti
8
- } from "../chunk-EGYDW57S.js";
8
+ } from "../chunk-H2BE7ZPC.js";
9
9
  import "../chunk-AB4PAQYK.js";
10
10
  import "../chunk-LVG5ATTU.js";
11
11
  import "../chunk-PENPH5AG.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  registerAllTools
3
- } from "../chunk-FUOXMZUZ.js";
3
+ } from "../chunk-HKXNF72F.js";
4
4
  import "../chunk-557C2IGL.js";
5
5
  import "../chunk-PELEK2IT.js";
6
6
  import "../chunk-L3DKZC4R.js";
@@ -12,9 +12,9 @@ import "../chunk-MBULOZJF.js";
12
12
  import "../chunk-KBFHODXV.js";
13
13
  import "../chunk-OPDZ62TW.js";
14
14
  import "../chunk-YJBBW6OT.js";
15
- import "../chunk-4NPP7ASA.js";
15
+ import "../chunk-AD42TL2C.js";
16
16
  import "../chunk-CRCB5S7I.js";
17
- import "../chunk-EDEVSNAF.js";
17
+ import "../chunk-P5C7JCIZ.js";
18
18
  import "../chunk-KES3SNOH.js";
19
19
  import "../chunk-E6ORBQHP.js";
20
20
  import "../chunk-WAVZDYXS.js";
@@ -72,7 +72,7 @@ import "../chunk-S3THSOWV.js";
72
72
  import "../chunk-IOEUAQWP.js";
73
73
  import "../chunk-I5AVZOL2.js";
74
74
  import "../chunk-APRVAUOR.js";
75
- import "../chunk-EGYDW57S.js";
75
+ import "../chunk-H2BE7ZPC.js";
76
76
  import "../chunk-AB4PAQYK.js";
77
77
  import "../chunk-LVG5ATTU.js";
78
78
  import "../chunk-PENPH5AG.js";
@@ -10,7 +10,7 @@ import {
10
10
  } from "../chunk-WCGNCH3Q.js";
11
11
  import {
12
12
  registerAllTools
13
- } from "../chunk-FUOXMZUZ.js";
13
+ } from "../chunk-HKXNF72F.js";
14
14
  import "../chunk-557C2IGL.js";
15
15
  import "../chunk-PELEK2IT.js";
16
16
  import "../chunk-L3DKZC4R.js";
@@ -22,9 +22,9 @@ import "../chunk-MBULOZJF.js";
22
22
  import "../chunk-KBFHODXV.js";
23
23
  import "../chunk-OPDZ62TW.js";
24
24
  import "../chunk-YJBBW6OT.js";
25
- import "../chunk-4NPP7ASA.js";
25
+ import "../chunk-AD42TL2C.js";
26
26
  import "../chunk-CRCB5S7I.js";
27
- import "../chunk-EDEVSNAF.js";
27
+ import "../chunk-P5C7JCIZ.js";
28
28
  import "../chunk-KES3SNOH.js";
29
29
  import "../chunk-E6ORBQHP.js";
30
30
  import "../chunk-WAVZDYXS.js";
@@ -89,7 +89,7 @@ import {
89
89
  disposeEmbedder
90
90
  } from "../chunk-I5AVZOL2.js";
91
91
  import "../chunk-APRVAUOR.js";
92
- import "../chunk-EGYDW57S.js";
92
+ import "../chunk-H2BE7ZPC.js";
93
93
  import "../chunk-AB4PAQYK.js";
94
94
  import {
95
95
  disposeStore,
@@ -5,7 +5,7 @@ import {
5
5
  rerank,
6
6
  rerankWithContext,
7
7
  rerankWithScores
8
- } from "./chunk-4NPP7ASA.js";
8
+ } from "./chunk-AD42TL2C.js";
9
9
  import "./chunk-BCZF3AGJ.js";
10
10
  import "./chunk-HSGBZSCA.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.350",
3
+ "version": "0.9.352",
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,15 +1,42 @@
1
1
  {
2
- "current": "0.9.350",
2
+ "current": "0.9.352",
3
3
  "notes": {
4
- "0.9.350": {
5
- "version": "0.9.350",
6
- "date": "2026-07-24",
4
+ "0.9.352": {
5
+ "version": "0.9.352",
6
+ "date": "2026-07-25",
7
7
  "features": [],
8
8
  "fixes": [],
9
9
  "security": [],
10
10
  "other": [
11
- "v0.9.350ship closeout-timeout (#470) + subfolder-resolver (#471) fixes (#472)"
11
+ "v0.9.352multi-coordinator session-scope fix (7eec74b7/45a9f87e) (#477)"
12
+ ],
13
+ "migration_notes": []
14
+ },
15
+ "0.9.351": {
16
+ "version": "0.9.351",
17
+ "date": "2026-07-25",
18
+ "features": [
19
+ "daemon offloads heavy timer reads (review polling, agent-data refresh, trace-TTL sweep) to the db-read-worker so long scans no longer block the MCP-serving event loop (d73b5014) (#454)"
12
20
  ],
21
+ "fixes": [
22
+ "task(resume)/resume_employee no longer throws \"Database client not initialized\" — the resume handler uses the client fastDbInit() returns instead of re-grabbing a global the degraded init paths never register, so reviving a dead cross-project employee works (ff3ef612) (#474)",
23
+ "daemon lag-aware timer watchdog stops false-flagging a timer that is merely awaiting slow I/O as a blocked event loop, killing bogus self-heal restarts (c5fdb821) (#455)",
24
+ "daemon auto-releases a stale task-claim whose holder tmux session is gone (dead-holder-session half of the claim-integrity cluster), so an owner locked out by a dead subagent claim can re-claim (784ebe98, 31a59ab2) (#473)"
25
+ ],
26
+ "security": [],
27
+ "other": [],
28
+ "migration_notes": []
29
+ },
30
+ "0.9.350": {
31
+ "version": "0.9.350",
32
+ "date": "2026-07-24",
33
+ "features": [],
34
+ "fixes": [
35
+ "closeout no longer misreports a long dreaming/consolidation timeout as \"Daemon unavailable\" — request-timeouts are classified as timeouts (retryable) and the dreaming + final write are retried with bounded backoff (6b09c8bc) (#470)",
36
+ "create_task resolves the project ROOT when the coordinator cwd is a SUBFOLDER of the project — ancestor-walk to the enclosing git repo instead of refusing dispatch or returning the subfolder (3afb8eb9) (#471)"
37
+ ],
38
+ "security": [],
39
+ "other": [],
13
40
  "migration_notes": []
14
41
  },
15
42
  "0.9.349": {
@@ -49,58 +76,6 @@
49
76
  "security": [],
50
77
  "other": [],
51
78
  "migration_notes": []
52
- },
53
- "0.9.347": {
54
- "version": "0.9.347",
55
- "date": "2026-07-22",
56
- "features": [],
57
- "fixes": [
58
- "daemon: cloud_sync timer no longer blocks the event loop for minutes–hours — the root cause of recurring \"MCP connected but tools fail\" instability; drains in bounded per-tick slices with a durable resumable cursor (c5fdb821 p0) (#422)",
59
- "stack-update: fail-loud + fail-safe on image auth/pull failure — never leave prod silently partial; pre-deploy pullability check aborts before any mutation (f1c36209 p0) (#432)",
60
- "api-router: runtime self-heal ALTER for support_feature_requests.product — list_my_features no longer 500s on drifted D1 instances (5604f580) (#421)",
61
- "orchestration: re-validate the dispatch claim before a stale auto-blocked task resumes — kills duplicate-fleet / wrong-work on pane un-wedge (e1d26a94) (#431)",
62
- "codex: configurable working default model (EXE_CODEX_DEFAULT_MODEL, fallback gpt-5.5) instead of the ChatGPT-account-rejected gpt-5.3-codex (d691ab3a) (#430)",
63
- "mcp: reconcile consolidated tool schemas with handlers — config.import_orchestration no longer throws; graph.merge_entities merges or errors loudly instead of silently no-opping (9f6216fe, b8773ad7) (#428)",
64
- "task: assigned reviewer can now close_task (was mis-gated on caller identity) (b6543735) (#427)",
65
- "task: completion \"What Changed\" derives from git diff, not scraped prose — no more fabricated changelogs (ae43d0b9) (#429)"
66
- ],
67
- "security": [],
68
- "other": [
69
- "test: deflake ReDoS redaction timing bound (1000ms→5000ms) — was blocking releases; still catches real ReDoS (#426)",
70
- "test: deflake mcp-proxy retry-budget (20ms→2000ms test config) — recurring release-blocker, no production change (#433)",
71
- "ci: classified auto-retry on infra failures (e381fcb0) (#425)"
72
- ],
73
- "migration_notes": []
74
- },
75
- "0.9.346": {
76
- "version": "0.9.346",
77
- "date": "2026-07-21",
78
- "features": [
79
- "exe-os mcp — control plane to list active/inactive MCP servers across Claude/Codex/OpenCode + one-command enable/disable (2aa87aba) (#405)",
80
- "add Moonshot Kimi K3 to the opencode runtime model whitelist (777f9591) (#404)"
81
- ],
82
- "fixes": [
83
- "auto-reclaim stale db.lock left by a dead writer (dead-PID / PID-reuse / legacy) + clamp waitForDaemonReady probes to the caller budget — daemon no longer crash-loops with MCP down (caef9285 p0, 7a4aa0d5) (#399)",
84
- "await resolveExeSession in the create dispatch path — an un-awaited Promise was reaching ensureEmployeeAsync as the session arg, poisoning dispatch session resolution; also ClickHouse restore profile + git-crypt worktree smudge retry + spawn_worktree preserved (95ca2cd5, d18606d9) (#418)",
85
- "subagent-aware liveness; a reaped session no longer self-reports a false completion (routes to blocked, preserves result only as unverified evidence) (7de95f57, 879c354d) (#403)",
86
- "session-instance claims + honest liveness — the duplicate-racer compound defect: bulk-kill circuit breaker, live-sibling checkpoint skipping, owner-scoped auto-wake (#400)",
87
- "assigned-agent identity at spawn (no more coordinator-identity leak) + dead-spawn dispatch-claim release (8e1bb3de, 629b4c4d) (#408)",
88
- "gate task nudges on real queue state + invalidate stale resume checkpoints — kills the phantom P0-nudge death spiral (22e464ad, 0f30e7a5) (#414)",
89
- "re-arming timer watchdog, per-timer sweep-pause accounting, undici connection-loss detection (UND_ERR_SOCKET / other side closed / terminated) (35b72cd3, a705c2bf, 90ba3f38) (#407)",
90
- "honor INSERT OR IGNORE rowsAffected so dropped duplicates skip ontology/graph/hygiene follow-up; align graph-rag content_hash with the governor (504f76fc, ae584290) (#401)",
91
- "nested-repo-aware worktree guard + scoped-hash index self-heal with id tie-break (60cb17eb, 8d711f75) (#397)",
92
- "support add_comment/get_comments now resolve feature-request ids, not just bug ids (64a42e0f) (#406)",
93
- "align api-router support redaction tokens to the real [REDACTED:<class>] contract; bind cloud-sync verify stamp to file identity (237384bd, e0d1353a) (#417)",
94
- "8 re-review leftovers — the last exe-os code-fixable batch (#413)"
95
- ],
96
- "security": [
97
- "redaction token contract aligned across client/server + api-router so license keys, API keys, tokens and recovery phrases redact consistently (237384bd) (#417)"
98
- ],
99
- "other": [
100
- "CI: eliminate false reds on self-hosted build-my — per-run NPM_CONFIG_CACHE removes node-20 setup-cancellation flake; smoke needs build-and-test to cut contention; publish green-CI gate no longer counts schedule-only runs (a80addb4) (#411)",
101
- "test: deflake daemon-ready \"returns within budget when pings are slow\" with fake timers — real contract is 1..2 budget-bounded pings (#419)"
102
- ],
103
- "migration_notes": []
104
79
  }
105
80
  }
106
81
  }
@@ -12,13 +12,21 @@ Triggered by the coordinator via `tmux send-keys -t {window} '/exe-intercom' Ent
12
12
  # Resolve the configured coordinator and current tmux session.
13
13
  COORDINATOR=$(node -e "const fs=require('fs'), os=require('os'), path=require('path'); try { const r=JSON.parse(fs.readFileSync(path.join(os.homedir(),'.exe-os','exe-employees.json'),'utf8')); const c=r.find(e => String(e.role||'').toLowerCase()==='coo'); console.log(c?.name || 'exe'); } catch { console.log('exe'); }" 2>/dev/null)
14
14
 
15
- if [ -n "$EXE_SESSION_NAME" ]; then
16
- SESSION_NAME="$EXE_SESSION_NAME"
17
- elif [ -n "$TMUX" ]; then
15
+ # Bugs 7eec74b7 + 45a9f87e (multi-coordinator scope mis-resolution): an employee
16
+ # session MUST derive its identity from its OWN live tmux session name
17
+ # (davinci-yoda1), never from the EXE_SESSION_NAME env baked at spawn. With two
18
+ # coordinators live (yoda1 + yoda2) that env can carry the WRONG coordinator,
19
+ # making the worker refuse its own yoda1-scoped task as a "cross-session leak".
20
+ # Live tmux is authoritative; fall back to env only when not inside tmux.
21
+ if [ -n "$TMUX" ]; then
18
22
  SESSION_NAME=$(tmux display-message -p '#{session_name}' 2>/dev/null)
23
+ [ -z "$SESSION_NAME" ] && SESSION_NAME="$EXE_SESSION_NAME"
24
+ elif [ -n "$EXE_SESSION_NAME" ]; then
25
+ SESSION_NAME="$EXE_SESSION_NAME"
19
26
  else
20
27
  SESSION_NAME="UNKNOWN"
21
28
  fi
29
+ [ -z "$SESSION_NAME" ] && SESSION_NAME="UNKNOWN"
22
30
 
23
31
  # Employee sessions are {employee}-{coordinatorSession}; coordinator sessions have no dash.
24
32
  if [ "$SESSION_NAME" = "UNKNOWN" ]; then
File without changes