@asermax/tachikoma 2.0.0

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 (345) hide show
  1. package/README.md +64 -0
  2. package/dist/agent/adapter.d.ts +8 -0
  3. package/dist/agent/adapter.js +86 -0
  4. package/dist/agent/adapter.js.map +1 -0
  5. package/dist/agent/manager.d.ts +35 -0
  6. package/dist/agent/manager.js +76 -0
  7. package/dist/agent/manager.js.map +1 -0
  8. package/dist/agent/models.d.ts +46 -0
  9. package/dist/agent/models.js +96 -0
  10. package/dist/agent/models.js.map +1 -0
  11. package/dist/agent/side-run.d.ts +42 -0
  12. package/dist/agent/side-run.js +83 -0
  13. package/dist/agent/side-run.js.map +1 -0
  14. package/dist/app.d.ts +5 -0
  15. package/dist/app.js +79 -0
  16. package/dist/app.js.map +1 -0
  17. package/dist/channels/types.d.ts +37 -0
  18. package/dist/channels/types.js +5 -0
  19. package/dist/channels/types.js.map +1 -0
  20. package/dist/config/default-template.d.ts +1 -0
  21. package/dist/config/default-template.js +49 -0
  22. package/dist/config/default-template.js.map +1 -0
  23. package/dist/config/load.d.ts +8 -0
  24. package/dist/config/load.js +28 -0
  25. package/dist/config/load.js.map +1 -0
  26. package/dist/config/parse.d.ts +5 -0
  27. package/dist/config/parse.js +18 -0
  28. package/dist/config/parse.js.map +1 -0
  29. package/dist/config/schema.d.ts +29 -0
  30. package/dist/config/schema.js +35 -0
  31. package/dist/config/schema.js.map +1 -0
  32. package/dist/coordinator.d.ts +54 -0
  33. package/dist/coordinator.js +344 -0
  34. package/dist/coordinator.js.map +1 -0
  35. package/dist/db/core-schema.d.ts +250 -0
  36. package/dist/db/core-schema.js +19 -0
  37. package/dist/db/core-schema.js.map +1 -0
  38. package/dist/db/index.d.ts +8 -0
  39. package/dist/db/index.js +16 -0
  40. package/dist/db/index.js.map +1 -0
  41. package/dist/db/schema.d.ts +4 -0
  42. package/dist/db/schema.js +7 -0
  43. package/dist/db/schema.js.map +1 -0
  44. package/dist/db/state.d.ts +10 -0
  45. package/dist/db/state.js +36 -0
  46. package/dist/db/state.js.map +1 -0
  47. package/dist/domain/agent-events.d.ts +26 -0
  48. package/dist/domain/agent-events.js +2 -0
  49. package/dist/domain/agent-events.js.map +1 -0
  50. package/dist/domain/message.d.ts +25 -0
  51. package/dist/domain/message.js +17 -0
  52. package/dist/domain/message.js.map +1 -0
  53. package/dist/events.d.ts +9 -0
  54. package/dist/events.js +27 -0
  55. package/dist/events.js.map +1 -0
  56. package/dist/extensions/api.d.ts +118 -0
  57. package/dist/extensions/api.js +7 -0
  58. package/dist/extensions/api.js.map +1 -0
  59. package/dist/extensions/boundary/detector.d.ts +20 -0
  60. package/dist/extensions/boundary/detector.js +57 -0
  61. package/dist/extensions/boundary/detector.js.map +1 -0
  62. package/dist/extensions/boundary/idle.d.ts +10 -0
  63. package/dist/extensions/boundary/idle.js +28 -0
  64. package/dist/extensions/boundary/idle.js.map +1 -0
  65. package/dist/extensions/boundary/index.d.ts +12 -0
  66. package/dist/extensions/boundary/index.js +65 -0
  67. package/dist/extensions/boundary/index.js.map +1 -0
  68. package/dist/extensions/boundary/summary.d.ts +5 -0
  69. package/dist/extensions/boundary/summary.js +33 -0
  70. package/dist/extensions/boundary/summary.js.map +1 -0
  71. package/dist/extensions/commands/index.d.ts +7 -0
  72. package/dist/extensions/commands/index.js +21 -0
  73. package/dist/extensions/commands/index.js.map +1 -0
  74. package/dist/extensions/context/index.d.ts +7 -0
  75. package/dist/extensions/context/index.js +65 -0
  76. package/dist/extensions/context/index.js.map +1 -0
  77. package/dist/extensions/context/processor.d.ts +27 -0
  78. package/dist/extensions/context/processor.js +228 -0
  79. package/dist/extensions/context/processor.js.map +1 -0
  80. package/dist/extensions/detached-processes/index.d.ts +12 -0
  81. package/dist/extensions/detached-processes/index.js +51 -0
  82. package/dist/extensions/detached-processes/index.js.map +1 -0
  83. package/dist/extensions/detached-processes/limits.d.ts +27 -0
  84. package/dist/extensions/detached-processes/limits.js +55 -0
  85. package/dist/extensions/detached-processes/limits.js.map +1 -0
  86. package/dist/extensions/detached-processes/output.d.ts +2 -0
  87. package/dist/extensions/detached-processes/output.js +26 -0
  88. package/dist/extensions/detached-processes/output.js.map +1 -0
  89. package/dist/extensions/detached-processes/reconcile.d.ts +31 -0
  90. package/dist/extensions/detached-processes/reconcile.js +71 -0
  91. package/dist/extensions/detached-processes/reconcile.js.map +1 -0
  92. package/dist/extensions/detached-processes/repository.d.ts +33 -0
  93. package/dist/extensions/detached-processes/repository.js +62 -0
  94. package/dist/extensions/detached-processes/repository.js.map +1 -0
  95. package/dist/extensions/detached-processes/schema.d.ts +252 -0
  96. package/dist/extensions/detached-processes/schema.js +23 -0
  97. package/dist/extensions/detached-processes/schema.js.map +1 -0
  98. package/dist/extensions/detached-processes/spawn.d.ts +40 -0
  99. package/dist/extensions/detached-processes/spawn.js +137 -0
  100. package/dist/extensions/detached-processes/spawn.js.map +1 -0
  101. package/dist/extensions/detached-processes/tools.d.ts +41 -0
  102. package/dist/extensions/detached-processes/tools.js +243 -0
  103. package/dist/extensions/detached-processes/tools.js.map +1 -0
  104. package/dist/extensions/detached-processes/watcher.d.ts +7 -0
  105. package/dist/extensions/detached-processes/watcher.js +19 -0
  106. package/dist/extensions/detached-processes/watcher.js.map +1 -0
  107. package/dist/extensions/external/index.d.ts +11 -0
  108. package/dist/extensions/external/index.js +40 -0
  109. package/dist/extensions/external/index.js.map +1 -0
  110. package/dist/extensions/external/installs.d.ts +39 -0
  111. package/dist/extensions/external/installs.js +98 -0
  112. package/dist/extensions/external/installs.js.map +1 -0
  113. package/dist/extensions/external/loader.d.ts +19 -0
  114. package/dist/extensions/external/loader.js +70 -0
  115. package/dist/extensions/external/loader.js.map +1 -0
  116. package/dist/extensions/external/tools.d.ts +17 -0
  117. package/dist/extensions/external/tools.js +112 -0
  118. package/dist/extensions/external/tools.js.map +1 -0
  119. package/dist/extensions/git/commit.d.ts +19 -0
  120. package/dist/extensions/git/commit.js +44 -0
  121. package/dist/extensions/git/commit.js.map +1 -0
  122. package/dist/extensions/git/git.d.ts +11 -0
  123. package/dist/extensions/git/git.js +29 -0
  124. package/dist/extensions/git/git.js.map +1 -0
  125. package/dist/extensions/git/hooks.d.ts +10 -0
  126. package/dist/extensions/git/hooks.js +88 -0
  127. package/dist/extensions/git/hooks.js.map +1 -0
  128. package/dist/extensions/git/index.d.ts +11 -0
  129. package/dist/extensions/git/index.js +28 -0
  130. package/dist/extensions/git/index.js.map +1 -0
  131. package/dist/extensions/git/processor.d.ts +13 -0
  132. package/dist/extensions/git/processor.js +52 -0
  133. package/dist/extensions/git/processor.js.map +1 -0
  134. package/dist/extensions/git/sync.d.ts +44 -0
  135. package/dist/extensions/git/sync.js +189 -0
  136. package/dist/extensions/git/sync.js.map +1 -0
  137. package/dist/extensions/git/tools.d.ts +21 -0
  138. package/dist/extensions/git/tools.js +101 -0
  139. package/dist/extensions/git/tools.js.map +1 -0
  140. package/dist/extensions/host.d.ts +31 -0
  141. package/dist/extensions/host.js +75 -0
  142. package/dist/extensions/host.js.map +1 -0
  143. package/dist/extensions/index.d.ts +3 -0
  144. package/dist/extensions/index.js +32 -0
  145. package/dist/extensions/index.js.map +1 -0
  146. package/dist/extensions/memory/archive.d.ts +8 -0
  147. package/dist/extensions/memory/archive.js +46 -0
  148. package/dist/extensions/memory/archive.js.map +1 -0
  149. package/dist/extensions/memory/dates.d.ts +2 -0
  150. package/dist/extensions/memory/dates.js +7 -0
  151. package/dist/extensions/memory/dates.js.map +1 -0
  152. package/dist/extensions/memory/extraction.d.ts +17 -0
  153. package/dist/extensions/memory/extraction.js +218 -0
  154. package/dist/extensions/memory/extraction.js.map +1 -0
  155. package/dist/extensions/memory/index.d.ts +20 -0
  156. package/dist/extensions/memory/index.js +67 -0
  157. package/dist/extensions/memory/index.js.map +1 -0
  158. package/dist/extensions/memory/indexes.d.ts +14 -0
  159. package/dist/extensions/memory/indexes.js +64 -0
  160. package/dist/extensions/memory/indexes.js.map +1 -0
  161. package/dist/extensions/memory/layout.d.ts +20 -0
  162. package/dist/extensions/memory/layout.js +79 -0
  163. package/dist/extensions/memory/layout.js.map +1 -0
  164. package/dist/extensions/memory/maintenance.d.ts +21 -0
  165. package/dist/extensions/memory/maintenance.js +357 -0
  166. package/dist/extensions/memory/maintenance.js.map +1 -0
  167. package/dist/extensions/memory/prompts.d.ts +8 -0
  168. package/dist/extensions/memory/prompts.js +125 -0
  169. package/dist/extensions/memory/prompts.js.map +1 -0
  170. package/dist/extensions/memory/transcript.d.ts +18 -0
  171. package/dist/extensions/memory/transcript.js +79 -0
  172. package/dist/extensions/memory/transcript.js.map +1 -0
  173. package/dist/extensions/notifications/format.d.ts +5 -0
  174. package/dist/extensions/notifications/format.js +17 -0
  175. package/dist/extensions/notifications/format.js.map +1 -0
  176. package/dist/extensions/notifications/index.d.ts +13 -0
  177. package/dist/extensions/notifications/index.js +29 -0
  178. package/dist/extensions/notifications/index.js.map +1 -0
  179. package/dist/extensions/notifications/payload.d.ts +22 -0
  180. package/dist/extensions/notifications/payload.js +29 -0
  181. package/dist/extensions/notifications/payload.js.map +1 -0
  182. package/dist/extensions/notifications/router.d.ts +29 -0
  183. package/dist/extensions/notifications/router.js +55 -0
  184. package/dist/extensions/notifications/router.js.map +1 -0
  185. package/dist/extensions/notifications/tools.d.ts +12 -0
  186. package/dist/extensions/notifications/tools.js +41 -0
  187. package/dist/extensions/notifications/tools.js.map +1 -0
  188. package/dist/extensions/projects/context-provider.d.ts +9 -0
  189. package/dist/extensions/projects/context-provider.js +37 -0
  190. package/dist/extensions/projects/context-provider.js.map +1 -0
  191. package/dist/extensions/projects/git.d.ts +28 -0
  192. package/dist/extensions/projects/git.js +91 -0
  193. package/dist/extensions/projects/git.js.map +1 -0
  194. package/dist/extensions/projects/hooks.d.ts +7 -0
  195. package/dist/extensions/projects/hooks.js +42 -0
  196. package/dist/extensions/projects/hooks.js.map +1 -0
  197. package/dist/extensions/projects/index.d.ts +11 -0
  198. package/dist/extensions/projects/index.js +30 -0
  199. package/dist/extensions/projects/index.js.map +1 -0
  200. package/dist/extensions/projects/processor.d.ts +13 -0
  201. package/dist/extensions/projects/processor.js +63 -0
  202. package/dist/extensions/projects/processor.js.map +1 -0
  203. package/dist/extensions/projects/tools.d.ts +21 -0
  204. package/dist/extensions/projects/tools.js +118 -0
  205. package/dist/extensions/projects/tools.js.map +1 -0
  206. package/dist/extensions/registrations.d.ts +21 -0
  207. package/dist/extensions/registrations.js +12 -0
  208. package/dist/extensions/registrations.js.map +1 -0
  209. package/dist/extensions/repl/index.d.ts +2 -0
  210. package/dist/extensions/repl/index.js +85 -0
  211. package/dist/extensions/repl/index.js.map +1 -0
  212. package/dist/extensions/skills/agents.d.ts +17 -0
  213. package/dist/extensions/skills/agents.js +77 -0
  214. package/dist/extensions/skills/agents.js.map +1 -0
  215. package/dist/extensions/skills/delegate.d.ts +22 -0
  216. package/dist/extensions/skills/delegate.js +54 -0
  217. package/dist/extensions/skills/delegate.js.map +1 -0
  218. package/dist/extensions/skills/index.d.ts +11 -0
  219. package/dist/extensions/skills/index.js +43 -0
  220. package/dist/extensions/skills/index.js.map +1 -0
  221. package/dist/extensions/skills/reload.d.ts +8 -0
  222. package/dist/extensions/skills/reload.js +38 -0
  223. package/dist/extensions/skills/reload.js.map +1 -0
  224. package/dist/extensions/tasks/executor.d.ts +43 -0
  225. package/dist/extensions/tasks/executor.js +179 -0
  226. package/dist/extensions/tasks/executor.js.map +1 -0
  227. package/dist/extensions/tasks/expiration.d.ts +12 -0
  228. package/dist/extensions/tasks/expiration.js +17 -0
  229. package/dist/extensions/tasks/expiration.js.map +1 -0
  230. package/dist/extensions/tasks/generation.d.ts +14 -0
  231. package/dist/extensions/tasks/generation.js +70 -0
  232. package/dist/extensions/tasks/generation.js.map +1 -0
  233. package/dist/extensions/tasks/index.d.ts +14 -0
  234. package/dist/extensions/tasks/index.js +75 -0
  235. package/dist/extensions/tasks/index.js.map +1 -0
  236. package/dist/extensions/tasks/repository.d.ts +53 -0
  237. package/dist/extensions/tasks/repository.js +147 -0
  238. package/dist/extensions/tasks/repository.js.map +1 -0
  239. package/dist/extensions/tasks/schedule.d.ts +13 -0
  240. package/dist/extensions/tasks/schedule.js +32 -0
  241. package/dist/extensions/tasks/schedule.js.map +1 -0
  242. package/dist/extensions/tasks/schema.d.ts +423 -0
  243. package/dist/extensions/tasks/schema.js +45 -0
  244. package/dist/extensions/tasks/schema.js.map +1 -0
  245. package/dist/extensions/tasks/session-delivery.d.ts +18 -0
  246. package/dist/extensions/tasks/session-delivery.js +39 -0
  247. package/dist/extensions/tasks/session-delivery.js.map +1 -0
  248. package/dist/extensions/tasks/tools.d.ts +38 -0
  249. package/dist/extensions/tasks/tools.js +181 -0
  250. package/dist/extensions/tasks/tools.js.map +1 -0
  251. package/dist/extensions/telegram/buttons.d.ts +14 -0
  252. package/dist/extensions/telegram/buttons.js +49 -0
  253. package/dist/extensions/telegram/buttons.js.map +1 -0
  254. package/dist/extensions/telegram/channel.d.ts +39 -0
  255. package/dist/extensions/telegram/channel.js +201 -0
  256. package/dist/extensions/telegram/channel.js.map +1 -0
  257. package/dist/extensions/telegram/chunking.d.ts +7 -0
  258. package/dist/extensions/telegram/chunking.js +67 -0
  259. package/dist/extensions/telegram/chunking.js.map +1 -0
  260. package/dist/extensions/telegram/inbound.d.ts +7 -0
  261. package/dist/extensions/telegram/inbound.js +29 -0
  262. package/dist/extensions/telegram/inbound.js.map +1 -0
  263. package/dist/extensions/telegram/index.d.ts +13 -0
  264. package/dist/extensions/telegram/index.js +67 -0
  265. package/dist/extensions/telegram/index.js.map +1 -0
  266. package/dist/extensions/telegram/media.d.ts +39 -0
  267. package/dist/extensions/telegram/media.js +223 -0
  268. package/dist/extensions/telegram/media.js.map +1 -0
  269. package/dist/extensions/telegram/mutex.d.ts +9 -0
  270. package/dist/extensions/telegram/mutex.js +14 -0
  271. package/dist/extensions/telegram/mutex.js.map +1 -0
  272. package/dist/extensions/telegram/sending.d.ts +48 -0
  273. package/dist/extensions/telegram/sending.js +119 -0
  274. package/dist/extensions/telegram/sending.js.map +1 -0
  275. package/dist/extensions/telegram/streaming.d.ts +46 -0
  276. package/dist/extensions/telegram/streaming.js +140 -0
  277. package/dist/extensions/telegram/streaming.js.map +1 -0
  278. package/dist/extensions/telegram/tools.d.ts +80 -0
  279. package/dist/extensions/telegram/tools.js +232 -0
  280. package/dist/extensions/telegram/tools.js.map +1 -0
  281. package/dist/extensions/workflows/cleanup.d.ts +10 -0
  282. package/dist/extensions/workflows/cleanup.js +38 -0
  283. package/dist/extensions/workflows/cleanup.js.map +1 -0
  284. package/dist/extensions/workflows/index.d.ts +11 -0
  285. package/dist/extensions/workflows/index.js +42 -0
  286. package/dist/extensions/workflows/index.js.map +1 -0
  287. package/dist/extensions/workflows/loader.d.ts +27 -0
  288. package/dist/extensions/workflows/loader.js +90 -0
  289. package/dist/extensions/workflows/loader.js.map +1 -0
  290. package/dist/extensions/workflows/model.d.ts +19 -0
  291. package/dist/extensions/workflows/model.js +7 -0
  292. package/dist/extensions/workflows/model.js.map +1 -0
  293. package/dist/extensions/workflows/repository.d.ts +24 -0
  294. package/dist/extensions/workflows/repository.js +61 -0
  295. package/dist/extensions/workflows/repository.js.map +1 -0
  296. package/dist/extensions/workflows/schema.d.ts +193 -0
  297. package/dist/extensions/workflows/schema.js +20 -0
  298. package/dist/extensions/workflows/schema.js.map +1 -0
  299. package/dist/extensions/workflows/tools.d.ts +27 -0
  300. package/dist/extensions/workflows/tools.js +285 -0
  301. package/dist/extensions/workflows/tools.js.map +1 -0
  302. package/dist/log.d.ts +8 -0
  303. package/dist/log.js +15 -0
  304. package/dist/log.js.map +1 -0
  305. package/dist/main.d.ts +2 -0
  306. package/dist/main.js +27 -0
  307. package/dist/main.js.map +1 -0
  308. package/dist/migration/ask.d.ts +8 -0
  309. package/dist/migration/ask.js +24 -0
  310. package/dist/migration/ask.js.map +1 -0
  311. package/dist/migration/config.d.ts +10 -0
  312. package/dist/migration/config.js +122 -0
  313. package/dist/migration/config.js.map +1 -0
  314. package/dist/migration/context.d.ts +3 -0
  315. package/dist/migration/context.js +24 -0
  316. package/dist/migration/context.js.map +1 -0
  317. package/dist/migration/database.d.ts +8 -0
  318. package/dist/migration/database.js +51 -0
  319. package/dist/migration/database.js.map +1 -0
  320. package/dist/migration/fs.d.ts +1 -0
  321. package/dist/migration/fs.js +11 -0
  322. package/dist/migration/fs.js.map +1 -0
  323. package/dist/migration/index.d.ts +11 -0
  324. package/dist/migration/index.js +28 -0
  325. package/dist/migration/index.js.map +1 -0
  326. package/dist/migration/skills.d.ts +19 -0
  327. package/dist/migration/skills.js +77 -0
  328. package/dist/migration/skills.js.map +1 -0
  329. package/dist/scheduler.d.ts +17 -0
  330. package/dist/scheduler.js +53 -0
  331. package/dist/scheduler.js.map +1 -0
  332. package/dist/sessions/registry.d.ts +15 -0
  333. package/dist/sessions/registry.js +42 -0
  334. package/dist/sessions/registry.js.map +1 -0
  335. package/dist/workspace.d.ts +13 -0
  336. package/dist/workspace.js +32 -0
  337. package/dist/workspace.js.map +1 -0
  338. package/drizzle/0000_init.sql +19 -0
  339. package/drizzle/0001_extensions.sql +63 -0
  340. package/drizzle/meta/0000_snapshot.json +134 -0
  341. package/drizzle/meta/0001_snapshot.json +526 -0
  342. package/drizzle/meta/_journal.json +20 -0
  343. package/package.json +63 -0
  344. package/skills/skill-authoring/SKILL.md +168 -0
  345. package/skills/workflow-authoring/SKILL.md +251 -0
