monday-cli 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (418) hide show
  1. package/CHANGELOG.md +324 -2
  2. package/README.md +128 -30
  3. package/dist/api/board-favorites.d.ts +329 -0
  4. package/dist/api/board-favorites.d.ts.map +1 -0
  5. package/dist/api/board-favorites.js +353 -0
  6. package/dist/api/board-favorites.js.map +1 -0
  7. package/dist/api/board-mutation-result.d.ts +9 -5
  8. package/dist/api/board-mutation-result.d.ts.map +1 -1
  9. package/dist/api/board-mutation-result.js +9 -5
  10. package/dist/api/board-mutation-result.js.map +1 -1
  11. package/dist/api/board-relation-validation.d.ts +161 -0
  12. package/dist/api/board-relation-validation.d.ts.map +1 -0
  13. package/dist/api/board-relation-validation.js +317 -0
  14. package/dist/api/board-relation-validation.js.map +1 -0
  15. package/dist/api/cache.d.ts +14 -5
  16. package/dist/api/cache.d.ts.map +1 -1
  17. package/dist/api/cache.js +8 -10
  18. package/dist/api/cache.js.map +1 -1
  19. package/dist/api/column-mapping.js +2 -2
  20. package/dist/api/column-mapping.js.map +1 -1
  21. package/dist/api/column-mutation-result.d.ts +9 -5
  22. package/dist/api/column-mutation-result.d.ts.map +1 -1
  23. package/dist/api/column-mutation-result.js +9 -5
  24. package/dist/api/column-mutation-result.js.map +1 -1
  25. package/dist/api/column-types.d.ts +26 -7
  26. package/dist/api/column-types.d.ts.map +1 -1
  27. package/dist/api/column-types.js +42 -3
  28. package/dist/api/column-types.js.map +1 -1
  29. package/dist/api/column-values.d.ts +228 -31
  30. package/dist/api/column-values.d.ts.map +1 -1
  31. package/dist/api/column-values.js +551 -124
  32. package/dist/api/column-values.js.map +1 -1
  33. package/dist/api/cross-board-search.d.ts +501 -0
  34. package/dist/api/cross-board-search.d.ts.map +1 -0
  35. package/dist/api/cross-board-search.js +547 -0
  36. package/dist/api/cross-board-search.js.map +1 -0
  37. package/dist/api/dev-conventions.d.ts +1038 -0
  38. package/dist/api/dev-conventions.d.ts.map +1 -0
  39. package/dist/api/dev-conventions.js +1556 -0
  40. package/dist/api/dev-conventions.js.map +1 -0
  41. package/dist/api/dry-run.d.ts +32 -5
  42. package/dist/api/dry-run.d.ts.map +1 -1
  43. package/dist/api/dry-run.js +149 -32
  44. package/dist/api/dry-run.js.map +1 -1
  45. package/dist/api/errors.d.ts.map +1 -1
  46. package/dist/api/errors.js +28 -7
  47. package/dist/api/errors.js.map +1 -1
  48. package/dist/api/group-mutation-result.d.ts +9 -5
  49. package/dist/api/group-mutation-result.d.ts.map +1 -1
  50. package/dist/api/group-mutation-result.js +9 -5
  51. package/dist/api/group-mutation-result.js.map +1 -1
  52. package/dist/api/item-history-projection.d.ts +919 -0
  53. package/dist/api/item-history-projection.d.ts.map +1 -0
  54. package/dist/api/item-history-projection.js +1104 -0
  55. package/dist/api/item-history-projection.js.map +1 -0
  56. package/dist/api/item-mutation-execute.d.ts +82 -0
  57. package/dist/api/item-mutation-execute.d.ts.map +1 -0
  58. package/dist/api/item-mutation-execute.js +199 -0
  59. package/dist/api/item-mutation-execute.js.map +1 -0
  60. package/dist/api/notifications.d.ts +156 -0
  61. package/dist/api/notifications.d.ts.map +1 -0
  62. package/dist/api/notifications.js +215 -0
  63. package/dist/api/notifications.js.map +1 -0
  64. package/dist/api/oauth-test-helper.d.ts +64 -0
  65. package/dist/api/oauth-test-helper.d.ts.map +1 -0
  66. package/dist/api/oauth-test-helper.js +179 -0
  67. package/dist/api/oauth-test-helper.js.map +1 -0
  68. package/dist/api/oauth.d.ts +198 -0
  69. package/dist/api/oauth.d.ts.map +1 -0
  70. package/dist/api/oauth.js +471 -0
  71. package/dist/api/oauth.js.map +1 -0
  72. package/dist/api/partial-success-bulk.d.ts +422 -0
  73. package/dist/api/partial-success-bulk.d.ts.map +1 -0
  74. package/dist/api/partial-success-bulk.js +378 -0
  75. package/dist/api/partial-success-bulk.js.map +1 -0
  76. package/dist/api/people.d.ts +54 -1
  77. package/dist/api/people.d.ts.map +1 -1
  78. package/dist/api/people.js +27 -3
  79. package/dist/api/people.js.map +1 -1
  80. package/dist/api/probes.d.ts +487 -0
  81. package/dist/api/probes.d.ts.map +1 -0
  82. package/dist/api/probes.js +881 -0
  83. package/dist/api/probes.js.map +1 -0
  84. package/dist/api/raw-document.d.ts.map +1 -1
  85. package/dist/api/raw-document.js +2 -2
  86. package/dist/api/raw-document.js.map +1 -1
  87. package/dist/api/raw-write.d.ts.map +1 -1
  88. package/dist/api/raw-write.js +11 -3
  89. package/dist/api/raw-write.js.map +1 -1
  90. package/dist/api/resolution-context.d.ts +23 -11
  91. package/dist/api/resolution-context.d.ts.map +1 -1
  92. package/dist/api/resolution-context.js +53 -12
  93. package/dist/api/resolution-context.js.map +1 -1
  94. package/dist/api/resolution-pass.d.ts +30 -1
  95. package/dist/api/resolution-pass.d.ts.map +1 -1
  96. package/dist/api/resolution-pass.js +36 -1
  97. package/dist/api/resolution-pass.js.map +1 -1
  98. package/dist/api/resolve-client.d.ts +11 -0
  99. package/dist/api/resolve-client.d.ts.map +1 -1
  100. package/dist/api/resolve-client.js +1 -1
  101. package/dist/api/resolve-client.js.map +1 -1
  102. package/dist/api/response-root.d.ts +92 -46
  103. package/dist/api/response-root.d.ts.map +1 -1
  104. package/dist/api/response-root.js +93 -41
  105. package/dist/api/response-root.js.map +1 -1
  106. package/dist/api/tag-directory.d.ts +154 -0
  107. package/dist/api/tag-directory.d.ts.map +1 -0
  108. package/dist/api/tag-directory.js +325 -0
  109. package/dist/api/tag-directory.js.map +1 -0
  110. package/dist/api/time-tracking.d.ts +165 -0
  111. package/dist/api/time-tracking.d.ts.map +1 -0
  112. package/dist/api/time-tracking.js +135 -0
  113. package/dist/api/time-tracking.js.map +1 -0
  114. package/dist/api/transport.js +3 -3
  115. package/dist/api/transport.js.map +1 -1
  116. package/dist/api/usage.d.ts +190 -0
  117. package/dist/api/usage.d.ts.map +1 -0
  118. package/dist/api/usage.js +194 -0
  119. package/dist/api/usage.js.map +1 -0
  120. package/dist/api/users-fan-out-mutation.d.ts.map +1 -1
  121. package/dist/api/users-fan-out-mutation.js +10 -5
  122. package/dist/api/users-fan-out-mutation.js.map +1 -1
  123. package/dist/api/webhooks.d.ts +357 -0
  124. package/dist/api/webhooks.d.ts.map +1 -0
  125. package/dist/api/webhooks.js +333 -0
  126. package/dist/api/webhooks.js.map +1 -0
  127. package/dist/cli/envelope-out.d.ts +18 -1
  128. package/dist/cli/envelope-out.d.ts.map +1 -1
  129. package/dist/cli/envelope-out.js +16 -2
  130. package/dist/cli/envelope-out.js.map +1 -1
  131. package/dist/cli/program.d.ts.map +1 -1
  132. package/dist/cli/program.js +120 -1
  133. package/dist/cli/program.js.map +1 -1
  134. package/dist/cli/run.d.ts +12 -0
  135. package/dist/cli/run.d.ts.map +1 -1
  136. package/dist/cli/run.js +2 -0
  137. package/dist/cli/run.js.map +1 -1
  138. package/dist/commands/account/tags.d.ts +37 -0
  139. package/dist/commands/account/tags.d.ts.map +1 -0
  140. package/dist/commands/account/tags.js +84 -0
  141. package/dist/commands/account/tags.js.map +1 -0
  142. package/dist/commands/auth/login.d.ts +14 -0
  143. package/dist/commands/auth/login.d.ts.map +1 -0
  144. package/dist/commands/auth/login.js +314 -0
  145. package/dist/commands/auth/login.js.map +1 -0
  146. package/dist/commands/auth/logout.d.ts +28 -0
  147. package/dist/commands/auth/logout.d.ts.map +1 -0
  148. package/dist/commands/auth/logout.js +94 -0
  149. package/dist/commands/auth/logout.js.map +1 -0
  150. package/dist/commands/board/archive.d.ts.map +1 -1
  151. package/dist/commands/board/archive.js +14 -14
  152. package/dist/commands/board/archive.js.map +1 -1
  153. package/dist/commands/board/column-create.d.ts +3 -3
  154. package/dist/commands/board/column-create.d.ts.map +1 -1
  155. package/dist/commands/board/column-create.js +52 -45
  156. package/dist/commands/board/column-create.js.map +1 -1
  157. package/dist/commands/board/column-delete.d.ts.map +1 -1
  158. package/dist/commands/board/column-delete.js +15 -16
  159. package/dist/commands/board/column-delete.js.map +1 -1
  160. package/dist/commands/board/column-update.d.ts.map +1 -1
  161. package/dist/commands/board/column-update.js +23 -22
  162. package/dist/commands/board/column-update.js.map +1 -1
  163. package/dist/commands/board/create.d.ts.map +1 -1
  164. package/dist/commands/board/create.js +14 -17
  165. package/dist/commands/board/create.js.map +1 -1
  166. package/dist/commands/board/delete.d.ts.map +1 -1
  167. package/dist/commands/board/delete.js +12 -15
  168. package/dist/commands/board/delete.js.map +1 -1
  169. package/dist/commands/board/describe.d.ts.map +1 -1
  170. package/dist/commands/board/describe.js +30 -0
  171. package/dist/commands/board/describe.js.map +1 -1
  172. package/dist/commands/board/duplicate.d.ts.map +1 -1
  173. package/dist/commands/board/duplicate.js +12 -13
  174. package/dist/commands/board/duplicate.js.map +1 -1
  175. package/dist/commands/board/favorites.d.ts +33 -0
  176. package/dist/commands/board/favorites.d.ts.map +1 -0
  177. package/dist/commands/board/favorites.js +74 -0
  178. package/dist/commands/board/favorites.js.map +1 -0
  179. package/dist/commands/board/find.d.ts +1 -1
  180. package/dist/commands/board/group-archive.d.ts.map +1 -1
  181. package/dist/commands/board/group-archive.js +12 -16
  182. package/dist/commands/board/group-archive.js.map +1 -1
  183. package/dist/commands/board/group-create.d.ts.map +1 -1
  184. package/dist/commands/board/group-create.js +9 -19
  185. package/dist/commands/board/group-create.js.map +1 -1
  186. package/dist/commands/board/group-delete.d.ts.map +1 -1
  187. package/dist/commands/board/group-delete.js +12 -16
  188. package/dist/commands/board/group-delete.js.map +1 -1
  189. package/dist/commands/board/group-duplicate.d.ts.map +1 -1
  190. package/dist/commands/board/group-duplicate.js +12 -16
  191. package/dist/commands/board/group-duplicate.js.map +1 -1
  192. package/dist/commands/board/group-update.d.ts.map +1 -1
  193. package/dist/commands/board/group-update.js +12 -11
  194. package/dist/commands/board/group-update.js.map +1 -1
  195. package/dist/commands/board/list.d.ts +1 -1
  196. package/dist/commands/board/update.d.ts.map +1 -1
  197. package/dist/commands/board/update.js +16 -11
  198. package/dist/commands/board/update.js.map +1 -1
  199. package/dist/commands/cache/list.d.ts +2 -0
  200. package/dist/commands/cache/list.d.ts.map +1 -1
  201. package/dist/commands/cache/list.js +2 -2
  202. package/dist/commands/cache/list.js.map +1 -1
  203. package/dist/commands/dev/_shared.d.ts +40 -0
  204. package/dist/commands/dev/_shared.d.ts.map +1 -0
  205. package/dist/commands/dev/_shared.js +104 -0
  206. package/dist/commands/dev/_shared.js.map +1 -0
  207. package/dist/commands/dev/configure.d.ts +36 -0
  208. package/dist/commands/dev/configure.d.ts.map +1 -0
  209. package/dist/commands/dev/configure.js +145 -0
  210. package/dist/commands/dev/configure.js.map +1 -0
  211. package/dist/commands/dev/discover.d.ts +34 -0
  212. package/dist/commands/dev/discover.d.ts.map +1 -0
  213. package/dist/commands/dev/discover.js +117 -0
  214. package/dist/commands/dev/discover.js.map +1 -0
  215. package/dist/commands/dev/doctor.d.ts +39 -0
  216. package/dist/commands/dev/doctor.d.ts.map +1 -0
  217. package/dist/commands/dev/doctor.js +91 -0
  218. package/dist/commands/dev/doctor.js.map +1 -0
  219. package/dist/commands/dev/epic/items.d.ts +24 -0
  220. package/dist/commands/dev/epic/items.d.ts.map +1 -0
  221. package/dist/commands/dev/epic/items.js +103 -0
  222. package/dist/commands/dev/epic/items.js.map +1 -0
  223. package/dist/commands/dev/epic/list.d.ts +36 -0
  224. package/dist/commands/dev/epic/list.d.ts.map +1 -0
  225. package/dist/commands/dev/epic/list.js +120 -0
  226. package/dist/commands/dev/epic/list.js.map +1 -0
  227. package/dist/commands/dev/release/list.d.ts +21 -0
  228. package/dist/commands/dev/release/list.d.ts.map +1 -0
  229. package/dist/commands/dev/release/list.js +73 -0
  230. package/dist/commands/dev/release/list.js.map +1 -0
  231. package/dist/commands/dev/sprint/current.d.ts +24 -0
  232. package/dist/commands/dev/sprint/current.d.ts.map +1 -0
  233. package/dist/commands/dev/sprint/current.js +90 -0
  234. package/dist/commands/dev/sprint/current.js.map +1 -0
  235. package/dist/commands/dev/sprint/items.d.ts +34 -0
  236. package/dist/commands/dev/sprint/items.d.ts.map +1 -0
  237. package/dist/commands/dev/sprint/items.js +118 -0
  238. package/dist/commands/dev/sprint/items.js.map +1 -0
  239. package/dist/commands/dev/sprint/list.d.ts +41 -0
  240. package/dist/commands/dev/sprint/list.d.ts.map +1 -0
  241. package/dist/commands/dev/sprint/list.js +104 -0
  242. package/dist/commands/dev/sprint/list.js.map +1 -0
  243. package/dist/commands/dev/task/block.d.ts +29 -0
  244. package/dist/commands/dev/task/block.d.ts.map +1 -0
  245. package/dist/commands/dev/task/block.js +106 -0
  246. package/dist/commands/dev/task/block.js.map +1 -0
  247. package/dist/commands/dev/task/done.d.ts +30 -0
  248. package/dist/commands/dev/task/done.d.ts.map +1 -0
  249. package/dist/commands/dev/task/done.js +113 -0
  250. package/dist/commands/dev/task/done.js.map +1 -0
  251. package/dist/commands/dev/task/list.d.ts +42 -0
  252. package/dist/commands/dev/task/list.d.ts.map +1 -0
  253. package/dist/commands/dev/task/list.js +227 -0
  254. package/dist/commands/dev/task/list.js.map +1 -0
  255. package/dist/commands/dev/task/start.d.ts +29 -0
  256. package/dist/commands/dev/task/start.d.ts.map +1 -0
  257. package/dist/commands/dev/task/start.js +90 -0
  258. package/dist/commands/dev/task/start.js.map +1 -0
  259. package/dist/commands/emit.d.ts.map +1 -1
  260. package/dist/commands/emit.js +5 -3
  261. package/dist/commands/emit.js.map +1 -1
  262. package/dist/commands/index.d.ts.map +1 -1
  263. package/dist/commands/index.js +95 -0
  264. package/dist/commands/index.js.map +1 -1
  265. package/dist/commands/item/archive.d.ts.map +1 -1
  266. package/dist/commands/item/archive.js +11 -0
  267. package/dist/commands/item/archive.js.map +1 -1
  268. package/dist/commands/item/clear.d.ts.map +1 -1
  269. package/dist/commands/item/clear.js +15 -0
  270. package/dist/commands/item/clear.js.map +1 -1
  271. package/dist/commands/item/create.d.ts.map +1 -1
  272. package/dist/commands/item/create.js +41 -8
  273. package/dist/commands/item/create.js.map +1 -1
  274. package/dist/commands/item/delete.d.ts.map +1 -1
  275. package/dist/commands/item/delete.js +11 -0
  276. package/dist/commands/item/delete.js.map +1 -1
  277. package/dist/commands/item/duplicate.d.ts.map +1 -1
  278. package/dist/commands/item/duplicate.js +12 -0
  279. package/dist/commands/item/duplicate.js.map +1 -1
  280. package/dist/commands/item/history.d.ts +60 -0
  281. package/dist/commands/item/history.d.ts.map +1 -0
  282. package/dist/commands/item/history.js +309 -0
  283. package/dist/commands/item/history.js.map +1 -0
  284. package/dist/commands/item/list.d.ts.map +1 -1
  285. package/dist/commands/item/list.js +16 -13
  286. package/dist/commands/item/list.js.map +1 -1
  287. package/dist/commands/item/move.d.ts.map +1 -1
  288. package/dist/commands/item/move.js +41 -7
  289. package/dist/commands/item/move.js.map +1 -1
  290. package/dist/commands/item/search.d.ts +99 -15
  291. package/dist/commands/item/search.d.ts.map +1 -1
  292. package/dist/commands/item/search.js +480 -36
  293. package/dist/commands/item/search.js.map +1 -1
  294. package/dist/commands/item/set.d.ts.map +1 -1
  295. package/dist/commands/item/set.js +52 -8
  296. package/dist/commands/item/set.js.map +1 -1
  297. package/dist/commands/item/time-track/start.d.ts +61 -0
  298. package/dist/commands/item/time-track/start.d.ts.map +1 -0
  299. package/dist/commands/item/time-track/start.js +138 -0
  300. package/dist/commands/item/time-track/start.js.map +1 -0
  301. package/dist/commands/item/time-track/stop.d.ts +32 -0
  302. package/dist/commands/item/time-track/stop.d.ts.map +1 -0
  303. package/dist/commands/item/time-track/stop.js +97 -0
  304. package/dist/commands/item/time-track/stop.js.map +1 -0
  305. package/dist/commands/item/update.d.ts +1 -0
  306. package/dist/commands/item/update.d.ts.map +1 -1
  307. package/dist/commands/item/update.js +103 -113
  308. package/dist/commands/item/update.js.map +1 -1
  309. package/dist/commands/item/upsert.d.ts.map +1 -1
  310. package/dist/commands/item/upsert.js +48 -1
  311. package/dist/commands/item/upsert.js.map +1 -1
  312. package/dist/commands/notification/send.d.ts +60 -0
  313. package/dist/commands/notification/send.d.ts.map +1 -0
  314. package/dist/commands/notification/send.js +147 -0
  315. package/dist/commands/notification/send.js.map +1 -0
  316. package/dist/commands/parse-argv.d.ts.map +1 -1
  317. package/dist/commands/parse-argv.js +14 -4
  318. package/dist/commands/parse-argv.js.map +1 -1
  319. package/dist/commands/raw/index.d.ts.map +1 -1
  320. package/dist/commands/raw/index.js +13 -15
  321. package/dist/commands/raw/index.js.map +1 -1
  322. package/dist/commands/run-by-id-lookup.d.ts.map +1 -1
  323. package/dist/commands/run-by-id-lookup.js +2 -2
  324. package/dist/commands/run-by-id-lookup.js.map +1 -1
  325. package/dist/commands/schema/index.d.ts +2 -0
  326. package/dist/commands/schema/index.d.ts.map +1 -1
  327. package/dist/commands/status.d.ts +120 -0
  328. package/dist/commands/status.d.ts.map +1 -0
  329. package/dist/commands/status.js +365 -0
  330. package/dist/commands/status.js.map +1 -0
  331. package/dist/commands/update/body-source.d.ts.map +1 -1
  332. package/dist/commands/update/body-source.js +2 -2
  333. package/dist/commands/update/body-source.js.map +1 -1
  334. package/dist/commands/update/create.d.ts +2 -3
  335. package/dist/commands/update/create.d.ts.map +1 -1
  336. package/dist/commands/update/create.js +15 -3
  337. package/dist/commands/update/create.js.map +1 -1
  338. package/dist/commands/update/delete.d.ts.map +1 -1
  339. package/dist/commands/update/delete.js +11 -0
  340. package/dist/commands/update/delete.js.map +1 -1
  341. package/dist/commands/update/edit.d.ts.map +1 -1
  342. package/dist/commands/update/edit.js +11 -0
  343. package/dist/commands/update/edit.js.map +1 -1
  344. package/dist/commands/update/list.d.ts.map +1 -1
  345. package/dist/commands/update/list.js +15 -12
  346. package/dist/commands/update/list.js.map +1 -1
  347. package/dist/commands/update/reply.d.ts.map +1 -1
  348. package/dist/commands/update/reply.js +11 -0
  349. package/dist/commands/update/reply.js.map +1 -1
  350. package/dist/commands/update/toggle.d.ts.map +1 -1
  351. package/dist/commands/update/toggle.js +13 -0
  352. package/dist/commands/update/toggle.js.map +1 -1
  353. package/dist/commands/usage.d.ts +58 -0
  354. package/dist/commands/usage.d.ts.map +1 -0
  355. package/dist/commands/usage.js +94 -0
  356. package/dist/commands/usage.js.map +1 -0
  357. package/dist/commands/webhook/create.d.ts +74 -0
  358. package/dist/commands/webhook/create.d.ts.map +1 -0
  359. package/dist/commands/webhook/create.js +150 -0
  360. package/dist/commands/webhook/create.js.map +1 -0
  361. package/dist/commands/webhook/delete.d.ts +46 -0
  362. package/dist/commands/webhook/delete.d.ts.map +1 -0
  363. package/dist/commands/webhook/delete.js +141 -0
  364. package/dist/commands/webhook/delete.js.map +1 -0
  365. package/dist/commands/webhook/list.d.ts +23 -0
  366. package/dist/commands/webhook/list.d.ts.map +1 -0
  367. package/dist/commands/webhook/list.js +68 -0
  368. package/dist/commands/webhook/list.js.map +1 -0
  369. package/dist/commands/workspace/create.d.ts.map +1 -1
  370. package/dist/commands/workspace/create.js +16 -0
  371. package/dist/commands/workspace/create.js.map +1 -1
  372. package/dist/commands/workspace/delete.d.ts.map +1 -1
  373. package/dist/commands/workspace/delete.js +13 -13
  374. package/dist/commands/workspace/delete.js.map +1 -1
  375. package/dist/commands/workspace/list.d.ts +1 -1
  376. package/dist/commands/workspace/update.d.ts.map +1 -1
  377. package/dist/commands/workspace/update.js +15 -15
  378. package/dist/commands/workspace/update.js.map +1 -1
  379. package/dist/config/credentials.d.ts +189 -0
  380. package/dist/config/credentials.d.ts.map +1 -0
  381. package/dist/config/credentials.js +300 -0
  382. package/dist/config/credentials.js.map +1 -0
  383. package/dist/config/profiles.d.ts +125 -0
  384. package/dist/config/profiles.d.ts.map +1 -0
  385. package/dist/config/profiles.js +227 -0
  386. package/dist/config/profiles.js.map +1 -0
  387. package/dist/types/global-flags.d.ts +1 -1
  388. package/dist/types/global-flags.d.ts.map +1 -1
  389. package/dist/types/global-flags.js +28 -16
  390. package/dist/types/global-flags.js.map +1 -1
  391. package/dist/types/ids.d.ts +2 -0
  392. package/dist/types/ids.d.ts.map +1 -1
  393. package/dist/types/ids.js +5 -3
  394. package/dist/types/ids.js.map +1 -1
  395. package/dist/utils/errors.d.ts +57 -3
  396. package/dist/utils/errors.d.ts.map +1 -1
  397. package/dist/utils/errors.js +69 -2
  398. package/dist/utils/errors.js.map +1 -1
  399. package/dist/utils/fs.d.ts +35 -0
  400. package/dist/utils/fs.d.ts.map +1 -0
  401. package/dist/utils/fs.js +36 -0
  402. package/dist/utils/fs.js.map +1 -0
  403. package/dist/utils/json.d.ts +60 -0
  404. package/dist/utils/json.d.ts.map +1 -0
  405. package/dist/utils/json.js +86 -0
  406. package/dist/utils/json.js.map +1 -0
  407. package/dist/utils/output/ndjson.d.ts +65 -3
  408. package/dist/utils/output/ndjson.d.ts.map +1 -1
  409. package/dist/utils/output/ndjson.js +21 -0
  410. package/dist/utils/output/ndjson.js.map +1 -1
  411. package/dist/utils/redact.d.ts.map +1 -1
  412. package/dist/utils/redact.js +31 -0
  413. package/dist/utils/redact.js.map +1 -1
  414. package/package.json +2 -1
  415. package/dist/commands/account/client-helper.d.ts +0 -37
  416. package/dist/commands/account/client-helper.d.ts.map +0 -1
  417. package/dist/commands/account/client-helper.js +0 -55
  418. package/dist/commands/account/client-helper.js.map +0 -1
