@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
@@ -5,12 +5,15 @@
5
5
  * bank amounts need to be inverted to match YNAB's sign convention.
6
6
  */
7
7
 
8
- import type { BankTransaction, NormalizedYNABTransaction } from '../../types/reconciliation.js';
8
+ import type {
9
+ BankTransaction,
10
+ NormalizedYNABTransaction,
11
+ } from "../../types/reconciliation.js";
9
12
 
10
13
  interface SignMatch {
11
- bankAmount: number;
12
- ynabAmount: number;
13
- oppositeSign: boolean;
14
+ bankAmount: number;
15
+ ynabAmount: number;
16
+ oppositeSign: boolean;
14
17
  }
15
18
 
16
19
  /**
@@ -27,91 +30,94 @@ interface SignMatch {
27
30
  * @returns true if bank amounts should be inverted, false otherwise
28
31
  */
29
32
  export function detectSignInversion(
30
- bankTransactions: BankTransaction[],
31
- ynabTransactions: NormalizedYNABTransaction[],
33
+ bankTransactions: BankTransaction[],
34
+ ynabTransactions: NormalizedYNABTransaction[],
32
35
  ): boolean {
33
- // Edge cases: empty lists
34
- if (bankTransactions.length === 0 || ynabTransactions.length === 0) {
35
- return false; // Conservative default: don't invert
36
- }
37
-
38
- // Sample up to 20 transactions for performance
39
- const sampleSize = Math.min(20, bankTransactions.length);
40
- const sample = bankTransactions.slice(0, sampleSize);
41
-
42
- const matches: SignMatch[] = [];
43
-
44
- // Try to find matches for each bank transaction
45
- for (const bankTxn of sample) {
46
- const match = findClosestMatch(bankTxn, ynabTransactions);
47
- if (match) {
48
- matches.push(match);
49
- }
50
- }
51
-
52
- // Need at least 1 match to make a determination
53
- if (matches.length === 0) {
54
- return false; // Conservative default: don't invert
55
- }
56
-
57
- // Count how many matches have opposite signs
58
- const oppositeSignCount = matches.filter((m) => m.oppositeSign).length;
59
- const oppositeSignRatio = oppositeSignCount / matches.length;
60
-
61
- // If more than 50% have opposite signs, inversion is needed
62
- return oppositeSignRatio > 0.5;
36
+ // Edge cases: empty lists
37
+ if (bankTransactions.length === 0 || ynabTransactions.length === 0) {
38
+ return false; // Conservative default: don't invert
39
+ }
40
+
41
+ // Sample up to 20 transactions for performance
42
+ const sampleSize = Math.min(20, bankTransactions.length);
43
+ const sample = bankTransactions.slice(0, sampleSize);
44
+
45
+ const matches: SignMatch[] = [];
46
+
47
+ // Try to find matches for each bank transaction
48
+ for (const bankTxn of sample) {
49
+ const match = findClosestMatch(bankTxn, ynabTransactions);
50
+ if (match) {
51
+ matches.push(match);
52
+ }
53
+ }
54
+
55
+ // Need at least 1 match to make a determination
56
+ if (matches.length === 0) {
57
+ return false; // Conservative default: don't invert
58
+ }
59
+
60
+ // Count how many matches have opposite signs
61
+ const oppositeSignCount = matches.filter((m) => m.oppositeSign).length;
62
+ const oppositeSignRatio = oppositeSignCount / matches.length;
63
+
64
+ // If more than 50% have opposite signs, inversion is needed
65
+ return oppositeSignRatio > 0.5;
63
66
  }
64
67
 
65
68
  /**
66
69
  * Find the closest matching YNAB transaction for a bank transaction
67
70
  */
