agentplane 0.3.7 → 0.3.9

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 (619) hide show
  1. package/assets/AGENTS.md +11 -1
  2. package/assets/RUNNER.md +17 -0
  3. package/bin/agentplane.js +16 -7
  4. package/bin/framework-dev-contract.d.ts +6 -0
  5. package/bin/framework-dev-contract.js +13 -0
  6. package/bin/stale-dist-policy.js +6 -1
  7. package/dist/.build-manifest.json +692 -337
  8. package/dist/adapters/task-backend/task-backend-adapter.d.ts +3 -1
  9. package/dist/adapters/task-backend/task-backend-adapter.d.ts.map +1 -1
  10. package/dist/adapters/task-backend/task-backend-adapter.js +13 -0
  11. package/dist/backends/task-backend/local-backend-doc.d.ts +5 -0
  12. package/dist/backends/task-backend/local-backend-doc.d.ts.map +1 -0
  13. package/dist/backends/task-backend/local-backend-doc.js +98 -0
  14. package/dist/backends/task-backend/local-backend-read.d.ts +7 -0
  15. package/dist/backends/task-backend/local-backend-read.d.ts.map +1 -0
  16. package/dist/backends/task-backend/local-backend-read.js +186 -0
  17. package/dist/backends/task-backend/local-backend-state.d.ts +17 -0
  18. package/dist/backends/task-backend/local-backend-state.d.ts.map +1 -0
  19. package/dist/backends/task-backend/local-backend-state.js +50 -0
  20. package/dist/backends/task-backend/local-backend-write.d.ts +15 -0
  21. package/dist/backends/task-backend/local-backend-write.d.ts.map +1 -0
  22. package/dist/backends/task-backend/local-backend-write.js +254 -0
  23. package/dist/backends/task-backend/local-backend.d.ts +4 -2
  24. package/dist/backends/task-backend/local-backend.d.ts.map +1 -1
  25. package/dist/backends/task-backend/local-backend.js +26 -403
  26. package/dist/backends/task-backend/redmine/backend-cache-doc.d.ts +40 -0
  27. package/dist/backends/task-backend/redmine/backend-cache-doc.d.ts.map +1 -0
  28. package/dist/backends/task-backend/redmine/backend-cache-doc.js +178 -0
  29. package/dist/backends/task-backend/redmine/backend-report.d.ts +10 -0
  30. package/dist/backends/task-backend/redmine/backend-report.d.ts.map +1 -0
  31. package/dist/backends/task-backend/redmine/backend-report.js +43 -0
  32. package/dist/backends/task-backend/redmine/backend-sync.d.ts +67 -0
  33. package/dist/backends/task-backend/redmine/backend-sync.d.ts.map +1 -0
  34. package/dist/backends/task-backend/redmine/backend-sync.js +367 -0
  35. package/dist/backends/task-backend/redmine/mapping.d.ts +2 -1
  36. package/dist/backends/task-backend/redmine/mapping.d.ts.map +1 -1
  37. package/dist/backends/task-backend/redmine/mapping.js +12 -2
  38. package/dist/backends/task-backend/redmine/parse.d.ts +2 -1
  39. package/dist/backends/task-backend/redmine/parse.d.ts.map +1 -1
  40. package/dist/backends/task-backend/redmine/parse.js +5 -3
  41. package/dist/backends/task-backend/redmine/state.d.ts +2 -0
  42. package/dist/backends/task-backend/redmine/state.d.ts.map +1 -1
  43. package/dist/backends/task-backend/redmine/state.js +15 -1
  44. package/dist/backends/task-backend/redmine-backend.d.ts +5 -2
  45. package/dist/backends/task-backend/redmine-backend.d.ts.map +1 -1
  46. package/dist/backends/task-backend/redmine-backend.js +88 -536
  47. package/dist/backends/task-backend/shared/constants.d.ts +2 -1
  48. package/dist/backends/task-backend/shared/constants.d.ts.map +1 -1
  49. package/dist/backends/task-backend/shared/doc.d.ts.map +1 -1
  50. package/dist/backends/task-backend/shared/doc.js +25 -39
  51. package/dist/backends/task-backend/shared/export.d.ts +2 -9
  52. package/dist/backends/task-backend/shared/export.d.ts.map +1 -1
  53. package/dist/backends/task-backend/shared/export.js +73 -8
  54. package/dist/backends/task-backend/shared/normalize.d.ts +5 -1
  55. package/dist/backends/task-backend/shared/normalize.d.ts.map +1 -1
  56. package/dist/backends/task-backend/shared/normalize.js +166 -0
  57. package/dist/backends/task-backend/shared/record.d.ts +1 -1
  58. package/dist/backends/task-backend/shared/record.d.ts.map +1 -1
  59. package/dist/backends/task-backend/shared/record.js +7 -2
  60. package/dist/backends/task-backend/shared/types.d.ts +38 -36
  61. package/dist/backends/task-backend/shared/types.d.ts.map +1 -1
  62. package/dist/backends/task-backend/shared.d.ts +2 -2
  63. package/dist/backends/task-backend/shared.d.ts.map +1 -1
  64. package/dist/backends/task-backend/shared.js +1 -1
  65. package/dist/backends/task-backend.d.ts +1 -1
  66. package/dist/backends/task-backend.d.ts.map +1 -1
  67. package/dist/backends/task-backend.js +1 -1
  68. package/dist/backends/task-index.d.ts +2 -2
  69. package/dist/backends/task-index.d.ts.map +1 -1
  70. package/dist/backends/task-index.js +9 -6
  71. package/dist/cli/bootstrap-guide.d.ts +2 -2
  72. package/dist/cli/bootstrap-guide.d.ts.map +1 -1
  73. package/dist/cli/bootstrap-guide.js +10 -10
  74. package/dist/cli/command-guide.d.ts.map +1 -1
  75. package/dist/cli/command-guide.js +11 -9
  76. package/dist/cli/command-invocations.d.ts +4 -0
  77. package/dist/cli/command-invocations.d.ts.map +1 -0
  78. package/dist/cli/command-invocations.js +35 -0
  79. package/dist/cli/command-snippets.d.ts +12 -8
  80. package/dist/cli/command-snippets.d.ts.map +1 -1
  81. package/dist/cli/command-snippets.js +14 -8
  82. package/dist/cli/exit-codes.d.ts.map +1 -1
  83. package/dist/cli/exit-codes.js +1 -0
  84. package/dist/cli/group-command.d.ts +18 -0
  85. package/dist/cli/group-command.d.ts.map +1 -0
  86. package/dist/cli/group-command.js +45 -0
  87. package/dist/cli/output.d.ts +29 -0
  88. package/dist/cli/output.d.ts.map +1 -1
  89. package/dist/cli/output.js +76 -0
  90. package/dist/cli/prompts.d.ts.map +1 -1
  91. package/dist/cli/prompts.js +5 -1
  92. package/dist/cli/run-cli/command-catalog/core.d.ts.map +1 -1
  93. package/dist/cli/run-cli/command-catalog/core.js +38 -29
  94. package/dist/cli/run-cli/command-catalog/lifecycle.d.ts.map +1 -1
  95. package/dist/cli/run-cli/command-catalog/lifecycle.js +9 -6
  96. package/dist/cli/run-cli/command-catalog/project.d.ts +1 -1
  97. package/dist/cli/run-cli/command-catalog/project.d.ts.map +1 -1
  98. package/dist/cli/run-cli/command-catalog/project.js +8 -6
  99. package/dist/cli/run-cli/command-catalog/shared.d.ts +12 -3
  100. package/dist/cli/run-cli/command-catalog/shared.d.ts.map +1 -1
  101. package/dist/cli/run-cli/command-catalog/shared.js +6 -3
  102. package/dist/cli/run-cli/command-catalog/task.d.ts +1 -1
  103. package/dist/cli/run-cli/command-catalog/task.d.ts.map +1 -1
  104. package/dist/cli/run-cli/command-catalog/task.js +46 -11
  105. package/dist/cli/run-cli/command-catalog.d.ts +11 -1
  106. package/dist/cli/run-cli/command-catalog.d.ts.map +1 -1
  107. package/dist/cli/run-cli/command-catalog.js +29 -0
  108. package/dist/cli/run-cli/commands/config.d.ts.map +1 -1
  109. package/dist/cli/run-cli/commands/config.js +52 -6
  110. package/dist/cli/run-cli/commands/core/agent-profiles.d.ts +34 -0
  111. package/dist/cli/run-cli/commands/core/agent-profiles.d.ts.map +1 -0
  112. package/dist/cli/run-cli/commands/core/agent-profiles.js +97 -0
  113. package/dist/cli/run-cli/commands/core/agents.d.ts +7 -0
  114. package/dist/cli/run-cli/commands/core/agents.d.ts.map +1 -0
  115. package/dist/cli/run-cli/commands/core/agents.js +97 -0
  116. package/dist/cli/run-cli/commands/core/preflight.d.ts +10 -0
  117. package/dist/cli/run-cli/commands/core/preflight.d.ts.map +1 -0
  118. package/dist/cli/run-cli/commands/core/preflight.js +286 -0
  119. package/dist/cli/run-cli/commands/core/quickstart.d.ts +8 -0
  120. package/dist/cli/run-cli/commands/core/quickstart.d.ts.map +1 -0
  121. package/dist/cli/run-cli/commands/core/quickstart.js +43 -0
  122. package/dist/cli/run-cli/commands/core/role.d.ts +9 -0
  123. package/dist/cli/run-cli/commands/core/role.d.ts.map +1 -0
  124. package/dist/cli/run-cli/commands/core/role.js +128 -0
  125. package/dist/cli/run-cli/commands/core.d.ts +4 -24
  126. package/dist/cli/run-cli/commands/core.d.ts.map +1 -1
  127. package/dist/cli/run-cli/commands/core.js +4 -630
  128. package/dist/cli/run-cli/error-guidance.js +10 -0
  129. package/dist/cli/run-cli/globals.d.ts +5 -2
  130. package/dist/cli/run-cli/globals.d.ts.map +1 -1
  131. package/dist/cli/run-cli/globals.js +82 -86
  132. package/dist/cli/run-cli.d.ts.map +1 -1
  133. package/dist/cli/run-cli.js +137 -100
  134. package/dist/cli/run-cli.test-helpers.d.ts +21 -0
  135. package/dist/cli/run-cli.test-helpers.d.ts.map +1 -1
  136. package/dist/cli/run-cli.test-helpers.js +122 -12
  137. package/dist/cli/spec/help.d.ts +10 -2
  138. package/dist/cli/spec/help.d.ts.map +1 -1
  139. package/dist/cli/spec/help.js +7 -5
  140. package/dist/cli/spec/registry.d.ts +27 -1
  141. package/dist/cli/spec/registry.d.ts.map +1 -1
  142. package/dist/cli/spec/registry.js +98 -25
  143. package/dist/commands/backend/sync.command.d.ts +3 -5
  144. package/dist/commands/backend/sync.command.d.ts.map +1 -1
  145. package/dist/commands/backend/sync.command.js +9 -12
  146. package/dist/commands/backend.d.ts.map +1 -1
  147. package/dist/commands/backend.js +8 -7
  148. package/dist/commands/branch/base.command.d.ts +2 -3
  149. package/dist/commands/branch/base.command.d.ts.map +1 -1
  150. package/dist/commands/branch/base.command.js +8 -12
  151. package/dist/commands/branch/base.d.ts.map +1 -1
  152. package/dist/commands/branch/base.js +11 -7
  153. package/dist/commands/branch/cleanup-merged.d.ts.map +1 -1
  154. package/dist/commands/branch/cleanup-merged.js +9 -8
  155. package/dist/commands/branch/remove.d.ts.map +1 -1
  156. package/dist/commands/branch/remove.js +4 -3
  157. package/dist/commands/branch/status.d.ts.map +1 -1
  158. package/dist/commands/branch/status.js +4 -3
  159. package/dist/commands/branch/work-start.d.ts.map +1 -1
  160. package/dist/commands/branch/work-start.js +48 -5
  161. package/dist/commands/cleanup/merged.command.d.ts +2 -3
  162. package/dist/commands/cleanup/merged.command.d.ts.map +1 -1
  163. package/dist/commands/cleanup/merged.command.js +8 -12
  164. package/dist/commands/docs/cli.command.js +2 -2
  165. package/dist/commands/doctor/runtime.js +1 -1
  166. package/dist/commands/doctor/workflow.d.ts.map +1 -1
  167. package/dist/commands/doctor/workflow.js +10 -1
  168. package/dist/commands/finish.spec.d.ts.map +1 -1
  169. package/dist/commands/finish.spec.js +7 -0
  170. package/dist/commands/guard/guard.command.d.ts +3 -3
  171. package/dist/commands/guard/guard.command.d.ts.map +1 -1
  172. package/dist/commands/guard/guard.command.js +9 -14
  173. package/dist/commands/guard/impl/commands.d.ts +2 -0
  174. package/dist/commands/guard/impl/commands.d.ts.map +1 -1
  175. package/dist/commands/guard/impl/commands.js +55 -7
  176. package/dist/commands/guard/impl/policy.d.ts +1 -0
  177. package/dist/commands/guard/impl/policy.d.ts.map +1 -1
  178. package/dist/commands/guard/impl/policy.js +9 -6
  179. package/dist/commands/hooks/hooks.command.d.ts +3 -3
  180. package/dist/commands/hooks/hooks.command.d.ts.map +1 -1
  181. package/dist/commands/hooks/hooks.command.js +9 -11
  182. package/dist/commands/hooks/index.d.ts.map +1 -1
  183. package/dist/commands/hooks/index.js +8 -4
  184. package/dist/commands/pr/check.d.ts.map +1 -1
  185. package/dist/commands/pr/check.js +90 -18
  186. package/dist/commands/pr/integrate/cmd.d.ts.map +1 -1
  187. package/dist/commands/pr/integrate/cmd.js +31 -3
  188. package/dist/commands/pr/integrate/internal/cleanup.d.ts +12 -0
  189. package/dist/commands/pr/integrate/internal/cleanup.d.ts.map +1 -0
  190. package/dist/commands/pr/integrate/internal/cleanup.js +46 -0
  191. package/dist/commands/pr/integrate/internal/finalize.d.ts +4 -0
  192. package/dist/commands/pr/integrate/internal/finalize.d.ts.map +1 -1
  193. package/dist/commands/pr/integrate/internal/finalize.js +34 -40
  194. package/dist/commands/pr/integrate/internal/merge.d.ts +6 -0
  195. package/dist/commands/pr/integrate/internal/merge.d.ts.map +1 -1
  196. package/dist/commands/pr/integrate/internal/merge.js +92 -0
  197. package/dist/commands/pr/integrate/internal/prepare.d.ts +1 -0
  198. package/dist/commands/pr/integrate/internal/prepare.d.ts.map +1 -1
  199. package/dist/commands/pr/integrate/internal/prepare.js +1 -0
  200. package/dist/commands/pr/integrate/verify.d.ts.map +1 -1
  201. package/dist/commands/pr/integrate/verify.js +4 -3
  202. package/dist/commands/pr/note.d.ts.map +1 -1
  203. package/dist/commands/pr/note.js +3 -2
  204. package/dist/commands/pr/open.d.ts.map +1 -1
  205. package/dist/commands/pr/open.js +9 -12
  206. package/dist/commands/pr/pr.command.d.ts +3 -4
  207. package/dist/commands/pr/pr.command.d.ts.map +1 -1
  208. package/dist/commands/pr/pr.command.js +6 -11
  209. package/dist/commands/pr/update.d.ts.map +1 -1
  210. package/dist/commands/pr/update.js +5 -10
  211. package/dist/commands/recipes/cache.command.d.ts +3 -4
  212. package/dist/commands/recipes/cache.command.d.ts.map +1 -1
  213. package/dist/commands/recipes/cache.command.js +8 -26
  214. package/dist/commands/recipes/impl/apply.js +1 -1
  215. package/dist/commands/recipes/impl/commands/explain.js +1 -1
  216. package/dist/commands/recipes/impl/installed-recipes.d.ts.map +1 -1
  217. package/dist/commands/recipes/impl/installed-recipes.js +1 -1
  218. package/dist/commands/recipes/impl/manifest.d.ts.map +1 -1
  219. package/dist/commands/recipes/impl/manifest.js +0 -10
  220. package/dist/commands/recipes/impl/project-installed-recipes.d.ts.map +1 -1
  221. package/dist/commands/recipes/impl/project-installed-recipes.js +1 -1
  222. package/dist/commands/recipes/impl/resolver.d.ts +1 -1
  223. package/dist/commands/recipes/impl/resolver.d.ts.map +1 -1
  224. package/dist/commands/recipes/impl/resolver.js +26 -16
  225. package/dist/commands/recipes/impl/scenario.d.ts.map +1 -1
  226. package/dist/commands/recipes/impl/scenario.js +80 -0
  227. package/dist/commands/recipes/impl/types.d.ts +27 -13
  228. package/dist/commands/recipes/impl/types.d.ts.map +1 -1
  229. package/dist/commands/recipes/recipes.command.d.ts +3 -4
  230. package/dist/commands/recipes/recipes.command.d.ts.map +1 -1
  231. package/dist/commands/recipes/recipes.command.js +8 -34
  232. package/dist/commands/recipes.d.ts.map +1 -1
  233. package/dist/commands/recipes.test-helpers.d.ts +17 -0
  234. package/dist/commands/recipes.test-helpers.d.ts.map +1 -1
  235. package/dist/commands/recipes.test-helpers.js +56 -2
  236. package/dist/commands/release/apply.command.d.ts.map +1 -1
  237. package/dist/commands/release/apply.command.js +77 -56
  238. package/dist/commands/release/plan.command.d.ts.map +1 -1
  239. package/dist/commands/release/plan.command.js +7 -3
  240. package/dist/commands/release/release.command.d.ts +3 -3
  241. package/dist/commands/release/release.command.d.ts.map +1 -1
  242. package/dist/commands/release/release.command.js +9 -11
  243. package/dist/commands/release.test-helpers.d.ts +34 -0
  244. package/dist/commands/release.test-helpers.d.ts.map +1 -0
  245. package/dist/commands/release.test-helpers.js +48 -0
  246. package/dist/commands/runtime.command.d.ts +7 -7
  247. package/dist/commands/runtime.command.d.ts.map +1 -1
  248. package/dist/commands/runtime.command.js +29 -33
  249. package/dist/commands/scenario/execute.command.d.ts +8 -0
  250. package/dist/commands/scenario/execute.command.d.ts.map +1 -0
  251. package/dist/commands/scenario/execute.command.js +117 -0
  252. package/dist/commands/scenario/impl/commands.d.ts.map +1 -1
  253. package/dist/commands/scenario/impl/commands.js +45 -32
  254. package/dist/commands/scenario/run.command.js +2 -2
  255. package/dist/commands/scenario/scenario.command.d.ts +3 -4
  256. package/dist/commands/scenario/scenario.command.d.ts.map +1 -1
  257. package/dist/commands/scenario/scenario.command.js +8 -26
  258. package/dist/commands/shared/git-context.d.ts +1 -0
  259. package/dist/commands/shared/git-context.d.ts.map +1 -1
  260. package/dist/commands/shared/git-context.js +4 -2
  261. package/dist/commands/shared/git-ops.d.ts +1 -0
  262. package/dist/commands/shared/git-ops.d.ts.map +1 -1
  263. package/dist/commands/shared/git-ops.js +13 -0
  264. package/dist/commands/shared/operator-pipeline.d.ts +10 -0
  265. package/dist/commands/shared/operator-pipeline.d.ts.map +1 -0
  266. package/dist/commands/shared/operator-pipeline.js +16 -0
  267. package/dist/commands/shared/pr-meta.d.ts +32 -12
  268. package/dist/commands/shared/pr-meta.d.ts.map +1 -1
  269. package/dist/commands/shared/pr-meta.js +49 -14
  270. package/dist/commands/shared/reconcile-check.d.ts.map +1 -1
  271. package/dist/commands/shared/reconcile-check.js +28 -3
  272. package/dist/commands/shared/task-backend.d.ts +10 -6
  273. package/dist/commands/shared/task-backend.d.ts.map +1 -1
  274. package/dist/commands/shared/task-backend.js +99 -25
  275. package/dist/commands/shared/task-handoff.d.ts +64 -0
  276. package/dist/commands/shared/task-handoff.d.ts.map +1 -0
  277. package/dist/commands/shared/task-handoff.js +151 -0
  278. package/dist/commands/shared/task-mutation.d.ts +36 -0
  279. package/dist/commands/shared/task-mutation.d.ts.map +1 -0
  280. package/dist/commands/shared/task-mutation.js +67 -0
  281. package/dist/commands/shared/task-store.d.ts +5 -1
  282. package/dist/commands/shared/task-store.d.ts.map +1 -1
  283. package/dist/commands/shared/task-store.js +72 -92
  284. package/dist/commands/task/add.d.ts.map +1 -1
  285. package/dist/commands/task/add.js +41 -39
  286. package/dist/commands/task/block.d.ts.map +1 -1
  287. package/dist/commands/task/block.js +31 -110
  288. package/dist/commands/task/close-duplicate.d.ts.map +1 -1
  289. package/dist/commands/task/close-duplicate.js +0 -7
  290. package/dist/commands/task/close-noop.d.ts.map +1 -1
  291. package/dist/commands/task/close-noop.js +0 -21
  292. package/dist/commands/task/close-shared.d.ts +0 -2
  293. package/dist/commands/task/close-shared.d.ts.map +1 -1
  294. package/dist/commands/task/close-shared.js +25 -55
  295. package/dist/commands/task/comment.d.ts.map +1 -1
  296. package/dist/commands/task/comment.js +48 -37
  297. package/dist/commands/task/derive.d.ts.map +1 -1
  298. package/dist/commands/task/derive.js +14 -7
  299. package/dist/commands/task/doc.command.d.ts.map +1 -1
  300. package/dist/commands/task/doc.command.js +7 -6
  301. package/dist/commands/task/doc.d.ts.map +1 -1
  302. package/dist/commands/task/doc.js +58 -62
  303. package/dist/commands/task/finish-shared.d.ts +60 -0
  304. package/dist/commands/task/finish-shared.d.ts.map +1 -0
  305. package/dist/commands/task/finish-shared.js +181 -0
  306. package/dist/commands/task/finish.d.ts +1 -0
  307. package/dist/commands/task/finish.d.ts.map +1 -1
  308. package/dist/commands/task/finish.js +79 -210
  309. package/dist/commands/task/handoff-record.command.d.ts +17 -0
  310. package/dist/commands/task/handoff-record.command.d.ts.map +1 -0
  311. package/dist/commands/task/handoff-record.command.js +140 -0
  312. package/dist/commands/task/handoff-show.command.d.ts +8 -0
  313. package/dist/commands/task/handoff-show.command.d.ts.map +1 -0
  314. package/dist/commands/task/handoff-show.command.js +77 -0
  315. package/dist/commands/task/handoff.command.d.ts +7 -0
  316. package/dist/commands/task/handoff.command.d.ts.map +1 -0
  317. package/dist/commands/task/handoff.command.js +21 -0
  318. package/dist/commands/task/handoff.shared.d.ts +39 -0
  319. package/dist/commands/task/handoff.shared.d.ts.map +1 -0
  320. package/dist/commands/task/handoff.shared.js +134 -0
  321. package/dist/commands/task/hosted-close.command.d.ts +9 -0
  322. package/dist/commands/task/hosted-close.command.d.ts.map +1 -0
  323. package/dist/commands/task/hosted-close.command.js +190 -0
  324. package/dist/commands/task/hosted-merge-sync.d.ts +40 -0
  325. package/dist/commands/task/hosted-merge-sync.d.ts.map +1 -0
  326. package/dist/commands/task/hosted-merge-sync.js +277 -0
  327. package/dist/commands/task/list.d.ts.map +1 -1
  328. package/dist/commands/task/list.js +7 -24
  329. package/dist/commands/task/new.d.ts.map +1 -1
  330. package/dist/commands/task/new.js +26 -6
  331. package/dist/commands/task/next.d.ts.map +1 -1
  332. package/dist/commands/task/next.js +10 -28
  333. package/dist/commands/task/normalize.command.d.ts +1 -0
  334. package/dist/commands/task/normalize.command.d.ts.map +1 -1
  335. package/dist/commands/task/normalize.command.js +12 -0
  336. package/dist/commands/task/normalize.d.ts +1 -0
  337. package/dist/commands/task/normalize.d.ts.map +1 -1
  338. package/dist/commands/task/normalize.js +21 -9
  339. package/dist/commands/task/plan.command.d.ts +3 -4
  340. package/dist/commands/task/plan.command.d.ts.map +1 -1
  341. package/dist/commands/task/plan.command.js +6 -12
  342. package/dist/commands/task/plan.d.ts.map +1 -1
  343. package/dist/commands/task/plan.js +96 -103
  344. package/dist/commands/task/reclaim.command.d.ts +11 -0
  345. package/dist/commands/task/reclaim.command.d.ts.map +1 -0
  346. package/dist/commands/task/reclaim.command.js +102 -0
  347. package/dist/commands/task/resume-context.command.d.ts +9 -0
  348. package/dist/commands/task/resume-context.command.d.ts.map +1 -0
  349. package/dist/commands/task/resume-context.command.js +60 -0
  350. package/dist/commands/task/run-cancel.command.d.ts +6 -0
  351. package/dist/commands/task/run-cancel.command.d.ts.map +1 -0
  352. package/dist/commands/task/run-cancel.command.js +45 -0
  353. package/dist/commands/task/run-cancel.spec.d.ts +7 -0
  354. package/dist/commands/task/run-cancel.spec.d.ts.map +1 -0
  355. package/dist/commands/task/run-cancel.spec.js +20 -0
  356. package/dist/commands/task/run-resume.command.d.ts +6 -0
  357. package/dist/commands/task/run-resume.command.d.ts.map +1 -0
  358. package/dist/commands/task/run-resume.command.js +55 -0
  359. package/dist/commands/task/run-resume.spec.d.ts +7 -0
  360. package/dist/commands/task/run-resume.spec.d.ts.map +1 -0
  361. package/dist/commands/task/run-resume.spec.js +20 -0
  362. package/dist/commands/task/run-retry.command.d.ts +6 -0
  363. package/dist/commands/task/run-retry.command.d.ts.map +1 -0
  364. package/dist/commands/task/run-retry.command.js +56 -0
  365. package/dist/commands/task/run-retry.spec.d.ts +7 -0
  366. package/dist/commands/task/run-retry.spec.d.ts.map +1 -0
  367. package/dist/commands/task/run-retry.spec.js +20 -0
  368. package/dist/commands/task/run-show.command.d.ts +6 -0
  369. package/dist/commands/task/run-show.command.d.ts.map +1 -0
  370. package/dist/commands/task/run-show.command.js +133 -0
  371. package/dist/commands/task/run-show.spec.d.ts +8 -0
  372. package/dist/commands/task/run-show.spec.d.ts.map +1 -0
  373. package/dist/commands/task/run-show.spec.js +44 -0
  374. package/dist/commands/task/run-tail.command.d.ts +6 -0
  375. package/dist/commands/task/run-tail.command.d.ts.map +1 -0
  376. package/dist/commands/task/run-tail.command.js +26 -0
  377. package/dist/commands/task/run-tail.spec.d.ts +8 -0
  378. package/dist/commands/task/run-tail.spec.d.ts.map +1 -0
  379. package/dist/commands/task/run-tail.spec.js +51 -0
  380. package/dist/commands/task/run-trace.command.d.ts +6 -0
  381. package/dist/commands/task/run-trace.command.d.ts.map +1 -0
  382. package/dist/commands/task/run-trace.command.js +25 -0
  383. package/dist/commands/task/run-trace.spec.d.ts +7 -0
  384. package/dist/commands/task/run-trace.spec.d.ts.map +1 -0
  385. package/dist/commands/task/run-trace.spec.js +31 -0
  386. package/dist/commands/task/run.command.d.ts +6 -0
  387. package/dist/commands/task/run.command.d.ts.map +1 -0
  388. package/dist/commands/task/run.command.js +74 -0
  389. package/dist/commands/task/run.spec.d.ts +7 -0
  390. package/dist/commands/task/run.spec.d.ts.map +1 -0
  391. package/dist/commands/task/run.spec.js +26 -0
  392. package/dist/commands/task/scaffold.d.ts.map +1 -1
  393. package/dist/commands/task/scaffold.js +4 -2
  394. package/dist/commands/task/scrub.d.ts.map +1 -1
  395. package/dist/commands/task/scrub.js +27 -24
  396. package/dist/commands/task/search.d.ts.map +1 -1
  397. package/dist/commands/task/search.js +21 -31
  398. package/dist/commands/task/set-status.d.ts.map +1 -1
  399. package/dist/commands/task/set-status.js +36 -152
  400. package/dist/commands/task/shared/dependencies.d.ts +4 -4
  401. package/dist/commands/task/shared/dependencies.d.ts.map +1 -1
  402. package/dist/commands/task/shared/dependencies.js +10 -2
  403. package/dist/commands/task/shared/docs.d.ts +6 -1
  404. package/dist/commands/task/shared/docs.d.ts.map +1 -1
  405. package/dist/commands/task/shared/docs.js +13 -0
  406. package/dist/commands/task/shared/listing.d.ts +16 -2
  407. package/dist/commands/task/shared/listing.d.ts.map +1 -1
  408. package/dist/commands/task/shared/listing.js +56 -0
  409. package/dist/commands/task/shared/transition-command.d.ts +15 -0
  410. package/dist/commands/task/shared/transition-command.d.ts.map +1 -0
  411. package/dist/commands/task/shared/transition-command.js +43 -0
  412. package/dist/commands/task/shared/transitions.d.ts +39 -0
  413. package/dist/commands/task/shared/transitions.d.ts.map +1 -1
  414. package/dist/commands/task/shared/transitions.js +62 -1
  415. package/dist/commands/task/shared/workflow-transition-service.d.ts +75 -0
  416. package/dist/commands/task/shared/workflow-transition-service.d.ts.map +1 -0
  417. package/dist/commands/task/shared/workflow-transition-service.js +226 -0
  418. package/dist/commands/task/shared.d.ts +5 -3
  419. package/dist/commands/task/shared.d.ts.map +1 -1
  420. package/dist/commands/task/shared.js +5 -3
  421. package/dist/commands/task/show.d.ts.map +1 -1
  422. package/dist/commands/task/show.js +37 -3
  423. package/dist/commands/task/start.d.ts.map +1 -1
  424. package/dist/commands/task/start.js +33 -119
  425. package/dist/commands/task/task.command.d.ts +3 -4
  426. package/dist/commands/task/task.command.d.ts.map +1 -1
  427. package/dist/commands/task/task.command.js +22 -37
  428. package/dist/commands/task/verify-record.d.ts.map +1 -1
  429. package/dist/commands/task/verify-record.js +16 -141
  430. package/dist/commands/task/verify.command.d.ts.map +1 -1
  431. package/dist/commands/task/verify.command.js +7 -6
  432. package/dist/commands/task.test-helpers.d.ts +13 -0
  433. package/dist/commands/task.test-helpers.d.ts.map +1 -0
  434. package/dist/commands/task.test-helpers.js +65 -0
  435. package/dist/commands/upgrade/materialize.d.ts +28 -0
  436. package/dist/commands/upgrade/materialize.d.ts.map +1 -0
  437. package/dist/commands/upgrade/materialize.js +154 -0
  438. package/dist/commands/upgrade/plan.d.ts +18 -0
  439. package/dist/commands/upgrade/plan.d.ts.map +1 -0
  440. package/dist/commands/upgrade/plan.js +219 -0
  441. package/dist/commands/upgrade/policy.d.ts +24 -0
  442. package/dist/commands/upgrade/policy.d.ts.map +1 -0
  443. package/dist/commands/upgrade/policy.js +182 -0
  444. package/dist/commands/upgrade/report.d.ts.map +1 -1
  445. package/dist/commands/upgrade/report.js +7 -5
  446. package/dist/commands/upgrade.d.ts.map +1 -1
  447. package/dist/commands/upgrade.js +154 -642
  448. package/dist/commands/workflow.command.d.ts +3 -4
  449. package/dist/commands/workflow.command.d.ts.map +1 -1
  450. package/dist/commands/workflow.command.js +8 -25
  451. package/dist/ports/task-backend-port.d.ts +3 -1
  452. package/dist/ports/task-backend-port.d.ts.map +1 -1
  453. package/dist/runner/adapters/codex.d.ts +9 -0
  454. package/dist/runner/adapters/codex.d.ts.map +1 -0
  455. package/dist/runner/adapters/codex.js +414 -0
  456. package/dist/runner/adapters/custom.d.ts +12 -0
  457. package/dist/runner/adapters/custom.d.ts.map +1 -0
  458. package/dist/runner/adapters/custom.js +512 -0
  459. package/dist/runner/adapters/index.d.ts +8 -0
  460. package/dist/runner/adapters/index.d.ts.map +1 -0
  461. package/dist/runner/adapters/index.js +15 -0
  462. package/dist/runner/adapters/recipe-run-profile.d.ts +8 -0
  463. package/dist/runner/adapters/recipe-run-profile.d.ts.map +1 -0
  464. package/dist/runner/adapters/recipe-run-profile.js +53 -0
  465. package/dist/runner/adapters/shared.d.ts +45 -0
  466. package/dist/runner/adapters/shared.d.ts.map +1 -0
  467. package/dist/runner/adapters/shared.js +58 -0
  468. package/dist/runner/artifacts.d.ts +31 -0
  469. package/dist/runner/artifacts.d.ts.map +1 -0
  470. package/dist/runner/artifacts.js +153 -0
  471. package/dist/runner/codex-approval-probe.d.ts +23 -0
  472. package/dist/runner/codex-approval-probe.d.ts.map +1 -0
  473. package/dist/runner/codex-approval-probe.js +55 -0
  474. package/dist/runner/codex-smoke.d.ts +11 -0
  475. package/dist/runner/codex-smoke.d.ts.map +1 -0
  476. package/dist/runner/codex-smoke.js +45 -0
  477. package/dist/runner/config.d.ts +6 -0
  478. package/dist/runner/config.d.ts.map +1 -0
  479. package/dist/runner/config.js +15 -0
  480. package/dist/runner/context/base-prompts.d.ts +10 -0
  481. package/dist/runner/context/base-prompts.d.ts.map +1 -0
  482. package/dist/runner/context/base-prompts.js +255 -0
  483. package/dist/runner/context/recipe-context.d.ts +17 -0
  484. package/dist/runner/context/recipe-context.d.ts.map +1 -0
  485. package/dist/runner/context/recipe-context.js +48 -0
  486. package/dist/runner/context/task-context.d.ts +24 -0
  487. package/dist/runner/context/task-context.d.ts.map +1 -0
  488. package/dist/runner/context/task-context.js +266 -0
  489. package/dist/runner/index.d.ts +12 -0
  490. package/dist/runner/index.d.ts.map +1 -0
  491. package/dist/runner/index.js +11 -0
  492. package/dist/runner/policy-decision.d.ts +12 -0
  493. package/dist/runner/policy-decision.d.ts.map +1 -0
  494. package/dist/runner/policy-decision.js +89 -0
  495. package/dist/runner/policy-display.d.ts +4 -0
  496. package/dist/runner/policy-display.d.ts.map +1 -0
  497. package/dist/runner/policy-display.js +41 -0
  498. package/dist/runner/process-supervision.d.ts +48 -0
  499. package/dist/runner/process-supervision.d.ts.map +1 -0
  500. package/dist/runner/process-supervision.js +490 -0
  501. package/dist/runner/result-manifest-policy.d.ts +9 -0
  502. package/dist/runner/result-manifest-policy.d.ts.map +1 -0
  503. package/dist/runner/result-manifest-policy.js +96 -0
  504. package/dist/runner/result-manifest.d.ts +30 -0
  505. package/dist/runner/result-manifest.d.ts.map +1 -0
  506. package/dist/runner/result-manifest.js +322 -0
  507. package/dist/runner/run-id.d.ts +2 -0
  508. package/dist/runner/run-id.d.ts.map +1 -0
  509. package/dist/runner/run-id.js +3 -0
  510. package/dist/runner/run-repository.d.ts +51 -0
  511. package/dist/runner/run-repository.d.ts.map +1 -0
  512. package/dist/runner/run-repository.js +222 -0
  513. package/dist/runner/task-run-paths.d.ts +19 -0
  514. package/dist/runner/task-run-paths.d.ts.map +1 -0
  515. package/dist/runner/task-run-paths.js +25 -0
  516. package/dist/runner/task-state.d.ts +9 -0
  517. package/dist/runner/task-state.d.ts.map +1 -0
  518. package/dist/runner/task-state.js +354 -0
  519. package/dist/runner/test-helpers.d.ts +30 -0
  520. package/dist/runner/test-helpers.d.ts.map +1 -0
  521. package/dist/runner/test-helpers.js +97 -0
  522. package/dist/runner/trace-artifacts.d.ts +14 -0
  523. package/dist/runner/trace-artifacts.d.ts.map +1 -0
  524. package/dist/runner/trace-artifacts.js +80 -0
  525. package/dist/runner/trace.d.ts +10 -0
  526. package/dist/runner/trace.d.ts.map +1 -0
  527. package/dist/runner/trace.js +37 -0
  528. package/dist/runner/types.d.ts +317 -0
  529. package/dist/runner/types.d.ts.map +1 -0
  530. package/dist/runner/types.js +3 -0
  531. package/dist/runner/usecases/scenario-materialize-task.d.ts +29 -0
  532. package/dist/runner/usecases/scenario-materialize-task.d.ts.map +1 -0
  533. package/dist/runner/usecases/scenario-materialize-task.js +151 -0
  534. package/dist/runner/usecases/task-run-inspect.d.ts +41 -0
  535. package/dist/runner/usecases/task-run-inspect.d.ts.map +1 -0
  536. package/dist/runner/usecases/task-run-inspect.js +74 -0
  537. package/dist/runner/usecases/task-run-lifecycle-cancel.d.ts +10 -0
  538. package/dist/runner/usecases/task-run-lifecycle-cancel.d.ts.map +1 -0
  539. package/dist/runner/usecases/task-run-lifecycle-cancel.js +172 -0
  540. package/dist/runner/usecases/task-run-lifecycle-replay.d.ts +18 -0
  541. package/dist/runner/usecases/task-run-lifecycle-replay.d.ts.map +1 -0
  542. package/dist/runner/usecases/task-run-lifecycle-replay.js +128 -0
  543. package/dist/runner/usecases/task-run-lifecycle-shared.d.ts +45 -0
  544. package/dist/runner/usecases/task-run-lifecycle-shared.d.ts.map +1 -0
  545. package/dist/runner/usecases/task-run-lifecycle-shared.js +172 -0
  546. package/dist/runner/usecases/task-run-lifecycle.d.ts +4 -0
  547. package/dist/runner/usecases/task-run-lifecycle.d.ts.map +1 -0
  548. package/dist/runner/usecases/task-run-lifecycle.js +2 -0
  549. package/dist/runner/usecases/task-run.d.ts +32 -0
  550. package/dist/runner/usecases/task-run.d.ts.map +1 -0
  551. package/dist/runner/usecases/task-run.js +278 -0
  552. package/dist/shared/agent-emoji.d.ts.map +1 -1
  553. package/dist/shared/agent-emoji.js +1 -0
  554. package/dist/shared/errors.d.ts +1 -1
  555. package/dist/shared/errors.d.ts.map +1 -1
  556. package/dist/shared/guards.d.ts.map +1 -1
  557. package/dist/shared/guards.js +1 -0
  558. package/dist/shared/repo-cli-version.d.ts.map +1 -1
  559. package/dist/shared/repo-cli-version.js +7 -5
  560. package/dist/shared/task-doc-conflicts.d.ts +12 -0
  561. package/dist/shared/task-doc-conflicts.d.ts.map +1 -0
  562. package/dist/shared/task-doc-conflicts.js +40 -0
  563. package/dist/shared/task-doc-state.d.ts +10 -0
  564. package/dist/shared/task-doc-state.d.ts.map +1 -0
  565. package/dist/shared/task-doc-state.js +15 -0
  566. package/dist/test-helpers/fs.d.ts +2 -0
  567. package/dist/test-helpers/fs.d.ts.map +1 -0
  568. package/dist/test-helpers/fs.js +9 -0
  569. package/dist/usecases/context/resolve-context.d.ts +2 -0
  570. package/dist/usecases/context/resolve-context.d.ts.map +1 -1
  571. package/dist/usecases/context/resolve-context.js +4 -1
  572. package/dist/usecases/task/task-list-usecase.d.ts.map +1 -1
  573. package/dist/usecases/task/task-list-usecase.js +2 -8
  574. package/dist/workflow-runtime/fix.d.ts +9 -1
  575. package/dist/workflow-runtime/fix.d.ts.map +1 -1
  576. package/dist/workflow-runtime/fix.js +9 -1
  577. package/package.json +2 -2
  578. package/dist/backends/task-backend.test-helpers.d.ts +0 -4
  579. package/dist/backends/task-backend.test-helpers.d.ts.map +0 -1
  580. package/dist/backends/task-backend.test-helpers.js +0 -33
  581. package/dist/cli/run-cli/catalog.d.ts +0 -7
  582. package/dist/cli/run-cli/catalog.d.ts.map +0 -1
  583. package/dist/cli/run-cli/catalog.js +0 -22
  584. package/dist/cli/run-cli.core.pr-flow.test-helpers.d.ts +0 -3
  585. package/dist/cli/run-cli.core.pr-flow.test-helpers.d.ts.map +0 -1
  586. package/dist/cli/run-cli.core.pr-flow.test-helpers.js +0 -41
  587. package/dist/cli/run-cli.core.tasks.test-helpers.d.ts +0 -2
  588. package/dist/cli/run-cli.core.tasks.test-helpers.d.ts.map +0 -1
  589. package/dist/cli/run-cli.core.tasks.test-helpers.js +0 -6
  590. package/dist/commands/block.command.d.ts +0 -4
  591. package/dist/commands/block.command.d.ts.map +0 -1
  592. package/dist/commands/block.command.js +0 -2
  593. package/dist/commands/doctor.command.d.ts +0 -3
  594. package/dist/commands/doctor.command.d.ts.map +0 -1
  595. package/dist/commands/doctor.command.js +0 -2
  596. package/dist/commands/finish.command.d.ts +0 -4
  597. package/dist/commands/finish.command.d.ts.map +0 -1
  598. package/dist/commands/finish.command.js +0 -2
  599. package/dist/commands/recipes/install.command.d.ts +0 -3
  600. package/dist/commands/recipes/install.command.d.ts.map +0 -1
  601. package/dist/commands/recipes/install.command.js +0 -2
  602. package/dist/commands/start.command.d.ts +0 -4
  603. package/dist/commands/start.command.d.ts.map +0 -1
  604. package/dist/commands/start.command.js +0 -2
  605. package/dist/commands/task/list.command.d.ts +0 -4
  606. package/dist/commands/task/list.command.d.ts.map +0 -1
  607. package/dist/commands/task/list.command.js +0 -2
  608. package/dist/commands/task/next.command.d.ts +0 -4
  609. package/dist/commands/task/next.command.d.ts.map +0 -1
  610. package/dist/commands/task/next.command.js +0 -2
  611. package/dist/commands/task/search.command.d.ts +0 -4
  612. package/dist/commands/task/search.command.d.ts.map +0 -1
  613. package/dist/commands/task/search.command.js +0 -2
  614. package/dist/commands/task/show.command.d.ts +0 -4
  615. package/dist/commands/task/show.command.d.ts.map +0 -1
  616. package/dist/commands/task/show.command.js +0 -2
  617. package/dist/commands/verify.command.d.ts +0 -4
  618. package/dist/commands/verify.command.d.ts.map +0 -1
  619. package/dist/commands/verify.command.js +0 -2
