jaz-clio 4.35.0 → 4.35.2

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 (69) hide show
  1. package/assets/skills/api/SKILL.md +1 -1
  2. package/assets/skills/cli/SKILL.md +1 -1
  3. package/assets/skills/conversion/SKILL.md +1 -1
  4. package/assets/skills/jobs/SKILL.md +1 -1
  5. package/assets/skills/transaction-recipes/SKILL.md +1 -1
  6. package/dist/commands/accounts.js +6 -6
  7. package/dist/commands/attachments.js +8 -8
  8. package/dist/commands/auth.js +41 -41
  9. package/dist/commands/bank-rules.js +14 -14
  10. package/dist/commands/bank.js +27 -27
  11. package/dist/commands/bills.js +35 -35
  12. package/dist/commands/bookmarks.js +8 -8
  13. package/dist/commands/calc.js +2 -2
  14. package/dist/commands/capsules.js +14 -14
  15. package/dist/commands/cash-entry.js +16 -16
  16. package/dist/commands/cash-transfer.js +4 -4
  17. package/dist/commands/cashflow.js +2 -2
  18. package/dist/commands/contact-groups.js +10 -10
  19. package/dist/commands/contacts.js +14 -14
  20. package/dist/commands/currencies.js +2 -2
  21. package/dist/commands/currency-rates.js +8 -8
  22. package/dist/commands/custom-fields.js +12 -12
  23. package/dist/commands/customer-credit-notes.js +30 -30
  24. package/dist/commands/draft-helpers.js +12 -12
  25. package/dist/commands/exports.js +4 -4
  26. package/dist/commands/fixed-assets.js +23 -23
  27. package/dist/commands/format-helpers.js +5 -0
  28. package/dist/commands/help-examples.js +2 -2
  29. package/dist/commands/init.js +8 -8
  30. package/dist/commands/inventory.js +7 -7
  31. package/dist/commands/invoices.js +36 -36
  32. package/dist/commands/items.js +11 -11
  33. package/dist/commands/jobs.js +33 -33
  34. package/dist/commands/journals.js +27 -27
  35. package/dist/commands/kb.js +6 -6
  36. package/dist/commands/magic.js +40 -40
  37. package/dist/commands/nano-classifiers.js +8 -8
  38. package/dist/commands/org-users.js +5 -5
  39. package/dist/commands/org.js +8 -8
  40. package/dist/commands/output.js +3 -3
  41. package/dist/commands/pagination.js +2 -2
  42. package/dist/commands/parsers.js +20 -20
  43. package/dist/commands/payments.js +9 -9
  44. package/dist/commands/picker.js +88 -90
  45. package/dist/commands/quick-fix.js +8 -8
  46. package/dist/commands/recipe.js +16 -16
  47. package/dist/commands/reports.js +11 -11
  48. package/dist/commands/resolve.js +8 -8
  49. package/dist/commands/schedulers.js +25 -25
  50. package/dist/commands/schema.js +15 -24
  51. package/dist/commands/search.js +4 -4
  52. package/dist/commands/subscriptions.js +17 -17
  53. package/dist/commands/supplier-credit-notes.js +28 -28
  54. package/dist/commands/tags.js +10 -10
  55. package/dist/commands/tax-profiles.js +11 -11
  56. package/dist/commands/ui/index.js +1 -0
  57. package/dist/commands/ui/picker.js +180 -0
  58. package/dist/commands/ui/table.js +2 -3
  59. package/dist/commands/ui/theme.js +1 -0
  60. package/dist/commands/update.js +2 -2
  61. package/dist/commands/versions.js +3 -3
  62. package/dist/core/calc/format.js +126 -126
  63. package/dist/core/jobs/document-collection/tools/ingest/format.js +25 -25
  64. package/dist/core/jobs/format.js +23 -23
  65. package/dist/core/jobs/payment-run/tools/bank-file/format.js +7 -7
  66. package/dist/core/jobs/payment-run/tools/outstanding/format.js +9 -9
  67. package/dist/core/jobs/statutory-filing/tools/sg-tax/format-sg.js +19 -19
  68. package/dist/index.js +11 -11
  69. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: jaz-api
3
- version: 4.35.0
3
+ version: 4.35.2
4
4
  description: >-
5
5
  Use this skill whenever you call, debug, or review code that touches the Jaz
6
6
  REST API. Covers field names, response shapes, 117 production gotchas, error
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: jaz-cli
3
- version: 4.35.0
3
+ version: 4.35.2
4
4
  description: >-
5
5
  Use this skill when running Clio CLI commands, building shell scripts with
6
6
  Clio, debugging auth issues, understanding --json output, paginating results,
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: jaz-conversion
3
- version: 4.35.0
3
+ version: 4.35.2
4
4
  description: >-
