@integrity-labs/xero-broker 0.1.5 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +14 -4
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -21190,19 +21190,29 @@ var XERO_WRITE_VERBS = [
21190
21190
  "xero.bill.approve",
21191
21191
  "xero.invoice.void",
21192
21192
  "xero.invoice.update",
21193
+ // CS-1779: the verb was BUILT and UNREACHABLE. `xero.invoice.create` has
21194
+ // existed since CS-1630 - it is in approval-core's ApprovalVerb union, the
21195
+ // executor implements it in xero-api.ts, xero-broker.ts classifies it as a
21196
+ // broker verb, ENG-10263 fixed it missing from the poll path, and it has its
21197
+ // own test file. It was never added to THIS list, and `verbSchema` below is
21198
+ // `z.enum(XERO_WRITE_VERBS)` - so an agent could not even NAME the verb: the
21199
+ // enum rejected the request client-side, before it left the agent. A finance
21200
+ // agent asked for the capability to be built; it already was, on the far side
21201
+ // of a one-line omission.
21202
+ "xero.invoice.create",
21193
21203
  "xero.contact.merge",
21194
21204
  "xero.bank_transaction.delete",
21195
21205
  "xero.manual_journal.create"
21196
21206
  ];
21197
21207
  var verbSchema = external_exports.enum(XERO_WRITE_VERBS).describe(
21198
- "The Xero write operation to perform. One of: xero.payment.create (pay an invoice/bill \u2014 moves money), xero.bill.create (create a payable), xero.bill.approve (DRAFT/SUBMITTED \u2192 AUTHORISED), xero.invoice.void (irreversible), xero.invoice.update (edit line items / unit amounts / tax treatment on an existing invoice or bill), xero.contact.merge (irreversible), xero.bank_transaction.delete (irreversible), xero.manual_journal.create (post a multi-line GL entry \u2014 reclasses, accruals, corrections; debits must equal credits)."
21208
+ "The Xero write operation to perform. One of: xero.payment.create (pay an invoice/bill \u2014 moves money), xero.bill.create (create a payable), xero.bill.approve (DRAFT/SUBMITTED \u2192 AUTHORISED), xero.invoice.void (irreversible), xero.invoice.update (edit line items / unit amounts / tax treatment on an existing invoice or bill), xero.invoice.create (raise an ACCREC customer/sales invoice - `reference` is REQUIRED and is the idempotency key), xero.contact.merge (irreversible), xero.bank_transaction.delete (irreversible), xero.manual_journal.create (post a multi-line GL entry \u2014 reclasses, accruals, corrections; debits must equal credits)."
21199
21209
  );
