@askexenow/exe-os 0.9.289 → 0.9.290

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.
Files changed (244) hide show
  1. package/dist/active-agent-L22OENGJ.js +26 -0
  2. package/dist/active-agent-SVG6F6HY.js +27 -0
  3. package/dist/agentic-ontology-3GHJHLDY.js +25 -0
  4. package/dist/backfill-metadata-HJNVBORD.js +599 -0
  5. package/dist/behaviors-ROOZS234.js +39 -0
  6. package/dist/bin/agentic-ontology-backfill.js +5 -5
  7. package/dist/bin/agentic-reflection-backfill.js +6 -6
  8. package/dist/bin/agentic-semantic-label.js +5 -5
  9. package/dist/bin/backfill-conversations.js +4 -4
  10. package/dist/bin/backfill-responses.js +4 -4
  11. package/dist/bin/backfill-vectors.js +98 -13
  12. package/dist/bin/bulk-sync-postgres.js +6 -6
  13. package/dist/bin/cc-doctor.js +4 -4
  14. package/dist/bin/cleanup-stale-review-tasks.js +9 -9
  15. package/dist/bin/cli.js +51 -15
  16. package/dist/bin/exe-agent-config.js +2 -2
  17. package/dist/bin/exe-agent.js +4 -4
  18. package/dist/bin/exe-assign.js +5 -5
  19. package/dist/bin/exe-boot.js +16 -16
  20. package/dist/bin/exe-call.js +4 -4
  21. package/dist/bin/exe-cloud.js +23 -5
  22. package/dist/bin/exe-dispatch.js +9 -9
  23. package/dist/bin/exe-doctor.js +1 -1
  24. package/dist/bin/exe-export-behaviors.js +7 -7
  25. package/dist/bin/exe-forget.js +6 -6
  26. package/dist/bin/exe-gateway.js +7 -7
  27. package/dist/bin/exe-healthcheck.js +4 -4
  28. package/dist/bin/exe-heartbeat.js +9 -9
  29. package/dist/bin/exe-kill.js +12 -12
  30. package/dist/bin/exe-launch-agent.js +16 -16
  31. package/dist/bin/exe-new-employee.js +6 -6
  32. package/dist/bin/exe-pending-messages.js +10 -10
  33. package/dist/bin/exe-pending-notifications.js +9 -9
  34. package/dist/bin/exe-pending-reviews.js +9 -9
  35. package/dist/bin/exe-rename.js +4 -4
  36. package/dist/bin/exe-review.js +11 -11
  37. package/dist/bin/exe-search.js +5 -5
  38. package/dist/bin/exe-session-cleanup.js +14 -14
  39. package/dist/bin/exe-settings.js +4 -4
  40. package/dist/bin/exe-start-codex.js +11 -11
  41. package/dist/bin/exe-start-opencode.js +8 -8
  42. package/dist/bin/exe-status.js +10 -10
  43. package/dist/bin/exe-team.js +3 -3
  44. package/dist/bin/git-sweep.js +10 -10
  45. package/dist/bin/graph-backfill.js +4 -4
  46. package/dist/bin/graph-export.js +5 -5
  47. package/dist/bin/import-history.js +7 -7
  48. package/dist/bin/install.js +6 -6
  49. package/dist/bin/intercom-check.js +4 -4
  50. package/dist/bin/mcp-sessions.js +2 -2
  51. package/dist/bin/orchestration-metrics.js +4 -4
  52. package/dist/bin/postgres-agentic-reflection-backfill.js +2 -2
  53. package/dist/bin/postgres-agentic-semantic-backfill.js +1 -1
  54. package/dist/bin/scan-tasks.js +9 -9
  55. package/dist/bin/setup.js +1 -1
  56. package/dist/bin/shard-migrate.js +4 -4
  57. package/dist/capability-cards-O6XB2AU4.js +88 -0
  58. package/dist/capacity-monitor-ZE7CFVWH.js +50 -0
  59. package/dist/catchup-brief-3NONSIMA.js +174 -0
  60. package/dist/chunk-232DHK5C.js +1119 -0
  61. package/dist/chunk-272SJ4RN.js +129 -0
  62. package/dist/chunk-4NMTGHUE.js +127 -0
  63. package/dist/chunk-5PLW3QL6.js +668 -0
  64. package/dist/chunk-66EIYAF2.js +157 -0
  65. package/dist/chunk-6IPJF5QD.js +630 -0
  66. package/dist/chunk-6NSJTOXE.js +122 -0
  67. package/dist/chunk-6TLURATK.js +4318 -0
  68. package/dist/chunk-73JAJQRY.js +85 -0
  69. package/dist/chunk-7FTKXL5A.js +286 -0
  70. package/dist/chunk-7IRQSO3F.js +735 -0
  71. package/dist/chunk-7MINWZ3J.js +214 -0
  72. package/dist/chunk-7T5PS5DG.js +14439 -0
  73. package/dist/chunk-A74WXY4S.js +227 -0
  74. package/dist/chunk-AVD5C3NG.js +197 -0
  75. package/dist/chunk-B36MRLEP.js +58 -0
  76. package/dist/chunk-B4TCZ3PS.js +373 -0
  77. package/dist/chunk-BPLEJ3EU.js +411 -0
  78. package/dist/chunk-BTDPLFGK.js +221 -0
  79. package/dist/chunk-BU45UYTK.js +185 -0
  80. package/dist/chunk-CCAA6XOZ.js +284 -0
  81. package/dist/chunk-DBQ6I6K2.js +3276 -0
  82. package/dist/chunk-DDWFHEPG.js +345 -0
  83. package/dist/chunk-DSOKTUTT.js +167 -0
  84. package/dist/chunk-ETCARC76.js +836 -0
  85. package/dist/chunk-EZHTLPOS.js +280 -0
  86. package/dist/chunk-F3DQ3HDH.js +333 -0
  87. package/dist/chunk-F6ZCUDCN.js +244 -0
  88. package/dist/chunk-FI5Q6F5S.js +382 -0
  89. package/dist/chunk-FNQZGNSG.js +1094 -0
  90. package/dist/chunk-FVKTXXKK.js +128 -0
  91. package/dist/chunk-HHR5NB6N.js +377 -0
  92. package/dist/chunk-HRZLGHT6.js +290 -0
  93. package/dist/chunk-HSSRWMVA.js +68 -0
  94. package/dist/chunk-I3NVB5MG.js +85 -0
  95. package/dist/chunk-I7Z6MK2B.js +240 -0
  96. package/dist/chunk-ID4SMRYX.js +2078 -0
  97. package/dist/chunk-JXGHDROV.js +546 -0
  98. package/dist/chunk-KQY4QIEN.js +731 -0
  99. package/dist/chunk-LRSU2ZU2.js +38 -0
  100. package/dist/chunk-MFCL4GAN.js +2113 -0
  101. package/dist/chunk-MFGMVKGM.js +150 -0
  102. package/dist/chunk-NHGBVLCD.js +210 -0
  103. package/dist/chunk-NOEBJMNN.js +33 -0
  104. package/dist/chunk-NQ2VNTGL.js +538 -0
  105. package/dist/chunk-O4PZPM6H.js +204 -0
  106. package/dist/chunk-O5OW3YGQ.js +262 -0
  107. package/dist/chunk-OJQTONDJ.js +171 -0
  108. package/dist/chunk-OKZGUHE5.js +76 -0
  109. package/dist/chunk-OOH5M36Q.js +448 -0
  110. package/dist/chunk-P5ARTZP2.js +128 -0
  111. package/dist/chunk-PKRSYS7F.js +402 -0
  112. package/dist/chunk-PQWO5D3F.js +348 -0
  113. package/dist/chunk-Q6MJIJ2O.js +1352 -0
  114. package/dist/chunk-QKDRYZ2N.js +231 -0
  115. package/dist/chunk-RAV356E6.js +30 -0
  116. package/dist/chunk-RK7EAA53.js +1157 -0
  117. package/dist/chunk-RSLVAYWS.js +192 -0
  118. package/dist/chunk-SL6WJP2Q.js +123 -0
  119. package/dist/chunk-T57DOVGE.js +97 -0
  120. package/dist/chunk-TMCKL43Q.js +181 -0
  121. package/dist/chunk-TQZABASE.js +97 -0
  122. package/dist/chunk-UBWBEY6I.js +81 -0
  123. package/dist/chunk-UP7DNYG7.js +456 -0
  124. package/dist/chunk-V5MGYIZS.js +70 -0
  125. package/dist/chunk-XCPVYQVK.js +336 -0
  126. package/dist/chunk-XWVBLZRP.js +50 -0
  127. package/dist/chunk-YBTN5F2U.js +1068 -0
  128. package/dist/chunk-Z772TGD2.js +54 -0
  129. package/dist/chunk-ZAMPIXLH.js +1350 -0
  130. package/dist/chunk-ZYEOHGU5.js +362 -0
  131. package/dist/co-activation-WJTFJOTK.js +73 -0
  132. package/dist/co-occurrence-KFP6ZS7G.js +94 -0
  133. package/dist/core-memory-DBZJ72TV.js +110 -0
  134. package/dist/crdt-sync-6DVGRMTV.js +33 -0
  135. package/dist/crm-webhook-55T4Z6XJ.js +10 -0
  136. package/dist/cto-delegation-gate-SPM6LAL2.js +279 -0
  137. package/dist/daemon-orchestration-XZLWWIV4.js +138 -0
  138. package/dist/db-backup-JHCI47JQ.js +37 -0
  139. package/dist/doc-graph-extractor-4X23NP4I.js +132 -0
  140. package/dist/dreaming-TFZDGA72.js +33 -0
  141. package/dist/exe-drift-TEM7ELNY.js +69 -0
  142. package/dist/exe-export-CRCA4T4S.js +75 -0
  143. package/dist/exe-import-UZMMWNHJ.js +78 -0
  144. package/dist/exe-key-NQQXEDUA.js +672 -0
  145. package/dist/exe-snapshot-P7PUAJTV.js +337 -0
  146. package/dist/fast-db-init-G63PRINQ.js +7 -0
  147. package/dist/gateway/index.js +8 -8
  148. package/dist/git-staleness-42TTCFDP.js +111 -0
  149. package/dist/git-task-sweep-4LW5RYYO.js +41 -0
  150. package/dist/global-procedures-BVFRWJAV.js +21 -0
  151. package/dist/graph-auto-extract-4ZA7UC6C.js +182 -0
  152. package/dist/hooks/bug-report-worker.js +11 -11
  153. package/dist/hooks/codex-stop-task-finalizer.js +11 -11
  154. package/dist/hooks/commit-complete.js +11 -11
  155. package/dist/hooks/error-recall.js +6 -6
  156. package/dist/hooks/exe-heartbeat-hook.js +3 -3
  157. package/dist/hooks/ingest.js +6 -6
  158. package/dist/hooks/instructions-loaded.js +4 -4
  159. package/dist/hooks/manifest.json +19 -19
  160. package/dist/hooks/notification.js +4 -4
  161. package/dist/hooks/post-compact.js +10 -10
  162. package/dist/hooks/post-tool-combined.js +5 -5
  163. package/dist/hooks/pre-compact.js +11 -11
  164. package/dist/hooks/pre-tool-use.js +14 -14
  165. package/dist/hooks/prompt-submit.js +21 -21
  166. package/dist/hooks/session-end.js +15 -15
  167. package/dist/hooks/session-start.js +12 -12
  168. package/dist/hooks/stop.js +14 -14
  169. package/dist/hooks/subagent-stop.js +10 -10
  170. package/dist/hooks/summary-worker.js +14 -14
  171. package/dist/index.js +17 -17
  172. package/dist/installer-CBGRTGIF.js +297 -0
  173. package/dist/installer-DGU4WZKJ.js +39 -0
  174. package/dist/installer-WTWEOSEK.js +343 -0
  175. package/dist/lib/cloud-sync.js +4 -4
  176. package/dist/lib/consolidation.js +7 -5
  177. package/dist/lib/database.js +2 -2
  178. package/dist/lib/db.js +2 -2
  179. package/dist/lib/employee-templates.js +4 -4
  180. package/dist/lib/employees.js +2 -2
  181. package/dist/lib/exe-daemon.js +64 -43
  182. package/dist/lib/hybrid-search.js +5 -5
  183. package/dist/lib/identity.js +2 -2
  184. package/dist/lib/messaging.js +9 -9
  185. package/dist/lib/reminders.js +3 -3
  186. package/dist/lib/schedules.js +5 -5
  187. package/dist/lib/session-registry.js +4 -4
  188. package/dist/lib/skill-learning.js +6 -6
  189. package/dist/lib/store.js +4 -4
  190. package/dist/lib/task-router.js +3 -3
  191. package/dist/lib/tasks.js +10 -10
  192. package/dist/lib/tmux-routing.js +8 -8
  193. package/dist/lib/token-spend.js +3 -3
  194. package/dist/license-gate-OSPA2OD7.js +16 -0
  195. package/dist/mcp/register-tools.js +55 -55
  196. package/dist/mcp/server.js +117 -73
  197. package/dist/mcp/tools/complete-reminder.js +4 -4
  198. package/dist/mcp/tools/create-reminder.js +4 -4
  199. package/dist/mcp/tools/create-task.js +12 -12
  200. package/dist/mcp/tools/deactivate-behavior.js +7 -7
  201. package/dist/mcp/tools/list-reminders.js +4 -4
  202. package/dist/mcp/tools/list-tasks.js +12 -12
  203. package/dist/mcp/tools/send-message.js +11 -11
  204. package/dist/mcp/tools/update-task.js +11 -11
  205. package/dist/mcp-http-config-OGFPLJYH.js +28 -0
  206. package/dist/memory-cards-GJ3VHKAM.js +179 -0
  207. package/dist/memory-graph-extractor-TCTCM7PZ.js +21 -0
  208. package/dist/memory-poisoning-defense-FVLGA35X.js +223 -0
  209. package/dist/memory-reflection-BYJFIFSV.js +243 -0
  210. package/dist/notifications-AQKZFSR3.js +46 -0
  211. package/dist/orchestration-events-RDSYLFXZ.js +26 -0
  212. package/dist/orchestrator-2JTJQLPG.js +34 -0
  213. package/dist/pipeline-router-HBSTKHG5.js +14 -0
  214. package/dist/plan-limits-GQENSNTG.js +27 -0
  215. package/dist/project-boot-W2LTP7WW.js +299 -0
  216. package/dist/projection-worker-ZMT5KNJJ.js +1084 -0
  217. package/dist/prospective-memory-LANRNOJX.js +231 -0
  218. package/dist/reranker-QGJO6EHO.js +19 -0
  219. package/dist/retrieval-health-JE66LJ3I.js +11 -0
  220. package/dist/review-polling-IXJ57M6Q.js +125 -0
  221. package/dist/runtime/index.js +11 -11
  222. package/dist/session-events-XKG66APL.js +37 -0
  223. package/dist/session-kill-telemetry-VTU7YBII.js +30 -0
  224. package/dist/session-scope-TQZONLZL.js +87 -0
  225. package/dist/setup-wizard-PXK6SC2D.js +12 -0
  226. package/dist/skill-refinement-Y6LLKYRL.js +158 -0
  227. package/dist/steward-gate-QV2APBFB.js +14 -0
  228. package/dist/task-enforcement-GLDD2W5D.js +505 -0
  229. package/dist/task-scope-HMPIP6XB.js +36 -0
  230. package/dist/tasks-crud-FH2SFCNQ.js +78 -0
  231. package/dist/tasks-notify-3ZW2GLCS.js +39 -0
  232. package/dist/tasks-review-XERV6KZD.js +48 -0
  233. package/dist/telemetry-upload-R77W7I7G.js +740 -0
  234. package/dist/token-budget-NA4WQAY6.js +85 -0
  235. package/dist/tool-telemetry-D4Q76LAS.js +17 -0
  236. package/dist/tui/App.js +16 -16
  237. package/dist/tui-data-NJSEIA2Q.js +259 -0
  238. package/dist/wiki-acl-RE5IR5VV.js +111 -0
  239. package/dist/worker-gate-VN2POPFL.js +21 -0
  240. package/dist/workflow-engine-D7ALMSDM.js +28 -0
  241. package/dist/worktree-6I45JV5N.js +27 -0
  242. package/dist/worktree-sweep-IMDR3XHT.js +20 -0
  243. package/package.json +1 -1
  244. package/release-notes.json +88 -88
