@dizzlkheinz/ynab-mcpb 0.12.2 → 0.15.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 (262) hide show
  1. package/.code/agents/01a13ef4-3f23-4f52-b33b-3585b73cfa60/error.txt +3 -0
  2. package/.code/agents/084fd32f-e298-4728-9103-a78d7dc39613/error.txt +3 -0
  3. package/.code/agents/0fed51e1-a943-4b97-a2a8-a6f0f27c844d/status.txt +1 -0
  4. package/.code/agents/1059b6bd-5ccd-4d83-a12c-7c9d89137399/error.txt +5 -0
  5. package/.code/agents/110/exec-call_F9BDNG7JfxKkq7Vc8ESAvdft.txt +1569 -0
  6. package/.code/agents/11ebcef3-b13f-4e44-ad80-d94a866804b7/error.txt +3 -0
  7. package/.code/agents/1398/exec-call_CjItcWMU1G6JoPshX62QvpaR.txt +2832 -0
  8. package/.code/agents/1398/exec-call_SUVq2ivmONQ5LMCmd7ngmOqr.txt +2709 -0
  9. package/.code/agents/1398/exec-call_SdNY4NOffdcC5pRYjVXHjPCK.txt +2832 -0
  10. package/.code/agents/1398/exec-call_qblJo9et1gsFFB63TtLOiji2.txt +2832 -0
  11. package/.code/agents/1398/exec-call_zaRrzlGz7GJcNzVfkAmML7Zg.txt +2709 -0
  12. package/.code/agents/171834fd-5905-42fc-bbcc-2c755145b0fc/status.txt +1 -0
  13. package/.code/agents/1724/exec-call_HvHQe0w5CCG3T7Q3ULT6MO3g.txt +5217 -0
  14. package/.code/agents/1724/exec-call_QwUNESVzfxxk78K1frh1Vahb.txt +2594 -0
  15. package/.code/agents/1724/exec-call_aJ1Xwz71XmIpD4SBxSHERzLe.txt +2594 -0
  16. package/.code/agents/1d7d7ab7-7473-4b69-8b97-6e914f56056a/result.txt +231 -0
  17. package/.code/agents/210/exec-call_0tQCsKNJ1WTuIchb8wlcFJpW.txt +2590 -0
  18. package/.code/agents/210/exec-call_8ZlY9cUc8Ft1twi4ch8UJ6IN.txt +5195 -0
  19. package/.code/agents/2188/exec-call_5HqayBxIteJtoI8oPTiLWgvJ.txt +286 -0
  20. package/.code/agents/2188/exec-call_XRbBKBq3adZe6dcppAvQtM7G.txt +218 -0
  21. package/.code/agents/2188/exec-call_ehA0SjpYtrUi6GJXmibLjp4i.txt +180 -0
  22. package/.code/agents/21902821-ecaf-4759-bb9d-222b90921af5/error.txt +3 -0
  23. package/.code/agents/232073be-aa0e-46da-b478-5b64dbf03cf5/status.txt +1 -0
  24. package/.code/agents/234ff534-2336-4771-a8d9-aa04421a63be/result.txt +747 -0
  25. package/.code/agents/253e2695-dc36-4022-b436-27655e0fc6c7/status.txt +1 -0
  26. package/.code/agents/2583/exec-call_M59I4eDjpjlBIWBiSxyS0YlJ.txt +2594 -0
  27. package/.code/agents/2583/exec-call_usLRGh7OhVHtsRBL4iUwRhjq.txt +2594 -0
  28. package/.code/agents/292aa3ff-dbab-470f-97c9-e7e8fd65e0db/result.txt +144 -0
  29. package/.code/agents/3134/exec-call_IgCAMGx19lWfuo8zfYIt5FFC.txt +416 -0
  30. package/.code/agents/3134/exec-call_IxvLR2Oo7kba2QTsI1gHVko8.txt +2590 -0
  31. package/.code/agents/3134/exec-call_jYvc8hksZChSiysbzKjl2ZbB.txt +2590 -0
  32. package/.code/agents/329/exec-call_4QdP3SfSO7HGPCwVcqZIth6s.txt +2590 -0
  33. package/.code/agents/472/exec-call_4AxzEEcWwkKhpqRB3bE8Ha4L.txt +790 -0
  34. package/.code/agents/472/exec-call_CB3LPYQA8QIZRi8I6kj4J17A.txt +766 -0
  35. package/.code/agents/472/exec-call_YeoUWvaFoktay2nqVUsa9KKX.txt +790 -0
  36. package/.code/agents/472/exec-call_jPWgKVquBBXTg0T3Lks5ZfkK.txt +2594 -0
  37. package/.code/agents/472/exec-call_qBkvunpGBDEHph2jPmTwtcsb.txt +1000 -0
  38. package/.code/agents/472/exec-call_v0ffRV1p0kTckBmJPzzHAEy0.txt +3489 -0
  39. package/.code/agents/472/exec-call_xAX5FXqWIlk02d9WubHbHWh8.txt +766 -0
  40. package/.code/agents/5346/exec-call_9q0muXUuLaucwEqI51Pt7idT.txt +2594 -0
  41. package/.code/agents/5346/exec-call_B2el3B79rVkq9LhWTI2VYlz7.txt +2456 -0
  42. package/.code/agents/5346/exec-call_BfX08f02qkZI9uJD5dvCvuoj.txt +2594 -0
  43. package/.code/agents/543328d0-61d6-4fd1-a723-bb168656e2e2/error.txt +18 -0
  44. package/.code/agents/5580c02c-1383-4d18-9cbd-cc8a06e3408d/result.txt +48 -0
  45. package/.code/agents/60ce1a22-5126-44b2-b977-1d5b56142a7b/status.txt +1 -0
  46. package/.code/agents/6215d9db-7fa9-4429-aeec-3835c3212291/error.txt +1 -0
  47. package/.code/agents/6743db55-30e5-4b4e-9366-a8214fc7f714/error.txt +1 -0
  48. package/.code/agents/6bf9591b-b9c9-422c-b0a5-e968c7d8422a/status.txt +1 -0
  49. package/.code/agents/7/exec-call_eww3GfdEiJZx61sJEQ9wNmt3.txt +1271 -0
  50. package/.code/agents/70/exec-call_owUtDMYiVgqDf8vsz1i32PFf.txt +1570 -0
  51. package/.code/agents/8/exec-call_UtrjAcLbhYLatxR4O97fZgnm.txt +2590 -0
  52. package/.code/agents/82490bc9-f34e-4b1b-8a8e-bccc2e6254f5/error.txt +3 -0
  53. package/.code/agents/841/exec-call_7nTNhSBCNjTDUIJv7py6CepO.txt +3299 -0
  54. package/.code/agents/841/exec-call_TLI0yUdUijuUAvI4o3DXEvHO.txt +3299 -0
  55. package/.code/agents/9/exec-call_XaABQT1hIlRpnKZ2uyBMWsTC.txt +1882 -0
  56. package/.code/agents/941/exec-call_GuGHRx7NNXWIDAnxUG2NEWPa.txt +2594 -0
  57. package/.code/agents/95d9fbab-19a2-48af-83f9-c792566a347f/error.txt +1 -0
  58. package/.code/agents/b0098cb8-cb32-4ada-9bc4-37c587518896/result.txt +170 -0
  59. package/.code/agents/b4fe59a4-81df-42e2-a112-0153e504faca/error.txt +1 -0
  60. package/.code/agents/bf4ce152-f623-49d7-aa52-c18631625c3c/error.txt +3 -0
  61. package/.code/agents/d7d1db75-d7eb-468e-adea-4ef4d916d187/status.txt +1 -0
  62. package/.code/agents/e2baa9c8-bac3-49e3-a39d-024333e6a990/status.txt +1 -0
  63. package/.code/agents/e350b8c3-8483-408c-b2bb-94515f492a11/error.txt +3 -0
  64. package/.code/agents/e63f9919-719f-4ad0-bccf-01b1a596e1e9/status.txt +1 -0
  65. package/.code/agents/e71695a8-3044-478d-8f12-ed13d02884c7/status.txt +1 -0
  66. package/.code/agents/f95b7464-3e25-4897-b153-c8dfd63fd605/error.txt +5 -0
  67. package/.code/agents/fa3c5ddf-cdf7-47a2-930a-b806c6363689/status.txt +1 -0
  68. package/.github/workflows/ci-tests.yml +6 -2
  69. package/.github/workflows/publish.yml +3 -3
  70. package/.github/workflows/release.yml +4 -0
  71. package/CHANGELOG.md +89 -1
  72. package/NUL +1 -1
  73. package/README.md +36 -10
  74. package/dist/bundle/index.cjs +65 -42
  75. package/dist/index.js +9 -20
  76. package/dist/server/YNABMCPServer.d.ts +2 -1
  77. package/dist/server/YNABMCPServer.js +61 -27
  78. package/dist/server/cacheKeys.d.ts +8 -0
  79. package/dist/server/cacheKeys.js +8 -0
  80. package/dist/server/config.d.ts +22 -3
  81. package/dist/server/config.js +16 -17
  82. package/dist/server/errorHandler.d.ts +2 -0
  83. package/dist/server/errorHandler.js +49 -5
  84. package/dist/server/securityMiddleware.js +3 -6
  85. package/dist/server/toolRegistry.js +8 -10
  86. package/dist/tools/accountTools.js +4 -3
  87. package/dist/tools/categoryTools.js +8 -7
  88. package/dist/tools/monthTools.js +2 -1
  89. package/dist/tools/payeeTools.js +2 -1
  90. package/dist/tools/reconcileAdapter.js +10 -5
  91. package/dist/tools/reconciliation/analyzer.d.ts +4 -2
  92. package/dist/tools/reconciliation/analyzer.js +120 -404
  93. package/dist/tools/reconciliation/csvParser.d.ts +51 -0
  94. package/dist/tools/reconciliation/csvParser.js +413 -0
  95. package/dist/tools/reconciliation/executor.d.ts +8 -0
  96. package/dist/tools/reconciliation/executor.js +277 -50
  97. package/dist/tools/reconciliation/index.d.ts +7 -7
  98. package/dist/tools/reconciliation/index.js +115 -39
  99. package/dist/tools/reconciliation/matcher.d.ts +24 -3
  100. package/dist/tools/reconciliation/matcher.js +175 -133
  101. package/dist/tools/reconciliation/recommendationEngine.js +22 -18
  102. package/dist/tools/reconciliation/reportFormatter.js +9 -8
  103. package/dist/tools/reconciliation/signDetector.d.ts +2 -0
  104. package/dist/tools/reconciliation/signDetector.js +54 -0
  105. package/dist/tools/reconciliation/types.d.ts +20 -34
  106. package/dist/tools/reconciliation/types.js +1 -7
  107. package/dist/tools/reconciliation/ynabAdapter.d.ts +4 -0
  108. package/dist/tools/reconciliation/ynabAdapter.js +15 -0
  109. package/dist/tools/transactionTools.d.ts +3 -17
  110. package/dist/tools/transactionTools.js +5 -17
  111. package/dist/types/reconciliation.d.ts +24 -0
  112. package/dist/types/reconciliation.js +1 -0
  113. package/dist/utils/baseError.d.ts +3 -0
  114. package/dist/utils/baseError.js +7 -0
  115. package/dist/utils/errors.d.ts +13 -0
  116. package/dist/utils/errors.js +15 -0
  117. package/dist/utils/validationError.d.ts +3 -0
  118. package/dist/utils/validationError.js +3 -0
  119. package/docs/guides/ARCHITECTURE.md +12 -129
  120. package/docs/plans/2025-11-20-reloadable-config-token-validation.md +93 -0
  121. package/docs/plans/2025-11-21-fix-transaction-cached-property.md +362 -0
  122. package/docs/plans/2025-11-21-reconciliation-error-handling.md +90 -0
  123. package/docs/plans/2025-11-21-v014-hardening.md +153 -0
  124. package/docs/plans/reconciliation-v2-redesign.md +1571 -0
  125. package/package.json +8 -2
  126. package/scripts/run-throttled-integration-tests.js +9 -3
  127. package/scripts/test-recommendations.ts +1 -1
  128. package/src/__tests__/performance.test.ts +12 -5
  129. package/src/__tests__/testUtils.ts +62 -5
  130. package/src/__tests__/tools/reconciliation/csvParser.integration.test.ts +129 -0
  131. package/src/__tests__/tools/reconciliation/real-world.integration.test.ts +53 -0
  132. package/src/__tests__/workflows.e2e.test.ts +33 -0
  133. package/src/index.ts +8 -31
  134. package/src/server/YNABMCPServer.ts +81 -42
  135. package/src/server/__tests__/YNABMCPServer.integration.test.ts +10 -12
  136. package/src/server/__tests__/YNABMCPServer.test.ts +27 -15
  137. package/src/server/__tests__/config.test.ts +76 -152
  138. package/src/server/__tests__/server-startup.integration.test.ts +42 -14
  139. package/src/server/__tests__/toolRegistry.test.ts +1 -1
  140. package/src/server/cacheKeys.ts +8 -0
  141. package/src/server/config.ts +20 -38
  142. package/src/server/errorHandler.ts +52 -5
  143. package/src/server/securityMiddleware.ts +3 -7
  144. package/src/server/toolRegistry.ts +14 -10
  145. package/src/tools/__tests__/categoryTools.test.ts +37 -19
  146. package/src/tools/__tests__/transactionTools.test.ts +58 -2
  147. package/src/tools/accountTools.ts +8 -3
  148. package/src/tools/categoryTools.ts +12 -7
  149. package/src/tools/monthTools.ts +7 -1
  150. package/src/tools/payeeTools.ts +7 -1
  151. package/src/tools/reconcileAdapter.ts +10 -5
  152. package/src/tools/reconciliation/__tests__/adapter.test.ts +28 -22
  153. package/src/tools/reconciliation/__tests__/analyzer.test.ts +114 -180
  154. package/src/tools/reconciliation/__tests__/csvParser.test.ts +87 -0
  155. package/src/tools/reconciliation/__tests__/executor.integration.test.ts +26 -6
  156. package/src/tools/reconciliation/__tests__/executor.test.ts +133 -60
  157. package/src/tools/reconciliation/__tests__/matcher.test.ts +68 -54
  158. package/src/tools/reconciliation/__tests__/recommendationEngine.test.ts +37 -30
  159. package/src/tools/reconciliation/__tests__/reportFormatter.test.ts +6 -5
  160. package/src/tools/reconciliation/__tests__/scenarios/extremes.scenario.test.ts +30 -11
  161. package/src/tools/reconciliation/__tests__/scenarios/repeatAmount.scenario.test.ts +50 -15
  162. package/src/tools/reconciliation/__tests__/signDetector.test.ts +211 -0
  163. package/src/tools/reconciliation/__tests__/ynabAdapter.test.ts +61 -0
  164. package/src/tools/reconciliation/analyzer.ts +174 -545
  165. package/src/tools/reconciliation/csvParser.ts +617 -0
  166. package/src/tools/reconciliation/executor.ts +344 -58
  167. package/src/tools/reconciliation/index.ts +141 -48
  168. package/src/tools/reconciliation/matcher.ts +234 -214
  169. package/src/tools/reconciliation/recommendationEngine.ts +23 -19
  170. package/src/tools/reconciliation/reportFormatter.ts +16 -11
  171. package/src/tools/reconciliation/signDetector.ts +117 -0
  172. package/src/tools/reconciliation/types.ts +39 -61
  173. package/src/tools/reconciliation/ynabAdapter.ts +33 -0
  174. package/src/tools/schemas/outputs/utilityOutputs.ts +1 -1
  175. package/src/tools/transactionTools.ts +7 -18
  176. package/src/types/reconciliation.ts +49 -0
  177. package/src/utils/baseError.ts +7 -0
  178. package/src/utils/errors.ts +21 -0
  179. package/src/utils/validationError.ts +3 -0
  180. package/temp-recon.ts +126 -0
  181. package/test-exports/ynab_since_2025-10-16_account_53298e13_238items_2025-11-28_13-46-20.json +3662 -0
  182. package/test_mcp_tools.mjs +75 -0
  183. package/.code/agents/0427d95e-edca-431f-a214-5e53264e29c4/error.txt +0 -8
  184. package/.code/agents/0d675174-d1e1-41c3-9975-4c2e275819a9/error.txt +0 -3
  185. package/.code/agents/0d8c5afd-4787-422b-abf8-2e5943fc7e67/error.txt +0 -3
  186. package/.code/agents/0ec34a70-ed5d-4b9e-bee4-bb0e4cccbc4b/error.txt +0 -1
  187. package/.code/agents/0ef51a21-1ab1-49d7-9561-0eaa43875ebc/error.txt +0 -12
  188. package/.code/agents/15db95d7-abad-4b4d-9c3b-8446089cb61d/error.txt +0 -1
  189. package/.code/agents/19ab9acb-f675-4ff0-902a-09a5476f8149/error.txt +0 -1
  190. package/.code/agents/1ef7e12d-f6ff-4897-8a9b-152d523d898e/error.txt +0 -5
  191. package/.code/agents/2465/exec-call_lroN9KKzJVWC7t5423DK1nT9.txt +0 -1453
  192. package/.code/agents/28edb6fe-95a9-41a0-ae69-aa0100d26c0c/error.txt +0 -8
  193. package/.code/agents/2ae40cf5-b4bf-42e2-92bf-7ea350a7755e/error.txt +0 -9
  194. package/.code/agents/2bfc4e1f-ac4b-45a5-b6df-bf89d4dbb54c/error.txt +0 -1
  195. package/.code/agents/2e2e1134-eff0-49be-ba25-8e2c3468a564/error.txt +0 -5
  196. package/.code/agents/3/exec-call_203OC4TNVkLxW7z2HCVEQ1cM.txt +0 -81
  197. package/.code/agents/3/exec-call_SS5T0XSiXB4LSNzUKTl75wkh.txt +0 -610
  198. package/.code/agents/3322c003-ce5e-48e3-a342-f5049c5bf9a2/error.txt +0 -1
  199. package/.code/agents/391e9b08-1ebc-468c-9bcd-6d0cc3193b37/error.txt +0 -1
  200. package/.code/agents/3ab0aa84-b7bb-4054-afa3-40b8fd7d3be0/error.txt +0 -1
  201. package/.code/agents/3bed368d-50fe-477e-aee3-a6707eaa1ab9/error.txt +0 -3
  202. package/.code/agents/3e40b925-db12-442f-8d7a-a25fc69a6672/error.txt +0 -8
  203. package/.code/agents/414d5776-cf58-41f3-9328-a6daed503a50/error.txt +0 -5
  204. package/.code/agents/42687751-4565-4610-b240-67835b17d861/error.txt +0 -1
  205. package/.code/agents/46b98876-1a39-43c9-9e2f-507ca6d47335/error.txt +0 -9
  206. package/.code/agents/4a7d9491-b26f-43dd-850d-2ecdc49b5d1b/error.txt +0 -1
  207. package/.code/agents/4e60f00a-1b3e-447f-87f3-7faf9deddec3/error.txt +0 -13
  208. package/.code/agents/5138fc1c-4d49-4b74-a7da-ccdb3a8e44e7/error.txt +0 -14
  209. package/.code/agents/521cff39-a7a3-42e5-a557-134f0f7daaa0/error.txt +0 -5
  210. package/.code/agents/53302dc5-3857-4413-9a47-9e0f64a51dc4/error.txt +0 -5
  211. package/.code/agents/567c7c2e-6a6f-4761-a08d-d36deeb2e0ac/error.txt +0 -5
  212. package/.code/agents/57b00845-80dc-47c9-953c-3028d16275d6/error.txt +0 -3
  213. package/.code/agents/593d9005-c2a5-48fd-8813-ece0d3f2de96/error.txt +0 -1
  214. package/.code/agents/5a112e66-0e1a-42f9-877c-53af56ea3551/error.txt +0 -1
  215. package/.code/agents/5b05e8ed-7788-4738-b7ee-9faa8180f992/error.txt +0 -5
  216. package/.code/agents/5f888d6f-d7ca-4ac8-be23-9ea1bf753951/error.txt +0 -5
  217. package/.code/agents/607db3ab-e4b0-435b-b497-93e9aa525549/error.txt +0 -8
  218. package/.code/agents/67dcb2a2-900f-4c78-b3fc-80b5213e0ddf/error.txt +0 -8
  219. package/.code/agents/69ad848c-4e98-49b3-b16c-0094ac2d1759/error.txt +0 -5
  220. package/.code/agents/6c9cfc5f-0d0b-445c-b121-9f60082c4f70/error.txt +0 -1
  221. package/.code/agents/6f6f8f77-4ab0-4f6e-9f30-40e8be0bd8f5/error.txt +0 -1
  222. package/.code/agents/72a7cde4-fa8a-4024-9038-27faa550539b/error.txt +0 -1
  223. package/.code/agents/7b48335c-8247-43aa-9949-5f820ba8e199/error.txt +0 -1
  224. package/.code/agents/80944249-bea9-4ac5-87de-a666c4df306e/error.txt +0 -1
  225. package/.code/agents/826099df-1b66-4186-a915-7eb59f9db19d/error.txt +0 -5
  226. package/.code/agents/8291d158-18a8-4a92-b799-4e9a4d9cce88/error.txt +0 -1
  227. package/.code/agents/82fb71a3-20fb-4341-804a-a2fc900f95bc/error.txt +0 -1
  228. package/.code/agents/855790ea-54ee-43e4-8209-a66994e37590/error.txt +0 -1
  229. package/.code/agents/88ce3a2e-04f2-42be-9062-bf97aa798da0/error.txt +0 -3
  230. package/.code/agents/9a17e398-b6ed-4218-bb55-bc64a8d38ce8/error.txt +0 -8
  231. package/.code/agents/9a4f4bfc-a2a6-4f40-a896-9335b41a7ed1/error.txt +0 -1
  232. package/.code/agents/9b633e55-ef84-47d6-94bb-fd3dd172ad97/error.txt +0 -1
  233. package/.code/agents/9b81f3ab-c72b-4a81-9a8f-28a49ddba84a/error.txt +0 -8
  234. package/.code/agents/a35daf29-b2d1-4aef-9b42-dad63a76bd47/error.txt +0 -3
  235. package/.code/agents/a81990cc-69ee-44d2-b907-17403c9bc5d7/error.txt +0 -5
  236. package/.code/agents/ab56260a-4a83-4ad4-9410-f88a23d6520a/error.txt +0 -1
  237. package/.code/agents/ad722c31-2d1d-45f7-bae2-3f02ca455b60/error.txt +0 -1
  238. package/.code/agents/b62e8690-3324-4b97-9309-731bee79416b/error.txt +0 -5
  239. package/.code/agents/baf60a3a-752b-4ad8-99d6-df32423ed2eb/error.txt +0 -1
  240. package/.code/agents/be049042-7dcb-4ac8-9beb-c8f1aea67742/error.txt +0 -14
  241. package/.code/agents/bed1dcb4-bfce-4a9f-8594-0f994962aafd/error.txt +0 -1
  242. package/.code/agents/c324a6cf-e935-4ede-9529-b3ebc18e8d6b/error.txt +0 -5
  243. package/.code/agents/c37c06ff-dfe3-43f2-9bbc-3ec73ec8f41d/error.txt +0 -5
  244. package/.code/agents/c8cd6671-433a-456b-9f88-e51cb2df6bfc/error.txt +0 -11
  245. package/.code/agents/ca2ccb67-2f24-428e-b27d-9365beadd140/error.txt +0 -1
  246. package/.code/agents/cf08c0c8-e7f0-423e-93ba-547e8e818340/error.txt +0 -8
  247. package/.code/agents/d579c74f-874b-40a4-9d56-ced1eb6a701d/error.txt +0 -1
  248. package/.code/agents/df412c98-7378-4deb-8e1e-76c416931181/error.txt +0 -3
  249. package/.code/agents/e5134eb3-2af4-45b0-8998-051cb4afdb45/error.txt +0 -3
  250. package/.code/agents/e6308471-aa45-4e9e-9496-2e9404164d97/error.txt +0 -8
  251. package/.code/agents/e7bd8bc7-23fb-4f46-98dc-b0dcf11b75a1/error.txt +0 -1
  252. package/.code/agents/e92bec35-378d-4fe1-8ac0-6e1bb3c86911/error.txt +0 -5
  253. package/.code/agents/ed918fbf-2dc4-4aa2-bfc5-04b65d9471ea/error.txt +0 -1
  254. package/.code/agents/ef1d756f-b272-48fc-8729-f05c494674f7/error.txt +0 -1
  255. package/.code/agents/ef359853-0249-4e41-a804-c0fc459fe456/error.txt +0 -1
  256. package/.code/agents/effc7b4a-4b90-40a0-8c86-a7a99d2d5fd2/error.txt +0 -1
  257. package/.code/agents/fa15f8d5-8359-4a8b-83a3-2f2056b3ff40/error.txt +0 -3
  258. package/.code/agents/fbef4193-eadf-4c8a-83ff-4878a6310f25/error.txt +0 -8
  259. package/.code/agents/fd0a4b4a-fda4-4964-a6d6-2b8a2da387c6/error.txt +0 -1
  260. package/.gemini/settings.json +0 -8
  261. package/ADOS-2-Module-1-Complete-Manual.md +0 -757
  262. package/WARP.md +0 -245