5
5
  Use this skill when migrating accounting data into Jaz — importing from Xero,
6
6
  QuickBooks, Sage, MYOB, or Excel exports. Covers the full conversion pipeline:
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: jaz-jobs
3
- version: 4.35.0
3
+ version: 4.35.2
4
4
  description: >-
5
5
  Use this skill for recurring accounting workflows — month/quarter/year-end
6
6
  close, bank reconciliation, GST/VAT filing, payment runs, credit control,
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: jaz-recipes
3
- version: 4.35.0
3
+ version: 4.35.2
4
4
  description: >-
5
5
  Use this skill when modeling complex multi-step accounting transactions —
6
6
  anything that spans multiple periods, involves changing amounts, or requires
@@ -1,4 +1,3 @@
1
- import chalk from 'chalk';
2
1
  import { listAccounts, searchAccounts, createAccount, deleteAccount } from '../core/api/chart-of-accounts.js';
3
2
  import { findExistingAccount, normalizeAccountType } from '../core/api/guards.js';
4
3
  import { apiAction } from './api-action.js';
@@ -6,6 +5,7 @@ import { outputList } from './output.js';
6
5
  import { parsePositiveInt, parseNonNegativeInt, readBodyInput, requireFields } from './parsers.js';
7
6
  import { paginatedFetch } from './pagination.js';
8
7
  import { formatId } from './format-helpers.js';
8
+ import { accent, highlight, success } from './ui/theme.js';
9
9
  const ACCOUNTS_COLUMNS = [
10
10
  { key: 'resourceId', header: 'ID', format: formatId },
11
11
  { key: 'code', header: 'Code' },
@@ -74,8 +74,8 @@ export function registerAccountsCommand(program) {
74
74
  console.log(JSON.stringify(existing, null, 2));
75
75
  }
76
76
  else {
77
- console.log(chalk.cyan(`Account "${acctName}" already exists`));
78
- console.log(chalk.bold('ID:'), existing.resourceId);
77
+ console.log(accent(`Account "${acctName}" already exists`));
78
+ console.log(highlight('ID:'), existing.resourceId);
79
79
  }
80
80
  return;
81
81
  }
@@ -105,8 +105,8 @@ export function registerAccountsCommand(program) {
105
105
  console.log(JSON.stringify(res.data, null, 2));
106
106
  }
107
107
  else {
108
- console.log(chalk.green(`Account created: ${res.data.name} (${res.data.code})`));
109
- console.log(chalk.bold('ID:'), res.data.resourceId);
108
+ console.log(success(`Account created: ${res.data.name} (${res.data.code})`));
109
+ console.log(highlight('ID:'), res.data.resourceId);
110
110
  }
111
111
  }));
112
112
  // ── clio accounts delete ──────────────────────────────────────
@@ -122,7 +122,7 @@ export function registerAccountsCommand(program) {
122
122
  console.log(JSON.stringify({ deleted: true, resourceId }));
123
123
  }
124
124
  else {
125
- console.log(chalk.green(`Account ${resourceId} deleted.`));
125
+ console.log(success(`Account ${resourceId} deleted.`));
126
126
  }
127
127
  })(opts));
128
128
  }
@@ -1,10 +1,10 @@
1
- import chalk from 'chalk';
2
1
  import { readFileSync } from 'node:fs';
3
2
  import { basename, extname, resolve } from 'node:path';
4
3
  import { listAttachments, addAttachment, deleteAttachment, fetchAttachmentTable } from '../core/api/attachments.js';
5
4
  import { apiAction } from './api-action.js';
6
5
  import { outputList } from './output.js';
7
6
  import { formatId } from './format-helpers.js';
