jaz-clio 4.25.4 → 4.25.6
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/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/attachments.js +15 -10
- package/dist/commands/auth.js +23 -0
- package/dist/commands/bookmarks.js +11 -13
- package/dist/commands/org-users.js +20 -30
- package/dist/commands/tax-profiles.js +19 -41
- package/dist/core/registry/tools.js +78 -35
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: jaz-api
|
|
3
|
-
version: 4.25.
|
|
3
|
+
version: 4.25.6
|
|
4
4
|
description: Complete reference for the Jaz REST API — the accounting platform backend. Use this skill whenever building, modifying, debugging, or extending any code that calls the API — including API clients, integrations, data seeding, test data, or new endpoint work. Contains every field name, response shape, error, gotcha, and edge case discovered through live production testing.
|
|
5
5
|
license: MIT
|
|
6
6
|
compatibility: Requires Jaz API key (x-jk-api-key header). Works with Claude Code, Google Antigravity, OpenAI Codex, GitHub Copilot, Cursor, and any agent that reads markdown.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: jaz-conversion
|
|
3
|
-
version: 4.25.
|
|
3
|
+
version: 4.25.6
|
|
4
4
|
description: Accounting data conversion skill — migrates customer data from Xero, QuickBooks, Sage, MYOB, and Excel exports to Jaz. Covers config, quick, and full conversion workflows, Excel parsing, CoA/contact/tax/items mapping, clearing accounts, TTB, and TB verification.
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: jaz-jobs
|
|
3
|
-
version: 4.25.
|
|
3
|
+
version: 4.25.6
|
|
4
4
|
description: 12 accounting jobs for SMB bookkeepers and accountants — month-end, quarter-end, and year-end close playbooks plus 9 ad-hoc operational jobs (bank recon, document collection, GST/VAT filing, payment runs, credit control, supplier recon, audit prep, fixed asset review, statutory filing). Jobs can have paired tools as nested subcommands (e.g., `clio jobs bank-recon match`, `clio jobs document-collection ingest`, `clio jobs statutory-filing sg-cs`). Paired with an interactive CLI blueprint generator (clio jobs).
|
|
5
5
|
license: MIT
|
|
6
6
|
compatibility: Works with Claude Code, Claude Cowork, Claude.ai, and any agent that reads markdown. For API payloads, load the jaz-api skill. For individual transaction patterns, load the jaz-recipes skill.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: jaz-recipes
|
|
3
|
-
version: 4.25.
|
|
3
|
+
version: 4.25.6
|
|
4
4
|
description: 16 IFRS-compliant recipes for complex multi-step accounting in Jaz — prepaid amortization, deferred revenue, loan schedules, IFRS 16 leases, hire purchase, fixed deposits, asset disposal, FX revaluation, ECL provisioning, IAS 37 provisions, dividends, intercompany, and capital WIP. Each recipe includes journal entries, capsule structure, and verification steps. Paired with 13 financial calculators that produce execution-ready blueprints with workings.
|
|
5
5
|
license: MIT
|
|
6
6
|
compatibility: Works with Claude Code, Claude Cowork, Claude.ai, and any agent that reads markdown. For API payloads, load the jaz-api skill alongside this one.
|
|
@@ -3,6 +3,12 @@ import { readFileSync } from 'node:fs';
|
|
|
3
3
|
import { basename, extname, resolve } from 'node:path';
|
|
4
4
|
import { listAttachments, addAttachment, fetchAttachmentTable } from '../core/api/attachments.js';
|
|
5
5
|
import { apiAction } from './api-action.js';
|
|
6
|
+
import { outputList } from './output.js';
|
|
7
|
+
import { formatId } from './format-helpers.js';
|
|
8
|
+
const ATTACHMENTS_COLUMNS = [
|
|
9
|
+
{ key: 'resourceId', header: 'ID', format: formatId },
|
|
10
|
+
{ key: 'fileName', header: 'File Name' },
|
|
11
|
+
];
|
|
6
12
|
const BT_TYPES = ['invoices', 'bills', 'journals', 'scheduled_journals', 'customer-credit-notes', 'supplier-credit-notes'];
|
|
7
13
|
const ATTACHMENT_MIME_MAP = {
|
|
8
14
|
'.pdf': 'application/pdf',
|
|
@@ -27,6 +33,7 @@ export function registerAttachmentsCommand(program) {
|
|
|
27
33
|
.requiredOption('--type <type>', `Transaction type (${BT_TYPES.join(', ')})`)
|
|
28
34
|
.requiredOption('--id <resourceId>', 'Transaction resourceId')
|
|
29
35
|
.option('--api-key <key>', 'API key')
|
|
36
|
+
.option('--format <type>', 'Output format: table, json, csv, yaml')
|
|
30
37
|
.option('--json', 'Output as JSON')
|
|
31
38
|
.action(apiAction(async (client, opts) => {
|
|
32
39
|
const btType = opts.type;
|
|
@@ -35,16 +42,14 @@ export function registerAttachmentsCommand(program) {
|
|
|
35
42
|
process.exit(1);
|
|
36
43
|
}
|
|
37
44
|
const result = await listAttachments(client, btType, opts.id);
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
}
|
|
45
|
+
const items = result.data ?? [];
|
|
46
|
+
const wrapped = {
|
|
47
|
+
data: items,
|
|
48
|
+
totalElements: result.totalElements ?? items.length, // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
49
|
+
totalPages: result.totalPages ?? 1, // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
50
|
+
truncated: result.truncated ?? false, // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
51
|
+
};
|
|
52
|
+
outputList(wrapped, ATTACHMENTS_COLUMNS, opts, 'Attachments'); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
48
53
|
}));
|
|
49
54
|
// ── clio attachments add ───────────────────────────────────────
|
|
50
55
|
attachments
|
package/dist/commands/auth.js
CHANGED
|
@@ -3,6 +3,7 @@ import prompts from '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';
|
|
6
|
+
import { outputList } from './output.js';
|
|
6
7
|
/** Escape a string for safe use in shell export statements. */
|
|
7
8
|
function shellEscape(s) {
|
|
8
9
|
if (/^[a-zA-Z0-9_-]+$/.test(s))
|
|
@@ -159,10 +160,12 @@ export function registerAuthCommand(program) {
|
|
|
159
160
|
auth
|
|
160
161
|
.command('list')
|
|
161
162
|
.description('List all registered orgs')
|
|
163
|
+
.option('--format <type>', 'Output format: table, json, csv, yaml')
|
|
162
164
|
.option('--json', 'Output as JSON')
|
|
163
165
|
.action((opts) => {
|
|
164
166
|
const orgs = listProfiles();
|
|
165
167
|
const active = getActiveLabel();
|
|
168
|
+
// Preserve original --json envelope (backwards compat)
|
|
166
169
|
if (opts.json) {
|
|
167
170
|
const entries = Object.entries(orgs).map(([label, entry]) => ({
|
|
168
171
|
label,
|
|
@@ -172,6 +175,26 @@ export function registerAuthCommand(program) {
|
|
|
172
175
|
console.log(JSON.stringify({ active, orgs: entries }, null, 2));
|
|
173
176
|
return;
|
|
174
177
|
}
|
|
178
|
+
// --format (table/csv/yaml) via outputList
|
|
179
|
+
if (opts.format) {
|
|
180
|
+
const entries = Object.entries(orgs).map(([label, entry]) => ({
|
|
181
|
+
label,
|
|
182
|
+
active: label === active,
|
|
183
|
+
orgName: entry.orgName,
|
|
184
|
+
currency: entry.currency,
|
|
185
|
+
country: entry.country,
|
|
186
|
+
}));
|
|
187
|
+
const columns = [
|
|
188
|
+
{ key: 'label', header: 'Label' },
|
|
189
|
+
{ key: 'active', header: 'Active' },
|
|
190
|
+
{ key: 'orgName', header: 'Org Name' },
|
|
191
|
+
{ key: 'currency', header: 'Currency' },
|
|
192
|
+
{ key: 'country', header: 'Country' },
|
|
193
|
+
];
|
|
194
|
+
const wrapped = { data: entries, totalElements: entries.length, totalPages: 1, truncated: false }; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
195
|
+
outputList(wrapped, columns, opts, 'Auth Profiles');
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
175
198
|
const labels = Object.keys(orgs);
|
|
176
199
|
if (labels.length === 0) {
|
|
177
200
|
console.error(chalk.yellow('No orgs registered. Run `clio auth add <key>` to get started.'));
|
|
@@ -2,7 +2,15 @@ import chalk from 'chalk';
|
|
|
2
2
|
import { listBookmarks, getBookmark, createBookmarks, updateBookmark, } from '../core/api/bookmarks.js';
|
|
3
3
|
import { apiAction } from './api-action.js';
|
|
4
4
|
import { parsePositiveInt, parseNonNegativeInt, readBodyInput, requireFields } from './parsers.js';
|
|
5
|
-
import { paginatedFetch
|
|
5
|
+
import { paginatedFetch } from './pagination.js';
|
|
6
|
+
import { outputList } from './output.js';
|
|
7
|
+
import { formatId } from './format-helpers.js';
|
|
8
|
+
const BOOKMARKS_COLUMNS = [
|
|
9
|
+
{ key: 'resourceId', header: 'ID', format: formatId },
|
|
10
|
+
{ key: 'name', header: 'Name' },
|
|
11
|
+
{ key: 'categoryCode', header: 'Category' },
|
|
12
|
+
{ key: 'value', header: 'Value' },
|
|
13
|
+
];
|
|
6
14
|
export function registerBookmarksCommand(program) {
|
|
7
15
|
const bm = program
|
|
8
16
|
.command('bookmarks')
|
|
@@ -16,21 +24,11 @@ export function registerBookmarksCommand(program) {
|
|
|
16
24
|
.option('--all', 'Fetch all pages')
|
|
17
25
|
.option('--max-rows <n>', 'Max rows for --all (default 10000)', parsePositiveInt)
|
|
18
26
|
.option('--api-key <key>', 'API key (overrides stored/env)')
|
|
27
|
+
.option('--format <type>', 'Output format: table, json, csv, yaml')
|
|
19
28
|
.option('--json', 'Output as JSON')
|
|
20
29
|
.action(apiAction(async (client, opts) => {
|
|
21
30
|
const result = await paginatedFetch(opts, (p) => listBookmarks(client, p), { label: 'Fetching bookmarks' });
|
|
22
|
-
|
|
23
|
-
console.log(paginatedJson(result, opts));
|
|
24
|
-
}
|
|
25
|
-
else {
|
|
26
|
-
console.log(chalk.bold(`Bookmarks (${result.data.length} of ${result.totalElements}):\n`));
|
|
27
|
-
const { items, overflow } = displaySlice(result.data);
|
|
28
|
-
for (const b of items) {
|
|
29
|
-
console.log(` ${chalk.cyan(b.resourceId)} ${b.name} ${chalk.dim(b.categoryCode)} ${b.value}`);
|
|
30
|
-
}
|
|
31
|
-
if (overflow > 0)
|
|
32
|
-
console.log(chalk.dim(` ... and ${overflow.toLocaleString()} more (use --json for full output)`));
|
|
33
|
-
}
|
|
31
|
+
outputList(result, BOOKMARKS_COLUMNS, opts, 'Bookmarks'); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
34
32
|
}));
|
|
35
33
|
// ── clio bookmarks get ────────────────────────────────────────
|
|
36
34
|
bm
|
|
@@ -2,7 +2,22 @@ import chalk from 'chalk';
|
|
|
2
2
|
import { listOrgUsers, searchOrgUsers, inviteOrgUser, updateOrgUser, removeOrgUser, } from '../core/api/org-users.js';
|
|
3
3
|
import { apiAction } from './api-action.js';
|
|
4
4
|
import { parsePositiveInt, parseNonNegativeInt, readBodyInput, requireFields } from './parsers.js';
|
|
5
|
-
import { paginatedFetch
|
|
5
|
+
import { paginatedFetch } from './pagination.js';
|
|
6
|
+
import { outputList } from './output.js';
|
|
7
|
+
import { formatId } from './format-helpers.js';
|
|
8
|
+
const ORG_USERS_COLUMNS = [
|
|
9
|
+
{ key: 'resourceId', header: 'ID', format: formatId },
|
|
10
|
+
{ key: 'firstName', header: 'First Name' },
|
|
11
|
+
{ key: 'lastName', header: 'Last Name' },
|
|
12
|
+
{ key: 'email', header: 'Email' },
|
|
13
|
+
{
|
|
14
|
+
key: 'moduleRoles',
|
|
15
|
+
header: 'Roles',
|
|
16
|
+
format: (roles) => Array.isArray(roles)
|
|
17
|
+
? roles.map((r) => `${r.moduleName}:${r.roleCode}`).join(', ')
|
|
18
|
+
: String(roles ?? ''),
|
|
19
|
+
},
|
|
20
|
+
];
|
|
6
21
|
export function registerOrgUsersCommand(program) {
|
|
7
22
|
const ou = program
|
|
8
23
|
.command('org-users')
|
|
@@ -16,22 +31,11 @@ export function registerOrgUsersCommand(program) {
|
|
|
16
31
|
.option('--all', 'Fetch all pages')
|
|
17
32
|
.option('--max-rows <n>', 'Max rows for --all (default 10000)', parsePositiveInt)
|
|
18
33
|
.option('--api-key <key>', 'API key (overrides stored/env)')
|
|
34
|
+
.option('--format <type>', 'Output format: table, json, csv, yaml')
|
|
19
35
|
.option('--json', 'Output as JSON')
|
|
20
36
|
.action(apiAction(async (client, opts) => {
|
|
21
37
|
const result = await paginatedFetch(opts, (p) => listOrgUsers(client, p), { label: 'Fetching org users' });
|
|
22
|
-
|
|
23
|
-
console.log(paginatedJson(result, opts));
|
|
24
|
-
}
|
|
25
|
-
else {
|
|
26
|
-
console.log(chalk.bold(`Org Users (${result.data.length} of ${result.totalElements}):\n`));
|
|
27
|
-
const { items, overflow } = displaySlice(result.data);
|
|
28
|
-
for (const u of items) {
|
|
29
|
-
const roles = u.moduleRoles.map((r) => `${r.moduleName}:${r.roleCode}`).join(', ');
|
|
30
|
-
console.log(` ${chalk.cyan(u.resourceId)} ${u.firstName} ${u.lastName} ${chalk.dim(u.email)} ${roles}`);
|
|
31
|
-
}
|
|
32
|
-
if (overflow > 0)
|
|
33
|
-
console.log(chalk.dim(` ... and ${overflow.toLocaleString()} more (use --json for full output)`));
|
|
34
|
-
}
|
|
38
|
+
outputList(result, ORG_USERS_COLUMNS, opts, 'Org Users'); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
35
39
|
}));
|
|
36
40
|
// ── clio org-users search ─────────────────────────────────────
|
|
37
41
|
ou
|
|
@@ -44,6 +48,7 @@ export function registerOrgUsersCommand(program) {
|
|
|
44
48
|
.option('--all', 'Fetch all pages')
|
|
45
49
|
.option('--max-rows <n>', 'Max rows for --all (default 10000)', parsePositiveInt)
|
|
46
50
|
.option('--api-key <key>', 'API key (overrides stored/env)')
|
|
51
|
+
.option('--format <type>', 'Output format: table, json, csv, yaml')
|
|
47
52
|
.option('--json', 'Output as JSON')
|
|
48
53
|
.action((query, opts) => apiAction(async (client) => {
|
|
49
54
|
const filter = {
|
|
@@ -55,22 +60,7 @@ export function registerOrgUsersCommand(program) {
|
|
|
55
60
|
};
|
|
56
61
|
const sort = { sortBy: [opts.sort ?? 'firstName'], order: (opts.order ?? 'ASC') };
|
|
57
62
|
const result = await paginatedFetch(opts, ({ limit, offset }) => searchOrgUsers(client, { filter, limit, offset, sort }), { label: 'Searching org users', defaultLimit: 20 });
|
|
58
|
-
|
|
59
|
-
console.log(paginatedJson(result, opts));
|
|
60
|
-
}
|
|
61
|
-
else {
|
|
62
|
-
if (result.data.length === 0) {
|
|
63
|
-
console.log('No users found.');
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
console.log(chalk.bold(`Found ${result.data.length} user(s):\n`));
|
|
67
|
-
const { items, overflow } = displaySlice(result.data);
|
|
68
|
-
for (const u of items) {
|
|
69
|
-
console.log(` ${chalk.cyan(u.resourceId)} ${u.firstName} ${u.lastName} ${chalk.dim(u.email)}`);
|
|
70
|
-
}
|
|
71
|
-
if (overflow > 0)
|
|
72
|
-
console.log(chalk.dim(` ... and ${overflow.toLocaleString()} more (use --json for full output)`));
|
|
73
|
-
}
|
|
63
|
+
outputList(result, ORG_USERS_COLUMNS, opts, 'Org Users'); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
74
64
|
})(opts));
|
|
75
65
|
// ── clio org-users invite ─────────────────────────────────────
|
|
76
66
|
ou
|
|
@@ -2,7 +2,19 @@ import chalk from 'chalk';
|
|
|
2
2
|
import { listTaxProfiles, listTaxTypes, createTaxProfile, getTaxProfile, searchTaxProfiles, updateTaxProfile, listWithholdingTaxCodes, } from '../core/api/tax-profiles.js';
|
|
3
3
|
import { apiAction } from './api-action.js';
|
|
4
4
|
import { parsePositiveInt, parseNonNegativeInt, requireFields } from './parsers.js';
|
|
5
|
-
import { paginatedFetch
|
|
5
|
+
import { paginatedFetch } from './pagination.js';
|
|
6
|
+
import { outputList } from './output.js';
|
|
7
|
+
import { formatId } from './format-helpers.js';
|
|
8
|
+
const TAX_PROFILES_COLUMNS = [
|
|
9
|
+
{ key: 'resourceId', header: 'ID', format: formatId },
|
|
10
|
+
{ key: 'name', header: 'Name' },
|
|
11
|
+
{ key: 'taxRate', header: 'Rate (%)' },
|
|
12
|
+
{ key: 'taxTypeCode', header: 'Tax Type' },
|
|
13
|
+
];
|
|
14
|
+
const TAX_TYPES_COLUMNS = [
|
|
15
|
+
{ key: 'code', header: 'Code' },
|
|
16
|
+
{ key: 'name', header: 'Name' },
|
|
17
|
+
];
|
|
6
18
|
export function registerTaxProfilesCommand(program) {
|
|
7
19
|
const tp = program
|
|
8
20
|
.command('tax-profiles')
|
|
@@ -16,21 +28,11 @@ export function registerTaxProfilesCommand(program) {
|
|
|
16
28
|
.option('--all', 'Fetch all pages')
|
|
17
29
|
.option('--max-rows <n>', 'Max rows for --all (default 10000)', parsePositiveInt)
|
|
18
30
|
.option('--api-key <key>', 'API key (overrides stored/env)')
|
|
31
|
+
.option('--format <type>', 'Output format: table, json, csv, yaml')
|
|
19
32
|
.option('--json', 'Output as JSON')
|
|
20
33
|
.action(apiAction(async (client, opts) => {
|
|
21
34
|
const result = await paginatedFetch(opts, (p) => listTaxProfiles(client, p), { label: 'Fetching tax profiles' });
|
|
22
|
-
|
|
23
|
-
console.log(paginatedJson(result, opts));
|
|
24
|
-
}
|
|
25
|
-
else {
|
|
26
|
-
console.log(chalk.bold(`Tax Profiles (${result.data.length} of ${result.totalElements}):\n`));
|
|
27
|
-
const { items, overflow } = displaySlice(result.data);
|
|
28
|
-
for (const tp of items) {
|
|
29
|
-
console.log(` ${chalk.cyan(tp.resourceId)} ${tp.name} ${tp.taxRate}% ${chalk.dim(tp.taxTypeCode)}`);
|
|
30
|
-
}
|
|
31
|
-
if (overflow > 0)
|
|
32
|
-
console.log(chalk.dim(` ... and ${overflow.toLocaleString()} more (use --json for full output)`));
|
|
33
|
-
}
|
|
35
|
+
outputList(result, TAX_PROFILES_COLUMNS, opts, 'Tax Profiles'); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
34
36
|
}));
|
|
35
37
|
// ── clio tax-profiles types ───────────────────────────────────
|
|
36
38
|
tp
|
|
@@ -41,21 +43,11 @@ export function registerTaxProfilesCommand(program) {
|
|
|
41
43
|
.option('--all', 'Fetch all pages')
|
|
42
44
|
.option('--max-rows <n>', 'Max rows for --all (default 10000)', parsePositiveInt)
|
|
43
45
|
.option('--api-key <key>', 'API key (overrides stored/env)')
|
|
46
|
+
.option('--format <type>', 'Output format: table, json, csv, yaml')
|
|
44
47
|
.option('--json', 'Output as JSON')
|
|
45
48
|
.action(apiAction(async (client, opts) => {
|
|
46
49
|
const result = await paginatedFetch(opts, (p) => listTaxTypes(client, p), { label: 'Fetching tax types' });
|
|
47
|
-
|
|
48
|
-
console.log(paginatedJson(result, opts));
|
|
49
|
-
}
|
|
50
|
-
else {
|
|
51
|
-
console.log(chalk.bold(`Tax Types (${result.data.length} of ${result.totalElements}):\n`));
|
|
52
|
-
const { items, overflow } = displaySlice(result.data);
|
|
53
|
-
for (const tt of items) {
|
|
54
|
-
console.log(` ${chalk.cyan(tt.code)} ${tt.name}`);
|
|
55
|
-
}
|
|
56
|
-
if (overflow > 0)
|
|
57
|
-
console.log(chalk.dim(` ... and ${overflow.toLocaleString()} more (use --json for full output)`));
|
|
58
|
-
}
|
|
50
|
+
outputList(result, TAX_TYPES_COLUMNS, opts, 'Tax Types'); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
59
51
|
}));
|
|
60
52
|
// ── clio tax-profiles get ────────────────────────────────────
|
|
61
53
|
tp
|
|
@@ -89,6 +81,7 @@ export function registerTaxProfilesCommand(program) {
|
|
|
89
81
|
.option('--all', 'Fetch all pages')
|
|
90
82
|
.option('--max-rows <n>', 'Max rows for --all (default 10000)', parsePositiveInt)
|
|
91
83
|
.option('--api-key <key>', 'API key (overrides stored/env)')
|
|
84
|
+
.option('--format <type>', 'Output format: table, json, csv, yaml')
|
|
92
85
|
.option('--json', 'Output as JSON')
|
|
93
86
|
.action(apiAction(async (client, opts) => {
|
|
94
87
|
const filter = {};
|
|
@@ -99,22 +92,7 @@ export function registerTaxProfilesCommand(program) {
|
|
|
99
92
|
const searchFilter = Object.keys(filter).length > 0 ? filter : undefined;
|
|
100
93
|
const sort = { sortBy: [opts.sort ?? 'name'], order: (opts.order ?? 'ASC') };
|
|
101
94
|
const result = await paginatedFetch(opts, ({ limit, offset }) => searchTaxProfiles(client, { filter: searchFilter, limit, offset, sort }), { label: 'Searching tax profiles', defaultLimit: 20 });
|
|
102
|
-
|
|
103
|
-
console.log(paginatedJson(result, opts));
|
|
104
|
-
}
|
|
105
|
-
else {
|
|
106
|
-
if (result.data.length === 0) {
|
|
107
|
-
console.log('No tax profiles found.');
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
console.log(chalk.bold(`Found ${result.data.length} tax profile(s):\n`));
|
|
111
|
-
const { items, overflow } = displaySlice(result.data);
|
|
112
|
-
for (const p of items) {
|
|
113
|
-
console.log(` ${chalk.cyan(p.resourceId)} ${p.name} ${p.taxRate}% ${chalk.dim(p.taxTypeCode)}`);
|
|
114
|
-
}
|
|
115
|
-
if (overflow > 0)
|
|
116
|
-
console.log(chalk.dim(` ... and ${overflow.toLocaleString()} more (use --json for full output)`));
|
|
117
|
-
}
|
|
95
|
+
outputList(result, TAX_PROFILES_COLUMNS, opts, 'Tax Profiles'); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
118
96
|
}));
|
|
119
97
|
// ── clio tax-profiles update ────────────────────────────────
|
|
120
98
|
tp
|
|
@@ -212,18 +212,36 @@ export const TOOL_DEFINITIONS = [
|
|
|
212
212
|
params: {
|
|
213
213
|
name: { type: 'string', description: 'Account name' },
|
|
214
214
|
code: { type: 'string', description: 'Account code (unique)' },
|
|
215
|
-
accountType: { type: 'string', description: '
|
|
215
|
+
accountType: { type: 'string', description: 'Exact API values: "Bank Accounts", "Cash", "Current Asset", "Fixed Asset", "Inventory", "Current Liability", "Non-current Liability", "Shareholders Equity", "Operating Revenue", "Other Revenue", "Operating Expense", "Direct Costs"' },
|
|
216
216
|
currencyCode: { type: 'string', description: 'Currency code (e.g., "SGD")' },
|
|
217
217
|
},
|
|
218
218
|
required: ['name', 'code', 'accountType'],
|
|
219
219
|
group: 'accounts',
|
|
220
220
|
readOnly: false,
|
|
221
|
-
execute: async (ctx, input) =>
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
221
|
+
execute: async (ctx, input) => {
|
|
222
|
+
// Normalize common LLM variations to exact API values
|
|
223
|
+
const typeMap = {
|
|
224
|
+
'current assets': 'Current Asset', 'current asset': 'Current Asset',
|
|
225
|
+
'fixed assets': 'Fixed Asset', 'fixed asset': 'Fixed Asset',
|
|
226
|
+
'bank account': 'Bank Accounts', 'bank accounts': 'Bank Accounts', 'bank': 'Bank Accounts',
|
|
227
|
+
'current liabilities': 'Current Liability', 'current liability': 'Current Liability',
|
|
228
|
+
'non-current liabilities': 'Non-current Liability', 'non-current liability': 'Non-current Liability',
|
|
229
|
+
'equity': 'Shareholders Equity', 'shareholders equity': 'Shareholders Equity', "shareholders' equity": 'Shareholders Equity', "shareholder's equity": 'Shareholders Equity',
|
|
230
|
+
'revenue': 'Operating Revenue', 'operating revenue': 'Operating Revenue',
|
|
231
|
+
'other revenue': 'Other Revenue', 'other income': 'Other Revenue',
|
|
232
|
+
'expense': 'Operating Expense', 'operating expense': 'Operating Expense', 'expenses': 'Operating Expense',
|
|
233
|
+
'direct costs': 'Direct Costs', 'cost of goods sold': 'Direct Costs', 'cogs': 'Direct Costs',
|
|
234
|
+
'cash': 'Cash', 'inventory': 'Inventory',
|
|
235
|
+
};
|
|
236
|
+
const rawType = input.accountType;
|
|
237
|
+
const accountType = typeMap[rawType.toLowerCase()] ?? rawType;
|
|
238
|
+
return createAccount(ctx.client, {
|
|
239
|
+
code: input.code,
|
|
240
|
+
name: input.name,
|
|
241
|
+
accountType,
|
|
242
|
+
currencyCode: input.currencyCode,
|
|
243
|
+
});
|
|
244
|
+
},
|
|
227
245
|
},
|
|
228
246
|
{
|
|
229
247
|
name: 'update_account',
|
|
@@ -316,24 +334,32 @@ export const TOOL_DEFINITIONS = [
|
|
|
316
334
|
listTool('list_invoices', 'List invoices. Returns reference, date, status, contact, totalAmount. Paginated — response includes totalElements. Use limit/offset to page.', 'invoices', (client, off, lim) => listInvoices(client, { limit: lim, offset: off })),
|
|
317
335
|
{
|
|
318
336
|
name: 'search_invoices',
|
|
319
|
-
description: 'Search invoices by reference or contact name.
|
|
337
|
+
description: 'Search invoices by reference and/or contact name. Provide query for reference search, contactName for contact search, or both.',
|
|
320
338
|
params: {
|
|
321
|
-
query: { type: 'string', description: 'Search
|
|
339
|
+
query: { type: 'string', description: 'Search by invoice reference number' },
|
|
340
|
+
contactName: { type: 'string', description: 'Search by contact name' },
|
|
322
341
|
...SEARCH_PARAMS,
|
|
323
342
|
},
|
|
324
|
-
required: [
|
|
343
|
+
required: [],
|
|
325
344
|
group: 'invoices',
|
|
326
345
|
readOnly: true,
|
|
327
346
|
execute: async (ctx, input) => {
|
|
328
347
|
const { mode, limit, offset, sortBy, sortOrder } = extractPaginationInput(input);
|
|
329
348
|
const query = input.query;
|
|
349
|
+
const contactName = input.contactName;
|
|
350
|
+
// Build filter — avoid nested `contact` inside `or` (causes 400)
|
|
351
|
+
let filter;
|
|
352
|
+
if (query && contactName) {
|
|
353
|
+
filter = { reference: { contains: query }, contact: { name: { contains: contactName } } };
|
|
354
|
+
}
|
|
355
|
+
else if (query) {
|
|
356
|
+
filter = { reference: { contains: query } };
|
|
357
|
+
}
|
|
358
|
+
else if (contactName) {
|
|
359
|
+
filter = { contact: { name: { contains: contactName } } };
|
|
360
|
+
}
|
|
330
361
|
return handlePaginationMode(mode, (off, lim) => searchInvoices(ctx.client, {
|
|
331
|
-
filter
|
|
332
|
-
or: [
|
|
333
|
-
{ reference: { contains: query } },
|
|
334
|
-
{ contact: { name: { contains: query } } },
|
|
335
|
-
],
|
|
336
|
-
} : undefined,
|
|
362
|
+
filter,
|
|
337
363
|
limit: lim, offset: off,
|
|
338
364
|
sort: { sortBy: [sortBy ?? 'valueDate'], order: (sortOrder ?? 'DESC') },
|
|
339
365
|
}), limit, offset, 100);
|
|
@@ -437,7 +463,7 @@ export const TOOL_DEFINITIONS = [
|
|
|
437
463
|
accountResourceId: input.accountResourceId,
|
|
438
464
|
valueDate: input.valueDate,
|
|
439
465
|
dueDate: input.valueDate,
|
|
440
|
-
reference: input.reference
|
|
466
|
+
reference: input.reference || `PMT-${Date.now()}`,
|
|
441
467
|
paymentMethod: (input.paymentMethod ?? 'BANK_TRANSFER'),
|
|
442
468
|
saveAsDraft: false,
|
|
443
469
|
customFields: input.customFields, // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
@@ -501,24 +527,31 @@ export const TOOL_DEFINITIONS = [
|
|
|
501
527
|
listTool('list_bills', 'List bills (purchase invoices). Returns reference, date, status, contact, amounts. Paginated — response includes totalElements. Use limit/offset to page.', 'bills', (client, off, lim) => listBills(client, { limit: lim, offset: off })),
|
|
502
528
|
{
|
|
503
529
|
name: 'search_bills',
|
|
504
|
-
description: 'Search bills by reference or contact name.
|
|
530
|
+
description: 'Search bills by reference and/or contact name. Provide query for reference search, contactName for contact search, or both.',
|
|
505
531
|
params: {
|
|
506
|
-
query: { type: 'string', description: 'Search
|
|
532
|
+
query: { type: 'string', description: 'Search by bill reference number' },
|
|
533
|
+
contactName: { type: 'string', description: 'Search by contact name' },
|
|
507
534
|
...SEARCH_PARAMS,
|
|
508
535
|
},
|
|
509
|
-
required: [
|
|
536
|
+
required: [],
|
|
510
537
|
group: 'bills',
|
|
511
538
|
readOnly: true,
|
|
512
539
|
execute: async (ctx, input) => {
|
|
513
540
|
const { mode, limit, offset, sortBy, sortOrder } = extractPaginationInput(input);
|
|
514
541
|
const query = input.query;
|
|
542
|
+
const contactName = input.contactName;
|
|
543
|
+
let filter;
|
|
544
|
+
if (query && contactName) {
|
|
545
|
+
filter = { reference: { contains: query }, contact: { name: { contains: contactName } } };
|
|
546
|
+
}
|
|
547
|
+
else if (query) {
|
|
548
|
+
filter = { reference: { contains: query } };
|
|
549
|
+
}
|
|
550
|
+
else if (contactName) {
|
|
551
|
+
filter = { contact: { name: { contains: contactName } } };
|
|
552
|
+
}
|
|
515
553
|
return handlePaginationMode(mode, (off, lim) => searchBills(ctx.client, {
|
|
516
|
-
filter
|
|
517
|
-
or: [
|
|
518
|
-
{ reference: { contains: query } },
|
|
519
|
-
{ contact: { name: { contains: query } } },
|
|
520
|
-
],
|
|
521
|
-
} : undefined,
|
|
554
|
+
filter,
|
|
522
555
|
limit: lim, offset: off,
|
|
523
556
|
sort: { sortBy: [sortBy ?? 'valueDate'], order: (sortOrder ?? 'DESC') },
|
|
524
557
|
}), limit, offset, 100);
|
|
@@ -625,7 +658,7 @@ export const TOOL_DEFINITIONS = [
|
|
|
625
658
|
accountResourceId: input.accountResourceId,
|
|
626
659
|
valueDate: input.valueDate,
|
|
627
660
|
dueDate: input.valueDate,
|
|
628
|
-
reference: input.reference
|
|
661
|
+
reference: input.reference || `PMT-${Date.now()}`,
|
|
629
662
|
paymentMethod: (input.paymentMethod ?? 'BANK_TRANSFER'),
|
|
630
663
|
saveAsDraft: false,
|
|
631
664
|
customFields: input.customFields, // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
@@ -1553,7 +1586,12 @@ export const TOOL_DEFINITIONS = [
|
|
|
1553
1586
|
required: ['valueDate', 'accountResourceId', 'journalEntries'],
|
|
1554
1587
|
group: 'cash_entries',
|
|
1555
1588
|
readOnly: false,
|
|
1556
|
-
execute: async (ctx, input) =>
|
|
1589
|
+
execute: async (ctx, input) => {
|
|
1590
|
+
const data = { ...input };
|
|
1591
|
+
if (!data.reference)
|
|
1592
|
+
data.reference = `CI-${Date.now()}`;
|
|
1593
|
+
return createCashIn(ctx.client, data);
|
|
1594
|
+
},
|
|
1557
1595
|
},
|
|
1558
1596
|
listTool('list_cash_out', 'List cash-out entries (direct cash disbursements). Paginated.', 'cash_entries', (client, off, lim) => listCashOut(client, { limit: lim, offset: off })),
|
|
1559
1597
|
{
|
|
@@ -1584,7 +1622,12 @@ export const TOOL_DEFINITIONS = [
|
|
|
1584
1622
|
required: ['valueDate', 'accountResourceId', 'journalEntries'],
|
|
1585
1623
|
group: 'cash_entries',
|
|
1586
1624
|
readOnly: false,
|
|
1587
|
-
execute: async (ctx, input) =>
|
|
1625
|
+
execute: async (ctx, input) => {
|
|
1626
|
+
const data = { ...input };
|
|
1627
|
+
if (!data.reference)
|
|
1628
|
+
data.reference = `CO-${Date.now()}`;
|
|
1629
|
+
return createCashOut(ctx.client, data);
|
|
1630
|
+
},
|
|
1588
1631
|
},
|
|
1589
1632
|
{
|
|
1590
1633
|
name: 'get_cash_in',
|
|
@@ -1858,10 +1901,10 @@ export const TOOL_DEFINITIONS = [
|
|
|
1858
1901
|
items: {
|
|
1859
1902
|
type: 'object',
|
|
1860
1903
|
properties: {
|
|
1861
|
-
|
|
1862
|
-
|
|
1904
|
+
moduleName: { type: 'string', description: 'Module name: ORGANIZATION, USER_MANAGEMENT, ACCOUNTING, SALES, PURCHASES, REPORTS, or FIXED_ASSET' },
|
|
1905
|
+
roleCode: { type: 'string', description: 'Role code: ADMIN, EDITOR, VIEWER, or NONE' },
|
|
1863
1906
|
},
|
|
1864
|
-
required: ['
|
|
1907
|
+
required: ['moduleName', 'roleCode'],
|
|
1865
1908
|
},
|
|
1866
1909
|
description: 'Module role assignments',
|
|
1867
1910
|
},
|
|
@@ -1881,10 +1924,10 @@ export const TOOL_DEFINITIONS = [
|
|
|
1881
1924
|
items: {
|
|
1882
1925
|
type: 'object',
|
|
1883
1926
|
properties: {
|
|
1884
|
-
|
|
1885
|
-
|
|
1927
|
+
moduleName: { type: 'string', description: 'Module name: ORGANIZATION, USER_MANAGEMENT, ACCOUNTING, SALES, PURCHASES, REPORTS, or FIXED_ASSET' },
|
|
1928
|
+
roleCode: { type: 'string', description: 'Role code: ADMIN, EDITOR, VIEWER, or NONE' },
|
|
1886
1929
|
},
|
|
1887
|
-
required: ['
|
|
1930
|
+
required: ['moduleName', 'roleCode'],
|
|
1888
1931
|
},
|
|
1889
1932
|
},
|
|
1890
1933
|
},
|