@dizzlkheinz/ynab-mcpb 0.18.4 → 0.19.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 (343) hide show
  1. package/CLAUDE.md +87 -8
  2. package/bin/ynab-mcp-server.cjs +2 -2
  3. package/bin/ynab-mcp-server.js +3 -3
  4. package/biome.json +39 -0
  5. package/dist/bundle/index.cjs +67 -67
  6. package/dist/index.d.ts +1 -1
  7. package/dist/index.js +27 -27
  8. package/dist/server/YNABMCPServer.d.ts +3 -4
  9. package/dist/server/YNABMCPServer.js +111 -116
  10. package/dist/server/budgetResolver.d.ts +6 -5
  11. package/dist/server/budgetResolver.js +46 -36
  12. package/dist/server/cacheKeys.js +6 -6
  13. package/dist/server/cacheManager.js +14 -11
  14. package/dist/server/completions.d.ts +2 -2
  15. package/dist/server/completions.js +20 -15
  16. package/dist/server/config.d.ts +10 -5
  17. package/dist/server/config.js +24 -7
  18. package/dist/server/deltaCache.d.ts +2 -2
  19. package/dist/server/deltaCache.js +22 -16
  20. package/dist/server/deltaCache.merge.d.ts +2 -2
  21. package/dist/server/diagnostics.d.ts +4 -4
  22. package/dist/server/diagnostics.js +38 -32
  23. package/dist/server/errorHandler.d.ts +5 -12
  24. package/dist/server/errorHandler.js +219 -217
  25. package/dist/server/prompts.d.ts +2 -2
  26. package/dist/server/prompts.js +45 -45
  27. package/dist/server/rateLimiter.js +4 -4
  28. package/dist/server/requestLogger.d.ts +1 -1
  29. package/dist/server/requestLogger.js +40 -35
  30. package/dist/server/resources.d.ts +3 -3
  31. package/dist/server/resources.js +55 -52
  32. package/dist/server/responseFormatter.js +6 -6
  33. package/dist/server/securityMiddleware.d.ts +2 -2
  34. package/dist/server/securityMiddleware.js +22 -20
  35. package/dist/server/serverKnowledgeStore.js +1 -1
  36. package/dist/server/toolRegistry.d.ts +3 -3
  37. package/dist/server/toolRegistry.js +47 -40
  38. package/dist/tools/__tests__/deltaTestUtils.d.ts +3 -3
  39. package/dist/tools/__tests__/deltaTestUtils.js +2 -2
  40. package/dist/tools/accountTools.d.ts +9 -8
  41. package/dist/tools/accountTools.js +47 -47
  42. package/dist/tools/adapters.d.ts +13 -8
  43. package/dist/tools/adapters.js +21 -11
  44. package/dist/tools/budgetTools.d.ts +8 -7
  45. package/dist/tools/budgetTools.js +22 -22
  46. package/dist/tools/categoryTools.d.ts +9 -8
  47. package/dist/tools/categoryTools.js +68 -59
  48. package/dist/tools/compareTransactions/formatter.d.ts +3 -3
  49. package/dist/tools/compareTransactions/formatter.js +9 -9
  50. package/dist/tools/compareTransactions/index.d.ts +6 -6
  51. package/dist/tools/compareTransactions/index.js +58 -43
  52. package/dist/tools/compareTransactions/matcher.d.ts +1 -1
  53. package/dist/tools/compareTransactions/matcher.js +28 -15
  54. package/dist/tools/compareTransactions/parser.d.ts +2 -2
  55. package/dist/tools/compareTransactions/parser.js +144 -138
  56. package/dist/tools/compareTransactions/types.d.ts +4 -4
  57. package/dist/tools/compareTransactions.d.ts +1 -1
  58. package/dist/tools/compareTransactions.js +1 -1
  59. package/dist/tools/deltaFetcher.d.ts +2 -2
  60. package/dist/tools/deltaFetcher.js +16 -15
  61. package/dist/tools/deltaSupport.d.ts +4 -4
  62. package/dist/tools/deltaSupport.js +35 -41
  63. package/dist/tools/exportTransactions.d.ts +5 -4
  64. package/dist/tools/exportTransactions.js +61 -59
  65. package/dist/tools/monthTools.d.ts +7 -6
  66. package/dist/tools/monthTools.js +31 -29
  67. package/dist/tools/payeeTools.d.ts +7 -6
  68. package/dist/tools/payeeTools.js +28 -28
  69. package/dist/tools/reconcileAdapter.d.ts +2 -2
  70. package/dist/tools/reconcileAdapter.js +19 -12
  71. package/dist/tools/reconciliation/analyzer.d.ts +4 -4
  72. package/dist/tools/reconciliation/analyzer.js +73 -59
  73. package/dist/tools/reconciliation/csvParser.d.ts +3 -3
  74. package/dist/tools/reconciliation/csvParser.js +128 -104
  75. package/dist/tools/reconciliation/executor.d.ts +4 -4
  76. package/dist/tools/reconciliation/executor.js +148 -109
  77. package/dist/tools/reconciliation/index.d.ts +10 -10
  78. package/dist/tools/reconciliation/index.js +96 -83
  79. package/dist/tools/reconciliation/matcher.d.ts +3 -3
  80. package/dist/tools/reconciliation/matcher.js +17 -16
  81. package/dist/tools/reconciliation/payeeNormalizer.js +19 -8
  82. package/dist/tools/reconciliation/recommendationEngine.d.ts +1 -1
  83. package/dist/tools/reconciliation/recommendationEngine.js +40 -40
  84. package/dist/tools/reconciliation/reportFormatter.d.ts +2 -2
  85. package/dist/tools/reconciliation/reportFormatter.js +59 -58
  86. package/dist/tools/reconciliation/signDetector.d.ts +1 -1
  87. package/dist/tools/reconciliation/types.d.ts +16 -16
  88. package/dist/tools/reconciliation/ynabAdapter.d.ts +2 -2
  89. package/dist/tools/schemas/common.d.ts +1 -1
  90. package/dist/tools/schemas/common.js +1 -1
  91. package/dist/tools/schemas/outputs/accountOutputs.d.ts +1 -1
  92. package/dist/tools/schemas/outputs/accountOutputs.js +24 -18
  93. package/dist/tools/schemas/outputs/budgetOutputs.d.ts +1 -1
  94. package/dist/tools/schemas/outputs/budgetOutputs.js +14 -11
  95. package/dist/tools/schemas/outputs/categoryOutputs.d.ts +1 -1
  96. package/dist/tools/schemas/outputs/categoryOutputs.js +49 -29
  97. package/dist/tools/schemas/outputs/comparisonOutputs.d.ts +1 -1
  98. package/dist/tools/schemas/outputs/comparisonOutputs.js +12 -12
  99. package/dist/tools/schemas/outputs/index.d.ts +14 -14
  100. package/dist/tools/schemas/outputs/index.js +14 -14
  101. package/dist/tools/schemas/outputs/monthOutputs.d.ts +1 -1
  102. package/dist/tools/schemas/outputs/monthOutputs.js +56 -41
  103. package/dist/tools/schemas/outputs/payeeOutputs.d.ts +1 -1
  104. package/dist/tools/schemas/outputs/payeeOutputs.js +10 -10
  105. package/dist/tools/schemas/outputs/reconciliationOutputs.d.ts +2 -2
  106. package/dist/tools/schemas/outputs/reconciliationOutputs.js +45 -45
  107. package/dist/tools/schemas/outputs/transactionMutationOutputs.d.ts +1 -1
  108. package/dist/tools/schemas/outputs/transactionMutationOutputs.js +28 -22
  109. package/dist/tools/schemas/outputs/transactionOutputs.d.ts +1 -1
  110. package/dist/tools/schemas/outputs/transactionOutputs.js +43 -35
  111. package/dist/tools/schemas/outputs/utilityOutputs.d.ts +1 -1
  112. package/dist/tools/schemas/outputs/utilityOutputs.js +5 -3
  113. package/dist/tools/schemas/shared/commonOutputs.d.ts +1 -1
  114. package/dist/tools/schemas/shared/commonOutputs.js +15 -9
  115. package/dist/tools/transactionReadTools.d.ts +11 -0
  116. package/dist/tools/transactionReadTools.js +202 -0
  117. package/dist/tools/transactionSchemas.d.ts +7 -7
  118. package/dist/tools/transactionSchemas.js +77 -57
  119. package/dist/tools/transactionTools.d.ts +6 -24
  120. package/dist/tools/transactionTools.js +7 -1499
  121. package/dist/tools/transactionUtils.d.ts +6 -6
  122. package/dist/tools/transactionUtils.js +78 -63
  123. package/dist/tools/transactionWriteTools.d.ts +20 -0
  124. package/dist/tools/transactionWriteTools.js +1342 -0
  125. package/dist/tools/utilityTools.d.ts +5 -4
  126. package/dist/tools/utilityTools.js +11 -11
  127. package/dist/types/index.d.ts +7 -7
  128. package/dist/types/index.js +6 -6
  129. package/dist/types/reconciliation.d.ts +1 -1
  130. package/dist/types/toolRegistration.d.ts +14 -12
  131. package/dist/utils/amountUtils.js +1 -1
  132. package/dist/utils/dateUtils.js +4 -4
  133. package/dist/utils/errors.d.ts +3 -3
  134. package/dist/utils/errors.js +4 -4
  135. package/dist/utils/money.d.ts +2 -2
  136. package/dist/utils/money.js +8 -8
  137. package/dist/utils/validationError.d.ts +1 -1
  138. package/dist/utils/validationError.js +1 -1
  139. package/docs/assets/examples/reconciliation-with-recommendations.json +66 -66
  140. package/docs/assets/schemas/reconciliation-v2.json +360 -336
  141. package/esbuild.config.mjs +53 -50
  142. package/meta.json +12548 -12548
  143. package/package.json +98 -111
  144. package/scripts/analyze-bundle.mjs +33 -30
  145. package/scripts/create-pr-description.js +169 -120
  146. package/scripts/run-all-tests.js +178 -169
  147. package/scripts/run-domain-integration-tests.js +28 -18
  148. package/scripts/run-generate-mcpb.js +19 -17
  149. package/scripts/run-throttled-integration-tests.js +92 -83
  150. package/scripts/test-delta-params.mjs +149 -120
  151. package/scripts/test-recommendations.ts +36 -32
  152. package/scripts/tmpTransaction.ts +80 -43
  153. package/scripts/validate-env.js +98 -91
  154. package/scripts/verify-build.js +78 -76
  155. package/src/__tests__/comprehensive.integration.test.ts +1281 -1154
  156. package/src/__tests__/performance.test.ts +723 -671
  157. package/src/__tests__/setup.ts +442 -395
  158. package/src/__tests__/smoke.e2e.test.ts +41 -39
  159. package/src/__tests__/testRunner.ts +314 -295
  160. package/src/__tests__/testUtils.ts +456 -364
  161. package/src/__tests__/tools/reconciliation/csvParser.integration.test.ts +109 -107
  162. package/src/__tests__/tools/reconciliation/real-world.integration.test.ts +41 -41
  163. package/src/index.ts +68 -59
  164. package/src/server/CLAUDE.md +480 -0
  165. package/src/server/YNABMCPServer.ts +821 -794
  166. package/src/server/__tests__/YNABMCPServer.integration.test.ts +929 -893
  167. package/src/server/__tests__/YNABMCPServer.test.ts +903 -899
  168. package/src/server/__tests__/budgetResolver.test.ts +466 -423
  169. package/src/server/__tests__/cacheManager.test.ts +891 -874
  170. package/src/server/__tests__/completions.integration.test.ts +115 -106
  171. package/src/server/__tests__/completions.test.ts +334 -313
  172. package/src/server/__tests__/config.test.ts +98 -86
  173. package/src/server/__tests__/deltaCache.merge.test.ts +774 -703
  174. package/src/server/__tests__/deltaCache.swr.test.ts +198 -153
  175. package/src/server/__tests__/deltaCache.test.ts +946 -759
  176. package/src/server/__tests__/diagnostics.test.ts +825 -792
  177. package/src/server/__tests__/errorHandler.integration.test.ts +512 -462
  178. package/src/server/__tests__/errorHandler.test.ts +402 -397
  179. package/src/server/__tests__/prompts.test.ts +424 -347
  180. package/src/server/__tests__/rateLimiter.test.ts +313 -309
  181. package/src/server/__tests__/requestLogger.test.ts +443 -403
  182. package/src/server/__tests__/resources.template.test.ts +196 -185
  183. package/src/server/__tests__/resources.test.ts +294 -288
  184. package/src/server/__tests__/security.integration.test.ts +487 -421
  185. package/src/server/__tests__/securityMiddleware.test.ts +519 -444
  186. package/src/server/__tests__/server-startup.integration.test.ts +509 -490
  187. package/src/server/__tests__/serverKnowledgeStore.test.ts +174 -173
  188. package/src/server/__tests__/toolRegistration.test.ts +239 -210
  189. package/src/server/__tests__/toolRegistry.test.ts +907 -845
  190. package/src/server/budgetResolver.ts +221 -181
  191. package/src/server/cacheKeys.ts +6 -6
  192. package/src/server/cacheManager.ts +498 -484
  193. package/src/server/completions.ts +267 -243
  194. package/src/server/config.ts +35 -14
  195. package/src/server/deltaCache.merge.ts +146 -128
  196. package/src/server/deltaCache.ts +352 -309
  197. package/src/server/diagnostics.ts +257 -242
  198. package/src/server/errorHandler.ts +747 -744
  199. package/src/server/prompts.ts +181 -176
  200. package/src/server/rateLimiter.ts +131 -129
  201. package/src/server/requestLogger.ts +350 -322
  202. package/src/server/resources.ts +442 -374
  203. package/src/server/responseFormatter.ts +41 -37
  204. package/src/server/securityMiddleware.ts +223 -205
  205. package/src/server/serverKnowledgeStore.ts +67 -67
  206. package/src/server/toolRegistry.ts +508 -474
  207. package/src/tools/CLAUDE.md +604 -0
  208. package/src/tools/__tests__/accountTools.delta.integration.test.ts +128 -111
  209. package/src/tools/__tests__/accountTools.integration.test.ts +129 -111
  210. package/src/tools/__tests__/accountTools.test.ts +685 -638
  211. package/src/tools/__tests__/adapters.test.ts +142 -108
  212. package/src/tools/__tests__/budgetTools.delta.integration.test.ts +73 -73
  213. package/src/tools/__tests__/budgetTools.integration.test.ts +132 -124
  214. package/src/tools/__tests__/budgetTools.test.ts +442 -413
  215. package/src/tools/__tests__/categoryTools.delta.integration.test.ts +76 -68
  216. package/src/tools/__tests__/categoryTools.integration.test.ts +314 -288
  217. package/src/tools/__tests__/categoryTools.test.ts +656 -625
  218. package/src/tools/__tests__/compareTransactions/formatter.test.ts +535 -462
  219. package/src/tools/__tests__/compareTransactions/index.test.ts +378 -358
  220. package/src/tools/__tests__/compareTransactions/matcher.test.ts +497 -398
  221. package/src/tools/__tests__/compareTransactions/parser.test.ts +765 -747
  222. package/src/tools/__tests__/compareTransactions.test.ts +352 -332
  223. package/src/tools/__tests__/compareTransactions.window.test.ts +150 -146
  224. package/src/tools/__tests__/deltaFetcher.scheduled.integration.test.ts +69 -65
  225. package/src/tools/__tests__/deltaFetcher.test.ts +325 -265
  226. package/src/tools/__tests__/deltaSupport.test.ts +211 -184
  227. package/src/tools/__tests__/deltaTestUtils.ts +37 -33
  228. package/src/tools/__tests__/exportTransactions.test.ts +205 -200
  229. package/src/tools/__tests__/monthTools.delta.integration.test.ts +68 -68
  230. package/src/tools/__tests__/monthTools.integration.test.ts +178 -166
  231. package/src/tools/__tests__/monthTools.test.ts +561 -512
  232. package/src/tools/__tests__/payeeTools.delta.integration.test.ts +68 -68
  233. package/src/tools/__tests__/payeeTools.integration.test.ts +158 -142
  234. package/src/tools/__tests__/payeeTools.test.ts +486 -434
  235. package/src/tools/__tests__/transactionSchemas.test.ts +1202 -1186
  236. package/src/tools/__tests__/transactionTools.integration.test.ts +875 -825
  237. package/src/tools/__tests__/transactionTools.test.ts +4923 -4366
  238. package/src/tools/__tests__/transactionUtils.test.ts +1004 -977
  239. package/src/tools/__tests__/utilityTools.integration.test.ts +32 -32
  240. package/src/tools/__tests__/utilityTools.test.ts +68 -58
  241. package/src/tools/accountTools.ts +293 -271
  242. package/src/tools/adapters.ts +120 -63
  243. package/src/tools/budgetTools.ts +121 -116
  244. package/src/tools/categoryTools.ts +379 -339
  245. package/src/tools/compareTransactions/formatter.ts +131 -119
  246. package/src/tools/compareTransactions/index.ts +249 -214
  247. package/src/tools/compareTransactions/matcher.ts +259 -209
  248. package/src/tools/compareTransactions/parser.ts +517 -487
  249. package/src/tools/compareTransactions/types.ts +38 -38
  250. package/src/tools/compareTransactions.ts +1 -1
  251. package/src/tools/deltaFetcher.ts +281 -260
  252. package/src/tools/deltaSupport.ts +264 -259
  253. package/src/tools/exportTransactions.ts +230 -218
  254. package/src/tools/monthTools.ts +180 -165
  255. package/src/tools/payeeTools.ts +152 -140
  256. package/src/tools/reconcileAdapter.ts +297 -252
  257. package/src/tools/reconciliation/CLAUDE.md +506 -0
  258. package/src/tools/reconciliation/__tests__/adapter.causes.test.ts +133 -124
  259. package/src/tools/reconciliation/__tests__/adapter.test.ts +249 -230
  260. package/src/tools/reconciliation/__tests__/analyzer.test.ts +408 -400
  261. package/src/tools/reconciliation/__tests__/csvParser.test.ts +71 -69
  262. package/src/tools/reconciliation/__tests__/executor.integration.test.ts +348 -323
  263. package/src/tools/reconciliation/__tests__/executor.progress.test.ts +503 -457
  264. package/src/tools/reconciliation/__tests__/executor.test.ts +898 -831
  265. package/src/tools/reconciliation/__tests__/matcher.test.ts +667 -663
  266. package/src/tools/reconciliation/__tests__/payeeNormalizer.test.ts +296 -276
  267. package/src/tools/reconciliation/__tests__/recommendationEngine.integration.test.ts +692 -624
  268. package/src/tools/reconciliation/__tests__/recommendationEngine.test.ts +1008 -989
  269. package/src/tools/reconciliation/__tests__/reconciliation.delta.integration.test.ts +187 -146
  270. package/src/tools/reconciliation/__tests__/reportFormatter.test.ts +583 -533
  271. package/src/tools/reconciliation/__tests__/scenarios/adapterCurrency.scenario.test.ts +75 -74
  272. package/src/tools/reconciliation/__tests__/scenarios/extremes.scenario.test.ts +70 -62
  273. package/src/tools/reconciliation/__tests__/scenarios/repeatAmount.scenario.test.ts +102 -88
  274. package/src/tools/reconciliation/__tests__/schemaUrl.test.ts +56 -55
  275. package/src/tools/reconciliation/__tests__/signDetector.test.ts +209 -206
  276. package/src/tools/reconciliation/__tests__/ynabAdapter.test.ts +66 -60
  277. package/src/tools/reconciliation/analyzer.ts +564 -504
  278. package/src/tools/reconciliation/csvParser.ts +656 -609
  279. package/src/tools/reconciliation/executor.ts +1290 -1128
  280. package/src/tools/reconciliation/index.ts +580 -528
  281. package/src/tools/reconciliation/matcher.ts +256 -240
  282. package/src/tools/reconciliation/payeeNormalizer.ts +92 -78
  283. package/src/tools/reconciliation/recommendationEngine.ts +357 -345
  284. package/src/tools/reconciliation/reportFormatter.ts +343 -307
  285. package/src/tools/reconciliation/signDetector.ts +89 -83
  286. package/src/tools/reconciliation/types.ts +164 -159
  287. package/src/tools/reconciliation/ynabAdapter.ts +17 -15
  288. package/src/tools/schemas/CLAUDE.md +546 -0
  289. package/src/tools/schemas/common.ts +1 -1
  290. package/src/tools/schemas/outputs/__tests__/accountOutputs.test.ts +410 -409
  291. package/src/tools/schemas/outputs/__tests__/budgetOutputs.test.ts +305 -299
  292. package/src/tools/schemas/outputs/__tests__/categoryOutputs.test.ts +431 -430
  293. package/src/tools/schemas/outputs/__tests__/comparisonOutputs.test.ts +510 -495
  294. package/src/tools/schemas/outputs/__tests__/dateValidation.test.ts +179 -153
  295. package/src/tools/schemas/outputs/__tests__/discrepancyDirection.test.ts +293 -254
  296. package/src/tools/schemas/outputs/__tests__/monthOutputs.test.ts +457 -457
  297. package/src/tools/schemas/outputs/__tests__/payeeOutputs.test.ts +362 -356
  298. package/src/tools/schemas/outputs/__tests__/reconciliationOutputs.test.ts +402 -399
  299. package/src/tools/schemas/outputs/__tests__/transactionMutationSchemas.test.ts +225 -211
  300. package/src/tools/schemas/outputs/__tests__/transactionOutputs.test.ts +457 -454
  301. package/src/tools/schemas/outputs/__tests__/utilityOutputs.test.ts +316 -315
  302. package/src/tools/schemas/outputs/accountOutputs.ts +40 -34
  303. package/src/tools/schemas/outputs/budgetOutputs.ts +24 -19
  304. package/src/tools/schemas/outputs/categoryOutputs.ts +76 -56
  305. package/src/tools/schemas/outputs/comparisonOutputs.ts +192 -169
  306. package/src/tools/schemas/outputs/index.ts +163 -163
  307. package/src/tools/schemas/outputs/monthOutputs.ts +95 -80
  308. package/src/tools/schemas/outputs/payeeOutputs.ts +18 -18
  309. package/src/tools/schemas/outputs/reconciliationOutputs.ts +386 -373
  310. package/src/tools/schemas/outputs/transactionMutationOutputs.ts +259 -231
  311. package/src/tools/schemas/outputs/transactionOutputs.ts +81 -71
  312. package/src/tools/schemas/outputs/utilityOutputs.ts +90 -84
  313. package/src/tools/schemas/shared/commonOutputs.ts +27 -19
  314. package/src/tools/toolCategories.ts +114 -114
  315. package/src/tools/transactionReadTools.ts +327 -0
  316. package/src/tools/transactionSchemas.ts +322 -291
  317. package/src/tools/transactionTools.ts +84 -2246
  318. package/src/tools/transactionUtils.ts +507 -422
  319. package/src/tools/transactionWriteTools.ts +2110 -0
  320. package/src/tools/utilityTools.ts +46 -41
  321. package/src/types/CLAUDE.md +477 -0
  322. package/src/types/__tests__/index.test.ts +51 -51
  323. package/src/types/index.ts +43 -39
  324. package/src/types/integration-tests.d.ts +26 -26
  325. package/src/types/reconciliation.ts +29 -29
  326. package/src/types/toolAnnotations.ts +30 -30
  327. package/src/types/toolRegistration.ts +43 -32
  328. package/src/utils/CLAUDE.md +508 -0
  329. package/src/utils/__tests__/dateUtils.test.ts +174 -168
  330. package/src/utils/__tests__/money.test.ts +193 -187
  331. package/src/utils/amountUtils.ts +5 -5
  332. package/src/utils/baseError.ts +5 -5
  333. package/src/utils/dateUtils.ts +29 -26
  334. package/src/utils/errors.ts +14 -14
  335. package/src/utils/money.ts +66 -52
  336. package/src/utils/validationError.ts +1 -1
  337. package/tsconfig.json +29 -29
  338. package/tsconfig.prod.json +16 -16
  339. package/vitest-reporters/split-json-reporter.ts +247 -204
  340. package/vitest.config.ts +99 -95
  341. package/.prettierignore +0 -10
  342. package/.prettierrc.json +0 -10
  343. package/eslint.config.js +0 -49