@@ -0,0 +1,1104 @@
1
+ /**
2
+ * Per-item activity-log + comment-thread projection for the v0.3-M24
3
+ * `monday item history <iid>` verb (`cli-design.md` §13 v0.3 entry).
4
+ *
5
+ * **What `monday item history` answers:** "show me every change +
6
+ * comment on this item, chronologically, in one stream" — without
7
+ * the agent walking `activity_logs` AND `updates` separately and
8
+ * folding by `created_at` by hand. Two Monday surfaces feed the
9
+ * stream:
10
+ *
11
+ * 1. `boards(ids:) { activity_logs(item_ids:, from:, to:,
12
+ * page:, limit:) }` — Monday's per-board activity log,
13
+ * filtered to the target item via `item_ids` AND additionally
14
+ * filtered WALKER-SIDE (post-fetch, before projection) to
15
+ * `entity = 'pulse'` (the `item_ids` arg ALONE does NOT
16
+ * exclude board-scoped events; empirical-probe finding
17
+ * 2026-05-11). Page-numbered pagination (Monday's native
18
+ * shape; `--activity-logs-page <n>` / `--limit <n>` flags
19
+ * surface it).
20
+ * 2. `items(ids:) { updates(limit:, page:) { ... replies { ...
21
+ * } } }` — Monday's comment thread (top-level updates +
22
+ * nested replies). Projected into synthesized
23
+ * `update_posted` + `update_replied` event-objects so the
24
+ * merged stream is uniform.
25
+ *
26
+ * The merge projector orders the unified stream by `created_at`
27
+ * ascending; ties break by `id` for deterministic output across
28
+ * runs.
29
+ *
30
+ * **Decision 2 closure** (`a1f3025`, M24-prep empirical probe pass
31
+ * 2026-05-11; full findings at v0.3-plan §8 Decision 2 closure).
32
+ * Three load-bearing findings from the live probe against a real
33
+ * workspace + 19 captured `activity_logs` rows on a production
34
+ * board:
35
+ *
36
+ * - **Schema field name is `event`, NOT `kind`.** Monday's
37
+ * `ActivityLogType` exposes 7 fields per the introspection
38
+ * probe (all NON_NULL String): `account_id`, `created_at`,
39
+ * `data`, `entity`, `event`, `id`, `user_id`. The v0.3-plan
40
+ * §3 M24 description used "kind" as the synonym; the projector
41
+ * keeps `kind` as the CLI agent-facing discriminator (domain-
42
+ * neutral) but maps it 1:1 from the wire's `event` slot.
43
+ * - **Observed event taxonomy (production data; 19 rows on one
44
+ * board over 30 days; NOT exhaustive):** `create_column`
45
+ * (10×), `update_column_value` (4×; the dominant ITEM-SCOPED
46
+ * event), `create_group` (2×), `board_workspace_id_changed`
47
+ * (1×), `update_board_name` (1×), `update_board_nickname`
48
+ * (1×). The `update_column_value` payload carries `column_id`
49
+ * + `column_type` + `value` + `previous_value` + `textual_value`
50
+ * + `pulse_id` + `pulse_name`; `previous_value` is sometimes
51
+ * `{}` for first-set events (decoded defensively as
52
+ * "previously-unset" — preserved as `{}` on the projected
53
+ * event so agents distinguish "first set" from "no prior
54
+ * value tracked"). The runtime projector applies one level
55
+ * of nested-JSON unwrap on `value` / `previous_value` so the
56
+ * before/after slots carry structured payloads (e.g.
57
+ * `{label, index}` for status, ISO string for date) rather
58
+ * than opaque JSON-string scalars.
59
+ * - **`entity` field discriminates item-scoped from board-scoped
60
+ * events.** Observed values: `pulse` (4×; item-scoped) and
61
+ * `board` (15×; board-scoped). The walker filters
62
+ * `entity = 'pulse'` to drop board-level noise (column
63
+ * additions, group creation, board renames) that aren't part
64
+ * of the item's history. **The `item_ids` filter alone is
65
+ * INSUFFICIENT** — passing it does NOT exclude board-scoped
66
+ * events from the response.
67
+ *
68
+ * **Eventual-consistency caveat (carry to cli-design §13 v0.3
69
+ * entry).** Monday's `activity_logs` has an empirically-measured
70
+ * propagation lag **>30s** on freshly-edited boards. The verb's
71
+ * help text MUST NOT promise immediate-history for newly-modified
72
+ * items; agents polling `monday item history` after a write should
73
+ * wait at least 30s before expecting their write to surface.
74
+ *
75
+ * **Update + Reply shapes (also pinned by the probe).** `Update`
76
+ * carries 16 fields per introspection; the projector projects only
77
+ * the load-bearing ones: `id` (NON_NULL ID), `body` (NON_NULL
78
+ * String), `text_body` (nullable String), `created_at` (nullable
79
+ * `Date`), `creator_id` (nullable String), `replies` (LIST[Reply!]
80
+ * with the list itself nullable; items non-null). `Reply` carries
81
+ * its OWN `kind: String!` field — separate taxonomy from
82
+ * `activity_logs.event` — and the projector surfaces it under the
83
+ * synthesized `update_replied` event's `reply_kind` slot.
84
+ *
85
+ * **Runtime composition.** {@link fetchItemHistory} drives the
86
+ * two-source walker; {@link projectActivityLogRow},
87
+ * {@link projectUpdateRow}, and {@link projectReplyRow} are the
88
+ * per-row projectors (the activity-log projector reads the wire
89
+ * `data` JSON, dispatches on `event`, and applies a one-level
90
+ * nested-JSON unwrap on `update_column_value`'s `value` /
91
+ * `previous_value` so agents see the structured payload — e.g.
92
+ * `{label, index}` for status, ISO string for date — rather than
93
+ * an opaque JSON-string). The walker filters
94
+ * `entity === ITEM_SCOPED_ENTITY` walker-side (single source of
95
+ * truth per Decision 2 closure; projector does NOT re-filter).
96
+ *
97
+ * **Streaming reuse.** Per the v0.3-plan §3 M24 deliverable, the
98
+ * verb reuses `startNdjsonStream` (R52) when `--stream` is on; the
99
+ * trailer meta carries `{has_more, total_returned, complexity,
100
+ * source}` per cli-design §6.3 + the symmetric page-numbered
101
+ * per-source `activity_logs.last_page` + `updates.last_page` slots
102
+ * (both 1-indexed; `null` when the walker exhausted that source) so
103
+ * agents resuming a partial walk re-issue with the per-source
104
+ * `last_page + 1`. No cursor surface at v0.3 — both sources
105
+ * paginate page-numbered.
106
+ */
107
+ import { z } from 'zod';
108
+ import { isPlainObject } from '../utils/json.js';
109
+ import { unwrapOrThrow } from '../utils/parse-boundary.js';
110
+ /**
111
+ * Wire field name on `ActivityLogType` that discriminates
112
+ * item-scoped (`pulse`) from board-scoped (`board`) events per the
113
+ * Decision 2 closure entity-filter finding. The walker filters on
114
+ * this constant before handing rows to the projector; the projector
115
+ * itself does NOT re-filter (single source of truth at the walker
116
+ * layer).
117
+ */
118
+ export const ITEM_SCOPED_ENTITY = 'pulse';
119
+ /**
120
+ * Default per-page slice for `activity_logs(limit: <n>, page: <n>)`.
121
+ * Monday's `activity_logs` resolver caps the per-call slice at 10000;
122
+ * the CLI default of 100 keeps the per-call latency below the per-
123
+ * page budget while letting `--limit <n>` cap the aggregate. Mirrors
124
+ * the v0.1 `DEFAULT_PAGE_SIZE` of 100.
125
+ */
126
+ export const DEFAULT_HISTORY_PAGE_SIZE = 100;
127
+ /**
128
+ * Hard cap on `--limit` for `activity_logs` per-call slice. Monday's
129
+ * documented ceiling is 10000; the CLI mirrors it so the parse
130
+ * boundary rejects over-large requests with `usage_error` rather
131
+ * than letting Monday's server-side rejection surface as
132
+ * `validation_failed` mid-walk.
133
+ */
134
+ export const HARD_CAP_HISTORY_PAGE_SIZE = 10_000;
135
+ /**
136
+ * Stage-1 GraphQL document — `activity_logs` per-page slice.
137
+ *
138
+ * Per the Decision 2 closure introspection finding,
139
+ * `ActivityLogType` has 7 NON_NULL String fields. The projector
140
+ * reads all 6 non-`account_id` slots (`account_id` carries no
141
+ * item-history signal — every row in a single-account CLI session
142
+ * shares it).
143
+ *
144
+ * **`item_ids` filter is necessary BUT NOT SUFFICIENT.** Per the
145
+ * probe finding, board-scoped events (entity = 'board') leak
146
+ * through even with `item_ids` set. The WALKER
147
+ * ({@link fetchItemHistory}) filters `row.entity ===
148
+ * ITEM_SCOPED_ENTITY` immediately after the page parses and
149
+ * BEFORE handing rows to {@link projectActivityLogRow}. The
150
+ * projector itself does NOT re-filter — single source of truth at
151
+ * the walker layer per Decision 2 closure. Server-side filtering
152
+ * would require a custom GraphQL middleware Monday doesn't expose;
153
+ * filtering later than the walker would force row-shaping code to
154
+ * know about the entity discriminator, which belongs to the
155
+ * walker's "which rows are part of THIS item's history" question,
156
+ * not the projector's "how do I shape this row's payload" question.
157
+ *
158
+ * Monday's `activity_logs(item_ids:, from:, to:, page:, limit:)`
159
+ * signature accepts ISO-8601 timestamps for `from` / `to` per the
160
+ * sibling `created_at` ISO8601DateTime scalar; nullable on both
161
+ * sides so a partial range (`--since` only / `--until` only) maps
162
+ * cleanly to omitting the absent slot.
163
+ */
164
+ export const ACTIVITY_LOGS_QUERY = `
165
+ query ItemHistoryActivityLogs(
166
+ $bid: [ID!]!,
167
+ $iid: [ID!]!,
168
+ $from: ISO8601DateTime,
169
+ $to: ISO8601DateTime,
170
+ $page: Int!,
171
+ $limit: Int!
172
+ ) {
173
+ boards(ids: $bid) {
174
+ id
175
+ activity_logs(
176
+ item_ids: $iid,
177
+ from: $from,
178
+ to: $to,
179
+ page: $page,
180
+ limit: $limit
181
+ ) {
182
+ id
183
+ event
184
+ entity
185
+ user_id
186
+ created_at
187
+ data
188
+ }
189
+ }
190
+ }
191
+ `;
192
+ /**
193
+ * Stage-2 GraphQL document — `items(ids:) { updates(...) }` for
194
+ * the comment-thread source.
195
+ *
196
+ * Per the Decision 2 closure introspection finding, `Update` has
197
+ * 16 fields; the projector selects only the load-bearing slots
198
+ * (id / body / text_body / created_at / creator_id / replies +
199
+ * the Reply sub-selection). Other fields (`likes`, `pinned_to_top`,
200
+ * `viewers`, `assets`) are not part of the item-history surface in
201
+ * v0.3; a v0.4 follow-up may extend the projection under the
202
+ * `update_posted` event's `after` slot if those fields become
203
+ * agent-useful (envelope-additive per §6.1).
204
+ *
205
+ * **Update.created_at + Reply.created_at are nullable** per the
206
+ * probe introspection (both fields are `SCALAR/Date`, nullable).
207
+ * The projector substitutes `Update.edited_at` (NON_NULL Date) as
208
+ * the chronological key when `created_at` is null — silent
209
+ * projection behaviour (NOT a warning surface; the substitution is
210
+ * deterministic + agents observing a null-`created_at` Update on
211
+ * the wire reproduce the same merge order on a re-walk). v0.3's
212
+ * `warnings[]` shape is `unknown_event_kind` only; adding a
213
+ * `synthesized_created_at` warning is a v0.4 envelope-additive
214
+ * extension if the substitution turns out to be agent-visible in
215
+ * practice.
216
+ *
217
+ * Monday's `updates(limit:, page:)` signature is page-numbered;
218
+ * the projector exposes `--updates-page <n>` so the two sources
219
+ * paginate independently (activity_logs and updates have their own
220
+ * page counters; merging them onto a single `--page <n>` flag would
221
+ * conflate two different denominators).
222
+ */
223
+ export const UPDATES_QUERY = `
224
+ query ItemHistoryUpdates(
225
+ $iid: [ID!]!,
226
+ $page: Int!,
227
+ $limit: Int!
228
+ ) {
229
+ items(ids: $iid) {
230
+ id
231
+ updates(limit: $limit, page: $page) {
232
+ id
233
+ body
234
+ text_body
235
+ created_at
236
+ edited_at
237
+ creator_id
238
+ replies {
239
+ id
240
+ kind
241
+ body
242
+ text_body
243
+ created_at
244
+ updated_at
245
+ creator_id
246
+ }
247
+ }
248
+ }
249
+ }
250
+ `;
251
+ /**
252
+ * Wire-shape schema for an `ActivityLogType` row (Decision 2 closure
253
+ * introspection finding — 7 NON_NULL String fields). `.loose()` so
254
+ * future Monday surface extensions don't break the parse — the
255
+ * projector reads only the fields it knows about and forward-compat
256
+ * fields pass through to no consumer.
257
+ */
258
+ export const rawActivityLogRowSchema = z
259
+ .object({
260
+ id: z.string().min(1),
261
+ event: z.string().min(1),
262
+ entity: z.string().min(1),
263
+ user_id: z.string().min(1),
264
+ created_at: z.string().min(1),
265
+ data: z.string(),
266
+ })
267
+ .loose();
268
+ /**
269
+ * Wire-shape schema for one `Reply` row inside `Update.replies`.
270
+ * Per the Decision 2 closure introspection finding, `Reply.id` +
271
+ * `Reply.body` + `Reply.kind` are NON_NULL; `Reply.created_at` is
272
+ * nullable Date; `Reply.creator_id` is nullable String.
273
+ *
274
+ * **`Reply.kind` is a separate taxonomy from
275
+ * `activity_logs.event`.** Reply's kind discriminates comment-thread
276
+ * reply types (e.g., a regular reply vs a system-generated reply);
277
+ * activity_logs's event discriminates board-level change types. The
278
+ * projector surfaces `Reply.kind` under the synthesized
279
+ * `update_replied` event's `reply_kind` slot so agents can
280
+ * introspect it without confusion.
281
+ */
282
+ export const rawReplyRowSchema = z
283
+ .object({
284
+ id: z.string().min(1),
285
+ body: z.string(),
286
+ kind: z.string().min(1),
287
+ text_body: z.string().nullable(),
288
+ created_at: z.string().nullable(),
289
+ updated_at: z.string().nullable(),
290
+ creator_id: z.string().nullable(),
291
+ })
292
+ .loose();
293
+ /**
294
+ * Wire-shape schema for one `Update` row. `created_at` is nullable
295
+ * per the probe introspection (Date scalar, optional); the
296
+ * projector substitutes `edited_at` (NON_NULL Date) when
297
+ * `created_at` is absent.
298
+ */
299
+ export const rawUpdateRowSchema = z
300
+ .object({
301
+ id: z.string().min(1),
302
+ body: z.string(),
303
+ text_body: z.string().nullable(),
304
+ created_at: z.string().nullable(),
305
+ edited_at: z.string().min(1),
306
+ creator_id: z.string().nullable(),
307
+ replies: z.array(rawReplyRowSchema).nullable(),
308
+ })
309
+ .loose();
310
+ /**
311
+ * Common base-field shape on every projected `HistoryEvent` variant.
312
+ *
313
+ * - `id` — stable per-row identifier. Activity-log rows reuse the
314
+ * wire `ActivityLogType.id`; `update_posted` reuses
315
+ * `Update.id`; `update_replied` reuses `Reply.id`. Cross-source
316
+ * `id` clashes are not possible — Monday assigns separate ID
317
+ * spaces to activity_logs / updates / replies.
318
+ * - `created_at` — ISO-8601 timestamp. The chronological merge key
319
+ * (see `mergeByCreatedAt`).
320
+ * - `actor_id` — nullable to accommodate the wire variance:
321
+ * `ActivityLogType.user_id` is NON_NULL per the probe;
322
+ * `Update.creator_id` is nullable; `Reply.creator_id` is
323
+ * nullable. `null` means "no actor recorded" (system event,
324
+ * deleted user); agents distinguish via the variant `kind`.
325
+ */
326
+ const baseEventFields = {
327
+ id: z.string().min(1),
328
+ created_at: z.string().min(1),
329
+ actor_id: z.string().nullable(),
330
+ };
331
+ /**
332
+ * **`update_column_value`** — the dominant ITEM-SCOPED activity-log
333
+ * event per the Decision 2 closure observed-events list (4× of 19
334
+ * rows; the only item-scoped kind in the sample). Carries the
335
+ * column-edit before / after payload.
336
+ *
337
+ * Schema slots:
338
+ * - `column_id` + `column_type` from the wire `data` payload
339
+ * (always present per the probe).
340
+ * - `before` + `after` as `z.unknown()` slots carrying the
341
+ * parsed `previous_value` / `value` JSON. The runtime
342
+ * projector applies one level of nested-JSON unwrap so
343
+ * agents see structured payloads (e.g. `{label, index}` for
344
+ * status, ISO string for date) rather than opaque JSON-
345
+ * string scalars. `z.unknown()` keeps the schema permissive
346
+ * so future Monday column types don't break the parse —
347
+ * agents introspect via `column_type` and the runtime
348
+ * payload.
349
+ * - `textual_value` — Monday's human-readable rendering of the
350
+ * new value (always present per the probe; nullable for
351
+ * defensive forward-compat with future column types Monday
352
+ * may not provide a textual rendering for).
353
+ * - `pulse_id` + `pulse_name` — item identity for cross-board
354
+ * consumers; nullable for subitem variants where the parent
355
+ * identification carries the load. `pulse_id` ships as an
356
+ * unquoted JSON number on the wire (probe-confirmed); the
357
+ * runtime projector stringifies it via
358
+ * `readNullableIdField` (Codex impl round-2 P2-1).
359
+ */
360
+ export const updateColumnValueEventSchema = z
361
+ .object({
362
+ ...baseEventFields,
363
+ kind: z.literal('update_column_value'),
364
+ column_id: z.string().min(1),
365
+ column_type: z.string().min(1),
366
+ before: z.unknown(),
367
+ after: z.unknown(),
368
+ textual_value: z.string().nullable(),
369
+ pulse_id: z.string().nullable(),
370
+ pulse_name: z.string().nullable(),
371
+ })
372
+ .strict();
373
+ /**
374
+ * Board-scoped activity-log variants. The walker filters
375
+ * `entity = 'pulse'` BEFORE handing rows to the projector, so these
376
+ * variants are not surfaced on the projected stream in normal
377
+ * operation. They stay in the discriminated union as parser-
378
+ * roundtrip targets so a future regression that bypasses the
379
+ * entity filter falls back to the typed variant rather than to
380
+ * `unknown` (cleaner failure mode; agents see the expected kind
381
+ * literal rather than a fallback shape).
382
+ *
383
+ * Both `before` / `after` carry the raw parsed JSON payload as
384
+ * `z.unknown()` slots. Uniform shape (not `null` even for
385
+ * creation-shaped events) because the observed taxonomy includes
386
+ * both creation events (`create_column`, `create_group`) where
387
+ * `before` is meaningless AND edit events (`update_board_name`,
388
+ * `update_board_nickname`, `board_workspace_id_changed`) where
389
+ * `before` carries the prior value from the wire `data.previous_value`
390
+ * payload — uniform `z.unknown()` keeps the discriminator schema
391
+ * stable regardless of which variant a row resolves to.
392
+ */
393
+ const boardScopedEventSchema = (kindLiteral) => z
394
+ .object({
395
+ ...baseEventFields,
396
+ kind: z.literal(kindLiteral),
397
+ before: z.unknown(),
398
+ after: z.unknown(),
399
+ })
400
+ .strict();
401
+ export const createColumnEventSchema = boardScopedEventSchema('create_column');
402
+ export const createGroupEventSchema = boardScopedEventSchema('create_group');
403
+ export const updateBoardNameEventSchema = boardScopedEventSchema('update_board_name');
404
+ export const updateBoardNicknameEventSchema = boardScopedEventSchema('update_board_nickname');
405
+ export const boardWorkspaceIdChangedEventSchema = boardScopedEventSchema('board_workspace_id_changed');
406
+ /**
407
+ * **`update_posted`** — synthesized event for a top-level comment
408
+ * on the item. The projector maps `Update` rows from the
409
+ * comment-thread source into this shape; activity_logs does NOT
410
+ * surface comments as its own events, so the cross-source merge
411
+ * is what unifies them.
412
+ *
413
+ * - `before: null` — comments are append-only events (no prior
414
+ * state).
415
+ * - `after.body` — `Update.body` (NON_NULL String per the probe).
416
+ * - `after.text_body` — `Update.text_body` (nullable; Monday's
417
+ * plain-text rendering of the rich-text body).
418
+ * - `after.reply_count` — count of `Update.replies` after the
419
+ * wire-side null-coalesce (Monday returns `null` for "no
420
+ * replies known"; the projector folds to `0` for agent
421
+ * ergonomics — see `mergeByCreatedAt` semantics).
422
+ */
423
+ export const updatePostedEventSchema = z
424
+ .object({
425
+ ...baseEventFields,
426
+ kind: z.literal('update_posted'),
427
+ before: z.null(),
428
+ after: z
429
+ .object({
430
+ body: z.string(),
431
+ text_body: z.string().nullable(),
432
+ reply_count: z.number().int().nonnegative(),
433
+ })
434
+ .strict(),
435
+ })
436
+ .strict();
437
+ /**
438
+ * **`update_replied`** — synthesized event for one reply within a
439
+ * comment thread. The projector emits ONE event per `Reply` row;
440
+ * the parent `Update.id` lands on `parent_update_id` so agents can
441
+ * reconstruct thread context without a second round-trip.
442
+ *
443
+ * `reply_kind` carries `Reply.kind` (NON_NULL String per the
444
+ * probe — a SEPARATE taxonomy from `activity_logs.event`). Pre-
445
+ * flight pins this as `z.string()` (open enum) per the same
446
+ * forward-compat policy as M23 favorites' `object.type` field —
447
+ * Monday may extend Reply.kind with new variants without breaking
448
+ * the parse.
449
+ */
450
+ export const updateRepliedEventSchema = z
451
+ .object({
452
+ ...baseEventFields,
453
+ kind: z.literal('update_replied'),
454
+ parent_update_id: z.string().min(1),
455
+ reply_kind: z.string().min(1),
456
+ before: z.null(),
457
+ after: z
458
+ .object({
459
+ body: z.string(),
460
+ text_body: z.string().nullable(),
461
+ })
462
+ .strict(),
463
+ })
464
+ .strict();
465
+ /**
466
+ * **`unknown`** — fallback variant for an `activity_logs.event`
467
+ * value the projector doesn't recognise. Carries the raw wire
468
+ * `event` slot (so agents see the unrecognised string) + the raw
469
+ * `entity` slot (so the walker filter discrepancy is visible) +
470
+ * the raw parsed `data` JSON under `after` (so a future-extension
471
+ * consumer can reproject without a second wire call). `before` is
472
+ * `null` for uniform shape with the synthesized comment-event
473
+ * variants (`update_posted` / `update_replied`) which also pin
474
+ * `before: null` for their append-only-events semantics — the
475
+ * `unknown` variant similarly has no meaningful "before" since the
476
+ * projector by definition doesn't know how to extract the prior
477
+ * state from the wire payload (the typed variants are the place
478
+ * that knowledge lives). Agents wanting to introspect the raw
479
+ * payload read `after` (the full parsed `data` JSON) alongside
480
+ * `event` + `entity` for routing.
481
+ *
482
+ * Surfaces alongside a `warnings[]` entry of code
483
+ * `unknown_event_kind` (per {@link buildUnknownEventKindWarning})
484
+ * so agents introspect the projector's coverage gap without parsing
485
+ * the events list for `kind === 'unknown'` themselves.
486
+ *
487
+ * Per Decision 2 closure: this variant is the registry-stable
488
+ * surface for forward-compat with Monday's expanding event
489
+ * taxonomy. The 29-error-code registry stays AT 29 — the unknown-
490
+ * event-kind surface is a `warnings[]` shape, NOT a new
491
+ * `error.code` entry.
492
+ */
493
+ export const unknownEventSchema = z
494
+ .object({
495
+ ...baseEventFields,
496
+ kind: z.literal('unknown'),
497
+ event: z.string().min(1),
498
+ entity: z.string().min(1),
499
+ before: z.null(),
500
+ after: z.unknown(),
501
+ })
502
+ .strict();
503
+ /**
504
+ * The projected per-event discriminated union — the contract surface
505
+ * for `monday item history`. Agents read `kind` to route per-variant
506
+ * handling. Adding a new variant is non-breaking (envelope-additive
507
+ * per §6.1); renaming or removing one is the SemVer-major boundary.
508
+ *
509
+ * **Variant count: 9** (1 item-scoped activity-log + 5 board-scoped
510
+ * activity-log variants kept for parser-roundtrip + 2 synthesized
511
+ * comment-thread variants + 1 unknown fallback). The Decision 2
512
+ * closure observed-events list capped the activity-log variants at
513
+ * 6; the synthesized + fallback variants are the projector's own
514
+ * contract.
515
+ *
516
+ * **Decision 2 ratification.** The discriminator field name `kind`
517
+ * maps 1:1 from Monday's wire `ActivityLogType.event` field
518
+ * (schema field-name drift); the variants enumerate the observed
519
+ * production taxonomy + the `unknown` fallback for forward-compat.
520
+ */
521
+ export const historyEventSchema = z.discriminatedUnion('kind', [
522
+ updateColumnValueEventSchema,
523
+ createColumnEventSchema,
524
+ createGroupEventSchema,
525
+ updateBoardNameEventSchema,
526
+ updateBoardNicknameEventSchema,
527
+ boardWorkspaceIdChangedEventSchema,
528
+ updatePostedEventSchema,
529
+ updateRepliedEventSchema,
530
+ unknownEventSchema,
531
+ ]);
532
+ /**
533
+ * The top-level command output schema — `data` is the chronologically-
534
+ * merged event array. Mirrors M23's `crossBoardSearchOutputSchema`
535
+ * (a flat array of typed rows; no top-level metadata in `data`).
536
+ */
537
+ export const historyEventOutputSchema = z.array(historyEventSchema);
538
+ export const unknownEventKindWarningSchema = z
539
+ .object({
540
+ code: z.literal('unknown_event_kind'),
541
+ message: z.string().min(1),
542
+ details: z
543
+ .object({
544
+ event: z.string().min(1),
545
+ entity: z.string().min(1),
546
+ occurrence_count: z.number().int().positive(),
547
+ hint: z.string().min(1),
548
+ })
549
+ .strict(),
550
+ })
551
+ .strict();
552
+ /**
553
+ * Builds an {@link UnknownEventKindWarning} from one observed
554
+ * unknown event + its occurrence count across the merged stream.
555
+ * **Real implementation** at pre-flight (pure helper; the warning
556
+ * shape is the contract surface).
557
+ *
558
+ * The hint forward-references the projector's extensibility point
559
+ * so agents have a concrete next step (vs a generic "unknown"
560
+ * message that requires reading the source).
561
+ */
562
+ export const buildUnknownEventKindWarning = (event, entity, occurrenceCount) => ({
563
+ code: 'unknown_event_kind',
564
+ message: `activity_logs returned ${String(occurrenceCount)} ${occurrenceCount === 1 ? 'row' : 'rows'} with an unrecognised event kind "${event}" (entity: "${entity}"); surfaced under the \`unknown\` event variant`,
565
+ details: {
566
+ event,
567
+ entity,
568
+ occurrence_count: occurrenceCount,
569
+ hint: 'Monday may have extended `activity_logs.event` with a new kind; extend `historyEventSchema` in `src/api/item-history-projection.ts` with a typed variant to surface the before/after payload, or consume the raw parsed payload from the `unknown` variant\'s `after` slot',
570
+ },
571
+ });
572
+ /**
573
+ * Merges two pre-projected event streams (activity-log + comment-
574
+ * thread) into a single chronologically-ordered stream. **Real
575
+ * implementation** at pre-flight (pure helper).
576
+ *
577
+ * Ordering rules:
578
+ * - Primary: `created_at` ascending (oldest first; matches
579
+ * Monday's UI activity log + comment thread chronological
580
+ * reading order).
581
+ * - Tie-break: `id` (lexicographic) — deterministic across runs
582
+ * even when two events share the exact same `created_at`
583
+ * timestamp (Monday's resolver issues IDs in monotonic order
584
+ * per source, so the tie-break preserves intra-source order).
585
+ *
586
+ * **Why merge here, not at the walker.** The two source walkers
587
+ * paginate independently (activity_logs page-numbered;
588
+ * updates page-numbered with a different denominator); merging at
589
+ * the walker would force coupled pagination on the streaming
590
+ * path. The projector merges the FULLY-DRAINED-PER-WALL-CLOCK-CAP
591
+ * lists — `fetchItemHistory` walks both sources to the `--since`
592
+ * / `--until` cap independently, then this helper merges.
593
+ *
594
+ * **Streaming semantics.** When `--stream` is on, the merge is
595
+ * NOT incremental — the entire `--since`-bounded slice must be
596
+ * resident to order it. The NDJSON stream emits the merged array
597
+ * per-item via the walker's `onItem` hook AFTER the merge
598
+ * completes; the trailer carries the per-source pagination state
599
+ * for resumption.
600
+ */
601
+ export const mergeByCreatedAt = (activityEvents, commentEvents) => {
602
+ const merged = [...activityEvents, ...commentEvents];
603
+ return merged.sort((a, b) => {
604
+ if (a.created_at !== b.created_at) {
605
+ return a.created_at < b.created_at ? -1 : 1;
606
+ }
607
+ return a.id < b.id ? -1 : a.id > b.id ? 1 : 0;
608
+ });
609
+ };
610
+ /**
611
+ * Parses a wire `data` payload defensively. Monday encodes
612
+ * `ActivityLogType.data` as a JSON string carrying the per-event
613
+ * payload (per Decision 2 closure introspection). On parse failure
614
+ * the projector falls back to the raw string under
615
+ * `{raw_data: <string>}` so the `unknown` variant's `after` slot
616
+ * still carries diagnostic content rather than a discarded payload.
617
+ */
618
+ const parseActivityLogDataJson = (raw) => {
619
+ try {
620
+ return JSON.parse(raw);
621
+ }
622
+ catch {
623
+ return { raw_data: raw };
624
+ }
625
+ };
626
+ /**
627
+ * Extracts `value` / `previous_value` from a Monday `data` payload.
628
+ * The wire shape carries them as JSON-encoded strings inside the
629
+ * outer parsed object (Monday's nested-JSON convention); the
630
+ * projector unwraps one level so agents see the structured payload
631
+ * (e.g. `{label, index}`, `{date, time}`) rather than an opaque
632
+ * string. When the slot is already a structured value (Monday's
633
+ * shape varies per column type and per event), pass it through.
634
+ *
635
+ * Per Decision 2 closure: `previous_value` is sometimes `{}` on
636
+ * first-set events ("previously-unset"). The projector preserves
637
+ * the empty-object shape rather than collapsing to `null` — agents
638
+ * keying off the empty-object distinguish "first set" from
639
+ * "no prior value tracked".
640
+ */
641
+ const unwrapNestedJson = (value) => {
642
+ if (typeof value !== 'string')
643
+ return value;
644
+ try {
645
+ return JSON.parse(value);
646
+ }
647
+ catch {
648
+ return value;
649
+ }
650
+ };
651
+ /**
652
+ * Reads `column_id` / `column_type` from a parsed `data` payload.
653
+ * Both fields are required for the `update_column_value` typed
654
+ * variant per Decision 2 closure (the wire payload always carries
655
+ * them for item-scoped column-edit events). Missing / non-string
656
+ * slots fall back to empty strings — the projector then routes the
657
+ * row through the `unknown` fallback rather than emitting a typed
658
+ * variant with an empty discriminator.
659
+ */
660
+ const readStringField = (obj, key) => {
661
+ const v = obj[key];
662
+ return typeof v === 'string' ? v : '';
663
+ };
664
+ const readNullableString = (obj, key) => {
665
+ const v = obj[key];
666
+ return typeof v === 'string' ? v : null;
667
+ };
668
+ /**
669
+ * Reads a Monday ID field that the wire emits as either a string
670
+ * or an unquoted JSON number. The Decision 2 probe shows
671
+ * `update_column_value.pulse_id` ships as a `<number>` JSON
672
+ * literal on the wire; the Update / Reply surfaces ship the same
673
+ * id-shaped slots as strings. Both need to land on the projected
674
+ * event as `string | null` (the CLI's branded `ItemId` shape +
675
+ * agent ergonomics — JSON IDs are stringified throughout the
676
+ * envelope to avoid floating-point precision issues on large
677
+ * board / item / pulse identifiers).
678
+ *
679
+ * Codex impl review round 2 P2-1: without this helper,
680
+ * `readNullableString` rejected the numeric wire shape and the
681
+ * projected event would carry `pulse_id: null` despite the
682
+ * probe-confirmed wire value.
683
+ */
684
+ const readNullableIdField = (obj, key) => {
685
+ const v = obj[key];
686
+ if (typeof v === 'string')
687
+ return v;
688
+ if (typeof v === 'number' && Number.isFinite(v))
689
+ return String(v);
690
+ return null;
691
+ };
692
+ /**
693
+ * Projects one wire `ActivityLogType` row into a typed
694
+ * {@link HistoryEvent}. Parses the wire `data` JSON, dispatches
695
+ * on `row.event`, and emits the matching typed variant. Unknown
696
+ * event kinds fall back to the `unknown` variant carrying the raw
697
+ * parsed `data` under `after`.
698
+ *
699
+ * The projector is the SINGLE per-row dispatch point; the walker
700
+ * delegates to it after the `entity === 'pulse'` filter (single
701
+ * source of truth at the walker layer per Decision 2 closure;
702
+ * projector does NOT re-filter).
703
+ *
704
+ * Per-`column_type` typed before/after for `update_column_value`:
705
+ * `value` and `previous_value` are passed through with one level
706
+ * of nested-JSON unwrap (Monday encodes nested values as JSON
707
+ * strings inside the outer `data` payload); each column type's
708
+ * concrete payload shape (e.g. status `{label, index}`, date ISO
709
+ * string, text raw string) flows through unchanged. Per Decision
710
+ * 2 closure: `previous_value: {}` is preserved as "previously-
711
+ * unset" rather than collapsed to `null` — agents distinguish
712
+ * the empty-object shape.
713
+ */
714
+ export const projectActivityLogRow = (inputs) => {
715
+ const { row } = inputs;
716
+ const parsedData = parseActivityLogDataJson(row.data);
717
+ const dataObj = isPlainObject(parsedData) ? parsedData : {};
718
+ switch (row.event) {
719
+ case 'update_column_value': {
720
+ const columnId = readStringField(dataObj, 'column_id');
721
+ const columnType = readStringField(dataObj, 'column_type');
722
+ // Missing / empty discriminator fields → fall through to
723
+ // `unknown` rather than emit a typed variant with empty
724
+ // strings. Defensive: the probe pinned both fields always
725
+ // present on `update_column_value` payloads, but a future
726
+ // Monday rename or partial-payload bug would otherwise
727
+ // produce a malformed typed event.
728
+ if (columnId !== '' && columnType !== '') {
729
+ return {
730
+ id: row.id,
731
+ created_at: row.created_at,
732
+ actor_id: row.user_id,
733
+ kind: 'update_column_value',
734
+ column_id: columnId,
735
+ column_type: columnType,
736
+ before: unwrapNestedJson(dataObj.previous_value),
737
+ after: unwrapNestedJson(dataObj.value),
738
+ textual_value: readNullableString(dataObj, 'textual_value'),
739
+ pulse_id: readNullableIdField(dataObj, 'pulse_id'),
740
+ pulse_name: readNullableString(dataObj, 'pulse_name'),
741
+ };
742
+ }
743
+ break;
744
+ }
745
+ case 'create_column':
746
+ case 'create_group':
747
+ case 'update_board_name':
748
+ case 'update_board_nickname':
749
+ case 'board_workspace_id_changed': {
750
+ // Board-scoped variants — the walker's entity filter
751
+ // normally drops these, but the projector keeps the typed
752
+ // branch so a future regression that bypasses the filter
753
+ // fails into the typed variant rather than `unknown`.
754
+ // Both `before` / `after` carry the raw parsed payload so
755
+ // agents see Monday's full event payload without re-parsing.
756
+ return {
757
+ id: row.id,
758
+ created_at: row.created_at,
759
+ actor_id: row.user_id,
760
+ kind: row.event,
761
+ before: unwrapNestedJson(dataObj.previous_value),
762
+ after: parsedData,
763
+ };
764
+ }
765
+ default: // fall through to the unknown variant below.
766
+ }
767
+ return {
768
+ id: row.id,
769
+ created_at: row.created_at,
770
+ actor_id: row.user_id,
771
+ kind: 'unknown',
772
+ event: row.event,
773
+ entity: row.entity,
774
+ before: null,
775
+ after: parsedData,
776
+ };
777
+ };
778
+ /**
779
+ * Projects one wire `Update` row into a synthesized
780
+ * {@link HistoryEvent} of kind `update_posted` plus one
781
+ * `update_replied` event per `row.replies` entry (via
782
+ * {@link projectReplyRow}). Returns a flat array suitable for
783
+ * the merger.
784
+ *
785
+ * `Update.created_at` is nullable per Decision 2 closure probe
786
+ * findings; the projector substitutes `Update.edited_at`
787
+ * (NON_NULL) as the chronological key — silent projection
788
+ * behaviour, deterministic across re-walks.
789
+ *
790
+ * Replies are flat-mapped here (not at the walker) so the
791
+ * walker stays surface-symmetric with the activity_logs source
792
+ * (both project per-row → events). The merge projector orders
793
+ * the combined stream.
794
+ */
795
+ export const projectUpdateRow = (inputs) => {
796
+ const { row } = inputs;
797
+ const createdAt = row.created_at ?? row.edited_at;
798
+ const replies = row.replies ?? [];
799
+ const posted = {
800
+ id: row.id,
801
+ created_at: createdAt,
802
+ actor_id: row.creator_id,
803
+ kind: 'update_posted',
804
+ before: null,
805
+ after: {
806
+ body: row.body,
807
+ text_body: row.text_body,
808
+ reply_count: replies.length,
809
+ },
810
+ };
811
+ const repliedEvents = replies.map((reply) => projectReplyRow({
812
+ row: reply,
813
+ parentUpdateId: row.id,
814
+ parentCreatedAt: createdAt,
815
+ }));
816
+ return [posted, ...repliedEvents];
817
+ };
818
+ /**
819
+ * Projects one wire `Reply` row into a synthesized
820
+ * {@link HistoryEvent} of kind `update_replied`. The parent
821
+ * `Update.id` lands on `parent_update_id`; `Reply.kind` lands on
822
+ * `reply_kind` (separate from `activity_logs.event` taxonomy per
823
+ * the Decision 2 closure probe finding).
824
+ *
825
+ * `Reply.created_at` is nullable per the probe introspection;
826
+ * fallback chain: `Reply.created_at` → `Reply.updated_at` →
827
+ * the parent Update's projected timestamp. The final fallback
828
+ * is load-bearing: the event schema requires `created_at` to be
829
+ * non-empty (`min(1)`) and the parent's timestamp is guaranteed
830
+ * non-empty by `projectUpdateRow`'s `created_at ?? edited_at`
831
+ * resolution (Codex impl review round 1 P2-2). A Reply with both
832
+ * timestamps null then merges right next to its parent on the
833
+ * chronological stream.
834
+ */
835
+ export const projectReplyRow = (inputs) => {
836
+ const { row, parentUpdateId, parentCreatedAt } = inputs;
837
+ const createdAt = row.created_at ?? row.updated_at ?? parentCreatedAt;
838
+ return {
839
+ id: row.id,
840
+ created_at: createdAt,
841
+ actor_id: row.creator_id,
842
+ kind: 'update_replied',
843
+ parent_update_id: parentUpdateId,
844
+ reply_kind: row.kind,
845
+ before: null,
846
+ after: {
847
+ body: row.body,
848
+ text_body: row.text_body,
849
+ },
850
+ };
851
+ };
852
+ /**
853
+ * Two-source GraphQL response schemas — parse boundaries for the
854
+ * walker's per-stage `unwrapOrThrow` calls. `.loose()` lets
855
+ * additive Monday surface fields pass through without breaking
856
+ * the parse (same forward-compat policy as M22/M23 wire schemas).
857
+ */
858
+ const activityLogsResponseSchema = z
859
+ .object({
860
+ boards: z
861
+ .array(z
862
+ .object({
863
+ id: z.string().min(1),
864
+ activity_logs: z.array(rawActivityLogRowSchema).nullable(),
865
+ })
866
+ .loose()
867
+ .nullable())
868
+ .nullable(),
869
+ })
870
+ .loose();
871
+ const updatesResponseSchema = z
872
+ .object({
873
+ items: z
874
+ .array(z
875
+ .object({
876
+ id: z.string().min(1),
877
+ updates: z.array(rawUpdateRowSchema).nullable(),
878
+ })
879
+ .loose()
880
+ .nullable())
881
+ .nullable(),
882
+ })
883
+ .loose();
884
+ /**
885
+ * Tests whether an ISO-8601 timestamp falls within the
886
+ * `--since` / `--until` range. Uses `Date.parse` rather than
887
+ * lexicographic compare because the wire payload may carry
888
+ * UTC `Z`-suffixed timestamps (Monday's `ISO8601DateTime`
889
+ * scalar — Decision 2 probe) while the CLI's `--since` /
890
+ * `--until` accept any ISO-8601 surface, including mixed
891
+ * offsets (`+01:00`, `-05:00`, etc.). Lex compare gives the
892
+ * wrong answer when offsets differ — e.g. `09:30:00Z` should
893
+ * pass `--since 10:00:00+01:00` (= 09:00:00Z) but lex compare
894
+ * would reject it (Codex impl review round 1 P2-1).
895
+ *
896
+ * `since` / `until` epoch values are precomputed by the caller
897
+ * to avoid the per-row Date.parse cost on large slices.
898
+ *
899
+ * **NaN guard.** `Date.parse` returns `NaN` on malformed input.
900
+ * All `NaN`-vs-number comparisons are `false`, so without a
901
+ * guard a malformed row timestamp would slip through the filter
902
+ * (Codex impl review round 2 P3-1). The walker's argv schema
903
+ * filters user-supplied bounds upstream, but the row epoch is
904
+ * sourced from Monday's wire and may drift if Monday ships a
905
+ * malformed `Update.created_at`. Treat unparseable rows as
906
+ * out-of-range so the merger doesn't surface them.
907
+ */
908
+ const inWallClockRange = (timestamp, sinceEpoch, untilEpoch) => {
909
+ const epoch = Date.parse(timestamp);
910
+ if (Number.isNaN(epoch))
911
+ return false;
912
+ if (sinceEpoch !== undefined && epoch < sinceEpoch)
913
+ return false;
914
+ if (untilEpoch !== undefined && epoch > untilEpoch)
915
+ return false;
916
+ return true;
917
+ };
918
+ /**
919
+ * Two-source merged-history walker. Issues two independent
920
+ * GraphQL calls (activity_logs + updates), filters + projects
921
+ * each per Decision 2 closure ratified shape, merges
922
+ * chronologically, aggregates `unknown_event_kind` warnings,
923
+ * applies optional `--kinds` projection filter, and streams via
924
+ * `inputs.onItem` (per-merged-event AFTER the merge — merging
925
+ * requires full slice resident per the `mergeByCreatedAt`
926
+ * docstring).
927
+ *
928
+ * **`source: 'live'` constant.** activity_logs + updates are
929
+ * pure reads with no per-call cache; the action layer aggregates
930
+ * this with the item-board lookup's `'live'` source via
931
+ * `SourceAggregator` and resolves the envelope's `meta.source`
932
+ * from the aggregator's resolved state (mirrors M23
933
+ * cross-board-search).
934
+ *
935
+ * **`complexity`** is the larger of the two stages' per-call
936
+ * complexity values (under `--verbose` only; null outside). Two
937
+ * independent calls → take the worst-case stage so agents see
938
+ * the more conservative budget snapshot rather than averaging.
939
+ *
940
+ * **Per-source pagination state.** Each source's `last_page` is
941
+ * the page number the walker DRAINED if the response returned a
942
+ * full slice (`response.length === limit` → more pages likely);
943
+ * `null` when the response returned less than `limit` rows
944
+ * (source exhausted). Monday's page-numbered surfaces have no
945
+ * "next" sentinel; the heuristic mirrors the v0.2 page-walker
946
+ * shape.
947
+ */
948
+ export const fetchItemHistory = async (inputs) => {
949
+ const limit = inputs.limit ?? DEFAULT_HISTORY_PAGE_SIZE;
950
+ const activityPage = inputs.activityLogsPage ?? 1;
951
+ const updatesPage = inputs.updatesPage ?? 1;
952
+ // Stage 1 — activity_logs page-walk.
953
+ const stage1 = await inputs.client.raw(ACTIVITY_LOGS_QUERY, {
954
+ bid: [inputs.boardId],
955
+ iid: [inputs.itemId],
956
+ // Monday's `from` / `to` accept null for unbounded sides; we
957
+ // omit the key entirely when undefined to keep the wire
958
+ // payload minimal (the `.loose()` parse on the response is
959
+ // unaffected by which args we send).
960
+ ...(inputs.since === undefined ? {} : { from: inputs.since }),
961
+ ...(inputs.until === undefined ? {} : { to: inputs.until }),
962
+ page: activityPage,
963
+ limit,
964
+ }, { operationName: 'ItemHistoryActivityLogs' });
965
+ const stage1Data = unwrapOrThrow(activityLogsResponseSchema.safeParse(stage1.data), {
966
+ context: 'Monday `boards.activity_logs` response',
967
+ details: { item_id: inputs.itemId, board_id: inputs.boardId },
968
+ hint: 'Monday may have amended the `boards(ids:) { activity_logs }` surface — re-probe via `scripts/probe/m24-history-kinds.ts` and amend cli-design §13 v0.3 entry if so',
969
+ });
970
+ const rawActivityRows = [];
971
+ const boards = stage1Data.boards ?? [];
972
+ for (const board of boards) {
973
+ if (board === null)
974
+ continue;
975
+ const rows = board.activity_logs ?? [];
976
+ rawActivityRows.push(...rows);
977
+ }
978
+ // Walker-side entity filter (Decision 2 ratified): drop
979
+ // board-scoped events that leak through `item_ids` per the
980
+ // empirical-probe finding. Single source of truth at the walker;
981
+ // projector does NOT re-filter.
982
+ const itemScopedRows = rawActivityRows.filter((r) => r.entity === ITEM_SCOPED_ENTITY);
983
+ const activityEvents = itemScopedRows.map((row) => projectActivityLogRow({ row }));
984
+ // Aggregate unknown_event_kind warnings: one warning per unique
985
+ // (event, entity) tuple observed; `occurrence_count` carries the
986
+ // multiplicity so the warnings array stays bounded on degenerate
987
+ // inputs. Keyed by `${event}\x00${entity}` to disambiguate the
988
+ // same event name surfacing under two entity values.
989
+ const unknownByKey = new Map();
990
+ for (const ev of activityEvents) {
991
+ if (ev.kind === 'unknown') {
992
+ const key = `${ev.event}\x00${ev.entity}`;
993
+ const entry = unknownByKey.get(key);
994
+ if (entry === undefined) {
995
+ unknownByKey.set(key, {
996
+ event: ev.event,
997
+ entity: ev.entity,
998
+ count: 1,
999
+ });
1000
+ }
1001
+ else {
1002
+ entry.count++;
1003
+ }
1004
+ }
1005
+ }
1006
+ // Stage 2 — updates page-walk (independent denominator).
1007
+ const stage2 = await inputs.client.raw(UPDATES_QUERY, {
1008
+ iid: [inputs.itemId],
1009
+ page: updatesPage,
1010
+ limit,
1011
+ }, { operationName: 'ItemHistoryUpdates' });
1012
+ const stage2Data = unwrapOrThrow(updatesResponseSchema.safeParse(stage2.data), {
1013
+ context: 'Monday `items.updates` response',
1014
+ details: { item_id: inputs.itemId },
1015
+ hint: 'Monday may have amended the `items(ids:) { updates }` surface — re-probe via `scripts/probe/m24-history-kinds.ts` and amend cli-design §13 v0.3 entry if so',
1016
+ });
1017
+ const rawUpdateRows = [];
1018
+ const items = stage2Data.items ?? [];
1019
+ for (const it of items) {
1020
+ if (it === null)
1021
+ continue;
1022
+ const rows = it.updates ?? [];
1023
+ rawUpdateRows.push(...rows);
1024
+ }
1025
+ // Project each Update + flat-map its replies. The projector
1026
+ // returns a flat array (parent + N replies) per row; flat-map
1027
+ // here so the wall-clock filter and merger see one combined
1028
+ // list per source.
1029
+ const allUpdateEvents = rawUpdateRows.flatMap((row) => projectUpdateRow({ row }));
1030
+ // Client-side wall-clock filter. Monday's `updates` resolver
1031
+ // doesn't expose `from:` / `to:` per Decision 2 probe; filter
1032
+ // after projection so the per-row chronological key matches the
1033
+ // merger's sort. Precompute epoch bounds once so we don't pay
1034
+ // the `Date.parse(bound)` cost per row.
1035
+ const sinceEpoch = inputs.since === undefined ? undefined : Date.parse(inputs.since);
1036
+ const untilEpoch = inputs.until === undefined ? undefined : Date.parse(inputs.until);
1037
+ const updateEvents = sinceEpoch === undefined && untilEpoch === undefined
1038
+ ? allUpdateEvents
1039
+ : allUpdateEvents.filter((ev) => inWallClockRange(ev.created_at, sinceEpoch, untilEpoch));
1040
+ // Chronological merge of both fully-drained source lists.
1041
+ const merged = mergeByCreatedAt(activityEvents, updateEvents);
1042
+ // Optional `--kinds` projection filter — narrows `data` array
1043
+ // but warnings stay (per the docstring contract). Set lookup
1044
+ // keeps the filter O(N).
1045
+ const kindsSet = inputs.kinds === undefined ? undefined : new Set(inputs.kinds);
1046
+ const filtered = kindsSet === undefined
1047
+ ? merged
1048
+ : merged.filter((ev) => kindsSet.has(ev.kind));
1049
+ // Stream hook — per-merged-event AFTER the merge (merging is
1050
+ // not incremental per the helper's docstring). Awaiting each
1051
+ // call preserves backpressure when the hook drives an NDJSON
1052
+ // stream against a slow consumer.
1053
+ if (inputs.onItem !== undefined) {
1054
+ for (const event of filtered) {
1055
+ await inputs.onItem(event);
1056
+ }
1057
+ }
1058
+ // Build warnings array — sorted deterministically by event so
1059
+ // re-walks against the same wire produce identical envelopes.
1060
+ // Entity disambiguation lives in the map key (defensive against
1061
+ // a future bypass of the walker's entity filter) but the sort
1062
+ // is primary-on-event only: the walker's `entity === 'pulse'`
1063
+ // filter means every surfaced warning carries entity='pulse'
1064
+ // in production, so a secondary entity sort would be dead code.
1065
+ const warnings = Array.from(unknownByKey.values())
1066
+ .sort((a, b) => (a.event < b.event ? -1 : a.event > b.event ? 1 : 0))
1067
+ .map((entry) => buildUnknownEventKindWarning(entry.event, entry.entity, entry.count));
1068
+ // Per-source pagination state. Heuristic: a response of less
1069
+ // than `limit` rows means "drained" → last_page null; a full
1070
+ // slice means "potentially more" → last_page = current page.
1071
+ const activityLastPage = rawActivityRows.length < limit ? null : activityPage;
1072
+ const updatesLastPage = rawUpdateRows.length < limit ? null : updatesPage;
1073
+ // Complexity — worst-case (smaller) of the two stages'
1074
+ // `remaining` budget under `--verbose`; null outside. Two
1075
+ // independent calls → pick the stage that consumed the most
1076
+ // budget so agents see the more conservative remaining
1077
+ // snapshot rather than averaging.
1078
+ const complexity = stage1.complexity === null
1079
+ ? stage2.complexity
1080
+ : stage2.complexity === null
1081
+ ? stage1.complexity
1082
+ : stage1.complexity.remaining <= stage2.complexity.remaining
1083
+ ? stage1.complexity
1084
+ : stage2.complexity;
1085
+ return {
1086
+ events: filtered,
1087
+ pagination: {
1088
+ activity_logs: { last_page: activityLastPage },
1089
+ updates: { last_page: updatesLastPage },
1090
+ },
1091
+ warnings,
1092
+ complexity,
1093
+ source: 'live',
1094
+ };
1095
+ };
1096
+ /**
1097
+ * Adapter from a {@link FetchItemHistoryResult}'s `warnings`
1098
+ * array to the envelope-shaped {@link Warning} array consumed by
1099
+ * `emitSuccess`. Pre-flight pure helper — type-narrows the
1100
+ * `code` discriminator so the envelope's `warnings[]` slot
1101
+ * carries the precise shape rather than a generic `Warning`.
1102
+ */
1103
+ export const toEnvelopeWarnings = (warnings) => warnings;
1104
+ //# sourceMappingURL=item-history-projection.js.map