jaz-clio 5.40.3 → 5.40.5

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.40.3
3
+ version: 5.40.5
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, 159 production gotchas, error
@@ -164,7 +164,7 @@ The rest of this skill — field names, gotchas, error catalog, dependency order
164
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. **Payload tier (`view`) — page-then-drill:** `search_*` and the lean `list_*` tools (invoices, bills, contacts, items, journals, customer/supplier credit notes, sale/purchase orders) return a **compact summary row by default** (`view:"lean"` — id + reference/status/date/contact/amount). Search lean to FIND a record, then read it in full via its `get_*`; pass `view:"full"` only when you need whole rows up front (heavier — avoid for broad searches). Other collections always return full. CLI defaults to full; use `--view lean`.
165
165
 
166
166
  ### Other
167
- 39. **Currency rates use `/organization/currencies/:code/rates`** — 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). The older hyphenated `/organization-currencies/...` rate paths still resolve but are marked **deprecated** in the OpenAPI spec prefer the nested form. Cannot set rates for org base currency. Full CRUD: POST (create), GET (list), GET/:id, PUT/:id, DELETE/:id.
167
+ 39. **Currency rates use `/organization/currencies/:code/rates`** — 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). The older hyphenated `/organization-currencies/...` rate paths still resolve but are **superseded**: treat the nested form as the only supported path. The reference is migrating away from the hyphenated form, so do not rely on it being documented. Cannot set rates for org base currency. Full CRUD: POST (create), GET (list), GET/:id, PUT/:id, DELETE/:id.
168
168
  40. **FX invoices/bills MUST use `currency` object** — `currencyCode: "USD"` (string) is **silently ignored** (transaction created in base currency!). Use `currency: { sourceCurrency: "USD" }` to auto-fetch platform rate (ECB/FRANKFURTER), or `currency: { sourceCurrency: "USD", exchangeRate: 0.74 }` for a custom rate. Rate hierarchy: org rate → platform/ECB → transaction-level. **Direction**: `exchangeRate` is functionalToSource (1 org-base unit = N `sourceCurrency`) — usually the inverse of a quoted rate. Pass your figure as-is with `rateDirection` rather than inverting by hand; Rule 49.
169
169
  41. **Invoice GET uses `organizationAccountResourceId`** for line item accounts — POST uses `accountResourceId`. Request-side aliases resolve `issueDate` → `valueDate`, `bankAccountResourceId` → `accountResourceId`, etc.
170
170
  42. **Scheduler GET returns `interval`** — POST uses `repeat`. (Response-side asymmetry remains.)
@@ -548,4 +548,4 @@ When the user wants to OPEN, SEE, or SHARE something in the Jaz dashboard ("open
548
548
  - **jaz-conversion** — Data migration workflows from Xero, QuickBooks, Sage, MYOB, and Excel
549
549
  - **jaz-cli** — CLI command reference, auth, output formats, pagination, and workflow patterns
550
550
 
551
- 160. **Payment `adjustment` is a CASH-LEG-only correction — it never moves the document balance.** Records an overpayment or a rounding difference on the bank side of a payment: `netCash = paymentAmount -/+ fees +/- adjustmentValue` (fees are deducted from cash received on an invoice and added to cash spent on a bill). AR/AP is untouched, so an overpaid invoice stays PAID with the excess sitting on the account you chose and NO credit note is created. Shape: `adjustment: { adjustmentValue, adjustmentAccountResourceId, adjustmentDescription? }` — signed, non-zero, max 2dp, always FLAT (never a percentage), never taxed. Accepted on `pay_invoice` / `pay_bill` / both credit-note refunds / `update_payment` / both receipt reconciliations. **NOT** on batch payments, and not for `DEBT_WRITE_OFF` / `CLEARING_SETTLEMENT` / `INTER_COMPANY` / `WITHHOLDING_TAX_CERTIFICATE` (those record a settlement, so there is no cash leg). The account must be non-controlled: not AR/AP, not the VAT or FX accounts, not bank/cash, not deposit-linked. **Write/read asymmetry:** you WRITE the nested `adjustment.adjustmentValue` but READ a flat `adjustmentAmount` on the payment record, alongside `adjustmentOrganizationAccountResourceId`. Don't confuse either with `lineItems[].taxVatAdjustment.adjustmentAmount`, which is line-item tax and unrelated. **On `update_payment`, adding an adjustment and changing an existing one both APPLY.** Both paths verified separately against production on 2026-08-10 on arap `v10.7.20`: changing an existing one moved it 5.00 to 9.00, and adding one to a payment that had none set it to 7.25 with its account and description. `paymentAmount` and `transactionAmount` were untouched in both. **Removing one does NOT work.** `adjustmentValue: 0` is rejected at the edge with a 422, and `"adjustment": null` is indistinguishable from omitting the field, so both leave the stored value unchanged. To remove an adjustment, delete the payment record and record it again without one. An explicit clear flag is being added upstream; zero stays rejected, so omit-to-clear will never be the answer. Because update applies again, `PAYMENT_ADJUSTMENT_CANNOT_CHANGE_WHEN_RECONCILED` is reachable through this API again. Anything written between arap `v10.7.19` and `v10.7.20` describing this field as inert on update is stale.
551
+ 160. **Payment `adjustment` is a CASH-LEG-only correction — it never moves the document balance.** Records an overpayment or a rounding difference on the bank side of a payment: `netCash = paymentAmount -/+ fees +/- adjustmentValue` (fees are deducted from cash received on an invoice and added to cash spent on a bill). AR/AP is untouched, so an overpaid invoice stays PAID with the excess sitting on the account you chose and NO credit note is created. Shape: `adjustment: { adjustmentValue, adjustmentAccountResourceId, adjustmentDescription? }` — signed, non-zero, max 2dp, always FLAT (never a percentage), never taxed. Accepted on `pay_invoice` / `pay_bill` / both credit-note refunds / `update_payment` / both receipt reconciliations. **NOT** on batch payments, and not for `DEBT_WRITE_OFF` / `CLEARING_SETTLEMENT` / `INTER_COMPANY` / `WITHHOLDING_TAX_CERTIFICATE` (those record a settlement, so there is no cash leg). The account must be non-controlled: not AR/AP, not the VAT or FX accounts, not bank/cash, not deposit-linked. **Write/read asymmetry:** you WRITE the nested `adjustment.adjustmentValue` but READ a flat `adjustmentAmount` on the payment record, alongside `adjustmentOrganizationAccountResourceId`. Don't confuse either with `lineItems[].taxVatAdjustment.adjustmentAmount`, which is line-item tax and unrelated. **On `update_payment`, adding an adjustment and changing an existing one both APPLY.** Verified against production on arap `v10.7.21` (2026-08-11): an amount move and an account-plus-description move both returned 200 and applied. `paymentAmount` and `transactionAmount` are untouched. **Removing one does NOT work.** `adjustmentValue: 0` is rejected at the edge with a 422, and `"adjustment": null` is indistinguishable from omitting the field, so both leave the stored value unchanged. To remove an adjustment, delete the payment record and record it again without one. An explicit clear flag is being added upstream; zero stays rejected, so omit-to-clear will never be the answer. Anything describing this field as inert on update is stale. **arap `v10.7.21` put both guards behind one comparator, and a CHANGE now has two rejection conditions.** `PaymentAmountCalculator.adjustmentChanged` answers "did the adjustment change?" for the reconciled check AND for lock-date validation, which previously disagreed: the reconciled check compared the amount alone, and lock-date validation did not look at the adjustment at all. It compares **amount, account AND description** (amount by `compareTo`, so `5.0` and `5.00` are equal). Two conditions reject a change: **(a) the payment is RECONCILED** to a bank statement entry, giving `PAYMENT_ADJUSTMENT_CANNOT_CHANGE_WHEN_RECONCILED` (moving it to a different account trips this now, where the amount-only check let it through); **(b) an account on the payment's LEDGER ROWS carries a lock date later than the `valueDate`**, giving `DELETE_TRANSACTION_VALUE_DATE_CANNOT_BE_EARLIER_THAN_LOCK_DATE` -- an update deletes and recreates the ledger rows, so the delete half trips first and the code names a delete for a call that was an update. **The escape hatch:** resending the same adjustment, or omitting the field, compares equal and is NOT a change, so it does not by itself trip either guard. **But that is not a general exemption, and this is the trap.** `adjustmentDescription` is optional, so resending only `adjustmentValue` + `adjustmentAccountResourceId` against a payment that HAS a description compares unequal and counts as a change. Resend all three, or omit the object entirely. And lock-date validation gates on seven other fields independently: changing `reference`, `valueDate`, `paymentMethod`, `organizationAccountResourceId`, `paymentAmount`, `transactionAmount`, or converting a draft to active is lock-date validated on its own. Only edits that move no ledger row survive a lock. **Measured on production 2026-08-11**, throwaway account locked at 2026-07-31 over a payment dated 2026-06-15: change the adjustment -> 422; change ONLY `reference` -> 422; resend all three values unchanged -> 200; resend WITHOUT the description -> 422; then unlock and repeat the first call -> 200 and applied. That last row is the control. Condition (a) is read from the deployed source, not triggered: it needs a bank statement entry, which has no delete, so proving it costs permanent state on a shared org.
@@ -67,7 +67,7 @@ All GET list endpoints and POST `/search` endpoints use **`limit`/`offset` pagin
67
67
  | Async batch kickoff (`/bulk-request-changes`, claims `bulk/*`) | **202** |
68
68
  | Quick Fix / bulk partial failure | **207** (body shape identical to 200 — check `failed[]`) |
69
69
 
70
- **Changed 2026-08-10**: seven `PUT` endpoints moved 201 → 200 — `/bills/{id}`, `/contacts/{id}`, `/nano-classifiers/{id}`, `/items/{id}`, `/journals/{id}`, `/scheduled/journals/{id}`, `/organization-currencies/{code}/rates/{id}`. Request shapes and response bodies are byte-identical; only the status changed. The same release corrected 114 published success codes that disagreed with what the endpoints actually returned, so the API reference now matches runtime everywhere. A client that asserted `status === 201` on an update breaks; one that checks `response.ok` does not.
70
+ **Changed 2026-08-10**: seven `PUT` endpoints moved 201 → 200 — `/bills/{id}`, `/contacts/{id}`, `/nano-classifiers/{id}`, `/items/{id}`, `/journals/{id}`, `/scheduled/journals/{id}`, `/organization/currencies/{code}/rates/{id}`. Request shapes and response bodies are byte-identical; only the status changed. The same release corrected 114 published success codes that disagreed with what the endpoints actually returned, so the API reference now matches runtime everywhere. A client that asserted `status === 201` on an update breaks; one that checks `response.ok` does not.
71
71
 
72
72
  ---
73
73
 
@@ -308,7 +308,7 @@ Enable currencies first, then set rates via the **separate** rate endpoints belo
308
308
 
309
309
  ### Currency Rates — `/organization/currencies/:code/rates`
310
310
 
311
- **Path note**: both enable and rates live under the nested `/organization/currencies` family. The older hyphenated `/organization-currencies/...` rate paths still resolve but are marked **deprecated** in the OpenAPI spec use the nested form.
311
+ **Path note**: both enable and rates live under the nested `/organization/currencies` family. The older hyphenated `/organization-currencies/...` rate paths still resolve but are **superseded**. Use the nested form; do not rely on the hyphenated one being documented.
312
312
 
313
313
  #### POST /api/v1/organization/currencies/:currencyCode/rates
314
314
 
@@ -2112,8 +2112,9 @@ Update an existing payment record. All fields optional — only included fields
2112
2112
  "feeTaxVatApplicable": false
2113
2113
  },
