jaz-clio 5.29.2 → 5.30.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.29.2
3
+ version: 5.30.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, 158 production gotchas, error
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: jaz-cli
3
- version: 5.29.2
3
+ version: 5.30.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.29.2
3
+ version: 5.30.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
- name: clio-kit
3
- version: 5.29.2
2
+ name: jaz-kit
3
+ version: 5.30.1
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
@@ -12,7 +12,7 @@ license: MIT
12
12
  compatibility: Works with Claude Code, Codex CLI, Cursor, Copilot, Claude Cowork, Claude.ai, and any agent that reads markdown. Multi-organization workflows need the `clio` CLI (`npm i -g jaz-clio`); a single organization works through MCP tools alone. Load alongside jaz-jobs for close playbooks, jaz-recipes for IFRS patterns, jaz-api for payload shapes, jaz-conversion for migrations.
13
13
  ---
14
14
 
15
- # Clio Kit
15
+ # Jaz Kit
16
16
 
17
17
  The operator layer for people who run books in Jaz. Where the other skills know *how to do accounting*, this one knows *whose books these are, what was decided last time, and where the close left off*.
18
18
 
@@ -20,17 +20,17 @@ The operator layer for people who run books in Jaz. Where the other skills know
20
20
 
21
21
  A close is not one conversation. Month-end runs eighteen steps over one to three days, and an accountant serving eight clients runs it eight times with eight different sets of bank accounts, materiality thresholds, and recurring accruals. Without somewhere to keep that, every session re-asks what it should already know, and every interruption loses the thread.
22
22
 
23
- Clio Kit gives each organization a folder: what the organization is, how it likes things done, what has been decided, and exactly where the current close stands.
23
+ Jaz Kit gives each organization a folder: what the organization is, how it likes things done, what has been decided, and exactly where the current close stands.
24
24
 
25
25
  ## The workspace
26
26
 
27
27
  ```
28
- ~/Documents/Clio Kit/ override with JAZ_KIT_HOME
28
+ ~/Documents/Jaz Kit/ override with JAZ_KIT_HOME
29
29
  KIT.md who you are, index of organizations
30
30
  _shared/policies/ skills/ firm-wide, applies to every organization
31
31
  orgs/<slug>/
32
32
  ORG.md the close config + session journal
33
- .env JAZ_ORG=<label>a pointer, never a key
33
+ .env JAZ_API_KEYthis company's key (gitignored)
34
34
  policies/ rules/ skills/ how this organization works
35
35
  scripts/ work/ automations · scratch (swept on exit, after asking)
36
36
  closes/<period>/
@@ -38,25 +38,25 @@ Clio Kit gives each organization a folder: what the organization is, how it like
38
38
  workpapers/ permanent audit file
39
39
  ```
40
40
 
41
- Keys never live here. They stay in the CLI's credential store (`clio auth`), outside any synced folder; the workspace holds only the label that points at one. That is what makes the kit safe to keep in Documents, back up, or share with a colleague through a private git repository.
41
+ The company's key lives in its own folder. A `jk-` key is org-scoped — it reaches exactly one company's books so the folder you open decides which ledger you touch; there is no profile to switch and no `--org` to get wrong. The `.env` is gitignored and its value is never printed. (On a default Mac, `~/Documents` syncs to iCloud, so the key syncs too — bounded and revocable, and set `JAZ_KIT_HOME` outside `~/Documents` to avoid it. See `references/workspace.md`.)
42
42
 
43
43
  ## Operations
44
44
 
45
- Every flow is specified in `references/flows.md` — that file is the procedure, and Claude Code's `/clio-*` commands are thin pointers into it. In agents without slash commands, the trigger phrases below reach the same flows.
45
+ Every flow is specified in `references/flows.md` — that file is the procedure, and Claude Code's `/jk-*` commands are thin pointers into it. In agents without slash commands, the trigger phrases below reach the same flows.
46
46
 
47
47
  | Intent | Flow | Command |
48
48
  |---|---|---|
49
- | Set up the kit · add a company | `setup` | `/clio-setup` |
50
- | Start work on one organization | `open` | `/clio-open <org>` |
51
- | Run a period close | `close` | `/clio-close <period>` |
52
- | Clear the draft review queue | `review` | `/clio-review` |
53
- | See every organization at a glance | `status` | `/clio-status` |
54
- | Connect, check, or rotate a key | `keys` | `/clio-keys` |
55
- | Record how this organization works | `policy` | `/clio-policy` |
56
- | Save a procedure for next time | `teach` | `/clio-teach` |
57
- | Checkpoint mid-close | `save` | `/clio-save` |
58
- | End the session cleanly | `exit` | `/clio-exit` |
59
- | What can I do right now | `help` | `/clio-help` |
49
+ | Set up the kit · add a company | `setup` | `/jk-setup` |
50
+ | Start work on one organization | `open` | `/jk-open <org>` |
51
+ | Run a period close | `close` | `/jk-close <period>` |
52
+ | Clear the draft review queue | `review` | `/jk-review` |
53
+ | See every organization at a glance | `status` | `/jk-status` |
54
+ | Connect, check, or rotate a key | `keys` | `/jk-keys` |
55
+ | Record how this organization works | `policy` | `/jk-policy` |
56
+ | Save a procedure for next time | `teach` | `/jk-teach` |
57
+ | Checkpoint mid-close | `save` | `/jk-save` |
58
+ | End the session cleanly | `exit` | `/jk-exit` |
59
+ | What can I do right now | `help` | `/jk-help` |
60
60
 
61
61
  ## Rules that hold across every flow
62
62
 
@@ -64,7 +64,7 @@ Six ground rules govern every operation — one organization per session, draft
64
64
 
65
65
  ## This is a harness, not a rulebook
66
66
 
67
- Clio Kit supplies structure: memory between sessions, sequencing, safety rails, and an audit trail. **The accountant supplies the domain truth** — their materiality, their filing dates, their accounting policies, their sign-off model, their procedures.
67
+ Jaz Kit supplies structure: memory between sessions, sequencing, safety rails, and an audit trail. **The accountant supplies the domain truth** — their materiality, their filing dates, their accounting policies, their sign-off model, their procedures.
68
68
 
69
69
  So: never assert a statutory deadline, a reporting standard, or a "best practice" from memory, and never offer a jurisdiction default for the user to correct. A confident wrong answer costs them more than an open question. When a fact is missing from ORG.md, ask for it and record it. When they tell you how they do something, write it to `policies/` or `rules/` and follow it thereafter.
70
70
 
@@ -1,14 +1,18 @@
1
- # Clio Kit flows
1
+ # Jaz Kit flows
2
2
 
3
- The canonical procedure for every Clio Kit operation. Slash commands (`/clio-*`) point here; agents without slash commands reach the same flows from the trigger phrases in `SKILL.md`. One source of truth — command files add nothing.
3
+ The canonical procedure for every Jaz Kit operation. Slash commands (`/jk-*`) point here; agents without slash commands reach the same flows from the trigger phrases in `SKILL.md`. One source of truth — command files add nothing.
4
4
 
5
5
  Schemas live in `workspace.md` (KIT.md, ORG.md, `.env`) and `close-state.md` (CLOSE.md, review pack). Field-by-field onboarding questions live in `org-interview.md`. Copy-paste scaffolds live in `templates.md`.
6
6
 
7
7
  ## Ground rules for every flow
8
8
 
9
- 1. **One organization per session.** Resolve the label once at open, then pass `--org <label>` on every `clio` call. Never run `clio auth switch` inside a Clio Kit flow it rewrites the shared active profile in `~/.config/jaz-clio/credentials.json`, which silently changes the org for every other terminal and agent session on the machine. `--org` is explicit, per-call, and cannot leak across sessions.
10
- 2. **Draft first.** `saveAsDraft` defaults to `false` in the API — omitting it posts live. Every write in a Clio Kit flow sets `saveAsDraft: true` (or `--plan` then a non-finalized run for `clio ct`) unless the org's `rules/` explicitly relaxes that transaction type. Finalization happens in the review flow, never as a side effect.
11
- 3. **Never print a key.** Not in output, not in a file the user can paste, not in an error. Key values only ever move between the Jaz UI and `clio auth add`. `jk-` strings are redacted on sight.
9
+ 1. **One organization per session the key decides which.** Each workspace's `.env` holds that company's own `jk-` key, and a `jk-` key is org-scoped: one key, one company's books. So the folder you open determines which ledger you touch there is no active profile to switch, no label, no `--org` to get wrong. Load the key in the same command as each `clio` call:
10
+ ```
11
+ set -a; . "orgs/<slug>/.env"; set +a; clio <command> --json
12
+ ```
13
+ `set -a; . file; set +a` sources `JAZ_API_KEY` for that one command without echoing it — the value never reaches the transcript or `ps`. Never pass `--org`, never `clio auth switch`, and never carry a `JAZ_API_KEY` exported from another shell into a Jaz Kit session.
14
+ 2. **Draft first.** `saveAsDraft` defaults to `false` in the API — omitting it posts live. Every write in a Jaz Kit flow sets `saveAsDraft: true` (or `--plan` then a non-finalized run for `clio ct`) unless the org's `rules/` explicitly relaxes that transaction type. Finalization happens in the review flow, never as a side effect.
15
+ 3. **Never print a key.** The key lives in the workspace `.env`, which the user pastes into — never chat, never a message, never an error. Source the file; do not read the key value into your own output. `jk-` strings are redacted on sight.
12
16
  4. **Judgment gets recorded.** When the user accepts a variance, carries a residual, or overrides a default, call `jot` at that moment. Mechanical steps never jot.
13
17
  5. **Report exceptions, not dumps.** Surface the top few items that need a decision; write the full output to the period's `workpapers/`.
14
18
 