7
+ import { danger, success } from './ui/theme.js';
8
8
  const ATTACHMENTS_COLUMNS = [
9
9
  { key: 'resourceId', header: 'ID', format: formatId },
10
10
  { key: 'fileName', header: 'File Name' },
@@ -38,7 +38,7 @@ export function registerAttachmentsCommand(program) {
38
38
  .action(apiAction(async (client, opts) => {
39
39
  const btType = opts.type;
40
40
  if (!BT_TYPES.includes(btType)) {
41
- console.error(chalk.red(`Invalid type. Use one of: ${BT_TYPES.join(', ')}`));
41
+ console.error(danger(`Invalid type. Use one of: ${BT_TYPES.join(', ')}`));
42
42
  process.exit(1);
43
43
  }
44
44
  const result = await listAttachments(client, btType, opts.id);
@@ -65,11 +65,11 @@ export function registerAttachmentsCommand(program) {
65
65
  .action(apiAction(async (client, opts) => {
66
66
  const btType = opts.type;
67
67
  if (!BT_TYPES.includes(btType)) {
68
- console.error(chalk.red(`Invalid type. Use one of: ${BT_TYPES.join(', ')}`));
68
+ console.error(danger(`Invalid type. Use one of: ${BT_TYPES.join(', ')}`));
69
69
  process.exit(1);
70
70
  }
71
71
  if (!opts.attachmentId && !opts.url && !opts.file) {
72
- console.error(chalk.red('Provide --file, --url, or --attachment-id'));
72
+ console.error(danger('Provide --file, --url, or --attachment-id'));
73
73
  process.exit(1);
74
74
  }
75
75
  let file;
@@ -87,7 +87,7 @@ export function registerAttachmentsCommand(program) {
87
87
  // Download from URL, then upload as file
88
88
  const res = await fetch(opts.url);
89
89
  if (!res.ok) {
90
- console.error(chalk.red(`Failed to download: ${res.status} ${res.statusText}`));
90
+ console.error(danger(`Failed to download: ${res.status} ${res.statusText}`));
91
91
  process.exit(1);
92
92
  }
93
93
  const buffer = await res.arrayBuffer();
@@ -108,7 +108,7 @@ export function registerAttachmentsCommand(program) {
108
108
  console.log(JSON.stringify(result, null, 2));
109
109
  }
110
110
  else {
111
- console.log(chalk.green('Attachment added.'));
111
+ console.log(success('Attachment added.'));
112
112
  }
113
113
  }));
114
114
  // ── clio attachments delete ────────────────────────────────────
@@ -123,7 +123,7 @@ export function registerAttachmentsCommand(program) {
123
123
  .action((attachmentResourceId, rawOpts) => {
124
124
  const btType = rawOpts.type;
125
125
  if (!BT_TYPES.includes(btType)) {
126
- console.error(chalk.red(`Invalid type. Use one of: ${BT_TYPES.join(', ')}`));
126
+ console.error(danger(`Invalid type. Use one of: ${BT_TYPES.join(', ')}`));
127
127
  process.exit(1);
128
128
  }
129
129
  return apiAction(async (client) => {
@@ -132,7 +132,7 @@ export function registerAttachmentsCommand(program) {
132
132
  console.log(JSON.stringify(result, null, 2));
133
133
  }
134
134
  else {
135
- console.log(chalk.green('Attachment deleted.'));
135
+ console.log(success('Attachment deleted.'));
136
136
  }
137
137
  })(rawOpts);
138
138
  });
@@ -1,4 +1,4 @@
1
- import chalk from 'chalk';
1
+ import { danger, success, warning, muted, highlight } from './ui/theme.js';
2
2
  import * as p from '@clack/prompts';
3
3
  import { clearStoredCredentials, requireAuth, getProfile, setProfile, removeProfile, getActiveLabel, setActiveLabel, listProfiles, findLabelByApiKey, resolvedAuthSource, } from '../core/auth/index.js';
4
4
  import { JazClient } from '../core/api/client.js';
@@ -26,7 +26,7 @@ async function validateKey(apiKey) {
26
26
  /** Shared add-org logic used by both `auth add` and `auth set-key`. */
27
27
  async function addOrg(key, opts) {
28
28
  if (!key.startsWith('jk-')) {
29
- console.error(chalk.red('Error: API key must start with "jk-"'));
29
+ console.error(danger('Error: API key must start with "jk-"'));
30
30
  process.exit(1);
31
31
  }
32
32
  // Check for duplicate key under the same (or default) label
@@ -36,7 +36,7 @@ async function addOrg(key, opts) {
36
36
  console.log(JSON.stringify({ error: 'duplicate', existingLabel }));
37
37
  }
38
38
  else {
39
- console.error(chalk.yellow(`This key is already registered as '${existingLabel}'.`));
39
+ console.error(warning(`This key is already registered as '${existingLabel}'.`));
40
40
  }
41
41
  return;
42
42
  }
@@ -46,14 +46,14 @@ async function addOrg(key, opts) {
46
46
  org = await validateKey(key);
47
47
  }
48
48
  catch {
49
- console.error(chalk.red('Error: API key is invalid or the API is unreachable.'));
49
+ console.error(danger('Error: API key is invalid or the API is unreachable.'));
50
50
  process.exit(2);
51
51
  }
52
52
  const label = opts.as ?? slugify(org.name);
53
53
  // Warn if same key exists under different label
54
54
  if (existingLabel && existingLabel !== label) {
55
55
  if (!opts.json) {
56
- console.error(chalk.yellow(`Note: This key is also registered as '${existingLabel}'.`));
56
+ console.error(warning(`Note: This key is also registered as '${existingLabel}'.`));
57
57
  }
58
58
  }
59
59
  // Overwrite protection — don't silently replace a different key under the same label
@@ -63,7 +63,7 @@ async function addOrg(key, opts) {
63
63
  console.log(JSON.stringify({ error: 'label_taken', label, existingOrgName: existingProfile.orgName }));
64
64
  }
65
65
  else {
66
- console.error(chalk.red(`Label '${label}' is already used by ${existingProfile.orgName}. Use --as <label> to choose a different label.`));
66
+ console.error(danger(`Label '${label}' is already used by ${existingProfile.orgName}. Use --as <label> to choose a different label.`));
67
67
  }
68
68
  process.exit(1);
69
69
  }
@@ -80,10 +80,10 @@ async function addOrg(key, opts) {
80
80
  console.log(JSON.stringify({ registered: true, label, orgName: org.name, currency: org.currency, country: org.countryCode }));
81
81
  }
82
82
  else {
83
- console.log(chalk.green(`\u2713 Registered: ${label} \u2014 ${org.name} (${org.currency}, ${org.countryCode})`));
83
+ console.log(success(`\u2713 Registered: ${label} \u2014 ${org.name} (${org.currency}, ${org.countryCode})`));
84
84
  const active = getActiveLabel();
85
85
  if (active === label) {
86
- console.log(chalk.dim(` Active org set to ${label}`));
86
+ console.log(muted(` Active org set to ${label}`));
87
87
  }
88
88
  }
89
89
  }
@@ -108,18 +108,18 @@ export function registerAuthCommand(program) {
108
108
  const orgs = listProfiles();
109
109
  const labels = Object.keys(orgs);
110
110
  if (labels.length === 0) {
111
- console.error(chalk.red('No orgs registered. Run `clio auth add <key>` first.'));
111
+ console.error(danger('No orgs registered. Run `clio auth add <key>` first.'));
112
112
  process.exit(1);
113
113
  }
114
114
  let target = label;
115
115
  // Interactive picker if no label provided
116
116
  if (!target) {
117
117
  if (opts.json || opts.export) {
118
- console.error(chalk.red('Error: --json and --export require a label argument.'));
118
+ console.error(danger('Error: --json and --export require a label argument.'));
119
119
  process.exit(1);
120
120
  }
121
121
  if (!process.stdin.isTTY || !process.stdout.isTTY) {
122
- console.error(chalk.red('Error: interactive picker requires a TTY. Provide a label argument.'));
122
+ console.error(danger('Error: interactive picker requires a TTY. Provide a label argument.'));
123
123
  process.exit(1);
124
124
  }
125
125
  const active = getActiveLabel();
@@ -138,7 +138,7 @@ export function registerAuthCommand(program) {
138
138
  setActiveLabel(target);
139
139
  }
140
140
  catch (err) {
141
- console.error(chalk.red(err.message));
141
+ console.error(danger(err.message));
142
142
  process.exit(1);
143
143
  }
144
144
  const entry = orgs[target];
@@ -151,10 +151,10 @@ export function registerAuthCommand(program) {
151
151
  console.log(JSON.stringify({ switched: true, label: target, orgName: entry.orgName, currency: entry.currency }));
152
152
  }
153
153
  else {
154
- console.log(chalk.green(`Switched to: ${target} \u2014 ${entry.orgName} (${entry.currency}, ${entry.country})`));
154
+ console.log(success(`Switched to: ${target} \u2014 ${entry.orgName} (${entry.currency}, ${entry.country})`));
155
155
  if (labels.length > 1) {
156
- console.log(chalk.dim(` Tip: Pin to this terminal: eval "$(clio auth switch ${target} --export)"`));
157
- console.log(chalk.dim(` Or add shell integration: eval "$(clio auth shell-init)"`));
156
+ console.log(muted(` Tip: Pin to this terminal: eval "$(clio auth switch ${target} --export)"`));
157
+ console.log(muted(` Or add shell integration: eval "$(clio auth shell-init)"`));
158
158
  }
159
159
  }
160
160
  });
@@ -199,13 +199,13 @@ export function registerAuthCommand(program) {
199
199
  }
200
200
  const labels = Object.keys(orgs);
201
201
  if (labels.length === 0) {
202
- console.error(chalk.yellow('No orgs registered. Run `clio auth add <key>` to get started.'));
202
+ console.error(warning('No orgs registered. Run `clio auth add <key>` to get started.'));
203
203
  return;
204
204
  }
205
205
  for (const label of labels) {
206
206
  const entry = orgs[label];
207
- const marker = label === active ? chalk.yellow('\u2605') : ' ';
208
- const labelStr = label === active ? chalk.bold(label) : label;
207
+ const marker = label === active ? warning('\u2605') : ' ';
208
+ const labelStr = label === active ? highlight(label) : label;
209
209
  const countryStr = entry.country ? ` ${entry.country}` : '';
210
210
  console.log(` ${marker} ${labelStr.padEnd(18)} ${entry.orgName.padEnd(22)} ${entry.currency}${countryStr}`);
211
211
  }
@@ -213,7 +213,7 @@ export function registerAuthCommand(program) {
213
213
  const pinnedOrg = process.env.JAZ_ORG;
214
214
  if (pinnedOrg) {
215
215
  const safe = pinnedOrg.replace(/[\x00-\x1F\x7F]/g, '');
216
- console.log(chalk.dim(`\n This terminal is pinned to: ${safe} (via JAZ_ORG)`));
216
+ console.log(muted(`\n This terminal is pinned to: ${safe} (via JAZ_ORG)`));
217
217
  }
218
218
  });
219
219
  // ── clio auth remove <label> ────────────────────────────────────
@@ -227,17 +227,17 @@ export function registerAuthCommand(program) {
227
227
  const orgs = listProfiles();
228
228
  const available = Object.keys(orgs);
229
229
  const hint = available.length > 0 ? ` Available: ${available.join(', ')}` : '';
230
- console.error(chalk.red(`Org '${label}' not found.${hint}`));
230
+ console.error(danger(`Org '${label}' not found.${hint}`));
231
231
  process.exit(1);
232
232
  }
233
233
  if (opts.json) {
234
234
  console.log(JSON.stringify({ removed: true, label }));
235
235
  }
236
236
  else {
237
- console.log(chalk.green(`Removed: ${label}`));
237
+ console.log(success(`Removed: ${label}`));
238
238
  const active = getActiveLabel();
239
239
  if (!active) {
240
- console.error(chalk.yellow('No active org. Run `clio auth switch <label>` to set one.'));
240
+ console.error(warning('No active org. Run `clio auth switch <label>` to set one.'));
241
241
  }
242
242
  }
243
243
  });
@@ -255,7 +255,7 @@ export function registerAuthCommand(program) {
255
255
  if (!entry) {
256
256
  const available = Object.keys(listProfiles());
257
257
  const hint = available.length > 0 ? ` Available: ${available.join(', ')}` : '';
258
- console.error(chalk.red(`Org '${opts.org}' not found.${hint}`));
258
+ console.error(danger(`Org '${opts.org}' not found.${hint}`));
259
259
  process.exit(1);
260
260
  }
261
261
  if (opts.json) {
@@ -276,14 +276,14 @@ export function registerAuthCommand(program) {
276
276
  }
277
277
  else {
278
278
  if (active) {
279
- console.log(chalk.bold('Label:'), active);
279
+ console.log(highlight('Label:'), active);
280
280
  }
281
- console.log(chalk.bold('Organization:'), org.name);
282
- console.log(chalk.bold('Currency:'), org.currency);
283
- console.log(chalk.bold('Country:'), org.countryCode);
284
- console.log(chalk.bold('Status:'), org.status);
281
+ console.log(highlight('Organization:'), org.name);
282
+ console.log(highlight('Currency:'), org.currency);
283
+ console.log(highlight('Country:'), org.countryCode);
284
+ console.log(highlight('Status:'), org.status);
285
285
  if (org.lockDate) {
286
- console.log(chalk.bold('Lock Date:'), org.lockDate);
286
+ console.log(highlight('Lock Date:'), org.lockDate);
287
287
  }
288
288
  if (source) {
289
289
  const sourceHuman = {
@@ -295,13 +295,13 @@ export function registerAuthCommand(program) {
295
295
  };
296
296
  const isPinned = source === 'env-org' || source === 'flag-org' || source === 'flag-api-key' || source === 'env-api-key';
297
297
  const sourceStr = sourceHuman[source] ?? source;
298
- console.log(chalk.bold('Source:'), isPinned ? chalk.green(sourceStr) : chalk.yellow(sourceStr));
298
+ console.log(highlight('Source:'), isPinned ? success(sourceStr) : warning(sourceStr));
299
299
  }
300
300
  }
301
301
  }
302
302
  catch (err) {
303
303
  const isAuthError = err.name === 'AuthError';
304
- console.error(chalk.red(`Error: ${err.message}`));
304
+ console.error(danger(`Error: ${err.message}`));
305
305
  process.exit(isAuthError ? 3 : 2);
306
306
  }
307
307
  });
@@ -323,10 +323,10 @@ export function registerAuthCommand(program) {
323
323
  console.log(JSON.stringify({ removed }));
324
324
  }
325
325
  else if (removed) {
326
- console.log(chalk.green('All credentials removed.'));
326
+ console.log(success('All credentials removed.'));
327
327
  }
328
328
  else {
329
- console.error(chalk.yellow('No credentials file found.'));
329
+ console.error(warning('No credentials file found.'));
330
330
  }
331
331
  });
332
332
  // ── clio auth shell-init ────────────────────────────────────────
@@ -348,20 +348,20 @@ export function registerAuthCommand(program) {
348
348
  }
349
349
  if (process.env.JAZ_ORG) {
350
350
  const safe = process.env.JAZ_ORG.replace(/[\x00-\x1F\x7F]/g, '');
351
- console.log(chalk.green(`Session is pinned to: ${safe}`));
352
- console.log(chalk.dim(' To unpin: eval "$(clio auth unpin --export)"'));
353
- console.log(chalk.dim(' Or simply: unset JAZ_ORG'));
351
+ console.log(success(`Session is pinned to: ${safe}`));
352
+ console.log(muted(' To unpin: eval "$(clio auth unpin --export)"'));
353
+ console.log(muted(' Or simply: unset JAZ_ORG'));
354
354
  }
355
355
  else {
356
- console.log(chalk.dim('Session is not pinned (JAZ_ORG is not set).'));
356
+ console.log(muted('Session is not pinned (JAZ_ORG is not set).'));
357
357
  }
358
358
  });
