@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
@@ -3,12 +3,13 @@
3
3
  * Implements guided reconciliation workflow with conservative matching
4
4
  */
5
5
 
6
+ import { promises as fs } from 'fs';
6
7
  import { z } from 'zod/v4';
7
8
  import type * as ynab from 'ynab';
8
9
  import { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
9
10
  import { withToolErrorHandling } from '../../types/index.js';
10
11
  import { analyzeReconciliation } from './analyzer.js';
11
- import type { MatchingConfig } from './types.js';
12
+ import type { MatchingConfig } from './matcher.js';
12
13
  import { buildReconciliationPayload } from '../reconcileAdapter.js';
13
14
  import {
14
15
  executeReconciliation,
@@ -16,9 +17,11 @@ import {
16
17
  type LegacyReconciliationResult,
17
18
  } from './executor.js';
18
19
  import { responseFormatter } from '../../server/responseFormatter.js';
19
- import { extractDateRangeFromCSV, autoDetectCSVFormat } from '../compareTransactions/parser.js';
20
+ import { parseCSV, type ParseCSVOptions, type CSVParseResult } from './csvParser.js';
20
21
  import type { DeltaFetcher } from '../deltaFetcher.js';
21
22
  import { resolveDeltaFetcherArgs } from '../deltaSupport.js';
23
+ import { detectSignInversion } from './signDetector.js';
24
+ import { normalizeYNABTransactions } from './ynabAdapter.js';
22
25
 
23
26
  // Re-export types for external use
24
27
  export type * from './types.js';
@@ -75,25 +78,17 @@ export const ReconcileAccountSchema = z
75
78
 
76
79
  csv_format: z
77
80
  .object({
78
- date_column: z.union([z.string(), z.number()]).optional().default('Date'),
81
+ date_column: z.union([z.string(), z.number()]).optional(),
79
82
  amount_column: z.union([z.string(), z.number()]).optional(),
80
83
  debit_column: z.union([z.string(), z.number()]).optional(),
81
84
  credit_column: z.union([z.string(), z.number()]).optional(),
82
- description_column: z.union([z.string(), z.number()]).optional().default('Description'),
83
- date_format: z.string().optional().default('MM/DD/YYYY'),
84
- has_header: z.boolean().optional().default(true),
85
- delimiter: z.string().optional().default(','),
85
+ description_column: z.union([z.string(), z.number()]).optional(),
86
+ date_format: z.string().optional(),
87
+ has_header: z.boolean().optional(),
88
+ delimiter: z.string().optional(),
86
89
  })
87
90
  .strict()
88
- .optional()
89
- .default(() => ({
90
- date_column: 'Date',
91
- amount_column: 'Amount',
92
- description_column: 'Description',
93
- date_format: 'MM/DD/YYYY',
94
- has_header: true,
95
- delimiter: ',',
96
- })),
91
+ .optional(),
97
92
 
98
93
  // Statement information
99
94
  statement_balance: z.number({
@@ -106,9 +101,9 @@ export const ReconcileAccountSchema = z
106
101
  as_of_timezone: z.string().optional(),
107
102
 
108
103
  // Matching configuration (optional)
109
- date_tolerance_days: z.number().min(0).max(7).optional().default(5),
104
+ date_tolerance_days: z.number().min(0).max(7).optional().default(7),
110
105
  amount_tolerance_cents: z.number().min(0).max(100).optional().default(1),
111
- auto_match_threshold: z.number().min(0).max(100).optional().default(90),
106
+ auto_match_threshold: z.number().min(0).max(100).optional().default(85),
112
107
  suggestion_threshold: z.number().min(0).max(100).optional().default(60),
113
108
  amount_tolerance: z.number().min(0).max(1).optional(),
114
109
 
@@ -166,13 +161,21 @@ export async function handleReconcileAccount(
166
161
  const forceFullRefresh = params.force_full_refresh ?? true;
167
162
  return await withToolErrorHandling(
168
163
  async () => {
169
- // Build matching configuration from parameters
164
+ // Build matching configuration from parameters (V2 Format)
170
165
  const config: MatchingConfig = {
171
- dateToleranceDays: params.date_tolerance_days,
172
- amountToleranceCents: params.amount_tolerance_cents,
173
- descriptionSimilarityThreshold: 0.8, // Fixed for Phase 1
174
- autoMatchThreshold: params.auto_match_threshold,
175
- suggestionThreshold: params.suggestion_threshold,
166
+ weights: {
167
+ amount: 0.5,
168
+ date: 0.15,
169
+ payee: 0.35,
170
+ },
171
+ dateToleranceDays: params.date_tolerance_days ?? 5,
172
+ amountToleranceMilliunits: (params.amount_tolerance_cents ?? 1) * 10,
173
+ autoMatchThreshold: params.auto_match_threshold ?? 90,
174
+ suggestedMatchThreshold: params.suggestion_threshold ?? 60,
175
+ minimumCandidateScore: 40,
176
+ exactAmountBonus: 10,
177
+ exactDateBonus: 5,
178
+ exactPayeeBonus: 10,
176
179
  };
177
180
 
178
181
  const accountResult = forceFullRefresh
@@ -213,37 +216,78 @@ export async function handleReconcileAccount(
213
216
  const budgetResponse = await ynabAPI.budgets.getBudgetById(params.budget_id);
214
217
  const currencyCode = budgetResponse.data.budget?.currency_format?.iso_code ?? 'USD';
215
218
 
219
+ // Prepare CSV parsing options from request
220
+ const dateFormat = mapCsvDateFormatToHint(params.csv_format?.date_format);
221
+ const csvOptions: ParseCSVOptions = {
222
+ columns: {
223
+ ...(params.csv_format?.date_column !== undefined && {
224
+ date: String(params.csv_format.date_column),
225
+ }),
226
+ ...(params.csv_format?.amount_column !== undefined && {
227
+ amount: String(params.csv_format.amount_column),
228
+ }),
229
+ ...(params.csv_format?.debit_column !== undefined && {
230
+ debit: String(params.csv_format.debit_column),
231
+ }),
232
+ ...(params.csv_format?.credit_column !== undefined && {
233
+ credit: String(params.csv_format.credit_column),
234
+ }),
235
+ ...(params.csv_format?.description_column !== undefined && {
236
+ description: String(params.csv_format.description_column),
237
+ }),
238
+ },
239
+ ...(dateFormat && { dateFormat }),
240
+ ...(params.csv_format?.has_header !== undefined && {
241
+ header: params.csv_format.has_header,
242
+ }),
243
+ };
244
+
245
+ // Load CSV content from either inline data or filesystem path
246
+ let csvContent = params.csv_data ?? '';
247
+ if (!csvContent && params.csv_file_path) {
248
+ try {
249
+ csvContent = await fs.readFile(params.csv_file_path, 'utf8');
250
+ } catch (error) {
251
+ const message =
252
+ error instanceof Error && error.message
253
+ ? error.message
254
+ : 'Unknown error while reading CSV file';
255
+ throw new Error(`Failed to read CSV file at path ${params.csv_file_path}: ${message}`);
256
+ }
257
+ }
258
+
216
259
  // Fetch YNAB transactions for the account
217
260
  // Auto-detect date range from CSV if not explicitly provided
218
261
  let sinceDate: Date;
262
+ let parseResult: CSVParseResult | undefined;
219
263
 
220
264
  if (params.statement_start_date) {
221
265
  // User provided explicit start date
222
266
  sinceDate = new Date(params.statement_start_date);
223
267
  } else {
224
- // Auto-detect from CSV content
268
+ // Auto-detect from CSV content using new parser
225
269
  try {
226
- const csvContent = params.csv_data || params.csv_file_path || '';
227
- const csvFormat = params.csv_format || autoDetectCSVFormat(csvContent);
228
-
229
- // Convert schema format to parser format
230
- const parserFormat = {
231
- date_column: csvFormat.date_column || 'Date',
232
- amount_column: csvFormat.amount_column,
233
- debit_column: csvFormat.debit_column,
234
- credit_column: csvFormat.credit_column,
235
- description_column: csvFormat.description_column || 'Description',
236
- date_format: csvFormat.date_format || 'MM/DD/YYYY',
237
- has_header: csvFormat.has_header ?? true,
238
- delimiter: csvFormat.delimiter || ',',
239
- };
240
-
241
- const { minDate } = extractDateRangeFromCSV(csvContent, parserFormat);
242
-
243
- // Add 7-day buffer before min date for pending transactions
244
- const minDateObj = new Date(minDate);
245
- minDateObj.setDate(minDateObj.getDate() - 7);
246
- sinceDate = minDateObj;
270
+ parseResult = parseCSV(csvContent, {
271
+ ...csvOptions,
272
+ invertAmounts: shouldInvertBankAmounts,
273
+ });
274
+
275
+ if (parseResult.transactions.length > 0) {
276
+ // Find min date
277
+ const dates = parseResult.transactions
278
+ .map((t) => new Date(t.date).getTime())
279
+ .filter((t) => !isNaN(t));
280
+ if (dates.length > 0) {
281
+ const minTime = Math.min(...dates);
282
+ const minDateObj = new Date(minTime);
283
+ minDateObj.setDate(minDateObj.getDate() - 7); // 7-day buffer
284
+ sinceDate = minDateObj;
285
+ } else {
286
+ sinceDate = new Date(Date.now() - 90 * 24 * 60 * 60 * 1000);
287
+ }
288
+ } else {
289
+ sinceDate = new Date(Date.now() - 90 * 24 * 60 * 60 * 1000);
290
+ }
247
291
  } catch {
248
292
  // Fallback to 90 days if CSV parsing fails
249
293
  sinceDate = new Date(Date.now() - 90 * 24 * 60 * 60 * 1000);
@@ -265,6 +309,32 @@ export async function handleReconcileAccount(
265
309
 
266
310
  const ynabTransactions = transactionsResult.data;
267
311
 
312
+ // Smart sign detection: If invert_bank_amounts not explicitly set, auto-detect
313
+ let finalInvertAmounts = shouldInvertBankAmounts;
314
+ if (params.invert_bank_amounts === undefined && csvContent) {
315
+ // Parse CSV without inversion to get raw amounts
316
+ const rawParseResult = parseCSV(csvContent, {
317
+ ...csvOptions,
318
+ invertAmounts: false, // Don't invert yet
319
+ });
320
+
321
+ if (rawParseResult.transactions.length > 0 && ynabTransactions.length > 0) {
322
+ // Normalize YNAB transactions for comparison
323
+ const normalizedYNAB = normalizeYNABTransactions(ynabTransactions);
324
+
325
+ // Detect if signs are mismatched
326
+ const needsInversion = detectSignInversion(rawParseResult.transactions, normalizedYNAB);
327
+
328
+ finalInvertAmounts = needsInversion;
329
+
330
+ // If detection result differs from default, invalidate parseResult
331
+ // to force re-parsing with correct inversion
332
+ if (needsInversion !== shouldInvertBankAmounts && parseResult) {
333
+ parseResult = undefined;
334
+ }
335
+ }
336
+ }
337
+
268
338
  const auditMetadata = {
269
339
  data_freshness: getDataFreshness(transactionsResult, forceFullRefresh),
270
340
  data_source: getAuditDataSource(transactionsResult, forceFullRefresh),
@@ -281,7 +351,7 @@ export async function handleReconcileAccount(
281
351
 
282
352
  // Perform analysis
283
353
  const analysis = analyzeReconciliation(
284
- params.csv_data || params.csv_file_path || '',
354
+ parseResult ?? csvContent,
285
355
  params.csv_file_path,
286
356
  ynabTransactions,
287
357
  adjustedStatementBalance,
@@ -289,7 +359,8 @@ export async function handleReconcileAccount(
289
359
  currencyCode,
290
360
  params.account_id,
291
361
  params.budget_id,
292
- shouldInvertBankAmounts,
362
+ finalInvertAmounts, // Use smart-detected value
363
+ csvOptions,
293
364
  );
294
365
 
295
366
  const initialAccount: AccountSnapshot = {
@@ -359,6 +430,28 @@ export async function handleReconcileAccount(
359
430
  );
360
431
  }
361
432
 
433
+ function mapCsvDateFormatToHint(
434
+ format: string | undefined,
435
+ ): ParseCSVOptions['dateFormat'] | undefined {
436
+ if (!format) {
437
+ return undefined;
438
+ }
439
+
440
+ const normalized = format.toUpperCase().replace(/[^YMD]/g, '');
441
+
442
+ if (normalized === 'YYYYMMDD' || normalized === 'YYMMDD' || normalized === 'YMD') {
443
+ return 'YMD';
444
+ }
445
+ if (normalized === 'MMDDYYYY' || normalized === 'MDY') {
446
+ return 'MDY';
447
+ }
448
+ if (normalized === 'DDMMYYYY' || normalized === 'DMY') {
449
+ return 'DMY';
450
+ }
451
+
452
+ return undefined;
453
+ }
454
+
362
455
  function mapCsvFormatForPayload(format: ReconcileAccountRequest['csv_format'] | undefined):
363
456
  | {
364
457
  delimiter: string;