@@ -0,0 +1,38 @@
1
+ import { Type } from "typebox";
2
+ /**
3
+ * Mid-session resource reload, pi-style: a /reload command (reload must run in
4
+ * command context) plus a tool that queues it, so the agent can refresh skills
5
+ * itself when the user mentions adding or editing one. New sessions always
6
+ * rediscover skills regardless — this covers the live session.
7
+ */
8
+ export const registerReload = (pi) => {
9
+ pi.registerCommand("reload", {
10
+ description: "Reload skills, prompts, and extensions from disk",
11
+ handler: async (_args, ctx) => {
12
+ await ctx.reload();
13
+ },
14
+ });
15
+ pi.registerTool({
16
+ name: "reload_resources",
17
+ label: "Reload Resources",
18
+ description: "Reload skills, prompts, and extensions from disk so additions and edits become available in the current session.",
19
+ parameters: Type.Object({}),
20
+ promptSnippet: "Reload skills/prompts/extensions from disk mid-session",
21
+ promptGuidelines: [
22
+ "Use reload_resources when the user says they added or changed a skill, so it loads without restarting.",
23
+ ],
24
+ async execute() {
25
+ pi.sendUserMessage("/reload", { deliverAs: "followUp" });
26
+ return {
27
+ content: [
28
+ {
29
+ type: "text",
30
+ text: "Queued /reload — resources refresh when the current run finishes.",
31
+ },
32
+ ],
33
+ details: {},
34
+ };
35
+ },
36
+ });
37
+ };
38
+ //# sourceMappingURL=reload.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reload.js","sourceRoot":"","sources":["../../../src/extensions/skills/reload.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE/B;;;;;GAKG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,EAAgB,EAAQ,EAAE;IACvD,EAAE,CAAC,eAAe,CAAC,QAAQ,EAAE;QAC3B,WAAW,EAAE,kDAAkD;QAC/D,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YAC5B,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC;QACrB,CAAC;KACF,CAAC,CAAC;IAEH,EAAE,CAAC,YAAY,CAAC;QACd,IAAI,EAAE,kBAAkB;QACxB,KAAK,EAAE,kBAAkB;QACzB,WAAW,EACT,kHAAkH;QACpH,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3B,aAAa,EAAE,wDAAwD;QACvE,gBAAgB,EAAE;YAChB,wGAAwG;SACzG;QACD,KAAK,CAAC,OAAO;YACX,EAAE,CAAC,eAAe,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC,CAAC;YAEzD,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,mEAAmE;qBAC1E;iBACF;gBACD,OAAO,EAAE,EAAE;aACZ,CAAC;QACJ,CAAC;KACF,CAAC,CAAC;AACL,CAAC,CAAC"}
@@ -0,0 +1,43 @@
1
+ import { type Static, Type } from "typebox";
2
+ import type { SideRunner } from "../../agent/side-run.ts";
3
+ import type { Delivery } from "../../channels/types.ts";
4
+ import type { Logger } from "../../log.ts";
5
+ import type { TaskRepository } from "./repository.ts";
6
+ import type { TaskInstanceRecord } from "./schema.ts";
7
+ export declare const TaskEvaluationSchema: Type.TObject<{
8
+ status: Type.TUnsafe<"error" | "continue" | "complete">;
9
+ reason: Type.TString;
10
+ }>;
11
+ export type TaskEvaluation = Static<typeof TaskEvaluationSchema>;
12
+ export interface TaskNotification {
13
+ source: string;
14
+ instanceId: string;
15
+ status: "completed" | "failed";
16
+ message: string;
17
+ }
18
+ export type BackgroundSide = Pick<SideRunner, "run" | "classify">;
19
+ export interface ExecutorDeps {
20
+ repository: TaskRepository;
21
+ side: BackgroundSide;
22
+ deliver: (delivery: Delivery) => void;
23
+ notify: (notification: TaskNotification) => void;
24
+ maxIterations: number;
25
+ timezone: string | undefined;
26
+ now: () => Date;
27
+ log: Logger;
28
+ }
29
+ export declare const evaluateCompletion: (side: Pick<SideRunner, "classify">, taskPrompt: string, agentResponse: string, log: Logger) => Promise<TaskEvaluation>;
30
+ /** Execute one background instance through the iterative evaluator loop. */
31
+ export declare const executeBackgroundInstance: (deps: ExecutorDeps, instance: TaskInstanceRecord) => Promise<void>;
32
+ /**
33
+ * Tick-driven dispatcher for background instances. In-flight executions are
34
+ * tracked across ticks so a slow run is never dispatched twice.
35
+ */
36
+ export declare class BackgroundRunner {
37
+ private readonly deps;
38
+ private readonly inFlight;
39
+ constructor(deps: ExecutorDeps);
40
+ tick(): void;
41
+ /** Await in-flight executions (tests and shutdown). */
42
+ drain(): Promise<void>;
43
+ }
@@ -0,0 +1,179 @@
1
+ import { StringEnum } from "@earendil-works/pi-ai";
2
+ import { defineTool } from "@earendil-works/pi-coding-agent";
3
+ import { Type } from "typebox";
4
+ export const TaskEvaluationSchema = Type.Object({
5
+ status: StringEnum(["complete", "continue", "error"]),
6
+ reason: Type.String(),
7
+ });
8
+ const BACKGROUND_TOOLS = ["read", "bash", "edit", "write", "grep", "find", "ls"];
9
+ const RESPONSE_EXCERPT_CHARS = 4000;
10
+ const BACKGROUND_SYSTEM_PROMPT = `You are a background task agent. You are executing a scheduled task autonomously. Complete the task described below. Your work will be saved automatically.
11
+
12
+ You are operating without direct user interaction. Work through the task methodically, and when you believe the task is complete, provide a clear summary of what was accomplished. Your final summary is delivered to the user when the task completes — failure notices are sent automatically.`;
13
+ const EVALUATOR_SYSTEM = `You are a task completion evaluator for a background task agent. Your ONLY job is to classify the agent's current workflow state using the ordered rules below.
14
+
15
+ You are a CLASSIFIER, not a reviewer. You MUST NOT:
16
+ - Perform any qualitative analysis of the agent's output (correctness, thoroughness, style, usefulness, depth of investigation)
17
+ - Offer corrective feedback, suggestions, improvements, or opinions about what the agent should have done differently
18
+ - Apply any criteria beyond the rules listed below
19
+
20
+ The "reason" field explains why you chose this classification and must describe observable facts about what the agent said or did — never advice, critique, or evaluation directed at the agent.
21
+
22
+ Classification rules (evaluate in order, use the first match):
23
+
24
+ 1. Blocking error: Did the agent report an unrecoverable error, get stuck in a loop, or fail repeatedly without making progress?
25
+ -> {"status": "error", "reason": "Factual description of the blocking signal the agent reported"}
26
+
27
+ 2. Workflow complete: Did the agent execute the requested actions and announce completion, summarize results, or produce final output? Classify as complete even if the agent mentions optional follow-up actions it could take — completion announcements take precedence over hypothetical next steps.
28
+ -> {"status": "complete", "reason": "Brief factual summary of what the agent reported accomplishing"}
29
+
30
+ 3. Mid-workflow: Is the agent still working — it announced next steps but hasn't executed them yet, or it's partway through a multi-step process?
31
+ -> {"status": "continue", "reason": "What the agent said it would do next but has not yet executed"}`;
32
+ const buildSystemPrompt = (now, timezone) => {
33
+ const formatted = now.toLocaleString("en-US", {
34
+ timeZone: timezone,
35
+ weekday: "long",
36
+ year: "numeric",
37
+ month: "long",
38
+ day: "numeric",
39
+ hour: "2-digit",
40
+ minute: "2-digit",
41
+ second: "2-digit",
42
+ hour12: false,
43
+ });
44
+ const zone = timezone != null ? ` ${timezone}` : "";
45
+ return `Current date and time: ${formatted}${zone}\n\n${BACKGROUND_SYSTEM_PROMPT}`;
46
+ };
47
+ // Side runs are ephemeral (no session continuity), so each continuation
48
+ // carries the task, the previous progress, and the evaluator's observation.
49
+ const buildContinuationPrompt = (taskPrompt, previousResponse, reason) => `You are resuming a background task that is not finished yet.
50
+
51
+ <task>
52
+ ${taskPrompt}
53
+ </task>
54
+
55
+ <previous-progress>
56
+ ${previousResponse.slice(0, RESPONSE_EXCERPT_CHARS)}
57
+ </previous-progress>
58
+
59
+ An evaluator observed: ${reason}
60
+
61
+ Continue working on the task from where you left off.`;
62
+ export const evaluateCompletion = async (side, taskPrompt, agentResponse, log) => {
63
+ try {
64
+ return await side.classify({
65
+ system: EVALUATOR_SYSTEM,
66
+ user: `<task-definition>\n${taskPrompt}\n</task-definition>\n\n<agent-response>\n${agentResponse.slice(0, RESPONSE_EXCERPT_CHARS)}\n</agent-response>`,
67
+ schema: TaskEvaluationSchema,
68
+ });
69
+ }
70
+ catch (error) {
71
+ // The evaluator is best-effort: a failure must never abort the run.
72
+ log.warn({ err: error }, "evaluator failed — continuing");
73
+ return { status: "continue", reason: "Evaluator failed, continuing" };
74
+ }
75
+ };
76
+ /** Execute one background instance through the iterative evaluator loop. */
77
+ export const executeBackgroundInstance = async (deps, instance) => {
78
+ const { repository, side, deliver, notify, maxIterations, timezone, now, log } = deps;
79
+ const definition = instance.definitionId != null ? repository.getDefinition(instance.definitionId) : null;
80
+ const source = definition != null
81
+ ? `Background task: ${definition.name}`
82
+ : `Background task: ${instance.prompt.slice(0, 100)}`;
83
+ const fail = (reason, noticeMessage) => {
84
+ repository.updateInstance(instance.id, {
85
+ status: "failed",
86
+ completedAt: now(),
87
+ result: reason,
88
+ });
89
+ deliver({ text: `❌ ${source} — ${noticeMessage}`, gate: "idle" });
90
+ notify({ source, instanceId: instance.id, status: "failed", message: noticeMessage });
91
+ log.warn({ instanceId: instance.id, reason }, "background task failed");
92
+ };
93
+ repository.updateInstance(instance.id, { status: "running", startedAt: now() });
94
+ log.info({ instanceId: instance.id }, "executing background task instance");
95
+ try {
96
+ const system = buildSystemPrompt(now(), timezone);
97
+ let prompt = instance.prompt;
98
+ const notifyTool = defineTool({
99
+ name: "notify_user",
100
+ label: "Notify User",
101
+ description: "Send the user a notification about something important discovered during this background task.",
102
+ parameters: Type.Object({
103
+ text: Type.String({ description: "Notification text" }),
104
+ severity: StringEnum(["info", "warning", "urgent"], { default: "info" }),
105
+ }),
106
+ execute: async (_id, params) => {
107
+ deliver({
108
+ text: `${params.severity === "urgent" ? "🚨 " : ""}${source}: ${params.text}`,
109
+ gate: params.severity === "urgent" ? "immediate" : "idle",
110
+ priority: params.severity === "urgent" ? 10 : 0,
111
+ });
112
+ return { content: [{ type: "text", text: "Notification queued." }], details: {} };
113
+ },
114
+ });
115
+ for (let iteration = 1; iteration <= maxIterations; iteration += 1) {
116
+ const { text } = await side.run({
117
+ system,
118
+ prompt,
119
+ tools: BACKGROUND_TOOLS,
120
+ customTools: [notifyTool],
121
+ tier: "processor",
122
+ });
123
+ const evaluation = await evaluateCompletion(side, instance.prompt, text, log);
124
+ log.debug({ instanceId: instance.id, iteration, status: evaluation.status }, "evaluator result");
125
+ if (evaluation.status === "complete") {
126
+ repository.updateInstance(instance.id, {
127
+ status: "completed",
128
+ completedAt: now(),
129
+ result: evaluation.reason,
130
+ });
131
+ deliver({ text: `✅ ${source} — completed.\n\n${text}`, gate: "idle" });
132
+ notify({
133
+ source,
134
+ instanceId: instance.id,
135
+ status: "completed",
136
+ message: evaluation.reason,
137
+ });
138
+ log.info({ instanceId: instance.id }, "background task completed");
139
+ return;
140
+ }
141
+ if (evaluation.status === "error") {
142
+ fail(`Agent stuck: ${evaluation.reason}`, `Task failed: ${evaluation.reason}`);
143
+ return;
144
+ }
145
+ prompt = buildContinuationPrompt(instance.prompt, text, evaluation.reason);
146
+ }
147
+ fail(`Max iterations (${maxIterations}) reached without completion`, `Task failed: reached max iterations (${maxIterations})`);
148
+ }
149
+ catch (error) {
150
+ log.error({ instanceId: instance.id, err: error }, "background task errored");
151
+ fail(`Task failed: ${error}`, `Task failed with error: ${error}`);
152
+ }
153
+ };
154
+ /**
155
+ * Tick-driven dispatcher for background instances. In-flight executions are
156
+ * tracked across ticks so a slow run is never dispatched twice.
157
+ */
158
+ export class BackgroundRunner {
159
+ deps;
160
+ inFlight = new Map();
161
+ constructor(deps) {
162
+ this.deps = deps;
163
+ }
164
+ tick() {
165
+ for (const instance of this.deps.repository.getPendingInstances("background")) {
166
+ if (this.inFlight.has(instance.id))
167
+ continue;
168
+ const run = executeBackgroundInstance(this.deps, instance)
169
+ .catch((error) => this.deps.log.error({ instanceId: instance.id, err: error }, "background executor crashed"))
170
+ .finally(() => this.inFlight.delete(instance.id));
171
+ this.inFlight.set(instance.id, run);
172
+ }
173
+ }
174
+ /** Await in-flight executions (tests and shutdown). */
175
+ async drain() {
176
+ await Promise.allSettled(this.inFlight.values());
177
+ }
178
+ }
179
+ //# sourceMappingURL=executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../../src/extensions/tasks/executor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { Logger } from "../../log.ts";
2
+ import type { TaskRepository } from "./repository.ts";
3
+ import type { TaskInstanceRecord } from "./schema.ts";
4
+ export interface ExpirationDeps {
5
+ repository: TaskRepository;
6
+ waitTimeoutSeconds: number;
7
+ now: () => Date;
8
+ log: Logger;
9
+ onExpired?: (instance: TaskInstanceRecord, reason: string) => void;
10
+ }
11
+ /** Fail waiting instances whose last update exceeded the wait timeout. */
12
+ export declare const expireWaitingInstances: ({ repository, waitTimeoutSeconds, now, log, onExpired, }: ExpirationDeps) => void;
@@ -0,0 +1,17 @@
1
+ /** Fail waiting instances whose last update exceeded the wait timeout. */
2
+ export const expireWaitingInstances = ({ repository, waitTimeoutSeconds, now, log, onExpired, }) => {
3
+ const expired = repository.listExpiredWaitingInstances(waitTimeoutSeconds);
4
+ for (const instance of expired) {
5
+ const reason = `Task timed out waiting for user input after ${waitTimeoutSeconds}s`;
6
+ repository.updateInstance(instance.id, {
7
+ status: "failed",
8
+ completedAt: now(),
9
+ result: reason,
10
+ });
11
+ onExpired?.(instance, reason);
12
+ }
13
+ if (expired.length > 0) {
14
+ log.info({ count: expired.length }, "expired waiting instances past timeout");
15
+ }
16
+ };
17
+ //# sourceMappingURL=expiration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expiration.js","sourceRoot":"","sources":["../../../src/extensions/tasks/expiration.ts"],"names":[],"mappings":"AAYA,0EAA0E;AAC1E,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,EACrC,UAAU,EACV,kBAAkB,EAClB,GAAG,EACH,GAAG,EACH,SAAS,GACM,EAAQ,EAAE;IACzB,MAAM,OAAO,GAAG,UAAU,CAAC,2BAA2B,CAAC,kBAAkB,CAAC,CAAC;IAE3E,KAAK,MAAM,QAAQ,IAAI,OAAO,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAG,+CAA+C,kBAAkB,GAAG,CAAC;QAEpF,UAAU,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,EAAE;YACrC,MAAM,EAAE,QAAQ;YAChB,WAAW,EAAE,GAAG,EAAE;YAClB,MAAM,EAAE,MAAM;SACf,CAAC,CAAC;QAEH,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAChC,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE,EAAE,wCAAwC,CAAC,CAAC;IAChF,CAAC;AACH,CAAC,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { Logger } from "../../log.ts";
2
+ import type { TaskRepository } from "./repository.ts";
3
+ export interface GenerationDeps {
4
+ repository: TaskRepository;
5
+ timezone: string | undefined;
6
+ now: () => Date;
7
+ log: Logger;
8
+ }
9
+ /**
10
+ * One generation pass: evaluate every enabled definition against the current
11
+ * time, create pending instances for due schedules, and advance bookkeeping.
12
+ * One-shot definitions are auto-disabled after firing.
13
+ */
14
+ export declare const generateDueInstances: (deps: GenerationDeps) => void;
@@ -0,0 +1,70 @@
1
+ import { nextCronRun } from "./schedule.js";
2
+ const HOUR_MS = 3_600_000;
3
+ /**
4
+ * One generation pass: evaluate every enabled definition against the current
5
+ * time, create pending instances for due schedules, and advance bookkeeping.
6
+ * One-shot definitions are auto-disabled after firing.
7
+ */
8
+ export const generateDueInstances = (deps) => {
9
+ for (const definition of deps.repository.listEnabledDefinitions()) {
10
+ try {
11
+ if (definition.schedule.type === "cron") {
12
+ generateForCron(deps, definition, definition.schedule.expression);
13
+ }
14
+ else {
15
+ generateForOneShot(deps, definition, new Date(definition.schedule.at));
16
+ }
17
+ }
18
+ catch (error) {
19
+ deps.log.error({ definitionId: definition.id, err: error }, "error processing definition");
20
+ }
21
+ }
22
+ };
23
+ const generateForCron = ({ repository, timezone, now, log }, definition, expression) => {
24
+ const current = now();
25
+ // First evaluation looks back to the start of the current hour (minus a second
26
+ // so an exact on-the-hour match still fires); afterwards the last fire anchors.
27
+ const anchor = definition.lastFiredAt ?? new Date(Math.floor(current.getTime() / HOUR_MS) * HOUR_MS - 1000);
28
+ let nextFire = nextCronRun(expression, timezone, anchor);
29
+ // Stale-cron prevention: never fire for occurrences that predate the
30
+ // definition's latest edit — advance past `since` instead.
31
+ if (nextFire != null && nextFire <= definition.since) {
32
+ nextFire = nextCronRun(expression, timezone, definition.since);
33
+ }
34
+ if (nextFire == null || nextFire > current)
35
+ return;
36
+ const duplicate = repository.getActiveInstanceForDefinition(definition.id, nextFire);
37
+ if (duplicate != null) {
38
+ log.debug({ definitionId: definition.id, scheduledFor: nextFire.toISOString() }, "duplicate suppressed — period already covered");
39
+ return;
40
+ }
41
+ const instance = repository.createInstance({
42
+ definitionId: definition.id,
43
+ taskType: definition.taskType,
44
+ prompt: definition.prompt,
45
+ scheduledFor: nextFire,
46
+ });
47
+ // Advance lastFiredAt so the next pass anchors in the future, preventing
48
+ // catch-up duplicates for the same period.
49
+ repository.updateDefinition(definition.id, { lastFiredAt: current });
50
+ log.info({ instanceId: instance.id, name: definition.name, taskType: definition.taskType }, "created task instance");
51
+ };
52
+ const generateForOneShot = ({ repository, now, log }, definition, at) => {
53
+ const current = now();
54
+ if (definition.lastFiredAt != null || at > current)
55
+ return;
56
+ const active = repository.getActiveInstanceForDefinition(definition.id);
57
+ if (active != null) {
58
+ log.debug({ definitionId: definition.id, instanceId: active.id }, "skipping one-shot — already has an active instance");
59
+ return;
60
+ }
61
+ const instance = repository.createInstance({
62
+ definitionId: definition.id,
63
+ taskType: definition.taskType,
64
+ prompt: definition.prompt,
65
+ scheduledFor: at,
66
+ });
67
+ repository.updateDefinition(definition.id, { lastFiredAt: current, enabled: false });
68
+ log.info({ instanceId: instance.id, name: definition.name, taskType: definition.taskType }, "created one-shot instance and auto-disabled its definition");
69
+ };
70
+ //# sourceMappingURL=generation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generation.js","sourceRoot":"","sources":["../../../src/extensions/tasks/generation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ interface TasksConfig {
2
+ timezone?: string;
3
+ sessionTaskMaxHoldSeconds: number;
4
+ backgroundMaxIterations: number;
5
+ waitTimeoutSeconds: number;
6
+ }
7
+ /**
8
+ * Scheduled tasks: cron or one-shot definitions fire as instances that are
9
+ * either delivered into the conversation during idle time (session mode) or
10
+ * executed autonomously through an evaluator loop (background mode). The agent
11
+ * manages definitions through the task tools.
12
+ */
13
+ declare const _default: import("../api.ts").TachikomaExtension<TasksConfig>;
14
+ export default _default;
@@ -0,0 +1,75 @@
1
+ import { Type } from "typebox";
2
+ import { defineExtension } from "../api.js";
3
+ import { BackgroundRunner } from "./executor.js";
4
+ import { expireWaitingInstances } from "./expiration.js";
5
+ import { generateDueInstances } from "./generation.js";
6
+ import { TaskRepository } from "./repository.js";
7
+ import { deliverSessionTasks } from "./session-delivery.js";
8
+ import { createTaskToolsFactory } from "./tools.js";
9
+ const TICK_INTERVAL_SECONDS = 60;
10
+ /**
11
+ * Scheduled tasks: cron or one-shot definitions fire as instances that are
12
+ * either delivered into the conversation during idle time (session mode) or
13
+ * executed autonomously through an evaluator loop (background mode). The agent
14
+ * manages definitions through the task tools.
15
+ */
16
+ export default defineExtension({
17
+ name: "tasks",
18
+ configSchema: Type.Object({
19
+ timezone: Type.Optional(Type.String()),
20
+ sessionTaskMaxHoldSeconds: Type.Number({ default: 900 }),
21
+ backgroundMaxIterations: Type.Number({ default: 10 }),
22
+ waitTimeoutSeconds: Type.Number({ default: 7200 }),
23
+ }),
24
+ setup(app) {
25
+ const repository = new TaskRepository(app.db);
26
+ const timezone = app.extensionConfig.timezone ?? app.config.scheduler.timezone;
27
+ const now = () => new Date();
28
+ app.bootstrap("crash-recovery", () => {
29
+ const count = repository.markRunningAsFailed("system restart");
30
+ if (count > 0) {
31
+ app.log.warn({ count }, "crash recovery: marked running instances as failed");
32
+ }
33
+ });
34
+ const runner = new BackgroundRunner({
35
+ repository,
36
+ side: app.agent.side,
37
+ deliver: (delivery) => app.channels.deliver(delivery),
38
+ // User-facing output goes through deliver(); this signal is for other extensions.
39
+ notify: (notification) => app.events.emit("tasks:instance-finished", notification),
40
+ maxIterations: app.extensionConfig.backgroundMaxIterations,
41
+ timezone,
42
+ now,
43
+ log: app.log,
44
+ });
45
+ app.agent.use(createTaskToolsFactory({ repository, timezone, now }));
46
+ app.scheduler.every("tasks-tick", TICK_INTERVAL_SECONDS, () => {
47
+ generateDueInstances({ repository, timezone, now, log: app.log });
48
+ expireWaitingInstances({
49
+ repository,
50
+ waitTimeoutSeconds: app.extensionConfig.waitTimeoutSeconds,
51
+ now,
52
+ log: app.log,
53
+ onExpired: (instance, reason) => {
54
+ app.channels.deliver({ text: `❌ Background task failed: ${reason}`, gate: "idle" });
55
+ app.events.emit("tasks:instance-finished", {
56
+ source: "Background task",
57
+ instanceId: instance.id,
58
+ status: "failed",
59
+ message: reason,
60
+ });
61
+ },
62
+ });
63
+ deliverSessionTasks({
64
+ repository,
65
+ deliver: (delivery) => app.channels.deliver(delivery),
66
+ maxHoldSeconds: app.extensionConfig.sessionTaskMaxHoldSeconds,
67
+ now,
68
+ log: app.log,
69
+ });
70
+ // Background executions run detached — the runner tracks them across ticks.
71
+ runner.tick();
72
+ });
73
+ },
74
+ });
75
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/extensions/tasks/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ import type { AppDatabase } from "../../db/index.ts";
2
+ import { type StoredSchedule, type TaskDefinitionRecord, type TaskInstanceRecord, type TaskStatus, type TaskType } from "./schema.ts";
3
+ export interface NewTaskDefinition {
4
+ name: string;
5
+ schedule: StoredSchedule;
6
+ taskType: TaskType;
7
+ prompt: string;
8
+ enabled?: boolean;
9
+ }
10
+ export interface NewTaskInstance {
11
+ definitionId: string | null;
12
+ taskType: TaskType;
13
+ prompt: string;
14
+ scheduledFor: Date;
15
+ }
16
+ export type DefinitionPatch = Partial<Omit<TaskDefinitionRecord, "id" | "createdAt">>;
17
+ export type InstancePatch = Partial<Omit<TaskInstanceRecord, "id" | "createdAt">>;
18
+ export interface InstanceQuery {
19
+ status?: TaskStatus;
20
+ taskType?: TaskType;
21
+ definitionId?: string;
22
+ limit?: number;
23
+ }
24
+ export declare class TaskRepository {
25
+ private readonly db;
26
+ private readonly now;
27
+ constructor(db: AppDatabase, now?: () => Date);
28
+ createDefinition(values: NewTaskDefinition): TaskDefinitionRecord;
29
+ getDefinition(id: string): TaskDefinitionRecord | null;
30
+ listEnabledDefinitions(): TaskDefinitionRecord[];
31
+ listDisabledDefinitions(): TaskDefinitionRecord[];
32
+ /** Stamps `since` on every update (overridable) so schedule edits reset the cron anchor. */
33
+ updateDefinition(id: string, patch: DefinitionPatch): TaskDefinitionRecord | null;
34
+ createInstance(values: NewTaskInstance): TaskInstanceRecord;
35
+ getInstance(id: string): TaskInstanceRecord | null;
36
+ getPendingInstances(taskType: TaskType): TaskInstanceRecord[];
37
+ /**
38
+ * Duplicate prevention. With `scheduledFor`, performs a period-aware check
39
+ * (pending/running/waiting/completed instances covering that exact cron match);
40
+ * without it, returns any pending/running/waiting instance for the definition.
41
+ */
42
+ getActiveInstanceForDefinition(definitionId: string, scheduledFor?: Date): TaskInstanceRecord | null;
43
+ /** Waiting instances whose last update is older than `timeoutSeconds`. */
44
+ listExpiredWaitingInstances(timeoutSeconds: number): TaskInstanceRecord[];
45
+ /** Stamps `updatedAt` on every update unless the patch overrides it. */
46
+ updateInstance(id: string, patch: InstancePatch): TaskInstanceRecord | null;
47
+ queryInstances({ status, taskType, definitionId, limit, }: InstanceQuery): TaskInstanceRecord[];
48
+ /**
49
+ * Crash recovery: running instances from a previous process are failed because
50
+ * their executors are gone. Returns the number of instances marked.
51
+ */
52
+ markRunningAsFailed(reason: string): number;
53
+ }