359
359
  }
360
360
  function printProfile(label, entry) {
361
- console.log(chalk.bold('Label:'), label);
362
- console.log(chalk.bold('Organization:'), entry.orgName);
363
- console.log(chalk.bold('Currency:'), entry.currency);
364
- console.log(chalk.bold('Country:'), entry.country);
361
+ console.log(highlight('Label:'), label);
362
+ console.log(highlight('Organization:'), entry.orgName);
363
+ console.log(highlight('Currency:'), entry.currency);
364
+ console.log(highlight('Country:'), entry.country);
365
365
  }
366
366
  /** Generate shell function for session auto-pinning. Works in bash and zsh. */
367
367
  function generateShellInit() {
@@ -1,4 +1,4 @@
1
- import chalk from 'chalk';
1
+ import { danger, success, muted, highlight } from './ui/theme.js';
2
2
  import { listBankRules, getBankRule, searchBankRules, createBankRule, updateBankRule, deleteBankRule, } from '../core/api/bank-rules.js';
3
3
  import { apiAction } from './api-action.js';
4
4
  import { outputList } from './output.js';
@@ -44,9 +44,9 @@ Strings are replaced with actual bank record values during reconciliation.`);
44
44
  console.log(JSON.stringify(res.data, null, 2));
45
45
  return;
46
46
  }
47
- console.log(chalk.bold('Name:'), res.data.name);
48
- console.log(chalk.bold('Action:'), res.data.actionType);
49
- console.log(chalk.bold('ID:'), res.data.resourceId);
47
+ console.log(highlight('Name:'), res.data.name);
48
+ console.log(highlight('Action:'), res.data.actionType);
49
+ console.log(highlight('ID:'), res.data.resourceId);
50
50
  })(opts));
51
51
  cmd
52
52
  .command('search <query>')
@@ -81,8 +81,8 @@ Strings are replaced with actual bank record values during reconciliation.`);
81
81
  let body = readBodyInput(opts);