@@ -1,248 +1,285 @@
1
- import { toMoneyValue, toMoneyValueFromDecimal } from '../utils/money.js';
1
+ import { toMoneyValue, toMoneyValueFromDecimal } from "../utils/money.js";
2
2
  import type {
3
- ReconciliationAnalysis,
4
- TransactionMatch,
5
- BankTransaction,
6
- YNABTransaction,
7
- ReconciliationInsight,
8
- } from './reconciliation/types.js';
9
- import type { LegacyReconciliationResult, AccountSnapshot } from './reconciliation/executor.js';
3
+ AccountSnapshot,
4
+ LegacyReconciliationResult,
5
+ } from "./reconciliation/executor.js";
10
6
  import {
11
- formatHumanReadableReport,
12
- type ReportFormatterOptions,
13
- } from './reconciliation/reportFormatter.js';
14
-
15
- const OUTPUT_VERSION = '2.0';
7
+ type ReportFormatterOptions,
8
+ formatHumanReadableReport,
9
+ } from "./reconciliation/reportFormatter.js";
10
+ import type {
11
+ BankTransaction,
12
+ ReconciliationAnalysis,
13
+ ReconciliationInsight,
14
+ TransactionMatch,
15
+ YNABTransaction,
16
+ } from "./reconciliation/types.js";
17
+
18
+ const OUTPUT_VERSION = "2.0";
16
19
  const SCHEMA_URL =
