sqlew 3.7.3 → 3.8.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 (786) hide show
  1. package/CHANGELOG.md +427 -1
  2. package/README.md +71 -2
  3. package/assets/kanban-visualizer.png +0 -0
  4. package/assets/sample-agents/sqlew-scrum-master.md +4 -4
  5. package/dist/adapters/postgresql-adapter.d.ts +197 -5
  6. package/dist/adapters/postgresql-adapter.d.ts.map +1 -1
  7. package/dist/adapters/postgresql-adapter.js +300 -36
  8. package/dist/adapters/postgresql-adapter.js.map +1 -1
  9. package/dist/cli/db-export.d.ts +29 -0
  10. package/dist/cli/db-export.d.ts.map +1 -0
  11. package/dist/cli/db-export.js +251 -0
  12. package/dist/cli/db-export.js.map +1 -0
  13. package/dist/cli/db-import.d.ts +31 -0
  14. package/dist/cli/db-import.d.ts.map +1 -0
  15. package/dist/cli/db-import.js +258 -0
  16. package/dist/cli/db-import.js.map +1 -0
  17. package/dist/cli.d.ts +1 -1
  18. package/dist/cli.js +32 -73
  19. package/dist/cli.js.map +1 -1
  20. package/dist/config/knex/bootstrap/20251025021416_seed_master_data.d.ts.map +1 -1
  21. package/dist/config/knex/bootstrap/20251025021416_seed_master_data.js +158 -45
  22. package/dist/config/knex/bootstrap/20251025021416_seed_master_data.js.map +1 -1
  23. package/dist/config/knex/bootstrap/20251025070349_create_views.d.ts.map +1 -1
  24. package/dist/config/knex/bootstrap/20251025070349_create_views.js +60 -8
  25. package/dist/config/knex/bootstrap/20251025070349_create_views.js.map +1 -1
  26. package/dist/config/knex/enhancements/20251025100000_seed_help_metadata.js +1 -1
  27. package/dist/config/knex/enhancements/20251025100100_seed_remaining_use_cases.js +5 -5
  28. package/dist/config/knex/enhancements/20251028000000_simplify_agent_system.d.ts.map +1 -1
  29. package/dist/config/knex/enhancements/20251028000000_simplify_agent_system.js +9 -1
  30. package/dist/config/knex/enhancements/20251028000000_simplify_agent_system.js.map +1 -1
  31. package/dist/config/knex/enhancements/20251105000000_add_token_usage_table.d.ts.map +1 -1
  32. package/dist/config/knex/enhancements/20251105000000_add_token_usage_table.js +8 -1
  33. package/dist/config/knex/enhancements/20251105000000_add_token_usage_table.js.map +1 -1
  34. package/dist/config/knex/enhancements/20251108000000_add_planning_layers_v3_8_0.d.ts +21 -0
  35. package/dist/config/knex/enhancements/20251108000000_add_planning_layers_v3_8_0.d.ts.map +1 -0
  36. package/dist/config/knex/enhancements/20251108000000_add_planning_layers_v3_8_0.js +73 -0
  37. package/dist/config/knex/enhancements/20251108000000_add_planning_layers_v3_8_0.js.map +1 -0
  38. package/dist/config/knex/enhancements/20251109000000_fix_task_file_links_unique_constraint_v3_8_0.d.ts +19 -0
  39. package/dist/config/knex/enhancements/20251109000000_fix_task_file_links_unique_constraint_v3_8_0.d.ts.map +1 -0
  40. package/dist/config/knex/enhancements/20251109000000_fix_task_file_links_unique_constraint_v3_8_0.js +88 -0
  41. package/dist/config/knex/enhancements/20251109000000_fix_task_file_links_unique_constraint_v3_8_0.js.map +1 -0
  42. package/dist/config/knex/enhancements/20251109000003_token_usage_cross_db_compat_v3_7_5.d.ts +24 -0
  43. package/dist/config/knex/enhancements/20251109000003_token_usage_cross_db_compat_v3_7_5.d.ts.map +1 -0
  44. package/dist/config/knex/enhancements/20251109000003_token_usage_cross_db_compat_v3_7_5.js +79 -0
  45. package/dist/config/knex/enhancements/20251109000003_token_usage_cross_db_compat_v3_7_5.js.map +1 -0
  46. package/dist/config/knex/enhancements/20251109010000_tool_cleanup_v3_8_0.d.ts +27 -0
  47. package/dist/config/knex/enhancements/20251109010000_tool_cleanup_v3_8_0.d.ts.map +1 -0
  48. package/dist/config/knex/enhancements/20251109010000_tool_cleanup_v3_8_0.js +347 -0
  49. package/dist/config/knex/enhancements/20251109010000_tool_cleanup_v3_8_0.js.map +1 -0
  50. package/dist/config/knex/enhancements/20251109020000_fix_missing_help_actions_v3_8_0.d.ts +30 -0
  51. package/dist/config/knex/enhancements/20251109020000_fix_missing_help_actions_v3_8_0.d.ts.map +1 -0
  52. package/dist/config/knex/enhancements/20251109020000_fix_missing_help_actions_v3_8_0.js +232 -0
  53. package/dist/config/knex/enhancements/20251109020000_fix_missing_help_actions_v3_8_0.js.map +1 -0
  54. package/dist/config/knex/upgrades/20251104000000_add_multi_project_v3_7_0.d.ts.map +1 -1
  55. package/dist/config/knex/upgrades/20251104000000_add_multi_project_v3_7_0.js +9 -0
  56. package/dist/config/knex/upgrades/20251104000000_add_multi_project_v3_7_0.js.map +1 -1
  57. package/dist/config/knex/upgrades/20251108000000_hotfix_v_tagged_constraints_project_id.d.ts +14 -0
  58. package/dist/config/knex/upgrades/20251108000000_hotfix_v_tagged_constraints_project_id.d.ts.map +1 -0
  59. package/dist/config/knex/upgrades/20251108000000_hotfix_v_tagged_constraints_project_id.js +97 -0
  60. package/dist/config/knex/upgrades/20251108000000_hotfix_v_tagged_constraints_project_id.js.map +1 -0
  61. package/dist/config/knex/upgrades/20251109000002_multi_project_cross_db_compat_v3_7_5.d.ts +24 -0
  62. package/dist/config/knex/upgrades/20251109000002_multi_project_cross_db_compat_v3_7_5.d.ts.map +1 -0
  63. package/dist/config/knex/upgrades/20251109000002_multi_project_cross_db_compat_v3_7_5.js +303 -0
  64. package/dist/config/knex/upgrades/20251109000002_multi_project_cross_db_compat_v3_7_5.js.map +1 -0
  65. package/dist/constants.d.ts +14 -2
  66. package/dist/constants.d.ts.map +1 -1
  67. package/dist/constants.js +28 -1
  68. package/dist/constants.js.map +1 -1
  69. package/dist/database/config/adapter-factory.d.ts +13 -0
  70. package/dist/database/config/adapter-factory.d.ts.map +1 -0
  71. package/dist/database/config/adapter-factory.js +21 -0
  72. package/dist/database/config/adapter-factory.js.map +1 -0
  73. package/dist/database/config/config-ops.d.ts +34 -0
  74. package/dist/database/config/config-ops.d.ts.map +1 -0
  75. package/dist/database/config/config-ops.js +76 -0
  76. package/dist/database/config/config-ops.js.map +1 -0
  77. package/dist/database/index.d.ts +21 -0
  78. package/dist/database/index.d.ts.map +1 -0
  79. package/dist/database/index.js +31 -0
  80. package/dist/database/index.js.map +1 -0
  81. package/dist/database/initialization/cleanup.d.ts +8 -0
  82. package/dist/database/initialization/cleanup.d.ts.map +1 -0
  83. package/dist/database/initialization/cleanup.js +17 -0
  84. package/dist/database/initialization/cleanup.js.map +1 -0
  85. package/dist/database/initialization/init.d.ts +21 -0
  86. package/dist/database/initialization/init.d.ts.map +1 -0
  87. package/dist/database/initialization/init.js +83 -0
  88. package/dist/database/initialization/init.js.map +1 -0
  89. package/dist/database/operations/deletes.d.ts +10 -0
  90. package/dist/database/operations/deletes.d.ts.map +1 -0
  91. package/dist/database/operations/deletes.js +14 -0
  92. package/dist/database/operations/deletes.js.map +1 -0
  93. package/dist/database/operations/inserts.d.ts +40 -0
  94. package/dist/database/operations/inserts.d.ts.map +1 -0
  95. package/dist/database/operations/inserts.js +202 -0
  96. package/dist/database/operations/inserts.js.map +1 -0
  97. package/dist/database/operations/queries.d.ts +57 -0
  98. package/dist/database/operations/queries.d.ts.map +1 -0
  99. package/dist/database/operations/queries.js +77 -0
  100. package/dist/database/operations/queries.js.map +1 -0
  101. package/dist/database/operations/updates.d.ts +10 -0
  102. package/dist/database/operations/updates.d.ts.map +1 -0
  103. package/dist/database/operations/updates.js +14 -0
  104. package/dist/database/operations/updates.js.map +1 -0
  105. package/dist/database/types.d.ts +5 -0
  106. package/dist/database/types.d.ts.map +1 -0
  107. package/dist/database/types.js +5 -0
  108. package/dist/database/types.js.map +1 -0
  109. package/dist/database.d.ts +4 -144
  110. package/dist/database.d.ts.map +1 -1
  111. package/dist/database.js +5 -461
  112. package/dist/database.js.map +1 -1
  113. package/dist/index.js +29 -777
  114. package/dist/index.js.map +1 -1
  115. package/dist/server/arg-parser.d.ts +40 -0
  116. package/dist/server/arg-parser.d.ts.map +1 -0
  117. package/dist/server/arg-parser.js +137 -0
  118. package/dist/server/arg-parser.js.map +1 -0
  119. package/dist/server/setup.d.ts +31 -0
  120. package/dist/server/setup.d.ts.map +1 -0
  121. package/dist/server/setup.js +186 -0
  122. package/dist/server/setup.js.map +1 -0
  123. package/dist/server/shutdown.d.ts +15 -0
  124. package/dist/server/shutdown.d.ts.map +1 -0
  125. package/dist/server/shutdown.js +42 -0
  126. package/dist/server/shutdown.js.map +1 -0
  127. package/dist/server/tool-handlers.d.ts +10 -0
  128. package/dist/server/tool-handlers.d.ts.map +1 -0
  129. package/dist/server/tool-handlers.js +478 -0
  130. package/dist/server/tool-handlers.js.map +1 -0
  131. package/dist/server/tool-registry.d.ts +11 -0
  132. package/dist/server/tool-registry.d.ts.map +1 -0
  133. package/dist/server/tool-registry.js +225 -0
  134. package/dist/server/tool-registry.js.map +1 -0
  135. package/dist/tests/all-features.test.js +6 -38
  136. package/dist/tests/all-features.test.js.map +1 -1
  137. package/dist/tests/batch-validation-comprehensive.test.d.ts +12 -0
  138. package/dist/tests/batch-validation-comprehensive.test.d.ts.map +1 -0
  139. package/dist/tests/batch-validation-comprehensive.test.js +472 -0
  140. package/dist/tests/batch-validation-comprehensive.test.js.map +1 -0
  141. package/dist/tests/batch-validation-integration.test.d.ts +6 -0
  142. package/dist/tests/batch-validation-integration.test.d.ts.map +1 -0
  143. package/dist/tests/batch-validation-integration.test.js +193 -0
  144. package/dist/tests/batch-validation-integration.test.js.map +1 -0
  145. package/dist/tests/batch-validation.test.d.ts +6 -0
  146. package/dist/tests/batch-validation.test.d.ts.map +1 -0
  147. package/dist/tests/batch-validation.test.js +298 -0
  148. package/dist/tests/batch-validation.test.js.map +1 -0
  149. package/dist/tests/context-modular.test.d.ts +7 -0
  150. package/dist/tests/context-modular.test.d.ts.map +1 -0
  151. package/dist/tests/context-modular.test.js +271 -0
  152. package/dist/tests/context-modular.test.js.map +1 -0
  153. package/dist/tests/decision-batch-validation.test.d.ts +6 -0
  154. package/dist/tests/decision-batch-validation.test.d.ts.map +1 -0
  155. package/dist/tests/decision-batch-validation.test.js +253 -0
  156. package/dist/tests/decision-batch-validation.test.js.map +1 -0
  157. package/dist/tests/help-system.test.js +1 -1
  158. package/dist/tests/help-system.test.js.map +1 -1
  159. package/dist/tests/migrations/test-all-versions-real.js +3 -2
  160. package/dist/tests/migrations/test-all-versions-real.js.map +1 -1
  161. package/dist/tests/multi-project.test.js +2 -2
  162. package/dist/tests/multi-project.test.js.map +1 -1
  163. package/dist/tests/parameter-validation.test.js +2 -16
  164. package/dist/tests/parameter-validation.test.js.map +1 -1
  165. package/dist/tests/tasks.auto-pruning-decision-link.test.js +1 -1
  166. package/dist/tests/tasks.auto-pruning-decision-link.test.js.map +1 -1
  167. package/dist/tests/tasks.file-actions-integration.test.d.ts +10 -0
  168. package/dist/tests/tasks.file-actions-integration.test.d.ts.map +1 -0
  169. package/dist/tests/tasks.file-actions-integration.test.js +162 -0
  170. package/dist/tests/tasks.file-actions-integration.test.js.map +1 -0
  171. package/dist/tests/tasks.file-actions-validation.test.d.ts +6 -0
  172. package/dist/tests/tasks.file-actions-validation.test.d.ts.map +1 -0
  173. package/dist/tests/tasks.file-actions-validation.test.js +221 -0
  174. package/dist/tests/tasks.file-actions-validation.test.js.map +1 -0
  175. package/dist/tools/constraints/actions/add.d.ts +15 -0
  176. package/dist/tools/constraints/actions/add.d.ts.map +1 -0
  177. package/dist/tools/constraints/actions/add.js +101 -0
  178. package/dist/tools/constraints/actions/add.js.map +1 -0
  179. package/dist/tools/constraints/actions/deactivate.d.ts +16 -0
  180. package/dist/tools/constraints/actions/deactivate.d.ts.map +1 -0
  181. package/dist/tools/constraints/actions/deactivate.js +49 -0
  182. package/dist/tools/constraints/actions/deactivate.js.map +1 -0
  183. package/dist/tools/constraints/actions/get.d.ts +16 -0
  184. package/dist/tools/constraints/actions/get.d.ts.map +1 -0
  185. package/dist/tools/constraints/actions/get.js +76 -0
  186. package/dist/tools/constraints/actions/get.js.map +1 -0
  187. package/dist/tools/constraints/help/example.d.ts +9 -0
  188. package/dist/tools/constraints/help/example.d.ts.map +1 -0
  189. package/dist/tools/constraints/help/example.js +144 -0
  190. package/dist/tools/constraints/help/example.js.map +1 -0
  191. package/dist/tools/constraints/help/help.d.ts +9 -0
  192. package/dist/tools/constraints/help/help.d.ts.map +1 -0
  193. package/dist/tools/constraints/help/help.js +31 -0
  194. package/dist/tools/constraints/help/help.js.map +1 -0
  195. package/dist/tools/constraints/index.d.ts +12 -0
  196. package/dist/tools/constraints/index.d.ts.map +1 -0
  197. package/dist/tools/constraints/index.js +13 -0
  198. package/dist/tools/constraints/index.js.map +1 -0
  199. package/dist/tools/constraints/internal/validation.d.ts +11 -0
  200. package/dist/tools/constraints/internal/validation.d.ts.map +1 -0
  201. package/dist/tools/constraints/internal/validation.js +17 -0
  202. package/dist/tools/constraints/internal/validation.js.map +1 -0
  203. package/dist/tools/constraints/types.d.ts +6 -0
  204. package/dist/tools/constraints/types.d.ts.map +1 -0
  205. package/dist/tools/constraints/types.js +6 -0
  206. package/dist/tools/constraints/types.js.map +1 -0
  207. package/dist/tools/context/actions/add-context.d.ts +14 -0
  208. package/dist/tools/context/actions/add-context.d.ts.map +1 -0
  209. package/dist/tools/context/actions/add-context.js +62 -0
  210. package/dist/tools/context/actions/add-context.js.map +1 -0
  211. package/dist/tools/context/actions/batch-set.d.ts +16 -0
  212. package/dist/tools/context/actions/batch-set.d.ts.map +1 -0
  213. package/dist/tools/context/actions/batch-set.js +126 -0
  214. package/dist/tools/context/actions/batch-set.js.map +1 -0
  215. package/dist/tools/context/actions/create-template.d.ts +15 -0
  216. package/dist/tools/context/actions/create-template.d.ts.map +1 -0
  217. package/dist/tools/context/actions/create-template.js +68 -0
  218. package/dist/tools/context/actions/create-template.js.map +1 -0
  219. package/dist/tools/context/actions/get.d.ts +18 -0
  220. package/dist/tools/context/actions/get.d.ts.map +1 -0
  221. package/dist/tools/context/actions/get.js +80 -0
  222. package/dist/tools/context/actions/get.js.map +1 -0
  223. package/dist/tools/context/actions/hard-delete.d.ts +18 -0
  224. package/dist/tools/context/actions/hard-delete.d.ts.map +1 -0
  225. package/dist/tools/context/actions/hard-delete.js +85 -0
  226. package/dist/tools/context/actions/hard-delete.js.map +1 -0
  227. package/dist/tools/context/actions/has-updates.d.ts +16 -0
  228. package/dist/tools/context/actions/has-updates.d.ts.map +1 -0
  229. package/dist/tools/context/actions/has-updates.js +83 -0
  230. package/dist/tools/context/actions/has-updates.js.map +1 -0
  231. package/dist/tools/context/actions/list-contexts.d.ts +14 -0
  232. package/dist/tools/context/actions/list-contexts.d.ts.map +1 -0
  233. package/dist/tools/context/actions/list-contexts.js +43 -0
  234. package/dist/tools/context/actions/list-contexts.js.map +1 -0
  235. package/dist/tools/context/actions/list-templates.d.ts +15 -0
  236. package/dist/tools/context/actions/list-templates.d.ts.map +1 -0
  237. package/dist/tools/context/actions/list-templates.js +47 -0
  238. package/dist/tools/context/actions/list-templates.js.map +1 -0
  239. package/dist/tools/context/actions/list.d.ts +16 -0
  240. package/dist/tools/context/actions/list.d.ts.map +1 -0
  241. package/dist/tools/context/actions/list.js +100 -0
  242. package/dist/tools/context/actions/list.js.map +1 -0
  243. package/dist/tools/context/actions/quick-set.d.ts +21 -0
  244. package/dist/tools/context/actions/quick-set.d.ts.map +1 -0
  245. package/dist/tools/context/actions/quick-set.js +104 -0
  246. package/dist/tools/context/actions/quick-set.js.map +1 -0
  247. package/dist/tools/context/actions/search-advanced.d.ts +15 -0
  248. package/dist/tools/context/actions/search-advanced.d.ts.map +1 -0
  249. package/dist/tools/context/actions/search-advanced.js +140 -0
  250. package/dist/tools/context/actions/search-advanced.js.map +1 -0
  251. package/dist/tools/context/actions/search-layer.d.ts +15 -0
  252. package/dist/tools/context/actions/search-layer.d.ts.map +1 -0
  253. package/dist/tools/context/actions/search-layer.js +106 -0
  254. package/dist/tools/context/actions/search-layer.js.map +1 -0
  255. package/dist/tools/context/actions/search-tags.d.ts +15 -0
  256. package/dist/tools/context/actions/search-tags.d.ts.map +1 -0
  257. package/dist/tools/context/actions/search-tags.js +85 -0
  258. package/dist/tools/context/actions/search-tags.js.map +1 -0
  259. package/dist/tools/context/actions/set-from-template.d.ts +16 -0
  260. package/dist/tools/context/actions/set-from-template.d.ts.map +1 -0
  261. package/dist/tools/context/actions/set-from-template.js +83 -0
  262. package/dist/tools/context/actions/set-from-template.js.map +1 -0
  263. package/dist/tools/context/actions/set.d.ts +16 -0
  264. package/dist/tools/context/actions/set.d.ts.map +1 -0
  265. package/dist/tools/context/actions/set.js +56 -0
  266. package/dist/tools/context/actions/set.js.map +1 -0
  267. package/dist/tools/context/actions/versions.d.ts +15 -0
  268. package/dist/tools/context/actions/versions.d.ts.map +1 -0
  269. package/dist/tools/context/actions/versions.js +69 -0
  270. package/dist/tools/context/actions/versions.js.map +1 -0
  271. package/dist/tools/context/help/example.d.ts +5 -0
  272. package/dist/tools/context/help/example.d.ts.map +1 -0
  273. package/dist/tools/context/help/example.js +96 -0
  274. package/dist/tools/context/help/example.js.map +1 -0
  275. package/dist/tools/context/help/help.d.ts +5 -0
  276. package/dist/tools/context/help/help.d.ts.map +1 -0
  277. package/dist/tools/context/help/help.js +65 -0
  278. package/dist/tools/context/help/help.js.map +1 -0
  279. package/dist/tools/context/index.d.ts +25 -0
  280. package/dist/tools/context/index.d.ts.map +1 -0
  281. package/dist/tools/context/index.js +26 -0
  282. package/dist/tools/context/index.js.map +1 -0
  283. package/dist/tools/context/internal/queries.d.ts +18 -0
  284. package/dist/tools/context/internal/queries.d.ts.map +1 -0
  285. package/dist/tools/context/internal/queries.js +160 -0
  286. package/dist/tools/context/internal/queries.js.map +1 -0
  287. package/dist/tools/context/internal/validation.d.ts +39 -0
  288. package/dist/tools/context/internal/validation.d.ts.map +1 -0
  289. package/dist/tools/context/internal/validation.js +125 -0
  290. package/dist/tools/context/internal/validation.js.map +1 -0
  291. package/dist/tools/context/types.d.ts +6 -0
  292. package/dist/tools/context/types.d.ts.map +1 -0
  293. package/dist/tools/context/types.js +6 -0
  294. package/dist/tools/context/types.js.map +1 -0
  295. package/dist/tools/example/actions/get.d.ts +14 -0
  296. package/dist/tools/example/actions/get.d.ts.map +1 -0
  297. package/dist/tools/example/actions/get.js +40 -0
  298. package/dist/tools/example/actions/get.js.map +1 -0
  299. package/dist/tools/example/actions/list-all.d.ts +13 -0
  300. package/dist/tools/example/actions/list-all.d.ts.map +1 -0
  301. package/dist/tools/example/actions/list-all.js +39 -0
  302. package/dist/tools/example/actions/list-all.js.map +1 -0
  303. package/dist/tools/example/actions/search.d.ts +14 -0
  304. package/dist/tools/example/actions/search.d.ts.map +1 -0
  305. package/dist/tools/example/actions/search.js +52 -0
  306. package/dist/tools/example/actions/search.js.map +1 -0
  307. package/dist/tools/example/help/example.d.ts +6 -0
  308. package/dist/tools/example/help/example.d.ts.map +1 -0
  309. package/dist/tools/example/help/example.js +69 -0
  310. package/dist/tools/example/help/example.js.map +1 -0
  311. package/dist/tools/example/help/help.d.ts +6 -0
  312. package/dist/tools/example/help/help.d.ts.map +1 -0
  313. package/dist/tools/example/help/help.js +133 -0
  314. package/dist/tools/example/help/help.js.map +1 -0
  315. package/dist/tools/example/index.d.ts +11 -0
  316. package/dist/tools/example/index.d.ts.map +1 -0
  317. package/dist/tools/example/index.js +12 -0
  318. package/dist/tools/example/index.js.map +1 -0
  319. package/dist/tools/example/types.d.ts +59 -0
  320. package/dist/tools/example/types.d.ts.map +1 -0
  321. package/dist/tools/example/types.js +6 -0
  322. package/dist/tools/example/types.js.map +1 -0
  323. package/dist/tools/files/actions/check-lock.d.ts +16 -0
  324. package/dist/tools/files/actions/check-lock.d.ts.map +1 -0
  325. package/dist/tools/files/actions/check-lock.js +70 -0
  326. package/dist/tools/files/actions/check-lock.js.map +1 -0
  327. package/dist/tools/files/actions/get.d.ts +16 -0
  328. package/dist/tools/files/actions/get.d.ts.map +1 -0
  329. package/dist/tools/files/actions/get.js +113 -0
  330. package/dist/tools/files/actions/get.js.map +1 -0
  331. package/dist/tools/files/actions/record-batch.d.ts +18 -0
  332. package/dist/tools/files/actions/record-batch.d.ts.map +1 -0
  333. package/dist/tools/files/actions/record-batch.js +114 -0
  334. package/dist/tools/files/actions/record-batch.js.map +1 -0
  335. package/dist/tools/files/actions/record.d.ts +16 -0
  336. package/dist/tools/files/actions/record.d.ts.map +1 -0
  337. package/dist/tools/files/actions/record.js +37 -0
  338. package/dist/tools/files/actions/record.js.map +1 -0
  339. package/dist/tools/files/actions/sqlite-flush.d.ts +27 -0
  340. package/dist/tools/files/actions/sqlite-flush.d.ts.map +1 -0
  341. package/dist/tools/files/actions/sqlite-flush.js +66 -0
  342. package/dist/tools/files/actions/sqlite-flush.js.map +1 -0
  343. package/dist/tools/files/help/example.d.ts +5 -0
  344. package/dist/tools/files/help/example.d.ts.map +1 -0
  345. package/dist/tools/files/help/example.js +98 -0
  346. package/dist/tools/files/help/example.js.map +1 -0
  347. package/dist/tools/files/help/help.d.ts +5 -0
  348. package/dist/tools/files/help/help.d.ts.map +1 -0
  349. package/dist/tools/files/help/help.js +29 -0
  350. package/dist/tools/files/help/help.js.map +1 -0
  351. package/dist/tools/files/index.d.ts +14 -0
  352. package/dist/tools/files/index.d.ts.map +1 -0
  353. package/dist/tools/files/index.js +15 -0
  354. package/dist/tools/files/index.js.map +1 -0
  355. package/dist/tools/files/internal/queries.d.ts +18 -0
  356. package/dist/tools/files/internal/queries.d.ts.map +1 -0
  357. package/dist/tools/files/internal/queries.js +63 -0
  358. package/dist/tools/files/internal/queries.js.map +1 -0
  359. package/dist/tools/files/internal/validation.d.ts +18 -0
  360. package/dist/tools/files/internal/validation.d.ts.map +1 -0
  361. package/dist/tools/files/internal/validation.js +40 -0
  362. package/dist/tools/files/internal/validation.js.map +1 -0
  363. package/dist/tools/files/types.d.ts +6 -0
  364. package/dist/tools/files/types.d.ts.map +1 -0
  365. package/dist/tools/files/types.js +6 -0
  366. package/dist/tools/files/types.js.map +1 -0
  367. package/dist/tools/help/actions/batch-guide.d.ts +14 -0
  368. package/dist/tools/help/actions/batch-guide.d.ts.map +1 -0
  369. package/dist/tools/help/actions/batch-guide.js +59 -0
  370. package/dist/tools/help/actions/batch-guide.js.map +1 -0
  371. package/dist/tools/help/actions/error-recovery.d.ts +12 -0
  372. package/dist/tools/help/actions/error-recovery.d.ts.map +1 -0
  373. package/dist/tools/help/actions/error-recovery.js +107 -0
  374. package/dist/tools/help/actions/error-recovery.js.map +1 -0
  375. package/dist/tools/help/actions/query-action.d.ts +15 -0
  376. package/dist/tools/help/actions/query-action.d.ts.map +1 -0
  377. package/dist/tools/help/actions/query-action.js +15 -0
  378. package/dist/tools/help/actions/query-action.js.map +1 -0
  379. package/dist/tools/help/actions/query-params.d.ts +15 -0
  380. package/dist/tools/help/actions/query-params.d.ts.map +1 -0
  381. package/dist/tools/help/actions/query-params.js +15 -0
  382. package/dist/tools/help/actions/query-params.js.map +1 -0
  383. package/dist/tools/help/actions/query-tool.d.ts +15 -0
  384. package/dist/tools/help/actions/query-tool.d.ts.map +1 -0
  385. package/dist/tools/help/actions/query-tool.js +15 -0
  386. package/dist/tools/help/actions/query-tool.js.map +1 -0
  387. package/dist/tools/help/actions/workflow-hints.d.ts +14 -0
  388. package/dist/tools/help/actions/workflow-hints.d.ts.map +1 -0
  389. package/dist/tools/help/actions/workflow-hints.js +15 -0
  390. package/dist/tools/help/actions/workflow-hints.js.map +1 -0
  391. package/dist/tools/help/help/example.d.ts +6 -0
  392. package/dist/tools/help/help/example.d.ts.map +1 -0
  393. package/dist/tools/help/help/example.js +70 -0
  394. package/dist/tools/help/help/example.js.map +1 -0
  395. package/dist/tools/help/help/help.d.ts +6 -0
  396. package/dist/tools/help/help/help.d.ts.map +1 -0
  397. package/dist/tools/help/help/help.js +67 -0
  398. package/dist/tools/help/help/help.js.map +1 -0
  399. package/dist/tools/help/index.d.ts +14 -0
  400. package/dist/tools/help/index.d.ts.map +1 -0
  401. package/dist/tools/help/index.js +15 -0
  402. package/dist/tools/help/index.js.map +1 -0
  403. package/dist/tools/help/types.d.ts +92 -0
  404. package/dist/tools/help/types.d.ts.map +1 -0
  405. package/dist/tools/help/types.js +6 -0
  406. package/dist/tools/help/types.js.map +1 -0
  407. package/dist/tools/help-queries.d.ts.map +1 -1
  408. package/dist/tools/help-queries.js +1 -0
  409. package/dist/tools/help-queries.js.map +1 -1
  410. package/dist/tools/tasks/actions/add-dependency.d.ts +12 -0
  411. package/dist/tools/tasks/actions/add-dependency.d.ts.map +1 -0
  412. package/dist/tools/tasks/actions/add-dependency.js +124 -0
  413. package/dist/tools/tasks/actions/add-dependency.js.map +1 -0
  414. package/dist/tools/tasks/actions/archive.d.ts +11 -0
  415. package/dist/tools/tasks/actions/archive.d.ts.map +1 -0
  416. package/dist/tools/tasks/actions/archive.js +67 -0
  417. package/dist/tools/tasks/actions/archive.js.map +1 -0
  418. package/dist/tools/tasks/actions/create-batch.d.ts +19 -0
  419. package/dist/tools/tasks/actions/create-batch.d.ts.map +1 -0
  420. package/dist/tools/tasks/actions/create-batch.js +103 -0
  421. package/dist/tools/tasks/actions/create-batch.js.map +1 -0
  422. package/dist/tools/tasks/actions/create.d.ts +16 -0
  423. package/dist/tools/tasks/actions/create.d.ts.map +1 -0
  424. package/dist/tools/tasks/actions/create.js +180 -0
  425. package/dist/tools/tasks/actions/create.js.map +1 -0
  426. package/dist/tools/tasks/actions/get-dependencies.d.ts +12 -0
  427. package/dist/tools/tasks/actions/get-dependencies.d.ts.map +1 -0
  428. package/dist/tools/tasks/actions/get-dependencies.js +41 -0
  429. package/dist/tools/tasks/actions/get-dependencies.js.map +1 -0
  430. package/dist/tools/tasks/actions/get-pruned-files.d.ts +13 -0
  431. package/dist/tools/tasks/actions/get-pruned-files.d.ts.map +1 -0
  432. package/dist/tools/tasks/actions/get-pruned-files.js +45 -0
  433. package/dist/tools/tasks/actions/get-pruned-files.js.map +1 -0
  434. package/dist/tools/tasks/actions/get.d.ts +12 -0
  435. package/dist/tools/tasks/actions/get.d.ts.map +1 -0
  436. package/dist/tools/tasks/actions/get.js +88 -0
  437. package/dist/tools/tasks/actions/get.js.map +1 -0
  438. package/dist/tools/tasks/actions/link-pruned-file.d.ts +13 -0
  439. package/dist/tools/tasks/actions/link-pruned-file.d.ts.map +1 -0
  440. package/dist/tools/tasks/actions/link-pruned-file.js +63 -0
  441. package/dist/tools/tasks/actions/link-pruned-file.js.map +1 -0
  442. package/dist/tools/tasks/actions/link.d.ts +14 -0
  443. package/dist/tools/tasks/actions/link.d.ts.map +1 -0
  444. package/dist/tools/tasks/actions/link.js +118 -0
  445. package/dist/tools/tasks/actions/link.js.map +1 -0
  446. package/dist/tools/tasks/actions/list.d.ts +17 -0
  447. package/dist/tools/tasks/actions/list.d.ts.map +1 -0
  448. package/dist/tools/tasks/actions/list.js +98 -0
  449. package/dist/tools/tasks/actions/list.js.map +1 -0
  450. package/dist/tools/tasks/actions/move.d.ts +12 -0
  451. package/dist/tools/tasks/actions/move.d.ts.map +1 -0
  452. package/dist/tools/tasks/actions/move.js +91 -0
  453. package/dist/tools/tasks/actions/move.js.map +1 -0
  454. package/dist/tools/tasks/actions/remove-dependency.d.ts +12 -0
  455. package/dist/tools/tasks/actions/remove-dependency.d.ts.map +1 -0
  456. package/dist/tools/tasks/actions/remove-dependency.js +36 -0
  457. package/dist/tools/tasks/actions/remove-dependency.js.map +1 -0
  458. package/dist/tools/tasks/actions/update.d.ts +10 -0
  459. package/dist/tools/tasks/actions/update.d.ts.map +1 -0
  460. package/dist/tools/tasks/actions/update.js +186 -0
  461. package/dist/tools/tasks/actions/update.js.map +1 -0
  462. package/dist/tools/tasks/actions/watch-files.d.ts +14 -0
  463. package/dist/tools/tasks/actions/watch-files.d.ts.map +1 -0
  464. package/dist/tools/tasks/actions/watch-files.js +127 -0
  465. package/dist/tools/tasks/actions/watch-files.js.map +1 -0
  466. package/dist/tools/tasks/help/example.d.ts +8 -0
  467. package/dist/tools/tasks/help/example.d.ts.map +1 -0
  468. package/dist/tools/tasks/help/example.js +215 -0
  469. package/dist/tools/tasks/help/example.js.map +1 -0
  470. package/dist/tools/tasks/help/help.d.ts +8 -0
  471. package/dist/tools/tasks/help/help.d.ts.map +1 -0
  472. package/dist/tools/tasks/help/help.js +293 -0
  473. package/dist/tools/tasks/help/help.js.map +1 -0
  474. package/dist/tools/tasks/help/use-case.d.ts +11 -0
  475. package/dist/tools/tasks/help/use-case.d.ts.map +1 -0
  476. package/dist/tools/tasks/help/use-case.js +768 -0
  477. package/dist/tools/tasks/help/use-case.js.map +1 -0
  478. package/dist/tools/tasks/index.d.ts +28 -0
  479. package/dist/tools/tasks/index.d.ts.map +1 -0
  480. package/dist/tools/tasks/index.js +33 -0
  481. package/dist/tools/tasks/index.js.map +1 -0
  482. package/dist/tools/tasks/internal/state-machine.d.ts +16 -0
  483. package/dist/tools/tasks/internal/state-machine.d.ts.map +1 -0
  484. package/dist/tools/tasks/internal/state-machine.js +36 -0
  485. package/dist/tools/tasks/internal/state-machine.js.map +1 -0
  486. package/dist/tools/tasks/internal/task-queries.d.ts +12 -0
  487. package/dist/tools/tasks/internal/task-queries.d.ts.map +1 -0
  488. package/dist/tools/tasks/internal/task-queries.js +61 -0
  489. package/dist/tools/tasks/internal/task-queries.js.map +1 -0
  490. package/dist/tools/tasks/internal/validation.d.ts +47 -0
  491. package/dist/tools/tasks/internal/validation.d.ts.map +1 -0
  492. package/dist/tools/tasks/internal/validation.js +261 -0
  493. package/dist/tools/tasks/internal/validation.js.map +1 -0
  494. package/dist/tools/tasks/types.d.ts +68 -0
  495. package/dist/tools/tasks/types.d.ts.map +1 -0
  496. package/dist/tools/tasks/types.js +45 -0
  497. package/dist/tools/tasks/types.js.map +1 -0
  498. package/dist/tools/tasks/watcher/status.d.ts +9 -0
  499. package/dist/tools/tasks/watcher/status.d.ts.map +1 -0
  500. package/dist/tools/tasks/watcher/status.js +126 -0
  501. package/dist/tools/tasks/watcher/status.js.map +1 -0
  502. package/dist/tools/tasks.d.ts +12 -148
  503. package/dist/tools/tasks.d.ts.map +1 -1
  504. package/dist/tools/tasks.js +12 -2037
  505. package/dist/tools/tasks.js.map +1 -1
  506. package/dist/tools/use_case/actions/get.d.ts +14 -0
  507. package/dist/tools/use_case/actions/get.d.ts.map +1 -0
  508. package/dist/tools/use_case/actions/get.js +15 -0
  509. package/dist/tools/use_case/actions/get.js.map +1 -0
  510. package/dist/tools/use_case/actions/list-all.d.ts +15 -0
  511. package/dist/tools/use_case/actions/list-all.d.ts.map +1 -0
  512. package/dist/tools/use_case/actions/list-all.js +20 -0
  513. package/dist/tools/use_case/actions/list-all.js.map +1 -0
  514. package/dist/tools/use_case/actions/search.d.ts +14 -0
  515. package/dist/tools/use_case/actions/search.d.ts.map +1 -0
  516. package/dist/tools/use_case/actions/search.js +87 -0
  517. package/dist/tools/use_case/actions/search.js.map +1 -0
  518. package/dist/tools/use_case/help/example.d.ts +105 -0
  519. package/dist/tools/use_case/help/example.d.ts.map +1 -0
  520. package/dist/tools/use_case/help/example.js +138 -0
  521. package/dist/tools/use_case/help/example.js.map +1 -0
  522. package/dist/tools/use_case/help/help.d.ts +33 -0
  523. package/dist/tools/use_case/help/help.d.ts.map +1 -0
  524. package/dist/tools/use_case/help/help.js +109 -0
  525. package/dist/tools/use_case/help/help.js.map +1 -0
  526. package/dist/tools/use_case/index.d.ts +11 -0
  527. package/dist/tools/use_case/index.d.ts.map +1 -0
  528. package/dist/tools/use_case/index.js +12 -0
  529. package/dist/tools/use_case/index.js.map +1 -0
  530. package/dist/tools/use_case/types.d.ts +58 -0
  531. package/dist/tools/use_case/types.d.ts.map +1 -0
  532. package/dist/tools/use_case/types.js +6 -0
  533. package/dist/tools/use_case/types.js.map +1 -0
  534. package/dist/types/actions.d.ts +37 -0
  535. package/dist/types/actions.d.ts.map +1 -0
  536. package/dist/types/actions.js +6 -0
  537. package/dist/types/actions.js.map +1 -0
  538. package/dist/types/constraint/params.d.ts +2 -0
  539. package/dist/types/constraint/params.d.ts.map +1 -0
  540. package/dist/types/constraint/params.js +2 -0
  541. package/dist/types/constraint/params.js.map +1 -0
  542. package/dist/types/constraint/responses.d.ts +2 -0
  543. package/dist/types/constraint/responses.d.ts.map +1 -0
  544. package/dist/types/constraint/responses.js +2 -0
  545. package/dist/types/constraint/responses.js.map +1 -0
  546. package/dist/types/decision/batch.d.ts +24 -0
  547. package/dist/types/decision/batch.d.ts.map +1 -0
  548. package/dist/types/decision/batch.js +5 -0
  549. package/dist/types/decision/batch.js.map +1 -0
  550. package/dist/types/decision/params.d.ts +73 -0
  551. package/dist/types/decision/params.d.ts.map +1 -0
  552. package/dist/types/decision/params.js +5 -0
  553. package/dist/types/decision/params.js.map +1 -0
  554. package/dist/types/decision/responses.d.ts +79 -0
  555. package/dist/types/decision/responses.d.ts.map +1 -0
  556. package/dist/types/decision/responses.js +5 -0
  557. package/dist/types/decision/responses.js.map +1 -0
  558. package/dist/types/decision/templates.d.ts +74 -0
  559. package/dist/types/decision/templates.d.ts.map +1 -0
  560. package/dist/types/decision/templates.js +5 -0
  561. package/dist/types/decision/templates.js.map +1 -0
  562. package/dist/types/enums.d.ts +43 -0
  563. package/dist/types/enums.d.ts.map +1 -0
  564. package/dist/types/enums.js +47 -0
  565. package/dist/types/enums.js.map +1 -0
  566. package/dist/types/file/params.d.ts +40 -0
  567. package/dist/types/file/params.d.ts.map +1 -0
  568. package/dist/types/file/params.js +6 -0
  569. package/dist/types/file/params.js.map +1 -0
  570. package/dist/types/file/responses.d.ts +2 -0
  571. package/dist/types/file/responses.d.ts.map +1 -0
  572. package/dist/types/file/responses.js +2 -0
  573. package/dist/types/file/responses.js.map +1 -0
  574. package/dist/types/import-export.d.ts +126 -0
  575. package/dist/types/import-export.d.ts.map +1 -0
  576. package/dist/types/import-export.js +6 -0
  577. package/dist/types/import-export.js.map +1 -0
  578. package/dist/types/index.d.ts +25 -0
  579. package/dist/types/index.d.ts.map +1 -0
  580. package/dist/types/index.js +35 -0
  581. package/dist/types/index.js.map +1 -0
  582. package/dist/types/master-entities.d.ts +33 -0
  583. package/dist/types/master-entities.d.ts.map +1 -0
  584. package/dist/types/master-entities.js +6 -0
  585. package/dist/types/master-entities.js.map +1 -0
  586. package/dist/types/task/params.d.ts +172 -0
  587. package/dist/types/task/params.d.ts.map +1 -0
  588. package/dist/types/task/params.js +8 -0
  589. package/dist/types/task/params.js.map +1 -0
  590. package/dist/types/task/responses.d.ts +334 -0
  591. package/dist/types/task/responses.d.ts.map +1 -0
  592. package/dist/types/task/responses.js +8 -0
  593. package/dist/types/task/responses.js.map +1 -0
  594. package/dist/types/transaction-entities.d.ts +89 -0
  595. package/dist/types/transaction-entities.d.ts.map +1 -0
  596. package/dist/types/transaction-entities.js +5 -0
  597. package/dist/types/transaction-entities.js.map +1 -0
  598. package/dist/types/validation.d.ts +44 -0
  599. package/dist/types/validation.d.ts.map +1 -0
  600. package/dist/types/validation.js +6 -0
  601. package/dist/types/validation.js.map +1 -0
  602. package/dist/types/view-entities.d.ts +61 -0
  603. package/dist/types/view-entities.d.ts.map +1 -0
  604. package/dist/types/view-entities.js +5 -0
  605. package/dist/types/view-entities.js.map +1 -0
  606. package/dist/types.d.ts +133 -10
  607. package/dist/types.d.ts.map +1 -1
  608. package/dist/utils/action-specs/config-specs.d.ts +10 -0
  609. package/dist/utils/action-specs/config-specs.d.ts.map +1 -0
  610. package/dist/utils/action-specs/config-specs.js +12 -0
  611. package/dist/utils/action-specs/config-specs.js.map +1 -0
  612. package/dist/utils/action-specs/constraint-specs.d.ts +9 -0
  613. package/dist/utils/action-specs/constraint-specs.d.ts.map +1 -0
  614. package/dist/utils/action-specs/constraint-specs.js +42 -0
  615. package/dist/utils/action-specs/constraint-specs.js.map +1 -0
  616. package/dist/utils/action-specs/decision-specs.d.ts +9 -0
  617. package/dist/utils/action-specs/decision-specs.d.ts.map +1 -0
  618. package/dist/utils/action-specs/decision-specs.js +194 -0
  619. package/dist/utils/action-specs/decision-specs.js.map +1 -0
  620. package/dist/utils/action-specs/file-specs.d.ts +9 -0
  621. package/dist/utils/action-specs/file-specs.d.ts.map +1 -0
  622. package/dist/utils/action-specs/file-specs.js +56 -0
  623. package/dist/utils/action-specs/file-specs.js.map +1 -0
  624. package/dist/utils/action-specs/index.d.ts +38 -0
  625. package/dist/utils/action-specs/index.d.ts.map +1 -0
  626. package/dist/utils/action-specs/index.js +63 -0
  627. package/dist/utils/action-specs/index.js.map +1 -0
  628. package/dist/utils/action-specs/task-specs.d.ts +9 -0
  629. package/dist/utils/action-specs/task-specs.d.ts.map +1 -0
  630. package/dist/utils/action-specs/task-specs.js +143 -0
  631. package/dist/utils/action-specs/task-specs.js.map +1 -0
  632. package/dist/utils/action-specs/types.d.ts +14 -0
  633. package/dist/utils/action-specs/types.d.ts.map +1 -0
  634. package/dist/utils/action-specs/types.js +9 -0
  635. package/dist/utils/action-specs/types.js.map +1 -0
  636. package/dist/utils/batch-validation.d.ts +156 -0
  637. package/dist/utils/batch-validation.d.ts.map +1 -0
  638. package/dist/utils/batch-validation.example.d.ts +48 -0
  639. package/dist/utils/batch-validation.example.d.ts.map +1 -0
  640. package/dist/utils/batch-validation.example.js +180 -0
  641. package/dist/utils/batch-validation.example.js.map +1 -0
  642. package/dist/utils/batch-validation.js +345 -0
  643. package/dist/utils/batch-validation.js.map +1 -0
  644. package/dist/utils/exporter/export.d.ts +100 -0
  645. package/dist/utils/exporter/export.d.ts.map +1 -0
  646. package/dist/utils/exporter/export.js +363 -0
  647. package/dist/utils/exporter/export.js.map +1 -0
  648. package/dist/utils/importer/import.d.ts +29 -0
  649. package/dist/utils/importer/import.d.ts.map +1 -0
  650. package/dist/utils/importer/import.js +514 -0
  651. package/dist/utils/importer/import.js.map +1 -0
  652. package/dist/utils/importer/master-tables.d.ts +18 -0
  653. package/dist/utils/importer/master-tables.d.ts.map +1 -0
  654. package/dist/utils/importer/master-tables.js +255 -0
  655. package/dist/utils/importer/master-tables.js.map +1 -0
  656. package/dist/utils/importer/topological-sort.d.ts +61 -0
  657. package/dist/utils/importer/topological-sort.d.ts.map +1 -0
  658. package/dist/utils/importer/topological-sort.js +143 -0
  659. package/dist/utils/importer/topological-sort.js.map +1 -0
  660. package/dist/utils/levenshtein.d.ts +18 -0
  661. package/dist/utils/levenshtein.d.ts.map +1 -0
  662. package/dist/utils/levenshtein.js +46 -0
  663. package/dist/utils/levenshtein.js.map +1 -0
  664. package/dist/utils/parameter-validator.d.ts +3 -3
  665. package/dist/utils/parameter-validator.d.ts.map +1 -1
  666. package/dist/utils/parameter-validator.js +3 -39
  667. package/dist/utils/parameter-validator.js.map +1 -1
  668. package/dist/utils/sql-dump/core/dependency-sort.d.ts +16 -0
  669. package/dist/utils/sql-dump/core/dependency-sort.d.ts.map +1 -0
  670. package/dist/utils/sql-dump/core/dependency-sort.js +105 -0
  671. package/dist/utils/sql-dump/core/dependency-sort.js.map +1 -0
  672. package/dist/utils/sql-dump/core/generate-dump.d.ts +13 -0
  673. package/dist/utils/sql-dump/core/generate-dump.d.ts.map +1 -0
  674. package/dist/utils/sql-dump/core/generate-dump.js +181 -0
  675. package/dist/utils/sql-dump/core/generate-dump.js.map +1 -0
  676. package/dist/utils/sql-dump/core/index-export.d.ts +9 -0
  677. package/dist/utils/sql-dump/core/index-export.d.ts.map +1 -0
  678. package/dist/utils/sql-dump/core/index-export.js +173 -0
  679. package/dist/utils/sql-dump/core/index-export.js.map +1 -0
  680. package/dist/utils/sql-dump/core/sequence-reset.d.ts +6 -0
  681. package/dist/utils/sql-dump/core/sequence-reset.d.ts.map +1 -0
  682. package/dist/utils/sql-dump/core/sequence-reset.js +28 -0
  683. package/dist/utils/sql-dump/core/sequence-reset.js.map +1 -0
  684. package/dist/utils/sql-dump/core/table-export.d.ts +2 -0
  685. package/dist/utils/sql-dump/core/table-export.d.ts.map +1 -0
  686. package/dist/utils/sql-dump/core/table-export.js +4 -0
  687. package/dist/utils/sql-dump/core/table-export.js.map +1 -0
  688. package/dist/utils/sql-dump/core/view-export.d.ts +2 -0
  689. package/dist/utils/sql-dump/core/view-export.d.ts.map +1 -0
  690. package/dist/utils/sql-dump/core/view-export.js +4 -0
  691. package/dist/utils/sql-dump/core/view-export.js.map +1 -0
  692. package/dist/utils/sql-dump/formatters/bulk-insert.d.ts +14 -0
  693. package/dist/utils/sql-dump/formatters/bulk-insert.d.ts.map +1 -0
  694. package/dist/utils/sql-dump/formatters/bulk-insert.js +177 -0
  695. package/dist/utils/sql-dump/formatters/bulk-insert.js.map +1 -0
  696. package/dist/utils/sql-dump/formatters/identifiers.d.ts +6 -0
  697. package/dist/utils/sql-dump/formatters/identifiers.d.ts.map +1 -0
  698. package/dist/utils/sql-dump/formatters/identifiers.js +16 -0
  699. package/dist/utils/sql-dump/formatters/identifiers.js.map +1 -0
  700. package/dist/utils/sql-dump/formatters/value-formatter.d.ts +14 -0
  701. package/dist/utils/sql-dump/formatters/value-formatter.d.ts.map +1 -0
  702. package/dist/utils/sql-dump/formatters/value-formatter.js +281 -0
  703. package/dist/utils/sql-dump/formatters/value-formatter.js.map +1 -0
  704. package/dist/utils/sql-dump/generators/controls.d.ts +10 -0
  705. package/dist/utils/sql-dump/generators/controls.d.ts.map +1 -0
  706. package/dist/utils/sql-dump/generators/controls.js +36 -0
  707. package/dist/utils/sql-dump/generators/controls.js.map +1 -0
  708. package/dist/utils/sql-dump/generators/headers.d.ts +6 -0
  709. package/dist/utils/sql-dump/generators/headers.d.ts.map +1 -0
  710. package/dist/utils/sql-dump/generators/headers.js +19 -0
  711. package/dist/utils/sql-dump/generators/headers.js.map +1 -0
  712. package/dist/utils/sql-dump/index.d.ts +14 -0
  713. package/dist/utils/sql-dump/index.d.ts.map +1 -0
  714. package/dist/utils/sql-dump/index.js +16 -0
  715. package/dist/utils/sql-dump/index.js.map +1 -0
  716. package/dist/utils/sql-dump/schema/indexes.d.ts +6 -0
  717. package/dist/utils/sql-dump/schema/indexes.d.ts.map +1 -0
  718. package/dist/utils/sql-dump/schema/indexes.js +42 -0
  719. package/dist/utils/sql-dump/schema/indexes.js.map +1 -0
  720. package/dist/utils/sql-dump/schema/primary-keys.d.ts +6 -0
  721. package/dist/utils/sql-dump/schema/primary-keys.d.ts.map +1 -0
  722. package/dist/utils/sql-dump/schema/primary-keys.js +41 -0
  723. package/dist/utils/sql-dump/schema/primary-keys.js.map +1 -0
  724. package/dist/utils/sql-dump/schema/tables.d.ts +12 -0
  725. package/dist/utils/sql-dump/schema/tables.d.ts.map +1 -0
  726. package/dist/utils/sql-dump/schema/tables.js +370 -0
  727. package/dist/utils/sql-dump/schema/tables.js.map +1 -0
  728. package/dist/utils/sql-dump/schema/views.d.ts +11 -0
  729. package/dist/utils/sql-dump/schema/views.d.ts.map +1 -0
  730. package/dist/utils/sql-dump/schema/views.js +110 -0
  731. package/dist/utils/sql-dump/schema/views.js.map +1 -0
  732. package/dist/utils/sql-dump/types.d.ts +10 -0
  733. package/dist/utils/sql-dump/types.d.ts.map +1 -0
  734. package/dist/utils/sql-dump/types.js +3 -0
  735. package/dist/utils/sql-dump/types.js.map +1 -0
  736. package/docs/AI_AGENT_GUIDE.md +2 -2
  737. package/docs/AUTO_FILE_TRACKING.md +0 -1
  738. package/docs/BATCH_VALIDATION.md +617 -0
  739. package/docs/DATABASE_AUTH.md +1 -2
  740. package/docs/DECISION_TO_TASK_MIGRATION_GUIDE.md +2 -2
  741. package/docs/SHARED_CONCEPTS.md +2 -2
  742. package/docs/SPECIALIZED_AGENTS.md +1 -1
  743. package/docs/TASK_ACTIONS.md +7 -7
  744. package/docs/TASK_MIGRATION.md +5 -5
  745. package/docs/TASK_SYSTEM.md +5 -5
  746. package/docs/TOOL_REFERENCE.md +1 -3
  747. package/docs/WORKFLOWS.md +1 -1
  748. package/docs/{DATABASE_MIGRATION.md → cli/DATABASE_MIGRATION.md} +71 -32
  749. package/docs/cli/DATA_EXPORT_IMPORT.md +400 -0
  750. package/docs/cli/README.md +227 -0
  751. package/package.json +7 -4
  752. package/dist/tools/config.d.ts +0 -58
  753. package/dist/tools/config.d.ts.map +0 -1
  754. package/dist/tools/config.js +0 -281
  755. package/dist/tools/config.js.map +0 -1
  756. package/dist/tools/constraints.d.ts +0 -49
  757. package/dist/tools/constraints.d.ts.map +0 -1
  758. package/dist/tools/constraints.js +0 -378
  759. package/dist/tools/constraints.js.map +0 -1
  760. package/dist/tools/context.d.ts +0 -208
  761. package/dist/tools/context.d.ts.map +0 -1
  762. package/dist/tools/context.js +0 -1661
  763. package/dist/tools/context.js.map +0 -1
  764. package/dist/tools/files.d.ts +0 -54
  765. package/dist/tools/files.d.ts.map +0 -1
  766. package/dist/tools/files.js +0 -478
  767. package/dist/tools/files.js.map +0 -1
  768. package/dist/tools/messaging.d.ts +0 -71
  769. package/dist/tools/messaging.d.ts.map +0 -1
  770. package/dist/tools/messaging.js +0 -483
  771. package/dist/tools/messaging.js.map +0 -1
  772. package/dist/tools/utils.d.ts +0 -70
  773. package/dist/tools/utils.d.ts.map +0 -1
  774. package/dist/tools/utils.js +0 -483
  775. package/dist/tools/utils.js.map +0 -1
  776. package/dist/utils/action-specs.d.ts +0 -46
  777. package/dist/utils/action-specs.d.ts.map +0 -1
  778. package/dist/utils/action-specs.js +0 -527
  779. package/dist/utils/action-specs.js.map +0 -1
  780. package/docs/BASEADAPTER_IMPLEMENTATION.md +0 -399
  781. package/docs/HELP_PREVIEW_COMPARISON.md +0 -259
  782. package/docs/MIGRATION_CHAIN.md +0 -293
  783. package/docs/MIGRATION_v2.md +0 -538
  784. package/docs/MIGRATION_v3.3.md +0 -602
  785. package/docs/MIGRATION_v3.6.0.md +0 -170
  786. package/docs/MULTI_PROJECT_ARCHITECTURE.md +0 -497