82
82
  if (!body) {
83
83
  if (!opts.name || !opts.account) {
84
- console.error(chalk.red('Required: --name, --account'));
85
- console.error(chalk.dim('Or use --input <file> to provide full JSON body.'));
84
+ console.error(danger('Required: --name, --account'));
85
+ console.error(muted('Or use --input <file> to provide full JSON body.'));
86
86
  process.exit(1);
87
87
  }
88
88
  body = {
@@ -94,7 +94,7 @@ Strings are replaced with actual bank record values during reconciliation.`);
94
94
  body.configuration = JSON.parse(opts.config);
95
95
  }
96
96
  catch {
97
- console.error(chalk.red('Invalid --config JSON'));
97
+ console.error(danger('Invalid --config JSON'));
98
98
  process.exit(1);
99
99
  }
100
100
  }
@@ -105,8 +105,8 @@ Strings are replaced with actual bank record values during reconciliation.`);
105
105
  console.log(JSON.stringify(res.data, null, 2));
106
106
  return;
107
107
  }
108
- console.log(chalk.green('Bank rule created.'));
109
- console.log(chalk.bold('ID:'), res.data.resourceId);
108
+ console.log(success('Bank rule created.'));
109
+ console.log(highlight('ID:'), res.data.resourceId);
110
110
  }));