17
- 'https://raw.githubusercontent.com/dizzlkheinz/ynab-mcp-mcpb/master/docs/schemas/reconciliation-v2.json';
20
+ "https://raw.githubusercontent.com/dizzlkheinz/ynab-mcp-mcpb/master/docs/schemas/reconciliation-v2.json";
18
21
 
19
22
  interface AdapterOptions {
20
- accountName?: string;
21
- accountId?: string;
22
- currencyCode?: string;
23
- csvFormat?: CsvFormatPayload;
24
- auditMetadata?: Record<string, unknown>;
25
- notes?: string[];
23
+ accountName?: string;
24
+ accountId?: string;
25
+ currencyCode?: string;
26
+ csvFormat?: CsvFormatPayload;
27
+ auditMetadata?: Record<string, unknown>;
28
+ notes?: string[];
26
29
  }
27
30
 
28
31
  interface DualChannelPayload {
29
- human: string;
30
- structured: Record<string, unknown>;
32
+ human: string;
33
+ structured: Record<string, unknown>;
31
34
  }
32
35
 
33
36
  interface CsvFormatPayload {
34
- delimiter: string;
35
- decimal_separator: string;
36
- thousands_separator: string | null;
37
- date_format: string;
38
- header_row: boolean;
39
- date_column: string | null;
40
- amount_column: string | null;
41
- payee_column: string | null;
37
+ delimiter: string;
38
+ decimal_separator: string;
39
+ thousands_separator: string | null;
40
+ date_format: string;
41
+ header_row: boolean;
42
+ date_column: string | null;
43
+ amount_column: string | null;
44
+ payee_column: string | null;
42
45
  }