@@ -1,2042 +1,17 @@
1
1
  /**
2
2
  * Task management tools for Kanban Task Watcher
3
- * Implements create, update, get, list, move, link, archive, batch_create actions
4
3
  *
5
- * CONVERTED: Using Knex.js with DatabaseAdapter (async/await)
6
- */
7
- import { getAdapter, getOrCreateAgent, getOrCreateTag, getOrCreateContextKey, getLayerId, getOrCreateFile } from '../database.js';
8
- import { getProjectContext } from '../utils/project-context.js';
9
- import { detectAndTransitionStaleTasks, autoArchiveOldDoneTasks, detectAndCompleteReviewedTasks, detectAndArchiveOnCommit } from '../utils/task-stale-detection.js';
10
- import { FileWatcher } from '../watcher/index.js';
11
- import { validatePriorityRange, validateLength, validateRange } from '../utils/validators.js';
12
- import { logTaskCreate, logTaskStatusChange } from '../utils/activity-logging.js';
13
- import { parseStringArray } from '../utils/param-parser.js';
14
- import { validateActionParams, validateBatchParams } from '../utils/parameter-validator.js';
15
- import { debugLog } from '../utils/debug-logger.js';
16
- import connectionManager from '../utils/connection-manager.js';
17
- /**
18
- * Task status enum (matches m_task_statuses)
19
- */
20
- const TASK_STATUS = {
21
- TODO: 1,
22
- IN_PROGRESS: 2,
23
- WAITING_REVIEW: 3,
24
- BLOCKED: 4,
25
- DONE: 5,
26
- ARCHIVED: 6,
27
- };
28
- /**
29
- * Task status name mapping
30
- */
31
- const STATUS_TO_ID = {
32
- 'todo': TASK_STATUS.TODO,
33
- 'in_progress': TASK_STATUS.IN_PROGRESS,
34
- 'waiting_review': TASK_STATUS.WAITING_REVIEW,
35
- 'blocked': TASK_STATUS.BLOCKED,
36
- 'done': TASK_STATUS.DONE,
37
- 'archived': TASK_STATUS.ARCHIVED,
38
- };
39
- const ID_TO_STATUS = {
40
- [TASK_STATUS.TODO]: 'todo',
41
- [TASK_STATUS.IN_PROGRESS]: 'in_progress',
42
- [TASK_STATUS.WAITING_REVIEW]: 'waiting_review',
43
- [TASK_STATUS.BLOCKED]: 'blocked',
44
- [TASK_STATUS.DONE]: 'done',
45
- [TASK_STATUS.ARCHIVED]: 'archived',
46
- };
47
- /**
48
- * Valid status transitions
49
- */
50
- const VALID_TRANSITIONS = {
51
- [TASK_STATUS.TODO]: [TASK_STATUS.IN_PROGRESS, TASK_STATUS.BLOCKED],
52
- [TASK_STATUS.IN_PROGRESS]: [TASK_STATUS.WAITING_REVIEW, TASK_STATUS.BLOCKED, TASK_STATUS.DONE],
53
- [TASK_STATUS.WAITING_REVIEW]: [TASK_STATUS.IN_PROGRESS, TASK_STATUS.TODO, TASK_STATUS.DONE],
54
- [TASK_STATUS.BLOCKED]: [TASK_STATUS.TODO, TASK_STATUS.IN_PROGRESS],
55
- [TASK_STATUS.DONE]: [TASK_STATUS.ARCHIVED],
56
- [TASK_STATUS.ARCHIVED]: [], // No transitions from archived
57
- };
58
- /**
59
- * Internal helper: Create task without wrapping in transaction
60
- * Used by createTask (with transaction) and batchCreateTasks (manages its own transaction)
4
+ * REFACTORED: This file now re-exports from the modular tasks/ directory structure.
5
+ * The original 2,362-line monolithic file has been split into 23 action-based files.
61
6
  *
62
- * @param params - Task parameters
63
- * @param adapter - Database adapter instance
64
- * @param trx - Optional transaction
65
- * @returns Response with success status and task metadata
66
- */
67
- async function createTaskInternal(params, adapter, trx) {
68
- const knex = trx || adapter.getKnex();
69
- // Fail-fast project_id validation (Constraint #29)
70
- const projectId = getProjectContext().getProjectId();
71
- // Validate priority
72
- const priority = params.priority !== undefined ? params.priority : 2;
73
- validatePriorityRange(priority);
74
- // Get status_id
75
- const status = params.status || 'todo';
76
- const statusId = STATUS_TO_ID[status];
77
- if (!statusId) {
78
- throw new Error(`Invalid status: ${status}. Must be one of: todo, in_progress, waiting_review, blocked, done, archived`);
79
- }
80
- // Validate layer if provided
81
- let layerId = null;
82
- if (params.layer) {
83
- layerId = await getLayerId(adapter, params.layer, trx);
84
- if (layerId === null) {
85
- throw new Error(`Invalid layer: ${params.layer}. Must be one of: presentation, business, data, infrastructure, cross-cutting`);
86
- }
87
- }
88
- // Get or create agents
89
- let assignedAgentId = null;
90
- if (params.assigned_agent) {
91
- assignedAgentId = await getOrCreateAgent(adapter, params.assigned_agent, trx);
92
- }
93
- // Default to generic agent pool if no created_by_agent provided
94
- // Empty string triggers allocation from generic-N pool
95
- const createdBy = params.created_by_agent || '';
96
- const createdByAgentId = await getOrCreateAgent(adapter, createdBy, trx);
97
- // Insert task
98
- const now = Math.floor(Date.now() / 1000);
99
- const [taskId] = await knex('t_tasks').insert({
100
- project_id: projectId,
101
- title: params.title,
102
- status_id: statusId,
103
- priority: priority,
104
- assigned_agent_id: assignedAgentId,
105
- created_by_agent_id: createdByAgentId,
106
- layer_id: layerId,
107
- created_ts: now,
108
- updated_ts: now
109
- });
110
- // Process acceptance_criteria (can be string, JSON string, or array)
111
- let acceptanceCriteriaString = null;
112
- let acceptanceCriteriaJson = null;
113
- if (params.acceptance_criteria) {
114
- if (Array.isArray(params.acceptance_criteria)) {
115
- // Array format - store as JSON in acceptance_criteria_json
116
- acceptanceCriteriaJson = JSON.stringify(params.acceptance_criteria);
117
- // Also create human-readable summary in acceptance_criteria
118
- acceptanceCriteriaString = params.acceptance_criteria
119
- .map((check, i) => `${i + 1}. ${check.type}: ${check.command || check.file || check.pattern || ''}`)
120
- .join('\n');
121
- }
122
- else if (typeof params.acceptance_criteria === 'string') {
123
- // Try to parse as JSON first
124
- try {
125
- const parsed = JSON.parse(params.acceptance_criteria);
126
- if (Array.isArray(parsed)) {
127
- // It's a JSON array string - store in JSON field
128
- acceptanceCriteriaJson = params.acceptance_criteria;
129
- // Also create human-readable summary
130
- acceptanceCriteriaString = parsed
131
- .map((check, i) => `${i + 1}. ${check.type}: ${check.command || check.file || check.pattern || ''}`)
132
- .join('\n');
133
- }
134
- else {
135
- // Valid JSON but not an array - store as plain text
136
- acceptanceCriteriaString = params.acceptance_criteria;
137
- }
138
- }
139
- catch {
140
- // Not valid JSON - store as plain text
141
- acceptanceCriteriaString = params.acceptance_criteria;
142
- }
143
- }
144
- }
145
- // Insert task details if provided
146
- if (params.description || acceptanceCriteriaString || acceptanceCriteriaJson || params.notes) {
147
- await knex('t_task_details').insert({
148
- project_id: projectId,
149
- task_id: Number(taskId),
150
- description: params.description || null,
151
- acceptance_criteria: acceptanceCriteriaString,
152
- acceptance_criteria_json: acceptanceCriteriaJson,
153
- notes: params.notes || null
154
- });
155
- }
156
- // Insert tags if provided
157
- if (params.tags && params.tags.length > 0) {
158
- // Parse tags - handle MCP SDK converting JSON string to char array
159
- let tagsParsed;
160
- if (typeof params.tags === 'string') {
161
- // String - try to parse as JSON
162
- try {
163
- tagsParsed = JSON.parse(params.tags);
164
- }
165
- catch {
166
- // If not valid JSON, treat as single tag name
167
- tagsParsed = [params.tags];
168
- }
169
- }
170
- else if (Array.isArray(params.tags)) {
171
- // Check if it's an array of single characters (MCP SDK bug)
172
- // Example: ['[', '"', 't', 'e', 's', 't', 'i', 'n', 'g', '"', ']']
173
- if (params.tags.every((item) => typeof item === 'string' && item.length === 1)) {
174
- // Join characters back into string and parse JSON
175
- const jsonString = params.tags.join('');
176
- try {
177
- tagsParsed = JSON.parse(jsonString);
178
- }
179
- catch (e) {
180
- const errMsg = e instanceof Error ? e.message : String(e);
181
- throw new Error(`Invalid tags format: ${jsonString}. ${errMsg}`);
182
- }
183
- }
184
- else {
185
- // Normal array of tag names
186
- tagsParsed = params.tags;
187
- }
188
- }
189
- else {
190
- throw new Error('Parameter "tags" must be a string or array');
191
- }
192
- for (const tagName of tagsParsed) {
193
- const tagId = await getOrCreateTag(adapter, projectId, tagName, trx); // v3.7.3: pass projectId
194
- await knex('t_task_tags').insert({
195
- project_id: projectId,
196
- task_id: Number(taskId),
197
- tag_id: tagId
198
- }).onConflict(['project_id', 'task_id', 'tag_id']).ignore();
199
- }
200
- }
201
- // Activity logging (replaces triggers)
202
- await logTaskCreate(knex, {
203
- task_id: Number(taskId),
204
- title: params.title,
205
- agent_id: createdByAgentId,
206
- layer_id: layerId || undefined
207
- });
208
- // Link files and register with watcher if watch_files provided (v3.4.1)
209
- if (params.watch_files && params.watch_files.length > 0) {
210
- // Parse watch_files - handle MCP SDK converting JSON string to char array
211
- let watchFilesParsed;
212
- if (typeof params.watch_files === 'string') {
213
- // String - try to parse as JSON
214
- try {
215
- watchFilesParsed = JSON.parse(params.watch_files);
216
- }
217
- catch {
218
- // If not valid JSON, treat as single file path
219
- watchFilesParsed = [params.watch_files];
220
- }
221
- }
222
- else if (Array.isArray(params.watch_files)) {
223
- // Check if it's an array of single characters (MCP SDK bug)
224
- // Example: ['[', '"', 'f', 'i', 'l', 'e', '.', 't', 'x', 't', '"', ']']
225
- if (params.watch_files.every((item) => typeof item === 'string' && item.length === 1)) {
226
- // Join characters back into string and parse JSON
227
- const jsonString = params.watch_files.join('');
228
- try {
229
- watchFilesParsed = JSON.parse(jsonString);
230
- }
231
- catch (e) {
232
- const errMsg = e instanceof Error ? e.message : String(e);
233
- throw new Error(`Invalid watch_files format: ${jsonString}. ${errMsg}`);
234
- }
235
- }
236
- else {
237
- // Normal array of file paths
238
- watchFilesParsed = params.watch_files;
239
- }
240
- }
241
- else {
242
- throw new Error('Parameter "watch_files" must be a string or array');
243
- }
244
- for (const filePath of watchFilesParsed) {
245
- const fileId = await getOrCreateFile(adapter, projectId, filePath, trx); // v3.7.3: pass projectId
246
- await knex('t_task_file_links').insert({
247
- project_id: projectId,
248
- task_id: Number(taskId),
249
- file_id: fileId
250
- }).onConflict(['project_id', 'task_id', 'file_id']).ignore();
251
- }
252
- // Register files with watcher for auto-tracking
253
- try {
254
- const watcher = FileWatcher.getInstance();
255
- for (const filePath of watchFilesParsed) {
256
- watcher.registerFile(filePath, Number(taskId), params.title, status);
257
- }
258
- }
259
- catch (error) {
260
- // Watcher may not be initialized yet, ignore
261
- debugLog('WARN', 'Could not register files with watcher', { error });
262
- }
263
- }
264
- return {
265
- success: true,
266
- task_id: Number(taskId),
267
- title: params.title,
268
- status: status,
269
- message: `Task "${params.title}" created successfully`
270
- };
271
- }
272
- /**
273
- * Create a new task
274
- */
275
- export async function createTask(params, adapter) {
276
- validateActionParams('task', 'create', params);
277
- const actualAdapter = adapter ?? getAdapter();
278
- // Validate required parameters
279
- if (!params.title || params.title.trim() === '') {
280
- throw new Error('Parameter "title" is required and cannot be empty');
281
- }
282
- validateLength(params.title, 'Parameter "title"', 200);
283
- try {
284
- return await connectionManager.executeWithRetry(async () => {
285
- return await actualAdapter.transaction(async (trx) => {
286
- return await createTaskInternal(params, actualAdapter, trx);
287
- });
288
- });
289
- }
290
- catch (error) {
291
- const message = error instanceof Error ? error.message : String(error);
292
- // Preserve validation errors (they already contain helpful information)
293
- if (message.startsWith('{') && message.includes('"error"')) {
294
- throw error;
295
- }
296
- throw new Error(`Failed to create task: ${message}`);
297
- }
298
- }
299
- /**
300
- * Update task metadata
301
- */
302
- export async function updateTask(params, adapter) {
303
- validateActionParams('task', 'update', params);
304
- const actualAdapter = adapter ?? getAdapter();
305
- // Validate required parameters
306
- if (!params.task_id) {
307
- throw new Error('Parameter "task_id" is required');
308
- }
309
- // Fail-fast project_id validation (Constraint #29)
310
- const projectId = getProjectContext().getProjectId();
311
- try {
312
- return await connectionManager.executeWithRetry(async () => {
313
- return await actualAdapter.transaction(async (trx) => {
314
- const knex = actualAdapter.getKnex();
315
- // Check if task exists with project_id isolation
316
- const taskExists = await trx('t_tasks')
317
- .where({ id: params.task_id, project_id: projectId })
318
- .first();
319
- if (!taskExists) {
320
- throw new Error(`Task with id ${params.task_id} not found`);
321
- }
322
- // Build update data dynamically
323
- const updateData = {};
324
- if (params.title !== undefined) {
325
- if (params.title.trim() === '') {
326
- throw new Error('Parameter "title" cannot be empty');
327
- }
328
- validateLength(params.title, 'Parameter "title"', 200);
329
- updateData.title = params.title;
330
- }
331
- if (params.priority !== undefined) {
332
- validatePriorityRange(params.priority);
333
- updateData.priority = params.priority;
334
- }
335
- if (params.assigned_agent !== undefined) {
336
- const agentId = await getOrCreateAgent(actualAdapter, params.assigned_agent, trx);
337
- updateData.assigned_agent_id = agentId;
338
- }
339
- if (params.layer !== undefined) {
340
- const layerId = await getLayerId(actualAdapter, params.layer, trx);
341
- if (layerId === null) {
342
- throw new Error(`Invalid layer: ${params.layer}. Must be one of: presentation, business, data, infrastructure, cross-cutting`);
343
- }
344
- updateData.layer_id = layerId;
345
- }
346
- // Update t_tasks if any updates (with project_id isolation)
347
- if (Object.keys(updateData).length > 0) {
348
- await trx('t_tasks')
349
- .where({ id: params.task_id, project_id: projectId })
350
- .update(updateData);
351
- // TODO: Add activity logging for updates if needed
352
- }
353
- // Update t_task_details if any detail fields provided
354
- if (params.description !== undefined || params.acceptance_criteria !== undefined || params.notes !== undefined) {
355
- // Process acceptance_criteria (can be string or array)
356
- let acceptanceCriteriaString = undefined;
357
- let acceptanceCriteriaJson = undefined;
358
- if (params.acceptance_criteria !== undefined) {
359
- if (Array.isArray(params.acceptance_criteria)) {
360
- // Array format - store as JSON in acceptance_criteria_json
361
- acceptanceCriteriaJson = JSON.stringify(params.acceptance_criteria);
362
- // Also create human-readable summary in acceptance_criteria
363
- acceptanceCriteriaString = params.acceptance_criteria
364
- .map((check, i) => `${i + 1}. ${check.type}: ${check.command || check.file || check.pattern || ''}`)
365
- .join('\n');
366
- }
367
- else if (typeof params.acceptance_criteria === 'string') {
368
- // Try to parse as JSON first
369
- try {
370
- const parsed = JSON.parse(params.acceptance_criteria);
371
- if (Array.isArray(parsed)) {
372
- // It's a JSON array string - store in JSON field
373
- acceptanceCriteriaJson = params.acceptance_criteria;
374
- // Also create human-readable summary
375
- acceptanceCriteriaString = parsed
376
- .map((check, i) => `${i + 1}. ${check.type}: ${check.command || check.file || check.pattern || ''}`)
377
- .join('\n');
378
- }
379
- else {
380
- // Valid JSON but not an array - store as plain text
381
- acceptanceCriteriaString = params.acceptance_criteria || null;
382
- acceptanceCriteriaJson = null;
383
- }
384
- }
385
- catch {
386
- // Not valid JSON - store as plain text
387
- acceptanceCriteriaString = params.acceptance_criteria || null;
388
- acceptanceCriteriaJson = null;
389
- }
390
- }
391
- }
392
- // Check if details exist (with project_id isolation)
393
- const detailsExist = await trx('t_task_details')
394
- .where({ task_id: params.task_id, project_id: projectId })
395
- .first();
396
- const detailsUpdate = {};
397
- if (params.description !== undefined) {
398
- detailsUpdate.description = params.description || null;
399
- }
400
- if (acceptanceCriteriaString !== undefined) {
401
- detailsUpdate.acceptance_criteria = acceptanceCriteriaString;
402
- }
403
- if (acceptanceCriteriaJson !== undefined) {
404
- detailsUpdate.acceptance_criteria_json = acceptanceCriteriaJson;
405
- }
406
- if (params.notes !== undefined) {
407
- detailsUpdate.notes = params.notes || null;
408
- }
409
- if (detailsExist && Object.keys(detailsUpdate).length > 0) {
410
- // Update existing details (with project_id isolation)
411
- await trx('t_task_details')
412
- .where({ task_id: params.task_id, project_id: projectId })
413
- .update(detailsUpdate);
414
- }
415
- else if (!detailsExist) {
416
- // Insert new details
417
- await trx('t_task_details').insert({
418
- project_id: projectId,
419
- task_id: params.task_id,
420
- description: params.description || null,
421
- acceptance_criteria: acceptanceCriteriaString !== undefined ? acceptanceCriteriaString : null,
422
- acceptance_criteria_json: acceptanceCriteriaJson !== undefined ? acceptanceCriteriaJson : null,
423
- notes: params.notes || null
424
- });
425
- }
426
- }
427
- // Handle watch_files if provided (v3.4.1)
428
- if (params.watch_files && params.watch_files.length > 0) {
429
- // Parse watch_files - handle MCP SDK converting JSON string to char array
430
- let watchFilesParsed;
431
- if (typeof params.watch_files === 'string') {
432
- // String - try to parse as JSON
433
- try {
434
- watchFilesParsed = JSON.parse(params.watch_files);
435
- }
436
- catch {
437
- // If not valid JSON, treat as single file path
438
- watchFilesParsed = [params.watch_files];
439
- }
440
- }
441
- else if (Array.isArray(params.watch_files)) {
442
- // Check if it's an array of single characters (MCP SDK bug)
443
- if (params.watch_files.every((item) => typeof item === 'string' && item.length === 1)) {
444
- // Join characters back into string and parse JSON
445
- const jsonString = params.watch_files.join('');
446
- try {
447
- watchFilesParsed = JSON.parse(jsonString);
448
- }
449
- catch {
450
- throw new Error(`Invalid watch_files format: ${jsonString}`);
451
- }
452
- }
453
- else {
454
- // Normal array of file paths
455
- watchFilesParsed = params.watch_files;
456
- }
457
- }
458
- else {
459
- throw new Error('Parameter "watch_files" must be a string or array');
460
- }
461
- for (const filePath of watchFilesParsed) {
462
- const fileId = await getOrCreateFile(actualAdapter, projectId, filePath, trx); // v3.7.3: pass projectId
463
- await trx('t_task_file_links').insert({
464
- project_id: projectId,
465
- task_id: params.task_id,
466
- file_id: fileId
467
- }).onConflict(['project_id', 'task_id', 'file_id']).ignore();
468
- }
469
- // Register files with watcher for auto-tracking
470
- try {
471
- const taskData = await trx('t_tasks as t')
472
- .join('m_task_statuses as s', 't.status_id', 's.id')
473
- .where({ 't.id': params.task_id, 't.project_id': projectId })
474
- .select('t.title', 's.name as status')
475
- .first();
476
- if (taskData) {
477
- const watcher = FileWatcher.getInstance();
478
- for (const filePath of watchFilesParsed) {
479
- watcher.registerFile(filePath, params.task_id, taskData.title, taskData.status);
480
- }
481
- }
482
- }
483
- catch (error) {
484
- // Watcher may not be initialized yet, ignore
485
- debugLog('WARN', 'Could not register files with watcher', { error });
486
- }
487
- }
488
- return {
489
- success: true,
490
- task_id: params.task_id,
491
- message: `Task ${params.task_id} updated successfully`
492
- };
493
- });
494
- });
495
- }
496
- catch (error) {
497
- const message = error instanceof Error ? error.message : String(error);
498
- // Preserve validation errors (they already contain helpful information)
499
- if (message.startsWith('{') && message.includes('"error"')) {
500
- throw error; // Re-throw validation error as-is
501
- }
502
- throw new Error(`Failed to update task: ${message}`);
503
- }
504
- }
505
- /**
506
- * Internal helper: Query task dependencies (used by getTask and getDependencies)
507
- */
508
- async function queryTaskDependencies(adapter, taskId, includeDetails = false) {
509
- const knex = adapter.getKnex();
510
- const projectId = getProjectContext().getProjectId();
511
- // Build query based on include_details flag
512
- const selectFields = includeDetails
513
- ? [
514
- 't.id',
515
- 't.title',
516
- 's.name as status',
517
- 't.priority',
518
- 'aa.name as assigned_to',
519
- 't.created_ts',
520
- 't.updated_ts',
521
- 'td.description'
522
- ]
523
- : [
524
- 't.id',
525
- 't.title',
526
- 's.name as status',
527
- 't.priority'
528
- ];
529
- // Get blockers (tasks that block this task) - with project_id isolation
530
- let blockersQuery = knex('t_tasks as t')
531
- .join('t_task_dependencies as d', 't.id', 'd.blocker_task_id')
532
- .leftJoin('m_task_statuses as s', 't.status_id', 's.id')
533
- .leftJoin('m_agents as aa', 't.assigned_agent_id', 'aa.id')
534
- .where({ 'd.blocked_task_id': taskId, 'd.project_id': projectId, 't.project_id': projectId })
535
- .select(selectFields);
536
- if (includeDetails) {
537
- blockersQuery = blockersQuery
538
- .leftJoin('t_task_details as td', function () {
539
- this.on('t.id', '=', 'td.task_id')
540
- .andOn('t.project_id', '=', 'td.project_id');
541
- });
542
- }
543
- const blockers = await blockersQuery;
544
- // Get blocking (tasks this task blocks) - with project_id isolation
545
- let blockingQuery = knex('t_tasks as t')
546
- .join('t_task_dependencies as d', 't.id', 'd.blocked_task_id')
547
- .leftJoin('m_task_statuses as s', 't.status_id', 's.id')
548
- .leftJoin('m_agents as aa', 't.assigned_agent_id', 'aa.id')
549
- .where({ 'd.blocker_task_id': taskId, 'd.project_id': projectId, 't.project_id': projectId })
550
- .select(selectFields);
551
- if (includeDetails) {
552
- blockingQuery = blockingQuery
553
- .leftJoin('t_task_details as td', function () {
554
- this.on('t.id', '=', 'td.task_id')
555
- .andOn('t.project_id', '=', 'td.project_id');
556
- });
557
- }
558
- const blocking = await blockingQuery;
559
- return { blockers, blocking };
560
- }
561
- /**
562
- * Get full task details
563
- */
564
- export async function getTask(params, adapter) {
565
- validateActionParams('task', 'get', params);
566
- const actualAdapter = adapter ?? getAdapter();
567
- const knex = actualAdapter.getKnex();
568
- if (!params.task_id) {
569
- throw new Error('Parameter "task_id" is required');
570
- }
571
- // Fail-fast project_id validation (Constraint #29)
572
- const projectId = getProjectContext().getProjectId();
573
- try {
574
- // Get task with details (with project_id isolation)
575
- const task = await knex('t_tasks as t')
576
- .leftJoin('m_task_statuses as s', 't.status_id', 's.id')
577
- .leftJoin('m_agents as aa', 't.assigned_agent_id', 'aa.id')
578
- .leftJoin('m_agents as ca', 't.created_by_agent_id', 'ca.id')
579
- .leftJoin('m_layers as l', 't.layer_id', 'l.id')
580
- .leftJoin('t_task_details as td', function () {
581
- this.on('t.id', '=', 'td.task_id')
582
- .andOn('t.project_id', '=', 'td.project_id');
583
- })
584
- .where({ 't.id': params.task_id, 't.project_id': projectId })
585
- .select('t.id', 't.title', 's.name as status', 't.priority', 'aa.name as assigned_to', 'ca.name as created_by', 'l.name as layer', 't.created_ts', 't.updated_ts', 't.completed_ts', 'td.description', 'td.acceptance_criteria', 'td.notes')
586
- .first();
587
- if (!task) {
588
- return {
589
- found: false,
590
- task_id: params.task_id
591
- };
592
- }
593
- // Get tags
594
- const tags = await knex('t_task_tags as tt')
595
- .join('m_tags as tg', 'tt.tag_id', 'tg.id')
596
- .where('tt.task_id', params.task_id)
597
- .select('tg.name')
598
- .then(rows => rows.map((row) => row.name));
599
- // Get decision links
600
- const decisions = await knex('t_task_decision_links as tdl')
601
- .join('m_context_keys as ck', 'tdl.decision_key_id', 'ck.id')
602
- .where('tdl.task_id', params.task_id)
603
- .select('ck.key', 'tdl.link_type');
604
- // Get constraint links
605
- const constraints = await knex('t_task_constraint_links as tcl')
606
- .join('t_constraints as c', 'tcl.constraint_id', 'c.id')
607
- .where('tcl.task_id', params.task_id)
608
- .select('c.id', 'c.constraint_text');
609
- // Get file links
610
- const files = await knex('t_task_file_links as tfl')
611
- .join('m_files as f', 'tfl.file_id', 'f.id')
612
- .where('tfl.task_id', params.task_id)
613
- .select('f.path')
614
- .then(rows => rows.map((row) => row.path));
615
- // Build result
616
- const result = {
617
- found: true,
618
- task: {
619
- ...task,
620
- tags: tags,
621
- linked_decisions: decisions,
622
- linked_constraints: constraints,
623
- linked_files: files
624
- }
625
- };
626
- // Include dependencies if requested (token-efficient, metadata-only)
627
- if (params.include_dependencies) {
628
- const deps = await queryTaskDependencies(actualAdapter, params.task_id, false);
629
- result.task.dependencies = {
630
- blockers: deps.blockers,
631
- blocking: deps.blocking
632
- };
633
- }
634
- return result;
635
- }
636
- catch (error) {
637
- const message = error instanceof Error ? error.message : String(error);
638
- throw new Error(`Failed to get task: ${message}`);
639
- }
640
- }
641
- /**
642
- * List tasks (token-efficient, no descriptions)
643
- */
644
- export async function listTasks(params = {}, adapter) {
645
- validateActionParams('task', 'list', params);
646
- const actualAdapter = adapter ?? getAdapter();
647
- const knex = actualAdapter.getKnex();
648
- // Get current project ID for filtering (Constraint #22)
649
- const projectId = getProjectContext().getProjectId();
650
- try {
651
- // Run auto-stale detection, git-aware completion, and auto-archive before listing
652
- const transitionCount = await detectAndTransitionStaleTasks(actualAdapter);
653
- const gitCompletedCount = await detectAndCompleteReviewedTasks(actualAdapter);
654
- const gitArchivedCount = await detectAndArchiveOnCommit(actualAdapter);
655
- const archiveCount = await autoArchiveOldDoneTasks(actualAdapter);
656
- // Build query with optional dependency counts
657
- let query;
658
- if (params.include_dependency_counts) {
659
- // Include dependency counts with LEFT JOINs
660
- const blockersCTE = knex('t_task_dependencies')
661
- .select('blocked_task_id')
662
- .count('* as blocked_by_count')
663
- .groupBy('blocked_task_id')
664
- .as('blockers');
665
- const blockingCTE = knex('t_task_dependencies')
666
- .select('blocker_task_id')
667
- .count('* as blocking_count')
668
- .groupBy('blocker_task_id')
669
- .as('blocking');
670
- query = knex('v_task_board as vt')
671
- .leftJoin(blockersCTE, 'vt.id', 'blockers.blocked_task_id')
672
- .leftJoin(blockingCTE, 'vt.id', 'blocking.blocker_task_id')
673
- .select('vt.*', knex.raw('COALESCE(blockers.blocked_by_count, 0) as blocked_by_count'), knex.raw('COALESCE(blocking.blocking_count, 0) as blocking_count'));
674
- }
675
- else {
676
- // Standard query without dependency counts
677
- query = knex('v_task_board');
678
- }
679
- // Filter by project_id (Constraint #22: Multi-project isolation)
680
- query = query.where(params.include_dependency_counts ? 'vt.project_id' : 'project_id', projectId);
681
- // Filter by status
682
- if (params.status) {
683
- if (!STATUS_TO_ID[params.status]) {
684
- throw new Error(`Invalid status: ${params.status}. Must be one of: todo, in_progress, waiting_review, blocked, done, archived`);
685
- }
686
- query = query.where(params.include_dependency_counts ? 'vt.status' : 'status', params.status);
687
- }
688
- // Filter by assigned agent
689
- if (params.assigned_agent) {
690
- query = query.where(params.include_dependency_counts ? 'vt.assigned_to' : 'assigned_to', params.assigned_agent);
691
- }
692
- // Filter by layer
693
- if (params.layer) {
694
- query = query.where(params.include_dependency_counts ? 'vt.layer' : 'layer', params.layer);
695
- }
696
- // Filter by tags
697
- if (params.tags && params.tags.length > 0) {
698
- // Parse tags (handles both arrays and JSON strings from MCP)
699
- const tags = parseStringArray(params.tags);
700
- for (const tag of tags) {
701
- query = query.where(params.include_dependency_counts ? 'vt.tags' : 'tags', 'like', `%${tag}%`);
702
- }
703
- }
704
- // Order by updated timestamp (most recent first)
705
- query = query.orderBy(params.include_dependency_counts ? 'vt.updated_ts' : 'updated_ts', 'desc');
706
- // Pagination
707
- const limit = params.limit !== undefined ? params.limit : 50;
708
- const offset = params.offset || 0;
709
- validateRange(limit, 'Parameter "limit"', 0, 100);
710
- validateRange(offset, 'Parameter "offset"', 0, Number.MAX_SAFE_INTEGER);
711
- query = query.limit(limit).offset(offset);
712
- // Execute query
713
- const rows = await query;
714
- return {
715
- tasks: rows,
716
- count: rows.length,
717
- stale_tasks_transitioned: transitionCount,
718
- git_auto_completed: gitCompletedCount,
719
- git_archived: gitArchivedCount,
720
- archived_tasks: archiveCount
721
- };
722
- }
723
- catch (error) {
724
- const message = error instanceof Error ? error.message : String(error);
725
- throw new Error(`Failed to list tasks: ${message}`);
726
- }
727
- }
728
- /**
729
- * Move task to different status
730
- */
731
- export async function moveTask(params, adapter) {
732
- validateActionParams('task', 'move', params);
733
- const actualAdapter = adapter ?? getAdapter();
734
- const knex = actualAdapter.getKnex();
735
- if (!params.task_id) {
736
- throw new Error('Parameter "task_id" is required');
737
- }
738
- if (!params.new_status) {
739
- throw new Error('Parameter "new_status" is required');
740
- }
741
- try {
742
- // Run auto-stale detection and auto-archive before move
743
- await detectAndTransitionStaleTasks(actualAdapter);
744
- await autoArchiveOldDoneTasks(actualAdapter);
745
- return await connectionManager.executeWithRetry(async () => {
746
- return await actualAdapter.transaction(async (trx) => {
747
- // Get current status
748
- const taskRow = await trx('t_tasks')
749
- .where({ id: params.task_id })
750
- .select('status_id')
751
- .first();
752
- if (!taskRow) {
753
- throw new Error(`Task with id ${params.task_id} not found`);
754
- }
755
- const currentStatusId = taskRow.status_id;
756
- const newStatusId = STATUS_TO_ID[params.new_status];
757
- if (!newStatusId) {
758
- throw new Error(`Invalid new_status: ${params.new_status}. Must be one of: todo, in_progress, waiting_review, blocked, done, archived`);
759
- }
760
- // Check if transition is valid
761
- const validNextStatuses = VALID_TRANSITIONS[currentStatusId] || [];
762
- if (!validNextStatuses.includes(newStatusId)) {
763
- throw new Error(`Invalid transition from ${ID_TO_STATUS[currentStatusId]} to ${params.new_status}. ` +
764
- `Valid transitions: ${validNextStatuses.map(id => ID_TO_STATUS[id]).join(', ')}`);
765
- }
766
- // Update status
767
- const updateData = {
768
- status_id: newStatusId
769
- };
770
- // Set completed_ts when moving to done
771
- if (newStatusId === TASK_STATUS.DONE) {
772
- updateData.completed_ts = Math.floor(Date.now() / 1000);
773
- }
774
- await trx('t_tasks')
775
- .where({ id: params.task_id })
776
- .update(updateData);
777
- // Activity logging (replaces trigger)
778
- // Note: Using system agent (id=1) for status changes
779
- // In a real implementation, you'd pass the actual agent_id who made the change
780
- const systemAgentId = 1;
781
- await logTaskStatusChange(trx, {
782
- task_id: params.task_id,
783
- old_status: currentStatusId,
784
- new_status: newStatusId,
785
- agent_id: systemAgentId
786
- });
787
- // Update watcher if moving to done or archived (stop watching)
788
- if (params.new_status === 'done' || params.new_status === 'archived') {
789
- try {
790
- const watcher = FileWatcher.getInstance();
791
- watcher.unregisterTask(params.task_id);
792
- }
793
- catch (error) {
794
- // Watcher may not be initialized, ignore
795
- }
796
- }
797
- return {
798
- success: true,
799
- task_id: params.task_id,
800
- old_status: ID_TO_STATUS[currentStatusId],
801
- new_status: params.new_status,
802
- message: `Task ${params.task_id} moved from ${ID_TO_STATUS[currentStatusId]} to ${params.new_status}`
803
- };
804
- });
805
- });
806
- }
807
- catch (error) {
808
- const message = error instanceof Error ? error.message : String(error);
809
- // Preserve validation errors (they already contain helpful information)
810
- if (message.startsWith('{') && message.includes('"error"')) {
811
- throw error;
812
- }
813
- throw new Error(`Failed to move task: ${message}`);
814
- }
815
- }
816
- /**
817
- * Link task to decision/constraint/file
818
- */
819
- export async function linkTask(params, adapter) {
820
- validateActionParams('task', 'link', params);
821
- const actualAdapter = adapter ?? getAdapter();
822
- const knex = actualAdapter.getKnex();
823
- // Get project context (v3.7.3)
824
- const projectId = getProjectContext().getProjectId();
825
- if (!params.task_id) {
826
- throw new Error('Parameter "task_id" is required');
827
- }
828
- if (!params.link_type) {
829
- throw new Error('Parameter "link_type" is required');
830
- }
831
- if (params.target_id === undefined || params.target_id === null) {
832
- throw new Error('Parameter "target_id" is required');
833
- }
834
- try {
835
- return await connectionManager.executeWithRetry(async () => {
836
- return await actualAdapter.transaction(async (trx) => {
837
- // Check if task exists
838
- const taskExists = await trx('t_tasks').where({ id: params.task_id }).first();
839
- if (!taskExists) {
840
- throw new Error(`Task with id ${params.task_id} not found`);
841
- }
842
- if (params.link_type === 'decision') {
843
- const decisionKey = String(params.target_id);
844
- const keyId = await getOrCreateContextKey(actualAdapter, decisionKey, trx);
845
- const linkRelation = params.link_relation || 'implements';
846
- await trx('t_task_decision_links').insert({
847
- task_id: params.task_id,
848
- decision_key_id: keyId,
849
- link_type: linkRelation
850
- }).onConflict(['task_id', 'decision_key_id']).merge();
851
- return {
852
- success: true,
853
- task_id: params.task_id,
854
- linked_to: 'decision',
855
- target: decisionKey,
856
- relation: linkRelation,
857
- message: `Task ${params.task_id} linked to decision "${decisionKey}"`
858
- };
859
- }
860
- else if (params.link_type === 'constraint') {
861
- const constraintId = Number(params.target_id);
862
- // Check if constraint exists
863
- const constraintExists = await trx('t_constraints').where({ id: constraintId }).first();
864
- if (!constraintExists) {
865
- throw new Error(`Constraint with id ${constraintId} not found`);
866
- }
867
- await trx('t_task_constraint_links').insert({
868
- task_id: params.task_id,
869
- constraint_id: constraintId
870
- }).onConflict(['task_id', 'constraint_id']).ignore();
871
- return {
872
- success: true,
873
- task_id: params.task_id,
874
- linked_to: 'constraint',
875
- target: constraintId,
876
- message: `Task ${params.task_id} linked to constraint ${constraintId}`
877
- };
878
- }
879
- else if (params.link_type === 'file') {
880
- // Deprecation warning (v3.4.1)
881
- debugLog('WARN', `DEPRECATION: task.link(link_type="file") is deprecated as of v3.4.1. Use task.create(watch_files=[...]) or task.update(watch_files=[...]) instead. Or use the new watch_files action: { action: "watch_files", task_id: ${params.task_id}, file_paths: ["..."] }`);
882
- const filePath = String(params.target_id);
883
- const fileId = await getOrCreateFile(actualAdapter, projectId, filePath, trx); // v3.7.3: pass projectId
884
- await trx('t_task_file_links').insert({
885
- task_id: params.task_id,
886
- file_id: fileId
887
- }).onConflict(['task_id', 'file_id']).ignore();
888
- // Register file with watcher for auto-tracking
889
- try {
890
- const taskData = await trx('t_tasks as t')
891
- .join('m_task_statuses as s', 't.status_id', 's.id')
892
- .where('t.id', params.task_id)
893
- .select('t.title', 's.name as status')
894
- .first();
895
- if (taskData) {
896
- const watcher = FileWatcher.getInstance();
897
- watcher.registerFile(filePath, params.task_id, taskData.title, taskData.status);
898
- }
899
- }
900
- catch (error) {
901
- // Watcher may not be initialized yet, ignore
902
- debugLog('WARN', 'Could not register file with watcher', { error });
903
- }
904
- return {
905
- success: true,
906
- task_id: params.task_id,
907
- linked_to: 'file',
908
- target: filePath,
909
- deprecation_warning: 'task.link(link_type="file") is deprecated. Use task.create/update(watch_files) or watch_files action instead.',
910
- message: `Task ${params.task_id} linked to file "${filePath}" (DEPRECATED API - use watch_files instead)`
911
- };
912
- }
913
- else {
914
- throw new Error(`Invalid link_type: ${params.link_type}. Must be one of: decision, constraint, file`);
915
- }
916
- });
917
- });
918
- }
919
- catch (error) {
920
- const message = error instanceof Error ? error.message : String(error);
921
- throw new Error(`Failed to link task: ${message}`);
922
- }
923
- }
924
- /**
925
- * Archive completed task
926
- */
927
- export async function archiveTask(params, adapter) {
928
- validateActionParams('task', 'archive', params);
929
- const actualAdapter = adapter ?? getAdapter();
930
- const knex = actualAdapter.getKnex();
931
- if (!params.task_id) {
932
- throw new Error('Parameter "task_id" is required');
933
- }
934
- try {
935
- return await connectionManager.executeWithRetry(async () => {
936
- return await actualAdapter.transaction(async (trx) => {
937
- // Check if task is in 'done' status
938
- const taskRow = await trx('t_tasks')
939
- .where({ id: params.task_id })
940
- .select('status_id')
941
- .first();
942
- if (!taskRow) {
943
- throw new Error(`Task with id ${params.task_id} not found`);
944
- }
945
- if (taskRow.status_id !== TASK_STATUS.DONE) {
946
- throw new Error(`Task ${params.task_id} must be in 'done' status to archive (current: ${ID_TO_STATUS[taskRow.status_id]})`);
947
- }
948
- // Update to archived
949
- await trx('t_tasks')
950
- .where({ id: params.task_id })
951
- .update({ status_id: TASK_STATUS.ARCHIVED });
952
- // Activity logging
953
- // Note: Using system agent (id=1) for status changes
954
- const systemAgentId = 1;
955
- await logTaskStatusChange(trx, {
956
- task_id: params.task_id,
957
- old_status: TASK_STATUS.DONE,
958
- new_status: TASK_STATUS.ARCHIVED,
959
- agent_id: systemAgentId
960
- });
961
- // Unregister from file watcher (archived tasks don't need tracking)
962
- try {
963
- const watcher = FileWatcher.getInstance();
964
- watcher.unregisterTask(params.task_id);
965
- }
966
- catch (error) {
967
- // Watcher may not be initialized, ignore
968
- }
969
- return {
970
- success: true,
971
- task_id: params.task_id,
972
- message: `Task ${params.task_id} archived successfully`
973
- };
974
- });
975
- });
976
- }
977
- catch (error) {
978
- const message = error instanceof Error ? error.message : String(error);
979
- throw new Error(`Failed to archive task: ${message}`);
980
- }
981
- }
982
- /**
983
- * Add dependency (blocking relationship) between tasks
984
- */
985
- export async function addDependency(params, adapter) {
986
- validateActionParams('task', 'add_dependency', params);
987
- const actualAdapter = adapter ?? getAdapter();
988
- const knex = actualAdapter.getKnex();
989
- if (!params.blocker_task_id) {
990
- throw new Error('Parameter "blocker_task_id" is required');
991
- }
992
- if (!params.blocked_task_id) {
993
- throw new Error('Parameter "blocked_task_id" is required');
994
- }
995
- try {
996
- return await connectionManager.executeWithRetry(async () => {
997
- return await actualAdapter.transaction(async (trx) => {
998
- // Validation 1: No self-dependencies
999
- if (params.blocker_task_id === params.blocked_task_id) {
1000
- throw new Error('Self-dependency not allowed');
1001
- }
1002
- // Validation 2: Both tasks must exist and check if archived
1003
- const blockerTask = await trx('t_tasks')
1004
- .where({ id: params.blocker_task_id })
1005
- .select('id', 'status_id')
1006
- .first();
1007
- const blockedTask = await trx('t_tasks')
1008
- .where({ id: params.blocked_task_id })
1009
- .select('id', 'status_id')
1010
- .first();
1011
- if (!blockerTask) {
1012
- throw new Error(`Blocker task #${params.blocker_task_id} not found`);
1013
- }
1014
- if (!blockedTask) {
1015
- throw new Error(`Blocked task #${params.blocked_task_id} not found`);
1016
- }
1017
- // Validation 3: Neither task is archived
1018
- if (blockerTask.status_id === TASK_STATUS.ARCHIVED) {
1019
- throw new Error(`Cannot add dependency: Task #${params.blocker_task_id} is archived`);
1020
- }
1021
- if (blockedTask.status_id === TASK_STATUS.ARCHIVED) {
1022
- throw new Error(`Cannot add dependency: Task #${params.blocked_task_id} is archived`);
1023
- }
1024
- // Validation 4: No direct circular (reverse relationship)
1025
- const reverseExists = await trx('t_task_dependencies')
1026
- .where({
1027
- blocker_task_id: params.blocked_task_id,
1028
- blocked_task_id: params.blocker_task_id
1029
- })
1030
- .first();
1031
- if (reverseExists) {
1032
- throw new Error(`Circular dependency detected: Task #${params.blocked_task_id} already blocks Task #${params.blocker_task_id}`);
1033
- }
1034
- // Validation 5: No transitive circular (check if adding this would create a cycle)
1035
- const cycleCheck = await trx.raw(`
1036
- WITH RECURSIVE dependency_chain AS (
1037
- -- Start from the task that would be blocked
1038
- SELECT blocked_task_id as task_id, 1 as depth
1039
- FROM t_task_dependencies
1040
- WHERE blocker_task_id = ?
1041
-
1042
- UNION ALL
1043
-
1044
- -- Follow the chain of dependencies
1045
- SELECT d.blocked_task_id, dc.depth + 1
1046
- FROM t_task_dependencies d
1047
- JOIN dependency_chain dc ON d.blocker_task_id = dc.task_id
1048
- WHERE dc.depth < 100
1049
- )
1050
- SELECT task_id FROM dependency_chain WHERE task_id = ?
1051
- `, [params.blocked_task_id, params.blocker_task_id])
1052
- .then((result) => result[0]);
1053
- if (cycleCheck) {
1054
- // Build cycle path for error message
1055
- const cyclePathResult = await trx.raw(`
1056
- WITH RECURSIVE dependency_chain AS (
1057
- SELECT blocked_task_id as task_id, 1 as depth,
1058
- CAST(blocked_task_id AS TEXT) as path
1059
- FROM t_task_dependencies
1060
- WHERE blocker_task_id = ?
1061
-
1062
- UNION ALL
1063
-
1064
- SELECT d.blocked_task_id, dc.depth + 1,
1065
- dc.path || ' → ' || d.blocked_task_id
1066
- FROM t_task_dependencies d
1067
- JOIN dependency_chain dc ON d.blocker_task_id = dc.task_id
1068
- WHERE dc.depth < 100
1069
- )
1070
- SELECT path FROM dependency_chain WHERE task_id = ? ORDER BY depth DESC LIMIT 1
1071
- `, [params.blocked_task_id, params.blocker_task_id])
1072
- .then((result) => result[0]);
1073
- const cyclePath = cyclePathResult?.path || `#${params.blocked_task_id} → ... → #${params.blocker_task_id}`;
1074
- throw new Error(`Circular dependency detected: Task #${params.blocker_task_id} → #${cyclePath} → #${params.blocker_task_id}`);
1075
- }
1076
- // All validations passed - insert dependency
1077
- await trx('t_task_dependencies').insert({
1078
- blocker_task_id: params.blocker_task_id,
1079
- blocked_task_id: params.blocked_task_id,
1080
- created_ts: Math.floor(Date.now() / 1000)
1081
- });
1082
- return {
1083
- success: true,
1084
- message: `Dependency added: Task #${params.blocker_task_id} blocks Task #${params.blocked_task_id}`
1085
- };
1086
- });
1087
- });
1088
- }
1089
- catch (error) {
1090
- const message = error instanceof Error ? error.message : String(error);
1091
- // Don't wrap error messages that are already descriptive
1092
- if (message.includes('not found') || message.includes('not allowed') || message.includes('Circular dependency') || message.includes('Cannot add dependency')) {
1093
- throw new Error(message);
1094
- }
1095
- throw new Error(`Failed to add dependency: ${message}`);
1096
- }
1097
- }
1098
- /**
1099
- * Remove dependency between tasks
1100
- */
1101
- export async function removeDependency(params, adapter) {
1102
- validateActionParams('task', 'remove_dependency', params);
1103
- const actualAdapter = adapter ?? getAdapter();
1104
- const knex = actualAdapter.getKnex();
1105
- if (!params.blocker_task_id) {
1106
- throw new Error('Parameter "blocker_task_id" is required');
1107
- }
1108
- if (!params.blocked_task_id) {
1109
- throw new Error('Parameter "blocked_task_id" is required');
1110
- }
1111
- try {
1112
- await knex('t_task_dependencies')
1113
- .where({
1114
- blocker_task_id: params.blocker_task_id,
1115
- blocked_task_id: params.blocked_task_id
1116
- })
1117
- .delete();
1118
- return {
1119
- success: true,
1120
- message: `Dependency removed: Task #${params.blocker_task_id} no longer blocks Task #${params.blocked_task_id}`
1121
- };
1122
- }
1123
- catch (error) {
1124
- const message = error instanceof Error ? error.message : String(error);
1125
- throw new Error(`Failed to remove dependency: ${message}`);
1126
- }
1127
- }
1128
- /**
1129
- * Get dependencies for a task (bidirectional: what blocks this task, what this task blocks)
1130
- */
1131
- export async function getDependencies(params, adapter) {
1132
- validateActionParams('task', 'get_dependencies', params);
1133
- const actualAdapter = adapter ?? getAdapter();
1134
- const knex = actualAdapter.getKnex();
1135
- if (!params.task_id) {
1136
- throw new Error('Parameter "task_id" is required');
1137
- }
1138
- const includeDetails = params.include_details || false;
1139
- try {
1140
- // Check if task exists
1141
- const taskExists = await knex('t_tasks').where({ id: params.task_id }).first();
1142
- if (!taskExists) {
1143
- throw new Error(`Task with id ${params.task_id} not found`);
1144
- }
1145
- // Use the shared helper function
1146
- const deps = await queryTaskDependencies(actualAdapter, params.task_id, includeDetails);
1147
- return {
1148
- task_id: params.task_id,
1149
- blockers: deps.blockers,
1150
- blocking: deps.blocking
1151
- };
1152
- }
1153
- catch (error) {
1154
- const message = error instanceof Error ? error.message : String(error);
1155
- // Don't wrap error messages that are already descriptive
1156
- if (message.includes('not found')) {
1157
- throw new Error(message);
1158
- }
1159
- throw new Error(`Failed to get dependencies: ${message}`);
1160
- }
1161
- }
1162
- /**
1163
- * Create multiple tasks atomically
1164
- */
1165
- export async function batchCreateTasks(params, adapter) {
1166
- validateBatchParams('task', 'tasks', params.tasks, 'create', 50);
1167
- const actualAdapter = adapter ?? getAdapter();
1168
- if (!params.tasks || !Array.isArray(params.tasks)) {
1169
- throw new Error('Parameter "tasks" is required and must be an array');
1170
- }
1171
- if (params.tasks.length > 50) {
1172
- throw new Error('Parameter "tasks" must contain at most 50 items');
1173
- }
1174
- const atomic = params.atomic !== undefined ? params.atomic : true;
1175
- try {
1176
- if (atomic) {
1177
- // Atomic mode: All or nothing
1178
- const results = await connectionManager.executeWithRetry(async () => {
1179
- return await actualAdapter.transaction(async (trx) => {
1180
- const processedResults = [];
1181
- for (const task of params.tasks) {
1182
- try {
1183
- const result = await createTaskInternal(task, actualAdapter, trx);
1184
- processedResults.push({
1185
- title: task.title,
1186
- task_id: result.task_id,
1187
- success: true,
1188
- error: undefined
1189
- });
1190
- }
1191
- catch (error) {
1192
- const errorMessage = error instanceof Error ? error.message : String(error);
1193
- throw new Error(`Batch failed at task "${task.title}": ${errorMessage}`);
1194
- }
1195
- }
1196
- return processedResults;
1197
- });
1198
- });
1199
- return {
1200
- success: true,
1201
- created: results.length,
1202
- failed: 0,
1203
- results: results
1204
- };
1205
- }
1206
- else {
1207
- // Non-atomic mode: Process each independently
1208
- const results = [];
1209
- let created = 0;
1210
- let failed = 0;
1211
- for (const task of params.tasks) {
1212
- try {
1213
- const result = await connectionManager.executeWithRetry(async () => {
1214
- return await actualAdapter.transaction(async (trx) => {
1215
- return await createTaskInternal(task, actualAdapter, trx);
1216
- });
1217
- });
1218
- results.push({
1219
- title: task.title,
1220
- task_id: result.task_id,
1221
- success: true,
1222
- error: undefined
1223
- });
1224
- created++;
1225
- }
1226
- catch (error) {
1227
- const errorMessage = error instanceof Error ? error.message : String(error);
1228
- results.push({
1229
- title: task.title,
1230
- task_id: undefined,
1231
- success: false,
1232
- error: errorMessage
1233
- });
1234
- failed++;
1235
- }
1236
- }
1237
- return {
1238
- success: failed === 0,
1239
- created: created,
1240
- failed: failed,
1241
- results: results
1242
- };
1243
- }
1244
- }
1245
- catch (error) {
1246
- const message = error instanceof Error ? error.message : String(error);
1247
- throw new Error(`Failed to execute batch operation: ${message}`);
1248
- }
1249
- }
1250
- /**
1251
- * Watch/unwatch files for a task (v3.4.1)
1252
- * Replaces the need to use task.link(file) for file watching
1253
- */
1254
- export async function watchFiles(params, adapter) {
1255
- validateActionParams('task', 'watch_files', params);
1256
- const actualAdapter = adapter ?? getAdapter();
1257
- const knex = actualAdapter.getKnex();
1258
- const projectId = getProjectContext().getProjectId();
1259
- if (!params.task_id) {
1260
- throw new Error('Parameter "task_id" is required');
1261
- }
1262
- if (!params.action) {
1263
- throw new Error('Parameter "action" is required (watch, unwatch, or list)');
1264
- }
1265
- try {
1266
- return await connectionManager.executeWithRetry(async () => {
1267
- return await actualAdapter.transaction(async (trx) => {
1268
- // Check if task exists (project-scoped)
1269
- const taskData = await trx('t_tasks as t')
1270
- .join('m_task_statuses as s', 't.status_id', 's.id')
1271
- .where({ 't.id': params.task_id, 't.project_id': projectId })
1272
- .select('t.id', 't.title', 's.name as status')
1273
- .first();
1274
- if (!taskData) {
1275
- throw new Error(`Task with id ${params.task_id} not found`);
1276
- }
1277
- if (params.action === 'watch') {
1278
- if (!params.file_paths || params.file_paths.length === 0) {
1279
- throw new Error('Parameter "file_paths" is required for watch action');
1280
- }
1281
- const addedFiles = [];
1282
- for (const filePath of params.file_paths) {
1283
- const fileId = await getOrCreateFile(actualAdapter, projectId, filePath, trx); // v3.7.3: pass projectId
1284
- // Check if already exists
1285
- const existing = await trx('t_task_file_links')
1286
- .where({ task_id: params.task_id, file_id: fileId })
1287
- .first();
1288
- if (!existing) {
1289
- await trx('t_task_file_links').insert({
1290
- task_id: params.task_id,
1291
- file_id: fileId
1292
- });
1293
- addedFiles.push(filePath);
1294
- }
1295
- }
1296
- // Register files with watcher
1297
- try {
1298
- const watcher = FileWatcher.getInstance();
1299
- for (const filePath of addedFiles) {
1300
- watcher.registerFile(filePath, params.task_id, taskData.title, taskData.status);
1301
- }
1302
- }
1303
- catch (error) {
1304
- // Watcher may not be initialized yet, ignore
1305
- debugLog('WARN', 'Could not register files with watcher', { error });
1306
- }
1307
- return {
1308
- success: true,
1309
- task_id: params.task_id,
1310
- action: 'watch',
1311
- files_added: addedFiles.length,
1312
- files: addedFiles,
1313
- message: `Watching ${addedFiles.length} file(s) for task ${params.task_id}`
1314
- };
1315
- }
1316
- else if (params.action === 'unwatch') {
1317
- if (!params.file_paths || params.file_paths.length === 0) {
1318
- throw new Error('Parameter "file_paths" is required for unwatch action');
1319
- }
1320
- const removedFiles = [];
1321
- for (const filePath of params.file_paths) {
1322
- const deleted = await trx('t_task_file_links')
1323
- .where('task_id', params.task_id)
1324
- .whereIn('file_id', function () {
1325
- this.select('id').from('m_files').where({ path: filePath });
1326
- })
1327
- .delete();
1328
- if (deleted > 0) {
1329
- removedFiles.push(filePath);
1330
- }
1331
- }
1332
- return {
1333
- success: true,
1334
- task_id: params.task_id,
1335
- action: 'unwatch',
1336
- files_removed: removedFiles.length,
1337
- files: removedFiles,
1338
- message: `Stopped watching ${removedFiles.length} file(s) for task ${params.task_id}`
1339
- };
1340
- }
1341
- else if (params.action === 'list') {
1342
- const files = await trx('t_task_file_links as tfl')
1343
- .join('m_files as f', 'tfl.file_id', 'f.id')
1344
- .where('tfl.task_id', params.task_id)
1345
- .select('f.path')
1346
- .then(rows => rows.map((row) => row.path));
1347
- return {
1348
- success: true,
1349
- task_id: params.task_id,
1350
- action: 'list',
1351
- files_count: files.length,
1352
- files: files,
1353
- message: `Task ${params.task_id} is watching ${files.length} file(s)`
1354
- };
1355
- }
1356
- else {
1357
- throw new Error(`Invalid action: ${params.action}. Must be one of: watch, unwatch, list`);
1358
- }
1359
- });
1360
- });
1361
- }
1362
- catch (error) {
1363
- const message = error instanceof Error ? error.message : String(error);
1364
- throw new Error(`Failed to ${params.action} files: ${message}`);
1365
- }
1366
- }
1367
- /**
1368
- * Get pruned files for a task (v3.5.0 Auto-Pruning)
1369
- * Returns audit trail of files that were auto-pruned as non-existent
1370
- */
1371
- export async function getPrunedFiles(params, adapter) {
1372
- const actualAdapter = adapter ?? getAdapter();
1373
- const knex = actualAdapter.getKnex();
1374
- try {
1375
- // Validate task_id
1376
- if (!params.task_id || typeof params.task_id !== 'number') {
1377
- throw new Error('task_id is required and must be a number');
1378
- }
1379
- // Validate task exists
1380
- const task = await knex('t_tasks').where({ id: params.task_id }).first();
1381
- if (!task) {
1382
- throw new Error(`Task not found: ${params.task_id}`);
1383
- }
1384
- // Get pruned files
1385
- const limit = params.limit || 100;
1386
- const rows = await knex('t_task_pruned_files as tpf')
1387
- .leftJoin('m_context_keys as k', 'tpf.linked_decision_key_id', 'k.id')
1388
- .where('tpf.task_id', params.task_id)
1389
- .select('tpf.id', 'tpf.file_path', knex.raw(`datetime(tpf.pruned_ts, 'unixepoch') as pruned_at`), 'k.key as linked_decision')
1390
- .orderBy('tpf.pruned_ts', 'desc')
1391
- .limit(limit);
1392
- return {
1393
- success: true,
1394
- task_id: params.task_id,
1395
- pruned_files: rows,
1396
- count: rows.length,
1397
- message: rows.length > 0
1398
- ? `Found ${rows.length} pruned file(s) for task ${params.task_id}`
1399
- : `No pruned files for task ${params.task_id}`
1400
- };
1401
- }
1402
- catch (error) {
1403
- const message = error instanceof Error ? error.message : String(error);
1404
- throw new Error(`Failed to get pruned files: ${message}`);
1405
- }
1406
- }
1407
- /**
1408
- * Link a pruned file to a decision (v3.5.0 Auto-Pruning)
1409
- * Attaches WHY reasoning to pruned files for project archaeology
1410
- */
1411
- export async function linkPrunedFile(params, adapter) {
1412
- const actualAdapter = adapter ?? getAdapter();
1413
- const knex = actualAdapter.getKnex();
1414
- try {
1415
- // Validate pruned_file_id
1416
- if (!params.pruned_file_id || typeof params.pruned_file_id !== 'number') {
1417
- throw new Error('pruned_file_id is required and must be a number');
1418
- }
1419
- // Validate decision_key
1420
- if (!params.decision_key || typeof params.decision_key !== 'string') {
1421
- throw new Error('decision_key is required and must be a string');
1422
- }
1423
- // Get decision key_id
1424
- const decision = await knex('m_context_keys as k')
1425
- .whereExists(function () {
1426
- this.select('*')
1427
- .from('t_decisions as d')
1428
- .whereRaw('d.key_id = k.id');
1429
- })
1430
- .where('k.key', params.decision_key)
1431
- .select('k.id as key_id')
1432
- .first();
1433
- if (!decision) {
1434
- throw new Error(`Decision not found: ${params.decision_key}`);
1435
- }
1436
- // Check if pruned file exists
1437
- const prunedFile = await knex('t_task_pruned_files')
1438
- .where({ id: params.pruned_file_id })
1439
- .select('id', 'task_id', 'file_path')
1440
- .first();
1441
- if (!prunedFile) {
1442
- throw new Error(`Pruned file record not found: ${params.pruned_file_id}`);
1443
- }
1444
- // Update the link
1445
- const updated = await knex('t_task_pruned_files')
1446
- .where({ id: params.pruned_file_id })
1447
- .update({ linked_decision_key_id: decision.key_id });
1448
- if (updated === 0) {
1449
- throw new Error(`Failed to link pruned file #${params.pruned_file_id} to decision ${params.decision_key}`);
1450
- }
1451
- return {
1452
- success: true,
1453
- pruned_file_id: params.pruned_file_id,
1454
- decision_key: params.decision_key,
1455
- task_id: prunedFile.task_id,
1456
- file_path: prunedFile.file_path,
1457
- message: `Linked pruned file "${prunedFile.file_path}" to decision "${params.decision_key}"`
1458
- };
1459
- }
1460
- catch (error) {
1461
- const message = error instanceof Error ? error.message : String(error);
1462
- throw new Error(`Failed to link pruned file: ${message}`);
1463
- }
1464
- }
1465
- /**
1466
- * Return comprehensive help documentation
1467
- */
1468
- export function taskHelp() {
1469
- return {
1470
- tool: 'task',
1471
- description: 'Kanban Task Watcher for managing tasks with AI-optimized lifecycle states',
1472
- note: '💡 TIP: Use action: "example" to see comprehensive usage scenarios and real-world examples for all task actions.',
1473
- important: '🚨 AUTOMATIC FILE WATCHING: Linking files to tasks activates automatic file change monitoring and acceptance criteria validation. You can save 300 tokens per file compared to registering watchers manually. See auto_file_tracking section below.',
1474
- actions: {
1475
- create: {
1476
- description: 'Create a new task',
1477
- required_params: ['title'],
1478
- optional_params: ['description', 'acceptance_criteria', 'notes', 'priority', 'assigned_agent', 'created_by_agent', 'layer', 'tags', 'status', 'watch_files'],
1479
- watch_files_param: '⭐ NEW in v3.4.1: Pass watch_files array to automatically link and watch files (replaces task.link(file))',
1480
- example: {
1481
- action: 'create',
1482
- title: 'Implement authentication endpoint',
1483
- description: 'Add JWT-based authentication to /api/login',
1484
- priority: 3,
1485
- assigned_agent: 'backend-agent',
1486
- layer: 'presentation',
1487
- tags: ['api', 'authentication'],
1488
- watch_files: ['src/api/auth.ts', 'src/middleware/jwt.ts']
1489
- }
1490
- },
1491
- update: {
1492
- description: 'Update task metadata',
1493
- required_params: ['task_id'],
1494
- optional_params: ['title', 'priority', 'assigned_agent', 'layer', 'description', 'acceptance_criteria', 'notes', 'watch_files'],
1495
- watch_files_param: '⭐ NEW in v3.4.1: Pass watch_files array to add files to watch list',
1496
- example: {
1497
- action: 'update',
1498
- task_id: 5,
1499
- priority: 4,
1500
- assigned_agent: 'senior-backend-agent',
1501
- watch_files: ['src/api/users.ts']
1502
- }
1503
- },
1504
- get: {
1505
- description: 'Get full task details including descriptions and links',
1506
- required_params: ['task_id'],
1507
- example: {
1508
- action: 'get',
1509
- task_id: 5
1510
- }
1511
- },
1512
- list: {
1513
- description: 'List tasks (token-efficient, no descriptions)',
1514
- required_params: [],
1515
- optional_params: ['status', 'assigned_agent', 'layer', 'tags', 'limit', 'offset'],
1516
- example: {
1517
- action: 'list',
1518
- status: 'in_progress',
1519
- assigned_agent: 'backend-agent',
1520
- limit: 20
1521
- }
1522
- },
1523
- move: {
1524
- description: 'Move task to different status with validation',
1525
- required_params: ['task_id', 'new_status'],
1526
- valid_statuses: ['todo', 'in_progress', 'waiting_review', 'blocked', 'done', 'archived'],
1527
- transitions: {
1528
- todo: ['in_progress', 'blocked'],
1529
- in_progress: ['waiting_review', 'blocked', 'done'],
1530
- waiting_review: ['in_progress', 'todo', 'done'],
1531
- blocked: ['todo', 'in_progress'],
1532
- done: ['archived'],
1533
- archived: []
1534
- },
1535
- example: {
1536
- action: 'move',
1537
- task_id: 5,
1538
- new_status: 'in_progress'
1539
- }
1540
- },
1541
- link: {
1542
- description: 'Link task to decision/constraint/file',
1543
- required_params: ['task_id', 'link_type', 'target_id'],
1544
- optional_params: ['link_relation'],
1545
- link_types: ['decision', 'constraint', 'file'],
1546
- file_linking_behavior: '⚠️ DEPRECATED in v3.4.1: link_type="file" is deprecated. Use watch_files action or watch_files parameter instead.',
1547
- deprecation_note: 'For file watching, use: (1) watch_files parameter in create/update, or (2) watch_files action with watch/unwatch/list',
1548
- example: {
1549
- action: 'link',
1550
- task_id: 5,
1551
- link_type: 'decision',
1552
- target_id: 'auth_method',
1553
- link_relation: 'implements'
1554
- }
1555
- },
1556
- watch_files: {
1557
- description: '⭐ NEW in v3.4.1: Watch/unwatch files for a task (replaces task.link(file))',
1558
- required_params: ['task_id', 'action'],
1559
- optional_params: ['file_paths'],
1560
- actions: ['watch', 'unwatch', 'list'],
1561
- behavior: {
1562
- watch: 'Add files to watch list and activate file monitoring',
1563
- unwatch: 'Remove files from watch list',
1564
- list: 'List all files currently watched by this task'
1565
- },
1566
- examples: {
1567
- watch: {
1568
- task_id: 5,
1569
- action: 'watch',
1570
- file_paths: ['src/api/auth.ts', 'src/middleware/jwt.ts']
1571
- },
1572
- unwatch: {
1573
- task_id: 5,
1574
- action: 'unwatch',
1575
- file_paths: ['src/middleware/jwt.ts']
1576
- },
1577
- list: {
1578
- task_id: 5,
1579
- action: 'list'
1580
- }
1581
- },
1582
- note: 'Preferred over task.link(file) for better clarity and batch operations'
1583
- },
1584
- archive: {
1585
- description: 'Archive completed task (must be in done status)',
1586
- required_params: ['task_id'],
1587
- example: {
1588
- action: 'archive',
1589
- task_id: 5
1590
- }
1591
- },
1592
- batch_create: {
1593
- description: 'Create multiple tasks atomically',
1594
- required_params: ['tasks'],
1595
- optional_params: ['atomic'],
1596
- limits: {
1597
- max_items: 50
1598
- },
1599
- note: '⚠️ IMPORTANT: The "tasks" parameter must be a JavaScript array, not a JSON string. MCP tools require pre-parsed objects.',
1600
- example: {
1601
- action: 'batch_create',
1602
- tasks: [
1603
- { title: 'Task 1', priority: 2 },
1604
- { title: 'Task 2', priority: 3, layer: 'business' }
1605
- ],
1606
- atomic: true
1607
- }
1608
- },
1609
- add_dependency: {
1610
- description: 'Add blocking relationship between tasks',
1611
- required_params: ['blocker_task_id', 'blocked_task_id'],
1612
- validations: [
1613
- 'No self-dependencies',
1614
- 'No circular dependencies (direct or transitive)',
1615
- 'Both tasks must exist',
1616
- 'Neither task can be archived'
1617
- ],
1618
- example: {
1619
- action: 'add_dependency',
1620
- blocker_task_id: 1,
1621
- blocked_task_id: 2
1622
- },
1623
- note: 'Task #1 must be completed before Task #2 can start'
1624
- },
1625
- remove_dependency: {
1626
- description: 'Remove blocking relationship between tasks',
1627
- required_params: ['blocker_task_id', 'blocked_task_id'],
1628
- example: {
1629
- action: 'remove_dependency',
1630
- blocker_task_id: 1,
1631
- blocked_task_id: 2
1632
- },
1633
- note: 'Silently succeeds even if dependency does not exist'
1634
- },
1635
- get_dependencies: {
1636
- description: 'Query task dependencies (bidirectional)',
1637
- required_params: ['task_id'],
1638
- optional_params: ['include_details'],
1639
- returns: {
1640
- blockers: 'Array of tasks that block this task',
1641
- blocking: 'Array of tasks this task blocks'
1642
- },
1643
- example: {
1644
- action: 'get_dependencies',
1645
- task_id: 2,
1646
- include_details: true
1647
- },
1648
- note: 'Defaults to metadata-only (token-efficient). Set include_details=true for full task details.'
1649
- },
1650
- watcher: {
1651
- description: 'Query file watcher status and monitored files/tasks',
1652
- required_params: [],
1653
- optional_params: ['subaction'],
1654
- subactions: ['status', 'list_files', 'list_tasks', 'help'],
1655
- default_subaction: 'status',
1656
- examples: {
1657
- status: {
1658
- action: 'watcher',
1659
- subaction: 'status'
1660
- },
1661
- list_files: {
1662
- action: 'watcher',
1663
- subaction: 'list_files'
1664
- },
1665
- list_tasks: {
1666
- action: 'watcher',
1667
- subaction: 'list_tasks'
1668
- }
1669
- },
1670
- note: 'Use to monitor which files/tasks are being watched. File watching activates automatically when you link files to tasks.'
1671
- },
1672
- help: {
1673
- description: 'Return this help documentation',
1674
- example: { action: 'help' }
1675
- }
1676
- },
1677
- auto_stale_detection: {
1678
- description: 'Tasks automatically transition when abandoned',
1679
- behavior: {
1680
- in_progress: 'Untouched for >2 hours → waiting_review',
1681
- waiting_review: 'Untouched for >24 hours → todo'
1682
- },
1683
- config_keys: {
1684
- task_stale_hours_in_progress: 'Hours before in_progress tasks go stale (default: 2)',
1685
- task_stale_hours_waiting_review: 'Hours before waiting_review tasks go stale (default: 24)',
1686
- task_auto_stale_enabled: 'Enable/disable auto-stale detection (default: true)'
1687
- }
1688
- },
1689
- priority_levels: {
1690
- 1: 'low',
1691
- 2: 'medium (default)',
1692
- 3: 'high',
1693
- 4: 'critical'
1694
- },
1695
- auto_file_tracking: {
1696
- description: 'Automatic file watching and acceptance criteria validation - save 300 tokens per file vs manual registration',
1697
- recommendation: '⭐ BEST PRACTICE: Except in exceptional cases, it is recommended to set up file watchers for all tasks that involve code changes. This provides automatic status tracking with zero token overhead.',
1698
- how_it_works: [
1699
- '1. Link files to tasks using the link action with link_type="file"',
1700
- '2. File watcher automatically activates and monitors linked files',
1701
- '3. When files are saved, watcher detects changes',
1702
- '4. If task has acceptance_criteria, watcher validates criteria against changes',
1703
- '5. Results appear in terminal output with pass/fail status'
1704
- ],
1705
- requirements: [
1706
- 'Task must have files linked via link action',
1707
- 'File paths must be relative to project root (e.g., "src/api/auth.ts")',
1708
- 'Watcher only monitors files explicitly linked to tasks'
1709
- ],
1710
- token_efficiency: 'File watching happens in background. No MCP tokens consumed until you query status. Manual file tracking would cost ~500-1000 tokens per file check.',
1711
- documentation_reference: 'docs/AUTO_FILE_TRACKING.md - Complete guide with examples'
1712
- },
1713
- documentation: {
1714
- task_overview: 'docs/TASK_OVERVIEW.md - Lifecycle, status transitions, auto-stale detection (363 lines, ~10k tokens)',
1715
- task_actions: 'docs/TASK_ACTIONS.md - All action references with examples (854 lines, ~21k tokens)',
1716
- task_linking: 'docs/TASK_LINKING.md - Link tasks to decisions/constraints/files (729 lines, ~18k tokens)',
1717
- task_migration: 'docs/TASK_MIGRATION.md - Migrate from decision-based tracking (701 lines, ~18k tokens)',
1718
- tool_selection: 'docs/TOOL_SELECTION.md - Task vs decision vs constraint comparison (236 lines, ~12k tokens)',
1719
- workflows: 'docs/WORKFLOWS.md - Multi-agent task coordination workflows (602 lines, ~30k tokens)',
1720
- shared_concepts: 'docs/SHARED_CONCEPTS.md - Layer definitions, enum values (status/priority), atomic mode (339 lines, ~17k tokens)'
1721
- }
1722
- };
1723
- }
1724
- /**
1725
- * Query file watcher status and monitored files/tasks
1726
- */
1727
- export async function watcherStatus(args, adapter) {
1728
- const actualAdapter = adapter ?? getAdapter();
1729
- const knex = actualAdapter.getKnex();
1730
- const projectId = getProjectContext().getProjectId();
1731
- const subaction = args.subaction || 'status';
1732
- const watcher = FileWatcher.getInstance();
1733
- if (subaction === 'help') {
1734
- return {
1735
- action: 'watcher',
1736
- description: 'Query file watcher status and monitored files/tasks',
1737
- subactions: {
1738
- status: {
1739
- description: 'Get overall watcher status (running, files watched, tasks monitored)',
1740
- example: { action: 'watcher', subaction: 'status' }
1741
- },
1742
- list_files: {
1743
- description: 'List all files being watched with their associated tasks',
1744
- example: { action: 'watcher', subaction: 'list_files' }
1745
- },
1746
- list_tasks: {
1747
- description: 'List all tasks that have active file watchers',
1748
- example: { action: 'watcher', subaction: 'list_tasks' }
1749
- },
1750
- help: {
1751
- description: 'Show this help documentation',
1752
- example: { action: 'watcher', subaction: 'help' }
1753
- }
1754
- },
1755
- note: 'File watching activates automatically when you link files to tasks using the link action with link_type="file". The watcher monitors linked files for changes and validates acceptance criteria.'
1756
- };
1757
- }
1758
- if (subaction === 'status') {
1759
- const status = watcher.getStatus();
1760
- return {
1761
- success: true,
1762
- watcher_status: {
1763
- running: status.running,
1764
- files_watched: status.filesWatched,
1765
- tasks_monitored: status.tasksWatched
1766
- },
1767
- message: status.running
1768
- ? `File watcher is running. Monitoring ${status.filesWatched} file(s) across ${status.tasksWatched} task(s).`
1769
- : 'File watcher is not running. Link files to tasks to activate automatic file watching.'
1770
- };
1771
- }
1772
- if (subaction === 'list_files') {
1773
- const fileLinks = await knex('t_task_file_links as tfl')
1774
- .join('t_tasks as t', function () {
1775
- this.on('tfl.task_id', '=', 't.id')
1776
- .andOn('tfl.project_id', '=', 't.project_id');
1777
- })
1778
- .join('m_task_statuses as ts', 't.status_id', 'ts.id')
1779
- .join('m_files as f', 'tfl.file_id', 'f.id')
1780
- .where('t.project_id', projectId)
1781
- .whereNot('t.status_id', STATUS_TO_ID['archived']) // Exclude archived tasks
1782
- .select('f.path as file_path', 't.id', 't.title', 'ts.name as status_name')
1783
- .orderBy(['f.path', 't.id']);
1784
- // Group by file
1785
- const fileMap = new Map();
1786
- for (const link of fileLinks) {
1787
- if (!fileMap.has(link.file_path)) {
1788
- fileMap.set(link.file_path, []);
1789
- }
1790
- fileMap.get(link.file_path).push({
1791
- task_id: link.id,
1792
- task_title: link.title,
1793
- status: link.status_name
1794
- });
1795
- }
1796
- const files = Array.from(fileMap.entries()).map(([path, tasks]) => ({
1797
- file_path: path,
1798
- tasks: tasks
1799
- }));
1800
- return {
1801
- success: true,
1802
- files_watched: files.length,
1803
- files: files,
1804
- message: files.length > 0
1805
- ? `Watching ${files.length} file(s) linked to tasks.`
1806
- : 'No files currently linked to tasks. Use link action with link_type="file" to activate file watching.'
1807
- };
1808
- }
1809
- if (subaction === 'list_tasks') {
1810
- const taskLinks = await knex('t_tasks as t')
1811
- .join('m_task_statuses as ts', 't.status_id', 'ts.id')
1812
- .join('t_task_file_links as tfl', function () {
1813
- this.on('t.id', '=', 'tfl.task_id')
1814
- .andOn('t.project_id', '=', 'tfl.project_id');
1815
- })
1816
- .join('m_files as f', 'tfl.file_id', 'f.id')
1817
- .where('t.project_id', projectId)
1818
- .whereNot('t.status_id', STATUS_TO_ID['archived']) // Exclude archived tasks
1819
- .groupBy('t.id', 't.title', 'ts.name')
1820
- .select('t.id', 't.title', 'ts.name as status_name', knex.raw('COUNT(DISTINCT tfl.file_id) as file_count'), knex.raw('GROUP_CONCAT(DISTINCT f.path, \', \') as files'))
1821
- .orderBy('t.id');
1822
- const tasks = taskLinks.map(task => ({
1823
- task_id: task.id,
1824
- task_title: task.title,
1825
- status: task.status_name,
1826
- files_count: task.file_count,
1827
- files: task.files.split(', ')
1828
- }));
1829
- return {
1830
- success: true,
1831
- tasks_monitored: tasks.length,
1832
- tasks: tasks,
1833
- message: tasks.length > 0
1834
- ? `Monitoring ${tasks.length} task(s) with linked files.`
1835
- : 'No tasks currently have linked files. Use link action with link_type="file" to activate file watching.'
1836
- };
1837
- }
1838
- return {
1839
- error: `Invalid subaction: ${subaction}. Valid subactions: status, list_files, list_tasks, help`
1840
- };
1841
- }
1842
- /**
1843
- * Get comprehensive examples for task tool
1844
- * @returns Examples documentation object
1845
- */
1846
- export function taskExample() {
1847
- return {
1848
- tool: 'task',
1849
- description: 'Comprehensive task management examples for Kanban-style workflow',
1850
- scenarios: {
1851
- basic_task_management: {
1852
- title: 'Creating and Managing Tasks',
1853
- examples: [
1854
- {
1855
- scenario: 'Create a new task',
1856
- request: '{ action: "create", title: "Implement user authentication", description: "Add JWT-based auth to API", priority: 3, assigned_agent: "backend-agent", layer: "business", tags: ["authentication", "security"] }',
1857
- explanation: 'Creates task in todo status with high priority'
1858
- },
1859
- {
1860
- scenario: 'Get task details',
1861
- request: '{ action: "get", task_id: 5 }',
1862
- response: 'Full task details including metadata, links, and timestamps'
1863
- },
1864
- {
1865
- scenario: 'List tasks by status',
1866
- request: '{ action: "list", status: "in_progress", limit: 20 }',
1867
- explanation: 'View all in-progress tasks'
1868
- }
1869
- ]
1870
- },
1871
- status_workflow: {
1872
- title: 'Task Lifecycle (Status Transitions)',
1873
- workflow: [
1874
- {
1875
- step: 1,
1876
- status: 'todo',
1877
- action: '{ action: "create", title: "...", status: "todo" }',
1878
- description: 'Task created and waiting to be started'
1879
- },
1880
- {
1881
- step: 2,
1882
- status: 'in_progress',
1883
- action: '{ action: "move", task_id: 1, new_status: "in_progress" }',
1884
- description: 'Agent starts working on task'
1885
- },
1886
- {
1887
- step: 3,
1888
- status: 'waiting_review',
1889
- action: '{ action: "move", task_id: 1, new_status: "waiting_review" }',
1890
- description: 'Work complete, awaiting review/approval'
1891
- },
1892
- {
1893
- step: 4,
1894
- status: 'done',
1895
- action: '{ action: "move", task_id: 1, new_status: "done" }',
1896
- description: 'Task reviewed and completed'
1897
- },
1898
- {
1899
- step: 5,
1900
- status: 'archived',
1901
- action: '{ action: "archive", task_id: 1 }',
1902
- description: 'Task archived for historical record'
1903
- }
1904
- ],
1905
- blocked_status: {
1906
- description: 'Use "blocked" when task cannot proceed due to dependencies',
1907
- example: '{ action: "move", task_id: 1, new_status: "blocked" }'
1908
- }
1909
- },
1910
- auto_stale_detection: {
1911
- title: 'Automatic Stale Task Management',
1912
- behavior: [
1913
- {
1914
- rule: 'in_progress > 2 hours → waiting_review',
1915
- explanation: 'Tasks stuck in progress auto-move to waiting_review',
1916
- rationale: 'Prevents tasks from being forgotten while in progress'
1917
- },
1918
- {
1919
- rule: 'waiting_review > 24 hours → todo',
1920
- explanation: 'Unreviewed tasks return to todo queue',
1921
- rationale: 'Ensures waiting tasks dont accumulate indefinitely'
1922
- }
1923
- ],
1924
- configuration: {
1925
- keys: ['task_stale_hours_in_progress', 'task_stale_hours_waiting_review', 'task_auto_stale_enabled'],
1926
- note: 'Configure via config table in database'
1927
- }
1928
- },
1929
- task_linking: {
1930
- title: 'Linking Tasks to Context',
1931
- examples: [
1932
- {
1933
- scenario: 'Link task to decision',
1934
- request: '{ action: "link", task_id: 5, link_type: "decision", target_id: "api_auth_method", link_relation: "implements" }',
1935
- explanation: 'Track which tasks implement specific decisions'
1936
- },
1937
- {
1938
- scenario: 'Link task to constraint',
1939
- request: '{ action: "link", task_id: 5, link_type: "constraint", target_id: 3, link_relation: "addresses" }',
1940
- explanation: 'Show task addresses a performance/architecture/security constraint'
1941
- },
1942
- {
1943
- scenario: 'Link task to file',
1944
- request: '{ action: "link", task_id: 5, link_type: "file", target_id: "src/api/auth.ts", link_relation: "modifies" }',
1945
- explanation: 'Activates automatic file watching for the task - saves 300 tokens per file vs manual registration',
1946
- behavior: 'File watcher monitors linked files and validates acceptance criteria when files change'
1947
- }
1948
- ]
1949
- },
1950
- batch_operations: {
1951
- title: 'Batch Task Creation',
1952
- examples: [
1953
- {
1954
- scenario: 'Create multiple related tasks',
1955
- request: '{ action: "batch_create", tasks: [{"title": "Design API", "priority": 3}, {"title": "Implement API", "priority": 3}, {"title": "Write tests", "priority": 2}], atomic: false }',
1956
- explanation: 'Create task breakdown - use atomic:false for best-effort'
1957
- }
1958
- ]
1959
- },
1960
- filtering_queries: {
1961
- title: 'Advanced Task Queries',
1962
- examples: [
1963
- {
1964
- scenario: 'Find high-priority tasks for agent',
1965
- request: '{ action: "list", assigned_agent: "backend-agent", priority: 3, status: "todo" }',
1966
- note: 'Priority is numeric: 1=low, 2=medium, 3=high, 4=critical'
1967
- },
1968
- {
1969
- scenario: 'Get all security-related tasks',
1970
- request: '{ action: "list", tags: ["security"], limit: 50 }',
1971
- explanation: 'Filter by tags for topic-based views'
1972
- },
1973
- {
1974
- scenario: 'View infrastructure layer tasks',
1975
- request: '{ action: "list", layer: "infrastructure" }',
1976
- explanation: 'See all DevOps/config related tasks'
1977
- }
1978
- ]
1979
- },
1980
- file_watcher_status: {
1981
- title: 'File Watcher Status Queries',
1982
- examples: [
1983
- {
1984
- scenario: 'Check if file watcher is running',
1985
- request: '{ action: "watcher", subaction: "status" }',
1986
- explanation: 'Returns running status, files watched count, tasks monitored count',
1987
- response: '{ running: true, files_watched: 5, tasks_monitored: 3 }'
1988
- },
1989
- {
1990
- scenario: 'List all files being watched',
1991
- request: '{ action: "watcher", subaction: "list_files" }',
1992
- explanation: 'Shows file paths and which tasks are watching them',
1993
- response: '{ files: [{ file_path: "src/api/auth.ts", tasks: [{ task_id: 5, title: "...", status: "in_progress" }] }] }'
1994
- },
1995
- {
1996
- scenario: 'List tasks with active file watchers',
1997
- request: '{ action: "watcher", subaction: "list_tasks" }',
1998
- explanation: 'Shows tasks and which files they are watching',
1999
- response: '{ tasks: [{ task_id: 5, title: "...", files: ["src/api/auth.ts", "src/api/middleware.ts"] }] }'
2000
- }
2001
- ]
2002
- }
2003
- },
2004
- valid_transitions: {
2005
- from_todo: ['in_progress', 'blocked', 'done', 'archived'],
2006
- from_in_progress: ['waiting_review', 'blocked', 'todo'],
2007
- from_waiting_review: ['done', 'in_progress', 'todo'],
2008
- from_blocked: ['todo', 'in_progress'],
2009
- from_done: ['archived', 'todo'],
2010
- from_archived: []
2011
- },
2012
- best_practices: {
2013
- task_creation: [
2014
- 'Use descriptive titles (200 char max)',
2015
- 'Set appropriate priority: 1=low, 2=medium (default), 3=high, 4=critical',
2016
- 'Assign to layer where work will be done',
2017
- 'Tag comprehensively for easy filtering',
2018
- 'Include acceptance_criteria for complex tasks'
2019
- ],
2020
- status_management: [
2021
- 'Move to in_progress when starting work',
2022
- 'Use waiting_review for completed but unverified work',
2023
- 'Set to blocked with notes explaining dependency',
2024
- 'Archive done tasks periodically for cleaner views'
2025
- ],
2026
- linking: [
2027
- '⭐ RECOMMENDED: Set up file watchers for all tasks involving code changes (except exceptional cases)',
2028
- 'Link tasks to decisions they implement',
2029
- 'Link to constraints they address',
2030
- 'Link files to activate automatic file watching (save 300 tokens per file vs manual registration)',
2031
- 'Use descriptive link_relation values'
2032
- ],
2033
- coordination: [
2034
- 'Use assigned_agent for clear ownership',
2035
- 'Filter by status for Kanban board views',
2036
- 'Monitor auto-stale transitions for stuck work',
2037
- 'Use tags for cross-cutting concerns (security, performance, etc.)'
2038
- ]
2039
- }
2040
- };
2041
- }
7
+ * Directory structure:
8
+ * - actions/ (14 action files - one per action)
9
+ * - internal/ (5 utility files - validation, state machine, queries)
10
+ * - watcher/ (2 watcher files - status queries)
11
+ * - help/ (2 help files - help and examples)
12
+ * - types.ts (Task-specific types and constants)
13
+ * - index.ts (Barrel export for all actions)
14
+ */
15
+ // Re-export everything from the modular implementation
16
+ export * from './tasks/index.js';
2042
17
  //# sourceMappingURL=tasks.js.map