@@ -1,4 +1,3 @@
1
- import { canonicalizeJson, taskDocToSectionMap } from "@agentplaneorg/core";
2
1
  import { isRecord } from "../../shared/guards.js";
3
2
  import { appendCommentNotes as appendCommentNotesImpl, normalizeComments as normalizeCommentsImpl, } from "./redmine/comments.js";
4
3
  import { requestJson as requestRedmineJson } from "./redmine/client.js";
@@ -6,15 +5,17 @@ import { appendCustomField as appendRedmineCustomField, customFieldValue as redm
6
5
  import { doneRatioForStatus, issueToTask as issueToTaskImpl, startDateFromTaskId, taskToIssuePayload as taskToIssuePayloadImpl, } from "./redmine/mapping.js";
7
6
  import { coerceDocVersion as coerceRedmineDocVersion, maybeParseJson as maybeParseRedmineJson, } from "./redmine/parse.js";
8
7
  import { findIssueByTaskId as findIssueByTaskIdImpl, listTasksRemote as listTasksRemoteImpl, } from "./redmine/remote.js";
9
- import { detectConfiguredFieldNameDrift, inferVisibleCanonicalStateFieldId, inspectVisibleCustomFields, } from "./redmine/inspect.js";
10
- import { buildRedmineCanonicalStateWithOptions, parseRedmineCanonicalState, } from "./redmine/state.js";
8
+ import { getRedmineTask, getRedmineTaskDoc, getRedmineTasks, listRedmineProjectionTasks, listRedmineTasks, normalizeRedmineTasks, exportRedmineProjectionSnapshot, exportRedmineTasksJson, setRedmineTaskDoc, touchRedmineTaskDocMetadata, } from "./redmine/backend-cache-doc.js";
9
+ import { diffRedmineTasks, inspectRedmineConfiguration, redmineTasksDiffer, } from "./redmine/backend-report.js";
10
+ import { generateRedmineTaskId, handleRedmineConflict, inferRedmineStatusIdForTaskStatus, loadRedmineInferredStatusByTaskStatus, migrateRedmineCanonicalState, selectRedmineInferredStatus, syncPullRedmine, syncPushRedmine, syncRedmine, writeRedmineTask, writeRedmineTasks, } from "./redmine/backend-sync.js";
11
11
  import { readRedmineEnv } from "./redmine/env.js";
12
- import { BackendError, DEFAULT_DOC_UPDATED_BY, DOC_VERSION, RedmineUnavailable, ensureDocMetadata, firstNonEmptyString, generateTaskId, mapLimit, missingTaskIdMessage, normalizeDocVersion, nowIso, redmineConfigMissingEnvMessage, redmineIssueIdMissingMessage, sleep, toStringSafe, unknownTaskIdMessage, validateTaskId, writeTasksExportFromTasks, } from "./shared.js";
12
+ import { BackendError, DEFAULT_DOC_UPDATED_BY, DOC_VERSION, firstNonEmptyString, normalizeDocVersion, nowIso, redmineConfigMissingEnvMessage, toStringSafe, } from "./shared.js";
13
13
  export class RedmineBackend {
14
14
  id = "redmine";
15
15
  capabilities = {
16
16
  canonical_source: "remote",
17
17
  projection: "cache",
18
+ projection_read_mode: "native",
18
19
  reads_from_projection_by_default: true,
19
20
  writes_task_readmes: true,
20
21
  supports_task_revisions: false,
@@ -87,50 +88,79 @@ export class RedmineBackend {
87
88
  this.reverseStatus.set(value, key);
88
89
  }
89
90
  }
91
+ cacheDocContext() {
92
+ return {
93
+ cache: this.cache,
94
+ customFields: this.customFields,
95
+ ownerAgent: this.ownerAgent,
96
+ batchSize: this.batchSize,
97
+ findIssueByTaskId: async (taskId) => await this.findIssueByTaskId(taskId),
98
+ issueToTask: (issue, taskIdOverride) => this.issueToTask(issue, taskIdOverride),
99
+ customFieldValue: (issue, fieldId) => this.customFieldValue(issue, fieldId),
100
+ appendCustomField: (fields, key, value) => this.appendCustomField(fields, key, value),
101
+ requestJson: async (method, reqPath, payload, params) => await this.requestJson(method, reqPath, payload, params),
102
+ assertExpectedRevisionSupported: (taskId, opts) => this.assertExpectedRevisionSupported(taskId, opts),
103
+ assertExpectedRevision: (taskId, expectedRevision, currentRevision) => this.assertExpectedRevision(taskId, expectedRevision, currentRevision),
104
+ cacheTask: async (task, dirty) => await this.cacheTask(task, dirty),
105
+ };
106
+ }
107
+ reportContext() {
108
+ return {
109
+ projectId: this.projectId,
110
+ customFields: this.customFields,
111
+ requestJson: async (method, reqPath, payload, params) => await this.requestJson(method, reqPath, payload, params),
112
+ };
113
+ }
114
+ syncContext() {
115
+ return {
116
+ cache: this.cache,
117
+ customFields: this.customFields,
118
+ ownerAgent: this.ownerAgent,
119
+ projectId: this.projectId,
120
+ batchSize: this.batchSize,
121
+ batchPauseMs: this.batchPauseMs,
122
+ statusMap: this.statusMap,
123
+ issueCache: this.issueCache,
124
+ inferredStatusByTaskStatus: this.inferredStatusByTaskStatus,
125
+ setInferredStatusByTaskStatus: (next) => {
126
+ this.inferredStatusByTaskStatus = next;
127
+ },
128
+ listTasksRemote: async () => await this.listTasksRemote(),
129
+ writeTask: async (task, opts) => await this.writeTask(task, opts),
130
+ writeTasks: async (tasks, opts) => await this.writeTasks(tasks, opts),
131
+ findIssueByTaskId: async (taskId) => await this.findIssueByTaskId(taskId),
132
+ issueToTask: (issue, taskIdOverride) => this.issueToTask(issue, taskIdOverride),
133
+ taskToIssuePayload: (task, existingIssue) => this.taskToIssuePayload(task, existingIssue),
134
+ appendCustomField: (fields, key, value) => this.appendCustomField(fields, key, value),
135
+ customFieldValue: (issue, fieldId) => this.customFieldValue(issue, fieldId),
136
+ maybeParseJson: (value) => this.maybeParseJson(value),
137
+ normalizeComments: (value) => this.normalizeComments(value),
138
+ appendCommentNotes: async (issueId, existingComments, desiredComments) => await this.appendCommentNotes(issueId, existingComments, desiredComments),
139
+ cacheTask: async (task, dirty) => await this.cacheTask(task, dirty),
140
+ assertExpectedRevisionSupported: (taskId, opts) => this.assertExpectedRevisionSupported(taskId, opts),
141
+ assertExpectedRevision: (taskId, expectedRevision, currentRevision) => this.assertExpectedRevision(taskId, expectedRevision, currentRevision),
142
+ ensureDocMetadata: (task) => this.ensureDocMetadata(task),
143
+ diffTasks: (localTask, remoteTask) => this.diffTasks(localTask, remoteTask),
144
+ tasksDiffer: (localTask, remoteTask) => this.tasksDiffer(localTask, remoteTask),
145
+ taskIdFieldId: () => this.taskIdFieldId(),
146
+ setIssueCustomFieldValue: (issue, fieldId, value) => this.setIssueCustomFieldValue(issue, fieldId, value),
147
+ requestJson: async (method, reqPath, payload, params, opts) => await this.requestJson(method, reqPath, payload, params, opts),
148
+ };
149
+ }
90
150
  async generateTaskId(opts) {
91
- const length = opts.length;
92
- const attempts = opts.attempts;
93
- let existingIds = new Set();
94
- try {
95
- const tasks = await this.listTasksRemote();
96
- existingIds = new Set(tasks.map((task) => toStringSafe(task.id)).filter(Boolean));
97
- }
98
- catch (err) {
99
- if (!(err instanceof RedmineUnavailable))
100
- throw err;
101
- if (!this.cache)
102
- throw err;
103
- const cached = await this.cache.listTasks();
104
- existingIds = new Set(cached.map((task) => toStringSafe(task.id)).filter(Boolean));
105
- }
106
- return await generateTaskId({
107
- length,
108
- attempts,
109
- isAvailable: (taskId) => !existingIds.has(taskId),
110
- });
151
+ return await generateRedmineTaskId(this.syncContext(), opts);
111
152
  }
112
153
  async listTasks() {
113
- if (!this.cache) {
114
- throw new BackendError("Redmine cache is disabled; projection reads are unavailable", "E_BACKEND");
115
- }
116
- return await this.cache.listTasks();
154
+ return await listRedmineTasks(this.cacheDocContext());
117
155
  }
118
156
  async listProjectionTasks() {
119
- if (!this.cache) {
120
- throw new BackendError("Redmine cache is disabled; projection reads are unavailable", "E_BACKEND");
121
- }
122
- return await this.cache.listTasks();
157
+ return await listRedmineProjectionTasks(this.cacheDocContext());
123
158
  }
124
159
  async exportTasksJson(outputPath) {
125
- const tasks = await this.listTasks();
126
- await writeTasksExportFromTasks({ outputPath, tasks });
160
+ await exportRedmineTasksJson(this.cacheDocContext(), outputPath);
127
161
  }
128
162
  async exportProjectionSnapshot(outputPath) {
129
- if (!this.cache) {
130
- throw new BackendError("Redmine cache is disabled; projection snapshot export is unavailable", "E_BACKEND");
131
- }
132
- const tasks = await this.cache.listTasks();
133
- await writeTasksExportFromTasks({ outputPath, tasks });
163
+ await exportRedmineProjectionSnapshot(this.cacheDocContext(), outputPath);
134
164
  }
135
165
  async refreshProjection(opts) {
136
166
  if (!opts.allowNetwork) {
@@ -139,364 +169,37 @@ export class RedmineBackend {
139
169
  await this.syncPull(opts.conflict ?? "prefer-remote", opts.quiet ?? true);
140
170
  }
141
171
  async normalizeTasks() {
142
- // Remote backends should avoid expensive downloads; best-effort normalize the local cache if present.
143
- if (this.cache?.normalizeTasks)
144
- return await this.cache.normalizeTasks();
145
- return { scanned: 0, changed: 0 };
172
+ return await normalizeRedmineTasks(this.cacheDocContext());
146
173
  }
147
174
  async migrateCanonicalState() {
148
- if (!this.customFields.canonical_state) {
149
- throw new BackendError(redmineConfigMissingEnvMessage("AGENTPLANE_REDMINE_CUSTOM_FIELDS_CANONICAL_STATE"), "E_BACKEND");
150
- }
151
- const tasks = await this.listTasksRemote();
152
- const result = {
153
- scanned: tasks.length,
154
- migrated: [],
155
- skippedStructured: [],
156
- skippedNoDoc: [],
157
- failed: [],
158
- };
159
- for (const [index, task] of tasks.entries()) {
160
- const taskId = toStringSafe(task.id).trim();
161
- if (!taskId)
162
- continue;
163
- const issue = this.issueCache.get(taskId);
164
- if (!issue) {
165
- result.failed.push({
166
- taskId,
167
- reason: "Redmine issue payload was not cached during remote list refresh",
168
- });
169
- continue;
170
- }
171
- const currentState = parseRedmineCanonicalState(this.customFieldValue(issue, this.customFields.canonical_state));
172
- if (currentState) {
173
- result.skippedStructured.push(taskId);
174
- continue;
175
- }
176
- const sections = task.sections && Object.keys(task.sections).length > 0
177
- ? task.sections
178
- : task.doc
179
- ? taskDocToSectionMap(task.doc)
180
- : undefined;
181
- if (!sections || Object.keys(sections).length === 0) {
182
- result.skippedNoDoc.push(taskId);
183
- continue;
184
- }
185
- const issueIdText = toStringSafe(issue.id);
186
- if (!issueIdText) {
187
- result.failed.push({ taskId, reason: redmineIssueIdMissingMessage() });
188
- continue;
189
- }
190
- const currentRevision = 0;
191
- const nextRevision = Math.max(task.revision ?? 0, currentRevision, 1);
192
- const nextCanonicalState = buildRedmineCanonicalStateWithOptions({
193
- ...task,
194
- sections,
195
- revision: nextRevision,
196
- }, { base: currentState, revision: nextRevision });
197
- if (!nextCanonicalState) {
198
- result.skippedNoDoc.push(taskId);
199
- continue;
200
- }
201
- const customFields = [];
202
- this.appendCustomField(customFields, "canonical_state", nextCanonicalState);
203
- try {
204
- await this.requestJson("PUT", `issues/${issueIdText}.json`, {
205
- issue: { custom_fields: customFields },
206
- });
207
- this.setIssueCustomFieldValue(issue, this.customFields.canonical_state, nextCanonicalState);
208
- this.issueCache.set(taskId, issue);
209
- await this.cacheTask({
210
- ...task,
211
- sections,
212
- revision: nextRevision,
213
- dirty: false,
214
- }, false);
215
- result.migrated.push(taskId);
216
- }
217
- catch (err) {
218
- const reason = err instanceof Error ? err.message : "Unknown Redmine canonical_state migration failure";
219
- result.failed.push({ taskId, reason });
220
- }
221
- if (this.batchPauseMs > 0 && this.batchSize > 0 && (index + 1) % this.batchSize === 0) {
222
- await sleep(this.batchPauseMs);
223
- }
224
- }
225
- return result;
175
+ return await migrateRedmineCanonicalState(this.syncContext());
226
176
  }
227
177
  async inspectConfiguration() {
228
- const visibleCustomFields = await inspectVisibleCustomFields({
229
- projectId: this.projectId,
230
- requestJson: async (method, reqPath, payload, params) => await this.requestJson(method, reqPath, payload, params),
231
- });
232
- const visibleCanonicalStateFieldId = inferVisibleCanonicalStateFieldId(visibleCustomFields);
233
- return {
234
- backendId: this.id,
235
- visibleCustomFields,
236
- canonicalState: {
237
- configuredFieldId: typeof this.customFields.canonical_state === "number"
238
- ? this.customFields.canonical_state
239
- : null,
240
- visibleFieldId: visibleCanonicalStateFieldId,
241
- },
242
- configuredFieldNameDrift: detectConfiguredFieldNameDrift({
243
- configuredFields: this.customFields,
244
- visibleFields: visibleCustomFields,
245
- }),
246
- };
178
+ return await inspectRedmineConfiguration(this.reportContext());
247
179
  }
248
180
  async getTask(taskId) {
249
- if (!this.cache) {
250
- throw new BackendError("Redmine cache is disabled; projection reads are unavailable", "E_BACKEND");
251
- }
252
- return (await this.cache.getTask(taskId)) ?? null;
181
+ return await getRedmineTask(this.cacheDocContext(), taskId);
253
182
  }
254
183
  async getTasks(taskIds) {
255
- // Use limited parallelism to avoid hammering the Redmine API.
256
- return await mapLimit(taskIds, this.batchSize, async (taskId) => await this.getTask(taskId));
184
+ return await getRedmineTasks(this.cacheDocContext(), taskIds);
257
185
  }
258
186
  async getTaskDoc(taskId) {
259
- const task = await this.getTask(taskId);
260
- if (!task)
261
- throw new Error(unknownTaskIdMessage(taskId));
262
- return toStringSafe(task.doc);
187
+ return await getRedmineTaskDoc(this.cacheDocContext(), taskId);
263
188
  }
264
189
  async setTaskDoc(taskId, doc, updatedBy, opts) {
265
- if (!this.customFields.doc) {
266
- throw new BackendError(redmineConfigMissingEnvMessage("AGENTPLANE_REDMINE_CUSTOM_FIELDS_DOC"), "E_BACKEND");
267
- }
268
- try {
269
- const issue = await this.findIssueByTaskId(taskId);
270
- if (!issue)
271
- throw new Error(unknownTaskIdMessage(taskId));
272
- const issueIdText = toStringSafe(issue.id);
273
- if (!issueIdText)
274
- throw new Error(redmineIssueIdMissingMessage());
275
- const cachedTask = this.issueToTask(issue, taskId);
276
- const currentState = parseRedmineCanonicalState(this.customFieldValue(issue, this.customFields.canonical_state));
277
- this.assertExpectedRevisionSupported(taskId, opts);
278
- this.assertExpectedRevision(taskId, opts?.expectedRevision, currentState?.revision ?? 1);
279
- const taskDoc = {
280
- doc: String(doc ?? ""),
281
- doc_version: cachedTask?.doc_version,
282
- };
283
- ensureDocMetadata(taskDoc, updatedBy);
284
- const nextSections = taskDocToSectionMap(String(taskDoc.doc ?? ""));
285
- const nextRevision = Math.max(cachedTask?.revision ?? 0, currentState?.revision ?? 0, 0) + 1;
286
- const customFields = [];
287
- this.appendCustomField(customFields, "doc", taskDoc.doc);
288
- const nextCanonicalState = buildRedmineCanonicalStateWithOptions({
289
- id: taskId,
290
- title: cachedTask?.title ?? "",
291
- description: cachedTask?.description ?? "",
292
- status: cachedTask?.status ?? "TODO",
293
- priority: cachedTask?.priority ?? "med",
294
- owner: cachedTask?.owner ?? this.ownerAgent,
295
- depends_on: cachedTask?.depends_on ?? [],
296
- tags: cachedTask?.tags ?? [],
297
- verify: cachedTask?.verify ?? [],
298
- doc: taskDoc.doc,
299
- sections: nextSections,
300
- revision: nextRevision,
301
- plan_approval: cachedTask?.plan_approval,
302
- verification: cachedTask?.verification,
303
- events: cachedTask?.events,
304
- }, { base: currentState, revision: nextRevision });
305
- if (nextCanonicalState) {
306
- this.appendCustomField(customFields, "canonical_state", nextCanonicalState);
307
- }
308
- this.appendCustomField(customFields, "doc_version", taskDoc.doc_version);
309
- this.appendCustomField(customFields, "doc_updated_at", taskDoc.doc_updated_at);
310
- this.appendCustomField(customFields, "doc_updated_by", taskDoc.doc_updated_by);
311
- await this.requestJson("PUT", `issues/${issueIdText}.json`, {
312
- issue: { custom_fields: customFields },
313
- });
314
- if (cachedTask) {
315
- cachedTask.doc = taskDoc.doc;
316
- cachedTask.sections = nextSections;
317
- cachedTask.revision = nextRevision;
318
- cachedTask.doc_version = taskDoc.doc_version;
319
- cachedTask.doc_updated_at = taskDoc.doc_updated_at;
320
- cachedTask.doc_updated_by = taskDoc.doc_updated_by;
321
- await this.cacheTask(cachedTask, false);
322
- }
323
- }
324
- catch (err) {
325
- if (err instanceof RedmineUnavailable) {
326
- if (!this.cache)
327
- throw err;
328
- const cached = await this.cache.getTask(taskId);
329
- if (!cached)
330
- throw new Error(unknownTaskIdMessage(taskId));
331
- this.assertExpectedRevisionSupported(taskId, opts);
332
- this.assertExpectedRevision(taskId, opts?.expectedRevision, cached.revision ?? 1);
333
- cached.doc = String(doc ?? "");
334
- cached.sections = taskDocToSectionMap(cached.doc);
335
- cached.revision = Math.max(cached.revision ?? 0, 0) + 1;
336
- ensureDocMetadata(cached, updatedBy);
337
- cached.dirty = true;
338
- await this.cache.writeTask(cached, opts);
339
- return;
340
- }
341
- throw err;
342
- }
190
+ await setRedmineTaskDoc(this.cacheDocContext(), taskId, doc, updatedBy, opts);
343
191
  }
344
192
  async touchTaskDocMetadata(taskId, updatedBy, opts) {
345
- try {
346
- const issue = await this.findIssueByTaskId(taskId);
347
- if (!issue)
348
- throw new Error(unknownTaskIdMessage(taskId));
349
- const issueIdText = toStringSafe(issue.id);
350
- if (!issueIdText)
351
- throw new Error(redmineIssueIdMissingMessage());
352
- const docValue = this.customFieldValue(issue, this.customFields.doc);
353
- const cachedTask = this.issueToTask(issue, taskId);
354
- const currentState = parseRedmineCanonicalState(this.customFieldValue(issue, this.customFields.canonical_state));
355
- this.assertExpectedRevisionSupported(taskId, opts);
356
- this.assertExpectedRevision(taskId, opts?.expectedRevision, currentState?.revision ?? 1);
357
- const taskDoc = {
358
- doc: docValue ?? "",
359
- doc_version: cachedTask?.doc_version,
360
- };
361
- ensureDocMetadata(taskDoc, updatedBy);
362
- const customFields = [];
363
- this.appendCustomField(customFields, "doc_version", taskDoc.doc_version);
364
- this.appendCustomField(customFields, "doc_updated_at", taskDoc.doc_updated_at);
365
- this.appendCustomField(customFields, "doc_updated_by", taskDoc.doc_updated_by);
366
- if (customFields.length > 0) {
367
- await this.requestJson("PUT", `issues/${issueIdText}.json`, {
368
- issue: { custom_fields: customFields },
369
- });
370
- if (cachedTask) {
371
- cachedTask.doc_version = taskDoc.doc_version;
372
- cachedTask.doc_updated_at = taskDoc.doc_updated_at;
373
- cachedTask.doc_updated_by = taskDoc.doc_updated_by;
374
- await this.cacheTask(cachedTask, false);
375
- }
376
- }
377
- }
378
- catch (err) {
379
- if (err instanceof RedmineUnavailable) {
380
- if (!this.cache)
381
- throw err;
382
- const cached = await this.cache.getTask(taskId);
383
- if (!cached)
384
- throw new Error(unknownTaskIdMessage(taskId));
385
- this.assertExpectedRevisionSupported(taskId, opts);
386
- this.assertExpectedRevision(taskId, opts?.expectedRevision, cached.revision ?? 1);
387
- ensureDocMetadata(cached, updatedBy);
388
- cached.dirty = true;
389
- await this.cache.writeTask(cached, opts);
390
- return;
391
- }
392
- throw err;
393
- }
193
+ await touchRedmineTaskDocMetadata(this.cacheDocContext(), taskId, updatedBy, opts);
394
194
  }
395
195
  async writeTask(task, opts) {
396
- const taskId = toStringSafe(task.id).trim();
397
- if (!taskId)
398
- throw new Error(missingTaskIdMessage());
399
- validateTaskId(taskId);
400
- try {
401
- this.ensureDocMetadata(task);
402
- let issue = await this.findIssueByTaskId(taskId);
403
- let issueId = issue?.id;
404
- let issueIdText = issueId ? toStringSafe(issueId) : "";
405
- let existingIssue = issue ?? null;
406
- if (issueIdText && !existingIssue) {
407
- const payload = await this.requestJson("GET", `issues/${issueIdText}.json`);
408
- existingIssue = this.issueFromPayload(payload);
409
- }
410
- const currentState = existingIssue && this.customFields.canonical_state
411
- ? parseRedmineCanonicalState(this.customFieldValue(existingIssue, this.customFields.canonical_state))
412
- : null;
413
- this.assertExpectedRevisionSupported(taskId, opts);
414
- this.assertExpectedRevision(taskId, opts?.expectedRevision, currentState?.revision ?? 0);
415
- const nextRevision = issueIdText
416
- ? Math.max(task.revision ?? 0, currentState?.revision ?? 0, 0) + 1
417
- : Math.max(task.revision ?? 0, currentState?.revision ?? 0, 1);
418
- const taskForWrite = {
419
- ...task,
420
- revision: nextRevision,
421
- sections: task.sections && Object.keys(task.sections).length > 0
422
- ? task.sections
423
- : task.doc
424
- ? taskDocToSectionMap(task.doc)
425
- : undefined,
426
- };
427
- const payload = this.taskToIssuePayload(taskForWrite, existingIssue ?? undefined);
428
- if (payload.status_id === undefined) {
429
- const inferredStatusId = await this.inferStatusIdForTaskStatus(taskForWrite.status);
430
- if (inferredStatusId !== null)
431
- payload.status_id = inferredStatusId;
432
- }
433
- if (issueIdText) {
434
- await this.requestJson("PUT", `issues/${issueIdText}.json`, { issue: payload });
435
- }
436
- else {
437
- const createPayload = { ...payload, project_id: this.projectId };
438
- const created = await this.requestJson("POST", "issues.json", { issue: createPayload });
439
- const createdIssue = this.issueFromPayload(created);
440
- issueId = createdIssue?.id;
441
- issueIdText = issueId ? toStringSafe(issueId) : "";
442
- if (issueIdText) {
443
- const updatePayload = { ...payload };
444
- delete updatePayload.project_id;
445
- await this.requestJson("PUT", `issues/${issueIdText}.json`, { issue: updatePayload });
446
- const refreshed = await this.requestJson("GET", `issues/${issueIdText}.json`);
447
- existingIssue = this.issueFromPayload(refreshed);
448
- }
449
- }
450
- if (issueIdText) {
451
- const existingComments = existingIssue && this.customFields.comments
452
- ? this.normalizeComments(this.maybeParseJson(this.customFieldValue(existingIssue, this.customFields.comments)))
453
- : [];
454
- const desiredComments = this.normalizeComments(taskForWrite.comments);
455
- await this.appendCommentNotes(issueIdText, existingComments, desiredComments);
456
- }
457
- taskForWrite.dirty = false;
458
- await this.cacheTask(taskForWrite, false);
459
- this.issueCache.clear();
460
- }
461
- catch (err) {
462
- if (err instanceof RedmineUnavailable) {
463
- if (!this.cache)
464
- throw err;
465
- this.assertExpectedRevisionSupported(taskId, opts);
466
- const taskForCache = {
467
- ...task,
468
- revision: Math.max(task.revision ?? 0, 1),
469
- sections: task.sections && Object.keys(task.sections).length > 0
470
- ? task.sections
471
- : task.doc
472
- ? taskDocToSectionMap(task.doc)
473
- : undefined,
474
- dirty: true,
475
- };
476
- await this.cache.writeTask(taskForCache, opts);
477
- return;
478
- }
479
- throw err;
480
- }
196
+ await writeRedmineTask(this.syncContext(), task, opts);
481
197
  }
482
198
  async writeTasks(tasks, opts) {
483
- for (const [index, task] of tasks.entries()) {
484
- await this.writeTask(task, opts);
485
- if (this.batchPauseMs > 0 && this.batchSize > 0 && (index + 1) % this.batchSize === 0) {
486
- await sleep(this.batchPauseMs);
487
- }
488
- }
199
+ await writeRedmineTasks(this.syncContext(), tasks, opts);
489
200
  }
490
201
  async sync(opts) {
491
- if (opts.direction === "push") {
492
- await this.syncPush(opts.quiet, opts.confirm);
493
- return;
494
- }
495
- if (opts.direction === "pull") {
496
- await this.syncPull(opts.conflict, opts.quiet);
497
- return;
498
- }
499
- throw new BackendError("Invalid sync direction (expected push|pull)", "E_BACKEND");
202
+ await syncRedmine(this.syncContext(), opts);
500
203
  }
501
204
  ensureDocMetadata(task) {
502
205
  if (task.doc === undefined)
@@ -506,97 +209,19 @@ export class RedmineBackend {
506
209
  task.doc_updated_by ??= DEFAULT_DOC_UPDATED_BY;
507
210
  }
508
211
  async syncPush(quiet, confirm) {
509
- if (!this.cache) {
510
- throw new BackendError("Redmine cache is disabled; sync push is unavailable", "E_BACKEND");
511
- }
512
- const tasks = await this.cache.listTasks();
513
- const dirty = tasks.filter((task) => task.dirty);
514
- if (dirty.length === 0) {
515
- if (!quiet)
516
- process.stdout.write("ℹ️ no local task changes to push\n");
517
- return;
518
- }
519
- if (!confirm) {
520
- for (const task of dirty) {
521
- process.stdout.write(`- pending push: ${task.id}\n`);
522
- }
523
- throw new BackendError("Refusing to push without --yes (preview above)", "E_BACKEND");
524
- }
525
- await this.writeTasks(dirty);
526
- if (!quiet)
527
- process.stdout.write(`✅ pushed ${dirty.length} task(s) (dirty)\n`);
212
+ await syncPushRedmine(this.syncContext(), quiet, confirm);
528
213
  }
529
214
  async syncPull(conflict, quiet) {
530
- if (!this.cache) {
531
- throw new BackendError("Redmine cache is disabled; sync pull is unavailable", "E_BACKEND");
532
- }
533
- const remoteTasks = await this.listTasksRemote();
534
- const remoteById = new Map();
535
- for (const task of remoteTasks) {
536
- const taskId = toStringSafe(task.id);
537
- if (taskId)
538
- remoteById.set(taskId, task);
539
- }
540
- const localTasks = await this.cache.listTasks();
541
- const localById = new Map();
542
- for (const task of localTasks) {
543
- const taskId = toStringSafe(task.id);
544
- if (taskId)
545
- localById.set(taskId, task);
546
- }
547
- for (const [taskId, remoteTask] of remoteById.entries()) {
548
- const localTask = localById.get(taskId);
549
- if (localTask?.dirty) {
550
- if (this.tasksDiffer(localTask, remoteTask)) {
551
- await this.handleConflict(taskId, localTask, remoteTask, conflict);
552
- continue;
553
- }
554
- localTask.dirty = false;
555
- await this.cacheTask(localTask, false);
556
- continue;
557
- }
558
- await this.cacheTask(remoteTask, false);
559
- }
560
- if (!quiet)
561
- process.stdout.write(`✅ pulled ${remoteById.size} task(s) (remote)\n`);
215
+ await syncPullRedmine(this.syncContext(), conflict, quiet);
562
216
  }
563
217
  async handleConflict(taskId, localTask, remoteTask, conflict) {
564
- if (conflict === "prefer-local") {
565
- await this.writeTask(localTask);
566
- return;
567
- }
568
- if (conflict === "prefer-remote") {
569
- await this.cacheTask(remoteTask, false);
570
- return;
571
- }
572
- if (conflict === "diff") {
573
- const diff = this.diffTasks(localTask, remoteTask);
574
- process.stdout.write(`${diff}\n`);
575
- throw new BackendError(`Conflict detected for ${taskId}`, "E_BACKEND");
576
- }
577
- throw new BackendError(`Conflict detected for ${taskId}`, "E_BACKEND");
218
+ await handleRedmineConflict(this.syncContext(), taskId, localTask, remoteTask, conflict);
578
219
  }
579
220
  diffTasks(localTask, remoteTask) {
580
- const localText = JSON.stringify(canonicalizeJson(localTask), null, 2).split("\n");
581
- const remoteText = JSON.stringify(canonicalizeJson(remoteTask), null, 2).split("\n");
582
- const diff = ["--- remote", "+++ local"];
583
- const max = Math.max(localText.length, remoteText.length);
584
- for (let i = 0; i < max; i++) {
585
- const l = localText[i];
586
- const r = remoteText[i];
587
- if (l === r)
588
- continue;
589
- if (r !== undefined)
590
- diff.push(`- ${r}`);
591
- if (l !== undefined)
592
- diff.push(`+ ${l}`);
593
- }
594
- return diff.join("\n");
221
+ return diffRedmineTasks(localTask, remoteTask);
595
222
  }
596
223
  tasksDiffer(localTask, remoteTask) {
597
- const localText = JSON.stringify(canonicalizeJson(localTask));
598
- const remoteText = JSON.stringify(canonicalizeJson(remoteTask));
599
- return localText !== remoteText;
224
+ return redmineTasksDiffer(localTask, remoteTask);
600
225
  }
601
226
  async cacheTask(task, dirty) {
602
227
  if (!this.cache)
@@ -644,86 +269,13 @@ export class RedmineBackend {
644
269
  return isRecord(payload.issue) ? payload.issue : null;
645
270
  }
646
271
  async inferStatusIdForTaskStatus(statusRaw) {
647
- const status = toStringSafe(statusRaw).trim().toUpperCase();
648
- if (!status)
649
- return null;
650
- const explicit = this.statusMap?.[status];
651
- if (typeof explicit === "number" && Number.isFinite(explicit))
652
- return explicit;
653
- const inferred = await this.loadInferredStatusByTaskStatus();
654
- return inferred.get(status) ?? null;
272
+ return await inferRedmineStatusIdForTaskStatus(this.syncContext(), statusRaw);
655
273
  }
656
274
  async loadInferredStatusByTaskStatus() {
657
- if (this.inferredStatusByTaskStatus)
658
- return this.inferredStatusByTaskStatus;
659
- const map = new Map();
660
- this.inferredStatusByTaskStatus = map;
661
- try {
662
- const payload = await this.requestJson("GET", "issue_statuses.json");
663
- const statuses = Array.isArray(payload.issue_statuses) ? payload.issue_statuses : [];
664
- const parsed = [];
665
- for (const item of statuses) {
666
- if (!isRecord(item))
667
- continue;
668
- const id = typeof item.id === "number" ? item.id : null;
669
- if (!id || !Number.isFinite(id))
670
- continue;
671
- parsed.push({
672
- id,
673
- name: toStringSafe(item.name).trim().toLowerCase(),
674
- isClosed: item.is_closed === true,
675
- isDefault: item.is_default === true,
676
- });
677
- }
678
- const done = this.selectInferredStatus(parsed, "DONE");
679
- const doing = this.selectInferredStatus(parsed, "DOING");
680
- const todo = this.selectInferredStatus(parsed, "TODO");
681
- if (done !== null)
682
- map.set("DONE", done);
683
- if (doing !== null)
684
- map.set("DOING", doing);
685
- if (todo !== null)
686
- map.set("TODO", todo);
687
- }
688
- catch {
689
- // Best effort: keep previous behavior when status discovery is unavailable.
690
- }
691
- return map;
275
+ return await loadRedmineInferredStatusByTaskStatus(this.syncContext());
692
276
  }
693
277
  selectInferredStatus(statuses, target) {
694
- if (statuses.length === 0)
695
- return null;
696
- if (target === "DOING") {
697
- const byId = statuses.find((item) => item.id === 2);
698
- if (byId)
699
- return byId.id;
700
- const byName = statuses.find((item) => item.name.includes("progress") || item.name.includes("doing"));
701
- if (byName)
702
- return byName.id;
703
- return null;
704
- }
705
- if (target === "DONE") {
706
- const closed = statuses.find((item) => item.isClosed);
707
- if (closed)
708
- return closed.id;
709
- const byId = statuses.find((item) => item.id === 5 || item.id === 3 || item.id === 6);
710
- if (byId)
711
- return byId.id;
712
- const byName = statuses.find((item) => item.name.includes("done") ||
713
- item.name.includes("closed") ||
714
- item.name.includes("resolved") ||
715
- item.name.includes("complete"));
716
- if (byName)
717
- return byName.id;
718
- return null;
719
- }
720
- const byDefault = statuses.find((item) => item.isDefault);
721
- if (byDefault)
722
- return byDefault.id;
723
- const byId = statuses.find((item) => item.id === 1);
724
- if (byId)
725
- return byId.id;
726
- return statuses[0]?.id ?? null;
278
+ return selectRedmineInferredStatus(statuses, target);
727
279
  }
728
280
  async findIssueByTaskId(taskId) {
729
281
  const taskFieldId = this.taskIdFieldId();