@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
|
@@ -3,384 +3,457 @@
|
|
|
3
3
|
* Implements Phase 3 of dual-channel output improvements
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
import type { MoneyValue } from "../../utils/money.js";
|
|
7
|
+
import type { LegacyReconciliationResult } from "./executor.js";
|
|
6
8
|
import type {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
} from
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const SECTION_DIVIDER = '-'.repeat(60);
|
|
9
|
+
BalanceInfo,
|
|
10
|
+
BankTransaction,
|
|
11
|
+
ReconciliationAnalysis,
|
|
12
|
+
ReconciliationInsight,
|
|
13
|
+
TransactionMatch,
|
|
14
|
+
YNABTransaction,
|
|
15
|
+
} from "./types.js";
|
|
16
|
+
|
|
17
|
+
const SECTION_DIVIDER = "-".repeat(60);
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* Options for report formatting
|
|
21
21
|
*/
|
|
22
22
|
export interface ReportFormatterOptions {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
23
|
+
accountName?: string | undefined;
|
|
24
|
+
accountId?: string | undefined;
|
|
25
|
+
currencyCode?: string | undefined;
|
|
26
|
+
includeDetailedMatches?: boolean | undefined;
|
|
27
|
+
maxUnmatchedToShow?: number | undefined;
|
|
28
|
+
maxInsightsToShow?: number | undefined;
|
|
29
|
+
notes?: string[] | undefined;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
33
|
* Format the main human-readable reconciliation report
|
|
34
34
|
*/
|
|
35
35
|
export function formatHumanReadableReport(
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
analysis: ReconciliationAnalysis,
|
|
37
|
+
options: ReportFormatterOptions = {},
|
|
38
|
+
execution?: LegacyReconciliationResult,
|
|
39
39
|
): string {
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
const accountLabel = options.accountName ?? "Account";
|
|
41
|
+
const sections: string[] = [];
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
// Header
|
|
44
|
+
sections.push(formatHeader(accountLabel, analysis));
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
// Contextual notes (if provided)
|
|
47
|
+
if (options.notes && options.notes.length > 0) {
|
|
48
|
+
sections.push(formatNotesSection(options.notes));
|
|
49
|
+
}
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
// Balance check section
|
|
52
|
+
sections.push(formatBalanceSection(analysis.balance_info, analysis.summary));
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
// Transaction analysis section
|
|
55
|
+
sections.push(formatTransactionAnalysisSection(analysis, options));
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
57
|
+
// Insights section (if any)
|
|
58
|
+
if (analysis.insights.length > 0) {
|
|
59
|
+
sections.push(
|
|
60
|
+
formatInsightsSection(analysis.insights, options.maxInsightsToShow),
|
|
61
|
+
);
|
|
62
|
+
}
|
|
61
63
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
// Execution summary (if any)
|
|
65
|
+
if (execution) {
|
|
66
|
+
sections.push(formatExecutionSection(execution));
|
|
67
|
+
}
|
|
66
68
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
+
// Recommendations/Next steps
|
|
70
|
+
sections.push(formatRecommendationsSection(analysis, execution));
|
|
69
71
|
|
|
70
|
-
|
|
72
|
+
return sections.join("\n\n");
|
|
71
73
|
}
|
|
72
74
|
|
|
73
75
|
/**
|
|
74
76
|
* Format the report header
|
|
75
77
|
*/
|
|
76
|
-
function formatHeader(
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
78
|
+
function formatHeader(
|
|
79
|
+
accountName: string,
|
|
80
|
+
analysis: ReconciliationAnalysis,
|
|
81
|
+
): string {
|
|
82
|
+
const lines: string[] = [];
|
|
83
|
+
lines.push(`${accountName} Reconciliation Report`);
|
|
84
|
+
lines.push(SECTION_DIVIDER);
|
|
85
|
+
lines.push(`Statement Period: ${analysis.summary.statement_date_range}`);
|
|
86
|
+
return lines.join("\n");
|
|
82
87
|
}
|
|
83
88
|
|
|
84
89
|
function formatNotesSection(notes: string[]): string {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
const lines: string[] = [];
|
|
91
|
+
lines.push("Notes");
|
|
92
|
+
lines.push(SECTION_DIVIDER);
|
|
93
|
+
for (const note of notes) {
|
|
94
|
+
lines.push(`- ${note}`);
|
|
95
|
+
}
|
|
96
|
+
return lines.join("\n");
|
|
92
97
|
}
|
|
93
98
|
|
|
94
99
|
/**
|
|
95
100
|
* Format the balance check section
|
|
96
101
|
*/
|
|
97
102
|
function formatBalanceSection(
|
|
98
|
-
|
|
99
|
-
|
|
103
|
+
balanceInfo: BalanceInfo,
|
|
104
|
+
summary: ReconciliationAnalysis["summary"],
|
|
100
105
|
): string {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
106
|
+
const lines: string[] = [];
|
|
107
|
+
lines.push("Balance Check");
|
|
108
|
+
lines.push(SECTION_DIVIDER);
|
|
109
|
+
|
|
110
|
+
// Current balances
|
|
111
|
+
lines.push(
|
|
112
|
+
`- YNAB Cleared Balance: ${summary.current_cleared_balance.value_display}`,
|
|
113
|
+
);
|
|
114
|
+
lines.push(
|
|
115
|
+
`- Statement Balance: ${summary.target_statement_balance.value_display}`,
|
|
116
|
+
);
|
|
117
|
+
lines.push("");
|
|
118
|
+
|
|
119
|
+
// Discrepancy status
|
|
120
|
+
const discrepancyMilli = balanceInfo.discrepancy.value_milliunits;
|
|
121
|
+
if (discrepancyMilli === 0) {
|
|
122
|
+
lines.push("Balances match perfectly.");
|
|
123
|
+
} else {
|
|
124
|
+
const direction = discrepancyMilli > 0 ? "ynab_higher" : "bank_higher";
|
|
125
|
+
const directionLabel =
|
|
126
|
+
direction === "ynab_higher"
|
|
127
|
+
? "YNAB shows MORE than statement"
|
|
128
|
+
: "Statement shows MORE than YNAB";
|
|
129
|
+
|
|
130
|
+
lines.push(`Discrepancy: ${balanceInfo.discrepancy.value_display}`);
|
|
131
|
+
lines.push(`Direction: ${directionLabel}`);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return lines.join("\n");
|
|
126
135
|
}
|
|
127
136
|
|
|
128
137
|
/**
|
|
129
138
|
* Format the transaction analysis section
|
|
130
139
|
*/
|
|
131
140
|
function formatTransactionAnalysisSection(
|
|
132
|
-
|
|
133
|
-
|
|
141
|
+
analysis: ReconciliationAnalysis,
|
|
142
|
+
options: ReportFormatterOptions,
|
|
134
143
|
): string {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
144
|
+
const lines: string[] = [];
|
|
145
|
+
lines.push("Transaction Analysis");
|
|
146
|
+
lines.push(SECTION_DIVIDER);
|
|
147
|
+
|
|
148
|
+
const summary = analysis.summary;
|
|
149
|
+
|
|
150
|
+
// Show date range context if transactions were filtered
|
|
151
|
+
const outsideRangeCount = summary.ynab_outside_range_count ?? 0;
|
|
152
|
+
if (outsideRangeCount > 0) {
|
|
153
|
+
const inRangeCount =
|
|
154
|
+
summary.ynab_in_range_count ?? summary.ynab_transactions_count;
|
|
155
|
+
lines.push(
|
|
156
|
+
`Comparing ${summary.bank_transactions_count} bank transactions with ${inRangeCount} YNAB transactions within statement period.`,
|
|
157
|
+
);
|
|
158
|
+
lines.push(
|
|
159
|
+
`(${outsideRangeCount} YNAB transactions outside statement period - not compared)`,
|
|
160
|
+
);
|
|
161
|
+
lines.push("");
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
lines.push(
|
|
165
|
+
`- Automatically matched: ${summary.auto_matched} of ${summary.bank_transactions_count} transactions`,
|
|
166
|
+
);
|
|
167
|
+
lines.push(`- Suggested matches: ${summary.suggested_matches}`);
|
|
168
|
+
lines.push(`- Unmatched bank: ${summary.unmatched_bank}`);
|
|
169
|
+
lines.push(`- Unmatched YNAB: ${summary.unmatched_ynab}`);
|
|
170
|
+
|
|
171
|
+
// Show unmatched bank transactions (if any)
|
|
172
|
+
if (analysis.unmatched_bank.length > 0) {
|
|
173
|
+
lines.push("");
|
|
174
|
+
lines.push("Missing from YNAB (bank transactions without matches):");
|
|
175
|
+
const maxToShow = options.maxUnmatchedToShow ?? 5;
|
|
176
|
+
const toShow = analysis.unmatched_bank.slice(0, maxToShow);
|
|
177
|
+
|
|
178
|
+
for (const txn of toShow) {
|
|
179
|
+
lines.push(formatBankTransactionLine(txn));
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (analysis.unmatched_bank.length > maxToShow) {
|
|
183
|
+
lines.push(
|
|
184
|
+
` ... and ${analysis.unmatched_bank.length - maxToShow} more`,
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Show unmatched YNAB transactions within date range (if any)
|
|
190
|
+
if (analysis.unmatched_ynab.length > 0) {
|
|
191
|
+
lines.push("");
|
|
192
|
+
lines.push(
|
|
193
|
+
"Missing from bank statement (YNAB transactions without matches):",
|
|
194
|
+
);
|
|
195
|
+
const maxToShow = options.maxUnmatchedToShow ?? 5;
|
|
196
|
+
const toShow = analysis.unmatched_ynab.slice(0, maxToShow);
|
|
197
|
+
|
|
198
|
+
for (const txn of toShow) {
|
|
199
|
+
lines.push(formatYnabTransactionLine(txn));
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (analysis.unmatched_ynab.length > maxToShow) {
|
|
203
|
+
lines.push(
|
|
204
|
+
` ... and ${analysis.unmatched_ynab.length - maxToShow} more`,
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Show suggested matches (if any)
|
|
210
|
+
if (analysis.suggested_matches.length > 0) {
|
|
211
|
+
lines.push("");
|
|
212
|
+
lines.push("Suggested matches (review manually):");
|
|
213
|
+
const maxToShow = options.maxUnmatchedToShow ?? 3;
|
|
214
|
+
const toShow = analysis.suggested_matches.slice(0, maxToShow);
|
|
215
|
+
|
|
216
|
+
for (const match of toShow) {
|
|
217
|
+
lines.push(formatSuggestedMatchLine(match));
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (analysis.suggested_matches.length > maxToShow) {
|
|
221
|
+
lines.push(
|
|
222
|
+
` ... and ${analysis.suggested_matches.length - maxToShow} more suggestions`,
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
return lines.join("\n");
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Format a YNAB transaction line
|
|
232
|
+
*/
|
|
233
|
+
function formatYnabTransactionLine(txn: YNABTransaction): string {
|
|
234
|
+
const amountStr = formatAmount(txn.amount);
|
|
235
|
+
const payee = txn.payee ?? "Unknown";
|
|
236
|
+
return ` ${txn.date} - ${payee.substring(0, 40).padEnd(40)} ${amountStr}`;
|
|
180
237
|
}
|
|
181
238
|
|
|
182
239
|
/**
|
|
183
240
|
* Format a bank transaction line
|
|
184
241
|
*/
|
|
185
242
|
function formatBankTransactionLine(txn: BankTransaction): string {
|
|
186
|
-
|
|
187
|
-
|
|
243
|
+
const amountStr = formatAmount(txn.amount);
|
|
244
|
+
return ` ${txn.date} - ${txn.payee.substring(0, 40).padEnd(40)} ${amountStr}`;
|
|
188
245
|
}
|
|
189
246
|
|
|
190
247
|
/**
|
|
191
248
|
* Format a suggested match line
|
|
192
249
|
*/
|
|
193
250
|
function formatSuggestedMatchLine(match: TransactionMatch): string {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
251
|
+
const bankTxn = match.bankTransaction;
|
|
252
|
+
const amountStr = formatAmount(bankTxn.amount);
|
|
253
|
+
const confidenceStr = `${match.confidenceScore}%`;
|
|
254
|
+
return ` ${bankTxn.date} - ${bankTxn.payee.substring(0, 35).padEnd(35)} ${amountStr} (${confidenceStr} confidence)`;
|
|
198
255
|
}
|
|
199
256
|
|
|
200
257
|
/**
|
|
201
258
|
* Format an amount for display (input in milliunits)
|
|
202
259
|
*/
|
|
203
260
|
function formatAmount(amountMilli: number): string {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
261
|
+
const amount = amountMilli / 1000;
|
|
262
|
+
const sign = amount >= 0 ? "+" : "-";
|
|
263
|
+
const absAmount = Math.abs(amount);
|
|
264
|
+
return `${sign}$${absAmount.toFixed(2)}`.padStart(10);
|
|
208
265
|
}
|
|
209
266
|
|
|
210
267
|
/**
|
|
211
268
|
* Format the insights section
|
|
212
269
|
*/
|
|
213
|
-
function formatInsightsSection(
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
270
|
+
function formatInsightsSection(
|
|
271
|
+
insights: ReconciliationInsight[],
|
|
272
|
+
maxToShow = 3,
|
|
273
|
+
): string {
|
|
274
|
+
const lines: string[] = [];
|
|
275
|
+
lines.push("Key Insights");
|
|
276
|
+
lines.push(SECTION_DIVIDER);
|
|
277
|
+
|
|
278
|
+
const toShow = insights.slice(0, maxToShow);
|
|
279
|
+
for (const insight of toShow) {
|
|
280
|
+
const severityIcon = getSeverityIcon(insight.severity);
|
|
281
|
+
lines.push(`${severityIcon} ${insight.title}`);
|
|
282
|
+
lines.push(` ${insight.description}`);
|
|
283
|
+
|
|
284
|
+
// Show evidence summary if available
|
|
285
|
+
if (insight.evidence && Object.keys(insight.evidence).length > 0) {
|
|
286
|
+
const evidenceSummary = formatEvidenceSummary(insight.evidence);
|
|
287
|
+
if (evidenceSummary) {
|
|
288
|
+
lines.push(` Evidence: ${evidenceSummary}`);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
lines.push("");
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (insights.length > maxToShow) {
|
|
296
|
+
lines.push(
|
|
297
|
+
`... and ${insights.length - maxToShow} more insights (see structured output)`,
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
return lines.join("\n").trimEnd();
|
|
240
302
|
}
|
|
241
303
|
|
|
242
304
|
/**
|
|
243
305
|
* Get text icon for severity level
|
|
244
306
|
*/
|
|
245
307
|
function getSeverityIcon(severity: string): string {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
308
|
+
switch (severity) {
|
|
309
|
+
case "critical":
|
|
310
|
+
return "[CRITICAL]";
|
|
311
|
+
case "warning":
|
|
312
|
+
return "[WARN]";
|
|
313
|
+
case "info":
|
|
314
|
+
return "[INFO]";
|
|
315
|
+
default:
|
|
316
|
+
return "[NOTE]";
|
|
317
|
+
}
|
|
256
318
|
}
|
|
257
319
|
|
|
258
320
|
/**
|
|
259
321
|
* Format evidence summary from insight evidence object
|
|
260
322
|
*/
|
|
261
|
-
function formatEvidenceSummary(
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
323
|
+
function formatEvidenceSummary(
|
|
324
|
+
evidence: Record<string, unknown>,
|
|
325
|
+
): string | null {
|
|
326
|
+
// Handle common evidence patterns
|
|
327
|
+
if ("transaction_count" in evidence) {
|
|
328
|
+
return `${evidence["transaction_count"]} transactions`;
|
|
329
|
+
}
|
|
330
|
+
if ("amount" in evidence && typeof evidence["amount"] === "object") {
|
|
331
|
+
const amount = evidence["amount"] as MoneyValue;
|
|
332
|
+
return amount.value_display;
|
|
333
|
+
}
|
|
334
|
+
if (
|
|
335
|
+
"transaction_ids" in evidence &&
|
|
336
|
+
Array.isArray(evidence["transaction_ids"])
|
|
337
|
+
) {
|
|
338
|
+
return `${evidence["transaction_ids"].length} transactions involved`;
|
|
339
|
+
}
|
|
340
|
+
return null;
|
|
274
341
|
}
|
|
275
342
|
|
|
276
343
|
/**
|
|
277
344
|
* Format the execution section
|
|
278
345
|
*/
|
|
279
346
|
function formatExecutionSection(execution: LegacyReconciliationResult): string {
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
347
|
+
const lines: string[] = [];
|
|
348
|
+
lines.push("Execution Summary");
|
|
349
|
+
lines.push(SECTION_DIVIDER);
|
|
350
|
+
|
|
351
|
+
const summary = execution.summary;
|
|
352
|
+
lines.push(`Transactions created: ${summary.transactions_created}`);
|
|
353
|
+
lines.push(`Transactions updated: ${summary.transactions_updated}`);
|
|
354
|
+
lines.push(`Date adjustments: ${summary.dates_adjusted}`);
|
|
355
|
+
|
|
356
|
+
// Show top recommendations if any
|
|
357
|
+
if (execution.recommendations.length > 0) {
|
|
358
|
+
lines.push("");
|
|
359
|
+
lines.push("Recommendations:");
|
|
360
|
+
const maxRecs = 3;
|
|
361
|
+
const toShow = execution.recommendations.slice(0, maxRecs);
|
|
362
|
+
for (const rec of toShow) {
|
|
363
|
+
lines.push(` - ${rec}`);
|
|
364
|
+
}
|
|
365
|
+
if (execution.recommendations.length > maxRecs) {
|
|
366
|
+
lines.push(
|
|
367
|
+
` ... and ${execution.recommendations.length - maxRecs} more`,
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
lines.push("");
|
|
373
|
+
if (summary.dry_run) {
|
|
374
|
+
lines.push("NOTE: Dry run only - no YNAB changes were applied.");
|
|
375
|
+
} else {
|
|
376
|
+
lines.push(
|
|
377
|
+
"Changes applied to YNAB. Review structured output for action details.",
|
|
378
|
+
);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
return lines.join("\n");
|
|
311
382
|
}
|
|
312
383
|
|
|
313
384
|
/**
|
|
314
385
|
* Format the recommendations/next steps section
|
|
315
386
|
*/
|
|
316
387
|
function formatRecommendationsSection(
|
|
317
|
-
|
|
318
|
-
|
|
388
|
+
analysis: ReconciliationAnalysis,
|
|
389
|
+
execution?: LegacyReconciliationResult,
|
|
319
390
|
): string {
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
391
|
+
const lines: string[] = [];
|
|
392
|
+
lines.push("Recommended Actions");
|
|
393
|
+
lines.push(SECTION_DIVIDER);
|
|
394
|
+
|
|
395
|
+
// If we have execution results, recommendations are already shown
|
|
396
|
+
if (execution && !execution.summary.dry_run) {
|
|
397
|
+
lines.push("All recommended actions have been applied.");
|
|
398
|
+
return lines.join("\n");
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// Show next steps from analysis
|
|
402
|
+
if (analysis.next_steps.length > 0) {
|
|
403
|
+
for (const step of analysis.next_steps) {
|
|
404
|
+
lines.push(`- ${step}`);
|
|
405
|
+
}
|
|
406
|
+
} else {
|
|
407
|
+
lines.push("No specific actions recommended.");
|
|
408
|
+
lines.push("Review the structured output for detailed match information.");
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
return lines.join("\n");
|
|
341
412
|
}
|
|
342
413
|
|
|
343
414
|
/**
|
|
344
415
|
* Format a balance section (helper for backward compatibility)
|
|
345
416
|
*/
|
|
346
417
|
export function formatBalanceInfo(balance: BalanceInfo): string {
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
418
|
+
const lines: string[] = [];
|
|
419
|
+
lines.push(`Current Cleared: ${balance.current_cleared.value_display}`);
|
|
420
|
+
lines.push(`Current Total: ${balance.current_total.value_display}`);
|
|
421
|
+
lines.push(`Target Statement: ${balance.target_statement.value_display}`);
|
|
422
|
+
lines.push(`Discrepancy: ${balance.discrepancy.value_display}`);
|
|
423
|
+
return lines.join("\n");
|
|
353
424
|
}
|
|
354
425
|
|
|
355
426
|
/**
|
|
356
427
|
* Format transaction list (helper for detailed reports)
|
|
357
428
|
*/
|
|
358
|
-
type FormattableYnabTransaction = YNABTransaction & {
|
|
429
|
+
type FormattableYnabTransaction = YNABTransaction & {
|
|
430
|
+
payee_name?: string | null;
|
|
431
|
+
};
|
|
359
432
|
|
|
360
433
|
export function formatTransactionList(
|
|
361
|
-
|
|
362
|
-
|
|
434
|
+
transactions: BankTransaction[] | YNABTransaction[],
|
|
435
|
+
maxItems = 10,
|
|
363
436
|
): string {
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
437
|
+
const lines: string[] = [];
|
|
438
|
+
const toShow = transactions.slice(0, maxItems);
|
|
439
|
+
|
|
440
|
+
for (const txn of toShow) {
|
|
441
|
+
if ("cleared" in txn) {
|
|
442
|
+
// YNAB transaction (normalized)
|
|
443
|
+
const ynabTxn = txn as FormattableYnabTransaction;
|
|
444
|
+
const payee = ynabTxn.payee_name ?? ynabTxn.payee ?? "Unknown";
|
|
445
|
+
lines.push(
|
|
446
|
+
` ${ynabTxn.date} - ${payee.substring(0, 40).padEnd(40)} ${formatAmount(ynabTxn.amount)}`,
|
|
447
|
+
);
|
|
448
|
+
} else {
|
|
449
|
+
// Bank transaction
|
|
450
|
+
lines.push(formatBankTransactionLine(txn as BankTransaction));
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
if (transactions.length > maxItems) {
|
|
455
|
+
lines.push(` ... and ${transactions.length - maxItems} more`);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
return lines.join("\n");
|
|
386
459
|
}
|