jaz-clio 5.8.0 → 5.8.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.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: jaz-api
3
- version: 5.8.0
3
+ version: 5.8.1
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, 141 production gotchas, error
@@ -161,7 +161,7 @@ The rest of this skill — field names, gotchas, error catalog, dependency order
161
161
  37a. **Data exports use simpler field names**: P&L export uses `startDate`/`endDate` (NOT `primarySnapshotDate`). AR/AP export uses `endDate`.
162
162
 
163
163
  ### Pagination
164
- 38. **All list/search endpoints use `limit`/`offset` pagination** — NOT `page`/`size`. Default limit=100, offset=0. Max limit=1000, max offset=65536. `page`/`size` params are silently ignored. Response shape: `{ totalPages, totalElements, truncated, data: [...] }`. When `truncated: true`, a `_meta: { fetchedRows, maxRows }` field explains why (offset cap or `--max-rows` soft cap — default 10,000). Use `--max-rows <n>` to override. Always check `truncated` before assuming the full dataset was returned.
164
+ 38. **All list/search endpoints use `limit`/`offset` pagination** — NOT `page`/`size`. **`offset` is a 0-indexed PAGE NUMBER, not a row-skip** (offset=1 = second page of `limit` rows). Default limit=100, offset=0. Max limit=1000, max offset=65536. `page`/`size` params are silently ignored. Response shape: `{ totalPages, totalElements, truncated, data: [...] }`. When `truncated: true`, a `_meta: { fetchedRows, maxRows }` field explains why (offset cap or `--max-rows` soft cap — default 10,000). Use `--max-rows <n>` to override. Always check `truncated` before assuming the full dataset was returned.
165
165
 
166
166
  ### Other
167
167
  39. **Currency rates use `/organization-currencies/:code/rates`** — note the HYPHENATED path (NOT `/organization/currencies`). Enable currencies first via `POST /organization/currencies`, then set rates via `POST /organization-currencies/:code/rates` with body `{ "rate": 0.74, "rateApplicableFrom": "YYYY-MM-DD" }` (see Rule 49 for direction). Cannot set rates for org base currency. Full CRUD: POST (create), GET (list), GET/:id, PUT/:id, DELETE/:id.
@@ -177,7 +177,7 @@ The rest of this skill — field names, gotchas, error catalog, dependency order
177
177
  49. **Currency rate direction: `rate` = functionalToSource (1 base = X foreign)** — POST `rate: 0.74` for a SGD org means 1 SGD = 0.74 USD. **If your data stores rates as "1 USD = 1.35 SGD" (sourceToFunctional), you MUST invert: `rate = 1 / 1.35 = 0.74`.** GET confirms both: `rateFunctionalToSource` (what you POSTed) and `rateSourceToFunctional` (the inverse).
178
178
 
179
179
  ### Search & Filter
180
- 50. **Search endpoint universal pattern** — All 28 `POST /*/search` endpoints share identical structure: `{ filter?, sort: { sortBy: ["field"], order: "ASC"|"DESC" }, limit: 1-1000, offset: 0-65536 }`. Sort is REQUIRED when offset is present (even `offset: 0`). Default limit: 100. `sortBy` is always an array on all endpoints (no exceptions). See `references/search-reference.md` for per-endpoint filter/sort fields.
180
+ 50. **Search endpoint universal pattern** — All 28 `POST /*/search` endpoints share identical structure: `{ filter?, sort: { sortBy: ["field"], order: "ASC"|"DESC" }, limit: 1-1000, offset: 0-65536 }`. `offset` is a 0-indexed page number (not row-skip). Sort is REQUIRED when offset is present (even `offset: 0`). Default limit: 100. `sortBy` is always an array on all endpoints (no exceptions). See `references/search-reference.md` for per-endpoint filter/sort fields.
181
181
  50a. **`query` field — Jaz search operators** — 14 endpoints accept an optional `query` string alongside `filter`: invoices, bills, customer/supplier credit notes, journals, cashflow-transactions, bank-records, contacts, items, capsules, fixed-assets, scheduled-transactions, chart-of-accounts, tax-profiles. Example: `{ "query": "status:unpaid AND $500+", "limit": 50 }`. Key syntax: amounts (`$500+`, `$100-500`, `amount:>2m`, magnitude suffixes `5k`/`2m`/`1b`), negative (`$-500`), absolute value (`abs:1000+`), dates (`date:this month`, `date:-30d`, `due:overdue`, `submitted:last week`, `lastpayment:-7d`), status/enum (`status:unpaid`, `currency:SGD,USD` — comma = OR), string fields (`customer:acme`, `ref:INV-*` wildcard, `=ref:INV-001` exact, `ref:/\d{4}/` regex), blank checks (`ref:blank`, `tag:!blank`), booleans (`hasattachment:yes`, `customer:yes`), negation (`!status:paid` or `NOT status:void` — **never `-`** for negation), logic (`AND`/`OR` with implicit AND on space), grouping, inline sort (`sort:amount:desc`). Full syntax spec (all fields, aliases, entity field lists, examples): **`references/search-syntax.md`**.
182
182
  50b. **`query` + `filter` merge** — When both are present, they are merged at the filter level. Explicit `filter` keys win on conflict. Use `query` for human-readable shorthand, `filter` for programmatic precision, or combine both: `{ "query": "date:this year", "filter": { "currencyCode": { "in": ["SGD"] } } }`.
183
183
  50c. **`query` error handling** — Unknown field name → `query_not_understood` (400). Bad enum value (e.g. `status:BADVALUE`) → **empty results, no error** (silent miss). Unsupported endpoint → `query_not_supported` (400). Parser unavailable → `query_parse_error` (502). Empty/null/whitespace query → passthrough (ignored). In CLI/MCP: use `--query` / `query` param only on supported entities — unsupported entities have no `--query` flag.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: jaz-cli
3
- version: 5.8.0
3
+ version: 5.8.1
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: 5.8.0
3
+ version: 5.8.1
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-pseudo-sql
3
- version: 5.8.0
3
+ version: 5.8.1
4
4
  description: >-
5
5
  Use this skill when answering ad-hoc data questions that aren't covered by