111
111
  cmd
112
112
  .command('update <resourceId>')
@@ -130,8 +130,8 @@ Strings are replaced with actual bank record values during reconciliation.`);
130
130
  // appliesToReconciliationAccount as an object (not UUID), so we can't
131
131
  // round-trip it. Require the UUID explicitly.
132
132
  if (!opts.account) {
133
- console.error(chalk.red('--account is required for update (PUT is full replacement — GET does not return the UUID)'));
134
- console.error(chalk.dim('Use: clio bank-rules update <id> --account <bank-account-uuid> [--name ...] [--config ...]'));
133
+ console.error(danger('--account is required for update (PUT is full replacement — GET does not return the UUID)'));
134
+ console.error(muted('Use: clio bank-rules update <id> --account <bank-account-uuid> [--name ...] [--config ...]'));
135
135
  process.exitCode = 1;
136
136
  return;
137
137
  }
@@ -148,7 +148,7 @@ Strings are replaced with actual bank record values during reconciliation.`);
148
148
  data.configuration = JSON.parse(opts.config);
149
149
  }
150
150
  catch {
151
- console.error(chalk.red('Invalid --config JSON'));
151
+ console.error(danger('Invalid --config JSON'));
152
152
  process.exit(1);
153
153
  }
154
154
  }
