@dizzlkheinz/ynab-mcpb 0.18.3 → 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.
- package/CHANGELOG.md +17 -0
- package/CLAUDE.md +87 -8
- package/bin/ynab-mcp-server.cjs +2 -2
- package/bin/ynab-mcp-server.js +3 -3
- package/biome.json +39 -0
- package/dist/bundle/index.cjs +67 -67
- package/dist/index.d.ts +1 -1
- package/dist/index.js +27 -27
- package/dist/server/YNABMCPServer.d.ts +3 -4
- package/dist/server/YNABMCPServer.js +111 -116
- package/dist/server/budgetResolver.d.ts +6 -5
- package/dist/server/budgetResolver.js +46 -36
- package/dist/server/cacheKeys.js +6 -6
- package/dist/server/cacheManager.js +14 -11
- package/dist/server/completions.d.ts +2 -2
- package/dist/server/completions.js +20 -15
- package/dist/server/config.d.ts +10 -5
- package/dist/server/config.js +24 -7
- package/dist/server/deltaCache.d.ts +2 -2
- package/dist/server/deltaCache.js +22 -16
- package/dist/server/deltaCache.merge.d.ts +2 -2
- package/dist/server/diagnostics.d.ts +4 -4
- package/dist/server/diagnostics.js +38 -32
- package/dist/server/errorHandler.d.ts +5 -12
- package/dist/server/errorHandler.js +219 -217
- package/dist/server/prompts.d.ts +2 -2
- package/dist/server/prompts.js +45 -45
- package/dist/server/rateLimiter.js +4 -4
- package/dist/server/requestLogger.d.ts +1 -1
- package/dist/server/requestLogger.js +40 -35
- package/dist/server/resources.d.ts +3 -3
- package/dist/server/resources.js +55 -52
- package/dist/server/responseFormatter.js +6 -6
- package/dist/server/securityMiddleware.d.ts +2 -2
- package/dist/server/securityMiddleware.js +22 -20
- package/dist/server/serverKnowledgeStore.js +1 -1
- package/dist/server/toolRegistry.d.ts +3 -3
- package/dist/server/toolRegistry.js +47 -40
- package/dist/tools/__tests__/deltaTestUtils.d.ts +3 -3
- package/dist/tools/__tests__/deltaTestUtils.js +2 -2
- package/dist/tools/accountTools.d.ts +9 -8
- package/dist/tools/accountTools.js +47 -47
- package/dist/tools/adapters.d.ts +13 -8
- package/dist/tools/adapters.js +21 -11
- package/dist/tools/budgetTools.d.ts +8 -7
- package/dist/tools/budgetTools.js +22 -22
- package/dist/tools/categoryTools.d.ts +9 -8
- package/dist/tools/categoryTools.js +68 -59
- package/dist/tools/compareTransactions/formatter.d.ts +3 -3
- package/dist/tools/compareTransactions/formatter.js +9 -9
- package/dist/tools/compareTransactions/index.d.ts +6 -6
- package/dist/tools/compareTransactions/index.js +58 -43
- package/dist/tools/compareTransactions/matcher.d.ts +1 -1
- package/dist/tools/compareTransactions/matcher.js +28 -15
- package/dist/tools/compareTransactions/parser.d.ts +2 -2
- package/dist/tools/compareTransactions/parser.js +144 -138
- package/dist/tools/compareTransactions/types.d.ts +4 -4
- package/dist/tools/compareTransactions.d.ts +1 -1
- package/dist/tools/compareTransactions.js +1 -1
- package/dist/tools/deltaFetcher.d.ts +2 -2
- package/dist/tools/deltaFetcher.js +16 -15
- package/dist/tools/deltaSupport.d.ts +4 -4
- package/dist/tools/deltaSupport.js +35 -41
- package/dist/tools/exportTransactions.d.ts +5 -4
- package/dist/tools/exportTransactions.js +61 -59
- package/dist/tools/monthTools.d.ts +7 -6
- package/dist/tools/monthTools.js +31 -29
- package/dist/tools/payeeTools.d.ts +7 -6
- package/dist/tools/payeeTools.js +28 -28
- package/dist/tools/reconcileAdapter.d.ts +2 -2
- package/dist/tools/reconcileAdapter.js +21 -11
- package/dist/tools/reconciliation/analyzer.d.ts +4 -4
- package/dist/tools/reconciliation/analyzer.js +136 -57
- package/dist/tools/reconciliation/csvParser.d.ts +3 -3
- package/dist/tools/reconciliation/csvParser.js +128 -104
- package/dist/tools/reconciliation/executor.d.ts +4 -4
- package/dist/tools/reconciliation/executor.js +148 -109
- package/dist/tools/reconciliation/index.d.ts +10 -10
- package/dist/tools/reconciliation/index.js +96 -83
- package/dist/tools/reconciliation/matcher.d.ts +3 -3
- package/dist/tools/reconciliation/matcher.js +17 -16
- package/dist/tools/reconciliation/payeeNormalizer.js +19 -8
- package/dist/tools/reconciliation/recommendationEngine.d.ts +1 -1
- package/dist/tools/reconciliation/recommendationEngine.js +40 -40
- package/dist/tools/reconciliation/reportFormatter.d.ts +2 -2
- package/dist/tools/reconciliation/reportFormatter.js +79 -54
- package/dist/tools/reconciliation/signDetector.d.ts +1 -1
- package/dist/tools/reconciliation/types.d.ts +19 -16
- package/dist/tools/reconciliation/ynabAdapter.d.ts +2 -2
- package/dist/tools/schemas/common.d.ts +1 -1
- package/dist/tools/schemas/common.js +1 -1
- package/dist/tools/schemas/outputs/accountOutputs.d.ts +1 -1
- package/dist/tools/schemas/outputs/accountOutputs.js +24 -18
- package/dist/tools/schemas/outputs/budgetOutputs.d.ts +1 -1
- package/dist/tools/schemas/outputs/budgetOutputs.js +14 -11
- package/dist/tools/schemas/outputs/categoryOutputs.d.ts +1 -1
- package/dist/tools/schemas/outputs/categoryOutputs.js +49 -29
- package/dist/tools/schemas/outputs/comparisonOutputs.d.ts +1 -1
- package/dist/tools/schemas/outputs/comparisonOutputs.js +12 -12
- package/dist/tools/schemas/outputs/index.d.ts +14 -14
- package/dist/tools/schemas/outputs/index.js +14 -14
- package/dist/tools/schemas/outputs/monthOutputs.d.ts +1 -1
- package/dist/tools/schemas/outputs/monthOutputs.js +56 -41
- package/dist/tools/schemas/outputs/payeeOutputs.d.ts +1 -1
- package/dist/tools/schemas/outputs/payeeOutputs.js +10 -10
- package/dist/tools/schemas/outputs/reconciliationOutputs.d.ts +2 -2
- package/dist/tools/schemas/outputs/reconciliationOutputs.js +45 -45
- package/dist/tools/schemas/outputs/transactionMutationOutputs.d.ts +1 -1
- package/dist/tools/schemas/outputs/transactionMutationOutputs.js +28 -22
- package/dist/tools/schemas/outputs/transactionOutputs.d.ts +1 -1
- package/dist/tools/schemas/outputs/transactionOutputs.js +43 -35
- package/dist/tools/schemas/outputs/utilityOutputs.d.ts +1 -1
- package/dist/tools/schemas/outputs/utilityOutputs.js +5 -3
- package/dist/tools/schemas/shared/commonOutputs.d.ts +1 -1
- package/dist/tools/schemas/shared/commonOutputs.js +15 -9
- package/dist/tools/transactionReadTools.d.ts +11 -0
- package/dist/tools/transactionReadTools.js +202 -0
- package/dist/tools/transactionSchemas.d.ts +309 -0
- package/dist/tools/transactionSchemas.js +235 -0
- package/dist/tools/transactionTools.d.ts +6 -302
- package/dist/tools/transactionTools.js +7 -2054
- package/dist/tools/transactionUtils.d.ts +31 -0
- package/dist/tools/transactionUtils.js +364 -0
- package/dist/tools/transactionWriteTools.d.ts +20 -0
- package/dist/tools/transactionWriteTools.js +1342 -0
- package/dist/tools/utilityTools.d.ts +5 -4
- package/dist/tools/utilityTools.js +11 -11
- package/dist/types/index.d.ts +7 -7
- package/dist/types/index.js +6 -6
- package/dist/types/reconciliation.d.ts +1 -1
- package/dist/types/toolRegistration.d.ts +14 -12
- package/dist/utils/amountUtils.js +1 -1
- package/dist/utils/dateUtils.js +4 -4
- package/dist/utils/errors.d.ts +3 -3
- package/dist/utils/errors.js +4 -4
- package/dist/utils/money.d.ts +2 -2
- package/dist/utils/money.js +8 -8
- package/dist/utils/validationError.d.ts +1 -1
- package/dist/utils/validationError.js +1 -1
- package/docs/assets/examples/reconciliation-with-recommendations.json +66 -66
- package/docs/assets/schemas/reconciliation-v2.json +360 -336
- package/docs/plans/2025-12-25-transaction-tools-refactor-design.md +211 -0
- package/docs/plans/2025-12-25-transaction-tools-refactor.md +905 -0
- package/esbuild.config.mjs +53 -50
- package/meta.json +12548 -12548
- package/package.json +98 -109
- package/scripts/analyze-bundle.mjs +33 -30
- package/scripts/create-pr-description.js +169 -120
- package/scripts/run-all-tests.js +205 -0
- package/scripts/run-domain-integration-tests.js +28 -18
- package/scripts/run-generate-mcpb.js +19 -17
- package/scripts/run-throttled-integration-tests.js +92 -83
- package/scripts/test-delta-params.mjs +149 -120
- package/scripts/test-recommendations.ts +36 -32
- package/scripts/tmpTransaction.ts +80 -43
- package/scripts/validate-env.js +98 -91
- package/scripts/verify-build.js +78 -76
- package/src/__tests__/comprehensive.integration.test.ts +1281 -1154
- package/src/__tests__/performance.test.ts +723 -671
- package/src/__tests__/setup.ts +442 -395
- package/src/__tests__/smoke.e2e.test.ts +41 -39
- package/src/__tests__/testRunner.ts +314 -295
- package/src/__tests__/testUtils.ts +456 -364
- package/src/__tests__/tools/reconciliation/csvParser.integration.test.ts +109 -107
- package/src/__tests__/tools/reconciliation/real-world.integration.test.ts +41 -41
- package/src/index.ts +68 -59
- package/src/server/CLAUDE.md +480 -0
- package/src/server/YNABMCPServer.ts +821 -794
- package/src/server/__tests__/YNABMCPServer.integration.test.ts +929 -893
- package/src/server/__tests__/YNABMCPServer.test.ts +903 -899
- package/src/server/__tests__/budgetResolver.test.ts +466 -423
- package/src/server/__tests__/cacheManager.test.ts +891 -874
- package/src/server/__tests__/completions.integration.test.ts +115 -106
- package/src/server/__tests__/completions.test.ts +334 -313
- package/src/server/__tests__/config.test.ts +98 -86
- package/src/server/__tests__/deltaCache.merge.test.ts +774 -703
- package/src/server/__tests__/deltaCache.swr.test.ts +198 -153
- package/src/server/__tests__/deltaCache.test.ts +946 -759
- package/src/server/__tests__/diagnostics.test.ts +825 -792
- package/src/server/__tests__/errorHandler.integration.test.ts +512 -462
- package/src/server/__tests__/errorHandler.test.ts +402 -397
- package/src/server/__tests__/prompts.test.ts +424 -347
- package/src/server/__tests__/rateLimiter.test.ts +313 -309
- package/src/server/__tests__/requestLogger.test.ts +443 -403
- package/src/server/__tests__/resources.template.test.ts +196 -185
- package/src/server/__tests__/resources.test.ts +294 -288
- package/src/server/__tests__/security.integration.test.ts +487 -421
- package/src/server/__tests__/securityMiddleware.test.ts +519 -444
- package/src/server/__tests__/server-startup.integration.test.ts +509 -490
- package/src/server/__tests__/serverKnowledgeStore.test.ts +174 -173
- package/src/server/__tests__/toolRegistration.test.ts +239 -210
- package/src/server/__tests__/toolRegistry.test.ts +907 -845
- package/src/server/budgetResolver.ts +221 -181
- package/src/server/cacheKeys.ts +6 -6
- package/src/server/cacheManager.ts +498 -484
- package/src/server/completions.ts +267 -243
- package/src/server/config.ts +35 -14
- package/src/server/deltaCache.merge.ts +146 -128
- package/src/server/deltaCache.ts +352 -309
- package/src/server/diagnostics.ts +257 -242
- package/src/server/errorHandler.ts +747 -744
- package/src/server/prompts.ts +181 -176
- package/src/server/rateLimiter.ts +131 -129
- package/src/server/requestLogger.ts +350 -322
- package/src/server/resources.ts +442 -374
- package/src/server/responseFormatter.ts +41 -37
- package/src/server/securityMiddleware.ts +223 -205
- package/src/server/serverKnowledgeStore.ts +67 -67
- package/src/server/toolRegistry.ts +508 -474
- package/src/tools/CLAUDE.md +604 -0
- package/src/tools/__tests__/accountTools.delta.integration.test.ts +128 -111
- package/src/tools/__tests__/accountTools.integration.test.ts +129 -111
- package/src/tools/__tests__/accountTools.test.ts +685 -638
- package/src/tools/__tests__/adapters.test.ts +142 -108
- package/src/tools/__tests__/budgetTools.delta.integration.test.ts +73 -73
- package/src/tools/__tests__/budgetTools.integration.test.ts +132 -124
- package/src/tools/__tests__/budgetTools.test.ts +442 -413
- package/src/tools/__tests__/categoryTools.delta.integration.test.ts +76 -68
- package/src/tools/__tests__/categoryTools.integration.test.ts +314 -288
- package/src/tools/__tests__/categoryTools.test.ts +656 -625
- package/src/tools/__tests__/compareTransactions/formatter.test.ts +535 -462
- package/src/tools/__tests__/compareTransactions/index.test.ts +378 -358
- package/src/tools/__tests__/compareTransactions/matcher.test.ts +497 -398
- package/src/tools/__tests__/compareTransactions/parser.test.ts +765 -747
- package/src/tools/__tests__/compareTransactions.test.ts +352 -332
- package/src/tools/__tests__/compareTransactions.window.test.ts +150 -146
- package/src/tools/__tests__/deltaFetcher.scheduled.integration.test.ts +69 -65
- package/src/tools/__tests__/deltaFetcher.test.ts +325 -265
- package/src/tools/__tests__/deltaSupport.test.ts +211 -184
- package/src/tools/__tests__/deltaTestUtils.ts +37 -33
- package/src/tools/__tests__/exportTransactions.test.ts +205 -200
- package/src/tools/__tests__/monthTools.delta.integration.test.ts +68 -68
- package/src/tools/__tests__/monthTools.integration.test.ts +178 -166
- package/src/tools/__tests__/monthTools.test.ts +561 -512
- package/src/tools/__tests__/payeeTools.delta.integration.test.ts +68 -68
- package/src/tools/__tests__/payeeTools.integration.test.ts +158 -142
- package/src/tools/__tests__/payeeTools.test.ts +486 -434
- package/src/tools/__tests__/transactionSchemas.test.ts +1204 -0
- package/src/tools/__tests__/transactionTools.integration.test.ts +875 -825
- package/src/tools/__tests__/transactionTools.test.ts +4923 -4366
- package/src/tools/__tests__/transactionUtils.test.ts +1016 -0
- package/src/tools/__tests__/utilityTools.integration.test.ts +32 -32
- package/src/tools/__tests__/utilityTools.test.ts +68 -58
- package/src/tools/accountTools.ts +293 -271
- package/src/tools/adapters.ts +120 -63
- package/src/tools/budgetTools.ts +121 -116
- package/src/tools/categoryTools.ts +379 -339
- package/src/tools/compareTransactions/formatter.ts +131 -119
- package/src/tools/compareTransactions/index.ts +249 -214
- package/src/tools/compareTransactions/matcher.ts +259 -209
- package/src/tools/compareTransactions/parser.ts +517 -487
- package/src/tools/compareTransactions/types.ts +38 -38
- package/src/tools/compareTransactions.ts +1 -1
- package/src/tools/deltaFetcher.ts +281 -260
- package/src/tools/deltaSupport.ts +264 -259
- package/src/tools/exportTransactions.ts +230 -218
- package/src/tools/monthTools.ts +180 -165
- package/src/tools/payeeTools.ts +152 -140
- package/src/tools/reconcileAdapter.ts +297 -246
- package/src/tools/reconciliation/CLAUDE.md +506 -0
- package/src/tools/reconciliation/__tests__/adapter.causes.test.ts +135 -112
- package/src/tools/reconciliation/__tests__/adapter.test.ts +249 -227
- package/src/tools/reconciliation/__tests__/analyzer.test.ts +408 -335
- package/src/tools/reconciliation/__tests__/csvParser.test.ts +71 -69
- package/src/tools/reconciliation/__tests__/executor.integration.test.ts +348 -323
- package/src/tools/reconciliation/__tests__/executor.progress.test.ts +503 -457
- package/src/tools/reconciliation/__tests__/executor.test.ts +898 -831
- package/src/tools/reconciliation/__tests__/matcher.test.ts +667 -663
- package/src/tools/reconciliation/__tests__/payeeNormalizer.test.ts +296 -276
- package/src/tools/reconciliation/__tests__/recommendationEngine.integration.test.ts +692 -624
- package/src/tools/reconciliation/__tests__/recommendationEngine.test.ts +1008 -986
- package/src/tools/reconciliation/__tests__/reconciliation.delta.integration.test.ts +187 -146
- package/src/tools/reconciliation/__tests__/reportFormatter.test.ts +583 -530
- package/src/tools/reconciliation/__tests__/scenarios/adapterCurrency.scenario.test.ts +75 -71
- package/src/tools/reconciliation/__tests__/scenarios/extremes.scenario.test.ts +70 -58
- package/src/tools/reconciliation/__tests__/scenarios/repeatAmount.scenario.test.ts +102 -88
- package/src/tools/reconciliation/__tests__/schemaUrl.test.ts +58 -43
- package/src/tools/reconciliation/__tests__/signDetector.test.ts +209 -206
- package/src/tools/reconciliation/__tests__/ynabAdapter.test.ts +66 -60
- package/src/tools/reconciliation/analyzer.ts +582 -406
- package/src/tools/reconciliation/csvParser.ts +656 -609
- package/src/tools/reconciliation/executor.ts +1290 -1128
- package/src/tools/reconciliation/index.ts +580 -528
- package/src/tools/reconciliation/matcher.ts +256 -240
- package/src/tools/reconciliation/payeeNormalizer.ts +92 -78
- package/src/tools/reconciliation/recommendationEngine.ts +357 -345
- package/src/tools/reconciliation/reportFormatter.ts +349 -276
- package/src/tools/reconciliation/signDetector.ts +89 -83
- package/src/tools/reconciliation/types.ts +164 -153
- package/src/tools/reconciliation/ynabAdapter.ts +17 -15
- package/src/tools/schemas/CLAUDE.md +546 -0
- package/src/tools/schemas/common.ts +1 -1
- package/src/tools/schemas/outputs/__tests__/accountOutputs.test.ts +410 -409
- package/src/tools/schemas/outputs/__tests__/budgetOutputs.test.ts +305 -299
- package/src/tools/schemas/outputs/__tests__/categoryOutputs.test.ts +431 -430
- package/src/tools/schemas/outputs/__tests__/comparisonOutputs.test.ts +510 -495
- package/src/tools/schemas/outputs/__tests__/dateValidation.test.ts +179 -153
- package/src/tools/schemas/outputs/__tests__/discrepancyDirection.test.ts +293 -254
- package/src/tools/schemas/outputs/__tests__/monthOutputs.test.ts +457 -457
- package/src/tools/schemas/outputs/__tests__/payeeOutputs.test.ts +362 -356
- package/src/tools/schemas/outputs/__tests__/reconciliationOutputs.test.ts +402 -399
- package/src/tools/schemas/outputs/__tests__/transactionMutationSchemas.test.ts +225 -211
- package/src/tools/schemas/outputs/__tests__/transactionOutputs.test.ts +457 -454
- package/src/tools/schemas/outputs/__tests__/utilityOutputs.test.ts +316 -315
- package/src/tools/schemas/outputs/accountOutputs.ts +40 -34
- package/src/tools/schemas/outputs/budgetOutputs.ts +24 -19
- package/src/tools/schemas/outputs/categoryOutputs.ts +76 -56
- package/src/tools/schemas/outputs/comparisonOutputs.ts +192 -169
- package/src/tools/schemas/outputs/index.ts +163 -163
- package/src/tools/schemas/outputs/monthOutputs.ts +95 -80
- package/src/tools/schemas/outputs/payeeOutputs.ts +18 -18
- package/src/tools/schemas/outputs/reconciliationOutputs.ts +386 -373
- package/src/tools/schemas/outputs/transactionMutationOutputs.ts +259 -231
- package/src/tools/schemas/outputs/transactionOutputs.ts +81 -71
- package/src/tools/schemas/outputs/utilityOutputs.ts +90 -84
- package/src/tools/schemas/shared/commonOutputs.ts +27 -19
- package/src/tools/toolCategories.ts +114 -114
- package/src/tools/transactionReadTools.ts +327 -0
- package/src/tools/transactionSchemas.ts +484 -0
- package/src/tools/transactionTools.ts +107 -2990
- package/src/tools/transactionUtils.ts +621 -0
- package/src/tools/transactionWriteTools.ts +2110 -0
- package/src/tools/utilityTools.ts +46 -41
- package/src/types/CLAUDE.md +477 -0
- package/src/types/__tests__/index.test.ts +51 -51
- package/src/types/index.ts +43 -39
- package/src/types/integration-tests.d.ts +26 -26
- package/src/types/reconciliation.ts +29 -29
- package/src/types/toolAnnotations.ts +30 -30
- package/src/types/toolRegistration.ts +43 -32
- package/src/utils/CLAUDE.md +508 -0
- package/src/utils/__tests__/dateUtils.test.ts +174 -168
- package/src/utils/__tests__/money.test.ts +193 -187
- package/src/utils/amountUtils.ts +5 -5
- package/src/utils/baseError.ts +5 -5
- package/src/utils/dateUtils.ts +29 -26
- package/src/utils/errors.ts +14 -14
- package/src/utils/money.ts +66 -52
- package/src/utils/validationError.ts +1 -1
- package/tsconfig.json +29 -29
- package/tsconfig.prod.json +16 -16
- package/vitest-reporters/split-json-reporter.ts +247 -204
- package/vitest.config.ts +99 -95
- package/.prettierignore +0 -10
- package/.prettierrc.json +0 -10
- 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 {
|
|
8
|
+
import type {
|
|
9
|
+
BankTransaction,
|
|
10
|
+
NormalizedYNABTransaction,
|
|
11
|
+
} from "../../types/reconciliation.js";
|
|
9
12
|
|
|
10
13
|
interface SignMatch {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
-
|
|
31
|
-
|
|
33
|
+
bankTransactions: BankTransaction[],
|
|
34
|
+
ynabTransactions: NormalizedYNABTransaction[],
|
|
32
35
|
): boolean {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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
|
-
|
|
70
|
-
|
|
72
|
+
bankTxn: BankTransaction,
|
|
73
|
+
ynabTransactions: NormalizedYNABTransaction[],
|
|
71
74
|
): SignMatch | null {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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
|
-
|
|
14
|
-
|
|
15
|
-
} from
|
|
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,272 +21,283 @@ export type YNABTransaction = CanonicalYNABTransaction;
|
|
|
21
21
|
/**
|
|
22
22
|
* Matching confidence levels
|
|
23
23
|
*/
|
|
24
|
-
export type MatchConfidence =
|
|
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
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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;
|
|
86
90
|
}
|
|
87
91
|
|
|
88
92
|
/**
|
|
89
93
|
* Insight severity levels
|
|
90
94
|
*/
|
|
91
|
-
export type InsightSeverity =
|
|
95
|
+
export type InsightSeverity = "info" | "warning" | "critical";
|
|
92
96
|
|
|
93
97
|
/**
|
|
94
98
|
* Insight types for reconciliation analysis
|
|
95
99
|
*/
|
|
96
|
-
export type InsightKind =
|
|
100
|
+
export type InsightKind = "repeat_amount" | "near_match" | "anomaly";
|
|
97
101
|
|
|
98
102
|
/**
|
|
99
103
|
* Reconciliation insight - highlights important findings that help explain discrepancies
|
|
100
104
|
*/
|
|
101
105
|
export interface ReconciliationInsight {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
106
|
+
id: string;
|
|
107
|
+
type: InsightKind;
|
|
108
|
+
severity: InsightSeverity;
|
|
109
|
+
title: string;
|
|
110
|
+
description: string;
|
|
111
|
+
evidence?: Record<string, unknown>;
|
|
108
112
|
}
|
|
109
113
|
|
|
110
114
|
/**
|
|
111
115
|
* Analysis phase result
|
|
112
116
|
*/
|
|
113
117
|
export interface ReconciliationAnalysis {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
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[];
|
|
125
131
|
}
|
|
126
132
|
|
|
127
133
|
/**
|
|
128
134
|
* Reconciliation action types
|
|
129
135
|
*/
|
|
130
|
-
export type ReconciliationActionType =
|
|
136
|
+
export type ReconciliationActionType =
|
|
137
|
+
| "match"
|
|
138
|
+
| "add"
|
|
139
|
+
| "unclear"
|
|
140
|
+
| "delete"
|
|
141
|
+
| "ignore";
|
|
131
142
|
|
|
132
143
|
/**
|
|
133
144
|
* Reconciliation action
|
|
134
145
|
*/
|
|
135
146
|
export interface ReconciliationAction {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
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>;
|
|
143
154
|
}
|
|
144
155
|
|
|
145
156
|
/**
|
|
146
157
|
* Matching algorithm configuration (V2)
|
|
147
158
|
*/
|
|
148
159
|
export interface MatchingConfig {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
160
|
+
weights: {
|
|
161
|
+
amount: number; // Recommended: 0.50
|
|
162
|
+
date: number; // Recommended: 0.15
|
|
163
|
+
payee: number; // Recommended: 0.35
|
|
164
|
+
};
|
|
154
165
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
166
|
+
// Tolerances (in MILLIUNITS for amount)
|
|
167
|
+
amountToleranceMilliunits: number; // Default: 10 (1 cent)
|
|
168
|
+
dateToleranceDays: number; // Default: 7
|
|
158
169
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
170
|
+
// Thresholds
|
|
171
|
+
autoMatchThreshold: number; // Default: 85
|
|
172
|
+
suggestedMatchThreshold: number; // Default: 60
|
|
173
|
+
minimumCandidateScore: number; // Default: 40
|
|
163
174
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
175
|
+
// Bonuses for perfect matches
|
|
176
|
+
exactAmountBonus: number; // Default: 10
|
|
177
|
+
exactDateBonus: number; // Default: 5
|
|
178
|
+
exactPayeeBonus: number; // Default: 10
|
|
168
179
|
}
|
|
169
180
|
|
|
170
181
|
/**
|
|
171
182
|
* Parsed CSV data from compareTransactions
|
|
172
183
|
*/
|
|
173
184
|
export interface ParsedCSVData {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
185
|
+
transactions: BankTransaction[];
|
|
186
|
+
format_detected: string;
|
|
187
|
+
delimiter: string;
|
|
188
|
+
total_rows: number;
|
|
189
|
+
valid_rows: number;
|
|
190
|
+
errors: string[];
|
|
180
191
|
}
|
|
181
192
|
|
|
182
193
|
/**
|
|
183
194
|
* Priority levels for actionable recommendations
|
|
184
195
|
*/
|
|
185
|
-
export type RecommendationPriority =
|
|
196
|
+
export type RecommendationPriority = "high" | "medium" | "low";
|
|
186
197
|
|
|
187
198
|
/**
|
|
188
199
|
* Base fields common to all recommendation types
|
|
189
200
|
*/
|
|
190
201
|
export interface BaseRecommendation {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
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>;
|
|
209
220
|
}
|
|
210
221
|
|
|
211
222
|
/**
|
|
212
223
|
* Recommendation to create a new YNAB transaction
|
|
213
224
|
*/
|
|
214
225
|
export interface CreateTransactionRecommendation extends BaseRecommendation {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
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
|
+
};
|
|
226
237
|
}
|
|
227
238
|
|
|
228
239
|
/**
|
|
229
240
|
* Recommendation to update a transaction's cleared status
|
|
230
241
|
*/
|
|
231
242
|
export interface UpdateClearedRecommendation extends BaseRecommendation {
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
243
|
+
action_type: "update_cleared";
|
|
244
|
+
parameters: {
|
|
245
|
+
transaction_id: string;
|
|
246
|
+
cleared: "cleared" | "uncleared" | "reconciled";
|
|
247
|
+
};
|
|
237
248
|
}
|
|
238
249
|
|
|
239
250
|
/**
|
|
240
251
|
* Recommendation to review potential duplicate transactions
|
|
241
252
|
*/
|
|
242
253
|
export interface ReviewDuplicateRecommendation extends BaseRecommendation {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
254
|
+
action_type: "review_duplicate";
|
|
255
|
+
parameters: {
|
|
256
|
+
candidate_ids: string[];
|
|
257
|
+
bank_transaction?: BankTransaction;
|
|
258
|
+
suggested_match_id?: string;
|
|
259
|
+
};
|
|
249
260
|
}
|
|
250
261
|
|
|
251
262
|
/**
|
|
252
263
|
* Related transaction reference for manual review
|
|
253
264
|
*/
|
|
254
265
|
export interface RelatedTransaction {
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
266
|
+
source: "bank" | "ynab";
|
|
267
|
+
id: string;
|
|
268
|
+
description: string;
|
|
258
269
|
}
|
|
259
270
|
|
|
260
271
|
/**
|
|
261
272
|
* Recommendation requiring manual investigation
|
|
262
273
|
*/
|
|
263
274
|
export interface ManualReviewRecommendation extends BaseRecommendation {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
275
|
+
action_type: "manual_review";
|
|
276
|
+
parameters: {
|
|
277
|
+
issue_type: "complex_match" | "large_discrepancy" | "unknown";
|
|
278
|
+
related_transactions?: RelatedTransaction[];
|
|
279
|
+
};
|
|
269
280
|
}
|
|
270
281
|
|
|
271
282
|
/**
|
|
272
283
|
* Union type of all possible recommendation types (discriminated by action_type)
|
|
273
284
|
*/
|
|
274
285
|
export type ActionableRecommendation =
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
286
|
+
| CreateTransactionRecommendation
|
|
287
|
+
| UpdateClearedRecommendation
|
|
288
|
+
| ReviewDuplicateRecommendation
|
|
289
|
+
| ManualReviewRecommendation;
|
|
279
290
|
|
|
280
291
|
/**
|
|
281
292
|
* Context passed to recommendation engine for generating recommendations
|
|
282
293
|
*/
|
|
283
294
|
export interface RecommendationContext {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
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;
|
|
292
303
|
}
|