43
46
 
44
47
  interface LegacyPrecisionCalculations {
45
- bank_statement_balance_milliunits: number;
46
- ynab_calculated_balance_milliunits: number;
47
- discrepancy_milliunits: number;
48
- discrepancy_dollars: number;
48
+ bank_statement_balance_milliunits: number;
49
+ ynab_calculated_balance_milliunits: number;
50
+ discrepancy_milliunits: number;
51
+ discrepancy_dollars: number;
49
52
  }
50
53
 
51
54
  interface LegacyLikelyCause {
52
- cause_type: string;
53
- description: string;
54
- confidence: number;
55
- amount_milliunits: number;
56
- suggested_resolution: string;
57
- evidence: unknown[];
55
+ cause_type: string;
56
+ description: string;
57
+ confidence: number;
58
+ amount_milliunits: number;
59
+ suggested_resolution: string;
60
+ evidence: unknown[];
58
61
  }
59
62
 
60
63
  interface LegacyBalanceReconciliation {
61
- status: string;
62
- precision_calculations?: LegacyPrecisionCalculations;
63
- discrepancy_analysis?:
64
- | {
65
- confidence_level: number;
66
- likely_causes: LegacyLikelyCause[];
67
- risk_assessment: string;
68
- }
69
- | undefined;
70
- final_verification?: {
71
- balance_matches_exactly: boolean;
72
- all_transactions_accounted: boolean;
73
- audit_trail_complete: boolean;
74
- reconciliation_complete: boolean;
75
- };
64
+ status: string;
65
+ precision_calculations?: LegacyPrecisionCalculations;
66
+ discrepancy_analysis?:
67
+ | {
68
+ confidence_level: number;
69
+ likely_causes: LegacyLikelyCause[];
70
+ risk_assessment: string;
71
+ }
72
+ | undefined;
73
+ final_verification?: {
74
+ balance_matches_exactly: boolean;
75
+ all_transactions_accounted: boolean;
76
+ audit_trail_complete: boolean;
77
+ reconciliation_complete: boolean;
78
+ };
76
79
  }