6
6
  download_export (canonical reports — anomaly, audit, aging, P&L, BS, GL,
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: jaz-jobs
3
- version: 5.8.0
3
+ version: 5.8.1
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-practice
3
- version: 5.8.0
3
+ version: 5.8.1
4
4
  description: >-
5
5
  Use this skill whenever an accounting practitioner is doing client work in
6
6
  Jaz — closing the books, filing GST, year-end statutory, onboarding a new
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: jaz-recipes
3
- version: 5.8.0
3
+ version: 5.8.1
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
@@ -20,7 +20,7 @@ Offline tools (no API key needed): `plan_recipe`, `search_help_center`, all `pra
20
20
  2. **Transaction dates are `valueDate`** (YYYY-MM-DD) — never `issueDate` / `invoiceDate` / `date`.
21
21
  3. **Line item text field is `name`** — never `description`.
22
22
  4. **`saveAsDraft` defaults `false`** at the API; CLI/MCP create-tools default `true`. Set explicitly when the user says "finalize".
23
- 5. **Pagination uses `limit` / `offset`** — sort is required when `offset` is set.
23
+ 5. **Pagination uses `limit` / `offset`** — `offset` is a 0-indexed page number (offset=1 = second page), not a row-skip. Sort is required when `offset` is set.
24
24
  6. **Create responses return `{ resourceId }` only** — re-GET to load the full entity.
25
25
 
26
26
  ## Transactions — never hand-construct journals for IFRS
package/cli.mjs CHANGED
@@ -852,7 +852,7 @@ Strings are replaced with values relative to the transaction date.`);t.command("
852
852
  `);if(t===-1)return null;let r=this._buffer.toString("utf8",0,t).replace(/\r$/,"");return this._buffer=this._buffer.subarray(t+1),bIe(r)}clear(){this._buffer=void 0}};function bIe(e){return xJ.parse(JSON.parse(e))}function CH(e){return JSON.stringify(e)+`
853
853
  `}var $E=class{constructor(t=xH.stdin,r=xH.stdout){this._stdin=t,this._stdout=r,this._readBuffer=new NE,this._started=!1,this._ondata=n=>{this._readBuffer.append(n),this.processReadBuffer()},this._onerror=n=>{this.onerror?.(n)}}async start(){if(this._started)throw new Error("StdioServerTransport already started! If using Server class, note that connect() calls start() automatically.");this._started=!0,this._stdin.on("data",this._ondata),this._stdin.on("error",this._onerror)}processReadBuffer(){for(;;)try{let t=this._readBuffer.readMessage();if(t===null)break;this.onmessage?.(t)}catch(t){this.onerror?.(t)}}async close(){this._stdin.off("data",this._ondata),this._stdin.off("error",this._onerror),this._stdin.listenerCount("data")===0&&this._stdin.pause(),this._readBuffer.clear(),this.onclose?.()}send(t){return new Promise(r=>{let n=CH(t);this._stdout.write(n)?r():this._stdout.once("drain",r)})}};Tm();$h();li();li();$h();var SIe=["search_","list_","get_","view_","describe_"];function _Ie(e){return SIe.some(t=>e.startsWith(t))}function kh(e){if(_Ie(e.tool)&&Bl(e.tool))return e}function AH(e,t,r){if(!(e instanceof Cn))return;let n=e.message.toLowerCase(),o=e.status;if(o===404||n.includes("not found")){if(typeof r.contactResourceId=="string"&&n.includes("contact"))return kh({tool:"search_contacts",arguments:{},reason:`Contact ${r.contactResourceId} not found. Search by name to find the correct resourceId before retrying.`});let s=/^(get|update|delete|finalize|pay)_(.+)$/.exec(t);if(s){let a=s[2],c=`search_${a}s`,u=typeof r.resourceId=="string"?r.resourceId:void 0;return kh({tool:c,arguments:{},reason:`${a} ${u??""} not found. Search to locate the correct resourceId, then retry.`.trim()})}}if(o===422&&(n.includes("accountresourceid")||n.includes("account resource id")))return kh({tool:"search_accounts",arguments:{},reason:"Line item missing accountResourceId. Search for the right GL account first (e.g. by name or accountType), then retry with the resourceId on each line item."});if(o===422&&(n.includes("duplicate")||n.includes("already exists"))){let s=typeof r.reference=="string"?r.reference:void 0;if(s){let a=/^create_(.+)$/.exec(t);if(a){let c=a[1];return kh({tool:`search_${c}s`,arguments:{filter:{reference:{eq:s}}},reason:`Reference "${s}" already exists in ${c}s. Look up the existing record before deciding whether to update it or use a new reference.`})}}}if(o===422&&(n.includes("taxprofileresourceid")||n.includes("tax profile")||n.includes("tax_profile"))&&(n.includes("direction")||n.includes("appliesto")||n.includes("applies to")||n.includes("sale")||n.includes("purchase")))return kh({tool:"search_tax_profiles",arguments:{},reason:'Tax profile rejected \u2014 direction mismatch. Use search_tax_profiles with the correct appliesTo direction ("sale" for invoices, "purchase" for bills) before retrying.'})}function EIe(e){switch(e){case 401:return"Invalid or missing API key. Run `clio auth add` or set JAZ_API_KEY.";case 403:return"Insufficient permissions for this operation.";case 404:return"Resource not found \u2014 check the resourceId. Use a search/list tool to look it up.";case 409:return"Conflict \u2014 resource may have been modified. Re-fetch and retry.";case 422:return"Validation error \u2014 check field values against the tool description.";case 429:return"Rate limited \u2014 wait a moment and retry.";default:return""}}function wH(e,t={}){if(e instanceof Cn){let n=EIe(e.status),o={error:e.message,status:e.status,endpoint:e.endpoint,...n?{hint:n}:{}};if(t.toolName&&t.input){let i=AH(e,t.toolName,t.input);i&&(o.repair=i)}return o}return{error:e instanceof Error?e.message:String(e)}}function TH(e,t){if(e.readOnly)return{valid:!0,errors:[]};let r=[];for(let n of e.required){let o=t[n];if(o==null){r.push(`Missing required field: ${n}`);continue}typeof o=="string"&&o.trim()===""&&r.push(`Required field "${n}" is empty`)}for(let[n,o]of Object.entries(t)){if(o==null)continue;let i=e.params[n];if(!i)continue;let s=IIe(n,o,i);s&&r.push(s),i.enum&&typeof o=="string"&&(i.enum.includes(o)||r.push(`Field "${n}" value "${o}" not in allowed values: ${i.enum.join(", ")}`))}return{valid:r.length===0,errors:r}}function IIe(e,t,r){switch(r.type){case"string":if(typeof t!="string")return`Field "${e}" expected string, got ${typeof t}`;break;case"number":if(typeof t!="number"||!Number.isFinite(t))return`Field "${e}" expected finite number, got ${typeof t=="number"?"non-finite":typeof t}`;break;case"boolean":if(typeof t!="boolean")return`Field "${e}" expected boolean, got ${typeof t}`;break;case"array":if(!Array.isArray(t))return`Field "${e}" expected array, got ${typeof t}`;break;case"object":if(typeof t!="object"||Array.isArray(t))return`Field "${e}" expected object, got ${Array.isArray(t)?"array":typeof t}`;break}return null}Fh();v$();PE();hu();li();Oa();_R();import{readFileSync as wIe,readdirSync as TIe,statSync as RIe}from"node:fs";import{dirname as FH,join as ea,relative as OIe}from"node:path";import{fileURLToPath as PH}from"node:url";function NIe(e,t){let r;try{r=RIe(e)}catch{return[]}if(!r.isDirectory())return[];let n=[],o=20,i=(s,a)=>{if(a>o)return;let c;try{c=TIe(s,{withFileTypes:!0})}catch{return}for(let u of c){let l=ea(s,u.name);if(u.isDirectory())i(l,a+1);else if(u.isFile()&&u.name.endsWith(".md")){let d=OIe(e,l).split(/[\\/]/).join("/");(!t||!t(d))&&n.push(d)}}};return i(e,0),n.sort()}function kH(e){let t=e.fileFilter??(()=>!0);return NIe(e.rootDir,n=>!t(n)).map(n=>{let o=e.uriPathBuilder?e.uriPathBuilder(n):n.replace(/\.md$/,"");return{uri:`${e.uriPrefix}/${o}`,name:e.nameBuilder(n),description:e.descriptionBuilder?.(n),mimeType:"text/markdown",filePath:ea(e.rootDir,n)}})}function $Ie(){let e=PH(import.meta.url),t=FH(e);return SR([ea(t,"..","..","..","assets","skills"),ea(t,"..","..","..","..","assets","skills"),ea(t,"skills")])}function kIe(){let e=PH(import.meta.url),t=FH(e);return SR([ea(t,"..","..","..","help-center-mirror"),ea(t,"..","..","..","assets","skills","api","help-center-mirror"),ea(t,"help-center-mirror")])}var FIe=["api","cli","conversion","jobs","transaction-recipes"],PIe={api:"Jaz REST API rules: every endpoint, field name, error code, production gotchas.",cli:"Jaz CLI commands, auth, calculators, jobs.",conversion:"Migration from Xero, QuickBooks, Sage, MYOB, or Excel exports into Jaz.",jobs:"12 recurring accounting workflow playbooks (close, reconciliation, GST/VAT, etc.).","transaction-recipes":"16 IFRS-compliant transaction recipes plus 13 financial calculators."};function LIe(e){if(e.includes("/help-center-mirror/"))return!1;let t=e.split("/")[0];return FIe.includes(t)}function jIe(e){let t=e.split("/"),r=t[0];if(t.length===2&&t[1]==="SKILL.md")return`Jaz ${r} skill`;if(t[1]==="references"){let n=t.slice(2).join("/").replace(/\.md$/,"");return`Jaz ${r} reference: ${n}`}return`Jaz ${r}: ${e}`}function MIe(e){let t=e.split("/")[0];return PIe[t]}function BIe(e){return!e.includes("/")}function UIe(e){return`Jaz help center: ${e.replace(/\.md$/,"").split("-").map(n=>n[0]?.toUpperCase()+n.slice(1)).join(" ")}`}var S$=null,_$=null;function E$(){if(S$)return S$;let e=$Ie(),t=kIe(),r=[];return e&&r.push(...kH({rootDir:e,uriPrefix:"jaz://skill",fileFilter:LIe,nameBuilder:jIe,descriptionBuilder:MIe,uriPathBuilder:n=>{let o=n.split("/");return o.length===2&&o[1]==="SKILL.md"?o[0]:n.replace(/\.md$/,"")}})),t&&r.push(...kH({rootDir:t,uriPrefix:"jaz://help-center",fileFilter:BIe,nameBuilder:UIe,descriptionBuilder:()=>"Jaz help center article. Same corpus search_help_center indexes."})),S$=r,_$=new Map(r.map(n=>[n.uri,n])),r}function LH(e){_$||E$();let t=_$.get(e);if(!t)throw new Error(`Resource not found: ${e}`);let r=wIe(t.filePath,"utf-8");return{mimeType:t.mimeType,text:r}}Fh();var ZIe=new Set(["close_jobs","operational_jobs","help_center"]),YH="Calculators, blueprints, and help center search work without an account.",JH="Get an API key or token from jaz.ai";function I$(e,t){return!!(ZIe.has(e)||e==="recipes"&&t==="plan_recipe")}function KIe(e,t){return new zr({mode:"pat",token:e,orgId:t})}async function GH(e,t=5e3){let r=new Map,n=[],o=a=>Promise.race([a,new Promise(c=>setTimeout(()=>c(null),t))]),i=e.map(a=>({auth:a,client:new zr(a)})),s=i[0]?.client??null;return await Promise.all(i.map(async({auth:a,client:c})=>{try{let u=await o(qn(c));if(u)r.set(u.resourceId,{name:u.name,resourceId:u.resourceId,currency:u.currency,client:c});else{let l=a.mode==="direct"?"api-key":a.mode;n.push(`Org lookup returned empty (${l}).`)}}catch(u){let l=a.mode==="direct"?"api-key":a.mode;n.push(`Org lookup failed (${l}): ${u instanceof Error?u.message:"unknown"}`)}})),{orgMap:r,primaryClient:s,errors:n}}function VH(e){e.command("mcp").description("Start MCP stdio server for Claude Code / Cowork").option("--api-key <key>","API key, PAT, or comma-separated keys (overrides stored/env)").action(async t=>{let r=[];try{r=Vx(t.apiKey)}catch(E){let I=E instanceof Error?E.message:String(E);process.stderr.write(`jaz-ai: ${I} (continuing in offline mode)
854
854
  `)}let n=e.version()??"0.0.0",o=new Map,i=null,s=r.length>1||r[0]?.mode==="pat";if(r.length>0){let E=await GH(r);o=E.orgMap,i=E.primaryClient;for(let I of E.errors)process.stderr.write(`warning: ${I}
855
- `)}let a="",c="";if(o.size>1){let E=[...o.values()].map(I=>`${I.name} (${I.currency})`);a=`Connected to ${o.size} organizations: ${E.join(", ")}.`,c=`${o.size} orgs`}else if(o.size===1){let E=[...o.values()][0];a=`Connected to: ${E.name} (${E.currency}).`,c=E.name}else if(i){let E=qd();if(E){let I=uo(E);I?.orgName&&(a=`Connected to: ${I.orgName} (${I.currency}).`,c=`${I.orgName} (${E})`)}}let u=Qs.map(E=>E.name).join(", "),l=i?"All API tools hit api.getjaz.com using the configured credentials.":`${JH} to bring Jaz into Claude for real accounting and finance work. ${YH}`,d=s&&o.size>0?["","MULTI-ORG MODE:",`You have access to ${o.size} organization(s):`,...[...o.values()].map(E=>` - ${E.name} (org_id: ${E.resourceId}, ${E.currency})`),"","RULES:","1. Every execute_tool call for API tools MUST include org_id.","2. If the user mentions an org by name, match it to the org_id above.",`3. If the user hasn't specified an org, ask: "Which organization?"`,"4. Once the user picks an org, use it for all subsequent calls until they say otherwise.",'5. If the user says "switch to [org]", update the active org for subsequent calls.','6. Always confirm the org on the first tool call: "Using [Org Name]."','7. For cross-org queries (e.g. "compare Acme and Beta"), make separate execute_tool calls with different org_ids.',"8. Call list_organizations to refresh the org list if needed."]:[],f=[`Jaz accounting platform \u2014 ${Go.length} tools across ${Qs.length} namespaces.`,a,"","WORKFLOW: search_tools \u2192 describe_tools \u2192 execute_tool.","1. Call search_tools with a keyword to find relevant tools.","2. Call describe_tools with tool names to get full parameter schemas.","3. Call execute_tool with the tool name and arguments to run it.","",`Namespaces: ${u}.`,"","Key API rules (apply to all tools):","- All IDs are `resourceId` (never `id`).","- All transaction dates are `valueDate` (not issueDate/invoiceDate/date). Format: YYYY-MM-DD.","- Line item text field is `name` (not `description`).","- `saveAsDraft` defaults to false \u2014 omitting it finalizes the transaction.","- Response dates are epoch milliseconds (convert with new Date(ms)).","- Pagination: use `limit`/`offset` (not page/size). Search sort is required when offset present.","- Create responses return only `{ resourceId }` \u2014 GET the full entity after creation.","","Offline tools (no auth needed): close-procedure blueprints (close_procedures, operational_jobs), plan_recipe calculator, and search_help_center for the Jaz help center.",l,...d].filter(E=>E!==void 0).join(`
855
+ `)}let a="",c="";if(o.size>1){let E=[...o.values()].map(I=>`${I.name} (${I.currency})`);a=`Connected to ${o.size} organizations: ${E.join(", ")}.`,c=`${o.size} orgs`}else if(o.size===1){let E=[...o.values()][0];a=`Connected to: ${E.name} (${E.currency}).`,c=E.name}else if(i){let E=qd();if(E){let I=uo(E);I?.orgName&&(a=`Connected to: ${I.orgName} (${I.currency}).`,c=`${I.orgName} (${E})`)}}let u=Qs.map(E=>E.name).join(", "),l=i?"All API tools hit api.getjaz.com using the configured credentials.":`${JH} to bring Jaz into Claude for real accounting and finance work. ${YH}`,d=s&&o.size>0?["","MULTI-ORG MODE:",`You have access to ${o.size} organization(s):`,...[...o.values()].map(E=>` - ${E.name} (org_id: ${E.resourceId}, ${E.currency})`),"","RULES:","1. Every execute_tool call for API tools MUST include org_id.","2. If the user mentions an org by name, match it to the org_id above.",`3. If the user hasn't specified an org, ask: "Which organization?"`,"4. Once the user picks an org, use it for all subsequent calls until they say otherwise.",'5. If the user says "switch to [org]", update the active org for subsequent calls.','6. Always confirm the org on the first tool call: "Using [Org Name]."','7. For cross-org queries (e.g. "compare Acme and Beta"), make separate execute_tool calls with different org_ids.',"8. Call list_organizations to refresh the org list if needed."]:[],f=[`Jaz accounting platform \u2014 ${Go.length} tools across ${Qs.length} namespaces.`,a,"","WORKFLOW: search_tools \u2192 describe_tools \u2192 execute_tool.","1. Call search_tools with a keyword to find relevant tools.","2. Call describe_tools with tool names to get full parameter schemas.","3. Call execute_tool with the tool name and arguments to run it.","",`Namespaces: ${u}.`,"","Key API rules (apply to all tools):","- All IDs are `resourceId` (never `id`).","- All transaction dates are `valueDate` (not issueDate/invoiceDate/date). Format: YYYY-MM-DD.","- Line item text field is `name` (not `description`).","- `saveAsDraft` defaults to false \u2014 omitting it finalizes the transaction.","- Response dates are epoch milliseconds (convert with new Date(ms)).","- Pagination: `limit`/`offset` (not page/size). `offset` is a 0-indexed PAGE NUMBER, not a row-skip (offset=1 = second page of `limit` rows). Search sort is required when offset present.","- Create responses return only `{ resourceId }` \u2014 GET the full entity after creation.","","Offline tools (no auth needed): close-procedure blueprints (close_procedures, operational_jobs), plan_recipe calculator, and search_help_center for the Jaz help center.",l,...d].filter(E=>E!==void 0).join(`
856
856
  `),p=new OE({name:"jaz-ai",version:n},{capabilities:{tools:{},resources:{}},instructions:f}),m=(process.env.JAZ_MCP_FLAT??"").trim().toLowerCase(),h=m==="1"||m==="true"||m==="yes",g=s&&o.size>0?[...ql,Ph]:ql;p.setRequestHandler(_1,async()=>{if(h){let E=Nh().reduce((I,O)=>{try{let R=Ic(O);I.push({name:R.name,description:R.description,inputSchema:R.input_schema,annotations:LE(O)})}catch(R){let F=R instanceof Error?R.message:String(R);process.stderr.write(`[jaz-mcp] flat-mode: skipping malformed tool '${O.name}': ${F}
857
857
  `)}return I},[]);return s&&o.size>0&&E.unshift({name:Ph.name,description:Ph.description,inputSchema:Ph.inputSchema,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!0}}),{tools:E}}return{tools:g.map(E=>({name:E.name,description:E.description,inputSchema:E.inputSchema,annotations:{readOnlyHint:E.name!=="execute_tool",openWorldHint:!0}}))}}),p.setRequestHandler(h1,async()=>({resources:E$().map(({uri:E,name:I,description:O,mimeType:R})=>({uri:E,name:I,...O?{description:O}:{},mimeType:R}))})),p.setRequestHandler(y1,async E=>{let I=E.params.uri;try{let{mimeType:O,text:R}=LH(I);return{contents:[{uri:I,mimeType:O,text:R}]}}catch(O){throw new Ie(Re.InvalidRequest,O instanceof Error?O.message:`Resource not found: ${I}`)}}),p.setRequestHandler(Qm,async E=>{let I=E.params.name,O=E.params.arguments??{};if(I==="search_tools"){let F=O.query;if(F!==void 0&&typeof F!="string")return{content:[{type:"text",text:JSON.stringify({error:"Invalid `query` parameter. Expected string."})}],isError:!0};let P=NH(F??"");return{content:[{type:"text",text:JSON.stringify(P,null,2)}]}}if(I==="describe_tools"){let F=$H(O.tools);return{content:[{type:"text",text:JSON.stringify(F,null,2)}]}}if(I==="list_organizations"){if(!s||o.size===0)return{content:[{type:"text",text:JSON.stringify({error:"list_organizations is only available in multi-org mode (PAT or multiple API keys)."})}],isError:!0};if(r[0]?.mode==="pat")try{o=(await GH(r,5e3)).orgMap}catch(F){process.stderr.write(`warning: org refresh failed, using cached list: ${F instanceof Error?F.message:"unknown"}
858
858
  `)}return{content:[{type:"text",text:JSON.stringify({organizations:[...o.values()].map(({name:F,resourceId:P,currency:Y})=>({name:F,resourceId:P,currency:Y}))},null,2)}]}}if(I==="execute_tool"){let F=O.tool,P=O.arguments??{},Y=O.org_id;if(!F)return{content:[{type:"text",text:JSON.stringify({error:"Missing `tool` parameter.",hint:'Call search_tools first, then describe_tools, then execute_tool with { tool: "tool_name", arguments: {...} }.'})}],isError:!0};let J=Bl(F);if(!J)throw new Ie(Re.MethodNotFound,`Unknown tool: ${F}. Use search_tools to find available tools.`);if(!i&&!I$(J.group,J.name))return{content:[{type:"text",text:JSON.stringify({error:"No API key configured.",hint:`${JH} to use API tools. ${YH}`})}],isError:!0};let G=i;if(s&&o.size>0&&!I$(J.group,J.name)){if(!Y)return{content:[{type:"text",text:JSON.stringify({error:"Missing org_id. Multi-org mode requires an explicit organization for API tools.",hint:"Call list_organizations to see available orgs, then include org_id in execute_tool.",organizations:[...o.values()].map(({name:ge,resourceId:ae})=>({name:ge,resourceId:ae}))})}],isError:!0};let K=o.get(Y);if(!K)return{content:[{type:"text",text:JSON.stringify({error:`Unknown org_id: "${Y}".`,hint:"Call list_organizations to refresh the org list.",available:[...o.values()].map(({name:ge,resourceId:ae})=>({name:ge,resourceId:ae}))})}],isError:!0};let H=r[0];G=H?.mode==="pat"?KIe(H.token,Y):K.client}let V=TH(J,P);if(!V.valid)return{content:[{type:"text",text:JSON.stringify({error:`Validation: ${V.errors.join("; ")}`,hint:"Check required fields and types via describe_tools."})}],isError:!0};try{if(!G&&!I$(J.group,J.name))return{content:[{type:"text",text:JSON.stringify({error:"No API client available.",hint:"Set JAZ_API_KEY or pass --api-key."})}],isError:!0};let K={client:G},H=await J.execute(K,P);return{content:[{type:"text",text:typeof H=="string"?H:JSON.stringify(H,null,2)}]}}catch(K){return{content:[{type:"text",text:JSON.stringify(wH(K,{toolName:J.name,input:P}))}],isError:!0}}}let R=s&&o.size>0?"search_tools, describe_tools, execute_tool, list_organizations":"search_tools, describe_tools, execute_tool";throw new Ie(Re.MethodNotFound,`Unknown tool: ${I}. Available tools: ${R}.`)});let D=new $E;await p.connect(D);try{let{measureAllScenarios:E,emitManifestSizeLog:I}=await Promise.resolve().then(()=>(zH(),qH));I("mcp",E())}catch(E){process.stderr.write(`R4 manifest-size emit failed (non-fatal): ${E.message}
@@ -862,7 +862,7 @@ Dynamic Strings (usable in name, reference \u2014 any free text field):
862
862
  {{bankReference}} Bank record reference (e.g., INV-03/01/2025-01)
863
863
  {{bankPayee}} Payer/payee name (e.g., Fruit Planet)
864
864
  {{bankDescription}} Transaction description (e.g., QR Payment)
865
- Strings are replaced with actual bank record values during reconciliation.`);t.command("list").description("List bank rules").option("--limit <n>","Max results",U).option("--offset <n>","Offset",me).option("--all","Fetch all pages").option("--api-key <key>","API key").option("--format <type>","Output format: table, json, csv, yaml").option("--json","JSON output").action(A(async(r,n)=>{let o=await ce(n,i=>dS(r,i),{label:"Fetching bank rules"});se(o,HH,n,"Bank Rules")})),t.command("get <resourceId>").description("Get a bank rule").option("--api-key <key>","API key").option("--format <type>","Output format: table, json, csv, yaml").option("--json","JSON output").action((r,n)=>A(async o=>{let i=await hm(o,r);if(n.json){console.log(JSON.stringify(i.data,null,2));return}console.log(S("Name:"),i.data.name),console.log(S("Action:"),i.data.actionType),console.log(S("ID:"),i.data.resourceId)})(n)),ve({parent:t,fields:Jf,defaults:Gf,fetcher:pS,columns:HH,label:"Searching bank rules",positionalArg:"name",positionalFilter:r=>({name:{contains:r}})}),t.command("create").description("Create a bank reconciliation rule").option("--name <name>","Rule name (required)").option("--account <resourceId>","Bank account resourceId this rule applies to (required)").option("--config <json>","Rule configuration as JSON (nested under reconcileWithDirectCashEntry key)").option("--input <file>","Read full request body from JSON file (overrides flags)").option("--api-key <key>","API key").option("--format <type>","Output format: table, json, csv, yaml").option("--json","JSON output").action(A(async(r,n)=>{let o=B(n);if(!o&&((!n.name||!n.account)&&(console.error(k("Required: --name, --account")),console.error(C("Or use --input <file> to provide full JSON body.")),process.exit(1)),o={name:n.name,appliesToReconciliationAccount:n.account},n.config))try{o.configuration=JSON.parse(n.config)}catch{console.error(k("Invalid --config JSON")),process.exit(1)}let i=await fS(r,o);if(n.json){console.log(JSON.stringify(i.data,null,2));return}console.log(T("Bank rule created.")),console.log(S("ID:"),i.data.resourceId)})),t.command("update <resourceId>").description("Update a bank rule (FULL REPLACEMENT \u2014 reads current state, merges changes, writes back)").option("--name <name>","New name").option("--account <resourceId>","Bank account resourceId (required \u2014 PUT is full replacement)").option("--config <json>","Updated configuration as JSON (full replacement)").option("--input <file>","Read full update body from JSON file (overrides flags)").option("--api-key <key>","API key").option("--format <type>","Output format: table, json, csv, yaml").option("--json","JSON output").action((r,n)=>A(async o=>{let i=B(n),s;if(i)s={resourceId:r,...i};else{if(!n.account){console.error(k("--account is required for update (PUT is full replacement \u2014 GET does not return the UUID)")),console.error(C("Use: clio bank-rules update <id> --account <bank-account-uuid> [--name ...] [--config ...]")),process.exitCode=1;return}let u=(await hm(o,r)).data;if(s={resourceId:r,name:n.name??u.name,appliesToReconciliationAccount:n.account,configuration:u.configuration},n.config)try{s.configuration=JSON.parse(n.config)}catch{console.error(k("Invalid --config JSON")),process.exit(1)}}let a=await mS(o,r,s);if(n.json){console.log(JSON.stringify(a.data,null,2));return}console.log(T(`Bank rule ${r} updated.`))})(n)),t.command("delete <resourceId>").description("Delete a bank rule").option("--api-key <key>","API key").option("--format <type>","Output format: table, json, csv, yaml").option("--json","JSON output").action((r,n)=>A(async o=>{if(await hS(o,r),n.json){console.log(JSON.stringify({deleted:!0,resourceId:r}));return}console.log(T(`Bank rule ${r} deleted.`))})(n))}Q();tO();we();je();function ZH(e){let t=e.command("reconciliations").alias("recon").description("Apply reconciliation decisions to bank statement entries");t.command("quick-reconcile").description("Async, bulk: match bank entries to journals (max 500). Returns a jobId \u2014 poll with `clio background-jobs get <jobId>`.").option("--input <file>","Read JSON body from file (or pipe via stdin with --input -)").option("--api-key <key>","API key (overrides stored/env)").option("--json","Output as JSON").action(A(async(n,o)=>{let i=B(o);i||(console.error("Error: --input <file> is required (JSON with bankAccountResourceId + journalsForReconciliation[])"),process.exit(1));let s=await o_(n,i);o.json?console.log(JSON.stringify(s.data,null,2)):(console.log(T(`Quick reconcile started. Job ID: ${s.data.jobId}`)),console.log(z(` Poll progress: clio background-jobs get ${s.data.jobId}`)))})),t.command("bank-rule").description("Async, bulk: apply a bank rule to a batch of bank entries (max 500). Returns a jobId.").option("--input <file>","Read JSON body from file (or pipe via stdin with --input -)").option("--api-key <key>","API key (overrides stored/env)").option("--json","Output as JSON").action(A(async(n,o)=>{let i=B(o);i||(console.error("Error: --input <file> is required (JSON with actionShortcutResourceId + businessTransactionResourceIds[])"),process.exit(1));let s=await i_(n,i);o.json?console.log(JSON.stringify(s.data,null,2)):(console.log(T(`Apply bank rule started. Job ID: ${s.data.jobId}`)),console.log(z(` Poll progress: clio background-jobs get ${s.data.jobId}`)))}));let r=[{name:"direct-cash-entry",description:"Sync: reconcile a bank entry with a single cash-in / cash-out line. Direction inferred from the entry sign. NOT idempotent.",fn:s_},{name:"cash-journal",description:"Sync: reconcile a bank entry with a multi-line cashflow journal (max 200 lines). NOT idempotent.",fn:a_},{name:"manual-journal",description:"Sync: reconcile a bank entry with a double-entry manual journal. Bank-side leg auto-added by API. NOT idempotent.",fn:c_},{name:"cash-transfer",description:"Sync: reconcile a bank entry with an inter-account transfer. NOT idempotent.",fn:u_},{name:"invoice-receipt",description:"Sync (AR): create an invoice and auto-reconcile it to a bank entry. NOT idempotent.",fn:l_},{name:"bill-receipt",description:"Sync (AP): create a bill and auto-reconcile it to a bank entry. NOT idempotent.",fn:d_}];for(let n of r)t.command(n.name).description(n.description).option("--input <file>","Read JSON body from file (or pipe via stdin with --input -)").option("--api-key <key>","API key (overrides stored/env)").option("--json","Output as JSON").action(A(async(o,i)=>{let s=B(i);s||(console.error(`Error: --input <file> is required (JSON body for ${n.name})`),process.exit(1));let a=await n.fn(o,s);if(i.json)console.log(JSON.stringify(a.data,null,2));else{let c=a.data;console.log(T(`Reconciled. Entry ${c.bankStatementEntryResourceId} \u2192 status ${c.status}${c.reference?` (ref: ${c.reference})`:""}`))}}))}Q();QR();we();je();function KH(e){let t=e.command("drafts").description("Bulk-action server-side draft lifecycle (max 500 per call, mixed BT types): validate, convert to active, submit for approval");t.command("validate").description("BULK validate (sync) \u2014 up to 500 drafts in ONE call, mixing any combination of invoices/bills/credit notes. Returns per-item errors inline. No state change.").option("--input <file>","Read JSON body from file (or pipe via stdin with --input -)").option("--api-key <key>","API key (overrides stored/env)").option("--json","Output as JSON").action(A(async(r,n)=>{let o=C$(n),i=await t_(r,o);n.json?console.log(JSON.stringify(i.data,null,2)):console.log(T(`Validated ${o.length} draft(s). See JSON for per-item details (--json).`))})),t.command("convert-to-active").description("BULK promote drafts to ACTIVE (async) \u2014 up to 500 in ONE call, mixing any combination of invoices/bills/credit notes. Returns a jobId \u2014 poll with `clio background-jobs get <jobId>`. NOT idempotent \u2014 filter by status: DRAFT before submitting.").option("--input <file>","Read JSON body from file (or pipe via stdin with --input -)").option("--api-key <key>","API key (overrides stored/env)").option("--json","Output as JSON").action(A(async(r,n)=>{let o=C$(n),i=await r_(r,o);n.json?console.log(JSON.stringify(i.data,null,2)):(console.log(T(`Convert started. Job ID: ${i.data.jobId}`)),console.log(z(` Poll progress: clio background-jobs get ${i.data.jobId}`)))})),t.command("submit-for-approval").description("BULK submit drafts for approval (async) \u2014 up to 500 in ONE call, mixing any combination of invoices/bills/credit notes. Returns a jobId. NOT idempotent on drafts with an in-flight approval.").option("--input <file>","Read JSON body from file (or pipe via stdin with --input -)").option("--api-key <key>","API key (overrides stored/env)").option("--json","Output as JSON").action(A(async(r,n)=>{let o=C$(n),i=await n_(r,o);n.json?console.log(JSON.stringify(i.data,null,2)):(console.log(T(`Submit started. Job ID: ${i.data.jobId}`)),console.log(z(` Poll progress: clio background-jobs get ${i.data.jobId}`)))}))}function C$(e){let t=B(e);t||(console.error('Error: --input <file> is required (JSON with { "items": [{btResourceId, btType}] } or a bare array)'),process.exit(1));let r=t.items??t;try{pl(r)}catch(n){console.error(`Error: ${n.message}`),process.exit(1)}return r}Q();xS();we();je();ct();ht();Ve();He();var XH=[{key:"resourceId",header:"ID",format:ie},{key:"name",header:"Name"},{key:"status",header:"Status"},{key:"purchasePrice",header:"Cost",align:"right",format:or}];function QH(e){let t=e.command("fixed-assets").alias("fa").description("Manage fixed assets");t.command("list").description("List fixed assets").option("--limit <n>","Max results",U).option("--offset <n>","Offset",me).option("--all","Fetch all pages").option("--format <type>","Output format: table, json, csv, yaml").option("--api-key <key>","API key").option("--json","JSON output").action(A(async(r,n)=>{let o=await ce(n,i=>gS(r,i),{label:"Fetching fixed assets"});se(o,XH,n,"Fixed Assets")})),t.command("get <resourceId>").description("Get fixed asset details").option("--format <type>","Output format: table, json, csv, yaml").option("--api-key <key>","API key").option("--json","JSON output").action((r,n)=>A(async o=>{let i=await yS(o,r);if(n.json){console.log(JSON.stringify(i.data,null,2));return}let s=i.data;console.log(S("Name:"),s.name),console.log(S("Ref:"),s.reference),console.log(S("Status:"),s.status),console.log(S("Type:"),s.typeName),console.log(S("Purchase:"),s.purchaseAmount),console.log(S("NBV:"),s.netBookValueAmount),console.log(S("ID:"),s.resourceId)})(n)),ve({parent:t,fields:Cf,defaults:xf,fetcher:DS,columns:XH,label:"Searching fixed assets"}),t.command("create").description("Register a new fixed asset").option("--name <name>","Asset name (required)").option("--type <typeName>",'Asset type (e.g., "Buildings", "Vehicles", "Furniture")').option("--category <cat>","TANGIBLE or INTANGIBLE").option("--amount <n>","Purchase cost (required)",et).option("--date <YYYY-MM-DD>","Purchase date (required)").option("--depreciation-start <YYYY-MM-DD>","Depreciation start date (required)").option("--asset-account <id>","Asset account resourceId (required)").option("--depreciation-method <method>","STRAIGHT_LINE or NO_DEPRECIATION").option("--effective-life <months>","Effective life in months",U).option("--residual <n>","Residual/salvage value",et).option("--depreciation-expense-account <id>","Depreciation expense account resourceId").option("--accumulated-depreciation-account <id>","Accumulated depreciation account resourceId").option("--purchase-bt-type <type>","Linked purchase BT type: PURCHASE (bill) or JOURNAL_MANUAL").option("--purchase-bt-id <id>","Linked purchase BT resourceId (required for ACTIVE assets)").option("--notes <text>","Internal notes").option("--draft","Save as draft (default: true)").option("--finalize","Activate immediately (saveAsDraft: false)").option("--tag <name>","Tag name").option("--custom-fields <json>","Custom field values as JSON array").option("--input <file>","Read full request body from JSON file (overrides flags)").option("--format <type>","Output format: table, json, csv, yaml").option("--api-key <key>","API key").option("--json","JSON output").action(A(async(r,n)=>{let o=B(n);o||((!n.name||n.amount===void 0||!n.date||!n.assetAccount||!n.depreciationStart)&&(console.error(k("Required: --name, --amount, --date, --depreciation-start, --asset-account")),console.error(C("Or use --input <file> to provide full JSON body.")),process.exit(1)),o={name:n.name,purchaseAmount:n.amount,purchaseDate:n.date,depreciationStartDate:n.depreciationStart,purchaseAssetAccountResourceId:n.assetAccount},n.type&&(o.typeName=n.type),n.category&&(o.category=n.category),n.depreciationMethod&&(o.depreciationMethod=n.depreciationMethod),n.effectiveLife&&(o.effectiveLife=n.effectiveLife),n.residual!==void 0&&(o.depreciableValueResidualAmount=n.residual),n.depreciationExpenseAccount&&(o.depreciationExpenseAccountResourceId=n.depreciationExpenseAccount),n.accumulatedDepreciationAccount&&(o.accumulatedDepreciationAccountResourceId=n.accumulatedDepreciationAccount),n.purchaseBtType&&(o.purchaseBusinessTransactionType=n.purchaseBtType),n.purchaseBtId&&(o.purchaseBusinessTransactionResourceId=n.purchaseBtId),n.notes&&(o.internalNotes=n.notes),n.tag&&(o.tags=[n.tag]),n.finalize&&(o.saveAsDraft=!1)),n.customFields&&(o.customFields=Kt(n.customFields));let i=await bS(r,o);if(n.json){console.log(JSON.stringify(i.data,null,2));return}console.log(T("Fixed asset created.")),console.log(S("ID:"),i.data.resourceId)})),t.command("delete <resourceId>").description("Delete a draft fixed asset").option("--format <type>","Output format: table, json, csv, yaml").option("--api-key <key>","API key").option("--json","JSON output").action((r,n)=>A(async o=>{if(await SS(o,r),n.json){console.log(JSON.stringify({deleted:!0,resourceId:r}));return}console.log(T(`Fixed asset ${r} deleted.`))})(n)),t.command("update <resourceId>").description("Update a fixed asset").option("--name <name>","New name").option("--notes <text>","Internal notes").option("--depreciation-method <method>","STRAIGHT_LINE or NO_DEPRECIATION").option("--effective-life <months>","Effective life in months",U).option("--tag <name>","Tag name").option("--custom-fields <json>","Custom field values as JSON array").option("--input <file>","Read full update body from JSON file (overrides flags)").option("--format <type>","Output format: table, json, csv, yaml").option("--api-key <key>","API key").option("--json","JSON output").action((r,n)=>A(async o=>{let i=B(n),s;i?s=i:(s={},n.name!==void 0&&(s.name=n.name),n.notes!==void 0&&(s.internalNotes=n.notes),n.depreciationMethod&&(s.depreciationMethod=n.depreciationMethod),n.effectiveLife&&(s.effectiveLife=n.effectiveLife),n.tag&&(s.tags=[n.tag])),n.customFields&&(s.customFields=Kt(n.customFields));let a=await vS(o,r,s);if(n.json){console.log(JSON.stringify(a.data,null,2));return}console.log(T(`Fixed asset ${r} updated.`))})(n)),t.command("sell").description("Mark a fixed asset as sold").option("--id <resourceId>","Fixed asset resourceId").option("--depreciation-end-date <date>","Final depreciation date (YYYY-MM-DD)").option("--gain-loss-account <id>","Gain/loss account resourceId").option("--sale-type <type>","Sale BT type (JOURNAL_MANUAL, PURCHASE, SALE)").option("--sale-item <id>","Sale item resourceId").option("--input <file>","Read full body from JSON file").option("--format <type>","Output format: table, json, csv, yaml").option("--api-key <key>","API key").option("--json","JSON output").action(A(async(r,n)=>{let o=B(n);if(o){let s=await gm(r,o);if(n.json){console.log(JSON.stringify(s.data,null,2));return}console.log(T("Fixed asset marked as sold."));return}(!n.id||!n.depreciationEndDate||!n.gainLossAccount||!n.saleType||!n.saleItem)&&(console.error(k("Required: --id, --depreciation-end-date, --gain-loss-account, --sale-type, --sale-item")),process.exit(1));let i=await gm(r,{resourceId:n.id,depreciationEndDate:n.depreciationEndDate,assetDisposalGainLossAccountResourceId:n.gainLossAccount,saleBusinessTransactionType:n.saleType,saleItemResourceId:n.saleItem});if(n.json){console.log(JSON.stringify(i.data,null,2));return}console.log(T(`Fixed asset ${n.id} marked as sold.`))})),t.command("transfer").description("Register a pre-existing fixed asset with accumulated depreciation (no linked purchase transaction)").option("--name <name>","Asset name (required)").option("--type <typeName>",'Asset type (e.g., "Computers and Electronics")').option("--category <cat>","TANGIBLE or INTANGIBLE").option("--amount <n>","Purchase cost (required)",et).option("--date <YYYY-MM-DD>","Purchase date (required)").option("--depreciation-start <YYYY-MM-DD>","Depreciation start date (required)").option("--asset-account <id>","Asset account resourceId (required)").option("--depreciation-method <method>","STRAIGHT_LINE or NO_DEPRECIATION").option("--effective-life <months>","Effective life in months",U).option("--accumulated-depreciation <n>","Depreciation already incurred",et).option("--residual <n>","Residual/salvage value",et).option("--depreciation-expense-account <id>","Depreciation expense account resourceId").option("--accumulated-depreciation-account <id>","Accumulated depreciation account resourceId").option("--notes <text>","Internal notes").option("--draft","Save as draft (default: true)").option("--finalize","Activate immediately (saveAsDraft: false)").option("--input <file>","Read full transfer body from JSON file (overrides flags)").option("--format <type>","Output format: table, json, csv, yaml").option("--api-key <key>","API key").option("--json","JSON output").action(A(async(r,n)=>{let o=B(n);o||((!n.name||n.amount===void 0||!n.date||!n.assetAccount||!n.depreciationStart)&&(console.error(k("Required: --name, --amount, --date, --depreciation-start, --asset-account")),console.error(C("Or use --input <file> to provide full JSON body.")),process.exit(1)),o={name:n.name,purchaseAmount:n.amount,purchaseDate:n.date,depreciationStartDate:n.depreciationStart,purchaseAssetAccountResourceId:n.assetAccount},n.type&&(o.typeName=n.type),n.category&&(o.category=n.category),n.depreciationMethod&&(o.depreciationMethod=n.depreciationMethod),n.effectiveLife&&(o.effectiveLife=n.effectiveLife),n.accumulatedDepreciation!==void 0&&(o.bookValueAccumulatedDepreciationAmount=n.accumulatedDepreciation),n.residual!==void 0&&(o.depreciableValueResidualAmount=n.residual),n.depreciationExpenseAccount&&(o.depreciationExpenseAccountResourceId=n.depreciationExpenseAccount),n.accumulatedDepreciationAccount&&(o.accumulatedDepreciationAccountResourceId=n.accumulatedDepreciationAccount),n.notes&&(o.internalNotes=n.notes),n.finalize&&(o.saveAsDraft=!1));let i=await ES(r,o);if(n.json){console.log(JSON.stringify(i.data,null,2));return}console.log(T("Fixed asset registered (transfer)."))})),t.command("discard <resourceId>").description("Discard (write off) a fixed asset").option("--disposal-date <date>","Disposal date (YYYY-MM-DD)").option("--depreciation-end-date <date>","Final depreciation date (YYYY-MM-DD)").option("--gain-loss-account <id>","Gain/loss account resourceId").option("--format <type>","Output format: table, json, csv, yaml").option("--api-key <key>","API key").option("--json","JSON output").action((r,n)=>A(async o=>{(!n.disposalDate||!n.depreciationEndDate)&&(console.error(k("--disposal-date and --depreciation-end-date are required.")),process.exit(1));let i=await _S(o,r,{disposalDate:n.disposalDate,depreciationEndDate:n.depreciationEndDate,assetDisposalGainLossAccountResourceId:n.gainLossAccount});if(n.json){console.log(JSON.stringify(i.data,null,2));return}console.log(T(`Fixed asset ${r} discarded.`))})(n)),t.command("undo-disposal <resourceId>").description("Undo a fixed asset disposal").option("--format <type>","Output format: table, json, csv, yaml").option("--api-key <key>","API key").option("--json","JSON output").action((r,n)=>A(async o=>{let i=await IS(o,r);if(n.json){console.log(JSON.stringify(i.data,null,2));return}console.log(T(`Disposal undone for ${r}.`))})(n)),t.command("bulk-upsert").description("Create or update fixed assets in bulk (max 500). Natural key: reference. Each row requires registrationType (NEW | TRANSFER) and a typeCode. Returns a jobId \u2014 poll with `clio background-jobs get <jobId>`.").option("--input <file>","Read JSON body from file (or pipe via stdin with --input -)").option("--api-key <key>","API key (overrides stored/env)").option("--json","Output as JSON").action(A(async(r,n)=>{let o=B(n);o||(console.error('Error: --input <file> is required (JSON with { "fixedAssets": [...] } or a bare array)'),process.exit(1));let i=o.fixedAssets??o;Array.isArray(i)||(console.error('Error: expected { "fixedAssets": [...] }'),process.exit(1)),i.length===0&&(console.error("Error: fixedAssets array is empty."),process.exit(1)),i.length>500&&(console.error(`Error: max 500 per call (got ${i.length}). Split into batches.`),process.exit(1));let s=await CS(r,i);n.json?console.log(JSON.stringify(s.data,null,2)):(console.log(T(`Bulk upsert started. Job ID: ${s.data.jobId}`)),console.log(z(` Poll progress: clio background-jobs get ${s.data.jobId}`)))}))}Q();JR();we();je();ct();Ve();He();ht();var XIe=[{key:"resourceId",header:"ID",format:ie},{key:"status",header:"Status",format:e=>String(e)==="ACTIVE"?T(String(e)):C(String(e))},{key:"interval",header:"Interval"},{key:"totalAmount",header:"Amount",align:"right"},{key:"businessTransactionType",header:"Type"}],QIe=[{key:"resourceId",header:"ID",format:ie},{key:"scheduledTransactionType",header:"Type"},{key:"status",header:"Status",format:e=>C(String(e??""))}];function eW(e){let t=e.command("subscriptions").alias("subs").description("Manage recurring subscriptions");t.command("list").description("List subscriptions").option("--limit <n>","Max results",U).option("--offset <n>","Offset",me).option("--all","Fetch all pages").option("--format <type>","Output format: table, json, csv, yaml").option("--api-key <key>","API key").option("--json","JSON output").action(A(async(r,n)=>{let o=await ce(n,i=>AS(r,i),{label:"Fetching subscriptions"});se(o,XIe,n,"Subscriptions")})),t.command("get <resourceId>").description("Get subscription details").option("--format <type>","Output format: table, json, csv, yaml").option("--api-key <key>","API key").option("--json","JSON output").action((r,n)=>A(async o=>{let i=await ym(o,r);if(n.json){console.log(JSON.stringify(i.data,null,2));return}let s=i.data;console.log(S("Status:"),s.status),console.log(S("Interval:"),s.interval),console.log(S("Amount:"),s.totalAmount),console.log(S("Next:"),s.nextScheduleDate??"N/A"),console.log(S("ID:"),s.resourceId)})(n)),t.command("create").description("Create a recurring subscription (invoices only, with proration)").option("--interval <interval>","WEEKLY, MONTHLY, QUARTERLY, or YEARLY (required)").option("--start-date <YYYY-MM-DD>","Start date (required)").option("--end-date <YYYY-MM-DD>","End date (optional, omit for ongoing)").option("--contact <name|resourceId>","Customer contact (required)").option("--ref <reference>","Invoice reference").option("--date <YYYY-MM-DD>","Invoice date").option("--due <YYYY-MM-DD>","Due date").option("--account <name|resourceId>","Revenue account \u2014 applied to ALL line items (required)").option("--tax-profile <name|resourceId>","Tax profile \u2014 applied to ALL line items").option("--lines <json>","Line items as JSON array (name, unitPrice, quantity)").option("--amount <n>","Single line item amount (shorthand)",et).option("--line-name <name>","Line item name (used with --amount)").option("--input <file>","Read full request body from JSON file (overrides flags)").option("--format <type>","Output format: table, json, csv, yaml").option("--api-key <key>","API key").option("--json","JSON output").action(A(async(r,n)=>{let o=B(n);if(!o){(!n.interval||!n.startDate)&&(console.error(k("Required: --interval, --start-date")),console.error(C("Or use --input <file> to provide full JSON body.")),process.exit(1));let s;if(n.lines)try{s=JSON.parse(n.lines)}catch{console.error(k("Invalid --lines JSON")),process.exit(1)}else n.amount!==void 0&&(s=[{name:n.lineName??"Subscription",unitPrice:n.amount,quantity:1}]);s&&(n.account||n.taxProfile)&&(s=s.map(a=>({...a,...n.account&&!a.accountResourceId?{accountResourceId:n.account}:{},...n.taxProfile&&!a.taxProfileResourceId?{taxProfileResourceId:n.taxProfile}:{}}))),o={repeat:n.interval,startDate:n.startDate,status:"ACTIVE",proratedConfig:{proratedAdjustmentLineText:"Prorated adjustment"},invoice:{contactResourceId:n.contact,reference:n.ref,valueDate:n.date,dueDate:n.due,lineItems:s,saveAsDraft:!1}},n.endDate&&(o.endDate=n.endDate)}let i=await wS(r,o);if(n.json){console.log(JSON.stringify(i.data,null,2));return}console.log(T("Subscription created.")),console.log(S("ID:"),i.data.resourceId)})),t.command("update <resourceId>").description("Update a subscription").option("--input <file>","Read full update body from JSON file").option("--format <type>","Output format: table, json, csv, yaml").option("--api-key <key>","API key").option("--json","JSON output").action((r,n)=>A(async o=>{let i=B(n);i||(console.error(k("Use --input <file> to provide update data.")),process.exit(1));let s=await TS(o,r,i);if(n.json){console.log(JSON.stringify(s.data,null,2));return}console.log(T(`Subscription ${r} updated.`))})(n)),t.command("delete <resourceId>").description("Delete a subscription").option("--format <type>","Output format: table, json, csv, yaml").option("--api-key <key>","API key").option("--json","JSON output").action((r,n)=>A(async o=>{if(await RS(o,r),n.json){console.log(JSON.stringify({deleted:!0,resourceId:r}));return}console.log(T(`Subscription ${r} deleted.`))})(n)),t.command("cancel <resourceId>").description("Cancel an active subscription (prorates remaining period)").option("--cancel-date-type <type>","END_OF_CURRENT_PERIOD, END_OF_LAST_PERIOD, or CUSTOM_DATE","END_OF_CURRENT_PERIOD").option("--end-date <YYYY-MM-DD>","Custom cancel date (only with CUSTOM_DATE)").option("--prorated-text <text>","Prorated adjustment line text","Prorated adjustment").option("--format <type>","Output format: table, json, csv, yaml").option("--api-key <key>","API key").option("--json","JSON output").action((r,n)=>A(async o=>{if(await OS(o,r,{cancelDateType:n.cancelDateType,proratedAdjustmentLineText:n.proratedText,endDate:n.endDate}),n.json){console.log(JSON.stringify({cancelled:!0,resourceId:r}));return}console.log(T(`Subscription ${r} cancelled.`))})(n)),ve({parent:t,commandName:"search-scheduled",fields:Af,defaults:wf,fetcher:NS,columns:QIe,label:"Searching scheduled transactions"})}Q();GR();we();Ve();je();ct();He();ht();var tW=[{key:"resourceId",header:"ID",format:ie},{key:"name",header:"Name"}];function rW(e){let t=e.command("contact-groups").description("Manage contact groups");t.command("list").description("List contact groups").option("--limit <n>","Max results",U).option("--offset <n>","Offset",me).option("--all","Fetch all pages").option("--api-key <key>","API key").option("--format <type>","Output format: table, json, csv, yaml").option("--json","JSON output").action(A(async(r,n)=>{let o=await ce(n,i=>$S(r,i),{label:"Fetching contact groups"});se(o,tW,n,"Contact Groups")})),t.command("get <resourceId>").description("Get contact group details").option("--api-key <key>","API key").option("--format <type>","Output format: table, json, csv, yaml").option("--json","JSON output").action((r,n)=>A(async o=>{let i=await kS(o,r);if(n.json){console.log(JSON.stringify(i.data,null,2));return}let s=i.data;console.log(S("Name:"),s.name),console.log(S("Contacts:"),s.associatedContacts?.length??0);for(let a of s.associatedContacts??[])console.log(` ${z(a.resourceId)} ${a.name}`);console.log(S("ID:"),s.resourceId)})(n)),ve({parent:t,fields:Uf,defaults:qf,fetcher:FS,columns:tW,label:"Searching contact groups",positionalArg:"name",positionalFilter:r=>({name:{contains:r}})}),t.command("create").description("Create a contact group").option("--name <name>","Group name").option("--api-key <key>","API key").option("--format <type>","Output format: table, json, csv, yaml").option("--json","JSON output").action(A(async(r,n)=>{ue(n,[{flag:"--name",key:"name"}]);let o=await PS(r,{name:n.name});if(n.json){console.log(JSON.stringify(o.data,null,2));return}console.log(T(`Contact group "${n.name}" created.`)),console.log(S("ID:"),o.data.resourceId)})),t.command("update <resourceId>").description("Update a contact group").option("--name <name>","New group name").option("--api-key <key>","API key").option("--format <type>","Output format: table, json, csv, yaml").option("--json","JSON output").action((r,n)=>A(async o=>{let i={};n.name&&(i.name=n.name);let s=await LS(o,r,i);if(n.json){console.log(JSON.stringify(s.data,null,2));return}console.log(T("Contact group updated.")),console.log(S("ID:"),s.data.resourceId)})(n)),t.command("delete <resourceId>").description("Delete a contact group").option("--api-key <key>","API key").option("--json","JSON output").action((r,n)=>A(async o=>{if(await jS(o,r),n.json){console.log(JSON.stringify({deleted:!0,resourceId:r}));return}console.log(T(`Contact group ${r} deleted.`))})(n))}VR();we();je();ct();Ve();He();Q();var eCe=[{key:"resourceId",header:"ID",format:ie},{key:"internalName",header:"Name",format:e=>String(e??"")},{key:"itemCode",header:"Code",format:e=>C(String(e??""))}];function nW(e){let t=e.command("inventory").alias("inv").description("Inventory management");t.command("items").description("List inventory-tracked items").option("--limit <n>","Max results",U).option("--offset <n>","Offset",me).option("--all","Fetch all pages").option("--format <type>","Output format: table, json, csv, yaml").option("--api-key <key>","API key").option("--json","JSON output").action(A(async(r,n)=>{let o=await ce(n,i=>MS(r,i),{label:"Fetching inventory items"});se(o,eCe,n,"Inventory Items")})),t.command("balance <itemResourceId>").description("Get inventory balance for an item").option("--format <type>","Output format: table, json, csv, yaml").option("--api-key <key>","API key").option("--json","JSON output").action((r,n)=>A(async o=>{let i=await US(o,r);if(n.json){console.log(JSON.stringify(i.data,null,2));return}let s=i.data;console.log(S("Item:"),s.itemResourceId),console.log(S("Qty:"),`${s.baseQty} ${s.baseUnit}`),console.log(S("Avg Cost:"),s.latestAverageCostAmount)})(n)),t.command("create").description("Create an inventory-tracked item (use --input for full JSON body)").option("--item-code <code>","Item code (SKU)").option("--name <name>","Item name").option("--unit <unit>","Unit of measure").option("--costing-method <method>","FIXED or WAC").option("--input <file>","Read full request body from JSON file (or pipe via stdin)").option("--api-key <key>","API key").option("--format <type>","Output format: table, json, csv, yaml").option("--json","JSON output").action(A(async(r,n)=>{let o=B(n);o||ue(n,[{flag:"--item-code",key:"itemCode"},{flag:"--name",key:"name"}]);let i=o??{itemCode:n.itemCode,name:n.name,unit:n.unit,costingMethod:n.costingMethod},s=await BS(r,i);if(n.json){console.log(JSON.stringify(s.data,null,2));return}console.log(T("Inventory item created.")),console.log(S("ID:"),s.data.resourceId)}))}Q();HR();we();Ve();je();ct();He();ht();var oW=[{key:"resourceId",header:"ID",format:ie},{key:"customFieldName",header:"Name"}];function iW(e){let t=e.command("custom-fields").description("Manage custom fields");t.command("list").description("List custom fields").option("--limit <n>","Max results",U).option("--offset <n>","Offset",me).option("--all","Fetch all pages").option("--api-key <key>","API key").option("--format <type>","Output format: table, json, csv, yaml").option("--json","JSON output").action(A(async(r,n)=>{let o=await ce(n,i=>qS(r,i),{label:"Fetching custom fields"});se(o,oW,n,"Custom Fields")})),t.command("get <resourceId>").description("Get a custom field by resourceId").option("--api-key <key>","API key").option("--format <type>","Output format: table, json, csv, yaml").option("--json","JSON output").action((r,n)=>A(async o=>{let s=(await zS(o,r)).data;if(n.json){console.log(JSON.stringify(s,null,2));return}console.log(S("Name:"),s.customFieldName||s.name||"(unnamed)"),console.log(S("ID:"),s.resourceId),console.log(S("Type:"),s.datatypeCode||s.fieldType||"\u2014"),s.description&&console.log(S("Description:"),s.description),s.defaultValue&&console.log(S("Default:"),s.defaultValue),s.listOptions?.length&&console.log(S("Options:"),s.listOptions.join(", "));let a=u=>u===!0||u==="true",c=[];a(s.applyToSales)&&c.push("invoices"),a(s.applyToPurchase)&&c.push("bills"),a(s.applyToSaleCreditNote)&&c.push("customer CNs"),a(s.applyToPurchaseCreditNote)&&c.push("supplier CNs"),a(s.applyToPayment)&&c.push("payments"),a(s.appliesToFixedAssets)&&c.push("fixed assets"),c.length&&console.log(S("Applies to:"),c.join(", "))})(n)),ve({parent:t,fields:Mf,defaults:Bf,fetcher:YS,columns:oW,label:"Searching custom fields"}),t.command("create").description("Create a custom field").option("--name <name>","Field name").option("--description <text>","Field description").option("--print-on-documents","Print this field on PDF documents").option("--invoices","Apply to invoices").option("--bills","Apply to bills").option("--customer-credits","Apply to customer credit notes").option("--supplier-credits","Apply to supplier credit notes").option("--payments","Apply to payments").option("--field-type <type>","Field type (TEXT, NUMBER, DATE, DROPDOWN)","TEXT").option("--entity-type <type>","Entity type (legacy, prefer --invoices/--bills flags)","BUSINESS_TRANSACTION").option("--api-key <key>","API key").option("--format <type>","Output format: table, json, csv, yaml").option("--json","JSON output").action(A(async(r,n)=>{ue(n,[{flag:"--name",key:"name"}]);let i=n.invoices||n.bills||n.customerCredits||n.supplierCredits||n.payments?{invoices:n.invoices??!1,bills:n.bills??!1,customerCredits:n.customerCredits??!1,supplierCredits:n.supplierCredits??!1,payments:n.payments??!1}:void 0,s=await JS(r,{name:n.name,description:n.description,printOnDocuments:n.printOnDocuments??!1,appliesTo:i,fieldType:n.fieldType,entityType:n.entityType});if(n.json){console.log(JSON.stringify(s.data,null,2));return}console.log(T(`Custom field "${n.name}" created.`)),console.log(S("ID:"),s.data.resourceId)})),t.command("update <resourceId>").description("Update a custom field").option("--name <name>","New field name").option("--description <text>","New description").option("--print-on-documents","Print on PDF documents").option("--no-print-on-documents","Do not print on PDF documents").option("--invoices","Apply to invoices").option("--bills","Apply to bills").option("--customer-credits","Apply to customer credit notes").option("--supplier-credits","Apply to supplier credit notes").option("--payments","Apply to payments").option("--api-key <key>","API key").option("--format <type>","Output format: table, json, csv, yaml").option("--json","JSON output").action((r,n)=>A(async o=>{let i={};n.name!==void 0&&(i.name=n.name),n.description!==void 0&&(i.description=n.description),n.printOnDocuments!==void 0&&(i.printOnDocuments=n.printOnDocuments),(n.invoices!==void 0||n.bills!==void 0||n.customerCredits!==void 0||n.supplierCredits!==void 0||n.payments!==void 0)&&(i.appliesTo={invoices:n.invoices??!1,bills:n.bills??!1,customerCredits:n.customerCredits??!1,supplierCredits:n.supplierCredits??!1,payments:n.payments??!1});let a=await GS(o,r,i);if(n.json){console.log(JSON.stringify(a.data,null,2));return}console.log(T(`Custom field ${r} updated.`))})(n)),t.command("delete <resourceId>").description("Delete a custom field").option("--api-key <key>","API key").option("--format <type>","Output format: table, json, csv, yaml").option("--json","JSON output").action((r,n)=>A(async o=>{if(await VS(o,r),n.json){console.log(JSON.stringify({deleted:!0,resourceId:r}));return}console.log(T(`Custom field ${r} deleted.`))})(n))}Q();WR();we();import{readFileSync as tCe}from"node:fs";function sW(e,t){try{return JSON.parse(e)}catch(r){return console.error(k(`Invalid JSON in ${t}: ${r.message}`)),process.exitCode=1,null}}function aW(e){let t=e.command("quick-fix <entity>").description("Bulk-update transactions or line items in one call").addHelpText("after",`
865
+ Strings are replaced with actual bank record values during reconciliation.`);t.command("list").description("List bank rules").option("--limit <n>","Max results",U).option("--offset <n>","Page number offset (0-indexed)",me).option("--all","Fetch all pages").option("--api-key <key>","API key").option("--format <type>","Output format: table, json, csv, yaml").option("--json","JSON output").action(A(async(r,n)=>{let o=await ce(n,i=>dS(r,i),{label:"Fetching bank rules"});se(o,HH,n,"Bank Rules")})),t.command("get <resourceId>").description("Get a bank rule").option("--api-key <key>","API key").option("--format <type>","Output format: table, json, csv, yaml").option("--json","JSON output").action((r,n)=>A(async o=>{let i=await hm(o,r);if(n.json){console.log(JSON.stringify(i.data,null,2));return}console.log(S("Name:"),i.data.name),console.log(S("Action:"),i.data.actionType),console.log(S("ID:"),i.data.resourceId)})(n)),ve({parent:t,fields:Jf,defaults:Gf,fetcher:pS,columns:HH,label:"Searching bank rules",positionalArg:"name",positionalFilter:r=>({name:{contains:r}})}),t.command("create").description("Create a bank reconciliation rule").option("--name <name>","Rule name (required)").option("--account <resourceId>","Bank account resourceId this rule applies to (required)").option("--config <json>","Rule configuration as JSON (nested under reconcileWithDirectCashEntry key)").option("--input <file>","Read full request body from JSON file (overrides flags)").option("--api-key <key>","API key").option("--format <type>","Output format: table, json, csv, yaml").option("--json","JSON output").action(A(async(r,n)=>{let o=B(n);if(!o&&((!n.name||!n.account)&&(console.error(k("Required: --name, --account")),console.error(C("Or use --input <file> to provide full JSON body.")),process.exit(1)),o={name:n.name,appliesToReconciliationAccount:n.account},n.config))try{o.configuration=JSON.parse(n.config)}catch{console.error(k("Invalid --config JSON")),process.exit(1)}let i=await fS(r,o);if(n.json){console.log(JSON.stringify(i.data,null,2));return}console.log(T("Bank rule created.")),console.log(S("ID:"),i.data.resourceId)})),t.command("update <resourceId>").description("Update a bank rule (FULL REPLACEMENT \u2014 reads current state, merges changes, writes back)").option("--name <name>","New name").option("--account <resourceId>","Bank account resourceId (required \u2014 PUT is full replacement)").option("--config <json>","Updated configuration as JSON (full replacement)").option("--input <file>","Read full update body from JSON file (overrides flags)").option("--api-key <key>","API key").option("--format <type>","Output format: table, json, csv, yaml").option("--json","JSON output").action((r,n)=>A(async o=>{let i=B(n),s;if(i)s={resourceId:r,...i};else{if(!n.account){console.error(k("--account is required for update (PUT is full replacement \u2014 GET does not return the UUID)")),console.error(C("Use: clio bank-rules update <id> --account <bank-account-uuid> [--name ...] [--config ...]")),process.exitCode=1;return}let u=(await hm(o,r)).data;if(s={resourceId:r,name:n.name??u.name,appliesToReconciliationAccount:n.account,configuration:u.configuration},n.config)try{s.configuration=JSON.parse(n.config)}catch{console.error(k("Invalid --config JSON")),process.exit(1)}}let a=await mS(o,r,s);if(n.json){console.log(JSON.stringify(a.data,null,2));return}console.log(T(`Bank rule ${r} updated.`))})(n)),t.command("delete <resourceId>").description("Delete a bank rule").option("--api-key <key>","API key").option("--format <type>","Output format: table, json, csv, yaml").option("--json","JSON output").action((r,n)=>A(async o=>{if(await hS(o,r),n.json){console.log(JSON.stringify({deleted:!0,resourceId:r}));return}console.log(T(`Bank rule ${r} deleted.`))})(n))}Q();tO();we();je();function ZH(e){let t=e.command("reconciliations").alias("recon").description("Apply reconciliation decisions to bank statement entries");t.command("quick-reconcile").description("Async, bulk: match bank entries to journals (max 500). Returns a jobId \u2014 poll with `clio background-jobs get <jobId>`.").option("--input <file>","Read JSON body from file (or pipe via stdin with --input -)").option("--api-key <key>","API key (overrides stored/env)").option("--json","Output as JSON").action(A(async(n,o)=>{let i=B(o);i||(console.error("Error: --input <file> is required (JSON with bankAccountResourceId + journalsForReconciliation[])"),process.exit(1));let s=await o_(n,i);o.json?console.log(JSON.stringify(s.data,null,2)):(console.log(T(`Quick reconcile started. Job ID: ${s.data.jobId}`)),console.log(z(` Poll progress: clio background-jobs get ${s.data.jobId}`)))})),t.command("bank-rule").description("Async, bulk: apply a bank rule to a batch of bank entries (max 500). Returns a jobId.").option("--input <file>","Read JSON body from file (or pipe via stdin with --input -)").option("--api-key <key>","API key (overrides stored/env)").option("--json","Output as JSON").action(A(async(n,o)=>{let i=B(o);i||(console.error("Error: --input <file> is required (JSON with actionShortcutResourceId + businessTransactionResourceIds[])"),process.exit(1));let s=await i_(n,i);o.json?console.log(JSON.stringify(s.data,null,2)):(console.log(T(`Apply bank rule started. Job ID: ${s.data.jobId}`)),console.log(z(` Poll progress: clio background-jobs get ${s.data.jobId}`)))}));let r=[{name:"direct-cash-entry",description:"Sync: reconcile a bank entry with a single cash-in / cash-out line. Direction inferred from the entry sign. NOT idempotent.",fn:s_},{name:"cash-journal",description:"Sync: reconcile a bank entry with a multi-line cashflow journal (max 200 lines). NOT idempotent.",fn:a_},{name:"manual-journal",description:"Sync: reconcile a bank entry with a double-entry manual journal. Bank-side leg auto-added by API. NOT idempotent.",fn:c_},{name:"cash-transfer",description:"Sync: reconcile a bank entry with an inter-account transfer. NOT idempotent.",fn:u_},{name:"invoice-receipt",description:"Sync (AR): create an invoice and auto-reconcile it to a bank entry. NOT idempotent.",fn:l_},{name:"bill-receipt",description:"Sync (AP): create a bill and auto-reconcile it to a bank entry. NOT idempotent.",fn:d_}];for(let n of r)t.command(n.name).description(n.description).option("--input <file>","Read JSON body from file (or pipe via stdin with --input -)").option("--api-key <key>","API key (overrides stored/env)").option("--json","Output as JSON").action(A(async(o,i)=>{let s=B(i);s||(console.error(`Error: --input <file> is required (JSON body for ${n.name})`),process.exit(1));let a=await n.fn(o,s);if(i.json)console.log(JSON.stringify(a.data,null,2));else{let c=a.data;console.log(T(`Reconciled. Entry ${c.bankStatementEntryResourceId} \u2192 status ${c.status}${c.reference?` (ref: ${c.reference})`:""}`))}}))}Q();QR();we();je();function KH(e){let t=e.command("drafts").description("Bulk-action server-side draft lifecycle (max 500 per call, mixed BT types): validate, convert to active, submit for approval");t.command("validate").description("BULK validate (sync) \u2014 up to 500 drafts in ONE call, mixing any combination of invoices/bills/credit notes. Returns per-item errors inline. No state change.").option("--input <file>","Read JSON body from file (or pipe via stdin with --input -)").option("--api-key <key>","API key (overrides stored/env)").option("--json","Output as JSON").action(A(async(r,n)=>{let o=C$(n),i=await t_(r,o);n.json?console.log(JSON.stringify(i.data,null,2)):console.log(T(`Validated ${o.length} draft(s). See JSON for per-item details (--json).`))})),t.command("convert-to-active").description("BULK promote drafts to ACTIVE (async) \u2014 up to 500 in ONE call, mixing any combination of invoices/bills/credit notes. Returns a jobId \u2014 poll with `clio background-jobs get <jobId>`. NOT idempotent \u2014 filter by status: DRAFT before submitting.").option("--input <file>","Read JSON body from file (or pipe via stdin with --input -)").option("--api-key <key>","API key (overrides stored/env)").option("--json","Output as JSON").action(A(async(r,n)=>{let o=C$(n),i=await r_(r,o);n.json?console.log(JSON.stringify(i.data,null,2)):(console.log(T(`Convert started. Job ID: ${i.data.jobId}`)),console.log(z(` Poll progress: clio background-jobs get ${i.data.jobId}`)))})),t.command("submit-for-approval").description("BULK submit drafts for approval (async) \u2014 up to 500 in ONE call, mixing any combination of invoices/bills/credit notes. Returns a jobId. NOT idempotent on drafts with an in-flight approval.").option("--input <file>","Read JSON body from file (or pipe via stdin with --input -)").option("--api-key <key>","API key (overrides stored/env)").option("--json","Output as JSON").action(A(async(r,n)=>{let o=C$(n),i=await n_(r,o);n.json?console.log(JSON.stringify(i.data,null,2)):(console.log(T(`Submit started. Job ID: ${i.data.jobId}`)),console.log(z(` Poll progress: clio background-jobs get ${i.data.jobId}`)))}))}function C$(e){let t=B(e);t||(console.error('Error: --input <file> is required (JSON with { "items": [{btResourceId, btType}] } or a bare array)'),process.exit(1));let r=t.items??t;try{pl(r)}catch(n){console.error(`Error: ${n.message}`),process.exit(1)}return r}Q();xS();we();je();ct();ht();Ve();He();var XH=[{key:"resourceId",header:"ID",format:ie},{key:"name",header:"Name"},{key:"status",header:"Status"},{key:"purchasePrice",header:"Cost",align:"right",format:or}];function QH(e){let t=e.command("fixed-assets").alias("fa").description("Manage fixed assets");t.command("list").description("List fixed assets").option("--limit <n>","Max results",U).option("--offset <n>","Page number offset (0-indexed)",me).option("--all","Fetch all pages").option("--format <type>","Output format: table, json, csv, yaml").option("--api-key <key>","API key").option("--json","JSON output").action(A(async(r,n)=>{let o=await ce(n,i=>gS(r,i),{label:"Fetching fixed assets"});se(o,XH,n,"Fixed Assets")})),t.command("get <resourceId>").description("Get fixed asset details").option("--format <type>","Output format: table, json, csv, yaml").option("--api-key <key>","API key").option("--json","JSON output").action((r,n)=>A(async o=>{let i=await yS(o,r);if(n.json){console.log(JSON.stringify(i.data,null,2));return}let s=i.data;console.log(S("Name:"),s.name),console.log(S("Ref:"),s.reference),console.log(S("Status:"),s.status),console.log(S("Type:"),s.typeName),console.log(S("Purchase:"),s.purchaseAmount),console.log(S("NBV:"),s.netBookValueAmount),console.log(S("ID:"),s.resourceId)})(n)),ve({parent:t,fields:Cf,defaults:xf,fetcher:DS,columns:XH,label:"Searching fixed assets"}),t.command("create").description("Register a new fixed asset").option("--name <name>","Asset name (required)").option("--type <typeName>",'Asset type (e.g., "Buildings", "Vehicles", "Furniture")').option("--category <cat>","TANGIBLE or INTANGIBLE").option("--amount <n>","Purchase cost (required)",et).option("--date <YYYY-MM-DD>","Purchase date (required)").option("--depreciation-start <YYYY-MM-DD>","Depreciation start date (required)").option("--asset-account <id>","Asset account resourceId (required)").option("--depreciation-method <method>","STRAIGHT_LINE or NO_DEPRECIATION").option("--effective-life <months>","Effective life in months",U).option("--residual <n>","Residual/salvage value",et).option("--depreciation-expense-account <id>","Depreciation expense account resourceId").option("--accumulated-depreciation-account <id>","Accumulated depreciation account resourceId").option("--purchase-bt-type <type>","Linked purchase BT type: PURCHASE (bill) or JOURNAL_MANUAL").option("--purchase-bt-id <id>","Linked purchase BT resourceId (required for ACTIVE assets)").option("--notes <text>","Internal notes").option("--draft","Save as draft (default: true)").option("--finalize","Activate immediately (saveAsDraft: false)").option("--tag <name>","Tag name").option("--custom-fields <json>","Custom field values as JSON array").option("--input <file>","Read full request body from JSON file (overrides flags)").option("--format <type>","Output format: table, json, csv, yaml").option("--api-key <key>","API key").option("--json","JSON output").action(A(async(r,n)=>{let o=B(n);o||((!n.name||n.amount===void 0||!n.date||!n.assetAccount||!n.depreciationStart)&&(console.error(k("Required: --name, --amount, --date, --depreciation-start, --asset-account")),console.error(C("Or use --input <file> to provide full JSON body.")),process.exit(1)),o={name:n.name,purchaseAmount:n.amount,purchaseDate:n.date,depreciationStartDate:n.depreciationStart,purchaseAssetAccountResourceId:n.assetAccount},n.type&&(o.typeName=n.type),n.category&&(o.category=n.category),n.depreciationMethod&&(o.depreciationMethod=n.depreciationMethod),n.effectiveLife&&(o.effectiveLife=n.effectiveLife),n.residual!==void 0&&(o.depreciableValueResidualAmount=n.residual),n.depreciationExpenseAccount&&(o.depreciationExpenseAccountResourceId=n.depreciationExpenseAccount),n.accumulatedDepreciationAccount&&(o.accumulatedDepreciationAccountResourceId=n.accumulatedDepreciationAccount),n.purchaseBtType&&(o.purchaseBusinessTransactionType=n.purchaseBtType),n.purchaseBtId&&(o.purchaseBusinessTransactionResourceId=n.purchaseBtId),n.notes&&(o.internalNotes=n.notes),n.tag&&(o.tags=[n.tag]),n.finalize&&(o.saveAsDraft=!1)),n.customFields&&(o.customFields=Kt(n.customFields));let i=await bS(r,o);if(n.json){console.log(JSON.stringify(i.data,null,2));return}console.log(T("Fixed asset created.")),console.log(S("ID:"),i.data.resourceId)})),t.command("delete <resourceId>").description("Delete a draft fixed asset").option("--format <type>","Output format: table, json, csv, yaml").option("--api-key <key>","API key").option("--json","JSON output").action((r,n)=>A(async o=>{if(await SS(o,r),n.json){console.log(JSON.stringify({deleted:!0,resourceId:r}));return}console.log(T(`Fixed asset ${r} deleted.`))})(n)),t.command("update <resourceId>").description("Update a fixed asset").option("--name <name>","New name").option("--notes <text>","Internal notes").option("--depreciation-method <method>","STRAIGHT_LINE or NO_DEPRECIATION").option("--effective-life <months>","Effective life in months",U).option("--tag <name>","Tag name").option("--custom-fields <json>","Custom field values as JSON array").option("--input <file>","Read full update body from JSON file (overrides flags)").option("--format <type>","Output format: table, json, csv, yaml").option("--api-key <key>","API key").option("--json","JSON output").action((r,n)=>A(async o=>{let i=B(n),s;i?s=i:(s={},n.name!==void 0&&(s.name=n.name),n.notes!==void 0&&(s.internalNotes=n.notes),n.depreciationMethod&&(s.depreciationMethod=n.depreciationMethod),n.effectiveLife&&(s.effectiveLife=n.effectiveLife),n.tag&&(s.tags=[n.tag])),n.customFields&&(s.customFields=Kt(n.customFields));let a=await vS(o,r,s);if(n.json){console.log(JSON.stringify(a.data,null,2));return}console.log(T(`Fixed asset ${r} updated.`))})(n)),t.command("sell").description("Mark a fixed asset as sold").option("--id <resourceId>","Fixed asset resourceId").option("--depreciation-end-date <date>","Final depreciation date (YYYY-MM-DD)").option("--gain-loss-account <id>","Gain/loss account resourceId").option("--sale-type <type>","Sale BT type (JOURNAL_MANUAL, PURCHASE, SALE)").option("--sale-item <id>","Sale item resourceId").option("--input <file>","Read full body from JSON file").option("--format <type>","Output format: table, json, csv, yaml").option("--api-key <key>","API key").option("--json","JSON output").action(A(async(r,n)=>{let o=B(n);if(o){let s=await gm(r,o);if(n.json){console.log(JSON.stringify(s.data,null,2));return}console.log(T("Fixed asset marked as sold."));return}(!n.id||!n.depreciationEndDate||!n.gainLossAccount||!n.saleType||!n.saleItem)&&(console.error(k("Required: --id, --depreciation-end-date, --gain-loss-account, --sale-type, --sale-item")),process.exit(1));let i=await gm(r,{resourceId:n.id,depreciationEndDate:n.depreciationEndDate,assetDisposalGainLossAccountResourceId:n.gainLossAccount,saleBusinessTransactionType:n.saleType,saleItemResourceId:n.saleItem});if(n.json){console.log(JSON.stringify(i.data,null,2));return}console.log(T(`Fixed asset ${n.id} marked as sold.`))})),t.command("transfer").description("Register a pre-existing fixed asset with accumulated depreciation (no linked purchase transaction)").option("--name <name>","Asset name (required)").option("--type <typeName>",'Asset type (e.g., "Computers and Electronics")').option("--category <cat>","TANGIBLE or INTANGIBLE").option("--amount <n>","Purchase cost (required)",et).option("--date <YYYY-MM-DD>","Purchase date (required)").option("--depreciation-start <YYYY-MM-DD>","Depreciation start date (required)").option("--asset-account <id>","Asset account resourceId (required)").option("--depreciation-method <method>","STRAIGHT_LINE or NO_DEPRECIATION").option("--effective-life <months>","Effective life in months",U).option("--accumulated-depreciation <n>","Depreciation already incurred",et).option("--residual <n>","Residual/salvage value",et).option("--depreciation-expense-account <id>","Depreciation expense account resourceId").option("--accumulated-depreciation-account <id>","Accumulated depreciation account resourceId").option("--notes <text>","Internal notes").option("--draft","Save as draft (default: true)").option("--finalize","Activate immediately (saveAsDraft: false)").option("--input <file>","Read full transfer body from JSON file (overrides flags)").option("--format <type>","Output format: table, json, csv, yaml").option("--api-key <key>","API key").option("--json","JSON output").action(A(async(r,n)=>{let o=B(n);o||((!n.name||n.amount===void 0||!n.date||!n.assetAccount||!n.depreciationStart)&&(console.error(k("Required: --name, --amount, --date, --depreciation-start, --asset-account")),console.error(C("Or use --input <file> to provide full JSON body.")),process.exit(1)),o={name:n.name,purchaseAmount:n.amount,purchaseDate:n.date,depreciationStartDate:n.depreciationStart,purchaseAssetAccountResourceId:n.assetAccount},n.type&&(o.typeName=n.type),n.category&&(o.category=n.category),n.depreciationMethod&&(o.depreciationMethod=n.depreciationMethod),n.effectiveLife&&(o.effectiveLife=n.effectiveLife),n.accumulatedDepreciation!==void 0&&(o.bookValueAccumulatedDepreciationAmount=n.accumulatedDepreciation),n.residual!==void 0&&(o.depreciableValueResidualAmount=n.residual),n.depreciationExpenseAccount&&(o.depreciationExpenseAccountResourceId=n.depreciationExpenseAccount),n.accumulatedDepreciationAccount&&(o.accumulatedDepreciationAccountResourceId=n.accumulatedDepreciationAccount),n.notes&&(o.internalNotes=n.notes),n.finalize&&(o.saveAsDraft=!1));let i=await ES(r,o);if(n.json){console.log(JSON.stringify(i.data,null,2));return}console.log(T("Fixed asset registered (transfer)."))})),t.command("discard <resourceId>").description("Discard (write off) a fixed asset").option("--disposal-date <date>","Disposal date (YYYY-MM-DD)").option("--depreciation-end-date <date>","Final depreciation date (YYYY-MM-DD)").option("--gain-loss-account <id>","Gain/loss account resourceId").option("--format <type>","Output format: table, json, csv, yaml").option("--api-key <key>","API key").option("--json","JSON output").action((r,n)=>A(async o=>{(!n.disposalDate||!n.depreciationEndDate)&&(console.error(k("--disposal-date and --depreciation-end-date are required.")),process.exit(1));let i=await _S(o,r,{disposalDate:n.disposalDate,depreciationEndDate:n.depreciationEndDate,assetDisposalGainLossAccountResourceId:n.gainLossAccount});if(n.json){console.log(JSON.stringify(i.data,null,2));return}console.log(T(`Fixed asset ${r} discarded.`))})(n)),t.command("undo-disposal <resourceId>").description("Undo a fixed asset disposal").option("--format <type>","Output format: table, json, csv, yaml").option("--api-key <key>","API key").option("--json","JSON output").action((r,n)=>A(async o=>{let i=await IS(o,r);if(n.json){console.log(JSON.stringify(i.data,null,2));return}console.log(T(`Disposal undone for ${r}.`))})(n)),t.command("bulk-upsert").description("Create or update fixed assets in bulk (max 500). Natural key: reference. Each row requires registrationType (NEW | TRANSFER) and a typeCode. Returns a jobId \u2014 poll with `clio background-jobs get <jobId>`.").option("--input <file>","Read JSON body from file (or pipe via stdin with --input -)").option("--api-key <key>","API key (overrides stored/env)").option("--json","Output as JSON").action(A(async(r,n)=>{let o=B(n);o||(console.error('Error: --input <file> is required (JSON with { "fixedAssets": [...] } or a bare array)'),process.exit(1));let i=o.fixedAssets??o;Array.isArray(i)||(console.error('Error: expected { "fixedAssets": [...] }'),process.exit(1)),i.length===0&&(console.error("Error: fixedAssets array is empty."),process.exit(1)),i.length>500&&(console.error(`Error: max 500 per call (got ${i.length}). Split into batches.`),process.exit(1));let s=await CS(r,i);n.json?console.log(JSON.stringify(s.data,null,2)):(console.log(T(`Bulk upsert started. Job ID: ${s.data.jobId}`)),console.log(z(` Poll progress: clio background-jobs get ${s.data.jobId}`)))}))}Q();JR();we();je();ct();Ve();He();ht();var XIe=[{key:"resourceId",header:"ID",format:ie},{key:"status",header:"Status",format:e=>String(e)==="ACTIVE"?T(String(e)):C(String(e))},{key:"interval",header:"Interval"},{key:"totalAmount",header:"Amount",align:"right"},{key:"businessTransactionType",header:"Type"}],QIe=[{key:"resourceId",header:"ID",format:ie},{key:"scheduledTransactionType",header:"Type"},{key:"status",header:"Status",format:e=>C(String(e??""))}];function eW(e){let t=e.command("subscriptions").alias("subs").description("Manage recurring subscriptions");t.command("list").description("List subscriptions").option("--limit <n>","Max results",U).option("--offset <n>","Page number offset (0-indexed)",me).option("--all","Fetch all pages").option("--format <type>","Output format: table, json, csv, yaml").option("--api-key <key>","API key").option("--json","JSON output").action(A(async(r,n)=>{let o=await ce(n,i=>AS(r,i),{label:"Fetching subscriptions"});se(o,XIe,n,"Subscriptions")})),t.command("get <resourceId>").description("Get subscription details").option("--format <type>","Output format: table, json, csv, yaml").option("--api-key <key>","API key").option("--json","JSON output").action((r,n)=>A(async o=>{let i=await ym(o,r);if(n.json){console.log(JSON.stringify(i.data,null,2));return}let s=i.data;console.log(S("Status:"),s.status),console.log(S("Interval:"),s.interval),console.log(S("Amount:"),s.totalAmount),console.log(S("Next:"),s.nextScheduleDate??"N/A"),console.log(S("ID:"),s.resourceId)})(n)),t.command("create").description("Create a recurring subscription (invoices only, with proration)").option("--interval <interval>","WEEKLY, MONTHLY, QUARTERLY, or YEARLY (required)").option("--start-date <YYYY-MM-DD>","Start date (required)").option("--end-date <YYYY-MM-DD>","End date (optional, omit for ongoing)").option("--contact <name|resourceId>","Customer contact (required)").option("--ref <reference>","Invoice reference").option("--date <YYYY-MM-DD>","Invoice date").option("--due <YYYY-MM-DD>","Due date").option("--account <name|resourceId>","Revenue account \u2014 applied to ALL line items (required)").option("--tax-profile <name|resourceId>","Tax profile \u2014 applied to ALL line items").option("--lines <json>","Line items as JSON array (name, unitPrice, quantity)").option("--amount <n>","Single line item amount (shorthand)",et).option("--line-name <name>","Line item name (used with --amount)").option("--input <file>","Read full request body from JSON file (overrides flags)").option("--format <type>","Output format: table, json, csv, yaml").option("--api-key <key>","API key").option("--json","JSON output").action(A(async(r,n)=>{let o=B(n);if(!o){(!n.interval||!n.startDate)&&(console.error(k("Required: --interval, --start-date")),console.error(C("Or use --input <file> to provide full JSON body.")),process.exit(1));let s;if(n.lines)try{s=JSON.parse(n.lines)}catch{console.error(k("Invalid --lines JSON")),process.exit(1)}else n.amount!==void 0&&(s=[{name:n.lineName??"Subscription",unitPrice:n.amount,quantity:1}]);s&&(n.account||n.taxProfile)&&(s=s.map(a=>({...a,...n.account&&!a.accountResourceId?{accountResourceId:n.account}:{},...n.taxProfile&&!a.taxProfileResourceId?{taxProfileResourceId:n.taxProfile}:{}}))),o={repeat:n.interval,startDate:n.startDate,status:"ACTIVE",proratedConfig:{proratedAdjustmentLineText:"Prorated adjustment"},invoice:{contactResourceId:n.contact,reference:n.ref,valueDate:n.date,dueDate:n.due,lineItems:s,saveAsDraft:!1}},n.endDate&&(o.endDate=n.endDate)}let i=await wS(r,o);if(n.json){console.log(JSON.stringify(i.data,null,2));return}console.log(T("Subscription created.")),console.log(S("ID:"),i.data.resourceId)})),t.command("update <resourceId>").description("Update a subscription").option("--input <file>","Read full update body from JSON file").option("--format <type>","Output format: table, json, csv, yaml").option("--api-key <key>","API key").option("--json","JSON output").action((r,n)=>A(async o=>{let i=B(n);i||(console.error(k("Use --input <file> to provide update data.")),process.exit(1));let s=await TS(o,r,i);if(n.json){console.log(JSON.stringify(s.data,null,2));return}console.log(T(`Subscription ${r} updated.`))})(n)),t.command("delete <resourceId>").description("Delete a subscription").option("--format <type>","Output format: table, json, csv, yaml").option("--api-key <key>","API key").option("--json","JSON output").action((r,n)=>A(async o=>{if(await RS(o,r),n.json){console.log(JSON.stringify({deleted:!0,resourceId:r}));return}console.log(T(`Subscription ${r} deleted.`))})(n)),t.command("cancel <resourceId>").description("Cancel an active subscription (prorates remaining period)").option("--cancel-date-type <type>","END_OF_CURRENT_PERIOD, END_OF_LAST_PERIOD, or CUSTOM_DATE","END_OF_CURRENT_PERIOD").option("--end-date <YYYY-MM-DD>","Custom cancel date (only with CUSTOM_DATE)").option("--prorated-text <text>","Prorated adjustment line text","Prorated adjustment").option("--format <type>","Output format: table, json, csv, yaml").option("--api-key <key>","API key").option("--json","JSON output").action((r,n)=>A(async o=>{if(await OS(o,r,{cancelDateType:n.cancelDateType,proratedAdjustmentLineText:n.proratedText,endDate:n.endDate}),n.json){console.log(JSON.stringify({cancelled:!0,resourceId:r}));return}console.log(T(`Subscription ${r} cancelled.`))})(n)),ve({parent:t,commandName:"search-scheduled",fields:Af,defaults:wf,fetcher:NS,columns:QIe,label:"Searching scheduled transactions"})}Q();GR();we();Ve();je();ct();He();ht();var tW=[{key:"resourceId",header:"ID",format:ie},{key:"name",header:"Name"}];function rW(e){let t=e.command("contact-groups").description("Manage contact groups");t.command("list").description("List contact groups").option("--limit <n>","Max results",U).option("--offset <n>","Page number offset (0-indexed)",me).option("--all","Fetch all pages").option("--api-key <key>","API key").option("--format <type>","Output format: table, json, csv, yaml").option("--json","JSON output").action(A(async(r,n)=>{let o=await ce(n,i=>$S(r,i),{label:"Fetching contact groups"});se(o,tW,n,"Contact Groups")})),t.command("get <resourceId>").description("Get contact group details").option("--api-key <key>","API key").option("--format <type>","Output format: table, json, csv, yaml").option("--json","JSON output").action((r,n)=>A(async o=>{let i=await kS(o,r);if(n.json){console.log(JSON.stringify(i.data,null,2));return}let s=i.data;console.log(S("Name:"),s.name),console.log(S("Contacts:"),s.associatedContacts?.length??0);for(let a of s.associatedContacts??[])console.log(` ${z(a.resourceId)} ${a.name}`);console.log(S("ID:"),s.resourceId)})(n)),ve({parent:t,fields:Uf,defaults:qf,fetcher:FS,columns:tW,label:"Searching contact groups",positionalArg:"name",positionalFilter:r=>({name:{contains:r}})}),t.command("create").description("Create a contact group").option("--name <name>","Group name").option("--api-key <key>","API key").option("--format <type>","Output format: table, json, csv, yaml").option("--json","JSON output").action(A(async(r,n)=>{ue(n,[{flag:"--name",key:"name"}]);let o=await PS(r,{name:n.name});if(n.json){console.log(JSON.stringify(o.data,null,2));return}console.log(T(`Contact group "${n.name}" created.`)),console.log(S("ID:"),o.data.resourceId)})),t.command("update <resourceId>").description("Update a contact group").option("--name <name>","New group name").option("--api-key <key>","API key").option("--format <type>","Output format: table, json, csv, yaml").option("--json","JSON output").action((r,n)=>A(async o=>{let i={};n.name&&(i.name=n.name);let s=await LS(o,r,i);if(n.json){console.log(JSON.stringify(s.data,null,2));return}console.log(T("Contact group updated.")),console.log(S("ID:"),s.data.resourceId)})(n)),t.command("delete <resourceId>").description("Delete a contact group").option("--api-key <key>","API key").option("--json","JSON output").action((r,n)=>A(async o=>{if(await jS(o,r),n.json){console.log(JSON.stringify({deleted:!0,resourceId:r}));return}console.log(T(`Contact group ${r} deleted.`))})(n))}VR();we();je();ct();Ve();He();Q();var eCe=[{key:"resourceId",header:"ID",format:ie},{key:"internalName",header:"Name",format:e=>String(e??"")},{key:"itemCode",header:"Code",format:e=>C(String(e??""))}];function nW(e){let t=e.command("inventory").alias("inv").description("Inventory management");t.command("items").description("List inventory-tracked items").option("--limit <n>","Max results",U).option("--offset <n>","Page number offset (0-indexed)",me).option("--all","Fetch all pages").option("--format <type>","Output format: table, json, csv, yaml").option("--api-key <key>","API key").option("--json","JSON output").action(A(async(r,n)=>{let o=await ce(n,i=>MS(r,i),{label:"Fetching inventory items"});se(o,eCe,n,"Inventory Items")})),t.command("balance <itemResourceId>").description("Get inventory balance for an item").option("--format <type>","Output format: table, json, csv, yaml").option("--api-key <key>","API key").option("--json","JSON output").action((r,n)=>A(async o=>{let i=await US(o,r);if(n.json){console.log(JSON.stringify(i.data,null,2));return}let s=i.data;console.log(S("Item:"),s.itemResourceId),console.log(S("Qty:"),`${s.baseQty} ${s.baseUnit}`),console.log(S("Avg Cost:"),s.latestAverageCostAmount)})(n)),t.command("create").description("Create an inventory-tracked item (use --input for full JSON body)").option("--item-code <code>","Item code (SKU)").option("--name <name>","Item name").option("--unit <unit>","Unit of measure").option("--costing-method <method>","FIXED or WAC").option("--input <file>","Read full request body from JSON file (or pipe via stdin)").option("--api-key <key>","API key").option("--format <type>","Output format: table, json, csv, yaml").option("--json","JSON output").action(A(async(r,n)=>{let o=B(n);o||ue(n,[{flag:"--item-code",key:"itemCode"},{flag:"--name",key:"name"}]);let i=o??{itemCode:n.itemCode,name:n.name,unit:n.unit,costingMethod:n.costingMethod},s=await BS(r,i);if(n.json){console.log(JSON.stringify(s.data,null,2));return}console.log(T("Inventory item created.")),console.log(S("ID:"),s.data.resourceId)}))}Q();HR();we();Ve();je();ct();He();ht();var oW=[{key:"resourceId",header:"ID",format:ie},{key:"customFieldName",header:"Name"}];function iW(e){let t=e.command("custom-fields").description("Manage custom fields");t.command("list").description("List custom fields").option("--limit <n>","Max results",U).option("--offset <n>","Page number offset (0-indexed)",me).option("--all","Fetch all pages").option("--api-key <key>","API key").option("--format <type>","Output format: table, json, csv, yaml").option("--json","JSON output").action(A(async(r,n)=>{let o=await ce(n,i=>qS(r,i),{label:"Fetching custom fields"});se(o,oW,n,"Custom Fields")})),t.command("get <resourceId>").description("Get a custom field by resourceId").option("--api-key <key>","API key").option("--format <type>","Output format: table, json, csv, yaml").option("--json","JSON output").action((r,n)=>A(async o=>{let s=(await zS(o,r)).data;if(n.json){console.log(JSON.stringify(s,null,2));return}console.log(S("Name:"),s.customFieldName||s.name||"(unnamed)"),console.log(S("ID:"),s.resourceId),console.log(S("Type:"),s.datatypeCode||s.fieldType||"\u2014"),s.description&&console.log(S("Description:"),s.description),s.defaultValue&&console.log(S("Default:"),s.defaultValue),s.listOptions?.length&&console.log(S("Options:"),s.listOptions.join(", "));let a=u=>u===!0||u==="true",c=[];a(s.applyToSales)&&c.push("invoices"),a(s.applyToPurchase)&&c.push("bills"),a(s.applyToSaleCreditNote)&&c.push("customer CNs"),a(s.applyToPurchaseCreditNote)&&c.push("supplier CNs"),a(s.applyToPayment)&&c.push("payments"),a(s.appliesToFixedAssets)&&c.push("fixed assets"),c.length&&console.log(S("Applies to:"),c.join(", "))})(n)),ve({parent:t,fields:Mf,defaults:Bf,fetcher:YS,columns:oW,label:"Searching custom fields"}),t.command("create").description("Create a custom field").option("--name <name>","Field name").option("--description <text>","Field description").option("--print-on-documents","Print this field on PDF documents").option("--invoices","Apply to invoices").option("--bills","Apply to bills").option("--customer-credits","Apply to customer credit notes").option("--supplier-credits","Apply to supplier credit notes").option("--payments","Apply to payments").option("--field-type <type>","Field type (TEXT, NUMBER, DATE, DROPDOWN)","TEXT").option("--entity-type <type>","Entity type (legacy, prefer --invoices/--bills flags)","BUSINESS_TRANSACTION").option("--api-key <key>","API key").option("--format <type>","Output format: table, json, csv, yaml").option("--json","JSON output").action(A(async(r,n)=>{ue(n,[{flag:"--name",key:"name"}]);let i=n.invoices||n.bills||n.customerCredits||n.supplierCredits||n.payments?{invoices:n.invoices??!1,bills:n.bills??!1,customerCredits:n.customerCredits??!1,supplierCredits:n.supplierCredits??!1,payments:n.payments??!1}:void 0,s=await JS(r,{name:n.name,description:n.description,printOnDocuments:n.printOnDocuments??!1,appliesTo:i,fieldType:n.fieldType,entityType:n.entityType});if(n.json){console.log(JSON.stringify(s.data,null,2));return}console.log(T(`Custom field "${n.name}" created.`)),console.log(S("ID:"),s.data.resourceId)})),t.command("update <resourceId>").description("Update a custom field").option("--name <name>","New field name").option("--description <text>","New description").option("--print-on-documents","Print on PDF documents").option("--no-print-on-documents","Do not print on PDF documents").option("--invoices","Apply to invoices").option("--bills","Apply to bills").option("--customer-credits","Apply to customer credit notes").option("--supplier-credits","Apply to supplier credit notes").option("--payments","Apply to payments").option("--api-key <key>","API key").option("--format <type>","Output format: table, json, csv, yaml").option("--json","JSON output").action((r,n)=>A(async o=>{let i={};n.name!==void 0&&(i.name=n.name),n.description!==void 0&&(i.description=n.description),n.printOnDocuments!==void 0&&(i.printOnDocuments=n.printOnDocuments),(n.invoices!==void 0||n.bills!==void 0||n.customerCredits!==void 0||n.supplierCredits!==void 0||n.payments!==void 0)&&(i.appliesTo={invoices:n.invoices??!1,bills:n.bills??!1,customerCredits:n.customerCredits??!1,supplierCredits:n.supplierCredits??!1,payments:n.payments??!1});let a=await GS(o,r,i);if(n.json){console.log(JSON.stringify(a.data,null,2));return}console.log(T(`Custom field ${r} updated.`))})(n)),t.command("delete <resourceId>").description("Delete a custom field").option("--api-key <key>","API key").option("--format <type>","Output format: table, json, csv, yaml").option("--json","JSON output").action((r,n)=>A(async o=>{if(await VS(o,r),n.json){console.log(JSON.stringify({deleted:!0,resourceId:r}));return}console.log(T(`Custom field ${r} deleted.`))})(n))}Q();WR();we();import{readFileSync as tCe}from"node:fs";function sW(e,t){try{return JSON.parse(e)}catch(r){return console.error(k(`Invalid JSON in ${t}: ${r.message}`)),process.exitCode=1,null}}function aW(e){let t=e.command("quick-fix <entity>").description("Bulk-update transactions or line items in one call").addHelpText("after",`
866
866
  Entities (grouped by domain):
867
867
  ARAP: invoices, bills, customer-credit-notes, supplier-credit-notes
868
868
  Accounting: journals, cash-entries
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jaz-clio",
3
- "version": "5.8.0",
3
+ "version": "5.8.1",
4
4
  "description": "Clio: Command Line Interface Operator for Jaz AI.",
5
5
  "type": "module",
6
6
  "bin": {