@runcore-sh/runcore 0.4.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (351) hide show
  1. package/dictionary.json +2 -2
  2. package/dist/activity/log.js +2 -2
  3. package/dist/activity/log.js.map +1 -1
  4. package/dist/agents/governed-spawn.d.ts.map +1 -1
  5. package/dist/cli.js +101 -11
  6. package/dist/cli.js.map +1 -1
  7. package/dist/extensions/cache.d.ts +57 -0
  8. package/dist/extensions/cache.d.ts.map +1 -0
  9. package/dist/extensions/cache.js +173 -0
  10. package/dist/extensions/cache.js.map +1 -0
  11. package/dist/extensions/client.d.ts +55 -0
  12. package/dist/extensions/client.d.ts.map +1 -0
  13. package/dist/extensions/client.js +120 -0
  14. package/dist/extensions/client.js.map +1 -0
  15. package/dist/extensions/index.d.ts +13 -0
  16. package/dist/extensions/index.d.ts.map +1 -0
  17. package/dist/extensions/index.js +12 -0
  18. package/dist/extensions/index.js.map +1 -0
  19. package/dist/extensions/loader.d.ts +50 -0
  20. package/dist/extensions/loader.d.ts.map +1 -0
  21. package/dist/extensions/loader.js +166 -0
  22. package/dist/extensions/loader.js.map +1 -0
  23. package/dist/extensions/manifest.d.ts +38 -0
  24. package/dist/extensions/manifest.d.ts.map +1 -0
  25. package/dist/extensions/manifest.js +17 -0
  26. package/dist/extensions/manifest.js.map +1 -0
  27. package/dist/extensions/stubs.d.ts +27 -0
  28. package/dist/extensions/stubs.d.ts.map +1 -0
  29. package/dist/extensions/stubs.js +45 -0
  30. package/dist/extensions/stubs.js.map +1 -0
  31. package/dist/lib/audit.js +2 -2
  32. package/dist/lib/audit.js.map +1 -1
  33. package/dist/lib/brain-migrate.d.ts +21 -0
  34. package/dist/lib/brain-migrate.d.ts.map +1 -0
  35. package/dist/lib/brain-migrate.js +137 -0
  36. package/dist/lib/brain-migrate.js.map +1 -0
  37. package/dist/lib/paths.d.ts +27 -0
  38. package/dist/lib/paths.d.ts.map +1 -1
  39. package/dist/lib/paths.js +65 -0
  40. package/dist/lib/paths.js.map +1 -1
  41. package/dist/llm/call-log.d.ts +40 -0
  42. package/dist/llm/call-log.d.ts.map +1 -0
  43. package/dist/llm/call-log.js +35 -0
  44. package/dist/llm/call-log.js.map +1 -0
  45. package/dist/llm/complete.d.ts +6 -0
  46. package/dist/llm/complete.d.ts.map +1 -1
  47. package/dist/llm/complete.js +27 -0
  48. package/dist/llm/complete.js.map +1 -1
  49. package/dist/mcp-server.js +118 -2
  50. package/dist/mcp-server.js.map +1 -1
  51. package/dist/memory/file-backed.d.ts +4 -0
  52. package/dist/memory/file-backed.d.ts.map +1 -1
  53. package/dist/memory/file-backed.js +4 -0
  54. package/dist/memory/file-backed.js.map +1 -1
  55. package/dist/memory/vector-index.d.ts +4 -12
  56. package/dist/memory/vector-index.d.ts.map +1 -1
  57. package/dist/memory/vector-index.js +11 -93
  58. package/dist/memory/vector-index.js.map +1 -1
  59. package/dist/search/brain-docs.d.ts +17 -7
  60. package/dist/search/brain-docs.d.ts.map +1 -1
  61. package/dist/search/brain-docs.js +170 -52
  62. package/dist/search/brain-docs.js.map +1 -1
  63. package/dist/search/brain-rag.d.ts +45 -0
  64. package/dist/search/brain-rag.d.ts.map +1 -0
  65. package/dist/search/brain-rag.js +275 -0
  66. package/dist/search/brain-rag.js.map +1 -0
  67. package/dist/search/chunker.d.ts +24 -0
  68. package/dist/search/chunker.d.ts.map +1 -0
  69. package/dist/search/chunker.js +95 -0
  70. package/dist/search/chunker.js.map +1 -0
  71. package/dist/search/embedder.d.ts +16 -0
  72. package/dist/search/embedder.d.ts.map +1 -0
  73. package/dist/search/embedder.js +108 -0
  74. package/dist/search/embedder.js.map +1 -0
  75. package/dist/search/file-watcher.d.ts +11 -0
  76. package/dist/search/file-watcher.d.ts.map +1 -0
  77. package/dist/search/file-watcher.js +86 -0
  78. package/dist/search/file-watcher.js.map +1 -0
  79. package/dist/server.d.ts.map +1 -1
  80. package/dist/server.js +814 -472
  81. package/dist/server.js.map +1 -1
  82. package/dist/sessions/store.d.ts +9 -0
  83. package/dist/sessions/store.d.ts.map +1 -1
  84. package/dist/sessions/store.js.map +1 -1
  85. package/dist/settings.d.ts +26 -0
  86. package/dist/settings.d.ts.map +1 -1
  87. package/dist/settings.js +78 -2
  88. package/dist/settings.js.map +1 -1
  89. package/dist/tracing/init.d.ts +1 -1
  90. package/dist/tracing/init.d.ts.map +1 -1
  91. package/dist/utils/logger.js +2 -2
  92. package/dist/utils/logger.js.map +1 -1
  93. package/module-tiers.json +164 -0
  94. package/package.json +9 -13
  95. package/public/avatar/cache/1184385ec5522b57.mp4 +0 -0
  96. package/public/avatar/cache/1f15f6a1ebd7e439.mp4 +0 -0
  97. package/public/avatar/cache/2c7e47ff0bdeb8d1.mp4 +0 -0
  98. package/public/avatar/cache/5f308566f7abb8f2.mp4 +0 -0
  99. package/public/avatar/cache/62f9cfba848d724e.mp4 +0 -0
  100. package/public/avatar/cache/6d64e657e6bf2aab.mp4 +0 -0
  101. package/public/avatar/cache/763ad0349e0b6f26.mp4 +0 -0
  102. package/public/avatar/cache/81a516cfd461b2b9.mp4 +0 -0
  103. package/public/avatar/cache/9366de15fd6910ca.mp4 +0 -0
  104. package/public/avatar/cache/ade41a846b283895.mp4 +0 -0
  105. package/public/avatar/cache/b6066e5c65383eec.mp4 +0 -0
  106. package/public/avatar/cache/edadb75d37891fc7.mp4 +0 -0
  107. package/public/avatar/cache/f0ae159640621dd9.mp4 +0 -0
  108. package/public/avatar/cache/fc2e5419adf29d96.mp4 +0 -0
  109. package/public/index.html +379 -59
  110. package/dist/agents/autonomous.js +0 -749
  111. package/dist/agents/autonomous.js.map +0 -1
  112. package/dist/agents/commit.js +0 -113
  113. package/dist/agents/commit.js.map +0 -1
  114. package/dist/agents/continue.js +0 -158
  115. package/dist/agents/continue.js.map +0 -1
  116. package/dist/agents/cooldown.js +0 -397
  117. package/dist/agents/cooldown.js.map +0 -1
  118. package/dist/agents/dedup-guard.js +0 -131
  119. package/dist/agents/dedup-guard.js.map +0 -1
  120. package/dist/agents/feed.js +0 -176
  121. package/dist/agents/feed.js.map +0 -1
  122. package/dist/agents/governance.js +0 -292
  123. package/dist/agents/governance.js.map +0 -1
  124. package/dist/agents/governed-spawn.js +0 -192
  125. package/dist/agents/governed-spawn.js.map +0 -1
  126. package/dist/agents/heartbeat.js +0 -324
  127. package/dist/agents/heartbeat.js.map +0 -1
  128. package/dist/agents/instance-manager.js +0 -850
  129. package/dist/agents/instance-manager.js.map +0 -1
  130. package/dist/agents/issue-reporter.js +0 -123
  131. package/dist/agents/issue-reporter.js.map +0 -1
  132. package/dist/agents/issues.js +0 -141
  133. package/dist/agents/issues.js.map +0 -1
  134. package/dist/agents/locks.js +0 -234
  135. package/dist/agents/locks.js.map +0 -1
  136. package/dist/agents/memory.js +0 -93
  137. package/dist/agents/memory.js.map +0 -1
  138. package/dist/agents/monitor.js +0 -235
  139. package/dist/agents/monitor.js.map +0 -1
  140. package/dist/agents/orchestration.js +0 -715
  141. package/dist/agents/orchestration.js.map +0 -1
  142. package/dist/agents/recover.js +0 -166
  143. package/dist/agents/recover.js.map +0 -1
  144. package/dist/agents/reflection.js +0 -199
  145. package/dist/agents/reflection.js.map +0 -1
  146. package/dist/agents/runtime/bus.js +0 -174
  147. package/dist/agents/runtime/bus.js.map +0 -1
  148. package/dist/agents/runtime/config.js +0 -101
  149. package/dist/agents/runtime/config.js.map +0 -1
  150. package/dist/agents/runtime/driver.js +0 -214
  151. package/dist/agents/runtime/driver.js.map +0 -1
  152. package/dist/agents/runtime/errors.js +0 -40
  153. package/dist/agents/runtime/errors.js.map +0 -1
  154. package/dist/agents/runtime/index.js +0 -54
  155. package/dist/agents/runtime/index.js.map +0 -1
  156. package/dist/agents/runtime/lifecycle.js +0 -116
  157. package/dist/agents/runtime/lifecycle.js.map +0 -1
  158. package/dist/agents/runtime/manager.js +0 -948
  159. package/dist/agents/runtime/manager.js.map +0 -1
  160. package/dist/agents/runtime/registry.js +0 -195
  161. package/dist/agents/runtime/registry.js.map +0 -1
  162. package/dist/agents/runtime/resources.js +0 -146
  163. package/dist/agents/runtime/resources.js.map +0 -1
  164. package/dist/agents/runtime/types.js +0 -24
  165. package/dist/agents/runtime/types.js.map +0 -1
  166. package/dist/agents/spawn-policy.js +0 -202
  167. package/dist/agents/spawn-policy.js.map +0 -1
  168. package/dist/agents/spawn.js +0 -970
  169. package/dist/agents/spawn.js.map +0 -1
  170. package/dist/agents/triage.js +0 -81
  171. package/dist/agents/triage.js.map +0 -1
  172. package/dist/agents/workflow.js +0 -543
  173. package/dist/agents/workflow.js.map +0 -1
  174. package/dist/avatar/client.js +0 -172
  175. package/dist/avatar/client.js.map +0 -1
  176. package/dist/avatar/sidecar.js +0 -125
  177. package/dist/avatar/sidecar.js.map +0 -1
  178. package/dist/browser/sessions.js +0 -122
  179. package/dist/browser/sessions.js.map +0 -1
  180. package/dist/capabilities/definitions/browser.js +0 -242
  181. package/dist/capabilities/definitions/browser.js.map +0 -1
  182. package/dist/channels/whatsapp.js +0 -200
  183. package/dist/channels/whatsapp.js.map +0 -1
  184. package/dist/credentials/store.js +0 -189
  185. package/dist/credentials/store.js.map +0 -1
  186. package/dist/files/deep-index.js +0 -337
  187. package/dist/files/deep-index.js.map +0 -1
  188. package/dist/files/extract.js +0 -33
  189. package/dist/files/extract.js.map +0 -1
  190. package/dist/files/gdrive.js +0 -246
  191. package/dist/files/gdrive.js.map +0 -1
  192. package/dist/github/client.js +0 -408
  193. package/dist/github/client.js.map +0 -1
  194. package/dist/github/commit-analysis.js +0 -276
  195. package/dist/github/commit-analysis.js.map +0 -1
  196. package/dist/github/contributor-stats.js +0 -119
  197. package/dist/github/contributor-stats.js.map +0 -1
  198. package/dist/github/issue-sla.js +0 -220
  199. package/dist/github/issue-sla.js.map +0 -1
  200. package/dist/github/issue-triage.js +0 -286
  201. package/dist/github/issue-triage.js.map +0 -1
  202. package/dist/github/pr-readiness.js +0 -197
  203. package/dist/github/pr-readiness.js.map +0 -1
  204. package/dist/github/pr-review.js +0 -410
  205. package/dist/github/pr-review.js.map +0 -1
  206. package/dist/github/release-notes.js +0 -227
  207. package/dist/github/release-notes.js.map +0 -1
  208. package/dist/github/repo-health.js +0 -303
  209. package/dist/github/repo-health.js.map +0 -1
  210. package/dist/github/retry.js +0 -117
  211. package/dist/github/retry.js.map +0 -1
  212. package/dist/github/types.js +0 -8
  213. package/dist/github/types.js.map +0 -1
  214. package/dist/github/webhooks.js +0 -153
  215. package/dist/github/webhooks.js.map +0 -1
  216. package/dist/google/auth.js +0 -325
  217. package/dist/google/auth.js.map +0 -1
  218. package/dist/google/calendar-timer.js +0 -91
  219. package/dist/google/calendar-timer.js.map +0 -1
  220. package/dist/google/calendar.js +0 -270
  221. package/dist/google/calendar.js.map +0 -1
  222. package/dist/google/docs.js +0 -309
  223. package/dist/google/docs.js.map +0 -1
  224. package/dist/google/gmail-send.js +0 -219
  225. package/dist/google/gmail-send.js.map +0 -1
  226. package/dist/google/gmail-timer.js +0 -223
  227. package/dist/google/gmail-timer.js.map +0 -1
  228. package/dist/google/gmail.js +0 -470
  229. package/dist/google/gmail.js.map +0 -1
  230. package/dist/google/plugin.js +0 -169
  231. package/dist/google/plugin.js.map +0 -1
  232. package/dist/google/tasks-timer.js +0 -107
  233. package/dist/google/tasks-timer.js.map +0 -1
  234. package/dist/google/tasks.js +0 -331
  235. package/dist/google/tasks.js.map +0 -1
  236. package/dist/google/temporal.js +0 -176
  237. package/dist/google/temporal.js.map +0 -1
  238. package/dist/integrations/gate.js +0 -100
  239. package/dist/integrations/gate.js.map +0 -1
  240. package/dist/integrations/github.js +0 -331
  241. package/dist/integrations/github.js.map +0 -1
  242. package/dist/integrations/google-tasks.js +0 -432
  243. package/dist/integrations/google-tasks.js.map +0 -1
  244. package/dist/mdns.js +0 -110
  245. package/dist/mdns.js.map +0 -1
  246. package/dist/notifications/channel.js +0 -83
  247. package/dist/notifications/channel.js.map +0 -1
  248. package/dist/notifications/channels/adapter.js +0 -55
  249. package/dist/notifications/channels/adapter.js.map +0 -1
  250. package/dist/notifications/channels/index.js +0 -6
  251. package/dist/notifications/channels/index.js.map +0 -1
  252. package/dist/notifications/channels/log.js +0 -29
  253. package/dist/notifications/channels/log.js.map +0 -1
  254. package/dist/notifications/email.js +0 -72
  255. package/dist/notifications/email.js.map +0 -1
  256. package/dist/notifications/engine.js +0 -198
  257. package/dist/notifications/engine.js.map +0 -1
  258. package/dist/notifications/index.js +0 -24
  259. package/dist/notifications/index.js.map +0 -1
  260. package/dist/notifications/phone.js +0 -48
  261. package/dist/notifications/phone.js.map +0 -1
  262. package/dist/notifications/sms.js +0 -65
  263. package/dist/notifications/sms.js.map +0 -1
  264. package/dist/notifications/types.js +0 -14
  265. package/dist/notifications/types.js.map +0 -1
  266. package/dist/notifications/webhook.js +0 -65
  267. package/dist/notifications/webhook.js.map +0 -1
  268. package/dist/resend/inbox.js +0 -199
  269. package/dist/resend/inbox.js.map +0 -1
  270. package/dist/resend/webhooks.js +0 -244
  271. package/dist/resend/webhooks.js.map +0 -1
  272. package/dist/search/browse.js +0 -225
  273. package/dist/search/browse.js.map +0 -1
  274. package/dist/search/perplexity.js +0 -41
  275. package/dist/search/perplexity.js.map +0 -1
  276. package/dist/slack/channels.js +0 -277
  277. package/dist/slack/channels.js.map +0 -1
  278. package/dist/slack/client.js +0 -468
  279. package/dist/slack/client.js.map +0 -1
  280. package/dist/slack/retry.js +0 -100
  281. package/dist/slack/retry.js.map +0 -1
  282. package/dist/slack/types.js +0 -52
  283. package/dist/slack/types.js.map +0 -1
  284. package/dist/slack/webhooks.js +0 -285
  285. package/dist/slack/webhooks.js.map +0 -1
  286. package/dist/stt/client.js +0 -66
  287. package/dist/stt/client.js.map +0 -1
  288. package/dist/stt/sidecar.js +0 -115
  289. package/dist/stt/sidecar.js.map +0 -1
  290. package/dist/tracing/bridge.js +0 -70
  291. package/dist/tracing/bridge.js.map +0 -1
  292. package/dist/tracing/correlation.js +0 -49
  293. package/dist/tracing/correlation.js.map +0 -1
  294. package/dist/tracing/index.js +0 -18
  295. package/dist/tracing/index.js.map +0 -1
  296. package/dist/tracing/init.js +0 -81
  297. package/dist/tracing/init.js.map +0 -1
  298. package/dist/tracing/instrument.js +0 -145
  299. package/dist/tracing/instrument.js.map +0 -1
  300. package/dist/tracing/middleware.js +0 -69
  301. package/dist/tracing/middleware.js.map +0 -1
  302. package/dist/tracing/tracer.js +0 -327
  303. package/dist/tracing/tracer.js.map +0 -1
  304. package/dist/tts/client.js +0 -48
  305. package/dist/tts/client.js.map +0 -1
  306. package/dist/tts/sidecar.js +0 -148
  307. package/dist/tts/sidecar.js.map +0 -1
  308. package/dist/twilio/call.js +0 -79
  309. package/dist/twilio/call.js.map +0 -1
  310. package/dist/vault/matcher.js +0 -197
  311. package/dist/vault/matcher.js.map +0 -1
  312. package/dist/vault/personal.js +0 -163
  313. package/dist/vault/personal.js.map +0 -1
  314. package/dist/vault/policy.js +0 -159
  315. package/dist/vault/policy.js.map +0 -1
  316. package/dist/vault/store.js +0 -122
  317. package/dist/vault/store.js.map +0 -1
  318. package/dist/vault/transfer.js +0 -188
  319. package/dist/vault/transfer.js.map +0 -1
  320. package/dist/volumes/index.js +0 -2
  321. package/dist/volumes/index.js.map +0 -1
  322. package/dist/volumes/manager.js +0 -462
  323. package/dist/volumes/manager.js.map +0 -1
  324. package/dist/volumes/types.js +0 -8
  325. package/dist/volumes/types.js.map +0 -1
  326. package/dist/webhooks/config.js +0 -214
  327. package/dist/webhooks/config.js.map +0 -1
  328. package/dist/webhooks/event-log.js +0 -132
  329. package/dist/webhooks/event-log.js.map +0 -1
  330. package/dist/webhooks/handler.js +0 -103
  331. package/dist/webhooks/handler.js.map +0 -1
  332. package/dist/webhooks/handlers.js +0 -231
  333. package/dist/webhooks/handlers.js.map +0 -1
  334. package/dist/webhooks/index.js +0 -33
  335. package/dist/webhooks/index.js.map +0 -1
  336. package/dist/webhooks/mount.js +0 -400
  337. package/dist/webhooks/mount.js.map +0 -1
  338. package/dist/webhooks/registry.js +0 -143
  339. package/dist/webhooks/registry.js.map +0 -1
  340. package/dist/webhooks/relay.js +0 -53
  341. package/dist/webhooks/relay.js.map +0 -1
  342. package/dist/webhooks/retry.js +0 -270
  343. package/dist/webhooks/retry.js.map +0 -1
  344. package/dist/webhooks/router.js +0 -290
  345. package/dist/webhooks/router.js.map +0 -1
  346. package/dist/webhooks/twilio.js +0 -129
  347. package/dist/webhooks/twilio.js.map +0 -1
  348. package/dist/webhooks/types.js +0 -8
  349. package/dist/webhooks/types.js.map +0 -1
  350. package/dist/webhooks/verify.js +0 -154
  351. package/dist/webhooks/verify.js.map +0 -1