77
80
 
81
+ type LegacyBalanceReconciliationView = {
82
+ status: string;
83
+ precision_calculations?: ReturnType<typeof convertPrecisionCalculations>;
84
+ discrepancy_analysis?: ReturnType<typeof convertLikelyCausesLegacy>;
85
+ final_verification?: LegacyBalanceReconciliation["final_verification"];
86
+ };
87
+
78
88
  const toBankTransactionView = (txn: BankTransaction, currency: string) => ({
79
- ...txn,
80
- amount_money: toMoneyValue(txn.amount, currency),
89
+ ...txn,
90
+ amount_money: toMoneyValue(txn.amount, currency),
81
91
  });
82
92
 
83
93
  const toYNABTransactionView = (txn: YNABTransaction, currency: string) => ({
84
- ...txn,
85
- amount_money: toMoneyValue(txn.amount, currency),
94
+ ...txn,
95
+ amount_money: toMoneyValue(txn.amount, currency),
86
96
  });
87
97
 
88
98
  const convertMatch = (match: TransactionMatch, currency: string) => ({
89
- bank_transaction: toBankTransactionView(match.bankTransaction, currency),
90
- ynab_transaction: match.ynabTransaction
91
- ? toYNABTransactionView(match.ynabTransaction, currency)
92
- : undefined,
93
- candidates: match.candidates?.map((candidate) => ({
94
- ...candidate,
95
- ynab_transaction: toYNABTransactionView(candidate.ynab_transaction, currency),
96
- })),
97
- confidence: match.confidence,
98
- confidence_score: match.confidenceScore,
99
- match_reason: match.matchReason,
100
- top_confidence: match.topConfidence,
101
- action_hint: match.actionHint,
102
- recommendation: match.recommendation,
99
+ bank_transaction: toBankTransactionView(match.bankTransaction, currency),
100
+ ynab_transaction: match.ynabTransaction
101
+ ? toYNABTransactionView(match.ynabTransaction, currency)
102
+ : undefined,
103
+ candidates: match.candidates?.map((candidate) => ({
104
+ ...candidate,
105
+ ynab_transaction: toYNABTransactionView(
106
+ candidate.ynab_transaction,
107
+ currency,
108
+ ),
109
+ })),
110
+ confidence: match.confidence,
111
+ confidence_score: match.confidenceScore,
112
+ match_reason: match.matchReason,
113
+ top_confidence: match.topConfidence,
114
+ action_hint: match.actionHint,
115
+ recommendation: match.recommendation,
103
116
  });
