@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
|
@@ -3,421 +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
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
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");
|
|
208
228
|
}
|
|
209
229
|
|
|
210
230
|
/**
|
|
211
231
|
* Format a YNAB transaction line
|
|
212
232
|
*/
|
|
213
233
|
function formatYnabTransactionLine(txn: YNABTransaction): string {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
234
|
+
const amountStr = formatAmount(txn.amount);
|
|
235
|
+
const payee = txn.payee ?? "Unknown";
|
|
236
|
+
return ` ${txn.date} - ${payee.substring(0, 40).padEnd(40)} ${amountStr}`;
|
|
217
237
|
}
|
|
218
238
|
|
|
219
239
|
/**
|
|
220
240
|
* Format a bank transaction line
|
|
221
241
|
*/
|
|
222
242
|
function formatBankTransactionLine(txn: BankTransaction): string {
|
|
223
|
-
|
|
224
|
-
|
|
243
|
+
const amountStr = formatAmount(txn.amount);
|
|
244
|
+
return ` ${txn.date} - ${txn.payee.substring(0, 40).padEnd(40)} ${amountStr}`;
|
|
225
245
|
}
|
|
226
246
|
|
|
227
247
|
/**
|
|
228
248
|
* Format a suggested match line
|
|
229
249
|
*/
|
|
230
250
|
function formatSuggestedMatchLine(match: TransactionMatch): string {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
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)`;
|
|
235
255
|
}
|
|
236
256
|
|
|
237
257
|
/**
|
|
238
258
|
* Format an amount for display (input in milliunits)
|
|
239
259
|
*/
|
|
240
260
|
function formatAmount(amountMilli: number): string {
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
261
|
+
const amount = amountMilli / 1000;
|
|
262
|
+
const sign = amount >= 0 ? "+" : "-";
|
|
263
|
+
const absAmount = Math.abs(amount);
|
|
264
|
+
return `${sign}$${absAmount.toFixed(2)}`.padStart(10);
|
|
245
265
|
}
|
|
246
266
|
|
|
247
267
|
/**
|
|
248
268
|
* Format the insights section
|
|
249
269
|
*/
|
|
250
|
-
function formatInsightsSection(
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
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();
|
|
277
302
|
}
|
|
278
303
|
|
|
279
304
|
/**
|
|
280
305
|
* Get text icon for severity level
|
|
281
306
|
*/
|
|
282
307
|
function getSeverityIcon(severity: string): string {
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
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
|
+
}
|
|
293
318
|
}
|
|
294
319
|
|
|
295
320
|
/**
|
|
296
321
|
* Format evidence summary from insight evidence object
|
|
297
322
|
*/
|
|
298
|
-
function formatEvidenceSummary(
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
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;
|
|
311
341
|
}
|
|
312
342
|
|
|
313
343
|
/**
|
|
314
344
|
* Format the execution section
|
|
315
345
|
*/
|
|
316
346
|
function formatExecutionSection(execution: LegacyReconciliationResult): string {
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
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");
|
|
348
382
|
}
|
|
349
383
|
|
|
350
384
|
/**
|
|
351
385
|
* Format the recommendations/next steps section
|
|
352
386
|
*/
|
|
353
387
|
function formatRecommendationsSection(
|
|
354
|
-
|
|
355
|
-
|
|
388
|
+
analysis: ReconciliationAnalysis,
|
|
389
|
+
execution?: LegacyReconciliationResult,
|
|
356
390
|
): string {
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
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");
|
|
378
412
|
}
|
|
379
413
|
|
|
380
414
|
/**
|
|
381
415
|
* Format a balance section (helper for backward compatibility)
|
|
382
416
|
*/
|
|
383
417
|
export function formatBalanceInfo(balance: BalanceInfo): string {
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
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");
|
|
390
424
|
}
|
|
391
425
|
|
|
392
426
|
/**
|
|
393
427
|
* Format transaction list (helper for detailed reports)
|
|
394
428
|
*/
|
|
395
|
-
type FormattableYnabTransaction = YNABTransaction & {
|
|
429
|
+
type FormattableYnabTransaction = YNABTransaction & {
|
|
430
|
+
payee_name?: string | null;
|
|
431
|
+
};
|
|
396
432
|
|
|
397
433
|
export function formatTransactionList(
|
|
398
|
-
|
|
399
|
-
|
|
434
|
+
transactions: BankTransaction[] | YNABTransaction[],
|
|
435
|
+
maxItems = 10,
|
|
400
436
|
): string {
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
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");
|
|
423
459
|
}
|