68
71
  function findClosestMatch(
69
- bankTxn: BankTransaction,
70
- ynabTransactions: NormalizedYNABTransaction[],
72
+ bankTxn: BankTransaction,
73
+ ynabTransactions: NormalizedYNABTransaction[],
71
74
  ): SignMatch | null {
72
- const bankDate = new Date(bankTxn.date);
73
- const bankAbsAmount = Math.abs(bankTxn.amount);
74
-
75
- let bestMatch: SignMatch | null = null;
76
- let bestScore = 0;
77
-
78
- for (const ynabTxn of ynabTransactions) {
79
- const ynabDate = new Date(ynabTxn.date);
80
- const ynabAbsAmount = Math.abs(ynabTxn.amount);
81
-
82
- // Check if amounts match (within tolerance)
83
- const amountDiff = Math.abs(bankAbsAmount - ynabAbsAmount);
84
- const amountTolerance = 100; // 10 cents in milliunits
85
- if (amountDiff > amountTolerance) {
86
- continue; // Amounts too different
87
- }
88
-
89
- // Check date proximity
90
- const daysDiff = Math.abs(bankDate.getTime() - ynabDate.getTime()) / (1000 * 60 * 60 * 24);
91
- if (daysDiff > 7) {
92
- continue; // Dates too far apart
93
- }
94
-
95
- // Calculate match score (closer = higher score)
96
- const amountScore = amountDiff === 0 ? 100 : Math.max(0, 100 - amountDiff / 10);
97
- const dateScore = daysDiff === 0 ? 100 : Math.max(0, 100 - daysDiff * 10);
98
- const score = amountScore * 0.7 + dateScore * 0.3;
99
-
100
- if (score > bestScore) {
101
- bestScore = score;
102
-
103
- // Check if signs are opposite
104
- const bankSign = Math.sign(bankTxn.amount);
105
- const ynabSign = Math.sign(ynabTxn.amount);
106
- const oppositeSign = bankSign !== 0 && ynabSign !== 0 && bankSign !== ynabSign;
107
-
108
- bestMatch = {
109
- bankAmount: bankTxn.amount,
110
- ynabAmount: ynabTxn.amount,
111
- oppositeSign,
112
- };
113
- }
114
- }
115
-
116
- return bestMatch;
75
+ const bankDate = new Date(bankTxn.date);
76
+ const bankAbsAmount = Math.abs(bankTxn.amount);
77
+
78
+ let bestMatch: SignMatch | null = null;
79
+ let bestScore = 0;
80
+
81
+ for (const ynabTxn of ynabTransactions) {
82
+ const ynabDate = new Date(ynabTxn.date);
83
+ const ynabAbsAmount = Math.abs(ynabTxn.amount);
84
+
85
+ // Check if amounts match (within tolerance)
86
+ const amountDiff = Math.abs(bankAbsAmount - ynabAbsAmount);
87
+ const amountTolerance = 100; // 10 cents in milliunits
88
+ if (amountDiff > amountTolerance) {
89
+ continue; // Amounts too different
90
+ }
91
+
92
+ // Check date proximity
93
+ const daysDiff =
94
+ Math.abs(bankDate.getTime() - ynabDate.getTime()) / (1000 * 60 * 60 * 24);
95
+ if (daysDiff > 7) {
96
+ continue; // Dates too far apart
97
+ }
98
+
99
+ // Calculate match score (closer = higher score)
100
+ const amountScore =
101
+ amountDiff === 0 ? 100 : Math.max(0, 100 - amountDiff / 10);
102
+ const dateScore = daysDiff === 0 ? 100 : Math.max(0, 100 - daysDiff * 10);
103
+ const score = amountScore * 0.7 + dateScore * 0.3;
104
+
105
+ if (score > bestScore) {
106
+ bestScore = score;
107
+
108
+ // Check if signs are opposite
109
+ const bankSign = Math.sign(bankTxn.amount);
110
+ const ynabSign = Math.sign(ynabTxn.amount);
111
+ const oppositeSign =
112
+ bankSign !== 0 && ynabSign !== 0 && bankSign !== ynabSign;
113
+
114
+ bestMatch = {
115
+ bankAmount: bankTxn.amount,
116
+ ynabAmount: ynabTxn.amount,
117
+ oppositeSign,
118
+ };
119
+ }
120
+ }
121
+
122
+ return bestMatch;
117
123
  }
@@ -8,11 +8,11 @@
8
8
  * All internal calculations use milliunits to avoid floating-point errors.
9
9
  */
10
10
 
11
- import type { MoneyValue } from '../../utils/money.js';
12
11
  import type {
13
- BankTransaction as CanonicalBankTransaction,
14
- NormalizedYNABTransaction as CanonicalYNABTransaction,
15
- } from '../../types/reconciliation.js';
12
+ BankTransaction as CanonicalBankTransaction,
13
+ NormalizedYNABTransaction as CanonicalYNABTransaction,
14
+ } from "../../types/reconciliation.js";
15
+ import type { MoneyValue } from "../../utils/money.js";
16
16
 
