ledgit-cli 0.4.2 → 0.5.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/dist/index.js +1173 -193
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -46345,6 +46345,10 @@ npx ledgit-cli generate-lines --inbox-dir <path> \\
|
|
|
46345
46345
|
# List available tax codes
|
|
46346
46346
|
npx ledgit-cli list-tax-codes
|
|
46347
46347
|
|
|
46348
|
+
# Skills - detailed guidance for specific tasks
|
|
46349
|
+
npx ledgit-cli skills # List available skills
|
|
46350
|
+
npx ledgit-cli skills <name> # Get detailed instructions for a skill
|
|
46351
|
+
|
|
46348
46352
|
# Update instructions
|
|
46349
46353
|
npx ledgit-cli update # Update AGENTS.md to latest version
|
|
46350
46354
|
\`\`\`
|
|
@@ -46359,6 +46363,25 @@ inbox/ → (create-entry) → journal-entries/ → (git review & commit) → (sy
|
|
|
46359
46363
|
|
|
46360
46364
|
When you run \`create-entry\` on main branch, a new git branch is automatically created (e.g., \`book/V-189-2025-10-15-anthropic\`). Review changes with \`git diff\`, commit, and sync to provider.
|
|
46361
46365
|
|
|
46366
|
+
## Skills
|
|
46367
|
+
|
|
46368
|
+
Skills provide detailed domain knowledge for specific accounting tasks. **Before creating journal entries**, load the relevant skill to get comprehensive guidance on accounts, tax codes, and workflows.
|
|
46369
|
+
|
|
46370
|
+
\`\`\`bash
|
|
46371
|
+
# List available skills
|
|
46372
|
+
npx ledgit-cli skills
|
|
46373
|
+
|
|
46374
|
+
# Load skill instructions (read the full output before proceeding)
|
|
46375
|
+
npx ledgit-cli skills swedish-bookkeeping # General bookkeeping, VAT, BAS accounts
|
|
46376
|
+
npx ledgit-cli skills travel-expenses # Hotels, flights, traktamente, per diem
|
|
46377
|
+
\`\`\`
|
|
46378
|
+
|
|
46379
|
+
**When to use skills:**
|
|
46380
|
+
- \`swedish-bookkeeping\` - Creating journal entries, handling VAT/moms, selecting accounts
|
|
46381
|
+
- \`travel-expenses\` - Business travel, hotels, flights, traktamente (per diem), mileage
|
|
46382
|
+
|
|
46383
|
+
Always load the appropriate skill when working on unfamiliar transaction types.
|
|
46384
|
+
|
|
46362
46385
|
## Bookkeeping New Entries
|
|
46363
46386
|
|
|
46364
46387
|
To create a journal entry from an inbox document:
|
|
@@ -46393,21 +46416,11 @@ This removes the directory and marks the item for deletion from the provider on
|
|
|
46393
46416
|
|
|
46394
46417
|
## Tax Codes
|
|
46395
46418
|
|
|
46396
|
-
|
|
46419
|
+
For detailed VAT/tax code guidance, run \`npx ledgit-cli skills swedish-bookkeeping\`.
|
|
46397
46420
|
|
|
46398
|
-
|
|
46399
|
-
|
|
46400
|
-
|
|
46401
|
-
| Domestic purchase 12% | \`SE_VAT_12_PURCHASE_DOMESTIC\` | Expense + 2641 + 2440 |
|
|
46402
|
-
| Non-EU services (US SaaS) | \`SE_VAT_25_PURCHASE_NON_EU_SERVICES_RC\` | 5422 + 2645 + 2614 + 2820 |
|
|
46403
|
-
| EU services | \`SE_VAT_25_PURCHASE_EU_SERVICES_RC\` | Expense + 2645 + 2614 + 2440 |
|
|
46404
|
-
| Exempt purchase | \`SE_VAT_EXEMPT_PURCHASE\` | Expense + balancing |
|
|
46405
|
-
|
|
46406
|
-
**Notes:**
|
|
46407
|
-
- \`RC\` = Reverse Charge (buyer reports VAT instead of seller)
|
|
46408
|
-
- Use \`--list-tax-codes\` to see all available codes with descriptions
|
|
46409
|
-
- Account 2641 = Incoming VAT (domestic), 2645 = Incoming VAT (reverse charge)
|
|
46410
|
-
- Account 2614 = Outgoing VAT (reverse charge)
|
|
46421
|
+
Quick reference:
|
|
46422
|
+
- \`npx ledgit-cli list-tax-codes\` - List all available codes
|
|
46423
|
+
- \`RC\` suffix = Reverse Charge (buyer reports VAT instead of seller)
|
|
46411
46424
|
|
|
46412
46425
|
## Entities
|
|
46413
46426
|
|
|
@@ -46461,26 +46474,11 @@ externalId: "12" # Provider reference
|
|
|
46461
46474
|
|
|
46462
46475
|
## Account Codes
|
|
46463
46476
|
|
|
46464
|
-
|
|
46465
|
-
|
|
46466
|
-
|
|
46467
|
-
|
|
46468
|
-
|
|
46469
|
-
- **4xxx** - Cost of goods sold (Inköp)
|
|
46470
|
-
- **5xxx-6xxx** - Operating expenses (Kostnader)
|
|
46471
|
-
- **7xxx** - Personnel costs (Personalkostnader)
|
|
46472
|
-
- **8xxx** - Financial items (Finansiella poster)
|
|
46473
|
-
- **9xxx** - Year-end allocations (Bokslutsdispositioner)
|
|
46474
|
-
|
|
46475
|
-
Common accounts:
|
|
46476
|
-
- \`1930\` - Business bank account
|
|
46477
|
-
- \`2440\` - Supplier payables
|
|
46478
|
-
- \`2610\` - Outgoing VAT 25%
|
|
46479
|
-
- \`2640\` - Incoming VAT
|
|
46480
|
-
- \`2820\` - Short-term liabilities (credit card, etc.)
|
|
46481
|
-
- \`4000\` - Cost of goods sold
|
|
46482
|
-
- \`5420\` - Software and IT services
|
|
46483
|
-
- \`6570\` - Bank charges
|
|
46477
|
+
For detailed BAS account guidance, run \`npx ledgit-cli skills swedish-bookkeeping\`.
|
|
46478
|
+
|
|
46479
|
+
Account ranges: 1xxx=Assets, 2xxx=Liabilities, 3xxx=Revenue, 4xxx=COGS, 5-6xxx=Expenses, 7xxx=Personnel, 8xxx=Financial.
|
|
46480
|
+
|
|
46481
|
+
Also check \`accounts.yaml\` in this repository for the company's chart of accounts.
|
|
46484
46482
|
`;
|
|
46485
46483
|
function getAgentsTemplate() {
|
|
46486
46484
|
return AGENTS_TEMPLATE;
|
|
@@ -48056,6 +48054,813 @@ class SyncProgressBar {
|
|
|
48056
48054
|
};
|
|
48057
48055
|
}
|
|
48058
48056
|
}
|
|
48057
|
+
// ../bookkeeping/dist/skills/swedish-bookkeeping.js
|
|
48058
|
+
var SWEDISH_BOOKKEEPING_SKILL = {
|
|
48059
|
+
name: "swedish-bookkeeping",
|
|
48060
|
+
description: "Swedish bookkeeping and accounting using BAS kontoplan. Use when creating journal entries (verifikationer), handling Swedish VAT (moms), categorizing expenses, or working with Swedish accounting data. Triggers on tasks involving BAS accounts (1xxx-9xxx), moms/VAT codes, reverse charge (omvänd skattskyldighet), supplier invoices, or financial record-keeping for Swedish companies.",
|
|
48061
|
+
content: `# Swedish Bookkeeping
|
|
48062
|
+
|
|
48063
|
+
Create journal entries following Swedish BAS accounting standards with correct VAT handling.
|
|
48064
|
+
|
|
48065
|
+
## Quick Reference
|
|
48066
|
+
|
|
48067
|
+
- **Accounts**: See accounts section below for BAS account codes
|
|
48068
|
+
- **VAT/Tax codes**: See VAT codes section below for tax code selection
|
|
48069
|
+
|
|
48070
|
+
## Journal Entry Structure
|
|
48071
|
+
|
|
48072
|
+
Every entry (verifikation) must balance: total debits = total credits.
|
|
48073
|
+
|
|
48074
|
+
\`\`\`yaml
|
|
48075
|
+
series: D # A=Admin, B=Customer invoices, C=Customer payments,
|
|
48076
|
+
# D=Supplier invoices, E=Supplier payments, K=Salary
|
|
48077
|
+
entryNumber: 1
|
|
48078
|
+
entryDate: 2024-01-15
|
|
48079
|
+
description: Supplier Name - Invoice description
|
|
48080
|
+
status: POSTED
|
|
48081
|
+
currency: SEK
|
|
48082
|
+
lines:
|
|
48083
|
+
- account: "5422" # Expense account
|
|
48084
|
+
debit: 1000.00
|
|
48085
|
+
memo: SaaS subscription
|
|
48086
|
+
- account: "2645" # VAT (if applicable)
|
|
48087
|
+
debit: 250.00
|
|
48088
|
+
memo: Input VAT reverse charge
|
|
48089
|
+
- account: "2614" # Output VAT for reverse charge
|
|
48090
|
+
credit: 250.00
|
|
48091
|
+
memo: Output VAT reverse charge
|
|
48092
|
+
- account: "2820" # Balancing account
|
|
48093
|
+
credit: 1000.00
|
|
48094
|
+
memo: Credit card payment
|
|
48095
|
+
\`\`\`
|
|
48096
|
+
|
|
48097
|
+
## Tax Code Selection
|
|
48098
|
+
|
|
48099
|
+
\`\`\`
|
|
48100
|
+
Swedish supplier (VAT on invoice)?
|
|
48101
|
+
├─ YES → SE_VAT_25_PURCHASE_DOMESTIC (or 12%/6%/exempt)
|
|
48102
|
+
└─ NO → Is it a service?
|
|
48103
|
+
├─ YES, EU supplier → SE_VAT_25_PURCHASE_EU_SERVICES_RC
|
|
48104
|
+
├─ YES, non-EU (US/UK) → SE_VAT_25_PURCHASE_NON_EU_SERVICES_RC
|
|
48105
|
+
└─ NO (goods) → SE_VAT_25_PURCHASE_EU_GOODS_RC or import
|
|
48106
|
+
\`\`\`
|
|
48107
|
+
|
|
48108
|
+
## Common Expense Accounts
|
|
48109
|
+
|
|
48110
|
+
| Type | Account | Example Vendors |
|
|
48111
|
+
|------|---------|-----------------|
|
|
48112
|
+
| SaaS/Software | 5422 | AWS, GitHub, Anthropic, Slack |
|
|
48113
|
+
| IT services | 6540 | Consulting, development |
|
|
48114
|
+
| Accounting | 6530 | Bokio, Fortnox |
|
|
48115
|
+
| Bank fees | 6570 | Bank charges (VAT exempt) |
|
|
48116
|
+
| Internet/Telecom | 6230 | ISP, phone plans |
|
|
48117
|
+
| Office supplies | 6110 | Stationery, small equipment |
|
|
48118
|
+
| Travel | 5800 | Flights, trains |
|
|
48119
|
+
| Meals (business) | 5831 | Hotels, business meals |
|
|
48120
|
+
|
|
48121
|
+
## Balancing Accounts
|
|
48122
|
+
|
|
48123
|
+
| Method | Account | Use |
|
|
48124
|
+
|--------|---------|-----|
|
|
48125
|
+
| Supplier payable | 2440 | When paying later via bank transfer |
|
|
48126
|
+
| Credit card | 2820 | Direct credit card charge |
|
|
48127
|
+
| Bank account | 1930 | Direct debit/immediate payment |
|
|
48128
|
+
|
|
48129
|
+
## Workflow: Creating an Entry
|
|
48130
|
+
|
|
48131
|
+
1. **Identify the supplier** - Swedish, EU, or non-EU?
|
|
48132
|
+
2. **Determine expense type** - Select appropriate 5xxx/6xxx account
|
|
48133
|
+
3. **Select tax code** - Based on supplier location and transaction type
|
|
48134
|
+
4. **Choose balancing account** - 2440 (payable), 2820 (credit card), or 1930 (bank)
|
|
48135
|
+
5. **Create balanced entry** - Ensure debits = credits
|
|
48136
|
+
|
|
48137
|
+
## Currency Handling
|
|
48138
|
+
|
|
48139
|
+
Foreign currency amounts must be converted to SEK using the exchange rate on the transaction date. Use Riksbank published rates.
|
|
48140
|
+
|
|
48141
|
+
## Series Codes
|
|
48142
|
+
|
|
48143
|
+
| Series | Swedish | Use |
|
|
48144
|
+
|--------|---------|-----|
|
|
48145
|
+
| A | Administration | Internal adjustments, corrections |
|
|
48146
|
+
| B | Kundfakturor | Customer invoices (sales) |
|
|
48147
|
+
| C | Kundbetalningar | Customer payments received |
|
|
48148
|
+
| D | Leverantörsfakturor | Supplier invoices (purchases) |
|
|
48149
|
+
| E | Leverantörsbetalningar | Supplier payments made |
|
|
48150
|
+
| K | Löner | Salary and payroll |
|
|
48151
|
+
|
|
48152
|
+
---
|
|
48153
|
+
|
|
48154
|
+
# Swedish BAS Account Codes
|
|
48155
|
+
|
|
48156
|
+
The BAS chart of accounts (kontoplan) is the standard accounting framework used by Swedish companies. Account numbers have 4 digits where the first digit indicates the account class.
|
|
48157
|
+
|
|
48158
|
+
## Account Classes
|
|
48159
|
+
|
|
48160
|
+
| Class | Swedish Name | English | Description |
|
|
48161
|
+
|-------|-------------|---------|-------------|
|
|
48162
|
+
| 1xxx | Tillgångar | Assets | Cash, receivables, inventory, fixed assets |
|
|
48163
|
+
| 2xxx | Skulder & Eget kapital | Liabilities & Equity | Payables, loans, VAT, equity |
|
|
48164
|
+
| 3xxx | Intäkter | Revenue | Sales, other income |
|
|
48165
|
+
| 4xxx | Inköp/Varor | Cost of Goods | Direct costs, materials |
|
|
48166
|
+
| 5xxx | Övriga externa kostnader | External Expenses | Rent, services, supplies |
|
|
48167
|
+
| 6xxx | Övriga externa kostnader | External Expenses | Marketing, admin, IT |
|
|
48168
|
+
| 7xxx | Personalkostnader | Personnel Costs | Salaries, benefits, taxes |
|
|
48169
|
+
| 8xxx | Finansiella poster | Financial Items | Interest, currency gains/losses |
|
|
48170
|
+
| 9xxx | Bokslutsdispositioner | Year-end Items | Appropriations, tax |
|
|
48171
|
+
|
|
48172
|
+
## Account Number Structure
|
|
48173
|
+
|
|
48174
|
+
- **First digit**: Account class (1-9)
|
|
48175
|
+
- **First two digits**: Account group
|
|
48176
|
+
- **Ending in 00**: Control account (aggregates entire group)
|
|
48177
|
+
- **Ending in 0**: Main account
|
|
48178
|
+
- **Ending in 1-9**: Sub-accounts (detailed breakdown)
|
|
48179
|
+
|
|
48180
|
+
## Commonly Used Accounts
|
|
48181
|
+
|
|
48182
|
+
### Assets (1xxx)
|
|
48183
|
+
|
|
48184
|
+
| Account | Name | Use |
|
|
48185
|
+
|---------|------|-----|
|
|
48186
|
+
| 1510 | Kundfordringar | Accounts receivable |
|
|
48187
|
+
| 1630 | Skattekonto | Tax account (Skatteverket) |
|
|
48188
|
+
| 1930 | Företagskonto | Business bank account |
|
|
48189
|
+
| 1940 | Placeringskonto | Savings/investment account |
|
|
48190
|
+
|
|
48191
|
+
### Liabilities & Equity (2xxx)
|
|
48192
|
+
|
|
48193
|
+
| Account | Name | Use |
|
|
48194
|
+
|---------|------|-----|
|
|
48195
|
+
| 2010 | Eget kapital | Owner's equity |
|
|
48196
|
+
| 2091 | Balanserad vinst | Retained earnings |
|
|
48197
|
+
| 2099 | Årets resultat | Current year profit/loss |
|
|
48198
|
+
| 2440 | Leverantörsskulder | Accounts payable |
|
|
48199
|
+
| 2510 | Skatteskulder | Tax liabilities |
|
|
48200
|
+
| 2610 | Utgående moms 25% | Output VAT 25% (sales) |
|
|
48201
|
+
| 2611 | Utgående moms 12% | Output VAT 12% |
|
|
48202
|
+
| 2612 | Utgående moms 6% | Output VAT 6% |
|
|
48203
|
+
| 2614 | Utgående moms omvänd skattskyldighet | Output VAT reverse charge |
|
|
48204
|
+
| 2640 | Ingående moms | Input VAT (general) |
|
|
48205
|
+
| 2641 | Ingående moms 25% | Input VAT 25% (domestic) |
|
|
48206
|
+
| 2645 | Ingående moms omvänd skattskyldighet | Input VAT reverse charge |
|
|
48207
|
+
| 2650 | Momsredovisningskonto | VAT settlement account |
|
|
48208
|
+
| 2820 | Kortfristiga skulder | Short-term liabilities (credit card) |
|
|
48209
|
+
| 2898 | Outtagen vinstutdelning | Undistributed dividends |
|
|
48210
|
+
|
|
48211
|
+
### Revenue (3xxx)
|
|
48212
|
+
|
|
48213
|
+
| Account | Name | Use |
|
|
48214
|
+
|---------|------|-----|
|
|
48215
|
+
| 3000 | Försäljning | Sales (general) |
|
|
48216
|
+
| 3001 | Försäljning 25% moms | Sales 25% VAT |
|
|
48217
|
+
| 3002 | Försäljning 12% moms | Sales 12% VAT |
|
|
48218
|
+
| 3003 | Försäljning 6% moms | Sales 6% VAT |
|
|
48219
|
+
| 3041 | Försäljning tjänster EU | Services sold to EU |
|
|
48220
|
+
| 3051 | Försäljning varor EU | Goods sold to EU |
|
|
48221
|
+
| 3305 | Försäljning utanför EU | Sales outside EU |
|
|
48222
|
+
| 3740 | Öres- och kronutjämning | Rounding adjustments |
|
|
48223
|
+
| 3960 | Valutakursvinster | Currency gains |
|
|
48224
|
+
|
|
48225
|
+
### Cost of Goods (4xxx)
|
|
48226
|
+
|
|
48227
|
+
| Account | Name | Use |
|
|
48228
|
+
|---------|------|-----|
|
|
48229
|
+
| 4000 | Inköp varor | Goods purchased |
|
|
48230
|
+
| 4010 | Inköp material | Materials purchased |
|
|
48231
|
+
| 4531 | Import EU varor | Imports from EU (goods) |
|
|
48232
|
+
| 4535 | Import utanför EU varor | Imports from non-EU (goods) |
|
|
48233
|
+
| 4545 | Inköp tjänster EU | Services from EU |
|
|
48234
|
+
| 4546 | Inköp tjänster utanför EU | Services from non-EU |
|
|
48235
|
+
|
|
48236
|
+
### External Expenses (5xxx-6xxx)
|
|
48237
|
+
|
|
48238
|
+
| Account | Name | Use |
|
|
48239
|
+
|---------|------|-----|
|
|
48240
|
+
| 5010 | Lokalhyra | Office rent |
|
|
48241
|
+
| 5400 | Förbrukningsinventarier | Consumable equipment |
|
|
48242
|
+
| 5410 | Förbrukningsmat. | Consumables |
|
|
48243
|
+
| 5420 | Programvara | Software |
|
|
48244
|
+
| 5422 | Programvara, onlinetjänster | SaaS subscriptions |
|
|
48245
|
+
| 5480 | Arbetskläder | Work clothing |
|
|
48246
|
+
| 5500 | Reparation maskiner | Repairs machinery |
|
|
48247
|
+
| 5800 | Resekostnader | Travel expenses |
|
|
48248
|
+
| 5831 | Kost och logi | Meals and accommodation |
|
|
48249
|
+
| 5910 | Annonsering | Advertising |
|
|
48250
|
+
| 6071 | Representation | Business entertainment |
|
|
48251
|
+
| 6110 | Kontorsmaterial | Office supplies |
|
|
48252
|
+
| 6212 | Mobiltelefon | Mobile phone |
|
|
48253
|
+
| 6230 | Datakommunikation | Internet/data |
|
|
48254
|
+
| 6310 | Företagsförsäkringar | Business insurance |
|
|
48255
|
+
| 6420 | Ersättning styrelsen | Board compensation |
|
|
48256
|
+
| 6530 | Redovisningstjänster | Accounting services |
|
|
48257
|
+
| 6540 | IT-tjänster | IT services |
|
|
48258
|
+
| 6570 | Bankkostnader | Bank charges |
|
|
48259
|
+
| 6970 | Tidningar och tidskrifter | Subscriptions |
|
|
48260
|
+
|
|
48261
|
+
### Personnel Costs (7xxx)
|
|
48262
|
+
|
|
48263
|
+
| Account | Name | Use |
|
|
48264
|
+
|---------|------|-----|
|
|
48265
|
+
| 7010 | Löner tjänstemän | Salaries (employees) |
|
|
48266
|
+
| 7082 | Sjuklön | Sick pay |
|
|
48267
|
+
| 7090 | Förändring semesterlöneskuld | Vacation pay accrual |
|
|
48268
|
+
| 7210 | Löner styrelse | Board salaries |
|
|
48269
|
+
| 7381 | Kostnadsersättning | Expense reimbursement |
|
|
48270
|
+
| 7510 | Arbetsgivaravgifter | Employer contributions |
|
|
48271
|
+
| 7533 | Särskild löneskatt pensionskostnader | Special payroll tax (pensions) |
|
|
48272
|
+
| 7820 | Utbildning | Training/education |
|
|
48273
|
+
|
|
48274
|
+
### Financial Items (8xxx)
|
|
48275
|
+
|
|
48276
|
+
| Account | Name | Use |
|
|
48277
|
+
|---------|------|-----|
|
|
48278
|
+
| 8310 | Ränteintäkter | Interest income |
|
|
48279
|
+
| 8410 | Räntekostnader | Interest expenses |
|
|
48280
|
+
| 8423 | Räntekostnader skattekonto | Tax account interest |
|
|
48281
|
+
| 8910 | Skatt på årets resultat | Income tax |
|
|
48282
|
+
|
|
48283
|
+
## Double-Entry Principles
|
|
48284
|
+
|
|
48285
|
+
Swedish bookkeeping follows standard double-entry principles:
|
|
48286
|
+
- **Debit (debet)**: Increases assets (1xxx), decreases liabilities (2xxx), increases expenses (4xxx-8xxx)
|
|
48287
|
+
- **Credit (kredit)**: Decreases assets, increases liabilities/equity, increases revenue (3xxx)
|
|
48288
|
+
|
|
48289
|
+
Every transaction must balance: total debits = total credits.
|
|
48290
|
+
|
|
48291
|
+
---
|
|
48292
|
+
|
|
48293
|
+
# Swedish VAT (Moms) Tax Codes
|
|
48294
|
+
|
|
48295
|
+
Swedish VAT (Mervärdesskatt/Moms) uses different rates and reporting rules depending on the type of transaction and geographic origin.
|
|
48296
|
+
|
|
48297
|
+
## VAT Rates
|
|
48298
|
+
|
|
48299
|
+
| Rate | Description | Common Uses |
|
|
48300
|
+
|------|-------------|-------------|
|
|
48301
|
+
| 25% | Standard rate | Most goods and services |
|
|
48302
|
+
| 12% | Reduced rate | Food, hotels, restaurants |
|
|
48303
|
+
| 6% | Reduced rate | Books, newspapers, public transport, cultural events |
|
|
48304
|
+
| 0% | Zero-rated | Exports, certain financial services |
|
|
48305
|
+
|
|
48306
|
+
## Tax Code Patterns
|
|
48307
|
+
|
|
48308
|
+
### Domestic Purchases (Swedish Seller)
|
|
48309
|
+
|
|
48310
|
+
When purchasing from a Swedish company that charges VAT:
|
|
48311
|
+
|
|
48312
|
+
| Tax Code | Rate | Expense Account | VAT Account | Balancing |
|
|
48313
|
+
|----------|------|-----------------|-------------|-----------|
|
|
48314
|
+
| \`SE_VAT_25_PURCHASE_DOMESTIC\` | 25% | Expense (5xxx/6xxx) | 2641 | 2440 |
|
|
48315
|
+
| \`SE_VAT_12_PURCHASE_DOMESTIC\` | 12% | Expense | 2641 | 2440 |
|
|
48316
|
+
| \`SE_VAT_6_PURCHASE_DOMESTIC\` | 6% | Expense | 2641 | 2440 |
|
|
48317
|
+
| \`SE_VAT_EXEMPT_PURCHASE\` | 0% | Expense | - | 2440/2820 |
|
|
48318
|
+
|
|
48319
|
+
**Example**: SEK 1,250 domestic purchase with 25% VAT
|
|
48320
|
+
\`\`\`
|
|
48321
|
+
Debit 5420 (Software) 1,000.00
|
|
48322
|
+
Debit 2641 (Input VAT) 250.00
|
|
48323
|
+
Credit 2440 (Supplier payables) 1,250.00
|
|
48324
|
+
\`\`\`
|
|
48325
|
+
|
|
48326
|
+
### Reverse Charge - EU Services
|
|
48327
|
+
|
|
48328
|
+
For B2B services from EU countries (not goods), the buyer reports VAT:
|
|
48329
|
+
|
|
48330
|
+
| Tax Code | Use Case | VAT Handling |
|
|
48331
|
+
|----------|----------|--------------|
|
|
48332
|
+
| \`SE_VAT_25_PURCHASE_EU_SERVICES_RC\` | SaaS, consulting from EU | Reverse charge 25% |
|
|
48333
|
+
| \`SE_VAT_12_PURCHASE_EU_SERVICES_RC\` | Reduced rate EU services | Reverse charge 12% |
|
|
48334
|
+
|
|
48335
|
+
**Journal pattern** (25% reverse charge):
|
|
48336
|
+
\`\`\`
|
|
48337
|
+
Debit 5422 (Expense) 1,000.00 # Net amount
|
|
48338
|
+
Debit 2645 (Input VAT RC) 250.00 # Deductible VAT
|
|
48339
|
+
Credit 2614 (Output VAT RC) 250.00 # VAT liability
|
|
48340
|
+
Credit 2440 (Supplier payables) 1,000.00 # Net to pay
|
|
48341
|
+
\`\`\`
|
|
48342
|
+
|
|
48343
|
+
### Reverse Charge - Non-EU Services
|
|
48344
|
+
|
|
48345
|
+
For B2B services from countries outside EU (US, UK, etc.):
|
|
48346
|
+
|
|
48347
|
+
| Tax Code | Use Case | VAT Handling |
|
|
48348
|
+
|----------|----------|--------------|
|
|
48349
|
+
| \`SE_VAT_25_PURCHASE_NON_EU_SERVICES_RC\` | US SaaS (AWS, GitHub, etc.) | Reverse charge 25% |
|
|
48350
|
+
| \`SE_VAT_12_PURCHASE_NON_EU_SERVICES_RC\` | Reduced rate non-EU services | Reverse charge 12% |
|
|
48351
|
+
|
|
48352
|
+
**Journal pattern** (US SaaS subscription USD 100 = SEK 1,000):
|
|
48353
|
+
\`\`\`
|
|
48354
|
+
Debit 5422 (SaaS expense) 1,000.00
|
|
48355
|
+
Debit 2645 (Input VAT RC) 250.00
|
|
48356
|
+
Credit 2614 (Output VAT RC) 250.00
|
|
48357
|
+
Credit 2820 (Credit card) 1,000.00
|
|
48358
|
+
\`\`\`
|
|
48359
|
+
|
|
48360
|
+
### Reverse Charge - EU Goods
|
|
48361
|
+
|
|
48362
|
+
Physical goods purchased from EU require different handling:
|
|
48363
|
+
|
|
48364
|
+
| Tax Code | Use Case |
|
|
48365
|
+
|----------|----------|
|
|
48366
|
+
| \`SE_VAT_25_PURCHASE_EU_GOODS_RC\` | Hardware, equipment from EU |
|
|
48367
|
+
| \`SE_VAT_12_PURCHASE_EU_GOODS_RC\` | Reduced rate goods from EU |
|
|
48368
|
+
|
|
48369
|
+
### Sales Tax Codes
|
|
48370
|
+
|
|
48371
|
+
| Tax Code | Use Case |
|
|
48372
|
+
|----------|----------|
|
|
48373
|
+
| \`SE_VAT_25_SALE_DOMESTIC\` | Domestic sales 25% |
|
|
48374
|
+
| \`SE_VAT_12_SALE_DOMESTIC\` | Domestic sales 12% |
|
|
48375
|
+
| \`SE_VAT_6_SALE_DOMESTIC\` | Domestic sales 6% |
|
|
48376
|
+
| \`SE_VAT_EXEMPT_SALE_EU\` | B2B sales to EU (reverse charge applies to buyer) |
|
|
48377
|
+
| \`SE_VAT_EXEMPT_SALE_EXPORT\` | Sales outside EU (export) |
|
|
48378
|
+
|
|
48379
|
+
## Determining the Right Tax Code
|
|
48380
|
+
|
|
48381
|
+
\`\`\`
|
|
48382
|
+
Is the supplier Swedish?
|
|
48383
|
+
├─ YES → Use DOMESTIC tax code
|
|
48384
|
+
│ └─ Match VAT rate on invoice (25%, 12%, 6%, or exempt)
|
|
48385
|
+
│
|
|
48386
|
+
└─ NO → Is it a service or goods?
|
|
48387
|
+
│
|
|
48388
|
+
├─ SERVICE → Is supplier in EU?
|
|
48389
|
+
│ ├─ YES → SE_VAT_25_PURCHASE_EU_SERVICES_RC
|
|
48390
|
+
│ └─ NO → SE_VAT_25_PURCHASE_NON_EU_SERVICES_RC
|
|
48391
|
+
│
|
|
48392
|
+
└─ GOODS → Is supplier in EU?
|
|
48393
|
+
├─ YES → SE_VAT_25_PURCHASE_EU_GOODS_RC
|
|
48394
|
+
└─ NO → Import VAT (customs declaration)
|
|
48395
|
+
\`\`\`
|
|
48396
|
+
|
|
48397
|
+
## Key VAT Accounts
|
|
48398
|
+
|
|
48399
|
+
| Account | Swedish Name | Use |
|
|
48400
|
+
|---------|-------------|-----|
|
|
48401
|
+
| 2610 | Utgående moms 25% | Output VAT on sales |
|
|
48402
|
+
| 2611 | Utgående moms 12% | Output VAT 12% |
|
|
48403
|
+
| 2612 | Utgående moms 6% | Output VAT 6% |
|
|
48404
|
+
| 2614 | Utgående moms omvänd skattskyldighet | Output VAT (reverse charge liability) |
|
|
48405
|
+
| 2640 | Ingående moms | Input VAT (general) |
|
|
48406
|
+
| 2641 | Ingående moms | Input VAT on domestic purchases |
|
|
48407
|
+
| 2645 | Ingående moms omvänd skattskyldighet | Input VAT (reverse charge deduction) |
|
|
48408
|
+
| 2650 | Momsredovisningskonto | VAT settlement/clearing |
|
|
48409
|
+
|
|
48410
|
+
## VAT Reporting Periods
|
|
48411
|
+
|
|
48412
|
+
| Annual Turnover | Reporting Frequency |
|
|
48413
|
+
|-----------------|---------------------|
|
|
48414
|
+
| > SEK 40 million | Monthly |
|
|
48415
|
+
| SEK 1-40 million | Quarterly (or monthly by choice) |
|
|
48416
|
+
| < SEK 1 million | Annually (or quarterly by choice) |
|
|
48417
|
+
|
|
48418
|
+
## Common Scenarios
|
|
48419
|
+
|
|
48420
|
+
### US SaaS Subscription (GitHub, AWS, Anthropic)
|
|
48421
|
+
- Tax code: \`SE_VAT_25_PURCHASE_NON_EU_SERVICES_RC\`
|
|
48422
|
+
- Expense account: 5422 (Software/online services)
|
|
48423
|
+
- Balancing: 2820 (credit card) or 2440 (payables)
|
|
48424
|
+
|
|
48425
|
+
### EU Software/Service (Hetzner, OVH)
|
|
48426
|
+
- Tax code: \`SE_VAT_25_PURCHASE_EU_SERVICES_RC\`
|
|
48427
|
+
- Expense account: 5422 or appropriate 5xxx/6xxx
|
|
48428
|
+
- Balancing: 2440 or 2820
|
|
48429
|
+
|
|
48430
|
+
### Swedish Accounting Service (Bokio, Fortnox)
|
|
48431
|
+
- Tax code: \`SE_VAT_25_PURCHASE_DOMESTIC\`
|
|
48432
|
+
- Expense account: 6530 (Accounting services)
|
|
48433
|
+
- Balancing: 2440
|
|
48434
|
+
|
|
48435
|
+
### Bank Charges (Swedish Bank)
|
|
48436
|
+
- Tax code: \`SE_VAT_EXEMPT_PURCHASE\` (financial services exempt)
|
|
48437
|
+
- Expense account: 6570 (Bank charges)
|
|
48438
|
+
- No VAT accounts involved
|
|
48439
|
+
|
|
48440
|
+
### Domain Registration (EU or US Registrar)
|
|
48441
|
+
- EU: \`SE_VAT_25_PURCHASE_EU_SERVICES_RC\`
|
|
48442
|
+
- US: \`SE_VAT_25_PURCHASE_NON_EU_SERVICES_RC\`
|
|
48443
|
+
- Expense account: 6230 (Data communication)
|
|
48444
|
+
`
|
|
48445
|
+
};
|
|
48446
|
+
// ../bookkeeping/dist/skills/travel-expenses.js
|
|
48447
|
+
var TRAVEL_EXPENSES_SKILL = {
|
|
48448
|
+
name: "travel-expenses",
|
|
48449
|
+
description: "Swedish business travel expense accounting. Use when handling hotel receipts, flight bookings, taxi fares, traktamente (per diem), mileage claims, or grouping travel receipts into journal entries. Triggers on keywords - travel, hotel, flight, taxi, traktamente, per diem, business trip, resa, hotell, reseräkning, milersättning, accommodation.",
|
|
48450
|
+
content: `# Travel Expenses
|
|
48451
|
+
|
|
48452
|
+
Create journal entries for Swedish business travel, handling both company-paid expenses and employee reimbursements.
|
|
48453
|
+
|
|
48454
|
+
## Quick Reference
|
|
48455
|
+
|
|
48456
|
+
- **Accounts**: See accounts section below for 5800/7300 series
|
|
48457
|
+
- **VAT treatment**: See VAT rules section below for rates
|
|
48458
|
+
- **Non-travel expenses**: Use swedish-bookkeeping skill for SaaS, services, or other purchases during trips
|
|
48459
|
+
|
|
48460
|
+
## Payment Type Decision
|
|
48461
|
+
|
|
48462
|
+
\`\`\`
|
|
48463
|
+
Who paid?
|
|
48464
|
+
├─ Company (corporate card, invoice)
|
|
48465
|
+
│ └─ Use 5800 series accounts
|
|
48466
|
+
│ 5810 = tickets, 5820 = rental, 5831/5832 = hotel/meals
|
|
48467
|
+
│
|
|
48468
|
+
└─ Employee (personal card, cash)
|
|
48469
|
+
└─ Use 7300 series accounts
|
|
48470
|
+
7321/7323 = traktamente, 7381 = expense reimbursement
|
|
48471
|
+
\`\`\`
|
|
48472
|
+
|
|
48473
|
+
## Traktamente (Per Diem)
|
|
48474
|
+
|
|
48475
|
+
Use the CLI to calculate and create traktamente entries:
|
|
48476
|
+
|
|
48477
|
+
\`\`\`bash
|
|
48478
|
+
# List country rates
|
|
48479
|
+
npx ledgit-cli traktamente list
|
|
48480
|
+
npx ledgit-cli traktamente list --year 2026
|
|
48481
|
+
|
|
48482
|
+
# Create traktamente entry
|
|
48483
|
+
npx ledgit-cli traktamente create \\
|
|
48484
|
+
-d DK \\
|
|
48485
|
+
--departure-date 2025-01-15 --departure-time 08:00 \\
|
|
48486
|
+
--return-date 2025-01-17 --return-time 18:00 \\
|
|
48487
|
+
-s K -n 1 \\
|
|
48488
|
+
-o inbox/2025-01-15-traktamente-copenhagen
|
|
48489
|
+
\`\`\`
|
|
48490
|
+
|
|
48491
|
+
**Calculation rules (Skatteverket):**
|
|
48492
|
+
- Departure before 12:00 → full day
|
|
48493
|
+
- Departure 12:00 or later → half day
|
|
48494
|
+
- Return after 19:00 → full day
|
|
48495
|
+
- Return 19:00 or earlier → half day
|
|
48496
|
+
- Days in between → full days
|
|
48497
|
+
|
|
48498
|
+
**Output files:** \`documents.yaml\`, \`entry.yaml\`, \`traktamente.pdf\`
|
|
48499
|
+
|
|
48500
|
+
**Accounts:**
|
|
48501
|
+
- 7321 = Tax-free domestic per diem (SE)
|
|
48502
|
+
- 7323 = Tax-free international per diem (abroad)
|
|
48503
|
+
- 2820 = Debt to employee (credit)
|
|
48504
|
+
|
|
48505
|
+
## Grouping Trip Receipts
|
|
48506
|
+
|
|
48507
|
+
Combine related receipts from one trip into a single journal entry:
|
|
48508
|
+
|
|
48509
|
+
\`\`\`yaml
|
|
48510
|
+
series: D
|
|
48511
|
+
entryDate: 2025-01-15
|
|
48512
|
+
description: Business trip Copenhagen Jan 15-17
|
|
48513
|
+
currency: SEK
|
|
48514
|
+
lines:
|
|
48515
|
+
# Flight (6% VAT)
|
|
48516
|
+
- account: "5810"
|
|
48517
|
+
debit: 1415.09
|
|
48518
|
+
memo: SAS ARN-CPH return
|
|
48519
|
+
- account: "2641"
|
|
48520
|
+
debit: 84.91
|
|
48521
|
+
memo: Moms 6%
|
|
48522
|
+
# Hotel (no Swedish VAT - foreign)
|
|
48523
|
+
- account: "5832"
|
|
48524
|
+
debit: 3200.00
|
|
48525
|
+
memo: Hotel Copenhagen 2 nights
|
|
48526
|
+
# Taxi (6% VAT)
|
|
48527
|
+
- account: "5890"
|
|
48528
|
+
debit: 424.53
|
|
48529
|
+
memo: Taxi transfers
|
|
48530
|
+
- account: "2641"
|
|
48531
|
+
debit: 25.47
|
|
48532
|
+
memo: Moms 6%
|
|
48533
|
+
# Balancing
|
|
48534
|
+
- account: "2820"
|
|
48535
|
+
credit: 5150.00
|
|
48536
|
+
memo: Corporate card
|
|
48537
|
+
\`\`\`
|
|
48538
|
+
|
|
48539
|
+
## Common Expense Accounts
|
|
48540
|
+
|
|
48541
|
+
| Expense | Account | VAT Rate |
|
|
48542
|
+
|---------|---------|----------|
|
|
48543
|
+
| Flight (domestic) | 5810 | 6% |
|
|
48544
|
+
| Train/Bus | 5810 | 6% |
|
|
48545
|
+
| Hotel (Sweden) | 5831 | 12% |
|
|
48546
|
+
| Hotel (abroad) | 5832 | Exempt |
|
|
48547
|
+
| Rental car | 5820 | 25% |
|
|
48548
|
+
| Taxi | 5890 | 6% |
|
|
48549
|
+
| Meals (Sweden) | 5831 | 12% |
|
|
48550
|
+
| Meals (abroad) | 5832 | Exempt |
|
|
48551
|
+
|
|
48552
|
+
## Workflow: Trip with Multiple Receipts
|
|
48553
|
+
|
|
48554
|
+
1. **Collect receipts** - flight, hotel, taxi, meals
|
|
48555
|
+
2. **Identify payment method** - corporate card → 5800, employee → 7300
|
|
48556
|
+
3. **Calculate VAT per receipt** - Swedish rates: hotel 12%, transport 6%
|
|
48557
|
+
4. **Create single entry** - one line per expense type
|
|
48558
|
+
5. **Add traktamente if applicable** - separate entry via CLI
|
|
48559
|
+
|
|
48560
|
+
## Swedish VAT Rates
|
|
48561
|
+
|
|
48562
|
+
| Type | Rate | Calculation |
|
|
48563
|
+
|------|------|-------------|
|
|
48564
|
+
| Transport | 6% | Net = Gross / 1.06 |
|
|
48565
|
+
| Hotel/Restaurant | 12% | Net = Gross / 1.12 |
|
|
48566
|
+
| Rental car | 25% | Net = Gross / 1.25 |
|
|
48567
|
+
| International | 0% | Full amount to expense |
|
|
48568
|
+
|
|
48569
|
+
## Series Codes
|
|
48570
|
+
|
|
48571
|
+
| Series | Use |
|
|
48572
|
+
|--------|-----|
|
|
48573
|
+
| D | Company-paid travel (supplier invoice) |
|
|
48574
|
+
| E | Payment of travel expenses |
|
|
48575
|
+
| K | Employee traktamente/reimbursement |
|
|
48576
|
+
|
|
48577
|
+
---
|
|
48578
|
+
|
|
48579
|
+
# Travel Expense Accounts
|
|
48580
|
+
|
|
48581
|
+
Swedish BAS accounts for business travel expenses, covering both company-paid and employee reimbursement scenarios.
|
|
48582
|
+
|
|
48583
|
+
## Company-Paid Travel (5800 Series)
|
|
48584
|
+
|
|
48585
|
+
Use these accounts when the company pays directly (corporate card, invoice to company).
|
|
48586
|
+
|
|
48587
|
+
| Account | Swedish Name | Use |
|
|
48588
|
+
|---------|-------------|-----|
|
|
48589
|
+
| 5800 | Resekostnader | General travel expenses (control account) |
|
|
48590
|
+
| 5810 | Biljetter | Flights, trains, buses, ferries |
|
|
48591
|
+
| 5820 | Hyrbilskostnader | Rental cars |
|
|
48592
|
+
| 5830 | Kost och logi | Meals and lodging (general) |
|
|
48593
|
+
| 5831 | Kost och logi Sverige | Swedish hotels, meals, accommodation |
|
|
48594
|
+
| 5832 | Kost och logi utlandet | International hotels, meals, accommodation |
|
|
48595
|
+
| 5890 | Övriga resekostnader | Taxi, parking, tolls, other travel |
|
|
48596
|
+
|
|
48597
|
+
### When to Use 5800 Series
|
|
48598
|
+
|
|
48599
|
+
- Company credit card charges
|
|
48600
|
+
- Corporate travel bookings
|
|
48601
|
+
- Direct invoices to company
|
|
48602
|
+
- Prepaid travel expenses
|
|
48603
|
+
|
|
48604
|
+
## Employee Reimbursement (7300 Series)
|
|
48605
|
+
|
|
48606
|
+
Use these accounts when the employee pays first and gets reimbursed.
|
|
48607
|
+
|
|
48608
|
+
### Traktamente (Per Diem)
|
|
48609
|
+
|
|
48610
|
+
| Account | Swedish Name | Use |
|
|
48611
|
+
|---------|-------------|-----|
|
|
48612
|
+
| 7321 | Skattefria traktamenten, Sverige | Tax-free per diem (domestic travel) |
|
|
48613
|
+
| 7322 | Skattepliktiga traktamenten, Sverige | Taxable per diem (domestic) |
|
|
48614
|
+
| 7323 | Skattefria traktamenten, utlandet | Tax-free per diem (international) |
|
|
48615
|
+
| 7324 | Skattepliktiga traktamenten, utlandet | Taxable per diem (international) |
|
|
48616
|
+
|
|
48617
|
+
### Expense Reimbursement
|
|
48618
|
+
|
|
48619
|
+
| Account | Swedish Name | Use |
|
|
48620
|
+
|---------|-------------|-----|
|
|
48621
|
+
| 7381 | Kostnadsersättning | Employee expense reimbursement (receipts) |
|
|
48622
|
+
| 7385 | Bilersättningar, skattefria | Tax-free mileage reimbursement |
|
|
48623
|
+
| 7386 | Bilersättningar, skattepliktiga | Taxable mileage reimbursement |
|
|
48624
|
+
|
|
48625
|
+
### When to Use 7300 Series
|
|
48626
|
+
|
|
48627
|
+
- Employee paid with personal card
|
|
48628
|
+
- Expense reports with receipts
|
|
48629
|
+
- Per diem (traktamente) claims
|
|
48630
|
+
- Mileage reimbursement
|
|
48631
|
+
|
|
48632
|
+
## Balancing Accounts
|
|
48633
|
+
|
|
48634
|
+
| Account | Name | Use |
|
|
48635
|
+
|---------|------|-----|
|
|
48636
|
+
| 2820 | Kortfristiga skulder | Debt to employee (reimbursement pending) |
|
|
48637
|
+
| 2440 | Leverantörsskulder | Supplier payables (travel agency invoices) |
|
|
48638
|
+
| 1930 | Företagskonto | Direct bank payment |
|
|
48639
|
+
|
|
48640
|
+
## Decision Tree
|
|
48641
|
+
|
|
48642
|
+
\`\`\`
|
|
48643
|
+
Who paid for the expense?
|
|
48644
|
+
│
|
|
48645
|
+
├─ Company paid (corporate card, invoice)
|
|
48646
|
+
│ └─ Use 5800 series
|
|
48647
|
+
│ ├─ Flights/trains → 5810
|
|
48648
|
+
│ ├─ Rental car → 5820
|
|
48649
|
+
│ ├─ Hotel/meals Sweden → 5831
|
|
48650
|
+
│ ├─ Hotel/meals abroad → 5832
|
|
48651
|
+
│ └─ Taxi/parking/other → 5890
|
|
48652
|
+
│
|
|
48653
|
+
└─ Employee paid (personal card, cash)
|
|
48654
|
+
└─ Use 7300 series
|
|
48655
|
+
├─ Per diem claim → 7321 (SE) or 7323 (abroad)
|
|
48656
|
+
├─ Mileage → 7385
|
|
48657
|
+
└─ Receipt-based → 7381
|
|
48658
|
+
\`\`\`
|
|
48659
|
+
|
|
48660
|
+
## Journal Entry Examples
|
|
48661
|
+
|
|
48662
|
+
### Company-Paid Hotel (Sweden, 12% VAT)
|
|
48663
|
+
|
|
48664
|
+
\`\`\`yaml
|
|
48665
|
+
lines:
|
|
48666
|
+
- account: "5831"
|
|
48667
|
+
debit: 1785.71
|
|
48668
|
+
memo: Hotel Stockholm
|
|
48669
|
+
- account: "2641"
|
|
48670
|
+
debit: 214.29
|
|
48671
|
+
memo: Ingående moms 12%
|
|
48672
|
+
- account: "2820"
|
|
48673
|
+
credit: 2000.00
|
|
48674
|
+
memo: Corporate card
|
|
48675
|
+
\`\`\`
|
|
48676
|
+
|
|
48677
|
+
### Employee Traktamente (International)
|
|
48678
|
+
|
|
48679
|
+
\`\`\`yaml
|
|
48680
|
+
lines:
|
|
48681
|
+
- account: "7323"
|
|
48682
|
+
debit: 1226.00
|
|
48683
|
+
memo: Skattefria traktamenten, utlandet
|
|
48684
|
+
- account: "2820"
|
|
48685
|
+
credit: 1226.00
|
|
48686
|
+
memo: Kortfristiga skulder till anställda
|
|
48687
|
+
\`\`\`
|
|
48688
|
+
|
|
48689
|
+
### Grouped Trip Entry (Multiple Expenses)
|
|
48690
|
+
|
|
48691
|
+
\`\`\`yaml
|
|
48692
|
+
description: Business trip Copenhagen Jan 15-17
|
|
48693
|
+
lines:
|
|
48694
|
+
- account: "5810"
|
|
48695
|
+
debit: 1500.00
|
|
48696
|
+
memo: SAS flight ARN-CPH
|
|
48697
|
+
- account: "5832"
|
|
48698
|
+
debit: 3200.00
|
|
48699
|
+
memo: Hotel Copenhagen 2 nights
|
|
48700
|
+
- account: "5890"
|
|
48701
|
+
debit: 450.00
|
|
48702
|
+
memo: Taxi airport transfers
|
|
48703
|
+
- account: "2820"
|
|
48704
|
+
credit: 5150.00
|
|
48705
|
+
memo: Corporate card
|
|
48706
|
+
\`\`\`
|
|
48707
|
+
|
|
48708
|
+
---
|
|
48709
|
+
|
|
48710
|
+
# Travel Expense VAT Rules
|
|
48711
|
+
|
|
48712
|
+
Swedish VAT (moms) treatment for business travel expenses.
|
|
48713
|
+
|
|
48714
|
+
## Swedish VAT Rates for Travel
|
|
48715
|
+
|
|
48716
|
+
| Expense Type | VAT Rate | Tax Code |
|
|
48717
|
+
|--------------|----------|----------|
|
|
48718
|
+
| Hotels/Accommodation | 12% | SE_VAT_12_PURCHASE_DOMESTIC |
|
|
48719
|
+
| Restaurants/Meals | 12% | SE_VAT_12_PURCHASE_DOMESTIC |
|
|
48720
|
+
| Domestic flights | 6% | SE_VAT_6_PURCHASE_DOMESTIC |
|
|
48721
|
+
| Trains/Buses | 6% | SE_VAT_6_PURCHASE_DOMESTIC |
|
|
48722
|
+
| Taxi | 6% | SE_VAT_6_PURCHASE_DOMESTIC |
|
|
48723
|
+
| Rental car | 25% | SE_VAT_25_PURCHASE_DOMESTIC |
|
|
48724
|
+
| Fuel | 25% | SE_VAT_25_PURCHASE_DOMESTIC |
|
|
48725
|
+
| Parking | 25% | SE_VAT_25_PURCHASE_DOMESTIC |
|
|
48726
|
+
|
|
48727
|
+
## International Travel
|
|
48728
|
+
|
|
48729
|
+
| Scenario | VAT Treatment |
|
|
48730
|
+
|----------|---------------|
|
|
48731
|
+
| Foreign hotel | No Swedish VAT, use SE_VAT_EXEMPT_PURCHASE |
|
|
48732
|
+
| Foreign meals | No Swedish VAT, use SE_VAT_EXEMPT_PURCHASE |
|
|
48733
|
+
| International flight | Usually zero-rated or exempt |
|
|
48734
|
+
| EU transport | May have local VAT, no Swedish deduction |
|
|
48735
|
+
|
|
48736
|
+
## VAT Account Mapping
|
|
48737
|
+
|
|
48738
|
+
| VAT Type | Account | Use |
|
|
48739
|
+
|----------|---------|-----|
|
|
48740
|
+
| Input VAT 25% | 2641 | Rental car, parking, fuel |
|
|
48741
|
+
| Input VAT 12% | 2641 | Hotels, restaurants (reduced rate) |
|
|
48742
|
+
| Input VAT 6% | 2641 | Transport (trains, flights, taxi) |
|
|
48743
|
+
| No VAT | - | International, exempt, per diem |
|
|
48744
|
+
|
|
48745
|
+
## Decision Tree
|
|
48746
|
+
|
|
48747
|
+
\`\`\`
|
|
48748
|
+
Is this a Swedish expense?
|
|
48749
|
+
│
|
|
48750
|
+
├─ YES → Check the VAT rate on receipt
|
|
48751
|
+
│ ├─ 25% → SE_VAT_25_PURCHASE_DOMESTIC (rental car, parking)
|
|
48752
|
+
│ ├─ 12% → SE_VAT_12_PURCHASE_DOMESTIC (hotel, restaurant)
|
|
48753
|
+
│ ├─ 6% → SE_VAT_6_PURCHASE_DOMESTIC (transport)
|
|
48754
|
+
│ └─ 0% → SE_VAT_EXEMPT_PURCHASE
|
|
48755
|
+
│
|
|
48756
|
+
└─ NO → Is VAT shown on receipt?
|
|
48757
|
+
├─ YES → Usually not recoverable in Sweden
|
|
48758
|
+
│ Use SE_VAT_EXEMPT_PURCHASE, book gross amount
|
|
48759
|
+
└─ NO → SE_VAT_EXEMPT_PURCHASE
|
|
48760
|
+
\`\`\`
|
|
48761
|
+
|
|
48762
|
+
## Calculating Net from Gross
|
|
48763
|
+
|
|
48764
|
+
When you have the total including VAT:
|
|
48765
|
+
|
|
48766
|
+
| VAT Rate | Calculation |
|
|
48767
|
+
|----------|-------------|
|
|
48768
|
+
| 25% | Net = Gross / 1.25 |
|
|
48769
|
+
| 12% | Net = Gross / 1.12 |
|
|
48770
|
+
| 6% | Net = Gross / 1.06 |
|
|
48771
|
+
|
|
48772
|
+
**Example:** Hotel SEK 2,240 (12% VAT)
|
|
48773
|
+
- Net: 2,240 / 1.12 = 2,000.00
|
|
48774
|
+
- VAT: 2,240 - 2,000 = 240.00
|
|
48775
|
+
|
|
48776
|
+
## Journal Entry Examples
|
|
48777
|
+
|
|
48778
|
+
### Swedish Hotel (12% VAT)
|
|
48779
|
+
|
|
48780
|
+
Total: SEK 2,240 including 12% VAT
|
|
48781
|
+
|
|
48782
|
+
\`\`\`yaml
|
|
48783
|
+
lines:
|
|
48784
|
+
- account: "5831"
|
|
48785
|
+
debit: 2000.00
|
|
48786
|
+
memo: Hotel Scandic Stockholm
|
|
48787
|
+
- account: "2641"
|
|
48788
|
+
debit: 240.00
|
|
48789
|
+
memo: Ingående moms 12%
|
|
48790
|
+
- account: "2820"
|
|
48791
|
+
credit: 2240.00
|
|
48792
|
+
memo: Corporate card
|
|
48793
|
+
\`\`\`
|
|
48794
|
+
|
|
48795
|
+
### Swedish Taxi (6% VAT)
|
|
48796
|
+
|
|
48797
|
+
Total: SEK 530 including 6% VAT
|
|
48798
|
+
|
|
48799
|
+
\`\`\`yaml
|
|
48800
|
+
lines:
|
|
48801
|
+
- account: "5890"
|
|
48802
|
+
debit: 500.00
|
|
48803
|
+
memo: Taxi Arlanda-City
|
|
48804
|
+
- account: "2641"
|
|
48805
|
+
debit: 30.00
|
|
48806
|
+
memo: Ingående moms 6%
|
|
48807
|
+
- account: "2820"
|
|
48808
|
+
credit: 530.00
|
|
48809
|
+
memo: Corporate card
|
|
48810
|
+
\`\`\`
|
|
48811
|
+
|
|
48812
|
+
### Foreign Hotel (No Swedish VAT)
|
|
48813
|
+
|
|
48814
|
+
Total: EUR 180 = SEK 2,016 (converted)
|
|
48815
|
+
|
|
48816
|
+
\`\`\`yaml
|
|
48817
|
+
lines:
|
|
48818
|
+
- account: "5832"
|
|
48819
|
+
debit: 2016.00
|
|
48820
|
+
memo: Hotel Berlin
|
|
48821
|
+
- account: "2820"
|
|
48822
|
+
credit: 2016.00
|
|
48823
|
+
memo: Corporate card
|
|
48824
|
+
\`\`\`
|
|
48825
|
+
|
|
48826
|
+
## Per Diem (Traktamente) - No VAT
|
|
48827
|
+
|
|
48828
|
+
Per diem allowances have no VAT component. Book the full amount to the traktamente account.
|
|
48829
|
+
|
|
48830
|
+
\`\`\`yaml
|
|
48831
|
+
lines:
|
|
48832
|
+
- account: "7323"
|
|
48833
|
+
debit: 1226.00
|
|
48834
|
+
memo: Traktamente Denmark 1 day
|
|
48835
|
+
- account: "2820"
|
|
48836
|
+
credit: 1226.00
|
|
48837
|
+
\`\`\`
|
|
48838
|
+
|
|
48839
|
+
## Limitations on VAT Deduction
|
|
48840
|
+
|
|
48841
|
+
Some travel VAT is not deductible in Sweden:
|
|
48842
|
+
|
|
48843
|
+
| Item | VAT Deductible? |
|
|
48844
|
+
|------|-----------------|
|
|
48845
|
+
| Business meals (representation) | 50% deductible |
|
|
48846
|
+
| Employee lunch | Not deductible |
|
|
48847
|
+
| Personal travel portion | Not deductible |
|
|
48848
|
+
| Entertainment | Not deductible |
|
|
48849
|
+
|
|
48850
|
+
For representation meals, only deduct 50% of the VAT amount.
|
|
48851
|
+
`
|
|
48852
|
+
};
|
|
48853
|
+
// ../bookkeeping/dist/skills/index.js
|
|
48854
|
+
var SKILLS = [
|
|
48855
|
+
SWEDISH_BOOKKEEPING_SKILL,
|
|
48856
|
+
TRAVEL_EXPENSES_SKILL
|
|
48857
|
+
];
|
|
48858
|
+
function listSkills() {
|
|
48859
|
+
return SKILLS;
|
|
48860
|
+
}
|
|
48861
|
+
function getSkill(name) {
|
|
48862
|
+
return SKILLS.find((skill) => skill.name === name);
|
|
48863
|
+
}
|
|
48059
48864
|
// src/lib/env.ts
|
|
48060
48865
|
import * as fs11 from "node:fs";
|
|
48061
48866
|
import * as path7 from "node:path";
|
|
@@ -48242,16 +49047,6 @@ async function getValidAccessToken(cwd = process.cwd()) {
|
|
|
48242
49047
|
return null;
|
|
48243
49048
|
}
|
|
48244
49049
|
}
|
|
48245
|
-
function deleteAuth0Token(cwd = process.cwd()) {
|
|
48246
|
-
const localPath = getLocalTokenPath(cwd);
|
|
48247
|
-
const globalPath = getGlobalTokenPath();
|
|
48248
|
-
if (fs10.existsSync(localPath)) {
|
|
48249
|
-
fs10.unlinkSync(localPath);
|
|
48250
|
-
}
|
|
48251
|
-
if (fs10.existsSync(globalPath)) {
|
|
48252
|
-
fs10.unlinkSync(globalPath);
|
|
48253
|
-
}
|
|
48254
|
-
}
|
|
48255
49050
|
|
|
48256
49051
|
// src/lib/env.ts
|
|
48257
49052
|
async function loadConfig(cwd = process.cwd()) {
|
|
@@ -48287,7 +49082,10 @@ async function loadConfig(cwd = process.cwd()) {
|
|
|
48287
49082
|
if (!companyId) {
|
|
48288
49083
|
throw new Error("BOKIO_COMPANY_ID environment variable not set");
|
|
48289
49084
|
}
|
|
48290
|
-
|
|
49085
|
+
let inboxProvider = process.env.INBOX_PROVIDER;
|
|
49086
|
+
if (!inboxProvider && process.env.LEDGIT_API_TOKEN) {
|
|
49087
|
+
inboxProvider = "ledgit";
|
|
49088
|
+
}
|
|
48291
49089
|
const result = {
|
|
48292
49090
|
provider: "bokio",
|
|
48293
49091
|
bokio: { token, companyId }
|
|
@@ -48296,6 +49094,10 @@ async function loadConfig(cwd = process.cwd()) {
|
|
|
48296
49094
|
result.inboxProvider = "ledgit";
|
|
48297
49095
|
result.ledgit = {
|
|
48298
49096
|
getAccessToken: async () => {
|
|
49097
|
+
const apiToken = process.env.LEDGIT_API_TOKEN;
|
|
49098
|
+
if (apiToken) {
|
|
49099
|
+
return apiToken;
|
|
49100
|
+
}
|
|
48299
49101
|
const accessToken = await getValidAccessToken(cwd);
|
|
48300
49102
|
if (!accessToken) {
|
|
48301
49103
|
throw new Error("Ledgit authentication required for inbox. Run 'ledgit login' to authenticate.");
|
|
@@ -48310,6 +49112,10 @@ async function loadConfig(cwd = process.cwd()) {
|
|
|
48310
49112
|
provider: "ledgit",
|
|
48311
49113
|
ledgit: {
|
|
48312
49114
|
getAccessToken: async () => {
|
|
49115
|
+
const apiToken = process.env.LEDGIT_API_TOKEN;
|
|
49116
|
+
if (apiToken) {
|
|
49117
|
+
return apiToken;
|
|
49118
|
+
}
|
|
48313
49119
|
const token = await getValidAccessToken(cwd);
|
|
48314
49120
|
if (!token) {
|
|
48315
49121
|
throw new Error("Ledgit authentication required. Run 'ledgit login' to authenticate.");
|
|
@@ -56291,7 +57097,7 @@ async function listTaxCodesCommand() {
|
|
|
56291
57097
|
|
|
56292
57098
|
// src/commands/login.ts
|
|
56293
57099
|
import ora6 from "ora";
|
|
56294
|
-
async function loginCommand(
|
|
57100
|
+
async function loginCommand(_options) {
|
|
56295
57101
|
console.log(`
|
|
56296
57102
|
Authenticating with Ledgit...
|
|
56297
57103
|
`);
|
|
@@ -56333,7 +57139,7 @@ async function loginCommand(options) {
|
|
|
56333
57139
|
companyName = bokioCompany.name;
|
|
56334
57140
|
organizationNumber = bokioCompany.organizationNumber || "";
|
|
56335
57141
|
bokioSpinner.succeed(`Found Bokio company: ${companyName}`);
|
|
56336
|
-
} catch
|
|
57142
|
+
} catch {
|
|
56337
57143
|
bokioSpinner.fail("Failed to fetch from Bokio, falling back to manual input");
|
|
56338
57144
|
console.log(`
|
|
56339
57145
|
Let's register your company with Ledgit:
|
|
@@ -56393,80 +57199,131 @@ async function loginCommand(options) {
|
|
|
56393
57199
|
}
|
|
56394
57200
|
|
|
56395
57201
|
// src/commands/token.ts
|
|
56396
|
-
|
|
57202
|
+
var API_BASE_URL = process.env.LEDGIT_API_URL || "https://api.ledgit.se";
|
|
57203
|
+
async function tokenCommand(action = "list", _options = {}) {
|
|
56397
57204
|
const cwd = process.cwd();
|
|
57205
|
+
const accessToken = await getValidAccessToken(cwd);
|
|
57206
|
+
if (!accessToken) {
|
|
57207
|
+
console.error(`
|
|
57208
|
+
Not logged in. Run 'ledgit login' first.
|
|
57209
|
+
`);
|
|
57210
|
+
process.exit(1);
|
|
57211
|
+
}
|
|
56398
57212
|
switch (action) {
|
|
56399
|
-
case "
|
|
56400
|
-
const
|
|
56401
|
-
|
|
56402
|
-
|
|
56403
|
-
|
|
56404
|
-
|
|
57213
|
+
case "list": {
|
|
57214
|
+
const response = await fetch(`${API_BASE_URL}/api/tokens`, {
|
|
57215
|
+
headers: {
|
|
57216
|
+
Authorization: `Bearer ${accessToken}`
|
|
57217
|
+
}
|
|
57218
|
+
});
|
|
57219
|
+
if (!response.ok) {
|
|
57220
|
+
const error = await response.json().catch(() => ({}));
|
|
57221
|
+
console.error(`
|
|
57222
|
+
Failed to fetch tokens: ${error.error || response.statusText} (${response.status})
|
|
56405
57223
|
`);
|
|
56406
57224
|
process.exit(1);
|
|
56407
57225
|
}
|
|
56408
|
-
const
|
|
56409
|
-
const
|
|
56410
|
-
|
|
56411
|
-
|
|
56412
|
-
|
|
56413
|
-
|
|
56414
|
-
console.log(` Has Refresh Token: ${token.refresh_token ? "Yes" : "No"}`);
|
|
56415
|
-
console.log("");
|
|
56416
|
-
if (expired) {
|
|
56417
|
-
console.log(` Token is expired. Run 'ledgit token refresh' or 'ledgit login' to get a new token.
|
|
57226
|
+
const result = await response.json();
|
|
57227
|
+
const tokens = result.data;
|
|
57228
|
+
if (tokens.length === 0) {
|
|
57229
|
+
console.log(`
|
|
57230
|
+
No API tokens found.`);
|
|
57231
|
+
console.log(` Create one with: ledgit token create
|
|
56418
57232
|
`);
|
|
57233
|
+
return;
|
|
56419
57234
|
}
|
|
56420
|
-
|
|
56421
|
-
|
|
56422
|
-
|
|
56423
|
-
const
|
|
56424
|
-
|
|
56425
|
-
console.
|
|
56426
|
-
|
|
57235
|
+
console.log(`
|
|
57236
|
+
API Tokens:
|
|
57237
|
+
`);
|
|
57238
|
+
for (const token of tokens) {
|
|
57239
|
+
const lastUsed = token.lastUsedAt ? new Date(token.lastUsedAt).toLocaleDateString() : "Never";
|
|
57240
|
+
console.log(` ${token.name}`);
|
|
57241
|
+
console.log(` Token: ${token.tokenPrefix}...`);
|
|
57242
|
+
console.log(` Scopes: ${token.scopes.join(", ")}`);
|
|
57243
|
+
console.log(` Last used: ${lastUsed}`);
|
|
57244
|
+
console.log("");
|
|
56427
57245
|
}
|
|
56428
|
-
process.stdout.write(accessToken);
|
|
56429
57246
|
break;
|
|
56430
57247
|
}
|
|
56431
|
-
case "
|
|
56432
|
-
const
|
|
56433
|
-
|
|
56434
|
-
|
|
56435
|
-
|
|
56436
|
-
|
|
57248
|
+
case "create": {
|
|
57249
|
+
const name = await dist_default4({
|
|
57250
|
+
message: "Token name:",
|
|
57251
|
+
default: "GitHub Actions"
|
|
57252
|
+
});
|
|
57253
|
+
const scopes = ["read", "write"];
|
|
57254
|
+
console.log(`
|
|
57255
|
+
Creating API token...`);
|
|
57256
|
+
const response = await fetch(`${API_BASE_URL}/api/tokens`, {
|
|
57257
|
+
method: "POST",
|
|
57258
|
+
headers: {
|
|
57259
|
+
Authorization: `Bearer ${accessToken}`,
|
|
57260
|
+
"Content-Type": "application/json"
|
|
57261
|
+
},
|
|
57262
|
+
body: JSON.stringify({ name, scopes })
|
|
57263
|
+
});
|
|
57264
|
+
if (!response.ok) {
|
|
57265
|
+
const error = await response.json().catch(() => ({}));
|
|
57266
|
+
console.error(`
|
|
57267
|
+
Failed to create token: ${error.error || response.statusText}
|
|
56437
57268
|
`);
|
|
56438
57269
|
process.exit(1);
|
|
56439
57270
|
}
|
|
56440
|
-
|
|
56441
|
-
|
|
56442
|
-
|
|
56443
|
-
console.log(` Run 'ledgit login' to get a new token.
|
|
57271
|
+
const result = await response.json();
|
|
57272
|
+
console.log(`
|
|
57273
|
+
✓ API token created successfully!
|
|
56444
57274
|
`);
|
|
56445
|
-
|
|
56446
|
-
|
|
56447
|
-
|
|
56448
|
-
const accessToken = await getValidAccessToken(cwd);
|
|
56449
|
-
if (accessToken) {
|
|
56450
|
-
console.log(` Token refreshed successfully!
|
|
57275
|
+
console.log(" Token (copy now - it won't be shown again):");
|
|
57276
|
+
console.log(`
|
|
57277
|
+
${result.data.token}
|
|
56451
57278
|
`);
|
|
56452
|
-
|
|
56453
|
-
|
|
57279
|
+
console.log(" To use in GitHub Actions, add as a secret:");
|
|
57280
|
+
console.log(` gh secret set LEDGIT_API_TOKEN
|
|
56454
57281
|
`);
|
|
56455
|
-
process.exit(1);
|
|
56456
|
-
}
|
|
56457
57282
|
break;
|
|
56458
57283
|
}
|
|
56459
57284
|
case "revoke": {
|
|
56460
|
-
const
|
|
56461
|
-
|
|
57285
|
+
const listResponse = await fetch(`${API_BASE_URL}/api/tokens`, {
|
|
57286
|
+
headers: {
|
|
57287
|
+
Authorization: `Bearer ${accessToken}`
|
|
57288
|
+
}
|
|
57289
|
+
});
|
|
57290
|
+
if (!listResponse.ok) {
|
|
57291
|
+
const error = await listResponse.json().catch(() => ({}));
|
|
57292
|
+
console.error(`
|
|
57293
|
+
Failed to fetch tokens: ${error.error || listResponse.statusText} (${listResponse.status})
|
|
57294
|
+
`);
|
|
57295
|
+
process.exit(1);
|
|
57296
|
+
}
|
|
57297
|
+
const listResult = await listResponse.json();
|
|
57298
|
+
const tokens = listResult.data;
|
|
57299
|
+
if (tokens.length === 0) {
|
|
56462
57300
|
console.log(`
|
|
56463
|
-
No
|
|
57301
|
+
No API tokens to revoke.
|
|
56464
57302
|
`);
|
|
56465
57303
|
return;
|
|
56466
57304
|
}
|
|
56467
|
-
|
|
57305
|
+
const tokenId = await dist_default8({
|
|
57306
|
+
message: "Select token to revoke:",
|
|
57307
|
+
choices: tokens.map((t) => ({
|
|
57308
|
+
value: t.id,
|
|
57309
|
+
name: `${t.name} (${t.tokenPrefix}...)`
|
|
57310
|
+
}))
|
|
57311
|
+
});
|
|
57312
|
+
const response = await fetch(`${API_BASE_URL}/api/tokens/${tokenId}`, {
|
|
57313
|
+
method: "DELETE",
|
|
57314
|
+
headers: {
|
|
57315
|
+
Authorization: `Bearer ${accessToken}`
|
|
57316
|
+
}
|
|
57317
|
+
});
|
|
57318
|
+
if (!response.ok) {
|
|
57319
|
+
const error = await response.json().catch(() => ({}));
|
|
57320
|
+
console.error(`
|
|
57321
|
+
Failed to revoke token: ${error.error || response.statusText} (${response.status})
|
|
57322
|
+
`);
|
|
57323
|
+
process.exit(1);
|
|
57324
|
+
}
|
|
56468
57325
|
console.log(`
|
|
56469
|
-
|
|
57326
|
+
✓ Token revoked.
|
|
56470
57327
|
`);
|
|
56471
57328
|
break;
|
|
56472
57329
|
}
|
|
@@ -56474,10 +57331,9 @@ async function tokenCommand(action = "show", options = {}) {
|
|
|
56474
57331
|
console.error(`Unknown action: ${action}`);
|
|
56475
57332
|
console.log(`
|
|
56476
57333
|
Usage:`);
|
|
56477
|
-
console.log(" ledgit token
|
|
56478
|
-
console.log(" ledgit token
|
|
56479
|
-
console.log(" ledgit token
|
|
56480
|
-
console.log(" ledgit token revoke - Revoke/delete stored token");
|
|
57334
|
+
console.log(" ledgit token list - List all API tokens");
|
|
57335
|
+
console.log(" ledgit token create - Create a new API token");
|
|
57336
|
+
console.log(" ledgit token revoke - Revoke an API token");
|
|
56481
57337
|
process.exit(1);
|
|
56482
57338
|
}
|
|
56483
57339
|
}
|
|
@@ -56516,6 +57372,7 @@ jobs:
|
|
|
56516
57372
|
- name: Sync inbox
|
|
56517
57373
|
run: npx ledgit-cli sync-inbox
|
|
56518
57374
|
env:
|
|
57375
|
+
LEDGIT_API_TOKEN: \${{ secrets.LEDGIT_API_TOKEN }}
|
|
56519
57376
|
BOKIO_TOKEN: \${{ secrets.BOKIO_TOKEN }}
|
|
56520
57377
|
BOKIO_COMPANY_ID: \${{ secrets.BOKIO_COMPANY_ID }}
|
|
56521
57378
|
|
|
@@ -56591,40 +57448,6 @@ jobs:
|
|
|
56591
57448
|
--verbose \\
|
|
56592
57449
|
--output-format stream-json \\
|
|
56593
57450
|
2>&1 | tee /tmp/claude-output.json
|
|
56594
|
-
|
|
56595
|
-
- name: Write job summary
|
|
56596
|
-
if: always() && steps.check.outputs.has_new == 'true'
|
|
56597
|
-
run: |
|
|
56598
|
-
echo "## \uD83E\uDD16 Claude Bookkeeping Report" >> $GITHUB_STEP_SUMMARY
|
|
56599
|
-
echo "" >> $GITHUB_STEP_SUMMARY
|
|
56600
|
-
|
|
56601
|
-
# Show model from init
|
|
56602
|
-
jq -r 'select(.type == "system" and .subtype == "init") | "**Model:** \\(.model // "claude")"' /tmp/claude-output.json >> $GITHUB_STEP_SUMMARY 2>/dev/null || true
|
|
56603
|
-
echo "" >> $GITHUB_STEP_SUMMARY
|
|
56604
|
-
|
|
56605
|
-
# Count tool uses
|
|
56606
|
-
TOOL_COUNT=$(jq -s '[.[] | select(.type == "tool_use")] | length' /tmp/claude-output.json 2>/dev/null || echo "0")
|
|
56607
|
-
echo "**Tool calls:** $TOOL_COUNT" >> $GITHUB_STEP_SUMMARY
|
|
56608
|
-
echo "" >> $GITHUB_STEP_SUMMARY
|
|
56609
|
-
|
|
56610
|
-
# List unique tools used
|
|
56611
|
-
echo "### Tools Used" >> $GITHUB_STEP_SUMMARY
|
|
56612
|
-
jq -r 'select(.type == "tool_use") | .name' /tmp/claude-output.json 2>/dev/null | sort | uniq -c | while read count name; do
|
|
56613
|
-
echo "- $name ($count calls)" >> $GITHUB_STEP_SUMMARY
|
|
56614
|
-
done
|
|
56615
|
-
echo "" >> $GITHUB_STEP_SUMMARY
|
|
56616
|
-
|
|
56617
|
-
# Final result
|
|
56618
|
-
echo "### Result" >> $GITHUB_STEP_SUMMARY
|
|
56619
|
-
jq -r 'select(.type == "result") | "**Status:** \\(.subtype // "completed")\\n**Duration:** \\((.duration_ms // 0) / 1000 | floor)s\\n**Turns:** \\(.num_turns // "N/A")\\n**Cost:** $\\(.total_cost_usd // 0 | tostring | .[0:6])"' /tmp/claude-output.json >> $GITHUB_STEP_SUMMARY 2>/dev/null || true
|
|
56620
|
-
|
|
56621
|
-
- name: Upload Claude execution log
|
|
56622
|
-
if: always() && steps.check.outputs.has_new == 'true'
|
|
56623
|
-
uses: actions/upload-artifact@v4
|
|
56624
|
-
with:
|
|
56625
|
-
name: claude-execution-log
|
|
56626
|
-
path: /tmp/claude-output.json
|
|
56627
|
-
retention-days: 7
|
|
56628
57451
|
`;
|
|
56629
57452
|
var CLAUDE_BOOKKEEPING_WORKFLOW = `name: Claude Bookkeeping
|
|
56630
57453
|
on:
|
|
@@ -56719,40 +57542,6 @@ jobs:
|
|
|
56719
57542
|
--verbose \\
|
|
56720
57543
|
--output-format stream-json \\
|
|
56721
57544
|
2>&1 | tee /tmp/claude-output.json
|
|
56722
|
-
|
|
56723
|
-
- name: Write job summary
|
|
56724
|
-
if: always()
|
|
56725
|
-
run: |
|
|
56726
|
-
echo "## \uD83E\uDD16 Claude Response Report" >> $GITHUB_STEP_SUMMARY
|
|
56727
|
-
echo "" >> $GITHUB_STEP_SUMMARY
|
|
56728
|
-
|
|
56729
|
-
# Show model from init
|
|
56730
|
-
jq -r 'select(.type == "system" and .subtype == "init") | "**Model:** \\(.model // "claude")"' /tmp/claude-output.json >> $GITHUB_STEP_SUMMARY 2>/dev/null || true
|
|
56731
|
-
echo "" >> $GITHUB_STEP_SUMMARY
|
|
56732
|
-
|
|
56733
|
-
# Count tool uses
|
|
56734
|
-
TOOL_COUNT=$(jq -s '[.[] | select(.type == "tool_use")] | length' /tmp/claude-output.json 2>/dev/null || echo "0")
|
|
56735
|
-
echo "**Tool calls:** $TOOL_COUNT" >> $GITHUB_STEP_SUMMARY
|
|
56736
|
-
echo "" >> $GITHUB_STEP_SUMMARY
|
|
56737
|
-
|
|
56738
|
-
# List unique tools used
|
|
56739
|
-
echo "### Tools Used" >> $GITHUB_STEP_SUMMARY
|
|
56740
|
-
jq -r 'select(.type == "tool_use") | .name' /tmp/claude-output.json 2>/dev/null | sort | uniq -c | while read count name; do
|
|
56741
|
-
echo "- $name ($count calls)" >> $GITHUB_STEP_SUMMARY
|
|
56742
|
-
done
|
|
56743
|
-
echo "" >> $GITHUB_STEP_SUMMARY
|
|
56744
|
-
|
|
56745
|
-
# Final result
|
|
56746
|
-
echo "### Result" >> $GITHUB_STEP_SUMMARY
|
|
56747
|
-
jq -r 'select(.type == "result") | "**Status:** \\(.subtype // "completed")\\n**Duration:** \\((.duration_ms // 0) / 1000 | floor)s\\n**Turns:** \\(.num_turns // "N/A")\\n**Cost:** $\\(.total_cost_usd // 0 | tostring | .[0:6])"' /tmp/claude-output.json >> $GITHUB_STEP_SUMMARY 2>/dev/null || true
|
|
56748
|
-
|
|
56749
|
-
- name: Upload Claude execution log
|
|
56750
|
-
if: always()
|
|
56751
|
-
uses: actions/upload-artifact@v4
|
|
56752
|
-
with:
|
|
56753
|
-
name: claude-execution-log-pr-\${{ github.event.issue.number }}
|
|
56754
|
-
path: /tmp/claude-output.json
|
|
56755
|
-
retention-days: 7
|
|
56756
57545
|
`;
|
|
56757
57546
|
var SYNC_JOURNAL_WORKFLOW = `name: Sync Journal
|
|
56758
57547
|
on:
|
|
@@ -56778,6 +57567,7 @@ jobs:
|
|
|
56778
57567
|
- name: Sync to Bokio
|
|
56779
57568
|
run: npx ledgit-cli sync-journal
|
|
56780
57569
|
env:
|
|
57570
|
+
LEDGIT_API_TOKEN: \${{ secrets.LEDGIT_API_TOKEN }}
|
|
56781
57571
|
BOKIO_TOKEN: \${{ secrets.BOKIO_TOKEN }}
|
|
56782
57572
|
BOKIO_COMPANY_ID: \${{ secrets.BOKIO_COMPANY_ID }}
|
|
56783
57573
|
`;
|
|
@@ -57216,6 +58006,23 @@ async function authenticateClaude(options = {}) {
|
|
|
57216
58006
|
|
|
57217
58007
|
// src/lib/github.ts
|
|
57218
58008
|
var execAsync3 = promisify7(exec7);
|
|
58009
|
+
async function saveToEnv(cwd, key, value) {
|
|
58010
|
+
const envPath = path15.join(cwd, ".env");
|
|
58011
|
+
let content = "";
|
|
58012
|
+
try {
|
|
58013
|
+
content = await fs19.readFile(envPath, "utf-8");
|
|
58014
|
+
} catch {
|
|
58015
|
+
}
|
|
58016
|
+
const regex2 = new RegExp(`^${key}=.*$`, "m");
|
|
58017
|
+
if (regex2.test(content)) {
|
|
58018
|
+
content = content.replace(regex2, `${key}=${value}`);
|
|
58019
|
+
} else {
|
|
58020
|
+
content = `${content.trimEnd()}
|
|
58021
|
+
${key}=${value}
|
|
58022
|
+
`;
|
|
58023
|
+
}
|
|
58024
|
+
await fs19.writeFile(envPath, content);
|
|
58025
|
+
}
|
|
57219
58026
|
async function checkGhInstalled() {
|
|
57220
58027
|
try {
|
|
57221
58028
|
await execAsync3("which gh");
|
|
@@ -57241,6 +58048,22 @@ async function checkGhWorkflowScope() {
|
|
|
57241
58048
|
return false;
|
|
57242
58049
|
}
|
|
57243
58050
|
}
|
|
58051
|
+
async function checkRepoAccess() {
|
|
58052
|
+
try {
|
|
58053
|
+
await execAsync3("gh repo view --json name");
|
|
58054
|
+
return true;
|
|
58055
|
+
} catch {
|
|
58056
|
+
return false;
|
|
58057
|
+
}
|
|
58058
|
+
}
|
|
58059
|
+
async function checkRepoSecretsAccess() {
|
|
58060
|
+
try {
|
|
58061
|
+
await execAsync3("gh api repos/{owner}/{repo}/actions/secrets/public-key");
|
|
58062
|
+
return true;
|
|
58063
|
+
} catch {
|
|
58064
|
+
return false;
|
|
58065
|
+
}
|
|
58066
|
+
}
|
|
57244
58067
|
async function hasGitRemote(cwd) {
|
|
57245
58068
|
try {
|
|
57246
58069
|
const cmd = cwd ? `git -C "${cwd}" remote -v` : "git remote -v";
|
|
@@ -57350,6 +58173,7 @@ needed to manage GitHub Actions and secrets.
|
|
|
57350
58173
|
To fix this, run:
|
|
57351
58174
|
gh auth refresh -h github.com -s repo,workflow`);
|
|
57352
58175
|
}
|
|
58176
|
+
const hasSecretsAccess = await checkRepoSecretsAccess();
|
|
57353
58177
|
let config3;
|
|
57354
58178
|
try {
|
|
57355
58179
|
config3 = await loadConfig(cwd);
|
|
@@ -57385,6 +58209,17 @@ Fortnox support requires OAuth token handling in CI, coming soon.`);
|
|
|
57385
58209
|
}
|
|
57386
58210
|
const secretName = authMethod === "api_key" ? "ANTHROPIC_API_KEY" : "CLAUDE_CODE_OAUTH_TOKEN";
|
|
57387
58211
|
let claudeToken = options.claudeToken;
|
|
58212
|
+
if (!claudeToken && authMethod === "oauth") {
|
|
58213
|
+
claudeToken = process.env.CLAUDE_CODE_OAUTH_TOKEN;
|
|
58214
|
+
if (claudeToken) {
|
|
58215
|
+
console.log(" Using existing CLAUDE_CODE_OAUTH_TOKEN from .env");
|
|
58216
|
+
}
|
|
58217
|
+
} else if (!claudeToken && authMethod === "api_key") {
|
|
58218
|
+
claudeToken = process.env.ANTHROPIC_API_KEY;
|
|
58219
|
+
if (claudeToken) {
|
|
58220
|
+
console.log(" Using existing ANTHROPIC_API_KEY from .env");
|
|
58221
|
+
}
|
|
58222
|
+
}
|
|
57388
58223
|
if (!claudeToken) {
|
|
57389
58224
|
if (authMethod === "api_key") {
|
|
57390
58225
|
claudeToken = await dist_default6({
|
|
@@ -57406,6 +58241,8 @@ Starting Claude OAuth authentication...`);
|
|
|
57406
58241
|
});
|
|
57407
58242
|
spinner.succeed("Claude authentication successful!");
|
|
57408
58243
|
claudeToken = result.token;
|
|
58244
|
+
await saveToEnv(cwd, "CLAUDE_CODE_OAUTH_TOKEN", claudeToken);
|
|
58245
|
+
console.log(" Saved token to .env");
|
|
57409
58246
|
} catch (error) {
|
|
57410
58247
|
spinner.fail("Claude authentication failed");
|
|
57411
58248
|
throw error;
|
|
@@ -57415,27 +58252,60 @@ Starting Claude OAuth authentication...`);
|
|
|
57415
58252
|
if (!claudeToken) {
|
|
57416
58253
|
throw new Error("Token is required.");
|
|
57417
58254
|
}
|
|
57418
|
-
|
|
58255
|
+
if (hasSecretsAccess) {
|
|
58256
|
+
console.log(`
|
|
57419
58257
|
Setting up GitHub secrets...`);
|
|
57420
|
-
|
|
57421
|
-
|
|
57422
|
-
|
|
57423
|
-
|
|
57424
|
-
|
|
57425
|
-
|
|
57426
|
-
|
|
57427
|
-
|
|
57428
|
-
|
|
57429
|
-
|
|
57430
|
-
|
|
58258
|
+
await setGhSecret(secretName, claudeToken);
|
|
58259
|
+
console.log(` Set ${secretName}`);
|
|
58260
|
+
await setGhSecret("BOKIO_TOKEN", config3.bokio.token);
|
|
58261
|
+
console.log(" Set BOKIO_TOKEN");
|
|
58262
|
+
await setGhSecret("BOKIO_COMPANY_ID", config3.bokio.companyId);
|
|
58263
|
+
console.log(" Set BOKIO_COMPANY_ID");
|
|
58264
|
+
if (options.ledgitApiToken) {
|
|
58265
|
+
await setGhSecret("LEDGIT_API_TOKEN", options.ledgitApiToken);
|
|
58266
|
+
console.log(" Set LEDGIT_API_TOKEN");
|
|
58267
|
+
}
|
|
58268
|
+
try {
|
|
58269
|
+
await enableActionsPrPermission();
|
|
58270
|
+
console.log(" Enabled Actions to create pull requests");
|
|
58271
|
+
} catch {
|
|
58272
|
+
console.error(`
|
|
57431
58273
|
Warning: Could not enable PR creation for Actions.`);
|
|
57432
|
-
|
|
58274
|
+
console.error("You may need to enable this manually in Settings > Actions > General");
|
|
58275
|
+
}
|
|
58276
|
+
} else {
|
|
58277
|
+
console.log(`
|
|
58278
|
+
⚠️ Unable to set secrets via GitHub CLI.`);
|
|
58279
|
+
console.log(` This can happen if you don't have admin access to this repository.
|
|
58280
|
+
`);
|
|
58281
|
+
console.log(" To fix gh access and retry, run:");
|
|
58282
|
+
console.log(` gh auth refresh -h github.com -s repo,workflow
|
|
58283
|
+
`);
|
|
58284
|
+
console.log(" Or add these secrets manually in GitHub:");
|
|
58285
|
+
console.log(` Go to: Settings > Secrets and variables > Actions > New repository secret
|
|
58286
|
+
`);
|
|
58287
|
+
console.log(` ${secretName}:`);
|
|
58288
|
+
console.log(` ${claudeToken}
|
|
58289
|
+
`);
|
|
58290
|
+
console.log(" BOKIO_TOKEN:");
|
|
58291
|
+
console.log(` ${config3.bokio.token}
|
|
58292
|
+
`);
|
|
58293
|
+
console.log(" BOKIO_COMPANY_ID:");
|
|
58294
|
+
console.log(` ${config3.bokio.companyId}
|
|
58295
|
+
`);
|
|
58296
|
+
if (options.ledgitApiToken) {
|
|
58297
|
+
console.log(" LEDGIT_API_TOKEN:");
|
|
58298
|
+
console.log(` ${options.ledgitApiToken}
|
|
58299
|
+
`);
|
|
58300
|
+
}
|
|
57433
58301
|
}
|
|
57434
58302
|
console.log(`
|
|
57435
58303
|
Creating workflow files...`);
|
|
57436
58304
|
const workflowsDir = path15.join(cwd, ".github", "workflows");
|
|
57437
58305
|
await fs19.mkdir(workflowsDir, { recursive: true });
|
|
57438
|
-
const
|
|
58306
|
+
const apiKeyAuth = "anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}";
|
|
58307
|
+
const oauthAuth = "claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}";
|
|
58308
|
+
const claudeAuthLine = authMethod === "api_key" ? apiKeyAuth : oauthAuth;
|
|
57439
58309
|
const replaceAuth = (template) => template.replace(/\{\{CLAUDE_AUTH\}\}/g, claudeAuthLine);
|
|
57440
58310
|
await fs19.writeFile(path15.join(workflowsDir, "sync-inbox.yml"), replaceAuth(SYNC_INBOX_WORKFLOW));
|
|
57441
58311
|
console.log(" Created .github/workflows/sync-inbox.yml");
|
|
@@ -57468,6 +58338,7 @@ Workflows created:`);
|
|
|
57468
58338
|
|
|
57469
58339
|
// src/commands/setup-github.ts
|
|
57470
58340
|
var execAsync4 = promisify8(exec8);
|
|
58341
|
+
var API_BASE_URL2 = process.env.LEDGIT_API_URL || "https://api.ledgit.se";
|
|
57471
58342
|
async function setupGithubCommand() {
|
|
57472
58343
|
const cwd = process.cwd();
|
|
57473
58344
|
console.log(`Setting up GitHub Actions for automated bookkeeping...
|
|
@@ -57482,7 +58353,73 @@ async function setupGithubCommand() {
|
|
|
57482
58353
|
console.log(` Using existing remote: ${repoUrl}
|
|
57483
58354
|
`);
|
|
57484
58355
|
}
|
|
57485
|
-
|
|
58356
|
+
let ghUser = "unknown";
|
|
58357
|
+
try {
|
|
58358
|
+
const { stdout } = await execAsync4("gh api user -q .login");
|
|
58359
|
+
ghUser = stdout.trim();
|
|
58360
|
+
} catch {
|
|
58361
|
+
}
|
|
58362
|
+
const hasRepoAccess = await checkRepoAccess();
|
|
58363
|
+
if (!hasRepoAccess) {
|
|
58364
|
+
throw new UserError(`Cannot access repository.
|
|
58365
|
+
|
|
58366
|
+
` + `You are logged in as '${ghUser}' but this account doesn't have access to the repository.
|
|
58367
|
+
|
|
58368
|
+
` + `To fix this:
|
|
58369
|
+
` + ` 1. Check your gh accounts: gh auth status
|
|
58370
|
+
` + ` 2. Switch account: gh auth switch -u <username>`);
|
|
58371
|
+
}
|
|
58372
|
+
const hasSecretsAccess = await checkRepoSecretsAccess();
|
|
58373
|
+
if (!hasSecretsAccess) {
|
|
58374
|
+
throw new UserError(`Cannot access repository secrets.
|
|
58375
|
+
|
|
58376
|
+
` + `You are logged in as '${ghUser}' but don't have admin/write access to manage secrets.
|
|
58377
|
+
|
|
58378
|
+
` + `To fix this:
|
|
58379
|
+
` + ` 1. Ensure you have admin access to this repository
|
|
58380
|
+
` + ` 2. Or refresh auth: gh auth refresh -h github.com -s repo,workflow`);
|
|
58381
|
+
}
|
|
58382
|
+
console.log(` Repository access verified (${ghUser})
|
|
58383
|
+
`);
|
|
58384
|
+
let ledgitApiToken;
|
|
58385
|
+
let config3;
|
|
58386
|
+
try {
|
|
58387
|
+
config3 = await loadConfig(cwd);
|
|
58388
|
+
} catch {
|
|
58389
|
+
}
|
|
58390
|
+
const needsLedgitToken = config3?.provider === "ledgit" || config3?.inboxProvider === "ledgit";
|
|
58391
|
+
if (needsLedgitToken) {
|
|
58392
|
+
const accessToken = await getValidAccessToken(cwd);
|
|
58393
|
+
if (accessToken) {
|
|
58394
|
+
console.log(" Creating Ledgit API token...");
|
|
58395
|
+
const response = await fetch(`${API_BASE_URL2}/api/tokens`, {
|
|
58396
|
+
method: "POST",
|
|
58397
|
+
headers: {
|
|
58398
|
+
Authorization: `Bearer ${accessToken}`,
|
|
58399
|
+
"Content-Type": "application/json"
|
|
58400
|
+
},
|
|
58401
|
+
body: JSON.stringify({
|
|
58402
|
+
name: "GitHub Actions",
|
|
58403
|
+
scopes: ["read", "write"]
|
|
58404
|
+
})
|
|
58405
|
+
});
|
|
58406
|
+
if (response.ok) {
|
|
58407
|
+
const result = await response.json();
|
|
58408
|
+
console.log(` ✓ Ledgit API token created
|
|
58409
|
+
`);
|
|
58410
|
+
ledgitApiToken = result.data.token;
|
|
58411
|
+
} else {
|
|
58412
|
+
console.log(" Could not create API token. You can create one later with:");
|
|
58413
|
+
console.log(` ledgit token create
|
|
58414
|
+
`);
|
|
58415
|
+
}
|
|
58416
|
+
} else {
|
|
58417
|
+
console.log(" Not logged in - skipping Ledgit API token creation.");
|
|
58418
|
+
console.log(` Run 'ledgit login' then 'ledgit token create' to create one.
|
|
58419
|
+
`);
|
|
58420
|
+
}
|
|
58421
|
+
}
|
|
58422
|
+
await setupClaudeWorkflow({ cwd, autoCommit: false, ledgitApiToken });
|
|
57486
58423
|
try {
|
|
57487
58424
|
await execAsync4("git add .github/workflows");
|
|
57488
58425
|
const { stdout: status } = await execAsync4("git status --porcelain .github/workflows");
|
|
@@ -58342,6 +59279,29 @@ Traktamente rates for ${year}:`);
|
|
|
58342
59279
|
console.log("");
|
|
58343
59280
|
}
|
|
58344
59281
|
|
|
59282
|
+
// src/commands/skills.ts
|
|
59283
|
+
async function skillsCommand(skillName) {
|
|
59284
|
+
if (skillName) {
|
|
59285
|
+
const skill = getSkill(skillName);
|
|
59286
|
+
if (!skill) {
|
|
59287
|
+
const available = listSkills().map((s) => s.name).join(", ");
|
|
59288
|
+
console.error(`Unknown skill: ${skillName}`);
|
|
59289
|
+
console.error(`Available skills: ${available}`);
|
|
59290
|
+
process.exit(1);
|
|
59291
|
+
}
|
|
59292
|
+
console.log(skill.content);
|
|
59293
|
+
} else {
|
|
59294
|
+
const skills2 = listSkills();
|
|
59295
|
+
console.log(`Available skills:
|
|
59296
|
+
`);
|
|
59297
|
+
for (const skill of skills2) {
|
|
59298
|
+
console.log(` ${skill.name.padEnd(22)} ${skill.description}`);
|
|
59299
|
+
}
|
|
59300
|
+
console.log(`
|
|
59301
|
+
Usage: ledgit skills <name>`);
|
|
59302
|
+
}
|
|
59303
|
+
}
|
|
59304
|
+
|
|
58345
59305
|
// src/index.ts
|
|
58346
59306
|
config3();
|
|
58347
59307
|
var require2 = createRequire2(import.meta.url);
|
|
@@ -58352,6 +59312,13 @@ initialize({
|
|
|
58352
59312
|
appName: "ledgit"
|
|
58353
59313
|
});
|
|
58354
59314
|
setVersion(pkg.version);
|
|
59315
|
+
|
|
59316
|
+
class UserError extends Error {
|
|
59317
|
+
constructor(message) {
|
|
59318
|
+
super(message);
|
|
59319
|
+
this.name = "UserError";
|
|
59320
|
+
}
|
|
59321
|
+
}
|
|
58355
59322
|
function withTelemetry(command, action) {
|
|
58356
59323
|
return async (...args) => {
|
|
58357
59324
|
const start = Date.now();
|
|
@@ -58375,6 +59342,13 @@ function withTelemetry(command, action) {
|
|
|
58375
59342
|
if (error instanceof Error) {
|
|
58376
59343
|
trackError("cli_command", error, { command });
|
|
58377
59344
|
}
|
|
59345
|
+
if (error instanceof UserError) {
|
|
59346
|
+
console.error(`
|
|
59347
|
+
Error: ${error.message}
|
|
59348
|
+
`);
|
|
59349
|
+
await shutdown();
|
|
59350
|
+
process.exit(1);
|
|
59351
|
+
}
|
|
58378
59352
|
throw error;
|
|
58379
59353
|
} finally {
|
|
58380
59354
|
await shutdown();
|
|
@@ -58391,21 +59365,24 @@ program.command("parse-pdf").description("Extract text from a PDF file").require
|
|
|
58391
59365
|
program.command("create-entry").description("Create a journal entry from an inbox document or raw file").option("-p, --path <path>", "Path to file or inbox directory").option("-i, --inbox-dir <path>", "Path to inbox directory (deprecated, use --path)").requiredOption("-t, --tax-code <code>", "Swedish tax code (e.g., SE_VAT_25_PURCHASE_DOMESTIC)").requiredOption("-b, --base-account <code>", "Expense/revenue account code (e.g., 5422)").requiredOption("-B, --balancing-account <code>", "Balancing account (e.g., 2440, 2820)").requiredOption("-s, --series <letter>", "Voucher series (A, B, C, D, E, K)").requiredOption("-n, --entry-number <number>", "Entry number within series").option("-m, --memo <text>", "Memo to add to lines").option("-d, --description <text>", "Document description (required for raw files)").option("-D, --document-date <date>", "Document date YYYY-MM-DD (required for raw files)").option("-a, --amount <number>", "Amount (required for raw files)").option("-c, --currency <code>", "Currency code (default: SEK)").option("--dry-run", "Preview without writing files").action(withTelemetry("create-entry", createEntryCommand));
|
|
58392
59366
|
program.command("generate-lines").description("Append journal lines to an existing entry.yaml").requiredOption("-i, --inbox-dir <path>", "Path to directory with entry.yaml and documents.yaml").requiredOption("-t, --tax-code <code>", "Swedish tax code (e.g., SE_VAT_25_PURCHASE_DOMESTIC)").requiredOption("-a, --base-amount <number>", "Net amount before VAT").requiredOption("-b, --base-account <code>", "Expense/revenue account code").requiredOption("-B, --balancing-account <code>", "Balancing account").option("-m, --memo <text>", "Memo to add to lines").option("-c, --amount-currency <code>", "Currency of base amount (default: SEK)").action(withTelemetry("generate-lines", generateLinesCommand));
|
|
58393
59367
|
program.command("list-tax-codes").description("List all available Swedish tax codes").action(withTelemetry("list-tax-codes", listTaxCodesCommand));
|
|
59368
|
+
program.command("skills [name]").description("List available skills or show skill instructions for AI agents").addHelpText("after", `
|
|
59369
|
+
Examples:
|
|
59370
|
+
$ ledgit skills
|
|
59371
|
+
$ ledgit skills swedish-bookkeeping
|
|
59372
|
+
$ ledgit skills travel-expenses
|
|
59373
|
+
`).action(withTelemetry("skills", skillsCommand));
|
|
58394
59374
|
program.command("discard <inbox-directory>").description("Remove an inbox item and mark for deletion from provider").action(withTelemetry("discard", discardCommand));
|
|
58395
59375
|
program.command("login").description("Authenticate with Ledgit").option("-f, --force", "Overwrite existing token without prompting").action(withTelemetry("login", loginCommand));
|
|
58396
|
-
program.command("token [action]").description("Manage
|
|
59376
|
+
program.command("token [action]").description("Manage API tokens (PATs) for CI/CD").addHelpText("after", `
|
|
58397
59377
|
Actions:
|
|
58398
|
-
|
|
58399
|
-
|
|
58400
|
-
|
|
58401
|
-
revoke Revoke/delete stored token
|
|
59378
|
+
list List all API tokens (default)
|
|
59379
|
+
create Create a new API token
|
|
59380
|
+
revoke Revoke an API token
|
|
58402
59381
|
|
|
58403
59382
|
Examples:
|
|
58404
59383
|
$ ledgit token
|
|
58405
|
-
$ ledgit token
|
|
58406
|
-
$ ledgit token
|
|
58407
|
-
$ LEDGIT_TOKEN=$(ledgit token export)
|
|
58408
|
-
$ ledgit token refresh
|
|
59384
|
+
$ ledgit token list
|
|
59385
|
+
$ ledgit token create
|
|
58409
59386
|
$ ledgit token revoke
|
|
58410
59387
|
`).action(withTelemetry("token", tokenCommand));
|
|
58411
59388
|
program.command("update").description("Update AGENTS.md to the latest version").option("-f, --force", "Overwrite without prompting if modified").action(withTelemetry("update", updateCommand));
|
|
@@ -58442,3 +59419,6 @@ Examples:
|
|
|
58442
59419
|
`).action(withTelemetry("traktamente:create", traktamenteCommand));
|
|
58443
59420
|
traktamente.command("list").description("List available countries and traktamente rates").option("-y, --year <year>", "Year for rates (default: current year)").action(withTelemetry("traktamente:list", listCountriesCommand));
|
|
58444
59421
|
program.parse();
|
|
59422
|
+
export {
|
|
59423
|
+
UserError
|
|
59424
|
+
};
|