104
117
 
105
118
  const convertInsight = (insight: ReconciliationInsight) => ({
106
- id: insight.id,
107
- type: insight.type,
108
- severity: insight.severity,
109
- title: insight.title,
110
- description: insight.description,
111
- evidence: insight.evidence ?? {},
119
+ id: insight.id,
120
+ type: insight.type,
121
+ severity: insight.severity,
122
+ title: insight.title,
123
+ description: insight.description,
124
+ evidence: insight.evidence ?? {},
112
125
  });
113
126
 
114
127
  const convertSummary = (analysis: ReconciliationAnalysis) => ({
115
- statement_date_range: analysis.summary.statement_date_range,
116
- bank_transactions_count: analysis.summary.bank_transactions_count,
117
- ynab_transactions_count: analysis.summary.ynab_transactions_count,
118
- ynab_in_range_count:
119
- analysis.summary.ynab_in_range_count ?? analysis.summary.ynab_transactions_count,
120
- ynab_outside_range_count: analysis.summary.ynab_outside_range_count ?? 0,
121
- auto_matched: analysis.summary.auto_matched,
122
- suggested_matches: analysis.summary.suggested_matches,
123
- unmatched_bank: analysis.summary.unmatched_bank,
124
- unmatched_ynab: analysis.summary.unmatched_ynab,
125
- current_cleared_balance: analysis.summary.current_cleared_balance,
126
- target_statement_balance: analysis.summary.target_statement_balance,
127
- discrepancy: analysis.summary.discrepancy,
128
- discrepancy_explanation: analysis.summary.discrepancy_explanation,
128
+ statement_date_range: analysis.summary.statement_date_range,
129
+ bank_transactions_count: analysis.summary.bank_transactions_count,
130
+ ynab_transactions_count: analysis.summary.ynab_transactions_count,
131
+ ynab_in_range_count:
132
+ analysis.summary.ynab_in_range_count ??
133
+ analysis.summary.ynab_transactions_count,
134
+ ynab_outside_range_count: analysis.summary.ynab_outside_range_count ?? 0,
135
+ auto_matched: analysis.summary.auto_matched,
136
+ suggested_matches: analysis.summary.suggested_matches,
137
+ unmatched_bank: analysis.summary.unmatched_bank,
138
+ unmatched_ynab: analysis.summary.unmatched_ynab,
139
+ current_cleared_balance: analysis.summary.current_cleared_balance,
140
+ target_statement_balance: analysis.summary.target_statement_balance,
141
+ discrepancy: analysis.summary.discrepancy,
142
+ discrepancy_explanation: analysis.summary.discrepancy_explanation,
129
143
  });
130
144
 
131
145
  const convertBalanceInfo = (analysis: ReconciliationAnalysis) => {
132
- const discrepancyMilli = analysis.balance_info.discrepancy.value_milliunits;
133
- const direction =
134
- discrepancyMilli === 0 ? 'balanced' : discrepancyMilli > 0 ? 'ynab_higher' : 'bank_higher';
135
-
136
- return {
137
- current_cleared: analysis.balance_info.current_cleared,
138
- current_uncleared: analysis.balance_info.current_uncleared,
139
- current_total: analysis.balance_info.current_total,
140
- target_statement: analysis.balance_info.target_statement,
141
- discrepancy: analysis.balance_info.discrepancy,
142
- discrepancy_direction: direction,
143
- on_track: analysis.balance_info.on_track,
144
- };
146
+ const discrepancyMilli = analysis.balance_info.discrepancy.value_milliunits;
147
+ const direction =
148
+ discrepancyMilli === 0
149
+ ? "balanced"
150
+ : discrepancyMilli > 0
151
+ ? "ynab_higher"
152
+ : "bank_higher";
153
+
154
+ return {
155
+ current_cleared: analysis.balance_info.current_cleared,
156
+ current_uncleared: analysis.balance_info.current_uncleared,
157
+ current_total: analysis.balance_info.current_total,
158
+ target_statement: analysis.balance_info.target_statement,
159
+ discrepancy: analysis.balance_info.discrepancy,
160
+ discrepancy_direction: direction,
161
+ on_track: analysis.balance_info.on_track,
162
+ };
145
163
  };
146
164
 