17
17
  // Re-export canonical types as the standard types
18
18
  export type BankTransaction = CanonicalBankTransaction;
@@ -21,278 +21,283 @@ export type YNABTransaction = CanonicalYNABTransaction;
21
21
  /**
22
22
  * Matching confidence levels
23
23
  */
24
- export type MatchConfidence = 'high' | 'medium' | 'low' | 'none';
24
+ export type MatchConfidence = "high" | "medium" | "low" | "none";
25
25
 
26
26
  /**
27
27
  * Match candidate with confidence score
28
28
  */
29
29
  export interface MatchCandidate {
30
- ynab_transaction: YNABTransaction;
31
- confidence: number;
32
- match_reason: string;
33
- explanation: string;
30
+ ynab_transaction: YNABTransaction;
31
+ confidence: number;
32
+ match_reason: string;
33
+ explanation: string;
34
34
  }
35
35
 
36
36
  /**
37
37
  * Transaction match result
38
38
  */
39
39
  export interface TransactionMatch {
40
- bankTransaction: BankTransaction;
41
- /** Best matched YNAB transaction (if any) */
42
- ynabTransaction?: YNABTransaction;
43
- /** Alternative candidates for suggested matches */
44
- candidates?: MatchCandidate[];
45
- /** Confidence level */
46
- confidence: MatchConfidence;
47
- /** Confidence score 0-100 */
48
- confidenceScore: number;
49
- /** Reason for the match */
50
- matchReason: string;
51
- /** Top confidence from candidates */
52
- topConfidence?: number;
53
- /** Action hint for user */
54
- actionHint?: string;
55
- /** Recommendation text */
56
- recommendation?: string;
40
+ bankTransaction: BankTransaction;
41
+ /** Best matched YNAB transaction (if any) */
42
+ ynabTransaction?: YNABTransaction;
43
+ /** Alternative candidates for suggested matches */
44
+ candidates?: MatchCandidate[];
45
+ /** Confidence level */
46
+ confidence: MatchConfidence;
47
+ /** Confidence score 0-100 */
48
+ confidenceScore: number;
49
+ /** Reason for the match */
50
+ matchReason: string;
51
+ /** Top confidence from candidates */
52
+ topConfidence?: number;
53
+ /** Action hint for user */
54
+ actionHint?: string;
55
+ /** Recommendation text */
56
+ recommendation?: string;
57
57
  }
58
58
 
59
59
  /**
60
60
  * Balance information with structured monetary values
61
61
  */
62
62
  export interface BalanceInfo {
63
- current_cleared: MoneyValue;
64
- current_uncleared: MoneyValue;
65
- current_total: MoneyValue;
66
- target_statement: MoneyValue;
67
- discrepancy: MoneyValue;
68
- on_track: boolean;
63
+ current_cleared: MoneyValue;
64
+ current_uncleared: MoneyValue;
65
+ current_total: MoneyValue;
66
+ target_statement: MoneyValue;
67
+ discrepancy: MoneyValue;
68
+ on_track: boolean;
69
69
  }
70
70
 
71
71
  /**
72
72
  * Reconciliation summary statistics with structured monetary values
73
73
  */
74
74
  export interface ReconciliationSummary {
75
- statement_date_range: string;
76
- bank_transactions_count: number;
77
- ynab_transactions_count: number;
78
- /** YNAB transactions within the statement date range (used for matching) */
79
- ynab_in_range_count: number;
80
- /** YNAB transactions outside the statement date range (not compared) */
81
- ynab_outside_range_count: number;
82
- auto_matched: number;
83
- suggested_matches: number;
84
- unmatched_bank: number;
85
- unmatched_ynab: number;
86
- current_cleared_balance: MoneyValue;
87
- target_statement_balance: MoneyValue;
88
- discrepancy: MoneyValue;
89
- discrepancy_explanation: string;
75
+ statement_date_range: string;
76
+ bank_transactions_count: number;
77
+ ynab_transactions_count: number;
78
+ /** YNAB transactions within the statement date range (used for matching) */
79
+ ynab_in_range_count: number;
80
+ /** YNAB transactions outside the statement date range (not compared) */
81
+ ynab_outside_range_count: number;
82
+ auto_matched: number;
83
+ suggested_matches: number;
84
+ unmatched_bank: number;
85
+ unmatched_ynab: number;
86
+ current_cleared_balance: MoneyValue;
87
+ target_statement_balance: MoneyValue;
88
+ discrepancy: MoneyValue;
89
+ discrepancy_explanation: string;
90
90
  }
