@stephendolan/ynab-cli 2.1.1 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,220 +1,136 @@
1
1
  # YNAB CLI
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/@stephendolan/ynab-cli.svg)](https://www.npmjs.com/package/@stephendolan/ynab-cli)
4
- [![npm downloads](https://img.shields.io/npm/dm/@stephendolan/ynab-cli.svg)](https://www.npmjs.com/package/@stephendolan/ynab-cli)
5
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
- [![Bun](https://img.shields.io/badge/Bun-%3E%3D1.0-black)](https://bun.sh)
7
5
 
8
- A command-line interface for You Need a Budget (YNAB) designed to enable LLMs (Claude, ChatGPT, etc.) and developers to quickly interface with YNAB budgets, make changes, and audit financial data.
9
-
10
- ## Features
11
-
12
- - **LLM-First Design**: JSON output by default for easy parsing and integration with AI assistants
13
- - **Advanced Filtering**: Built-in filters reduce need for external tools like `jq` - filter by approval status, amount ranges, field selection, and search capabilities
14
- - **Comprehensive Coverage**: Support for all major YNAB API endpoints
15
- - **Type Safety**: Built with TypeScript for robust error handling
16
- - **Raw API Access**: Fallback command for any operation not covered by convenience commands
17
- - **Simple Authentication**: Uses personal access tokens stored securely in OS keychain
6
+ A command-line interface for YNAB designed for LLMs and developers. JSON output by default with built-in filtering.
18
7
 
19
8
  ## Installation
20
9
 
21
- Requires [Bun](https://bun.sh) runtime.
10
+ Requires [Bun](https://bun.sh).
22
11
 
23
12
  ```bash
24
- # Install globally with bun (recommended)
25
13
  bun install -g @stephendolan/ynab-cli
26
14
 
27
- # Or run directly without installing
15
+ # Or run without installing
28
16
  bunx @stephendolan/ynab-cli budgets list
29
- npx @stephendolan/ynab-cli budgets list # also works
30
17
  ```
31
18
 
32
- ### Linux Prerequisites
33
-
34
- Requires `libsecret` for keychain storage:
19
+ <details>
20
+ <summary>Linux: requires libsecret for keychain storage</summary>
35
21
 
36
22
  ```bash
37
- # Ubuntu/Debian
38
- sudo apt-get install libsecret-1-dev
39
-
40
- # Fedora/RHEL
41
- sudo dnf install libsecret-devel
42
-
43
- # Arch Linux
44
- sudo pacman -S libsecret
23
+ sudo apt-get install libsecret-1-dev # Ubuntu/Debian
24
+ sudo dnf install libsecret-devel # Fedora/RHEL
25
+ sudo pacman -S libsecret # Arch
45
26
  ```
46
27
 
47
- Without `libsecret`, use the `YNAB_API_KEY` environment variable instead.
48
-
49
- ### From Source
50
-
51
- ```bash
52
- git clone https://github.com/stephendolan/ynab-cli.git
53
- cd ynab-cli
54
- bun install
55
- bun run link # Build and link globally
56
- ```
28
+ Without libsecret, use `YNAB_API_KEY` environment variable instead.
29
+ </details>
57
30
 
58
31
  ## Authentication
59
32
 
60
- Set your YNAB personal access token using the CLI or environment variables:
61
-
62
33
  ```bash
63
- ynab auth login # Interactive token entry, stored in OS keychain
64
- ynab auth status # Check authentication status
65
- ynab auth logout # Remove stored credentials
34
+ ynab auth login # Store token in OS keychain
35
+ ynab auth status # Check authentication
36
+ ynab auth logout # Remove credentials
66
37
  ```
67
38
 
68
- Or use environment variables (recommended for development):
69
-
70
- ```env
71
- YNAB_API_KEY=your_personal_access_token
72
- YNAB_BUDGET_ID=your_default_budget_id # Optional
73
- ```
39
+ Or set `YNAB_API_KEY` environment variable.
74
40
 
75
- ## Usage
41
+ ## Commands
76
42
 
77
- ### Global Flags
43
+ ### Budgets
78
44
 
79
45
  ```bash
80
- --compact, -c # Minified JSON output (single line)
46
+ ynab budgets list
47
+ ynab budgets view [id]
48
+ ynab budgets set-default <id>
81
49
  ```
82
50
 
83
- ### Commands
84
-
85
- #### User
51
+ ### Accounts
86
52
 
87
53
  ```bash
88
- ynab user info # Get authenticated user information
54
+ ynab accounts list
55
+ ynab accounts view <id>
56
+ ynab accounts transactions <id>
89
57
  ```
90
58
 
91
- #### Budgets
59
+ ### Categories
92
60
 
93
61
  ```bash
94
- ynab budgets list # List all budgets
95
- ynab budgets view [id] # View budget details
96
- ynab budgets settings [id] # View budget settings
97
- ynab budgets set-default <id> # Set default budget
98
- ```
99
-
100
- #### Accounts
101
-
102
- ```bash
103
- ynab accounts list # List all accounts
104
- ynab accounts view <id> # View account details
105
- ynab accounts transactions <id> # List transactions for account
106
- ```
107
-
108
- #### Categories
109
-
110
- ```bash
111
- ynab categories list # List all categories
112
- ynab categories view <id> # View category details
62
+ ynab categories list
63
+ ynab categories view <id>
113
64
  ynab categories budget <id> --month <YYYY-MM> --amount <amount>
114
- ynab categories transactions <id> # List transactions for category
65
+ ynab categories transactions <id>
115
66
  ```
116
67
 
117
- #### Transactions
68
+ ### Transactions
118
69
 
119
70
  ```bash
120
- # List and filter
121
- ynab transactions list
122
- ynab transactions list --account <id>
123
- ynab transactions list --category <id>
124
- ynab transactions list --payee <id>
125
- ynab transactions list --since <YYYY-MM-DD> --until <YYYY-MM-DD>
126
- ynab transactions list --approved=false
127
- ynab transactions list --min-amount 100 --max-amount 500
128
- ynab transactions list --status=cleared,reconciled
71
+ # List with filters
72
+ ynab transactions list --account <id> --since <YYYY-MM-DD>
73
+ ynab transactions list --approved=false --min-amount 100
129
74
  ynab transactions list --fields id,date,amount,memo
130
75
 
131
76
  # Search
132
77
  ynab transactions search --memo "coffee"
133
78
  ynab transactions search --payee-name "Amazon"
134
- ynab transactions search --amount 42.50
135
79
 
136
- # CRUD operations
80
+ # CRUD
137
81
  ynab transactions view <id>
138
- ynab transactions create
139
82
  ynab transactions create --account <id> --amount <amount> --date <YYYY-MM-DD>
140
83
  ynab transactions update <id> --amount <amount>
141
84
  ynab transactions delete <id>
142
- ynab transactions import
143
- ynab transactions split <id> --splits '[{"amount": -50.00, "category_id": "xxx", "memo": "..."}]'
85
+ ynab transactions split <id> --splits '[{"amount": -50.00, "category_id": "xxx"}]'
144
86
  ```
145
87
 
146
- #### Scheduled Transactions
88
+ ### Payees
147
89
 
148
90
  ```bash
149
- ynab scheduled list # List all scheduled transactions
150
- ynab scheduled view <id> # View scheduled transaction
151
- ynab scheduled delete <id> # Delete scheduled transaction
91
+ ynab payees list
92
+ ynab payees view <id>
93
+ ynab payees update <id> --name <name>
94
+ ynab payees transactions <id>
152
95
  ```
153
96
 
154
- #### Payees
97
+ ### Months
155
98
 
156
99
  ```bash
157
- ynab payees list # List all payees
158
- ynab payees view <id> # View payee details
159
- ynab payees update <id> --name <name> # Rename payee
160
- ynab payees locations <id> # List locations for payee
161
- ynab payees transactions <id> # List transactions for payee
100
+ ynab months list
101
+ ynab months view <YYYY-MM>
162
102
  ```
163
103
 
164
- #### Months
104
+ ### Scheduled Transactions
165
105
 
166
106
  ```bash
167
- ynab months list # List all budget months
168
- ynab months view <YYYY-MM> # View specific month details
107
+ ynab scheduled list
108
+ ynab scheduled view <id>
109
+ ynab scheduled delete <id>
169
110
  ```
170
111
 
171
- #### Raw API Access
112
+ ### Raw API Access
172
113
 
173
114
  ```bash
174
- ynab api <method> <path> [--data <json>]
175
-
176
- # Examples:
177
115
  ynab api GET /budgets
178
- ynab api GET /budgets/{budget_id}/transactions
179
116
  ynab api POST /budgets/{budget_id}/transactions --data '{"transaction": {...}}'
180
117
  ```
181
118
 
182
- ## Output Format
119
+ ## Output
183
120
 
184
- All commands return JSON by default:
121
+ All commands return JSON. Use `--compact` for minified output.
185
122
 
186
- - **Lists**: Arrays of objects (not wrapped)
187
- - **Single items**: Objects directly
188
- - **Errors**: `{"error": {"name": "...", "detail": "...", "statusCode": 400}}`
189
-
190
- ## Currency Format
191
-
192
- **All amounts are in dollars.** The CLI automatically converts YNAB's internal milliunit format (1000 = $1.00) in both input and output.
193
-
194
- - Input: `--min-amount 100` means $100
195
- - Output: `"amount": -555.28` means -$555.28
123
+ **Amounts are in dollars** (not YNAB's internal milliunits). `--min-amount 100` means $100.
196
124
 
197
125
  ## API Limitations
198
126
 
199
- The YNAB API does not support:
200
-
201
- - Creating categories, category groups, or payees
202
- - Updating accounts (beyond initial creation)
203
-
204
- Use the YNAB web or mobile app for these operations.
205
-
206
- ## API Rate Limits
207
-
208
- The YNAB API enforces a rate limit of **200 requests per hour** per access token. When exceeded, the API returns HTTP 429 errors.
127
+ The YNAB API does not support creating categories, category groups, or payees. Use the web or mobile app for these.
209
128
 
210
- **If you hit the rate limit:**
211
- - Wait 5-10 minutes before retrying (the limit uses a rolling 60-minute window)
212
- - For batch operations, add delays between requests: `sleep 20` in shell loops ensures ~180 requests/hour
129
+ Rate limit: 200 requests/hour per token. If exceeded, wait 5-10 minutes.
213
130
 
214
131
  ## References
215
132
 
216
133
  - [YNAB API Documentation](https://api.ynab.com/)
217
- - [YNAB JavaScript SDK](https://github.com/ynab/ynab-sdk-js)
218
134
  - [Specification](./SPEC.md)
219
135
 
220
136
  ## License
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env bun
2
2
 
3
3
  // src/cli.ts
4
- import { Command as Command11 } from "commander";
4
+ import { Command as Command12 } from "commander";
5
5
 
6
6
  // src/lib/errors.ts
7
7
  var YnabCliError = class extends Error {
@@ -1287,9 +1287,154 @@ function createApiCommand() {
1287
1287
  return cmd;
1288
1288
  }
1289
1289
 
1290
+ // src/commands/mcp.ts
1291
+ import { Command as Command11 } from "commander";
1292
+
1293
+ // src/mcp/server.ts
1294
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
1295
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
1296
+ import { z } from "zod";
1297
+ var server = new McpServer({
1298
+ name: "ynab",
1299
+ version: "1.0.0"
1300
+ });
1301
+ function jsonResponse(data) {
1302
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
1303
+ }
1304
+ function currencyResponse(data) {
1305
+ return jsonResponse(convertMilliunitsToAmounts(data));
1306
+ }
1307
+ server.tool(
1308
+ "list_budgets",
1309
+ "List all budgets in the YNAB account",
1310
+ { includeAccounts: z.boolean().optional().describe("Include account details") },
1311
+ async ({ includeAccounts }) => currencyResponse(await client.getBudgets(includeAccounts))
1312
+ );
1313
+ server.tool(
1314
+ "get_budget",
1315
+ "Get detailed information about a specific budget",
1316
+ { budgetId: z.string().optional().describe("Budget ID (uses default if not specified)") },
1317
+ async ({ budgetId }) => currencyResponse(await client.getBudget(budgetId))
1318
+ );
1319
+ server.tool(
1320
+ "list_accounts",
1321
+ "List all accounts in a budget",
1322
+ { budgetId: z.string().optional().describe("Budget ID (uses default if not specified)") },
1323
+ async ({ budgetId }) => currencyResponse(await client.getAccounts(budgetId))
1324
+ );
1325
+ server.tool(
1326
+ "get_account",
1327
+ "Get detailed information about a specific account",
1328
+ {
1329
+ accountId: z.string().describe("Account ID"),
1330
+ budgetId: z.string().optional().describe("Budget ID (uses default if not specified)")
1331
+ },
1332
+ async ({ accountId, budgetId }) => currencyResponse(await client.getAccount(accountId, budgetId))
1333
+ );
1334
+ server.tool(
1335
+ "list_categories",
1336
+ "List all category groups and categories in a budget",
1337
+ { budgetId: z.string().optional().describe("Budget ID (uses default if not specified)") },
1338
+ async ({ budgetId }) => currencyResponse(await client.getCategories(budgetId))
1339
+ );
1340
+ server.tool(
1341
+ "get_category",
1342
+ "Get detailed information about a specific category",
1343
+ {
1344
+ categoryId: z.string().describe("Category ID"),
1345
+ budgetId: z.string().optional().describe("Budget ID (uses default if not specified)")
1346
+ },
1347
+ async ({ categoryId, budgetId }) => currencyResponse(await client.getCategory(categoryId, budgetId))
1348
+ );
1349
+ server.tool(
1350
+ "list_transactions",
1351
+ "List transactions with optional filtering",
1352
+ {
1353
+ budgetId: z.string().optional().describe("Budget ID (uses default if not specified)"),
1354
+ sinceDate: z.string().optional().describe("Only return transactions on or after this date (YYYY-MM-DD)"),
1355
+ type: z.enum(["uncategorized", "unapproved"]).optional().describe("Filter by transaction type")
1356
+ },
1357
+ async ({ budgetId, sinceDate, type }) => currencyResponse(await client.getTransactions({ budgetId, sinceDate, type }))
1358
+ );
1359
+ server.tool(
1360
+ "get_transaction",
1361
+ "Get detailed information about a specific transaction",
1362
+ {
1363
+ transactionId: z.string().describe("Transaction ID"),
1364
+ budgetId: z.string().optional().describe("Budget ID (uses default if not specified)")
1365
+ },
1366
+ async ({ transactionId, budgetId }) => currencyResponse(await client.getTransaction(transactionId, budgetId))
1367
+ );
1368
+ server.tool(
1369
+ "list_transactions_by_account",
1370
+ "List transactions for a specific account",
1371
+ {
1372
+ accountId: z.string().describe("Account ID"),
1373
+ budgetId: z.string().optional().describe("Budget ID (uses default if not specified)"),
1374
+ sinceDate: z.string().optional().describe("Only return transactions on or after this date (YYYY-MM-DD)")
1375
+ },
1376
+ async ({ accountId, budgetId, sinceDate }) => currencyResponse(await client.getTransactionsByAccount(accountId, { budgetId, sinceDate }))
1377
+ );
1378
+ server.tool(
1379
+ "list_transactions_by_category",
1380
+ "List transactions for a specific category",
1381
+ {
1382
+ categoryId: z.string().describe("Category ID"),
1383
+ budgetId: z.string().optional().describe("Budget ID (uses default if not specified)"),
1384
+ sinceDate: z.string().optional().describe("Only return transactions on or after this date (YYYY-MM-DD)")
1385
+ },
1386
+ async ({ categoryId, budgetId, sinceDate }) => currencyResponse(await client.getTransactionsByCategory(categoryId, { budgetId, sinceDate }))
1387
+ );
1388
+ server.tool(
1389
+ "list_payees",
1390
+ "List all payees in a budget",
1391
+ { budgetId: z.string().optional().describe("Budget ID (uses default if not specified)") },
1392
+ async ({ budgetId }) => jsonResponse(await client.getPayees(budgetId))
1393
+ );
1394
+ server.tool(
1395
+ "get_budget_month",
1396
+ "Get budget details for a specific month",
1397
+ {
1398
+ month: z.string().describe("Month in YYYY-MM-DD format (day is ignored, use first of month)"),
1399
+ budgetId: z.string().optional().describe("Budget ID (uses default if not specified)")
1400
+ },
1401
+ async ({ month, budgetId }) => currencyResponse(await client.getBudgetMonth(month, budgetId))
1402
+ );
1403
+ server.tool(
1404
+ "list_scheduled_transactions",
1405
+ "List all scheduled transactions in a budget",
1406
+ { budgetId: z.string().optional().describe("Budget ID (uses default if not specified)") },
1407
+ async ({ budgetId }) => currencyResponse(await client.getScheduledTransactions(budgetId))
1408
+ );
1409
+ server.tool(
1410
+ "get_user",
1411
+ "Get information about the authenticated user",
1412
+ {},
1413
+ async () => jsonResponse(await client.getUser())
1414
+ );
1415
+ server.tool(
1416
+ "check_auth",
1417
+ "Check if YNAB authentication is configured",
1418
+ {},
1419
+ async () => jsonResponse({ authenticated: await auth.isAuthenticated() })
1420
+ );
1421
+ async function runMcpServer() {
1422
+ const transport = new StdioServerTransport();
1423
+ await server.connect(transport);
1424
+ }
1425
+
1426
+ // src/commands/mcp.ts
1427
+ function createMcpCommand() {
1428
+ const cmd = new Command11("mcp").description("Run YNAB MCP server");
1429
+ cmd.action(async () => {
1430
+ await runMcpServer();
1431
+ });
1432
+ return cmd;
1433
+ }
1434
+
1290
1435
  // src/cli.ts
1291
- var program = new Command11();
1292
- program.name("ynab").description("A command-line interface for You Need a Budget (YNAB)").version("2.1.1").option("-c, --compact", "Minified JSON output (single line)").hook("preAction", (thisCommand) => {
1436
+ var program = new Command12();
1437
+ program.name("ynab").description("A command-line interface for You Need a Budget (YNAB)").version("2.2.0").option("-c, --compact", "Minified JSON output (single line)").hook("preAction", (thisCommand) => {
1293
1438
  const options = thisCommand.opts();
1294
1439
  setOutputOptions({
1295
1440
  compact: options.compact
@@ -1305,5 +1450,6 @@ program.addCommand(createScheduledCommand());
1305
1450
  program.addCommand(createPayeesCommand());
1306
1451
  program.addCommand(createMonthsCommand());
1307
1452
  program.addCommand(createApiCommand());
1453
+ program.addCommand(createMcpCommand());
1308
1454
  program.parse();
1309
1455
  //# sourceMappingURL=cli.js.map
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/lib/errors.ts","../src/lib/utils.ts","../src/lib/output.ts","../src/commands/auth.ts","../src/lib/auth.ts","../src/lib/config.ts","../src/lib/api-client.ts","../src/lib/command-utils.ts","../src/commands/user.ts","../src/commands/budgets.ts","../src/commands/accounts.ts","../src/lib/dates.ts","../src/commands/categories.ts","../src/commands/transactions.ts","../src/lib/schemas.ts","../src/commands/scheduled.ts","../src/commands/payees.ts","../src/commands/months.ts","../src/commands/api.ts"],"sourcesContent":["#!/usr/bin/env bun\n\nimport { Command } from 'commander';\nimport { setOutputOptions } from './lib/output.js';\nimport { createAuthCommand } from './commands/auth.js';\nimport { createUserCommand } from './commands/user.js';\nimport { createBudgetsCommand } from './commands/budgets.js';\nimport { createAccountsCommand } from './commands/accounts.js';\nimport { createCategoriesCommand } from './commands/categories.js';\nimport { createTransactionsCommand } from './commands/transactions.js';\nimport { createScheduledCommand } from './commands/scheduled.js';\nimport { createPayeesCommand } from './commands/payees.js';\nimport { createMonthsCommand } from './commands/months.js';\nimport { createApiCommand } from './commands/api.js';\n\ndeclare const __VERSION__: string;\n\nconst program = new Command();\n\nprogram\n .name('ynab')\n .description('A command-line interface for You Need a Budget (YNAB)')\n .version(__VERSION__)\n .option('-c, --compact', 'Minified JSON output (single line)')\n .hook('preAction', (thisCommand) => {\n const options = thisCommand.opts();\n setOutputOptions({\n compact: options.compact,\n });\n });\n\nprogram.addCommand(createAuthCommand());\nprogram.addCommand(createUserCommand());\nprogram.addCommand(createBudgetsCommand());\nprogram.addCommand(createAccountsCommand());\nprogram.addCommand(createCategoriesCommand());\nprogram.addCommand(createTransactionsCommand());\nprogram.addCommand(createScheduledCommand());\nprogram.addCommand(createPayeesCommand());\nprogram.addCommand(createMonthsCommand());\nprogram.addCommand(createApiCommand());\n\nprogram.parse();\n","import type { YnabError } from '../types/index.js';\nimport { outputJson } from './output.js';\n\nexport class YnabCliError extends Error {\n constructor(\n message: string,\n public statusCode?: number\n ) {\n super(message);\n this.name = 'YnabCliError';\n }\n}\n\nconst ERROR_STATUS_CODES: Record<string, number> = {\n bad_request: 400,\n not_authorized: 401,\n subscription_lapsed: 403,\n trial_expired: 403,\n unauthorized_scope: 403,\n data_limit_reached: 403,\n not_found: 404,\n resource_not_found: 404,\n conflict: 409,\n too_many_requests: 429,\n internal_server_error: 500,\n service_unavailable: 503,\n};\n\nexport function sanitizeErrorMessage(message: string): string {\n const sensitivePatterns = [\n /Bearer\\s+[\\w\\-._~+/]+=*/gi,\n /token[=:]\\s*[\\w\\-._~+/]+=*/gi,\n /api[_-]?key[=:]\\s*[\\w\\-._~+/]+=*/gi,\n /authorization:\\s*bearer\\s+[\\w\\-._~+/]+=*/gi,\n ];\n\n let sanitized = message;\n for (const pattern of sensitivePatterns) {\n sanitized = sanitized.replace(pattern, '[REDACTED]');\n }\n\n return sanitized.length > 500 ? sanitized.substring(0, 500) + '...' : sanitized;\n}\n\ninterface YnabApiError {\n name?: string;\n detail?: string;\n message?: string;\n id?: string;\n}\n\nfunction isErrorObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nexport function sanitizeApiError(error: unknown): YnabError {\n if (!isErrorObject(error)) {\n return {\n name: 'api_error',\n detail: 'An error occurred',\n id: undefined,\n };\n }\n\n const apiError = error as YnabApiError;\n const detail = sanitizeErrorMessage(\n String(apiError.detail || apiError.message || 'An error occurred')\n );\n\n return {\n name: apiError.name || 'api_error',\n detail,\n id: apiError.id,\n };\n}\n\nfunction enhanceRateLimitMessage(detail: string): string {\n return `${detail}\\n\\nYNAB API limit: 200 requests/hour (rolling window). Wait a few minutes and retry.`;\n}\n\nfunction formatErrorResponse(name: string, detail: string, statusCode: number): never {\n const enhancedDetail = name === 'too_many_requests' ? enhanceRateLimitMessage(detail) : detail;\n\n outputJson({ error: { name, detail: enhancedDetail, statusCode } });\n process.exit(1);\n}\n\nexport function handleYnabError(error: unknown): never {\n if (!isErrorObject(error)) {\n formatErrorResponse('unknown_error', 'An unexpected error occurred', 1);\n }\n\n const errorObj = error as { error?: unknown; message?: string };\n\n if (errorObj.error) {\n const ynabError: YnabError = sanitizeApiError(errorObj.error);\n formatErrorResponse(\n ynabError.name,\n ynabError.detail,\n ERROR_STATUS_CODES[ynabError.name] || 500\n );\n }\n\n if (error instanceof YnabCliError) {\n const sanitized = sanitizeErrorMessage(error.message);\n formatErrorResponse('cli_error', sanitized, error.statusCode || 1);\n }\n\n const sanitized = sanitizeErrorMessage(errorObj.message || 'An unexpected error occurred');\n formatErrorResponse('unknown_error', sanitized, 1);\n}\n","import { YnabCliError } from './errors.js';\n\nexport function milliunitsToAmount(milliunits: number): number {\n return milliunits / 1000;\n}\n\nexport function amountToMilliunits(amount: number): number {\n return Math.round(amount * 1000);\n}\n\nexport function convertMilliunitsToAmounts(data: unknown): unknown {\n if (data === null || data === undefined) return data;\n if (Array.isArray(data)) return data.map(convertMilliunitsToAmounts);\n if (typeof data !== 'object') return data;\n\n const converted: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(data)) {\n if (isAmountField(key) && typeof value === 'number') {\n converted[key] = milliunitsToAmount(value);\n } else if (\n isDebtAmountMapField(key) &&\n typeof value === 'object' &&\n value !== null &&\n !Array.isArray(value)\n ) {\n const convertedMap: Record<string, unknown> = {};\n for (const [dateKey, amountValue] of Object.entries(value)) {\n convertedMap[dateKey] =\n typeof amountValue === 'number' ? milliunitsToAmount(amountValue) : amountValue;\n }\n converted[key] = convertedMap;\n } else {\n converted[key] = convertMilliunitsToAmounts(value);\n }\n }\n return converted;\n}\n\nfunction isAmountField(fieldName: string): boolean {\n const amountFields = [\n 'amount',\n 'balance',\n 'cleared_balance',\n 'uncleared_balance',\n 'budgeted',\n 'activity',\n 'available',\n 'goal_target',\n 'goal_under_funded',\n 'goal_overall_funded',\n 'goal_overall_left',\n 'income',\n 'to_be_budgeted',\n 'debt_original_balance',\n ];\n\n return amountFields.includes(fieldName) || fieldName.endsWith('_amount');\n}\n\nfunction isDebtAmountMapField(fieldName: string): boolean {\n const debtAmountMapFields = [\n 'debt_minimum_payments',\n 'debt_escrow_amounts',\n 'debt_interest_rates',\n ];\n\n return debtAmountMapFields.includes(fieldName);\n}\n\nexport function parseApprovedFilter(value: string): boolean {\n const normalized = value.toLowerCase();\n if (normalized !== 'true' && normalized !== 'false') {\n throw new YnabCliError(`--approved must be 'true' or 'false', got '${value}'`, 400);\n }\n return normalized === 'true';\n}\n\nexport function parseStatusFilter(value: string): string[] {\n const statuses = value.split(',').map((s) => s.trim().toLowerCase());\n const validStatuses = ['cleared', 'uncleared', 'reconciled'];\n\n for (const status of statuses) {\n if (!validStatuses.includes(status)) {\n throw new YnabCliError(\n `Invalid status '${status}'. Must be one of: ${validStatuses.join(', ')}`,\n 400\n );\n }\n }\n\n return statuses;\n}\n\nexport type TransactionLike = {\n date: string;\n amount: number;\n approved: boolean;\n cleared: string;\n};\n\nexport function applyTransactionFilters<T extends TransactionLike>(\n transactions: T[],\n filters: {\n until?: string;\n approved?: string;\n status?: string;\n minAmount?: number;\n maxAmount?: number;\n }\n): T[] {\n let filtered = transactions;\n\n if (filters.until) {\n filtered = filtered.filter((t) => t.date <= filters.until!);\n }\n\n if (filters.approved !== undefined) {\n const approvedValue = parseApprovedFilter(filters.approved);\n filtered = filtered.filter((t) => t.approved === approvedValue);\n }\n\n if (filters.status) {\n const statuses = parseStatusFilter(filters.status);\n filtered = filtered.filter((t) => statuses.includes(t.cleared.toLowerCase()));\n }\n\n if (filters.minAmount !== undefined) {\n const minMilliunits = amountToMilliunits(filters.minAmount);\n filtered = filtered.filter((t) => t.amount >= minMilliunits);\n }\n\n if (filters.maxAmount !== undefined) {\n const maxMilliunits = amountToMilliunits(filters.maxAmount);\n filtered = filtered.filter((t) => t.amount <= maxMilliunits);\n }\n\n return filtered;\n}\n\nexport function applyFieldSelection<T>(items: T[], fields?: string): Partial<T>[] {\n if (!fields) return items;\n\n const fieldList = fields.split(',').map((f) => f.trim());\n return items.map((item) => {\n const filtered: Partial<T> = {};\n const itemRecord = item as Record<string, unknown>;\n for (const field of fieldList) {\n if (field in itemRecord) {\n (filtered as Record<string, unknown>)[field] = itemRecord[field];\n }\n }\n return filtered;\n });\n}\n","import type { OutputOptions } from '../types/index.js';\nimport { convertMilliunitsToAmounts } from './utils.js';\n\nlet globalOutputOptions: OutputOptions = {};\n\nexport function setOutputOptions(options: OutputOptions): void {\n globalOutputOptions = options;\n}\n\nexport function outputJson(data: unknown, options: OutputOptions = {}): void {\n const convertedData = convertMilliunitsToAmounts(data);\n const mergedOptions = { ...globalOutputOptions, ...options };\n const jsonString = mergedOptions.compact\n ? JSON.stringify(convertedData)\n : JSON.stringify(convertedData, null, 2);\n\n console.log(jsonString);\n}\n","import { Command } from 'commander';\nimport { auth } from '../lib/auth.js';\nimport { outputJson } from '../lib/output.js';\nimport { client } from '../lib/api-client.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\nimport { YnabCliError } from '../lib/errors.js';\n\nexport function createAuthCommand(): Command {\n const cmd = new Command('auth').description('Authentication management');\n\n cmd\n .command('login')\n .description('Configure access token')\n .requiredOption('-t, --token <token>', 'YNAB Personal Access Token')\n .action(\n withErrorHandling(async (options: { token: string }) => {\n const token = options.token.trim();\n if (!token) {\n throw new YnabCliError('Access token cannot be empty', 400);\n }\n await auth.setAccessToken(token);\n client.clearApi();\n\n try {\n const user = await client.getUser();\n outputJson({\n message: 'Successfully authenticated',\n user: { id: user?.id },\n });\n } catch (error) {\n await auth.deleteAccessToken();\n client.clearApi();\n throw error;\n }\n })\n );\n\n cmd\n .command('status')\n .description('Check authentication status')\n .action(\n withErrorHandling(async () => {\n const isAuthenticated = await auth.isAuthenticated();\n\n if (!isAuthenticated) {\n outputJson({ authenticated: false, message: 'Not authenticated' });\n return;\n }\n\n try {\n const user = await client.getUser();\n outputJson({ authenticated: true, user: { id: user?.id } });\n } catch {\n outputJson({ authenticated: false, message: 'Token exists but is invalid' });\n }\n })\n );\n\n cmd\n .command('logout')\n .description('Remove stored credentials')\n .action(\n withErrorHandling(async () => {\n await auth.logout();\n client.clearApi();\n outputJson({ message: 'Successfully logged out' });\n })\n );\n\n return cmd;\n}\n","import { Entry } from '@napi-rs/keyring';\nimport { config } from './config.js';\n\nconst SERVICE_NAME = 'ynab-cli';\nconst ACCOUNT_NAME = 'access-token';\n\nconst KEYRING_UNAVAILABLE_ERROR =\n 'Keychain storage unavailable. Cannot store credentials securely.\\n' +\n 'On Linux, install libsecret: sudo apt-get install libsecret-1-dev\\n' +\n 'Then reinstall: bun install -g @stephendolan/ynab-cli\\n' +\n 'Alternatively, use the YNAB_API_KEY environment variable.';\n\nlet keyring: Entry | null | undefined = undefined;\n\nfunction getKeyring(): Entry | null {\n if (keyring !== undefined) {\n return keyring;\n }\n try {\n keyring = new Entry(SERVICE_NAME, ACCOUNT_NAME);\n } catch {\n keyring = null;\n }\n return keyring;\n}\n\nexport function resetKeyringForTesting(): void {\n keyring = undefined;\n}\n\nexport class AuthManager {\n async getAccessToken(): Promise<string | null> {\n const entry = getKeyring();\n if (entry) {\n try {\n return entry.getPassword();\n } catch {\n return null;\n }\n }\n return null;\n }\n\n async setAccessToken(token: string): Promise<void> {\n const entry = getKeyring();\n if (!entry) {\n throw new Error(KEYRING_UNAVAILABLE_ERROR);\n }\n try {\n entry.setPassword(token);\n } catch (error) {\n throw new Error(\n `Failed to store token in keychain: ${error instanceof Error ? error.message : error}\\n\\n` +\n 'On Linux, ensure the Secret Service is running and unlocked.\\n' +\n 'Try: gnome-keyring-daemon --unlock\\n' +\n 'Or use the YNAB_API_KEY environment variable instead.'\n );\n }\n }\n\n async deleteAccessToken(): Promise<boolean> {\n const entry = getKeyring();\n if (entry) {\n return entry.deletePassword();\n }\n return false;\n }\n\n async isAuthenticated(): Promise<boolean> {\n return (await this.getAccessToken()) !== null;\n }\n\n async logout(): Promise<void> {\n await this.deleteAccessToken();\n config.clearDefaultBudget();\n }\n}\n\nexport const auth = new AuthManager();\n","import Conf from 'conf';\nimport type { Config } from '../types/index.js';\n\nclass ConfigManager {\n private conf: Conf<Config>;\n\n constructor() {\n this.conf = new Conf<Config>({\n projectName: 'ynab-cli',\n schema: {\n defaultBudget: { type: 'string' },\n version: { type: 'string', default: '1.0.0' },\n },\n defaults: { version: '1.0.0' },\n });\n }\n\n getDefaultBudget(): string | undefined {\n return this.conf.get('defaultBudget');\n }\n\n setDefaultBudget(budgetId: string): void {\n this.conf.set('defaultBudget', budgetId);\n }\n\n clearDefaultBudget(): void {\n this.conf.delete('defaultBudget');\n }\n\n clear(): void {\n this.conf.clear();\n }\n}\n\nexport const config = new ConfigManager();\n","import * as ynab from 'ynab';\nimport { config } from './config.js';\nimport { YnabCliError, handleYnabError, sanitizeApiError } from './errors.js';\nimport { auth } from './auth.js';\n\ntype TransactionTypeFilter = 'uncategorized' | 'unapproved' | undefined;\n\nexport class YnabClient {\n private api: ynab.API | null = null;\n private envVarWarningShown = false;\n\n clearApi(): void {\n this.api = null;\n this.envVarWarningShown = false;\n }\n\n async getApi(): Promise<ynab.API> {\n if (this.api) {\n return this.api;\n }\n\n const keychainToken = await auth.getAccessToken();\n const accessToken = keychainToken || process.env.YNAB_API_KEY || null;\n\n if (!accessToken) {\n throw new YnabCliError(\n 'Not authenticated. Please run: ynab auth login or set YNAB_API_KEY environment variable',\n 401\n );\n }\n\n if (!keychainToken && process.env.YNAB_API_KEY && !this.envVarWarningShown) {\n console.warn(\n '\\x1b[33m⚠️ WARNING: Using YNAB_API_KEY environment variable.\\n' +\n 'Environment variables may be visible to other processes.\\n' +\n 'For better security, use: ynab auth login\\x1b[0m\\n'\n );\n this.envVarWarningShown = true;\n }\n\n this.api = new ynab.API(accessToken);\n return this.api;\n }\n\n async getBudgetId(budgetIdOrDefault?: string): Promise<string> {\n const budgetId = budgetIdOrDefault || config.getDefaultBudget() || process.env.YNAB_BUDGET_ID;\n\n if (!budgetId) {\n throw new YnabCliError(\n 'No budget specified. Use --budget flag, set default with \"ynab budgets set-default\", or set YNAB_BUDGET_ID environment variable',\n 400\n );\n }\n\n return budgetId;\n }\n\n private async withErrorHandling<T>(fn: () => Promise<T>): Promise<T> {\n try {\n return await fn();\n } catch (error) {\n handleYnabError(error);\n }\n }\n\n async getUser() {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const response = await api.user.getUser();\n return response.data.user;\n });\n }\n\n async getBudgets(includeAccounts = false) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const response = await api.budgets.getBudgets(includeAccounts);\n return {\n budgets: response.data.budgets,\n server_knowledge: 0,\n };\n });\n }\n\n async getBudget(budgetId?: string, lastKnowledgeOfServer?: number) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.budgets.getBudgetById(id, lastKnowledgeOfServer);\n return {\n budget: response.data.budget,\n server_knowledge: response.data.server_knowledge,\n };\n });\n }\n\n async getBudgetSettings(budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.budgets.getBudgetSettingsById(id);\n return response.data.settings;\n });\n }\n\n async getAccounts(budgetId?: string, lastKnowledgeOfServer?: number) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.accounts.getAccounts(id, lastKnowledgeOfServer);\n return {\n accounts: response.data.accounts,\n server_knowledge: response.data.server_knowledge,\n };\n });\n }\n\n async getAccount(accountId: string, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.accounts.getAccountById(id, accountId);\n return response.data.account;\n });\n }\n\n async getCategories(budgetId?: string, lastKnowledgeOfServer?: number) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.categories.getCategories(id, lastKnowledgeOfServer);\n return {\n category_groups: response.data.category_groups,\n server_knowledge: response.data.server_knowledge,\n };\n });\n }\n\n async getCategory(categoryId: string, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.categories.getCategoryById(id, categoryId);\n return response.data.category;\n });\n }\n\n async updateMonthCategory(\n month: string,\n categoryId: string,\n data: ynab.PatchMonthCategoryWrapper,\n budgetId?: string\n ) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.categories.updateMonthCategory(id, month, categoryId, data);\n return response.data.category;\n });\n }\n\n async getPayees(budgetId?: string, lastKnowledgeOfServer?: number) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.payees.getPayees(id, lastKnowledgeOfServer);\n return {\n payees: response.data.payees,\n server_knowledge: response.data.server_knowledge,\n };\n });\n }\n\n async getPayee(payeeId: string, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.payees.getPayeeById(id, payeeId);\n return response.data.payee;\n });\n }\n\n async updatePayee(payeeId: string, data: ynab.PatchPayeeWrapper, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.payees.updatePayee(id, payeeId, data);\n return response.data.payee;\n });\n }\n\n async getPayeeLocationsByPayee(payeeId: string, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.payeeLocations.getPayeeLocationsByPayee(id, payeeId);\n return response.data.payee_locations;\n });\n }\n\n async getBudgetMonths(budgetId?: string, lastKnowledgeOfServer?: number) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.months.getBudgetMonths(id, lastKnowledgeOfServer);\n return {\n months: response.data.months,\n server_knowledge: response.data.server_knowledge,\n };\n });\n }\n\n async getBudgetMonth(month: string, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.months.getBudgetMonth(id, month);\n return response.data.month;\n });\n }\n\n async getTransactions(params: {\n budgetId?: string;\n sinceDate?: string;\n type?: string;\n lastKnowledgeOfServer?: number;\n }) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(params.budgetId);\n const response = await api.transactions.getTransactions(\n id,\n params.sinceDate,\n params.type as TransactionTypeFilter,\n params.lastKnowledgeOfServer\n );\n return {\n transactions: response.data.transactions,\n server_knowledge: response.data.server_knowledge,\n };\n });\n }\n\n async getTransactionsByAccount(\n accountId: string,\n params: {\n budgetId?: string;\n sinceDate?: string;\n type?: string;\n lastKnowledgeOfServer?: number;\n }\n ) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(params.budgetId);\n const response = await api.transactions.getTransactionsByAccount(\n id,\n accountId,\n params.sinceDate,\n params.type as TransactionTypeFilter,\n params.lastKnowledgeOfServer\n );\n return {\n transactions: response.data.transactions,\n server_knowledge: response.data.server_knowledge,\n };\n });\n }\n\n async getTransactionsByCategory(\n categoryId: string,\n params: {\n budgetId?: string;\n sinceDate?: string;\n type?: string;\n lastKnowledgeOfServer?: number;\n }\n ) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(params.budgetId);\n const response = await api.transactions.getTransactionsByCategory(\n id,\n categoryId,\n params.sinceDate,\n params.type as TransactionTypeFilter,\n params.lastKnowledgeOfServer\n );\n return {\n transactions: response.data.transactions,\n server_knowledge: response.data.server_knowledge,\n };\n });\n }\n\n async getTransactionsByPayee(\n payeeId: string,\n params: {\n budgetId?: string;\n sinceDate?: string;\n type?: string;\n lastKnowledgeOfServer?: number;\n }\n ) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(params.budgetId);\n const response = await api.transactions.getTransactionsByPayee(\n id,\n payeeId,\n params.sinceDate,\n params.type as TransactionTypeFilter,\n params.lastKnowledgeOfServer\n );\n return {\n transactions: response.data.transactions,\n server_knowledge: response.data.server_knowledge,\n };\n });\n }\n\n async getTransaction(transactionId: string, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.transactions.getTransactionById(id, transactionId);\n return response.data.transaction;\n });\n }\n\n async createTransaction(transactionData: ynab.PostTransactionsWrapper, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.transactions.createTransaction(id, transactionData);\n return response.data.transaction;\n });\n }\n\n async updateTransaction(\n transactionId: string,\n transactionData: ynab.PutTransactionWrapper,\n budgetId?: string\n ) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.transactions.updateTransaction(id, transactionId, transactionData);\n return response.data.transaction;\n });\n }\n\n async deleteTransaction(transactionId: string, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.transactions.deleteTransaction(id, transactionId);\n return response.data.transaction;\n });\n }\n\n async importTransactions(budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.transactions.importTransactions(id);\n return response.data.transaction_ids;\n });\n }\n\n async getScheduledTransactions(budgetId?: string, lastKnowledgeOfServer?: number) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.scheduledTransactions.getScheduledTransactions(\n id,\n lastKnowledgeOfServer\n );\n return {\n scheduled_transactions: response.data.scheduled_transactions,\n server_knowledge: response.data.server_knowledge,\n };\n });\n }\n\n async getScheduledTransaction(scheduledTransactionId: string, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.scheduledTransactions.getScheduledTransactionById(\n id,\n scheduledTransactionId\n );\n return response.data.scheduled_transaction;\n });\n }\n\n async deleteScheduledTransaction(scheduledTransactionId: string, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.scheduledTransactions.deleteScheduledTransaction(\n id,\n scheduledTransactionId\n );\n return response.data.scheduled_transaction;\n });\n }\n\n async rawApiCall(method: string, path: string, data?: unknown, budgetId?: string) {\n return this.withErrorHandling(async () => {\n await this.getApi();\n\n const fullPath = path.includes('{budget_id}')\n ? path.replace('{budget_id}', await this.getBudgetId(budgetId))\n : path;\n\n const url = `https://api.ynab.com/v1${fullPath}`;\n const accessToken = (await auth.getAccessToken()) || process.env.YNAB_API_KEY;\n const headers = {\n Authorization: `Bearer ${accessToken}`,\n 'Content-Type': 'application/json',\n };\n\n const httpMethod = method.toUpperCase();\n const hasBody = ['POST', 'PUT', 'PATCH'].includes(httpMethod);\n\n if (!['GET', 'POST', 'PUT', 'PATCH', 'DELETE'].includes(httpMethod)) {\n throw new YnabCliError(`Unsupported HTTP method: ${method}`, 400);\n }\n\n const response = await fetch(url, {\n method: httpMethod,\n headers,\n ...(hasBody && { body: JSON.stringify(data) }),\n });\n\n if (!response.ok) {\n const errorData = (await response.json()) as Record<string, unknown>;\n throw { error: sanitizeApiError(errorData.error || errorData) };\n }\n\n return await response.json();\n });\n }\n}\n\nexport const client = new YnabClient();\n","import { handleYnabError, YnabCliError } from './errors.js';\n\nexport function withErrorHandling<TArgs extends unknown[], R>(\n fn: (...args: TArgs) => Promise<R>\n): (...args: TArgs) => Promise<void> {\n return async (...args: TArgs) => {\n try {\n await fn(...args);\n } catch (error) {\n handleYnabError(error);\n }\n };\n}\n\nexport function requireConfirmation(itemType: string, confirmed: boolean = false): void {\n if (!confirmed) {\n throw new YnabCliError(\n `Deleting ${itemType} requires --yes flag to confirm`,\n 400\n );\n }\n}\n\nexport function buildUpdateObject<T>(\n options: T,\n mapping: Record<string, string>\n): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n const optionsRecord = options as Record<string, unknown>;\n\n for (const [optionKey, targetKey] of Object.entries(mapping)) {\n if (optionsRecord[optionKey] !== undefined) {\n result[targetKey] = optionsRecord[optionKey];\n }\n }\n\n return result;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputJson } from '../lib/output.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\n\nexport function createUserCommand(): Command {\n const cmd = new Command('user').description('User information');\n\n cmd\n .command('info')\n .description('Get authenticated user information')\n .action(\n withErrorHandling(async () => {\n const user = await client.getUser();\n outputJson(user);\n })\n );\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { config } from '../lib/config.js';\nimport { outputJson } from '../lib/output.js';\nimport { YnabCliError } from '../lib/errors.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\n\nexport function createBudgetsCommand(): Command {\n const cmd = new Command('budgets').description('Budget operations');\n\n cmd\n .command('list')\n .description('List all budgets')\n .option('--include-accounts', 'Include accounts in response')\n .action(\n withErrorHandling(async (options: { includeAccounts?: boolean }) => {\n const result = await client.getBudgets(options.includeAccounts);\n outputJson(result?.budgets);\n })\n );\n\n cmd\n .command('view')\n .description('View budget details (uses default if no id provided)')\n .argument('[id]', 'Budget ID')\n .action(\n withErrorHandling(async (id: string | undefined) => {\n const result = await client.getBudget(id);\n outputJson(result?.budget);\n })\n );\n\n cmd\n .command('settings')\n .description('View budget settings')\n .argument('[id]', 'Budget ID')\n .action(\n withErrorHandling(async (id: string | undefined) => {\n const settings = await client.getBudgetSettings(id);\n outputJson(settings);\n })\n );\n\n cmd\n .command('set-default')\n .description('Set default budget for commands')\n .argument('<id>', 'Budget ID')\n .action(\n withErrorHandling(async (id: string) => {\n const result = await client.getBudgets();\n const budget = result?.budgets.find((b) => b.id === id);\n\n if (!budget) {\n throw new YnabCliError(`Budget with ID ${id} not found`, 404);\n }\n\n config.setDefaultBudget(id);\n outputJson({\n message: 'Default budget set',\n budget: { id: budget.id, name: budget.name },\n });\n })\n );\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputJson } from '../lib/output.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\nimport { parseDate } from '../lib/dates.js';\nimport type { CommandOptions } from '../types/index.js';\n\nexport function createAccountsCommand(): Command {\n const cmd = new Command('accounts').description('Account operations');\n\n cmd\n .command('list')\n .description('List all accounts')\n .option('-b, --budget <id>', 'Budget ID')\n .action(\n withErrorHandling(async (options: CommandOptions) => {\n const result = await client.getAccounts(options.budget);\n outputJson(result?.accounts);\n })\n );\n\n cmd\n .command('view')\n .description('View account details')\n .argument('<id>', 'Account ID')\n .option('-b, --budget <id>', 'Budget ID')\n .action(\n withErrorHandling(async (id: string, options: CommandOptions) => {\n const account = await client.getAccount(id, options.budget);\n outputJson(account);\n })\n );\n\n cmd\n .command('transactions')\n .description('List transactions for account')\n .argument('<id>', 'Account ID')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--since <date>', 'Filter transactions since date')\n .option('--type <type>', 'Filter by transaction type')\n .action(\n withErrorHandling(\n async (\n id: string,\n options: {\n budget?: string;\n since?: string;\n type?: string;\n } & CommandOptions\n ) => {\n const result = await client.getTransactionsByAccount(id, {\n budgetId: options.budget,\n sinceDate: options.since ? parseDate(options.since) : undefined,\n type: options.type,\n });\n outputJson(result?.transactions);\n }\n )\n );\n\n return cmd;\n}\n","import dayjs from 'dayjs';\nimport { YnabCliError } from './errors.js';\n\nexport function parseDate(input: string): string {\n const d = dayjs(input);\n if (!d.isValid()) {\n throw new YnabCliError(`Invalid date: ${input}`, 400);\n }\n return d.format('YYYY-MM-DD');\n}\n\nexport function todayDate(): string {\n return dayjs().format('YYYY-MM-DD');\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputJson } from '../lib/output.js';\nimport { YnabCliError } from '../lib/errors.js';\nimport { amountToMilliunits } from '../lib/utils.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\nimport { parseDate } from '../lib/dates.js';\nimport type { CommandOptions } from '../types/index.js';\n\nexport function createCategoriesCommand(): Command {\n const cmd = new Command('categories').description('Category operations');\n\n cmd\n .command('list')\n .description('List all categories')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--last-knowledge <number>', 'Last knowledge of server', parseInt)\n .action(\n withErrorHandling(\n async (options: { budget?: string; lastKnowledge?: number } & CommandOptions) => {\n const result = await client.getCategories(options.budget, options.lastKnowledge);\n outputJson(result?.category_groups);\n }\n )\n );\n\n cmd\n .command('view')\n .description('View category details')\n .argument('<id>', 'Category ID')\n .option('-b, --budget <id>', 'Budget ID')\n .action(\n withErrorHandling(async (id: string, options: CommandOptions) => {\n const category = await client.getCategory(id, options.budget);\n outputJson(category);\n })\n );\n\n cmd\n .command('budget')\n .description('Set category budgeted amount for a month (overrides existing amount)')\n .argument('<id>', 'Category ID')\n .requiredOption('--month <month>', 'Budget month (e.g., 2025-07-01)')\n .requiredOption('--amount <amount>', 'Total budgeted amount to set (e.g., 100.50)', parseFloat)\n .option('-b, --budget <id>', 'Budget ID')\n .action(\n withErrorHandling(\n async (\n id: string,\n options: {\n month: string;\n amount: number;\n budget?: string;\n } & CommandOptions\n ) => {\n if (isNaN(options.amount)) {\n throw new YnabCliError('Amount must be a valid number', 400);\n }\n\n const milliunits = amountToMilliunits(options.amount);\n const category = await client.updateMonthCategory(\n parseDate(options.month),\n id,\n { category: { budgeted: milliunits } },\n options.budget\n );\n outputJson(category);\n }\n )\n );\n\n cmd\n .command('transactions')\n .description('List transactions for category')\n .argument('<id>', 'Category ID')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--since <date>', 'Filter transactions since date')\n .option('--type <type>', 'Filter by transaction type')\n .option('--last-knowledge <number>', 'Last knowledge of server', parseInt)\n .action(\n withErrorHandling(\n async (\n id: string,\n options: {\n budget?: string;\n since?: string;\n type?: string;\n lastKnowledge?: number;\n } & CommandOptions\n ) => {\n const result = await client.getTransactionsByCategory(id, {\n budgetId: options.budget,\n sinceDate: options.since ? parseDate(options.since) : undefined,\n type: options.type,\n lastKnowledgeOfServer: options.lastKnowledge,\n });\n outputJson(result?.transactions);\n }\n )\n );\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputJson } from '../lib/output.js';\nimport { YnabCliError } from '../lib/errors.js';\nimport {\n amountToMilliunits,\n applyTransactionFilters,\n applyFieldSelection,\n type TransactionLike,\n} from '../lib/utils.js';\nimport { withErrorHandling, requireConfirmation, buildUpdateObject } from '../lib/command-utils.js';\nimport { validateTransactionSplits } from '../lib/schemas.js';\nimport { parseDate, todayDate } from '../lib/dates.js';\nimport type { CommandOptions } from '../types/index.js';\n\ninterface TransactionOptions {\n account?: string;\n date?: string;\n amount?: number;\n payeeName?: string;\n payeeId?: string;\n categoryId?: string;\n memo?: string;\n cleared?: string;\n approved?: boolean;\n}\n\nfunction buildTransactionData(options: TransactionOptions): Record<string, unknown> {\n if (!options.account) {\n throw new YnabCliError('--account is required in non-interactive mode', 400);\n }\n if (options.amount === undefined) {\n throw new YnabCliError('--amount is required in non-interactive mode', 400);\n }\n\n return {\n account_id: options.account,\n date: options.date ? parseDate(options.date) : todayDate(),\n amount: amountToMilliunits(options.amount),\n payee_name: options.payeeName,\n payee_id: options.payeeId,\n category_id: options.categoryId,\n memo: options.memo,\n cleared: options.cleared,\n approved: options.approved,\n };\n}\n\nexport function createTransactionsCommand(): Command {\n const cmd = new Command('transactions').description('Transaction operations');\n\n cmd\n .command('list')\n .description('List transactions')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--account <id>', 'Filter by account ID')\n .option('--category <id>', 'Filter by category ID')\n .option('--payee <id>', 'Filter by payee ID')\n .option('--since <date>', 'Filter transactions since date')\n .option('--until <date>', 'Filter transactions until date')\n .option('--type <type>', 'Filter by transaction type')\n .option('--approved <value>', 'Filter by approval status: true or false')\n .option(\n '--status <statuses>',\n 'Filter by cleared status: cleared, uncleared, reconciled (comma-separated for multiple)'\n )\n .option('--min-amount <amount>', 'Minimum amount in currency units (e.g., 10.50)', parseFloat)\n .option('--max-amount <amount>', 'Maximum amount in currency units (e.g., 100.00)', parseFloat)\n .option(\n '--fields <fields>',\n 'Comma-separated list of fields to include (e.g., id,date,amount,memo)'\n )\n .action(\n withErrorHandling(\n async (\n options: {\n budget?: string;\n account?: string;\n category?: string;\n payee?: string;\n since?: string;\n until?: string;\n type?: string;\n approved?: string;\n status?: string;\n minAmount?: number;\n maxAmount?: number;\n fields?: string;\n } & CommandOptions\n ) => {\n const params = {\n budgetId: options.budget,\n sinceDate: options.since ? parseDate(options.since) : undefined,\n type: options.type,\n };\n\n const result = options.account\n ? await client.getTransactionsByAccount(options.account, params)\n : options.category\n ? await client.getTransactionsByCategory(options.category, params)\n : options.payee\n ? await client.getTransactionsByPayee(options.payee, params)\n : await client.getTransactions(params);\n\n const transactions = result?.transactions || [];\n\n const filtered = applyTransactionFilters(transactions as TransactionLike[], {\n until: options.until ? parseDate(options.until) : undefined,\n approved: options.approved,\n status: options.status,\n minAmount: options.minAmount,\n maxAmount: options.maxAmount,\n });\n\n const selected = applyFieldSelection(filtered, options.fields);\n\n outputJson(selected);\n }\n )\n );\n\n cmd\n .command('view')\n .description('View single transaction')\n .argument('<id>', 'Transaction ID')\n .option('-b, --budget <id>', 'Budget ID')\n .action(\n withErrorHandling(async (id: string, options: CommandOptions) => {\n const transaction = await client.getTransaction(id, options.budget);\n outputJson(transaction);\n })\n );\n\n cmd\n .command('create')\n .description('Create transaction')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--account <id>', 'Account ID')\n .option('--date <date>', 'Transaction date')\n .option('--amount <amount>', 'Amount in currency units (e.g., 10.50)', parseFloat)\n .option('--payee-name <name>', 'Payee name')\n .option('--payee-id <id>', 'Payee ID')\n .option('--category-id <id>', 'Category ID')\n .option('--memo <memo>', 'Memo')\n .option('--cleared <status>', 'Cleared status (cleared, uncleared, reconciled)')\n .option('--approved', 'Mark as approved')\n .action(\n withErrorHandling(\n async (\n options: {\n budget?: string;\n account?: string;\n date?: string;\n amount?: number;\n payeeName?: string;\n payeeId?: string;\n categoryId?: string;\n memo?: string;\n cleared?: string;\n approved?: boolean;\n } & CommandOptions\n ) => {\n const transactionData = buildTransactionData(options);\n const transaction = await client.createTransaction(\n { transaction: transactionData },\n options.budget\n );\n outputJson(transaction);\n }\n )\n );\n\n cmd\n .command('update')\n .description('Update transaction')\n .argument('<id>', 'Transaction ID')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--account <id>', 'Account ID')\n .option('--date <date>', 'Transaction date')\n .option('--amount <amount>', 'Amount in currency units', parseFloat)\n .option('--payee-name <name>', 'Payee name')\n .option('--payee-id <id>', 'Payee ID')\n .option('--category-id <id>', 'Category ID')\n .option('--memo <memo>', 'Memo')\n .option('--cleared <status>', 'Cleared status')\n .option('--approved', 'Mark as approved')\n .action(\n withErrorHandling(\n async (id: string, options: TransactionOptions & { budget?: string } & CommandOptions) => {\n const transactionData = buildUpdateObject(options, {\n account: 'account_id',\n date: 'date',\n payeeName: 'payee_name',\n payeeId: 'payee_id',\n categoryId: 'category_id',\n memo: 'memo',\n cleared: 'cleared',\n approved: 'approved',\n });\n\n if (options.amount !== undefined) {\n transactionData.amount = amountToMilliunits(options.amount);\n }\n\n const transaction = await client.updateTransaction(\n id,\n { transaction: transactionData },\n options.budget\n );\n outputJson(transaction);\n }\n )\n );\n\n cmd\n .command('delete')\n .description('Delete transaction')\n .argument('<id>', 'Transaction ID')\n .option('-b, --budget <id>', 'Budget ID')\n .option('-y, --yes', 'Skip confirmation')\n .action(\n withErrorHandling(\n async (id: string, options: { budget?: string; yes?: boolean } & CommandOptions) => {\n requireConfirmation('transaction', options.yes);\n const transaction = await client.deleteTransaction(id, options.budget);\n outputJson({ message: 'Transaction deleted', transaction });\n }\n )\n );\n\n cmd\n .command('import')\n .description('Import transactions')\n .option('-b, --budget <id>', 'Budget ID')\n .action(\n withErrorHandling(async (options: CommandOptions) => {\n const transactionIds = await client.importTransactions(options.budget);\n outputJson({ transaction_ids: transactionIds });\n })\n );\n\n cmd\n .command('split')\n .description(\n 'Split transaction into multiple categories. Amounts should be in dollars (e.g., 10.50).'\n )\n .argument('<id>', 'Transaction ID')\n .requiredOption(\n '--splits <json>',\n 'JSON array of splits with dollar amounts: [{\"amount\": -21.40, \"category_id\": \"xxx\", \"memo\": \"...\"}]'\n )\n .option('-b, --budget <id>', 'Budget ID')\n .option('-f, --force', 'Force update of already-split transactions by deleting and recreating')\n .action(\n withErrorHandling(\n async (\n id: string,\n options: { splits: string; budget?: string; force?: boolean } & CommandOptions\n ) => {\n let parsedSplits;\n try {\n parsedSplits = JSON.parse(options.splits);\n } catch {\n throw new YnabCliError('Invalid JSON in --splits parameter', 400);\n }\n\n const splits = validateTransactionSplits(parsedSplits);\n\n const splitsInMilliunits = splits.map((split) => ({\n ...split,\n amount: amountToMilliunits(split.amount),\n }));\n\n const existingTransaction = await client.getTransaction(id, options.budget);\n const isAlreadySplit =\n existingTransaction.subtransactions && existingTransaction.subtransactions.length > 0;\n\n if (isAlreadySplit && !options.force) {\n throw new YnabCliError(\n 'Transaction is already split. YNAB API does not support updating split transactions. ' +\n 'Use --force to delete and recreate the transaction with new splits.',\n 400\n );\n }\n\n if (isAlreadySplit) {\n await client.deleteTransaction(id, options.budget);\n\n const recreatedTransaction = await client.createTransaction(\n {\n transaction: {\n account_id: existingTransaction.account_id,\n date: existingTransaction.date,\n amount: existingTransaction.amount,\n payee_id: existingTransaction.payee_id,\n payee_name: existingTransaction.payee_name,\n category_id: null,\n memo: existingTransaction.memo,\n cleared: existingTransaction.cleared,\n approved: existingTransaction.approved,\n flag_color: existingTransaction.flag_color,\n subtransactions: splitsInMilliunits,\n },\n },\n options.budget\n );\n outputJson(recreatedTransaction);\n } else {\n const transaction = await client.updateTransaction(\n id,\n {\n transaction: {\n category_id: null,\n subtransactions: splitsInMilliunits,\n },\n },\n options.budget\n );\n outputJson(transaction);\n }\n }\n )\n );\n\n cmd\n .command('search')\n .description('Search transactions')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--memo <text>', 'Search in memo field')\n .option('--payee-name <name>', 'Search in payee name')\n .option('--amount <amount>', 'Search for exact amount in currency units', parseFloat)\n .option('--since <date>', 'Search transactions since date')\n .option('--until <date>', 'Search transactions until date')\n .option('--approved <value>', 'Filter by approval status: true or false')\n .option(\n '--status <statuses>',\n 'Filter by cleared status: cleared, uncleared, reconciled (comma-separated)'\n )\n .option('--fields <fields>', 'Comma-separated list of fields to include')\n .action(\n withErrorHandling(\n async (\n options: {\n budget?: string;\n memo?: string;\n payeeName?: string;\n amount?: number;\n since?: string;\n until?: string;\n approved?: string;\n status?: string;\n fields?: string;\n } & CommandOptions\n ) => {\n if (!options.memo && !options.payeeName && options.amount === undefined) {\n throw new YnabCliError(\n 'At least one search criteria required: --memo, --payee-name, or --amount',\n 400\n );\n }\n\n const params = {\n budgetId: options.budget,\n sinceDate: options.since ? parseDate(options.since) : undefined,\n };\n\n const result = await client.getTransactions(params);\n let transactions = result?.transactions || [];\n\n if (options.memo) {\n const searchTerm = options.memo.toLowerCase();\n transactions = transactions.filter((t) => t.memo?.toLowerCase().includes(searchTerm));\n }\n\n if (options.payeeName) {\n const searchTerm = options.payeeName.toLowerCase();\n transactions = transactions.filter((t) =>\n t.payee_name?.toLowerCase().includes(searchTerm)\n );\n }\n\n if (options.amount !== undefined) {\n const amountMilliunits = amountToMilliunits(options.amount);\n transactions = transactions.filter((t) => t.amount === amountMilliunits);\n }\n\n transactions = applyTransactionFilters(transactions, {\n until: options.until ? parseDate(options.until) : undefined,\n approved: options.approved,\n status: options.status,\n });\n\n const filteredTransactions = applyFieldSelection(transactions, options.fields);\n\n outputJson(filteredTransactions);\n }\n )\n );\n\n return cmd;\n}\n","import { YnabCliError } from './errors.js';\n\nexport interface TransactionSplit {\n amount: number;\n category_id?: string | null;\n memo?: string;\n payee_id?: string;\n}\n\nexport function validateTransactionSplits(data: unknown): TransactionSplit[] {\n if (!Array.isArray(data)) {\n throw new YnabCliError('Transaction splits must be an array', 400);\n }\n\n return data.map((item, index) => {\n if (typeof item !== 'object' || item === null) {\n throw new YnabCliError(`Split at index ${index} must be an object`, 400);\n }\n\n const split = item as Record<string, unknown>;\n\n if (typeof split.amount !== 'number') {\n throw new YnabCliError(`Split at index ${index} must have a numeric amount`, 400);\n }\n\n return {\n amount: split.amount,\n category_id: split.category_id as string | null | undefined,\n memo: split.memo as string | undefined,\n payee_id: split.payee_id as string | undefined,\n };\n });\n}\n\nexport function validateApiData(data: unknown): Record<string, unknown> {\n if (typeof data !== 'object' || data === null || Array.isArray(data)) {\n throw new YnabCliError('API data must be an object', 400);\n }\n return data as Record<string, unknown>;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputJson } from '../lib/output.js';\nimport { withErrorHandling, requireConfirmation } from '../lib/command-utils.js';\nimport type { CommandOptions } from '../types/index.js';\n\nexport function createScheduledCommand(): Command {\n const cmd = new Command('scheduled').description('Scheduled transaction operations');\n\n cmd\n .command('list')\n .description('List all scheduled transactions')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--last-knowledge <number>', 'Last knowledge of server', parseInt)\n .action(\n withErrorHandling(\n async (options: { budget?: string; lastKnowledge?: number } & CommandOptions) => {\n const result = await client.getScheduledTransactions(\n options.budget,\n options.lastKnowledge\n );\n outputJson(result?.scheduled_transactions);\n }\n )\n );\n\n cmd\n .command('view')\n .description('View scheduled transaction')\n .argument('<id>', 'Scheduled transaction ID')\n .option('-b, --budget <id>', 'Budget ID')\n .action(\n withErrorHandling(async (id: string, options: CommandOptions) => {\n const scheduledTransaction = await client.getScheduledTransaction(id, options.budget);\n outputJson(scheduledTransaction);\n })\n );\n\n cmd\n .command('delete')\n .description('Delete scheduled transaction')\n .argument('<id>', 'Scheduled transaction ID')\n .option('-b, --budget <id>', 'Budget ID')\n .option('-y, --yes', 'Skip confirmation')\n .action(\n withErrorHandling(\n async (id: string, options: { budget?: string; yes?: boolean } & CommandOptions) => {\n requireConfirmation('scheduled transaction', options.yes);\n const scheduledTransaction = await client.deleteScheduledTransaction(id, options.budget);\n outputJson({\n message: 'Scheduled transaction deleted',\n scheduled_transaction: scheduledTransaction,\n });\n }\n )\n );\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputJson } from '../lib/output.js';\nimport { YnabCliError } from '../lib/errors.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\nimport { parseDate } from '../lib/dates.js';\nimport type { CommandOptions } from '../types/index.js';\n\nexport function createPayeesCommand(): Command {\n const cmd = new Command('payees').description('Payee operations');\n\n cmd\n .command('list')\n .description('List all payees')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--last-knowledge <number>', 'Last knowledge of server', parseInt)\n .action(\n withErrorHandling(\n async (options: { budget?: string; lastKnowledge?: number } & CommandOptions) => {\n const result = await client.getPayees(options.budget, options.lastKnowledge);\n outputJson(result?.payees);\n }\n )\n );\n\n cmd\n .command('view')\n .description('View payee details')\n .argument('<id>', 'Payee ID')\n .option('-b, --budget <id>', 'Budget ID')\n .action(\n withErrorHandling(async (id: string, options: CommandOptions) => {\n const payee = await client.getPayee(id, options.budget);\n outputJson(payee);\n })\n );\n\n cmd\n .command('update')\n .description('Rename payee')\n .argument('<id>', 'Payee ID')\n .requiredOption('--name <name>', 'New payee name')\n .option('-b, --budget <id>', 'Budget ID')\n .action(\n withErrorHandling(\n async (id: string, options: { name: string; budget?: string } & CommandOptions) => {\n if (!options.name?.trim()) {\n throw new YnabCliError('Name cannot be empty', 400);\n }\n\n const payee = await client.updatePayee(\n id,\n { payee: { name: options.name } },\n options.budget\n );\n outputJson(payee);\n }\n )\n );\n\n cmd\n .command('locations')\n .description('List locations for payee')\n .argument('<id>', 'Payee ID')\n .option('-b, --budget <id>', 'Budget ID')\n .action(\n withErrorHandling(async (id: string, options: CommandOptions) => {\n const locations = await client.getPayeeLocationsByPayee(id, options.budget);\n outputJson(locations);\n })\n );\n\n cmd\n .command('transactions')\n .description('List transactions for payee')\n .argument('<id>', 'Payee ID')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--since <date>', 'Filter transactions since date')\n .option('--type <type>', 'Filter by transaction type')\n .option('--last-knowledge <number>', 'Last knowledge of server', parseInt)\n .action(\n withErrorHandling(\n async (\n id: string,\n options: {\n budget?: string;\n since?: string;\n type?: string;\n lastKnowledge?: number;\n } & CommandOptions\n ) => {\n const result = await client.getTransactionsByPayee(id, {\n budgetId: options.budget,\n sinceDate: options.since ? parseDate(options.since) : undefined,\n type: options.type,\n lastKnowledgeOfServer: options.lastKnowledge,\n });\n outputJson(result?.transactions);\n }\n )\n );\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputJson } from '../lib/output.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\nimport { parseDate } from '../lib/dates.js';\nimport type { CommandOptions } from '../types/index.js';\n\nexport function createMonthsCommand(): Command {\n const cmd = new Command('months').description('Monthly budget operations');\n\n cmd\n .command('list')\n .description('List all budget months')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--last-knowledge <number>', 'Last knowledge of server', parseInt)\n .action(\n withErrorHandling(\n async (options: { budget?: string; lastKnowledge?: number } & CommandOptions) => {\n const result = await client.getBudgetMonths(options.budget, options.lastKnowledge);\n outputJson(result?.months);\n }\n )\n );\n\n cmd\n .command('view')\n .description('View specific month details')\n .argument('<month>', 'Budget month (e.g., 2025-07-01)')\n .option('-b, --budget <id>', 'Budget ID')\n .action(\n withErrorHandling(async (month: string, options: CommandOptions) => {\n const monthData = await client.getBudgetMonth(parseDate(month), options.budget);\n outputJson(monthData);\n })\n );\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputJson } from '../lib/output.js';\nimport { YnabCliError } from '../lib/errors.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\nimport { validateApiData } from '../lib/schemas.js';\nimport type { CommandOptions } from '../types/index.js';\n\nconst VALID_HTTP_METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'];\n\nexport function createApiCommand(): Command {\n const cmd = new Command('api').description('Raw API access');\n\n cmd\n .argument('<method>', 'HTTP method (GET, POST, PUT, PATCH, DELETE)')\n .argument('<path>', 'API path (e.g., /budgets or /budgets/{budget_id}/transactions)')\n .option('-b, --budget <id>', 'Budget ID (used to replace {budget_id} in path)')\n .option('--data <json>', 'JSON data for POST/PUT/PATCH requests')\n .description('Make raw API calls to YNAB')\n .action(\n withErrorHandling(\n async (\n method: string,\n path: string,\n options: { budget?: string; data?: string } & CommandOptions\n ) => {\n const upperMethod = method.toUpperCase();\n\n if (!VALID_HTTP_METHODS.includes(upperMethod)) {\n throw new YnabCliError(\n `Invalid HTTP method: ${method}. Must be one of: ${VALID_HTTP_METHODS.join(', ')}`,\n 400\n );\n }\n\n let data: Record<string, unknown> | undefined;\n if (options.data) {\n let parsedData: unknown;\n try {\n parsedData = JSON.parse(options.data);\n } catch {\n throw new YnabCliError('Invalid JSON in --data parameter', 400);\n }\n data = validateApiData(parsedData);\n }\n\n const result = await client.rawApiCall(upperMethod, path, data, options.budget);\n outputJson(result);\n }\n )\n );\n\n return cmd;\n}\n"],"mappings":"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","names":["Command","sanitized","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/lib/errors.ts","../src/lib/utils.ts","../src/lib/output.ts","../src/commands/auth.ts","../src/lib/auth.ts","../src/lib/config.ts","../src/lib/api-client.ts","../src/lib/command-utils.ts","../src/commands/user.ts","../src/commands/budgets.ts","../src/commands/accounts.ts","../src/lib/dates.ts","../src/commands/categories.ts","../src/commands/transactions.ts","../src/lib/schemas.ts","../src/commands/scheduled.ts","../src/commands/payees.ts","../src/commands/months.ts","../src/commands/api.ts","../src/commands/mcp.ts","../src/mcp/server.ts"],"sourcesContent":["#!/usr/bin/env bun\n\nimport { Command } from 'commander';\nimport { setOutputOptions } from './lib/output.js';\nimport { createAuthCommand } from './commands/auth.js';\nimport { createUserCommand } from './commands/user.js';\nimport { createBudgetsCommand } from './commands/budgets.js';\nimport { createAccountsCommand } from './commands/accounts.js';\nimport { createCategoriesCommand } from './commands/categories.js';\nimport { createTransactionsCommand } from './commands/transactions.js';\nimport { createScheduledCommand } from './commands/scheduled.js';\nimport { createPayeesCommand } from './commands/payees.js';\nimport { createMonthsCommand } from './commands/months.js';\nimport { createApiCommand } from './commands/api.js';\nimport { createMcpCommand } from './commands/mcp.js';\n\ndeclare const __VERSION__: string;\n\nconst program = new Command();\n\nprogram\n .name('ynab')\n .description('A command-line interface for You Need a Budget (YNAB)')\n .version(__VERSION__)\n .option('-c, --compact', 'Minified JSON output (single line)')\n .hook('preAction', (thisCommand) => {\n const options = thisCommand.opts();\n setOutputOptions({\n compact: options.compact,\n });\n });\n\nprogram.addCommand(createAuthCommand());\nprogram.addCommand(createUserCommand());\nprogram.addCommand(createBudgetsCommand());\nprogram.addCommand(createAccountsCommand());\nprogram.addCommand(createCategoriesCommand());\nprogram.addCommand(createTransactionsCommand());\nprogram.addCommand(createScheduledCommand());\nprogram.addCommand(createPayeesCommand());\nprogram.addCommand(createMonthsCommand());\nprogram.addCommand(createApiCommand());\nprogram.addCommand(createMcpCommand());\n\nprogram.parse();\n","import type { YnabError } from '../types/index.js';\nimport { outputJson } from './output.js';\n\nexport class YnabCliError extends Error {\n constructor(\n message: string,\n public statusCode?: number\n ) {\n super(message);\n this.name = 'YnabCliError';\n }\n}\n\nconst ERROR_STATUS_CODES: Record<string, number> = {\n bad_request: 400,\n not_authorized: 401,\n subscription_lapsed: 403,\n trial_expired: 403,\n unauthorized_scope: 403,\n data_limit_reached: 403,\n not_found: 404,\n resource_not_found: 404,\n conflict: 409,\n too_many_requests: 429,\n internal_server_error: 500,\n service_unavailable: 503,\n};\n\nexport function sanitizeErrorMessage(message: string): string {\n const sensitivePatterns = [\n /Bearer\\s+[\\w\\-._~+/]+=*/gi,\n /token[=:]\\s*[\\w\\-._~+/]+=*/gi,\n /api[_-]?key[=:]\\s*[\\w\\-._~+/]+=*/gi,\n /authorization:\\s*bearer\\s+[\\w\\-._~+/]+=*/gi,\n ];\n\n let sanitized = message;\n for (const pattern of sensitivePatterns) {\n sanitized = sanitized.replace(pattern, '[REDACTED]');\n }\n\n return sanitized.length > 500 ? sanitized.substring(0, 500) + '...' : sanitized;\n}\n\ninterface YnabApiError {\n name?: string;\n detail?: string;\n message?: string;\n id?: string;\n}\n\nfunction isErrorObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nexport function sanitizeApiError(error: unknown): YnabError {\n if (!isErrorObject(error)) {\n return {\n name: 'api_error',\n detail: 'An error occurred',\n id: undefined,\n };\n }\n\n const apiError = error as YnabApiError;\n const detail = sanitizeErrorMessage(\n String(apiError.detail || apiError.message || 'An error occurred')\n );\n\n return {\n name: apiError.name || 'api_error',\n detail,\n id: apiError.id,\n };\n}\n\nfunction enhanceRateLimitMessage(detail: string): string {\n return `${detail}\\n\\nYNAB API limit: 200 requests/hour (rolling window). Wait a few minutes and retry.`;\n}\n\nfunction formatErrorResponse(name: string, detail: string, statusCode: number): never {\n const enhancedDetail = name === 'too_many_requests' ? enhanceRateLimitMessage(detail) : detail;\n\n outputJson({ error: { name, detail: enhancedDetail, statusCode } });\n process.exit(1);\n}\n\nexport function handleYnabError(error: unknown): never {\n if (!isErrorObject(error)) {\n formatErrorResponse('unknown_error', 'An unexpected error occurred', 1);\n }\n\n const errorObj = error as { error?: unknown; message?: string };\n\n if (errorObj.error) {\n const ynabError: YnabError = sanitizeApiError(errorObj.error);\n formatErrorResponse(\n ynabError.name,\n ynabError.detail,\n ERROR_STATUS_CODES[ynabError.name] || 500\n );\n }\n\n if (error instanceof YnabCliError) {\n const sanitized = sanitizeErrorMessage(error.message);\n formatErrorResponse('cli_error', sanitized, error.statusCode || 1);\n }\n\n const sanitized = sanitizeErrorMessage(errorObj.message || 'An unexpected error occurred');\n formatErrorResponse('unknown_error', sanitized, 1);\n}\n","import { YnabCliError } from './errors.js';\n\nexport function milliunitsToAmount(milliunits: number): number {\n return milliunits / 1000;\n}\n\nexport function amountToMilliunits(amount: number): number {\n return Math.round(amount * 1000);\n}\n\nexport function convertMilliunitsToAmounts(data: unknown): unknown {\n if (data === null || data === undefined) return data;\n if (Array.isArray(data)) return data.map(convertMilliunitsToAmounts);\n if (typeof data !== 'object') return data;\n\n const converted: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(data)) {\n if (isAmountField(key) && typeof value === 'number') {\n converted[key] = milliunitsToAmount(value);\n } else if (\n isDebtAmountMapField(key) &&\n typeof value === 'object' &&\n value !== null &&\n !Array.isArray(value)\n ) {\n const convertedMap: Record<string, unknown> = {};\n for (const [dateKey, amountValue] of Object.entries(value)) {\n convertedMap[dateKey] =\n typeof amountValue === 'number' ? milliunitsToAmount(amountValue) : amountValue;\n }\n converted[key] = convertedMap;\n } else {\n converted[key] = convertMilliunitsToAmounts(value);\n }\n }\n return converted;\n}\n\nfunction isAmountField(fieldName: string): boolean {\n const amountFields = [\n 'amount',\n 'balance',\n 'cleared_balance',\n 'uncleared_balance',\n 'budgeted',\n 'activity',\n 'available',\n 'goal_target',\n 'goal_under_funded',\n 'goal_overall_funded',\n 'goal_overall_left',\n 'income',\n 'to_be_budgeted',\n 'debt_original_balance',\n ];\n\n return amountFields.includes(fieldName) || fieldName.endsWith('_amount');\n}\n\nfunction isDebtAmountMapField(fieldName: string): boolean {\n const debtAmountMapFields = [\n 'debt_minimum_payments',\n 'debt_escrow_amounts',\n 'debt_interest_rates',\n ];\n\n return debtAmountMapFields.includes(fieldName);\n}\n\nexport function parseApprovedFilter(value: string): boolean {\n const normalized = value.toLowerCase();\n if (normalized !== 'true' && normalized !== 'false') {\n throw new YnabCliError(`--approved must be 'true' or 'false', got '${value}'`, 400);\n }\n return normalized === 'true';\n}\n\nexport function parseStatusFilter(value: string): string[] {\n const statuses = value.split(',').map((s) => s.trim().toLowerCase());\n const validStatuses = ['cleared', 'uncleared', 'reconciled'];\n\n for (const status of statuses) {\n if (!validStatuses.includes(status)) {\n throw new YnabCliError(\n `Invalid status '${status}'. Must be one of: ${validStatuses.join(', ')}`,\n 400\n );\n }\n }\n\n return statuses;\n}\n\nexport type TransactionLike = {\n date: string;\n amount: number;\n approved: boolean;\n cleared: string;\n};\n\nexport function applyTransactionFilters<T extends TransactionLike>(\n transactions: T[],\n filters: {\n until?: string;\n approved?: string;\n status?: string;\n minAmount?: number;\n maxAmount?: number;\n }\n): T[] {\n let filtered = transactions;\n\n if (filters.until) {\n filtered = filtered.filter((t) => t.date <= filters.until!);\n }\n\n if (filters.approved !== undefined) {\n const approvedValue = parseApprovedFilter(filters.approved);\n filtered = filtered.filter((t) => t.approved === approvedValue);\n }\n\n if (filters.status) {\n const statuses = parseStatusFilter(filters.status);\n filtered = filtered.filter((t) => statuses.includes(t.cleared.toLowerCase()));\n }\n\n if (filters.minAmount !== undefined) {\n const minMilliunits = amountToMilliunits(filters.minAmount);\n filtered = filtered.filter((t) => t.amount >= minMilliunits);\n }\n\n if (filters.maxAmount !== undefined) {\n const maxMilliunits = amountToMilliunits(filters.maxAmount);\n filtered = filtered.filter((t) => t.amount <= maxMilliunits);\n }\n\n return filtered;\n}\n\nexport function applyFieldSelection<T>(items: T[], fields?: string): Partial<T>[] {\n if (!fields) return items;\n\n const fieldList = fields.split(',').map((f) => f.trim());\n return items.map((item) => {\n const filtered: Partial<T> = {};\n const itemRecord = item as Record<string, unknown>;\n for (const field of fieldList) {\n if (field in itemRecord) {\n (filtered as Record<string, unknown>)[field] = itemRecord[field];\n }\n }\n return filtered;\n });\n}\n","import type { OutputOptions } from '../types/index.js';\nimport { convertMilliunitsToAmounts } from './utils.js';\n\nlet globalOutputOptions: OutputOptions = {};\n\nexport function setOutputOptions(options: OutputOptions): void {\n globalOutputOptions = options;\n}\n\nexport function outputJson(data: unknown, options: OutputOptions = {}): void {\n const convertedData = convertMilliunitsToAmounts(data);\n const mergedOptions = { ...globalOutputOptions, ...options };\n const jsonString = mergedOptions.compact\n ? JSON.stringify(convertedData)\n : JSON.stringify(convertedData, null, 2);\n\n console.log(jsonString);\n}\n","import { Command } from 'commander';\nimport { auth } from '../lib/auth.js';\nimport { outputJson } from '../lib/output.js';\nimport { client } from '../lib/api-client.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\nimport { YnabCliError } from '../lib/errors.js';\n\nexport function createAuthCommand(): Command {\n const cmd = new Command('auth').description('Authentication management');\n\n cmd\n .command('login')\n .description('Configure access token')\n .requiredOption('-t, --token <token>', 'YNAB Personal Access Token')\n .action(\n withErrorHandling(async (options: { token: string }) => {\n const token = options.token.trim();\n if (!token) {\n throw new YnabCliError('Access token cannot be empty', 400);\n }\n await auth.setAccessToken(token);\n client.clearApi();\n\n try {\n const user = await client.getUser();\n outputJson({\n message: 'Successfully authenticated',\n user: { id: user?.id },\n });\n } catch (error) {\n await auth.deleteAccessToken();\n client.clearApi();\n throw error;\n }\n })\n );\n\n cmd\n .command('status')\n .description('Check authentication status')\n .action(\n withErrorHandling(async () => {\n const isAuthenticated = await auth.isAuthenticated();\n\n if (!isAuthenticated) {\n outputJson({ authenticated: false, message: 'Not authenticated' });\n return;\n }\n\n try {\n const user = await client.getUser();\n outputJson({ authenticated: true, user: { id: user?.id } });\n } catch {\n outputJson({ authenticated: false, message: 'Token exists but is invalid' });\n }\n })\n );\n\n cmd\n .command('logout')\n .description('Remove stored credentials')\n .action(\n withErrorHandling(async () => {\n await auth.logout();\n client.clearApi();\n outputJson({ message: 'Successfully logged out' });\n })\n );\n\n return cmd;\n}\n","import { Entry } from '@napi-rs/keyring';\nimport { config } from './config.js';\n\nconst SERVICE_NAME = 'ynab-cli';\nconst ACCOUNT_NAME = 'access-token';\n\nconst KEYRING_UNAVAILABLE_ERROR =\n 'Keychain storage unavailable. Cannot store credentials securely.\\n' +\n 'On Linux, install libsecret: sudo apt-get install libsecret-1-dev\\n' +\n 'Then reinstall: bun install -g @stephendolan/ynab-cli\\n' +\n 'Alternatively, use the YNAB_API_KEY environment variable.';\n\nlet keyring: Entry | null | undefined = undefined;\n\nfunction getKeyring(): Entry | null {\n if (keyring !== undefined) {\n return keyring;\n }\n try {\n keyring = new Entry(SERVICE_NAME, ACCOUNT_NAME);\n } catch {\n keyring = null;\n }\n return keyring;\n}\n\nexport function resetKeyringForTesting(): void {\n keyring = undefined;\n}\n\nexport class AuthManager {\n async getAccessToken(): Promise<string | null> {\n const entry = getKeyring();\n if (entry) {\n try {\n return entry.getPassword();\n } catch {\n return null;\n }\n }\n return null;\n }\n\n async setAccessToken(token: string): Promise<void> {\n const entry = getKeyring();\n if (!entry) {\n throw new Error(KEYRING_UNAVAILABLE_ERROR);\n }\n try {\n entry.setPassword(token);\n } catch (error) {\n throw new Error(\n `Failed to store token in keychain: ${error instanceof Error ? error.message : error}\\n\\n` +\n 'On Linux, ensure the Secret Service is running and unlocked.\\n' +\n 'Try: gnome-keyring-daemon --unlock\\n' +\n 'Or use the YNAB_API_KEY environment variable instead.'\n );\n }\n }\n\n async deleteAccessToken(): Promise<boolean> {\n const entry = getKeyring();\n if (entry) {\n return entry.deletePassword();\n }\n return false;\n }\n\n async isAuthenticated(): Promise<boolean> {\n return (await this.getAccessToken()) !== null;\n }\n\n async logout(): Promise<void> {\n await this.deleteAccessToken();\n config.clearDefaultBudget();\n }\n}\n\nexport const auth = new AuthManager();\n","import Conf from 'conf';\nimport type { Config } from '../types/index.js';\n\nclass ConfigManager {\n private conf: Conf<Config>;\n\n constructor() {\n this.conf = new Conf<Config>({\n projectName: 'ynab-cli',\n schema: {\n defaultBudget: { type: 'string' },\n version: { type: 'string', default: '1.0.0' },\n },\n defaults: { version: '1.0.0' },\n });\n }\n\n getDefaultBudget(): string | undefined {\n return this.conf.get('defaultBudget');\n }\n\n setDefaultBudget(budgetId: string): void {\n this.conf.set('defaultBudget', budgetId);\n }\n\n clearDefaultBudget(): void {\n this.conf.delete('defaultBudget');\n }\n\n clear(): void {\n this.conf.clear();\n }\n}\n\nexport const config = new ConfigManager();\n","import * as ynab from 'ynab';\nimport { config } from './config.js';\nimport { YnabCliError, handleYnabError, sanitizeApiError } from './errors.js';\nimport { auth } from './auth.js';\n\ntype TransactionTypeFilter = 'uncategorized' | 'unapproved' | undefined;\n\nexport class YnabClient {\n private api: ynab.API | null = null;\n private envVarWarningShown = false;\n\n clearApi(): void {\n this.api = null;\n this.envVarWarningShown = false;\n }\n\n async getApi(): Promise<ynab.API> {\n if (this.api) {\n return this.api;\n }\n\n const keychainToken = await auth.getAccessToken();\n const accessToken = keychainToken || process.env.YNAB_API_KEY || null;\n\n if (!accessToken) {\n throw new YnabCliError(\n 'Not authenticated. Please run: ynab auth login or set YNAB_API_KEY environment variable',\n 401\n );\n }\n\n if (!keychainToken && process.env.YNAB_API_KEY && !this.envVarWarningShown) {\n console.warn(\n '\\x1b[33m⚠️ WARNING: Using YNAB_API_KEY environment variable.\\n' +\n 'Environment variables may be visible to other processes.\\n' +\n 'For better security, use: ynab auth login\\x1b[0m\\n'\n );\n this.envVarWarningShown = true;\n }\n\n this.api = new ynab.API(accessToken);\n return this.api;\n }\n\n async getBudgetId(budgetIdOrDefault?: string): Promise<string> {\n const budgetId = budgetIdOrDefault || config.getDefaultBudget() || process.env.YNAB_BUDGET_ID;\n\n if (!budgetId) {\n throw new YnabCliError(\n 'No budget specified. Use --budget flag, set default with \"ynab budgets set-default\", or set YNAB_BUDGET_ID environment variable',\n 400\n );\n }\n\n return budgetId;\n }\n\n private async withErrorHandling<T>(fn: () => Promise<T>): Promise<T> {\n try {\n return await fn();\n } catch (error) {\n handleYnabError(error);\n }\n }\n\n async getUser() {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const response = await api.user.getUser();\n return response.data.user;\n });\n }\n\n async getBudgets(includeAccounts = false) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const response = await api.budgets.getBudgets(includeAccounts);\n return {\n budgets: response.data.budgets,\n server_knowledge: 0,\n };\n });\n }\n\n async getBudget(budgetId?: string, lastKnowledgeOfServer?: number) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.budgets.getBudgetById(id, lastKnowledgeOfServer);\n return {\n budget: response.data.budget,\n server_knowledge: response.data.server_knowledge,\n };\n });\n }\n\n async getBudgetSettings(budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.budgets.getBudgetSettingsById(id);\n return response.data.settings;\n });\n }\n\n async getAccounts(budgetId?: string, lastKnowledgeOfServer?: number) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.accounts.getAccounts(id, lastKnowledgeOfServer);\n return {\n accounts: response.data.accounts,\n server_knowledge: response.data.server_knowledge,\n };\n });\n }\n\n async getAccount(accountId: string, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.accounts.getAccountById(id, accountId);\n return response.data.account;\n });\n }\n\n async getCategories(budgetId?: string, lastKnowledgeOfServer?: number) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.categories.getCategories(id, lastKnowledgeOfServer);\n return {\n category_groups: response.data.category_groups,\n server_knowledge: response.data.server_knowledge,\n };\n });\n }\n\n async getCategory(categoryId: string, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.categories.getCategoryById(id, categoryId);\n return response.data.category;\n });\n }\n\n async updateMonthCategory(\n month: string,\n categoryId: string,\n data: ynab.PatchMonthCategoryWrapper,\n budgetId?: string\n ) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.categories.updateMonthCategory(id, month, categoryId, data);\n return response.data.category;\n });\n }\n\n async getPayees(budgetId?: string, lastKnowledgeOfServer?: number) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.payees.getPayees(id, lastKnowledgeOfServer);\n return {\n payees: response.data.payees,\n server_knowledge: response.data.server_knowledge,\n };\n });\n }\n\n async getPayee(payeeId: string, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.payees.getPayeeById(id, payeeId);\n return response.data.payee;\n });\n }\n\n async updatePayee(payeeId: string, data: ynab.PatchPayeeWrapper, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.payees.updatePayee(id, payeeId, data);\n return response.data.payee;\n });\n }\n\n async getPayeeLocationsByPayee(payeeId: string, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.payeeLocations.getPayeeLocationsByPayee(id, payeeId);\n return response.data.payee_locations;\n });\n }\n\n async getBudgetMonths(budgetId?: string, lastKnowledgeOfServer?: number) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.months.getBudgetMonths(id, lastKnowledgeOfServer);\n return {\n months: response.data.months,\n server_knowledge: response.data.server_knowledge,\n };\n });\n }\n\n async getBudgetMonth(month: string, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.months.getBudgetMonth(id, month);\n return response.data.month;\n });\n }\n\n async getTransactions(params: {\n budgetId?: string;\n sinceDate?: string;\n type?: string;\n lastKnowledgeOfServer?: number;\n }) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(params.budgetId);\n const response = await api.transactions.getTransactions(\n id,\n params.sinceDate,\n params.type as TransactionTypeFilter,\n params.lastKnowledgeOfServer\n );\n return {\n transactions: response.data.transactions,\n server_knowledge: response.data.server_knowledge,\n };\n });\n }\n\n async getTransactionsByAccount(\n accountId: string,\n params: {\n budgetId?: string;\n sinceDate?: string;\n type?: string;\n lastKnowledgeOfServer?: number;\n }\n ) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(params.budgetId);\n const response = await api.transactions.getTransactionsByAccount(\n id,\n accountId,\n params.sinceDate,\n params.type as TransactionTypeFilter,\n params.lastKnowledgeOfServer\n );\n return {\n transactions: response.data.transactions,\n server_knowledge: response.data.server_knowledge,\n };\n });\n }\n\n async getTransactionsByCategory(\n categoryId: string,\n params: {\n budgetId?: string;\n sinceDate?: string;\n type?: string;\n lastKnowledgeOfServer?: number;\n }\n ) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(params.budgetId);\n const response = await api.transactions.getTransactionsByCategory(\n id,\n categoryId,\n params.sinceDate,\n params.type as TransactionTypeFilter,\n params.lastKnowledgeOfServer\n );\n return {\n transactions: response.data.transactions,\n server_knowledge: response.data.server_knowledge,\n };\n });\n }\n\n async getTransactionsByPayee(\n payeeId: string,\n params: {\n budgetId?: string;\n sinceDate?: string;\n type?: string;\n lastKnowledgeOfServer?: number;\n }\n ) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(params.budgetId);\n const response = await api.transactions.getTransactionsByPayee(\n id,\n payeeId,\n params.sinceDate,\n params.type as TransactionTypeFilter,\n params.lastKnowledgeOfServer\n );\n return {\n transactions: response.data.transactions,\n server_knowledge: response.data.server_knowledge,\n };\n });\n }\n\n async getTransaction(transactionId: string, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.transactions.getTransactionById(id, transactionId);\n return response.data.transaction;\n });\n }\n\n async createTransaction(transactionData: ynab.PostTransactionsWrapper, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.transactions.createTransaction(id, transactionData);\n return response.data.transaction;\n });\n }\n\n async updateTransaction(\n transactionId: string,\n transactionData: ynab.PutTransactionWrapper,\n budgetId?: string\n ) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.transactions.updateTransaction(id, transactionId, transactionData);\n return response.data.transaction;\n });\n }\n\n async deleteTransaction(transactionId: string, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.transactions.deleteTransaction(id, transactionId);\n return response.data.transaction;\n });\n }\n\n async importTransactions(budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.transactions.importTransactions(id);\n return response.data.transaction_ids;\n });\n }\n\n async getScheduledTransactions(budgetId?: string, lastKnowledgeOfServer?: number) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.scheduledTransactions.getScheduledTransactions(\n id,\n lastKnowledgeOfServer\n );\n return {\n scheduled_transactions: response.data.scheduled_transactions,\n server_knowledge: response.data.server_knowledge,\n };\n });\n }\n\n async getScheduledTransaction(scheduledTransactionId: string, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.scheduledTransactions.getScheduledTransactionById(\n id,\n scheduledTransactionId\n );\n return response.data.scheduled_transaction;\n });\n }\n\n async deleteScheduledTransaction(scheduledTransactionId: string, budgetId?: string) {\n return this.withErrorHandling(async () => {\n const api = await this.getApi();\n const id = await this.getBudgetId(budgetId);\n const response = await api.scheduledTransactions.deleteScheduledTransaction(\n id,\n scheduledTransactionId\n );\n return response.data.scheduled_transaction;\n });\n }\n\n async rawApiCall(method: string, path: string, data?: unknown, budgetId?: string) {\n return this.withErrorHandling(async () => {\n await this.getApi();\n\n const fullPath = path.includes('{budget_id}')\n ? path.replace('{budget_id}', await this.getBudgetId(budgetId))\n : path;\n\n const url = `https://api.ynab.com/v1${fullPath}`;\n const accessToken = (await auth.getAccessToken()) || process.env.YNAB_API_KEY;\n const headers = {\n Authorization: `Bearer ${accessToken}`,\n 'Content-Type': 'application/json',\n };\n\n const httpMethod = method.toUpperCase();\n const hasBody = ['POST', 'PUT', 'PATCH'].includes(httpMethod);\n\n if (!['GET', 'POST', 'PUT', 'PATCH', 'DELETE'].includes(httpMethod)) {\n throw new YnabCliError(`Unsupported HTTP method: ${method}`, 400);\n }\n\n const response = await fetch(url, {\n method: httpMethod,\n headers,\n ...(hasBody && { body: JSON.stringify(data) }),\n });\n\n if (!response.ok) {\n const errorData = (await response.json()) as Record<string, unknown>;\n throw { error: sanitizeApiError(errorData.error || errorData) };\n }\n\n return await response.json();\n });\n }\n}\n\nexport const client = new YnabClient();\n","import { handleYnabError, YnabCliError } from './errors.js';\n\nexport function withErrorHandling<TArgs extends unknown[], R>(\n fn: (...args: TArgs) => Promise<R>\n): (...args: TArgs) => Promise<void> {\n return async (...args: TArgs) => {\n try {\n await fn(...args);\n } catch (error) {\n handleYnabError(error);\n }\n };\n}\n\nexport function requireConfirmation(itemType: string, confirmed: boolean = false): void {\n if (!confirmed) {\n throw new YnabCliError(\n `Deleting ${itemType} requires --yes flag to confirm`,\n 400\n );\n }\n}\n\nexport function buildUpdateObject<T>(\n options: T,\n mapping: Record<string, string>\n): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n const optionsRecord = options as Record<string, unknown>;\n\n for (const [optionKey, targetKey] of Object.entries(mapping)) {\n if (optionsRecord[optionKey] !== undefined) {\n result[targetKey] = optionsRecord[optionKey];\n }\n }\n\n return result;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputJson } from '../lib/output.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\n\nexport function createUserCommand(): Command {\n const cmd = new Command('user').description('User information');\n\n cmd\n .command('info')\n .description('Get authenticated user information')\n .action(\n withErrorHandling(async () => {\n const user = await client.getUser();\n outputJson(user);\n })\n );\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { config } from '../lib/config.js';\nimport { outputJson } from '../lib/output.js';\nimport { YnabCliError } from '../lib/errors.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\n\nexport function createBudgetsCommand(): Command {\n const cmd = new Command('budgets').description('Budget operations');\n\n cmd\n .command('list')\n .description('List all budgets')\n .option('--include-accounts', 'Include accounts in response')\n .action(\n withErrorHandling(async (options: { includeAccounts?: boolean }) => {\n const result = await client.getBudgets(options.includeAccounts);\n outputJson(result?.budgets);\n })\n );\n\n cmd\n .command('view')\n .description('View budget details (uses default if no id provided)')\n .argument('[id]', 'Budget ID')\n .action(\n withErrorHandling(async (id: string | undefined) => {\n const result = await client.getBudget(id);\n outputJson(result?.budget);\n })\n );\n\n cmd\n .command('settings')\n .description('View budget settings')\n .argument('[id]', 'Budget ID')\n .action(\n withErrorHandling(async (id: string | undefined) => {\n const settings = await client.getBudgetSettings(id);\n outputJson(settings);\n })\n );\n\n cmd\n .command('set-default')\n .description('Set default budget for commands')\n .argument('<id>', 'Budget ID')\n .action(\n withErrorHandling(async (id: string) => {\n const result = await client.getBudgets();\n const budget = result?.budgets.find((b) => b.id === id);\n\n if (!budget) {\n throw new YnabCliError(`Budget with ID ${id} not found`, 404);\n }\n\n config.setDefaultBudget(id);\n outputJson({\n message: 'Default budget set',\n budget: { id: budget.id, name: budget.name },\n });\n })\n );\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputJson } from '../lib/output.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\nimport { parseDate } from '../lib/dates.js';\nimport type { CommandOptions } from '../types/index.js';\n\nexport function createAccountsCommand(): Command {\n const cmd = new Command('accounts').description('Account operations');\n\n cmd\n .command('list')\n .description('List all accounts')\n .option('-b, --budget <id>', 'Budget ID')\n .action(\n withErrorHandling(async (options: CommandOptions) => {\n const result = await client.getAccounts(options.budget);\n outputJson(result?.accounts);\n })\n );\n\n cmd\n .command('view')\n .description('View account details')\n .argument('<id>', 'Account ID')\n .option('-b, --budget <id>', 'Budget ID')\n .action(\n withErrorHandling(async (id: string, options: CommandOptions) => {\n const account = await client.getAccount(id, options.budget);\n outputJson(account);\n })\n );\n\n cmd\n .command('transactions')\n .description('List transactions for account')\n .argument('<id>', 'Account ID')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--since <date>', 'Filter transactions since date')\n .option('--type <type>', 'Filter by transaction type')\n .action(\n withErrorHandling(\n async (\n id: string,\n options: {\n budget?: string;\n since?: string;\n type?: string;\n } & CommandOptions\n ) => {\n const result = await client.getTransactionsByAccount(id, {\n budgetId: options.budget,\n sinceDate: options.since ? parseDate(options.since) : undefined,\n type: options.type,\n });\n outputJson(result?.transactions);\n }\n )\n );\n\n return cmd;\n}\n","import dayjs from 'dayjs';\nimport { YnabCliError } from './errors.js';\n\nexport function parseDate(input: string): string {\n const d = dayjs(input);\n if (!d.isValid()) {\n throw new YnabCliError(`Invalid date: ${input}`, 400);\n }\n return d.format('YYYY-MM-DD');\n}\n\nexport function todayDate(): string {\n return dayjs().format('YYYY-MM-DD');\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputJson } from '../lib/output.js';\nimport { YnabCliError } from '../lib/errors.js';\nimport { amountToMilliunits } from '../lib/utils.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\nimport { parseDate } from '../lib/dates.js';\nimport type { CommandOptions } from '../types/index.js';\n\nexport function createCategoriesCommand(): Command {\n const cmd = new Command('categories').description('Category operations');\n\n cmd\n .command('list')\n .description('List all categories')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--last-knowledge <number>', 'Last knowledge of server', parseInt)\n .action(\n withErrorHandling(\n async (options: { budget?: string; lastKnowledge?: number } & CommandOptions) => {\n const result = await client.getCategories(options.budget, options.lastKnowledge);\n outputJson(result?.category_groups);\n }\n )\n );\n\n cmd\n .command('view')\n .description('View category details')\n .argument('<id>', 'Category ID')\n .option('-b, --budget <id>', 'Budget ID')\n .action(\n withErrorHandling(async (id: string, options: CommandOptions) => {\n const category = await client.getCategory(id, options.budget);\n outputJson(category);\n })\n );\n\n cmd\n .command('budget')\n .description('Set category budgeted amount for a month (overrides existing amount)')\n .argument('<id>', 'Category ID')\n .requiredOption('--month <month>', 'Budget month (e.g., 2025-07-01)')\n .requiredOption('--amount <amount>', 'Total budgeted amount to set (e.g., 100.50)', parseFloat)\n .option('-b, --budget <id>', 'Budget ID')\n .action(\n withErrorHandling(\n async (\n id: string,\n options: {\n month: string;\n amount: number;\n budget?: string;\n } & CommandOptions\n ) => {\n if (isNaN(options.amount)) {\n throw new YnabCliError('Amount must be a valid number', 400);\n }\n\n const milliunits = amountToMilliunits(options.amount);\n const category = await client.updateMonthCategory(\n parseDate(options.month),\n id,\n { category: { budgeted: milliunits } },\n options.budget\n );\n outputJson(category);\n }\n )\n );\n\n cmd\n .command('transactions')\n .description('List transactions for category')\n .argument('<id>', 'Category ID')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--since <date>', 'Filter transactions since date')\n .option('--type <type>', 'Filter by transaction type')\n .option('--last-knowledge <number>', 'Last knowledge of server', parseInt)\n .action(\n withErrorHandling(\n async (\n id: string,\n options: {\n budget?: string;\n since?: string;\n type?: string;\n lastKnowledge?: number;\n } & CommandOptions\n ) => {\n const result = await client.getTransactionsByCategory(id, {\n budgetId: options.budget,\n sinceDate: options.since ? parseDate(options.since) : undefined,\n type: options.type,\n lastKnowledgeOfServer: options.lastKnowledge,\n });\n outputJson(result?.transactions);\n }\n )\n );\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputJson } from '../lib/output.js';\nimport { YnabCliError } from '../lib/errors.js';\nimport {\n amountToMilliunits,\n applyTransactionFilters,\n applyFieldSelection,\n type TransactionLike,\n} from '../lib/utils.js';\nimport { withErrorHandling, requireConfirmation, buildUpdateObject } from '../lib/command-utils.js';\nimport { validateTransactionSplits } from '../lib/schemas.js';\nimport { parseDate, todayDate } from '../lib/dates.js';\nimport type { CommandOptions } from '../types/index.js';\n\ninterface TransactionOptions {\n account?: string;\n date?: string;\n amount?: number;\n payeeName?: string;\n payeeId?: string;\n categoryId?: string;\n memo?: string;\n cleared?: string;\n approved?: boolean;\n}\n\nfunction buildTransactionData(options: TransactionOptions): Record<string, unknown> {\n if (!options.account) {\n throw new YnabCliError('--account is required in non-interactive mode', 400);\n }\n if (options.amount === undefined) {\n throw new YnabCliError('--amount is required in non-interactive mode', 400);\n }\n\n return {\n account_id: options.account,\n date: options.date ? parseDate(options.date) : todayDate(),\n amount: amountToMilliunits(options.amount),\n payee_name: options.payeeName,\n payee_id: options.payeeId,\n category_id: options.categoryId,\n memo: options.memo,\n cleared: options.cleared,\n approved: options.approved,\n };\n}\n\nexport function createTransactionsCommand(): Command {\n const cmd = new Command('transactions').description('Transaction operations');\n\n cmd\n .command('list')\n .description('List transactions')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--account <id>', 'Filter by account ID')\n .option('--category <id>', 'Filter by category ID')\n .option('--payee <id>', 'Filter by payee ID')\n .option('--since <date>', 'Filter transactions since date')\n .option('--until <date>', 'Filter transactions until date')\n .option('--type <type>', 'Filter by transaction type')\n .option('--approved <value>', 'Filter by approval status: true or false')\n .option(\n '--status <statuses>',\n 'Filter by cleared status: cleared, uncleared, reconciled (comma-separated for multiple)'\n )\n .option('--min-amount <amount>', 'Minimum amount in currency units (e.g., 10.50)', parseFloat)\n .option('--max-amount <amount>', 'Maximum amount in currency units (e.g., 100.00)', parseFloat)\n .option(\n '--fields <fields>',\n 'Comma-separated list of fields to include (e.g., id,date,amount,memo)'\n )\n .action(\n withErrorHandling(\n async (\n options: {\n budget?: string;\n account?: string;\n category?: string;\n payee?: string;\n since?: string;\n until?: string;\n type?: string;\n approved?: string;\n status?: string;\n minAmount?: number;\n maxAmount?: number;\n fields?: string;\n } & CommandOptions\n ) => {\n const params = {\n budgetId: options.budget,\n sinceDate: options.since ? parseDate(options.since) : undefined,\n type: options.type,\n };\n\n const result = options.account\n ? await client.getTransactionsByAccount(options.account, params)\n : options.category\n ? await client.getTransactionsByCategory(options.category, params)\n : options.payee\n ? await client.getTransactionsByPayee(options.payee, params)\n : await client.getTransactions(params);\n\n const transactions = result?.transactions || [];\n\n const filtered = applyTransactionFilters(transactions as TransactionLike[], {\n until: options.until ? parseDate(options.until) : undefined,\n approved: options.approved,\n status: options.status,\n minAmount: options.minAmount,\n maxAmount: options.maxAmount,\n });\n\n const selected = applyFieldSelection(filtered, options.fields);\n\n outputJson(selected);\n }\n )\n );\n\n cmd\n .command('view')\n .description('View single transaction')\n .argument('<id>', 'Transaction ID')\n .option('-b, --budget <id>', 'Budget ID')\n .action(\n withErrorHandling(async (id: string, options: CommandOptions) => {\n const transaction = await client.getTransaction(id, options.budget);\n outputJson(transaction);\n })\n );\n\n cmd\n .command('create')\n .description('Create transaction')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--account <id>', 'Account ID')\n .option('--date <date>', 'Transaction date')\n .option('--amount <amount>', 'Amount in currency units (e.g., 10.50)', parseFloat)\n .option('--payee-name <name>', 'Payee name')\n .option('--payee-id <id>', 'Payee ID')\n .option('--category-id <id>', 'Category ID')\n .option('--memo <memo>', 'Memo')\n .option('--cleared <status>', 'Cleared status (cleared, uncleared, reconciled)')\n .option('--approved', 'Mark as approved')\n .action(\n withErrorHandling(\n async (\n options: {\n budget?: string;\n account?: string;\n date?: string;\n amount?: number;\n payeeName?: string;\n payeeId?: string;\n categoryId?: string;\n memo?: string;\n cleared?: string;\n approved?: boolean;\n } & CommandOptions\n ) => {\n const transactionData = buildTransactionData(options);\n const transaction = await client.createTransaction(\n { transaction: transactionData },\n options.budget\n );\n outputJson(transaction);\n }\n )\n );\n\n cmd\n .command('update')\n .description('Update transaction')\n .argument('<id>', 'Transaction ID')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--account <id>', 'Account ID')\n .option('--date <date>', 'Transaction date')\n .option('--amount <amount>', 'Amount in currency units', parseFloat)\n .option('--payee-name <name>', 'Payee name')\n .option('--payee-id <id>', 'Payee ID')\n .option('--category-id <id>', 'Category ID')\n .option('--memo <memo>', 'Memo')\n .option('--cleared <status>', 'Cleared status')\n .option('--approved', 'Mark as approved')\n .action(\n withErrorHandling(\n async (id: string, options: TransactionOptions & { budget?: string } & CommandOptions) => {\n const transactionData = buildUpdateObject(options, {\n account: 'account_id',\n date: 'date',\n payeeName: 'payee_name',\n payeeId: 'payee_id',\n categoryId: 'category_id',\n memo: 'memo',\n cleared: 'cleared',\n approved: 'approved',\n });\n\n if (options.amount !== undefined) {\n transactionData.amount = amountToMilliunits(options.amount);\n }\n\n const transaction = await client.updateTransaction(\n id,\n { transaction: transactionData },\n options.budget\n );\n outputJson(transaction);\n }\n )\n );\n\n cmd\n .command('delete')\n .description('Delete transaction')\n .argument('<id>', 'Transaction ID')\n .option('-b, --budget <id>', 'Budget ID')\n .option('-y, --yes', 'Skip confirmation')\n .action(\n withErrorHandling(\n async (id: string, options: { budget?: string; yes?: boolean } & CommandOptions) => {\n requireConfirmation('transaction', options.yes);\n const transaction = await client.deleteTransaction(id, options.budget);\n outputJson({ message: 'Transaction deleted', transaction });\n }\n )\n );\n\n cmd\n .command('import')\n .description('Import transactions')\n .option('-b, --budget <id>', 'Budget ID')\n .action(\n withErrorHandling(async (options: CommandOptions) => {\n const transactionIds = await client.importTransactions(options.budget);\n outputJson({ transaction_ids: transactionIds });\n })\n );\n\n cmd\n .command('split')\n .description(\n 'Split transaction into multiple categories. Amounts should be in dollars (e.g., 10.50).'\n )\n .argument('<id>', 'Transaction ID')\n .requiredOption(\n '--splits <json>',\n 'JSON array of splits with dollar amounts: [{\"amount\": -21.40, \"category_id\": \"xxx\", \"memo\": \"...\"}]'\n )\n .option('-b, --budget <id>', 'Budget ID')\n .option('-f, --force', 'Force update of already-split transactions by deleting and recreating')\n .action(\n withErrorHandling(\n async (\n id: string,\n options: { splits: string; budget?: string; force?: boolean } & CommandOptions\n ) => {\n let parsedSplits;\n try {\n parsedSplits = JSON.parse(options.splits);\n } catch {\n throw new YnabCliError('Invalid JSON in --splits parameter', 400);\n }\n\n const splits = validateTransactionSplits(parsedSplits);\n\n const splitsInMilliunits = splits.map((split) => ({\n ...split,\n amount: amountToMilliunits(split.amount),\n }));\n\n const existingTransaction = await client.getTransaction(id, options.budget);\n const isAlreadySplit =\n existingTransaction.subtransactions && existingTransaction.subtransactions.length > 0;\n\n if (isAlreadySplit && !options.force) {\n throw new YnabCliError(\n 'Transaction is already split. YNAB API does not support updating split transactions. ' +\n 'Use --force to delete and recreate the transaction with new splits.',\n 400\n );\n }\n\n if (isAlreadySplit) {\n await client.deleteTransaction(id, options.budget);\n\n const recreatedTransaction = await client.createTransaction(\n {\n transaction: {\n account_id: existingTransaction.account_id,\n date: existingTransaction.date,\n amount: existingTransaction.amount,\n payee_id: existingTransaction.payee_id,\n payee_name: existingTransaction.payee_name,\n category_id: null,\n memo: existingTransaction.memo,\n cleared: existingTransaction.cleared,\n approved: existingTransaction.approved,\n flag_color: existingTransaction.flag_color,\n subtransactions: splitsInMilliunits,\n },\n },\n options.budget\n );\n outputJson(recreatedTransaction);\n } else {\n const transaction = await client.updateTransaction(\n id,\n {\n transaction: {\n category_id: null,\n subtransactions: splitsInMilliunits,\n },\n },\n options.budget\n );\n outputJson(transaction);\n }\n }\n )\n );\n\n cmd\n .command('search')\n .description('Search transactions')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--memo <text>', 'Search in memo field')\n .option('--payee-name <name>', 'Search in payee name')\n .option('--amount <amount>', 'Search for exact amount in currency units', parseFloat)\n .option('--since <date>', 'Search transactions since date')\n .option('--until <date>', 'Search transactions until date')\n .option('--approved <value>', 'Filter by approval status: true or false')\n .option(\n '--status <statuses>',\n 'Filter by cleared status: cleared, uncleared, reconciled (comma-separated)'\n )\n .option('--fields <fields>', 'Comma-separated list of fields to include')\n .action(\n withErrorHandling(\n async (\n options: {\n budget?: string;\n memo?: string;\n payeeName?: string;\n amount?: number;\n since?: string;\n until?: string;\n approved?: string;\n status?: string;\n fields?: string;\n } & CommandOptions\n ) => {\n if (!options.memo && !options.payeeName && options.amount === undefined) {\n throw new YnabCliError(\n 'At least one search criteria required: --memo, --payee-name, or --amount',\n 400\n );\n }\n\n const params = {\n budgetId: options.budget,\n sinceDate: options.since ? parseDate(options.since) : undefined,\n };\n\n const result = await client.getTransactions(params);\n let transactions = result?.transactions || [];\n\n if (options.memo) {\n const searchTerm = options.memo.toLowerCase();\n transactions = transactions.filter((t) => t.memo?.toLowerCase().includes(searchTerm));\n }\n\n if (options.payeeName) {\n const searchTerm = options.payeeName.toLowerCase();\n transactions = transactions.filter((t) =>\n t.payee_name?.toLowerCase().includes(searchTerm)\n );\n }\n\n if (options.amount !== undefined) {\n const amountMilliunits = amountToMilliunits(options.amount);\n transactions = transactions.filter((t) => t.amount === amountMilliunits);\n }\n\n transactions = applyTransactionFilters(transactions, {\n until: options.until ? parseDate(options.until) : undefined,\n approved: options.approved,\n status: options.status,\n });\n\n const filteredTransactions = applyFieldSelection(transactions, options.fields);\n\n outputJson(filteredTransactions);\n }\n )\n );\n\n return cmd;\n}\n","import { YnabCliError } from './errors.js';\n\nexport interface TransactionSplit {\n amount: number;\n category_id?: string | null;\n memo?: string;\n payee_id?: string;\n}\n\nexport function validateTransactionSplits(data: unknown): TransactionSplit[] {\n if (!Array.isArray(data)) {\n throw new YnabCliError('Transaction splits must be an array', 400);\n }\n\n return data.map((item, index) => {\n if (typeof item !== 'object' || item === null) {\n throw new YnabCliError(`Split at index ${index} must be an object`, 400);\n }\n\n const split = item as Record<string, unknown>;\n\n if (typeof split.amount !== 'number') {\n throw new YnabCliError(`Split at index ${index} must have a numeric amount`, 400);\n }\n\n return {\n amount: split.amount,\n category_id: split.category_id as string | null | undefined,\n memo: split.memo as string | undefined,\n payee_id: split.payee_id as string | undefined,\n };\n });\n}\n\nexport function validateApiData(data: unknown): Record<string, unknown> {\n if (typeof data !== 'object' || data === null || Array.isArray(data)) {\n throw new YnabCliError('API data must be an object', 400);\n }\n return data as Record<string, unknown>;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputJson } from '../lib/output.js';\nimport { withErrorHandling, requireConfirmation } from '../lib/command-utils.js';\nimport type { CommandOptions } from '../types/index.js';\n\nexport function createScheduledCommand(): Command {\n const cmd = new Command('scheduled').description('Scheduled transaction operations');\n\n cmd\n .command('list')\n .description('List all scheduled transactions')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--last-knowledge <number>', 'Last knowledge of server', parseInt)\n .action(\n withErrorHandling(\n async (options: { budget?: string; lastKnowledge?: number } & CommandOptions) => {\n const result = await client.getScheduledTransactions(\n options.budget,\n options.lastKnowledge\n );\n outputJson(result?.scheduled_transactions);\n }\n )\n );\n\n cmd\n .command('view')\n .description('View scheduled transaction')\n .argument('<id>', 'Scheduled transaction ID')\n .option('-b, --budget <id>', 'Budget ID')\n .action(\n withErrorHandling(async (id: string, options: CommandOptions) => {\n const scheduledTransaction = await client.getScheduledTransaction(id, options.budget);\n outputJson(scheduledTransaction);\n })\n );\n\n cmd\n .command('delete')\n .description('Delete scheduled transaction')\n .argument('<id>', 'Scheduled transaction ID')\n .option('-b, --budget <id>', 'Budget ID')\n .option('-y, --yes', 'Skip confirmation')\n .action(\n withErrorHandling(\n async (id: string, options: { budget?: string; yes?: boolean } & CommandOptions) => {\n requireConfirmation('scheduled transaction', options.yes);\n const scheduledTransaction = await client.deleteScheduledTransaction(id, options.budget);\n outputJson({\n message: 'Scheduled transaction deleted',\n scheduled_transaction: scheduledTransaction,\n });\n }\n )\n );\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputJson } from '../lib/output.js';\nimport { YnabCliError } from '../lib/errors.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\nimport { parseDate } from '../lib/dates.js';\nimport type { CommandOptions } from '../types/index.js';\n\nexport function createPayeesCommand(): Command {\n const cmd = new Command('payees').description('Payee operations');\n\n cmd\n .command('list')\n .description('List all payees')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--last-knowledge <number>', 'Last knowledge of server', parseInt)\n .action(\n withErrorHandling(\n async (options: { budget?: string; lastKnowledge?: number } & CommandOptions) => {\n const result = await client.getPayees(options.budget, options.lastKnowledge);\n outputJson(result?.payees);\n }\n )\n );\n\n cmd\n .command('view')\n .description('View payee details')\n .argument('<id>', 'Payee ID')\n .option('-b, --budget <id>', 'Budget ID')\n .action(\n withErrorHandling(async (id: string, options: CommandOptions) => {\n const payee = await client.getPayee(id, options.budget);\n outputJson(payee);\n })\n );\n\n cmd\n .command('update')\n .description('Rename payee')\n .argument('<id>', 'Payee ID')\n .requiredOption('--name <name>', 'New payee name')\n .option('-b, --budget <id>', 'Budget ID')\n .action(\n withErrorHandling(\n async (id: string, options: { name: string; budget?: string } & CommandOptions) => {\n if (!options.name?.trim()) {\n throw new YnabCliError('Name cannot be empty', 400);\n }\n\n const payee = await client.updatePayee(\n id,\n { payee: { name: options.name } },\n options.budget\n );\n outputJson(payee);\n }\n )\n );\n\n cmd\n .command('locations')\n .description('List locations for payee')\n .argument('<id>', 'Payee ID')\n .option('-b, --budget <id>', 'Budget ID')\n .action(\n withErrorHandling(async (id: string, options: CommandOptions) => {\n const locations = await client.getPayeeLocationsByPayee(id, options.budget);\n outputJson(locations);\n })\n );\n\n cmd\n .command('transactions')\n .description('List transactions for payee')\n .argument('<id>', 'Payee ID')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--since <date>', 'Filter transactions since date')\n .option('--type <type>', 'Filter by transaction type')\n .option('--last-knowledge <number>', 'Last knowledge of server', parseInt)\n .action(\n withErrorHandling(\n async (\n id: string,\n options: {\n budget?: string;\n since?: string;\n type?: string;\n lastKnowledge?: number;\n } & CommandOptions\n ) => {\n const result = await client.getTransactionsByPayee(id, {\n budgetId: options.budget,\n sinceDate: options.since ? parseDate(options.since) : undefined,\n type: options.type,\n lastKnowledgeOfServer: options.lastKnowledge,\n });\n outputJson(result?.transactions);\n }\n )\n );\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputJson } from '../lib/output.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\nimport { parseDate } from '../lib/dates.js';\nimport type { CommandOptions } from '../types/index.js';\n\nexport function createMonthsCommand(): Command {\n const cmd = new Command('months').description('Monthly budget operations');\n\n cmd\n .command('list')\n .description('List all budget months')\n .option('-b, --budget <id>', 'Budget ID')\n .option('--last-knowledge <number>', 'Last knowledge of server', parseInt)\n .action(\n withErrorHandling(\n async (options: { budget?: string; lastKnowledge?: number } & CommandOptions) => {\n const result = await client.getBudgetMonths(options.budget, options.lastKnowledge);\n outputJson(result?.months);\n }\n )\n );\n\n cmd\n .command('view')\n .description('View specific month details')\n .argument('<month>', 'Budget month (e.g., 2025-07-01)')\n .option('-b, --budget <id>', 'Budget ID')\n .action(\n withErrorHandling(async (month: string, options: CommandOptions) => {\n const monthData = await client.getBudgetMonth(parseDate(month), options.budget);\n outputJson(monthData);\n })\n );\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { client } from '../lib/api-client.js';\nimport { outputJson } from '../lib/output.js';\nimport { YnabCliError } from '../lib/errors.js';\nimport { withErrorHandling } from '../lib/command-utils.js';\nimport { validateApiData } from '../lib/schemas.js';\nimport type { CommandOptions } from '../types/index.js';\n\nconst VALID_HTTP_METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'];\n\nexport function createApiCommand(): Command {\n const cmd = new Command('api').description('Raw API access');\n\n cmd\n .argument('<method>', 'HTTP method (GET, POST, PUT, PATCH, DELETE)')\n .argument('<path>', 'API path (e.g., /budgets or /budgets/{budget_id}/transactions)')\n .option('-b, --budget <id>', 'Budget ID (used to replace {budget_id} in path)')\n .option('--data <json>', 'JSON data for POST/PUT/PATCH requests')\n .description('Make raw API calls to YNAB')\n .action(\n withErrorHandling(\n async (\n method: string,\n path: string,\n options: { budget?: string; data?: string } & CommandOptions\n ) => {\n const upperMethod = method.toUpperCase();\n\n if (!VALID_HTTP_METHODS.includes(upperMethod)) {\n throw new YnabCliError(\n `Invalid HTTP method: ${method}. Must be one of: ${VALID_HTTP_METHODS.join(', ')}`,\n 400\n );\n }\n\n let data: Record<string, unknown> | undefined;\n if (options.data) {\n let parsedData: unknown;\n try {\n parsedData = JSON.parse(options.data);\n } catch {\n throw new YnabCliError('Invalid JSON in --data parameter', 400);\n }\n data = validateApiData(parsedData);\n }\n\n const result = await client.rawApiCall(upperMethod, path, data, options.budget);\n outputJson(result);\n }\n )\n );\n\n return cmd;\n}\n","import { Command } from 'commander';\nimport { runMcpServer } from '../mcp/server.js';\n\nexport function createMcpCommand(): Command {\n const cmd = new Command('mcp').description('Run YNAB MCP server');\n\n cmd.action(async () => {\n await runMcpServer();\n });\n\n return cmd;\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { z } from 'zod';\nimport { client } from '../lib/api-client.js';\nimport { auth } from '../lib/auth.js';\nimport { convertMilliunitsToAmounts } from '../lib/utils.js';\n\nconst server = new McpServer({\n name: 'ynab',\n version: '1.0.0',\n});\n\nfunction jsonResponse(data: unknown) {\n return { content: [{ type: 'text' as const, text: JSON.stringify(data, null, 2) }] };\n}\n\nfunction currencyResponse(data: unknown) {\n return jsonResponse(convertMilliunitsToAmounts(data));\n}\n\nserver.tool(\n 'list_budgets',\n 'List all budgets in the YNAB account',\n { includeAccounts: z.boolean().optional().describe('Include account details') },\n async ({ includeAccounts }) => currencyResponse(await client.getBudgets(includeAccounts))\n);\n\nserver.tool(\n 'get_budget',\n 'Get detailed information about a specific budget',\n { budgetId: z.string().optional().describe('Budget ID (uses default if not specified)') },\n async ({ budgetId }) => currencyResponse(await client.getBudget(budgetId))\n);\n\nserver.tool(\n 'list_accounts',\n 'List all accounts in a budget',\n { budgetId: z.string().optional().describe('Budget ID (uses default if not specified)') },\n async ({ budgetId }) => currencyResponse(await client.getAccounts(budgetId))\n);\n\nserver.tool(\n 'get_account',\n 'Get detailed information about a specific account',\n {\n accountId: z.string().describe('Account ID'),\n budgetId: z.string().optional().describe('Budget ID (uses default if not specified)'),\n },\n async ({ accountId, budgetId }) => currencyResponse(await client.getAccount(accountId, budgetId))\n);\n\nserver.tool(\n 'list_categories',\n 'List all category groups and categories in a budget',\n { budgetId: z.string().optional().describe('Budget ID (uses default if not specified)') },\n async ({ budgetId }) => currencyResponse(await client.getCategories(budgetId))\n);\n\nserver.tool(\n 'get_category',\n 'Get detailed information about a specific category',\n {\n categoryId: z.string().describe('Category ID'),\n budgetId: z.string().optional().describe('Budget ID (uses default if not specified)'),\n },\n async ({ categoryId, budgetId }) => currencyResponse(await client.getCategory(categoryId, budgetId))\n);\n\nserver.tool(\n 'list_transactions',\n 'List transactions with optional filtering',\n {\n budgetId: z.string().optional().describe('Budget ID (uses default if not specified)'),\n sinceDate: z.string().optional().describe('Only return transactions on or after this date (YYYY-MM-DD)'),\n type: z.enum(['uncategorized', 'unapproved']).optional().describe('Filter by transaction type'),\n },\n async ({ budgetId, sinceDate, type }) =>\n currencyResponse(await client.getTransactions({ budgetId, sinceDate, type }))\n);\n\nserver.tool(\n 'get_transaction',\n 'Get detailed information about a specific transaction',\n {\n transactionId: z.string().describe('Transaction ID'),\n budgetId: z.string().optional().describe('Budget ID (uses default if not specified)'),\n },\n async ({ transactionId, budgetId }) => currencyResponse(await client.getTransaction(transactionId, budgetId))\n);\n\nserver.tool(\n 'list_transactions_by_account',\n 'List transactions for a specific account',\n {\n accountId: z.string().describe('Account ID'),\n budgetId: z.string().optional().describe('Budget ID (uses default if not specified)'),\n sinceDate: z.string().optional().describe('Only return transactions on or after this date (YYYY-MM-DD)'),\n },\n async ({ accountId, budgetId, sinceDate }) =>\n currencyResponse(await client.getTransactionsByAccount(accountId, { budgetId, sinceDate }))\n);\n\nserver.tool(\n 'list_transactions_by_category',\n 'List transactions for a specific category',\n {\n categoryId: z.string().describe('Category ID'),\n budgetId: z.string().optional().describe('Budget ID (uses default if not specified)'),\n sinceDate: z.string().optional().describe('Only return transactions on or after this date (YYYY-MM-DD)'),\n },\n async ({ categoryId, budgetId, sinceDate }) =>\n currencyResponse(await client.getTransactionsByCategory(categoryId, { budgetId, sinceDate }))\n);\n\nserver.tool(\n 'list_payees',\n 'List all payees in a budget',\n { budgetId: z.string().optional().describe('Budget ID (uses default if not specified)') },\n async ({ budgetId }) => jsonResponse(await client.getPayees(budgetId))\n);\n\nserver.tool(\n 'get_budget_month',\n 'Get budget details for a specific month',\n {\n month: z.string().describe('Month in YYYY-MM-DD format (day is ignored, use first of month)'),\n budgetId: z.string().optional().describe('Budget ID (uses default if not specified)'),\n },\n async ({ month, budgetId }) => currencyResponse(await client.getBudgetMonth(month, budgetId))\n);\n\nserver.tool(\n 'list_scheduled_transactions',\n 'List all scheduled transactions in a budget',\n { budgetId: z.string().optional().describe('Budget ID (uses default if not specified)') },\n async ({ budgetId }) => currencyResponse(await client.getScheduledTransactions(budgetId))\n);\n\nserver.tool(\n 'get_user',\n 'Get information about the authenticated user',\n {},\n async () => jsonResponse(await client.getUser())\n);\n\nserver.tool(\n 'check_auth',\n 'Check if YNAB authentication is configured',\n {},\n async () => jsonResponse({ authenticated: await auth.isAuthenticated() })\n);\n\nexport async function runMcpServer() {\n const transport = new StdioServerTransport();\n await server.connect(transport);\n}\n"],"mappings":"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","names":["Command","sanitized","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stephendolan/ynab-cli",
3
- "version": "2.1.1",
3
+ "version": "2.2.0",
4
4
  "description": "A command-line interface for You Need a Budget (YNAB)",
5
5
  "type": "module",
6
6
  "main": "./dist/cli.js",
@@ -45,11 +45,13 @@
45
45
  "LICENSE"
46
46
  ],
47
47
  "dependencies": {
48
+ "@modelcontextprotocol/sdk": "^1.12.0",
48
49
  "@napi-rs/keyring": "^1.2.0",
49
50
  "commander": "^12.0.0",
50
51
  "conf": "^12.0.0",
51
52
  "dayjs": "^1.11.19",
52
- "ynab": "^2.10.0"
53
+ "ynab": "^2.10.0",
54
+ "zod": "^3.24.0"
53
55
  },
54
56
  "devDependencies": {
55
57
  "@biomejs/biome": "^1.9.4",