147
- const convertAccountSnapshot = (snapshot: AccountSnapshot, currency: string) => ({
148
- balance: toMoneyValue(snapshot.balance, currency),
149
- cleared_balance: toMoneyValue(snapshot.cleared_balance, currency),
150
- uncleared_balance: toMoneyValue(snapshot.uncleared_balance, currency),
165
+ const convertAccountSnapshot = (
166
+ snapshot: AccountSnapshot,
167
+ currency: string,
168
+ ) => ({
169
+ balance: toMoneyValue(snapshot.balance, currency),
170
+ cleared_balance: toMoneyValue(snapshot.cleared_balance, currency),
171
+ uncleared_balance: toMoneyValue(snapshot.uncleared_balance, currency),
151
172
  });
152
173
 
153
174
  const convertPrecisionCalculations = (
154
- precision: LegacyPrecisionCalculations,
155
- currency: string,
175
+ precision: LegacyPrecisionCalculations,
176
+ currency: string,
156
177
  ) => ({
157
- bank_statement_balance: toMoneyValue(precision.bank_statement_balance_milliunits, currency),
158
- ynab_calculated_balance: toMoneyValue(precision.ynab_calculated_balance_milliunits, currency),
159
- discrepancy: toMoneyValue(precision.discrepancy_milliunits, currency),
160
- discrepancy_decimal: toMoneyValueFromDecimal(precision.discrepancy_dollars, currency),
178
+ bank_statement_balance: toMoneyValue(
179
+ precision.bank_statement_balance_milliunits,
180
+ currency,
181
+ ),
182
+ ynab_calculated_balance: toMoneyValue(
183
+ precision.ynab_calculated_balance_milliunits,
184
+ currency,
185
+ ),
186
+ discrepancy: toMoneyValue(precision.discrepancy_milliunits, currency),
187
+ discrepancy_decimal: toMoneyValueFromDecimal(
188
+ precision.discrepancy_dollars,
189
+ currency,
190
+ ),
161
191
  });
162
192
 
163
193
  const convertLikelyCausesLegacy = (
164
- analysis: NonNullable<LegacyBalanceReconciliation['discrepancy_analysis']>,
165
- currency: string,
194
+ analysis: NonNullable<LegacyBalanceReconciliation["discrepancy_analysis"]>,
195
+ currency: string,
166
196
  ) => ({
167
- confidence_level: analysis.confidence_level,
168
- risk_assessment: analysis.risk_assessment,
169
- likely_causes: analysis.likely_causes.map((cause) => ({
170
- type: cause.cause_type.toLowerCase(),
171
- description: cause.description,
172
- confidence: cause.confidence,
173
- suggested_action: cause.suggested_resolution,
174
- amount: toMoneyValue(cause.amount_milliunits, currency),
175
- evidence: cause.evidence,
176
- })),
197
+ confidence_level: analysis.confidence_level,
198
+ risk_assessment: analysis.risk_assessment,
199
+ likely_causes: analysis.likely_causes.map((cause) => ({
200
+ type: cause.cause_type.toLowerCase(),
201
+ description: cause.description,
202
+ confidence: cause.confidence,
203
+ suggested_action: cause.suggested_resolution,
204
+ amount: toMoneyValue(cause.amount_milliunits, currency),
205
+ evidence: cause.evidence,
206
+ })),
177
207
  });
178
208
 
179
209
  const convertBalanceReconciliationLegacy = (
180
- balance: LegacyBalanceReconciliation | undefined,
181
- currency: string,
210
+ balance: LegacyBalanceReconciliation | undefined,
211
+ currency: string,
182
212
  ) => {
183
- if (!balance) return undefined;
184
-
185
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
186
- const result: any = {
187
- status: balance.status,
188
- };
189
-
190
- if (balance.precision_calculations) {
191
- result.precision_calculations = convertPrecisionCalculations(
192
- balance.precision_calculations,
193
- currency,
194
- );
195
- }
196
-
197
- if (balance.discrepancy_analysis) {
198
- result.discrepancy_analysis = convertLikelyCausesLegacy(balance.discrepancy_analysis, currency);
199
- }
200
-
201
- if (balance.final_verification) {
202
- result.final_verification = balance.final_verification;
203
- }
204
-
205
- return result;
213
+ if (!balance) return undefined;
214
+
215
+ const result: LegacyBalanceReconciliationView = {
216
+ status: balance.status,
217
+ };
218
+
219
+ if (balance.precision_calculations) {
220
+ result.precision_calculations = convertPrecisionCalculations(
221
+ balance.precision_calculations,
222
+ currency,
223
+ );
224
+ }
225
+
226
+ if (balance.discrepancy_analysis) {
227
+ result.discrepancy_analysis = convertLikelyCausesLegacy(
228
+ balance.discrepancy_analysis,
229
+ currency,
230
+ );
231
+ }
232
+
233
+ if (balance.final_verification) {
234
+ result.final_verification = balance.final_verification;
235
+ }
236
+
237
+ return result;
206
238
  };
207
239
 
208
240
  interface ConvertedExecutionResult {
209
- summary: LegacyReconciliationResult['summary'];
210
- account_balance: {
211
- before: ReturnType<typeof convertAccountSnapshot>;
212
- after: ReturnType<typeof convertAccountSnapshot>;
213
- };
214
- actions_taken: LegacyReconciliationResult['actions_taken'];
215
- recommendations: LegacyReconciliationResult['recommendations'];
216
- balance_reconciliation?: ReturnType<typeof convertBalanceReconciliationLegacy>;
217
- bulk_operation_details?: LegacyReconciliationResult['bulk_operation_details'];
241
+ summary: LegacyReconciliationResult["summary"];
242
+ account_balance: {
243
+ before: ReturnType<typeof convertAccountSnapshot>;
244
+ after: ReturnType<typeof convertAccountSnapshot>;
245
+ };
246
+ actions_taken: LegacyReconciliationResult["actions_taken"];
247
+ recommendations: LegacyReconciliationResult["recommendations"];
248
+ balance_reconciliation?: ReturnType<
249
+ typeof convertBalanceReconciliationLegacy
250
+ >;
251
+ bulk_operation_details?: LegacyReconciliationResult["bulk_operation_details"];
218
252
  }
219
253
 
220
254
  const convertExecution = (
221
- execution: LegacyReconciliationResult,
222
- currency: string,
255
+ execution: LegacyReconciliationResult,
256
+ currency: string,
223
257
  ): ConvertedExecutionResult => {
224
- const result: ConvertedExecutionResult = {
225
- summary: execution.summary,
226
- account_balance: {
227
- before: convertAccountSnapshot(execution.account_balance.before, currency),
228
- after: convertAccountSnapshot(execution.account_balance.after, currency),
229
- },
230
- actions_taken: execution.actions_taken,
231
- recommendations: execution.recommendations,
232
- };
233
-
234
- if (execution.balance_reconciliation) {
235
- result.balance_reconciliation = convertBalanceReconciliationLegacy(
236
- execution.balance_reconciliation,
237
- currency,
238
- );
239
- }
240
-
241
- if (execution.bulk_operation_details) {
242
- result.bulk_operation_details = execution.bulk_operation_details;
243
- }
244
-
245
- return result;
258
+ const result: ConvertedExecutionResult = {
259
+ summary: execution.summary,
260
+ account_balance: {
261
+ before: convertAccountSnapshot(
262
+ execution.account_balance.before,
263
+ currency,
264
+ ),
265
+ after: convertAccountSnapshot(execution.account_balance.after, currency),
266
+ },
267
+ actions_taken: execution.actions_taken,
268
+ recommendations: execution.recommendations,
269
+ };
270
+
271
+ if (execution.balance_reconciliation) {
272
+ result.balance_reconciliation = convertBalanceReconciliationLegacy(
273
+ execution.balance_reconciliation,
274
+ currency,
275
+ );
276
+ }
277
+
278
+ if (execution.bulk_operation_details) {
279
+ result.bulk_operation_details = execution.bulk_operation_details;
280
+ }
281
+
282
+ return result;
246
283
  };
247
284
 
248
285
  // Helper functions for converting data structures (kept for structured output)
@@ -251,75 +288,83 @@ const convertExecution = (
251
288
  * Build human-readable narrative using the comprehensive report formatter
252
289
  */
253
290
  const buildHumanNarrative = (
254
- analysis: ReconciliationAnalysis,
255
- options: AdapterOptions,
256
- execution?: LegacyReconciliationResult,
291
+ analysis: ReconciliationAnalysis,
292
+ options: AdapterOptions,
293
+ execution?: LegacyReconciliationResult,
257
294
  ): string => {
258
- const formatterOptions: ReportFormatterOptions = {
259
- accountName: options.accountName,
260
- accountId: options.accountId,
261
- currencyCode: options.currencyCode,
262
- includeDetailedMatches: false,
263
- maxUnmatchedToShow: 5,
264
- maxInsightsToShow: 3,
265
- notes: options.notes,
266
- };
267
-
268
- return formatHumanReadableReport(analysis, formatterOptions, execution);
295
+ const formatterOptions: ReportFormatterOptions = {
296
+ accountName: options.accountName,
297
+ accountId: options.accountId,
298
+ currencyCode: options.currencyCode,
299
+ includeDetailedMatches: false,
300
+ maxUnmatchedToShow: 5,
301
+ maxInsightsToShow: 3,
302
+ notes: options.notes,
303
+ };
304
+
305
+ return formatHumanReadableReport(analysis, formatterOptions, execution);
269
306
  };
270
307
 
271
308
  export const buildReconciliationPayload = (
272
- analysis: ReconciliationAnalysis,
273
- options: AdapterOptions = {},
274
- execution?: LegacyReconciliationResult,
309
+ analysis: ReconciliationAnalysis,
310
+ options: AdapterOptions = {},
311
+ execution?: LegacyReconciliationResult,
275
312
  ): DualChannelPayload => {
276
- const currency = options.currencyCode ?? 'USD';
277
- const executionView = execution ? convertExecution(execution, currency) : undefined;
278
-
279
- const structured: Record<string, unknown> = {
280
- version: OUTPUT_VERSION,
281
- schema_url: SCHEMA_URL,
282
- generated_at: new Date().toISOString(),
283
- account: {
284
- id: options.accountId,
285
- name: options.accountName,
286
- },
287
- summary: convertSummary(analysis),
288
- balance: convertBalanceInfo(analysis),
289
- insights: analysis.insights.map(convertInsight),
290
- next_steps: analysis.next_steps,
291
- matches: {
292
- auto: analysis.auto_matches.map((match) => convertMatch(match, currency)),
293
- suggested: analysis.suggested_matches.map((match) => convertMatch(match, currency)),
294
- },
295
- unmatched: {
296
- bank: analysis.unmatched_bank.map((txn) => toBankTransactionView(txn, currency)),
297
- ynab: analysis.unmatched_ynab.map((txn) => toYNABTransactionView(txn, currency)),
298
- ynab_outside_date_range: (analysis.ynab_outside_date_range ?? []).map((txn) =>
299
- toYNABTransactionView(txn, currency),
300
- ),
301
- },
302
- };
303
-
304
- // Include recommendations if available
305
- if (analysis.recommendations && analysis.recommendations.length > 0) {
306
- structured['recommendations'] = analysis.recommendations;
307
- }
308
-
309
- if (options.csvFormat) {
310
- structured['csv_format'] = options.csvFormat;
311
- }
312
-
313
- if (executionView) {
314
- structured['execution'] = executionView;
315
- }
316
-
317
- if (options.auditMetadata) {
318
- structured['audit'] = options.auditMetadata;
319
- }
320
-
321
- return {
322
- human: buildHumanNarrative(analysis, options, execution),
323
- structured,
324
- };
313
+ const currency = options.currencyCode ?? "USD";
314
+ const executionView = execution
315
+ ? convertExecution(execution, currency)
316
+ : undefined;
317
+
318
+ const structured: Record<string, unknown> = {
319
+ version: OUTPUT_VERSION,
320
+ schema_url: SCHEMA_URL,
321
+ generated_at: new Date().toISOString(),
322
+ account: {
323
+ id: options.accountId,
324
+ name: options.accountName,
325
+ },
326
+ summary: convertSummary(analysis),
327
+ balance: convertBalanceInfo(analysis),
328
+ insights: analysis.insights.map(convertInsight),
329
+ next_steps: analysis.next_steps,
330
+ matches: {
331
+ auto: analysis.auto_matches.map((match) => convertMatch(match, currency)),
332
+ suggested: analysis.suggested_matches.map((match) =>
333
+ convertMatch(match, currency),
334
+ ),
335
+ },
336
+ unmatched: {
337
+ bank: analysis.unmatched_bank.map((txn) =>
338
+ toBankTransactionView(txn, currency),
339
+ ),
340
+ ynab: analysis.unmatched_ynab.map((txn) =>
341
+ toYNABTransactionView(txn, currency),
342
+ ),
343
+ ynab_outside_date_range: (analysis.ynab_outside_date_range ?? []).map(
344
+ (txn) => toYNABTransactionView(txn, currency),
345
+ ),
346
+ },
347
+ };
348
+
349
+ // Include recommendations if available
350
+ if (analysis.recommendations && analysis.recommendations.length > 0) {
351
+ structured["recommendations"] = analysis.recommendations;
352
+ }
353
+
354
+ if (options.csvFormat) {
355
+ structured["csv_format"] = options.csvFormat;
356
+ }
357
+
358
+ if (executionView) {
359
+ structured["execution"] = executionView;
360
+ }
361
+
362
+ if (options.auditMetadata) {
363
+ structured["audit"] = options.auditMetadata;
364
+ }
365
+
366
+ return {
367
+ human: buildHumanNarrative(analysis, options, execution),
368
+ structured,
369
+ };
325
370
  };