jaz-cli 2.3.0 → 2.6.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.
Files changed (33) hide show
  1. package/assets/skills/api/SKILL.md +35 -34
  2. package/assets/skills/api/references/errors.md +15 -7
  3. package/assets/skills/api/references/feature-glossary.md +2 -0
  4. package/assets/skills/api/references/field-map.md +3 -3
  5. package/assets/skills/conversion/SKILL.md +1 -1
  6. package/assets/skills/transaction-recipes/SKILL.md +158 -14
  7. package/assets/skills/transaction-recipes/references/asset-disposal.md +174 -0
  8. package/assets/skills/transaction-recipes/references/bad-debt-provision.md +145 -0
  9. package/assets/skills/transaction-recipes/references/building-blocks.md +25 -2
  10. package/assets/skills/transaction-recipes/references/capital-wip.md +167 -0
  11. package/assets/skills/transaction-recipes/references/dividend.md +111 -0
  12. package/assets/skills/transaction-recipes/references/employee-accruals.md +154 -0
  13. package/assets/skills/transaction-recipes/references/fixed-deposit.md +164 -0
  14. package/assets/skills/transaction-recipes/references/fx-revaluation.md +135 -0
  15. package/assets/skills/transaction-recipes/references/hire-purchase.md +190 -0
  16. package/assets/skills/transaction-recipes/references/intercompany.md +150 -0
  17. package/assets/skills/transaction-recipes/references/provisions.md +142 -0
  18. package/dist/calc/amortization.js +122 -0
  19. package/dist/calc/asset-disposal.js +151 -0
  20. package/dist/calc/blueprint.js +46 -0
  21. package/dist/calc/depreciation.js +200 -0
  22. package/dist/calc/ecl.js +101 -0
  23. package/dist/calc/fixed-deposit.js +169 -0
  24. package/dist/calc/format.js +494 -0
  25. package/dist/calc/fx-reval.js +93 -0
  26. package/dist/calc/lease.js +146 -0
  27. package/dist/calc/loan.js +107 -0
  28. package/dist/calc/provision.js +128 -0
  29. package/dist/calc/types.js +21 -0
  30. package/dist/calc/validate.js +48 -0
  31. package/dist/commands/calc.js +252 -0
  32. package/dist/index.js +2 -0
  33. package/package.json +3 -2