2114
2114
  // Cash-leg adjustment: overpayment or rounding. Bank leg only, never AR/AP.
2115
- // Only applies when RECORDING a payment. On update it is inert: add, change
2116
- // and remove all return 200 and do nothing. See rule 160.
2115
+ // On update, add and change APPLY; remove does not (0 rejected, null reads as
2116
+ // omitted). Rejected if the payment is reconciled or an account on its ledger
2117
+ // rows is lock-dated. See rule 160.
2117
2118
  "adjustment": {
2118
2119
  "adjustmentValue": -0.03,
2119
2120
  "adjustmentAccountResourceId": "uuid-rounding-account",
@@ -182,16 +182,8 @@ Valid `type` values: `"TEXT"`, `"DATE"`, `"DROPDOWN"` (UPPERCASE).
182
182
  - `/api/v1/organization/currencies/USD/rate` → 404 (singular)
183
183
  - `/api/v1/organization/currencies/{id}/rate` → 404 (singular)
184
184
  **Fix**: Rate endpoints live under the nested `/organization/currencies` family. The older
185
- hyphenated `/organization-currencies/...` rate paths still resolve but are marked
186
- **deprecated** in the OpenAPI spec prefer the nested form:
187
- ```
188
- POST /api/v1/organization/currencies/:currencyCode/rates Set rate
189
- GET /api/v1/organization/currencies/:currencyCode/rates List rates
190
- GET /api/v1/organization/currencies/:currencyCode/rates/:id Get rate
191
- PUT /api/v1/organization/currencies/:currencyCode/rates/:id Update rate
192
- DELETE /api/v1/organization/currencies/:currencyCode/rates/:id Delete rate
193
- ```
194
- Enable currencies first via `POST /organization/currencies`, then set rates via `/organization/currencies/:code/rates`.
185
+ hyphenated `/organization-currencies/...` rate paths still resolve but are
186
+ **superseded** — use the nested form.
195
187
 
196
188
  ### "Cannot set rate for organization base currency" (400)
197
189
  **Cause**: Trying to POST/PUT a rate for the org's base currency (e.g., SGD for a Singapore org).
@@ -864,7 +856,8 @@ Two of the seven never reach you through this path: a zero `adjustmentValue` and
864
856
  | `INVALID_PAYMENT_ADJUSTMENT_ACCOUNT` | Account is a control account (AR, AP, the VAT pair, the FX accounts, Retained Earnings, withholding tax), a bank or cash account, deposit-linked, missing, or deleted | Pick an ordinary postable account. Most seeded accounts qualify — Rounding, Other Income, Bank Charges |
865
857
  | `PAYMENT_ADJUSTMENT_MAKES_NET_CASH_INVALID` | Net cash would not remain above zero | Reduce the magnitude of a negative adjustment |
866
858
  | `PAYMENT_ADJUSTMENT_NOT_APPLICABLE_FOR_PAYMENT_METHOD` | Method is `DEBT_WRITE_OFF`, `CLEARING_SETTLEMENT`, `INTER_COMPANY` or `WITHHOLDING_TAX_CERTIFICATE` | Those record a settlement, not a bank movement, so there is no cash leg to adjust. Drop the adjustment |
867
- | `PAYMENT_ADJUSTMENT_CANNOT_CHANGE_WHEN_RECONCILED` | The payment is matched to a bank statement entry and the request would change its adjustment | **Unreachable through this API since 2026-08-10.** The update path never reads the caller's adjustment, so nothing can present a changed value for this rule to reject. Editing the `reference` on a reconciled adjusted payment now succeeds. Still listed because it fires for other clients and will return here when the upstream regression is fixed |
859
+ | `PAYMENT_ADJUSTMENT_CANNOT_CHANGE_WHEN_RECONCILED` | The payment is matched to a bank statement entry and the request would change its adjustment | **Reachable.** The update path reads the caller's adjustment, and since arap v10.7.21 the comparison covers amount, account AND description, so an account-only or description-only move trips it too. Un-reconcile the payment first, or resend the adjustment unchanged. Resending all three values unchanged, or omitting the field, is not a change. See rule 160 |
860
+ | `DELETE_TRANSACTION_VALUE_DATE_CANNOT_BE_EARLIER_THAN_LOCK_DATE` | An account on the payment's ledger rows has a lock date later than the payment `valueDate` | An update deletes and recreates the ledger rows, so the delete half trips first and the code names a delete for a call that was an update. Since arap v10.7.21 the adjustment account is in scope too. Not adjustment-specific: changing the `reference`, `valueDate`, `paymentMethod`, either amount or the bank account is lock-date validated on its own. Clear the lock via `update_account`, or leave the ledger rows alone. Verified on production 2026-08-11 |
868
861
  | `PAYMENT_ADJUSTMENT_NOT_APPLICABLE_FOR_BATCH_PAYMENT` | Batch payments do not support adjustments | Record the adjustment on an individual payment |
869
862
 
870
863
  ---
@@ -462,7 +462,7 @@ DELETE → expects "A" (parentEntityResourceId, via /cash-entries/:id)
462
462
 
463
463
  | What You'd Guess | Actual API Field | Notes |
464
464
  |------------------|-------------------|-------|
465
- | `/organization-currencies/:code/rates` (older docs) | `/organization/currencies/:code/rates` | Nested path is current; hyphenated form is **deprecated** in the spec |
465
+ | `/organization-currencies/:code/rates` (older docs) | `/organization/currencies/:code/rates` | Nested path is the supported one; the hyphenated form still resolves but is **superseded** |
466
466
  | `exchangeRate` (rate POST body) | `rate` | Just `rate`, not `exchangeRate` |
467
467
  | `effectiveDate` / `valueDate` / `date` | `rateApplicableFrom` | Rate start date, `YYYY-MM-DD` only |
468
468
  | `expiryDate` | `rateApplicableTo` | Optional rate end date |
@@ -317,7 +317,7 @@ Body for all three: `{ items: [{btResourceId: "<uuid>", btType: "SALE|PURCHASE|S
317
317
  | DELETE | `/organization/currencies/:currencyCode/rates/:resourceId` | Delete rate |
318
318
  | POST | `/organization/currencies/rates/bulk-upsert` | Bulk create exchange rates (max 500, auto-enables currencies) |
319
319
 
320
- **Path note**: rate management, enable/disable and bulk-upsert all live under the nested `/organization/currencies` family. The older hyphenated `/organization-currencies/...` rate paths still resolve but are marked **deprecated** in the OpenAPI spec prefer the nested form. POST body: `{ "rate": 0.74, "rateApplicableFrom": "YYYY-MM-DD" }` (rate = 1 base → X foreign; see endpoints.md for direction details). Base currency rates return 400. See endpoints.md for full examples.
320
+ **Path note**: rate management, enable/disable and bulk-upsert all live under the nested `/organization/currencies` family. The older hyphenated `/organization-currencies/...` rate paths still resolve but are **superseded**. Use the nested form; do not rely on the hyphenated one being documented. POST body: `{ "rate": 0.74, "rateApplicableFrom": "YYYY-MM-DD" }` (rate = 1 base → X foreign; see endpoints.md for direction details). Base currency rates return 400. See endpoints.md for full examples.
321
321
 
322
322
  ---
323
323
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: jaz-cli
3
- version: 5.40.3
3
+ version: 5.40.5
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.40.3
3
+ version: 5.40.5
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:
@@ -231,7 +231,7 @@ POST /api/v1/organization/currencies/<code>/rates
231
231
 
232
232
  **Rate direction:** `functionalToSource` — how many units of SOURCE (foreign) currency = 1 unit of FUNCTIONAL (base) currency. Example: base SGD, 1 SGD = 0.74 USD → rate = 0.74. A quote written foreign-first ("1 USD = 1.35 SGD") is the inverse — send 1/1.35 = 0.74, or send 1.35 with `rateDirection: "SOURCE_TO_FUNCTIONAL"` and let the endpoint apply it. Omitting `rateDirection` means `FUNCTIONAL_TO_SOURCE`.
233
233
 
234
- **Note:** Rate endpoints and enable/disable both live under the nested `/organization/currencies` family. The older hyphenated `/organization-currencies/...` rate paths are **deprecated** in the OpenAPI spec.
234
+ **Note:** Rate endpoints and enable/disable both live under the nested `/organization/currencies` family. The older hyphenated `/organization-currencies/...` rate paths still resolve but are **superseded**; use the nested form.
235
235
 
236
236
  **CRITICAL:** The field is `rateApplicableFrom` (NOT `effectiveDate`). Using the wrong field name will silently fail.
237
237
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: jaz-kit
3
- version: 5.40.3
3
+ version: 5.40.5
4
4
  description: >-
5
5
  Use this skill when an accountant, bookkeeper, or owner is running real books
6
6
  in Jaz across one or more organizations from the terminal — setting up a
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: jaz-pseudo-sql
3
- version: 5.40.3
3
+ version: 5.40.5
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.40.3
3
+ version: 5.40.5
4
4
  description: >-
5
5
  Use this skill for recurring accounting workflows — month/quarter/year-end
6
6
  close, bank reconciliation, GST/VAT filing, payment runs, credit control,
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: jaz-recipes
3
- version: 5.40.3
3
+ version: 5.40.5
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
package/cli.mjs CHANGED
@@ -687,7 +687,7 @@ Call with { operation, arguments${o?`, ${Vl}`:""}${a.length?", file":""}${t?", o
687
687
  `+r.map(Gv).join(`
688
688
  `)+(t?`
689
689
 
690
- Multiple organizations are accessible: pass org_id (from list_organizations) to target one. Confirm the organization with the user before any create/update/delete.`:""),u={operation:{type:"string",enum:n,description:`The ${e.name} operation to run.`},arguments:{type:"object",description:"Parameters for the chosen operation (see the operation list above). Validated by the Jaz API.",additionalProperties:!0}};return o&&(u[Vl]={type:"string",description:$it}),a.length&&(u.file={type:"object",description:`A file from the conversation, when the client supports passing one. Accepted by: ${a.join(", ")}. The content is fetched server-side \u2014 leave source arguments out of \`arguments\`.`,properties:{download_url:{type:"string",description:"URL the file content can be fetched from (may be temporary)."},file_id:{type:"string",description:"Host-side file identifier."},mime_type:{type:"string"},file_name:{type:"string"}},required:["download_url"]}),t&&(u.org_id={type:"string",description:"The organization (resourceId from list_organizations) to run this operation against. Required when more than one organization is accessible."}),{name:e.name,description:c,inputSchema:{type:"object",properties:u,required:["operation"],additionalProperties:!1},...a.length?{_meta:{"openai/fileParams":["file"]}}:{},annotations:{title:`${e.title??Fvr(e.name)} \xB7 ${r.length} operation${r.length===1?"":"s"}`,readOnlyHint:i,destructiveHint:!i&&s,idempotentHint:i,openWorldHint:!1}}})}function Yit(t){return Qvr.has(t)}function Zde(t,e){let r=Ri.find(o=>o.name===t);if(!r)return{error:`Unknown namespace: ${t}.`};let n=jit(r.groups),i=n.find(o=>o.name===e||o.aliases?.includes(e));return i?{tool:i}:{error:`Unknown operation "${e}" for the ${t} tool.`,operations:n.map(o=>o.name)}}var Qvr,RT=X(()=>{"use strict";ed();td();zv();q8();Qvr=new Set(Ri.map(t=>t.name))});var Hit={};gs(Hit,{loadAgentSuiteContent:()=>qvr});import{readFileSync as Lvr}from"node:fs";import{dirname as Mvr,join as Pvr}from"node:path";import{fileURLToPath as Uvr}from"node:url";function qvr(){return Xde||(Xde=JSON.parse(Lvr(Pvr($vr,"agent-suite-content.json"),"utf8"))),Xde}var $vr,Xde,zit=X(()=>{"use strict";$vr=Mvr(Uvr(import.meta.url)),Xde=null});var Git={};gs(Git,{buildCapabilityMap:()=>Yvr});async function jvr(){try{let{loadAgentSuiteContent:t}=await Promise.resolve().then(()=>(zit(),Hit)),e=t().counts;return{cli_command_groups:e.commands,api_rules:e.apiRules,skills:e.skills,ifrs_recipes:e.recipes,calculators:e.calculators,job_playbooks:e.jobs}}catch{return}}async function Yvr(t={}){if(t.query&&t.query.trim())return P8(t.query);if(t.namespace){let r=Ri.find(i=>i.name===t.namespace);if(!r)return{error:`Unknown namespace "${t.namespace}".`,namespaces:Ri.map(i=>i.name),hint:"Call with no arguments for the full map, or pass `query` to rank operations by keyword."};let n=jv(r.groups);return{namespace:r.name,description:r.description,operations:n.length,operation_list:n.map(Gv),hint:"Call the namespace tool with { operation, arguments }, or execute_tool with the operation name on a meta-tool surface."}}let e=Sy(t.surface,t.multiOrg);return{...e,map:t.full?DT().map(r=>({...r,operation_list:jv(Ri.find(n=>n.name===r.namespace).groups).map(Gv)})):e.map,beyond_mcp:await jvr()}}var Jit=X(()=>{"use strict";ed();RT();zv();Q8()});import{randomUUID as Hvr}from"node:crypto";function dot(t){let e=t.limit,r=t.offset;return{limit:e,offset:r,sortBy:void 0,sortOrder:void 0}}function pr(t,e,r,n,i,o){let s={...ife};return o?.leanView&&(s.view={type:"string",enum:["lean","full"],description:"Payload tier: 'lean' (default) = summary row (id + key scalars); 'full' = whole entity per row (heavier). List lean, then drill in with get_*."}),{name:t,description:e,params:s,required:[],group:r,readOnly:!0,isConcurrencySafe:!0,maxResultSizeChars:5e4,...i?{searchHint:i}:{},execute:async(a,c)=>{let{limit:u,offset:d}=dot(c),f=o?.leanView?c.view==="full"?"full":"lean":void 0;return VD((h,m)=>n(a.client,h,m,f),u,d,f==="lean"?50:20)}}}function xi(t,e,r,n,i){return{name:t,description:e,params:{resourceId:{type:"string",description:"Resource ID (UUID)"}},required:["resourceId"],group:r,readOnly:!0,isConcurrencySafe:!0,maxResultSizeChars:2e4,...i?{searchHint:i}:{},execute:async(o,s)=>n(o.client,s.resourceId)}}function Zvr(t){if(!t||typeof t!="object"||Array.isArray(t))return{};let e=t.data;return e&&typeof e=="object"&&!Array.isArray(e)?e:t}function fot(t,e,r,n){return{...Zvr(t),[e]:!0,[r]:n}}function Vr(t,e,r,n,i,o){let s=o?.verb??"deleted";return{name:t,description:e,params:{resourceId:{type:"string",description:o?.paramDescription??"Resource ID (UUID)"}},required:["resourceId"],group:r,readOnly:!1,isDestructive:!0,...i?{searchHint:i}:{},execute:async(a,c)=>{let u=c.resourceId,d=await n(a.client,u);return fot(d,s,"resourceId",u)}}}function nfe(t,e,r,n,i){return{name:t,description:e,params:{resourceId:{type:"string",description:"Resource ID (UUID)"}},required:["resourceId"],group:r,readOnly:!1,...i?.destructive?{isDestructive:!0}:{},...i?.searchHint?{searchHint:i.searchHint}:{},execute:async(o,s)=>n(o.client,s.resourceId)}}function rot(t){if(typeof t!="string"||/^\d{4}-\d{2}-\d{2}$/.test(t))return t;let e=/^(\d{4}-\d{2}-\d{2})T/.exec(t);return e?e[1]:t}function e0r(t){return Array.isArray(t)?t.map(e=>{let r={};for(let[n,i]of Object.entries(e))if(i!=null)if(n==="organizationAccountResourceId")r.accountResourceId=i;else if(n==="taxProfile"&&typeof i=="object"&&i!==null){let o=i.resourceId;o&&(r.taxProfileResourceId=o)}else if(n==="discount"&&typeof i=="object"&&i!==null){let o=i.rateValue;o&&Number(o)!==0&&(r.discount=i)}else Kvr.has(n)&&(r[n]=i);return r}):t}async function BT(t,e,r,n){let s=(await(e==="invoice"?Ns:e==="bill"?Ds:e==="customer_credit_note"?kl:Nl)(t,r)).data,a=Xvr[e],c={};for(let[p,h]of Object.entries(s))a.has(p)&&h!==null&&h!==void 0&&(c[p]=h);c.valueDate&&(c.valueDate=rot(c.valueDate)),c.dueDate&&(c.dueDate=rot(c.dueDate)),c.lineItems&&(c.lineItems=e0r(c.lineItems));for(let[p,h]of Object.entries(n))h!==void 0&&(c[p]=h);let u=e==="invoice"?Jc:e==="bill"?fa:no,{missingFields:d,ready:f}=$s(c,u);if(!f)throw new Error(`Cannot finalize: missing ${d.join(", ")}. Use search_accounts (filter by accountType) and search_contacts to resolve, then pass the missing fields to this tool.`);return c}async function not(t,e,r,n){if((await t(e,r)).data.status==="DRAFT")throw new Error(`Cannot pay a DRAFT ${n}. Finalize it first with finalize_${n}.`)}function z8(t,e,r){if(!(typeof t=="string"&&e.includes(t)))return{error:`Unknown documentType ${JSON.stringify(t)}.`,status:422,hint:`Use one of: ${e.join(", ")}.`,repair:{tool:r,arguments:{},reason:"Pass a supported documentType."}}}function sot(t,e,r){let n=oot[t];if(!n)return{error:`Unknown documentType "${t}".`,status:422,hint:`Valid document types: ${Object.keys(oot).join(", ")}.`,repair:{tool:r,arguments:{},reason:"Pass a supported documentType."}};if(!n.includes(e)){let i=n.includes("ACCEPT")?"ACCEPT":"CONFIRM";return{error:`Action "${e}" is not valid for ${t}. Valid actions: ${n.join(", ")}.`,status:422,hint:`${t} advances its lifecycle with ${i}, not ${e}.`,repair:{tool:r,arguments:{documentType:t,action:i},reason:`${t} is advanced with ${i}.`}}}}async function aot(t,e,r,n,i,o,s){let a;try{a=(await e(t,r)).data?.status}catch{return}if(a==="DRAFT"||a==="VOID"){let c=a==="DRAFT"?`A DRAFT ${n} can't be linked or accepted \u2014 issue it by creating the ${n} with saveAsDraft:false (status ${s}), then link the order to that one.`:`A VOID ${n} can't be used \u2014 create a fresh ${n} (saveAsDraft:false) and link to it.`;return{error:`Cannot create an order linked to a ${a} ${n} (${r}).`,status:422,hint:`Pre-flight guard \u2014 request never hit the API. ${c}`,repair:{tool:o,arguments:{documentType:i,saveAsDraft:!1},reason:c}}}}async function cot(t,e,r,n,i,o){let s;try{s=(await e(t,r)).data?.status}catch{return}if(s==="VOID")return{error:`Cannot convert a VOID ${n} (${r}) into a ${i}.`,status:422,hint:`Pre-flight guard \u2014 request never hit the API. Convert a non-VOID ${n}.`,repair:{tool:o,arguments:{},reason:`The source ${n} is VOID.`}}}async function lot(t,e,r,n,i){let o;try{o=(await e(t,r,n)).data?.status}catch{return}if(o&&o!=="DRAFT")return{error:`Cannot DELETE a ${o} ${r} \u2014 delete is only allowed on DRAFT records.`,status:422,hint:"Use action VOID to cancel a non-draft quote/request/order.",repair:{tool:i,arguments:{documentType:r,resourceId:n,action:"VOID"},reason:`${r} is ${o}; void it instead of deleting.`}}}var Wa,Eo,Wl,bo,li,rd,Y8,xy,zvr,Kde,ky,Gvr,Jvr,efe,Vit,Wit,tfe,ife,hm,rfe,Zit,Xit,Kit,eot,Oi,tot,xT,Vvr,By,pa,uot,nd,Ty,Ny,Wvr,Xvr,Kvr,TT,kT,H8,iot,oot,Rf,G8=X(()=>{"use strict";oP();gC();SLe();NLe();GD();wa();dr();Pn();fF();sA();xE();NMe();LMe();Vf();eg();vd();vX();wX();_C();_X();bp();gF();OF();Nw();DX();rPe();U2();G2();K2();vnt();Ow();UF();Pw();vH();qw();FP();kH();Kue();ede();GH();tde();ude();hde();eit();bp();fT();mde();Ade();oz();pit();wde();_de();Dde();git();xde();fm();_z();tD();Bde();Tde();jw();M5();bit();Dit();Rit();pX();xit();Ode();Hz();Fde();Qde();Lde();Mde();Pde();Ude();$de();qde();Vf();eg();vd();U2();G2();_C();Hz();Sa();jde();Hde();dr();Jde();Lit();Wa={type:"string",description:"Resource ID of the record"},Eo={type:"string",description:"Transaction date (YYYY-MM-DD)"},Wl={type:"string",description:"Due date (YYYY-MM-DD)"},bo={type:"string",description:"Reference number"},li={type:"string",description:"Notes or memo text"},rd={type:"string",description:"Tag name for categorization"},Y8={type:"boolean",description:"Save as draft (default true). Set false to finalize immediately."},xy={type:"boolean",description:"Return full entity (default: minimal {resourceId} only). Saves a follow-up get_* round trip."},zvr={type:"boolean",description:"Retry-only: set true after the duplicate guard surfaced a candidate and the user confirmed this is a separate document. Never on a first attempt."},Kde={type:"string",description:"Contact resourceId (customer or supplier)"},ky={type:"string",description:"Bank/cash account resourceId"},Gvr={type:"number",description:"Payment amount (in bank currency)"},Jvr={type:"string",description:"Period start date (YYYY-MM-DD)"},efe={type:"string",description:"Period end date (YYYY-MM-DD)"},Vit={type:"string",enum:["full","aggregate"],description:`Output detail (default 'full'). 'aggregate' returns a compact aging-bucket summary (current, <1 month, 1/2/3 months, older + total outstanding + contact count). Prefer 'aggregate' for a general or unqualified report request (e.g. "show me my aged receivables", "my AR report") \u2014 it's the at-a-glance overview a chat user expects and it won't truncate on large orgs. Use 'full' only when the user explicitly asks for the per-contact (customer/supplier) breakdown for deeper analysis.`},Wit={type:"string",description:"Currency code (e.g. SGD, USD)"},tfe={type:"string",description:"Display name"},ife={limit:{type:"number",description:"Max results per page (\u22641000)."},offset:{type:"number",description:"Page offset (0-indexed). Use with limit to paginate."}},hm={type:"object",properties:{sourceCurrency:{type:"string",description:"Foreign currency code (ISO 4217)."},exchangeRate:{type:"number",description:'Base\u2192source: N where 1 org-base unit = N sourceCurrency. Invert ONLY if your quote reads "1 source = X base" (send 1/X), or declare rateDirection and skip the arithmetic. Omit for the org/platform rate.'},rateDirection:{type:"string",enum:["FUNCTIONAL_TO_SOURCE","SOURCE_TO_FUNCTIONAL"],description:"How exchangeRate reads. SOURCE_TO_FUNCTIONAL accepts a bank quote verbatim. Default FUNCTIONAL_TO_SOURCE."}}},rfe={type:"string",enum:[...jd],description:"Entity type to export"},Zit={type:"string",description:'Structured search query using dashboard syntax (e.g., "status:unpaid $500+ date:this month"). Mutually exclusive with filter \u2014 pass one or the other, never both.'},Xit={type:"object",description:'Raw JSON filter object (e.g., {"status":{"in":["UNPAID"]}}). Mutually exclusive with query \u2014 pass one or the other, never both.'},Kit={type:"array",items:{type:"object",properties:{path:{type:"string",description:"Column path from get_export_columns (e.g., s.reference)"},header:{type:"string",description:"Column header label in the export file"},type:{type:"string",enum:["STRING","NUMBER","CURRENCY","DATE","BOOLEAN"],description:"Column data type (optional)"}},required:["path","header"]},description:"Custom column definitions. Omit to use default columns. Use get_export_columns to discover available paths."},eot={type:"object",properties:{field:{type:"string",description:"Column path to sort by (e.g., s.total_amount)"},direction:{type:"string",enum:["ASC","DESC"],description:"Sort direction"}},required:["field"],description:"Sort results by a column path."},Oi={type:"array",items:{type:"object",properties:{customFieldName:{type:"string"},actualValue:{type:"string"}}},description:'Custom field values: [{ customFieldName: "PO Number", actualValue: "PO-123" }]'},tot={type:"array",description:"Full replacement line-item set \u2014 non-empty REPLACES all lines, [] clears, omit = no change. claimTypeResourceId + name + unitPrice + quantity are required at submit time.",items:{type:"object",properties:{resourceId:{type:"string",description:"Existing line resourceId (omit to add a new line)"},claimTypeResourceId:{type:"string",description:"Claim type resourceId"},name:{type:"string",description:"Line name"},description:{type:"string",description:"Line description"},unitPrice:{type:"number",description:"Unit price"},quantity:{type:"number",description:"Quantity"},currency:{type:"string",description:"Line currency (ISO 4217; falls back to header)"},itemSubTotal:{type:"number",description:"Line subtotal (unitPrice \xD7 quantity)"}}}},xT={type:"array",items:{type:"string"},description:"Claim resourceIds (1-500)"},Vvr={type:"array",items:{type:"object",properties:{resourceId:{type:"string",description:"Capsule type resourceId"},type:{type:"string",enum:["invoice","bill"],description:"Resource type"},selectedClasses:{type:"array",items:{type:"object",properties:{className:{type:"string"},resourceId:Wa}}},printable:{type:"boolean"}}},description:"Nano classifier config for line items. Each entry links a capsule type with selected classes."},By={type:"array",items:{type:"object",properties:{accountResourceId:{type:"string",description:"Account resourceId"},type:{type:"string",enum:["DEBIT","CREDIT"],description:"Debit or credit"},amount:{type:"number",description:"Amount"},description:{type:"string",description:"Line description"}},required:["accountResourceId","type","amount"]},description:"Journal entries (debit/credit lines with accountResourceId, type, amount)"},pa={type:"array",items:{type:"object",properties:{name:{type:"string",description:"Line item description/name"},quantity:{type:"number"},unitPrice:{type:"number"},accountResourceId:ky,taxProfileResourceId:{type:"string"},classifierConfig:Vvr},required:["name","quantity","unitPrice"]},description:"Line items \u2014 include accountResourceId on each line when finalizing (saveAsDraft: false)"},uot={type:"array",items:{type:"object",properties:{slotKey:{type:"string",description:"Slot from get_capsule_recipe templateSlots[]."},template:{type:"string",description:"Text with {{vars}} for that slot; empty string clears a nullable slot. Max 2000."}},required:["slotKey"]},description:"Optional. Customize recipe-generated text via published slots (see get_capsule_recipe)."},nd={type:"object",description:"Optional IFRS recipe trigger. Mutex with capsuleResourceId. Silent-null on failure \u2014 preview_capsule_recipe first. Rule 143.",properties:{recipeName:{type:"string",enum:["LOAN_AMORTIZATION","ACCRUAL_REVERSAL","PREPAID_AMORTIZATION","DEFERRED_REVENUE","IFRS16_LEASE"],description:"Must match mutation's allowedBaseTransactionTypes (see list_capsule_recipes)."},recipeVersion:{type:"number",description:"Optional version pin."},inputs:{type:"object",description:"Schema at versions[0].inputSchema. Single-currency; *AccountResourceId x-accountClass-locked."},templateOverrides:uot},required:["recipeName","inputs"]},Ty={type:"string",enum:[...oMe],description:"Payment method (default BANK_TRANSFER)"},Ny={type:"object",description:"Cash-leg adjustment (overpayment/rounding). Bank leg only, never AR/AP. Not with DEBT_WRITE_OFF/CLEARING_SETTLEMENT/INTER_COMPANY/WITHHOLDING_TAX_CERTIFICATE. See rule 160.",properties:{adjustmentValue:{type:"number",description:"Signed, non-zero, max 2dp"},adjustmentAccountResourceId:{type:"string",description:"Non-controlled account, not bank/cash"},adjustmentDescription:{type:"string",description:"Optional"}},required:["adjustmentValue","adjustmentAccountResourceId"]},Wvr={...Ny,description:"Adding or changing an adjustment applies here. REMOVING does not: 0 is rejected and null reads as omitted, so both leave the stored value unchanged. To remove one, delete the payment and record it again. See rule 160."};Xvr={invoice:new Set(["reference","valueDate","dueDate","contactResourceId","lineItems","notes","invoiceNotes","internalNotes","tag","tags","isTaxVatApplicable","isTaxVATApplicable","taxInclusion","terms","currency","customFields","capsuleResourceId","capsuleRecipe","taxProfileResourceId","customerPaymentProfileResourceId"]),bill:new Set(["reference","valueDate","dueDate","contactResourceId","lineItems","invoiceNotes","internalNotes","tag","tags","isTaxVatApplicable","isTaxVATApplicable","taxInclusion","terms","currency","customFields","capsuleResourceId","capsuleRecipe","taxProfileResourceId"]),customer_credit_note:new Set(["reference","valueDate","contactResourceId","lineItems","invoiceNotes","tag","tags","isTaxVatApplicable","isTaxVATApplicable","taxInclusion","currency","customFields","capsuleResourceId","taxProfileResourceId"]),supplier_credit_note:new Set(["reference","valueDate","contactResourceId","lineItems","invoiceNotes","tag","tags","isTaxVatApplicable","isTaxVATApplicable","taxInclusion","currency","customFields","capsuleResourceId","taxProfileResourceId"])};Kvr=new Set(["name","quantity","unitPrice","unit","accountResourceId","taxProfileResourceId","description","classifierConfig","itemResourceId","discount"]);TT={type:"string",enum:["SALE_QUOTE","SALE_ORDER"],description:"Which sales document: SALE_QUOTE (estimate) or SALE_ORDER."},kT={type:"string",enum:["PURCHASE_REQUEST","PURCHASE_ORDER"],description:"Which purchase document: PURCHASE_REQUEST (requisition) or PURCHASE_ORDER."},H8={type:"number",description:"Payment terms in days (one of 0, 7, 15, 30, 45, 60)."},iot={type:"string",enum:["ACCEPT","CONFIRM","VOID","DELETE"],description:"Lifecycle action. ACCEPT=quote/request only; CONFIRM=order only; VOID=any non-draft; DELETE=draft only."},oot={SALE_QUOTE:["ACCEPT","VOID","DELETE"],SALE_ORDER:["CONFIRM","VOID","DELETE"],PURCHASE_REQUEST:["ACCEPT","VOID","DELETE"],PURCHASE_ORDER:["CONFIRM","VOID","DELETE"]};Rf=[{name:"get_organization",description:"Get organization details: name, base currency, country, and financial year end.",params:{},required:[],group:"organization",readOnly:!0,searchHint:"get organization details currency country fiscal year",isConcurrencySafe:!0,maxResultSizeChars:2e4,execute:async t=>_a(t.client)},{name:"get_my_context",description:"Resolve the CALLER's own context \u2014 identity, the employee bound to their login (if any), and per-module access (moduleRoles). Use to route a receipt (bill if PURCHASES access, expense claim if EMPLOYEE_CLAIMS access). A service api-key usually has no bound employee. Magic claim drafts auto-bind the uploader server-side \u2014 no need to read employee.resourceId to bind one.",params:{},required:[],group:"organization",readOnly:!0,searchHint:"who am i my employee my permissions module roles what can i do self caller capabilities bills claims",isConcurrencySafe:!0,maxResultSizeChars:2e4,execute:async t=>Sve(t.client)},pr("list_accounts","List chart of accounts. Returns account name, code, type, class, status. Paginated \u2014 response includes totalElements. Use limit/offset to page.","accounts",(t,e,r)=>wd(t,{limit:r,offset:e}),"list chart of accounts with code type class status"),Vt({name:"search_accounts",description:'Search chart of accounts. For OR (name or code), use filter: {"or":{"name":{"contains":"X"},"code":{"contains":"X"}}}.',group:"accounts",fields:FS,defaults:QS,fetcher:RE,searchHint:"find accounts chart of accounts CoA by name code type class status OR search"}),{name:"create_account",description:"Create a new chart of accounts entry. Auto-checks for duplicates by name \u2014 returns existing account if found. Code must be unique. Account class is inferred from accountType.",params:{name:{type:"string",description:"Account name"},code:{type:"string",description:"Account code (unique)"},accountType:{type:"string",description:'Exact API string. Classic 12: Bank Accounts | Cash | Current Asset | Fixed Asset | Inventory | Current Liability | Non-current Liability | Shareholders Equity | Operating Revenue | Other Revenue | Operating Expense | Direct Costs. IFRS 18 (effective 2027): Discontinued Expense | Discontinued Income | Finance Cost | Financing Income | Goodwill | Income Tax Expense | Investing Expense | Investing Income | Investment. Common variants normalized client-side. For "interest expense"/"interest income", pick Financing or Investing yourself \u2014 depends on entity main business activity, NOT auto-classified.'},currencyCode:{type:"string",description:'Currency code (e.g., "SGD")'},lockDate:{type:"string",description:"Period lock date (YYYY-MM-DD, org timezone). Blocks recording or modifying any GL transaction on this account on or before this date."}},required:["name","code","accountType"],group:"accounts",readOnly:!1,searchHint:"create new chart of accounts entry with type code lock date",execute:async(t,e)=>{let r=e.name,n=await a1(t.client,r);if(n)return{_guard:"duplicate_skipped",message:`Account "${r}" already exists.`,existing:n};let i=BE(e.accountType);return Bw(t.client,{code:e.code,name:r,accountType:i,currencyCode:e.currencyCode,lockDate:e.lockDate})}},{name:"update_account",description:"Update a chart of accounts entry \u2014 rename, re-code, set its period lock date, or remove an existing lock date. Setting lockDate (YYYY-MM-DD) is how an individual ledger account is locked for a period: it blocks recording or editing any transaction on that account dated on or before the lock date. Pass clearLockDate to remove (unlock) an existing lock.",params:{resourceId:{type:"string",description:"Account resourceId"},name:{type:"string",description:"New account name"},code:{type:"string",description:"New account code"},lockDate:{type:"string",description:"Period lock date (YYYY-MM-DD, org timezone). Blocks recording or modifying any GL transaction on this account on or before this date."},clearLockDate:{type:"boolean",description:"Set true to remove an existing period lock date (unlock the period). Use when the user asks to remove, delete, clear, lift, or unset the lock. Do not also pass lockDate."}},required:["resourceId"],group:"accounts",readOnly:!1,searchHint:"update rename chart of accounts entry name code lock date unlock remove clear lock",execute:async(t,e)=>{let r=e.resourceId,n=(await Kve(t.client,r)).data,o=Object.fromEntries(["name","code","classificationType","taxProfileResourceId","currency","description"].filter(a=>n[a]!==void 0&&n[a]!==null).map(a=>[a,n[a]]));!o.classificationType&&n.accountType&&(o.classificationType=n.accountType);let s=e.clearLockDate===!0;if(s&&e.lockDate!==void 0)throw new Error("clearLockDate and lockDate are mutually exclusive \u2014 pass one or the other.");return!s&&typeof n.accountLockDate=="string"&&n.accountLockDate&&(o.lockDate=n.accountLockDate.slice(0,10)),e.name!==void 0&&(o.name=e.name),e.code!==void 0&&(o.code=e.code),!s&&e.lockDate!==void 0&&(o.lockDate=e.lockDate),e0e(t.client,r,o)}},{name:"bulk_upsert_chart_of_accounts",description:`Bulk create/update CoA entries (max 500). SYNC: returns { resourceIds, failedRows: [{rowIndex, columnName, columnValue, errorCode, errorMessage}], failedCount } \u2014 no jobId polling. PARTIAL_SUCCESS: failed rows surface in failedRows[]; others still succeed.
690
+ Multiple organizations are accessible: pass org_id (from list_organizations) to target one. Confirm the organization with the user before any create/update/delete.`:""),u={operation:{type:"string",enum:n,description:`The ${e.name} operation to run.`},arguments:{type:"object",description:"Parameters for the chosen operation (see the operation list above). Validated by the Jaz API.",additionalProperties:!0}};return o&&(u[Vl]={type:"string",description:$it}),a.length&&(u.file={type:"object",description:`A file from the conversation, when the client supports passing one. Accepted by: ${a.join(", ")}. The content is fetched server-side \u2014 leave source arguments out of \`arguments\`.`,properties:{download_url:{type:"string",description:"URL the file content can be fetched from (may be temporary)."},file_id:{type:"string",description:"Host-side file identifier."},mime_type:{type:"string"},file_name:{type:"string"}},required:["download_url"]}),t&&(u.org_id={type:"string",description:"The organization (resourceId from list_organizations) to run this operation against. Required when more than one organization is accessible."}),{name:e.name,description:c,inputSchema:{type:"object",properties:u,required:["operation"],additionalProperties:!1},...a.length?{_meta:{"openai/fileParams":["file"]}}:{},annotations:{title:`${e.title??Fvr(e.name)} \xB7 ${r.length} operation${r.length===1?"":"s"}`,readOnlyHint:i,destructiveHint:!i&&s,idempotentHint:i,openWorldHint:!1}}})}function Yit(t){return Qvr.has(t)}function Zde(t,e){let r=Ri.find(o=>o.name===t);if(!r)return{error:`Unknown namespace: ${t}.`};let n=jit(r.groups),i=n.find(o=>o.name===e||o.aliases?.includes(e));return i?{tool:i}:{error:`Unknown operation "${e}" for the ${t} tool.`,operations:n.map(o=>o.name)}}var Qvr,RT=X(()=>{"use strict";ed();td();zv();q8();Qvr=new Set(Ri.map(t=>t.name))});var Hit={};gs(Hit,{loadAgentSuiteContent:()=>qvr});import{readFileSync as Lvr}from"node:fs";import{dirname as Mvr,join as Pvr}from"node:path";import{fileURLToPath as Uvr}from"node:url";function qvr(){return Xde||(Xde=JSON.parse(Lvr(Pvr($vr,"agent-suite-content.json"),"utf8"))),Xde}var $vr,Xde,zit=X(()=>{"use strict";$vr=Mvr(Uvr(import.meta.url)),Xde=null});var Git={};gs(Git,{buildCapabilityMap:()=>Yvr});async function jvr(){try{let{loadAgentSuiteContent:t}=await Promise.resolve().then(()=>(zit(),Hit)),e=t().counts;return{cli_command_groups:e.commands,api_rules:e.apiRules,skills:e.skills,ifrs_recipes:e.recipes,calculators:e.calculators,job_playbooks:e.jobs}}catch{return}}async function Yvr(t={}){if(t.query&&t.query.trim())return P8(t.query);if(t.namespace){let r=Ri.find(i=>i.name===t.namespace);if(!r)return{error:`Unknown namespace "${t.namespace}".`,namespaces:Ri.map(i=>i.name),hint:"Call with no arguments for the full map, or pass `query` to rank operations by keyword."};let n=jv(r.groups);return{namespace:r.name,description:r.description,operations:n.length,operation_list:n.map(Gv),hint:"Call the namespace tool with { operation, arguments }, or execute_tool with the operation name on a meta-tool surface."}}let e=Sy(t.surface,t.multiOrg);return{...e,map:t.full?DT().map(r=>({...r,operation_list:jv(Ri.find(n=>n.name===r.namespace).groups).map(Gv)})):e.map,beyond_mcp:await jvr()}}var Jit=X(()=>{"use strict";ed();RT();zv();Q8()});import{randomUUID as Hvr}from"node:crypto";function dot(t){let e=t.limit,r=t.offset;return{limit:e,offset:r,sortBy:void 0,sortOrder:void 0}}function pr(t,e,r,n,i,o){let s={...ife};return o?.leanView&&(s.view={type:"string",enum:["lean","full"],description:"Payload tier: 'lean' (default) = summary row (id + key scalars); 'full' = whole entity per row (heavier). List lean, then drill in with get_*."}),{name:t,description:e,params:s,required:[],group:r,readOnly:!0,isConcurrencySafe:!0,maxResultSizeChars:5e4,...i?{searchHint:i}:{},execute:async(a,c)=>{let{limit:u,offset:d}=dot(c),f=o?.leanView?c.view==="full"?"full":"lean":void 0;return VD((h,m)=>n(a.client,h,m,f),u,d,f==="lean"?50:20)}}}function xi(t,e,r,n,i){return{name:t,description:e,params:{resourceId:{type:"string",description:"Resource ID (UUID)"}},required:["resourceId"],group:r,readOnly:!0,isConcurrencySafe:!0,maxResultSizeChars:2e4,...i?{searchHint:i}:{},execute:async(o,s)=>n(o.client,s.resourceId)}}function Zvr(t){if(!t||typeof t!="object"||Array.isArray(t))return{};let e=t.data;return e&&typeof e=="object"&&!Array.isArray(e)?e:t}function fot(t,e,r,n){return{...Zvr(t),[e]:!0,[r]:n}}function Vr(t,e,r,n,i,o){let s=o?.verb??"deleted";return{name:t,description:e,params:{resourceId:{type:"string",description:o?.paramDescription??"Resource ID (UUID)"}},required:["resourceId"],group:r,readOnly:!1,isDestructive:!0,...i?{searchHint:i}:{},execute:async(a,c)=>{let u=c.resourceId,d=await n(a.client,u);return fot(d,s,"resourceId",u)}}}function nfe(t,e,r,n,i){return{name:t,description:e,params:{resourceId:{type:"string",description:"Resource ID (UUID)"}},required:["resourceId"],group:r,readOnly:!1,...i?.destructive?{isDestructive:!0}:{},...i?.searchHint?{searchHint:i.searchHint}:{},execute:async(o,s)=>n(o.client,s.resourceId)}}function rot(t){if(typeof t!="string"||/^\d{4}-\d{2}-\d{2}$/.test(t))return t;let e=/^(\d{4}-\d{2}-\d{2})T/.exec(t);return e?e[1]:t}function e0r(t){return Array.isArray(t)?t.map(e=>{let r={};for(let[n,i]of Object.entries(e))if(i!=null)if(n==="organizationAccountResourceId")r.accountResourceId=i;else if(n==="taxProfile"&&typeof i=="object"&&i!==null){let o=i.resourceId;o&&(r.taxProfileResourceId=o)}else if(n==="discount"&&typeof i=="object"&&i!==null){let o=i.rateValue;o&&Number(o)!==0&&(r.discount=i)}else Kvr.has(n)&&(r[n]=i);return r}):t}async function BT(t,e,r,n){let s=(await(e==="invoice"?Ns:e==="bill"?Ds:e==="customer_credit_note"?kl:Nl)(t,r)).data,a=Xvr[e],c={};for(let[p,h]of Object.entries(s))a.has(p)&&h!==null&&h!==void 0&&(c[p]=h);c.valueDate&&(c.valueDate=rot(c.valueDate)),c.dueDate&&(c.dueDate=rot(c.dueDate)),c.lineItems&&(c.lineItems=e0r(c.lineItems));for(let[p,h]of Object.entries(n))h!==void 0&&(c[p]=h);let u=e==="invoice"?Jc:e==="bill"?fa:no,{missingFields:d,ready:f}=$s(c,u);if(!f)throw new Error(`Cannot finalize: missing ${d.join(", ")}. Use search_accounts (filter by accountType) and search_contacts to resolve, then pass the missing fields to this tool.`);return c}async function not(t,e,r,n){if((await t(e,r)).data.status==="DRAFT")throw new Error(`Cannot pay a DRAFT ${n}. Finalize it first with finalize_${n}.`)}function z8(t,e,r){if(!(typeof t=="string"&&e.includes(t)))return{error:`Unknown documentType ${JSON.stringify(t)}.`,status:422,hint:`Use one of: ${e.join(", ")}.`,repair:{tool:r,arguments:{},reason:"Pass a supported documentType."}}}function sot(t,e,r){let n=oot[t];if(!n)return{error:`Unknown documentType "${t}".`,status:422,hint:`Valid document types: ${Object.keys(oot).join(", ")}.`,repair:{tool:r,arguments:{},reason:"Pass a supported documentType."}};if(!n.includes(e)){let i=n.includes("ACCEPT")?"ACCEPT":"CONFIRM";return{error:`Action "${e}" is not valid for ${t}. Valid actions: ${n.join(", ")}.`,status:422,hint:`${t} advances its lifecycle with ${i}, not ${e}.`,repair:{tool:r,arguments:{documentType:t,action:i},reason:`${t} is advanced with ${i}.`}}}}async function aot(t,e,r,n,i,o,s){let a;try{a=(await e(t,r)).data?.status}catch{return}if(a==="DRAFT"||a==="VOID"){let c=a==="DRAFT"?`A DRAFT ${n} can't be linked or accepted \u2014 issue it by creating the ${n} with saveAsDraft:false (status ${s}), then link the order to that one.`:`A VOID ${n} can't be used \u2014 create a fresh ${n} (saveAsDraft:false) and link to it.`;return{error:`Cannot create an order linked to a ${a} ${n} (${r}).`,status:422,hint:`Pre-flight guard \u2014 request never hit the API. ${c}`,repair:{tool:o,arguments:{documentType:i,saveAsDraft:!1},reason:c}}}}async function cot(t,e,r,n,i,o){let s;try{s=(await e(t,r)).data?.status}catch{return}if(s==="VOID")return{error:`Cannot convert a VOID ${n} (${r}) into a ${i}.`,status:422,hint:`Pre-flight guard \u2014 request never hit the API. Convert a non-VOID ${n}.`,repair:{tool:o,arguments:{},reason:`The source ${n} is VOID.`}}}async function lot(t,e,r,n,i){let o;try{o=(await e(t,r,n)).data?.status}catch{return}if(o&&o!=="DRAFT")return{error:`Cannot DELETE a ${o} ${r} \u2014 delete is only allowed on DRAFT records.`,status:422,hint:"Use action VOID to cancel a non-draft quote/request/order.",repair:{tool:i,arguments:{documentType:r,resourceId:n,action:"VOID"},reason:`${r} is ${o}; void it instead of deleting.`}}}var Wa,Eo,Wl,bo,li,rd,Y8,xy,zvr,Kde,ky,Gvr,Jvr,efe,Vit,Wit,tfe,ife,hm,rfe,Zit,Xit,Kit,eot,Oi,tot,xT,Vvr,By,pa,uot,nd,Ty,Ny,Wvr,Xvr,Kvr,TT,kT,H8,iot,oot,Rf,G8=X(()=>{"use strict";oP();gC();SLe();NLe();GD();wa();dr();Pn();fF();sA();xE();NMe();LMe();Vf();eg();vd();vX();wX();_C();_X();bp();gF();OF();Nw();DX();rPe();U2();G2();K2();vnt();Ow();UF();Pw();vH();qw();FP();kH();Kue();ede();GH();tde();ude();hde();eit();bp();fT();mde();Ade();oz();pit();wde();_de();Dde();git();xde();fm();_z();tD();Bde();Tde();jw();M5();bit();Dit();Rit();pX();xit();Ode();Hz();Fde();Qde();Lde();Mde();Pde();Ude();$de();qde();Vf();eg();vd();U2();G2();_C();Hz();Sa();jde();Hde();dr();Jde();Lit();Wa={type:"string",description:"Resource ID of the record"},Eo={type:"string",description:"Transaction date (YYYY-MM-DD)"},Wl={type:"string",description:"Due date (YYYY-MM-DD)"},bo={type:"string",description:"Reference number"},li={type:"string",description:"Notes or memo text"},rd={type:"string",description:"Tag name for categorization"},Y8={type:"boolean",description:"Save as draft (default true). Set false to finalize immediately."},xy={type:"boolean",description:"Return full entity (default: minimal {resourceId} only). Saves a follow-up get_* round trip."},zvr={type:"boolean",description:"Retry-only: set true after the duplicate guard surfaced a candidate and the user confirmed this is a separate document. Never on a first attempt."},Kde={type:"string",description:"Contact resourceId (customer or supplier)"},ky={type:"string",description:"Bank/cash account resourceId"},Gvr={type:"number",description:"Payment amount (in bank currency)"},Jvr={type:"string",description:"Period start date (YYYY-MM-DD)"},efe={type:"string",description:"Period end date (YYYY-MM-DD)"},Vit={type:"string",enum:["full","aggregate"],description:`Output detail (default 'full'). 'aggregate' returns a compact aging-bucket summary (current, <1 month, 1/2/3 months, older + total outstanding + contact count). Prefer 'aggregate' for a general or unqualified report request (e.g. "show me my aged receivables", "my AR report") \u2014 it's the at-a-glance overview a chat user expects and it won't truncate on large orgs. Use 'full' only when the user explicitly asks for the per-contact (customer/supplier) breakdown for deeper analysis.`},Wit={type:"string",description:"Currency code (e.g. SGD, USD)"},tfe={type:"string",description:"Display name"},ife={limit:{type:"number",description:"Max results per page (\u22641000)."},offset:{type:"number",description:"Page offset (0-indexed). Use with limit to paginate."}},hm={type:"object",properties:{sourceCurrency:{type:"string",description:"Foreign currency code (ISO 4217)."},exchangeRate:{type:"number",description:'Base\u2192source: N where 1 org-base unit = N sourceCurrency. Invert ONLY if your quote reads "1 source = X base" (send 1/X), or declare rateDirection and skip the arithmetic. Omit for the org/platform rate.'},rateDirection:{type:"string",enum:["FUNCTIONAL_TO_SOURCE","SOURCE_TO_FUNCTIONAL"],description:"How exchangeRate reads. SOURCE_TO_FUNCTIONAL accepts a bank quote verbatim. Default FUNCTIONAL_TO_SOURCE."}}},rfe={type:"string",enum:[...jd],description:"Entity type to export"},Zit={type:"string",description:'Structured search query using dashboard syntax (e.g., "status:unpaid $500+ date:this month"). Mutually exclusive with filter \u2014 pass one or the other, never both.'},Xit={type:"object",description:'Raw JSON filter object (e.g., {"status":{"in":["UNPAID"]}}). Mutually exclusive with query \u2014 pass one or the other, never both.'},Kit={type:"array",items:{type:"object",properties:{path:{type:"string",description:"Column path from get_export_columns (e.g., s.reference)"},header:{type:"string",description:"Column header label in the export file"},type:{type:"string",enum:["STRING","NUMBER","CURRENCY","DATE","BOOLEAN"],description:"Column data type (optional)"}},required:["path","header"]},description:"Custom column definitions. Omit to use default columns. Use get_export_columns to discover available paths."},eot={type:"object",properties:{field:{type:"string",description:"Column path to sort by (e.g., s.total_amount)"},direction:{type:"string",enum:["ASC","DESC"],description:"Sort direction"}},required:["field"],description:"Sort results by a column path."},Oi={type:"array",items:{type:"object",properties:{customFieldName:{type:"string"},actualValue:{type:"string"}}},description:'Custom field values: [{ customFieldName: "PO Number", actualValue: "PO-123" }]'},tot={type:"array",description:"Full replacement line-item set \u2014 non-empty REPLACES all lines, [] clears, omit = no change. claimTypeResourceId + name + unitPrice + quantity are required at submit time.",items:{type:"object",properties:{resourceId:{type:"string",description:"Existing line resourceId (omit to add a new line)"},claimTypeResourceId:{type:"string",description:"Claim type resourceId"},name:{type:"string",description:"Line name"},description:{type:"string",description:"Line description"},unitPrice:{type:"number",description:"Unit price"},quantity:{type:"number",description:"Quantity"},currency:{type:"string",description:"Line currency (ISO 4217; falls back to header)"},itemSubTotal:{type:"number",description:"Line subtotal (unitPrice \xD7 quantity)"}}}},xT={type:"array",items:{type:"string"},description:"Claim resourceIds (1-500)"},Vvr={type:"array",items:{type:"object",properties:{resourceId:{type:"string",description:"Capsule type resourceId"},type:{type:"string",enum:["invoice","bill"],description:"Resource type"},selectedClasses:{type:"array",items:{type:"object",properties:{className:{type:"string"},resourceId:Wa}}},printable:{type:"boolean"}}},description:"Nano classifier config for line items. Each entry links a capsule type with selected classes."},By={type:"array",items:{type:"object",properties:{accountResourceId:{type:"string",description:"Account resourceId"},type:{type:"string",enum:["DEBIT","CREDIT"],description:"Debit or credit"},amount:{type:"number",description:"Amount"},description:{type:"string",description:"Line description"}},required:["accountResourceId","type","amount"]},description:"Journal entries (debit/credit lines with accountResourceId, type, amount)"},pa={type:"array",items:{type:"object",properties:{name:{type:"string",description:"Line item description/name"},quantity:{type:"number"},unitPrice:{type:"number"},accountResourceId:ky,taxProfileResourceId:{type:"string"},classifierConfig:Vvr},required:["name","quantity","unitPrice"]},description:"Line items \u2014 include accountResourceId on each line when finalizing (saveAsDraft: false)"},uot={type:"array",items:{type:"object",properties:{slotKey:{type:"string",description:"Slot from get_capsule_recipe templateSlots[]."},template:{type:"string",description:"Text with {{vars}} for that slot; empty string clears a nullable slot. Max 2000."}},required:["slotKey"]},description:"Optional. Customize recipe-generated text via published slots (see get_capsule_recipe)."},nd={type:"object",description:"Optional IFRS recipe trigger. Mutex with capsuleResourceId. Silent-null on failure \u2014 preview_capsule_recipe first. Rule 143.",properties:{recipeName:{type:"string",enum:["LOAN_AMORTIZATION","ACCRUAL_REVERSAL","PREPAID_AMORTIZATION","DEFERRED_REVENUE","IFRS16_LEASE"],description:"Must match mutation's allowedBaseTransactionTypes (see list_capsule_recipes)."},recipeVersion:{type:"number",description:"Optional version pin."},inputs:{type:"object",description:"Schema at versions[0].inputSchema. Single-currency; *AccountResourceId x-accountClass-locked."},templateOverrides:uot},required:["recipeName","inputs"]},Ty={type:"string",enum:[...oMe],description:"Payment method (default BANK_TRANSFER)"},Ny={type:"object",description:"Cash-leg adjustment (overpayment/rounding). Bank leg only, never AR/AP. Not with DEBT_WRITE_OFF/CLEARING_SETTLEMENT/INTER_COMPANY/WITHHOLDING_TAX_CERTIFICATE. See rule 160.",properties:{adjustmentValue:{type:"number",description:"Signed, non-zero, max 2dp"},adjustmentAccountResourceId:{type:"string",description:"Non-controlled account, not bank/cash"},adjustmentDescription:{type:"string",description:"Optional"}},required:["adjustmentValue","adjustmentAccountResourceId"]},Wvr={...Ny,description:"Adding or changing an adjustment applies here. REMOVING does not: 0 is rejected and null reads as omitted, so both leave the stored value unchanged. To remove one, delete the payment and record it again. A change is rejected if the payment is reconciled or lock-dated, and amount, account and description are all compared, so resend all three unchanged if you are not editing it. See rule 160."};Xvr={invoice:new Set(["reference","valueDate","dueDate","contactResourceId","lineItems","notes","invoiceNotes","internalNotes","tag","tags","isTaxVatApplicable","isTaxVATApplicable","taxInclusion","terms","currency","customFields","capsuleResourceId","capsuleRecipe","taxProfileResourceId","customerPaymentProfileResourceId"]),bill:new Set(["reference","valueDate","dueDate","contactResourceId","lineItems","invoiceNotes","internalNotes","tag","tags","isTaxVatApplicable","isTaxVATApplicable","taxInclusion","terms","currency","customFields","capsuleResourceId","capsuleRecipe","taxProfileResourceId"]),customer_credit_note:new Set(["reference","valueDate","contactResourceId","lineItems","invoiceNotes","tag","tags","isTaxVatApplicable","isTaxVATApplicable","taxInclusion","currency","customFields","capsuleResourceId","taxProfileResourceId"]),supplier_credit_note:new Set(["reference","valueDate","contactResourceId","lineItems","invoiceNotes","tag","tags","isTaxVatApplicable","isTaxVATApplicable","taxInclusion","currency","customFields","capsuleResourceId","taxProfileResourceId"])};Kvr=new Set(["name","quantity","unitPrice","unit","accountResourceId","taxProfileResourceId","description","classifierConfig","itemResourceId","discount"]);TT={type:"string",enum:["SALE_QUOTE","SALE_ORDER"],description:"Which sales document: SALE_QUOTE (estimate) or SALE_ORDER."},kT={type:"string",enum:["PURCHASE_REQUEST","PURCHASE_ORDER"],description:"Which purchase document: PURCHASE_REQUEST (requisition) or PURCHASE_ORDER."},H8={type:"number",description:"Payment terms in days (one of 0, 7, 15, 30, 45, 60)."},iot={type:"string",enum:["ACCEPT","CONFIRM","VOID","DELETE"],description:"Lifecycle action. ACCEPT=quote/request only; CONFIRM=order only; VOID=any non-draft; DELETE=draft only."},oot={SALE_QUOTE:["ACCEPT","VOID","DELETE"],SALE_ORDER:["CONFIRM","VOID","DELETE"],PURCHASE_REQUEST:["ACCEPT","VOID","DELETE"],PURCHASE_ORDER:["CONFIRM","VOID","DELETE"]};Rf=[{name:"get_organization",description:"Get organization details: name, base currency, country, and financial year end.",params:{},required:[],group:"organization",readOnly:!0,searchHint:"get organization details currency country fiscal year",isConcurrencySafe:!0,maxResultSizeChars:2e4,execute:async t=>_a(t.client)},{name:"get_my_context",description:"Resolve the CALLER's own context \u2014 identity, the employee bound to their login (if any), and per-module access (moduleRoles). Use to route a receipt (bill if PURCHASES access, expense claim if EMPLOYEE_CLAIMS access). A service api-key usually has no bound employee. Magic claim drafts auto-bind the uploader server-side \u2014 no need to read employee.resourceId to bind one.",params:{},required:[],group:"organization",readOnly:!0,searchHint:"who am i my employee my permissions module roles what can i do self caller capabilities bills claims",isConcurrencySafe:!0,maxResultSizeChars:2e4,execute:async t=>Sve(t.client)},pr("list_accounts","List chart of accounts. Returns account name, code, type, class, status. Paginated \u2014 response includes totalElements. Use limit/offset to page.","accounts",(t,e,r)=>wd(t,{limit:r,offset:e}),"list chart of accounts with code type class status"),Vt({name:"search_accounts",description:'Search chart of accounts. For OR (name or code), use filter: {"or":{"name":{"contains":"X"},"code":{"contains":"X"}}}.',group:"accounts",fields:FS,defaults:QS,fetcher:RE,searchHint:"find accounts chart of accounts CoA by name code type class status OR search"}),{name:"create_account",description:"Create a new chart of accounts entry. Auto-checks for duplicates by name \u2014 returns existing account if found. Code must be unique. Account class is inferred from accountType.",params:{name:{type:"string",description:"Account name"},code:{type:"string",description:"Account code (unique)"},accountType:{type:"string",description:'Exact API string. Classic 12: Bank Accounts | Cash | Current Asset | Fixed Asset | Inventory | Current Liability | Non-current Liability | Shareholders Equity | Operating Revenue | Other Revenue | Operating Expense | Direct Costs. IFRS 18 (effective 2027): Discontinued Expense | Discontinued Income | Finance Cost | Financing Income | Goodwill | Income Tax Expense | Investing Expense | Investing Income | Investment. Common variants normalized client-side. For "interest expense"/"interest income", pick Financing or Investing yourself \u2014 depends on entity main business activity, NOT auto-classified.'},currencyCode:{type:"string",description:'Currency code (e.g., "SGD")'},lockDate:{type:"string",description:"Period lock date (YYYY-MM-DD, org timezone). Blocks recording or modifying any GL transaction on this account on or before this date."}},required:["name","code","accountType"],group:"accounts",readOnly:!1,searchHint:"create new chart of accounts entry with type code lock date",execute:async(t,e)=>{let r=e.name,n=await a1(t.client,r);if(n)return{_guard:"duplicate_skipped",message:`Account "${r}" already exists.`,existing:n};let i=BE(e.accountType);return Bw(t.client,{code:e.code,name:r,accountType:i,currencyCode:e.currencyCode,lockDate:e.lockDate})}},{name:"update_account",description:"Update a chart of accounts entry \u2014 rename, re-code, set its period lock date, or remove an existing lock date. Setting lockDate (YYYY-MM-DD) is how an individual ledger account is locked for a period: it blocks recording or editing any transaction on that account dated on or before the lock date. Pass clearLockDate to remove (unlock) an existing lock.",params:{resourceId:{type:"string",description:"Account resourceId"},name:{type:"string",description:"New account name"},code:{type:"string",description:"New account code"},lockDate:{type:"string",description:"Period lock date (YYYY-MM-DD, org timezone). Blocks recording or modifying any GL transaction on this account on or before this date."},clearLockDate:{type:"boolean",description:"Set true to remove an existing period lock date (unlock the period). Use when the user asks to remove, delete, clear, lift, or unset the lock. Do not also pass lockDate."}},required:["resourceId"],group:"accounts",readOnly:!1,searchHint:"update rename chart of accounts entry name code lock date unlock remove clear lock",execute:async(t,e)=>{let r=e.resourceId,n=(await Kve(t.client,r)).data,o=Object.fromEntries(["name","code","classificationType","taxProfileResourceId","currency","description"].filter(a=>n[a]!==void 0&&n[a]!==null).map(a=>[a,n[a]]));!o.classificationType&&n.accountType&&(o.classificationType=n.accountType);let s=e.clearLockDate===!0;if(s&&e.lockDate!==void 0)throw new Error("clearLockDate and lockDate are mutually exclusive \u2014 pass one or the other.");return!s&&typeof n.accountLockDate=="string"&&n.accountLockDate&&(o.lockDate=n.accountLockDate.slice(0,10)),e.name!==void 0&&(o.name=e.name),e.code!==void 0&&(o.code=e.code),!s&&e.lockDate!==void 0&&(o.lockDate=e.lockDate),e0e(t.client,r,o)}},{name:"bulk_upsert_chart_of_accounts",description:`Bulk create/update CoA entries (max 500). SYNC: returns { resourceIds, failedRows: [{rowIndex, columnName, columnValue, errorCode, errorMessage}], failedCount } \u2014 no jobId polling. PARTIAL_SUCCESS: failed rows surface in failedRows[]; others still succeed.
691
691
 
692
692
  resourceId per row \u2192 update; omit \u2192 create. Note: dedup is by NAME (not code) \u2014 duplicate name surfaces ORGANIZATION_CHART_OF_ACCOUNT_DUPLICATED per row. Accepts classic 12 + 9 IFRS 18 accountType values; common variants normalized via normalizeAccountType.
693
693
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jaz-clio",
3
- "version": "5.40.3",
3
+ "version": "5.40.5",
4
4
  "description": "Clio: Command Line Interface Operator for Jaz AI.",
5
5
  "type": "module",
6
6
  "bin": {