@@ -1,5 +1,6 @@
1
1
  import type { CallToolResult, Tool } from '@modelcontextprotocol/sdk/types.js';
2
2
  import { z, toJSONSchema } from 'zod/v4';
3
+ import { fromZodError } from 'zod-validation-error';
3
4
  import type { MCPToolAnnotations } from '../types/toolAnnotations.js';
4
5
 
5
6
  export type SecurityWrapperFactory = <T extends Record<string, unknown>>(
@@ -162,7 +163,10 @@ export class ToolRegistry {
162
163
  inputSchema,
163
164
  };
164
165
  if (tool.outputSchema) {
165
- const outputSchema = this.generateJsonSchema(tool.outputSchema) as Tool['outputSchema'];
166
+ const outputSchema = this.generateJsonSchema(
167
+ tool.outputSchema,
168
+ 'output',
169
+ ) as Tool['outputSchema'];
166
170
  result.outputSchema = outputSchema;
167
171
  }
168
172
  if (tool.metadata?.annotations) {
@@ -311,9 +315,10 @@ export class ToolRegistry {
311
315
  tool: RegisteredTool<Record<string, unknown>, Record<string, unknown>>,
312
316
  ): CallToolResult {
313
317
  if (error instanceof z.ZodError) {
318
+ const validationError = fromZodError(error);
314
319
  return this.deps.errorHandler.createValidationError(
315
320
  `Invalid parameters for ${tool.name}`,
316
- error.message,
321
+ validationError.message,
317
322
  );
318
323
  }
319
324
 
@@ -388,9 +393,12 @@ export class ToolRegistry {
388
393
  }
389
394
  }
390
395
 
391
- private generateJsonSchema(schema: z.ZodTypeAny): Record<string, unknown> {
396
+ private generateJsonSchema(
397
+ schema: z.ZodTypeAny,
398
+ ioMode: 'input' | 'output' = 'input',
399
+ ): Record<string, unknown> {
392
400
  try {
393
- return toJSONSchema(schema, { target: 'draft-2020-12', io: 'output' });
401
+ return toJSONSchema(schema, { target: 'draft-2020-12', io: ioMode });
394
402
  } catch (error) {
395
403
  console.warn(`Failed to generate JSON schema for tool: ${error}`);
396
404
  return { type: 'object', additionalProperties: true };
@@ -467,12 +475,8 @@ export class ToolRegistry {
467
475
  // Validate against schema
468
476
  const result = validator.safeParse(parsedOutput);
469
477
  if (!result.success) {
470
- const validationErrors = result.error.issues
471
- .map((err) => {
472
- const path = err.path.join('.');
473
- return path ? `${path}: ${err.message}` : err.message;
474
- })
475
- .join('; ');
478
+ const validationError = fromZodError(result.error);
479
+ const validationErrors = validationError.message;
476
480
  return this.deps.errorHandler.createValidationError(
477
481
  `Output validation failed for ${toolName}`,
478
482
  `Handler output does not match declared output schema: ${validationErrors}`,
@@ -9,6 +9,7 @@ import {
9
9
  UpdateCategorySchema,
10
10
  } from '../categoryTools.js';
11
11
  import { createDeltaFetcherMock, createRejectingDeltaFetcherMock } from './deltaTestUtils.js';
12
+ import { CacheKeys } from '../../server/cacheKeys.js';
12
13
 
13
14
  // Mock the cache manager
14
15
  vi.mock('../../server/cacheManager.js', () => ({
@@ -60,9 +61,22 @@ describe('Category Tools', () => {
60
61
  },
61
62
  );
62
63
  (cacheManager.has as ReturnType<typeof vi.fn>).mockReturnValue(false);
63
- (CacheManager.generateKey as ReturnType<typeof vi.fn>).mockImplementation(
64
- (prefix: string, ...parts: (string | number | boolean | undefined)[]) =>
65
- [prefix, ...parts.filter((part) => part !== undefined)].join(':'),
64
+ (CacheManager.generateKey as any).mockImplementation(
65
+ (prefix: string, type: string, budgetId: string, id?: string) => {
66
+ if (prefix === CacheKeys.CATEGORIES && type === 'list') {
67
+ return `categories:list:${budgetId}`;
68
+ }
69
+ if (prefix === CacheKeys.CATEGORIES && type === 'get' && id) {
70
+ return `categories:get:${budgetId}:${id}`;
71
+ }
72
+ if (prefix === CacheKeys.MONTHS && type === 'list') {
73
+ return `months:list:${budgetId}`;
74
+ }
75
+ if (prefix === CacheKeys.MONTHS && type === 'get' && id) {
76
+ return `months:get:${budgetId}:${id}`;
77
+ }
78
+ return `${prefix}:${type}:${budgetId}:${id || ''}`;
79
+ },
66
80
  );
67
81
  });
68
82
 
@@ -450,34 +464,38 @@ describe('Category Tools', () => {
450
464
  data: { category: mockUpdatedCategory },
451
465
  });
452
466
 
453
- const mockCacheKeys = [
454
- 'categories:list:budget-1:generated-key',
455
- 'category:get:budget-1:category-1:generated-key',
456
- ];
457
- (CacheManager.generateKey as any)
458
- .mockReturnValueOnce(mockCacheKeys[0])
459
- .mockReturnValueOnce(mockCacheKeys[1]);
460
-
461
- const result = await handleUpdateCategory(mockYnabAPI, {
467
+ await handleUpdateCategory(mockYnabAPI, {
462
468
  budget_id: 'budget-1',
463
469
  category_id: 'category-1',
464
470
  budgeted: 60000,
465
471
  });
466
472
 
467
473
  // Verify cache was invalidated for both category list and specific category
468
- expect(CacheManager.generateKey).toHaveBeenCalledWith('categories', 'list', 'budget-1');
469
474
  expect(CacheManager.generateKey).toHaveBeenCalledWith(
470
- 'category',
475
+ CacheKeys.CATEGORIES,
476
+ 'list',
477
+ 'budget-1',
478
+ );
479
+ expect(CacheManager.generateKey).toHaveBeenCalledWith(
480
+ CacheKeys.CATEGORIES,
471
481
  'get',
472
482
  'budget-1',
473
483
  'category-1',
474
484
  );
475
- expect(cacheManager.delete).toHaveBeenCalledWith(mockCacheKeys[0]);
476
- expect(cacheManager.delete).toHaveBeenCalledWith(mockCacheKeys[1]);
485
+ expect(cacheManager.delete).toHaveBeenCalledWith(`categories:list:budget-1`);
486
+ expect(cacheManager.delete).toHaveBeenCalledWith(`categories:get:budget-1:category-1`);
477
487
 
478
- expect(result.content).toHaveLength(1);
479
- const parsedContent = JSON.parse(result.content[0].text);
480
- expect(parsedContent.category.budgeted).toBe(60);
488
+ // Verify month-related caches were invalidated
489
+ expect(CacheManager.generateKey).toHaveBeenCalledWith(CacheKeys.MONTHS, 'list', 'budget-1');
490
+ expect(CacheManager.generateKey).toHaveBeenCalledWith(
491
+ CacheKeys.MONTHS,
492
+ 'get',
493
+ 'budget-1',
494
+ expect.stringMatching(/^\d{4}-\d{2}-01$/),
495
+ );
496
+ const currentMonth = `${new Date().getFullYear()}-${String(new Date().getMonth() + 1).padStart(2, '0')}-01`;
497
+ expect(cacheManager.delete).toHaveBeenCalledWith(`months:list:budget-1`);
498
+ expect(cacheManager.delete).toHaveBeenCalledWith(`months:get:budget-1:${currentMonth}`);
481
499
  });
482
500
 
483
501
  it('should not invalidate cache on dry_run category update', async () => {
@@ -352,6 +352,61 @@ describe('transactionTools', () => {
352
352
  const response = JSON.parse(result.content[0].text);
353
353
  expect(response.error.message).toBe('Failed to list transactions');
354
354
  });
355
+
356
+ it('should include cached property in large response path', async () => {
357
+ // Create large transaction list (> 90KB)
358
+ const largeTransactionList: ynab.TransactionDetail[] = [];
359
+ for (let i = 0; i < 5000; i++) {
360
+ largeTransactionList.push({
361
+ id: `transaction-${i}`,
362
+ date: '2025-01-01',
363
+ amount: -10000,
364
+ memo: 'Test transaction with long memo to increase size '.repeat(10),
365
+ cleared: 'cleared',
366
+ approved: true,
367
+ flag_color: null,
368
+ account_id: 'test-account',
369
+ payee_id: null,
370
+ category_id: null,
371
+ transfer_account_id: null,
372
+ transfer_transaction_id: null,
373
+ matched_transaction_id: null,
374
+ import_id: null,
375
+ import_payee_name: null,
376
+ import_payee_name_original: null,
377
+ debt_transaction_type: null,
378
+ deleted: false,
379
+ account_name: 'Test Account',
380
+ payee_name: 'Test Payee',
381
+ category_name: 'Test Category',
382
+ subtransactions: [],
383
+ } as ynab.TransactionDetail);
384
+ }
385
+
386
+ const mockResponse = {
387
+ data: {
388
+ transactions: largeTransactionList,
389
+ },
390
+ };
391
+
392
+ (mockYnabAPI.transactions.getTransactionsByAccount as any).mockResolvedValue(mockResponse);
393
+
394
+ const result = await handleListTransactions(mockYnabAPI, {
395
+ budget_id: 'test-budget',
396
+ account_id: 'test-account',
397
+ });
398
+
399
+ const content = result.content?.[0];
400
+ expect(content).toBeDefined();
401
+ expect(content?.type).toBe('text');
402
+
403
+ const parsedResponse = JSON.parse(content!.text);
404
+
405
+ // Should have cached property even in large response path
406
+ expect(parsedResponse.cached).toBeDefined();
407
+ expect(parsedResponse.cached).toBe(false);
408
+ expect(parsedResponse.cache_info).toBeDefined();
409
+ });
355
410
  });
356
411
 
357
412
  describe('GetTransactionSchema', () => {
@@ -1852,8 +1907,9 @@ describe('transactionTools', () => {
1852
1907
  const result = CreateTransactionsSchema.safeParse(params);
1853
1908
  expect(result.success).toBe(false);
1854
1909
  if (!result.success) {
1855
- const issue = result.error.issues.find((i) => i.path.includes('subtransactions'));
1856
- expect(issue?.message).toContain('Subtransactions are not supported');
1910
+ const issue = result.error.issues.find((i) => i.code === 'unrecognized_keys');
1911
+ expect(issue).toBeDefined();
1912
+ expect((issue as any)?.keys).toContain('subtransactions');
1857
1913
  }
1858
1914
  });
1859
1915
 
@@ -8,6 +8,7 @@ import { cacheManager, CACHE_TTLS, CacheManager } from '../server/cacheManager.j
8
8
  import type { DeltaFetcher } from './deltaFetcher.js';
9
9
  import type { DeltaCache } from '../server/deltaCache.js';
10
10
  import type { ServerKnowledgeStore } from '../server/serverKnowledgeStore.js';
11
+ import { CacheKeys } from '../server/cacheKeys.js';
11
12
  import { resolveDeltaFetcherArgs, resolveDeltaWriteArgs } from './deltaSupport.js';
12
13
 
13
14
  /**
@@ -139,7 +140,7 @@ export async function handleGetAccount(
139
140
  async () => {
140
141
  // Use enhanced CacheManager wrap method
141
142
  const cacheKey = CacheManager.generateKey(
142
- 'account',
143
+ CacheKeys.ACCOUNTS,
143
144
  'get',
144
145
  params.budget_id,
145
146
  params.account_id,
@@ -248,10 +249,14 @@ export async function handleCreateAccount(
248
249
  const account = response.data.account;
249
250
 
250
251
  // Invalidate accounts list cache after successful account creation
251
- const accountsListCacheKey = CacheManager.generateKey('accounts', 'list', params.budget_id);
252
+ const accountsListCacheKey = CacheManager.generateKey(
253
+ CacheKeys.ACCOUNTS,
254
+ 'list',
255
+ params.budget_id,
256
+ );
252
257
  cacheManager.delete(accountsListCacheKey);
253
258
 
254
- deltaCache.invalidate(params.budget_id, 'accounts');
259
+ deltaCache.invalidate(params.budget_id, CacheKeys.ACCOUNTS);
255
260
 
256
261
  return {
257
262
  content: [
@@ -8,6 +8,7 @@ import { cacheManager, CACHE_TTLS, CacheManager } from '../server/cacheManager.j
8
8
  import type { DeltaFetcher } from './deltaFetcher.js';
9
9
  import type { DeltaCache } from '../server/deltaCache.js';
10
10
  import type { ServerKnowledgeStore } from '../server/serverKnowledgeStore.js';
11
+ import { CacheKeys } from '../server/cacheKeys.js';
11
12
  import { resolveDeltaFetcherArgs, resolveDeltaWriteArgs } from './deltaSupport.js';
12
13
 
13
14
  /**
@@ -158,7 +159,7 @@ export async function handleGetCategory(
158
159
  async () => {
159
160
  // Use enhanced CacheManager wrap method
160
161
  const cacheKey = CacheManager.generateKey(
161
- 'category',
162
+ CacheKeys.CATEGORIES,
162
163
  'get',
163
164
  params.budget_id,
164
165
  params.category_id,
@@ -271,9 +272,13 @@ export async function handleUpdateCategory(
271
272
  const category = response.data.category;
272
273
 
273
274
  // Invalidate category-related caches after successful update
274
- const categoriesListCacheKey = CacheManager.generateKey('categories', 'list', params.budget_id);
275
+ const categoriesListCacheKey = CacheManager.generateKey(
276
+ CacheKeys.CATEGORIES,
277
+ 'list',
278
+ params.budget_id,
279
+ );
275
280
  const specificCategoryCacheKey = CacheManager.generateKey(
276
- 'category',
281
+ CacheKeys.CATEGORIES,
277
282
  'get',
278
283
  params.budget_id,
279
284
  params.category_id,
@@ -282,9 +287,9 @@ export async function handleUpdateCategory(
282
287
  cacheManager.delete(specificCategoryCacheKey);
283
288
 
284
289
  // Invalidate month-related caches as category budget changes affect month data
285
- const monthsListCacheKey = CacheManager.generateKey('months', 'list', params.budget_id);
290
+ const monthsListCacheKey = CacheManager.generateKey(CacheKeys.MONTHS, 'list', params.budget_id);
286
291
  const currentMonthCacheKey = CacheManager.generateKey(
287
- 'month',
292
+ CacheKeys.MONTHS,
288
293
  'get',
289
294
  params.budget_id,
290
295
  currentMonth,
@@ -292,8 +297,8 @@ export async function handleUpdateCategory(
292
297
  cacheManager.delete(monthsListCacheKey);
293
298
  cacheManager.delete(currentMonthCacheKey);
294
299
 
295
- deltaCache.invalidate(params.budget_id, 'categories');
296
- deltaCache.invalidate(params.budget_id, 'months');
300
+ deltaCache.invalidate(params.budget_id, CacheKeys.CATEGORIES);
301
+ deltaCache.invalidate(params.budget_id, CacheKeys.MONTHS);
297
302
  const serverKnowledge = response.data.server_knowledge;
298
303
  if (typeof serverKnowledge === 'number') {
299
304
  knowledgeStore.update(categoriesListCacheKey, serverKnowledge);
@@ -6,6 +6,7 @@ import { responseFormatter } from '../server/responseFormatter.js';
6
6
  import { milliunitsToAmount } from '../utils/amountUtils.js';
7
7
  import { cacheManager, CACHE_TTLS, CacheManager } from '../server/cacheManager.js';
8
8
  import type { DeltaFetcher } from './deltaFetcher.js';
9
+ import { CacheKeys } from '../server/cacheKeys.js';
9
10
  import { resolveDeltaFetcherArgs } from './deltaSupport.js';
10
11
 
11
12
  /**
@@ -42,7 +43,12 @@ export async function handleGetMonth(
42
43
  return await withToolErrorHandling(
43
44
  async () => {
44
45
  // Always use cache
45
- const cacheKey = CacheManager.generateKey('month', 'get', params.budget_id, params.month);
46
+ const cacheKey = CacheManager.generateKey(
47
+ CacheKeys.MONTHS,
48
+ 'get',
49
+ params.budget_id,
50
+ params.month,
51
+ );
46
52
  const wasCached = cacheManager.has(cacheKey);
47
53
  const month = await cacheManager.wrap<ynab.MonthDetail>(cacheKey, {
48
54
  ttl: CACHE_TTLS.MONTHS,
@@ -5,6 +5,7 @@ import { withToolErrorHandling } from '../types/index.js';
5
5
  import { responseFormatter } from '../server/responseFormatter.js';
6
6
  import { cacheManager, CACHE_TTLS, CacheManager } from '../server/cacheManager.js';
7
7
  import type { DeltaFetcher } from './deltaFetcher.js';
8
+ import { CacheKeys } from '../server/cacheKeys.js';
8
9
  import { resolveDeltaFetcherArgs } from './deltaSupport.js';
9
10
 
10
11
  /**
@@ -104,7 +105,12 @@ export async function handleGetPayee(
104
105
  return await withToolErrorHandling(
105
106
  async () => {
106
107
  // Use enhanced CacheManager wrap method
107
- const cacheKey = CacheManager.generateKey('payee', 'get', params.budget_id, params.payee_id);
108
+ const cacheKey = CacheManager.generateKey(
109
+ CacheKeys.PAYEES,
110
+ 'get',
111
+ params.budget_id,
112
+ params.payee_id,
113
+ );
108
114
  const wasCached = cacheManager.has(cacheKey);
109
115
  const payee = await cacheManager.wrap<ynab.Payee>(cacheKey, {
110
116
  ttl: CACHE_TTLS.PAYEES,
@@ -76,7 +76,7 @@ interface LegacyBalanceReconciliation {
76
76
 
77
77
  const toBankTransactionView = (txn: BankTransaction, currency: string) => ({
78
78
  ...txn,
79
- amount_money: toMoneyValueFromDecimal(txn.amount, currency),
79
+ amount_money: toMoneyValue(txn.amount, currency),
80
80
  });
81
81
 
82
82
  const toYNABTransactionView = (txn: YNABTransaction, currency: string) => ({
@@ -85,15 +85,20 @@ const toYNABTransactionView = (txn: YNABTransaction, currency: string) => ({
85
85
  });
86
86
 
87
87
  const convertMatch = (match: TransactionMatch, currency: string) => ({
88
- ...match,
89
- bank_transaction: toBankTransactionView(match.bank_transaction, currency),
90
- ynab_transaction: match.ynab_transaction
91
- ? toYNABTransactionView(match.ynab_transaction, currency)
88
+ bank_transaction: toBankTransactionView(match.bankTransaction, currency),
89
+ ynab_transaction: match.ynabTransaction
90
+ ? toYNABTransactionView(match.ynabTransaction, currency)
92
91
  : undefined,
93
92
  candidates: match.candidates?.map((candidate) => ({
94
93
  ...candidate,
95
94
  ynab_transaction: toYNABTransactionView(candidate.ynab_transaction, currency),
96
95
  })),
96
+ confidence: match.confidence,
97
+ confidence_score: match.confidenceScore,
98
+ match_reason: match.matchReason,
99
+ top_confidence: match.topConfidence,
100
+ action_hint: match.actionHint,
101
+ recommendation: match.recommendation,
97
102
  });
98
103
 
99
104
  const convertInsight = (insight: ReconciliationInsight) => ({
@@ -34,38 +34,41 @@ const buildAnalysis = (): ReconciliationAnalysis => ({
34
34
  },
35
35
  auto_matches: [
36
36
  {
37
- bank_transaction: {
37
+ bankTransaction: {
38
38
  id: 'bank-1',
39
39
  date: '2025-10-15',
40
- amount: -45.23,
40
+ amount: -45230,
41
41
  payee: 'Shell Gas',
42
- original_csv_row: 2,
42
+ sourceRow: 2,
43
+ raw: { date: '2025-10-15', amount: '-45.23', description: 'Shell Gas' },
43
44
  },
44
- ynab_transaction: {
45
+ ynabTransaction: {
45
46
  id: 'ynab-1',
46
47
  date: '2025-10-14',
47
48
  amount: -45230,
48
- payee_name: 'Shell',
49
- category_name: 'Auto',
49
+ payee: 'Shell',
50
+ categoryName: 'Auto',
50
51
  cleared: 'uncleared',
51
52
  approved: true,
53
+ memo: null,
52
54
  },
53
55
  candidates: [],
54
56
  confidence: 'high',
55
- confidence_score: 97,
56
- match_reason: 'exact_amount_and_date',
57
- top_confidence: 97,
58
- action_hint: 'mark_cleared',
57
+ confidenceScore: 97,
58
+ matchReason: 'exact_amount_and_date',
59
+ topConfidence: 97,
60
+ actionHint: 'mark_cleared',
59
61
  },
60
62
  ],
61
63
  suggested_matches: [
62
64
  {
63
- bank_transaction: {
65
+ bankTransaction: {
64
66
  id: 'bank-2',
65
67
  date: '2025-10-20',
66
- amount: -60,
68
+ amount: -60000,
67
69
  payee: 'Amazon',
68
- original_csv_row: 5,
70
+ sourceRow: 5,
71
+ raw: { date: '2025-10-20', amount: '-60.00', description: 'Amazon' },
69
72
  },
70
73
  candidates: [
71
74
  {
@@ -73,10 +76,11 @@ const buildAnalysis = (): ReconciliationAnalysis => ({
73
76
  id: 'ynab-2',
74
77
  date: '2025-10-19',
75
78
  amount: -60000,
76
- payee_name: 'Amazon Online',
77
- category_name: 'Shopping',
79
+ payee: 'Amazon Online',
80
+ categoryName: 'Shopping',
78
81
  cleared: 'uncleared',
79
82
  approved: true,
83
+ memo: null,
80
84
  },
81
85
  confidence: 75,
82
86
  match_reason: 'amount_and_date_fuzzy_payee',
@@ -84,18 +88,19 @@ const buildAnalysis = (): ReconciliationAnalysis => ({
84
88
  },
85
89
  ],
86
90
  confidence: 'medium',
87
- confidence_score: 75,
88
- match_reason: 'amount_and_date_fuzzy_payee',
89
- top_confidence: 75,
91
+ confidenceScore: 75,
92
+ matchReason: 'amount_and_date_fuzzy_payee',
93
+ topConfidence: 75,
90
94
  },
91
95
  ],
92
96
  unmatched_bank: [
93
97
  {
94
98
  id: 'bank-3',
95
99
  date: '2025-10-25',
96
- amount: 22.22,
100
+ amount: 22220,
97
101
  payee: 'EvoCarShare',
98
- original_csv_row: 7,
102
+ sourceRow: 7,
103
+ raw: { date: '2025-10-25', amount: '22.22', description: 'EvoCarShare' },
99
104
  },
100
105
  ],
101
106
  unmatched_ynab: [
@@ -103,10 +108,11 @@ const buildAnalysis = (): ReconciliationAnalysis => ({
103
108
  id: 'ynab-3',
104
109
  date: '2025-10-26',
105
110
  amount: -15000,
106
- payee_name: 'Coffee Shop',
107
- category_name: 'Dining',
111
+ payee: 'Coffee Shop',
112
+ categoryName: 'Dining',
108
113
  cleared: 'cleared',
109
114
  approved: true,
115
+ memo: null,
110
116
  },
111
117
  ],
112
118
  balance_info: {