@dizzlkheinz/ynab-mcpb 0.16.1 → 0.17.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/.env.example +33 -33
- package/.github/workflows/ci-tests.yml +45 -45
- package/.github/workflows/claude-code-review.yml +57 -57
- package/.github/workflows/claude.yml +50 -50
- package/.github/workflows/full-integration.yml +22 -22
- package/.github/workflows/publish.yml +11 -2
- package/CLAUDE.md +33 -47
- package/README.md +8 -10
- package/dist/bundle/index.cjs +54 -54
- package/dist/server/YNABMCPServer.d.ts +120 -54
- package/dist/server/YNABMCPServer.js +28 -381
- package/dist/server/config.d.ts +2 -0
- package/dist/server/config.js +1 -0
- package/dist/server/securityMiddleware.d.ts +37 -8
- package/dist/tools/accountTools.d.ts +2 -0
- package/dist/tools/accountTools.js +45 -0
- package/dist/tools/adapters.d.ts +12 -0
- package/dist/tools/adapters.js +25 -0
- package/dist/tools/budgetTools.d.ts +2 -0
- package/dist/tools/budgetTools.js +30 -0
- package/dist/tools/categoryTools.d.ts +2 -0
- package/dist/tools/categoryTools.js +45 -0
- package/dist/tools/monthTools.d.ts +2 -0
- package/dist/tools/monthTools.js +32 -0
- package/dist/tools/payeeTools.d.ts +2 -0
- package/dist/tools/payeeTools.js +32 -0
- package/dist/tools/reconciliation/index.d.ts +2 -0
- package/dist/tools/reconciliation/index.js +33 -0
- package/dist/tools/schemas/common.d.ts +3 -0
- package/dist/tools/schemas/common.js +3 -0
- package/dist/tools/schemas/outputs/comparisonOutputs.d.ts +1 -1
- package/dist/tools/schemas/outputs/index.d.ts +2 -2
- package/dist/tools/schemas/outputs/index.js +2 -2
- package/dist/tools/schemas/outputs/utilityOutputs.d.ts +0 -15
- package/dist/tools/schemas/outputs/utilityOutputs.js +0 -9
- package/dist/tools/transactionTools.d.ts +2 -0
- package/dist/tools/transactionTools.js +124 -0
- package/dist/tools/utilityTools.d.ts +2 -7
- package/dist/tools/utilityTools.js +19 -38
- package/dist/types/index.d.ts +1 -0
- package/dist/types/toolRegistration.d.ts +27 -0
- package/dist/types/toolRegistration.js +1 -0
- package/docs/maintainers/npm-publishing.md +27 -0
- package/docs/reference/API.md +15 -70
- package/docs/technical/reconciliation-system-architecture.md +2251 -2251
- package/package.json +6 -6
- package/scripts/analyze-bundle.mjs +41 -41
- package/scripts/generate-mcpb.ps1 +95 -95
- package/scripts/run-domain-integration-tests.js +4 -1
- package/scripts/watch-and-restart.ps1 +49 -49
- package/src/__tests__/comprehensive.integration.test.ts +0 -28
- package/src/__tests__/performance.test.ts +4 -12
- package/src/__tests__/setup.ts +45 -14
- package/src/__tests__/workflows.e2e.test.ts +1 -51
- package/src/server/YNABMCPServer.ts +33 -519
- package/src/server/__tests__/YNABMCPServer.test.ts +0 -1
- package/src/server/__tests__/toolRegistration.test.ts +236 -0
- package/src/server/config.ts +1 -0
- package/src/tools/__tests__/adapters.test.ts +113 -0
- package/src/tools/__tests__/transactionTools.integration.test.ts +63 -3
- package/src/tools/__tests__/utilityTools.integration.test.ts +1 -85
- package/src/tools/__tests__/utilityTools.test.ts +1 -123
- package/src/tools/accountTools.ts +53 -0
- package/src/tools/adapters.ts +74 -0
- package/src/tools/budgetTools.ts +37 -0
- package/src/tools/categoryTools.ts +53 -0
- package/src/tools/monthTools.ts +39 -0
- package/src/tools/payeeTools.ts +39 -0
- package/src/tools/reconciliation/index.ts +45 -0
- package/src/tools/schemas/common.ts +18 -0
- package/src/tools/schemas/outputs/index.ts +0 -3
- package/src/tools/schemas/outputs/utilityOutputs.ts +2 -43
- package/src/tools/toolCategories.ts +0 -1
- package/src/tools/transactionTools.ts +140 -0
- package/src/tools/utilityTools.ts +24 -55
- package/src/types/index.ts +3 -0
- package/src/types/toolRegistration.ts +88 -0
- package/vitest.config.ts +2 -1
- package/.chunkhound.json +0 -11
- package/.code/agents/01a13ef4-3f23-4f52-b33b-3585b73cfa60/error.txt +0 -3
- package/.code/agents/084fd32f-e298-4728-9103-a78d7dc39613/error.txt +0 -3
- package/.code/agents/0fed51e1-a943-4b97-a2a8-a6f0f27c844d/status.txt +0 -1
- package/.code/agents/1059b6bd-5ccd-4d83-a12c-7c9d89137399/error.txt +0 -5
- package/.code/agents/110/exec-call_F9BDNG7JfxKkq7Vc8ESAvdft.txt +0 -1569
- package/.code/agents/11ebcef3-b13f-4e44-ad80-d94a866804b7/error.txt +0 -3
- package/.code/agents/1398/exec-call_CjItcWMU1G6JoPshX62QvpaR.txt +0 -2832
- package/.code/agents/1398/exec-call_SUVq2ivmONQ5LMCmd7ngmOqr.txt +0 -2709
- package/.code/agents/1398/exec-call_SdNY4NOffdcC5pRYjVXHjPCK.txt +0 -2832
- package/.code/agents/1398/exec-call_qblJo9et1gsFFB63TtLOiji2.txt +0 -2832
- package/.code/agents/1398/exec-call_zaRrzlGz7GJcNzVfkAmML7Zg.txt +0 -2709
- package/.code/agents/171834fd-5905-42fc-bbcc-2c755145b0fc/status.txt +0 -1
- package/.code/agents/1724/exec-call_HvHQe0w5CCG3T7Q3ULT6MO3g.txt +0 -5217
- package/.code/agents/1724/exec-call_QwUNESVzfxxk78K1frh1Vahb.txt +0 -2594
- package/.code/agents/1724/exec-call_aJ1Xwz71XmIpD4SBxSHERzLe.txt +0 -2594
- package/.code/agents/1d7d7ab7-7473-4b69-8b97-6e914f56056a/result.txt +0 -231
- package/.code/agents/210/exec-call_0tQCsKNJ1WTuIchb8wlcFJpW.txt +0 -2590
- package/.code/agents/210/exec-call_8ZlY9cUc8Ft1twi4ch8UJ6IN.txt +0 -5195
- package/.code/agents/2188/exec-call_5HqayBxIteJtoI8oPTiLWgvJ.txt +0 -286
- package/.code/agents/2188/exec-call_XRbBKBq3adZe6dcppAvQtM7G.txt +0 -218
- package/.code/agents/2188/exec-call_ehA0SjpYtrUi6GJXmibLjp4i.txt +0 -180
- package/.code/agents/21902821-ecaf-4759-bb9d-222b90921af5/error.txt +0 -3
- package/.code/agents/232073be-aa0e-46da-b478-5b64dbf03cf5/status.txt +0 -1
- package/.code/agents/234ff534-2336-4771-a8d9-aa04421a63be/result.txt +0 -747
- package/.code/agents/253e2695-dc36-4022-b436-27655e0fc6c7/status.txt +0 -1
- package/.code/agents/2583/exec-call_M59I4eDjpjlBIWBiSxyS0YlJ.txt +0 -2594
- package/.code/agents/2583/exec-call_usLRGh7OhVHtsRBL4iUwRhjq.txt +0 -2594
- package/.code/agents/292aa3ff-dbab-470f-97c9-e7e8fd65e0db/result.txt +0 -144
- package/.code/agents/3134/exec-call_IgCAMGx19lWfuo8zfYIt5FFC.txt +0 -416
- package/.code/agents/3134/exec-call_IxvLR2Oo7kba2QTsI1gHVko8.txt +0 -2590
- package/.code/agents/3134/exec-call_jYvc8hksZChSiysbzKjl2ZbB.txt +0 -2590
- package/.code/agents/329/exec-call_4QdP3SfSO7HGPCwVcqZIth6s.txt +0 -2590
- package/.code/agents/472/exec-call_4AxzEEcWwkKhpqRB3bE8Ha4L.txt +0 -790
- package/.code/agents/472/exec-call_CB3LPYQA8QIZRi8I6kj4J17A.txt +0 -766
- package/.code/agents/472/exec-call_YeoUWvaFoktay2nqVUsa9KKX.txt +0 -790
- package/.code/agents/472/exec-call_jPWgKVquBBXTg0T3Lks5ZfkK.txt +0 -2594
- package/.code/agents/472/exec-call_qBkvunpGBDEHph2jPmTwtcsb.txt +0 -1000
- package/.code/agents/472/exec-call_v0ffRV1p0kTckBmJPzzHAEy0.txt +0 -3489
- package/.code/agents/472/exec-call_xAX5FXqWIlk02d9WubHbHWh8.txt +0 -766
- package/.code/agents/5346/exec-call_9q0muXUuLaucwEqI51Pt7idT.txt +0 -2594
- package/.code/agents/5346/exec-call_B2el3B79rVkq9LhWTI2VYlz7.txt +0 -2456
- package/.code/agents/5346/exec-call_BfX08f02qkZI9uJD5dvCvuoj.txt +0 -2594
- package/.code/agents/543328d0-61d6-4fd1-a723-bb168656e2e2/error.txt +0 -18
- package/.code/agents/5580c02c-1383-4d18-9cbd-cc8a06e3408d/result.txt +0 -48
- package/.code/agents/60ce1a22-5126-44b2-b977-1d5b56142a7b/status.txt +0 -1
- package/.code/agents/6215d9db-7fa9-4429-aeec-3835c3212291/error.txt +0 -1
- package/.code/agents/6743db55-30e5-4b4e-9366-a8214fc7f714/error.txt +0 -1
- package/.code/agents/6bf9591b-b9c9-422c-b0a5-e968c7d8422a/status.txt +0 -1
- package/.code/agents/7/exec-call_eww3GfdEiJZx61sJEQ9wNmt3.txt +0 -1271
- package/.code/agents/70/exec-call_owUtDMYiVgqDf8vsz1i32PFf.txt +0 -1570
- package/.code/agents/8/exec-call_UtrjAcLbhYLatxR4O97fZgnm.txt +0 -2590
- package/.code/agents/82490bc9-f34e-4b1b-8a8e-bccc2e6254f5/error.txt +0 -3
- package/.code/agents/841/exec-call_7nTNhSBCNjTDUIJv7py6CepO.txt +0 -3299
- package/.code/agents/841/exec-call_TLI0yUdUijuUAvI4o3DXEvHO.txt +0 -3299
- package/.code/agents/9/exec-call_XaABQT1hIlRpnKZ2uyBMWsTC.txt +0 -1882
- package/.code/agents/941/exec-call_GuGHRx7NNXWIDAnxUG2NEWPa.txt +0 -2594
- package/.code/agents/95d9fbab-19a2-48af-83f9-c792566a347f/error.txt +0 -1
- package/.code/agents/b0098cb8-cb32-4ada-9bc4-37c587518896/result.txt +0 -170
- package/.code/agents/b4fe59a4-81df-42e2-a112-0153e504faca/error.txt +0 -1
- package/.code/agents/bf4ce152-f623-49d7-aa52-c18631625c3c/error.txt +0 -3
- package/.code/agents/d7d1db75-d7eb-468e-adea-4ef4d916d187/status.txt +0 -1
- package/.code/agents/e2baa9c8-bac3-49e3-a39d-024333e6a990/status.txt +0 -1
- package/.code/agents/e350b8c3-8483-408c-b2bb-94515f492a11/error.txt +0 -3
- package/.code/agents/e63f9919-719f-4ad0-bccf-01b1a596e1e9/status.txt +0 -1
- package/.code/agents/e71695a8-3044-478d-8f12-ed13d02884c7/status.txt +0 -1
- package/.code/agents/f95b7464-3e25-4897-b153-c8dfd63fd605/error.txt +0 -5
- package/.code/agents/fa3c5ddf-cdf7-47a2-930a-b806c6363689/status.txt +0 -1
- package/.github/workflows/pr-description-check.yml +0 -88
- package/AGENTS.md +0 -36
- package/NUL +0 -1
- package/docs/README.md +0 -72
- package/docs/getting-started/CONFIGURATION.md +0 -175
- package/docs/getting-started/INSTALLATION.md +0 -333
- package/docs/getting-started/QUICKSTART.md +0 -282
- package/docs/guides/ARCHITECTURE.md +0 -533
- package/docs/guides/DEPLOYMENT.md +0 -189
- package/docs/guides/INTEGRATION_TESTING.md +0 -730
- package/docs/guides/TESTING.md +0 -591
- package/docs/reconciliation-flow.md +0 -83
- package/docs/reference/EXAMPLES.md +0 -946
- package/docs/reference/TOOLS.md +0 -348
- package/docs/reference/TROUBLESHOOTING.md +0 -481
- package/package.json.tmp +0 -105
- package/temp-recon.ts +0 -126
- package/test-exports/ynab_account_e9ddc2a6_minimal_1items_2025-11-19_09-04-53.json +0 -23
- package/test-exports/ynab_account_e9ddc2a6_minimal_1items_2025-11-19_10-37-42.json +0 -23
- package/test-exports/ynab_account_e9ddc2a6_minimal_4items_2025-11-19_09-02-09.json +0 -44
- package/test-exports/ynab_account_e9ddc2a6_minimal_6items_2025-11-19_10-37-52.json +0 -58
- package/test-exports/ynab_since_2025-10-16_account_53298e13_238items_2025-11-28_13-46-20.json +0 -3662
- package/test-exports/ynab_since_2025-11-01_account_4c18e9f0_minimal_14items_2025-11-16_10-07-10.json +0 -115
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
Note: I’m running in a read‑only sandbox with no escalation, so I can’t execute `node "$HOME/.codex/superpowers/.codex/superpowers-codex" bootstrap` here; you’ll need to run that manually outside this environment.
|
|
2
|
-
|
|
3
|
-
Below is a concrete implementation plan for the next iteration, focused on tightening type safety for mutation dry‑run outputs and exercising them via tests. Tasks are sized to ~2–5 minutes each and follow a TDD flow.
|
|
4
|
-
|
|
5
|
-
**Iteration Theme**
|
|
6
|
-
|
|
7
|
-
- Strengthen type safety for transaction mutation dry‑run responses by replacing `z.record(z.string(), z.unknown())` with strongly‑typed request schemas, and ensure handlers + tests are aligned.
|
|
8
|
-
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
**Phase 0 – Context & Scoping**
|
|
12
|
-
|
|
13
|
-
- Skim `SCHEMA_IMPROVEMENT_SUMMARY.md` again to align with the existing discriminated‑union pattern used for reconciliation outputs.
|
|
14
|
-
- Review current output schemas in `src/tools/schemas/outputs/transactionMutationOutputs.ts` (dry‑run branches for `CreateTransactionOutputSchema`, `UpdateTransactionOutputSchema`, `DeleteTransactionOutputSchema`).
|
|
15
|
-
- Review corresponding handlers in `src/tools/transactionTools.ts` (dry‑run branches in `handleCreateTransaction`, `handleUpdateTransaction`, `handleDeleteTransaction`).
|
|
16
|
-
- Review existing tests touching these areas:
|
|
17
|
-
- Schema tests: `src/tools/schemas/outputs/__tests__/transactionMutationSchemas.test.ts`
|
|
18
|
-
- Tool unit tests: `src/tools/__tests__/transactionTools.test.ts`
|
|
19
|
-
- E2E transaction workflow: `src/__tests__/workflows.e2e.test.ts`
|
|
20
|
-
|
|
21
|
-
---
|
|
22
|
-
|
|
23
|
-
**Phase 1 – TDD for New Dry‑Run Request Schemas (Schemas Layer)**
|
|
24
|
-
|
|
25
|
-
1. In `src/tools/schemas/outputs/transactionMutationOutputs.ts`, identify the three dry‑run `request` fields that still use `z.record(z.string(), z.unknown())`.
|
|
26
|
-
2. Design target request shapes:
|
|
27
|
-
- `CreateTransactionDryRunRequestSchema`: mirror `CreateTransactionSchema` from `src/tools/transactionTools.ts` but omit `budget_id` and `dry_run`, and keep only fields that actually affect the YNAB API call (`account_id`, `amount`, `date`, `payee_*`, `category_id`, `memo`, `cleared`, `approved`, `flag_color`, `import_id`, `subtransactions`).
|
|
28
|
-
- `UpdateTransactionDryRunRequestSchema`: mirror `UpdateTransactionSchema` but omit `budget_id`, `dry_run`; keep `transaction_id` plus the updatable fields (`account_id`, `amount`, `date`, `payee_*`, `category_id`, `memo`, `cleared`, `approved`, `flag_color`).
|
|
29
|
-
- `DeleteTransactionDryRunRequestSchema`: mirror `DeleteTransactionSchema` but omit `budget_id`, `dry_run`; keep `transaction_id`.
|
|
30
|
-
3. In `src/tools/schemas/outputs/__tests__/transactionMutationSchemas.test.ts`, add new `describe` blocks (or extend existing ones) for:
|
|
31
|
-
- `CreateTransactionOutputSchema` dry‑run branch:
|
|
32
|
-
- Accepts a `request` object matching `CreateTransactionDryRunRequestSchema` (no `budget_id`, no `dry_run`).
|
|
33
|
-
- Rejects payloads where `request` is missing required fields (e.g., no `account_id`, no `date`, or missing `amount`).
|
|
34
|
-
- Rejects payloads where `request` includes obviously wrong shapes (e.g., non‑ISO `date`), using schema’s existing validation.
|
|
35
|
-
- `UpdateTransactionOutputSchema` dry‑run branch:
|
|
36
|
-
- Accepts minimal valid request (`transaction_id` only) and one with optional fields.
|
|
37
|
-
- Rejects requests missing `transaction_id`.
|
|
38
|
-
- `DeleteTransactionOutputSchema` dry‑run branch:
|
|
39
|
-
- Accepts `{ transaction_id: '...' }` and no extra required fields.
|
|
40
|
-
- Rejects requests missing `transaction_id`.
|
|
41
|
-
4. Add negative tests in the same file asserting that generic `z.record`‑style payloads (e.g., arbitrary key/value maps or requests including `budget_id`, `dry_run`) are rejected by the new schemas.
|
|
42
|
-
5. Run only the schema tests to see them fail initially:
|
|
43
|
-
- `npm run test:unit -- src/tools/schemas/outputs/__tests__/transactionMutationSchemas.test.ts`
|
|
44
|
-
|
|
45
|
-
---
|
|
46
|
-
|
|
47
|
-
**Phase 2 – Implement Strongly‑Typed Dry‑Run Request Schemas**
|
|
48
|
-
|
|
49
|
-
6. In `src/tools/schemas/outputs/transactionMutationOutputs.ts`, define:
|
|
50
|
-
- `CreateTransactionDryRunRequestSchema` using `z.object({ ... })` or `CreateTransactionSchema.omit({ budget_id: true, dry_run: true })` (import `CreateTransactionSchema` if you prefer reuse).
|
|
51
|
-
- `UpdateTransactionDryRunRequestSchema` similarly from `UpdateTransactionSchema` or a dedicated `z.object`.
|
|
52
|
-
- `DeleteTransactionDryRunRequestSchema` similarly from `DeleteTransactionSchema`.
|
|
53
|
-
- Export TypeScript types using `z.infer<...>` for each new schema.
|
|
54
|
-
7. Replace the dry‑run `request` fields:
|
|
55
|
-
- `CreateTransactionOutputSchema` dry‑run branch: `request: CreateTransactionDryRunRequestSchema`.
|
|
56
|
-
- `UpdateTransactionOutputSchema` dry‑run branch: `request: UpdateTransactionDryRunRequestSchema`.
|
|
57
|
-
- `DeleteTransactionOutputSchema` dry‑run branch: `request: DeleteTransactionDryRunRequestSchema`.
|
|
58
|
-
8. Ensure unions remain backward compatible:
|
|
59
|
-
- Keep the non‑dry‑run branches unchanged.
|
|
60
|
-
- Preserve `.passthrough()` where it’s used for forward‑compatible metadata.
|
|
61
|
-
9. Re‑run the schema tests:
|
|
62
|
-
- `npm run test:unit -- src/tools/schemas/outputs/__tests__/transactionMutationSchemas.test.ts`
|
|
63
|
-
- Fix any mismatches between tests and actual schema shapes until green.
|
|
64
|
-
|
|
65
|
-
---
|
|
66
|
-
|
|
67
|
-
**Phase 3 – TDD for Handler Output Shape Changes (Tools Layer)**
|
|
68
|
-
|
|
69
|
-
10. In `src/tools/__tests__/transactionTools.test.ts`, locate the `handleCreateTransaction` dry‑run test (`should not invalidate cache on dry_run transaction creation`).
|
|
70
|
-
11. Update that test so it asserts:
|
|
71
|
-
- `parsedContent.dry_run === true` and `parsedContent.action === 'create_transaction'`.
|
|
72
|
-
- `parsedContent.request`:
|
|
73
|
-
- Does not include `budget_id` or `dry_run`.
|
|
74
|
-
- Contains only the transaction fields expected by `CreateTransactionDryRunRequestSchema`.
|
|
75
|
-
12. Add a new unit test for `handleUpdateTransaction` dry‑run behavior:
|
|
76
|
-
- Call `handleUpdateTransaction(mockYnabAPI, { budget_id, transaction_id, amount, dry_run: true })`.
|
|
77
|
-
- Assert:
|
|
78
|
-
- No API calls are made.
|
|
79
|
-
- Parsed JSON has `dry_run: true`, `action: 'update_transaction'`.
|
|
80
|
-
- `request` includes `transaction_id` and any optional fields you passed, but not `budget_id` or `dry_run`.
|
|
81
|
-
13. Add a complementary unit test for `handleDeleteTransaction` dry‑run behavior:
|
|
82
|
-
- Call `handleDeleteTransaction(mockYnabAPI, { budget_id, transaction_id, dry_run: true })`.
|
|
83
|
-
- Assert:
|
|
84
|
-
- No API calls are made.
|
|
85
|
-
- Parsed JSON has `dry_run: true`, `action: 'delete_transaction'`.
|
|
86
|
-
- `request` is `{ transaction_id: '...' }` only.
|
|
87
|
-
14. Run only the transaction tool unit tests to see failures before implementation:
|
|
88
|
-
- `npm run test:unit -- src/tools/__tests__/transactionTools.test.ts`
|
|
89
|
-
|
|
90
|
-
---
|
|
91
|
-
|
|
92
|
-
**Phase 4 – Implement Handler Changes to Match New Schemas**
|
|
93
|
-
|
|
94
|
-
15. In `src/tools/transactionTools.ts`, update the dry‑run branch of `handleCreateTransaction`:
|
|
95
|
-
- Instead of `request: params`, construct a new object that:
|
|
96
|
-
- Copies only transaction‑related fields: `account_id`, `amount`, `date`, `payee_*`, `category_id`, `memo`, `cleared`, `approved`, `flag_color`, `import_id`, `subtransactions`.
|
|
97
|
-
- Excludes `budget_id` and `dry_run`.
|
|
98
|
-
- Ensure this object’s shape matches `CreateTransactionDryRunRequestSchema`.
|
|
99
|
-
16. Update the dry‑run branch of `handleUpdateTransaction`:
|
|
100
|
-
- Build `request` containing `transaction_id` plus any provided update fields (`account_id`, `amount`, `date`, etc.).
|
|
101
|
-
- Exclude `budget_id` and `dry_run` from the `request` object.
|
|
102
|
-
17. Update the dry‑run branch of `handleDeleteTransaction`:
|
|
103
|
-
- Set `request: { transaction_id: params.transaction_id }` (and nothing else).
|
|
104
|
-
18. Re‑run the relevant unit tests:
|
|
105
|
-
- `npm run test:unit -- src/tools/__tests__/transactionTools.test.ts`
|
|
106
|
-
- Iterate until the dry‑run shape tests pass.
|
|
107
|
-
|
|
108
|
-
---
|
|
109
|
-
|
|
110
|
-
**Phase 5 – Integration & E2E Validation**
|
|
111
|
-
|
|
112
|
-
19. In `src/tools/__tests__/transactionTools.integration.test.ts`, optionally add a focused integration test (if not already covered) that:
|
|
113
|
-
- Calls each of the three handlers in dry‑run mode with realistic params.
|
|
114
|
-
- Parses the output and asserts it validates against `CreateTransactionOutputSchema`, `UpdateTransactionOutputSchema`, `DeleteTransactionOutputSchema` using the shared validation helper (if available).
|
|
115
|
-
20. In `src/__tests__/workflows.e2e.test.ts`, add a small E2E segment under “Complete Transaction Management Workflow” that:
|
|
116
|
-
- Calls `ynab:create_transaction` with `dry_run: true`.
|
|
117
|
-
- Uses `validateOutputSchema(server, 'create_transaction', result)` and asserts `valid === true`.
|
|
118
|
-
- Asserts the `data` payload contains the new, typed `request` shape (no `budget_id` / `dry_run` in `request`).
|
|
119
|
-
21. Run narrower test suites first:
|
|
120
|
-
- `npm run test:unit`
|
|
121
|
-
- `npm run test:integration`
|
|
122
|
-
22. When green, run the full test suite + build to ensure no regressions:
|
|
123
|
-
- `npm test`
|
|
124
|
-
- `npm run lint`
|
|
125
|
-
- `npm run build`
|
|
126
|
-
- Optionally: `npm run build:prod` and `npm run package:mcpb` if this will cut a new release.
|
|
127
|
-
|
|
128
|
-
---
|
|
129
|
-
|
|
130
|
-
**Phase 6 – Documentation & Release Hygiene**
|
|
131
|
-
|
|
132
|
-
23. Update any internal docs referencing dry‑run shapes:
|
|
133
|
-
- Check `docs/reference/API.md` and any tool‑specific docs for transaction mutation tools; adjust examples so `request` shows the new, typed payloads.
|
|
134
|
-
24. In `CHANGELOG.md`, add an entry for the next patch version (e.g., `0.13.5`) summarizing:
|
|
135
|
-
- “Improve transaction mutation dry‑run output typing for create/update/delete_transaction tools; no breaking changes to success payloads.”
|
|
136
|
-
25. Run quick formatting checks:
|
|
137
|
-
- `npm run format:check`
|
|
138
|
-
- `npm run lint` (again if needed).
|
|
139
|
-
26. If everything is green, prepare the PR:
|
|
140
|
-
- Ensure `TESTING_NOTES.md` / `.pr-description.md` mention:
|
|
141
|
-
- Tests run (`npm run test:unit`, `npm run test:integration`, `npm test`, `npm run build`).
|
|
142
|
-
- That changes are backward‑compatible for non‑dry‑run responses and tool contracts.
|
|
143
|
-
|
|
144
|
-
If you’d like, I can next draft the actual Zod schema snippets and handler code for these changes so you can drop them into the repo.
|
|
@@ -1,416 +0,0 @@
|
|
|
1
|
-
src\types\reconciliation.ts:4: * AMOUNTS ARE IN MILLIUNITS (integers, 1000 = $1.00).
|
|
2
|
-
src\types\reconciliation.ts:12: /** Amount in MILLIUNITS (negative = outflow, positive = inflow) */
|
|
3
|
-
src\types\reconciliation.ts:36: * AMOUNTS ARE IN MILLIUNITS - same as YNAB API native format.
|
|
4
|
-
src\types\reconciliation.ts:42: /** Amount in MILLIUNITS (same as YNAB API) */
|
|
5
|
-
src\__tests__\workflows.e2e.test.ts:825: it('should convert amounts between dollars and milliunits', async () => {
|
|
6
|
-
src\__tests__\workflows.e2e.test.ts:828: // Convert dollars to milliunits
|
|
7
|
-
src\__tests__\workflows.e2e.test.ts:829: const toMilliunitsResult = await executeToolCall(server, 'ynab:convert_amount', {
|
|
8
|
-
src\__tests__\workflows.e2e.test.ts:831: to_milliunits: true,
|
|
9
|
-
src\__tests__\workflows.e2e.test.ts:833: const milliunits = parseToolResult(toMilliunitsResult);
|
|
10
|
-
src\__tests__\workflows.e2e.test.ts:835: expect(milliunits.data?.conversion?.converted_amount).toBe(25500);
|
|
11
|
-
src\__tests__\workflows.e2e.test.ts:836: expect(milliunits.data?.conversion?.description).toContain('25500');
|
|
12
|
-
src\__tests__\workflows.e2e.test.ts:837: expect(milliunits.data?.conversion?.to_milliunits).toBe(true);
|
|
13
|
-
src\__tests__\workflows.e2e.test.ts:839: // Convert milliunits to dollars
|
|
14
|
-
src\__tests__\workflows.e2e.test.ts:842: to_milliunits: false,
|
|
15
|
-
src\__tests__\workflows.e2e.test.ts:848: expect(dollars.data?.conversion?.to_milliunits).toBe(false);
|
|
16
|
-
src\__tests__\workflows.e2e.test.ts:1146: { name: 'ynab:convert_amount', args: { amount: 100, to_milliunits: true } },
|
|
17
|
-
src\__tests__\workflows.e2e.test.ts:1629: to_milliunits: true,
|
|
18
|
-
src\server\prompts.ts:154:4. Create the transaction with the correct amount in milliunits (multiply by 1000)
|
|
19
|
-
src\server\prompts.ts:233:Convert milliunits to dollars for easy reading.`,
|
|
20
|
-
src\__tests__\performance.test.ts:629: to_milliunits: true,
|
|
21
|
-
src\__tests__\performance.test.ts:718: executeToolCall(server, 'ynab:convert_amount', { amount: i * 10, to_milliunits: true }),
|
|
22
|
-
src\__tests__\comprehensive.integration.test.ts:53: convertMilliUnitsToCurrencyAmount: vi.fn(
|
|
23
|
-
src\__tests__\comprehensive.integration.test.ts:54: (milliunits: number, currencyDecimalDigits: number = 2) => {
|
|
24
|
-
src\__tests__\comprehensive.integration.test.ts:55: const amount = milliunits / 1000;
|
|
25
|
-
src\__tests__\comprehensive.integration.test.ts:59: convertCurrencyAmountToMilliUnits: vi.fn((amount: number) => Math.round(amount * 1000)),
|
|
26
|
-
src\__tests__\comprehensive.integration.test.ts:68: 'converts milliunits using SDK rounding rules',
|
|
27
|
-
src\__tests__\comprehensive.integration.test.ts:73: expect(utils.convertMilliUnitsToCurrencyAmount(123456, 2)).toBe(123.46);
|
|
28
|
-
src\__tests__\comprehensive.integration.test.ts:74: expect(utils.convertMilliUnitsToCurrencyAmount(123456, 3)).toBe(123.456);
|
|
29
|
-
src\__tests__\comprehensive.integration.test.ts:75: expect(utils.convertMilliUnitsToCurrencyAmount(-98765, 2)).toBe(-98.77);
|
|
30
|
-
src\__tests__\comprehensive.integration.test.ts:756: // Test dollar to milliunits conversion
|
|
31
|
-
src\__tests__\comprehensive.integration.test.ts:757: const toMilliunitsResult = await executeToolCall(server, 'ynab:convert_amount', {
|
|
32
|
-
src\__tests__\comprehensive.integration.test.ts:759: to_milliunits: true,
|
|
33
|
-
src\__tests__\comprehensive.integration.test.ts:761: validateToolResult(toMilliunitsResult);
|
|
34
|
-
src\__tests__\comprehensive.integration.test.ts:763: const toMilli = parseToolResult(toMilliunitsResult);
|
|
35
|
-
src\__tests__\comprehensive.integration.test.ts:765: expect(toMilli.data.conversion.description).toBe('$25.75 = 25750 milliunits');
|
|
36
|
-
src\__tests__\comprehensive.integration.test.ts:767: // Test milliunits to dollar conversion
|
|
37
|
-
src\__tests__\comprehensive.integration.test.ts:770: to_milliunits: false,
|
|
38
|
-
src\__tests__\comprehensive.integration.test.ts:776: expect(dollars.data.conversion.description).toBe('25750 milliunits = $25.75');
|
|
39
|
-
src\tools\monthTools.ts:6:import { milliunitsToAmount } from '../utils/amountUtils.js';
|
|
40
|
-
src\tools\monthTools.ts:69: income: milliunitsToAmount(month.income),
|
|
41
|
-
src\tools\monthTools.ts:70: budgeted: milliunitsToAmount(month.budgeted),
|
|
42
|
-
src\tools\monthTools.ts:71: activity: milliunitsToAmount(month.activity),
|
|
43
|
-
src\tools\monthTools.ts:72: to_be_budgeted: milliunitsToAmount(month.to_be_budgeted),
|
|
44
|
-
src\tools\monthTools.ts:83: budgeted: milliunitsToAmount(category.budgeted),
|
|
45
|
-
src\tools\monthTools.ts:84: activity: milliunitsToAmount(category.activity),
|
|
46
|
-
src\tools\monthTools.ts:85: balance: milliunitsToAmount(category.balance),
|
|
47
|
-
src\tools\monthTools.ts:151: income: milliunitsToAmount(month.income),
|
|
48
|
-
src\tools\monthTools.ts:152: budgeted: milliunitsToAmount(month.budgeted),
|
|
49
|
-
src\tools\monthTools.ts:153: activity: milliunitsToAmount(month.activity),
|
|
50
|
-
src\tools\monthTools.ts:154: to_be_budgeted: milliunitsToAmount(month.to_be_budgeted),
|
|
51
|
-
src\tools\toolCategories.ts:123: * - convert_amount: Converts between dollars and milliunits
|
|
52
|
-
src\__tests__\testRunner.ts:349:- Milliunits handling
|
|
53
|
-
src\__tests__\tools\reconciliation\csvParser.integration.test.ts:18: expect(result.transactions[0].amount).toBe(-45230); // Milliunits!
|
|
54
|
-
src\__tests__\tools\reconciliation\csvParser.integration.test.ts:34: expect(result.transactions[0].amount).toBe(-45230); // Debit = negative milliunits
|
|
55
|
-
src\__tests__\tools\reconciliation\csvParser.integration.test.ts:35: expect(result.transactions[1].amount).toBe(500000); // Credit = positive milliunits
|
|
56
|
-
src\__tests__\tools\reconciliation\csvParser.integration.test.ts:59: expect(result.transactions[0].amount).toBe(1234560); // 1234.56 in milliunits
|
|
57
|
-
src\__tests__\tools\reconciliation\csvParser.integration.test.ts:94: // Shell: exact amount match (both -45230 milliunits)
|
|
58
|
-
src\__tests__\tools\reconciliation\csvParser.integration.test.ts:98: // Amazon: exact amount match (both -127990 milliunits)
|
|
59
|
-
src\__tests__\tools\reconciliation\csvParser.integration.test.ts:108: amount: -45230, // Integer milliunits
|
|
60
|
-
src\__tests__\tools\reconciliation\csvParser.integration.test.ts:117: amount: -45230, // Integer milliunits - direct from YNAB API
|
|
61
|
-
src\tools\accountTools.ts:6:import { milliunitsToAmount } from '../utils/amountUtils.js';
|
|
62
|
-
src\tools\accountTools.ts:108: balance: milliunitsToAmount(account.balance),
|
|
63
|
-
src\tools\accountTools.ts:109: cleared_balance: milliunitsToAmount(account.cleared_balance),
|
|
64
|
-
src\tools\accountTools.ts:110: uncleared_balance: milliunitsToAmount(account.uncleared_balance),
|
|
65
|
-
src\tools\accountTools.ts:172: balance: milliunitsToAmount(account.balance),
|
|
66
|
-
src\tools\accountTools.ts:173: cleared_balance: milliunitsToAmount(account.cleared_balance),
|
|
67
|
-
src\tools\accountTools.ts:174: uncleared_balance: milliunitsToAmount(account.uncleared_balance),
|
|
68
|
-
src\tools\accountTools.ts:242: balance: params.balance ? params.balance * 1000 : 0, // Convert to milliunits
|
|
69
|
-
src\tools\accountTools.ts:273: balance: milliunitsToAmount(account.balance),
|
|
70
|
-
src\tools\accountTools.ts:274: cleared_balance: milliunitsToAmount(account.cleared_balance),
|
|
71
|
-
src\tools\accountTools.ts:275: uncleared_balance: milliunitsToAmount(account.uncleared_balance),
|
|
72
|
-
src\tools\compareTransactions\types.ts:11: /** Transaction amount in milliunits (YNAB format) */
|
|
73
|
-
src\tools\compareTransactions\types.ts:31: /** Transaction amount in milliunits */
|
|
74
|
-
src\__tests__\testUtils.ts:362: * Generate test amounts in milliunits
|
|
75
|
-
src\tools\compareTransactions\parser.ts:47: * Convert dollar amount to milliunits
|
|
76
|
-
src\tools\compareTransactions\parser.ts:49:export function amountToMilliunits(amountStr: string): Milli {
|
|
77
|
-
src\tools\compareTransactions\parser.ts:482: amount = amountToMilliunits(rawAmount);
|
|
78
|
-
src\tools\reconciliation\csvParser.ts:193: * IMPORTANT: Amounts are converted to MILLIUNITS (integers) at this boundary.
|
|
79
|
-
src\tools\reconciliation\csvParser.ts:194: * This is the ONLY place where float-to-milliunit conversion happens.
|
|
80
|
-
src\tools\reconciliation\csvParser.ts:364: let amountMilliunits: number;
|
|
81
|
-
src\tools\reconciliation\csvParser.ts:369: amountMilliunits = dollarStringToMilliunits(rawAmount);
|
|
82
|
-
src\tools\reconciliation\csvParser.ts:375: const debitMilliunits = dollarStringToMilliunits(debit);
|
|
83
|
-
src\tools\reconciliation\csvParser.ts:376: const creditMilliunits = dollarStringToMilliunits(credit);
|
|
84
|
-
src\tools\reconciliation\csvParser.ts:379: if (Math.abs(debitMilliunits) > 0 && Math.abs(creditMilliunits) > 0) {
|
|
85
|
-
src\tools\reconciliation\csvParser.ts:385: if (Math.abs(debitMilliunits) > 0) {
|
|
86
|
-
src\tools\reconciliation\csvParser.ts:386: amountMilliunits = -Math.abs(debitMilliunits); // Debits are outflows (negative)
|
|
87
|
-
src\tools\reconciliation\csvParser.ts:387: } else if (Math.abs(creditMilliunits) > 0) {
|
|
88
|
-
src\tools\reconciliation\csvParser.ts:388: amountMilliunits = Math.abs(creditMilliunits); // Credits are inflows (positive)
|
|
89
|
-
src\tools\reconciliation\csvParser.ts:390: amountMilliunits = 0;
|
|
90
|
-
src\tools\reconciliation\csvParser.ts:394: if (debitMilliunits < 0) {
|
|
91
|
-
src\tools\reconciliation\csvParser.ts:403: if (!Number.isFinite(amountMilliunits)) {
|
|
92
|
-
src\tools\reconciliation\csvParser.ts:415: amountMilliunits *= multiplier;
|
|
93
|
-
src\tools\reconciliation\csvParser.ts:423: amount: amountMilliunits,
|
|
94
|
-
src\tools\reconciliation\csvParser.ts:555:function dollarStringToMilliunits(str: string): number {
|
|
95
|
-
src\tools\reconciliation\csvParser.ts:578: // Convert to milliunits: $1.00 → 1000
|
|
96
|
-
src\tools\categoryTools.ts:6:import { milliunitsToAmount } from '../utils/amountUtils.js';
|
|
97
|
-
src\tools\categoryTools.ts:44: budgeted: z.number().int('Budgeted amount must be an integer in milliunits'),
|
|
98
|
-
src\tools\categoryTools.ts:52: * Convert goal-related monetary fields from milliunits to dollars.
|
|
99
|
-
src\tools\categoryTools.ts:58: category.goal_target != null ? milliunitsToAmount(category.goal_target) : undefined,
|
|
100
|
-
src\tools\categoryTools.ts:61: ? milliunitsToAmount(category.goal_under_funded)
|
|
101
|
-
src\tools\categoryTools.ts:65: ? milliunitsToAmount(category.goal_overall_funded)
|
|
102
|
-
src\tools\categoryTools.ts:69: ? milliunitsToAmount(category.goal_overall_left)
|
|
103
|
-
src\tools\categoryTools.ts:113: budgeted: milliunitsToAmount(category.budgeted),
|
|
104
|
-
src\tools\categoryTools.ts:114: activity: milliunitsToAmount(category.activity),
|
|
105
|
-
src\tools\categoryTools.ts:115: balance: milliunitsToAmount(category.balance),
|
|
106
|
-
src\tools\categoryTools.ts:191: budgeted: milliunitsToAmount(category.budgeted),
|
|
107
|
-
src\tools\categoryTools.ts:192: activity: milliunitsToAmount(category.activity),
|
|
108
|
-
src\tools\categoryTools.ts:193: balance: milliunitsToAmount(category.balance),
|
|
109
|
-
src\tools\categoryTools.ts:253: budgeted: milliunitsToAmount(params.budgeted),
|
|
110
|
-
src\tools\categoryTools.ts:320: budgeted: milliunitsToAmount(category.budgeted),
|
|
111
|
-
src\tools\categoryTools.ts:321: activity: milliunitsToAmount(category.activity),
|
|
112
|
-
src\tools\categoryTools.ts:322: balance: milliunitsToAmount(category.balance),
|
|
113
|
-
src\tools\reconciliation\analyzer.ts:5: * V2 UPDATE: Uses new parser and matcher (milliunits based)
|
|
114
|
-
src\tools\reconciliation\analyzer.ts:48: const amount = txn.amount / 1000; // Convert from milliunits to dollars
|
|
115
|
-
src\tools\reconciliation\index.ts:170: amountToleranceMilliunits: (params.amount_tolerance_cents ?? 1) * 10,
|
|
116
|
-
src\tools\reconcileAdapter.ts:44: bank_statement_balance_milliunits: number;
|
|
117
|
-
src\tools\reconcileAdapter.ts:45: ynab_calculated_balance_milliunits: number;
|
|
118
|
-
src\tools\reconcileAdapter.ts:46: discrepancy_milliunits: number;
|
|
119
|
-
src\tools\reconcileAdapter.ts:54: amount_milliunits: number;
|
|
120
|
-
src\tools\reconcileAdapter.ts:123: const discrepancyMilli = analysis.balance_info.discrepancy.value_milliunits;
|
|
121
|
-
src\tools\reconcileAdapter.ts:148: bank_statement_balance: toMoneyValue(precision.bank_statement_balance_milliunits, currency),
|
|
122
|
-
src\tools\reconcileAdapter.ts:149: ynab_calculated_balance: toMoneyValue(precision.ynab_calculated_balance_milliunits, currency),
|
|
123
|
-
src\tools\reconcileAdapter.ts:150: discrepancy: toMoneyValue(precision.discrepancy_milliunits, currency),
|
|
124
|
-
src\tools\reconcileAdapter.ts:165: amount: toMoneyValue(cause.amount_milliunits, currency),
|
|
125
|
-
src\tools\reconciliation\executor.ts:14: balance: number; // milliunits
|
|
126
|
-
src\tools\reconciliation\executor.ts:15: cleared_balance: number; // milliunits
|
|
127
|
-
src\tools\reconciliation\executor.ts:16: uncleared_balance: number; // milliunits
|
|
128
|
-
src\tools\reconciliation\executor.ts:782: bank_statement_balance_milliunits: bankMilli,
|
|
129
|
-
src\tools\reconciliation\executor.ts:783: ynab_calculated_balance_milliunits: ynabMilli,
|
|
130
|
-
src\tools\reconciliation\executor.ts:784: discrepancy_milliunits: discrepancy,
|
|
131
|
-
src\tools\reconciliation\executor.ts:857: amount_milliunits: number;
|
|
132
|
-
src\tools\reconciliation\executor.ts:868: amount_milliunits: discrepancyMilli,
|
|
133
|
-
src\tools\reconciliation\executor.ts:957: 'value_milliunits' in value &&
|
|
134
|
-
src\tools\reconciliation\executor.ts:958: typeof (value as { value_milliunits: unknown }).value_milliunits === 'number'
|
|
135
|
-
src\tools\reconciliation\executor.ts:960: return (value as { value_milliunits: number }).value_milliunits;
|
|
136
|
-
src\utils\money.ts:4:export type Milli = number; // integer milliunits (no bigint)
|
|
137
|
-
src\utils\money.ts:9: value_milliunits: Milli;
|
|
138
|
-
src\utils\money.ts:45: * Convert milliunits to currency amount using proper decimal digits
|
|
139
|
-
src\utils\money.ts:47: * @param m - Milliunits value
|
|
140
|
-
src\utils\money.ts:51: return ynab.utils.convertMilliUnitsToCurrencyAmount(m, decimalDigits);
|
|
141
|
-
src\utils\money.ts:54:export const assertMilli = (m: number, msg = 'Expected safe integer milliunits') => {
|
|
142
|
-
src\utils\money.ts:60: if (!Number.isSafeInteger(s)) throw new Error('Milliunit sum overflow');
|
|
143
|
-
src\utils\money.ts:84: * Format milliunits as currency string with proper decimal digits
|
|
144
|
-
src\utils\money.ts:85: * @param value - Milliunits value
|
|
145
|
-
src\utils\money.ts:96: * Convert milliunits to MoneyValue with proper currency format
|
|
146
|
-
src\utils\money.ts:97: * @param value - Milliunits value
|
|
147
|
-
src\utils\money.ts:106: value_milliunits: value,
|
|
148
|
-
src\tools\reconciliation\recommendationEngine.ts:182: amount: toMilli(bankTxn.amount), // Convert dollars to milliunits for create_transaction
|
|
149
|
-
src\tools\reconciliation\recommendationEngine.ts:222: // Calculate total amount from candidates for context (convert from milliunits to decimal)
|
|
150
|
-
src\tools\reconciliation\recommendationEngine.ts:428: amount: toMilli(txn.amount), // Convert dollars to milliunits for create_transaction
|
|
151
|
-
src\tools\reconciliation\reportFormatter.ts:93: const discrepancyMilli = balanceInfo.discrepancy.value_milliunits;
|
|
152
|
-
src\tools\reconciliation\reportFormatter.ts:352: const amount = txn.amount / 1000; // Convert milliunits to dollars
|
|
153
|
-
src\tools\reconciliation\types.ts:37: /** Amount in milliunits */
|
|
154
|
-
src\tools\reconciliation\types.ts:175: // Tolerances (in MILLIUNITS for amount)
|
|
155
|
-
src\tools\reconciliation\types.ts:176: amountToleranceMilliunits: number; // Default: 10 (1 cent)
|
|
156
|
-
src\tools\transactionTools.ts:10:import { amountToMilliunits, milliunitsToAmount } from '../utils/amountUtils.js';
|
|
157
|
-
src\tools\transactionTools.ts:173: amount: z.number().int('Amount must be an integer in milliunits'),
|
|
158
|
-
src\tools\transactionTools.ts:188: amount: z.number().int('Subtransaction amount must be an integer in milliunits'),
|
|
159
|
-
src\tools\transactionTools.ts:626: amount: z.number().int('Amount must be an integer in milliunits').optional(),
|
|
160
|
-
src\tools\transactionTools.ts:651: amount: z.number().int('Amount must be an integer in milliunits').optional(),
|
|
161
|
-
src\tools\transactionTools.ts:808: amount: milliunitsToAmount(transaction.amount),
|
|
162
|
-
src\tools\transactionTools.ts:832: amount: milliunitsToAmount(transaction.amount),
|
|
163
|
-
src\tools\transactionTools.ts:906: amount: milliunitsToAmount(transaction.amount),
|
|
164
|
-
src\tools\transactionTools.ts:979: amount: params.amount, // Already validated as integer milliunits
|
|
165
|
-
src\tools\transactionTools.ts:1047: amount: milliunitsToAmount(transaction.amount),
|
|
166
|
-
src\tools\transactionTools.ts:1066: amount: milliunitsToAmount(subtransaction.amount),
|
|
167
|
-
src\tools\transactionTools.ts:1089: subtotal_milliunits: number;
|
|
168
|
-
src\tools\transactionTools.ts:1090: tax_milliunits: number;
|
|
169
|
-
src\tools\transactionTools.ts:1093: amount_milliunits: number;
|
|
170
|
-
src\tools\transactionTools.ts:1123: subtotalMilliunits: number,
|
|
171
|
-
src\tools\transactionTools.ts:1124: totalTaxMilliunits: number,
|
|
172
|
-
src\tools\transactionTools.ts:1127: if (totalTaxMilliunits === 0) {
|
|
173
|
-
src\tools\transactionTools.ts:1128: for (const category of categories) category.tax_milliunits = 0;
|
|
174
|
-
src\tools\transactionTools.ts:1132: if (subtotalMilliunits <= 0) {
|
|
175
|
-
src\tools\transactionTools.ts:1139: category.tax_milliunits = totalTaxMilliunits - allocated;
|
|
176
|
-
src\tools\transactionTools.ts:1142: (totalTaxMilliunits * category.subtotal_milliunits) / subtotalMilliunits,
|
|
177
|
-
src\tools\transactionTools.ts:1144: category.tax_milliunits = proportionalTax;
|
|
178
|
-
src\tools\transactionTools.ts:1176: amount_milliunits: amountToMilliunits(item.amount),
|
|
179
|
-
src\tools\transactionTools.ts:1180: const subtotalMilliunits = items.reduce((sum, item) => sum + item.amount_milliunits, 0);
|
|
180
|
-
src\tools\transactionTools.ts:1184: subtotal_milliunits: subtotalMilliunits,
|
|
181
|
-
src\tools\transactionTools.ts:1185: tax_milliunits: 0,
|
|
182
|
-
src\tools\transactionTools.ts:1190: const subtotalMilliunits = categoryCalculations.reduce(
|
|
183
|
-
src\tools\transactionTools.ts:1191: (sum, category) => sum + category.subtotal_milliunits,
|
|
184
|
-
src\tools\transactionTools.ts:1195: const declaredSubtotalMilliunits =
|
|
185
|
-
src\tools\transactionTools.ts:1196: params.receipt_subtotal !== undefined ? amountToMilliunits(params.receipt_subtotal) : undefined;
|
|
186
|
-
src\tools\transactionTools.ts:1198: declaredSubtotalMilliunits !== undefined &&
|
|
187
|
-
src\tools\transactionTools.ts:1199: Math.abs(declaredSubtotalMilliunits - subtotalMilliunits) > 1
|
|
188
|
-
src\tools\transactionTools.ts:1202: `Categorized items subtotal (${milliunitsToAmount(subtotalMilliunits)}) does not match receipt subtotal (${milliunitsToAmount(declaredSubtotalMilliunits)})`,
|
|
189
|
-
src\tools\transactionTools.ts:1206: const taxMilliunits = amountToMilliunits(params.receipt_tax);
|
|
190
|
-
src\tools\transactionTools.ts:1207: const totalMilliunits = amountToMilliunits(params.receipt_total);
|
|
191
|
-
src\tools\transactionTools.ts:1208: const computedTotal = subtotalMilliunits + taxMilliunits;
|
|
192
|
-
src\tools\transactionTools.ts:1209: if (Math.abs(computedTotal - totalMilliunits) > 1) {
|
|
193
|
-
src\tools\transactionTools.ts:1211: `Receipt total (${milliunitsToAmount(totalMilliunits)}) does not equal subtotal plus tax (${milliunitsToAmount(computedTotal)})`,
|
|
194
|
-
src\tools\transactionTools.ts:1215: distributeTaxProportionally(subtotalMilliunits, taxMilliunits, categoryCalculations);
|
|
195
|
-
src\tools\transactionTools.ts:1221: amount: -item.amount_milliunits,
|
|
196
|
-
src\tools\transactionTools.ts:1229: category.tax_milliunits > 0
|
|
197
|
-
src\tools\transactionTools.ts:1232: amount: -category.tax_milliunits,
|
|
198
|
-
src\tools\transactionTools.ts:1243: subtotal: milliunitsToAmount(subtotalMilliunits),
|
|
199
|
-
src\tools\transactionTools.ts:1244: tax: milliunitsToAmount(taxMilliunits),
|
|
200
|
-
src\tools\transactionTools.ts:1245: total: milliunitsToAmount(totalMilliunits),
|
|
201
|
-
src\tools\transactionTools.ts:1252: amount: milliunitsToAmount(item.amount_milliunits),
|
|
202
|
-
src\tools\transactionTools.ts:1255: subtotal: milliunitsToAmount(category.subtotal_milliunits),
|
|
203
|
-
src\tools\transactionTools.ts:1256: tax: milliunitsToAmount(category.tax_milliunits),
|
|
204
|
-
src\tools\transactionTools.ts:1257: total: milliunitsToAmount(category.subtotal_milliunits + category.tax_milliunits),
|
|
205
|
-
src\tools\transactionTools.ts:1273: amount: milliunitsToAmount(totalMilliunits),
|
|
206
|
-
src\tools\transactionTools.ts:1278: amount: milliunitsToAmount(-subtransaction.amount),
|
|
207
|
-
src\tools\transactionTools.ts:1291: amount: -totalMilliunits,
|
|
208
|
-
src\tools\transactionTools.ts:1494: amount: milliunitsToAmount(transaction.amount),
|
|
209
|
-
src\tools\transactionTools.ts:1733: amount: milliunitsToAmount(transaction.amount),
|
|
210
|
-
src\tools\transactionTools.ts:1751: total_amount: milliunitsToAmount(totalAmount),
|
|
211
|
-
src\tools\transactionTools.ts:2132: before['amount'] = milliunitsToAmount(currentState.amount);
|
|
212
|
-
src\tools\transactionTools.ts:2133: after['amount'] = milliunitsToAmount(transaction.amount);
|
|
213
|
-
src\tools\utilityTools.ts:13: to_milliunits: z.boolean(),
|
|
214
|
-
src\tools\utilityTools.ts:49: * Converts between dollars and milliunits with integer arithmetic for precision
|
|
215
|
-
src\tools\utilityTools.ts:54: const { amount, to_milliunits } = params;
|
|
216
|
-
src\tools\utilityTools.ts:59: if (to_milliunits) {
|
|
217
|
-
src\tools\utilityTools.ts:60: // Convert from dollars to milliunits
|
|
218
|
-
src\tools\utilityTools.ts:63: description = `$${amount.toFixed(2)} = ${result} milliunits`;
|
|
219
|
-
src\tools\utilityTools.ts:65: // Convert from milliunits to dollars
|
|
220
|
-
src\tools\utilityTools.ts:66: // Assume input amount is in milliunits
|
|
221
|
-
src\tools\utilityTools.ts:68: description = `${amount} milliunits = $${result.toFixed(2)}`;
|
|
222
|
-
src\tools\utilityTools.ts:79: to_milliunits,
|
|
223
|
-
src\tools\reconciliation\__tests__\adapter.causes.test.ts:59: bank_statement_balance_milliunits: -921240,
|
|
224
|
-
src\tools\reconciliation\__tests__\adapter.causes.test.ts:60: ynab_calculated_balance_milliunits: -899020,
|
|
225
|
-
src\tools\reconciliation\__tests__\adapter.causes.test.ts:61: discrepancy_milliunits: -22220,
|
|
226
|
-
src\tools\reconciliation\__tests__\adapter.causes.test.ts:72: amount_milliunits: -1500,
|
|
227
|
-
src\tools\reconciliation\__tests__\adapter.causes.test.ts:80: amount_milliunits: 500,
|
|
228
|
-
src\tools\reconciliation\__tests__\adapter.test.ts:9: value_milliunits: Math.round(value * 1000),
|
|
229
|
-
src\tools\reconciliation\__tests__\adapter.test.ts:149: expect(structured.matches.auto[0].bank_transaction.amount_money.value_milliunits).toBe(-45230);
|
|
230
|
-
src\tools\reconciliation\__tests__\adapter.test.ts:183: bank_statement_balance_milliunits: -921240,
|
|
231
|
-
src\tools\reconciliation\__tests__\adapter.test.ts:184: ynab_calculated_balance_milliunits: -899020,
|
|
232
|
-
src\tools\reconciliation\__tests__\adapter.test.ts:185: discrepancy_milliunits: -22220,
|
|
233
|
-
src\tools\reconciliation\__tests__\adapter.test.ts:195: amount_milliunits: 22220,
|
|
234
|
-
src\tools\reconciliation\__tests__\adapter.test.ts:224: expect(structured.execution.account_balance.after.cleared_balance.value_milliunits).toBe(
|
|
235
|
-
src\tools\reconciliation\matcher.ts:4: * V2 matcher works natively in milliunits using canonical BankTransaction
|
|
236
|
-
src\tools\reconciliation\matcher.ts:50: amountToleranceMilliunits: 10, // 1 cent
|
|
237
|
-
src\tools\reconciliation\matcher.ts:67: amountToleranceMilliunits:
|
|
238
|
-
src\tools\reconciliation\matcher.ts:68: config.amountToleranceMilliunits ?? DEFAULT_CONFIG.amountToleranceMilliunits,
|
|
239
|
-
src\tools\reconciliation\matcher.ts:293: if (amountDiff > config.amountToleranceMilliunits) {
|
|
240
|
-
src\tools\reconciliation\matcher.ts:338: // Amount score - now using INTEGER comparison (milliunits)
|
|
241
|
-
src\tools\reconciliation\matcher.ts:345: } else if (amountDiff <= config.amountToleranceMilliunits) {
|
|
242
|
-
src\tools\reconciliation\__tests__\analyzer.test.ts:24: amount: -45230, // milliunits
|
|
243
|
-
src\tools\reconciliation\__tests__\analyzer.test.ts:33: amount: -100000, // milliunits
|
|
244
|
-
src\tools\reconciliation\ynabAdapter.ts:10: * NOTE: Amount stays in milliunits - no conversion needed since
|
|
245
|
-
src\tools\reconciliation\ynabAdapter.ts:11: * YNAB API already uses milliunits natively.
|
|
246
|
-
src\tools\reconciliation\ynabAdapter.ts:17: amount: txn.amount, // Already in milliunits - no conversion!
|
|
247
|
-
src\server\YNABMCPServer.ts:901: description: 'Convert between dollars and milliunits with integer arithmetic for precision',
|
|
248
|
-
src\utils\amountUtils.ts:2: * Utility functions for converting between YNAB milliunits and dollars
|
|
249
|
-
src\utils\amountUtils.ts:6: * Converts an amount from milliunits to dollars
|
|
250
|
-
src\utils\amountUtils.ts:7: * @param milliunits - Amount in milliunits (1000 milliunits = $1.00)
|
|
251
|
-
src\utils\amountUtils.ts:10:export function milliunitsToAmount(milliunits: number): number {
|
|
252
|
-
src\utils\amountUtils.ts:11: return Math.round(milliunits) / 1000;
|
|
253
|
-
src\utils\amountUtils.ts:15: * Converts an amount from dollars to milliunits
|
|
254
|
-
src\utils\amountUtils.ts:17: * @returns Amount in milliunits
|
|
255
|
-
src\utils\amountUtils.ts:19:export function amountToMilliunits(amount: number): number {
|
|
256
|
-
src\utils\amountUtils.ts:24: * Formats an amount from milliunits to a currency string
|
|
257
|
-
src\utils\amountUtils.ts:25: * @param milliunits - Amount in milliunits
|
|
258
|
-
src\utils\amountUtils.ts:29:export function formatAmount(milliunits: number, currencySymbol = '$'): string {
|
|
259
|
-
src\utils\amountUtils.ts:30: const amount = milliunitsToAmount(milliunits);
|
|
260
|
-
src\tools\reconciliation\__tests__\recommendationEngine.test.ts:260: expect(rec.parameters.amount).toBe(-75500); // In milliunits
|
|
261
|
-
src\tools\reconciliation\__tests__\recommendationEngine.test.ts:458: expect(rec.parameters.amount).toBe(-45000); // In milliunits
|
|
262
|
-
src\tools\reconciliation\__tests__\recommendationEngine.test.ts:548: expect(rec.parameters.amount).toBe(-123450); // In milliunits
|
|
263
|
-
src\tools\reconciliation\__tests__\recommendationEngine.test.ts:569: expect(rec.parameters.amount).toBe(500000); // In milliunits
|
|
264
|
-
src\tools\reconciliation\__tests__\recommendationEngine.test.ts:594: expect(rec.parameters.amount).toBe(-99990); // In milliunits
|
|
265
|
-
src\tools\reconciliation\__tests__\recommendationEngine.test.ts:610: expect(rec.parameters.amount).toBe(0); // Zero in milliunits is still zero
|
|
266
|
-
src\tools\reconciliation\__tests__\recommendationEngine.test.ts:921: expect(rec.parameters.amount).toBe(-10); // In milliunits (0.01 * 1000)
|
|
267
|
-
src\tools\reconciliation\__tests__\recommendationEngine.test.ts:937: expect(rec.parameters.amount).toBe(-999999990); // In milliunits
|
|
268
|
-
src\tools\reconciliation\__tests__\recommendationEngine.integration.test.ts:17: amount: number, // in milliunits
|
|
269
|
-
src\tools\reconciliation\__tests__\recommendationEngine.integration.test.ts:87: expect(rec.parameters.amount).toBe(22220); // In milliunits
|
|
270
|
-
src\tools\reconciliation\__tests__\recommendationEngine.integration.test.ts:141: expect(evoCarShareRec!.parameters.amount).toBe(22220); // In milliunits
|
|
271
|
-
src\tools\reconciliation\__tests__\recommendationEngine.integration.test.ts:552: // 500 dollars in milliunits
|
|
272
|
-
src\tools\reconciliation\__tests__\recommendationEngine.integration.test.ts:651: expect(createRec!.parameters.amount).toBe(25500); // In milliunits
|
|
273
|
-
src\tools\reconciliation\__tests__\matcher.test.ts:15: amountToleranceMilliunits: 10,
|
|
274
|
-
src\tools\reconciliation\__tests__\matcher.test.ts:41: amount: -45230, // milliunits
|
|
275
|
-
src\tools\reconciliation\__tests__\matcher.test.ts:339: config.amountToleranceMilliunits = 10; // 1 cent
|
|
276
|
-
src\tools\reconciliation\__tests__\matcher.test.ts:532: amountToleranceMilliunits: 100, // 10 cents
|
|
277
|
-
src\tools\reconciliation\__tests__\matcher.test.ts:626: amount: -10, // 1 cent in milliunits
|
|
278
|
-
src\tools\reconciliation\__tests__\matcher.test.ts:652: amount: -10000000, // $10,000 in milliunits
|
|
279
|
-
src\tools\reconciliation\__tests__\reportFormatter.test.ts:20: value_milliunits: Math.round(value * 1000),
|
|
280
|
-
src\tools\schemas\outputs\accountOutputs.ts:68: * Represents account data with balances in dollars (converted from YNAB milliunits).
|
|
281
|
-
src\tools\__tests__\accountTools.test.ts:401: // Verify the API was called with balance 0 in milliunits
|
|
282
|
-
src\tools\__tests__\accountTools.test.ts:411: it('should convert balance to milliunits', async () => {
|
|
283
|
-
src\tools\__tests__\accountTools.test.ts:435: balance: 150, // $150 should become 150000 milliunits
|
|
284
|
-
src\tools\__tests__\accountTools.test.ts:438: // Verify the API was called with balance converted to milliunits
|
|
285
|
-
src\tools\reconciliation\__tests__\scenarios\adapterCurrency.scenario.test.ts:6: value_milliunits: Math.round(value * 1000),
|
|
286
|
-
src\tools\reconciliation\__tests__\scenarios\repeatAmount.scenario.test.ts:18: // Three -22.22 transactions in milliunits: one will match YNAB, two will remain unmatched
|
|
287
|
-
src\tools\schemas\outputs\categoryOutputs.ts:9: * goal_overall_funded, goal_overall_left) are converted from YNAB API milliunits to
|
|
288
|
-
src\tools\schemas\outputs\categoryOutputs.ts:123: /** Goal target amount in dollars (converted from YNAB API milliunits, optional) */
|
|
289
|
-
src\tools\schemas\outputs\comparisonOutputs.ts:344: * IMPORTANT: `amount` is the raw YNAB amount in **milliunits** (not dollar amounts).
|
|
290
|
-
src\tools\schemas\outputs\comparisonOutputs.ts:346: * For example, $25.50 is represented as 25500 milliunits.
|
|
291
|
-
src\tools\schemas\outputs\comparisonOutputs.ts:352: * @see src/tools/exportTransactions.ts:204 - Amount field directly from transaction.amount (milliunits)
|
|
292
|
-
src\tools\schemas\outputs\comparisonOutputs.ts:357: amount: z.number(), // Raw YNAB milliunits
|
|
293
|
-
src\tools\schemas\outputs\comparisonOutputs.ts:365: amount: z.number(), // Raw YNAB milliunits
|
|
294
|
-
src\tools\schemas\outputs\comparisonOutputs.ts:417: * { id: "txn-1", date: "2025-11-15", amount: -25500, payee_name: "Grocery Store", cleared: "cleared" }, // amount is milliunits
|
|
295
|
-
src\tools\schemas\outputs\comparisonOutputs.ts:435: * amount: -25500, // Raw milliunits: -$25.50
|
|
296
|
-
src\tools\schemas\outputs\comparisonOutputs.ts:592: amount: z.number(), // Raw YNAB milliunits
|
|
297
|
-
src\utils\__tests__\money.test.ts:19: it('converts dollars to milliunits correctly', () => {
|
|
298
|
-
src\utils\__tests__\money.test.ts:32: it('converts milliunits with 2 decimal digits (USD) by default', () => {
|
|
299
|
-
src\utils\__tests__\money.test.ts:38: it('converts milliunits with 0 decimal digits (JPY)', () => {
|
|
300
|
-
src\utils\__tests__\money.test.ts:43: it('converts milliunits with 3 decimal digits (BHD)', () => {
|
|
301
|
-
src\utils\__tests__\money.test.ts:48: it('converts milliunits with explicit 2 decimal digits', () => {
|
|
302
|
-
src\utils\__tests__\money.test.ts:61: expect(() => assertMilli(1.5)).toThrow('Expected safe integer milliunits');
|
|
303
|
-
src\utils\__tests__\money.test.ts:63: 'Expected safe integer milliunits',
|
|
304
|
-
src\utils\__tests__\money.test.ts:69: it('adds milliunits correctly', () => {
|
|
305
|
-
src\utils\__tests__\money.test.ts:75: expect(() => addMilli(Number.MAX_SAFE_INTEGER, 1)).toThrow('Milliunit sum overflow');
|
|
306
|
-
src\utils\__tests__\money.test.ts:152: it('formats milliunits into currency strings with default 2 decimals', () => {
|
|
307
|
-
src\utils\__tests__\money.test.ts:157: it('formats milliunits with custom currency format', () => {
|
|
308
|
-
src\utils\__tests__\money.test.ts:163: it('creates money values from milliunits with default 2 decimals', () => {
|
|
309
|
-
src\utils\__tests__\money.test.ts:184: expect(value.value_milliunits).toBe(-45670);
|
|
310
|
-
src\tools\schemas\outputs\monthOutputs.ts:128: /** Goal target amount in milliunits (optional) */
|
|
311
|
-
src\tools\schemas\outputs\monthOutputs.ts:129: goal_target: z.number().optional().describe('Goal target in milliunits'),
|
|
312
|
-
src\server\__tests__\prompts.test.ts:173: expect(text).toContain('Create the transaction with the correct amount in milliunits');
|
|
313
|
-
src\server\__tests__\prompts.test.ts:251: expect(text).toContain('Convert milliunits to dollars');
|
|
314
|
-
src\tools\schemas\outputs\transactionMutationOutputs.ts:17: * account_balance: 1500000, // Raw milliunits: $1,500.00
|
|
315
|
-
src\tools\schemas\outputs\transactionMutationOutputs.ts:18: * account_cleared_balance: 1000000 // Raw milliunits: $1,000.00
|
|
316
|
-
src\tools\schemas\outputs\transactionMutationOutputs.ts:77: * IMPORTANT: `account_balance` and `account_cleared_balance` are **raw YNAB milliunits** (not user-facing dollar amounts).
|
|
317
|
-
src\tools\schemas\outputs\transactionMutationOutputs.ts:79: * For example, $1,250.50 is represented as 1250500 milliunits.
|
|
318
|
-
src\tools\schemas\outputs\transactionMutationOutputs.ts:85: account_balance: z.number().optional(), // Raw YNAB milliunits
|
|
319
|
-
src\tools\schemas\outputs\transactionMutationOutputs.ts:86: account_cleared_balance: z.number().optional(), // Raw YNAB milliunits
|
|
320
|
-
src\tools\schemas\outputs\transactionMutationOutputs.ts:258: * account_balance: 1500000, // Raw milliunits: $1,500.00
|
|
321
|
-
src\tools\schemas\outputs\transactionMutationOutputs.ts:259: * account_cleared_balance: 1000000 // Raw milliunits: $1,000.00
|
|
322
|
-
src\tools\schemas\outputs\transactionMutationOutputs.ts:392: * updated_balance: 1450000, // Raw milliunits: $1,450.00
|
|
323
|
-
src\tools\schemas\outputs\transactionMutationOutputs.ts:393: * updated_cleared_balance: 950000 // Raw milliunits: $950.00
|
|
324
|
-
src\tools\schemas\outputs\transactionMutationOutputs.ts:412: updated_balance: z.number(), // Raw YNAB milliunits
|
|
325
|
-
src\tools\schemas\outputs\transactionMutationOutputs.ts:413: updated_cleared_balance: z.number(), // Raw YNAB milliunits
|
|
326
|
-
src\tools\schemas\outputs\transactionMutationOutputs.ts:529: updated_balance: z.number(), // Raw YNAB milliunits
|
|
327
|
-
src\tools\schemas\outputs\transactionMutationOutputs.ts:530: updated_cleared_balance: z.number(), // Raw YNAB milliunits
|
|
328
|
-
src\tools\schemas\outputs\transactionOutputs.ts:98: * Represents full transaction data with amounts in dollars (converted from YNAB milliunits).
|
|
329
|
-
src\tools\schemas\outputs\utilityOutputs.ts:56: * Contains the conversion result between dollars and YNAB milliunits.
|
|
330
|
-
src\tools\schemas\outputs\utilityOutputs.ts:61: to_milliunits: z.boolean(),
|
|
331
|
-
src\tools\schemas\outputs\utilityOutputs.ts:68: * Converts between dollars and YNAB milliunits (1 dollar = 1000 milliunits).
|
|
332
|
-
src\tools\schemas\outputs\utilityOutputs.ts:78: * to_milliunits: true,
|
|
333
|
-
src\tools\schemas\outputs\utilityOutputs.ts:79: * description: "$25.50 converted to 25500 milliunits"
|
|
334
|
-
src\tools\__tests__\categoryTools.integration.test.ts:133: console.warn(` - Budgeted: ${category.budgeted} milliunits`);
|
|
335
|
-
src\tools\__tests__\categoryTools.integration.test.ts:134: console.warn(` - Activity: ${category.activity} milliunits`);
|
|
336
|
-
src\tools\__tests__\categoryTools.integration.test.ts:135: console.warn(` - Balance: ${category.balance} milliunits`);
|
|
337
|
-
src\tools\__tests__\categoryTools.integration.test.ts:170: // Update with a test amount (add 1000 milliunits = $1.00)
|
|
338
|
-
src\tools\__tests__\categoryTools.integration.test.ts:204: console.warn(`✅ Successfully updated category budget to ${testBudgetedAmount} milliunits`);
|
|
339
|
-
src\tools\__tests__\categoryTools.integration.test.ts:214: console.warn(`✅ Restored original budget amount: ${originalBudgetedAmount} milliunits`);
|
|
340
|
-
src\tools\__tests__\categoryTools.integration.test.ts:281: `✅ Successfully set negative budget amount: ${negativeBudgetedAmount} milliunits`,
|
|
341
|
-
src\tools\__tests__\categoryTools.integration.test.ts:291: console.warn(`✅ Restored original budget amount: ${originalBudgetedAmount} milliunits`);
|
|
342
|
-
src\tools\schemas\outputs\__tests__\comparisonOutputs.test.ts:403: amount: -25500, // Milliunits
|
|
343
|
-
src\tools\schemas\outputs\__tests__\comparisonOutputs.test.ts:436: amount: -15000, // Milliunits: -$15.00
|
|
344
|
-
src\tools\__tests__\compareTransactions\parser.test.ts:7: amountToMilliunits,
|
|
345
|
-
src\tools\__tests__\compareTransactions\parser.test.ts:78: describe('amountToMilliunits', () => {
|
|
346
|
-
src\tools\__tests__\compareTransactions\parser.test.ts:80: expect(amountToMilliunits('123.45')).toBe(123450);
|
|
347
|
-
src\tools\__tests__\compareTransactions\parser.test.ts:84: expect(amountToMilliunits('-123.45')).toBe(-123450);
|
|
348
|
-
src\tools\__tests__\compareTransactions\parser.test.ts:88: expect(amountToMilliunits('(123.45)')).toBe(-123450);
|
|
349
|
-
src\tools\__tests__\compareTransactions\parser.test.ts:92: expect(amountToMilliunits('$123.45')).toBe(123450);
|
|
350
|
-
src\tools\__tests__\compareTransactions\parser.test.ts:96: expect(amountToMilliunits('1,234.56')).toBe(1234560);
|
|
351
|
-
src\tools\__tests__\compareTransactions\parser.test.ts:100: expect(amountToMilliunits('+123.45')).toBe(123450);
|
|
352
|
-
src\tools\__tests__\compareTransactions\parser.test.ts:104: expect(amountToMilliunits('0.00')).toBe(0);
|
|
353
|
-
src\tools\__tests__\compareTransactions\parser.test.ts:108: expect(amountToMilliunits(' 123.45 ')).toBe(123450);
|
|
354
|
-
src\tools\__tests__\compareTransactions\parser.test.ts:112: expect(amountToMilliunits('999999.99')).toBe(999999990);
|
|
355
|
-
src\tools\__tests__\utilityTools.test.ts:85: it('should convert dollars to milliunits correctly', async () => {
|
|
356
|
-
src\tools\__tests__\utilityTools.test.ts:86: const params = { amount: 10.5, to_milliunits: true };
|
|
357
|
-
src\tools\__tests__\utilityTools.test.ts:93: expect(response.conversion.to_milliunits).toBe(true);
|
|
358
|
-
src\tools\__tests__\utilityTools.test.ts:94: expect(response.conversion.description).toBe('$10.50 = 10500 milliunits');
|
|
359
|
-
src\tools\__tests__\utilityTools.test.ts:97: it('should convert milliunits to dollars correctly', async () => {
|
|
360
|
-
src\tools\__tests__\utilityTools.test.ts:98: const params = { amount: 10500, to_milliunits: false };
|
|
361
|
-
src\tools\__tests__\utilityTools.test.ts:105: expect(response.conversion.to_milliunits).toBe(false);
|
|
362
|
-
src\tools\__tests__\utilityTools.test.ts:106: expect(response.conversion.description).toBe('10500 milliunits = $10.50');
|
|
363
|
-
src\tools\__tests__\utilityTools.test.ts:110: const params = { amount: 0, to_milliunits: true };
|
|
364
|
-
src\tools\__tests__\utilityTools.test.ts:117: expect(response.conversion.description).toBe('$0.00 = 0 milliunits');
|
|
365
|
-
src\tools\__tests__\utilityTools.test.ts:121: const params = { amount: -5.25, to_milliunits: true };
|
|
366
|
-
src\tools\__tests__\utilityTools.test.ts:128: expect(response.conversion.description).toBe('$-5.25 = -5250 milliunits');
|
|
367
|
-
src\tools\__tests__\utilityTools.test.ts:132: const params = { amount: 0.01, to_milliunits: true };
|
|
368
|
-
src\tools\__tests__\utilityTools.test.ts:141: const params = { amount: 999999.99, to_milliunits: true };
|
|
369
|
-
src\tools\__tests__\utilityTools.test.ts:149: it('should round to nearest milliunit when converting from dollars', async () => {
|
|
370
|
-
src\tools\__tests__\utilityTools.test.ts:150: const params = { amount: 10.5555, to_milliunits: true };
|
|
371
|
-
src\tools\__tests__\utilityTools.test.ts:161: const validParams = { amount: 10.5, to_milliunits: true };
|
|
372
|
-
src\tools\__tests__\utilityTools.test.ts:171: const invalidParams = { amount: Infinity, to_milliunits: true };
|
|
373
|
-
src\tools\__tests__\utilityTools.test.ts:178: const invalidParams = { amount: NaN, to_milliunits: true };
|
|
374
|
-
src\tools\__tests__\utilityTools.test.ts:185: const invalidParams = { to_milliunits: true };
|
|
375
|
-
src\tools\__tests__\utilityTools.test.ts:191: it('should reject missing to_milliunits parameter', () => {
|
|
376
|
-
src\tools\__tests__\utilityTools.test.ts:198: it('should reject non-boolean to_milliunits parameter', () => {
|
|
377
|
-
src\tools\__tests__\utilityTools.test.ts:199: const invalidParams = { amount: 10.5, to_milliunits: 'true' };
|
|
378
|
-
src\tools\__tests__\compareTransactions.test.ts:78: amount: 100000, // $100.00 in milliunits
|
|
379
|
-
src\tools\__tests__\compareTransactions.test.ts:90: amount: -50000, // -$50.00 in milliunits
|
|
380
|
-
src\tools\__tests__\transactionTools.test.ts:136: amount: -50000, // $50.00 outflow in milliunits
|
|
381
|
-
src\tools\__tests__\transactionTools.test.ts:558: amount: -50000, // $50.00 outflow in milliunits
|
|
382
|
-
src\tools\__tests__\transactionTools.test.ts:618: expect(result.error.issues[0].message).toContain('Amount must be an integer in milliunits');
|
|
383
|
-
src\tools\__tests__\transactionTools.test.ts:1456: expect(result.error.issues[0].message).toContain('Amount must be an integer in milliunits');
|
|
384
|
-
src\tools\__tests__\transactionTools.test.ts:1881: it('should require integer milliunit amounts', () => {
|
|
385
|
-
src\tools\__tests__\transactionTools.test.ts:2704: it('should require integer milliunit amounts when provided', () => {
|
|
386
|
-
src\tools\__tests__\utilityTools.integration.test.ts:47: 'should convert various dollar amounts to milliunits',
|
|
387
|
-
src\tools\__tests__\utilityTools.integration.test.ts:51: { dollars: 1.0, expectedMilliunits: 1000 },
|
|
388
|
-
src\tools\__tests__\utilityTools.integration.test.ts:52: { dollars: 0.01, expectedMilliunits: 10 },
|
|
389
|
-
src\tools\__tests__\utilityTools.integration.test.ts:53: { dollars: 10.5, expectedMilliunits: 10500 },
|
|
390
|
-
src\tools\__tests__\utilityTools.integration.test.ts:54: { dollars: 999.99, expectedMilliunits: 999990 },
|
|
391
|
-
src\tools\__tests__\utilityTools.integration.test.ts:55: { dollars: 0, expectedMilliunits: 0 },
|
|
392
|
-
src\tools\__tests__\utilityTools.integration.test.ts:56: { dollars: -5.25, expectedMilliunits: -5250 },
|
|
393
|
-
src\tools\__tests__\utilityTools.integration.test.ts:62: to_milliunits: true,
|
|
394
|
-
src\tools\__tests__\utilityTools.integration.test.ts:66: expect(response.conversion.converted_amount).toBe(testCase.expectedMilliunits);
|
|
395
|
-
src\tools\__tests__\utilityTools.integration.test.ts:67: expect(response.conversion.to_milliunits).toBe(true);
|
|
396
|
-
src\tools\__tests__\utilityTools.integration.test.ts:70: `${testCase.expectedMilliunits} milliunits`,
|
|
397
|
-
src\tools\__tests__\utilityTools.integration.test.ts:77: 'should convert various milliunit amounts to dollars',
|
|
398
|
-
src\tools\__tests__\utilityTools.integration.test.ts:81: { milliunits: 1000, expectedDollars: 1.0 },
|
|
399
|
-
src\tools\__tests__\utilityTools.integration.test.ts:82: { milliunits: 10, expectedDollars: 0.01 },
|
|
400
|
-
src\tools\__tests__\utilityTools.integration.test.ts:83: { milliunits: 10500, expectedDollars: 10.5 },
|
|
401
|
-
src\tools\__tests__\utilityTools.integration.test.ts:84: { milliunits: 999990, expectedDollars: 999.99 },
|
|
402
|
-
src\tools\__tests__\utilityTools.integration.test.ts:85: { milliunits: 0, expectedDollars: 0 },
|
|
403
|
-
src\tools\__tests__\utilityTools.integration.test.ts:86: { milliunits: -5250, expectedDollars: -5.25 },
|
|
404
|
-
src\tools\__tests__\utilityTools.integration.test.ts:91: amount: testCase.milliunits,
|
|
405
|
-
src\tools\__tests__\utilityTools.integration.test.ts:92: to_milliunits: false,
|
|
406
|
-
src\tools\__tests__\utilityTools.integration.test.ts:97: expect(response.conversion.to_milliunits).toBe(false);
|
|
407
|
-
src\tools\__tests__\utilityTools.integration.test.ts:98: expect(response.conversion.description).toContain(`${testCase.milliunits} milliunits`);
|
|
408
|
-
src\tools\__tests__\utilityTools.integration.test.ts:112: { amount: 0.1 + 0.2, to_milliunits: true }, // Should handle 0.30000000000000004
|
|
409
|
-
src\tools\__tests__\utilityTools.integration.test.ts:113: { amount: 1.005, to_milliunits: true }, // Should round correctly
|
|
410
|
-
src\tools\__tests__\utilityTools.integration.test.ts:114: { amount: 999.999, to_milliunits: true }, // Should handle near-integer values
|
|
411
|
-
src\tools\__tests__\monthTools.integration.test.ts:63: console.warn(` - Income: ${firstMonth.income} milliunits`);
|
|
412
|
-
src\tools\__tests__\monthTools.integration.test.ts:64: console.warn(` - Budgeted: ${firstMonth.budgeted} milliunits`);
|
|
413
|
-
src\tools\__tests__\monthTools.integration.test.ts:126: console.warn(` - Income: ${month.income} milliunits`);
|
|
414
|
-
src\tools\__tests__\monthTools.integration.test.ts:127: console.warn(` - Budgeted: ${month.budgeted} milliunits`);
|
|
415
|
-
src\tools\__tests__\monthTools.integration.test.ts:128: console.warn(` - Activity: ${month.activity} milliunits`);
|
|
416
|
-
src\tools\__tests__\monthTools.integration.test.ts:129: console.warn(` - To be budgeted: ${month.to_be_budgeted} milliunits`);
|