@dizzlkheinz/ynab-mcpb 0.12.2 → 0.15.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/.code/agents/01a13ef4-3f23-4f52-b33b-3585b73cfa60/error.txt +3 -0
- package/.code/agents/084fd32f-e298-4728-9103-a78d7dc39613/error.txt +3 -0
- package/.code/agents/0fed51e1-a943-4b97-a2a8-a6f0f27c844d/status.txt +1 -0
- package/.code/agents/1059b6bd-5ccd-4d83-a12c-7c9d89137399/error.txt +5 -0
- package/.code/agents/110/exec-call_F9BDNG7JfxKkq7Vc8ESAvdft.txt +1569 -0
- package/.code/agents/11ebcef3-b13f-4e44-ad80-d94a866804b7/error.txt +3 -0
- package/.code/agents/1398/exec-call_CjItcWMU1G6JoPshX62QvpaR.txt +2832 -0
- package/.code/agents/1398/exec-call_SUVq2ivmONQ5LMCmd7ngmOqr.txt +2709 -0
- package/.code/agents/1398/exec-call_SdNY4NOffdcC5pRYjVXHjPCK.txt +2832 -0
- package/.code/agents/1398/exec-call_qblJo9et1gsFFB63TtLOiji2.txt +2832 -0
- package/.code/agents/1398/exec-call_zaRrzlGz7GJcNzVfkAmML7Zg.txt +2709 -0
- package/.code/agents/171834fd-5905-42fc-bbcc-2c755145b0fc/status.txt +1 -0
- package/.code/agents/1724/exec-call_HvHQe0w5CCG3T7Q3ULT6MO3g.txt +5217 -0
- package/.code/agents/1724/exec-call_QwUNESVzfxxk78K1frh1Vahb.txt +2594 -0
- package/.code/agents/1724/exec-call_aJ1Xwz71XmIpD4SBxSHERzLe.txt +2594 -0
- package/.code/agents/1d7d7ab7-7473-4b69-8b97-6e914f56056a/result.txt +231 -0
- package/.code/agents/210/exec-call_0tQCsKNJ1WTuIchb8wlcFJpW.txt +2590 -0
- package/.code/agents/210/exec-call_8ZlY9cUc8Ft1twi4ch8UJ6IN.txt +5195 -0
- package/.code/agents/2188/exec-call_5HqayBxIteJtoI8oPTiLWgvJ.txt +286 -0
- package/.code/agents/2188/exec-call_XRbBKBq3adZe6dcppAvQtM7G.txt +218 -0
- package/.code/agents/2188/exec-call_ehA0SjpYtrUi6GJXmibLjp4i.txt +180 -0
- package/.code/agents/21902821-ecaf-4759-bb9d-222b90921af5/error.txt +3 -0
- package/.code/agents/232073be-aa0e-46da-b478-5b64dbf03cf5/status.txt +1 -0
- package/.code/agents/234ff534-2336-4771-a8d9-aa04421a63be/result.txt +747 -0
- package/.code/agents/253e2695-dc36-4022-b436-27655e0fc6c7/status.txt +1 -0
- package/.code/agents/2583/exec-call_M59I4eDjpjlBIWBiSxyS0YlJ.txt +2594 -0
- package/.code/agents/2583/exec-call_usLRGh7OhVHtsRBL4iUwRhjq.txt +2594 -0
- package/.code/agents/292aa3ff-dbab-470f-97c9-e7e8fd65e0db/result.txt +144 -0
- package/.code/agents/3134/exec-call_IgCAMGx19lWfuo8zfYIt5FFC.txt +416 -0
- package/.code/agents/3134/exec-call_IxvLR2Oo7kba2QTsI1gHVko8.txt +2590 -0
- package/.code/agents/3134/exec-call_jYvc8hksZChSiysbzKjl2ZbB.txt +2590 -0
- package/.code/agents/329/exec-call_4QdP3SfSO7HGPCwVcqZIth6s.txt +2590 -0
- package/.code/agents/472/exec-call_4AxzEEcWwkKhpqRB3bE8Ha4L.txt +790 -0
- package/.code/agents/472/exec-call_CB3LPYQA8QIZRi8I6kj4J17A.txt +766 -0
- package/.code/agents/472/exec-call_YeoUWvaFoktay2nqVUsa9KKX.txt +790 -0
- package/.code/agents/472/exec-call_jPWgKVquBBXTg0T3Lks5ZfkK.txt +2594 -0
- package/.code/agents/472/exec-call_qBkvunpGBDEHph2jPmTwtcsb.txt +1000 -0
- package/.code/agents/472/exec-call_v0ffRV1p0kTckBmJPzzHAEy0.txt +3489 -0
- package/.code/agents/472/exec-call_xAX5FXqWIlk02d9WubHbHWh8.txt +766 -0
- package/.code/agents/5346/exec-call_9q0muXUuLaucwEqI51Pt7idT.txt +2594 -0
- package/.code/agents/5346/exec-call_B2el3B79rVkq9LhWTI2VYlz7.txt +2456 -0
- package/.code/agents/5346/exec-call_BfX08f02qkZI9uJD5dvCvuoj.txt +2594 -0
- package/.code/agents/543328d0-61d6-4fd1-a723-bb168656e2e2/error.txt +18 -0
- package/.code/agents/5580c02c-1383-4d18-9cbd-cc8a06e3408d/result.txt +48 -0
- package/.code/agents/60ce1a22-5126-44b2-b977-1d5b56142a7b/status.txt +1 -0
- package/.code/agents/6215d9db-7fa9-4429-aeec-3835c3212291/error.txt +1 -0
- package/.code/agents/6743db55-30e5-4b4e-9366-a8214fc7f714/error.txt +1 -0
- package/.code/agents/6bf9591b-b9c9-422c-b0a5-e968c7d8422a/status.txt +1 -0
- package/.code/agents/7/exec-call_eww3GfdEiJZx61sJEQ9wNmt3.txt +1271 -0
- package/.code/agents/70/exec-call_owUtDMYiVgqDf8vsz1i32PFf.txt +1570 -0
- package/.code/agents/8/exec-call_UtrjAcLbhYLatxR4O97fZgnm.txt +2590 -0
- package/.code/agents/82490bc9-f34e-4b1b-8a8e-bccc2e6254f5/error.txt +3 -0
- package/.code/agents/841/exec-call_7nTNhSBCNjTDUIJv7py6CepO.txt +3299 -0
- package/.code/agents/841/exec-call_TLI0yUdUijuUAvI4o3DXEvHO.txt +3299 -0
- package/.code/agents/9/exec-call_XaABQT1hIlRpnKZ2uyBMWsTC.txt +1882 -0
- package/.code/agents/941/exec-call_GuGHRx7NNXWIDAnxUG2NEWPa.txt +2594 -0
- package/.code/agents/95d9fbab-19a2-48af-83f9-c792566a347f/error.txt +1 -0
- package/.code/agents/b0098cb8-cb32-4ada-9bc4-37c587518896/result.txt +170 -0
- package/.code/agents/b4fe59a4-81df-42e2-a112-0153e504faca/error.txt +1 -0
- package/.code/agents/bf4ce152-f623-49d7-aa52-c18631625c3c/error.txt +3 -0
- package/.code/agents/d7d1db75-d7eb-468e-adea-4ef4d916d187/status.txt +1 -0
- package/.code/agents/e2baa9c8-bac3-49e3-a39d-024333e6a990/status.txt +1 -0
- package/.code/agents/e350b8c3-8483-408c-b2bb-94515f492a11/error.txt +3 -0
- package/.code/agents/e63f9919-719f-4ad0-bccf-01b1a596e1e9/status.txt +1 -0
- package/.code/agents/e71695a8-3044-478d-8f12-ed13d02884c7/status.txt +1 -0
- package/.code/agents/f95b7464-3e25-4897-b153-c8dfd63fd605/error.txt +5 -0
- package/.code/agents/fa3c5ddf-cdf7-47a2-930a-b806c6363689/status.txt +1 -0
- package/.github/workflows/ci-tests.yml +6 -2
- package/.github/workflows/publish.yml +3 -3
- package/.github/workflows/release.yml +4 -0
- package/CHANGELOG.md +89 -1
- package/NUL +1 -1
- package/README.md +36 -10
- package/dist/bundle/index.cjs +65 -42
- package/dist/index.js +9 -20
- package/dist/server/YNABMCPServer.d.ts +2 -1
- package/dist/server/YNABMCPServer.js +61 -27
- package/dist/server/cacheKeys.d.ts +8 -0
- package/dist/server/cacheKeys.js +8 -0
- package/dist/server/config.d.ts +22 -3
- package/dist/server/config.js +16 -17
- package/dist/server/errorHandler.d.ts +2 -0
- package/dist/server/errorHandler.js +49 -5
- package/dist/server/securityMiddleware.js +3 -6
- package/dist/server/toolRegistry.js +8 -10
- package/dist/tools/accountTools.js +4 -3
- package/dist/tools/categoryTools.js +8 -7
- package/dist/tools/monthTools.js +2 -1
- package/dist/tools/payeeTools.js +2 -1
- package/dist/tools/reconcileAdapter.js +10 -5
- package/dist/tools/reconciliation/analyzer.d.ts +4 -2
- package/dist/tools/reconciliation/analyzer.js +120 -404
- package/dist/tools/reconciliation/csvParser.d.ts +51 -0
- package/dist/tools/reconciliation/csvParser.js +413 -0
- package/dist/tools/reconciliation/executor.d.ts +8 -0
- package/dist/tools/reconciliation/executor.js +277 -50
- package/dist/tools/reconciliation/index.d.ts +7 -7
- package/dist/tools/reconciliation/index.js +115 -39
- package/dist/tools/reconciliation/matcher.d.ts +24 -3
- package/dist/tools/reconciliation/matcher.js +175 -133
- package/dist/tools/reconciliation/recommendationEngine.js +22 -18
- package/dist/tools/reconciliation/reportFormatter.js +9 -8
- package/dist/tools/reconciliation/signDetector.d.ts +2 -0
- package/dist/tools/reconciliation/signDetector.js +54 -0
- package/dist/tools/reconciliation/types.d.ts +20 -34
- package/dist/tools/reconciliation/types.js +1 -7
- package/dist/tools/reconciliation/ynabAdapter.d.ts +4 -0
- package/dist/tools/reconciliation/ynabAdapter.js +15 -0
- package/dist/tools/transactionTools.d.ts +3 -17
- package/dist/tools/transactionTools.js +5 -17
- package/dist/types/reconciliation.d.ts +24 -0
- package/dist/types/reconciliation.js +1 -0
- package/dist/utils/baseError.d.ts +3 -0
- package/dist/utils/baseError.js +7 -0
- package/dist/utils/errors.d.ts +13 -0
- package/dist/utils/errors.js +15 -0
- package/dist/utils/validationError.d.ts +3 -0
- package/dist/utils/validationError.js +3 -0
- package/docs/guides/ARCHITECTURE.md +12 -129
- package/docs/plans/2025-11-20-reloadable-config-token-validation.md +93 -0
- package/docs/plans/2025-11-21-fix-transaction-cached-property.md +362 -0
- package/docs/plans/2025-11-21-reconciliation-error-handling.md +90 -0
- package/docs/plans/2025-11-21-v014-hardening.md +153 -0
- package/docs/plans/reconciliation-v2-redesign.md +1571 -0
- package/package.json +8 -2
- package/scripts/run-throttled-integration-tests.js +9 -3
- package/scripts/test-recommendations.ts +1 -1
- package/src/__tests__/performance.test.ts +12 -5
- package/src/__tests__/testUtils.ts +62 -5
- package/src/__tests__/tools/reconciliation/csvParser.integration.test.ts +129 -0
- package/src/__tests__/tools/reconciliation/real-world.integration.test.ts +53 -0
- package/src/__tests__/workflows.e2e.test.ts +33 -0
- package/src/index.ts +8 -31
- package/src/server/YNABMCPServer.ts +81 -42
- package/src/server/__tests__/YNABMCPServer.integration.test.ts +10 -12
- package/src/server/__tests__/YNABMCPServer.test.ts +27 -15
- package/src/server/__tests__/config.test.ts +76 -152
- package/src/server/__tests__/server-startup.integration.test.ts +42 -14
- package/src/server/__tests__/toolRegistry.test.ts +1 -1
- package/src/server/cacheKeys.ts +8 -0
- package/src/server/config.ts +20 -38
- package/src/server/errorHandler.ts +52 -5
- package/src/server/securityMiddleware.ts +3 -7
- package/src/server/toolRegistry.ts +14 -10
- package/src/tools/__tests__/categoryTools.test.ts +37 -19
- package/src/tools/__tests__/transactionTools.test.ts +58 -2
- package/src/tools/accountTools.ts +8 -3
- package/src/tools/categoryTools.ts +12 -7
- package/src/tools/monthTools.ts +7 -1
- package/src/tools/payeeTools.ts +7 -1
- package/src/tools/reconcileAdapter.ts +10 -5
- package/src/tools/reconciliation/__tests__/adapter.test.ts +28 -22
- package/src/tools/reconciliation/__tests__/analyzer.test.ts +114 -180
- package/src/tools/reconciliation/__tests__/csvParser.test.ts +87 -0
- package/src/tools/reconciliation/__tests__/executor.integration.test.ts +26 -6
- package/src/tools/reconciliation/__tests__/executor.test.ts +133 -60
- package/src/tools/reconciliation/__tests__/matcher.test.ts +68 -54
- package/src/tools/reconciliation/__tests__/recommendationEngine.test.ts +37 -30
- package/src/tools/reconciliation/__tests__/reportFormatter.test.ts +6 -5
- package/src/tools/reconciliation/__tests__/scenarios/extremes.scenario.test.ts +30 -11
- package/src/tools/reconciliation/__tests__/scenarios/repeatAmount.scenario.test.ts +50 -15
- package/src/tools/reconciliation/__tests__/signDetector.test.ts +211 -0
- package/src/tools/reconciliation/__tests__/ynabAdapter.test.ts +61 -0
- package/src/tools/reconciliation/analyzer.ts +174 -545
- package/src/tools/reconciliation/csvParser.ts +617 -0
- package/src/tools/reconciliation/executor.ts +344 -58
- package/src/tools/reconciliation/index.ts +141 -48
- package/src/tools/reconciliation/matcher.ts +234 -214
- package/src/tools/reconciliation/recommendationEngine.ts +23 -19
- package/src/tools/reconciliation/reportFormatter.ts +16 -11
- package/src/tools/reconciliation/signDetector.ts +117 -0
- package/src/tools/reconciliation/types.ts +39 -61
- package/src/tools/reconciliation/ynabAdapter.ts +33 -0
- package/src/tools/schemas/outputs/utilityOutputs.ts +1 -1
- package/src/tools/transactionTools.ts +7 -18
- package/src/types/reconciliation.ts +49 -0
- package/src/utils/baseError.ts +7 -0
- package/src/utils/errors.ts +21 -0
- package/src/utils/validationError.ts +3 -0
- package/temp-recon.ts +126 -0
- package/test-exports/ynab_since_2025-10-16_account_53298e13_238items_2025-11-28_13-46-20.json +3662 -0
- package/test_mcp_tools.mjs +75 -0
- package/.code/agents/0427d95e-edca-431f-a214-5e53264e29c4/error.txt +0 -8
- package/.code/agents/0d675174-d1e1-41c3-9975-4c2e275819a9/error.txt +0 -3
- package/.code/agents/0d8c5afd-4787-422b-abf8-2e5943fc7e67/error.txt +0 -3
- package/.code/agents/0ec34a70-ed5d-4b9e-bee4-bb0e4cccbc4b/error.txt +0 -1
- package/.code/agents/0ef51a21-1ab1-49d7-9561-0eaa43875ebc/error.txt +0 -12
- package/.code/agents/15db95d7-abad-4b4d-9c3b-8446089cb61d/error.txt +0 -1
- package/.code/agents/19ab9acb-f675-4ff0-902a-09a5476f8149/error.txt +0 -1
- package/.code/agents/1ef7e12d-f6ff-4897-8a9b-152d523d898e/error.txt +0 -5
- package/.code/agents/2465/exec-call_lroN9KKzJVWC7t5423DK1nT9.txt +0 -1453
- package/.code/agents/28edb6fe-95a9-41a0-ae69-aa0100d26c0c/error.txt +0 -8
- package/.code/agents/2ae40cf5-b4bf-42e2-92bf-7ea350a7755e/error.txt +0 -9
- package/.code/agents/2bfc4e1f-ac4b-45a5-b6df-bf89d4dbb54c/error.txt +0 -1
- package/.code/agents/2e2e1134-eff0-49be-ba25-8e2c3468a564/error.txt +0 -5
- package/.code/agents/3/exec-call_203OC4TNVkLxW7z2HCVEQ1cM.txt +0 -81
- package/.code/agents/3/exec-call_SS5T0XSiXB4LSNzUKTl75wkh.txt +0 -610
- package/.code/agents/3322c003-ce5e-48e3-a342-f5049c5bf9a2/error.txt +0 -1
- package/.code/agents/391e9b08-1ebc-468c-9bcd-6d0cc3193b37/error.txt +0 -1
- package/.code/agents/3ab0aa84-b7bb-4054-afa3-40b8fd7d3be0/error.txt +0 -1
- package/.code/agents/3bed368d-50fe-477e-aee3-a6707eaa1ab9/error.txt +0 -3
- package/.code/agents/3e40b925-db12-442f-8d7a-a25fc69a6672/error.txt +0 -8
- package/.code/agents/414d5776-cf58-41f3-9328-a6daed503a50/error.txt +0 -5
- package/.code/agents/42687751-4565-4610-b240-67835b17d861/error.txt +0 -1
- package/.code/agents/46b98876-1a39-43c9-9e2f-507ca6d47335/error.txt +0 -9
- package/.code/agents/4a7d9491-b26f-43dd-850d-2ecdc49b5d1b/error.txt +0 -1
- package/.code/agents/4e60f00a-1b3e-447f-87f3-7faf9deddec3/error.txt +0 -13
- package/.code/agents/5138fc1c-4d49-4b74-a7da-ccdb3a8e44e7/error.txt +0 -14
- package/.code/agents/521cff39-a7a3-42e5-a557-134f0f7daaa0/error.txt +0 -5
- package/.code/agents/53302dc5-3857-4413-9a47-9e0f64a51dc4/error.txt +0 -5
- package/.code/agents/567c7c2e-6a6f-4761-a08d-d36deeb2e0ac/error.txt +0 -5
- package/.code/agents/57b00845-80dc-47c9-953c-3028d16275d6/error.txt +0 -3
- package/.code/agents/593d9005-c2a5-48fd-8813-ece0d3f2de96/error.txt +0 -1
- package/.code/agents/5a112e66-0e1a-42f9-877c-53af56ea3551/error.txt +0 -1
- package/.code/agents/5b05e8ed-7788-4738-b7ee-9faa8180f992/error.txt +0 -5
- package/.code/agents/5f888d6f-d7ca-4ac8-be23-9ea1bf753951/error.txt +0 -5
- package/.code/agents/607db3ab-e4b0-435b-b497-93e9aa525549/error.txt +0 -8
- package/.code/agents/67dcb2a2-900f-4c78-b3fc-80b5213e0ddf/error.txt +0 -8
- package/.code/agents/69ad848c-4e98-49b3-b16c-0094ac2d1759/error.txt +0 -5
- package/.code/agents/6c9cfc5f-0d0b-445c-b121-9f60082c4f70/error.txt +0 -1
- package/.code/agents/6f6f8f77-4ab0-4f6e-9f30-40e8be0bd8f5/error.txt +0 -1
- package/.code/agents/72a7cde4-fa8a-4024-9038-27faa550539b/error.txt +0 -1
- package/.code/agents/7b48335c-8247-43aa-9949-5f820ba8e199/error.txt +0 -1
- package/.code/agents/80944249-bea9-4ac5-87de-a666c4df306e/error.txt +0 -1
- package/.code/agents/826099df-1b66-4186-a915-7eb59f9db19d/error.txt +0 -5
- package/.code/agents/8291d158-18a8-4a92-b799-4e9a4d9cce88/error.txt +0 -1
- package/.code/agents/82fb71a3-20fb-4341-804a-a2fc900f95bc/error.txt +0 -1
- package/.code/agents/855790ea-54ee-43e4-8209-a66994e37590/error.txt +0 -1
- package/.code/agents/88ce3a2e-04f2-42be-9062-bf97aa798da0/error.txt +0 -3
- package/.code/agents/9a17e398-b6ed-4218-bb55-bc64a8d38ce8/error.txt +0 -8
- package/.code/agents/9a4f4bfc-a2a6-4f40-a896-9335b41a7ed1/error.txt +0 -1
- package/.code/agents/9b633e55-ef84-47d6-94bb-fd3dd172ad97/error.txt +0 -1
- package/.code/agents/9b81f3ab-c72b-4a81-9a8f-28a49ddba84a/error.txt +0 -8
- package/.code/agents/a35daf29-b2d1-4aef-9b42-dad63a76bd47/error.txt +0 -3
- package/.code/agents/a81990cc-69ee-44d2-b907-17403c9bc5d7/error.txt +0 -5
- package/.code/agents/ab56260a-4a83-4ad4-9410-f88a23d6520a/error.txt +0 -1
- package/.code/agents/ad722c31-2d1d-45f7-bae2-3f02ca455b60/error.txt +0 -1
- package/.code/agents/b62e8690-3324-4b97-9309-731bee79416b/error.txt +0 -5
- package/.code/agents/baf60a3a-752b-4ad8-99d6-df32423ed2eb/error.txt +0 -1
- package/.code/agents/be049042-7dcb-4ac8-9beb-c8f1aea67742/error.txt +0 -14
- package/.code/agents/bed1dcb4-bfce-4a9f-8594-0f994962aafd/error.txt +0 -1
- package/.code/agents/c324a6cf-e935-4ede-9529-b3ebc18e8d6b/error.txt +0 -5
- package/.code/agents/c37c06ff-dfe3-43f2-9bbc-3ec73ec8f41d/error.txt +0 -5
- package/.code/agents/c8cd6671-433a-456b-9f88-e51cb2df6bfc/error.txt +0 -11
- package/.code/agents/ca2ccb67-2f24-428e-b27d-9365beadd140/error.txt +0 -1
- package/.code/agents/cf08c0c8-e7f0-423e-93ba-547e8e818340/error.txt +0 -8
- package/.code/agents/d579c74f-874b-40a4-9d56-ced1eb6a701d/error.txt +0 -1
- package/.code/agents/df412c98-7378-4deb-8e1e-76c416931181/error.txt +0 -3
- package/.code/agents/e5134eb3-2af4-45b0-8998-051cb4afdb45/error.txt +0 -3
- package/.code/agents/e6308471-aa45-4e9e-9496-2e9404164d97/error.txt +0 -8
- package/.code/agents/e7bd8bc7-23fb-4f46-98dc-b0dcf11b75a1/error.txt +0 -1
- package/.code/agents/e92bec35-378d-4fe1-8ac0-6e1bb3c86911/error.txt +0 -5
- package/.code/agents/ed918fbf-2dc4-4aa2-bfc5-04b65d9471ea/error.txt +0 -1
- package/.code/agents/ef1d756f-b272-48fc-8729-f05c494674f7/error.txt +0 -1
- package/.code/agents/ef359853-0249-4e41-a804-c0fc459fe456/error.txt +0 -1
- package/.code/agents/effc7b4a-4b90-40a0-8c86-a7a99d2d5fd2/error.txt +0 -1
- package/.code/agents/fa15f8d5-8359-4a8b-83a3-2f2056b3ff40/error.txt +0 -3
- package/.code/agents/fbef4193-eadf-4c8a-83ff-4878a6310f25/error.txt +0 -8
- package/.code/agents/fd0a4b4a-fda4-4964-a6d6-2b8a2da387c6/error.txt +0 -1
- package/.gemini/settings.json +0 -8
- package/ADOS-2-Module-1-Complete-Manual.md +0 -757
- package/WARP.md +0 -245
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { CallToolResult, Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
2
2
|
import { z, toJSONSchema } from 'zod/v4';
|
|
3
|
+
import { fromZodError } from 'zod-validation-error';
|
|
3
4
|
import type { MCPToolAnnotations } from '../types/toolAnnotations.js';
|
|
4
5
|
|
|
5
6
|
export type SecurityWrapperFactory = <T extends Record<string, unknown>>(
|
|
@@ -162,7 +163,10 @@ export class ToolRegistry {
|
|
|
162
163
|
inputSchema,
|
|
163
164
|
};
|
|
164
165
|
if (tool.outputSchema) {
|
|
165
|
-
const outputSchema = this.generateJsonSchema(
|
|
166
|
+
const outputSchema = this.generateJsonSchema(
|
|
167
|
+
tool.outputSchema,
|
|
168
|
+
'output',
|
|
169
|
+
) as Tool['outputSchema'];
|
|
166
170
|
result.outputSchema = outputSchema;
|
|
167
171
|
}
|
|
168
172
|
if (tool.metadata?.annotations) {
|
|
@@ -311,9 +315,10 @@ export class ToolRegistry {
|
|
|
311
315
|
tool: RegisteredTool<Record<string, unknown>, Record<string, unknown>>,
|
|
312
316
|
): CallToolResult {
|
|
313
317
|
if (error instanceof z.ZodError) {
|
|
318
|
+
const validationError = fromZodError(error);
|
|
314
319
|
return this.deps.errorHandler.createValidationError(
|
|
315
320
|
`Invalid parameters for ${tool.name}`,
|
|
316
|
-
|
|
321
|
+
validationError.message,
|
|
317
322
|
);
|
|
318
323
|
}
|
|
319
324
|
|
|
@@ -388,9 +393,12 @@ export class ToolRegistry {
|
|
|
388
393
|
}
|
|
389
394
|
}
|
|
390
395
|
|
|
391
|
-
private generateJsonSchema(
|
|
396
|
+
private generateJsonSchema(
|
|
397
|
+
schema: z.ZodTypeAny,
|
|
398
|
+
ioMode: 'input' | 'output' = 'input',
|
|
399
|
+
): Record<string, unknown> {
|
|
392
400
|
try {
|
|
393
|
-
return toJSONSchema(schema, { target: 'draft-2020-12', io:
|
|
401
|
+
return toJSONSchema(schema, { target: 'draft-2020-12', io: ioMode });
|
|
394
402
|
} catch (error) {
|
|
395
403
|
console.warn(`Failed to generate JSON schema for tool: ${error}`);
|
|
396
404
|
return { type: 'object', additionalProperties: true };
|
|
@@ -467,12 +475,8 @@ export class ToolRegistry {
|
|
|
467
475
|
// Validate against schema
|
|
468
476
|
const result = validator.safeParse(parsedOutput);
|
|
469
477
|
if (!result.success) {
|
|
470
|
-
const
|
|
471
|
-
|
|
472
|
-
const path = err.path.join('.');
|
|
473
|
-
return path ? `${path}: ${err.message}` : err.message;
|
|
474
|
-
})
|
|
475
|
-
.join('; ');
|
|
478
|
+
const validationError = fromZodError(result.error);
|
|
479
|
+
const validationErrors = validationError.message;
|
|
476
480
|
return this.deps.errorHandler.createValidationError(
|
|
477
481
|
`Output validation failed for ${toolName}`,
|
|
478
482
|
`Handler output does not match declared output schema: ${validationErrors}`,
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
UpdateCategorySchema,
|
|
10
10
|
} from '../categoryTools.js';
|
|
11
11
|
import { createDeltaFetcherMock, createRejectingDeltaFetcherMock } from './deltaTestUtils.js';
|
|
12
|
+
import { CacheKeys } from '../../server/cacheKeys.js';
|
|
12
13
|
|
|
13
14
|
// Mock the cache manager
|
|
14
15
|
vi.mock('../../server/cacheManager.js', () => ({
|
|
@@ -60,9 +61,22 @@ describe('Category Tools', () => {
|
|
|
60
61
|
},
|
|
61
62
|
);
|
|
62
63
|
(cacheManager.has as ReturnType<typeof vi.fn>).mockReturnValue(false);
|
|
63
|
-
(CacheManager.generateKey as
|
|
64
|
-
(prefix: string,
|
|
65
|
-
|
|
64
|
+
(CacheManager.generateKey as any).mockImplementation(
|
|
65
|
+
(prefix: string, type: string, budgetId: string, id?: string) => {
|
|
66
|
+
if (prefix === CacheKeys.CATEGORIES && type === 'list') {
|
|
67
|
+
return `categories:list:${budgetId}`;
|
|
68
|
+
}
|
|
69
|
+
if (prefix === CacheKeys.CATEGORIES && type === 'get' && id) {
|
|
70
|
+
return `categories:get:${budgetId}:${id}`;
|
|
71
|
+
}
|
|
72
|
+
if (prefix === CacheKeys.MONTHS && type === 'list') {
|
|
73
|
+
return `months:list:${budgetId}`;
|
|
74
|
+
}
|
|
75
|
+
if (prefix === CacheKeys.MONTHS && type === 'get' && id) {
|
|
76
|
+
return `months:get:${budgetId}:${id}`;
|
|
77
|
+
}
|
|
78
|
+
return `${prefix}:${type}:${budgetId}:${id || ''}`;
|
|
79
|
+
},
|
|
66
80
|
);
|
|
67
81
|
});
|
|
68
82
|
|
|
@@ -450,34 +464,38 @@ describe('Category Tools', () => {
|
|
|
450
464
|
data: { category: mockUpdatedCategory },
|
|
451
465
|
});
|
|
452
466
|
|
|
453
|
-
|
|
454
|
-
'categories:list:budget-1:generated-key',
|
|
455
|
-
'category:get:budget-1:category-1:generated-key',
|
|
456
|
-
];
|
|
457
|
-
(CacheManager.generateKey as any)
|
|
458
|
-
.mockReturnValueOnce(mockCacheKeys[0])
|
|
459
|
-
.mockReturnValueOnce(mockCacheKeys[1]);
|
|
460
|
-
|
|
461
|
-
const result = await handleUpdateCategory(mockYnabAPI, {
|
|
467
|
+
await handleUpdateCategory(mockYnabAPI, {
|
|
462
468
|
budget_id: 'budget-1',
|
|
463
469
|
category_id: 'category-1',
|
|
464
470
|
budgeted: 60000,
|
|
465
471
|
});
|
|
466
472
|
|
|
467
473
|
// Verify cache was invalidated for both category list and specific category
|
|
468
|
-
expect(CacheManager.generateKey).toHaveBeenCalledWith('categories', 'list', 'budget-1');
|
|
469
474
|
expect(CacheManager.generateKey).toHaveBeenCalledWith(
|
|
470
|
-
|
|
475
|
+
CacheKeys.CATEGORIES,
|
|
476
|
+
'list',
|
|
477
|
+
'budget-1',
|
|
478
|
+
);
|
|
479
|
+
expect(CacheManager.generateKey).toHaveBeenCalledWith(
|
|
480
|
+
CacheKeys.CATEGORIES,
|
|
471
481
|
'get',
|
|
472
482
|
'budget-1',
|
|
473
483
|
'category-1',
|
|
474
484
|
);
|
|
475
|
-
expect(cacheManager.delete).toHaveBeenCalledWith(
|
|
476
|
-
expect(cacheManager.delete).toHaveBeenCalledWith(
|
|
485
|
+
expect(cacheManager.delete).toHaveBeenCalledWith(`categories:list:budget-1`);
|
|
486
|
+
expect(cacheManager.delete).toHaveBeenCalledWith(`categories:get:budget-1:category-1`);
|
|
477
487
|
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
expect(
|
|
488
|
+
// Verify month-related caches were invalidated
|
|
489
|
+
expect(CacheManager.generateKey).toHaveBeenCalledWith(CacheKeys.MONTHS, 'list', 'budget-1');
|
|
490
|
+
expect(CacheManager.generateKey).toHaveBeenCalledWith(
|
|
491
|
+
CacheKeys.MONTHS,
|
|
492
|
+
'get',
|
|
493
|
+
'budget-1',
|
|
494
|
+
expect.stringMatching(/^\d{4}-\d{2}-01$/),
|
|
495
|
+
);
|
|
496
|
+
const currentMonth = `${new Date().getFullYear()}-${String(new Date().getMonth() + 1).padStart(2, '0')}-01`;
|
|
497
|
+
expect(cacheManager.delete).toHaveBeenCalledWith(`months:list:budget-1`);
|
|
498
|
+
expect(cacheManager.delete).toHaveBeenCalledWith(`months:get:budget-1:${currentMonth}`);
|
|
481
499
|
});
|
|
482
500
|
|
|
483
501
|
it('should not invalidate cache on dry_run category update', async () => {
|
|
@@ -352,6 +352,61 @@ describe('transactionTools', () => {
|
|
|
352
352
|
const response = JSON.parse(result.content[0].text);
|
|
353
353
|
expect(response.error.message).toBe('Failed to list transactions');
|
|
354
354
|
});
|
|
355
|
+
|
|
356
|
+
it('should include cached property in large response path', async () => {
|
|
357
|
+
// Create large transaction list (> 90KB)
|
|
358
|
+
const largeTransactionList: ynab.TransactionDetail[] = [];
|
|
359
|
+
for (let i = 0; i < 5000; i++) {
|
|
360
|
+
largeTransactionList.push({
|
|
361
|
+
id: `transaction-${i}`,
|
|
362
|
+
date: '2025-01-01',
|
|
363
|
+
amount: -10000,
|
|
364
|
+
memo: 'Test transaction with long memo to increase size '.repeat(10),
|
|
365
|
+
cleared: 'cleared',
|
|
366
|
+
approved: true,
|
|
367
|
+
flag_color: null,
|
|
368
|
+
account_id: 'test-account',
|
|
369
|
+
payee_id: null,
|
|
370
|
+
category_id: null,
|
|
371
|
+
transfer_account_id: null,
|
|
372
|
+
transfer_transaction_id: null,
|
|
373
|
+
matched_transaction_id: null,
|
|
374
|
+
import_id: null,
|
|
375
|
+
import_payee_name: null,
|
|
376
|
+
import_payee_name_original: null,
|
|
377
|
+
debt_transaction_type: null,
|
|
378
|
+
deleted: false,
|
|
379
|
+
account_name: 'Test Account',
|
|
380
|
+
payee_name: 'Test Payee',
|
|
381
|
+
category_name: 'Test Category',
|
|
382
|
+
subtransactions: [],
|
|
383
|
+
} as ynab.TransactionDetail);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
const mockResponse = {
|
|
387
|
+
data: {
|
|
388
|
+
transactions: largeTransactionList,
|
|
389
|
+
},
|
|
390
|
+
};
|
|
391
|
+
|
|
392
|
+
(mockYnabAPI.transactions.getTransactionsByAccount as any).mockResolvedValue(mockResponse);
|
|
393
|
+
|
|
394
|
+
const result = await handleListTransactions(mockYnabAPI, {
|
|
395
|
+
budget_id: 'test-budget',
|
|
396
|
+
account_id: 'test-account',
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
const content = result.content?.[0];
|
|
400
|
+
expect(content).toBeDefined();
|
|
401
|
+
expect(content?.type).toBe('text');
|
|
402
|
+
|
|
403
|
+
const parsedResponse = JSON.parse(content!.text);
|
|
404
|
+
|
|
405
|
+
// Should have cached property even in large response path
|
|
406
|
+
expect(parsedResponse.cached).toBeDefined();
|
|
407
|
+
expect(parsedResponse.cached).toBe(false);
|
|
408
|
+
expect(parsedResponse.cache_info).toBeDefined();
|
|
409
|
+
});
|
|
355
410
|
});
|
|
356
411
|
|
|
357
412
|
describe('GetTransactionSchema', () => {
|
|
@@ -1852,8 +1907,9 @@ describe('transactionTools', () => {
|
|
|
1852
1907
|
const result = CreateTransactionsSchema.safeParse(params);
|
|
1853
1908
|
expect(result.success).toBe(false);
|
|
1854
1909
|
if (!result.success) {
|
|
1855
|
-
const issue = result.error.issues.find((i) => i.
|
|
1856
|
-
expect(issue
|
|
1910
|
+
const issue = result.error.issues.find((i) => i.code === 'unrecognized_keys');
|
|
1911
|
+
expect(issue).toBeDefined();
|
|
1912
|
+
expect((issue as any)?.keys).toContain('subtransactions');
|
|
1857
1913
|
}
|
|
1858
1914
|
});
|
|
1859
1915
|
|
|
@@ -8,6 +8,7 @@ import { cacheManager, CACHE_TTLS, CacheManager } from '../server/cacheManager.j
|
|
|
8
8
|
import type { DeltaFetcher } from './deltaFetcher.js';
|
|
9
9
|
import type { DeltaCache } from '../server/deltaCache.js';
|
|
10
10
|
import type { ServerKnowledgeStore } from '../server/serverKnowledgeStore.js';
|
|
11
|
+
import { CacheKeys } from '../server/cacheKeys.js';
|
|
11
12
|
import { resolveDeltaFetcherArgs, resolveDeltaWriteArgs } from './deltaSupport.js';
|
|
12
13
|
|
|
13
14
|
/**
|
|
@@ -139,7 +140,7 @@ export async function handleGetAccount(
|
|
|
139
140
|
async () => {
|
|
140
141
|
// Use enhanced CacheManager wrap method
|
|
141
142
|
const cacheKey = CacheManager.generateKey(
|
|
142
|
-
|
|
143
|
+
CacheKeys.ACCOUNTS,
|
|
143
144
|
'get',
|
|
144
145
|
params.budget_id,
|
|
145
146
|
params.account_id,
|
|
@@ -248,10 +249,14 @@ export async function handleCreateAccount(
|
|
|
248
249
|
const account = response.data.account;
|
|
249
250
|
|
|
250
251
|
// Invalidate accounts list cache after successful account creation
|
|
251
|
-
const accountsListCacheKey = CacheManager.generateKey(
|
|
252
|
+
const accountsListCacheKey = CacheManager.generateKey(
|
|
253
|
+
CacheKeys.ACCOUNTS,
|
|
254
|
+
'list',
|
|
255
|
+
params.budget_id,
|
|
256
|
+
);
|
|
252
257
|
cacheManager.delete(accountsListCacheKey);
|
|
253
258
|
|
|
254
|
-
deltaCache.invalidate(params.budget_id,
|
|
259
|
+
deltaCache.invalidate(params.budget_id, CacheKeys.ACCOUNTS);
|
|
255
260
|
|
|
256
261
|
return {
|
|
257
262
|
content: [
|
|
@@ -8,6 +8,7 @@ import { cacheManager, CACHE_TTLS, CacheManager } from '../server/cacheManager.j
|
|
|
8
8
|
import type { DeltaFetcher } from './deltaFetcher.js';
|
|
9
9
|
import type { DeltaCache } from '../server/deltaCache.js';
|
|
10
10
|
import type { ServerKnowledgeStore } from '../server/serverKnowledgeStore.js';
|
|
11
|
+
import { CacheKeys } from '../server/cacheKeys.js';
|
|
11
12
|
import { resolveDeltaFetcherArgs, resolveDeltaWriteArgs } from './deltaSupport.js';
|
|
12
13
|
|
|
13
14
|
/**
|
|
@@ -158,7 +159,7 @@ export async function handleGetCategory(
|
|
|
158
159
|
async () => {
|
|
159
160
|
// Use enhanced CacheManager wrap method
|
|
160
161
|
const cacheKey = CacheManager.generateKey(
|
|
161
|
-
|
|
162
|
+
CacheKeys.CATEGORIES,
|
|
162
163
|
'get',
|
|
163
164
|
params.budget_id,
|
|
164
165
|
params.category_id,
|
|
@@ -271,9 +272,13 @@ export async function handleUpdateCategory(
|
|
|
271
272
|
const category = response.data.category;
|
|
272
273
|
|
|
273
274
|
// Invalidate category-related caches after successful update
|
|
274
|
-
const categoriesListCacheKey = CacheManager.generateKey(
|
|
275
|
+
const categoriesListCacheKey = CacheManager.generateKey(
|
|
276
|
+
CacheKeys.CATEGORIES,
|
|
277
|
+
'list',
|
|
278
|
+
params.budget_id,
|
|
279
|
+
);
|
|
275
280
|
const specificCategoryCacheKey = CacheManager.generateKey(
|
|
276
|
-
|
|
281
|
+
CacheKeys.CATEGORIES,
|
|
277
282
|
'get',
|
|
278
283
|
params.budget_id,
|
|
279
284
|
params.category_id,
|
|
@@ -282,9 +287,9 @@ export async function handleUpdateCategory(
|
|
|
282
287
|
cacheManager.delete(specificCategoryCacheKey);
|
|
283
288
|
|
|
284
289
|
// Invalidate month-related caches as category budget changes affect month data
|
|
285
|
-
const monthsListCacheKey = CacheManager.generateKey(
|
|
290
|
+
const monthsListCacheKey = CacheManager.generateKey(CacheKeys.MONTHS, 'list', params.budget_id);
|
|
286
291
|
const currentMonthCacheKey = CacheManager.generateKey(
|
|
287
|
-
|
|
292
|
+
CacheKeys.MONTHS,
|
|
288
293
|
'get',
|
|
289
294
|
params.budget_id,
|
|
290
295
|
currentMonth,
|
|
@@ -292,8 +297,8 @@ export async function handleUpdateCategory(
|
|
|
292
297
|
cacheManager.delete(monthsListCacheKey);
|
|
293
298
|
cacheManager.delete(currentMonthCacheKey);
|
|
294
299
|
|
|
295
|
-
deltaCache.invalidate(params.budget_id,
|
|
296
|
-
deltaCache.invalidate(params.budget_id,
|
|
300
|
+
deltaCache.invalidate(params.budget_id, CacheKeys.CATEGORIES);
|
|
301
|
+
deltaCache.invalidate(params.budget_id, CacheKeys.MONTHS);
|
|
297
302
|
const serverKnowledge = response.data.server_knowledge;
|
|
298
303
|
if (typeof serverKnowledge === 'number') {
|
|
299
304
|
knowledgeStore.update(categoriesListCacheKey, serverKnowledge);
|
package/src/tools/monthTools.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { responseFormatter } from '../server/responseFormatter.js';
|
|
|
6
6
|
import { milliunitsToAmount } from '../utils/amountUtils.js';
|
|
7
7
|
import { cacheManager, CACHE_TTLS, CacheManager } from '../server/cacheManager.js';
|
|
8
8
|
import type { DeltaFetcher } from './deltaFetcher.js';
|
|
9
|
+
import { CacheKeys } from '../server/cacheKeys.js';
|
|
9
10
|
import { resolveDeltaFetcherArgs } from './deltaSupport.js';
|
|
10
11
|
|
|
11
12
|
/**
|
|
@@ -42,7 +43,12 @@ export async function handleGetMonth(
|
|
|
42
43
|
return await withToolErrorHandling(
|
|
43
44
|
async () => {
|
|
44
45
|
// Always use cache
|
|
45
|
-
const cacheKey = CacheManager.generateKey(
|
|
46
|
+
const cacheKey = CacheManager.generateKey(
|
|
47
|
+
CacheKeys.MONTHS,
|
|
48
|
+
'get',
|
|
49
|
+
params.budget_id,
|
|
50
|
+
params.month,
|
|
51
|
+
);
|
|
46
52
|
const wasCached = cacheManager.has(cacheKey);
|
|
47
53
|
const month = await cacheManager.wrap<ynab.MonthDetail>(cacheKey, {
|
|
48
54
|
ttl: CACHE_TTLS.MONTHS,
|
package/src/tools/payeeTools.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { withToolErrorHandling } from '../types/index.js';
|
|
|
5
5
|
import { responseFormatter } from '../server/responseFormatter.js';
|
|
6
6
|
import { cacheManager, CACHE_TTLS, CacheManager } from '../server/cacheManager.js';
|
|
7
7
|
import type { DeltaFetcher } from './deltaFetcher.js';
|
|
8
|
+
import { CacheKeys } from '../server/cacheKeys.js';
|
|
8
9
|
import { resolveDeltaFetcherArgs } from './deltaSupport.js';
|
|
9
10
|
|
|
10
11
|
/**
|
|
@@ -104,7 +105,12 @@ export async function handleGetPayee(
|
|
|
104
105
|
return await withToolErrorHandling(
|
|
105
106
|
async () => {
|
|
106
107
|
// Use enhanced CacheManager wrap method
|
|
107
|
-
const cacheKey = CacheManager.generateKey(
|
|
108
|
+
const cacheKey = CacheManager.generateKey(
|
|
109
|
+
CacheKeys.PAYEES,
|
|
110
|
+
'get',
|
|
111
|
+
params.budget_id,
|
|
112
|
+
params.payee_id,
|
|
113
|
+
);
|
|
108
114
|
const wasCached = cacheManager.has(cacheKey);
|
|
109
115
|
const payee = await cacheManager.wrap<ynab.Payee>(cacheKey, {
|
|
110
116
|
ttl: CACHE_TTLS.PAYEES,
|
|
@@ -76,7 +76,7 @@ interface LegacyBalanceReconciliation {
|
|
|
76
76
|
|
|
77
77
|
const toBankTransactionView = (txn: BankTransaction, currency: string) => ({
|
|
78
78
|
...txn,
|
|
79
|
-
amount_money:
|
|
79
|
+
amount_money: toMoneyValue(txn.amount, currency),
|
|
80
80
|
});
|
|
81
81
|
|
|
82
82
|
const toYNABTransactionView = (txn: YNABTransaction, currency: string) => ({
|
|
@@ -85,15 +85,20 @@ const toYNABTransactionView = (txn: YNABTransaction, currency: string) => ({
|
|
|
85
85
|
});
|
|
86
86
|
|
|
87
87
|
const convertMatch = (match: TransactionMatch, currency: string) => ({
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
? toYNABTransactionView(match.ynab_transaction, currency)
|
|
88
|
+
bank_transaction: toBankTransactionView(match.bankTransaction, currency),
|
|
89
|
+
ynab_transaction: match.ynabTransaction
|
|
90
|
+
? toYNABTransactionView(match.ynabTransaction, currency)
|
|
92
91
|
: undefined,
|
|
93
92
|
candidates: match.candidates?.map((candidate) => ({
|
|
94
93
|
...candidate,
|
|
95
94
|
ynab_transaction: toYNABTransactionView(candidate.ynab_transaction, currency),
|
|
96
95
|
})),
|
|
96
|
+
confidence: match.confidence,
|
|
97
|
+
confidence_score: match.confidenceScore,
|
|
98
|
+
match_reason: match.matchReason,
|
|
99
|
+
top_confidence: match.topConfidence,
|
|
100
|
+
action_hint: match.actionHint,
|
|
101
|
+
recommendation: match.recommendation,
|
|
97
102
|
});
|
|
98
103
|
|
|
99
104
|
const convertInsight = (insight: ReconciliationInsight) => ({
|
|
@@ -34,38 +34,41 @@ const buildAnalysis = (): ReconciliationAnalysis => ({
|
|
|
34
34
|
},
|
|
35
35
|
auto_matches: [
|
|
36
36
|
{
|
|
37
|
-
|
|
37
|
+
bankTransaction: {
|
|
38
38
|
id: 'bank-1',
|
|
39
39
|
date: '2025-10-15',
|
|
40
|
-
amount: -
|
|
40
|
+
amount: -45230,
|
|
41
41
|
payee: 'Shell Gas',
|
|
42
|
-
|
|
42
|
+
sourceRow: 2,
|
|
43
|
+
raw: { date: '2025-10-15', amount: '-45.23', description: 'Shell Gas' },
|
|
43
44
|
},
|
|
44
|
-
|
|
45
|
+
ynabTransaction: {
|
|
45
46
|
id: 'ynab-1',
|
|
46
47
|
date: '2025-10-14',
|
|
47
48
|
amount: -45230,
|
|
48
|
-
|
|
49
|
-
|
|
49
|
+
payee: 'Shell',
|
|
50
|
+
categoryName: 'Auto',
|
|
50
51
|
cleared: 'uncleared',
|
|
51
52
|
approved: true,
|
|
53
|
+
memo: null,
|
|
52
54
|
},
|
|
53
55
|
candidates: [],
|
|
54
56
|
confidence: 'high',
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
confidenceScore: 97,
|
|
58
|
+
matchReason: 'exact_amount_and_date',
|
|
59
|
+
topConfidence: 97,
|
|
60
|
+
actionHint: 'mark_cleared',
|
|
59
61
|
},
|
|
60
62
|
],
|
|
61
63
|
suggested_matches: [
|
|
62
64
|
{
|
|
63
|
-
|
|
65
|
+
bankTransaction: {
|
|
64
66
|
id: 'bank-2',
|
|
65
67
|
date: '2025-10-20',
|
|
66
|
-
amount: -
|
|
68
|
+
amount: -60000,
|
|
67
69
|
payee: 'Amazon',
|
|
68
|
-
|
|
70
|
+
sourceRow: 5,
|
|
71
|
+
raw: { date: '2025-10-20', amount: '-60.00', description: 'Amazon' },
|
|
69
72
|
},
|
|
70
73
|
candidates: [
|
|
71
74
|
{
|
|
@@ -73,10 +76,11 @@ const buildAnalysis = (): ReconciliationAnalysis => ({
|
|
|
73
76
|
id: 'ynab-2',
|
|
74
77
|
date: '2025-10-19',
|
|
75
78
|
amount: -60000,
|
|
76
|
-
|
|
77
|
-
|
|
79
|
+
payee: 'Amazon Online',
|
|
80
|
+
categoryName: 'Shopping',
|
|
78
81
|
cleared: 'uncleared',
|
|
79
82
|
approved: true,
|
|
83
|
+
memo: null,
|
|
80
84
|
},
|
|
81
85
|
confidence: 75,
|
|
82
86
|
match_reason: 'amount_and_date_fuzzy_payee',
|
|
@@ -84,18 +88,19 @@ const buildAnalysis = (): ReconciliationAnalysis => ({
|
|
|
84
88
|
},
|
|
85
89
|
],
|
|
86
90
|
confidence: 'medium',
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
91
|
+
confidenceScore: 75,
|
|
92
|
+
matchReason: 'amount_and_date_fuzzy_payee',
|
|
93
|
+
topConfidence: 75,
|
|
90
94
|
},
|
|
91
95
|
],
|
|
92
96
|
unmatched_bank: [
|
|
93
97
|
{
|
|
94
98
|
id: 'bank-3',
|
|
95
99
|
date: '2025-10-25',
|
|
96
|
-
amount:
|
|
100
|
+
amount: 22220,
|
|
97
101
|
payee: 'EvoCarShare',
|
|
98
|
-
|
|
102
|
+
sourceRow: 7,
|
|
103
|
+
raw: { date: '2025-10-25', amount: '22.22', description: 'EvoCarShare' },
|
|
99
104
|
},
|
|
100
105
|
],
|
|
101
106
|
unmatched_ynab: [
|
|
@@ -103,10 +108,11 @@ const buildAnalysis = (): ReconciliationAnalysis => ({
|
|
|
103
108
|
id: 'ynab-3',
|
|
104
109
|
date: '2025-10-26',
|
|
105
110
|
amount: -15000,
|
|
106
|
-
|
|
107
|
-
|
|
111
|
+
payee: 'Coffee Shop',
|
|
112
|
+
categoryName: 'Dining',
|
|
108
113
|
cleared: 'cleared',
|
|
109
114
|
approved: true,
|
|
115
|
+
memo: null,
|
|
110
116
|
},
|
|
111
117
|
],
|
|
112
118
|
balance_info: {
|