91
91
 
92
92
  /**
93
93
  * Insight severity levels
94
94
  */
95
- export type InsightSeverity = 'info' | 'warning' | 'critical';
95
+ export type InsightSeverity = "info" | "warning" | "critical";
96
96
 
97
97
  /**
98
98
  * Insight types for reconciliation analysis
99
99
  */
100
- export type InsightKind = 'repeat_amount' | 'near_match' | 'anomaly';
100
+ export type InsightKind = "repeat_amount" | "near_match" | "anomaly";
101
101
 
102
102
  /**
103
103
  * Reconciliation insight - highlights important findings that help explain discrepancies
104
104
  */
105
105
  export interface ReconciliationInsight {
106
- id: string;
107
- type: InsightKind;
108
- severity: InsightSeverity;
109
- title: string;
110
- description: string;
111
- evidence?: Record<string, unknown>;
106
+ id: string;
107
+ type: InsightKind;
108
+ severity: InsightSeverity;
109
+ title: string;
110
+ description: string;
111
+ evidence?: Record<string, unknown>;
112
112
  }
113
113
 
114
114
  /**
115
115
  * Analysis phase result
116
116
  */
117
117
  export interface ReconciliationAnalysis {
118
- success: true;
119
- phase: 'analysis';
120
- summary: ReconciliationSummary;
121
- auto_matches: TransactionMatch[];
122
- suggested_matches: TransactionMatch[];
123
- unmatched_bank: BankTransaction[];
124
- unmatched_ynab: YNABTransaction[];
125
- /** YNAB transactions outside the statement date range (not compared, expected) */
126
- ynab_outside_date_range: YNABTransaction[];
127
- balance_info: BalanceInfo;
128
- next_steps: string[];
129
- insights: ReconciliationInsight[];
130
- recommendations?: ActionableRecommendation[];
118
+ success: true;
119
+ phase: "analysis";
120
+ summary: ReconciliationSummary;
121
+ auto_matches: TransactionMatch[];
122
+ suggested_matches: TransactionMatch[];
123
+ unmatched_bank: BankTransaction[];
124
+ unmatched_ynab: YNABTransaction[];
125
+ /** YNAB transactions outside the statement date range (not compared, expected) */
126
+ ynab_outside_date_range: YNABTransaction[];
127
+ balance_info: BalanceInfo;
128
+ next_steps: string[];
129
+ insights: ReconciliationInsight[];
130
+ recommendations?: ActionableRecommendation[];
131
131
  }
132
132
 
133
133
  /**
134
134
  * Reconciliation action types
135
135
  */
136
- export type ReconciliationActionType = 'match' | 'add' | 'unclear' | 'delete' | 'ignore';
136
+ export type ReconciliationActionType =
137
+ | "match"
138
+ | "add"
139
+ | "unclear"
140
+ | "delete"
141
+ | "ignore";
137
142
 
138
143
  /**
139
144
  * Reconciliation action
140
145
  */
141
146
  export interface ReconciliationAction {
142
- type: ReconciliationActionType;
143
- bank_txn_id?: string;
144
- ynab_txn_id?: string;
145
- mark_cleared?: boolean;
146
- create_as_cleared?: boolean;
147
- reason?: string;
148
- metadata?: Record<string, unknown>;
147
+ type: ReconciliationActionType;
148
+ bank_txn_id?: string;
149
+ ynab_txn_id?: string;
150
+ mark_cleared?: boolean;
151
+ create_as_cleared?: boolean;
152
+ reason?: string;
153
+ metadata?: Record<string, unknown>;
149
154
  }
150
155
 
151
156
  /**
152
157
  * Matching algorithm configuration (V2)
153
158
  */