@@ -0,0 +1,252 @@
1
+ import chalk from 'chalk';
2
+ import { calculateLoan } from '../calc/loan.js';
3
+ import { calculateLease } from '../calc/lease.js';
4
+ import { calculateDepreciation } from '../calc/depreciation.js';
5
+ import { calculatePrepaidExpense, calculateDeferredRevenue } from '../calc/amortization.js';
6
+ import { calculateFxReval } from '../calc/fx-reval.js';
7
+ import { calculateEcl } from '../calc/ecl.js';
8
+ import { calculateProvision } from '../calc/provision.js';
9
+ import { calculateFixedDeposit } from '../calc/fixed-deposit.js';
10
+ import { calculateAssetDisposal } from '../calc/asset-disposal.js';
11
+ import { printResult, printJson } from '../calc/format.js';
12
+ import { CalcValidationError } from '../calc/validate.js';
13
+ /** Wrap calc action with validation error handling. */
14
+ function calcAction(fn) {
15
+ return (opts) => {
16
+ try {
17
+ fn(opts);
18
+ }
19
+ catch (err) {
20
+ if (err instanceof CalcValidationError) {
21
+ console.error(chalk.red(`Error: ${err.message}`));
22
+ process.exit(1);
23
+ }
24
+ throw err;
25
+ }
26
+ };
27
+ }
28
+ export function registerCalcCommand(program) {
29
+ const calc = program
30
+ .command('calc')
31
+ .description('Financial calculators — loan, lease, depreciation, prepaid-expense, deferred-revenue, fx-reval, ecl, provision, fixed-deposit, asset-disposal');
32
+ // ── jaz calc loan ──────────────────────────────────────────────
33
+ calc
34
+ .command('loan')
35
+ .description('Loan amortization schedule')
36
+ .requiredOption('--principal <amount>', 'Loan principal', parseFloat)
37
+ .requiredOption('--rate <percent>', 'Annual interest rate (%)', parseFloat)
38
+ .requiredOption('--term <months>', 'Loan term in months', parseInt)
39
+ .option('--start-date <date>', 'Start date (YYYY-MM-DD)')
40
+ .option('--currency <code>', 'Currency code (e.g. SGD, USD)')
41
+ .option('--json', 'Output as JSON')
42
+ .action(calcAction((opts) => {
43
+ const result = calculateLoan({
44
+ principal: opts.principal,
45
+ annualRate: opts.rate,
46
+ termMonths: opts.term,
47
+ startDate: opts.startDate,
48
+ currency: opts.currency,
49
+ });
50
+ opts.json ? printJson(result) : printResult(result);
51
+ }));
52
+ // ── jaz calc lease ─────────────────────────────────────────────
53
+ calc
54
+ .command('lease')
55
+ .description('IFRS 16 lease schedule (liability unwinding + ROU depreciation). Add --useful-life for hire purchase.')
56
+ .requiredOption('--payment <amount>', 'Monthly lease payment', parseFloat)
57
+ .requiredOption('--term <months>', 'Lease term in months', parseInt)
58
+ .requiredOption('--rate <percent>', 'Incremental borrowing rate (%)', parseFloat)
59
+ .option('--useful-life <months>', 'Asset useful life in months (hire purchase: depreciate over useful life, not term)', parseInt)
60
+ .option('--start-date <date>', 'Lease commencement date (YYYY-MM-DD)')
61
+ .option('--currency <code>', 'Currency code (e.g. SGD, USD)')
62
+ .option('--json', 'Output as JSON')
63
+ .action(calcAction((opts) => {
64
+ const result = calculateLease({
65
+ monthlyPayment: opts.payment,
66
+ termMonths: opts.term,
67
+ annualRate: opts.rate,
68
+ usefulLifeMonths: opts.usefulLife,
69
+ startDate: opts.startDate,
70
+ currency: opts.currency,
71
+ });
72
+ opts.json ? printJson(result) : printResult(result);
73
+ }));
74
+ // ── jaz calc depreciation ──────────────────────────────────────
75
+ calc
76
+ .command('depreciation')
77
+ .description('Depreciation schedule (straight-line, double declining, or 150% declining)')
78
+ .requiredOption('--cost <amount>', 'Asset cost', parseFloat)
79
+ .requiredOption('--salvage <amount>', 'Salvage value', parseFloat)
80
+ .requiredOption('--life <years>', 'Useful life in years', parseInt)
81
+ .option('--method <method>', 'Method: sl, ddb (default), or 150db', 'ddb')
82
+ .option('--frequency <freq>', 'Frequency: annual (default) or monthly', 'annual')
83
+ .option('--currency <code>', 'Currency code (e.g. SGD, USD)')
84
+ .option('--json', 'Output as JSON')
85
+ .action(calcAction((opts) => {
86
+ const result = calculateDepreciation({
87
+ cost: opts.cost,
88
+ salvageValue: opts.salvage,
89
+ usefulLifeYears: opts.life,
90
+ method: opts.method,
91
+ frequency: opts.frequency,
92
+ currency: opts.currency,
93
+ });
94
+ opts.json ? printJson(result) : printResult(result);
95
+ }));
96
+ // ── jaz calc prepaid-expense ──────────────────────────────────
97
+ calc
98
+ .command('prepaid-expense')
99
+ .description('Prepaid expense recognition schedule (e.g. insurance, rent, subscriptions)')
100
+ .requiredOption('--amount <amount>', 'Total prepaid amount', parseFloat)
101
+ .requiredOption('--periods <count>', 'Number of recognition periods', parseInt)
102
+ .option('--frequency <freq>', 'Frequency: monthly (default) or quarterly', 'monthly')
103
+ .option('--start-date <date>', 'Start date (YYYY-MM-DD)')
104
+ .option('--currency <code>', 'Currency code (e.g. SGD, USD)')
105
+ .option('--json', 'Output as JSON')
106
+ .action(calcAction((opts) => {
107
+ const result = calculatePrepaidExpense({
108
+ amount: opts.amount,
109
+ periods: opts.periods,
110
+ frequency: opts.frequency,
111
+ startDate: opts.startDate,
112
+ currency: opts.currency,
113
+ });
114
+ opts.json ? printJson(result) : printResult(result);
115
+ }));
116
+ // ── jaz calc deferred-revenue ───────────────────────────────────
117
+ calc
118
+ .command('deferred-revenue')
119
+ .description('Deferred revenue recognition schedule (e.g. annual contracts, retainers)')
120
+ .requiredOption('--amount <amount>', 'Total deferred amount', parseFloat)
121
+ .requiredOption('--periods <count>', 'Number of recognition periods', parseInt)
122
+ .option('--frequency <freq>', 'Frequency: monthly (default) or quarterly', 'monthly')
123
+ .option('--start-date <date>', 'Start date (YYYY-MM-DD)')
124
+ .option('--currency <code>', 'Currency code (e.g. SGD, USD)')
125
+ .option('--json', 'Output as JSON')
126
+ .action(calcAction((opts) => {
127
+ const result = calculateDeferredRevenue({
128
+ amount: opts.amount,
129
+ periods: opts.periods,
130
+ frequency: opts.frequency,
131
+ startDate: opts.startDate,
132
+ currency: opts.currency,
133
+ });
134
+ opts.json ? printJson(result) : printResult(result);
135
+ }));
136
+ // ── jaz calc fx-reval ───────────────────────────────────────────
137
+ calc
138
+ .command('fx-reval')
139
+ .description('FX revaluation — unrealized gain/loss on non-AR/AP foreign currency balances (IAS 21)')
140
+ .requiredOption('--amount <amount>', 'Foreign currency amount outstanding', parseFloat)
141
+ .requiredOption('--book-rate <rate>', 'Original booking exchange rate', parseFloat)
142
+ .requiredOption('--closing-rate <rate>', 'Period-end closing exchange rate', parseFloat)
143
+ .option('--currency <code>', 'Foreign currency code (e.g. USD)', 'USD')
144
+ .option('--base-currency <code>', 'Base (functional) currency code (e.g. SGD)', 'SGD')
145
+ .option('--json', 'Output as JSON')
146
+ .action(calcAction((opts) => {
147
+ const result = calculateFxReval({
148
+ amount: opts.amount,
149
+ bookRate: opts.bookRate,
150
+ closingRate: opts.closingRate,
151
+ currency: opts.currency,
152
+ baseCurrency: opts.baseCurrency,
153
+ });
154
+ opts.json ? printJson(result) : printResult(result);
155
+ }));
156
+ // ── jaz calc ecl ────────────────────────────────────────────────
157
+ calc
158
+ .command('ecl')
159
+ .description('Expected credit loss provision matrix (IFRS 9 simplified approach)')
160
+ .requiredOption('--current <amount>', 'Current (not overdue) receivables balance', parseFloat)
161
+ .requiredOption('--30d <amount>', '1-30 days overdue balance', parseFloat)
162
+ .requiredOption('--60d <amount>', '31-60 days overdue balance', parseFloat)
163
+ .requiredOption('--90d <amount>', '61-90 days overdue balance', parseFloat)
164
+ .requiredOption('--120d <amount>', '91+ days overdue balance', parseFloat)
165
+ .requiredOption('--rates <rates>', 'Loss rates per bucket (comma-separated %)', (v) => v.split(',').map(Number))
166
+ .option('--existing-provision <amount>', 'Existing provision balance', parseFloat, 0)
167
+ .option('--currency <code>', 'Currency code (e.g. SGD, USD)')
168
+ .option('--json', 'Output as JSON')
169
+ .action(calcAction((opts) => {
170
+ const rates = opts.rates;
171
+ const result = calculateEcl({
172
+ buckets: [
173
+ { name: 'Current', balance: opts.current, rate: rates[0] },
174
+ { name: '1-30 days', balance: opts['30d'], rate: rates[1] },
175
+ { name: '31-60 days', balance: opts['60d'], rate: rates[2] },
176
+ { name: '61-90 days', balance: opts['90d'], rate: rates[3] },
177
+ { name: '91+ days', balance: opts['120d'], rate: rates[4] },
178
+ ],
179
+ existingProvision: opts.existingProvision,
180
+ currency: opts.currency,
181
+ });
182
+ opts.json ? printJson(result) : printResult(result);
183
+ }));
184
+ // ── jaz calc provision ──────────────────────────────────────────
185
+ calc
186
+ .command('provision')
187
+ .description('IAS 37 provision PV measurement + discount unwinding schedule')
188
+ .requiredOption('--amount <amount>', 'Estimated future cash outflow', parseFloat)
189
+ .requiredOption('--rate <percent>', 'Discount rate (%)', parseFloat)
190
+ .requiredOption('--term <months>', 'Months until expected settlement', parseInt)
191
+ .option('--start-date <date>', 'Recognition date (YYYY-MM-DD)')
192
+ .option('--currency <code>', 'Currency code (e.g. SGD, USD)')
193
+ .option('--json', 'Output as JSON')
194
+ .action(calcAction((opts) => {
195
+ const result = calculateProvision({
196
+ amount: opts.amount,
197
+ annualRate: opts.rate,
198
+ termMonths: opts.term,
199
+ startDate: opts.startDate,
200
+ currency: opts.currency,
201
+ });
202
+ opts.json ? printJson(result) : printResult(result);
203
+ }));
204
+ // ── jaz calc fixed-deposit ────────────────────────────────────
205
+ calc
206
+ .command('fixed-deposit')
207
+ .description('Fixed deposit interest accrual schedule (IFRS 9 amortized cost)')
208
+ .requiredOption('--principal <amount>', 'Deposit principal', parseFloat)
209
+ .requiredOption('--rate <percent>', 'Annual interest rate (%)', parseFloat)
210
+ .requiredOption('--term <months>', 'Term in months', parseInt)
211
+ .option('--compound <method>', 'Compounding: none (default), monthly, quarterly, annually', 'none')
212
+ .option('--start-date <date>', 'Placement date (YYYY-MM-DD)')
213
+ .option('--currency <code>', 'Currency code (e.g. SGD, USD)')
214
+ .option('--json', 'Output as JSON')
215
+ .action(calcAction((opts) => {
216
+ const result = calculateFixedDeposit({
217
+ principal: opts.principal,
218
+ annualRate: opts.rate,
219
+ termMonths: opts.term,
220
+ compounding: opts.compound,
221
+ startDate: opts.startDate,
222
+ currency: opts.currency,
223
+ });
224
+ opts.json ? printJson(result) : printResult(result);
225
+ }));
226
+ // ── jaz calc asset-disposal ───────────────────────────────────
227
+ calc
228
+ .command('asset-disposal')
229
+ .description('Fixed asset disposal — gain/loss calculation (IAS 16)')
230
+ .requiredOption('--cost <amount>', 'Original asset cost', parseFloat)
231
+ .requiredOption('--salvage <amount>', 'Salvage value', parseFloat)
232
+ .requiredOption('--life <years>', 'Useful life in years', parseInt)
233
+ .requiredOption('--acquired <date>', 'Acquisition date (YYYY-MM-DD)')
234
+ .requiredOption('--disposed <date>', 'Disposal date (YYYY-MM-DD)')
235
+ .requiredOption('--proceeds <amount>', 'Disposal proceeds (0 for scrap)', parseFloat)
236
+ .option('--method <method>', 'Depreciation method: sl (default), ddb, 150db', 'sl')
237
+ .option('--currency <code>', 'Currency code (e.g. SGD, USD)')
238
+ .option('--json', 'Output as JSON')
239
+ .action(calcAction((opts) => {
240
+ const result = calculateAssetDisposal({
241
+ cost: opts.cost,
242
+ salvageValue: opts.salvage,
243
+ usefulLifeYears: opts.life,
244
+ acquisitionDate: opts.acquired,
245
+ disposalDate: opts.disposed,
246
+ proceeds: opts.proceeds,
247
+ method: opts.method,
248
+ currency: opts.currency,
249
+ });
250
+ opts.json ? printJson(result) : printResult(result);
251
+ }));
252
+ }
package/dist/index.js CHANGED
@@ -6,6 +6,7 @@ import { dirname, join } from 'path';
6
6
  import { initCommand } from './commands/init.js';
7
7
  import { versionsCommand } from './commands/versions.js';
8
8
  import { updateCommand } from './commands/update.js';
9
+ import { registerCalcCommand } from './commands/calc.js';
9
10
  import { SKILL_TYPES } from './types/index.js';
10
11
  const __filename = fileURLToPath(import.meta.url);
11
12
  const __dirname = dirname(__filename);
@@ -49,4 +50,5 @@ program
49
50
  skill: options.skill,
50
51
  });
51
52
  });
53
+ registerCalcCommand(program);
52
54
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jaz-cli",
3
- "version": "2.3.0",
3
+ "version": "2.6.0",
4
4
  "description": "CLI to install Jaz AI skills for Claude Code",
5
5
  "type": "module",
6
6
  "bin": {
@@ -36,8 +36,9 @@
36
36
  "author": "Jaz Engineering <api-support@jaz.ai>",
37
37
  "license": "MIT",
38
38
  "dependencies": {
39
- "commander": "^12.1.0",
40
39
  "chalk": "^5.3.0",
40
+ "commander": "^12.1.0",
41
+ "financial": "^0.2.4",
41
42
  "ora": "^8.1.1",
42
43
  "prompts": "^2.4.2"
43
44
  },