21200
21210
  var payloadSchema = external_exports.object({
21201
21211
  tenant_id: external_exports.string().min(1).max(128).describe(
21202
21212
  "Xero organisation id (the Xero-Tenant-Id header value) the write lands in. NOT the Augmented team. Required \u2014 a missing tenant risks writing to the wrong set of books."
21203
21213
  )
21204
21214
  }).passthrough().describe(
21205
- "Verb-specific fields. xero.payment.create: { invoice_id, account_id, amount, currency?, counterparty? }. xero.bill.create: { contact_id, amount, currency?, counterparty?, line_items_preview }. xero.bill.approve: { invoice_id, amount?, currency?, counterparty? }. xero.invoice.void: { invoice_id, invoice_number?, amount?, counterparty? }. xero.invoice.update: { invoice_id, line_items?: [{ description, unit_amount, quantity?, account_code?, tax_type? }], line_amount_types? (Exclusive|Inclusive|NoTax), reference?, date?, due_date?, invoice_number?, counterparty?, amount?, currency? } \u2014 WARNING: line_items REPLACES the entire line set on the invoice, so send every line the invoice should end up with; omit the field entirely to leave the lines untouched. Use line_amount_types to fix a wrong tax treatment (e.g. a GST-inclusive total mistakenly entered on a Tax Exclusive line). xero.contact.merge: { source_contact_id, target_contact_id, source_name?, target_name? }. xero.bank_transaction.delete: { bank_transaction_id, amount?, counterparty? }. xero.manual_journal.create: { narration, journal_lines: [{ account_code, line_amount (positive=debit, negative=credit), description?, tax_type? }], date? (YYYY-MM-DD), status? (DRAFT|POSTED, default DRAFT), amount?, currency? } \u2014 lines must balance to zero. Always include tenant_id."
21215
+ "Verb-specific fields. xero.payment.create: { invoice_id, account_id, amount, currency?, counterparty? }. xero.bill.create: { contact_id, amount, currency?, counterparty?, line_items_preview, line_items?: [{ description, unit_amount, quantity?, account_code?, tax_type? }], line_amount_types? (Exclusive|Inclusive|NoTax), reference?, date? (YYYY-MM-DD), due_date? (YYYY-MM-DD), account_code? } \u2014 `amount` MUST equal the sum of unit_amount x quantity across line_items (the approval card shows `amount`, so a mismatch is refused rather than silently rewritten); `currency` is sent to Xero as CurrencyCode. Send line_items to raise a CODED payable in ONE approval; omit it and the bill is a single synthesized line from line_items_preview + amount, which posts as an uncoded lump dated today. line_amount_types matters: Xero defaults to Exclusive, so a GST-INCLUSIVE total sent without it is read as a subtotal and the bill total comes out wrong. xero.bill.approve: { invoice_id, amount?, currency?, counterparty? }. xero.invoice.void: { invoice_id, invoice_number?, amount?, counterparty? }. xero.invoice.create: { contact_id, reference (REQUIRED - it is the idempotency key; must not contain a double quote or backslash), line_items: [{ description, unit_amount, quantity?, account_code?, tax_type?, item_code? }], line_amount_types? (Exclusive|Inclusive|NoTax, default Exclusive), date? (YYYY-MM-DD), due_date? (YYYY-MM-DD), status? (DRAFT|AUTHORISED, default DRAFT), amount?, currency?, counterparty? } \u2014 raises an ACCREC customer/sales invoice. `reference` is required because a duplicate ACCREC invoice is a second bill against a customer: the executor reconciles on it before creating, so a retry adopts the existing invoice instead of raising another. AUTHORISED is the status a customer can be sent, so it must be asked for rather than inherited. `amount` MUST equal the sum of unit_amount x quantity across line_items - the tax-EXCLUSIVE SUBTOTAL under the default Exclusive treatment, the total under Inclusive/NoTax - because the approval card shows `amount` and a mismatch is REFUSED rather than silently rewritten. Do not send the gross tax-inclusive figure on an Exclusive invoice; it cannot be verified and it will be refused. xero.invoice.update: { invoice_id, line_items?: [{ description, unit_amount, quantity?, account_code?, tax_type?, item_code? }], line_amount_types? (Exclusive|Inclusive|NoTax), reference?, date?, due_date?, invoice_number?, counterparty?, amount?, currency? } \u2014 WARNING: line_items REPLACES the entire line set on the invoice, so send every line the invoice should end up with, EACH WITH ITS item_code where the org tracks inventory \u2014 a resent line without its item_code loses the item association, so a one-line correction can silently strip inventory tracking off the whole invoice; omit the field entirely to leave the lines untouched. Use line_amount_types to fix a wrong tax treatment (e.g. a GST-inclusive total mistakenly entered on a Tax Exclusive line). `amount` here is the DISPLAY-ONLY NEW TOTAL shown on the card and is NOT checked against line_items - unlike xero.invoice.create and xero.bill.create - because it is the gross figure and the gross depends on tax rates this payload does not carry. Said explicitly so the absence of a check is a documented decision rather than something to be read as a gap. xero.contact.merge: { source_contact_id, target_contact_id, source_name?, target_name? }. xero.bank_transaction.delete: { bank_transaction_id, amount?, counterparty? }. xero.manual_journal.create: { narration, journal_lines: [{ account_code, line_amount (positive=debit, negative=credit), description?, tax_type? }], date? (YYYY-MM-DD), status? (DRAFT|POSTED, default DRAFT), amount?, currency? } \u2014 lines must balance to zero. Always include tenant_id."
21206
21216
  );
21207
21217
  var reasonSchema = external_exports.string().min(1).max(2e3).describe(
21208
21218
  "Why the agent needs to perform this write. Surfaced verbatim on the approval card for the human reviewer. Mandatory."
@@ -21240,7 +21250,7 @@ var awaitDecisionSchema = external_exports.object({
21240
21250
  // package.json
21241
21251
  var package_default = {
21242
21252
  name: "@integrity-labs/xero-broker",
21243
- version: "0.1.5",
21253
+ version: "0.1.7",
21244
21254
  description: "Xero Broker \u2014 MCP server that routes money- and ledger-touching Xero writes through approval-core (HITL). Sibling to cloud-broker / channel-broker; the only write path for an agent once the vendor xero-mcp-server's write tools are stripped. ENG-4922.",
21245
21255
  type: "module",
21246
21256
  bin: {
@@ -21258,7 +21268,7 @@ var package_default = {
21258
21268
  scripts: {
21259
21269
  build: "tsup",
21260
21270
  dev: "tsx watch src/index.ts",
21261
- typecheck: "tsc --noEmit",
21271
+ typecheck: "bash ../../scripts/typecheck-guard.sh tsc --noEmit",
21262
21272
  test: "vitest run",
21263
21273
  clean: "rm -rf dist"
21264
21274
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@integrity-labs/xero-broker",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "Xero Broker — MCP server that routes money- and ledger-touching Xero writes through approval-core (HITL). Sibling to cloud-broker / channel-broker; the only write path for an agent once the vendor xero-mcp-server's write tools are stripped. ENG-4922.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -18,7 +18,7 @@
18
18
  "scripts": {
19
19
  "build": "tsup",
20
20
  "dev": "tsx watch src/index.ts",
21
- "typecheck": "tsc --noEmit",
21
+ "typecheck": "bash ../../scripts/typecheck-guard.sh tsc --noEmit",
22
22
  "test": "vitest run",
23
23
  "clean": "rm -rf dist"
24
24
  },