154
159
  export interface MatchingConfig {
155
- weights: {
156
- amount: number; // Recommended: 0.50
157
- date: number; // Recommended: 0.15
158
- payee: number; // Recommended: 0.35
159
- };
160
+ weights: {
161
+ amount: number; // Recommended: 0.50
162
+ date: number; // Recommended: 0.15
163
+ payee: number; // Recommended: 0.35
164
+ };
160
165
 
161
- // Tolerances (in MILLIUNITS for amount)
162
- amountToleranceMilliunits: number; // Default: 10 (1 cent)
163
- dateToleranceDays: number; // Default: 7
166
+ // Tolerances (in MILLIUNITS for amount)
167
+ amountToleranceMilliunits: number; // Default: 10 (1 cent)
168
+ dateToleranceDays: number; // Default: 7
164
169
 
165
- // Thresholds
166
- autoMatchThreshold: number; // Default: 85
167
- suggestedMatchThreshold: number; // Default: 60
168
- minimumCandidateScore: number; // Default: 40
170
+ // Thresholds
171
+ autoMatchThreshold: number; // Default: 85
172
+ suggestedMatchThreshold: number; // Default: 60
173
+ minimumCandidateScore: number; // Default: 40
169
174
 
170
- // Bonuses for perfect matches
171
- exactAmountBonus: number; // Default: 10
172
- exactDateBonus: number; // Default: 5
173
- exactPayeeBonus: number; // Default: 10
175
+ // Bonuses for perfect matches
176
+ exactAmountBonus: number; // Default: 10
177
+ exactDateBonus: number; // Default: 5
178
+ exactPayeeBonus: number; // Default: 10
174
179
  }
175
180
 
176
181
  /**
177
182
  * Parsed CSV data from compareTransactions
178
183
  */
179
184
  export interface ParsedCSVData {
180
- transactions: BankTransaction[];
181
- format_detected: string;
182
- delimiter: string;
183
- total_rows: number;
184
- valid_rows: number;
185
- errors: string[];
185
+ transactions: BankTransaction[];
186
+ format_detected: string;
187
+ delimiter: string;
188
+ total_rows: number;
189
+ valid_rows: number;
190
+ errors: string[];
186
191
  }
187
192
 
188
193
  /**
189
194
  * Priority levels for actionable recommendations
190
195
  */
191
- export type RecommendationPriority = 'high' | 'medium' | 'low';
196
+ export type RecommendationPriority = "high" | "medium" | "low";
192
197
 
193
198
  /**
194
199
  * Base fields common to all recommendation types
195
200
  */
196
201
  export interface BaseRecommendation {
197
- /** Unique identifier for this recommendation */
198
- id: string;
199
- /** Priority level for execution */
200
- priority: RecommendationPriority;
201
- /** Confidence score 0-1 (higher = more confident) */
202
- confidence: number;
203
- /** Human-readable message describing the recommendation */
204
- message: string;
205
- /** Explanation of why this recommendation was generated */
206
- reason: string;
207
- /** Estimated impact on reconciliation balance */
208
- estimated_impact: MoneyValue;
209
- /** YNAB account ID this recommendation applies to */
210
- account_id: string;
211
- /** Optional link to the insight that generated this recommendation */
212
- source_insight_id?: string;
213
- /** Additional metadata (version, timestamps, etc.) */
214
- metadata?: Record<string, unknown>;
202
+ /** Unique identifier for this recommendation */
203
+ id: string;
204
+ /** Priority level for execution */
205
+ priority: RecommendationPriority;
206
+ /** Confidence score 0-1 (higher = more confident) */
207
+ confidence: number;
208
+ /** Human-readable message describing the recommendation */
209
+ message: string;
210
+ /** Explanation of why this recommendation was generated */
211
+ reason: string;
212
+ /** Estimated impact on reconciliation balance */
213
+ estimated_impact: MoneyValue;
214
+ /** YNAB account ID this recommendation applies to */
215
+ account_id: string;
216
+ /** Optional link to the insight that generated this recommendation */
217
+ source_insight_id?: string;
218
+ /** Additional metadata (version, timestamps, etc.) */
219
+ metadata?: Record<string, unknown>;
215
220
  }
216
221
 
217
222
  /**
218
223
  * Recommendation to create a new YNAB transaction
219
224
  */