@@ -159,7 +159,7 @@ Strings are replaced with actual bank record values during reconciliation.`);
159
159
  console.log(JSON.stringify(res.data, null, 2));
160
160
  return;
161
161
  }
162
- console.log(chalk.green(`Bank rule ${resourceId} updated.`));
162
+ console.log(success(`Bank rule ${resourceId} updated.`));
163
163
  })(opts));
164
164
  cmd
165
165
  .command('delete <resourceId>')
@@ -173,6 +173,6 @@ Strings are replaced with actual bank record values during reconciliation.`);
173
173
  console.log(JSON.stringify({ deleted: true, resourceId }));
174
174
  return;
175
175
  }
176
- console.log(chalk.green(`Bank rule ${resourceId} deleted.`));
176
+ console.log(success(`Bank rule ${resourceId} deleted.`));
177
177
  })(opts));
178
178
  }
@@ -1,4 +1,4 @@
1
- import chalk from 'chalk';
1
+ import { danger, success, accent, warning, muted, highlight } from './ui/theme.js';
2
2
  import { readFileSync } from 'node:fs';
3
3
  import { basename, extname, resolve } from 'node:path';
4
4
  import { listBankAccounts, getBankAccount, searchBankRecords, addBankRecords, importBankStatement, } from '../core/api/bank.js';
@@ -31,9 +31,9 @@ export function registerBankCommand(program) {
31
31
  console.log(JSON.stringify(res, null, 2));
32
32
  }
33
33
  else {
34
- console.log(chalk.bold(`Bank Accounts (${res.data.length}):\n`));
34
+ console.log(highlight(`Bank Accounts (${res.data.length}):\n`));
35
35
  for (const a of res.data) {
36
- console.log(` ${chalk.cyan(a.resourceId)} ${a.name} ${chalk.dim(a.currencyCode)} ${a.status}`);
36
+ console.log(` ${accent(a.resourceId)} ${a.name} ${muted(a.currencyCode)} ${a.status}`);
37
37
  }
38
38
  }
39
39
  }));
@@ -51,11 +51,11 @@ export function registerBankCommand(program) {
51
51
  console.log(JSON.stringify(a, null, 2));
52
52
  }
53
53
  else {
54
- console.log(chalk.bold('Name:'), a.name);
55
- console.log(chalk.bold('ID:'), a.resourceId);
56
- console.log(chalk.bold('Account ID:'), a.accountResourceId);
57
- console.log(chalk.bold('Currency:'), a.currencyCode);
58
- console.log(chalk.bold('Status:'), a.status);
54
+ console.log(highlight('Name:'), a.name);
55
+ console.log(highlight('ID:'), a.resourceId);
56
+ console.log(highlight('Account ID:'), a.accountResourceId);
57
+ console.log(highlight('Currency:'), a.currencyCode);
58
+ console.log(highlight('Status:'), a.status);
59
59
  }
60
60
  })(opts));
61
61
  // ── clio bank records ───────────────────────────────────────────
@@ -99,14 +99,14 @@ export function registerBankCommand(program) {
99
99
  console.log('No records found.');
100
100
  return;
101
101
  }
102
- console.log(chalk.bold(`Bank Records (${res.data.length} of ${res.totalElements}):\n`));
102
+ console.log(highlight(`Bank Records (${res.data.length} of ${res.totalElements}):\n`));
103
103
  for (const r of res.data) {
104
104
  const net = typeof r.netAmount === 'number' && Number.isFinite(r.netAmount) ? r.netAmount : 0;
105
105
  const amount = net >= 0
106
- ? chalk.green(`+${net.toFixed(2)}`)
107
- : chalk.red(net.toFixed(2));
108
- const payer = r.extContactName ? ` ${chalk.yellow(r.extContactName)}` : '';
109
- console.log(` ${chalk.cyan(r.resourceId)} ${r.valueDate} ${amount} ${r.description ?? ''}${payer} ${chalk.dim(r.status)}`);
106
+ ? success(`+${net.toFixed(2)}`)
107
+ : danger(net.toFixed(2));
108
+ const payer = r.extContactName ? ` ${muted(r.extContactName)}` : '';
109
+ console.log(` ${accent(r.resourceId)} ${r.valueDate} ${amount} ${r.description ?? ''}${payer} ${muted(r.status)}`);
110
110
  }
