jaz-clio 4.34.6 → 4.35.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/skills/api/SKILL.md +1 -1
- package/assets/skills/cli/SKILL.md +1 -1
- package/assets/skills/conversion/SKILL.md +1 -1
- package/assets/skills/jobs/SKILL.md +1 -1
- package/assets/skills/transaction-recipes/SKILL.md +1 -1
- package/dist/commands/accounts.js +6 -6
- package/dist/commands/api-action.js +22 -22
- package/dist/commands/attachments.js +8 -8
- package/dist/commands/auth.js +50 -48
- package/dist/commands/bank-rules.js +14 -14
- package/dist/commands/bank.js +27 -27
- package/dist/commands/bills.js +35 -35
- package/dist/commands/bookmarks.js +8 -8
- package/dist/commands/calc.js +2 -2
- package/dist/commands/capsules.js +14 -14
- package/dist/commands/cash-entry.js +16 -16
- package/dist/commands/cash-transfer.js +4 -4
- package/dist/commands/cashflow.js +2 -2
- package/dist/commands/contact-groups.js +10 -10
- package/dist/commands/contacts.js +14 -14
- package/dist/commands/currencies.js +2 -2
- package/dist/commands/currency-rates.js +8 -8
- package/dist/commands/custom-fields.js +12 -12
- package/dist/commands/customer-credit-notes.js +30 -30
- package/dist/commands/draft-helpers.js +12 -12
- package/dist/commands/exports.js +4 -4
- package/dist/commands/fixed-assets.js +23 -23
- package/dist/commands/format-helpers.js +28 -14
- package/dist/commands/help-examples.js +2 -2
- package/dist/commands/init.js +26 -28
- package/dist/commands/inventory.js +7 -7
- package/dist/commands/invoices.js +36 -36
- package/dist/commands/items.js +11 -11
- package/dist/commands/jobs.js +80 -78
- package/dist/commands/journals.js +27 -27
- package/dist/commands/kb.js +6 -6
- package/dist/commands/magic.js +44 -46
- package/dist/commands/nano-classifiers.js +8 -8
- package/dist/commands/org-users.js +5 -5
- package/dist/commands/org.js +8 -8
- package/dist/commands/output.js +5 -4
- package/dist/commands/pagination.js +10 -18
- package/dist/commands/parsers.js +20 -20
- package/dist/commands/payments.js +9 -9
- package/dist/commands/picker.js +38 -59
- package/dist/commands/quick-fix.js +8 -8
- package/dist/commands/recipe.js +16 -16
- package/dist/commands/reports.js +11 -11
- package/dist/commands/resolve.js +8 -8
- package/dist/commands/schedulers.js +25 -25
- package/dist/commands/schema.js +15 -24
- package/dist/commands/search.js +4 -4
- package/dist/commands/subscriptions.js +17 -17
- package/dist/commands/supplier-credit-notes.js +28 -28
- package/dist/commands/table-formatter.js +3 -82
- package/dist/commands/tags.js +10 -10
- package/dist/commands/tax-profiles.js +11 -11
- package/dist/commands/ui/banner.js +21 -0
- package/dist/commands/ui/error.js +96 -0
- package/dist/commands/ui/index.js +7 -0
- package/dist/commands/ui/progress.js +32 -0
- package/dist/commands/ui/record.js +72 -0
- package/dist/commands/ui/table.js +109 -0
- package/dist/commands/ui/theme.js +55 -0
- package/dist/commands/update.js +2 -2
- package/dist/commands/versions.js +3 -3
- package/dist/core/calc/format.js +126 -126
- package/dist/core/jobs/document-collection/tools/ingest/format.js +25 -25
- package/dist/core/jobs/format.js +23 -23
- package/dist/core/jobs/payment-run/tools/bank-file/format.js +7 -7
- package/dist/core/jobs/payment-run/tools/outstanding/format.js +9 -9
- package/dist/core/jobs/statutory-filing/tools/sg-tax/format-sg.js +19 -19
- package/dist/core/registry/tools.js +0 -2
- package/dist/index.js +30 -31
- package/dist/utils/logger.js +17 -7
- package/package.json +4 -3
|
@@ -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(
|
|
78
|
-
console.log(
|
|
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(
|
|
109
|
-
console.log(
|
|
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(
|
|
125
|
+
console.log(success(`Account ${resourceId} deleted.`));
|
|
126
126
|
}
|
|
127
127
|
})(opts));
|
|
128
128
|
}
|
|
@@ -1,15 +1,23 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
1
|
import { JazClient, JazApiError } from '../core/api/client.js';
|
|
3
2
|
import { requireAuth, AuthError, resolvedProfileLabel, resolvedAuthSource, getProfile, listProfiles } from '../core/auth/index.js';
|
|
4
3
|
import { isMachineFormat } from './output.js';
|
|
4
|
+
import { renderOrgBanner } from './ui/banner.js';
|
|
5
|
+
import { formatApiError, formatAuthError, formatGenericError } from './ui/error.js';
|
|
5
6
|
/**
|
|
6
7
|
* Shared action wrapper for all online CLI commands.
|
|
7
|
-
* Handles auth resolution, client creation, org banner, and error formatting.
|
|
8
|
+
* Handles auth resolution, client creation, org banner, spinner, and error formatting.
|
|
8
9
|
*
|
|
9
10
|
* Exit codes: 1 = validation, 2 = API error, 3 = auth error.
|
|
10
11
|
*/
|
|
11
12
|
export function apiAction(fn) {
|
|
12
13
|
return async (opts) => {
|
|
14
|
+
let spinner;
|
|
15
|
+
// Hoist machine flag — computed once, safe to use in catch even if resolveFormat would throw
|
|
16
|
+
let machine = false;
|
|
17
|
+
try {
|
|
18
|
+
machine = isMachineFormat(opts);
|
|
19
|
+
}
|
|
20
|
+
catch { /* --json + --format conflict — treat as human mode for error display */ }
|
|
13
21
|
try {
|
|
14
22
|
// Conflict check: --api-key and --org are mutually exclusive
|
|
15
23
|
if (opts.apiKey && opts.org) {
|
|
@@ -17,9 +25,8 @@ export function apiAction(fn) {
|
|
|
17
25
|
}
|
|
18
26
|
const auth = requireAuth(opts.apiKey);
|
|
19
27
|
const client = new JazClient(auth);
|
|
20
|
-
// Org banner —
|
|
21
|
-
|
|
22
|
-
if (!isMachineFormat(opts)) {
|
|
28
|
+
// Org banner — stderr, suppressed in machine formats
|
|
29
|
+
if (!machine) {
|
|
23
30
|
const label = resolvedProfileLabel();
|
|
24
31
|
if (label) {
|
|
25
32
|
const entry = getProfile(label);
|
|
@@ -31,43 +38,36 @@ export function apiAction(fn) {
|
|
|
31
38
|
orgCount = Object.keys(listProfiles() ?? {}).length;
|
|
32
39
|
}
|
|
33
40
|
catch { /* best-effort */ }
|
|
34
|
-
|
|
35
|
-
// UNPINNED multi-org: prominent yellow warning
|
|
36
|
-
process.stderr.write(chalk.yellow(` \u26A0 ${label} \u00B7 ${entry.orgName} (${entry.currency})`) +
|
|
37
|
-
chalk.dim(` \u2014 not pinned to this terminal\n`) +
|
|
38
|
-
chalk.dim(` Pin: export JAZ_ORG=${label} or --org ${label}\n`));
|
|
39
|
-
}
|
|
40
|
-
else {
|
|
41
|
-
// Pinned or single-org: normal dim banner
|
|
42
|
-
process.stderr.write(chalk.dim(` \u25B8 ${label} \u00B7 ${entry.orgName} (${entry.currency})\n`));
|
|
43
|
-
}
|
|
41
|
+
renderOrgBanner({ label, orgName: entry.orgName, currency: entry.currency }, isPinned, orgCount > 1);
|
|
44
42
|
}
|
|
45
43
|
}
|
|
46
44
|
}
|
|
47
45
|
await fn(client, opts, auth);
|
|
48
46
|
}
|
|
49
47
|
catch (err) {
|
|
50
|
-
const machine = isMachineFormat(opts);
|
|
51
48
|
if (err instanceof AuthError) {
|
|
52
49
|
if (machine)
|
|
53
|
-
console.
|
|
50
|
+
console.error(JSON.stringify({ error: { code: 'AUTH_ERROR', message: err.message } }));
|
|
54
51
|
else
|
|
55
|
-
console.error(
|
|
52
|
+
console.error(formatAuthError(err.message));
|
|
56
53
|
process.exit(3);
|
|
57
54
|
}
|
|
58
55
|
if (err instanceof JazApiError) {
|
|
59
56
|
if (machine)
|
|
60
|
-
console.
|
|
57
|
+
console.error(JSON.stringify({ error: { code: 'API_ERROR', status: err.status, message: err.message } }));
|
|
61
58
|
else
|
|
62
|
-
console.error(
|
|
59
|
+
console.error(formatApiError(err.status, err.message, err.endpoint));
|
|
63
60
|
process.exit(2);
|
|
64
61
|
}
|
|
65
62
|
const message = err.message;
|
|
66
63
|
if (machine)
|
|
67
|
-
console.
|
|
64
|
+
console.error(JSON.stringify({ error: { code: 'UNKNOWN_ERROR', message } }));
|
|
68
65
|
else
|
|
69
|
-
console.error(
|
|
66
|
+
console.error(formatGenericError(message));
|
|
70
67
|
process.exit(2);
|
|
71
68
|
}
|
|
69
|
+
finally {
|
|
70
|
+
spinner?.stop();
|
|
71
|
+
}
|
|
72
72
|
};
|
|
73
73
|
}
|
|
@@ -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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
135
|
+
console.log(success('Attachment deleted.'));
|
|
136
136
|
}
|
|
137
137
|
})(rawOpts);
|
|
138
138
|
});
|
package/dist/commands/auth.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
1
|
+
import { danger, success, warning, muted, highlight } from './ui/theme.js';
|
|
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';
|
|
5
5
|
import { getOrganization } from '../core/api/organization.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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
86
|
+
console.log(muted(` Active org set to ${label}`));
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
}
|
|
@@ -108,35 +108,37 @@ 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(
|
|
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(
|
|
118
|
+
console.error(danger('Error: --json and --export require a label argument.'));
|
|
119
|
+
process.exit(1);
|
|
120
|
+
}
|
|
121
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
122
|
+
console.error(danger('Error: interactive picker requires a TTY. Provide a label argument.'));
|
|
119
123
|
process.exit(1);
|
|
120
124
|
}
|
|
121
125
|
const active = getActiveLabel();
|
|
122
|
-
const
|
|
123
|
-
type: 'select',
|
|
124
|
-
name: 'label',
|
|
126
|
+
const selected = await p.select({
|
|
125
127
|
message: 'Switch to:',
|
|
126
|
-
|
|
127
|
-
|
|
128
|
+
options: labels.map(l => ({
|
|
129
|
+
label: `${l === active ? '\u2605 ' : ' '}${l} \u2014 ${orgs[l].orgName} (${orgs[l].currency})`,
|
|
128
130
|
value: l,
|
|
129
131
|
})),
|
|
130
132
|
});
|
|
131
|
-
if (
|
|
133
|
+
if (p.isCancel(selected))
|
|
132
134
|
return; // User cancelled
|
|
133
|
-
target =
|
|
135
|
+
target = selected;
|
|
134
136
|
}
|
|
135
137
|
try {
|
|
136
138
|
setActiveLabel(target);
|
|
137
139
|
}
|
|
138
140
|
catch (err) {
|
|
139
|
-
console.error(
|
|
141
|
+
console.error(danger(err.message));
|
|
140
142
|
process.exit(1);
|
|
141
143
|
}
|
|
142
144
|
const entry = orgs[target];
|
|
@@ -149,10 +151,10 @@ export function registerAuthCommand(program) {
|
|
|
149
151
|
console.log(JSON.stringify({ switched: true, label: target, orgName: entry.orgName, currency: entry.currency }));
|
|
150
152
|
}
|
|
151
153
|
else {
|
|
152
|
-
console.log(
|
|
154
|
+
console.log(success(`Switched to: ${target} \u2014 ${entry.orgName} (${entry.currency}, ${entry.country})`));
|
|
153
155
|
if (labels.length > 1) {
|
|
154
|
-
console.log(
|
|
155
|
-
console.log(
|
|
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)"`));
|
|
156
158
|
}
|
|
157
159
|
}
|
|
158
160
|
});
|
|
@@ -197,13 +199,13 @@ export function registerAuthCommand(program) {
|
|
|
197
199
|
}
|
|
198
200
|
const labels = Object.keys(orgs);
|
|
199
201
|
if (labels.length === 0) {
|
|
200
|
-
console.error(
|
|
202
|
+
console.error(warning('No orgs registered. Run `clio auth add <key>` to get started.'));
|
|
201
203
|
return;
|
|
202
204
|
}
|
|
203
205
|
for (const label of labels) {
|
|
204
206
|
const entry = orgs[label];
|
|
205
|
-
const marker = label === active ?
|
|
206
|
-
const labelStr = label === active ?
|
|
207
|
+
const marker = label === active ? warning('\u2605') : ' ';
|
|
208
|
+
const labelStr = label === active ? highlight(label) : label;
|
|
207
209
|
const countryStr = entry.country ? ` ${entry.country}` : '';
|
|
208
210
|
console.log(` ${marker} ${labelStr.padEnd(18)} ${entry.orgName.padEnd(22)} ${entry.currency}${countryStr}`);
|
|
209
211
|
}
|
|
@@ -211,7 +213,7 @@ export function registerAuthCommand(program) {
|
|
|
211
213
|
const pinnedOrg = process.env.JAZ_ORG;
|
|
212
214
|
if (pinnedOrg) {
|
|
213
215
|
const safe = pinnedOrg.replace(/[\x00-\x1F\x7F]/g, '');
|
|
214
|
-
console.log(
|
|
216
|
+
console.log(muted(`\n This terminal is pinned to: ${safe} (via JAZ_ORG)`));
|
|
215
217
|
}
|
|
216
218
|
});
|
|
217
219
|
// ── clio auth remove <label> ────────────────────────────────────
|
|
@@ -225,17 +227,17 @@ export function registerAuthCommand(program) {
|
|
|
225
227
|
const orgs = listProfiles();
|
|
226
228
|
const available = Object.keys(orgs);
|
|
227
229
|
const hint = available.length > 0 ? ` Available: ${available.join(', ')}` : '';
|
|
228
|
-
console.error(
|
|
230
|
+
console.error(danger(`Org '${label}' not found.${hint}`));
|
|
229
231
|
process.exit(1);
|
|
230
232
|
}
|
|
231
233
|
if (opts.json) {
|
|
232
234
|
console.log(JSON.stringify({ removed: true, label }));
|
|
233
235
|
}
|
|
234
236
|
else {
|
|
235
|
-
console.log(
|
|
237
|
+
console.log(success(`Removed: ${label}`));
|
|
236
238
|
const active = getActiveLabel();
|
|
237
239
|
if (!active) {
|
|
238
|
-
console.error(
|
|
240
|
+
console.error(warning('No active org. Run `clio auth switch <label>` to set one.'));
|
|
239
241
|
}
|
|
240
242
|
}
|
|
241
243
|
});
|
|
@@ -253,7 +255,7 @@ export function registerAuthCommand(program) {
|
|
|
253
255
|
if (!entry) {
|
|
254
256
|
const available = Object.keys(listProfiles());
|
|
255
257
|
const hint = available.length > 0 ? ` Available: ${available.join(', ')}` : '';
|
|
256
|
-
console.error(
|
|
258
|
+
console.error(danger(`Org '${opts.org}' not found.${hint}`));
|
|
257
259
|
process.exit(1);
|
|
258
260
|
}
|
|
259
261
|
if (opts.json) {
|
|
@@ -274,14 +276,14 @@ export function registerAuthCommand(program) {
|
|
|
274
276
|
}
|
|
275
277
|
else {
|
|
276
278
|
if (active) {
|
|
277
|
-
console.log(
|
|
279
|
+
console.log(highlight('Label:'), active);
|
|
278
280
|
}
|
|
279
|
-
console.log(
|
|
280
|
-
console.log(
|
|
281
|
-
console.log(
|
|
282
|
-
console.log(
|
|
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);
|
|
283
285
|
if (org.lockDate) {
|
|
284
|
-
console.log(
|
|
286
|
+
console.log(highlight('Lock Date:'), org.lockDate);
|
|
285
287
|
}
|
|
286
288
|
if (source) {
|
|
287
289
|
const sourceHuman = {
|
|
@@ -293,13 +295,13 @@ export function registerAuthCommand(program) {
|
|
|
293
295
|
};
|
|
294
296
|
const isPinned = source === 'env-org' || source === 'flag-org' || source === 'flag-api-key' || source === 'env-api-key';
|
|
295
297
|
const sourceStr = sourceHuman[source] ?? source;
|
|
296
|
-
console.log(
|
|
298
|
+
console.log(highlight('Source:'), isPinned ? success(sourceStr) : warning(sourceStr));
|
|
297
299
|
}
|
|
298
300
|
}
|
|
299
301
|
}
|
|
300
302
|
catch (err) {
|
|
301
303
|
const isAuthError = err.name === 'AuthError';
|
|
302
|
-
console.error(
|
|
304
|
+
console.error(danger(`Error: ${err.message}`));
|
|
303
305
|
process.exit(isAuthError ? 3 : 2);
|
|
304
306
|
}
|
|
305
307
|
});
|
|
@@ -321,10 +323,10 @@ export function registerAuthCommand(program) {
|
|
|
321
323
|
console.log(JSON.stringify({ removed }));
|
|
322
324
|
}
|
|
323
325
|
else if (removed) {
|
|
324
|
-
console.log(
|
|
326
|
+
console.log(success('All credentials removed.'));
|
|
325
327
|
}
|
|
326
328
|
else {
|
|
327
|
-
console.error(
|
|
329
|
+
console.error(warning('No credentials file found.'));
|
|
328
330
|
}
|
|
329
331
|
});
|
|
330
332
|
// ── clio auth shell-init ────────────────────────────────────────
|
|
@@ -346,20 +348,20 @@ export function registerAuthCommand(program) {
|
|
|
346
348
|
}
|
|
347
349
|
if (process.env.JAZ_ORG) {
|
|
348
350
|
const safe = process.env.JAZ_ORG.replace(/[\x00-\x1F\x7F]/g, '');
|
|
349
|
-
console.log(
|
|
350
|
-
console.log(
|
|
351
|
-
console.log(
|
|
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'));
|
|
352
354
|
}
|
|
353
355
|
else {
|
|
354
|
-
console.log(
|
|
356
|
+
console.log(muted('Session is not pinned (JAZ_ORG is not set).'));
|
|
355
357
|
}
|
|
356
358
|
});
|
|
357
359
|
}
|
|
358
360
|
function printProfile(label, entry) {
|
|
359
|
-
console.log(
|
|
360
|
-
console.log(
|
|
361
|
-
console.log(
|
|
362
|
-
console.log(
|
|
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);
|
|
363
365
|
}
|
|
364
366
|
/** Generate shell function for session auto-pinning. Works in bash and zsh. */
|
|
365
367
|
function generateShellInit() {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
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(
|
|
48
|
-
console.log(
|
|
49
|
-
console.log(
|
|
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(
|
|
85
|
-
console.error(
|
|
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(
|
|
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(
|
|
109
|
-
console.log(
|
|
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(
|
|
134
|
-
console.error(
|
|
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(
|
|
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(
|
|
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(
|
|
176
|
+
console.log(success(`Bank rule ${resourceId} deleted.`));
|
|
177
177
|
})(opts));
|
|
178
178
|
}
|