@@ -0,0 +1,158 @@
1
+ import {
2
+ getClient
3
+ } from "./chunk-DBQ6I6K2.js";
4
+ import "./chunk-2I23RPSI.js";
5
+ import "./chunk-XCPVYQVK.js";
6
+ import "./chunk-PNQDP3OA.js";
7
+ import "./chunk-FXU7JOXK.js";
8
+ import "./chunk-5P3HOBZX.js";
9
+ import "./chunk-LYH5HE24.js";
10
+ import "./chunk-MLKGABMK.js";
11
+
12
+ // src/lib/skill-refinement.ts
13
+ import crypto from "crypto";
14
+ async function incrementSkillUsage(behaviors) {
15
+ const skills = behaviors.filter((b) => b.domain === "skill");
16
+ if (skills.length === 0) return;
17
+ try {
18
+ const client = getClient();
19
+ const now = (/* @__PURE__ */ new Date()).toISOString();
20
+ for (const skill of skills) {
21
+ await client.execute({
22
+ sql: `UPDATE behaviors SET use_count = use_count + 1, last_used_at = ?, updated_at = ? WHERE id = ?`,
23
+ args: [now, now, skill.id]
24
+ });
25
+ }
26
+ } catch (err) {
27
+ process.stderr.write(
28
+ `[skill-refinement] Failed to increment usage: ${err instanceof Error ? err.message : String(err)}
29
+ `
30
+ );
31
+ }
32
+ }
33
+ async function incrementSkillSuccess(assignedTo, projectName) {
34
+ try {
35
+ const client = getClient();
36
+ const now = (/* @__PURE__ */ new Date()).toISOString();
37
+ const cutoff = new Date(Date.now() - 24 * 60 * 60 * 1e3).toISOString();
38
+ const rows = await client.execute({
39
+ sql: `SELECT id FROM behaviors
40
+ WHERE agent_id = ? AND domain = 'skill' AND active = 1
41
+ AND use_count > 0 AND last_used_at > ?
42
+ ${projectName ? "AND (project_name = ? OR project_name IS NULL)" : ""}`,
43
+ args: projectName ? [assignedTo, cutoff, projectName] : [assignedTo, cutoff]
44
+ });
45
+ for (const row of rows.rows) {
46
+ const id = String(row.id);
47
+ await client.execute({
48
+ sql: `UPDATE behaviors SET success_count = success_count + 1, updated_at = ? WHERE id = ?`,
49
+ args: [now, id]
50
+ });
51
+ }
52
+ if (rows.rows.length > 0) {
53
+ process.stderr.write(
54
+ `[skill-refinement] Incremented success_count for ${rows.rows.length} skill(s) (agent: ${assignedTo})
55
+ `
56
+ );
57
+ }
58
+ } catch (err) {
59
+ process.stderr.write(
60
+ `[skill-refinement] Failed to increment success: ${err instanceof Error ? err.message : String(err)}
61
+ `
62
+ );
63
+ }
64
+ }
65
+ var MIN_USES_FOR_REVIEW = 3;
66
+ var LOW_SUCCESS_RATE = 0.8;
67
+ var HIGH_SUCCESS_RATE = 0.9;
68
+ var MIN_USES_FOR_PROMOTION = 10;
69
+ async function runSkillRefinement() {
70
+ const client = getClient();
71
+ const now = (/* @__PURE__ */ new Date()).toISOString();
72
+ const result = {
73
+ reviewed: 0,
74
+ flaggedLowSuccess: 0,
75
+ boostedConfidence: 0,
76
+ promotedToIdentity: 0
77
+ };
78
+ const rows = await client.execute({
79
+ sql: `SELECT id, agent_id, content, use_count, success_count, last_refined_at, project_name
80
+ FROM behaviors
81
+ WHERE domain = 'skill' AND active = 1 AND use_count >= ?`,
82
+ args: [MIN_USES_FOR_REVIEW]
83
+ });
84
+ for (const rawRow of rows.rows) {
85
+ const row = rawRow;
86
+ result.reviewed++;
87
+ const successRate = row.use_count > 0 ? row.success_count / row.use_count : 0;
88
+ if (successRate < LOW_SUCCESS_RATE) {
89
+ result.flaggedLowSuccess++;
90
+ const { writeMemory } = await import("./lib/store.js");
91
+ await writeMemory({
92
+ id: crypto.randomUUID(),
93
+ agent_id: row.agent_id,
94
+ agent_role: "",
95
+ session_id: "",
96
+ timestamp: now,
97
+ tool_name: "skill-refinement",
98
+ project_name: row.project_name ?? "",
99
+ has_error: false,
100
+ raw_text: `SKILL REVIEW NEEDED: "${row.content.slice(0, 100)}..." has ${Math.round(successRate * 100)}% success rate (${row.success_count}/${row.use_count} uses). Consider revising or deactivating.`,
101
+ vector: null,
102
+ memory_type: "observation"
103
+ });
104
+ await client.execute({
105
+ sql: `UPDATE behaviors SET last_refined_at = ?, updated_at = ? WHERE id = ?`,
106
+ args: [now, now, row.id]
107
+ });
108
+ } else if (row.use_count >= MIN_USES_FOR_PROMOTION && successRate > HIGH_SUCCESS_RATE) {
109
+ result.promotedToIdentity++;
110
+ try {
111
+ const { getIdentity, updateIdentity } = await import("./lib/identity.js");
112
+ const identity = await getIdentity(row.agent_id);
113
+ if (identity) {
114
+ const promotionBlock = `
115
+
116
+ ## Promoted Skill (auto-promoted ${now.split("T")[0]})
117
+ ${row.content}`;
118
+ await updateIdentity(row.agent_id, identity + promotionBlock, "skill-refinement");
119
+ }
120
+ await client.execute({
121
+ sql: `UPDATE behaviors SET active = 0, last_refined_at = ?, updated_at = ? WHERE id = ?`,
122
+ args: [now, now, row.id]
123
+ });
124
+ const { writeMemory: writePromoMemory } = await import("./lib/store.js");
125
+ await writePromoMemory({
126
+ id: crypto.randomUUID(),
127
+ agent_id: row.agent_id,
128
+ agent_role: "",
129
+ session_id: "",
130
+ timestamp: now,
131
+ tool_name: "skill-refinement",
132
+ project_name: row.project_name ?? "",
133
+ has_error: false,
134
+ raw_text: `SKILL PROMOTED TO IDENTITY: "${row.content.slice(0, 100)}..." \u2014 ${row.success_count}/${row.use_count} uses (${Math.round(successRate * 100)}% success). Deactivated as behavior, appended to identity.`,
135
+ vector: null,
136
+ memory_type: "decision"
137
+ });
138
+ } catch (err) {
139
+ process.stderr.write(
140
+ `[skill-refinement] Failed to promote skill ${row.id}: ${err instanceof Error ? err.message : String(err)}
141
+ `
142
+ );
143
+ }
144
+ } else if (successRate > HIGH_SUCCESS_RATE) {
145
+ result.boostedConfidence++;
146
+ await client.execute({
147
+ sql: `UPDATE behaviors SET priority = 'p0', last_refined_at = ?, updated_at = ? WHERE id = ? AND priority != 'p0'`,
148
+ args: [now, now, row.id]
149
+ });
150
+ }
151
+ }
152
+ return result;
153
+ }
154
+ export {
155
+ incrementSkillSuccess,
156
+ incrementSkillUsage,
157
+ runSkillRefinement
158
+ };
@@ -0,0 +1,14 @@
1
+ import {
2
+ StewardGate
3
+ } from "./chunk-I7Z6MK2B.js";
4
+ import "./chunk-DBQ6I6K2.js";
5
+ import "./chunk-2I23RPSI.js";
6
+ import "./chunk-XCPVYQVK.js";
7
+ import "./chunk-PNQDP3OA.js";
8
+ import "./chunk-FXU7JOXK.js";
9
+ import "./chunk-5P3HOBZX.js";
10
+ import "./chunk-LYH5HE24.js";
11
+ import "./chunk-MLKGABMK.js";
12
+ export {
13
+ StewardGate
14
+ };
@@ -0,0 +1,505 @@
1
+ import {
2
+ sendIntercom,
3
+ updateTaskStatus
4
+ } from "./chunk-6TLURATK.js";
5
+ import "./chunk-EZHTLPOS.js";
6
+ import "./chunk-4JERP7NT.js";
7
+ import "./chunk-4FVVJ7ME.js";
8
+ import "./chunk-QKDRYZ2N.js";
9
+ import "./chunk-MVW62NIZ.js";
10
+ import "./chunk-OYNKIAVW.js";
11
+ import "./chunk-SSTLTIF3.js";
12
+ import {
13
+ recordOrchestrationEventBestEffort
14
+ } from "./chunk-6IPJF5QD.js";
15
+ import "./chunk-RJY45A5J.js";
16
+ import "./chunk-NGP6LSV2.js";
17
+ import "./chunk-272SJ4RN.js";
18
+ import "./chunk-CVYC6DUW.js";
19
+ import "./chunk-OPU3NYOO.js";
20
+ import "./chunk-GJV3WDWM.js";
21
+ import "./chunk-MP2AFCGL.js";
22
+ import "./chunk-V5MGYIZS.js";
23
+ import "./chunk-HYZV25LY.js";
24
+ import {
25
+ isCoordinatorName
26
+ } from "./chunk-DBQ6I6K2.js";
27
+ import "./chunk-2I23RPSI.js";
28
+ import "./chunk-XCPVYQVK.js";
29
+ import "./chunk-PNQDP3OA.js";
30
+ import "./chunk-FXU7JOXK.js";
31
+ import "./chunk-SYOGNG2R.js";
32
+ import "./chunk-5P3HOBZX.js";
33
+ import "./chunk-LYH5HE24.js";
34
+ import "./chunk-MLKGABMK.js";
35
+
36
+ // src/lib/task-enforcement.ts
37
+ import { appendFile } from "fs/promises";
38
+ import path from "path";
39
+ var TASK_ENFORCEMENT_INTERVAL_MS = 6e4;
40
+ var TASK_ENFORCEMENT_DEBOUNCE_MS = 18e4;
41
+ var MANAGER_GRACE_PERIOD_MS = 6e5;
42
+ var STUCK_TASK_THRESHOLD_MS = (() => {
43
+ const raw = process.env.EXE_STUCK_TASK_THRESHOLD_MS;
44
+ const parsed = raw ? Number(raw) : NaN;
45
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : 72 * 60 * 60 * 1e3;
46
+ })();
47
+ var IDLE_PATTERNS = [
48
+ "Standing by",
49
+ "All tasks complete",
50
+ "No tasks found",
51
+ "Anything else?",
52
+ "What do you need?"
53
+ ];
54
+ var NUDGE_ECHO_PATTERNS = [
55
+ "You have pending notifications",
56
+ "You have open tasks. Run list_tasks",
57
+ "You have more open tasks to dispatch",
58
+ "Run list_tasks to check for assigned work",
59
+ "Run list_tasks to find them"
60
+ ];
61
+ var MCP_ZOMBIE_PATTERNS = [
62
+ "session expired",
63
+ "MCP server disconnected",
64
+ "MCP server is not connected",
65
+ 'MCP server "exe-os" is not connected',
66
+ "MCP connection lost",
67
+ "MCP error",
68
+ "MCP_UNHEALTHY"
69
+ ];
70
+ var MANAGER_ROLES = ["COO", "CTO"];
71
+ var AUDIT_LOG_PATH = path.join(
72
+ process.env.HOME ?? process.env.USERPROFILE ?? "/tmp",
73
+ ".exe-os",
74
+ "enforcement-audit.jsonl"
75
+ );
76
+ function writeAuditEntry(entry) {
77
+ const line = JSON.stringify(entry) + "\n";
78
+ appendFile(AUDIT_LOG_PATH, line).catch(() => {
79
+ });
80
+ }
81
+ function decideManagerAction(counts, isIdle, withinGracePeriod, nudgeEcho) {
82
+ if (counts.openTasks === 0) return "skip";
83
+ if (withinGracePeriod) return "grace_period";
84
+ if (!isIdle) return "active";
85
+ if (nudgeEcho) return "active";
86
+ if ((counts.inProgressTasks ?? 0) > 0) return "active";
87
+ if (counts.activeSubtasks === 0) return "nudge";
88
+ return "soft_nudge";
89
+ }
90
+ function decideWorkerAction(taskCount, isIdle, nudgeEcho) {
91
+ if (taskCount === 0) return "skip";
92
+ if (nudgeEcho) return "idle";
93
+ return isIdle ? "nudge" : "idle";
94
+ }
95
+ function isIdlePane(paneText) {
96
+ return IDLE_PATTERNS.some((p) => paneText.includes(p));
97
+ }
98
+ function isCurrentlyIdle(paneText) {
99
+ const nonEmptyLines = paneText.split("\n").map((line) => line.trim()).filter(Boolean);
100
+ const lastLine = nonEmptyLines.at(-1) ?? "";
101
+ if (/(?:^|[>❯$#])\s*\/mcp\s*$/.test(lastLine)) return true;
102
+ if (IDLE_PATTERNS.some((p) => lastLine.includes(p))) return true;
103
+ if (lineHasMcpZombiePattern(lastLine)) return true;
104
+ const currentLines = nonEmptyLines.slice(-3);
105
+ return tailHasMcpZombieContext(currentLines) && lineLooksLikeMcpReconnectPrompt(lastLine);
106
+ }
107
+ function isNudgeEcho(paneText) {
108
+ return NUDGE_ECHO_PATTERNS.some((p) => paneText.includes(p));
109
+ }
110
+ function lineHasMcpZombiePattern(line) {
111
+ const lower = line.toLowerCase();
112
+ if (lower.includes("not connected") && !lower.includes("mcp server")) return false;
113
+ return MCP_ZOMBIE_PATTERNS.some((p) => lower.includes(p.toLowerCase()));
114
+ }
115
+ function tailHasMcpZombieContext(lines) {
116
+ return lines.some(lineHasMcpZombiePattern);
117
+ }
118
+ function lineLooksLikeMcpReconnectPrompt(line) {
119
+ const lower = line.toLowerCase();
120
+ return lower.includes("/mcp") && (lower.includes("reconnect") || lower.includes("connect") || lower.includes("run") || lower.includes("try"));
121
+ }
122
+ function isMcpZombiePane(paneText, paneCurrentlyIdle) {
123
+ if (!paneCurrentlyIdle) return false;
124
+ const nonEmptyLines = paneText.split("\n").map((line) => line.trim()).filter(Boolean);
125
+ const lastLine = nonEmptyLines.at(-1) ?? "";
126
+ if (/(?:^|[>❯$#])\s*\/mcp\s*$/.test(lastLine)) return true;
127
+ if (lineHasMcpZombiePattern(lastLine)) return true;
128
+ const currentLines = nonEmptyLines.slice(-3);
129
+ return tailHasMcpZombieContext(currentLines) && lineLooksLikeMcpReconnectPrompt(lastLine);
130
+ }
131
+ function sendNudge(transport, session, runtime, action) {
132
+ const message = action === "nudge" ? "You have open tasks. Run list_tasks to find them." : "You have more open tasks to dispatch. Run list_tasks.";
133
+ if (transport.sendKeysLiteral) {
134
+ transport.sendKeysLiteral(session, message);
135
+ } else {
136
+ transport.sendKeys(session, message);
137
+ }
138
+ process.stderr.write(
139
+ `[enforcement-audit] SENT nudge to ${session} (${runtime}, ${action})
140
+ `
141
+ );
142
+ }
143
+ function _resetNudgeState() {
144
+ }
145
+ function coordinatorScopeFromSession(session) {
146
+ const dashIndex = session.indexOf("-");
147
+ if (dashIndex <= 0) return null;
148
+ const scope = session.slice(dashIndex + 1).trim();
149
+ return scope.length > 0 ? scope : null;
150
+ }
151
+ function strictTaskSessionScope(scope) {
152
+ if (!scope) return { sql: " AND session_scope IS NOT NULL AND 1 = 0", args: [] };
153
+ return { sql: " AND session_scope = ?", args: [scope] };
154
+ }
155
+ async function countOrphanedTasksForAgent(client, agentName, statuses) {
156
+ const result = await client.execute({
157
+ sql: `SELECT COUNT(*) as cnt FROM tasks WHERE assigned_to = ? AND status IN (${statuses}) AND session_scope IS NULL`,
158
+ args: [agentName]
159
+ });
160
+ return Number(result.rows[0]?.cnt ?? 0);
161
+ }
162
+ async function findStuckTasks(client, scopeList, now, thresholdMs = STUCK_TASK_THRESHOLD_MS) {
163
+ if (scopeList.length === 0) return [];
164
+ const result = await client.execute({
165
+ sql: `SELECT id, title, assigned_to, status, created_at, updated_at
166
+ FROM tasks
167
+ WHERE status IN ('open', 'blocked')
168
+ AND session_scope IN (${scopeList.map(() => "?").join(",")})`,
169
+ args: scopeList
170
+ });
171
+ const stuck = [];
172
+ for (const row of result.rows) {
173
+ const updatedAt = row.updated_at ?? row.created_at;
174
+ if (!updatedAt) continue;
175
+ const ts = new Date(updatedAt).getTime();
176
+ if (!Number.isFinite(ts)) continue;
177
+ const ageMs = now - ts;
178
+ if (ageMs > thresholdMs) {
179
+ stuck.push({
180
+ id: String(row.id),
181
+ title: String(row.title ?? ""),
182
+ assigned_to: String(row.assigned_to ?? ""),
183
+ status: String(row.status ?? ""),
184
+ ageMs
185
+ });
186
+ }
187
+ }
188
+ stuck.sort((a, b) => b.ageMs - a.ageMs);
189
+ return stuck;
190
+ }
191
+ async function runTaskEnforcementTick(deps) {
192
+ const { transport, employees, client } = deps;
193
+ const now = deps.now ?? Date.now();
194
+ const tickStartedAt = Date.now();
195
+ const sessions = transport.listSessions();
196
+ let processedAnyEmployee = false;
197
+ let processedSessions = 0;
198
+ let nudgesSent = 0;
199
+ const processedScopes = /* @__PURE__ */ new Set();
200
+ recordOrchestrationEventBestEffort({
201
+ eventType: "daemon.tick.started",
202
+ source: "task-enforcement.runTaskEnforcementTick",
203
+ payload: { sessionCount: sessions.length }
204
+ });
205
+ const hasScopeRestriction = deps.scopeFilter.sql.length > 0;
206
+ const allowedScope = hasScopeRestriction && deps.scopeFilter.args.length > 0 ? String(deps.scopeFilter.args[deps.scopeFilter.args.length - 1]) : null;
207
+ for (const session of sessions) {
208
+ if (!session.includes("-")) continue;
209
+ const agentName = session.split("-")[0]?.replace(/\d+$/, "");
210
+ if (!agentName) continue;
211
+ if (allowedScope) {
212
+ const sessionSuffix = session.slice(session.indexOf("-") + 1);
213
+ if (sessionSuffix !== allowedScope) continue;
214
+ }
215
+ if ("isAlive" in transport && typeof transport.isAlive === "function") {
216
+ if (!transport.isAlive(session)) continue;
217
+ }
218
+ const employee = employees.find((e) => e.name === agentName);
219
+ if (!employee) continue;
220
+ processedAnyEmployee = true;
221
+ processedSessions++;
222
+ const coordinatorSession = coordinatorScopeFromSession(session);
223
+ const effectiveScope = strictTaskSessionScope(coordinatorSession);
224
+ if (coordinatorSession) processedScopes.add(coordinatorSession);
225
+ const isManager = MANAGER_ROLES.includes(employee.role);
226
+ try {
227
+ let action = "skip";
228
+ let reason = "";
229
+ let openTasks = 0;
230
+ let activeSubtasks = 0;
231
+ let paneIdle;
232
+ if (isManager) {
233
+ const openResult = await client.execute({
234
+ sql: `SELECT COUNT(*) as cnt FROM tasks WHERE assigned_to = ? AND status = 'open'${effectiveScope.sql}`,
235
+ args: [agentName, ...effectiveScope.args]
236
+ });
237
+ openTasks = Number(openResult.rows[0]?.cnt ?? 0);
238
+ if (openTasks === 0 && coordinatorSession) {
239
+ const orphaned = await countOrphanedTasksForAgent(client, agentName, "'open'");
240
+ if (orphaned > 0) {
241
+ process.stderr.write(
242
+ `[exed] Task enforcement: ${agentName}-${coordinatorSession} has ${orphaned} orphaned open task(s) with NULL session_scope; not nudging until owning scope is repaired.
243
+ `
244
+ );
245
+ }
246
+ }
247
+ if (openTasks > 0) {
248
+ const subtaskResult = await client.execute({
249
+ sql: `SELECT COUNT(*) as cnt FROM tasks WHERE assigned_by = ? AND status = 'in_progress'${effectiveScope.sql}`,
250
+ args: [agentName, ...effectiveScope.args]
251
+ });
252
+ activeSubtasks = Number(subtaskResult.rows[0]?.cnt ?? 0);
253
+ }
254
+ let withinGracePeriod = false;
255
+ let graceRemaining = 0;
256
+ if (openTasks > 0) {
257
+ const newestResult = await client.execute({
258
+ sql: `SELECT created_at FROM tasks WHERE assigned_to = ? AND status = 'open'${effectiveScope.sql} ORDER BY created_at DESC LIMIT 1`,
259
+ args: [agentName, ...effectiveScope.args]
260
+ });
261
+ const newestCreatedAt = newestResult.rows[0]?.created_at;
262
+ if (newestCreatedAt) {
263
+ const taskAge = now - new Date(newestCreatedAt).getTime();
264
+ if (taskAge < MANAGER_GRACE_PERIOD_MS) {
265
+ withinGracePeriod = true;
266
+ graceRemaining = Math.round((MANAGER_GRACE_PERIOD_MS - taskAge) / 1e3);
267
+ }
268
+ }
269
+ }
270
+ let inProgressTasks = 0;
271
+ if (openTasks > 0) {
272
+ const ipResult = await client.execute({
273
+ sql: `SELECT COUNT(*) as cnt FROM tasks WHERE assigned_to = ? AND status = 'in_progress'${effectiveScope.sql}`,
274
+ args: [agentName, ...effectiveScope.args]
275
+ });
276
+ inProgressTasks = Number(ipResult.rows[0]?.cnt ?? 0);
277
+ }
278
+ const pane = deps.paneCache?.get(session) ?? (deps.capturePaneAsync ? await deps.capturePaneAsync(session, 20) : transport.capturePane(session, 20));
279
+ paneIdle = isIdlePane(pane);
280
+ const nudgeEcho = isNudgeEcho(pane);
281
+ action = decideManagerAction({ openTasks, activeSubtasks, inProgressTasks }, paneIdle, withinGracePeriod, nudgeEcho);
282
+ if (action === "skip") reason = "no open tasks";
283
+ else if (action === "grace_period") reason = `task assigned <10min ago (${graceRemaining}s remaining)`;
284
+ else if (action === "active") reason = nudgeEcho ? "pane shows previous nudge (anti-loop)" : inProgressTasks > 0 ? `${inProgressTasks} tasks in_progress` : "pane shows active work";
285
+ else if (action === "nudge") reason = `${openTasks} open tasks, 0 delegated, pane idle`;
286
+ else if (action === "soft_nudge") reason = `${openTasks} open tasks, ${activeSubtasks} delegated, pane idle`;
287
+ writeAuditEntry({
288
+ timestamp: new Date(now).toISOString(),
289
+ session,
290
+ agent: agentName,
291
+ role: "manager",
292
+ action,
293
+ reason,
294
+ openTasks,
295
+ activeSubtasks,
296
+ paneIdle,
297
+ graceRemaining: withinGracePeriod ? graceRemaining : void 0
298
+ });
299
+ process.stderr.write(
300
+ `[exed] Task enforcement: ${agentName} (manager) ${openTasks} open, ${activeSubtasks} delegated, pane=${paneIdle ? "idle" : "active"}. Action: ${action} (${reason})
301
+ `
302
+ );
303
+ } else {
304
+ const taskResult = await client.execute({
305
+ sql: `SELECT COUNT(*) as cnt FROM tasks WHERE assigned_to = ? AND status IN ('open', 'in_progress')${effectiveScope.sql}`,
306
+ args: [agentName, ...effectiveScope.args]
307
+ });
308
+ const taskCount = Number(taskResult.rows[0]?.cnt ?? 0);
309
+ openTasks = taskCount;
310
+ if (taskCount === 0 && coordinatorSession) {
311
+ const orphaned = await countOrphanedTasksForAgent(client, agentName, "'open','in_progress'");
312
+ if (orphaned > 0) {
313
+ process.stderr.write(
314
+ `[exed] Task enforcement: ${agentName}-${coordinatorSession} has ${orphaned} orphaned task(s) with NULL session_scope; not nudging until owning scope is repaired.
315
+ `
316
+ );
317
+ }
318
+ }
319
+ if (taskCount > 0) {
320
+ const pane = deps.paneCache?.get(session) ?? (deps.capturePaneAsync ? await deps.capturePaneAsync(session, 20) : transport.capturePane(session, 20));
321
+ paneIdle = isIdlePane(pane);
322
+ const workerNudgeEcho = isNudgeEcho(pane);
323
+ const paneCurrentlyIdle = isCurrentlyIdle(pane);
324
+ if (isMcpZombiePane(pane, paneCurrentlyIdle) && deps.zombieWorkerRecover) {
325
+ const reason2 = "pane shows dead MCP client";
326
+ await deps.zombieWorkerRecover(session, agentName, coordinatorSession ?? "", reason2);
327
+ writeAuditEntry({
328
+ timestamp: new Date(now).toISOString(),
329
+ session,
330
+ agent: agentName,
331
+ role: "worker",
332
+ action: "active",
333
+ reason: reason2,
334
+ openTasks: taskCount,
335
+ paneIdle
336
+ });
337
+ continue;
338
+ }
339
+ action = decideWorkerAction(taskCount, paneIdle, workerNudgeEcho);
340
+ }
341
+ if (action === "skip") reason = "no tasks";
342
+ else if (action === "idle") reason = `${taskCount} tasks but pane active`;
343
+ else if (action === "nudge") reason = `${taskCount} tasks, pane idle`;
344
+ writeAuditEntry({
345
+ timestamp: new Date(now).toISOString(),
346
+ session,
347
+ agent: agentName,
348
+ role: "worker",
349
+ action,
350
+ reason,
351
+ openTasks: taskCount,
352
+ paneIdle
353
+ });
354
+ process.stderr.write(
355
+ `[exed] Task enforcement: ${agentName} (worker) ${taskCount} tasks, pane=${paneIdle ?? "n/a"}. Action: ${action} (${reason})
356
+ `
357
+ );
358
+ }
359
+ if (action === "skip" || action === "idle" || action === "grace_period" || action === "active") continue;
360
+ nudgesSent++;
361
+ sendIntercom(session, { callerSessionScope: coordinatorSession, reason: "nudge" });
362
+ } catch {
363
+ }
364
+ }
365
+ if (processedAnyEmployee) {
366
+ try {
367
+ const scopeList = allowedScope ? [...processedScopes].filter((s) => s === allowedScope) : [...processedScopes];
368
+ const staleBlocked = scopeList.length === 0 ? { rows: [] } : await client.execute({
369
+ sql: `SELECT t.id, t.title, b.status as blocker_status
370
+ FROM tasks t
371
+ JOIN tasks b ON t.blocked_by = b.id
372
+ WHERE t.status = 'blocked'
373
+ AND b.status IN ('done', 'cancelled', 'closed')
374
+ AND t.session_scope IN (${scopeList.map(() => "?").join(",")})`,
375
+ args: scopeList
376
+ });
377
+ const nowIso = new Date(now).toISOString();
378
+ for (const row of staleBlocked.rows) {
379
+ try {
380
+ await updateTaskStatus({ taskId: String(row.id), status: "open" });
381
+ } catch {
382
+ await client.execute({
383
+ sql: `UPDATE tasks SET status = 'open', updated_at = ? WHERE id = ?`,
384
+ args: [nowIso, String(row.id)]
385
+ });
386
+ }
387
+ await client.execute({
388
+ sql: `UPDATE tasks SET blocked_by = NULL WHERE id = ?`,
389
+ args: [String(row.id)]
390
+ });
391
+ process.stderr.write(
392
+ `[exed] Auto-unblocked "${String(row.title)}" \u2014 blocker already ${String(row.blocker_status)}
393
+ `
394
+ );
395
+ }
396
+ } catch {
397
+ }
398
+ }
399
+ if (processedAnyEmployee && deps.reviewerSpawn) {
400
+ try {
401
+ const scopeList = allowedScope ? [...processedScopes].filter((s) => s === allowedScope) : [...processedScopes];
402
+ const reviewerRows = scopeList.length === 0 ? { rows: [] } : await client.execute({
403
+ sql: `SELECT DISTINCT reviewer, session_scope FROM tasks
404
+ WHERE status = 'needs_review'
405
+ AND reviewer IS NOT NULL
406
+ AND reviewer != ''
407
+ AND session_scope IN (${scopeList.map(() => "?").join(",")})`,
408
+ args: scopeList
409
+ });
410
+ const liveSessionSet = new Set(sessions);
411
+ for (const row of reviewerRows.rows) {
412
+ const reviewerName = String(row.reviewer ?? "");
413
+ const sessionScope = row.session_scope ? String(row.session_scope) : null;
414
+ if (!reviewerName || !sessionScope) continue;
415
+ if (isCoordinatorName(reviewerName, employees)) {
416
+ process.stderr.write(
417
+ `[exed] Reviewer auto-spawn: skipping ${reviewerName} (coordinator, not dispatchable)
418
+ `
419
+ );
420
+ continue;
421
+ }
422
+ const reviewerSession = `${reviewerName}-${sessionScope}`;
423
+ if (liveSessionSet.has(reviewerSession)) continue;
424
+ try {
425
+ const result = deps.reviewerSpawn(reviewerName, sessionScope);
426
+ if (!result) continue;
427
+ if (result.status === "spawned") {
428
+ process.stderr.write(
429
+ `[exed] Reviewer auto-spawn: spawned ${reviewerName} in ${sessionScope} (has needs_review tasks)
430
+ `
431
+ );
432
+ } else if (result.status === "failed") {
433
+ process.stderr.write(
434
+ `[exed] Reviewer auto-spawn: failed to spawn ${reviewerName} in ${sessionScope}: ${result.error ?? "unknown"}
435
+ `
436
+ );
437
+ }
438
+ } catch (spawnErr) {
439
+ process.stderr.write(
440
+ `[exed] Reviewer auto-spawn error for ${reviewerName}: ${spawnErr instanceof Error ? spawnErr.message : String(spawnErr)}
441
+ `
442
+ );
443
+ }
444
+ }
445
+ } catch {
446
+ }
447
+ }
448
+ if (processedAnyEmployee) {
449
+ try {
450
+ const scopeList = allowedScope ? [...processedScopes].filter((s) => s === allowedScope) : [...processedScopes];
451
+ const stuck = await findStuckTasks(client, scopeList, now);
452
+ if (stuck.length > 0) {
453
+ const oldest = stuck[0];
454
+ const oldestStuckHours = Math.round(oldest.ageMs / 36e5);
455
+ writeAuditEntry({
456
+ timestamp: new Date(now).toISOString(),
457
+ session: allowedScope ?? "(all-scopes)",
458
+ agent: "(enforcement)",
459
+ role: "manager",
460
+ action: "stuck_alert",
461
+ reason: `${stuck.length} stuck task(s) > ${Math.round(STUCK_TASK_THRESHOLD_MS / 36e5)}h; oldest "${oldest.title}" (${oldest.assigned_to}, ${oldest.status}) ${oldestStuckHours}h`,
462
+ stuckTasks: stuck.length,
463
+ oldestStuckHours
464
+ });
465
+ process.stderr.write(
466
+ `[exed] STUCK-TASK ALERT: ${stuck.length} open/blocked task(s) idle > ${Math.round(STUCK_TASK_THRESHOLD_MS / 36e5)}h. Oldest: "${oldest.title}" (assigned ${oldest.assigned_to}, ${oldest.status}, ${oldestStuckHours}h).
467
+ `
468
+ );
469
+ recordOrchestrationEventBestEffort({
470
+ eventType: "task.stuck.detected",
471
+ source: "task-enforcement.runTaskEnforcementTick",
472
+ payload: { stuckTasks: stuck.length, oldestStuckHours, oldestTaskId: oldest.id }
473
+ });
474
+ }
475
+ } catch {
476
+ }
477
+ }
478
+ recordOrchestrationEventBestEffort({
479
+ eventType: "daemon.tick.completed",
480
+ source: "task-enforcement.runTaskEnforcementTick",
481
+ durationMs: Date.now() - tickStartedAt,
482
+ result: processedAnyEmployee ? "processed" : "no_employee_sessions",
483
+ payload: { sessionCount: sessions.length, processedSessions, nudgesSent }
484
+ });
485
+ }
486
+ export {
487
+ IDLE_PATTERNS,
488
+ MANAGER_GRACE_PERIOD_MS,
489
+ MANAGER_ROLES,
490
+ MCP_ZOMBIE_PATTERNS,
491
+ NUDGE_ECHO_PATTERNS,
492
+ STUCK_TASK_THRESHOLD_MS,
493
+ TASK_ENFORCEMENT_DEBOUNCE_MS,
494
+ TASK_ENFORCEMENT_INTERVAL_MS,
495
+ _resetNudgeState,
496
+ decideManagerAction,
497
+ decideWorkerAction,
498
+ findStuckTasks,
499
+ isCurrentlyIdle,
500
+ isIdlePane,
501
+ isMcpZombiePane,
502
+ isNudgeEcho,
503
+ runTaskEnforcementTick,
504
+ sendNudge
505
+ };