@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
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { randomUUID } from
|
|
2
|
-
import { toMoneyValue, toMoneyValueFromDecimal,
|
|
3
|
-
const RECOMMENDATION_VERSION =
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { fromMilli, toMoneyValue, toMoneyValueFromDecimal, } from "../../utils/money.js";
|
|
3
|
+
const RECOMMENDATION_VERSION = "1.0";
|
|
4
4
|
const CONFIDENCE = {
|
|
5
5
|
CREATE_EXACT_MATCH: 0.95,
|
|
6
6
|
NEAR_MATCH_REVIEW: 0.7,
|
|
@@ -22,11 +22,11 @@ export function generateRecommendations(context) {
|
|
|
22
22
|
}
|
|
23
23
|
function processInsight(insight, context) {
|
|
24
24
|
switch (insight.type) {
|
|
25
|
-
case
|
|
25
|
+
case "near_match":
|
|
26
26
|
return [createNearMatchRecommendation(insight, context)];
|
|
27
|
-
case
|
|
27
|
+
case "repeat_amount":
|
|
28
28
|
return createRepeatAmountRecommendations(insight, context);
|
|
29
|
-
case
|
|
29
|
+
case "anomaly":
|
|
30
30
|
return [createManualReviewRecommendation(insight, context)];
|
|
31
31
|
default:
|
|
32
32
|
return [];
|
|
@@ -34,11 +34,11 @@ function processInsight(insight, context) {
|
|
|
34
34
|
}
|
|
35
35
|
function createSuggestedMatchRecommendation(match, context) {
|
|
36
36
|
const bankTxn = match.bankTransaction;
|
|
37
|
-
if (match.ynabTransaction && match.confidence !==
|
|
37
|
+
if (match.ynabTransaction && match.confidence !== "none") {
|
|
38
38
|
return {
|
|
39
39
|
id: randomUUID(),
|
|
40
|
-
action_type:
|
|
41
|
-
priority:
|
|
40
|
+
action_type: "review_duplicate",
|
|
41
|
+
priority: "high",
|
|
42
42
|
confidence: Math.max(0, Math.min(1, match.confidenceScore / 100)),
|
|
43
43
|
message: `Review possible match: ${bankTxn.payee}`,
|
|
44
44
|
reason: match.matchReason,
|
|
@@ -64,7 +64,7 @@ function createSuggestedMatchRecommendation(match, context) {
|
|
|
64
64
|
date: bankTxn.date,
|
|
65
65
|
amount: bankTxn.amount,
|
|
66
66
|
payee_name: bankTxn.payee,
|
|
67
|
-
cleared:
|
|
67
|
+
cleared: "cleared",
|
|
68
68
|
approved: true,
|
|
69
69
|
};
|
|
70
70
|
if (bankTxn.memo) {
|
|
@@ -72,11 +72,11 @@ function createSuggestedMatchRecommendation(match, context) {
|
|
|
72
72
|
}
|
|
73
73
|
return {
|
|
74
74
|
id: randomUUID(),
|
|
75
|
-
action_type:
|
|
76
|
-
priority:
|
|
75
|
+
action_type: "create_transaction",
|
|
76
|
+
priority: "high",
|
|
77
77
|
confidence: CONFIDENCE.CREATE_EXACT_MATCH,
|
|
78
78
|
message: `Create transaction for ${bankTxn.payee}`,
|
|
79
|
-
reason:
|
|
79
|
+
reason: "This transaction exactly matches your discrepancy",
|
|
80
80
|
estimated_impact: toMoneyValue(bankTxn.amount, context.analysis.balance_info.current_cleared.currency),
|
|
81
81
|
account_id: context.account_id,
|
|
82
82
|
metadata: {
|
|
@@ -99,12 +99,12 @@ function createCombinationReviewRecommendation(match, context) {
|
|
|
99
99
|
}, 0) ?? 0;
|
|
100
100
|
return {
|
|
101
101
|
id: randomUUID(),
|
|
102
|
-
action_type:
|
|
103
|
-
priority:
|
|
102
|
+
action_type: "manual_review",
|
|
103
|
+
priority: "medium",
|
|
104
104
|
confidence: CONFIDENCE.NEAR_MATCH_REVIEW,
|
|
105
105
|
message: `Review combination match: ${bankTxn.payee}`,
|
|
106
106
|
reason: match.recommendation ??
|
|
107
|
-
|
|
107
|
+
"Multiple YNAB transactions appear to match this bank transaction. Review before creating anything new.",
|
|
108
108
|
estimated_impact: toMoneyValueFromDecimal(0, context.analysis.balance_info.current_cleared.currency),
|
|
109
109
|
account_id: context.account_id,
|
|
110
110
|
metadata: {
|
|
@@ -115,18 +115,18 @@ function createCombinationReviewRecommendation(match, context) {
|
|
|
115
115
|
candidate_count: match.candidates?.length ?? 0,
|
|
116
116
|
},
|
|
117
117
|
parameters: {
|
|
118
|
-
issue_type:
|
|
118
|
+
issue_type: "complex_match",
|
|
119
119
|
related_transactions: [
|
|
120
120
|
{
|
|
121
|
-
source:
|
|
121
|
+
source: "bank",
|
|
122
122
|
id: bankTxn.id,
|
|
123
123
|
description: bankTxn.payee,
|
|
124
124
|
},
|
|
125
125
|
...candidateIds.map((id) => ({
|
|
126
|
-
source:
|
|
126
|
+
source: "ynab",
|
|
127
127
|
id,
|
|
128
|
-
description: match.candidates?.find((c) => c.ynab_transaction.id === id)
|
|
129
|
-
|
|
128
|
+
description: match.candidates?.find((c) => c.ynab_transaction.id === id)
|
|
129
|
+
?.ynab_transaction.payee ?? "Unknown",
|
|
130
130
|
})),
|
|
131
131
|
],
|
|
132
132
|
},
|
|
@@ -135,8 +135,8 @@ function createCombinationReviewRecommendation(match, context) {
|
|
|
135
135
|
function createNearMatchRecommendation(insight, context) {
|
|
136
136
|
return {
|
|
137
137
|
id: randomUUID(),
|
|
138
|
-
action_type:
|
|
139
|
-
priority:
|
|
138
|
+
action_type: "manual_review",
|
|
139
|
+
priority: "medium",
|
|
140
140
|
confidence: CONFIDENCE.NEAR_MATCH_REVIEW,
|
|
141
141
|
message: `Review: ${insight.title}`,
|
|
142
142
|
reason: insight.description,
|
|
@@ -150,7 +150,7 @@ function createNearMatchRecommendation(insight, context) {
|
|
|
150
150
|
insight_severity: insight.severity,
|
|
151
151
|
},
|
|
152
152
|
parameters: {
|
|
153
|
-
issue_type:
|
|
153
|
+
issue_type: "complex_match",
|
|
154
154
|
},
|
|
155
155
|
};
|
|
156
156
|
}
|
|
@@ -158,8 +158,8 @@ function createRepeatAmountRecommendations(insight, context) {
|
|
|
158
158
|
return [
|
|
159
159
|
{
|
|
160
160
|
id: randomUUID(),
|
|
161
|
-
action_type:
|
|
162
|
-
priority:
|
|
161
|
+
action_type: "manual_review",
|
|
162
|
+
priority: "medium",
|
|
163
163
|
confidence: CONFIDENCE.REPEAT_AMOUNT,
|
|
164
164
|
message: `Review recurring pattern: ${insight.title}`,
|
|
165
165
|
reason: insight.description,
|
|
@@ -173,7 +173,7 @@ function createRepeatAmountRecommendations(insight, context) {
|
|
|
173
173
|
insight_severity: insight.severity,
|
|
174
174
|
},
|
|
175
175
|
parameters: {
|
|
176
|
-
issue_type:
|
|
176
|
+
issue_type: "complex_match",
|
|
177
177
|
},
|
|
178
178
|
},
|
|
179
179
|
];
|
|
@@ -181,8 +181,8 @@ function createRepeatAmountRecommendations(insight, context) {
|
|
|
181
181
|
function createManualReviewRecommendation(insight, context) {
|
|
182
182
|
return {
|
|
183
183
|
id: randomUUID(),
|
|
184
|
-
action_type:
|
|
185
|
-
priority:
|
|
184
|
+
action_type: "manual_review",
|
|
185
|
+
priority: "low",
|
|
186
186
|
confidence: CONFIDENCE.ANOMALY_REVIEW,
|
|
187
187
|
message: `Review: ${insight.title}`,
|
|
188
188
|
reason: insight.description,
|
|
@@ -196,7 +196,7 @@ function createManualReviewRecommendation(insight, context) {
|
|
|
196
196
|
insight_severity: insight.severity,
|
|
197
197
|
},
|
|
198
198
|
parameters: {
|
|
199
|
-
issue_type: insight.severity ===
|
|
199
|
+
issue_type: insight.severity === "critical" ? "large_discrepancy" : "unknown",
|
|
200
200
|
},
|
|
201
201
|
};
|
|
202
202
|
}
|
|
@@ -213,7 +213,7 @@ function processUnmatchedTransactions(context) {
|
|
|
213
213
|
recommendations.push(createSuggestedMatchRecommendation(match, context));
|
|
214
214
|
}
|
|
215
215
|
for (const ynabTxn of context.analysis.unmatched_ynab) {
|
|
216
|
-
if (ynabTxn.cleared ===
|
|
216
|
+
if (ynabTxn.cleared === "uncleared") {
|
|
217
217
|
recommendations.push(createUpdateClearedRecommendation(ynabTxn, context));
|
|
218
218
|
}
|
|
219
219
|
}
|
|
@@ -225,7 +225,7 @@ function createUnmatchedBankRecommendation(txn, context) {
|
|
|
225
225
|
date: txn.date,
|
|
226
226
|
amount: txn.amount,
|
|
227
227
|
payee_name: txn.payee,
|
|
228
|
-
cleared:
|
|
228
|
+
cleared: "cleared",
|
|
229
229
|
approved: true,
|
|
230
230
|
};
|
|
231
231
|
if (txn.memo) {
|
|
@@ -233,11 +233,11 @@ function createUnmatchedBankRecommendation(txn, context) {
|
|
|
233
233
|
}
|
|
234
234
|
return {
|
|
235
235
|
id: randomUUID(),
|
|
236
|
-
action_type:
|
|
237
|
-
priority:
|
|
236
|
+
action_type: "create_transaction",
|
|
237
|
+
priority: "medium",
|
|
238
238
|
confidence: CONFIDENCE.UNMATCHED_BANK,
|
|
239
239
|
message: `Create missing transaction: ${txn.payee}`,
|
|
240
|
-
reason:
|
|
240
|
+
reason: "Transaction appears on bank statement but not in YNAB",
|
|
241
241
|
estimated_impact: toMoneyValue(txn.amount, context.analysis.balance_info.current_cleared.currency),
|
|
242
242
|
account_id: context.account_id,
|
|
243
243
|
metadata: {
|
|
@@ -250,11 +250,11 @@ function createUnmatchedBankRecommendation(txn, context) {
|
|
|
250
250
|
function createUpdateClearedRecommendation(txn, context) {
|
|
251
251
|
return {
|
|
252
252
|
id: randomUUID(),
|
|
253
|
-
action_type:
|
|
254
|
-
priority:
|
|
253
|
+
action_type: "update_cleared",
|
|
254
|
+
priority: "low",
|
|
255
255
|
confidence: CONFIDENCE.UPDATE_CLEARED,
|
|
256
|
-
message: `Mark transaction as cleared: ${txn.payee ||
|
|
257
|
-
reason:
|
|
256
|
+
message: `Mark transaction as cleared: ${txn.payee || "Unknown"}`,
|
|
257
|
+
reason: "Transaction exists in YNAB but not yet cleared",
|
|
258
258
|
estimated_impact: toMoneyValueFromDecimal(0, context.analysis.balance_info.current_cleared.currency),
|
|
259
259
|
account_id: context.account_id,
|
|
260
260
|
metadata: {
|
|
@@ -263,7 +263,7 @@ function createUpdateClearedRecommendation(txn, context) {
|
|
|
263
263
|
},
|
|
264
264
|
parameters: {
|
|
265
265
|
transaction_id: txn.id,
|
|
266
|
-
cleared:
|
|
266
|
+
cleared: "cleared",
|
|
267
267
|
},
|
|
268
268
|
};
|
|
269
269
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
1
|
+
import type { LegacyReconciliationResult } from "./executor.js";
|
|
2
|
+
import type { BalanceInfo, BankTransaction, ReconciliationAnalysis, YNABTransaction } from "./types.js";
|
|
3
3
|
export interface ReportFormatterOptions {
|
|
4
4
|
accountName?: string | undefined;
|
|
5
5
|
accountId?: string | undefined;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
const SECTION_DIVIDER =
|
|
1
|
+
const SECTION_DIVIDER = "-".repeat(60);
|
|
2
2
|
export function formatHumanReadableReport(analysis, options = {}, execution) {
|
|
3
|
-
const accountLabel = options.accountName ??
|
|
3
|
+
const accountLabel = options.accountName ?? "Account";
|
|
4
4
|
const sections = [];
|
|
5
5
|
sections.push(formatHeader(accountLabel, analysis));
|
|
6
6
|
if (options.notes && options.notes.length > 0) {
|
|
@@ -15,57 +15,64 @@ export function formatHumanReadableReport(analysis, options = {}, execution) {
|
|
|
15
15
|
sections.push(formatExecutionSection(execution));
|
|
16
16
|
}
|
|
17
17
|
sections.push(formatRecommendationsSection(analysis, execution));
|
|
18
|
-
return sections.join(
|
|
18
|
+
return sections.join("\n\n");
|
|
19
19
|
}
|
|
20
20
|
function formatHeader(accountName, analysis) {
|
|
21
21
|
const lines = [];
|
|
22
22
|
lines.push(`${accountName} Reconciliation Report`);
|
|
23
23
|
lines.push(SECTION_DIVIDER);
|
|
24
24
|
lines.push(`Statement Period: ${analysis.summary.statement_date_range}`);
|
|
25
|
-
return lines.join(
|
|
25
|
+
return lines.join("\n");
|
|
26
26
|
}
|
|
27
27
|
function formatNotesSection(notes) {
|
|
28
28
|
const lines = [];
|
|
29
|
-
lines.push(
|
|
29
|
+
lines.push("Notes");
|
|
30
30
|
lines.push(SECTION_DIVIDER);
|
|
31
31
|
for (const note of notes) {
|
|
32
32
|
lines.push(`- ${note}`);
|
|
33
33
|
}
|
|
34
|
-
return lines.join(
|
|
34
|
+
return lines.join("\n");
|
|
35
35
|
}
|
|
36
36
|
function formatBalanceSection(balanceInfo, summary) {
|
|
37
37
|
const lines = [];
|
|
38
|
-
lines.push(
|
|
38
|
+
lines.push("Balance Check");
|
|
39
39
|
lines.push(SECTION_DIVIDER);
|
|
40
40
|
lines.push(`- YNAB Cleared Balance: ${summary.current_cleared_balance.value_display}`);
|
|
41
41
|
lines.push(`- Statement Balance: ${summary.target_statement_balance.value_display}`);
|
|
42
|
-
lines.push(
|
|
42
|
+
lines.push("");
|
|
43
43
|
const discrepancyMilli = balanceInfo.discrepancy.value_milliunits;
|
|
44
44
|
if (discrepancyMilli === 0) {
|
|
45
|
-
lines.push(
|
|
45
|
+
lines.push("Balances match perfectly.");
|
|
46
46
|
}
|
|
47
47
|
else {
|
|
48
|
-
const direction = discrepancyMilli > 0 ?
|
|
49
|
-
const directionLabel = direction ===
|
|
50
|
-
?
|
|
51
|
-
:
|
|
48
|
+
const direction = discrepancyMilli > 0 ? "ynab_higher" : "bank_higher";
|
|
49
|
+
const directionLabel = direction === "ynab_higher"
|
|
50
|
+
? "YNAB shows MORE than statement"
|
|
51
|
+
: "Statement shows MORE than YNAB";
|
|
52
52
|
lines.push(`Discrepancy: ${balanceInfo.discrepancy.value_display}`);
|
|
53
53
|
lines.push(`Direction: ${directionLabel}`);
|
|
54
54
|
}
|
|
55
|
-
return lines.join(
|
|
55
|
+
return lines.join("\n");
|
|
56
56
|
}
|
|
57
57
|
function formatTransactionAnalysisSection(analysis, options) {
|
|
58
58
|
const lines = [];
|
|
59
|
-
lines.push(
|
|
59
|
+
lines.push("Transaction Analysis");
|
|
60
60
|
lines.push(SECTION_DIVIDER);
|
|
61
61
|
const summary = analysis.summary;
|
|
62
|
+
const outsideRangeCount = summary.ynab_outside_range_count ?? 0;
|
|
63
|
+
if (outsideRangeCount > 0) {
|
|
64
|
+
const inRangeCount = summary.ynab_in_range_count ?? summary.ynab_transactions_count;
|
|
65
|
+
lines.push(`Comparing ${summary.bank_transactions_count} bank transactions with ${inRangeCount} YNAB transactions within statement period.`);
|
|
66
|
+
lines.push(`(${outsideRangeCount} YNAB transactions outside statement period - not compared)`);
|
|
67
|
+
lines.push("");
|
|
68
|
+
}
|
|
62
69
|
lines.push(`- Automatically matched: ${summary.auto_matched} of ${summary.bank_transactions_count} transactions`);
|
|
63
70
|
lines.push(`- Suggested matches: ${summary.suggested_matches}`);
|
|
64
71
|
lines.push(`- Unmatched bank: ${summary.unmatched_bank}`);
|
|
65
72
|
lines.push(`- Unmatched YNAB: ${summary.unmatched_ynab}`);
|
|
66
73
|
if (analysis.unmatched_bank.length > 0) {
|
|
67
|
-
lines.push(
|
|
68
|
-
lines.push(
|
|
74
|
+
lines.push("");
|
|
75
|
+
lines.push("Missing from YNAB (bank transactions without matches):");
|
|
69
76
|
const maxToShow = options.maxUnmatchedToShow ?? 5;
|
|
70
77
|
const toShow = analysis.unmatched_bank.slice(0, maxToShow);
|
|
71
78
|
for (const txn of toShow) {
|
|
@@ -75,9 +82,21 @@ function formatTransactionAnalysisSection(analysis, options) {
|
|
|
75
82
|
lines.push(` ... and ${analysis.unmatched_bank.length - maxToShow} more`);
|
|
76
83
|
}
|
|
77
84
|
}
|
|
85
|
+
if (analysis.unmatched_ynab.length > 0) {
|
|
86
|
+
lines.push("");
|
|
87
|
+
lines.push("Missing from bank statement (YNAB transactions without matches):");
|
|
88
|
+
const maxToShow = options.maxUnmatchedToShow ?? 5;
|
|
89
|
+
const toShow = analysis.unmatched_ynab.slice(0, maxToShow);
|
|
90
|
+
for (const txn of toShow) {
|
|
91
|
+
lines.push(formatYnabTransactionLine(txn));
|
|
92
|
+
}
|
|
93
|
+
if (analysis.unmatched_ynab.length > maxToShow) {
|
|
94
|
+
lines.push(` ... and ${analysis.unmatched_ynab.length - maxToShow} more`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
78
97
|
if (analysis.suggested_matches.length > 0) {
|
|
79
|
-
lines.push(
|
|
80
|
-
lines.push(
|
|
98
|
+
lines.push("");
|
|
99
|
+
lines.push("Suggested matches (review manually):");
|
|
81
100
|
const maxToShow = options.maxUnmatchedToShow ?? 3;
|
|
82
101
|
const toShow = analysis.suggested_matches.slice(0, maxToShow);
|
|
83
102
|
for (const match of toShow) {
|
|
@@ -87,7 +106,12 @@ function formatTransactionAnalysisSection(analysis, options) {
|
|
|
87
106
|
lines.push(` ... and ${analysis.suggested_matches.length - maxToShow} more suggestions`);
|
|
88
107
|
}
|
|
89
108
|
}
|
|
90
|
-
return lines.join(
|
|
109
|
+
return lines.join("\n");
|
|
110
|
+
}
|
|
111
|
+
function formatYnabTransactionLine(txn) {
|
|
112
|
+
const amountStr = formatAmount(txn.amount);
|
|
113
|
+
const payee = txn.payee ?? "Unknown";
|
|
114
|
+
return ` ${txn.date} - ${payee.substring(0, 40).padEnd(40)} ${amountStr}`;
|
|
91
115
|
}
|
|
92
116
|
function formatBankTransactionLine(txn) {
|
|
93
117
|
const amountStr = formatAmount(txn.amount);
|
|
@@ -101,13 +125,13 @@ function formatSuggestedMatchLine(match) {
|
|
|
101
125
|
}
|
|
102
126
|
function formatAmount(amountMilli) {
|
|
103
127
|
const amount = amountMilli / 1000;
|
|
104
|
-
const sign = amount >= 0 ?
|
|
128
|
+
const sign = amount >= 0 ? "+" : "-";
|
|
105
129
|
const absAmount = Math.abs(amount);
|
|
106
130
|
return `${sign}$${absAmount.toFixed(2)}`.padStart(10);
|
|
107
131
|
}
|
|
108
132
|
function formatInsightsSection(insights, maxToShow = 3) {
|
|
109
133
|
const lines = [];
|
|
110
|
-
lines.push(
|
|
134
|
+
lines.push("Key Insights");
|
|
111
135
|
lines.push(SECTION_DIVIDER);
|
|
112
136
|
const toShow = insights.slice(0, maxToShow);
|
|
113
137
|
for (const insight of toShow) {
|
|
@@ -120,49 +144,50 @@ function formatInsightsSection(insights, maxToShow = 3) {
|
|
|
120
144
|
lines.push(` Evidence: ${evidenceSummary}`);
|
|
121
145
|
}
|
|
122
146
|
}
|
|
123
|
-
lines.push(
|
|
147
|
+
lines.push("");
|
|
124
148
|
}
|
|
125
149
|
if (insights.length > maxToShow) {
|
|
126
150
|
lines.push(`... and ${insights.length - maxToShow} more insights (see structured output)`);
|
|
127
151
|
}
|
|
128
|
-
return lines.join(
|
|
152
|
+
return lines.join("\n").trimEnd();
|
|
129
153
|
}
|
|
130
154
|
function getSeverityIcon(severity) {
|
|
131
155
|
switch (severity) {
|
|
132
|
-
case
|
|
133
|
-
return
|
|
134
|
-
case
|
|
135
|
-
return
|
|
136
|
-
case
|
|
137
|
-
return
|
|
156
|
+
case "critical":
|
|
157
|
+
return "[CRITICAL]";
|
|
158
|
+
case "warning":
|
|
159
|
+
return "[WARN]";
|
|
160
|
+
case "info":
|
|
161
|
+
return "[INFO]";
|
|
138
162
|
default:
|
|
139
|
-
return
|
|
163
|
+
return "[NOTE]";
|
|
140
164
|
}
|
|
141
165
|
}
|
|
142
166
|
function formatEvidenceSummary(evidence) {
|
|
143
|
-
if (
|
|
144
|
-
return `${evidence[
|
|
167
|
+
if ("transaction_count" in evidence) {
|
|
168
|
+
return `${evidence["transaction_count"]} transactions`;
|
|
145
169
|
}
|
|
146
|
-
if (
|
|
147
|
-
const amount = evidence[
|
|
170
|
+
if ("amount" in evidence && typeof evidence["amount"] === "object") {
|
|
171
|
+
const amount = evidence["amount"];
|
|
148
172
|
return amount.value_display;
|
|
149
173
|
}
|
|
150
|
-
if (
|
|
151
|
-
|
|
174
|
+
if ("transaction_ids" in evidence &&
|
|
175
|
+
Array.isArray(evidence["transaction_ids"])) {
|
|
176
|
+
return `${evidence["transaction_ids"].length} transactions involved`;
|
|
152
177
|
}
|
|
153
178
|
return null;
|
|
154
179
|
}
|
|
155
180
|
function formatExecutionSection(execution) {
|
|
156
181
|
const lines = [];
|
|
157
|
-
lines.push(
|
|
182
|
+
lines.push("Execution Summary");
|
|
158
183
|
lines.push(SECTION_DIVIDER);
|
|
159
184
|
const summary = execution.summary;
|
|
160
185
|
lines.push(`Transactions created: ${summary.transactions_created}`);
|
|
161
186
|
lines.push(`Transactions updated: ${summary.transactions_updated}`);
|
|
162
187
|
lines.push(`Date adjustments: ${summary.dates_adjusted}`);
|
|
163
188
|
if (execution.recommendations.length > 0) {
|
|
164
|
-
lines.push(
|
|
165
|
-
lines.push(
|
|
189
|
+
lines.push("");
|
|
190
|
+
lines.push("Recommendations:");
|
|
166
191
|
const maxRecs = 3;
|
|
167
192
|
const toShow = execution.recommendations.slice(0, maxRecs);
|
|
168
193
|
for (const rec of toShow) {
|
|
@@ -172,22 +197,22 @@ function formatExecutionSection(execution) {
|
|
|
172
197
|
lines.push(` ... and ${execution.recommendations.length - maxRecs} more`);
|
|
173
198
|
}
|
|
174
199
|
}
|
|
175
|
-
lines.push(
|
|
200
|
+
lines.push("");
|
|
176
201
|
if (summary.dry_run) {
|
|
177
|
-
lines.push(
|
|
202
|
+
lines.push("NOTE: Dry run only - no YNAB changes were applied.");
|
|
178
203
|
}
|
|
179
204
|
else {
|
|
180
|
-
lines.push(
|
|
205
|
+
lines.push("Changes applied to YNAB. Review structured output for action details.");
|
|
181
206
|
}
|
|
182
|
-
return lines.join(
|
|
207
|
+
return lines.join("\n");
|
|
183
208
|
}
|
|
184
209
|
function formatRecommendationsSection(analysis, execution) {
|
|
185
210
|
const lines = [];
|
|
186
|
-
lines.push(
|
|
211
|
+
lines.push("Recommended Actions");
|
|
187
212
|
lines.push(SECTION_DIVIDER);
|
|
188
213
|
if (execution && !execution.summary.dry_run) {
|
|
189
|
-
lines.push(
|
|
190
|
-
return lines.join(
|
|
214
|
+
lines.push("All recommended actions have been applied.");
|
|
215
|
+
return lines.join("\n");
|
|
191
216
|
}
|
|
192
217
|
if (analysis.next_steps.length > 0) {
|
|
193
218
|
for (const step of analysis.next_steps) {
|
|
@@ -195,10 +220,10 @@ function formatRecommendationsSection(analysis, execution) {
|
|
|
195
220
|
}
|
|
196
221
|
}
|
|
197
222
|
else {
|
|
198
|
-
lines.push(
|
|
199
|
-
lines.push(
|
|
223
|
+
lines.push("No specific actions recommended.");
|
|
224
|
+
lines.push("Review the structured output for detailed match information.");
|
|
200
225
|
}
|
|
201
|
-
return lines.join(
|
|
226
|
+
return lines.join("\n");
|
|
202
227
|
}
|
|
203
228
|
export function formatBalanceInfo(balance) {
|
|
204
229
|
const lines = [];
|
|
@@ -206,15 +231,15 @@ export function formatBalanceInfo(balance) {
|
|
|
206
231
|
lines.push(`Current Total: ${balance.current_total.value_display}`);
|
|
207
232
|
lines.push(`Target Statement: ${balance.target_statement.value_display}`);
|
|
208
233
|
lines.push(`Discrepancy: ${balance.discrepancy.value_display}`);
|
|
209
|
-
return lines.join(
|
|
234
|
+
return lines.join("\n");
|
|
210
235
|
}
|
|
211
236
|
export function formatTransactionList(transactions, maxItems = 10) {
|
|
212
237
|
const lines = [];
|
|
213
238
|
const toShow = transactions.slice(0, maxItems);
|
|
214
239
|
for (const txn of toShow) {
|
|
215
|
-
if (
|
|
240
|
+
if ("cleared" in txn) {
|
|
216
241
|
const ynabTxn = txn;
|
|
217
|
-
const payee = ynabTxn.payee_name ?? ynabTxn.payee ??
|
|
242
|
+
const payee = ynabTxn.payee_name ?? ynabTxn.payee ?? "Unknown";
|
|
218
243
|
lines.push(` ${ynabTxn.date} - ${payee.substring(0, 40).padEnd(40)} ${formatAmount(ynabTxn.amount)}`);
|
|
219
244
|
}
|
|
220
245
|
else {
|
|
@@ -224,5 +249,5 @@ export function formatTransactionList(transactions, maxItems = 10) {
|
|
|
224
249
|
if (transactions.length > maxItems) {
|
|
225
250
|
lines.push(` ... and ${transactions.length - maxItems} more`);
|
|
226
251
|
}
|
|
227
|
-
return lines.join(
|
|
252
|
+
return lines.join("\n");
|
|
228
253
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type { BankTransaction, NormalizedYNABTransaction } from
|
|
1
|
+
import type { BankTransaction, NormalizedYNABTransaction } from "../../types/reconciliation.js";
|
|
2
2
|
export declare function detectSignInversion(bankTransactions: BankTransaction[], ynabTransactions: NormalizedYNABTransaction[]): boolean;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
1
|
+
import type { BankTransaction as CanonicalBankTransaction, NormalizedYNABTransaction as CanonicalYNABTransaction } from "../../types/reconciliation.js";
|
|
2
|
+
import type { MoneyValue } from "../../utils/money.js";
|
|
3
3
|
export type BankTransaction = CanonicalBankTransaction;
|
|
4
4
|
export type YNABTransaction = CanonicalYNABTransaction;
|
|
5
|
-
export type MatchConfidence =
|
|
5
|
+
export type MatchConfidence = "high" | "medium" | "low" | "none";
|
|
6
6
|
export interface MatchCandidate {
|
|
7
7
|
ynab_transaction: YNABTransaction;
|
|
8
8
|
confidence: number;
|
|
@@ -32,6 +32,8 @@ export interface ReconciliationSummary {
|
|
|
32
32
|
statement_date_range: string;
|
|
33
33
|
bank_transactions_count: number;
|
|
34
34
|
ynab_transactions_count: number;
|
|
35
|
+
ynab_in_range_count: number;
|
|
36
|
+
ynab_outside_range_count: number;
|
|
35
37
|
auto_matched: number;
|
|
36
38
|
suggested_matches: number;
|
|
37
39
|
unmatched_bank: number;
|
|
@@ -41,8 +43,8 @@ export interface ReconciliationSummary {
|
|
|
41
43
|
discrepancy: MoneyValue;
|
|
42
44
|
discrepancy_explanation: string;
|
|
43
45
|
}
|
|
44
|
-
export type InsightSeverity =
|
|
45
|
-
export type InsightKind =
|
|
46
|
+
export type InsightSeverity = "info" | "warning" | "critical";
|
|
47
|
+
export type InsightKind = "repeat_amount" | "near_match" | "anomaly";
|
|
46
48
|
export interface ReconciliationInsight {
|
|
47
49
|
id: string;
|
|
48
50
|
type: InsightKind;
|
|
@@ -53,18 +55,19 @@ export interface ReconciliationInsight {
|
|
|
53
55
|
}
|
|
54
56
|
export interface ReconciliationAnalysis {
|
|
55
57
|
success: true;
|
|
56
|
-
phase:
|
|
58
|
+
phase: "analysis";
|
|
57
59
|
summary: ReconciliationSummary;
|
|
58
60
|
auto_matches: TransactionMatch[];
|
|
59
61
|
suggested_matches: TransactionMatch[];
|
|
60
62
|
unmatched_bank: BankTransaction[];
|
|
61
63
|
unmatched_ynab: YNABTransaction[];
|
|
64
|
+
ynab_outside_date_range: YNABTransaction[];
|
|
62
65
|
balance_info: BalanceInfo;
|
|
63
66
|
next_steps: string[];
|
|
64
67
|
insights: ReconciliationInsight[];
|
|
65
68
|
recommendations?: ActionableRecommendation[];
|
|
66
69
|
}
|
|
67
|
-
export type ReconciliationActionType =
|
|
70
|
+
export type ReconciliationActionType = "match" | "add" | "unclear" | "delete" | "ignore";
|
|
68
71
|
export interface ReconciliationAction {
|
|
69
72
|
type: ReconciliationActionType;
|
|
70
73
|
bank_txn_id?: string;
|
|
@@ -97,7 +100,7 @@ export interface ParsedCSVData {
|
|
|
97
100
|
valid_rows: number;
|
|
98
101
|
errors: string[];
|
|
99
102
|
}
|
|
100
|
-
export type RecommendationPriority =
|
|
103
|
+
export type RecommendationPriority = "high" | "medium" | "low";
|
|
101
104
|
export interface BaseRecommendation {
|
|
102
105
|
id: string;
|
|
103
106
|
priority: RecommendationPriority;
|
|
@@ -110,27 +113,27 @@ export interface BaseRecommendation {
|
|
|
110
113
|
metadata?: Record<string, unknown>;
|
|
111
114
|
}
|
|
112
115
|
export interface CreateTransactionRecommendation extends BaseRecommendation {
|
|
113
|
-
action_type:
|
|
116
|
+
action_type: "create_transaction";
|
|
114
117
|
parameters: {
|
|
115
118
|
account_id: string;
|
|
116
119
|
date: string;
|
|
117
120
|
amount: number;
|
|
118
121
|
payee_name: string;
|
|
119
122
|
memo?: string;
|
|
120
|
-
cleared:
|
|
123
|
+
cleared: "cleared" | "uncleared";
|
|
121
124
|
approved: boolean;
|
|
122
125
|
category_id?: string;
|
|
123
126
|
};
|
|
124
127
|
}
|
|
125
128
|
export interface UpdateClearedRecommendation extends BaseRecommendation {
|
|
126
|
-
action_type:
|
|
129
|
+
action_type: "update_cleared";
|
|
127
130
|
parameters: {
|
|
128
131
|
transaction_id: string;
|
|
129
|
-
cleared:
|
|
132
|
+
cleared: "cleared" | "uncleared" | "reconciled";
|
|
130
133
|
};
|
|
131
134
|
}
|
|
132
135
|
export interface ReviewDuplicateRecommendation extends BaseRecommendation {
|
|
133
|
-
action_type:
|
|
136
|
+
action_type: "review_duplicate";
|
|
134
137
|
parameters: {
|
|
135
138
|
candidate_ids: string[];
|
|
136
139
|
bank_transaction?: BankTransaction;
|
|
@@ -138,14 +141,14 @@ export interface ReviewDuplicateRecommendation extends BaseRecommendation {
|
|
|
138
141
|
};
|
|
139
142
|
}
|
|
140
143
|
export interface RelatedTransaction {
|
|
141
|
-
source:
|
|
144
|
+
source: "bank" | "ynab";
|
|
142
145
|
id: string;
|
|
143
146
|
description: string;
|
|
144
147
|
}
|
|
145
148
|
export interface ManualReviewRecommendation extends BaseRecommendation {
|
|
146
|
-
action_type:
|
|
149
|
+
action_type: "manual_review";
|
|
147
150
|
parameters: {
|
|
148
|
-
issue_type:
|
|
151
|
+
issue_type: "complex_match" | "large_discrepancy" | "unknown";
|
|
149
152
|
related_transactions?: RelatedTransaction[];
|
|
150
153
|
};
|
|
151
154
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type * as ynab from
|
|
2
|
-
import type { NormalizedYNABTransaction } from
|
|
1
|
+
import type * as ynab from "ynab";
|
|
2
|
+
import type { NormalizedYNABTransaction } from "../../types/reconciliation.js";
|
|
3
3
|
export declare function normalizeYNABTransaction(txn: ynab.TransactionDetail): NormalizedYNABTransaction;
|
|
4
4
|
export declare function normalizeYNABTransactions(txns: ynab.TransactionDetail[]): NormalizedYNABTransaction[];
|