@agimon-ai/doompi-task 0.0.1-alpha.2 → 0.0.1-alpha.21

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 (330) hide show
  1. package/README.md +39 -12
  2. package/dist/adapters/pi/extension.cjs +3 -0
  3. package/dist/adapters/pi/extension.cjs.map +1 -0
  4. package/dist/adapters/pi/extension.d.cts +12 -0
  5. package/dist/adapters/pi/extension.d.cts.map +1 -0
  6. package/dist/adapters/pi/extension.d.mts +12 -0
  7. package/dist/adapters/pi/extension.d.mts.map +1 -0
  8. package/dist/adapters/pi/extension.mjs +3 -0
  9. package/dist/adapters/pi/extension.mjs.map +1 -0
  10. package/dist/adapters/store/paths.cjs +2 -0
  11. package/dist/adapters/store/paths.cjs.map +1 -0
  12. package/dist/adapters/store/paths.d.cts +26 -0
  13. package/dist/adapters/store/paths.d.cts.map +1 -0
  14. package/dist/adapters/store/paths.d.mts +26 -0
  15. package/dist/adapters/store/paths.d.mts.map +1 -0
  16. package/dist/adapters/store/paths.mjs +2 -0
  17. package/dist/adapters/store/paths.mjs.map +1 -0
  18. package/dist/adapters/store/taskStore.cjs +2 -0
  19. package/dist/adapters/store/taskStore.cjs.map +1 -0
  20. package/dist/adapters/store/taskStore.d.cts +87 -0
  21. package/dist/adapters/store/taskStore.d.cts.map +1 -0
  22. package/dist/adapters/store/taskStore.d.mts +87 -0
  23. package/dist/adapters/store/taskStore.d.mts.map +1 -0
  24. package/dist/adapters/store/taskStore.mjs +2 -0
  25. package/dist/adapters/store/taskStore.mjs.map +1 -0
  26. package/dist/adapters/telemetry/logSinkTelemetry.cjs +2 -0
  27. package/dist/adapters/telemetry/logSinkTelemetry.cjs.map +1 -0
  28. package/dist/adapters/telemetry/logSinkTelemetry.d.cts +52 -0
  29. package/dist/adapters/telemetry/logSinkTelemetry.d.cts.map +1 -0
  30. package/dist/adapters/telemetry/logSinkTelemetry.d.mts +52 -0
  31. package/dist/adapters/telemetry/logSinkTelemetry.d.mts.map +1 -0
  32. package/dist/adapters/telemetry/logSinkTelemetry.mjs +2 -0
  33. package/dist/adapters/telemetry/logSinkTelemetry.mjs.map +1 -0
  34. package/dist/commands/index.cjs +2 -0
  35. package/dist/commands/index.cjs.map +1 -0
  36. package/dist/commands/index.d.cts +15 -0
  37. package/dist/commands/index.d.cts.map +1 -0
  38. package/dist/commands/index.d.mts +15 -0
  39. package/dist/commands/index.d.mts.map +1 -0
  40. package/dist/commands/index.mjs +2 -0
  41. package/dist/commands/index.mjs.map +1 -0
  42. package/dist/commands/task/promptGuidelines.cjs +2 -0
  43. package/dist/commands/task/promptGuidelines.cjs.map +1 -0
  44. package/dist/commands/task/promptGuidelines.d.cts +5 -0
  45. package/dist/commands/task/promptGuidelines.d.cts.map +1 -0
  46. package/dist/commands/task/promptGuidelines.d.mts +5 -0
  47. package/dist/commands/task/promptGuidelines.d.mts.map +1 -0
  48. package/dist/commands/task/promptGuidelines.mjs +2 -0
  49. package/dist/commands/task/promptGuidelines.mjs.map +1 -0
  50. package/dist/commands/task/responseEnvelope.cjs +7 -0
  51. package/dist/commands/task/responseEnvelope.cjs.map +1 -0
  52. package/dist/commands/task/responseEnvelope.d.cts +51 -0
  53. package/dist/commands/task/responseEnvelope.d.cts.map +1 -0
  54. package/dist/commands/task/responseEnvelope.d.mts +51 -0
  55. package/dist/commands/task/responseEnvelope.d.mts.map +1 -0
  56. package/dist/commands/task/responseEnvelope.mjs +7 -0
  57. package/dist/commands/task/responseEnvelope.mjs.map +1 -0
  58. package/dist/commands/task/taskTool.cjs +3 -0
  59. package/dist/commands/task/taskTool.cjs.map +1 -0
  60. package/dist/commands/task/taskTool.d.cts +19 -0
  61. package/dist/commands/task/taskTool.d.cts.map +1 -0
  62. package/dist/commands/task/taskTool.d.mts +19 -0
  63. package/dist/commands/task/taskTool.d.mts.map +1 -0
  64. package/dist/commands/task/taskTool.mjs +3 -0
  65. package/dist/commands/task/taskTool.mjs.map +1 -0
  66. package/dist/commands.cjs +1 -2
  67. package/dist/commands.d.cts +2 -14
  68. package/dist/commands.d.mts +2 -14
  69. package/dist/commands.mjs +1 -2
  70. package/dist/config.cjs +1 -2
  71. package/dist/config.d.cts +2 -38
  72. package/dist/config.d.mts +2 -38
  73. package/dist/config.mjs +1 -2
  74. package/dist/delegation/manager.cjs +1 -6
  75. package/dist/delegation/manager.d.cts +2 -189
  76. package/dist/delegation/manager.d.mts +2 -189
  77. package/dist/delegation/manager.mjs +1 -6
  78. package/dist/extension.cjs +1 -3
  79. package/dist/extension.d.cts +2 -12
  80. package/dist/extension.d.mts +2 -12
  81. package/dist/extension.mjs +1 -3
  82. package/dist/extensions/doom.cjs +1 -1
  83. package/dist/extensions/doom.cjs.map +1 -1
  84. package/dist/extensions/doom.mjs +1 -1
  85. package/dist/extensions/doom.mjs.map +1 -1
  86. package/dist/extensions/pi.cjs +1 -1
  87. package/dist/extensions/pi.cjs.map +1 -1
  88. package/dist/extensions/pi.d.cts +1 -1
  89. package/dist/extensions/pi.d.mts +1 -1
  90. package/dist/extensions/pi.mjs +1 -1
  91. package/dist/extensions/pi.mjs.map +1 -1
  92. package/dist/index.cjs +1 -1
  93. package/dist/index.d.cts +15 -14
  94. package/dist/index.d.mts +15 -14
  95. package/dist/index.mjs +1 -1
  96. package/dist/logSinkTelemetry.cjs +1 -2
  97. package/dist/logSinkTelemetry.d.cts +2 -51
  98. package/dist/logSinkTelemetry.d.mts +2 -51
  99. package/dist/logSinkTelemetry.mjs +1 -2
  100. package/dist/schemas/task.cjs +2 -0
  101. package/dist/schemas/task.cjs.map +1 -0
  102. package/dist/schemas/task.d.cts +103 -0
  103. package/dist/schemas/task.d.cts.map +1 -0
  104. package/dist/schemas/task.d.mts +103 -0
  105. package/dist/schemas/task.d.mts.map +1 -0
  106. package/dist/schemas/task.mjs +2 -0
  107. package/dist/schemas/task.mjs.map +1 -0
  108. package/dist/services/delegation/manager.cjs +6 -0
  109. package/dist/services/delegation/manager.cjs.map +1 -0
  110. package/dist/services/delegation/manager.d.cts +188 -0
  111. package/dist/services/delegation/manager.d.cts.map +1 -0
  112. package/dist/services/delegation/manager.d.mts +188 -0
  113. package/dist/services/delegation/manager.d.mts.map +1 -0
  114. package/dist/services/delegation/manager.mjs +6 -0
  115. package/dist/services/delegation/manager.mjs.map +1 -0
  116. package/dist/services/narration/taskNarration.cjs +2 -0
  117. package/dist/services/narration/taskNarration.cjs.map +1 -0
  118. package/dist/services/narration/taskNarration.mjs +2 -0
  119. package/dist/services/narration/taskNarration.mjs.map +1 -0
  120. package/dist/services/store/invariants.cjs +2 -0
  121. package/dist/services/store/invariants.cjs.map +1 -0
  122. package/dist/services/store/invariants.d.cts +14 -0
  123. package/dist/services/store/invariants.d.cts.map +1 -0
  124. package/dist/services/store/invariants.d.mts +14 -0
  125. package/dist/services/store/invariants.d.mts.map +1 -0
  126. package/dist/services/store/invariants.mjs +2 -0
  127. package/dist/services/store/invariants.mjs.map +1 -0
  128. package/dist/services/store/paths.cjs +1 -0
  129. package/dist/services/store/paths.mjs +1 -0
  130. package/dist/services/store/processLiveness.cjs +2 -0
  131. package/dist/services/store/processLiveness.cjs.map +1 -0
  132. package/dist/services/store/processLiveness.d.cts +12 -0
  133. package/dist/services/store/processLiveness.d.cts.map +1 -0
  134. package/dist/services/store/processLiveness.d.mts +12 -0
  135. package/dist/services/store/processLiveness.d.mts.map +1 -0
  136. package/dist/services/store/processLiveness.mjs +2 -0
  137. package/dist/services/store/processLiveness.mjs.map +1 -0
  138. package/dist/services/store/reconcile.cjs +2 -0
  139. package/dist/services/store/reconcile.cjs.map +1 -0
  140. package/dist/services/store/reconcile.d.cts +34 -0
  141. package/dist/services/store/reconcile.d.cts.map +1 -0
  142. package/dist/services/store/reconcile.d.mts +34 -0
  143. package/dist/services/store/reconcile.d.mts.map +1 -0
  144. package/dist/services/store/reconcile.mjs +2 -0
  145. package/dist/services/store/reconcile.mjs.map +1 -0
  146. package/dist/services/store/reducer.cjs +3 -0
  147. package/dist/services/store/reducer.cjs.map +1 -0
  148. package/dist/services/store/reducer.d.cts +72 -0
  149. package/dist/services/store/reducer.d.cts.map +1 -0
  150. package/dist/services/store/reducer.d.mts +72 -0
  151. package/dist/services/store/reducer.d.mts.map +1 -0
  152. package/dist/services/store/reducer.mjs +3 -0
  153. package/dist/services/store/reducer.mjs.map +1 -0
  154. package/dist/services/store/taskGraph.cjs +2 -0
  155. package/dist/services/store/taskGraph.cjs.map +1 -0
  156. package/dist/services/store/taskGraph.d.cts +25 -0
  157. package/dist/services/store/taskGraph.d.cts.map +1 -0
  158. package/dist/services/store/taskGraph.d.mts +25 -0
  159. package/dist/services/store/taskGraph.d.mts.map +1 -0
  160. package/dist/services/store/taskGraph.mjs +2 -0
  161. package/dist/services/store/taskGraph.mjs.map +1 -0
  162. package/dist/services/store/taskStore.cjs +1 -0
  163. package/dist/services/store/taskStore.d.cts +2 -0
  164. package/dist/services/store/taskStore.d.mts +2 -0
  165. package/dist/services/store/taskStore.mjs +1 -0
  166. package/dist/services/store/types.cjs +2 -0
  167. package/dist/services/store/types.cjs.map +1 -0
  168. package/dist/services/store/types.d.cts +177 -0
  169. package/dist/services/store/types.d.cts.map +1 -0
  170. package/dist/services/store/types.d.mts +177 -0
  171. package/dist/services/store/types.d.mts.map +1 -0
  172. package/dist/services/store/types.mjs +2 -0
  173. package/dist/services/store/types.mjs.map +1 -0
  174. package/dist/store/invariants.cjs +1 -2
  175. package/dist/store/invariants.d.cts +2 -14
  176. package/dist/store/invariants.d.mts +2 -14
  177. package/dist/store/invariants.mjs +1 -2
  178. package/dist/store/paths.cjs +1 -2
  179. package/dist/store/paths.d.cts +2 -23
  180. package/dist/store/paths.d.mts +2 -23
  181. package/dist/store/paths.mjs +1 -2
  182. package/dist/store/processLiveness.cjs +1 -2
  183. package/dist/store/processLiveness.d.cts +2 -12
  184. package/dist/store/processLiveness.d.mts +2 -12
  185. package/dist/store/processLiveness.mjs +1 -2
  186. package/dist/store/reconcile.cjs +1 -2
  187. package/dist/store/reconcile.d.cts +2 -34
  188. package/dist/store/reconcile.d.mts +2 -34
  189. package/dist/store/reconcile.mjs +1 -2
  190. package/dist/store/reducer.cjs +1 -3
  191. package/dist/store/reducer.d.cts +2 -72
  192. package/dist/store/reducer.d.mts +2 -72
  193. package/dist/store/reducer.mjs +1 -3
  194. package/dist/store/taskGraph.cjs +1 -2
  195. package/dist/store/taskGraph.d.cts +2 -25
  196. package/dist/store/taskGraph.d.mts +2 -25
  197. package/dist/store/taskGraph.mjs +1 -2
  198. package/dist/store/taskStore.cjs +1 -2
  199. package/dist/store/taskStore.d.cts +3 -77
  200. package/dist/store/taskStore.d.mts +3 -77
  201. package/dist/store/taskStore.mjs +1 -2
  202. package/dist/store/types.cjs +1 -2
  203. package/dist/store/types.d.cts +2 -165
  204. package/dist/store/types.d.mts +2 -165
  205. package/dist/store/types.mjs +1 -2
  206. package/dist/tool/promptGuidelines.cjs +1 -2
  207. package/dist/tool/promptGuidelines.d.cts +2 -5
  208. package/dist/tool/promptGuidelines.d.mts +2 -5
  209. package/dist/tool/promptGuidelines.mjs +1 -2
  210. package/dist/tool/responseEnvelope.cjs +1 -6
  211. package/dist/tool/responseEnvelope.d.cts +2 -39
  212. package/dist/tool/responseEnvelope.d.mts +2 -39
  213. package/dist/tool/responseEnvelope.mjs +1 -6
  214. package/dist/tool/schema.cjs +1 -2
  215. package/dist/tool/schema.d.cts +2 -86
  216. package/dist/tool/schema.d.mts +2 -86
  217. package/dist/tool/schema.mjs +1 -2
  218. package/dist/tool/taskTool.cjs +1 -3
  219. package/dist/tool/taskTool.d.cts +3 -17
  220. package/dist/tool/taskTool.d.mts +3 -17
  221. package/dist/tool/taskTool.mjs +1 -3
  222. package/dist/tui/format.cjs +3 -3
  223. package/dist/tui/format.cjs.map +1 -1
  224. package/dist/tui/format.d.cts +5 -5
  225. package/dist/tui/format.d.cts.map +1 -1
  226. package/dist/tui/format.d.mts +5 -5
  227. package/dist/tui/format.d.mts.map +1 -1
  228. package/dist/tui/format.mjs +3 -3
  229. package/dist/tui/format.mjs.map +1 -1
  230. package/dist/tui/selectors.cjs +1 -1
  231. package/dist/tui/selectors.cjs.map +1 -1
  232. package/dist/tui/selectors.d.cts +8 -1
  233. package/dist/tui/selectors.d.cts.map +1 -1
  234. package/dist/tui/selectors.d.mts +8 -1
  235. package/dist/tui/selectors.d.mts.map +1 -1
  236. package/dist/tui/selectors.mjs +1 -1
  237. package/dist/tui/selectors.mjs.map +1 -1
  238. package/dist/tui/taskOverlay.cjs +1 -1
  239. package/dist/tui/taskOverlay.cjs.map +1 -1
  240. package/dist/tui/taskOverlay.d.cts +2 -2
  241. package/dist/tui/taskOverlay.d.cts.map +1 -1
  242. package/dist/tui/taskOverlay.d.mts +2 -2
  243. package/dist/tui/taskOverlay.d.mts.map +1 -1
  244. package/dist/tui/taskOverlay.mjs +1 -1
  245. package/dist/tui/taskOverlay.mjs.map +1 -1
  246. package/dist/tui/taskSpace.cjs +3 -3
  247. package/dist/tui/taskSpace.cjs.map +1 -1
  248. package/dist/tui/taskSpace.d.cts +2 -1
  249. package/dist/tui/taskSpace.d.cts.map +1 -1
  250. package/dist/tui/taskSpace.d.mts +2 -1
  251. package/dist/tui/taskSpace.d.mts.map +1 -1
  252. package/dist/tui/taskSpace.mjs +3 -3
  253. package/dist/tui/taskSpace.mjs.map +1 -1
  254. package/dist/types/config.cjs +2 -0
  255. package/dist/types/config.cjs.map +1 -0
  256. package/dist/types/config.d.cts +43 -0
  257. package/dist/types/config.d.cts.map +1 -0
  258. package/dist/types/config.d.mts +43 -0
  259. package/dist/types/config.d.mts.map +1 -0
  260. package/dist/types/config.mjs +2 -0
  261. package/dist/types/config.mjs.map +1 -0
  262. package/package.json +16 -9
  263. package/dist/commands.cjs.map +0 -1
  264. package/dist/commands.d.cts.map +0 -1
  265. package/dist/commands.d.mts.map +0 -1
  266. package/dist/commands.mjs.map +0 -1
  267. package/dist/config.cjs.map +0 -1
  268. package/dist/config.d.cts.map +0 -1
  269. package/dist/config.d.mts.map +0 -1
  270. package/dist/config.mjs.map +0 -1
  271. package/dist/delegation/manager.cjs.map +0 -1
  272. package/dist/delegation/manager.d.cts.map +0 -1
  273. package/dist/delegation/manager.d.mts.map +0 -1
  274. package/dist/delegation/manager.mjs.map +0 -1
  275. package/dist/extension.cjs.map +0 -1
  276. package/dist/extension.d.cts.map +0 -1
  277. package/dist/extension.d.mts.map +0 -1
  278. package/dist/extension.mjs.map +0 -1
  279. package/dist/logSinkTelemetry.cjs.map +0 -1
  280. package/dist/logSinkTelemetry.d.cts.map +0 -1
  281. package/dist/logSinkTelemetry.d.mts.map +0 -1
  282. package/dist/logSinkTelemetry.mjs.map +0 -1
  283. package/dist/store/invariants.cjs.map +0 -1
  284. package/dist/store/invariants.d.cts.map +0 -1
  285. package/dist/store/invariants.d.mts.map +0 -1
  286. package/dist/store/invariants.mjs.map +0 -1
  287. package/dist/store/paths.cjs.map +0 -1
  288. package/dist/store/paths.d.cts.map +0 -1
  289. package/dist/store/paths.d.mts.map +0 -1
  290. package/dist/store/paths.mjs.map +0 -1
  291. package/dist/store/processLiveness.cjs.map +0 -1
  292. package/dist/store/processLiveness.d.cts.map +0 -1
  293. package/dist/store/processLiveness.d.mts.map +0 -1
  294. package/dist/store/processLiveness.mjs.map +0 -1
  295. package/dist/store/reconcile.cjs.map +0 -1
  296. package/dist/store/reconcile.d.cts.map +0 -1
  297. package/dist/store/reconcile.d.mts.map +0 -1
  298. package/dist/store/reconcile.mjs.map +0 -1
  299. package/dist/store/reducer.cjs.map +0 -1
  300. package/dist/store/reducer.d.cts.map +0 -1
  301. package/dist/store/reducer.d.mts.map +0 -1
  302. package/dist/store/reducer.mjs.map +0 -1
  303. package/dist/store/taskGraph.cjs.map +0 -1
  304. package/dist/store/taskGraph.d.cts.map +0 -1
  305. package/dist/store/taskGraph.d.mts.map +0 -1
  306. package/dist/store/taskGraph.mjs.map +0 -1
  307. package/dist/store/taskStore.cjs.map +0 -1
  308. package/dist/store/taskStore.d.cts.map +0 -1
  309. package/dist/store/taskStore.d.mts.map +0 -1
  310. package/dist/store/taskStore.mjs.map +0 -1
  311. package/dist/store/types.cjs.map +0 -1
  312. package/dist/store/types.d.cts.map +0 -1
  313. package/dist/store/types.d.mts.map +0 -1
  314. package/dist/store/types.mjs.map +0 -1
  315. package/dist/tool/promptGuidelines.cjs.map +0 -1
  316. package/dist/tool/promptGuidelines.d.cts.map +0 -1
  317. package/dist/tool/promptGuidelines.d.mts.map +0 -1
  318. package/dist/tool/promptGuidelines.mjs.map +0 -1
  319. package/dist/tool/responseEnvelope.cjs.map +0 -1
  320. package/dist/tool/responseEnvelope.d.cts.map +0 -1
  321. package/dist/tool/responseEnvelope.d.mts.map +0 -1
  322. package/dist/tool/responseEnvelope.mjs.map +0 -1
  323. package/dist/tool/schema.cjs.map +0 -1
  324. package/dist/tool/schema.d.cts.map +0 -1
  325. package/dist/tool/schema.d.mts.map +0 -1
  326. package/dist/tool/schema.mjs.map +0 -1
  327. package/dist/tool/taskTool.cjs.map +0 -1
  328. package/dist/tool/taskTool.d.cts.map +0 -1
  329. package/dist/tool/taskTool.d.mts.map +0 -1
  330. package/dist/tool/taskTool.mjs.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"taskStore.mjs","names":[],"sources":["../../src/store/taskStore.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { TASK_EVENT, type TaskFailureReporter } from '../logSinkTelemetry.ts';\nimport { lockPathFor, resolveStorePath, STORE_PATH_ENV, tempPathFor } from './paths.ts';\nimport { isProcessAlive } from './processLiveness.ts';\nimport { emptyDocument, STORE_SCHEMA_VERSION, type Task, type TaskDocument } from './types.ts';\n\nconst LOCK_TIMEOUT_MS = 2000;\nconst LOCK_STALE_MS = 10_000;\nconst LOCK_RETRY_BASE_MS = 10;\nconst LOCK_RETRY_MAX_MS = 60;\nconst WATCH_DEBOUNCE_MS = 150;\nconst POLL_INTERVAL_MS = 2000;\nconst UTF8_ENCODING = 'utf8';\nconst MISSING_FILE_CODE = 'ENOENT';\nconst LOCK_EXISTS_CODE = 'EEXIST';\nconst STORE_PATH_ATTRIBUTE = 'store.path';\n\nexport interface TaskStoreOptions {\n cwd?: string;\n env?: NodeJS.ProcessEnv;\n storePath?: string;\n /** Backstop poll cadence for change detection. Lowered in tests so they do\n * not depend on `fs.watch`, whose delivery timing is platform-dependent. */\n pollIntervalMs?: number;\n /** How long to wait for the advisory lock before proceeding lock-free. */\n lockTimeoutMs?: number;\n /** Where swallowed failures go, so silent degradation stays visible. */\n report?: TaskFailureReporter;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Coerce arbitrary parsed JSON into a valid document.\n *\n * A corrupt or truncated store must not take the session down: the worst\n * acceptable outcome is starting from an empty list, never a crash on startup.\n */\nfunction normalizeDocument(parsed: unknown): TaskDocument {\n if (!parsed || typeof parsed !== 'object') return emptyDocument();\n const candidate = parsed as Partial<TaskDocument>;\n if (!Array.isArray(candidate.tasks)) return emptyDocument();\n\n const tasks = candidate.tasks.filter(\n (task): task is Task => Boolean(task) && typeof task === 'object' && typeof (task as Task).id === 'number',\n );\n const maxId = tasks.reduce((max, task) => Math.max(max, task.id), 0);\n return {\n version: typeof candidate.version === 'number' ? candidate.version : STORE_SCHEMA_VERSION,\n rev: typeof candidate.rev === 'number' ? candidate.rev : 0,\n nextId: typeof candidate.nextId === 'number' && candidate.nextId > maxId ? candidate.nextId : maxId + 1,\n tasks,\n };\n}\n\n/**\n * File-backed task store shared by one root session and its delegated children.\n *\n * Durability model: the JSON file is the source of truth. Mutations are\n * read-modify-write under an advisory lock so concurrent delegated processes\n * cannot clobber each other, and writes land via temp-file rename so a\n * crash mid-write can never leave a partial document behind.\n */\nexport class TaskStore {\n storePath: string;\n\n private readonly cwd: string;\n private readonly env: NodeJS.ProcessEnv;\n private cached: TaskDocument = emptyDocument();\n private lastKnownRev = -1;\n private watcher?: fs.FSWatcher;\n private pollTimer?: NodeJS.Timeout;\n private debounceTimer?: NodeJS.Timeout;\n private readonly listeners = new Set<(document: TaskDocument) => void>();\n private readonly pollIntervalMs: number;\n private readonly lockTimeoutMs: number;\n private readonly report?: TaskFailureReporter;\n\n constructor(options: TaskStoreOptions = {}) {\n this.cwd = options.cwd ?? process.cwd();\n this.env = options.env ?? process.env;\n this.storePath = options.storePath ?? resolveStorePath(this.cwd, this.env);\n this.pollIntervalMs = options.pollIntervalMs ?? POLL_INTERVAL_MS;\n this.lockTimeoutMs = options.lockTimeoutMs ?? LOCK_TIMEOUT_MS;\n this.report = options.report;\n }\n\n /** Bind a default store to the current session tree before reading or watching it. */\n configureSession(sessionKey: string): void {\n if (this.env[STORE_PATH_ENV]?.trim()) return;\n this.stopWatching();\n this.storePath = resolveStorePath(this.cwd, this.env, sessionKey);\n this.cached = emptyDocument();\n this.lastKnownRev = -1;\n }\n\n /** Last document read from disk, without hitting the filesystem. */\n get snapshot(): TaskDocument {\n return this.cached;\n }\n\n read(): TaskDocument {\n try {\n const raw = fs.readFileSync(this.storePath, UTF8_ENCODING);\n this.cached = normalizeDocument(JSON.parse(raw));\n } catch (error) {\n // A missing file is the normal state before the first write. Anything\n // else means the task list just silently became empty, which is worth a\n // record: unreadable or corrupt JSON looks identical to \"no tasks yet\".\n if ((error as NodeJS.ErrnoException).code !== MISSING_FILE_CODE) {\n this.report?.error(TASK_EVENT.storeReadFailed, error, { [STORE_PATH_ATTRIBUTE]: this.storePath });\n }\n this.cached = emptyDocument();\n }\n this.lastKnownRev = this.cached.rev;\n return this.cached;\n }\n\n /**\n * Apply a mutation under the store lock.\n *\n * `mutate` receives the freshest on-disk document and returns either the next\n * document to commit or `undefined` for a read-only action (list/get), which\n * skips the write entirely so queries never bump `rev`.\n */\n async mutate<T>(\n mutate: (document: TaskDocument) => { document?: TaskDocument; value: T },\n ): Promise<{ document: TaskDocument; value: T }> {\n const release = await this.acquireLock();\n try {\n const current = this.read();\n const outcome = mutate(current);\n if (!outcome.document) {\n return { document: current, value: outcome.value };\n }\n const committed = this.write(outcome.document);\n return { document: committed, value: outcome.value };\n } finally {\n release();\n }\n }\n\n private write(document: TaskDocument): TaskDocument {\n const next: TaskDocument = { ...document, version: STORE_SCHEMA_VERSION, rev: document.rev + 1 };\n fs.mkdirSync(path.dirname(this.storePath), { recursive: true });\n const temp = tempPathFor(this.storePath);\n fs.writeFileSync(temp, `${JSON.stringify(next, undefined, 2)}\\n`, UTF8_ENCODING);\n fs.renameSync(temp, this.storePath);\n this.cached = next;\n this.lastKnownRev = next.rev;\n return next;\n }\n\n private async acquireLock(): Promise<() => void> {\n const lockPath = lockPathFor(this.storePath);\n fs.mkdirSync(path.dirname(this.storePath), { recursive: true });\n const deadline = Date.now() + this.lockTimeoutMs;\n\n for (;;) {\n try {\n const handle = fs.openSync(lockPath, 'wx');\n fs.writeSync(handle, JSON.stringify({ pid: process.pid, time: Date.now() }));\n fs.closeSync(handle);\n return () => fs.rmSync(lockPath, { force: true });\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== LOCK_EXISTS_CODE) throw error;\n // The deadline is checked before breaking a stale lock so a peer that\n // keeps recreating one cannot spin this loop without bound.\n if (Date.now() >= deadline) {\n // Proceeding lock-free beats stalling the agent: the rename is atomic,\n // so the worst case is a lost concurrent update, not a corrupt file.\n // Reported because a lost update here can strand a delegation.\n this.report?.warn(\n TASK_EVENT.storeLockTimeout,\n new Error(`Task store lock still held after ${this.lockTimeoutMs}ms; proceeding without it`),\n { [STORE_PATH_ATTRIBUTE]: this.storePath },\n );\n return () => {};\n }\n // Clearing a dead holder's lock still goes through the backoff. Yielding\n // on every iteration is what stops a peer that keeps recreating the\n // lock from turning this into a spin.\n this.breakStaleLock(lockPath);\n await sleep(LOCK_RETRY_BASE_MS + Math.random() * LOCK_RETRY_MAX_MS);\n }\n }\n }\n\n /** Remove a lock left behind by a dead process or one held implausibly long. */\n private breakStaleLock(lockPath: string): boolean {\n try {\n const holder = JSON.parse(fs.readFileSync(lockPath, UTF8_ENCODING)) as { pid?: number; time?: number };\n const expired = typeof holder.time === 'number' && Date.now() - holder.time > LOCK_STALE_MS;\n const dead = typeof holder.pid === 'number' && !isProcessAlive(holder.pid);\n if (!expired && !dead) return false;\n fs.unlinkSync(lockPath);\n return true;\n } catch (error) {\n // Losing the race to another breaker is normal; a persistent failure here\n // shows up as the lock timeout above, so this stays a warning.\n if ((error as NodeJS.ErrnoException).code !== MISSING_FILE_CODE) {\n this.report?.warn(TASK_EVENT.storeLockBreakFailed, error, { [STORE_PATH_ATTRIBUTE]: lockPath });\n }\n return false;\n }\n }\n\n /**\n * Notify when another process changes the store.\n *\n * `fs.watch` alone is unreliable across the rename-based write (and on some\n * network filesystems), so a slow poll backs it up. Writes made by this\n * process are filtered out by revision so the UI does not redraw twice.\n */\n onExternalChange(listener: (document: TaskDocument) => void): () => void {\n this.listeners.add(listener);\n this.startWatching();\n return () => {\n this.listeners.delete(listener);\n if (this.listeners.size === 0) this.stopWatching();\n };\n }\n\n private startWatching(): void {\n if (this.watcher || this.pollTimer) return;\n const directory = path.dirname(this.storePath);\n const fileName = path.basename(this.storePath);\n\n try {\n fs.mkdirSync(directory, { recursive: true });\n this.watcher = fs.watch(directory, (_event, changed) => {\n if (changed && changed !== fileName) return;\n this.scheduleCheck();\n });\n } catch (error) {\n // Polling still covers change detection, just more slowly.\n this.report?.warn(TASK_EVENT.storeWatchFailed, error, { [STORE_PATH_ATTRIBUTE]: this.storePath });\n }\n\n this.pollTimer = setInterval(() => this.checkForChange(), this.pollIntervalMs);\n this.pollTimer.unref?.();\n }\n\n private scheduleCheck(): void {\n clearTimeout(this.debounceTimer);\n this.debounceTimer = setTimeout(() => this.checkForChange(), WATCH_DEBOUNCE_MS);\n this.debounceTimer.unref?.();\n }\n\n private checkForChange(): void {\n const previousRev = this.lastKnownRev;\n const document = this.read();\n if (document.rev === previousRev) return;\n for (const listener of this.listeners) {\n try {\n listener(document);\n } catch (error) {\n // This runs from a timer and from the fs.watch callback, so an\n // unguarded listener throw is an uncaught exception that takes the\n // harness down rather than a handled render failure.\n this.report?.error(TASK_EVENT.storeListenerFailed, error, { [STORE_PATH_ATTRIBUTE]: this.storePath });\n }\n }\n }\n\n private stopWatching(): void {\n this.watcher?.close();\n this.watcher = undefined;\n if (this.pollTimer) clearInterval(this.pollTimer);\n this.pollTimer = undefined;\n clearTimeout(this.debounceTimer);\n this.debounceTimer = undefined;\n }\n\n dispose(): void {\n this.listeners.clear();\n this.stopWatching();\n }\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.cjs","names":[],"sources":["../../src/store/types.ts"],"sourcesContent":["/**\n * Domain types for the file-backed task store.\n *\n * The on-disk document is the durable source of truth (unlike rpiv-todo, which\n * replayed state from the transcript). Every field here round-trips through\n * JSON, so nothing may hold non-serializable values.\n */\n\nimport type { InlineAgent } from '@agimon-ai/doompi-extension-contracts/subagent-tool';\n\nexport type TaskStatus = 'pending' | 'in_progress' | 'completed' | 'failed' | 'deleted';\n\nexport const DELETED_STATUS: TaskStatus = 'deleted';\n\nexport type TaskAction = 'upsert' | 'list' | 'get' | 'delete' | 'clear' | 'assign' | 'cancel';\n\nexport type DelegationState = 'requested' | 'running' | 'completed' | 'failed' | 'cancelled';\n\n/** Terminal result of a delegated subagent run, copied off the delegation response. */\nexport interface DelegationResult {\n status: string;\n output?: string;\n outputPath?: string;\n sessionFile?: string;\n error?: string;\n durationMs?: number;\n toolCount?: number;\n}\n\n/**\n * Delegation bookkeeping attached to a task that was handed to a subagent.\n *\n * `pid` is the harness process that owns the run: it is the only way to tell an\n * genuinely-running delegation from one orphaned by a harness crash, since the\n * child dies with its parent but the file survives.\n */\nexport interface TaskDelegation {\n requestId: string;\n agent: string;\n state: DelegationState;\n sessionId?: string;\n pid?: number;\n runId?: string;\n model?: string;\n startedAt?: string;\n endedAt?: string;\n result?: DelegationResult;\n}\n\nexport interface Task {\n id: number;\n subject: string;\n description?: string;\n activeForm?: string;\n status: TaskStatus;\n blockedBy?: number[];\n owner?: string;\n metadata?: Record<string, unknown>;\n createdAt?: string;\n updatedAt?: string;\n delegation?: TaskDelegation;\n}\n\nexport const STORE_SCHEMA_VERSION = 1;\n\n/** The complete on-disk document. `rev` increments on every committed write. */\nexport interface TaskDocument {\n version: number;\n rev: number;\n nextId: number;\n tasks: Task[];\n}\n\nexport function emptyDocument(): TaskDocument {\n return { version: STORE_SCHEMA_VERSION, rev: 0, nextId: 1, tasks: [] };\n}\n\n/**\n * A dependency target inside an upsert item: an existing task id, or the `ref`\n * of a task created earlier in the same call.\n *\n * Refs must start with a letter (see `REF_PATTERN`), so a ref is structurally\n * unconfusable with a stringified id and the discrimination is just `typeof`.\n */\nexport type DepToken = number | string;\n\n/**\n * One entry of an `upsert` call. No `id` creates a task; an `id` updates one.\n *\n * `blockedBy` (absolute set) is create-only and `addBlockedBy`/`removeBlockedBy`\n * (additive merge) are update-only, matching the split the two former actions\n * had. A field used against the wrong kind fails that item rather than being\n * silently ignored.\n */\nexport interface TaskItemMutation {\n id?: number;\n ref?: string;\n subject?: string;\n description?: string;\n activeForm?: string;\n status?: TaskStatus;\n blockedBy?: DepToken[];\n addBlockedBy?: DepToken[];\n removeBlockedBy?: DepToken[];\n owner?: string;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * What one upsert item did. `index` is its position in the request array, so a\n * model reading a partial result can tell which entries still need resending.\n *\n * `message` is unprefixed: the `item[N] failed:` framing belongs to the\n * formatter, because the Task Space overlay shows this text on its own.\n */\nexport type UpsertItemOutcome =\n | {\n index: number;\n kind: 'created';\n id: number;\n subject: string;\n status: TaskStatus;\n ref?: string;\n blockedBy?: number[];\n }\n | { index: number; kind: 'updated'; id: number; fromStatus: TaskStatus; toStatus: TaskStatus }\n | { index: number; kind: 'unchanged'; id: number; status: TaskStatus }\n | { index: number; kind: 'failed'; message: string; id?: number; ref?: string };\n\n/** Which tasks an upsert touched, so renderResult names them instead of guessing. */\nexport interface UpsertSummary {\n /** Ids of applied entries, in request order. A failed entry contributes nothing. */\n applied: number[];\n failed: number;\n}\n\n/**\n * Open-shape input bag the reducer accepts. The index signature lets the\n * runtime pass a TypeBox `Static<typeof TaskParamsSchema>` through without\n * casting each field.\n *\n * Per-task fields live on `tasks[]`, not here: a top-level `subject` or\n * `status` would be ambiguous once one call can carry many tasks.\n */\nexport interface TaskMutationParams {\n [key: string]: unknown;\n tasks?: TaskItemMutation[];\n /** `list` filter only. To set a status, upsert the task by id. */\n status?: TaskStatus;\n /** `get`, `delete`, `assign` and `cancel` only. */\n id?: number;\n includeDeleted?: boolean;\n agent?: string;\n inlineAgent?: InlineAgent;\n instructions?: string;\n /** `assign` only: the context pack the parent hands to the child. */\n relevantFiles?: string[];\n priorFindings?: string;\n model?: string;\n context?: 'fresh' | 'fork';\n}\n\n/** Snapshot returned under a tool result's `details` for renderResult. */\nexport interface TaskDetails {\n action: TaskAction;\n params: Record<string, unknown>;\n tasks: Task[];\n nextId: number;\n rev: number;\n error?: string;\n upsert?: UpsertSummary;\n}\n\n/** A delegation is \"live\" while the owning run may still produce a response. */\nexport function isDelegationActive(task: Task): boolean {\n const state = task.delegation?.state;\n return state === 'requested' || state === 'running';\n}\n"],"mappings":"mEAyEA,SAAgB,GAA8B,CAC5C,MAAO,CAAE,QAAA,EAA+B,IAAK,EAAG,OAAQ,EAAG,MAAO,CAAC,CAAE,CACvE,CAmGA,SAAgB,EAAmB,EAAqB,CACtD,IAAM,EAAQ,EAAK,YAAY,MAC/B,OAAO,IAAU,aAAe,IAAU,SAC5C"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.d.cts","names":[],"sources":["../../src/store/types.ts"],"mappings":";;KAUY;cAEC,gBAAgB;KAEjB;KAEA;;UAGK;EACf;EACA;EACA;EACA;EACA;EACA;EACA;;;;;;;;;UAUe;EACf;EACA;EACA,OAAO;EACP;EACA;EACA;EACA;EACA;EACA;EACA,SAAS;;UAGM;EACf;EACA;EACA;EACA;EACA,QAAQ;EACR;EACA;EACA,WAAW;EACX;EACA;EACA,aAAa;;cAGF;;UAGI;EACf;EACA;EACA;EACA,OAAO;;iBAGO,iBAAiB;;;;;;;;KAWrB;;;;;;;;;UAUK;EACf;EACA;EACA;EACA;EACA;EACA,SAAS;EACT,YAAY;EACZ,eAAe;EACf,kBAAkB;EAClB;EACA,WAAW;;;;;;;;;KAUD;EAEN;EACA;EACA;EACA;EACA,QAAQ;EACR;EACA;;EAEA;EAAe;EAAiB;EAAY,YAAY;EAAY,UAAU;;EAC9E;EAAe;EAAmB;EAAY,QAAQ;;EACtD;EAAe;EAAgB;EAAiB;EAAa;;;UAGlD;;EAEf;EACA;;;;;;;;;;UAWe;GACd;EACD,QAAQ;;EAER,SAAS;;EAET;EACA;EACA;EACA,cAAc;EACd;;EAEA;EACA;EACA;EACA;;;UAIe;EACf,QAAQ;EACR,QAAQ;EACR,OAAO;EACP;EACA;EACA;EACA,SAAS;;;iBAIK,mBAAmB,MAAM"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.d.mts","names":[],"sources":["../../src/store/types.ts"],"mappings":";;KAUY;cAEC,gBAAgB;KAEjB;KAEA;;UAGK;EACf;EACA;EACA;EACA;EACA;EACA;EACA;;;;;;;;;UAUe;EACf;EACA;EACA,OAAO;EACP;EACA;EACA;EACA;EACA;EACA;EACA,SAAS;;UAGM;EACf;EACA;EACA;EACA;EACA,QAAQ;EACR;EACA;EACA,WAAW;EACX;EACA;EACA,aAAa;;cAGF;;UAGI;EACf;EACA;EACA;EACA,OAAO;;iBAGO,iBAAiB;;;;;;;;KAWrB;;;;;;;;;UAUK;EACf;EACA;EACA;EACA;EACA;EACA,SAAS;EACT,YAAY;EACZ,eAAe;EACf,kBAAkB;EAClB;EACA,WAAW;;;;;;;;;KAUD;EAEN;EACA;EACA;EACA;EACA,QAAQ;EACR;EACA;;EAEA;EAAe;EAAiB;EAAY,YAAY;EAAY,UAAU;;EAC9E;EAAe;EAAmB;EAAY,QAAQ;;EACtD;EAAe;EAAgB;EAAiB;EAAa;;;UAGlD;;EAEf;EACA;;;;;;;;;;UAWe;GACd;EACD,QAAQ;;EAER,SAAS;;EAET;EACA;EACA;EACA,cAAc;EACd;;EAEA;EACA;EACA;EACA;;;UAIe;EACf,QAAQ;EACR,QAAQ;EACR,OAAO;EACP;EACA;EACA;EACA,SAAS;;;iBAIK,mBAAmB,MAAM"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.mjs","names":[],"sources":["../../src/store/types.ts"],"sourcesContent":["/**\n * Domain types for the file-backed task store.\n *\n * The on-disk document is the durable source of truth (unlike rpiv-todo, which\n * replayed state from the transcript). Every field here round-trips through\n * JSON, so nothing may hold non-serializable values.\n */\n\nimport type { InlineAgent } from '@agimon-ai/doompi-extension-contracts/subagent-tool';\n\nexport type TaskStatus = 'pending' | 'in_progress' | 'completed' | 'failed' | 'deleted';\n\nexport const DELETED_STATUS: TaskStatus = 'deleted';\n\nexport type TaskAction = 'upsert' | 'list' | 'get' | 'delete' | 'clear' | 'assign' | 'cancel';\n\nexport type DelegationState = 'requested' | 'running' | 'completed' | 'failed' | 'cancelled';\n\n/** Terminal result of a delegated subagent run, copied off the delegation response. */\nexport interface DelegationResult {\n status: string;\n output?: string;\n outputPath?: string;\n sessionFile?: string;\n error?: string;\n durationMs?: number;\n toolCount?: number;\n}\n\n/**\n * Delegation bookkeeping attached to a task that was handed to a subagent.\n *\n * `pid` is the harness process that owns the run: it is the only way to tell an\n * genuinely-running delegation from one orphaned by a harness crash, since the\n * child dies with its parent but the file survives.\n */\nexport interface TaskDelegation {\n requestId: string;\n agent: string;\n state: DelegationState;\n sessionId?: string;\n pid?: number;\n runId?: string;\n model?: string;\n startedAt?: string;\n endedAt?: string;\n result?: DelegationResult;\n}\n\nexport interface Task {\n id: number;\n subject: string;\n description?: string;\n activeForm?: string;\n status: TaskStatus;\n blockedBy?: number[];\n owner?: string;\n metadata?: Record<string, unknown>;\n createdAt?: string;\n updatedAt?: string;\n delegation?: TaskDelegation;\n}\n\nexport const STORE_SCHEMA_VERSION = 1;\n\n/** The complete on-disk document. `rev` increments on every committed write. */\nexport interface TaskDocument {\n version: number;\n rev: number;\n nextId: number;\n tasks: Task[];\n}\n\nexport function emptyDocument(): TaskDocument {\n return { version: STORE_SCHEMA_VERSION, rev: 0, nextId: 1, tasks: [] };\n}\n\n/**\n * A dependency target inside an upsert item: an existing task id, or the `ref`\n * of a task created earlier in the same call.\n *\n * Refs must start with a letter (see `REF_PATTERN`), so a ref is structurally\n * unconfusable with a stringified id and the discrimination is just `typeof`.\n */\nexport type DepToken = number | string;\n\n/**\n * One entry of an `upsert` call. No `id` creates a task; an `id` updates one.\n *\n * `blockedBy` (absolute set) is create-only and `addBlockedBy`/`removeBlockedBy`\n * (additive merge) are update-only, matching the split the two former actions\n * had. A field used against the wrong kind fails that item rather than being\n * silently ignored.\n */\nexport interface TaskItemMutation {\n id?: number;\n ref?: string;\n subject?: string;\n description?: string;\n activeForm?: string;\n status?: TaskStatus;\n blockedBy?: DepToken[];\n addBlockedBy?: DepToken[];\n removeBlockedBy?: DepToken[];\n owner?: string;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * What one upsert item did. `index` is its position in the request array, so a\n * model reading a partial result can tell which entries still need resending.\n *\n * `message` is unprefixed: the `item[N] failed:` framing belongs to the\n * formatter, because the Task Space overlay shows this text on its own.\n */\nexport type UpsertItemOutcome =\n | {\n index: number;\n kind: 'created';\n id: number;\n subject: string;\n status: TaskStatus;\n ref?: string;\n blockedBy?: number[];\n }\n | { index: number; kind: 'updated'; id: number; fromStatus: TaskStatus; toStatus: TaskStatus }\n | { index: number; kind: 'unchanged'; id: number; status: TaskStatus }\n | { index: number; kind: 'failed'; message: string; id?: number; ref?: string };\n\n/** Which tasks an upsert touched, so renderResult names them instead of guessing. */\nexport interface UpsertSummary {\n /** Ids of applied entries, in request order. A failed entry contributes nothing. */\n applied: number[];\n failed: number;\n}\n\n/**\n * Open-shape input bag the reducer accepts. The index signature lets the\n * runtime pass a TypeBox `Static<typeof TaskParamsSchema>` through without\n * casting each field.\n *\n * Per-task fields live on `tasks[]`, not here: a top-level `subject` or\n * `status` would be ambiguous once one call can carry many tasks.\n */\nexport interface TaskMutationParams {\n [key: string]: unknown;\n tasks?: TaskItemMutation[];\n /** `list` filter only. To set a status, upsert the task by id. */\n status?: TaskStatus;\n /** `get`, `delete`, `assign` and `cancel` only. */\n id?: number;\n includeDeleted?: boolean;\n agent?: string;\n inlineAgent?: InlineAgent;\n instructions?: string;\n /** `assign` only: the context pack the parent hands to the child. */\n relevantFiles?: string[];\n priorFindings?: string;\n model?: string;\n context?: 'fresh' | 'fork';\n}\n\n/** Snapshot returned under a tool result's `details` for renderResult. */\nexport interface TaskDetails {\n action: TaskAction;\n params: Record<string, unknown>;\n tasks: Task[];\n nextId: number;\n rev: number;\n error?: string;\n upsert?: UpsertSummary;\n}\n\n/** A delegation is \"live\" while the owning run may still produce a response. */\nexport function isDelegationActive(task: Task): boolean {\n const state = task.delegation?.state;\n return state === 'requested' || state === 'running';\n}\n"],"mappings":"AAYA,MAAa,EAA6B,UAmD7B,EAAuB,EAUpC,SAAgB,GAA8B,CAC5C,MAAO,CAAE,QAAA,EAA+B,IAAK,EAAG,OAAQ,EAAG,MAAO,CAAC,CAAE,CACvE,CAmGA,SAAgB,EAAmB,EAAqB,CACtD,IAAM,EAAQ,EAAK,YAAY,MAC/B,OAAO,IAAU,aAAe,IAAU,SAC5C"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"promptGuidelines.cjs","names":[],"sources":["../../src/tool/promptGuidelines.ts"],"sourcesContent":["export const DEFAULT_PROMPT_GUIDELINES: string[] = [\n 'Use `task` for work with 3+ steps, when the user gives you a list of tasks, or immediately after receiving new instructions to capture requirements. Skip it for single trivial tasks and purely conversational requests.',\n 'Capture a whole plan in one call: {\"action\":\"upsert\",\"tasks\":[{\"subject\":\"Research existing tool\"},{\"subject\":\"Write the reducer\"},{\"subject\":\"Add tests\"}]}. Batch whenever you are writing the plan down — the initial list, a revised plan, or wiring dependencies across several tasks — because one call keeps ids and blockers consistent and shows the user the whole plan at once.',\n 'Do not batch progress. Mark a task in_progress with its own call BEFORE beginning work, and completed with its own call IMMEDIATELY when it is done. upsert accepts many tasks, but a batch of completions sent at the end of a turn is still wrong: batching is for writing a plan down, single calls are for reporting progress, and the user watches the task list to see where you are. Exactly one task should be in_progress for your own work; delegated tasks run in parallel and do not count against that.',\n 'Never mark a task completed if tests are failing, the implementation is partial, or you hit unresolved errors, use status \"failed\" or keep it in_progress and add a new task for the blocker in the same upsert.',\n 'When every non-deleted task is completed, review the full task list once more and call task {\"action\":\"clear\"} to close it. Do not leave an all-completed list open.',\n \"Status is a state machine: pending → in_progress → completed, plus failed (recoverable, can go back to pending or in_progress) and deleted as a tombstone. Pass activeForm (present-continuous, e.g. 'writing tests') when marking in_progress.\",\n 'One call does both: an entry with an id changes that task, an entry without an id creates one. To change status, upsert the task by id, e.g. {\"action\":\"upsert\",\"tasks\":[{\"id\":3,\"status\":\"completed\"}]}. Never omit the id when you meant to change an existing task — an entry with no id creates a new one instead. An entry that carries an id and no other field is rejected.',\n 'Use blockedBy for dependencies (A is blocked by B). On an entry with no id pass blockedBy as the initial set; on an entry with an id use addBlockedBy / removeBlockedBy (additive merge, do not resend the full array). To depend on a task created earlier in the SAME call, give that earlier entry a \"ref\" and list the ref string in place of an id: [{\"ref\":\"api\",\"subject\":\"Design the API\"},{\"subject\":\"Implement the API\",\"blockedBy\":[\"api\"]}]. A ref must be declared before it is used. Cycles are rejected.',\n 'upsert applies each entry independently: the entries that pass are committed and the failures are reported with their array index. A failed entry changed nothing, so resend only the corrected failures — never resend the whole call, because an already-applied entry with no id would create a duplicate task.',\n 'Before assigning work, call subagent with {\"action\":\"agents\"} and match each task to an exact discovered agent name. Prefer a discovered general-purpose write-capable agent such as delegate or worker when no specialist fits. Use a focused inlineAgent only for read-only work.',\n 'Assign every unblocked pending task with task {\"action\":\"assign\",\"id\":3,\"agent\":\"reviewer\"}, including implementation tasks. Do not use a direct subagent run for work already represented in the shared task list. Use task assign so ownership and terminal results stay visible.',\n 'Hand over what you already know when you assign. Pass relevantFiles with the paths you have actually read or located for that task, and priorFindings with the facts you established: symbol names, call sites, the approach you picked, what you ruled out. A fresh-context child starts with none of your context and will otherwise spend most of its run re-reading the repo. It treats this verified pack as satisfying initial context exploration, reads known paths directly, and widens discovery only for a concrete missing dependency. Send at most a dozen files and only ones you really opened — a guessed path costs the child more than an omitted one — and keep priorFindings to a few lines of facts, not directives.',\n 'After assigning work, continue non-overlapping parent work or end the turn and wait. Do not poll or duplicate delegated scope.',\n 'When a delegated task completes and unblocks another task, repeat agent discovery if needed and assign that newly eligible task promptly. Do not poll in a loop. Completion notifications wake the parent session.',\n 'If a child asks for a decision through intercom, or an assignment fails to start for another concrete issue, respond, rescope, or retry explicitly. Do not silently leave the task pending.',\n 'assign refuses tasks that are blocked, already delegated, or completed. Resolve blockers first. Use {\"action\":\"cancel\",\"id\":3} to stop a running delegation; the task returns to pending.',\n 'Doom Task records delegated lifecycle and results on the shared task. The child does not update task status directly. Read the completion or failure result before deciding what to do next.',\n 'The task list is scoped to this session tree: delegated subagents share it, while unrelated sessions start empty. It persists for later inspection until retention cleanup.',\n \"Subject must be short and imperative (e.g. 'Research existing tool'); description is long-form detail written when you plan the task, and the delegated brief is that description plus the assign-time instructions, relevantFiles and priorFindings. Put durable scope in description and what you learned while exploring in the assign-time pack — do not repeat one in the other.\",\n];\n"],"mappings":"mEAAA,MAAa,EAAsC,CACjD,4NACA,6XACA,ufACA,mNACA,uKACA,kPACA,qXACA,0fACA,qTACA,sRACA,sRACA,4sBACA,iIACA,qNACA,8LACA,4LACA,+LACA,8KACA,uXACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"promptGuidelines.d.cts","names":[],"sources":["../../src/tool/promptGuidelines.ts"],"mappings":";cAAa"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"promptGuidelines.d.mts","names":[],"sources":["../../src/tool/promptGuidelines.ts"],"mappings":";cAAa"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"promptGuidelines.mjs","names":[],"sources":["../../src/tool/promptGuidelines.ts"],"sourcesContent":["export const DEFAULT_PROMPT_GUIDELINES: string[] = [\n 'Use `task` for work with 3+ steps, when the user gives you a list of tasks, or immediately after receiving new instructions to capture requirements. Skip it for single trivial tasks and purely conversational requests.',\n 'Capture a whole plan in one call: {\"action\":\"upsert\",\"tasks\":[{\"subject\":\"Research existing tool\"},{\"subject\":\"Write the reducer\"},{\"subject\":\"Add tests\"}]}. Batch whenever you are writing the plan down — the initial list, a revised plan, or wiring dependencies across several tasks — because one call keeps ids and blockers consistent and shows the user the whole plan at once.',\n 'Do not batch progress. Mark a task in_progress with its own call BEFORE beginning work, and completed with its own call IMMEDIATELY when it is done. upsert accepts many tasks, but a batch of completions sent at the end of a turn is still wrong: batching is for writing a plan down, single calls are for reporting progress, and the user watches the task list to see where you are. Exactly one task should be in_progress for your own work; delegated tasks run in parallel and do not count against that.',\n 'Never mark a task completed if tests are failing, the implementation is partial, or you hit unresolved errors, use status \"failed\" or keep it in_progress and add a new task for the blocker in the same upsert.',\n 'When every non-deleted task is completed, review the full task list once more and call task {\"action\":\"clear\"} to close it. Do not leave an all-completed list open.',\n \"Status is a state machine: pending → in_progress → completed, plus failed (recoverable, can go back to pending or in_progress) and deleted as a tombstone. Pass activeForm (present-continuous, e.g. 'writing tests') when marking in_progress.\",\n 'One call does both: an entry with an id changes that task, an entry without an id creates one. To change status, upsert the task by id, e.g. {\"action\":\"upsert\",\"tasks\":[{\"id\":3,\"status\":\"completed\"}]}. Never omit the id when you meant to change an existing task — an entry with no id creates a new one instead. An entry that carries an id and no other field is rejected.',\n 'Use blockedBy for dependencies (A is blocked by B). On an entry with no id pass blockedBy as the initial set; on an entry with an id use addBlockedBy / removeBlockedBy (additive merge, do not resend the full array). To depend on a task created earlier in the SAME call, give that earlier entry a \"ref\" and list the ref string in place of an id: [{\"ref\":\"api\",\"subject\":\"Design the API\"},{\"subject\":\"Implement the API\",\"blockedBy\":[\"api\"]}]. A ref must be declared before it is used. Cycles are rejected.',\n 'upsert applies each entry independently: the entries that pass are committed and the failures are reported with their array index. A failed entry changed nothing, so resend only the corrected failures — never resend the whole call, because an already-applied entry with no id would create a duplicate task.',\n 'Before assigning work, call subagent with {\"action\":\"agents\"} and match each task to an exact discovered agent name. Prefer a discovered general-purpose write-capable agent such as delegate or worker when no specialist fits. Use a focused inlineAgent only for read-only work.',\n 'Assign every unblocked pending task with task {\"action\":\"assign\",\"id\":3,\"agent\":\"reviewer\"}, including implementation tasks. Do not use a direct subagent run for work already represented in the shared task list. Use task assign so ownership and terminal results stay visible.',\n 'Hand over what you already know when you assign. Pass relevantFiles with the paths you have actually read or located for that task, and priorFindings with the facts you established: symbol names, call sites, the approach you picked, what you ruled out. A fresh-context child starts with none of your context and will otherwise spend most of its run re-reading the repo. It treats this verified pack as satisfying initial context exploration, reads known paths directly, and widens discovery only for a concrete missing dependency. Send at most a dozen files and only ones you really opened — a guessed path costs the child more than an omitted one — and keep priorFindings to a few lines of facts, not directives.',\n 'After assigning work, continue non-overlapping parent work or end the turn and wait. Do not poll or duplicate delegated scope.',\n 'When a delegated task completes and unblocks another task, repeat agent discovery if needed and assign that newly eligible task promptly. Do not poll in a loop. Completion notifications wake the parent session.',\n 'If a child asks for a decision through intercom, or an assignment fails to start for another concrete issue, respond, rescope, or retry explicitly. Do not silently leave the task pending.',\n 'assign refuses tasks that are blocked, already delegated, or completed. Resolve blockers first. Use {\"action\":\"cancel\",\"id\":3} to stop a running delegation; the task returns to pending.',\n 'Doom Task records delegated lifecycle and results on the shared task. The child does not update task status directly. Read the completion or failure result before deciding what to do next.',\n 'The task list is scoped to this session tree: delegated subagents share it, while unrelated sessions start empty. It persists for later inspection until retention cleanup.',\n \"Subject must be short and imperative (e.g. 'Research existing tool'); description is long-form detail written when you plan the task, and the delegated brief is that description plus the assign-time instructions, relevantFiles and priorFindings. Put durable scope in description and what you learned while exploring in the assign-time pack — do not repeat one in the other.\",\n];\n"],"mappings":"AAAA,MAAa,EAAsC,CACjD,4NACA,6XACA,ufACA,mNACA,uKACA,kPACA,qXACA,0fACA,qTACA,sRACA,sRACA,4sBACA,iIACA,qNACA,8LACA,4LACA,+LACA,8KACA,uXACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"responseEnvelope.cjs","names":["deriveBlocks","isTaskListComplete"],"sources":["../../src/tool/responseEnvelope.ts"],"sourcesContent":["import type { Op } from '../store/reducer.ts';\nimport { deriveBlocks, isTaskListComplete } from '../store/taskGraph.ts';\nimport type {\n Task,\n TaskAction,\n TaskDetails,\n TaskDocument,\n TaskMutationParams,\n UpsertItemOutcome,\n} from '../store/types.ts';\n\nexport const MSG_ALL_COMPLETE_CLEAR =\n 'All tasks are completed. Review the full task list once more, then close it with task {\"action\":\"clear\"}.';\n\n/**\n * Steering for a mixed batch. Unlike a batch of spawned subagents, a failed\n * entry here had no side effect at all, so retrying the failures is the safe\n * move and the model must be told so or it will do nothing. The hazard is the\n * other half: resending an applied create would make a second task.\n */\nexport const MSG_UPSERT_PARTIAL =\n 'The applied entries are committed. Resend only the failed entries, corrected — a failed entry changed nothing, so a corrected retry is safe. Do not resend an entry that already applied: an entry without an id creates a second task.';\n\nexport const MSG_UPSERT_NONE_APPLIED = 'No task changed, so the whole call can be resent once corrected.';\n\n/** `[status] #id subject (activeForm) [agent] ⛓ #dep` — the `list` line format. */\nfunction formatListLine(task: Task): string {\n const block = task.blockedBy?.length ? ` ⛓ ${task.blockedBy.map((id) => `#${id}`).join(',')}` : '';\n const form = task.status === 'in_progress' && task.activeForm ? ` (${task.activeForm})` : '';\n const delegated = task.delegation && task.delegation.state !== 'cancelled' ? ` [${task.delegation.agent}]` : '';\n return `[${task.status}] #${task.id} ${task.subject}${form}${delegated}${block}`;\n}\n\nfunction formatDelegationLines(task: Task): string[] {\n const delegation = task.delegation;\n if (!delegation) return [];\n\n const lines = [` delegated to: ${delegation.agent} (${delegation.state})`];\n if (delegation.model) lines.push(` model: ${delegation.model}`);\n if (delegation.result?.error) lines.push(` error: ${delegation.result.error}`);\n if (delegation.result?.outputPath) lines.push(` output file: ${delegation.result.outputPath}`);\n if (delegation.result?.output) lines.push(` output: ${delegation.result.output}`);\n return lines;\n}\n\nfunction formatGetLines(task: Task, document: TaskDocument): string {\n const blocks = deriveBlocks(document.tasks).get(task.id) ?? [];\n const lines = [`#${task.id} [${task.status}] ${task.subject}`];\n if (task.description) lines.push(` description: ${task.description}`);\n if (task.activeForm) lines.push(` activeForm: ${task.activeForm}`);\n if (task.blockedBy?.length) lines.push(` blockedBy: ${task.blockedBy.map((id) => `#${id}`).join(', ')}`);\n if (blocks.length) lines.push(` blocks: ${blocks.map((id) => `#${id}`).join(', ')}`);\n if (task.owner) lines.push(` owner: ${task.owner}`);\n lines.push(...formatDelegationLines(task));\n return lines.join('\\n');\n}\n\n/** One entry's outcome. Batch lines prefix this with `- [n] `. */\nfunction formatUpsertItem(item: UpsertItemOutcome): string {\n switch (item.kind) {\n case 'created': {\n const ref = item.ref ? ` (ref \"${item.ref}\")` : '';\n const deps = item.blockedBy?.length ? ` — blocked by ${item.blockedBy.map((id) => `#${id}`).join(', ')}` : '';\n return `Created #${item.id}${ref}: ${item.subject} (${item.status})${deps}`;\n }\n case 'updated': {\n const transition = item.fromStatus === item.toStatus ? '' : ` (${item.fromStatus} -> ${item.toStatus})`;\n return `Updated #${item.id}${transition}`;\n }\n case 'unchanged':\n return `No change: #${item.id} already matches the requested values (status: ${item.status})`;\n case 'failed':\n return `Failed${item.id === undefined ? '' : ` #${item.id}`}: ${item.message}`;\n }\n}\n\n/**\n * The thrown message when an upsert applied nothing. Kept separate from\n * `formatContent` because the caller wraps it in the actionable Options block\n * rather than returning it as a successful result.\n */\nexport function formatUpsertFailureText(op: Extract<Op, { kind: 'upsert' }>): string {\n if (op.items.length === 1) return op.items[0].kind === 'failed' ? op.items[0].message : 'no entry was applied';\n return [\n 'no entry was applied.',\n ...op.items.map((item) => `- [${item.index}] ${formatUpsertItem(item)}`),\n MSG_UPSERT_NONE_APPLIED,\n ].join('\\n');\n}\n\n/**\n * Pure formatter: `(op, document) -> string`. The switch is closed over `Op`,\n * so a new reducer variant fails to compile until it is handled here.\n */\nexport function formatContent(op: Op, document: TaskDocument): string {\n switch (op.kind) {\n case 'upsert': {\n // A batch of one is the common case and must not read like a bulk\n // report, so it keeps the exact single-line shape it has always had.\n const lines =\n op.items.length === 1\n ? [formatUpsertItem(op.items[0])]\n : [\n `Upsert applied ${op.applied}/${op.items.length} entries${op.failed > 0 ? `; ${op.failed} failed` : ''}.`,\n ...op.items.map((item) => `- [${item.index}] ${formatUpsertItem(item)}`),\n ...(op.failed > 0 ? ['', MSG_UPSERT_PARTIAL] : []),\n ];\n // Once, last, and only when something landed: emitting it per entry\n // would repeat it for every completion in a batch.\n if (op.applied > 0 && isTaskListComplete(document.tasks)) lines.push(MSG_ALL_COMPLETE_CLEAR);\n return lines.join('\\n');\n }\n case 'delete':\n return `Deleted #${op.id}: ${op.subject}`;\n case 'clear':\n return `Closed task list (cleared ${op.count} tasks)`;\n case 'list': {\n let view = document.tasks;\n if (!op.includeDeleted) view = view.filter((task) => task.status !== 'deleted');\n if (op.statusFilter) view = view.filter((task) => task.status === op.statusFilter);\n return view.length === 0 ? 'No tasks' : view.map(formatListLine).join('\\n');\n }\n case 'get':\n return formatGetLines(op.task, document);\n case 'error':\n return `Error: ${op.message}`;\n }\n}\n\nexport interface ToolResult {\n content: Array<{ type: 'text'; text: string }>;\n details: TaskDetails;\n}\n\n/** Build the LLM-facing envelope. `details` carries the post-mutation snapshot. */\nexport function buildToolResult(\n action: TaskAction,\n params: TaskMutationParams,\n document: TaskDocument,\n op: Op,\n): ToolResult {\n return {\n content: [{ type: 'text', text: formatContent(op, document) }],\n details: {\n action,\n params: params as Record<string, unknown>,\n tasks: document.tasks,\n nextId: document.nextId,\n rev: document.rev,\n ...(op.kind === 'error' ? { error: op.message } : {}),\n // Deliberately no `error` on a partial success: renderResult treats\n // `details.error` as total failure and would hide the rows for the\n // entries that did land.\n ...(op.kind === 'upsert'\n ? {\n upsert: {\n applied: op.items.flatMap((item) => (item.kind === 'failed' ? [] : [item.id])),\n failed: op.failed,\n },\n }\n : {}),\n },\n };\n}\n\n/** Envelope for delegation actions, which do not flow through the reducer. */\nexport function buildTextResult(\n action: TaskAction,\n params: TaskMutationParams,\n document: TaskDocument,\n text: string,\n error?: string,\n): ToolResult {\n return {\n content: [{ type: 'text', text: error ? `Error: ${error}` : text }],\n details: {\n action,\n params: params as Record<string, unknown>,\n tasks: document.tasks,\n nextId: document.nextId,\n rev: document.rev,\n ...(error ? { error } : {}),\n },\n };\n}\n"],"mappings":"6GAWa,EACX,4GAQW,EACX,0OAEW,EAA0B,mEAGvC,SAAS,EAAe,EAAoB,CAC1C,IAAM,EAAQ,EAAK,WAAW,OAAS,MAAM,EAAK,UAAU,IAAK,GAAO,IAAI,GAAI,CAAC,CAAC,KAAK,GAAG,IAAM,GAC1F,EAAO,EAAK,SAAW,eAAiB,EAAK,WAAa,KAAK,EAAK,WAAW,GAAK,GACpF,EAAY,EAAK,YAAc,EAAK,WAAW,QAAU,YAAc,KAAK,EAAK,WAAW,MAAM,GAAK,GAC7G,MAAO,IAAI,EAAK,OAAO,KAAK,EAAK,GAAG,GAAG,EAAK,UAAU,IAAO,IAAY,GAC3E,CAEA,SAAS,EAAsB,EAAsB,CACnD,IAAM,EAAa,EAAK,WACxB,GAAI,CAAC,EAAY,MAAO,CAAC,EAEzB,IAAM,EAAQ,CAAC,mBAAmB,EAAW,MAAM,IAAI,EAAW,MAAM,EAAE,EAK1E,OAJI,EAAW,OAAO,EAAM,KAAK,YAAY,EAAW,OAAO,EAC3D,EAAW,QAAQ,OAAO,EAAM,KAAK,YAAY,EAAW,OAAO,OAAO,EAC1E,EAAW,QAAQ,YAAY,EAAM,KAAK,kBAAkB,EAAW,OAAO,YAAY,EAC1F,EAAW,QAAQ,QAAQ,EAAM,KAAK,aAAa,EAAW,OAAO,QAAQ,EAC1E,CACT,CAEA,SAAS,EAAe,EAAY,EAAgC,CAClE,IAAM,EAASA,EAAAA,aAAa,EAAS,KAAK,CAAC,CAAC,IAAI,EAAK,EAAE,GAAK,CAAC,EACvD,EAAQ,CAAC,IAAI,EAAK,GAAG,IAAI,EAAK,OAAO,IAAI,EAAK,SAAS,EAO7D,OANI,EAAK,aAAa,EAAM,KAAK,kBAAkB,EAAK,aAAa,EACjE,EAAK,YAAY,EAAM,KAAK,iBAAiB,EAAK,YAAY,EAC9D,EAAK,WAAW,QAAQ,EAAM,KAAK,gBAAgB,EAAK,UAAU,IAAK,GAAO,IAAI,GAAI,CAAC,CAAC,KAAK,IAAI,GAAG,EACpG,EAAO,QAAQ,EAAM,KAAK,aAAa,EAAO,IAAK,GAAO,IAAI,GAAI,CAAC,CAAC,KAAK,IAAI,GAAG,EAChF,EAAK,OAAO,EAAM,KAAK,YAAY,EAAK,OAAO,EACnD,EAAM,KAAK,GAAG,EAAsB,CAAI,CAAC,EAClC,EAAM,KAAK;CAAI,CACxB,CAGA,SAAS,EAAiB,EAAiC,CACzD,OAAQ,EAAK,KAAb,CACE,IAAK,UAAW,CACd,IAAM,EAAM,EAAK,IAAM,UAAU,EAAK,IAAI,IAAM,GAC1C,EAAO,EAAK,WAAW,OAAS,iBAAiB,EAAK,UAAU,IAAK,GAAO,IAAI,GAAI,CAAC,CAAC,KAAK,IAAI,IAAM,GAC3G,MAAO,YAAY,EAAK,KAAK,EAAI,IAAI,EAAK,QAAQ,IAAI,EAAK,OAAO,GAAG,GACvE,CACA,IAAK,UAAW,CACd,IAAM,EAAa,EAAK,aAAe,EAAK,SAAW,GAAK,KAAK,EAAK,WAAW,MAAM,EAAK,SAAS,GACrG,MAAO,YAAY,EAAK,KAAK,GAC/B,CACA,IAAK,YACH,MAAO,eAAe,EAAK,GAAG,iDAAiD,EAAK,OAAO,GAC7F,IAAK,SACH,MAAO,SAAS,EAAK,KAAO,IAAA,GAAY,GAAK,KAAK,EAAK,KAAK,IAAI,EAAK,SACzE,CACF,CAOA,SAAgB,EAAwB,EAA6C,CAEnF,OADI,EAAG,MAAM,SAAW,EAAU,EAAG,MAAM,EAAE,CAAC,OAAS,SAAW,EAAG,MAAM,EAAE,CAAC,QAAU,uBACjF,CACL,wBACA,GAAG,EAAG,MAAM,IAAK,GAAS,MAAM,EAAK,MAAM,IAAI,EAAiB,CAAI,GAAG,EACvE,CACF,CAAC,CAAC,KAAK;CAAI,CACb,CAMA,SAAgB,EAAc,EAAQ,EAAgC,CACpE,OAAQ,EAAG,KAAX,CACE,IAAK,SAAU,CAGb,IAAM,EACJ,EAAG,MAAM,SAAW,EAChB,CAAC,EAAiB,EAAG,MAAM,EAAE,CAAC,EAC9B,CACE,kBAAkB,EAAG,QAAQ,GAAG,EAAG,MAAM,OAAO,UAAU,EAAG,OAAS,EAAI,KAAK,EAAG,OAAO,SAAW,GAAG,GACvG,GAAG,EAAG,MAAM,IAAK,GAAS,MAAM,EAAK,MAAM,IAAI,EAAiB,CAAI,GAAG,EACvE,GAAI,EAAG,OAAS,EAAI,CAAC,GAAI,CAAkB,EAAI,CAAC,CAClD,EAIN,OADI,EAAG,QAAU,GAAKC,EAAAA,mBAAmB,EAAS,KAAK,GAAG,EAAM,KAAK,CAAsB,EACpF,EAAM,KAAK;CAAI,CACxB,CACA,IAAK,SACH,MAAO,YAAY,EAAG,GAAG,IAAI,EAAG,UAClC,IAAK,QACH,MAAO,6BAA6B,EAAG,MAAM,SAC/C,IAAK,OAAQ,CACX,IAAI,EAAO,EAAS,MAGpB,OAFK,EAAG,iBAAgB,EAAO,EAAK,OAAQ,GAAS,EAAK,SAAW,SAAS,GAC1E,EAAG,eAAc,EAAO,EAAK,OAAQ,GAAS,EAAK,SAAW,EAAG,YAAY,GAC1E,EAAK,SAAW,EAAI,WAAa,EAAK,IAAI,CAAc,CAAC,CAAC,KAAK;CAAI,CAC5E,CACA,IAAK,MACH,OAAO,EAAe,EAAG,KAAM,CAAQ,EACzC,IAAK,QACH,MAAO,UAAU,EAAG,SACxB,CACF,CAQA,SAAgB,EACd,EACA,EACA,EACA,EACY,CACZ,MAAO,CACL,QAAS,CAAC,CAAE,KAAM,OAAQ,KAAM,EAAc,EAAI,CAAQ,CAAE,CAAC,EAC7D,QAAS,CACP,SACQ,SACR,MAAO,EAAS,MAChB,OAAQ,EAAS,OACjB,IAAK,EAAS,IACd,GAAI,EAAG,OAAS,QAAU,CAAE,MAAO,EAAG,OAAQ,EAAI,CAAC,EAInD,GAAI,EAAG,OAAS,SACZ,CACE,OAAQ,CACN,QAAS,EAAG,MAAM,QAAS,GAAU,EAAK,OAAS,SAAW,CAAC,EAAI,CAAC,EAAK,EAAE,CAAE,EAC7E,OAAQ,EAAG,MACb,CACF,EACA,CAAC,CACP,CACF,CACF,CAGA,SAAgB,EACd,EACA,EACA,EACA,EACA,EACY,CACZ,MAAO,CACL,QAAS,CAAC,CAAE,KAAM,OAAQ,KAAM,EAAQ,UAAU,IAAU,CAAK,CAAC,EAClE,QAAS,CACP,SACQ,SACR,MAAO,EAAS,MAChB,OAAQ,EAAS,OACjB,IAAK,EAAS,IACd,GAAI,EAAQ,CAAE,OAAM,EAAI,CAAC,CAC3B,CACF,CACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"responseEnvelope.d.cts","names":[],"sources":["../../src/tool/responseEnvelope.ts"],"mappings":";;;cAWa;;;;;;;cASA;cAGA;;;;;;iBA0DG,wBAAwB,IAAI,QAAQ;EAAM;;;;;;iBAa1C,cAAc,IAAI,IAAI,UAAU;UAmC/B;EACf,SAAS;IAAQ;IAAc;;EAC/B,SAAS;;;iBAIK,gBACd,QAAQ,YACR,QAAQ,oBACR,UAAU,cACV,IAAI,KACH;;iBA0Ba,gBACd,QAAQ,YACR,QAAQ,oBACR,UAAU,cACV,cACA,iBACC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"responseEnvelope.d.mts","names":[],"sources":["../../src/tool/responseEnvelope.ts"],"mappings":";;;cAWa;;;;;;;cASA;cAGA;;;;;;iBA0DG,wBAAwB,IAAI,QAAQ;EAAM;;;;;;iBAa1C,cAAc,IAAI,IAAI,UAAU;UAmC/B;EACf,SAAS;IAAQ;IAAc;;EAC/B,SAAS;;;iBAIK,gBACd,QAAQ,YACR,QAAQ,oBACR,UAAU,cACV,IAAI,KACH;;iBA0Ba,gBACd,QAAQ,YACR,QAAQ,oBACR,UAAU,cACV,cACA,iBACC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"responseEnvelope.mjs","names":[],"sources":["../../src/tool/responseEnvelope.ts"],"sourcesContent":["import type { Op } from '../store/reducer.ts';\nimport { deriveBlocks, isTaskListComplete } from '../store/taskGraph.ts';\nimport type {\n Task,\n TaskAction,\n TaskDetails,\n TaskDocument,\n TaskMutationParams,\n UpsertItemOutcome,\n} from '../store/types.ts';\n\nexport const MSG_ALL_COMPLETE_CLEAR =\n 'All tasks are completed. Review the full task list once more, then close it with task {\"action\":\"clear\"}.';\n\n/**\n * Steering for a mixed batch. Unlike a batch of spawned subagents, a failed\n * entry here had no side effect at all, so retrying the failures is the safe\n * move and the model must be told so or it will do nothing. The hazard is the\n * other half: resending an applied create would make a second task.\n */\nexport const MSG_UPSERT_PARTIAL =\n 'The applied entries are committed. Resend only the failed entries, corrected — a failed entry changed nothing, so a corrected retry is safe. Do not resend an entry that already applied: an entry without an id creates a second task.';\n\nexport const MSG_UPSERT_NONE_APPLIED = 'No task changed, so the whole call can be resent once corrected.';\n\n/** `[status] #id subject (activeForm) [agent] ⛓ #dep` — the `list` line format. */\nfunction formatListLine(task: Task): string {\n const block = task.blockedBy?.length ? ` ⛓ ${task.blockedBy.map((id) => `#${id}`).join(',')}` : '';\n const form = task.status === 'in_progress' && task.activeForm ? ` (${task.activeForm})` : '';\n const delegated = task.delegation && task.delegation.state !== 'cancelled' ? ` [${task.delegation.agent}]` : '';\n return `[${task.status}] #${task.id} ${task.subject}${form}${delegated}${block}`;\n}\n\nfunction formatDelegationLines(task: Task): string[] {\n const delegation = task.delegation;\n if (!delegation) return [];\n\n const lines = [` delegated to: ${delegation.agent} (${delegation.state})`];\n if (delegation.model) lines.push(` model: ${delegation.model}`);\n if (delegation.result?.error) lines.push(` error: ${delegation.result.error}`);\n if (delegation.result?.outputPath) lines.push(` output file: ${delegation.result.outputPath}`);\n if (delegation.result?.output) lines.push(` output: ${delegation.result.output}`);\n return lines;\n}\n\nfunction formatGetLines(task: Task, document: TaskDocument): string {\n const blocks = deriveBlocks(document.tasks).get(task.id) ?? [];\n const lines = [`#${task.id} [${task.status}] ${task.subject}`];\n if (task.description) lines.push(` description: ${task.description}`);\n if (task.activeForm) lines.push(` activeForm: ${task.activeForm}`);\n if (task.blockedBy?.length) lines.push(` blockedBy: ${task.blockedBy.map((id) => `#${id}`).join(', ')}`);\n if (blocks.length) lines.push(` blocks: ${blocks.map((id) => `#${id}`).join(', ')}`);\n if (task.owner) lines.push(` owner: ${task.owner}`);\n lines.push(...formatDelegationLines(task));\n return lines.join('\\n');\n}\n\n/** One entry's outcome. Batch lines prefix this with `- [n] `. */\nfunction formatUpsertItem(item: UpsertItemOutcome): string {\n switch (item.kind) {\n case 'created': {\n const ref = item.ref ? ` (ref \"${item.ref}\")` : '';\n const deps = item.blockedBy?.length ? ` — blocked by ${item.blockedBy.map((id) => `#${id}`).join(', ')}` : '';\n return `Created #${item.id}${ref}: ${item.subject} (${item.status})${deps}`;\n }\n case 'updated': {\n const transition = item.fromStatus === item.toStatus ? '' : ` (${item.fromStatus} -> ${item.toStatus})`;\n return `Updated #${item.id}${transition}`;\n }\n case 'unchanged':\n return `No change: #${item.id} already matches the requested values (status: ${item.status})`;\n case 'failed':\n return `Failed${item.id === undefined ? '' : ` #${item.id}`}: ${item.message}`;\n }\n}\n\n/**\n * The thrown message when an upsert applied nothing. Kept separate from\n * `formatContent` because the caller wraps it in the actionable Options block\n * rather than returning it as a successful result.\n */\nexport function formatUpsertFailureText(op: Extract<Op, { kind: 'upsert' }>): string {\n if (op.items.length === 1) return op.items[0].kind === 'failed' ? op.items[0].message : 'no entry was applied';\n return [\n 'no entry was applied.',\n ...op.items.map((item) => `- [${item.index}] ${formatUpsertItem(item)}`),\n MSG_UPSERT_NONE_APPLIED,\n ].join('\\n');\n}\n\n/**\n * Pure formatter: `(op, document) -> string`. The switch is closed over `Op`,\n * so a new reducer variant fails to compile until it is handled here.\n */\nexport function formatContent(op: Op, document: TaskDocument): string {\n switch (op.kind) {\n case 'upsert': {\n // A batch of one is the common case and must not read like a bulk\n // report, so it keeps the exact single-line shape it has always had.\n const lines =\n op.items.length === 1\n ? [formatUpsertItem(op.items[0])]\n : [\n `Upsert applied ${op.applied}/${op.items.length} entries${op.failed > 0 ? `; ${op.failed} failed` : ''}.`,\n ...op.items.map((item) => `- [${item.index}] ${formatUpsertItem(item)}`),\n ...(op.failed > 0 ? ['', MSG_UPSERT_PARTIAL] : []),\n ];\n // Once, last, and only when something landed: emitting it per entry\n // would repeat it for every completion in a batch.\n if (op.applied > 0 && isTaskListComplete(document.tasks)) lines.push(MSG_ALL_COMPLETE_CLEAR);\n return lines.join('\\n');\n }\n case 'delete':\n return `Deleted #${op.id}: ${op.subject}`;\n case 'clear':\n return `Closed task list (cleared ${op.count} tasks)`;\n case 'list': {\n let view = document.tasks;\n if (!op.includeDeleted) view = view.filter((task) => task.status !== 'deleted');\n if (op.statusFilter) view = view.filter((task) => task.status === op.statusFilter);\n return view.length === 0 ? 'No tasks' : view.map(formatListLine).join('\\n');\n }\n case 'get':\n return formatGetLines(op.task, document);\n case 'error':\n return `Error: ${op.message}`;\n }\n}\n\nexport interface ToolResult {\n content: Array<{ type: 'text'; text: string }>;\n details: TaskDetails;\n}\n\n/** Build the LLM-facing envelope. `details` carries the post-mutation snapshot. */\nexport function buildToolResult(\n action: TaskAction,\n params: TaskMutationParams,\n document: TaskDocument,\n op: Op,\n): ToolResult {\n return {\n content: [{ type: 'text', text: formatContent(op, document) }],\n details: {\n action,\n params: params as Record<string, unknown>,\n tasks: document.tasks,\n nextId: document.nextId,\n rev: document.rev,\n ...(op.kind === 'error' ? { error: op.message } : {}),\n // Deliberately no `error` on a partial success: renderResult treats\n // `details.error` as total failure and would hide the rows for the\n // entries that did land.\n ...(op.kind === 'upsert'\n ? {\n upsert: {\n applied: op.items.flatMap((item) => (item.kind === 'failed' ? [] : [item.id])),\n failed: op.failed,\n },\n }\n : {}),\n },\n };\n}\n\n/** Envelope for delegation actions, which do not flow through the reducer. */\nexport function buildTextResult(\n action: TaskAction,\n params: TaskMutationParams,\n document: TaskDocument,\n text: string,\n error?: string,\n): ToolResult {\n return {\n content: [{ type: 'text', text: error ? `Error: ${error}` : text }],\n details: {\n action,\n params: params as Record<string, unknown>,\n tasks: document.tasks,\n nextId: document.nextId,\n rev: document.rev,\n ...(error ? { error } : {}),\n },\n };\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"schema.cjs","names":["Type","InlineAgentSchema"],"sources":["../../src/tool/schema.ts"],"sourcesContent":["import { InlineAgentSchema } from '@agimon-ai/doompi-extension-contracts/subagent-tool';\nimport { type Static, Type } from 'typebox';\nimport { MAX_BRIEF_FILES } from '../delegation/manager.ts';\nimport type { TaskAction } from '../store/types.ts';\n\nexport const TASK_ACTIONS = ['upsert', 'list', 'get', 'delete', 'clear', 'assign', 'cancel'] as const;\nexport const TASK_STATUSES = ['pending', 'in_progress', 'completed', 'failed', 'deleted'] as const;\nexport const TASK_CONTEXTS = ['fresh', 'fork'] as const;\n\nexport const TOOL_NAME = 'task';\nexport const TOOL_LABEL = 'Task';\nexport const COMMAND_NAME = 'tasks';\n\nexport const ERR_REQUIRES_INTERACTIVE = '/tasks requires interactive mode';\nexport const MSG_NO_TASKS = 'No tasks yet. Ask the agent to add some!';\n\n/**\n * Which top-level fields each action accepts.\n *\n * The params object is flat and shared across every action, so the schema alone\n * cannot express \"upsert has no top-level id\". That gap matters: a call like\n * `{\"action\":\"upsert\",\"id\":3,\"tasks\":[{\"status\":\"completed\"}]}` would otherwise\n * silently create a duplicate task, because the entry itself carries no id.\n */\nexport const TASK_ACTION_FIELDS = {\n upsert: ['action', 'tasks'],\n list: ['action', 'status', 'includeDeleted'],\n get: ['action', 'id'],\n delete: ['action', 'id'],\n clear: ['action'],\n assign: [\n 'action',\n 'id',\n 'agent',\n 'inlineAgent',\n 'instructions',\n 'relevantFiles',\n 'priorFindings',\n 'model',\n 'context',\n ],\n cancel: ['action', 'id'],\n} as const satisfies Record<TaskAction, readonly string[]>;\n\nexport function taskActionAcceptsField(action: TaskAction, field: string): boolean {\n return (TASK_ACTION_FIELDS[action] as readonly string[]).includes(field);\n}\n\n/** Correction hint appended when a per-task field lands at the top level. */\nexport const MSG_UPSERT_FIELD_MISPLACED =\n 'Per-task fields belong inside each tasks[] entry, not at the top level: {\"action\":\"upsert\",\"tasks\":[{\"id\":3,\"status\":\"completed\"}]}.';\n\n/**\n * A dependency target: an existing task id, or the `ref` of a task created\n * earlier in the same call.\n */\nconst DepTokenSchema = Type.Union([Type.Integer(), Type.String()]);\n\n/**\n * One entry of an upsert. `additionalProperties: false` is load-bearing: pi\n * validates tool arguments against this schema before `execute` runs, so a\n * stray `{\"action\":\"update\"}` inside an entry is rejected at the boundary.\n */\nexport const TaskItemSchema = Type.Object(\n {\n id: Type.Optional(\n Type.Integer({\n description:\n 'Existing task id to change. Omit to create a new task. An entry with an id never creates: if the id is unknown, only that entry fails.',\n }),\n ),\n ref: Type.Optional(\n Type.String({\n description:\n 'Temporary name for a task created by this entry, so a LATER entry in the same tasks[] can list it in blockedBy before its real id exists. Must start with a letter. Scoped to this one call and never stored; the response reports which real id it became.',\n }),\n ),\n subject: Type.Optional(\n Type.String({\n description:\n \"Short imperative subject line (e.g. 'Research existing tool'). Required when the entry has no id; on an entry with an id it renames the task.\",\n }),\n ),\n description: Type.Optional(\n Type.String({\n description: 'Long-form task detail. This becomes the brief handed to the subagent when the task is assigned.',\n }),\n ),\n activeForm: Type.Optional(\n Type.String({\n description: \"Present-continuous spinner label shown while status is in_progress (e.g. 'writing tests')\",\n }),\n ),\n status: Type.Optional(\n Type.String({\n enum: [...TASK_STATUSES],\n description:\n 'Starting status for a new entry (default pending; deleted is rejected), or the target status for an entry with an id, where the transition must be legal.',\n }),\n ),\n blockedBy: Type.Optional(\n Type.Array(DepTokenSchema, {\n description:\n 'Dependencies for a NEW entry (one with no id): this task is blocked by each target. A number is an existing task id; a string is the ref of a task created by an EARLIER entry in this same array. Use addBlockedBy / removeBlockedBy on an entry that has an id.',\n }),\n ),\n addBlockedBy: Type.Optional(\n Type.Array(DepTokenSchema, {\n description:\n 'Dependencies to add, for an entry with an id. Task ids, or refs declared by an earlier entry. Additive merge — do not resend the full array.',\n }),\n ),\n removeBlockedBy: Type.Optional(\n Type.Array(DepTokenSchema, {\n description: 'Dependencies to remove, for an entry with an id. Additive merge — do not resend the full array.',\n }),\n ),\n owner: Type.Optional(\n Type.String({ description: 'Owner label for this task. assign sets this to the subagent name automatically.' }),\n ),\n metadata: Type.Optional(\n Type.Record(Type.String(), Type.Unknown(), {\n description: 'Arbitrary metadata merged into the task; pass null as a value to delete that key',\n }),\n ),\n },\n { additionalProperties: false },\n);\n\n/**\n * Tool parameters. Every `description` doubles as LLM-facing prompt copy, so\n * wording changes here change model behaviour.\n */\nexport const TaskParamsSchema = Type.Object({\n action: Type.String({\n enum: [...TASK_ACTIONS],\n description:\n 'upsert (create new tasks and change existing ones, one or many per call), list, get, delete (tombstone), clear (close/reset the list), assign (delegate to a subagent), cancel (stop a delegated run)',\n }),\n tasks: Type.Optional(\n Type.Array(TaskItemSchema, {\n minItems: 1,\n description:\n 'upsert only. One entry per task: an entry with an id changes that task, an entry without an id creates one. Entries apply in array order, so a later entry can depend on an earlier one by ref. Each entry succeeds or fails on its own: the ones that succeed are committed and the ones that fail are reported by their array index.',\n }),\n ),\n id: Type.Optional(\n Type.Integer({\n description:\n 'Task id, for get, delete, assign and cancel. upsert does not accept this field — put the id inside the tasks[] entry you want to change.',\n }),\n ),\n status: Type.Optional(\n Type.String({\n enum: [...TASK_STATUSES],\n description:\n 'list only: return just the tasks in this status. To SET a status, use upsert with the task id inside tasks[].',\n }),\n ),\n includeDeleted: Type.Optional(\n Type.Boolean({\n description: 'If true, list returns deleted (tombstoned) tasks as well. Default: false.',\n }),\n ),\n agent: Type.Optional(\n Type.String({\n description: 'Name of the subagent to delegate this task to (required for assign)',\n }),\n ),\n inlineAgent: Type.Optional(InlineAgentSchema),\n instructions: Type.Optional(\n Type.String({\n description: 'Extra instructions appended to the delegated brief (assign only)',\n }),\n ),\n relevantFiles: Type.Optional(\n Type.Array(Type.String(), {\n description: `Files you have ALREADY read or located that the subagent should open first (assign only). Paths relative to the working directory. A child starts with none of your context and otherwise spends most of its run rediscovering the repo. Send only files you actually looked at — a guessed path costs the child more than an omitted one. At most ${MAX_BRIEF_FILES}; extras are dropped.`,\n }),\n ),\n priorFindings: Type.Optional(\n Type.String({\n description:\n 'What you already established about this task and the subagent should not re-derive (assign only): symbol names, call sites, the approach you chose, what you already ruled out. Facts you discovered, not directives — put directives in instructions. Keep it to a few lines; it is truncated past ~1500 characters.',\n }),\n ),\n model: Type.Optional(Type.String({ description: 'Model override for the delegated run (assign only)' })),\n context: Type.Optional(\n Type.String({\n enum: [...TASK_CONTEXTS],\n description:\n \"Subagent starting context (assign only): 'fresh' starts clean, 'fork' inherits this conversation. If omitted, uses the agent default, then fresh.\",\n }),\n ),\n});\n\nexport type TaskItemParams = Static<typeof TaskItemSchema>;\nexport type TaskParams = Static<typeof TaskParamsSchema>;\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"schema.d.cts","names":[],"sources":["../../src/tool/schema.ts"],"mappings":";;;cAKa;cACA;cACA;cAEA;cACA;cACA;cAEA;cACA;;;;;;;;;cAUA;;;;;;;;;iBAoBG,uBAAuB,QAAQ,YAAY;;cAK9C;;;;;;cAcA,gBAAc,KAAA;;;;;;;;;;;;;;;;;cAsEd,kBAAgB,KAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA+DjB,iBAAiB,cAAc;KAC/B,aAAa,cAAc"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"schema.d.mts","names":[],"sources":["../../src/tool/schema.ts"],"mappings":";;;cAKa;cACA;cACA;cAEA;cACA;cACA;cAEA;cACA;;;;;;;;;cAUA;;;;;;;;;iBAoBG,uBAAuB,QAAQ,YAAY;;cAK9C;;;;;;cAcA,gBAAc,KAAA;;;;;;;;;;;;;;;;;cAsEd,kBAAgB,KAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA+DjB,iBAAiB,cAAc;KAC/B,aAAa,cAAc"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"schema.mjs","names":[],"sources":["../../src/tool/schema.ts"],"sourcesContent":["import { InlineAgentSchema } from '@agimon-ai/doompi-extension-contracts/subagent-tool';\nimport { type Static, Type } from 'typebox';\nimport { MAX_BRIEF_FILES } from '../delegation/manager.ts';\nimport type { TaskAction } from '../store/types.ts';\n\nexport const TASK_ACTIONS = ['upsert', 'list', 'get', 'delete', 'clear', 'assign', 'cancel'] as const;\nexport const TASK_STATUSES = ['pending', 'in_progress', 'completed', 'failed', 'deleted'] as const;\nexport const TASK_CONTEXTS = ['fresh', 'fork'] as const;\n\nexport const TOOL_NAME = 'task';\nexport const TOOL_LABEL = 'Task';\nexport const COMMAND_NAME = 'tasks';\n\nexport const ERR_REQUIRES_INTERACTIVE = '/tasks requires interactive mode';\nexport const MSG_NO_TASKS = 'No tasks yet. Ask the agent to add some!';\n\n/**\n * Which top-level fields each action accepts.\n *\n * The params object is flat and shared across every action, so the schema alone\n * cannot express \"upsert has no top-level id\". That gap matters: a call like\n * `{\"action\":\"upsert\",\"id\":3,\"tasks\":[{\"status\":\"completed\"}]}` would otherwise\n * silently create a duplicate task, because the entry itself carries no id.\n */\nexport const TASK_ACTION_FIELDS = {\n upsert: ['action', 'tasks'],\n list: ['action', 'status', 'includeDeleted'],\n get: ['action', 'id'],\n delete: ['action', 'id'],\n clear: ['action'],\n assign: [\n 'action',\n 'id',\n 'agent',\n 'inlineAgent',\n 'instructions',\n 'relevantFiles',\n 'priorFindings',\n 'model',\n 'context',\n ],\n cancel: ['action', 'id'],\n} as const satisfies Record<TaskAction, readonly string[]>;\n\nexport function taskActionAcceptsField(action: TaskAction, field: string): boolean {\n return (TASK_ACTION_FIELDS[action] as readonly string[]).includes(field);\n}\n\n/** Correction hint appended when a per-task field lands at the top level. */\nexport const MSG_UPSERT_FIELD_MISPLACED =\n 'Per-task fields belong inside each tasks[] entry, not at the top level: {\"action\":\"upsert\",\"tasks\":[{\"id\":3,\"status\":\"completed\"}]}.';\n\n/**\n * A dependency target: an existing task id, or the `ref` of a task created\n * earlier in the same call.\n */\nconst DepTokenSchema = Type.Union([Type.Integer(), Type.String()]);\n\n/**\n * One entry of an upsert. `additionalProperties: false` is load-bearing: pi\n * validates tool arguments against this schema before `execute` runs, so a\n * stray `{\"action\":\"update\"}` inside an entry is rejected at the boundary.\n */\nexport const TaskItemSchema = Type.Object(\n {\n id: Type.Optional(\n Type.Integer({\n description:\n 'Existing task id to change. Omit to create a new task. An entry with an id never creates: if the id is unknown, only that entry fails.',\n }),\n ),\n ref: Type.Optional(\n Type.String({\n description:\n 'Temporary name for a task created by this entry, so a LATER entry in the same tasks[] can list it in blockedBy before its real id exists. Must start with a letter. Scoped to this one call and never stored; the response reports which real id it became.',\n }),\n ),\n subject: Type.Optional(\n Type.String({\n description:\n \"Short imperative subject line (e.g. 'Research existing tool'). Required when the entry has no id; on an entry with an id it renames the task.\",\n }),\n ),\n description: Type.Optional(\n Type.String({\n description: 'Long-form task detail. This becomes the brief handed to the subagent when the task is assigned.',\n }),\n ),\n activeForm: Type.Optional(\n Type.String({\n description: \"Present-continuous spinner label shown while status is in_progress (e.g. 'writing tests')\",\n }),\n ),\n status: Type.Optional(\n Type.String({\n enum: [...TASK_STATUSES],\n description:\n 'Starting status for a new entry (default pending; deleted is rejected), or the target status for an entry with an id, where the transition must be legal.',\n }),\n ),\n blockedBy: Type.Optional(\n Type.Array(DepTokenSchema, {\n description:\n 'Dependencies for a NEW entry (one with no id): this task is blocked by each target. A number is an existing task id; a string is the ref of a task created by an EARLIER entry in this same array. Use addBlockedBy / removeBlockedBy on an entry that has an id.',\n }),\n ),\n addBlockedBy: Type.Optional(\n Type.Array(DepTokenSchema, {\n description:\n 'Dependencies to add, for an entry with an id. Task ids, or refs declared by an earlier entry. Additive merge — do not resend the full array.',\n }),\n ),\n removeBlockedBy: Type.Optional(\n Type.Array(DepTokenSchema, {\n description: 'Dependencies to remove, for an entry with an id. Additive merge — do not resend the full array.',\n }),\n ),\n owner: Type.Optional(\n Type.String({ description: 'Owner label for this task. assign sets this to the subagent name automatically.' }),\n ),\n metadata: Type.Optional(\n Type.Record(Type.String(), Type.Unknown(), {\n description: 'Arbitrary metadata merged into the task; pass null as a value to delete that key',\n }),\n ),\n },\n { additionalProperties: false },\n);\n\n/**\n * Tool parameters. Every `description` doubles as LLM-facing prompt copy, so\n * wording changes here change model behaviour.\n */\nexport const TaskParamsSchema = Type.Object({\n action: Type.String({\n enum: [...TASK_ACTIONS],\n description:\n 'upsert (create new tasks and change existing ones, one or many per call), list, get, delete (tombstone), clear (close/reset the list), assign (delegate to a subagent), cancel (stop a delegated run)',\n }),\n tasks: Type.Optional(\n Type.Array(TaskItemSchema, {\n minItems: 1,\n description:\n 'upsert only. One entry per task: an entry with an id changes that task, an entry without an id creates one. Entries apply in array order, so a later entry can depend on an earlier one by ref. Each entry succeeds or fails on its own: the ones that succeed are committed and the ones that fail are reported by their array index.',\n }),\n ),\n id: Type.Optional(\n Type.Integer({\n description:\n 'Task id, for get, delete, assign and cancel. upsert does not accept this field — put the id inside the tasks[] entry you want to change.',\n }),\n ),\n status: Type.Optional(\n Type.String({\n enum: [...TASK_STATUSES],\n description:\n 'list only: return just the tasks in this status. To SET a status, use upsert with the task id inside tasks[].',\n }),\n ),\n includeDeleted: Type.Optional(\n Type.Boolean({\n description: 'If true, list returns deleted (tombstoned) tasks as well. Default: false.',\n }),\n ),\n agent: Type.Optional(\n Type.String({\n description: 'Name of the subagent to delegate this task to (required for assign)',\n }),\n ),\n inlineAgent: Type.Optional(InlineAgentSchema),\n instructions: Type.Optional(\n Type.String({\n description: 'Extra instructions appended to the delegated brief (assign only)',\n }),\n ),\n relevantFiles: Type.Optional(\n Type.Array(Type.String(), {\n description: `Files you have ALREADY read or located that the subagent should open first (assign only). Paths relative to the working directory. A child starts with none of your context and otherwise spends most of its run rediscovering the repo. Send only files you actually looked at — a guessed path costs the child more than an omitted one. At most ${MAX_BRIEF_FILES}; extras are dropped.`,\n }),\n ),\n priorFindings: Type.Optional(\n Type.String({\n description:\n 'What you already established about this task and the subagent should not re-derive (assign only): symbol names, call sites, the approach you chose, what you already ruled out. Facts you discovered, not directives — put directives in instructions. Keep it to a few lines; it is truncated past ~1500 characters.',\n }),\n ),\n model: Type.Optional(Type.String({ description: 'Model override for the delegated run (assign only)' })),\n context: Type.Optional(\n Type.String({\n enum: [...TASK_CONTEXTS],\n description:\n \"Subagent starting context (assign only): 'fresh' starts clean, 'fork' inherits this conversation. If omitted, uses the agent default, then fresh.\",\n }),\n ),\n});\n\nexport type TaskItemParams = Static<typeof TaskItemSchema>;\nexport type TaskParams = Static<typeof TaskParamsSchema>;\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"taskTool.cjs","names":["taskActionAcceptsField","MSG_UPSERT_FIELD_MISPLACED","applyTaskMutation","isCommittingOp","formatUpsertFailureText","buildToolResult","TOOL_NAME","TOOL_LABEL","DEFAULT_PROMPT_GUIDELINES","TaskParamsSchema","buildTextResult","TASK_EVENT","renderTaskCall","renderTaskResult"],"sources":["../../src/tool/taskTool.ts"],"sourcesContent":["import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport type { DelegationManager, DelegationOutcome } from '../delegation/manager.ts';\nimport { TASK_EVENT, type TaskFailureReporter } from '../logSinkTelemetry.ts';\nimport { applyTaskMutation, isCommittingOp, type ReducerAction } from '../store/reducer.ts';\nimport type { TaskStore } from '../store/taskStore.ts';\nimport type { TaskAction, TaskMutationParams } from '../store/types.ts';\nimport { renderTaskCall, renderTaskResult } from '../tui/format.ts';\nimport { buildTextResult, buildToolResult, formatUpsertFailureText, type ToolResult } from './responseEnvelope.ts';\nimport {\n MSG_UPSERT_FIELD_MISPLACED,\n TOOL_LABEL,\n TOOL_NAME,\n TaskParamsSchema,\n taskActionAcceptsField,\n} from './schema.ts';\nimport { DEFAULT_PROMPT_GUIDELINES } from './promptGuidelines.ts';\nexport { DEFAULT_PROMPT_GUIDELINES } from './promptGuidelines.ts';\n\nexport const DEFAULT_PROMPT_SNIPPET =\n 'Manage a shared task list to track multi-step progress, and delegate tasks to subagents';\n\nexport interface TaskToolDependencies {\n store: TaskStore;\n delegation: DelegationManager;\n onChange?: () => void;\n report?: TaskFailureReporter;\n}\n\nconst ACTION_ATTRIBUTE = 'tool.action';\nconst TASK_ID_ATTRIBUTE = 'task.id';\n\nconst REDUCER_ACTIONS = new Set<TaskAction>(['upsert', 'list', 'get', 'delete', 'clear']);\n\nclass TaskToolExecutionError extends Error {}\n\nfunction actionableTaskError(action: TaskAction, message: string): TaskToolExecutionError {\n return new TaskToolExecutionError(\n [\n `Task ${action} failed: ${message}`,\n '',\n 'Options:',\n '- List the task board and inspect the current ids, states, and blockers.',\n '- Correct the arguments or state conflict, then retry once.',\n '- Ask the user before cancelling work or changing dependencies to recover.',\n ].join('\\n'),\n );\n}\n\n/**\n * Reject a field that belongs to a different action.\n *\n * The params schema is flat and shared across every action, so this is the only\n * place `{\"action\":\"upsert\",\"id\":3}` can be caught — and it must be, because\n * the entry it carries has no id and would silently create a duplicate task.\n */\nfunction rejectStrayFields(action: TaskAction, params: TaskMutationParams): void {\n const stray = Object.keys(params).filter((key) => params[key] !== undefined && !taskActionAcceptsField(action, key));\n if (stray.length === 0) return;\n const hint = action === 'upsert' ? ` ${MSG_UPSERT_FIELD_MISPLACED}` : '';\n throw actionableTaskError(action, `${action} does not accept ${stray.join(', ')}.${hint}`);\n}\n\n/** Run an action through the reducer, persisting only when it produced a change. */\nasync function executeReducerAction(\n store: TaskStore,\n action: ReducerAction,\n params: TaskMutationParams,\n): Promise<ToolResult> {\n const { document, value } = await store.mutate((current) => {\n const result = applyTaskMutation(current, action, params);\n return {\n ...(isCommittingOp(result.op) ? { document: result.document } : {}),\n value: result,\n };\n });\n if (value.op.kind === 'error') throw actionableTaskError(action, value.op.message);\n // An upsert that applied nothing is a failed call: it wrote nothing and left\n // `rev` alone, so it must not read to the model as a success. A batch where\n // some entries landed returns normally — that is what partial apply means.\n if (value.op.kind === 'upsert' && value.op.applied === 0) {\n throw actionableTaskError(action, formatUpsertFailureText(value.op));\n }\n // `document` is the committed document, so `details.rev` matches what landed\n // on disk; `value.document` is the pre-write copy and lags by one.\n return buildToolResult(action, params, document, value.op);\n}\n\nexport function registerTaskTool(pi: ExtensionAPI, dependencies: TaskToolDependencies): void {\n const { store, delegation } = dependencies;\n\n pi.registerTool({\n name: TOOL_NAME,\n label: TOOL_LABEL,\n description:\n 'Manage a shared task list for tracking multi-step progress, and delegate tasks to subagents. Actions: upsert (write tasks — a tasks[] array where an entry with an id changes that task and an entry without an id creates one, so one call can capture a whole plan), list, get, delete (tombstone), clear (close/reset the list), assign (hand the task to a named subagent that works it in the background), cancel (stop a delegated run). upsert applies each entry independently: successes are committed and failures are reported by array index, and an entry can depend on a task created by an earlier entry in the same call via a ref. Batch when writing a plan down; report progress one task at a time. Status: pending → in_progress → completed, plus failed and a deleted tombstone. The list is shared within the current session tree, including delegated subagents, while unrelated sessions start empty. Session stores persist until retention cleanup.',\n promptSnippet: DEFAULT_PROMPT_SNIPPET,\n promptGuidelines: DEFAULT_PROMPT_GUIDELINES,\n parameters: TaskParamsSchema,\n\n async execute(_toolCallId, params, signal, onUpdate, _ctx) {\n const action = params.action as TaskAction;\n const mutationParams = params as TaskMutationParams;\n\n try {\n rejectStrayFields(action, mutationParams);\n if (REDUCER_ACTIONS.has(action)) {\n const result = await executeReducerAction(store, action as ReducerAction, mutationParams);\n dependencies.onChange?.();\n return result;\n }\n\n let outcome: DelegationOutcome;\n if (action === 'assign') {\n onUpdate?.(\n buildTextResult(\n action,\n mutationParams,\n store.snapshot,\n `Delegating task #${mutationParams.id ?? 'unknown'}...`,\n ),\n );\n outcome = await delegation.assign(mutationParams.id ?? Number.NaN, {\n agent: mutationParams.agent,\n inlineAgent: mutationParams.inlineAgent,\n instructions: mutationParams.instructions,\n relevantFiles: mutationParams.relevantFiles,\n priorFindings: mutationParams.priorFindings,\n model: mutationParams.model,\n context: mutationParams.context,\n signal,\n });\n } else {\n onUpdate?.(\n buildTextResult(\n action,\n mutationParams,\n store.snapshot,\n `Requesting cancellation for task #${mutationParams.id ?? 'unknown'}...`,\n ),\n );\n outcome = await delegation.cancel(mutationParams.id ?? Number.NaN);\n }\n\n dependencies.onChange?.();\n if (!outcome.ok) throw actionableTaskError(action, outcome.message);\n return buildTextResult(action, mutationParams, store.snapshot, outcome.message, undefined);\n } catch (error) {\n // Rethrown so pi still renders the failure to the model; recorded\n // because this is where a store fault becomes visible to the user.\n dependencies.report?.error(TASK_EVENT.toolFailed, error, {\n [ACTION_ATTRIBUTE]: action,\n ...(mutationParams.id === undefined ? {} : { [TASK_ID_ATTRIBUTE]: mutationParams.id }),\n });\n if (error instanceof TaskToolExecutionError) throw error;\n throw actionableTaskError(action, error instanceof Error ? error.message : String(error));\n }\n },\n\n // Render hooks receive no session identity, so they read the store snapshot\n // that the executing session last loaded. That is the foreground session's\n // own view, which is exactly what its transcript should show.\n renderCall(args, theme, _context) {\n return renderTaskCall(args as never, theme, store.snapshot.tasks);\n },\n\n renderResult(result, options, theme, _context) {\n return renderTaskResult(result, options, theme);\n },\n });\n}\n"],"mappings":"iRAkBa,EACX,0FAYI,EAAkB,IAAI,IAAgB,CAAC,SAAU,OAAQ,MAAO,SAAU,OAAO,CAAC,EAExF,IAAM,EAAN,cAAqC,KAAM,CAAC,EAE5C,SAAS,EAAoB,EAAoB,EAAyC,CACxF,OAAO,IAAI,EACT,CACE,QAAQ,EAAO,WAAW,IAC1B,GACA,WACA,2EACA,8DACA,4EACF,CAAC,CAAC,KAAK;CAAI,CACb,CACF,CASA,SAAS,EAAkB,EAAoB,EAAkC,CAC/E,IAAM,EAAQ,OAAO,KAAK,CAAM,CAAC,CAAC,OAAQ,GAAQ,EAAO,KAAS,IAAA,IAAa,CAACA,EAAAA,uBAAuB,EAAQ,CAAG,CAAC,EACnH,GAAI,EAAM,SAAW,EAAG,OACxB,IAAM,EAAO,IAAW,SAAW,IAAIC,EAAAA,6BAA+B,GACtE,MAAM,EAAoB,EAAQ,GAAG,EAAO,mBAAmB,EAAM,KAAK,IAAI,EAAE,GAAG,GAAM,CAC3F,CAGA,eAAe,EACb,EACA,EACA,EACqB,CACrB,GAAM,CAAE,WAAU,SAAU,MAAM,EAAM,OAAQ,GAAY,CAC1D,IAAM,EAASC,EAAAA,kBAAkB,EAAS,EAAQ,CAAM,EACxD,MAAO,CACL,GAAIC,EAAAA,eAAe,EAAO,EAAE,EAAI,CAAE,SAAU,EAAO,QAAS,EAAI,CAAC,EACjE,MAAO,CACT,CACF,CAAC,EACD,GAAI,EAAM,GAAG,OAAS,QAAS,MAAM,EAAoB,EAAQ,EAAM,GAAG,OAAO,EAIjF,GAAI,EAAM,GAAG,OAAS,UAAY,EAAM,GAAG,UAAY,EACrD,MAAM,EAAoB,EAAQC,EAAAA,wBAAwB,EAAM,EAAE,CAAC,EAIrE,OAAOC,EAAAA,gBAAgB,EAAQ,EAAQ,EAAU,EAAM,EAAE,CAC3D,CAEA,SAAgB,EAAiB,EAAkB,EAA0C,CAC3F,GAAM,CAAE,QAAO,cAAe,EAE9B,EAAG,aAAa,CACd,KAAMC,EAAAA,UACN,MAAOC,EAAAA,WACP,YACE,m7BACF,cAAe,EACf,iBAAkBC,EAAAA,0BAClB,WAAYC,EAAAA,iBAEZ,MAAM,QAAQ,EAAa,EAAQ,EAAQ,EAAU,EAAM,CACzD,IAAM,EAAS,EAAO,OAChB,EAAiB,EAEvB,GAAI,CAEF,GADA,EAAkB,EAAQ,CAAc,EACpC,EAAgB,IAAI,CAAM,EAAG,CAC/B,IAAM,EAAS,MAAM,EAAqB,EAAO,EAAyB,CAAc,EAExF,OADA,EAAa,WAAW,EACjB,CACT,CAEA,IAAI,EAiCJ,GAhCI,IAAW,UACb,IACEC,EAAAA,gBACE,EACA,EACA,EAAM,SACN,oBAAoB,EAAe,IAAM,UAAU,IACrD,CACF,EACA,EAAU,MAAM,EAAW,OAAO,EAAe,IAAM,IAAY,CACjE,MAAO,EAAe,MACtB,YAAa,EAAe,YAC5B,aAAc,EAAe,aAC7B,cAAe,EAAe,cAC9B,cAAe,EAAe,cAC9B,MAAO,EAAe,MACtB,QAAS,EAAe,QACxB,QACF,CAAC,IAED,IACEA,EAAAA,gBACE,EACA,EACA,EAAM,SACN,qCAAqC,EAAe,IAAM,UAAU,IACtE,CACF,EACA,EAAU,MAAM,EAAW,OAAO,EAAe,IAAM,GAAU,GAGnE,EAAa,WAAW,EACpB,CAAC,EAAQ,GAAI,MAAM,EAAoB,EAAQ,EAAQ,OAAO,EAClE,OAAOA,EAAAA,gBAAgB,EAAQ,EAAgB,EAAM,SAAU,EAAQ,QAAS,IAAA,EAAS,CAC3F,OAAS,EAAO,CAQd,MALA,EAAa,QAAQ,MAAMC,EAAAA,WAAW,WAAY,EAAO,CACtD,cAAmB,EACpB,GAAI,EAAe,KAAO,IAAA,GAAY,CAAC,EAAI,CAAG,UAAoB,EAAe,EAAG,CACtF,CAAC,EACG,aAAiB,EAA8B,EAC7C,EAAoB,EAAQ,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,CAAC,CAC1F,CACF,EAKA,WAAW,EAAM,EAAO,EAAU,CAChC,OAAOC,EAAAA,eAAe,EAAe,EAAO,EAAM,SAAS,KAAK,CAClE,EAEA,aAAa,EAAQ,EAAS,EAAO,EAAU,CAC7C,OAAOC,EAAAA,iBAAiB,EAAQ,EAAS,CAAK,CAChD,CACF,CAAC,CACH"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"taskTool.d.cts","names":[],"sources":["../../src/tool/taskTool.ts"],"mappings":";;;;;;cAkBa;UAGI;EACf,OAAO;EACP,YAAY;EACZ;EACA,SAAS;;iBA8DK,iBAAiB,IAAI,cAAc,cAAc"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"taskTool.d.mts","names":[],"sources":["../../src/tool/taskTool.ts"],"mappings":";;;;;;cAkBa;UAGI;EACf,OAAO;EACP,YAAY;EACZ;EACA,SAAS;;iBA8DK,iBAAiB,IAAI,cAAc,cAAc"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"taskTool.mjs","names":[],"sources":["../../src/tool/taskTool.ts"],"sourcesContent":["import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport type { DelegationManager, DelegationOutcome } from '../delegation/manager.ts';\nimport { TASK_EVENT, type TaskFailureReporter } from '../logSinkTelemetry.ts';\nimport { applyTaskMutation, isCommittingOp, type ReducerAction } from '../store/reducer.ts';\nimport type { TaskStore } from '../store/taskStore.ts';\nimport type { TaskAction, TaskMutationParams } from '../store/types.ts';\nimport { renderTaskCall, renderTaskResult } from '../tui/format.ts';\nimport { buildTextResult, buildToolResult, formatUpsertFailureText, type ToolResult } from './responseEnvelope.ts';\nimport {\n MSG_UPSERT_FIELD_MISPLACED,\n TOOL_LABEL,\n TOOL_NAME,\n TaskParamsSchema,\n taskActionAcceptsField,\n} from './schema.ts';\nimport { DEFAULT_PROMPT_GUIDELINES } from './promptGuidelines.ts';\nexport { DEFAULT_PROMPT_GUIDELINES } from './promptGuidelines.ts';\n\nexport const DEFAULT_PROMPT_SNIPPET =\n 'Manage a shared task list to track multi-step progress, and delegate tasks to subagents';\n\nexport interface TaskToolDependencies {\n store: TaskStore;\n delegation: DelegationManager;\n onChange?: () => void;\n report?: TaskFailureReporter;\n}\n\nconst ACTION_ATTRIBUTE = 'tool.action';\nconst TASK_ID_ATTRIBUTE = 'task.id';\n\nconst REDUCER_ACTIONS = new Set<TaskAction>(['upsert', 'list', 'get', 'delete', 'clear']);\n\nclass TaskToolExecutionError extends Error {}\n\nfunction actionableTaskError(action: TaskAction, message: string): TaskToolExecutionError {\n return new TaskToolExecutionError(\n [\n `Task ${action} failed: ${message}`,\n '',\n 'Options:',\n '- List the task board and inspect the current ids, states, and blockers.',\n '- Correct the arguments or state conflict, then retry once.',\n '- Ask the user before cancelling work or changing dependencies to recover.',\n ].join('\\n'),\n );\n}\n\n/**\n * Reject a field that belongs to a different action.\n *\n * The params schema is flat and shared across every action, so this is the only\n * place `{\"action\":\"upsert\",\"id\":3}` can be caught — and it must be, because\n * the entry it carries has no id and would silently create a duplicate task.\n */\nfunction rejectStrayFields(action: TaskAction, params: TaskMutationParams): void {\n const stray = Object.keys(params).filter((key) => params[key] !== undefined && !taskActionAcceptsField(action, key));\n if (stray.length === 0) return;\n const hint = action === 'upsert' ? ` ${MSG_UPSERT_FIELD_MISPLACED}` : '';\n throw actionableTaskError(action, `${action} does not accept ${stray.join(', ')}.${hint}`);\n}\n\n/** Run an action through the reducer, persisting only when it produced a change. */\nasync function executeReducerAction(\n store: TaskStore,\n action: ReducerAction,\n params: TaskMutationParams,\n): Promise<ToolResult> {\n const { document, value } = await store.mutate((current) => {\n const result = applyTaskMutation(current, action, params);\n return {\n ...(isCommittingOp(result.op) ? { document: result.document } : {}),\n value: result,\n };\n });\n if (value.op.kind === 'error') throw actionableTaskError(action, value.op.message);\n // An upsert that applied nothing is a failed call: it wrote nothing and left\n // `rev` alone, so it must not read to the model as a success. A batch where\n // some entries landed returns normally — that is what partial apply means.\n if (value.op.kind === 'upsert' && value.op.applied === 0) {\n throw actionableTaskError(action, formatUpsertFailureText(value.op));\n }\n // `document` is the committed document, so `details.rev` matches what landed\n // on disk; `value.document` is the pre-write copy and lags by one.\n return buildToolResult(action, params, document, value.op);\n}\n\nexport function registerTaskTool(pi: ExtensionAPI, dependencies: TaskToolDependencies): void {\n const { store, delegation } = dependencies;\n\n pi.registerTool({\n name: TOOL_NAME,\n label: TOOL_LABEL,\n description:\n 'Manage a shared task list for tracking multi-step progress, and delegate tasks to subagents. Actions: upsert (write tasks — a tasks[] array where an entry with an id changes that task and an entry without an id creates one, so one call can capture a whole plan), list, get, delete (tombstone), clear (close/reset the list), assign (hand the task to a named subagent that works it in the background), cancel (stop a delegated run). upsert applies each entry independently: successes are committed and failures are reported by array index, and an entry can depend on a task created by an earlier entry in the same call via a ref. Batch when writing a plan down; report progress one task at a time. Status: pending → in_progress → completed, plus failed and a deleted tombstone. The list is shared within the current session tree, including delegated subagents, while unrelated sessions start empty. Session stores persist until retention cleanup.',\n promptSnippet: DEFAULT_PROMPT_SNIPPET,\n promptGuidelines: DEFAULT_PROMPT_GUIDELINES,\n parameters: TaskParamsSchema,\n\n async execute(_toolCallId, params, signal, onUpdate, _ctx) {\n const action = params.action as TaskAction;\n const mutationParams = params as TaskMutationParams;\n\n try {\n rejectStrayFields(action, mutationParams);\n if (REDUCER_ACTIONS.has(action)) {\n const result = await executeReducerAction(store, action as ReducerAction, mutationParams);\n dependencies.onChange?.();\n return result;\n }\n\n let outcome: DelegationOutcome;\n if (action === 'assign') {\n onUpdate?.(\n buildTextResult(\n action,\n mutationParams,\n store.snapshot,\n `Delegating task #${mutationParams.id ?? 'unknown'}...`,\n ),\n );\n outcome = await delegation.assign(mutationParams.id ?? Number.NaN, {\n agent: mutationParams.agent,\n inlineAgent: mutationParams.inlineAgent,\n instructions: mutationParams.instructions,\n relevantFiles: mutationParams.relevantFiles,\n priorFindings: mutationParams.priorFindings,\n model: mutationParams.model,\n context: mutationParams.context,\n signal,\n });\n } else {\n onUpdate?.(\n buildTextResult(\n action,\n mutationParams,\n store.snapshot,\n `Requesting cancellation for task #${mutationParams.id ?? 'unknown'}...`,\n ),\n );\n outcome = await delegation.cancel(mutationParams.id ?? Number.NaN);\n }\n\n dependencies.onChange?.();\n if (!outcome.ok) throw actionableTaskError(action, outcome.message);\n return buildTextResult(action, mutationParams, store.snapshot, outcome.message, undefined);\n } catch (error) {\n // Rethrown so pi still renders the failure to the model; recorded\n // because this is where a store fault becomes visible to the user.\n dependencies.report?.error(TASK_EVENT.toolFailed, error, {\n [ACTION_ATTRIBUTE]: action,\n ...(mutationParams.id === undefined ? {} : { [TASK_ID_ATTRIBUTE]: mutationParams.id }),\n });\n if (error instanceof TaskToolExecutionError) throw error;\n throw actionableTaskError(action, error instanceof Error ? error.message : String(error));\n }\n },\n\n // Render hooks receive no session identity, so they read the store snapshot\n // that the executing session last loaded. That is the foreground session's\n // own view, which is exactly what its transcript should show.\n renderCall(args, theme, _context) {\n return renderTaskCall(args as never, theme, store.snapshot.tasks);\n },\n\n renderResult(result, options, theme, _context) {\n return renderTaskResult(result, options, theme);\n },\n });\n}\n"],"mappings":"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"}