@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.
- 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 +19 -12
- package/dist/tools/reconciliation/analyzer.d.ts +4 -4
- package/dist/tools/reconciliation/analyzer.js +73 -59
- 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 +59 -58
- package/dist/tools/reconciliation/signDetector.d.ts +1 -1
- package/dist/tools/reconciliation/types.d.ts +16 -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 +7 -7
- package/dist/tools/transactionSchemas.js +77 -57
- package/dist/tools/transactionTools.d.ts +6 -24
- package/dist/tools/transactionTools.js +7 -1499
- package/dist/tools/transactionUtils.d.ts +6 -6
- package/dist/tools/transactionUtils.js +78 -63
- 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/esbuild.config.mjs +53 -50
- package/meta.json +12548 -12548
- package/package.json +98 -111
- package/scripts/analyze-bundle.mjs +33 -30
- package/scripts/create-pr-description.js +169 -120
- package/scripts/run-all-tests.js +178 -169
- 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 +1202 -1186
- 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 +1004 -977
- 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 -252
- package/src/tools/reconciliation/CLAUDE.md +506 -0
- package/src/tools/reconciliation/__tests__/adapter.causes.test.ts +133 -124
- package/src/tools/reconciliation/__tests__/adapter.test.ts +249 -230
- package/src/tools/reconciliation/__tests__/analyzer.test.ts +408 -400
- 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 -989
- package/src/tools/reconciliation/__tests__/reconciliation.delta.integration.test.ts +187 -146
- package/src/tools/reconciliation/__tests__/reportFormatter.test.ts +583 -533
- package/src/tools/reconciliation/__tests__/scenarios/adapterCurrency.scenario.test.ts +75 -74
- package/src/tools/reconciliation/__tests__/scenarios/extremes.scenario.test.ts +70 -62
- package/src/tools/reconciliation/__tests__/scenarios/repeatAmount.scenario.test.ts +102 -88
- package/src/tools/reconciliation/__tests__/schemaUrl.test.ts +56 -55
- 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 +564 -504
- 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 +343 -307
- package/src/tools/reconciliation/signDetector.ts +89 -83
- package/src/tools/reconciliation/types.ts +164 -159
- 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 +322 -291
- package/src/tools/transactionTools.ts +84 -2246
- package/src/tools/transactionUtils.ts +507 -422
- 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,48 +15,48 @@ 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
62
|
const outsideRangeCount = summary.ynab_outside_range_count ?? 0;
|
|
@@ -64,15 +64,15 @@ function formatTransactionAnalysisSection(analysis, options) {
|
|
|
64
64
|
const inRangeCount = summary.ynab_in_range_count ?? summary.ynab_transactions_count;
|
|
65
65
|
lines.push(`Comparing ${summary.bank_transactions_count} bank transactions with ${inRangeCount} YNAB transactions within statement period.`);
|
|
66
66
|
lines.push(`(${outsideRangeCount} YNAB transactions outside statement period - not compared)`);
|
|
67
|
-
lines.push(
|
|
67
|
+
lines.push("");
|
|
68
68
|
}
|
|
69
69
|
lines.push(`- Automatically matched: ${summary.auto_matched} of ${summary.bank_transactions_count} transactions`);
|
|
70
70
|
lines.push(`- Suggested matches: ${summary.suggested_matches}`);
|
|
71
71
|
lines.push(`- Unmatched bank: ${summary.unmatched_bank}`);
|
|
72
72
|
lines.push(`- Unmatched YNAB: ${summary.unmatched_ynab}`);
|
|
73
73
|
if (analysis.unmatched_bank.length > 0) {
|
|
74
|
-
lines.push(
|
|
75
|
-
lines.push(
|
|
74
|
+
lines.push("");
|
|
75
|
+
lines.push("Missing from YNAB (bank transactions without matches):");
|
|
76
76
|
const maxToShow = options.maxUnmatchedToShow ?? 5;
|
|
77
77
|
const toShow = analysis.unmatched_bank.slice(0, maxToShow);
|
|
78
78
|
for (const txn of toShow) {
|
|
@@ -83,8 +83,8 @@ function formatTransactionAnalysisSection(analysis, options) {
|
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
85
|
if (analysis.unmatched_ynab.length > 0) {
|
|
86
|
-
lines.push(
|
|
87
|
-
lines.push(
|
|
86
|
+
lines.push("");
|
|
87
|
+
lines.push("Missing from bank statement (YNAB transactions without matches):");
|
|
88
88
|
const maxToShow = options.maxUnmatchedToShow ?? 5;
|
|
89
89
|
const toShow = analysis.unmatched_ynab.slice(0, maxToShow);
|
|
90
90
|
for (const txn of toShow) {
|
|
@@ -95,8 +95,8 @@ function formatTransactionAnalysisSection(analysis, options) {
|
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
if (analysis.suggested_matches.length > 0) {
|
|
98
|
-
lines.push(
|
|
99
|
-
lines.push(
|
|
98
|
+
lines.push("");
|
|
99
|
+
lines.push("Suggested matches (review manually):");
|
|
100
100
|
const maxToShow = options.maxUnmatchedToShow ?? 3;
|
|
101
101
|
const toShow = analysis.suggested_matches.slice(0, maxToShow);
|
|
102
102
|
for (const match of toShow) {
|
|
@@ -106,11 +106,11 @@ function formatTransactionAnalysisSection(analysis, options) {
|
|
|
106
106
|
lines.push(` ... and ${analysis.suggested_matches.length - maxToShow} more suggestions`);
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
|
-
return lines.join(
|
|
109
|
+
return lines.join("\n");
|
|
110
110
|
}
|
|
111
111
|
function formatYnabTransactionLine(txn) {
|
|
112
112
|
const amountStr = formatAmount(txn.amount);
|
|
113
|
-
const payee = txn.payee ??
|
|
113
|
+
const payee = txn.payee ?? "Unknown";
|
|
114
114
|
return ` ${txn.date} - ${payee.substring(0, 40).padEnd(40)} ${amountStr}`;
|
|
115
115
|
}
|
|
116
116
|
function formatBankTransactionLine(txn) {
|
|
@@ -125,13 +125,13 @@ function formatSuggestedMatchLine(match) {
|
|
|
125
125
|
}
|
|
126
126
|
function formatAmount(amountMilli) {
|
|
127
127
|
const amount = amountMilli / 1000;
|
|
128
|
-
const sign = amount >= 0 ?
|
|
128
|
+
const sign = amount >= 0 ? "+" : "-";
|
|
129
129
|
const absAmount = Math.abs(amount);
|
|
130
130
|
return `${sign}$${absAmount.toFixed(2)}`.padStart(10);
|
|
131
131
|
}
|
|
132
132
|
function formatInsightsSection(insights, maxToShow = 3) {
|
|
133
133
|
const lines = [];
|
|
134
|
-
lines.push(
|
|
134
|
+
lines.push("Key Insights");
|
|
135
135
|
lines.push(SECTION_DIVIDER);
|
|
136
136
|
const toShow = insights.slice(0, maxToShow);
|
|
137
137
|
for (const insight of toShow) {
|
|
@@ -144,49 +144,50 @@ function formatInsightsSection(insights, maxToShow = 3) {
|
|
|
144
144
|
lines.push(` Evidence: ${evidenceSummary}`);
|
|
145
145
|
}
|
|
146
146
|
}
|
|
147
|
-
lines.push(
|
|
147
|
+
lines.push("");
|
|
148
148
|
}
|
|
149
149
|
if (insights.length > maxToShow) {
|
|
150
150
|
lines.push(`... and ${insights.length - maxToShow} more insights (see structured output)`);
|
|
151
151
|
}
|
|
152
|
-
return lines.join(
|
|
152
|
+
return lines.join("\n").trimEnd();
|
|
153
153
|
}
|
|
154
154
|
function getSeverityIcon(severity) {
|
|
155
155
|
switch (severity) {
|
|
156
|
-
case
|
|
157
|
-
return
|
|
158
|
-
case
|
|
159
|
-
return
|
|
160
|
-
case
|
|
161
|
-
return
|
|
156
|
+
case "critical":
|
|
157
|
+
return "[CRITICAL]";
|
|
158
|
+
case "warning":
|
|
159
|
+
return "[WARN]";
|
|
160
|
+
case "info":
|
|
161
|
+
return "[INFO]";
|
|
162
162
|
default:
|
|
163
|
-
return
|
|
163
|
+
return "[NOTE]";
|
|
164
164
|
}
|
|
165
165
|
}
|
|
166
166
|
function formatEvidenceSummary(evidence) {
|
|
167
|
-
if (
|
|
168
|
-
return `${evidence[
|
|
167
|
+
if ("transaction_count" in evidence) {
|
|
168
|
+
return `${evidence["transaction_count"]} transactions`;
|
|
169
169
|
}
|
|
170
|
-
if (
|
|
171
|
-
const amount = evidence[
|
|
170
|
+
if ("amount" in evidence && typeof evidence["amount"] === "object") {
|
|
171
|
+
const amount = evidence["amount"];
|
|
172
172
|
return amount.value_display;
|
|
173
173
|
}
|
|
174
|
-
if (
|
|
175
|
-
|
|
174
|
+
if ("transaction_ids" in evidence &&
|
|
175
|
+
Array.isArray(evidence["transaction_ids"])) {
|
|
176
|
+
return `${evidence["transaction_ids"].length} transactions involved`;
|
|
176
177
|
}
|
|
177
178
|
return null;
|
|
178
179
|
}
|
|
179
180
|
function formatExecutionSection(execution) {
|
|
180
181
|
const lines = [];
|
|
181
|
-
lines.push(
|
|
182
|
+
lines.push("Execution Summary");
|
|
182
183
|
lines.push(SECTION_DIVIDER);
|
|
183
184
|
const summary = execution.summary;
|
|
184
185
|
lines.push(`Transactions created: ${summary.transactions_created}`);
|
|
185
186
|
lines.push(`Transactions updated: ${summary.transactions_updated}`);
|
|
186
187
|
lines.push(`Date adjustments: ${summary.dates_adjusted}`);
|
|
187
188
|
if (execution.recommendations.length > 0) {
|
|
188
|
-
lines.push(
|
|
189
|
-
lines.push(
|
|
189
|
+
lines.push("");
|
|
190
|
+
lines.push("Recommendations:");
|
|
190
191
|
const maxRecs = 3;
|
|
191
192
|
const toShow = execution.recommendations.slice(0, maxRecs);
|
|
192
193
|
for (const rec of toShow) {
|
|
@@ -196,22 +197,22 @@ function formatExecutionSection(execution) {
|
|
|
196
197
|
lines.push(` ... and ${execution.recommendations.length - maxRecs} more`);
|
|
197
198
|
}
|
|
198
199
|
}
|
|
199
|
-
lines.push(
|
|
200
|
+
lines.push("");
|
|
200
201
|
if (summary.dry_run) {
|
|
201
|
-
lines.push(
|
|
202
|
+
lines.push("NOTE: Dry run only - no YNAB changes were applied.");
|
|
202
203
|
}
|
|
203
204
|
else {
|
|
204
|
-
lines.push(
|
|
205
|
+
lines.push("Changes applied to YNAB. Review structured output for action details.");
|
|
205
206
|
}
|
|
206
|
-
return lines.join(
|
|
207
|
+
return lines.join("\n");
|
|
207
208
|
}
|
|
208
209
|
function formatRecommendationsSection(analysis, execution) {
|
|
209
210
|
const lines = [];
|
|
210
|
-
lines.push(
|
|
211
|
+
lines.push("Recommended Actions");
|
|
211
212
|
lines.push(SECTION_DIVIDER);
|
|
212
213
|
if (execution && !execution.summary.dry_run) {
|
|
213
|
-
lines.push(
|
|
214
|
-
return lines.join(
|
|
214
|
+
lines.push("All recommended actions have been applied.");
|
|
215
|
+
return lines.join("\n");
|
|
215
216
|
}
|
|
216
217
|
if (analysis.next_steps.length > 0) {
|
|
217
218
|
for (const step of analysis.next_steps) {
|
|
@@ -219,10 +220,10 @@ function formatRecommendationsSection(analysis, execution) {
|
|
|
219
220
|
}
|
|
220
221
|
}
|
|
221
222
|
else {
|
|
222
|
-
lines.push(
|
|
223
|
-
lines.push(
|
|
223
|
+
lines.push("No specific actions recommended.");
|
|
224
|
+
lines.push("Review the structured output for detailed match information.");
|
|
224
225
|
}
|
|
225
|
-
return lines.join(
|
|
226
|
+
return lines.join("\n");
|
|
226
227
|
}
|
|
227
228
|
export function formatBalanceInfo(balance) {
|
|
228
229
|
const lines = [];
|
|
@@ -230,15 +231,15 @@ export function formatBalanceInfo(balance) {
|
|
|
230
231
|
lines.push(`Current Total: ${balance.current_total.value_display}`);
|
|
231
232
|
lines.push(`Target Statement: ${balance.target_statement.value_display}`);
|
|
232
233
|
lines.push(`Discrepancy: ${balance.discrepancy.value_display}`);
|
|
233
|
-
return lines.join(
|
|
234
|
+
return lines.join("\n");
|
|
234
235
|
}
|
|
235
236
|
export function formatTransactionList(transactions, maxItems = 10) {
|
|
236
237
|
const lines = [];
|
|
237
238
|
const toShow = transactions.slice(0, maxItems);
|
|
238
239
|
for (const txn of toShow) {
|
|
239
|
-
if (
|
|
240
|
+
if ("cleared" in txn) {
|
|
240
241
|
const ynabTxn = txn;
|
|
241
|
-
const payee = ynabTxn.payee_name ?? ynabTxn.payee ??
|
|
242
|
+
const payee = ynabTxn.payee_name ?? ynabTxn.payee ?? "Unknown";
|
|
242
243
|
lines.push(` ${ynabTxn.date} - ${payee.substring(0, 40).padEnd(40)} ${formatAmount(ynabTxn.amount)}`);
|
|
243
244
|
}
|
|
244
245
|
else {
|
|
@@ -248,5 +249,5 @@ export function formatTransactionList(transactions, maxItems = 10) {
|
|
|
248
249
|
if (transactions.length > maxItems) {
|
|
249
250
|
lines.push(` ... and ${transactions.length - maxItems} more`);
|
|
250
251
|
}
|
|
251
|
-
return lines.join(
|
|
252
|
+
return lines.join("\n");
|
|
252
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;
|
|
@@ -43,8 +43,8 @@ export interface ReconciliationSummary {
|
|
|
43
43
|
discrepancy: MoneyValue;
|
|
44
44
|
discrepancy_explanation: string;
|
|
45
45
|
}
|
|
46
|
-
export type InsightSeverity =
|
|
47
|
-
export type InsightKind =
|
|
46
|
+
export type InsightSeverity = "info" | "warning" | "critical";
|
|
47
|
+
export type InsightKind = "repeat_amount" | "near_match" | "anomaly";
|
|
48
48
|
export interface ReconciliationInsight {
|
|
49
49
|
id: string;
|
|
50
50
|
type: InsightKind;
|
|
@@ -55,7 +55,7 @@ export interface ReconciliationInsight {
|
|
|
55
55
|
}
|
|
56
56
|
export interface ReconciliationAnalysis {
|
|
57
57
|
success: true;
|
|
58
|
-
phase:
|
|
58
|
+
phase: "analysis";
|
|
59
59
|
summary: ReconciliationSummary;
|
|
60
60
|
auto_matches: TransactionMatch[];
|
|
61
61
|
suggested_matches: TransactionMatch[];
|
|
@@ -67,7 +67,7 @@ export interface ReconciliationAnalysis {
|
|
|
67
67
|
insights: ReconciliationInsight[];
|
|
68
68
|
recommendations?: ActionableRecommendation[];
|
|
69
69
|
}
|
|
70
|
-
export type ReconciliationActionType =
|
|
70
|
+
export type ReconciliationActionType = "match" | "add" | "unclear" | "delete" | "ignore";
|
|
71
71
|
export interface ReconciliationAction {
|
|
72
72
|
type: ReconciliationActionType;
|
|
73
73
|
bank_txn_id?: string;
|
|
@@ -100,7 +100,7 @@ export interface ParsedCSVData {
|
|
|
100
100
|
valid_rows: number;
|
|
101
101
|
errors: string[];
|
|
102
102
|
}
|
|
103
|
-
export type RecommendationPriority =
|
|
103
|
+
export type RecommendationPriority = "high" | "medium" | "low";
|
|
104
104
|
export interface BaseRecommendation {
|
|
105
105
|
id: string;
|
|
106
106
|
priority: RecommendationPriority;
|
|
@@ -113,27 +113,27 @@ export interface BaseRecommendation {
|
|
|
113
113
|
metadata?: Record<string, unknown>;
|
|
114
114
|
}
|
|
115
115
|
export interface CreateTransactionRecommendation extends BaseRecommendation {
|
|
116
|
-
action_type:
|
|
116
|
+
action_type: "create_transaction";
|
|
117
117
|
parameters: {
|
|
118
118
|
account_id: string;
|
|
119
119
|
date: string;
|
|
120
120
|
amount: number;
|
|
121
121
|
payee_name: string;
|
|
122
122
|
memo?: string;
|
|
123
|
-
cleared:
|
|
123
|
+
cleared: "cleared" | "uncleared";
|
|
124
124
|
approved: boolean;
|
|
125
125
|
category_id?: string;
|
|
126
126
|
};
|
|
127
127
|
}
|
|
128
128
|
export interface UpdateClearedRecommendation extends BaseRecommendation {
|
|
129
|
-
action_type:
|
|
129
|
+
action_type: "update_cleared";
|
|
130
130
|
parameters: {
|
|
131
131
|
transaction_id: string;
|
|
132
|
-
cleared:
|
|
132
|
+
cleared: "cleared" | "uncleared" | "reconciled";
|
|
133
133
|
};
|
|
134
134
|
}
|
|
135
135
|
export interface ReviewDuplicateRecommendation extends BaseRecommendation {
|
|
136
|
-
action_type:
|
|
136
|
+
action_type: "review_duplicate";
|
|
137
137
|
parameters: {
|
|
138
138
|
candidate_ids: string[];
|
|
139
139
|
bank_transaction?: BankTransaction;
|
|
@@ -141,14 +141,14 @@ export interface ReviewDuplicateRecommendation extends BaseRecommendation {
|
|
|
141
141
|
};
|
|
142
142
|
}
|
|
143
143
|
export interface RelatedTransaction {
|
|
144
|
-
source:
|
|
144
|
+
source: "bank" | "ynab";
|
|
145
145
|
id: string;
|
|
146
146
|
description: string;
|
|
147
147
|
}
|
|
148
148
|
export interface ManualReviewRecommendation extends BaseRecommendation {
|
|
149
|
-
action_type:
|
|
149
|
+
action_type: "manual_review";
|
|
150
150
|
parameters: {
|
|
151
|
-
issue_type:
|
|
151
|
+
issue_type: "complex_match" | "large_discrepancy" | "unknown";
|
|
152
152
|
related_transactions?: RelatedTransaction[];
|
|
153
153
|
};
|
|
154
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[];
|