220
225
  export interface CreateTransactionRecommendation extends BaseRecommendation {
221
- action_type: 'create_transaction';
222
- parameters: {
223
- account_id: string;
224
- date: string;
225
- amount: number;
226
- payee_name: string;
227
- memo?: string;
228
- cleared: 'cleared' | 'uncleared';
229
- approved: boolean;
230
- category_id?: string;
231
- };
226
+ action_type: "create_transaction";
227
+ parameters: {
228
+ account_id: string;
229
+ date: string;
230
+ amount: number;
231
+ payee_name: string;
232
+ memo?: string;
233
+ cleared: "cleared" | "uncleared";
234
+ approved: boolean;
235
+ category_id?: string;
236
+ };
232
237
  }
233
238
 
234
239
  /**
235
240
  * Recommendation to update a transaction's cleared status
236
241
  */
237
242
  export interface UpdateClearedRecommendation extends BaseRecommendation {
238
- action_type: 'update_cleared';
239
- parameters: {
240
- transaction_id: string;
241
- cleared: 'cleared' | 'uncleared' | 'reconciled';
242
- };
243
+ action_type: "update_cleared";
244
+ parameters: {
245
+ transaction_id: string;
246
+ cleared: "cleared" | "uncleared" | "reconciled";
247
+ };
243
248
  }
244
249
 
245
250
  /**
246
251
  * Recommendation to review potential duplicate transactions
247
252
  */
248
253
  export interface ReviewDuplicateRecommendation extends BaseRecommendation {
249
- action_type: 'review_duplicate';
250
- parameters: {
251
- candidate_ids: string[];
252
- bank_transaction?: BankTransaction;
253
- suggested_match_id?: string;
254
- };
254
+ action_type: "review_duplicate";
255
+ parameters: {
256
+ candidate_ids: string[];
257
+ bank_transaction?: BankTransaction;
258
+ suggested_match_id?: string;
259
+ };
255
260
  }
256
261
 
257
262
  /**
258
263
  * Related transaction reference for manual review
259
264
  */
260
265
  export interface RelatedTransaction {
261
- source: 'bank' | 'ynab';
262
- id: string;
263
- description: string;
266
+ source: "bank" | "ynab";
267
+ id: string;
268
+ description: string;
264
269
  }
265
270
 
266
271
  /**
267
272
  * Recommendation requiring manual investigation
268
273
  */
269
274
  export interface ManualReviewRecommendation extends BaseRecommendation {
270
- action_type: 'manual_review';
271
- parameters: {
272
- issue_type: 'complex_match' | 'large_discrepancy' | 'unknown';
273
- related_transactions?: RelatedTransaction[];
274
- };
275
+ action_type: "manual_review";
276
+ parameters: {
277
+ issue_type: "complex_match" | "large_discrepancy" | "unknown";
278
+ related_transactions?: RelatedTransaction[];
279
+ };
275
280
  }
276
281
 
277
282
  /**
278
283
  * Union type of all possible recommendation types (discriminated by action_type)
279
284
  */
280
285
  export type ActionableRecommendation =
281
- | CreateTransactionRecommendation
282
- | UpdateClearedRecommendation
283
- | ReviewDuplicateRecommendation
284
- | ManualReviewRecommendation;
286
+ | CreateTransactionRecommendation
287
+ | UpdateClearedRecommendation
288
+ | ReviewDuplicateRecommendation
289
+ | ManualReviewRecommendation;
285
290
 
286
291
  /**
287
292
  * Context passed to recommendation engine for generating recommendations
288
293
  */
289
294
  export interface RecommendationContext {
290
- /** Account ID for the recommendations */
291
- account_id: string;
292
- /** Budget ID (reserved for future category suggestions) */
293
- budget_id: string;
294
- /** The reconciliation analysis results */
295
- analysis: ReconciliationAnalysis;
296
- /** Matching configuration used during analysis */
297
- matching_config: MatchingConfig;
295
+ /** Account ID for the recommendations */
296
+ account_id: string;
297
+ /** Budget ID (reserved for future category suggestions) */
298
+ budget_id: string;
299
+ /** The reconciliation analysis results */
300
+ analysis: ReconciliationAnalysis;
301
+ /** Matching configuration used during analysis */
302
+ matching_config: MatchingConfig;
298
303
  }