111
111
  }
112
112
  })(opts));
@@ -139,12 +139,12 @@ export function registerBankCommand(program) {
139
139
  }
140
140
  else {
141
141
  if (errors.length > 0) {
142
- console.log(chalk.red(`${errors.length} error(s):`));
142
+ console.log(danger(`${errors.length} error(s):`));
143
143
  for (const e of errors)
144
- console.log(` ${chalk.red(String(e))}`);
144
+ console.log(` ${danger(String(e))}`);
145
145
  }
146
146
  else {
147
- console.log(chalk.green(`Created ${parsed.length} bank record(s).`));
147
+ console.log(success(`Created ${parsed.length} bank record(s).`));
148
148
  }
149
149
  }
150
150
  })(opts));
@@ -161,8 +161,8 @@ export function registerBankCommand(program) {
161
161
  .action(apiAction(async (client, opts) => {
162
162
  const recType = opts.type.toUpperCase();
163
163
  if (!RECON_TYPES.includes(recType)) {
164
- console.error(chalk.red(`Invalid --type: ${recType}`));
165
- console.error(chalk.dim(`Valid types: ${RECON_TYPES.join(', ')}`));
164
+ console.error(danger(`Invalid --type: ${recType}`));
165
+ console.error(muted(`Valid types: ${RECON_TYPES.join(', ')}`));
166
166
  process.exit(1);
167
167
  }
168
168
  try {
@@ -176,16 +176,16 @@ export function registerBankCommand(program) {
176
176
  else {
177
177
  const data = res.data;
178
178
  const count = Array.isArray(data) ? data.length : 0;
179
- console.log(chalk.bold(`Auto-Reconciliation Suggestions (${recType}): ${count} found\n`));
179
+ console.log(highlight(`Auto-Reconciliation Suggestions (${recType}): ${count} found\n`));
180
180
  if (Array.isArray(data)) {
181
181
  for (const item of data.slice(0, 50)) {
182
182
  const r = item;
183
183
  const desc = r.description ?? r.bankRecordDescription ?? '';
184
- const amount = typeof r.amount === 'number' ? chalk.dim(` $${r.amount.toFixed(2)}`) : '';
185
- console.log(` ${chalk.cyan(String(r.bankRecordResourceId ?? r.resourceId ?? '?'))} ${desc}${amount}`);
184
+ const amount = typeof r.amount === 'number' ? muted(` $${r.amount.toFixed(2)}`) : '';
185
+ console.log(` ${accent(String(r.bankRecordResourceId ?? r.resourceId ?? '?'))} ${desc}${amount}`);
186
186
  }
187
187
  if (data.length > 50)
188
- console.log(chalk.dim(` ... and ${data.length - 50} more (use --json for full output)`));
188
+ console.log(muted(` ... and ${data.length - 50} more (use --json for full output)`));
189
189
  }
190
190
  else {
191
191
  console.log(JSON.stringify(res, null, 2));
@@ -195,7 +195,7 @@ export function registerBankCommand(program) {
195
195
  catch (e) {
196
196
  const status = e.status ?? e.response?.status;
197
197
  if (status === 404) {
198
- console.error(chalk.yellow('Auto-reconciliation endpoint not available on this server.'));
198
+ console.error(warning('Auto-reconciliation endpoint not available on this server.'));
199
199
  process.exit(1);
200
200
  }
201
201
  throw e;
@@ -215,7 +215,7 @@ export function registerBankCommand(program) {
215
215
  const ext = extname(filePath).toLowerCase();
216
216
  const mime = BANK_MIME_MAP[ext];
217
217
  if (!mime) {
218
- console.error(chalk.red(`Error: unsupported file type "${ext}". Supported: ${Object.keys(BANK_MIME_MAP).join(', ')}`));
218
+ console.error(danger(`Error: unsupported file type "${ext}". Supported: ${Object.keys(BANK_MIME_MAP).join(', ')}`));
219
219
  process.exit(1);
220
220
  }
221
221
  const buffer = readFileSync(filePath);
@@ -231,9 +231,9 @@ export function registerBankCommand(program) {
231
231
  console.log(JSON.stringify(res.data, null, 2));
232
232
  }
233
233
  else {
234
- console.log(chalk.green('Bank statement uploaded — processing started.'));
235
- console.log(chalk.bold('File:'), fileName);
236
- console.log(chalk.dim('Check status: clio magic search --type bank-statement'));
234
+ console.log(success('Bank statement uploaded — processing started.'));
235
+ console.log(highlight('File:'), fileName);
236
+ console.log(muted('Check status: clio magic search --type bank-statement'));
237
237
  }
238
238
  }));
239
239
  }