@@ -16,42 +20,48 @@ Schemas live in `workspace.md` (KIT.md, ORG.md, `.env`) and `close-state.md` (CL
16
20
 
17
21
  ## setup — set up the kit, onboard an organization
18
22
 
19
- Triggers: "set up Clio Kit", "add my company", "onboard a new client", "connect another org".
23
+ Triggers: "set up Jaz Kit", "add my company", "onboard a new client", "connect another org".
20
24
 
21
25
  Idempotent. No kit → create it. Kit exists → this is the add-a-company flow.
22
26
 
23
- **1. Locate the root.** `JAZ_KIT_HOME` if set, else `~/Documents/Clio Kit`. If it exists, skip to step 4.
27
+ **1. Locate the root.** `JAZ_KIT_HOME` if set, else `~/Documents/Jaz Kit`. If it exists, skip to step 4.
24
28
 
25
29
  **2. Ask who is being served** (one question, shapes vocabulary everywhere after):
26
30
  - *my own business* → say "your books", "your organization"
27
31
  - *clients* → say "the client", "the engagement"
28
32
  - *both* → default to client vocabulary, treat own entities as clients
29
33
 
30
- **3. Create the skeleton and KIT.md** from `templates.md`. Offer git (default yes) — write `.gitignore` **before** `git init` so nothing untracked is ever staged:
34
+ **3. Create the skeleton and KIT.md** from `templates.md`. The keys live inside the kit (step 5), so git hygiene matters — write `.gitignore` **before** `git init` so a key can never be staged:
31
35
  ```
32
36
  .env
37
+ *.env
38
+ .env.*
33
39
  work/
34
40
  *conflicted copy*
35
41
  ```
42
+ Offer git (default yes).
36
43
 
37
- **4. Check the CLI.** `clio auth list` if `clio` is missing, the user is on the MCP-only path: say multi-organization support needs the CLI (`npm i -g jaz-clio`), then continue in single-org mode using whatever key the MCP server already has. If auth commands misbehave, `clio update` (the CLI self-notifies about new versions; do not hand-roll a version comparison).
44
+ **4. Check the CLI.** Multi-company work runs through the `clio` CLI. If `clio` is missing, say so and offer `npm i -g jaz-clio`; a single company can still work through the plugin's MCP key alone, but the workspace-key model below needs the CLI. If commands misbehave, `clio update` (the CLI self-notifies about new versions do not hand-roll a version comparison).
38
45
 
39
- **5. Connect the organization.** Guide key creation in the Jaz UI (Settings API keys), then:
40
- ```
41
- clio auth add <key>
42
- ```
43
- The command validates the key against the API and registers the org under a label. It prints the org name, currency, and country — do not ask the user to retype what it already knows. If the derived label collides with an existing one the command exits — re-run with `--as <label>` to choose a distinct one.
46
+ **5. Connect the company — its key lives in its folder.** A `jk-` key is org-scoped: one key *is* one company's books, so the key in the folder is all the identity the workspace needs.
47
+ 1. Guide key creation in the Jaz UI (**Settings → API keys**).
48
+ 2. Write a staging `.env` (`<root>/.new-org.env`) containing the single line `JAZ_API_KEY=` and tell the user the exact path to paste their key after the `=`. **Never take the key through chat** — it goes straight into the file.
49
+ 3. Validate and identify the company in one call, sourcing the file so the value never surfaces:
50
+ ```
51
+ set -a; . "<root>/.new-org.env"; set +a; clio org info --json
52
+ ```
53
+ This returns the name, `resourceId`, currency, country, and financial year end — the key was valid if this succeeds, and it names the company so you never ask the user to retype it. A `401` means the pasted key is wrong or already revoked; send them back to step 5.1.
44
54
 
45
55
  **6. Auto-profile.** Two small calls answer almost everything:
46
56
  ```
47
- clio org info --org <label> --json # identity
48
- clio reports generate ledger-highlights --org <label> --json # shape of the books
57
+ set -a; . "<root>/.new-org.env"; set +a; clio reports generate ledger-highlights --json
49
58
  ```
59
+ (Identity already came from step 5.3's `clio org info`.)
50
60
  Highlights (`get_ledger_highlights` on MCP) returns what the organization actually *uses*, not what exists: `hasCrossCurrencyActivity` and `activeCurrencyCodes` settle `multi_currency`; `transactionCountByType` shows which modules are live (a `FIXED_ASSET` count means the register is in use); `distinctAccountCount` and `activeAccountResourceIds` name the accounts in play; first/last transaction dates bound the periods worth closing.
51
61
 
52
62
  That matters because *existing* and *used* diverge hard: one real organization had 1,027 accounts of which 144 were active, and 226 bank accounts. Never transcribe the ledger into ORG.md — read highlights, then ask which of the active accounts they reconcile in a close.
53
63
 
54
- **Never run a bare `clio context --json`** — unscoped it preloads every reference entity (1.5 MB on that same org). If you need reference detail, scope it: `clio context --org <label> -w chart_of_accounts --json`.
64
+ **Never run a bare `clio context --json`** — unscoped it preloads every reference entity (1.5 MB on that same org). If you need reference detail, scope it: `... clio context -w chart_of_accounts --json` (sourcing the same `.env`).
55
65
 
56
66
  Present the filled ORG.md and ask the user to confirm or correct. Never present a guess as a fact — mark anything inferred as *proposed*.
57
67
 
@@ -61,9 +71,11 @@ Present the filled ORG.md and ask the user to confirm or correct. Never present
61
71
 
62
72
  **If the directory already exists for THIS organization** (its `organization_id` matches), this is a re-onboard, not a new one. Never rewrite ORG.md and never reinstall the starter rules — that would destroy hand-edited materiality, accrual definitions, decisions, and the journal. Show a field-by-field diff of what auto-profiling found against what is on file, apply only what the user accepts, and leave everything else untouched.
63
73
 
64
- **9. Write the workspace**: `orgs/<slug>/` with ORG.md, `.env` (holding `JAZ_ORG=<label>` — a pointer, never a key), and empty `policies/ rules/ skills/ scripts/ work/ closes/`. Install the starter rules from `templates.md` (draft-first, locked-period, review threshold).
74
+ **9. Write the workspace**: create `orgs/<slug>/` with ORG.md, the empty folders `policies/ rules/ skills/ scripts/ work/ closes/`, and the starter rules from `templates.md` (draft-first, locked-period, review threshold). Then **move the staging key into place**: `mv <root>/.new-org.env orgs/<slug>/.env`. That file holds the real `JAZ_API_KEY` and is gitignored by step 3.
75
+
76
+ **iCloud note.** If the kit root resolves under an iCloud-synced path (the default `~/Documents/Jaz Kit` does on most Macs), say so plainly once: the `.env` key will sync to the user's iCloud and their other devices. That is usually an acceptable trade — a `jk-` key is scoped to this one company and revocable in the Jaz UI in seconds — but if they would rather keep keys off the cloud, they can set `JAZ_KIT_HOME` to a path outside `~/Documents` and re-run setup. Their call; make it once, do not nag.
65
77
 
66
- **10. Close the loop.** Show the path, the label, and the single next step: `/clio-open <slug>`.
78
+ **10. Close the loop.** Show the folder path and the single next step: `/jk-open <slug>`.
67
79
 
68
80
  ---
69
81
 
@@ -77,21 +89,15 @@ Triggers: "open <org>", "switch to <org>", "work on <client>", "let's do <org>'s
77
89
 
78
90
  **4. Load context**: ORG.md, then `policies/` and `rules/`, then `skills/` — org files first, `_shared/` second, and **org-level wins on conflict**. Do not re-read files already in context.
79
91
 
80
- **5. Assert no exported key is hijacking the session.** `JAZ_API_KEY` resolves *before* `--org` and silently voids it, with no error and no organization bannerevery write would land in that key's organization instead. Check the shell:
81
- ```
82
- clio auth whoami --json
83
- ```
84
- The `source` field must be `flag-org`, `env-org`, or `active-file`. If it is `env-api-key`, stop: tell the user to `unset JAZ_API_KEY` in this shell (or open a new one) and start again. Do not proceed and do not write.
85
-
86
- **6. Verify the connection with a live call**, not the local profile — `clio auth whoami --org <label>` prints only what is stored on disk and will happily report a revoked key as fine:
92
+ **5. Load the company's key and verify it live.** Confirm `orgs/<slug>/.env` exists and holds a `JAZ_API_KEY` line; if it doesn't, the workspace was never fully set uproute to `/jk-keys`. Then, sourcing the key so the value never surfaces:
87
93
  ```
88
- clio org info --org <label> --json
94
+ set -a; . "orgs/<slug>/.env"; set +a; clio org info --json
89
95
  ```
90
- Compare the returned `resourceId` against ORG.md. Different name, same identifier → the org was renamed; flag it and offer to update ORG.md. `401`/`403` → the key was revoked or access removed; send the user to `/clio-keys` and stop. Identifier mismatch the label points at the wrong organization; stop and do not write.
96
+ Compare the returned `resourceId` against ORG.md. Same identifier, different name → the company was renamed; flag it and offer to update ORG.md. Identifier mismatch → **the wrong key is in this folder** (someone pasted company B's key into company A's `.env`); stop, do not write, send them to `/jk-keys`. `401`/`403` → the key was revoked or access removed; `/jk-keys` and stop. This live check is why the key belonging to the folder matters — a session physically cannot write to the wrong company once its own key verifies.
91
97
 
92
- **7. Cross-check the tool plane.** If MCP tools are available, call `get_organization` and compare its identifier to what `clio org info` returned. A mismatch means the MCP server is pinned to a different organization by a `JAZ_API_KEY` in plugin or connector settings while the CLI points elsewhere — **stop immediately**, tell the user to clear that setting, and do not write anything. Note this check only catches a *divergence*: if the same exported key drives both planes they agree while both are wrong, which is what step 5 exists for.
98
+ **6. Cross-check the tool plane.** If MCP tools are available, call `get_organization` and compare its identifier to what step 5 returned. A mismatch means the plugin's own `JAZ_API_KEY` (from connector settings) points at a different company than this folder's key — **stop**, tell the user to clear that setting, and do not write. The MCP plane can't be pointed per-folder; when it disagrees with the workspace key, the workspace key is the intended one.
93
99
 
94
- **8. Report state, then wait**: open close and its phase, next filing deadline computed from ORG.md, count of items awaiting review, last session's closing note. Offer the obvious next action; do not start it unasked.
100
+ **7. Report state, then wait**: open close and its phase, next filing deadline computed from ORG.md, count of items awaiting review, last session's closing note. Offer the obvious next action; do not start it unasked.
95
101
 
96
102
  ---
97
103
 
@@ -162,14 +168,14 @@ Across every `orgs/*/`: organization, last closed period, any open close and its
162
168
 
163
169
  Triggers: "add a key", "rotate the key", "my key stopped working".
164
170
 
165
- Wraps `clio auth`. **Never display a key value.**
171
+ The key is the line `JAZ_API_KEY=jk-...` in `orgs/<slug>/.env`. Everything here is editing that one file. **Never display a key value, and never take one through chat — the user pastes into the file.**
166
172
 
167
- - **Check**: `clio auth list`, and `clio auth whoami --org <label>` for one org.
168
- - **Add**: guide creation in the Jaz UI `clio auth add <key>` confirm the org it resolved to.
169
- - **Rotate**: create the new key first, then `clio auth add <key> --as <label>-new`. The label is required: `clio auth add` derives it from the organization name, so a same-organization rotation collides with the existing profile and exits. Verify with `clio auth whoami --org <label>-new`, update `.env` to the new label, then `clio auth remove <old-label>` and revoke the old key in the UI. Never revoke before the replacement is proven.
170
- - **Revoked key**: `clio auth remove <label>`, then add the replacement.
173
+ - **Check**: source it and make a live call. `set -a; . "orgs/<slug>/.env"; set +a; clio org info --json` — success means the key is valid and names the company; `401` means it is wrong or revoked.
174
+ - **Add / repair** (empty or missing key): tell the user the path and the line to paste (`JAZ_API_KEY=<their key>`), then run the check above.
175
+ - **Rotate**: create the new key in the Jaz UI first. Have the user replace the `JAZ_API_KEY=` line in `orgs/<slug>/.env`. Run the check. Only once it passes, revoke the old key in the UI. Never revoke before the replacement verifies a `jk-` key is org-scoped, so an old and new key for the same company coexist fine until you retire the old one.
176
+ - **Revoked / stopped working**: same as rotate new key in the UI, paste over the line, check.
171
177
 
172
- **Headless automation.** Scheduled scripts cannot use an interactive credential store. The escape hatch, its exact file location outside the kit root, and the safe loader line are specified in `workspace.md` (Auth model). Say plainly that it trades safety for automation, that the exported key pins the whole shell to one organization, and that the pointer model is better whenever a human is present.
178
+ **Headless automation.** A cron job has no chat to paste into. Point its runner at the workspace file directly with the same safe loader `set -a; . "orgs/<slug>/.env"; set +a; clio <command>` and never under `set -x`, never `echo` the variable. It is the same file a human uses; nothing separate to manage.
173
179
 
174
180
  ---
175
181
 
@@ -221,6 +227,6 @@ Triggers: "done for today", "wrap up", "finish here".
221
227
 
222
228
  ## help — what can I do here
223
229
 
224
- Triggers: "help", "what commands", "what can Clio Kit do".
230
+ Triggers: "help", "what commands", "what can Jaz Kit do".
225
231
 
226
232
  The command table, the current state (which org is open, what is in flight), and the two or three actions that actually make sense right now given that state. Point at the jobs skill for the accounting workflows themselves rather than restating them.
@@ -4,18 +4,20 @@ Fill ORG.md from the platform first, then ask only what the platform cannot know
4
4
 
5
5
  ## Read first
6
6
 
7
+ Every call sources the company's key from its `.env` — `set -a; . "orgs/<slug>/.env"; set +a; clio …` (during setup the key is still in the staging `.new-org.env`). No `--org`; the key is the org.
8
+
7
9
  | Call | Fills |
8
10
  |---|---|
9
- | `clio org info --org <label> --json` | `name`, `organization_id`, `base_currency`, `country`, `fy_end` (returned as `financialYearEnd` in `DD-MM` — write it out in full) |
10
- | `clio reports generate ledger-highlights --org <label> --json` | `multi_currency`, which modules are live, active accounts, period range |
11
+ | `clio org info --json` | `name`, `organization_id`, `base_currency`, `country`, `fy_end` (returned as `financialYearEnd` in `DD-MM` — write it out in full) |
12
+ | `clio reports generate ledger-highlights --json` | `multi_currency`, which modules are live, active accounts, period range |
11
13
  | `search_journals` over the last three months | Candidate `recurring_accruals` |
12
- | `clio context --org <label> -w <workflow> --json` | Reference detail, only if needed — **always pass `-w`** |
14
+ | `clio context -w <workflow> --json` | Reference detail, only if needed — **always pass `-w`** |
13
15
 
14
16
  Lead with **ledger-highlights**: it reports what the books actually use rather than what exists. `hasCrossCurrencyActivity` settles multi-currency without listing 19 currencies; `transactionCountByType` shows whether fixed assets, credit notes, or cash transfers are even in play; `distinctAccountCount` and `activeAccountResourceIds` narrow 1,027 accounts to the 144 that matter.
15
17
 
16
18
  Never transcribe the ledger. One test org had 226 bank accounts. Ask which they reconcile in a close and record those. A bare `clio context --json` is 1.5 MB — always scope with `-w`.
17
19
 
18
- `clio auth add` already printed the organization name, currency, and country when the key was registered. Do not ask for them again.
20
+ The setup flow's first `clio org info` (step 5.3) already printed the name, currency, and country while validating the key. Do not ask for them again.
19
21
 
20
22
  **Derive, then confirm.** Multi-currency is inferred from currencies in use. The filing profile is inferred from tax profiles configured. Recurring accruals are inferred from repetition. Present each as *proposed* and let the user correct it — an inference stated as a fact is how a wrong materiality threshold ends up governing a close.
21
23
 
@@ -5,7 +5,7 @@ Copy these when creating files. Replace every `<…>`. Omit rows that do not app
5
5
  ## KIT.md
6
6
 
7
7
  ```markdown
8
- # Clio Kit — <operator name>
8
+ # Jaz Kit — <operator name>
9
9
 
10
10
  Mode: <own-books | client-books | both>
11
11
  Created: <YYYY-MM-DD>
@@ -32,7 +32,6 @@ Applied to new organizations unless overridden.
32
32
  ## Identity
33
33
 
34
34
  - Organization ID: <resourceId from clio org info>
35
- - Label: <clio auth profile label>
36
35
  - Country: <SG>
37
36
  - Base currency: <SGD>
38
37
  - Multi-currency: <yes | no>
@@ -172,7 +171,7 @@ item.
172
171
 
173
172
  ## Starter policy
174
173
 
175
- Create the file empty apart from its heading. **Do not seed it with suggestions** — policies are the operator's working practice, and a pre-filled list gets accepted unread, which turns our guesses into their file. It fills up through `/clio-policy` and `/clio-teach` as they say how they work.
174
+ Create the file empty apart from its heading. **Do not seed it with suggestions** — policies are the operator's working practice, and a pre-filled list gets accepted unread, which turns our guesses into their file. It fills up through `/jk-policy` and `/jk-teach` as they say how they work.
176
175
 
177
176
  **`policies/close-routine.md`**
178
177
  ```markdown
@@ -181,6 +180,14 @@ Create the file empty apart from its heading. **Do not seed it with suggestions*
181
180
  <Recorded as the operator states it. Nothing here is assumed.>
182
181
  ```
183
182
 
183
+ ## orgs/<slug>/.env
184
+
185
+ One line, the company's own org-scoped key. Created during setup as a staging file the user pastes into, then moved into the folder. Gitignored. Never echoed.
186
+
187
+ ```
188
+ JAZ_API_KEY=<paste this company's Jaz API key here>
189
+ ```
190
+
184
191
  ## .gitignore
185
192
 
186
193
  Written before `git init`, so nothing untracked is ever staged.
@@ -193,4 +200,4 @@ work/
193
200
  *conflicted copy*
194
201
  ```
195
202
 
196
- `*.env` matters: the headless escape-hatch file is named `<slug>.env`, and a bare `.env` pattern would not match a copy of it landing in the kit.
203
+ `*.env` and `.env.*` matter because each company's key sits in its `orgs/<slug>/.env`, and a bare `.env` pattern misses a stray copy or a `.env.backup`. Write this file **before** `git init`.
@@ -4,12 +4,12 @@ File formats and the credential design. Procedures live in `flows.md`; blank sca
4
4
 
5
5
  ## Root
6
6
 
7
- `JAZ_KIT_HOME` if set, otherwise `~/Documents/Clio Kit`.
7
+ `JAZ_KIT_HOME` if set, otherwise `~/Documents/Jaz Kit`.
8
8
 
9
9
  Documents is chosen deliberately: accountants need to find, back up, and attach these files, and Documents is where they look. That is only safe because **no secret is ever written inside the kit** — on a default Mac this directory syncs to iCloud.
10
10
 
11
11
  ```
12
- ~/Documents/Clio Kit/
12
+ ~/Documents/Jaz Kit/
13
13
  KIT.md
14
14
  _shared/
15
15
  policies/
@@ -50,8 +50,7 @@ The close configuration. Everything the jobs skill's playbooks otherwise stop to
50
50
  | Field | Meaning |
51
51
  |---|---|
52
52
  | `name` | Legal entity name as it appears in Jaz |
53
- | `organization_id` | Identifier from `clio org info` — the real identity key |
54
- | `label` | The `clio auth` profile label for this organization |
53
+ | `organization_id` | Identifier from `clio org info` — the real identity key, matched against the key on every open |
55
54
  | `country` | Recorded for the user's own reference and for report labelling |
56
55
  | `base_currency` | Reporting currency |
57
56
  | `multi_currency` | Whether foreign-currency balances exist — gates the FX verification step |
@@ -90,48 +89,42 @@ The next deadline is `filing_periods` + `filing_offset`. Past due with nothing r
90
89
 
91
90
  Estimation methods for accruals must match what the jobs skill's month-end playbook expects — see its accruals step for the list.
92
91
 
93
- ## .env
92
+ ## .env — the company's key
94
93
 
95
- Non-secret configuration only:
94
+ Each company's folder holds its own key:
96
95
 
97
96
  ```
98
- JAZ_ORG=acme-sg
97
+ JAZ_API_KEY=jk-<this company's key>
99
98
  ```
100
99
 
101
- This names a `clio auth` profile. It is a pointer, not a credential publishing it would reveal nothing but a local nickname. Gitignored anyway, because the escape hatch below can add a path, and because habit is cheaper than judgment.
100
+ That is a real secret, gitignored by `.env` / `*.env` / `.env.*` (write `.gitignore` before `git init`). Nothing else belongs in this file no other config, no second key.
102
101
 
103
102
  ## Auth model
104
103
 
105
- Keys live in the CLI's credential store at `~/.config/jaz-clio/credentials.json`, registered by `clio auth add`, which validates each key against the API before saving it. That path is outside Documents and therefore outside iCloud.
104
+ A `jk-` key is **org-scoped**: it grants access to exactly one company's books. So the key that sits in `orgs/acme/.env` *is* Acme's identity there is no separate profile, label, or active-org to keep in sync, and nothing to switch. Open a folder, its key is the org.
106
105
 
107
- **Resolution order** (first match wins): `--api-key` `JAZ_API_KEY` `--org <label>` `JAZ_ORG` active profile.
108
-
109
- Clio Kit uses `--org <label>` on every call, because `clio auth switch` is global: it rewrites the active profile in a shared file, so a second terminal, a scheduled script, or another agent session silently changes organization underneath itself. `--org` names the organization at the point of the write instead.
110
-
111
- **`--org` is not absolute — `JAZ_API_KEY` outranks it.** Read the resolution order again: an exported `JAZ_API_KEY` resolves at step 2 and returns before `--org` is ever consulted. The flag is then silently ignored, and because no profile was resolved the CLI prints no organization banner. Every write lands in the env key's organization with no error and no visual signal.
112
-
113
- That is the failure that posts one organization's entries into another's ledger, and it defeats a naive cross-check: if both the CLI and the MCP server read the same `JAZ_API_KEY`, they agree with each other while both being wrong. So the open flow does two distinct things — it asserts no `JAZ_API_KEY` is set for the session, and it compares the returned organization identifier against ORG.md. The second catches a mismatched label; only the first catches an exported key.
114
-
115
- **Never combine an exported `JAZ_API_KEY` with Clio Kit.** One shell per organization, and let `--org` do the work.
116
-
117
- **Headless escape hatch.** Scheduled jobs have no interactive credential store. Write the key to `~/.config/jaz-clio/kit-env/<slug>.env`, `chmod 600` — outside the kit root, never inside it. The organization's `.env` records only the path. The CLI does not read `.env` files, so the runner loads it explicitly:
106
+ **Loading the key.** The CLI reads `JAZ_API_KEY` from the environment (it does not itself read `.env` files), so every `clio` call in a session sources the folder's file in the same command:
118
107
 
119
108
  ```
120
- set -a; . ~/.config/jaz-clio/kit-env/<slug>.env; set +a
109
+ set -a; . "orgs/<slug>/.env"; set +a; clio <command> --json
121
110
  ```
122
111
 
123
- Use that form, not `export $(… | xargs)`: `xargs` execs a real subprocess, which puts the key in its argv where any local user can read it from `ps`, and it word-splits and glob-expands values. Never run the loader under `set -x`, and never echo the variable.
112
+ `set -a; . file; set +a` is the safe form never `export $(… | xargs)`, whose `xargs` subprocess exposes the key in `ps` argv and word-splits the value. Never run the loader under `set -x`, and never echo the variable. Because each command sources exactly one folder's key and passes no `--org`, there is no ambient state to leak between sessions.
113
+
114
+ **Two guards still apply** (they protect against habit and misconfiguration): the CLI refuses `--org` when `JAZ_API_KEY` is set — Jaz Kit never passes `--org`, so this only fires if something slips — and it refuses comma-separated keys. Neither is part of the normal path; both are backstops.
115
+
116
+ **The one cross-check worth doing.** The plugin's MCP server has its own `JAZ_API_KEY` from connector settings, which may point at a different company than the folder you opened. The MCP plane can't be re-pointed per folder, so at open the flow compares `get_organization` (MCP) against `clio org info` (the folder's key) and stops on a mismatch. Otherwise the two models coexist cleanly: MCP for a single-company user with no CLI, the folder key for everyone running several.
124
117
 
125
- This exports `JAZ_API_KEY` into the shell, which pins **every** command in it to that one organization and makes `--org` inert (see above). That is acceptable for a single-organization scheduled job and unacceptable anywhere else: one shell per organization, and never in an interactive Clio Kit session.
118
+ **iCloud.** The default root `~/Documents/Jaz Kit` syncs on most Macs, so the `.env` keys ride to the user's iCloud and their other devices. That is a real exposure and worth saying once at setup — but a bounded one: a `jk-` key reaches one company's books and is revocable in the Jaz UI in seconds. A user who would rather keep keys off the cloud sets `JAZ_KIT_HOME` to a path outside `~/Documents`. Git is separately handled by the ignore rules above.
126
119
 
127
120
  ## Sharing a kit across a team
128
121
 
129
- The kit is a git repository (offered at init, `.env` and `work/` ignored). To share:
122
+ The kit is a git repository (offered at setup; `.env` / `*.env` / `work/` ignored). To share:
130
123
 
131
- 1. Push to a **private** repository.
132
- 2. Colleagues clone it and run `clio auth add` with their own keys credentials never travel, only the labels do.
124
+ 1. Push to a **private** repository. The `.env` keys stay behind — they are gitignored, so nothing sensitive travels.
125
+ 2. Each colleague clones it and pastes their **own** key into each `orgs/<slug>/.env`. Keys are per-machine; only the ORG.md context and policies are shared.
133
126
  3. Pull before starting, push after finishing.
134
127
 
135
- Coordinate who works which organization. Two people closing the same period simultaneously will conflict in CLOSE.md, and worse, may both finalize the same drafts. Git surfaces the file conflict; nothing prevents the double-finalize, so agree who owns a client before starting.
128
+ Coordinate who works which company. Two people closing the same period simultaneously will conflict in CLOSE.md, and worse, may both finalize the same drafts. Git surfaces the file conflict; nothing prevents the double-finalize, so agree who owns a client before starting.
136
129
 
137
130
  **Do not share a kit through iCloud, Dropbox, or a shared drive.** File sync resolves concurrent edits by writing "conflicted copy" duplicates, which an agent may then read as truth. Git surfaces the conflict instead of hiding it. The open flow refuses to run when it finds conflicted-copy files.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: jaz-pseudo-sql
3
- version: 5.29.2
3
+ version: 5.30.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.29.2
3
+ version: 5.30.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-recipes
3
- version: 5.29.2
3
+ version: 5.30.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
package/cli.mjs CHANGED
@@ -892,7 +892,7 @@ ${qpt}
892
892
  Run `+or.cyan("{updateCommand}")+" to update",o=e.message||i;e.boxenOptions??={padding:1,margin:1,textAlignment:"center",borderColor:"yellow",borderStyle:"round"};let s=MN(uJ(o,{packageName:this._packageName,currentVersion:this.update.current,latestVersion:this.update.latest,updateCommand:n}),e.boxenOptions);return e.defer===!1?console.error(s):Tm.on("exit",()=>{console.error(s)}),this}};function fJ(t){let e=new FI(t);return e.check(),e}Ka();Ly();FJ();var PI=en(QJ(),1);import GN from"node:process";Ly();import Wc from"node:process";function LJ(){return Wc.platform!=="win32"?Wc.env.TERM!=="linux":!!Wc.env.CI||!!Wc.env.WT_SESSION||!!Wc.env.TERMINUS_SUBLIME||Wc.env.ConEmuTask==="{cmd::Cmder}"||Wc.env.TERM_PROGRAM==="Terminus-Sublime"||Wc.env.TERM_PROGRAM==="vscode"||Wc.env.TERM==="xterm-256color"||Wc.env.TERM==="alacritty"||Wc.env.TERMINAL_EMULATOR==="JetBrains-JediTerm"}var GEt={info:or.blue("\u2139"),success:or.green("\u2714"),warning:or.yellow("\u26A0"),error:or.red("\u2716")},JEt={info:or.blue("i"),success:or.green("\u221A"),warning:or.yellow("\u203C"),error:or.red("\xD7")},VEt=LJ()?GEt:JEt,LI=VEt;Bm();function MJ({stream:t=process.stdout}={}){return!!(t&&t.isTTY&&process.env.TERM!=="dumb"&&!("CI"in process.env))}PJ();import Zl from"node:process";var WEt=3,UJ=class{#e=0;start(){this.#e++,this.#e===1&&this.#r()}stop(){if(this.#e<=0)throw new Error("`stop` called more times than `start`");this.#e--,this.#e===0&&this.#n()}#r(){Zl.platform==="win32"||!Zl.stdin.isTTY||(Zl.stdin.setRawMode(!0),Zl.stdin.on("data",this.#i),Zl.stdin.resume())}#n(){Zl.stdin.isTTY&&(Zl.stdin.off("data",this.#i),Zl.stdin.pause(),Zl.stdin.setRawMode(!1))}#i(e){e[0]===WEt&&Zl.emit("SIGINT")}},ZEt=new UJ,$J=ZEt;var KEt=en(QJ(),1),qJ=class{#e=0;#r=!1;#n=0;#i=-1;#t=0;#o;#s;#a;#c;#d;#p;#f;#l;#m;#h;#u;color;constructor(e){typeof e=="string"&&(e={text:e}),this.#o={color:"cyan",stream:GN.stderr,discardStdin:!0,hideCursor:!0,...e},this.color=this.#o.color,this.spinner=this.#o.spinner,this.#d=this.#o.interval,this.#a=this.#o.stream,this.#p=typeof this.#o.isEnabled=="boolean"?this.#o.isEnabled:MJ({stream:this.#a}),this.#f=typeof this.#o.isSilent=="boolean"?this.#o.isSilent:!1,this.text=this.#o.text,this.prefixText=this.#o.prefixText,this.suffixText=this.#o.suffixText,this.indent=this.#o.indent,GN.env.NODE_ENV==="test"&&(this._stream=this.#a,this._isEnabled=this.#p,Object.defineProperty(this,"_linesToClear",{get(){return this.#e},set(r){this.#e=r}}),Object.defineProperty(this,"_frameIndex",{get(){return this.#i}}),Object.defineProperty(this,"_lineCount",{get(){return this.#n}}))}get indent(){return this.#l}set indent(e=0){if(!(e>=0&&Number.isInteger(e)))throw new Error("The `indent` option must be an integer from 0 and up");this.#l=e,this.#y()}get interval(){return this.#d??this.#s.interval??100}get spinner(){return this.#s}set spinner(e){if(this.#i=-1,this.#d=void 0,typeof e=="object"){if(e.frames===void 0)throw new Error("The given spinner must have a `frames` property");this.#s=e}else if(!MI())this.#s=PI.default.line;else if(e===void 0)this.#s=PI.default.dots;else if(e!=="default"&&PI.default[e])this.#s=PI.default[e];else throw new Error(`There is no built-in spinner named '${e}'. See https://github.com/sindresorhus/cli-spinners/blob/main/spinners.json for a full list.`)}get text(){return this.#m}set text(e=""){this.#m=e,this.#y()}get prefixText(){return this.#h}set prefixText(e=""){this.#h=e,this.#y()}get suffixText(){return this.#u}set suffixText(e=""){this.#u=e,this.#y()}get isSpinning(){return this.#c!==void 0}#A(e=this.#h,r=" "){return typeof e=="string"&&e!==""?e+r:typeof e=="function"?e()+r:""}#g(e=this.#u,r=" "){return typeof e=="string"&&e!==""?r+e:typeof e=="function"?r+e():""}#y(){let e=this.#a.columns??80,r=this.#A(this.#h,"-"),n=this.#g(this.#u,"-"),i=" ".repeat(this.#l)+r+"--"+this.#m+"--"+n;this.#n=0;for(let o of fa(i).split(`
893
893
  `))this.#n+=Math.max(1,Math.ceil(Eo(o,{countAnsiEscapeCodes:!0})/e))}get isEnabled(){return this.#p&&!this.#f}set isEnabled(e){if(typeof e!="boolean")throw new TypeError("The `isEnabled` option must be a boolean");this.#p=e}get isSilent(){return this.#f}set isSilent(e){if(typeof e!="boolean")throw new TypeError("The `isSilent` option must be a boolean");this.#f=e}frame(){let e=Date.now();(this.#i===-1||e-this.#t>=this.interval)&&(this.#i=++this.#i%this.#s.frames.length,this.#t=e);let{frames:r}=this.#s,n=r[this.#i];this.color&&(n=or[this.color](n));let i=typeof this.#h=="string"&&this.#h!==""?this.#h+" ":"",o=typeof this.text=="string"?" "+this.text:"",s=typeof this.#u=="string"&&this.#u!==""?" "+this.#u:"";return i+n+o+s}clear(){if(!this.#p||!this.#a.isTTY)return this;this.#a.cursorTo(0);for(let e=0;e<this.#e;e++)e>0&&this.#a.moveCursor(0,-1),this.#a.clearLine(1);return(this.#l||this.lastIndent!==this.#l)&&this.#a.cursorTo(this.#l),this.lastIndent=this.#l,this.#e=0,this}render(){return this.#f?this:(this.clear(),this.#a.write(this.frame()),this.#e=this.#n,this)}start(e){return e&&(this.text=e),this.#f?this:this.#p?this.isSpinning?this:(this.#o.hideCursor&&Wy.hide(this.#a),this.#o.discardStdin&&GN.stdin.isTTY&&(this.#r=!0,$J.start()),this.render(),this.#c=setInterval(this.render.bind(this),this.interval),this):(this.text&&this.#a.write(`- ${this.text}
894
894
  `),this)}stop(){return this.#p?(clearInterval(this.#c),this.#c=void 0,this.#i=0,this.clear(),this.#o.hideCursor&&Wy.show(this.#a),this.#o.discardStdin&&GN.stdin.isTTY&&this.#r&&($J.stop(),this.#r=!1),this):this}succeed(e){return this.stopAndPersist({symbol:LI.success,text:e})}fail(e){return this.stopAndPersist({symbol:LI.error,text:e})}warn(e){return this.stopAndPersist({symbol:LI.warning,text:e})}info(e){return this.stopAndPersist({symbol:LI.info,text:e})}stopAndPersist(e={}){if(this.#f)return this;let r=e.prefixText??this.#h,n=this.#A(r," "),i=e.symbol??" ",o=e.text??this.text,a=typeof o=="string"?(i?" ":"")+o:"",c=e.suffixText??this.#u,u=this.#g(c," "),d=n+i+a+u+`
895
- `;return this.stop(),this.#a.write(d),this}};function Sf(t){return new qJ(t)}Pm();var Bf=["jaz-api","jaz-cli","jaz-conversion","jaz-recipes","jaz-jobs","jaz-pseudo-sql","clio-kit","all"],pO=Bf.filter(t=>t!=="all"),xf={"jaz-api":"Jaz REST API reference \u2014 rule catalog, endpoint catalog, error catalog, field mapping","jaz-cli":"CLI command reference \u2014 auth, output formats, pagination, entity resolution, workflows","jaz-conversion":"Data conversion pipeline \u2014 Xero, QuickBooks, Sage, Excel migration to Jaz","jaz-recipes":"Complex accounting recipes \u2014 prepaid, deferred revenue, loans, IFRS 16, depreciation","jaz-jobs":"Accounting job blueprints \u2014 month/quarter/year-end close + 9 ad-hoc operational workflows","jaz-pseudo-sql":"Pseudo-SQL data queries \u2014 read-only ad-hoc SELECT against the curated reporting schema, live schema introspection, CSV export","clio-kit":"Multi-organization operator workspace \u2014 per-organization context, resumable period closes, draft review queue, policies and rules"};import{mkdir as XCe,cp as fCt,rm as pCt,access as hCt,readFile as e0e,writeFile as mCt,copyFile as ACt}from"node:fs/promises";import*as gCt from"node:fs";import{join as Fn,dirname as t0e,extname as yCt}from"node:path";import{fileURLToPath as ECt}from"node:url";var aCt="<!-- BEGIN jaz-agent-rules ",cCt=" -->",lCt="<!-- END jaz-agent-rules -->";function uCt(t){return`${aCt}v${t}${cCt}`}function dCt(t,e){return`${uCt(e)}
895
+ `;return this.stop(),this.#a.write(d),this}};function Sf(t){return new qJ(t)}Pm();var Bf=["jaz-api","jaz-cli","jaz-conversion","jaz-recipes","jaz-jobs","jaz-pseudo-sql","jaz-kit","all"],pO=Bf.filter(t=>t!=="all"),xf={"jaz-api":"Jaz REST API reference \u2014 rule catalog, endpoint catalog, error catalog, field mapping","jaz-cli":"CLI command reference \u2014 auth, output formats, pagination, entity resolution, workflows","jaz-conversion":"Data conversion pipeline \u2014 Xero, QuickBooks, Sage, Excel migration to Jaz","jaz-recipes":"Complex accounting recipes \u2014 prepaid, deferred revenue, loans, IFRS 16, depreciation","jaz-jobs":"Accounting job blueprints \u2014 month/quarter/year-end close + 9 ad-hoc operational workflows","jaz-pseudo-sql":"Pseudo-SQL data queries \u2014 read-only ad-hoc SELECT against the curated reporting schema, live schema introspection, CSV export","jaz-kit":"Multi-organization operator workspace \u2014 per-organization context, resumable period closes, draft review queue, policies and rules"};import{mkdir as XCe,cp as fCt,rm as pCt,access as hCt,readFile as e0e,writeFile as mCt,copyFile as ACt}from"node:fs/promises";import*as gCt from"node:fs";import{join as Fn,dirname as t0e,extname as yCt}from"node:path";import{fileURLToPath as ECt}from"node:url";var aCt="<!-- BEGIN jaz-agent-rules ",cCt=" -->",lCt="<!-- END jaz-agent-rules -->";function uCt(t){return`${aCt}v${t}${cCt}`}function dCt(t,e){return`${uCt(e)}
896
896
  ${t.trimEnd()}
897
897
  ${lCt}
898
898
  `}function CV(t){let e=/<!--\s*BEGIN\s+jaz-agent-rules\s+v?([0-9A-Za-z.+-]+?)(?=\s*-->)/,r=/<!--\s*END\s+jaz-agent-rules\s*-->/,n=e.exec(t);if(!n)return{version:null,beginIdx:-1,endIdx:-1,found:!1};let i=n.index,o=r.exec(t.slice(i));if(!o)return{version:n[1],beginIdx:i,endIdx:-1,found:!1};let s=i+o.index+o[0].length,a=t[s]===`
@@ -900,9 +900,9 @@ ${lCt}
900
900
  `)?`
901
901
  `:`
902
902
 
903
- `;return{outcome:"appended",body:t+c+i,installedVersion:null,drifted:!0}}var tE=t0e(ECt(import.meta.url));function bCt(){let t=[Fn(tE,"..","..","assets"),Fn(tE,"assets"),Fn(tE,"..","assets")];for(let e of t)try{return P("node:fs").accessSync(e),e}catch{}return t[0]}var hO=bCt(),CCt=pO,vCt={"jaz-api":"api","jaz-cli":"cli","jaz-conversion":"conversion","jaz-recipes":"transaction-recipes","jaz-jobs":"jobs","jaz-pseudo-sql":"jaz-pseudo-sql","clio-kit":"clio-kit"};async function ms(t){try{return await hCt(t),!0}catch{return!1}}async function mO(t){return await ms(Fn(t,".claude","skills"))?"claude":await ms(Fn(t,".agents","skills"))?"agents":await ms(Fn(t,".claude"))?"claude":await ms(Fn(t,".codex"))||await ms(Fn(t,".antigravity"))||await ms(Fn(t,".cursor"))||await ms(Fn(t,".copilot"))||await ms(Fn(t,".windsurf"))||await ms(Fn(t,".goose"))?"agents":await ms(Fn(t,"CLAUDE.md"))?"claude":(await ms(Fn(t,"AGENTS.md")),"agents")}function ICt(t){return t==="claude"?".claude/skills":".agents/skills"}async function wCt(t,e,r,n){let i=vCt[e],o=Fn(hO,"skills",i),s=ICt(n),a=Fn(t,s,i);if(!await ms(o))throw new Error(`Skill source not found: ${o}`);if(await ms(a)){if(!r)throw new Error(`${a} already exists. Use --force to overwrite.`);await pCt(a,{recursive:!0,force:!0})}return await XCe(a,{recursive:!0}),await fCt(o,a,{recursive:!0,force:!0}),`${s}/${i}`}var _Ct={claude:"CLAUDE.md",agents:"AGENTS.md",codex:"AGENTS.md",antigravity:"AGENTS.md",goose:"AGENTS.md",copilot:".github/copilot-instructions.md",cursor:".cursor/rules/jaz.mdc",windsurf:".windsurf/rules/jaz.md",gemini:"GEMINI.md"};async function DCt(t,e){return e==="auto"?await mO(t):e}function SCt(){return["---","description: Jaz accounting platform \u2014 agent operating rules","alwaysApply: true","---",""].join(`
903
+ `;return{outcome:"appended",body:t+c+i,installedVersion:null,drifted:!0}}var tE=t0e(ECt(import.meta.url));function bCt(){let t=[Fn(tE,"..","..","assets"),Fn(tE,"assets"),Fn(tE,"..","assets")];for(let e of t)try{return P("node:fs").accessSync(e),e}catch{}return t[0]}var hO=bCt(),CCt=pO,vCt={"jaz-api":"api","jaz-cli":"cli","jaz-conversion":"conversion","jaz-recipes":"transaction-recipes","jaz-jobs":"jobs","jaz-pseudo-sql":"jaz-pseudo-sql","jaz-kit":"jaz-kit"};async function ms(t){try{return await hCt(t),!0}catch{return!1}}async function mO(t){return await ms(Fn(t,".claude","skills"))?"claude":await ms(Fn(t,".agents","skills"))?"agents":await ms(Fn(t,".claude"))?"claude":await ms(Fn(t,".codex"))||await ms(Fn(t,".antigravity"))||await ms(Fn(t,".cursor"))||await ms(Fn(t,".copilot"))||await ms(Fn(t,".windsurf"))||await ms(Fn(t,".goose"))?"agents":await ms(Fn(t,"CLAUDE.md"))?"claude":(await ms(Fn(t,"AGENTS.md")),"agents")}function ICt(t){return t==="claude"?".claude/skills":".agents/skills"}async function wCt(t,e,r,n){let i=vCt[e],o=Fn(hO,"skills",i),s=ICt(n),a=Fn(t,s,i);if(!await ms(o))throw new Error(`Skill source not found: ${o}`);if(await ms(a)){if(!r)throw new Error(`${a} already exists. Use --force to overwrite.`);await pCt(a,{recursive:!0,force:!0})}return await XCe(a,{recursive:!0}),await fCt(o,a,{recursive:!0,force:!0}),`${s}/${i}`}var _Ct={claude:"CLAUDE.md",agents:"AGENTS.md",codex:"AGENTS.md",antigravity:"AGENTS.md",goose:"AGENTS.md",copilot:".github/copilot-instructions.md",cursor:".cursor/rules/jaz.mdc",windsurf:".windsurf/rules/jaz.md",gemini:"GEMINI.md"};async function DCt(t,e){return e==="auto"?await mO(t):e}function SCt(){return["---","description: Jaz accounting platform \u2014 agent operating rules","alwaysApply: true","---",""].join(`
904
904
  `)}function RCt(t){if(t==null)return null;if(!t.startsWith(`---
905
- `))return t;let e=/\n---\n/.exec(t);return e?t.slice(e.index+e[0].length):t}async function BCt(t){return await e0e(t,"utf8")}async function IV(t,e,r=!1,n={}){let i=await DCt(t,e),o=_Ct[i],s=Fn(t,o),a=Fn(hO,"templates","platform-rules","jaz-agent-rules.md");if(!await ms(a))throw new Error(`Platform rules template not found: ${a}`);let c=n.version??wV(),u=n.mode??(r?"overwrite":"merge"),d=await ms(s),f=d?await e0e(s,"utf8"):null;if(u==="check"){let E=f?CV(f).version:null;return{path:o,status:d?"unchanged":"installed",installedVersion:E}}let p=await BCt(a),h=yCt(o)===".mdc",m;u==="overwrite"&&d&&(m=`${o}.bak.${Math.floor(Date.now()/1e3)}`,await ACt(s,Fn(t,m)));let A=h?RCt(f):f,g=KCe(A,p,c,u),y=h?SCt()+g.body:g.body;g.outcome!=="unchanged"&&(await XCe(t0e(s),{recursive:!0}),await mCt(s,y,"utf8"));let C=g.outcome==="created"?"installed":g.outcome;return{path:o,status:C,installedVersion:g.installedVersion,backupPath:m}}var vV=null;function wV(){if(vV)return vV;let t=gCt,e=[Fn(tE,"..","package.json"),Fn(tE,"package.json"),Fn(tE,"..","..","package.json"),Fn(hO,"..","package.json"),Fn(hO,"..","..","package.json")];for(let r of e)try{let n=JSON.parse(t.readFileSync(r,"utf8"));if(n.version&&n.name==="jaz-clio")return vV=n.version,n.version}catch{}throw new Error("jaz-clio: unable to resolve package version from any candidate path. This likely means the install is corrupted \u2014 try `npm install -g jaz-clio` to repair.")}async function AO(t,e,r=!1,n="auto"){let i=n==="claude"?"claude":n==="auto"?await mO(t):"agents",o=e==="all"?CCt:[e],s=[];for(let a of o){let c=await wCt(t,a,r,i);s.push(c)}return s}Fe();var gs={title(t){console.log(),console.log(`${Rt}${Be(t)}`),console.log(`${Rt}${z(vn.horizontal.repeat(t.length))}`),console.log()},info(t){console.log(`${Rt}${tc(As.info)} ${t}`)},success(t){console.log(`${Rt}${Y(As.tick)} ${t}`)},warn(t){console.log(`${Rt}${ke(As.warning)} ${t}`)},error(t){console.log(`${Rt}${ie(As.cross)} ${t}`)},step(t,e){console.log(`${Rt}${z(`${t}.`)} ${e}`)},divider(){let t=process.stdout.columns?Math.min(process.stdout.columns-4,60):40;console.log(`${Rt}${z(vn.horizontal.repeat(t))}`)},blank(){console.log()}};Fe();var s0e=pO;async function a0e(t){if(t.check)return FCt(t);gs.title("Clio \u2014 Skill Installer");let e=t.skill??"all";if(!t.skill){let s=await HI({message:"Which skills do you want to install?",options:[{label:"All (Recommended)",hint:s0e.join(" + "),value:"all"},{label:"API only",hint:xf["jaz-api"],value:"jaz-api"},{label:"CLI only",hint:xf["jaz-cli"],value:"jaz-cli"},{label:"Conversion only",hint:xf["jaz-conversion"],value:"jaz-conversion"},{label:"Transaction Recipes only",hint:xf["jaz-recipes"],value:"jaz-recipes"},{label:"Jobs only",hint:xf["jaz-jobs"],value:"jaz-jobs"},{label:"Pseudo-SQL only",hint:xf["jaz-pseudo-sql"],value:"jaz-pseudo-sql"},{label:"Clio Kit only",hint:xf["clio-kit"],value:"clio-kit"}],initialValue:"all"});if(Xa(s)){gs.warn("Installation cancelled");return}e=s}let r=e==="all"?s0e.join(" + "):e;gs.info(`Installing: ${Be(r)}`);let n=Sf("Installing skill files...").start(),i=process.cwd(),o=t.platform??"auto";try{if(o==="auto"){let c=await mO(i);n.text=`Detected platform: ${c==="claude"?"Claude Code":"Agent Skills (universal)"}`}n.text="Copying skill files...";let s=await AO(i,e,t.force??!1,o),a=null;if(t.noRules||(n.text="Installing platform agent-rules...",a=await IV(i,o,t.force??!1)),n.succeed("Skills installed!"),console.log(),gs.info("Installed:"),s.forEach(c=>{console.log(` ${Y("+")} ${c}/`)}),a){let c=a.path;switch(a.status){case"installed":console.log(` ${Y("+")} ${c} ${z("(agent-rules \u2014 created)")}`);break;case"updated":console.log(` ${Y("+")} ${c} ${z(`(agent-rules \u2014 updated v${a.installedVersion} \u2192 current; user content preserved)`)}`);break;case"appended":console.log(` ${Y("+")} ${c} ${z("(agent-rules \u2014 appended marker block; user content preserved)")}`);break;case"unchanged":console.log(` ${z(`(unchanged) ${c} \u2014 agent-rules already at current version`)}`);break;case"overwritten":console.log(` ${Y("+")} ${c} ${z("(agent-rules, OVERWRITTEN \u2014 --force used)")}`),a.backupPath&&console.log(` ${z(` prior contents backed up \u2192 ${a.backupPath}`)}`);break}}console.log(),gs.success("Clio \u2014 Jaz AI skills installed successfully!"),console.log(),console.log(R("Next steps:")),console.log(z(" 1. Restart your AI tool (Claude Code, Antigravity, Codex, Copilot, Cursor, etc.)")),console.log(z(' 2. Try: "Create an invoice with line items and tax"')),(e==="all"||e==="jaz-conversion")&&console.log(z(' 3. Try: "Convert this Xero trial balance to Jaz"')),console.log(),console.log(z(` Docs: ${_V("https://help.jaz.ai")}`)),console.log()}catch(s){n.fail("Installation failed"),s instanceof Error&&gs.error(s.message),process.exit(1)}}async function FCt(t){let e=process.cwd(),r=t.platform??"auto",n=await IV(e,r,!1,{mode:"check"});if(console.log(),gs.title("Clio \u2014 Agent-rules drift check"),console.log(),console.log(` Platform target: ${Be(n.path)}`),n.installedVersion===null){n.status==="installed"&&(console.log(` Status: ${z("not installed")} \u2014 run ${R("clio init")} to add agent-rules.`),process.exit(1));let{readFileSync:o}=await import("node:fs"),s=`${process.cwd()}/${n.path}`,a="";try{a=o(s,"utf8")}catch{}a.includes("<!-- BEGIN jaz-agent-rules")&&(console.log(` Status: ${z("corrupted marker \u2014 BEGIN found but version unparseable or END missing")} \u2014 fix manually (repair marker version or add missing END), then re-run.`),process.exit(1)),console.log(` Status: ${z("legacy (no marker block)")} \u2014 run ${R("clio init")} to migrate to marker-aware merge. Existing user content will be preserved.`),process.exit(1)}let i=wV();n.installedVersion===i?(console.log(` Status: ${Y("current")} (v${n.installedVersion})`),console.log(),process.exit(0)):(console.log(` Status: ${z(`drift \u2014 installed v${n.installedVersion}, current v${i}`)}`),console.log(` Run ${R("clio init")} to update. User content above + below the marker block is preserved.`),console.log(),process.exit(1))}Fe();var QCt="teamjaz",LCt="jaz-ai",MCt="https://api.github.com",PCt=15e3,rE=class extends Error{constructor(e){super(e),this.name="GitHubRateLimitError"}},RV=class extends Error{constructor(e){super(e),this.name="GitHubDownloadError"}};function UCt(t){let e=t.headers.get("x-ratelimit-remaining");if(t.status===403&&e==="0"){let r=t.headers.get("x-ratelimit-reset"),n=r?new Date(parseInt(r)*1e3).toLocaleTimeString():"unknown";throw new rE(`GitHub API rate limit exceeded. Resets at ${n}`)}if(t.status===429)throw new rE("GitHub API rate limit exceeded (429 Too Many Requests)")}async function c0e(){let t=`${MCt}/repos/${QCt}/${LCt}/releases`,e=await fetch(t,{headers:{Accept:"application/vnd.github.v3+json","User-Agent":"jaz-clio"},signal:AbortSignal.timeout(PCt)});if(UCt(e),!e.ok)throw new RV(`Failed to fetch releases: ${e.status} ${e.statusText}`);return e.json()}async function l0e(){gs.title("Clio \u2014 Available Versions");let t=Sf("Fetching versions from GitHub...").start();try{let e=await c0e();if(e.length===0){t.warn("No releases found");return}t.succeed(`Found ${e.length} version(s)`),console.log(),e.forEach((r,n)=>{let i=r.tag_name,o=new Date(r.published_at).toLocaleDateString(),s=n===0?Y(" (latest)"):"";console.log(` ${Be(i)}${s} ${z(o)}`)}),console.log()}catch(e){e instanceof rE?(t.fail("GitHub rate limit reached. Try again later."),process.exit(1)):e instanceof Error&&e.message.includes("404")?t.info("No releases published yet."):e instanceof Error?(t.fail(`Failed to fetch versions: ${e.message}`),process.exit(1)):(t.fail("Failed to fetch versions."),process.exit(1))}}Fe();import{execFileSync as u0e}from"node:child_process";function d0e(t,e={}){try{return u0e("npm",t,{encoding:"utf-8",...e})}catch{let r=process.env.npm_execpath||"npm";return u0e(process.execPath,[r,...t],{encoding:"utf-8",...e})}}async function f0e(t){let{readFileSync:e}=await import("node:fs"),{join:r,dirname:n}=await import("node:path"),{fileURLToPath:i}=await import("node:url"),o=r(n(i(import.meta.url)),"..","..","package.json"),s;try{s=JSON.parse(e(o,"utf-8")).version}catch{s="unknown"}gs.title(`Clio v${s} \u2014 Update`);let a=Sf("Checking for CLI updates...").start();try{let d=d0e(["view","jaz-clio","version"]).trim();s===d?a.succeed(`CLI is up to date (v${s})`):(a.text=`Updating CLI v${s} \u2192 v${d}...`,d0e(["install","-g","jaz-clio@latest"],{stdio:"pipe"}),a.succeed(`CLI updated to v${d}`))}catch{a.warn("CLI self-update skipped (run manually: npm update -g jaz-clio)")}let c=t.skill??"all",u=Sf("Updating skill files...").start();try{let d=await AO(process.cwd(),c,!0);u.succeed("Skills updated!"),console.log(),gs.info("Updated:"),d.forEach(f=>{console.log(` ${Y("+")} ${f}/`)}),console.log(),gs.success("All up to date. Run: clio --help"),console.log()}catch(d){u.fail("Skill update failed"),d instanceof Error&&gs.error(d.message),process.exit(1)}}Fe();bO();ZI();nc();qm();import{execFileSync as w0e}from"node:child_process";import{readdirSync as i0t,readFileSync as _0e,existsSync as o0t}from"node:fs";import{dirname as D0e,join as ad}from"node:path";import{fileURLToPath as S0e}from"node:url";function R0e(){let t=S0e(import.meta.url),e=D0e(t),r=[ad(e,"..","..","package.json"),ad(e,"package.json")];for(let n of r)try{return{version:JSON.parse(_0e(n,"utf-8")).version,pkgPath:n}}catch{}return{version:"unknown",pkgPath:""}}function s0t(){try{return w0e("npm",["view","jaz-clio","version"],{encoding:"utf-8",timeout:1e4}).trim()}catch{try{let t=process.env.npm_execpath||"npm";return w0e(process.execPath,[t,"view","jaz-clio","version"],{encoding:"utf-8",timeout:1e4}).trim()}catch{return"unknown"}}}function a0t(t){try{return i0t(t,{withFileTypes:!0}).filter(e=>e.isDirectory()).length}catch{return 0}}function c0t(){let t=S0e(import.meta.url),e=D0e(t),r=[ad(e,"..","..","help-center-mirror"),ad(e,"..","..","assets","skills","api","help-center-mirror"),ad(e,"help-center-mirror")];for(let n of r)if(o0t(ad(n,"help-center-index.json")))return n;return null}function l0t(t){try{let e=JSON.parse(_0e(ad(t,"help-center-index.json"),"utf-8"));return Array.isArray(e)?e.length:e.articles&&Array.isArray(e.articles)?e.articles.length:Object.keys(e).length}catch{return 0}}async function u0t(){let t=[],{version:e}=R0e(),r=s0t(),n=r==="unknown"?"(npm check unavailable)":e===r?"(latest)":`(latest: ${r})`;t.push({name:"CLI version",status:r!=="unknown"&&e!==r?"warn":"ok",value:e,detail:n}),t.push({name:"Node.js",status:"ok",value:process.version});let i=!1,o=null;try{let f=EO();if(f){i=!0,o=new Yo(f,"cli");let p=Us(),h=p?rc(p):null,m=h?`${p} (${h.orgName}, ${h.currency})`:p??"api-key";t.push({name:"Auth",status:"ok",value:m})}else t.push({name:"Auth",status:"warn",value:"not configured",detail:"run `clio auth add <key>`"})}catch{t.push({name:"Auth",status:"warn",value:"not configured",detail:"run `clio auth add <key>`"})}if(i&&o){let f=Date.now();try{await Aa(o);let p=Date.now()-f;t.push({name:"API connection",status:"ok",value:`200 OK (${p}ms)`})}catch(p){let h=Date.now()-f,m=p instanceof Error?p.message:String(p);t.push({name:"API connection",status:"fail",value:`failed (${h}ms)`,detail:m})}}else t.push({name:"API connection",status:"warn",value:"skipped (no auth)"});let s=process.cwd(),a=[{path:ad(s,".claude","skills"),label:".claude/skills/"},{path:ad(s,".agents","skills"),label:".agents/skills/"}],c=0,u="";for(let{path:f,label:p}of a){let h=a0t(f);if(h>0){c=h,u=p;break}}t.push({name:"Skills",status:c>0?"ok":"warn",value:c>0?`${c} installed (${u})`:"none found",detail:c===0?"run `clio init` to install":void 0});let d=c0t();if(d){let f=l0t(d);t.push({name:"Help center",status:f>0?"ok":"warn",value:f>0?`${f} articles loaded`:"index empty"})}else t.push({name:"Help center",status:"ok",value:"served live (hosted)",detail:"no local corpus bundled; queried from the hosted route"});return{checks:t,ok:t.every(f=>f.status!=="fail")}}async function B0e(t){let e=await u0t(),{version:r}=R0e();if(t.json){console.log(JSON.stringify({version:r,...e},null,2)),e.ok||(process.exitCode=1);return}console.log(),console.log(`${Rt}${Be(`Clio v${r} \u2014 Health Check`)}`),console.log(`${Rt}${z("\u2500".repeat(30))}`),console.log();let n=Math.max(...e.checks.map(i=>i.name.length));for(let i of e.checks){let o=i.status==="ok"?Y("\u2713"):i.status==="warn"?z("\u2013"):ie("\u2717"),s=i.name.padEnd(n),a=i.detail?z(` ${i.detail}`):"";console.log(`${Rt}${o} ${z(s)} ${i.value}${a}`)}e.ok||(process.exitCode=1),console.log()}Fe();qV();jV();YV();HV();zV();GV();JV();VV();WV();ZV();KV();XV();Fe();var ut=t=>t.toLocaleString("en-US",{minimumFractionDigits:2,maximumFractionDigits:2}),Gt=t=>ut(t).padStart(14),LO=t=>`${t}%`,cd=t=>t?` (${t})`:"",Bt=t=>z("\u2500".repeat(t));function ld(t){let e=t.blueprint;if(e?.capsuleDescription){console.log(R("Workings (capsule description)")),console.log(Bt(60));for(let r of e.capsuleDescription.split(`
905
+ `))return t;let e=/\n---\n/.exec(t);return e?t.slice(e.index+e[0].length):t}async function BCt(t){return await e0e(t,"utf8")}async function IV(t,e,r=!1,n={}){let i=await DCt(t,e),o=_Ct[i],s=Fn(t,o),a=Fn(hO,"templates","platform-rules","jaz-agent-rules.md");if(!await ms(a))throw new Error(`Platform rules template not found: ${a}`);let c=n.version??wV(),u=n.mode??(r?"overwrite":"merge"),d=await ms(s),f=d?await e0e(s,"utf8"):null;if(u==="check"){let E=f?CV(f).version:null;return{path:o,status:d?"unchanged":"installed",installedVersion:E}}let p=await BCt(a),h=yCt(o)===".mdc",m;u==="overwrite"&&d&&(m=`${o}.bak.${Math.floor(Date.now()/1e3)}`,await ACt(s,Fn(t,m)));let A=h?RCt(f):f,g=KCe(A,p,c,u),y=h?SCt()+g.body:g.body;g.outcome!=="unchanged"&&(await XCe(t0e(s),{recursive:!0}),await mCt(s,y,"utf8"));let C=g.outcome==="created"?"installed":g.outcome;return{path:o,status:C,installedVersion:g.installedVersion,backupPath:m}}var vV=null;function wV(){if(vV)return vV;let t=gCt,e=[Fn(tE,"..","package.json"),Fn(tE,"package.json"),Fn(tE,"..","..","package.json"),Fn(hO,"..","package.json"),Fn(hO,"..","..","package.json")];for(let r of e)try{let n=JSON.parse(t.readFileSync(r,"utf8"));if(n.version&&n.name==="jaz-clio")return vV=n.version,n.version}catch{}throw new Error("jaz-clio: unable to resolve package version from any candidate path. This likely means the install is corrupted \u2014 try `npm install -g jaz-clio` to repair.")}async function AO(t,e,r=!1,n="auto"){let i=n==="claude"?"claude":n==="auto"?await mO(t):"agents",o=e==="all"?CCt:[e],s=[];for(let a of o){let c=await wCt(t,a,r,i);s.push(c)}return s}Fe();var gs={title(t){console.log(),console.log(`${Rt}${Be(t)}`),console.log(`${Rt}${z(vn.horizontal.repeat(t.length))}`),console.log()},info(t){console.log(`${Rt}${tc(As.info)} ${t}`)},success(t){console.log(`${Rt}${Y(As.tick)} ${t}`)},warn(t){console.log(`${Rt}${ke(As.warning)} ${t}`)},error(t){console.log(`${Rt}${ie(As.cross)} ${t}`)},step(t,e){console.log(`${Rt}${z(`${t}.`)} ${e}`)},divider(){let t=process.stdout.columns?Math.min(process.stdout.columns-4,60):40;console.log(`${Rt}${z(vn.horizontal.repeat(t))}`)},blank(){console.log()}};Fe();var s0e=pO;async function a0e(t){if(t.check)return FCt(t);gs.title("Clio \u2014 Skill Installer");let e=t.skill??"all";if(!t.skill){let s=await HI({message:"Which skills do you want to install?",options:[{label:"All (Recommended)",hint:s0e.join(" + "),value:"all"},{label:"API only",hint:xf["jaz-api"],value:"jaz-api"},{label:"CLI only",hint:xf["jaz-cli"],value:"jaz-cli"},{label:"Conversion only",hint:xf["jaz-conversion"],value:"jaz-conversion"},{label:"Transaction Recipes only",hint:xf["jaz-recipes"],value:"jaz-recipes"},{label:"Jobs only",hint:xf["jaz-jobs"],value:"jaz-jobs"},{label:"Pseudo-SQL only",hint:xf["jaz-pseudo-sql"],value:"jaz-pseudo-sql"},{label:"Jaz Kit only",hint:xf["jaz-kit"],value:"jaz-kit"}],initialValue:"all"});if(Xa(s)){gs.warn("Installation cancelled");return}e=s}let r=e==="all"?s0e.join(" + "):e;gs.info(`Installing: ${Be(r)}`);let n=Sf("Installing skill files...").start(),i=process.cwd(),o=t.platform??"auto";try{if(o==="auto"){let c=await mO(i);n.text=`Detected platform: ${c==="claude"?"Claude Code":"Agent Skills (universal)"}`}n.text="Copying skill files...";let s=await AO(i,e,t.force??!1,o),a=null;if(t.noRules||(n.text="Installing platform agent-rules...",a=await IV(i,o,t.force??!1)),n.succeed("Skills installed!"),console.log(),gs.info("Installed:"),s.forEach(c=>{console.log(` ${Y("+")} ${c}/`)}),a){let c=a.path;switch(a.status){case"installed":console.log(` ${Y("+")} ${c} ${z("(agent-rules \u2014 created)")}`);break;case"updated":console.log(` ${Y("+")} ${c} ${z(`(agent-rules \u2014 updated v${a.installedVersion} \u2192 current; user content preserved)`)}`);break;case"appended":console.log(` ${Y("+")} ${c} ${z("(agent-rules \u2014 appended marker block; user content preserved)")}`);break;case"unchanged":console.log(` ${z(`(unchanged) ${c} \u2014 agent-rules already at current version`)}`);break;case"overwritten":console.log(` ${Y("+")} ${c} ${z("(agent-rules, OVERWRITTEN \u2014 --force used)")}`),a.backupPath&&console.log(` ${z(` prior contents backed up \u2192 ${a.backupPath}`)}`);break}}console.log(),gs.success("Clio \u2014 Jaz AI skills installed successfully!"),console.log(),console.log(R("Next steps:")),console.log(z(" 1. Restart your AI tool (Claude Code, Antigravity, Codex, Copilot, Cursor, etc.)")),console.log(z(' 2. Try: "Create an invoice with line items and tax"')),(e==="all"||e==="jaz-conversion")&&console.log(z(' 3. Try: "Convert this Xero trial balance to Jaz"')),console.log(),console.log(z(` Docs: ${_V("https://help.jaz.ai")}`)),console.log()}catch(s){n.fail("Installation failed"),s instanceof Error&&gs.error(s.message),process.exit(1)}}async function FCt(t){let e=process.cwd(),r=t.platform??"auto",n=await IV(e,r,!1,{mode:"check"});if(console.log(),gs.title("Clio \u2014 Agent-rules drift check"),console.log(),console.log(` Platform target: ${Be(n.path)}`),n.installedVersion===null){n.status==="installed"&&(console.log(` Status: ${z("not installed")} \u2014 run ${R("clio init")} to add agent-rules.`),process.exit(1));let{readFileSync:o}=await import("node:fs"),s=`${process.cwd()}/${n.path}`,a="";try{a=o(s,"utf8")}catch{}a.includes("<!-- BEGIN jaz-agent-rules")&&(console.log(` Status: ${z("corrupted marker \u2014 BEGIN found but version unparseable or END missing")} \u2014 fix manually (repair marker version or add missing END), then re-run.`),process.exit(1)),console.log(` Status: ${z("legacy (no marker block)")} \u2014 run ${R("clio init")} to migrate to marker-aware merge. Existing user content will be preserved.`),process.exit(1)}let i=wV();n.installedVersion===i?(console.log(` Status: ${Y("current")} (v${n.installedVersion})`),console.log(),process.exit(0)):(console.log(` Status: ${z(`drift \u2014 installed v${n.installedVersion}, current v${i}`)}`),console.log(` Run ${R("clio init")} to update. User content above + below the marker block is preserved.`),console.log(),process.exit(1))}Fe();var QCt="teamjaz",LCt="jaz-ai",MCt="https://api.github.com",PCt=15e3,rE=class extends Error{constructor(e){super(e),this.name="GitHubRateLimitError"}},RV=class extends Error{constructor(e){super(e),this.name="GitHubDownloadError"}};function UCt(t){let e=t.headers.get("x-ratelimit-remaining");if(t.status===403&&e==="0"){let r=t.headers.get("x-ratelimit-reset"),n=r?new Date(parseInt(r)*1e3).toLocaleTimeString():"unknown";throw new rE(`GitHub API rate limit exceeded. Resets at ${n}`)}if(t.status===429)throw new rE("GitHub API rate limit exceeded (429 Too Many Requests)")}async function c0e(){let t=`${MCt}/repos/${QCt}/${LCt}/releases`,e=await fetch(t,{headers:{Accept:"application/vnd.github.v3+json","User-Agent":"jaz-clio"},signal:AbortSignal.timeout(PCt)});if(UCt(e),!e.ok)throw new RV(`Failed to fetch releases: ${e.status} ${e.statusText}`);return e.json()}async function l0e(){gs.title("Clio \u2014 Available Versions");let t=Sf("Fetching versions from GitHub...").start();try{let e=await c0e();if(e.length===0){t.warn("No releases found");return}t.succeed(`Found ${e.length} version(s)`),console.log(),e.forEach((r,n)=>{let i=r.tag_name,o=new Date(r.published_at).toLocaleDateString(),s=n===0?Y(" (latest)"):"";console.log(` ${Be(i)}${s} ${z(o)}`)}),console.log()}catch(e){e instanceof rE?(t.fail("GitHub rate limit reached. Try again later."),process.exit(1)):e instanceof Error&&e.message.includes("404")?t.info("No releases published yet."):e instanceof Error?(t.fail(`Failed to fetch versions: ${e.message}`),process.exit(1)):(t.fail("Failed to fetch versions."),process.exit(1))}}Fe();import{execFileSync as u0e}from"node:child_process";function d0e(t,e={}){try{return u0e("npm",t,{encoding:"utf-8",...e})}catch{let r=process.env.npm_execpath||"npm";return u0e(process.execPath,[r,...t],{encoding:"utf-8",...e})}}async function f0e(t){let{readFileSync:e}=await import("node:fs"),{join:r,dirname:n}=await import("node:path"),{fileURLToPath:i}=await import("node:url"),o=r(n(i(import.meta.url)),"..","..","package.json"),s;try{s=JSON.parse(e(o,"utf-8")).version}catch{s="unknown"}gs.title(`Clio v${s} \u2014 Update`);let a=Sf("Checking for CLI updates...").start();try{let d=d0e(["view","jaz-clio","version"]).trim();s===d?a.succeed(`CLI is up to date (v${s})`):(a.text=`Updating CLI v${s} \u2192 v${d}...`,d0e(["install","-g","jaz-clio@latest"],{stdio:"pipe"}),a.succeed(`CLI updated to v${d}`))}catch{a.warn("CLI self-update skipped (run manually: npm update -g jaz-clio)")}let c=t.skill??"all",u=Sf("Updating skill files...").start();try{let d=await AO(process.cwd(),c,!0);u.succeed("Skills updated!"),console.log(),gs.info("Updated:"),d.forEach(f=>{console.log(` ${Y("+")} ${f}/`)}),console.log(),gs.success("All up to date. Run: clio --help"),console.log()}catch(d){u.fail("Skill update failed"),d instanceof Error&&gs.error(d.message),process.exit(1)}}Fe();bO();ZI();nc();qm();import{execFileSync as w0e}from"node:child_process";import{readdirSync as i0t,readFileSync as _0e,existsSync as o0t}from"node:fs";import{dirname as D0e,join as ad}from"node:path";import{fileURLToPath as S0e}from"node:url";function R0e(){let t=S0e(import.meta.url),e=D0e(t),r=[ad(e,"..","..","package.json"),ad(e,"package.json")];for(let n of r)try{return{version:JSON.parse(_0e(n,"utf-8")).version,pkgPath:n}}catch{}return{version:"unknown",pkgPath:""}}function s0t(){try{return w0e("npm",["view","jaz-clio","version"],{encoding:"utf-8",timeout:1e4}).trim()}catch{try{let t=process.env.npm_execpath||"npm";return w0e(process.execPath,[t,"view","jaz-clio","version"],{encoding:"utf-8",timeout:1e4}).trim()}catch{return"unknown"}}}function a0t(t){try{return i0t(t,{withFileTypes:!0}).filter(e=>e.isDirectory()).length}catch{return 0}}function c0t(){let t=S0e(import.meta.url),e=D0e(t),r=[ad(e,"..","..","help-center-mirror"),ad(e,"..","..","assets","skills","api","help-center-mirror"),ad(e,"help-center-mirror")];for(let n of r)if(o0t(ad(n,"help-center-index.json")))return n;return null}function l0t(t){try{let e=JSON.parse(_0e(ad(t,"help-center-index.json"),"utf-8"));return Array.isArray(e)?e.length:e.articles&&Array.isArray(e.articles)?e.articles.length:Object.keys(e).length}catch{return 0}}async function u0t(){let t=[],{version:e}=R0e(),r=s0t(),n=r==="unknown"?"(npm check unavailable)":e===r?"(latest)":`(latest: ${r})`;t.push({name:"CLI version",status:r!=="unknown"&&e!==r?"warn":"ok",value:e,detail:n}),t.push({name:"Node.js",status:"ok",value:process.version});let i=!1,o=null;try{let f=EO();if(f){i=!0,o=new Yo(f,"cli");let p=Us(),h=p?rc(p):null,m=h?`${p} (${h.orgName}, ${h.currency})`:p??"api-key";t.push({name:"Auth",status:"ok",value:m})}else t.push({name:"Auth",status:"warn",value:"not configured",detail:"run `clio auth add <key>`"})}catch{t.push({name:"Auth",status:"warn",value:"not configured",detail:"run `clio auth add <key>`"})}if(i&&o){let f=Date.now();try{await Aa(o);let p=Date.now()-f;t.push({name:"API connection",status:"ok",value:`200 OK (${p}ms)`})}catch(p){let h=Date.now()-f,m=p instanceof Error?p.message:String(p);t.push({name:"API connection",status:"fail",value:`failed (${h}ms)`,detail:m})}}else t.push({name:"API connection",status:"warn",value:"skipped (no auth)"});let s=process.cwd(),a=[{path:ad(s,".claude","skills"),label:".claude/skills/"},{path:ad(s,".agents","skills"),label:".agents/skills/"}],c=0,u="";for(let{path:f,label:p}of a){let h=a0t(f);if(h>0){c=h,u=p;break}}t.push({name:"Skills",status:c>0?"ok":"warn",value:c>0?`${c} installed (${u})`:"none found",detail:c===0?"run `clio init` to install":void 0});let d=c0t();if(d){let f=l0t(d);t.push({name:"Help center",status:f>0?"ok":"warn",value:f>0?`${f} articles loaded`:"index empty"})}else t.push({name:"Help center",status:"ok",value:"served live (hosted)",detail:"no local corpus bundled; queried from the hosted route"});return{checks:t,ok:t.every(f=>f.status!=="fail")}}async function B0e(t){let e=await u0t(),{version:r}=R0e();if(t.json){console.log(JSON.stringify({version:r,...e},null,2)),e.ok||(process.exitCode=1);return}console.log(),console.log(`${Rt}${Be(`Clio v${r} \u2014 Health Check`)}`),console.log(`${Rt}${z("\u2500".repeat(30))}`),console.log();let n=Math.max(...e.checks.map(i=>i.name.length));for(let i of e.checks){let o=i.status==="ok"?Y("\u2713"):i.status==="warn"?z("\u2013"):ie("\u2717"),s=i.name.padEnd(n),a=i.detail?z(` ${i.detail}`):"";console.log(`${Rt}${o} ${z(s)} ${i.value}${a}`)}e.ok||(process.exitCode=1),console.log()}Fe();qV();jV();YV();HV();zV();GV();JV();VV();WV();ZV();KV();XV();Fe();var ut=t=>t.toLocaleString("en-US",{minimumFractionDigits:2,maximumFractionDigits:2}),Gt=t=>ut(t).padStart(14),LO=t=>`${t}%`,cd=t=>t?` (${t})`:"",Bt=t=>z("\u2500".repeat(t));function ld(t){let e=t.blueprint;if(e?.capsuleDescription){console.log(R("Workings (capsule description)")),console.log(Bt(60));for(let r of e.capsuleDescription.split(`
906
906
  `))console.log(z(` ${r}`));console.log()}}function ya(t){console.log(z(` ${t.description}`));for(let e of t.lines)e.debit>0&&console.log(z(` Dr ${e.account.padEnd(35)} ${ut(e.debit)}`)),e.credit>0&&console.log(z(` Cr ${e.account.padEnd(35)} ${ut(e.credit)}`))}function x0t(t){console.log(),console.log(R(`Loan Amortization Schedule${cd(t.currency)}`)),console.log(Bt(90)),console.log(R(` Principal: ${ut(t.inputs.principal)}`)),console.log(R(` Annual Rate: ${LO(t.inputs.annualRate)}`)),console.log(R(` Term: ${t.inputs.termMonths} months`)),console.log(R(` Monthly PMT: ${ut(t.monthlyPayment)}`)),console.log(Bt(90));let r=["Period".padStart(6),t.inputs.startDate?"Date".padStart(12):null,"Opening".padStart(14),"Payment".padStart(14),"Interest".padStart(14),"Principal".padStart(14),"Closing".padStart(14)].filter(Boolean).join(" ");console.log(z(r)),console.log(Bt(90));for(let i of t.schedule){let o=[String(i.period).padStart(6),i.date?i.date.padStart(12):null,Gt(i.openingBalance),Gt(i.payment),Gt(i.interest),Gt(i.principal),Gt(i.closingBalance)].filter(Boolean).join(" ");console.log(o)}console.log(Bt(90));let n=["TOTAL".padStart(6),t.inputs.startDate?"".padStart(12):null,"".padStart(14),Gt(t.totalPayments),Gt(t.totalInterest),Gt(t.totalPrincipal),Gt(0)].filter(Boolean).join(" ");console.log(R(n)),console.log(),console.log(R("Journal Entries")),console.log(Bt(60)),console.log(z(" Disbursement:")),console.log(z(` Dr Cash / Bank Account${" ".repeat(14)}${ut(t.inputs.principal)}`)),console.log(z(` Cr Loan Payable${" ".repeat(21)} ${ut(t.inputs.principal)}`)),console.log(),console.log(z(" Per period (example \u2014 Month 1):")),ya(t.schedule[0].journal),console.log(),ld(t)}function T0t(t){let r=t.isHirePurchase,n=r?"Hire Purchase Schedule (IFRS 16)":"IFRS 16 Lease Schedule";console.log(),console.log(R(`${n}${cd(t.currency)}`)),console.log(Bt(90)),console.log(R(` Monthly Payment: ${ut(t.inputs.monthlyPayment)}`)),console.log(R(` Lease Term: ${t.inputs.termMonths} months`)),r&&console.log(R(` Useful Life: ${t.depreciationMonths} months`)),console.log(R(` Discount Rate (IBR): ${LO(t.inputs.annualRate)}`)),console.log(R(` Present Value: ${ut(t.presentValue)}`)),console.log(R(` Monthly ROU Dep: ${ut(t.monthlyRouDepreciation)}${r?` (over ${t.depreciationMonths} months, not ${t.inputs.termMonths})`:""}`)),console.log(Bt(90)),console.log(R(`
907
907
  Initial Recognition`)),ya(t.initialJournal),console.log(R(`
908
908
  Liability Unwinding Schedule`));let i=["Period".padStart(6),t.inputs.startDate?"Date".padStart(12):null,"Opening".padStart(14),"Payment".padStart(14),"Interest".padStart(14),"Principal".padStart(14),"Closing".padStart(14)].filter(Boolean).join(" ");console.log(z(i)),console.log(Bt(90));for(let s of t.schedule){let a=[String(s.period).padStart(6),s.date?s.date.padStart(12):null,Gt(s.openingBalance),Gt(s.payment),Gt(s.interest),Gt(s.principal),Gt(s.closingBalance)].filter(Boolean).join(" ");console.log(a)}console.log(Bt(90));let o=["TOTAL".padStart(6),t.inputs.startDate?"".padStart(12):null,"".padStart(14),Gt(t.totalCashPayments),Gt(t.totalInterest),Gt(t.presentValue),Gt(0)].filter(Boolean).join(" ");console.log(R(o)),console.log(),console.log(R("Monthly ROU Depreciation")),console.log(z(` Dr Depreciation Expense \u2014 ROU${" ".repeat(8)}${ut(t.monthlyRouDepreciation)}`)),console.log(z(` Cr Accumulated Depreciation \u2014 ROU${" ".repeat(4)} ${ut(t.monthlyRouDepreciation)}`)),console.log(),console.log(R("Summary")),console.log(` Total cash payments: ${ut(t.totalCashPayments)}`),console.log(` Total interest expense: ${ut(t.totalInterest)}`),console.log(` Total ROU depreciation: ${ut(t.totalDepreciation)}`),console.log(` Total P&L impact: ${ut(t.totalInterest+t.totalDepreciation)}`),console.log(),ld(t)}function k0t(t){let e=t.inputs.method==="sl",n=t.inputs.frequency==="monthly"?"Month":"Year",i=t.inputs.method.toUpperCase(),o=e?72:100;if(console.log(),console.log(R(`${e?"Straight-Line":"Declining Balance"} Depreciation Schedule${e?"":` (${i})`}${cd(t.currency)}`)),console.log(Bt(o)),console.log(R(` Asset Cost: ${ut(t.inputs.cost)}`)),console.log(R(` Salvage Value: ${ut(t.inputs.salvageValue)}`)),console.log(R(` Useful Life: ${t.inputs.usefulLifeYears} years`)),!e){let s=t.inputs.method==="ddb"?2:1.5;console.log(R(` Method: ${i} (${s} / ${t.inputs.usefulLifeYears} = ${(s/t.inputs.usefulLifeYears*100).toFixed(1)}% per year)`))}if(console.log(Bt(o)),e){let s=[n.padStart(6),"Opening BV".padStart(14),"Depreciation".padStart(14),"Closing BV".padStart(14)].join(" ");console.log(z(s)),console.log(Bt(o));for(let a of t.schedule){let c=[String(a.period).padStart(6),Gt(a.openingBookValue),Gt(a.depreciation),Gt(a.closingBookValue)].join(" ");console.log(c)}}else{let s=[n.padStart(6),"Opening BV".padStart(14),"DDB".padStart(14),"SL".padStart(14),"Method".padStart(8),"Depreciation".padStart(14),"Closing BV".padStart(14)].join(" ");console.log(z(s)),console.log(Bt(o));for(let a of t.schedule){let c=[String(a.period).padStart(6),Gt(a.openingBookValue),Gt(a.ddbAmount),Gt(a.slAmount),a.methodUsed.padStart(8),Gt(a.depreciation),Gt(a.closingBookValue)].join(" ");console.log(c)}}console.log(Bt(o)),console.log(R(` Total depreciation: ${ut(t.totalDepreciation)} (cost ${ut(t.inputs.cost)} \u2212 salvage ${ut(t.inputs.salvageValue)})`)),console.log(),console.log(R("Journal Entry (per period)")),ya(t.schedule[0].journal),console.log(),ld(t)}function W0e(t){let e=t.type==="prepaid-expense",r=e?"Prepaid Expense Recognition Schedule":"Deferred Revenue Recognition Schedule",n=e?"Prepaid Amount":"Deferred Amount",i=60;console.log(),console.log(R(`${r}${cd(t.currency)}`)),console.log(Bt(i)),console.log(R(` ${n}: ${ut(t.inputs.amount)}`)),console.log(R(` Periods: ${t.inputs.periods} (${t.inputs.frequency})`)),console.log(R(` Per Period: ${ut(t.perPeriodAmount)}`)),console.log(Bt(i));let o=e?"Expensed":"Recognized",s=["Period".padStart(6),t.inputs.startDate?"Date".padStart(12):null,o.padStart(14),"Remaining".padStart(14)].filter(Boolean).join(" ");console.log(z(s)),console.log(Bt(i));for(let a of t.schedule){let c=[String(a.period).padStart(6),a.date?a.date.padStart(12):null,Gt(a.amortized),Gt(a.remainingBalance)].filter(Boolean).join(" ");console.log(c)}console.log(Bt(i)),console.log(),console.log(R("Journal Entry (per period)")),ya(t.schedule[0].journal),console.log(),ld(t)}function N0t(t){let r=t.currency??"FCY",n=t.inputs.baseCurrency;console.log(),console.log(R("FX Revaluation \u2014 IAS 21")),console.log(Bt(70)),console.log(R(` Foreign Currency: ${r}`)),console.log(R(` Base Currency: ${n}`)),console.log(R(` Amount Outstanding: ${r} ${ut(t.inputs.amount)}`)),console.log(R(` Book Rate: ${t.inputs.bookRate}`)),console.log(R(` Closing Rate: ${t.inputs.closingRate}`)),console.log(Bt(70)),console.log(),console.log(` Book Value (${n}): ${ut(t.bookValue)} (${r} ${ut(t.inputs.amount)} \xD7 ${t.inputs.bookRate})`),console.log(` Closing Value (${n}): ${ut(t.closingValue)} (${r} ${ut(t.inputs.amount)} \xD7 ${t.inputs.closingRate})`),console.log(Bt(70));let i=t.isGain?Y("Unrealized GAIN"):ie("Unrealized LOSS");console.log(` ${i}: ${n} ${ut(Math.abs(t.gainOrLoss))}`),console.log(),console.log(R("Revaluation Journal")),ya(t.journal),console.log(),console.log(R("Day 1 Reversal")),ya(t.reversalJournal),console.log(),ld(t)}function O0t(t){console.log(),console.log(R(`Expected Credit Loss \u2014 IFRS 9 Provision Matrix${cd(t.currency)}`)),console.log(Bt(75));let r=["Aging Bucket".padEnd(16),"Balance".padStart(14),"Loss Rate".padStart(10),"ECL".padStart(14)].join(" ");console.log(z(r)),console.log(Bt(75));for(let o of t.bucketDetails){let s=[o.bucket.padEnd(16),Gt(o.balance),`${o.lossRate}%`.padStart(10),Gt(o.ecl)].join(" ");console.log(s)}console.log(Bt(75));let n=["TOTAL".padEnd(16),Gt(t.totalReceivables),`${t.weightedRate}%`.padStart(10),Gt(t.totalEcl)].join(" ");console.log(R(n)),console.log(),console.log(R("Provision Adjustment")),console.log(` Required provision: ${ut(t.totalEcl)}`),console.log(` Existing provision: ${ut(t.inputs.existingProvision)}`),console.log(Bt(45));let i=t.isIncrease?ke("Increase needed"):Y("Release available");console.log(` ${i}: ${ut(Math.abs(t.adjustmentRequired))}`),console.log(),console.log(R("Journal Entry")),ya(t.journal),console.log(),ld(t)}function F0t(t){console.log(),console.log(R(`IAS 37 Provision \u2014 PV Measurement & Unwinding${cd(t.currency)}`)),console.log(Bt(80)),console.log(R(` Nominal Outflow: ${ut(t.nominalAmount)}`)),console.log(R(` Discount Rate: ${LO(t.inputs.annualRate)}`)),console.log(R(` Settlement Term: ${t.inputs.termMonths} months`)),console.log(R(` Present Value: ${ut(t.presentValue)}`)),console.log(R(` Total Unwinding: ${ut(t.totalUnwinding)}`)),console.log(Bt(80)),console.log(R(`
@@ -1156,7 +1156,7 @@ Call with { operation, arguments${o?`, ${Pl}`:""}${a.length?", file":""}${t?", o
1156
1156
  `+r.map(Lxr).join(`
1157
1157
  `)+(t?`
1158
1158
 
1159
- 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[Pl]={type:"string",description:Hnt}),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:Qxr(e.name),readOnlyHint:i,destructiveHint:!i&&s,idempotentHint:i,openWorldHint:!1}}})}var Mxr=new Set(qc.map(t=>t.name));function Tdt(t){return Mxr.has(t)}function mhe(t,e){let r=qc.find(o=>o.name===t);if(!r)return{error:`Unknown namespace: ${t}.`};let n=Bdt(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)}}G1();var Pxr=10*1024*1024,Uxr=2e4;function $xr(t){return t[0]===37&&t[1]===80&&t[2]===68&&t[3]===70?"application/pdf":t[0]===255&&t[1]===216?"image/jpeg":t[0]===137&&t[1]===80&&t[2]===78&&t[3]===71?"image/png":t[0]===80&&t[1]===75?"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":null}function qxr(t,e){let r=e.pathname.split("/").pop()??"",n;try{n=decodeURIComponent(r)}catch{n=r}let i=(t||n).trim();return!i||i==="."||i===".."||i.includes("/")||i.includes("\\")||/[\x00-\x1f\x7f]/.test(i)?"attachment":i.slice(0,255)}async function kdt(t,e=ab){if(typeof t!="object"||t===null||Array.isArray(t))return{error:{error:"The file was passed as a reference this server cannot fetch \u2014 some clients (notably mobile apps) cannot deliver conversation files yet.",hint:"Ask the user to retry from the web/desktop client, or upload the file in the Jaz dashboard and pass its attachmentId instead."}};let r=t,n;try{if(n=new URL(String(r.download_url??"")),n.protocol!=="https:")throw new Error("not https")}catch{return{error:{error:"The file reference has no fetchable https download_url.",hint:"Ask the user to re-attach the file, or upload it in the Jaz dashboard and pass its attachmentId instead."}}}try{let i=await e(n,{timeoutMs:Uxr,maxBytes:Pxr});if(!i.ok)return{error:{error:`Downloading the provided file failed (${i.status} ${i.statusText}) \u2014 the link may have expired.`,hint:"Ask the user to re-attach the file and retry."}};let o=await i.arrayBuffer(),s=(i.headers.get("content-type")??"").split(";")[0].trim(),a=typeof r.mime_type=="string"&&r.mime_type||(s&&s!=="application/octet-stream"?s:null)||$xr(new Uint8Array(o.slice(0,8)))||"application/octet-stream";return{file:{data:new Blob([o],{type:a}),fileName:qxr(typeof r.file_name=="string"?r.file_name:void 0,n)}}}catch(i){return{error:{error:`Downloading the provided file failed: ${i instanceof Error?i.message:String(i)}`,hint:"Ask the user to re-attach the file and retry. Files over 10MB cannot be ingested this way."}}}}nc();nc();my();var jxr=["search_","list_","get_","view_","describe_"];function Yxr(t){return jxr.some(e=>t.startsWith(e))}function Cf(t){if(Yxr(t.tool)&&uf(t.tool))return t}function Ndt(t,e,r){if(!(t instanceof ro))return;let n=t.message.toLowerCase(),i=t.status;if(i===404||n.includes("not found")){if(typeof r.contactResourceId=="string"&&n.includes("contact"))return Cf({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(e);if(s){let a=s[2],c=`search_${a}s`,u=typeof r.resourceId=="string"?r.resourceId:void 0;return Cf({tool:c,arguments:{},reason:`${a} ${u??""} not found. Search to locate the correct resourceId, then retry.`.trim()})}}if(i===422&&n.includes("user not found")&&n.includes("userresourceid"))return Cf({tool:"search_org_users",arguments:{},reason:"Employee binding needs the login user's resourceId. In search_org_users, read each member's `userResourceId` field (NOT the org-user record's own resourceId), then retry the bind with that."});if(i===422&&n.includes("claim profile is required"))return Cf({tool:"search_claim_profiles",arguments:{},reason:"An employee requires a claimProfileResourceId (it carries the employee balance account used to convert + pay claims; the org default is not auto-applied). Find one via search_claim_profiles, then set it on the employee."});if(i===422&&n.includes("expenseaccountresourceid"))return Cf({tool:"search_accounts",arguments:{},reason:'Claim type requires an expenseAccountResourceId. Search expense GL accounts via search_accounts \u2014 accountType is a display label (try "Operating Expense" or "Direct Costs", NOT "EXPENSE") \u2014 then set it on the claim type.'});if(i===422&&(n.includes("accountresourceid")||n.includes("account resource id")))return Cf({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(i===422&&(n.includes("duplicate")||n.includes("already exists"))){let s=typeof r.reference=="string"?r.reference:void 0;if(s){let a=/^create_(.+)$/.exec(e);if(a){let c=a[1];return Cf({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(i===422&&n.includes("every line item must carry a tax profile"))return Cf({tool:"search_tax_profiles",arguments:{},reason:"The claim profile is INCLUSIVE \u2014 every claim line must carry a tax profile to submit. Find a purchase tax profile via search_tax_profiles, set it on the claim type (so its lines inherit tax) or on the line, then resubmit."});if(i===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 Cf({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.'})}BM();function Hxr(t){switch(t){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 Odt(t,e={}){let r=e.readOnly===!1&&CD()?pQe:"";if(t instanceof ro){let i=[Hxr(t.status),r].filter(Boolean).join(" "),o={error:t.message,status:t.status,endpoint:t.endpoint,...i?{hint:i}:{}};if(e.toolName&&e.input){let s=Ndt(t,e.toolName,e.input);s&&(o.repair=s)}return o}return{error:t instanceof Error?t.message:String(t),...r?{hint:r}:{}}}function Fdt(t,e){if(t.readOnly)return{valid:!0,errors:[]};let r=[];for(let n of t.required){let i=e[n];if(i==null){r.push(`Missing required field: ${n}`);continue}typeof i=="string"&&i.trim()===""&&r.push(`Required field "${n}" is empty`)}for(let[n,i]of Object.entries(e)){if(i==null)continue;let o=t.params[n];if(!o)continue;let s=zxr(n,i,o);s&&r.push(s),o.enum&&typeof i=="string"&&(o.enum.includes(i)||r.push(`Field "${n}" value "${i}" not in allowed values: ${o.enum.join(", ")}`))}return{valid:r.length===0,errors:r}}function zxr(t,e,r){switch(r.type){case"string":if(typeof e!="string")return`Field "${t}" expected string, got ${typeof e}`;break;case"number":if(typeof e!="number"||!Number.isFinite(e))return`Field "${t}" expected finite number, got ${typeof e=="number"?"non-finite":typeof e}`;break;case"boolean":if(typeof e!="boolean")return`Field "${t}" expected boolean, got ${typeof e}`;break;case"array":if(!Array.isArray(e))return`Field "${t}" expected array, got ${typeof e}`;break;case"object":if(typeof e!="object"||Array.isArray(e))return`Field "${t}" expected object, got ${Array.isArray(e)?"array":typeof e}`;break}return null}kv();LT();nc();qm();rue();import{readFileSync as Gxr,readdirSync as Jxr,statSync as Vxr}from"node:fs";import{dirname as Wxr,join as hk,relative as Zxr}from"node:path";import{fileURLToPath as Kxr}from"node:url";function Xxr(t,e){let r;try{r=Vxr(t)}catch{return[]}if(!r.isDirectory())return[];let n=[],i=20,o=(s,a)=>{if(a>i)return;let c;try{c=Jxr(s,{withFileTypes:!0})}catch{return}for(let u of c){let d=hk(s,u.name);if(u.isDirectory())o(d,a+1);else if(u.isFile()&&u.name.endsWith(".md")){let f=Zxr(t,d).split(/[\\/]/).join("/");(!e||!e(f))&&n.push(f)}}};return o(t,0),n.sort()}function eTr(t){let e=t.fileFilter??(()=>!0);return Xxr(t.rootDir,n=>!e(n)).map(n=>{let i=t.uriPathBuilder?t.uriPathBuilder(n):n.replace(/\.md$/,"");return{uri:`${t.uriPrefix}/${i}`,name:t.nameBuilder(n),description:t.descriptionBuilder?.(n),mimeType:"text/markdown",filePath:hk(t.rootDir,n)}})}function tTr(){let t=Kxr(import.meta.url),e=Wxr(t);return mrt([hk(e,"..","..","..","assets","skills"),hk(e,"..","..","..","..","assets","skills"),hk(e,"skills")])}var rTr=["api","cli","conversion","jobs","transaction-recipes","jaz-pseudo-sql","clio-kit"],nTr={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.","jaz-pseudo-sql":"Read-only pseudo-SQL over the curated reporting schema for ad-hoc questions.","clio-kit":"Multi-organization operator workspace: per-org context, resumable closes, review queue."};function iTr(t){if(t.includes("/help-center-mirror/"))return!1;let e=t.split("/")[0];return rTr.includes(e)}function oTr(t){let e=t.split("/"),r=e[0];if(e.length===2&&e[1]==="SKILL.md")return`Jaz ${r} skill`;if(e[1]==="references"){let n=e.slice(2).join("/").replace(/\.md$/,"");return`Jaz ${r} reference: ${n}`}return`Jaz ${r}: ${t}`}function sTr(t){let e=t.split("/")[0];return nTr[e]}var Ahe=null,ghe=null;function yhe(){if(Ahe)return Ahe;let t=tTr(),e=[];return t&&e.push(...eTr({rootDir:t,uriPrefix:"jaz://skill",fileFilter:iTr,nameBuilder:oTr,descriptionBuilder:sTr,uriPathBuilder:r=>{let n=r.split("/");return n.length===2&&n[1]==="SKILL.md"?n[0]:r.replace(/\.md$/,"")}})),Ahe=e,ghe=new Map(e.map(r=>[r.uri,r])),e}function Qdt(t){ghe||yhe();let e=ghe.get(t);if(!e)throw new Error(`Resource not found: ${t}`);let r=Gxr(e.filePath,"utf-8");return{mimeType:e.mimeType,text:r}}var aTr=new Set(["help_center"]),bhe="Calculators, blueprints, and help center search work without an account.",Che="Get an API key or token from jaz.ai";function Ehe(t,e){return!!(aTr.has(t)||t==="recipes"&&e==="plan_recipe")}function cTr(t,e){return new Yo({mode:"pat",token:t,orgId:e},"mcp")}async function vhe(t,e=5e3){let r=new Map,n=[],i=async a=>{let c,u=new Promise(d=>{c=setTimeout(()=>d(null),e)});try{return await Promise.race([a,u])}finally{c&&clearTimeout(c)}},o=t.map(a=>({auth:a,client:new Yo(a,"mcp")})),s=o[0]?.client??null;return await Promise.all(o.map(async({auth:a,client:c})=>{try{let u=await i(Aa(c));if(u)r.set(u.resourceId,{name:u.name,resourceId:u.resourceId,currency:u.currency,client:c});else{let d=a.mode==="direct"?"api-key":a.mode;n.push(`Org lookup returned empty (${d}).`)}}catch(u){let d=a.mode==="direct"?"api-key":a.mode;n.push(`Org lookup failed (${d}): ${u instanceof Error?u.message:"unknown"}`)}})),{orgMap:r,primaryClient:s,errors:n}}function Ldt(t){let e=new I3({name:"jaz-ai",version:t.version},{capabilities:{tools:{},resources:{}},instructions:t.instructions});e.setRequestHandler(gfe,async()=>{if(t.flatMode){let o=qnt(void 0).reduce((s,a)=>{try{let c=Ey(a);s.push({name:c.name,description:c.description,inputSchema:c.input_schema,annotations:L8(a)})}catch(c){let u=c instanceof Error?c.message:String(c);process.stderr.write(`[jaz-mcp] flat-mode: skipping malformed tool '${a.name}': ${u}
1159
+ 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[Pl]={type:"string",description:Hnt}),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:Qxr(e.name),readOnlyHint:i,destructiveHint:!i&&s,idempotentHint:i,openWorldHint:!1}}})}var Mxr=new Set(qc.map(t=>t.name));function Tdt(t){return Mxr.has(t)}function mhe(t,e){let r=qc.find(o=>o.name===t);if(!r)return{error:`Unknown namespace: ${t}.`};let n=Bdt(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)}}G1();var Pxr=10*1024*1024,Uxr=2e4;function $xr(t){return t[0]===37&&t[1]===80&&t[2]===68&&t[3]===70?"application/pdf":t[0]===255&&t[1]===216?"image/jpeg":t[0]===137&&t[1]===80&&t[2]===78&&t[3]===71?"image/png":t[0]===80&&t[1]===75?"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":null}function qxr(t,e){let r=e.pathname.split("/").pop()??"",n;try{n=decodeURIComponent(r)}catch{n=r}let i=(t||n).trim();return!i||i==="."||i===".."||i.includes("/")||i.includes("\\")||/[\x00-\x1f\x7f]/.test(i)?"attachment":i.slice(0,255)}async function kdt(t,e=ab){if(typeof t!="object"||t===null||Array.isArray(t))return{error:{error:"The file was passed as a reference this server cannot fetch \u2014 some clients (notably mobile apps) cannot deliver conversation files yet.",hint:"Ask the user to retry from the web/desktop client, or upload the file in the Jaz dashboard and pass its attachmentId instead."}};let r=t,n;try{if(n=new URL(String(r.download_url??"")),n.protocol!=="https:")throw new Error("not https")}catch{return{error:{error:"The file reference has no fetchable https download_url.",hint:"Ask the user to re-attach the file, or upload it in the Jaz dashboard and pass its attachmentId instead."}}}try{let i=await e(n,{timeoutMs:Uxr,maxBytes:Pxr});if(!i.ok)return{error:{error:`Downloading the provided file failed (${i.status} ${i.statusText}) \u2014 the link may have expired.`,hint:"Ask the user to re-attach the file and retry."}};let o=await i.arrayBuffer(),s=(i.headers.get("content-type")??"").split(";")[0].trim(),a=typeof r.mime_type=="string"&&r.mime_type||(s&&s!=="application/octet-stream"?s:null)||$xr(new Uint8Array(o.slice(0,8)))||"application/octet-stream";return{file:{data:new Blob([o],{type:a}),fileName:qxr(typeof r.file_name=="string"?r.file_name:void 0,n)}}}catch(i){return{error:{error:`Downloading the provided file failed: ${i instanceof Error?i.message:String(i)}`,hint:"Ask the user to re-attach the file and retry. Files over 10MB cannot be ingested this way."}}}}nc();nc();my();var jxr=["search_","list_","get_","view_","describe_"];function Yxr(t){return jxr.some(e=>t.startsWith(e))}function Cf(t){if(Yxr(t.tool)&&uf(t.tool))return t}function Ndt(t,e,r){if(!(t instanceof ro))return;let n=t.message.toLowerCase(),i=t.status;if(i===404||n.includes("not found")){if(typeof r.contactResourceId=="string"&&n.includes("contact"))return Cf({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(e);if(s){let a=s[2],c=`search_${a}s`,u=typeof r.resourceId=="string"?r.resourceId:void 0;return Cf({tool:c,arguments:{},reason:`${a} ${u??""} not found. Search to locate the correct resourceId, then retry.`.trim()})}}if(i===422&&n.includes("user not found")&&n.includes("userresourceid"))return Cf({tool:"search_org_users",arguments:{},reason:"Employee binding needs the login user's resourceId. In search_org_users, read each member's `userResourceId` field (NOT the org-user record's own resourceId), then retry the bind with that."});if(i===422&&n.includes("claim profile is required"))return Cf({tool:"search_claim_profiles",arguments:{},reason:"An employee requires a claimProfileResourceId (it carries the employee balance account used to convert + pay claims; the org default is not auto-applied). Find one via search_claim_profiles, then set it on the employee."});if(i===422&&n.includes("expenseaccountresourceid"))return Cf({tool:"search_accounts",arguments:{},reason:'Claim type requires an expenseAccountResourceId. Search expense GL accounts via search_accounts \u2014 accountType is a display label (try "Operating Expense" or "Direct Costs", NOT "EXPENSE") \u2014 then set it on the claim type.'});if(i===422&&(n.includes("accountresourceid")||n.includes("account resource id")))return Cf({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(i===422&&(n.includes("duplicate")||n.includes("already exists"))){let s=typeof r.reference=="string"?r.reference:void 0;if(s){let a=/^create_(.+)$/.exec(e);if(a){let c=a[1];return Cf({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(i===422&&n.includes("every line item must carry a tax profile"))return Cf({tool:"search_tax_profiles",arguments:{},reason:"The claim profile is INCLUSIVE \u2014 every claim line must carry a tax profile to submit. Find a purchase tax profile via search_tax_profiles, set it on the claim type (so its lines inherit tax) or on the line, then resubmit."});if(i===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 Cf({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.'})}BM();function Hxr(t){switch(t){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 Odt(t,e={}){let r=e.readOnly===!1&&CD()?pQe:"";if(t instanceof ro){let i=[Hxr(t.status),r].filter(Boolean).join(" "),o={error:t.message,status:t.status,endpoint:t.endpoint,...i?{hint:i}:{}};if(e.toolName&&e.input){let s=Ndt(t,e.toolName,e.input);s&&(o.repair=s)}return o}return{error:t instanceof Error?t.message:String(t),...r?{hint:r}:{}}}function Fdt(t,e){if(t.readOnly)return{valid:!0,errors:[]};let r=[];for(let n of t.required){let i=e[n];if(i==null){r.push(`Missing required field: ${n}`);continue}typeof i=="string"&&i.trim()===""&&r.push(`Required field "${n}" is empty`)}for(let[n,i]of Object.entries(e)){if(i==null)continue;let o=t.params[n];if(!o)continue;let s=zxr(n,i,o);s&&r.push(s),o.enum&&typeof i=="string"&&(o.enum.includes(i)||r.push(`Field "${n}" value "${i}" not in allowed values: ${o.enum.join(", ")}`))}return{valid:r.length===0,errors:r}}function zxr(t,e,r){switch(r.type){case"string":if(typeof e!="string")return`Field "${t}" expected string, got ${typeof e}`;break;case"number":if(typeof e!="number"||!Number.isFinite(e))return`Field "${t}" expected finite number, got ${typeof e=="number"?"non-finite":typeof e}`;break;case"boolean":if(typeof e!="boolean")return`Field "${t}" expected boolean, got ${typeof e}`;break;case"array":if(!Array.isArray(e))return`Field "${t}" expected array, got ${typeof e}`;break;case"object":if(typeof e!="object"||Array.isArray(e))return`Field "${t}" expected object, got ${Array.isArray(e)?"array":typeof e}`;break}return null}kv();LT();nc();qm();rue();import{readFileSync as Gxr,readdirSync as Jxr,statSync as Vxr}from"node:fs";import{dirname as Wxr,join as hk,relative as Zxr}from"node:path";import{fileURLToPath as Kxr}from"node:url";function Xxr(t,e){let r;try{r=Vxr(t)}catch{return[]}if(!r.isDirectory())return[];let n=[],i=20,o=(s,a)=>{if(a>i)return;let c;try{c=Jxr(s,{withFileTypes:!0})}catch{return}for(let u of c){let d=hk(s,u.name);if(u.isDirectory())o(d,a+1);else if(u.isFile()&&u.name.endsWith(".md")){let f=Zxr(t,d).split(/[\\/]/).join("/");(!e||!e(f))&&n.push(f)}}};return o(t,0),n.sort()}function eTr(t){let e=t.fileFilter??(()=>!0);return Xxr(t.rootDir,n=>!e(n)).map(n=>{let i=t.uriPathBuilder?t.uriPathBuilder(n):n.replace(/\.md$/,"");return{uri:`${t.uriPrefix}/${i}`,name:t.nameBuilder(n),description:t.descriptionBuilder?.(n),mimeType:"text/markdown",filePath:hk(t.rootDir,n)}})}function tTr(){let t=Kxr(import.meta.url),e=Wxr(t);return mrt([hk(e,"..","..","..","assets","skills"),hk(e,"..","..","..","..","assets","skills"),hk(e,"skills")])}var rTr=["api","cli","conversion","jobs","transaction-recipes","jaz-pseudo-sql","jaz-kit"],nTr={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.","jaz-pseudo-sql":"Read-only pseudo-SQL over the curated reporting schema for ad-hoc questions.","jaz-kit":"Multi-organization operator workspace: per-org context, resumable closes, review queue."};function iTr(t){if(t.includes("/help-center-mirror/"))return!1;let e=t.split("/")[0];return rTr.includes(e)}function oTr(t){let e=t.split("/"),r=e[0];if(e.length===2&&e[1]==="SKILL.md")return`Jaz ${r} skill`;if(e[1]==="references"){let n=e.slice(2).join("/").replace(/\.md$/,"");return`Jaz ${r} reference: ${n}`}return`Jaz ${r}: ${t}`}function sTr(t){let e=t.split("/")[0];return nTr[e]}var Ahe=null,ghe=null;function yhe(){if(Ahe)return Ahe;let t=tTr(),e=[];return t&&e.push(...eTr({rootDir:t,uriPrefix:"jaz://skill",fileFilter:iTr,nameBuilder:oTr,descriptionBuilder:sTr,uriPathBuilder:r=>{let n=r.split("/");return n.length===2&&n[1]==="SKILL.md"?n[0]:r.replace(/\.md$/,"")}})),Ahe=e,ghe=new Map(e.map(r=>[r.uri,r])),e}function Qdt(t){ghe||yhe();let e=ghe.get(t);if(!e)throw new Error(`Resource not found: ${t}`);let r=Gxr(e.filePath,"utf-8");return{mimeType:e.mimeType,text:r}}var aTr=new Set(["help_center"]),bhe="Calculators, blueprints, and help center search work without an account.",Che="Get an API key or token from jaz.ai";function Ehe(t,e){return!!(aTr.has(t)||t==="recipes"&&e==="plan_recipe")}function cTr(t,e){return new Yo({mode:"pat",token:t,orgId:e},"mcp")}async function vhe(t,e=5e3){let r=new Map,n=[],i=async a=>{let c,u=new Promise(d=>{c=setTimeout(()=>d(null),e)});try{return await Promise.race([a,u])}finally{c&&clearTimeout(c)}},o=t.map(a=>({auth:a,client:new Yo(a,"mcp")})),s=o[0]?.client??null;return await Promise.all(o.map(async({auth:a,client:c})=>{try{let u=await i(Aa(c));if(u)r.set(u.resourceId,{name:u.name,resourceId:u.resourceId,currency:u.currency,client:c});else{let d=a.mode==="direct"?"api-key":a.mode;n.push(`Org lookup returned empty (${d}).`)}}catch(u){let d=a.mode==="direct"?"api-key":a.mode;n.push(`Org lookup failed (${d}): ${u instanceof Error?u.message:"unknown"}`)}})),{orgMap:r,primaryClient:s,errors:n}}function Ldt(t){let e=new I3({name:"jaz-ai",version:t.version},{capabilities:{tools:{},resources:{}},instructions:t.instructions});e.setRequestHandler(gfe,async()=>{if(t.flatMode){let o=qnt(void 0).reduce((s,a)=>{try{let c=Ey(a);s.push({name:c.name,description:c.description,inputSchema:c.input_schema,annotations:L8(a)})}catch(c){let u=c instanceof Error?c.message:String(c);process.stderr.write(`[jaz-mcp] flat-mode: skipping malformed tool '${a.name}': ${u}
1160
1160
  `)}return s},[]);return t.isMultiOrg&&t.orgMap.size>0&&o.unshift({name:Xh.name,description:Xh.description,inputSchema:Xh.inputSchema,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1}}),{tools:o}}if(t.namespaceMode){let o=t.isMultiOrg&&t.orgMap.size>0,s=xdt(o);return o&&s.unshift({name:Xh.name,description:Xh.description,inputSchema:Xh.inputSchema,annotations:{title:"List Organizations",readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1}}),{tools:s}}return{tools:(t.isMultiOrg&&t.orgMap.size>0?[...hf,Xh]:hf).map(o=>({name:o.name,description:o.description,inputSchema:o.inputSchema,annotations:{readOnlyHint:o.name!=="execute_tool",openWorldHint:!1}}))}}),e.setRequestHandler(ufe,async()=>({resources:yhe().map(({uri:i,name:o,description:s,mimeType:a})=>({uri:i,name:o,...s?{description:s}:{},mimeType:a}))})),e.setRequestHandler(ffe,async i=>{let o=i.params.uri;try{let{mimeType:s,text:a}=Qdt(o);return{contents:[{uri:o,mimeType:s,text:a}]}}catch(s){throw new Nt(qt.InvalidRequest,s instanceof Error?s.message:`Resource not found: ${o}`)}});let r=(i,o=!1)=>({content:[{type:"text",text:typeof i=="string"?i:JSON.stringify(i,null,2)}],...o?{isError:!0}:{}});async function n(i,o,s,a){let{jotText:c,cleanedInput:u}=znt(i,o);if(!t.primaryClient&&!Ehe(i.group,i.name))return r({error:"No API key configured.",hint:`${Che} to use API tools. ${bhe}`},!0);let d=t.primaryClient,f;if(t.isMultiOrg&&!Ehe(i.group,i.name)){if(t.orgMap.size===0)return r({error:"Organization discovery is unavailable, so this tenant-scoped tool cannot be run safely.",hint:"Retry once organizations resolve, or call list_organizations to refresh."},!0);let m=s;if(!m)if(t.orgMap.size===1)m=t.orgMap.keys().next().value;else return r({error:"Missing org_id. Multiple organizations are accessible \u2014 specify which one.",hint:"Call list_organizations to see available orgs, then include org_id.",organizations:[...t.orgMap.values()].map(({name:y,resourceId:C})=>({name:y,resourceId:C}))},!0);let A=t.orgMap.get(m);if(!A)return r({error:`Unknown org_id: "${m}".`,hint:"Call list_organizations to refresh the org list.",available:[...t.orgMap.values()].map(({name:y,resourceId:C})=>({name:y,resourceId:C}))},!0);f=A;let g=t.authConfigs[0];d=g?.mode==="pat"?cTr(g.token,m):A.client}let p=Fdt(i,u);if(!p.valid)return r({error:`Validation: ${p.errors.join("; ")}`,hint:"Check required fields and types."},!0);let h;if(a!=null){let m=await kdt(a);if(m.error)return r(m.error,!0);h=m.file}try{if(!d&&!Ehe(i.group,i.name))return r({error:"No API client available.",hint:"Set JAZ_API_KEY or pass --api-key."},!0);let m={client:d,org:f?{resourceId:f.resourceId}:void 0,file_blob:h},A=await i.execute(m,u);return c&&d&&Xz(d,i.name,c,A),f&&A&&typeof A=="object"&&!Array.isArray(A)?r({...A,_organization:{name:f.name,resourceId:f.resourceId,currency:f.currency}}):r(A)}catch(m){return r(Odt(m,{toolName:i.name,input:u,readOnly:i.readOnly}),!0)}}return e.setRequestHandler(kT,async i=>{let o=i.params.name,s=i.params.arguments??{};if(o==="search_tools"){let u=s.query;if(u!==void 0&&typeof u!="string")return{content:[{type:"text",text:JSON.stringify({error:"Invalid `query` parameter. Expected string."})}],isError:!0};let d=Fct(u??"");return{content:[{type:"text",text:JSON.stringify(d,null,2)}]}}if(o==="describe_tools"){let u=Qct(s.tools);return{content:[{type:"text",text:JSON.stringify(u,null,2)}]}}if(o==="list_organizations"){if(!t.isMultiOrg||t.orgMap.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};let u=t.refreshOrgs??(t.authConfigs[0]?.mode==="pat"?async()=>(await vhe(t.authConfigs,5e3)).orgMap:void 0);if(u)try{let d=await u();if(d.size>0){t.orgMap.clear();for(let[f,p]of d)t.orgMap.set(f,p)}}catch(d){process.stderr.write(`warning: org refresh failed, using cached list: ${d instanceof Error?d.message:"unknown"}
1161
1161
  `)}return{content:[{type:"text",text:JSON.stringify({organizations:[...t.orgMap.values()].map(({name:d,resourceId:f,currency:p})=>({name:d,resourceId:f,currency:p}))},null,2)}]}}if(o==="execute_tool"){let u=s.tool;if(!u)return r({error:"Missing `tool` parameter.",hint:'Call search_tools first, then describe_tools, then execute_tool with { tool: "tool_name", arguments: {...} }.'},!0);let d=uf(u);if(!d)throw new Nt(qt.MethodNotFound,`Unknown tool: ${u}. Use search_tools to find available tools.`);return n(d,s.arguments??{},s.org_id)}if(t.namespaceMode&&Tdt(o)){let u=s.operation;if(!u)return r({error:`Missing \`operation\` for the ${o} tool.`,operations:mhe(o,"").operations},!0);let d=mhe(o,u);if(!d.tool)return r({error:d.error,operations:d.operations},!0);if(s.file!==void 0&&s.file!==null&&!d.tool.acceptsHostFile)return r({error:`Operation "${u}" does not ingest files.`,hint:"Pick a file-capable operation (the tool description marks them), or omit `file`."},!0);let f={...s.arguments??{},...typeof s[Pl]=="string"&&!d.tool.readOnly&&!d.tool.params[Pl]?{[Pl]:s[Pl]}:{}};return n(d.tool,f,s.org_id,s.file)}let a=uf(o);if(a){let{org_id:u,...d}=s;return n(a,d,u)}let c=t.isMultiOrg&&t.orgMap.size>0?"search_tools, describe_tools, execute_tool, list_organizations":"search_tools, describe_tools, execute_tool";throw new Nt(qt.MethodNotFound,`Unknown tool: ${o}. Available tools: ${c}.`)}),e}function Mdt(t){let e=qc.map(o=>o.name).join(", "),r=t.hasAuth?"All API tools hit api.getjaz.com using the configured credentials.":`${Che} to bring Jaz into Claude for real accounting and finance work. ${bhe}`,n=t.surface==="namespace"?["WORKFLOW: each namespace below is ONE tool. Call it with `{ operation, arguments }` (plus `file` or `org_id` when the tool offers them).","1. Pick the namespace that fits the task (see the list below).","2. Set `operation` to the action and `arguments` to its parameters.","3. Read the result and chain follow-up calls as needed."]:t.surface==="flat"?["WORKFLOW: every tool is listed directly \u2014 call a tool by its own name with its arguments.","1. Find the tool for the task in the tool list.","2. Call it with its arguments. No separate discovery step is needed."]:["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."],i=t.isMultiOrg&&t.orgs.length>0?["","MULTI-ORG MODE:",`You have access to ${t.orgs.length} organization(s):`,...t.orgs.map(o=>` - ${o.name} (org_id: ${o.resourceId}, ${o.currency})`),"","RULES:","1. Pass org_id on each API tool call. With exactly one organization it may be omitted (it defaults); with two or more it is required.","2. If the user mentions an org by name, match it to the org_id above.",'3. If the user has not specified an org and more than one is accessible, ask: "Which organization?"','4. Confirm the target organization with the user BEFORE any create, update, or delete (e.g. "Create this invoice in [Org Name]?"). Reads need no confirmation.',"5. Once the user picks an org, use it for subsequent calls until they say to switch.","6. Every tool result includes the organization it acted on (`_organization`) \u2014 surface it so the user can catch a wrong-org call.",'7. For cross-org queries (e.g. "compare Acme and Beta"), make separate calls with different org_ids.',"8. Call list_organizations to refresh the org list if needed."]:[];return[`Jaz accounting platform \u2014 ${Mc.length} tools across ${qc.length} namespaces.`,t.orgDisplay,"",...n,"",`Namespaces: ${e}.`,"","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.","- Documents: when the user provides or uploads an invoice / bill / receipt / credit note, prefer AI extraction over re-keying \u2014 use the `document_ai` namespace's `create_bt_from_attachment` with the file (the `file` slot) or a `sourceUrl`, and set `businessTransactionType` (bill / purchase invoice \u2192 BILL, invoice / sales invoice \u2192 INVOICE, credit note \u2192 its matching type; ask if genuinely unclear). A bank or card statement is NOT one of these \u2014 that is a bank import (`import_bank_statement` / reconciliation), never a bill or invoice. Extraction is asynchronous: it returns a workflow id, NOT a record \u2014 tell the user the draft is being prepared and will appear in their Drafts, and do not claim a specific record or invent a link until a status check confirms one. If you cannot get the file or a URL, create from the fields you have (e.g. `create_bill`) and ask for anything missing \u2014 do not stop at only describing it. (This never overrides org confirmation before a create.)","","Judgment journal: when a real judgment call precedes a write, record it with `jot` after the write succeeds; when you deliberately hold a write, record that decision immediately. Check `recall` for prior judgments before repeating one (jots namespace).","","No account needed: plan_recipe calculator (offline) and search_help_center for the Jaz help center (served live).",r,...i].filter(o=>o!==void 0).join(`
1162
1162
  `)}uZ();kv();function Gdt(t){t.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 e=>{let r=[];try{r=FV(e.apiKey)}catch(C){let E=C instanceof Error?C.message:String(C);process.stderr.write(`jaz-ai: ${E} (continuing in offline mode)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jaz-clio",
3
- "version": "5.29.2",
3
+ "version": "5.30.1",
4
4
  "description": "Clio: Command Line Interface Operator for Jaz AI.",
5
5
  "type": "module",
6
6
  "bin": {