@@ -1,397 +0,0 @@
1
- /**
2
- * Task Cooldown Manager — prevents repeatedly-failing tasks from being
3
- * retried too aggressively, reducing GC pressure from excessive agent spawns.
4
- *
5
- * Tracks failure counts per board task ID with exponential backoff cooldowns.
6
- * Persists state to disk so cooldowns survive process restarts.
7
- *
8
- * Usage:
9
- * const cooldown = TaskCooldownManager.getInstance();
10
- * await cooldown.init();
11
- * cooldown.recordFailure("task-123", "Build feature X", "TypeError: ...");
12
- * if (cooldown.isOnCooldown("task-123")) { skip task }
13
- */
14
- import { readFile, writeFile, mkdir } from "node:fs/promises";
15
- import { join, dirname } from "node:path";
16
- import { createLogger } from "../utils/logger.js";
17
- import { logActivity } from "../activity/log.js";
18
- import { recordCooldownActivation, recordCooldownSkip } from "../metrics/firewall-metrics.js";
19
- import { BRAIN_DIR } from "../lib/paths.js";
20
- const log = createLogger("cooldown");
21
- const DEFAULT_CONFIG = {
22
- baseCooldownMs: 30 * 60 * 1000, // 30 min
23
- maxCooldownMs: 4 * 60 * 60 * 1000, // 4 hours
24
- backoffMultiplier: 2,
25
- persistPath: join(BRAIN_DIR, "agents", "cooldowns.json"),
26
- maxEntries: 200,
27
- maxTotalFailures: 6,
28
- };
29
- // ─── Singleton ──────────────────────────────────────────────────────────────
30
- let instance = null;
31
- // ─── Manager ────────────────────────────────────────────────────────────────
32
- export class TaskCooldownManager {
33
- config;
34
- entries = new Map();
35
- dirty = false;
36
- persistTimer = null;
37
- constructor(config) {
38
- this.config = { ...DEFAULT_CONFIG, ...config };
39
- }
40
- /** Get or create the singleton instance. */
41
- static getInstance(config) {
42
- if (!instance) {
43
- instance = new TaskCooldownManager(config);
44
- }
45
- return instance;
46
- }
47
- /** Reset singleton (for testing). */
48
- static resetInstance() {
49
- if (instance) {
50
- instance.shutdown();
51
- instance = null;
52
- }
53
- }
54
- // ── Lifecycle ─────────────────────────────────────────────────────────────
55
- /** Load persisted cooldown state from disk. */
56
- async init() {
57
- try {
58
- const raw = await readFile(this.config.persistPath, "utf-8");
59
- const data = JSON.parse(raw);
60
- for (const entry of data) {
61
- this.entries.set(entry.taskId, entry);
62
- }
63
- // Prune expired entries on load
64
- this.pruneExpired();
65
- log.info(`Loaded ${this.entries.size} cooldown entries from disk`);
66
- }
67
- catch (err) {
68
- const code = err.code;
69
- if (code === "ENOENT") {
70
- log.info("No cooldown state on disk, starting fresh");
71
- }
72
- else {
73
- log.warn(`Failed to load cooldown state: ${err.message}`);
74
- }
75
- }
76
- }
77
- /** Flush pending changes and stop the persist timer. */
78
- shutdown() {
79
- if (this.persistTimer) {
80
- clearTimeout(this.persistTimer);
81
- this.persistTimer = null;
82
- }
83
- if (this.dirty) {
84
- this.persistSync();
85
- }
86
- }
87
- // ── Core API ──────────────────────────────────────────────────────────────
88
- /**
89
- * Record a task failure. Increments the failure count and resets the
90
- * cooldown timer. Schedules a debounced persist to disk.
91
- */
92
- recordFailure(taskId, label, error) {
93
- const existing = this.entries.get(taskId);
94
- // DASH-143: Dedup burst — if the same task was recorded within 30s,
95
- // skip to prevent double-counting from multiple recording paths
96
- // (immediate failure handler + batch completion handler).
97
- if (existing) {
98
- const sinceLast = Date.now() - new Date(existing.lastFailedAt).getTime();
99
- if (sinceLast < 30_000) {
100
- log.debug(`Skipping duplicate failure record for ${taskId} (${sinceLast}ms since last)`);
101
- return;
102
- }
103
- }
104
- const failureCount = (existing?.failureCount ?? 0) + 1;
105
- const entry = {
106
- taskId,
107
- lastFailedAt: new Date().toISOString(),
108
- failureCount,
109
- lastError: error?.slice(0, 300),
110
- label: label ?? existing?.label,
111
- };
112
- this.entries.set(taskId, entry);
113
- this.dirty = true;
114
- this.schedulePersist();
115
- recordCooldownActivation();
116
- // Check if task is now permanently blocked
117
- if (failureCount >= this.config.maxTotalFailures) {
118
- log.warn(`Task ${taskId} BLOCKED after ${failureCount} failures — needs manual clearCooldown()`, {
119
- taskId,
120
- failureCount,
121
- label,
122
- });
123
- logActivity({
124
- source: "agent",
125
- summary: `BLOCKED: ${label ?? taskId} permanently blocked after ${failureCount} failures — needs human intervention`,
126
- detail: error?.slice(0, 200),
127
- actionLabel: "AUTONOMOUS",
128
- reason: "task permanently blocked (DASH-143 hard cap)",
129
- });
130
- }
131
- else {
132
- const cooldownMs = this.calculateCooldown(failureCount);
133
- const cooldownMin = Math.round(cooldownMs / 60_000);
134
- log.info(`Task ${taskId} failed ${failureCount} time(s), cooldown ${cooldownMin}min`, {
135
- taskId,
136
- failureCount,
137
- cooldownMin,
138
- label,
139
- });
140
- logActivity({
141
- source: "agent",
142
- summary: `Cooldown: ${label ?? taskId} failed ${failureCount}x, backing off ${cooldownMin}min`,
143
- detail: error?.slice(0, 200),
144
- actionLabel: "AUTONOMOUS",
145
- reason: "task cooldown escalation",
146
- });
147
- }
148
- }
149
- /**
150
- * Check if a task is currently on cooldown (or permanently blocked).
151
- *
152
- * DASH-143 fix: cooldown expiration no longer deletes the entry. Failure
153
- * history is preserved so the hard cap (maxTotalFailures) works across
154
- * cooldown cycles. Only clearCooldown() resets failure history.
155
- */
156
- isOnCooldown(taskId) {
157
- const entry = this.entries.get(taskId);
158
- if (!entry)
159
- return false;
160
- // Hard cap: permanently blocked until manual clearCooldown()
161
- if (entry.failureCount >= this.config.maxTotalFailures)
162
- return true;
163
- const cooldownMs = this.calculateCooldown(entry.failureCount);
164
- const elapsed = Date.now() - new Date(entry.lastFailedAt).getTime();
165
- // Cooldown expired — task is retryable, but keep the entry so
166
- // failureCount accumulates across cycles (DASH-143)
167
- if (elapsed >= cooldownMs)
168
- return false;
169
- return true;
170
- }
171
- /**
172
- * Check if a task has been permanently blocked (exceeded maxTotalFailures).
173
- * These tasks will never be retried until manually cleared.
174
- */
175
- isBlocked(taskId) {
176
- const entry = this.entries.get(taskId);
177
- return entry != null && entry.failureCount >= this.config.maxTotalFailures;
178
- }
179
- /**
180
- * Check cooldown and log a skip message if the task is on cooldown.
181
- * Returns true if the task should be skipped.
182
- */
183
- shouldSkip(taskId) {
184
- if (!this.isOnCooldown(taskId))
185
- return false;
186
- recordCooldownSkip();
187
- if (this.isBlocked(taskId)) {
188
- const entry = this.entries.get(taskId);
189
- log.info(`Skipping task ${taskId} — permanently blocked after ${entry?.failureCount} failures (needs manual clear)`, {
190
- taskId,
191
- failureCount: entry?.failureCount,
192
- label: entry?.label,
193
- });
194
- }
195
- else {
196
- const status = this.getStatus(taskId);
197
- if (status) {
198
- const remainMin = Math.round(status.remainingMs / 60_000);
199
- log.info(`Skipping task ${taskId} — on cooldown for ${remainMin} more min (${status.failureCount} failures)`, {
200
- taskId,
201
- remainingMin: remainMin,
202
- failureCount: status.failureCount,
203
- label: status.label,
204
- });
205
- }
206
- }
207
- return true;
208
- }
209
- /** Get detailed status for a single task's cooldown. */
210
- getStatus(taskId) {
211
- const entry = this.entries.get(taskId);
212
- if (!entry)
213
- return null;
214
- // Blocked tasks: report as permanently on cooldown
215
- if (entry.failureCount >= this.config.maxTotalFailures) {
216
- return {
217
- taskId,
218
- label: entry.label,
219
- failureCount: entry.failureCount,
220
- cooldownMs: Infinity,
221
- remainingMs: Infinity,
222
- expiresAt: "blocked",
223
- lastFailedAt: entry.lastFailedAt,
224
- lastError: entry.lastError,
225
- };
226
- }
227
- const cooldownMs = this.calculateCooldown(entry.failureCount);
228
- const elapsed = Date.now() - new Date(entry.lastFailedAt).getTime();
229
- const remainingMs = Math.max(0, cooldownMs - elapsed);
230
- if (remainingMs === 0)
231
- return null;
232
- return {
233
- taskId,
234
- label: entry.label,
235
- failureCount: entry.failureCount,
236
- cooldownMs,
237
- remainingMs,
238
- expiresAt: new Date(new Date(entry.lastFailedAt).getTime() + cooldownMs).toISOString(),
239
- lastFailedAt: entry.lastFailedAt,
240
- lastError: entry.lastError,
241
- };
242
- }
243
- /** Clear cooldown for a specific task (e.g., after manual intervention). */
244
- clearCooldown(taskId) {
245
- if (this.entries.delete(taskId)) {
246
- this.dirty = true;
247
- this.schedulePersist();
248
- log.info(`Cooldown cleared for task ${taskId}`);
249
- }
250
- }
251
- /** Clear all cooldowns. */
252
- clearAll() {
253
- if (this.entries.size > 0) {
254
- this.entries.clear();
255
- this.dirty = true;
256
- this.schedulePersist();
257
- log.info("All cooldowns cleared");
258
- }
259
- }
260
- /**
261
- * Remove expired cooldown entries that are safe to prune.
262
- * Entries at or above the hard failure cap are NEVER pruned — they
263
- * represent permanently blocked tasks that need manual clearCooldown().
264
- * Entries with failure history but expired cooldowns are pruned after
265
- * 24 hours of inactivity (enough time that if the task succeeds on
266
- * the next retry, the entry is no longer needed).
267
- */
268
- pruneExpired() {
269
- const now = Date.now();
270
- const STALE_THRESHOLD_MS = 24 * 60 * 60 * 1000; // 24 hours
271
- let pruned = 0;
272
- for (const [taskId, entry] of this.entries) {
273
- // Never prune permanently blocked entries
274
- if (entry.failureCount >= this.config.maxTotalFailures)
275
- continue;
276
- const cooldownMs = this.calculateCooldown(entry.failureCount);
277
- const elapsed = now - new Date(entry.lastFailedAt).getTime();
278
- // Only prune if cooldown expired AND entry is stale (24h inactive)
279
- if (elapsed >= cooldownMs + STALE_THRESHOLD_MS) {
280
- this.entries.delete(taskId);
281
- pruned++;
282
- }
283
- }
284
- if (pruned > 0) {
285
- this.dirty = true;
286
- this.schedulePersist();
287
- log.info(`Pruned ${pruned} stale cooldown entries`);
288
- }
289
- return pruned;
290
- }
291
- /** List all active cooldowns and blocked tasks with status details. */
292
- listActiveCooldowns() {
293
- this.pruneExpired();
294
- const results = [];
295
- for (const [taskId] of this.entries) {
296
- const status = this.getStatus(taskId);
297
- if (status)
298
- results.push(status);
299
- }
300
- // Blocked tasks (Infinity) sort last, then by remaining time
301
- results.sort((a, b) => {
302
- if (a.remainingMs === Infinity && b.remainingMs === Infinity)
303
- return 0;
304
- if (a.remainingMs === Infinity)
305
- return 1;
306
- if (b.remainingMs === Infinity)
307
- return -1;
308
- return a.remainingMs - b.remainingMs;
309
- });
310
- return results;
311
- }
312
- /** Get summary for planner context (what tasks are on cooldown or blocked). */
313
- getCooldownContext() {
314
- const active = this.listActiveCooldowns();
315
- if (active.length === 0)
316
- return null;
317
- const lines = active.map((s) => {
318
- if (s.expiresAt === "blocked") {
319
- return `- ${s.label ?? s.taskId}: BLOCKED (${s.failureCount} failures, needs human intervention)`;
320
- }
321
- const remainMin = Math.round(s.remainingMs / 60_000);
322
- return `- ${s.label ?? s.taskId}: failed ${s.failureCount}x, ${remainMin}min remaining`;
323
- });
324
- return lines.join("\n");
325
- }
326
- /** Get the failure count for a task (0 if not tracked). */
327
- getFailureCount(taskId) {
328
- return this.entries.get(taskId)?.failureCount ?? 0;
329
- }
330
- /** Get total number of tracked entries (active + expired pending prune). */
331
- get size() {
332
- return this.entries.size;
333
- }
334
- // ── Internals ─────────────────────────────────────────────────────────────
335
- /**
336
- * Calculate exponential backoff cooldown.
337
- * Formula: base × multiplier^(failureCount - 1), capped at max.
338
- *
339
- * Failures → Cooldown (with defaults):
340
- * 1 → 30min
341
- * 2 → 60min
342
- * 3 → 120min
343
- * 4 → 240min (capped at 4hr)
344
- * 5+ → 240min (capped at 4hr)
345
- */
346
- calculateCooldown(failureCount) {
347
- const { baseCooldownMs, maxCooldownMs, backoffMultiplier } = this.config;
348
- return Math.min(baseCooldownMs * Math.pow(backoffMultiplier, Math.max(0, failureCount - 1)), maxCooldownMs);
349
- }
350
- /** Debounced persist — waits 5s after last change before writing to disk. */
351
- schedulePersist() {
352
- if (this.persistTimer)
353
- return;
354
- this.persistTimer = setTimeout(() => {
355
- this.persistTimer = null;
356
- this.persistAsync().catch((err) => {
357
- log.warn(`Failed to persist cooldowns: ${err.message}`);
358
- });
359
- }, 5_000);
360
- }
361
- async persistAsync() {
362
- if (!this.dirty)
363
- return;
364
- // Prune before persisting
365
- this.pruneExpired();
366
- // Enforce max entries: keep the most recent
367
- if (this.entries.size > this.config.maxEntries) {
368
- const sorted = [...this.entries.entries()]
369
- .sort((a, b) => new Date(b[1].lastFailedAt).getTime() - new Date(a[1].lastFailedAt).getTime());
370
- this.entries = new Map(sorted.slice(0, this.config.maxEntries));
371
- }
372
- const data = [...this.entries.values()];
373
- try {
374
- await mkdir(dirname(this.config.persistPath), { recursive: true });
375
- await writeFile(this.config.persistPath, JSON.stringify(data, null, 2), "utf-8");
376
- this.dirty = false;
377
- log.debug(`Persisted ${data.length} cooldown entries to disk`);
378
- }
379
- catch (err) {
380
- log.warn(`Failed to write cooldown file: ${err.message}`);
381
- }
382
- }
383
- /** Synchronous persist for shutdown path (best-effort). */
384
- persistSync() {
385
- try {
386
- const { writeFileSync, mkdirSync } = require("node:fs");
387
- const data = [...this.entries.values()];
388
- mkdirSync(dirname(this.config.persistPath), { recursive: true });
389
- writeFileSync(this.config.persistPath, JSON.stringify(data, null, 2), "utf-8");
390
- this.dirty = false;
391
- }
392
- catch {
393
- // Best effort on shutdown
394
- }
395
- }
396
- }
397
- //# sourceMappingURL=cooldown.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cooldown.js","sourceRoot":"","sources":["../../src/agents/cooldown.ts"],"names":[],"mappings":"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"}
@@ -1,131 +0,0 @@
1
- /**
2
- * Dedup Guard — prevents the autonomous planner from spawning agents
3
- * that duplicate work already in progress or recently completed.
4
- *
5
- * Three checks, cheapest first:
6
- * 1. Active agent with same label (~0ms, in-memory)
7
- * 2. Recent task with same label (~5ms, reads task JSON files)
8
- * 3. Recent git commits touching related files (~50ms, shell out to git)
9
- */
10
- import { activeProcesses } from "./spawn.js";
11
- import { listTasks } from "./store.js";
12
- import { createLogger } from "../utils/logger.js";
13
- import { gitAvailable } from "../utils/git.js";
14
- const log = createLogger("dedup-guard");
15
- // ─── Constants ──────────────────────────────────────────────────────────────
16
- const DEDUP_RECENT_WINDOW_MS = 2 * 60 * 60 * 1000; // 2 hours
17
- /** Shorter window for failed tasks — blocks immediate re-planning while
18
- * cooldown manager handles longer-term backoff (DASH-143). */
19
- const DEDUP_FAILED_WINDOW_MS = 5 * 60 * 1000; // 5 minutes
20
- const GIT_LOOKBACK_MINUTES = 30;
21
- // ─── Helpers ────────────────────────────────────────────────────────────────
22
- /** Normalize a label for fuzzy matching: lowercase, trim whitespace. */
23
- function normalize(label) {
24
- return label.toLowerCase().trim();
25
- }
26
- /** Fuzzy match: either label contains the other (after normalization). */
27
- function fuzzyMatch(a, b) {
28
- const na = normalize(a);
29
- const nb = normalize(b);
30
- return na.includes(nb) || nb.includes(na);
31
- }
32
- /** Extract file paths from a prompt string. */
33
- function extractFilePaths(prompt) {
34
- const regex = /(?:src\/|brain\/|public\/)[^\s"'`,)}\]]+(?:\.ts|\.js|\.md|\.json|\.yaml|\.yml)?/g;
35
- const matches = prompt.match(regex) ?? [];
36
- // Deduplicate
37
- return [...new Set(matches)];
38
- }
39
- // ─── Main ───────────────────────────────────────────────────────────────────
40
- export async function checkDedup(label, prompt) {
41
- // Check 1: Active agent with same label (~0ms)
42
- for (const [, proc] of activeProcesses) {
43
- // activeProcesses is Map<taskId, ChildProcess> — we need labels from tasks
44
- // Skip this map-based check; we'll rely on the task list check below
45
- void proc;
46
- }
47
- // Better: check running tasks via store (covers both pool and direct spawns)
48
- try {
49
- const tasks = await listTasks();
50
- for (const t of tasks) {
51
- if (t.status === "running" && fuzzyMatch(t.label, label)) {
52
- return {
53
- blocked: true,
54
- reason: `Active agent already running: "${t.label}"`,
55
- };
56
- }
57
- }
58
- }
59
- catch (err) {
60
- log.debug(`Check 1 (active agents) failed: ${err instanceof Error ? err.message : String(err)}`);
61
- }
62
- // Check 2: Recent task with same label (~5ms)
63
- try {
64
- const tasks = await listTasks();
65
- const cutoff = Date.now() - DEDUP_RECENT_WINDOW_MS;
66
- const failedCutoff = Date.now() - DEDUP_FAILED_WINDOW_MS;
67
- for (const t of tasks) {
68
- const ts = t.finishedAt || t.createdAt;
69
- if (!ts)
70
- continue;
71
- const taskTime = new Date(ts).getTime();
72
- if (t.status === "running" || t.status === "completed") {
73
- if (taskTime < cutoff)
74
- continue;
75
- if (fuzzyMatch(t.label, label)) {
76
- return {
77
- blocked: true,
78
- reason: `Recent task (${t.status}) with same label: "${t.label}"`,
79
- };
80
- }
81
- }
82
- else if (t.status === "failed") {
83
- // DASH-143: Block re-spawning recently-failed tasks — prevents
84
- // rapid retry loops before cooldown manager kicks in.
85
- if (taskTime < failedCutoff)
86
- continue;
87
- if (fuzzyMatch(t.label, label)) {
88
- return {
89
- blocked: true,
90
- reason: `Recently failed task (cooldown active): "${t.label}"`,
91
- };
92
- }
93
- }
94
- }
95
- }
96
- catch (err) {
97
- log.debug(`Check 2 (recent tasks) failed: ${err instanceof Error ? err.message : String(err)}`);
98
- }
99
- // Check 3: Recent agent git commits touching related files (~50ms)
100
- // Only blocks on commits made by autonomous agents (contains "Auto-committed"
101
- // in the git log). Human/manual commits should not prevent agents from working.
102
- // Git is an optional signal source — skip silently if unavailable.
103
- if (gitAvailable())
104
- try {
105
- const { execSync } = await import("node:child_process");
106
- const paths = extractFilePaths(prompt);
107
- if (paths.length > 0) {
108
- const pathArgs = paths.map((p) => `"${p}"`).join(" ");
109
- const cmd = `git log --oneline --since="${GIT_LOOKBACK_MINUTES} minutes ago" --grep="Auto-committed" -- ${pathArgs}`;
110
- const result = execSync(cmd, {
111
- encoding: "utf-8",
112
- timeout: 5000,
113
- stdio: ["pipe", "pipe", "pipe"],
114
- }).trim();
115
- if (result.length > 0) {
116
- const commitCount = result.split("\n").length;
117
- const firstCommit = result.split("\n")[0];
118
- return {
119
- blocked: true,
120
- reason: `${commitCount} recent agent commit(s) touching related files: ${firstCommit}`,
121
- };
122
- }
123
- }
124
- }
125
- catch {
126
- // Git command failed — fail open (don't block)
127
- log.debug("Check 3 (git commits) failed or no git — skipping");
128
- }
129
- return { blocked: false };
130
- }
131
- //# sourceMappingURL=dedup-guard.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"dedup-guard.js","sourceRoot":"","sources":["../../src/agents/dedup-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,MAAM,GAAG,GAAG,YAAY,CAAC,aAAa,CAAC,CAAC;AAExC,+EAA+E;AAE/E,MAAM,sBAAsB,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAE,UAAU;AAC9D;+DAC+D;AAC/D,MAAM,sBAAsB,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAE,YAAY;AAC3D,MAAM,oBAAoB,GAAG,EAAE,CAAC;AAShC,+EAA+E;AAE/E,wEAAwE;AACxE,SAAS,SAAS,CAAC,KAAa;IAC9B,OAAO,KAAK,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;AACpC,CAAC;AAED,0EAA0E;AAC1E,SAAS,UAAU,CAAC,CAAS,EAAE,CAAS;IACtC,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;IACxB,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;IACxB,OAAO,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AAC5C,CAAC;AAED,+CAA+C;AAC/C,SAAS,gBAAgB,CAAC,MAAc;IACtC,MAAM,KAAK,GAAG,kFAAkF,CAAC;IACjG,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;IAC1C,cAAc;IACd,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;AAC/B,CAAC;AAED,+EAA+E;AAE/E,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,KAAa,EAAE,MAAc;IAC5D,+CAA+C;IAC/C,KAAK,MAAM,CAAC,EAAE,IAAI,CAAC,IAAI,eAAe,EAAE,CAAC;QACvC,2EAA2E;QAC3E,qEAAqE;QACrE,KAAK,IAAI,CAAC;IACZ,CAAC;IACD,6EAA6E;IAC7E,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,SAAS,EAAE,CAAC;QAChC,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;YACtB,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS,IAAI,UAAU,CAAC,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC;gBACzD,OAAO;oBACL,OAAO,EAAE,IAAI;oBACb,MAAM,EAAE,kCAAkC,CAAC,CAAC,KAAK,GAAG;iBACrD,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,GAAG,CAAC,KAAK,CAAC,mCAAmC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACnG,CAAC;IAED,8CAA8C;IAC9C,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,SAAS,EAAE,CAAC;QAChC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,sBAAsB,CAAC;QACnD,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,sBAAsB,CAAC;QACzD,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;YACtB,MAAM,EAAE,GAAG,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,SAAS,CAAC;YACvC,IAAI,CAAC,EAAE;gBAAE,SAAS;YAClB,MAAM,QAAQ,GAAG,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;YAExC,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;gBACvD,IAAI,QAAQ,GAAG,MAAM;oBAAE,SAAS;gBAChC,IAAI,UAAU,CAAC,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC;oBAC/B,OAAO;wBACL,OAAO,EAAE,IAAI;wBACb,MAAM,EAAE,gBAAgB,CAAC,CAAC,MAAM,uBAAuB,CAAC,CAAC,KAAK,GAAG;qBAClE,CAAC;gBACJ,CAAC;YACH,CAAC;iBAAM,IAAI,CAAC,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;gBACjC,+DAA+D;gBAC/D,sDAAsD;gBACtD,IAAI,QAAQ,GAAG,YAAY;oBAAE,SAAS;gBACtC,IAAI,UAAU,CAAC,CAAC,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC;oBAC/B,OAAO;wBACL,OAAO,EAAE,IAAI;wBACb,MAAM,EAAE,4CAA4C,CAAC,CAAC,KAAK,GAAG;qBAC/D,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,GAAG,CAAC,KAAK,CAAC,kCAAkC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAClG,CAAC;IAED,mEAAmE;IACnE,8EAA8E;IAC9E,gFAAgF;IAChF,mEAAmE;IACnE,IAAI,YAAY,EAAE;QAAE,IAAI,CAAC;YACvB,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;YACxD,MAAM,KAAK,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;YACvC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACrB,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBACtD,MAAM,GAAG,GAAG,8BAA8B,oBAAoB,4CAA4C,QAAQ,EAAE,CAAC;gBACrH,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,EAAE;oBAC3B,QAAQ,EAAE,OAAO;oBACjB,OAAO,EAAE,IAAI;oBACb,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;iBAChC,CAAC,CAAC,IAAI,EAAE,CAAC;gBAEV,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACtB,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;oBAC9C,MAAM,WAAW,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;oBAC1C,OAAO;wBACL,OAAO,EAAE,IAAI;wBACb,MAAM,EAAE,GAAG,WAAW,mDAAmD,WAAW,EAAE;qBACvF,CAAC;gBACJ,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,+CAA+C;YAC/C,GAAG,CAAC,KAAK,CAAC,mDAAmD,CAAC,CAAC;QACjE,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAC5B,CAAC"}