@dizzlkheinz/ynab-mcpb 0.12.1
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/.chunkhound.json +11 -0
- package/.code/agents/0427d95e-edca-431f-a214-5e53264e29c4/error.txt +8 -0
- package/.code/agents/0d675174-d1e1-41c3-9975-4c2e275819a9/error.txt +3 -0
- package/.code/agents/0d8c5afd-4787-422b-abf8-2e5943fc7e67/error.txt +3 -0
- package/.code/agents/0ec34a70-ed5d-4b9e-bee4-bb0e4cccbc4b/error.txt +1 -0
- package/.code/agents/0ef51a21-1ab1-49d7-9561-0eaa43875ebc/error.txt +12 -0
- package/.code/agents/15db95d7-abad-4b4d-9c3b-8446089cb61d/error.txt +1 -0
- package/.code/agents/19ab9acb-f675-4ff0-902a-09a5476f8149/error.txt +1 -0
- package/.code/agents/1ef7e12d-f6ff-4897-8a9b-152d523d898e/error.txt +5 -0
- package/.code/agents/2465/exec-call_lroN9KKzJVWC7t5423DK1nT9.txt +1453 -0
- package/.code/agents/28edb6fe-95a9-41a0-ae69-aa0100d26c0c/error.txt +8 -0
- package/.code/agents/2ae40cf5-b4bf-42e2-92bf-7ea350a7755e/error.txt +9 -0
- package/.code/agents/2bfc4e1f-ac4b-45a5-b6df-bf89d4dbb54c/error.txt +1 -0
- package/.code/agents/2e2e1134-eff0-49be-ba25-8e2c3468a564/error.txt +5 -0
- package/.code/agents/3/exec-call_203OC4TNVkLxW7z2HCVEQ1cM.txt +81 -0
- package/.code/agents/3/exec-call_SS5T0XSiXB4LSNzUKTl75wkh.txt +610 -0
- package/.code/agents/3322c003-ce5e-48e3-a342-f5049c5bf9a2/error.txt +1 -0
- package/.code/agents/391e9b08-1ebc-468c-9bcd-6d0cc3193b37/error.txt +1 -0
- package/.code/agents/3ab0aa84-b7bb-4054-afa3-40b8fd7d3be0/error.txt +1 -0
- package/.code/agents/3bed368d-50fe-477e-aee3-a6707eaa1ab9/error.txt +3 -0
- package/.code/agents/3e40b925-db12-442f-8d7a-a25fc69a6672/error.txt +8 -0
- package/.code/agents/414d5776-cf58-41f3-9328-a6daed503a50/error.txt +5 -0
- package/.code/agents/42687751-4565-4610-b240-67835b17d861/error.txt +1 -0
- package/.code/agents/46b98876-1a39-43c9-9e2f-507ca6d47335/error.txt +9 -0
- package/.code/agents/4a7d9491-b26f-43dd-850d-2ecdc49b5d1b/error.txt +1 -0
- package/.code/agents/4e60f00a-1b3e-447f-87f3-7faf9deddec3/error.txt +13 -0
- package/.code/agents/5138fc1c-4d49-4b74-a7da-ccdb3a8e44e7/error.txt +14 -0
- package/.code/agents/521cff39-a7a3-42e5-a557-134f0f7daaa0/error.txt +5 -0
- package/.code/agents/53302dc5-3857-4413-9a47-9e0f64a51dc4/error.txt +5 -0
- package/.code/agents/567c7c2e-6a6f-4761-a08d-d36deeb2e0ac/error.txt +5 -0
- package/.code/agents/57b00845-80dc-47c9-953c-3028d16275d6/error.txt +3 -0
- package/.code/agents/593d9005-c2a5-48fd-8813-ece0d3f2de96/error.txt +1 -0
- package/.code/agents/5a112e66-0e1a-42f9-877c-53af56ea3551/error.txt +1 -0
- package/.code/agents/5b05e8ed-7788-4738-b7ee-9faa8180f992/error.txt +5 -0
- package/.code/agents/5f888d6f-d7ca-4ac8-be23-9ea1bf753951/error.txt +5 -0
- package/.code/agents/607db3ab-e4b0-435b-b497-93e9aa525549/error.txt +8 -0
- package/.code/agents/67dcb2a2-900f-4c78-b3fc-80b5213e0ddf/error.txt +8 -0
- package/.code/agents/69ad848c-4e98-49b3-b16c-0094ac2d1759/error.txt +5 -0
- package/.code/agents/6c9cfc5f-0d0b-445c-b121-9f60082c4f70/error.txt +1 -0
- package/.code/agents/6f6f8f77-4ab0-4f6e-9f30-40e8be0bd8f5/error.txt +1 -0
- package/.code/agents/72a7cde4-fa8a-4024-9038-27faa550539b/error.txt +1 -0
- package/.code/agents/7b48335c-8247-43aa-9949-5f820ba8e199/error.txt +1 -0
- package/.code/agents/80944249-bea9-4ac5-87de-a666c4df306e/error.txt +1 -0
- package/.code/agents/826099df-1b66-4186-a915-7eb59f9db19d/error.txt +5 -0
- package/.code/agents/8291d158-18a8-4a92-b799-4e9a4d9cce88/error.txt +1 -0
- package/.code/agents/82fb71a3-20fb-4341-804a-a2fc900f95bc/error.txt +1 -0
- package/.code/agents/855790ea-54ee-43e4-8209-a66994e37590/error.txt +1 -0
- package/.code/agents/88ce3a2e-04f2-42be-9062-bf97aa798da0/error.txt +3 -0
- package/.code/agents/9a17e398-b6ed-4218-bb55-bc64a8d38ce8/error.txt +8 -0
- package/.code/agents/9a4f4bfc-a2a6-4f40-a896-9335b41a7ed1/error.txt +1 -0
- package/.code/agents/9b633e55-ef84-47d6-94bb-fd3dd172ad97/error.txt +1 -0
- package/.code/agents/9b81f3ab-c72b-4a81-9a8f-28a49ddba84a/error.txt +8 -0
- package/.code/agents/a35daf29-b2d1-4aef-9b42-dad63a76bd47/error.txt +3 -0
- package/.code/agents/a81990cc-69ee-44d2-b907-17403c9bc5d7/error.txt +5 -0
- package/.code/agents/ab56260a-4a83-4ad4-9410-f88a23d6520a/error.txt +1 -0
- package/.code/agents/ad722c31-2d1d-45f7-bae2-3f02ca455b60/error.txt +1 -0
- package/.code/agents/b62e8690-3324-4b97-9309-731bee79416b/error.txt +5 -0
- package/.code/agents/baf60a3a-752b-4ad8-99d6-df32423ed2eb/error.txt +1 -0
- package/.code/agents/be049042-7dcb-4ac8-9beb-c8f1aea67742/error.txt +14 -0
- package/.code/agents/bed1dcb4-bfce-4a9f-8594-0f994962aafd/error.txt +1 -0
- package/.code/agents/c324a6cf-e935-4ede-9529-b3ebc18e8d6b/error.txt +5 -0
- package/.code/agents/c37c06ff-dfe3-43f2-9bbc-3ec73ec8f41d/error.txt +5 -0
- package/.code/agents/c8cd6671-433a-456b-9f88-e51cb2df6bfc/error.txt +11 -0
- package/.code/agents/ca2ccb67-2f24-428e-b27d-9365beadd140/error.txt +1 -0
- package/.code/agents/cf08c0c8-e7f0-423e-93ba-547e8e818340/error.txt +8 -0
- package/.code/agents/d579c74f-874b-40a4-9d56-ced1eb6a701d/error.txt +1 -0
- package/.code/agents/df412c98-7378-4deb-8e1e-76c416931181/error.txt +3 -0
- package/.code/agents/e5134eb3-2af4-45b0-8998-051cb4afdb45/error.txt +3 -0
- package/.code/agents/e6308471-aa45-4e9e-9496-2e9404164d97/error.txt +8 -0
- package/.code/agents/e7bd8bc7-23fb-4f46-98dc-b0dcf11b75a1/error.txt +1 -0
- package/.code/agents/e92bec35-378d-4fe1-8ac0-6e1bb3c86911/error.txt +5 -0
- package/.code/agents/ed918fbf-2dc4-4aa2-bfc5-04b65d9471ea/error.txt +1 -0
- package/.code/agents/ef1d756f-b272-48fc-8729-f05c494674f7/error.txt +1 -0
- package/.code/agents/ef359853-0249-4e41-a804-c0fc459fe456/error.txt +1 -0
- package/.code/agents/effc7b4a-4b90-40a0-8c86-a7a99d2d5fd2/error.txt +1 -0
- package/.code/agents/fa15f8d5-8359-4a8b-83a3-2f2056b3ff40/error.txt +3 -0
- package/.code/agents/fbef4193-eadf-4c8a-83ff-4878a6310f25/error.txt +8 -0
- package/.code/agents/fd0a4b4a-fda4-4964-a6d6-2b8a2da387c6/error.txt +1 -0
- package/.dxtignore +57 -0
- package/.env.example +44 -0
- package/.gemini/settings.json +8 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +41 -0
- package/.github/ISSUE_TEMPLATE/config.yml +5 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +24 -0
- package/.github/ISSUE_TEMPLATE/release_checklist.md +31 -0
- package/.github/pull_request_template.md +41 -0
- package/.github/workflows/ci-tests.yml +41 -0
- package/.github/workflows/claude-code-review.yml +57 -0
- package/.github/workflows/claude.yml +50 -0
- package/.github/workflows/full-integration.yml +22 -0
- package/.github/workflows/pr-description-check.yml +88 -0
- package/.github/workflows/publish.yml +33 -0
- package/.github/workflows/release.yml +89 -0
- package/.mcpbignore +58 -0
- package/.prettierignore +10 -0
- package/.prettierrc.json +10 -0
- package/ADOS-2-Module-1-Complete-Manual.md +757 -0
- package/AGENTS.md +36 -0
- package/CHANGELOG.md +187 -0
- package/CLAUDE.md +414 -0
- package/CODEREVIEW_RESPONSE.md +128 -0
- package/LICENSE +17 -0
- package/NUL +1 -0
- package/README.md +222 -0
- package/SCHEMA_IMPROVEMENT_SUMMARY.md +120 -0
- package/TESTING_NOTES.md +217 -0
- package/WARP.md +245 -0
- package/accountactivity-merged.csv +149 -0
- package/bin/ynab-mcp-server.cjs +4 -0
- package/bin/ynab-mcp-server.js +8 -0
- package/bundle-analysis.html +13110 -0
- package/dist/bundle/index.cjs +124 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +85 -0
- package/dist/server/YNABMCPServer.d.ts +264 -0
- package/dist/server/YNABMCPServer.js +845 -0
- package/dist/server/budgetResolver.d.ts +15 -0
- package/dist/server/budgetResolver.js +99 -0
- package/dist/server/cacheManager.d.ts +74 -0
- package/dist/server/cacheManager.js +306 -0
- package/dist/server/config.d.ts +3 -0
- package/dist/server/config.js +19 -0
- package/dist/server/deltaCache.d.ts +61 -0
- package/dist/server/deltaCache.js +206 -0
- package/dist/server/deltaCache.merge.d.ts +9 -0
- package/dist/server/deltaCache.merge.js +111 -0
- package/dist/server/diagnostics.d.ts +90 -0
- package/dist/server/diagnostics.js +163 -0
- package/dist/server/errorHandler.d.ts +69 -0
- package/dist/server/errorHandler.js +524 -0
- package/dist/server/prompts.d.ts +31 -0
- package/dist/server/prompts.js +205 -0
- package/dist/server/rateLimiter.d.ts +27 -0
- package/dist/server/rateLimiter.js +82 -0
- package/dist/server/requestLogger.d.ts +62 -0
- package/dist/server/requestLogger.js +190 -0
- package/dist/server/resources.d.ts +39 -0
- package/dist/server/resources.js +85 -0
- package/dist/server/responseFormatter.d.ts +14 -0
- package/dist/server/responseFormatter.js +42 -0
- package/dist/server/securityMiddleware.d.ts +87 -0
- package/dist/server/securityMiddleware.js +117 -0
- package/dist/server/serverKnowledgeStore.d.ts +11 -0
- package/dist/server/serverKnowledgeStore.js +42 -0
- package/dist/server/toolRegistry.d.ts +85 -0
- package/dist/server/toolRegistry.js +272 -0
- package/dist/tools/__tests__/deltaTestUtils.d.ts +18 -0
- package/dist/tools/__tests__/deltaTestUtils.js +26 -0
- package/dist/tools/accountTools.d.ts +37 -0
- package/dist/tools/accountTools.js +175 -0
- package/dist/tools/budgetTools.d.ts +10 -0
- package/dist/tools/budgetTools.js +68 -0
- package/dist/tools/categoryTools.d.ts +27 -0
- package/dist/tools/categoryTools.js +232 -0
- package/dist/tools/compareTransactions/formatter.d.ts +71 -0
- package/dist/tools/compareTransactions/formatter.js +97 -0
- package/dist/tools/compareTransactions/index.d.ts +30 -0
- package/dist/tools/compareTransactions/index.js +160 -0
- package/dist/tools/compareTransactions/matcher.d.ts +12 -0
- package/dist/tools/compareTransactions/matcher.js +140 -0
- package/dist/tools/compareTransactions/parser.d.ts +14 -0
- package/dist/tools/compareTransactions/parser.js +430 -0
- package/dist/tools/compareTransactions/types.d.ts +27 -0
- package/dist/tools/compareTransactions/types.js +1 -0
- package/dist/tools/compareTransactions.d.ts +1 -0
- package/dist/tools/compareTransactions.js +1 -0
- package/dist/tools/deltaFetcher.d.ts +22 -0
- package/dist/tools/deltaFetcher.js +137 -0
- package/dist/tools/deltaSupport.d.ts +20 -0
- package/dist/tools/deltaSupport.js +176 -0
- package/dist/tools/exportTransactions.d.ts +17 -0
- package/dist/tools/exportTransactions.js +191 -0
- package/dist/tools/monthTools.d.ts +16 -0
- package/dist/tools/monthTools.js +107 -0
- package/dist/tools/payeeTools.d.ts +17 -0
- package/dist/tools/payeeTools.js +82 -0
- package/dist/tools/reconcileAdapter.d.ts +25 -0
- package/dist/tools/reconcileAdapter.js +167 -0
- package/dist/tools/reconciliation/analyzer.d.ts +3 -0
- package/dist/tools/reconciliation/analyzer.js +567 -0
- package/dist/tools/reconciliation/executor.d.ts +94 -0
- package/dist/tools/reconciliation/executor.js +611 -0
- package/dist/tools/reconciliation/index.d.ts +54 -0
- package/dist/tools/reconciliation/index.js +249 -0
- package/dist/tools/reconciliation/matcher.d.ts +3 -0
- package/dist/tools/reconciliation/matcher.js +160 -0
- package/dist/tools/reconciliation/payeeNormalizer.d.ts +6 -0
- package/dist/tools/reconciliation/payeeNormalizer.js +77 -0
- package/dist/tools/reconciliation/recommendationEngine.d.ts +2 -0
- package/dist/tools/reconciliation/recommendationEngine.js +273 -0
- package/dist/tools/reconciliation/reportFormatter.d.ts +13 -0
- package/dist/tools/reconciliation/reportFormatter.js +214 -0
- package/dist/tools/reconciliation/types.d.ts +172 -0
- package/dist/tools/reconciliation/types.js +7 -0
- package/dist/tools/schemas/outputs/accountOutputs.d.ts +58 -0
- package/dist/tools/schemas/outputs/accountOutputs.js +24 -0
- package/dist/tools/schemas/outputs/budgetOutputs.d.ts +48 -0
- package/dist/tools/schemas/outputs/budgetOutputs.js +15 -0
- package/dist/tools/schemas/outputs/categoryOutputs.d.ts +93 -0
- package/dist/tools/schemas/outputs/categoryOutputs.js +37 -0
- package/dist/tools/schemas/outputs/comparisonOutputs.d.ts +269 -0
- package/dist/tools/schemas/outputs/comparisonOutputs.js +181 -0
- package/dist/tools/schemas/outputs/index.d.ts +14 -0
- package/dist/tools/schemas/outputs/index.js +14 -0
- package/dist/tools/schemas/outputs/monthOutputs.d.ts +122 -0
- package/dist/tools/schemas/outputs/monthOutputs.js +51 -0
- package/dist/tools/schemas/outputs/payeeOutputs.d.ts +34 -0
- package/dist/tools/schemas/outputs/payeeOutputs.js +16 -0
- package/dist/tools/schemas/outputs/reconciliationOutputs.d.ts +1275 -0
- package/dist/tools/schemas/outputs/reconciliationOutputs.js +377 -0
- package/dist/tools/schemas/outputs/transactionMutationOutputs.d.ts +717 -0
- package/dist/tools/schemas/outputs/transactionMutationOutputs.js +260 -0
- package/dist/tools/schemas/outputs/transactionOutputs.d.ts +98 -0
- package/dist/tools/schemas/outputs/transactionOutputs.js +49 -0
- package/dist/tools/schemas/outputs/utilityOutputs.d.ts +219 -0
- package/dist/tools/schemas/outputs/utilityOutputs.js +120 -0
- package/dist/tools/schemas/shared/commonOutputs.d.ts +24 -0
- package/dist/tools/schemas/shared/commonOutputs.js +27 -0
- package/dist/tools/toolCategories.d.ts +32 -0
- package/dist/tools/toolCategories.js +32 -0
- package/dist/tools/transactionTools.d.ts +315 -0
- package/dist/tools/transactionTools.js +1722 -0
- package/dist/tools/utilityTools.d.ts +10 -0
- package/dist/tools/utilityTools.js +56 -0
- package/dist/types/index.d.ts +20 -0
- package/dist/types/index.js +16 -0
- package/dist/types/toolAnnotations.d.ts +7 -0
- package/dist/types/toolAnnotations.js +1 -0
- package/dist/utils/amountUtils.d.ts +3 -0
- package/dist/utils/amountUtils.js +10 -0
- package/dist/utils/dateUtils.d.ts +9 -0
- package/dist/utils/dateUtils.js +43 -0
- package/dist/utils/money.d.ts +21 -0
- package/dist/utils/money.js +51 -0
- package/docs/README.md +72 -0
- package/docs/assets/examples/reconciliation-with-recommendations.json +68 -0
- package/docs/assets/schemas/reconciliation-v2.json +338 -0
- package/docs/getting-started/CONFIGURATION.md +175 -0
- package/docs/getting-started/INSTALLATION.md +333 -0
- package/docs/getting-started/QUICKSTART.md +282 -0
- package/docs/guides/ARCHITECTURE.md +650 -0
- package/docs/guides/DEPLOYMENT.md +189 -0
- package/docs/guides/INTEGRATION_TESTING.md +730 -0
- package/docs/guides/TESTING.md +591 -0
- package/docs/reconciliation-flow.md +83 -0
- package/docs/reference/API.md +1450 -0
- package/docs/reference/EXAMPLES.md +946 -0
- package/docs/reference/TOOLS.md +348 -0
- package/docs/reference/TROUBLESHOOTING.md +481 -0
- package/esbuild.config.mjs +68 -0
- package/eslint.config.js +49 -0
- package/fix-types.sh +17 -0
- package/meta.json +12550 -0
- package/package.json +105 -0
- package/package.json.tmp +105 -0
- package/scripts/analyze-bundle.mjs +41 -0
- package/scripts/create-pr-description.js +203 -0
- package/scripts/generate-mcpb.ps1 +96 -0
- package/scripts/run-domain-integration-tests.js +33 -0
- package/scripts/run-generate-mcpb.js +29 -0
- package/scripts/run-throttled-integration-tests.js +116 -0
- package/scripts/test-delta-params.mjs +140 -0
- package/scripts/test-recommendations.ts +53 -0
- package/scripts/tmpTransaction.ts +48 -0
- package/scripts/validate-env.js +122 -0
- package/scripts/verify-build.js +105 -0
- package/scripts/watch-and-restart.ps1 +50 -0
- package/src/__tests__/comprehensive.integration.test.ts +1196 -0
- package/src/__tests__/delta.performance.test.ts +80 -0
- package/src/__tests__/performance.test.ts +725 -0
- package/src/__tests__/setup.ts +449 -0
- package/src/__tests__/testRunner.ts +444 -0
- package/src/__tests__/testUtils.ts +563 -0
- package/src/__tests__/workflows.e2e.test.ts +1675 -0
- package/src/index.ts +124 -0
- package/src/server/.gitkeep +1 -0
- package/src/server/YNABMCPServer.ts +1188 -0
- package/src/server/__tests__/YNABMCPServer.integration.test.ts +903 -0
- package/src/server/__tests__/YNABMCPServer.test.ts +894 -0
- package/src/server/__tests__/budgetResolver.test.ts +425 -0
- package/src/server/__tests__/cacheManager.test.ts +880 -0
- package/src/server/__tests__/config.test.ts +166 -0
- package/src/server/__tests__/deltaCache.merge.test.ts +724 -0
- package/src/server/__tests__/deltaCache.swr.test.ts +168 -0
- package/src/server/__tests__/deltaCache.test.ts +774 -0
- package/src/server/__tests__/diagnostics.test.ts +823 -0
- package/src/server/__tests__/errorHandler.integration.test.ts +466 -0
- package/src/server/__tests__/errorHandler.test.ts +416 -0
- package/src/server/__tests__/prompts.test.ts +354 -0
- package/src/server/__tests__/rateLimiter.test.ts +314 -0
- package/src/server/__tests__/requestLogger.test.ts +408 -0
- package/src/server/__tests__/resources.test.ts +299 -0
- package/src/server/__tests__/security.integration.test.ts +426 -0
- package/src/server/__tests__/securityMiddleware.test.ts +449 -0
- package/src/server/__tests__/server-startup.integration.test.ts +477 -0
- package/src/server/__tests__/serverKnowledgeStore.test.ts +174 -0
- package/src/server/__tests__/toolRegistry.test.ts +855 -0
- package/src/server/budgetResolver.ts +235 -0
- package/src/server/cacheManager.ts +503 -0
- package/src/server/config.ts +41 -0
- package/src/server/deltaCache.merge.ts +149 -0
- package/src/server/deltaCache.ts +341 -0
- package/src/server/diagnostics.ts +338 -0
- package/src/server/errorHandler.ts +756 -0
- package/src/server/prompts.ts +291 -0
- package/src/server/rateLimiter.ts +156 -0
- package/src/server/requestLogger.ts +344 -0
- package/src/server/resources.ts +168 -0
- package/src/server/responseFormatter.ts +51 -0
- package/src/server/securityMiddleware.ts +236 -0
- package/src/server/serverKnowledgeStore.ts +91 -0
- package/src/server/toolRegistry.ts +489 -0
- package/src/tools/.gitkeep +1 -0
- package/src/tools/__tests__/accountTools.delta.integration.test.ts +128 -0
- package/src/tools/__tests__/accountTools.integration.test.ts +117 -0
- package/src/tools/__tests__/accountTools.test.ts +653 -0
- package/src/tools/__tests__/budgetTools.delta.integration.test.ts +90 -0
- package/src/tools/__tests__/budgetTools.integration.test.ts +134 -0
- package/src/tools/__tests__/budgetTools.test.ts +423 -0
- package/src/tools/__tests__/categoryTools.delta.integration.test.ts +80 -0
- package/src/tools/__tests__/categoryTools.integration.test.ts +295 -0
- package/src/tools/__tests__/categoryTools.test.ts +622 -0
- package/src/tools/__tests__/compareTransactions/formatter.test.ts +486 -0
- package/src/tools/__tests__/compareTransactions/index.test.ts +383 -0
- package/src/tools/__tests__/compareTransactions/matcher.test.ts +410 -0
- package/src/tools/__tests__/compareTransactions/parser.test.ts +764 -0
- package/src/tools/__tests__/compareTransactions.test.ts +342 -0
- package/src/tools/__tests__/compareTransactions.window.test.ts +147 -0
- package/src/tools/__tests__/deltaFetcher.scheduled.integration.test.ts +76 -0
- package/src/tools/__tests__/deltaFetcher.test.ts +270 -0
- package/src/tools/__tests__/deltaSupport.test.ts +188 -0
- package/src/tools/__tests__/deltaTestUtils.ts +46 -0
- package/src/tools/__tests__/exportTransactions.test.ts +213 -0
- package/src/tools/__tests__/monthTools.delta.integration.test.ts +80 -0
- package/src/tools/__tests__/monthTools.integration.test.ts +174 -0
- package/src/tools/__tests__/monthTools.test.ts +523 -0
- package/src/tools/__tests__/payeeTools.delta.integration.test.ts +80 -0
- package/src/tools/__tests__/payeeTools.integration.test.ts +150 -0
- package/src/tools/__tests__/payeeTools.test.ts +445 -0
- package/src/tools/__tests__/transactionTools.integration.test.ts +762 -0
- package/src/tools/__tests__/transactionTools.test.ts +3521 -0
- package/src/tools/__tests__/utilityTools.integration.test.ts +128 -0
- package/src/tools/__tests__/utilityTools.test.ts +205 -0
- package/src/tools/accountTools.ts +283 -0
- package/src/tools/budgetTools.ts +112 -0
- package/src/tools/categoryTools.ts +366 -0
- package/src/tools/compareTransactions/formatter.ts +163 -0
- package/src/tools/compareTransactions/index.ts +228 -0
- package/src/tools/compareTransactions/matcher.ts +240 -0
- package/src/tools/compareTransactions/parser.ts +557 -0
- package/src/tools/compareTransactions/types.ts +60 -0
- package/src/tools/compareTransactions.ts +3 -0
- package/src/tools/deltaFetcher.ts +278 -0
- package/src/tools/deltaSupport.ts +293 -0
- package/src/tools/exportTransactions.ts +273 -0
- package/src/tools/monthTools.ts +164 -0
- package/src/tools/payeeTools.ts +140 -0
- package/src/tools/reconcileAdapter.ts +312 -0
- package/src/tools/reconciliation/__tests__/adapter.causes.test.ts +122 -0
- package/src/tools/reconciliation/__tests__/adapter.test.ts +234 -0
- package/src/tools/reconciliation/__tests__/analyzer.test.ts +406 -0
- package/src/tools/reconciliation/__tests__/executor.integration.test.ts +366 -0
- package/src/tools/reconciliation/__tests__/executor.test.ts +779 -0
- package/src/tools/reconciliation/__tests__/matcher.test.ts +650 -0
- package/src/tools/reconciliation/__tests__/payeeNormalizer.test.ts +278 -0
- package/src/tools/reconciliation/__tests__/recommendationEngine.integration.test.ts +658 -0
- package/src/tools/reconciliation/__tests__/recommendationEngine.test.ts +1000 -0
- package/src/tools/reconciliation/__tests__/reconciliation.delta.integration.test.ts +151 -0
- package/src/tools/reconciliation/__tests__/reportFormatter.test.ts +573 -0
- package/src/tools/reconciliation/__tests__/scenarios/adapterCurrency.scenario.test.ts +78 -0
- package/src/tools/reconciliation/__tests__/scenarios/extremes.scenario.test.ts +47 -0
- package/src/tools/reconciliation/__tests__/scenarios/repeatAmount.scenario.test.ts +61 -0
- package/src/tools/reconciliation/__tests__/schemaUrl.test.ts +49 -0
- package/src/tools/reconciliation/analyzer.ts +824 -0
- package/src/tools/reconciliation/executor.ts +880 -0
- package/src/tools/reconciliation/index.ts +400 -0
- package/src/tools/reconciliation/matcher.ts +269 -0
- package/src/tools/reconciliation/payeeNormalizer.ts +167 -0
- package/src/tools/reconciliation/recommendationEngine.ts +506 -0
- package/src/tools/reconciliation/reportFormatter.ts +363 -0
- package/src/tools/reconciliation/types.ts +314 -0
- package/src/tools/schemas/outputs/__tests__/accountOutputs.test.ts +424 -0
- package/src/tools/schemas/outputs/__tests__/budgetOutputs.test.ts +310 -0
- package/src/tools/schemas/outputs/__tests__/categoryOutputs.test.ts +448 -0
- package/src/tools/schemas/outputs/__tests__/comparisonOutputs.test.ts +519 -0
- package/src/tools/schemas/outputs/__tests__/dateValidation.test.ts +155 -0
- package/src/tools/schemas/outputs/__tests__/discrepancyDirection.test.ts +288 -0
- package/src/tools/schemas/outputs/__tests__/monthOutputs.test.ts +478 -0
- package/src/tools/schemas/outputs/__tests__/payeeOutputs.test.ts +370 -0
- package/src/tools/schemas/outputs/__tests__/reconciliationOutputs.test.ts +401 -0
- package/src/tools/schemas/outputs/__tests__/transactionMutationSchemas.test.ts +213 -0
- package/src/tools/schemas/outputs/__tests__/transactionOutputs.test.ts +474 -0
- package/src/tools/schemas/outputs/__tests__/utilityOutputs.test.ts +333 -0
- package/src/tools/schemas/outputs/accountOutputs.ts +137 -0
- package/src/tools/schemas/outputs/budgetOutputs.ts +86 -0
- package/src/tools/schemas/outputs/categoryOutputs.ts +194 -0
- package/src/tools/schemas/outputs/comparisonOutputs.ts +600 -0
- package/src/tools/schemas/outputs/index.ts +270 -0
- package/src/tools/schemas/outputs/monthOutputs.ts +243 -0
- package/src/tools/schemas/outputs/payeeOutputs.ts +105 -0
- package/src/tools/schemas/outputs/reconciliationOutputs.ts +796 -0
- package/src/tools/schemas/outputs/transactionMutationOutputs.ts +758 -0
- package/src/tools/schemas/outputs/transactionOutputs.ts +243 -0
- package/src/tools/schemas/outputs/utilityOutputs.ts +411 -0
- package/src/tools/schemas/shared/commonOutputs.ts +140 -0
- package/src/tools/toolCategories.ts +140 -0
- package/src/tools/transactionTools.ts +2509 -0
- package/src/tools/utilityTools.ts +90 -0
- package/src/types/.gitkeep +1 -0
- package/src/types/__tests__/index.test.ts +52 -0
- package/src/types/index.ts +67 -0
- package/src/types/integration-tests.d.ts +35 -0
- package/src/types/toolAnnotations.ts +44 -0
- package/src/utils/__tests__/dateUtils.test.ts +170 -0
- package/src/utils/__tests__/money.test.ts +189 -0
- package/src/utils/amountUtils.ts +32 -0
- package/src/utils/dateUtils.ts +108 -0
- package/src/utils/money.ts +123 -0
- package/test-csv-sample.csv +28 -0
- package/test-exports/sample_bank_statement.csv +7 -0
- package/test-exports/ynab_account_e9ddc2a6_minimal_1items_2025-11-19_09-04-53.json +23 -0
- package/test-exports/ynab_account_e9ddc2a6_minimal_1items_2025-11-19_10-37-42.json +23 -0
- package/test-exports/ynab_account_e9ddc2a6_minimal_4items_2025-11-19_09-02-09.json +44 -0
- package/test-exports/ynab_account_e9ddc2a6_minimal_6items_2025-11-19_10-37-52.json +58 -0
- package/test-exports/ynab_since_2025-11-01_account_4c18e9f0_minimal_14items_2025-11-16_10-07-10.json +115 -0
- package/test-reconcile-autodetect.js +40 -0
- package/test-reconcile-tool.js +152 -0
- package/test-reconcile-with-csv.cjs +89 -0
- package/test-statement.csv +8 -0
- package/test_debug.js +47 -0
- package/test_simple.mjs +16 -0
- package/tsconfig.json +31 -0
- package/tsconfig.prod.json +18 -0
- package/vitest-reporters/split-json-reporter.ts +211 -0
- package/vitest.config.ts +96 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Runs the full integration suite with simple rate-limit-aware throttling.
|
|
4
|
+
*/
|
|
5
|
+
import { spawn } from 'node:child_process';
|
|
6
|
+
import { readdirSync } from 'node:fs';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
|
|
9
|
+
const RATE_LIMIT = Number(process.env['RATE_LIMIT_PER_HOUR'] ?? 200);
|
|
10
|
+
const RATE_LIMIT_BUFFER = Number(process.env['RATE_LIMIT_BUFFER'] ?? 20);
|
|
11
|
+
const RATE_LIMIT_WINDOW_MS = Number(process.env['RATE_LIMIT_WINDOW_MS'] ?? 60 * 60 * 1000);
|
|
12
|
+
const MAX_WAIT_MS = Number(process.env['RATE_LIMIT_MAX_WAIT_MS'] ?? 60 * 60 * 1000);
|
|
13
|
+
const projectRoot = process.cwd();
|
|
14
|
+
|
|
15
|
+
const testFiles = collectIntegrationTests(path.join(projectRoot, 'src'));
|
|
16
|
+
const toPosixPath = (value) => value.split(path.sep).join(path.posix.sep);
|
|
17
|
+
if (testFiles.length === 0) {
|
|
18
|
+
console.error('No integration test files found.');
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const requestHistory = [];
|
|
23
|
+
|
|
24
|
+
await runSequentially(testFiles);
|
|
25
|
+
|
|
26
|
+
async function runSequentially(files) {
|
|
27
|
+
for (const filePath of files) {
|
|
28
|
+
const estimatedCalls = estimateCalls(filePath);
|
|
29
|
+
await throttleIfNeeded(estimatedCalls);
|
|
30
|
+
const relativePath = path.relative(projectRoot, filePath);
|
|
31
|
+
console.log(`ā¶ļø Running ${relativePath} (estimated ${estimatedCalls} API calls)`);
|
|
32
|
+
await runVitestFile(relativePath);
|
|
33
|
+
requestHistory.push({ timestamp: Date.now(), calls: estimatedCalls });
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function collectIntegrationTests(dir) {
|
|
38
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
39
|
+
const files = [];
|
|
40
|
+
for (const entry of entries) {
|
|
41
|
+
const fullPath = path.join(dir, entry.name);
|
|
42
|
+
if (entry.isDirectory()) {
|
|
43
|
+
files.push(...collectIntegrationTests(fullPath));
|
|
44
|
+
} else if (entry.isFile() && entry.name.endsWith('.integration.test.ts')) {
|
|
45
|
+
files.push(fullPath);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return files.sort((a, b) => a.localeCompare(b));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async function throttleIfNeeded(nextCalls) {
|
|
52
|
+
pruneHistory();
|
|
53
|
+
while (getRecentCalls() + nextCalls > RATE_LIMIT - RATE_LIMIT_BUFFER) {
|
|
54
|
+
const nextWindowTime = requestHistory[0]?.timestamp ?? Date.now();
|
|
55
|
+
const waitUntil = nextWindowTime + RATE_LIMIT_WINDOW_MS;
|
|
56
|
+
const waitMs = Math.min(Math.max(waitUntil - Date.now(), 1000), MAX_WAIT_MS);
|
|
57
|
+
const minutes = Math.max(1, Math.round(waitMs / 60000));
|
|
58
|
+
console.warn(
|
|
59
|
+
`ā³ Approaching rate limit (${getRecentCalls()}/${RATE_LIMIT}). Waiting ${minutes} minute${
|
|
60
|
+
minutes === 1 ? '' : 's'
|
|
61
|
+
}...`,
|
|
62
|
+
);
|
|
63
|
+
await sleep(waitMs);
|
|
64
|
+
pruneHistory();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function pruneHistory() {
|
|
69
|
+
const cutoff = Date.now() - RATE_LIMIT_WINDOW_MS;
|
|
70
|
+
while (requestHistory.length && requestHistory[0].timestamp < cutoff) {
|
|
71
|
+
requestHistory.shift();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function getRecentCalls() {
|
|
76
|
+
return requestHistory.reduce((sum, entry) => sum + entry.calls, 0);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function estimateCalls(filePath) {
|
|
80
|
+
const name = filePath.toLowerCase();
|
|
81
|
+
if (name.includes('delta')) return 15;
|
|
82
|
+
if (name.includes('reconciliation')) return 25;
|
|
83
|
+
if (name.includes('transaction')) return 12;
|
|
84
|
+
if (name.includes('budget')) return 8;
|
|
85
|
+
if (name.includes('account')) return 8;
|
|
86
|
+
if (name.includes('payee')) return 10;
|
|
87
|
+
if (name.includes('category')) return 10;
|
|
88
|
+
if (name.includes('month')) return 10;
|
|
89
|
+
return 10;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async function runVitestFile(testFile) {
|
|
93
|
+
const normalized = toPosixPath(testFile);
|
|
94
|
+
const vitestArgs = ['vitest', 'run', '--project', 'integration:full', normalized];
|
|
95
|
+
const runner = process.platform === 'win32' ? 'npx.cmd' : 'npx';
|
|
96
|
+
const child = spawn(runner, vitestArgs, {
|
|
97
|
+
stdio: 'inherit',
|
|
98
|
+
env: {
|
|
99
|
+
...process.env,
|
|
100
|
+
INTEGRATION_TEST_TIER: 'full',
|
|
101
|
+
INTEGRATION_TEST_DOMAINS: '',
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
await new Promise((resolve, reject) => {
|
|
106
|
+
child.on('close', (code) => {
|
|
107
|
+
if (code === 0) resolve();
|
|
108
|
+
else reject(new Error(`Vitest exited with code ${code}`));
|
|
109
|
+
});
|
|
110
|
+
child.on('error', reject);
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function sleep(ms) {
|
|
115
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
116
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import * as ynab from 'ynab';
|
|
2
|
+
|
|
3
|
+
const ACCESS_TOKEN = process.env.YNAB_ACCESS_TOKEN;
|
|
4
|
+
|
|
5
|
+
if (!ACCESS_TOKEN) {
|
|
6
|
+
console.error('Missing YNAB_ACCESS_TOKEN environment variable.');
|
|
7
|
+
process.exit(1);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const ynabAPI = new ynab.API(ACCESS_TOKEN);
|
|
11
|
+
|
|
12
|
+
const results = [];
|
|
13
|
+
|
|
14
|
+
function recordResult(name, signature, supported, notes, error) {
|
|
15
|
+
results.push({ name, signature, supported, notes, error: error?.message ?? null });
|
|
16
|
+
const status = supported ? 'ā' : 'ā';
|
|
17
|
+
const suffix = notes ? ` - ${notes}` : '';
|
|
18
|
+
console.log(`${status} ${name} (${signature})${suffix}`);
|
|
19
|
+
if (error) {
|
|
20
|
+
console.log(` Error: ${error.message}`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function verifySimpleEndpoint({ name, signature, fetchFull, fetchDelta }) {
|
|
25
|
+
try {
|
|
26
|
+
const full = await fetchFull();
|
|
27
|
+
const knowledge = full?.data?.server_knowledge;
|
|
28
|
+
if (typeof knowledge !== 'number') {
|
|
29
|
+
throw new Error('Response missing server_knowledge');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
await fetchDelta(knowledge);
|
|
33
|
+
recordResult(name, signature, true, `server_knowledge=${knowledge}`);
|
|
34
|
+
} catch (error) {
|
|
35
|
+
recordResult(name, signature, false, '', error);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async function main() {
|
|
40
|
+
console.log('Verifying YNAB SDK delta request signatures...\n');
|
|
41
|
+
const budgetsResponse = await ynabAPI.budgets.getBudgets();
|
|
42
|
+
const budget = budgetsResponse?.data?.budgets?.[0];
|
|
43
|
+
if (!budget) {
|
|
44
|
+
throw new Error('No budget available to test.');
|
|
45
|
+
}
|
|
46
|
+
const budgetId = budget.id;
|
|
47
|
+
console.log(`Using budget: ${budget.name} (${budgetId})\n`);
|
|
48
|
+
|
|
49
|
+
// Budgets API
|
|
50
|
+
await verifySimpleEndpoint({
|
|
51
|
+
name: 'budgets.getBudgetById',
|
|
52
|
+
signature: 'getBudgetById(budgetId, lastKnowledge?)',
|
|
53
|
+
fetchFull: () => ynabAPI.budgets.getBudgetById(budgetId),
|
|
54
|
+
fetchDelta: (knowledge) => ynabAPI.budgets.getBudgetById(budgetId, knowledge),
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Accounts API
|
|
58
|
+
await verifySimpleEndpoint({
|
|
59
|
+
name: 'accounts.getAccounts',
|
|
60
|
+
signature: 'getAccounts(budgetId, lastKnowledge?)',
|
|
61
|
+
fetchFull: () => ynabAPI.accounts.getAccounts(budgetId),
|
|
62
|
+
fetchDelta: (knowledge) => ynabAPI.accounts.getAccounts(budgetId, knowledge),
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// Categories API
|
|
66
|
+
await verifySimpleEndpoint({
|
|
67
|
+
name: 'categories.getCategories',
|
|
68
|
+
signature: 'getCategories(budgetId, lastKnowledge?)',
|
|
69
|
+
fetchFull: () => ynabAPI.categories.getCategories(budgetId),
|
|
70
|
+
fetchDelta: (knowledge) => ynabAPI.categories.getCategories(budgetId, knowledge),
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// Payees API
|
|
74
|
+
await verifySimpleEndpoint({
|
|
75
|
+
name: 'payees.getPayees',
|
|
76
|
+
signature: 'getPayees(budgetId, lastKnowledge?)',
|
|
77
|
+
fetchFull: () => ynabAPI.payees.getPayees(budgetId),
|
|
78
|
+
fetchDelta: (knowledge) => ynabAPI.payees.getPayees(budgetId, knowledge),
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Months API
|
|
82
|
+
await verifySimpleEndpoint({
|
|
83
|
+
name: 'months.getBudgetMonths',
|
|
84
|
+
signature: 'getBudgetMonths(budgetId, lastKnowledge?)',
|
|
85
|
+
fetchFull: () => ynabAPI.months.getBudgetMonths(budgetId),
|
|
86
|
+
fetchDelta: (knowledge) => ynabAPI.months.getBudgetMonths(budgetId, knowledge),
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// Scheduled Transactions API
|
|
90
|
+
await verifySimpleEndpoint({
|
|
91
|
+
name: 'scheduledTransactions.getScheduledTransactions',
|
|
92
|
+
signature: 'getScheduledTransactions(budgetId, lastKnowledge?)',
|
|
93
|
+
fetchFull: () => ynabAPI.scheduledTransactions.getScheduledTransactions(budgetId),
|
|
94
|
+
fetchDelta: (knowledge) =>
|
|
95
|
+
ynabAPI.scheduledTransactions.getScheduledTransactions(budgetId, knowledge),
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// Transactions API
|
|
99
|
+
try {
|
|
100
|
+
const full = await ynabAPI.transactions.getTransactions(budgetId);
|
|
101
|
+
const knowledge = full?.data?.server_knowledge;
|
|
102
|
+
if (typeof knowledge !== 'number') {
|
|
103
|
+
throw new Error('Response missing server_knowledge');
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
let supported = false;
|
|
107
|
+
let notes = '';
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
await ynabAPI.transactions.getTransactions(budgetId, undefined, undefined, knowledge);
|
|
111
|
+
supported = true;
|
|
112
|
+
notes = 'Signature: (budgetId, sinceDate?, type?, lastKnowledge?)';
|
|
113
|
+
} catch (error) {
|
|
114
|
+
notes = 'Failed with lastKnowledge as 4th parameter';
|
|
115
|
+
throw error;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
recordResult('transactions.getTransactions', notes, supported, `server_knowledge=${knowledge}`);
|
|
119
|
+
} catch (error) {
|
|
120
|
+
recordResult(
|
|
121
|
+
'transactions.getTransactions',
|
|
122
|
+
'getTransactions(budgetId, since?, type?, lastKnowledge?)',
|
|
123
|
+
false,
|
|
124
|
+
'',
|
|
125
|
+
error,
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
console.log('\nSummary:\n');
|
|
130
|
+
for (const row of results) {
|
|
131
|
+
console.log(
|
|
132
|
+
`${row.supported ? 'ā' : 'ā'} ${row.name} -> ${row.supported ? 'supports delta' : 'no delta'} (${row.signature})`,
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
main().catch((error) => {
|
|
138
|
+
console.error('Verification failed:', error);
|
|
139
|
+
process.exit(1);
|
|
140
|
+
});
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manual test script for recommendation engine
|
|
3
|
+
* Tests the EvoCarShare scenario from user feedback
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { analyzeReconciliation } from '../src/tools/reconciliation/analyzer.js';
|
|
7
|
+
import { DEFAULT_MATCHING_CONFIG } from '../src/tools/reconciliation/types.js';
|
|
8
|
+
|
|
9
|
+
// Test data from user's scenario
|
|
10
|
+
const csvContent = `Date,Description,Amount
|
|
11
|
+
2024-10-30,EvoCarShare,22.22`;
|
|
12
|
+
|
|
13
|
+
const ynabTransactions = []; // No YNAB transactions
|
|
14
|
+
|
|
15
|
+
const analysis = analyzeReconciliation(
|
|
16
|
+
csvContent,
|
|
17
|
+
undefined,
|
|
18
|
+
ynabTransactions,
|
|
19
|
+
122.22, // Statement balance
|
|
20
|
+
DEFAULT_MATCHING_CONFIG,
|
|
21
|
+
'USD',
|
|
22
|
+
'test-account',
|
|
23
|
+
'test-budget',
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
console.log('=== RECONCILIATION ANALYSIS ===');
|
|
27
|
+
console.log(`On Track: ${analysis.balance_info.on_track}`);
|
|
28
|
+
console.log(`Discrepancy: ${analysis.balance_info.discrepancy.value_display}`);
|
|
29
|
+
console.log(`\n=== RECOMMENDATIONS (${analysis.recommendations?.length || 0}) ===`);
|
|
30
|
+
|
|
31
|
+
if (analysis.recommendations && analysis.recommendations.length > 0) {
|
|
32
|
+
for (const rec of analysis.recommendations) {
|
|
33
|
+
console.log(`\n[${rec.priority.toUpperCase()}] ${rec.message}`);
|
|
34
|
+
console.log(` Type: ${rec.action_type}`);
|
|
35
|
+
console.log(` Confidence: ${(rec.confidence * 100).toFixed(0)}%`);
|
|
36
|
+
console.log(` Reason: ${rec.reason}`);
|
|
37
|
+
console.log(` Impact: ${rec.estimated_impact.value_display}`);
|
|
38
|
+
|
|
39
|
+
if (rec.action_type === 'create_transaction') {
|
|
40
|
+
console.log(` Parameters:`);
|
|
41
|
+
console.log(` - Date: ${rec.parameters.date}`);
|
|
42
|
+
console.log(` - Amount: $${(rec.parameters.amount / 1000).toFixed(2)}`);
|
|
43
|
+
console.log(` - Payee: ${rec.parameters.payee_name}`);
|
|
44
|
+
console.log(` - Cleared: ${rec.parameters.cleared}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
console.log('\nā
All checks passed!');
|
|
49
|
+
console.log('Recommendation engine is working correctly.');
|
|
50
|
+
} else {
|
|
51
|
+
console.log('ā No recommendations generated!');
|
|
52
|
+
process.exit(1);
|
|
53
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { handleCreateTransaction } from '../src/tools/transactionTools.js';
|
|
2
|
+
import { responseFormatter } from '../src/server/responseFormatter.js';
|
|
3
|
+
|
|
4
|
+
const mockAPI: any = {
|
|
5
|
+
transactions: {
|
|
6
|
+
createTransaction: async (_budgetId: string, _payload: any) => ({
|
|
7
|
+
data: {
|
|
8
|
+
transaction: {
|
|
9
|
+
id: 'transaction-3',
|
|
10
|
+
date: '2024-01-17',
|
|
11
|
+
amount: -2500,
|
|
12
|
+
memo: 'Test transaction',
|
|
13
|
+
cleared: 'uncleared',
|
|
14
|
+
approved: true,
|
|
15
|
+
flag_color: null,
|
|
16
|
+
account_id: 'test-account',
|
|
17
|
+
payee_id: null,
|
|
18
|
+
category_id: 'category-1',
|
|
19
|
+
transfer_account_id: null,
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
}),
|
|
23
|
+
},
|
|
24
|
+
accounts: {
|
|
25
|
+
getAccountById: async (_budgetId: string, _accountId: string) => ({
|
|
26
|
+
data: {
|
|
27
|
+
account: {
|
|
28
|
+
id: 'test-account',
|
|
29
|
+
balance: 1000,
|
|
30
|
+
cleared_balance: 1000,
|
|
31
|
+
uncleared_balance: 0,
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
}),
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
(async () => {
|
|
39
|
+
const result = await handleCreateTransaction(mockAPI, {
|
|
40
|
+
budget_id: 'test-budget',
|
|
41
|
+
account_id: 'test-account',
|
|
42
|
+
amount: -2500,
|
|
43
|
+
date: '2024-01-17',
|
|
44
|
+
memo: 'Test transaction',
|
|
45
|
+
cleared: 'uncleared',
|
|
46
|
+
});
|
|
47
|
+
console.log('result', result);
|
|
48
|
+
})();
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Environment Variable Validation Script
|
|
5
|
+
* Validates required environment variables for YNAB MCP Server
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { config } from 'dotenv';
|
|
9
|
+
import { fileURLToPath } from 'url';
|
|
10
|
+
import { dirname } from 'path';
|
|
11
|
+
|
|
12
|
+
// Load environment variables from .env file
|
|
13
|
+
config();
|
|
14
|
+
|
|
15
|
+
// Allow CI builds to skip strict validation when packaging artifacts
|
|
16
|
+
if (process.env['SKIP_ENV_VALIDATION'] === 'true') {
|
|
17
|
+
console.log('Skipping environment validation (SKIP_ENV_VALIDATION=true)');
|
|
18
|
+
process.exit(0);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
22
|
+
const __dirname = dirname(__filename);
|
|
23
|
+
|
|
24
|
+
const requiredEnvVars = [
|
|
25
|
+
{
|
|
26
|
+
name: 'YNAB_ACCESS_TOKEN',
|
|
27
|
+
description: 'YNAB Personal Access Token',
|
|
28
|
+
validation: (value) => {
|
|
29
|
+
if (!value) return 'YNAB_ACCESS_TOKEN is required';
|
|
30
|
+
if (typeof value !== 'string') return 'YNAB_ACCESS_TOKEN must be a string';
|
|
31
|
+
if (value.length < 10) return 'YNAB_ACCESS_TOKEN appears to be too short';
|
|
32
|
+
return null;
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
const optionalEnvVars = [
|
|
38
|
+
{
|
|
39
|
+
name: 'NODE_ENV',
|
|
40
|
+
description: 'Node.js environment (development, production, test)',
|
|
41
|
+
default: 'development',
|
|
42
|
+
validation: (value) => {
|
|
43
|
+
const validEnvs = ['development', 'production', 'test'];
|
|
44
|
+
if (value && !validEnvs.includes(value)) {
|
|
45
|
+
return `NODE_ENV must be one of: ${validEnvs.join(', ')}`;
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: 'LOG_LEVEL',
|
|
52
|
+
description: 'Logging level (error, warn, info, debug)',
|
|
53
|
+
default: 'info',
|
|
54
|
+
validation: (value) => {
|
|
55
|
+
const validLevels = ['error', 'warn', 'info', 'debug'];
|
|
56
|
+
if (value && !validLevels.includes(value)) {
|
|
57
|
+
return `LOG_LEVEL must be one of: ${validLevels.join(', ')}`;
|
|
58
|
+
}
|
|
59
|
+
return null;
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
];
|
|
63
|
+
|
|
64
|
+
function validateEnvironment() {
|
|
65
|
+
console.log('š Validating environment variables...\n');
|
|
66
|
+
|
|
67
|
+
let hasErrors = false;
|
|
68
|
+
const warnings = [];
|
|
69
|
+
|
|
70
|
+
// Validate required environment variables
|
|
71
|
+
for (const envVar of requiredEnvVars) {
|
|
72
|
+
const value = process.env[envVar.name];
|
|
73
|
+
const error = envVar.validation(value);
|
|
74
|
+
|
|
75
|
+
if (error) {
|
|
76
|
+
console.error(`ā ${envVar.name}: ${error}`);
|
|
77
|
+
console.error(` Description: ${envVar.description}\n`);
|
|
78
|
+
hasErrors = true;
|
|
79
|
+
} else {
|
|
80
|
+
console.log(`ā
${envVar.name}: Valid`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Validate optional environment variables
|
|
85
|
+
for (const envVar of optionalEnvVars) {
|
|
86
|
+
const value = process.env[envVar.name];
|
|
87
|
+
|
|
88
|
+
if (!value) {
|
|
89
|
+
warnings.push(`ā ļø ${envVar.name}: Not set (using default: ${envVar.default})`);
|
|
90
|
+
warnings.push(` Description: ${envVar.description}`);
|
|
91
|
+
} else {
|
|
92
|
+
const error = envVar.validation(value);
|
|
93
|
+
if (error) {
|
|
94
|
+
console.error(`ā ${envVar.name}: ${error}`);
|
|
95
|
+
console.error(` Description: ${envVar.description}\n`);
|
|
96
|
+
hasErrors = true;
|
|
97
|
+
} else {
|
|
98
|
+
console.log(`ā
${envVar.name}: ${value}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Display warnings
|
|
104
|
+
if (warnings.length > 0) {
|
|
105
|
+
console.log('\nWarnings:');
|
|
106
|
+
warnings.forEach((warning) => console.log(warning));
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (hasErrors) {
|
|
110
|
+
console.error('\nā Environment validation failed. Please fix the errors above.');
|
|
111
|
+
process.exit(1);
|
|
112
|
+
} else {
|
|
113
|
+
console.log('\nā
Environment validation passed!');
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Run validation if this script is executed directly
|
|
118
|
+
if (process.argv[1] === __filename) {
|
|
119
|
+
validateEnvironment();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export { validateEnvironment };
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Build Verification Script
|
|
5
|
+
* Verifies that the build output is correct and complete
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
import { fileURLToPath } from 'url';
|
|
11
|
+
import { dirname } from 'path';
|
|
12
|
+
|
|
13
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
14
|
+
const __dirname = dirname(__filename);
|
|
15
|
+
|
|
16
|
+
const DIST_DIR = path.join(__dirname, '..', 'dist');
|
|
17
|
+
const REQUIRED_FILES = [
|
|
18
|
+
'index.js',
|
|
19
|
+
'index.d.ts',
|
|
20
|
+
'server/YNABMCPServer.js',
|
|
21
|
+
'server/YNABMCPServer.d.ts',
|
|
22
|
+
'tools/budgetTools.js',
|
|
23
|
+
'tools/budgetTools.d.ts',
|
|
24
|
+
'tools/accountTools.js',
|
|
25
|
+
'tools/accountTools.d.ts',
|
|
26
|
+
'tools/transactionTools.js',
|
|
27
|
+
'tools/transactionTools.d.ts',
|
|
28
|
+
'tools/categoryTools.js',
|
|
29
|
+
'tools/categoryTools.d.ts',
|
|
30
|
+
'tools/payeeTools.js',
|
|
31
|
+
'tools/payeeTools.d.ts',
|
|
32
|
+
'tools/monthTools.js',
|
|
33
|
+
'tools/monthTools.d.ts',
|
|
34
|
+
'tools/utilityTools.js',
|
|
35
|
+
'tools/utilityTools.d.ts',
|
|
36
|
+
'types/index.js',
|
|
37
|
+
'types/index.d.ts',
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
function verifyBuild() {
|
|
41
|
+
console.log('š Verifying build output...\n');
|
|
42
|
+
|
|
43
|
+
// Check if dist directory exists
|
|
44
|
+
if (!fs.existsSync(DIST_DIR)) {
|
|
45
|
+
console.error('ā Build directory does not exist:', DIST_DIR);
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
let missingFiles = [];
|
|
50
|
+
let foundFiles = [];
|
|
51
|
+
|
|
52
|
+
// Check for required files
|
|
53
|
+
for (const file of REQUIRED_FILES) {
|
|
54
|
+
const filePath = path.join(DIST_DIR, file);
|
|
55
|
+
if (fs.existsSync(filePath)) {
|
|
56
|
+
foundFiles.push(file);
|
|
57
|
+
console.log(`ā
${file}`);
|
|
58
|
+
} else {
|
|
59
|
+
missingFiles.push(file);
|
|
60
|
+
console.error(`ā Missing: ${file}`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Check main entry point
|
|
65
|
+
const mainEntry = path.join(DIST_DIR, 'index.js');
|
|
66
|
+
if (fs.existsSync(mainEntry)) {
|
|
67
|
+
const content = fs.readFileSync(mainEntry, 'utf8');
|
|
68
|
+
if (content.includes('YNABMCPServer')) {
|
|
69
|
+
console.log('ā
Main entry point contains expected exports');
|
|
70
|
+
} else {
|
|
71
|
+
console.error('ā Main entry point missing expected exports');
|
|
72
|
+
missingFiles.push('index.js (invalid content)');
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Check TypeScript declarations
|
|
77
|
+
const hasDeclarations = foundFiles.some((file) => file.endsWith('.d.ts'));
|
|
78
|
+
if (hasDeclarations) {
|
|
79
|
+
console.log('ā
TypeScript declarations generated');
|
|
80
|
+
} else {
|
|
81
|
+
console.error('ā No TypeScript declarations found');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Summary
|
|
85
|
+
console.log(`\nš Build Verification Summary:`);
|
|
86
|
+
console.log(` Found files: ${foundFiles.length}`);
|
|
87
|
+
console.log(` Missing files: ${missingFiles.length}`);
|
|
88
|
+
|
|
89
|
+
if (missingFiles.length > 0) {
|
|
90
|
+
console.error('\nā Build verification failed!');
|
|
91
|
+
console.error('Missing files:');
|
|
92
|
+
missingFiles.forEach((file) => console.error(` - ${file}`));
|
|
93
|
+
process.exit(1);
|
|
94
|
+
} else {
|
|
95
|
+
console.log('\nā
Build verification passed!');
|
|
96
|
+
console.log('All required files are present and valid.');
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Run verification if this script is executed directly
|
|
101
|
+
if (process.argv[1] === __filename) {
|
|
102
|
+
verifyBuild();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export { verifyBuild };
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# PowerShell script to watch for file changes and restart MCP
|
|
2
|
+
param(
|
|
3
|
+
[string]$Path = ".\src",
|
|
4
|
+
[string]$Filter = "*.ts",
|
|
5
|
+
[int]$RestartDelay = 3
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
Write-Host "š Watching for changes in: $Path"
|
|
9
|
+
Write-Host "š Filter: $Filter"
|
|
10
|
+
|
|
11
|
+
$watcher = New-Object System.IO.FileSystemWatcher
|
|
12
|
+
$watcher.Path = Resolve-Path $Path
|
|
13
|
+
$watcher.Filter = $Filter
|
|
14
|
+
$watcher.EnableRaisingEvents = $true
|
|
15
|
+
$watcher.IncludeSubdirectories = $true
|
|
16
|
+
|
|
17
|
+
$action = {
|
|
18
|
+
$path = $Event.SourceEventArgs.FullPath
|
|
19
|
+
$changeType = $Event.SourceEventArgs.ChangeType
|
|
20
|
+
Write-Host "š File $changeType`: $path"
|
|
21
|
+
|
|
22
|
+
# Build the project
|
|
23
|
+
Write-Host "šļø Building project..."
|
|
24
|
+
npm run build
|
|
25
|
+
|
|
26
|
+
if ($LASTEXITCODE -eq 0) {
|
|
27
|
+
Write-Host "ā
Build successful"
|
|
28
|
+
Start-Sleep -Seconds $RestartDelay
|
|
29
|
+
|
|
30
|
+
Write-Host "š Reconnecting to YNAB MCP server..."
|
|
31
|
+
/mcp reconnect ynab-mcp-server
|
|
32
|
+
Start-Sleep -Seconds 1
|
|
33
|
+
/mcp reconnect ynab-mcp-server
|
|
34
|
+
Write-Host "ā
MCP server reconnected"
|
|
35
|
+
} else {
|
|
36
|
+
Write-Host "ā Build failed, skipping MCP restart"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
Register-ObjectEvent -InputObject $watcher -EventName "Changed" -Action $action
|
|
41
|
+
Register-ObjectEvent -InputObject $watcher -EventName "Created" -Action $action
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
Write-Host "ā
File watcher started. Press Ctrl+C to stop."
|
|
45
|
+
while ($true) { Start-Sleep 1 }
|
|
46
|
+
}
|
|
47
|
+
finally {
|
|
48
|
+
$watcher.Dispose()
|
|
49
|
+
Write-Host "š File watcher stopped"
|
|
50
|
+
}
|