@kashdao/cli 0.1.1 → 0.2.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.
Files changed (93) hide show
  1. package/CHANGELOG.md +96 -0
  2. package/README.md +78 -27
  3. package/dist/{account-CVJZ3HVT.js → account-QHPOIZ6I.js} +9 -9
  4. package/dist/{auth-V5WVZBCO.js → auth-TE7BCN5Q.js} +12 -12
  5. package/dist/{auth-V5WVZBCO.js.map → auth-TE7BCN5Q.js.map} +1 -1
  6. package/dist/{chunk-MQUJG224.js → chunk-2HFKULGG.js} +2 -2
  7. package/dist/{chunk-BVFDUI73.js → chunk-2SR77BYA.js} +10 -9
  8. package/dist/chunk-2SR77BYA.js.map +1 -0
  9. package/dist/chunk-6QSTFU4R.js +9 -0
  10. package/dist/{chunk-KAM6KOFD.js.map → chunk-6QSTFU4R.js.map} +1 -1
  11. package/dist/{chunk-R4NGUZKN.js → chunk-6UU43MF5.js} +5 -3
  12. package/dist/chunk-6UU43MF5.js.map +1 -0
  13. package/dist/{chunk-A3IH5HUV.js → chunk-AROIP4EQ.js} +3 -3
  14. package/dist/chunk-AROIP4EQ.js.map +1 -0
  15. package/dist/{chunk-QALDZHTX.js → chunk-H2QGFDZP.js} +9 -11
  16. package/dist/chunk-H2QGFDZP.js.map +1 -0
  17. package/dist/{chunk-L4AFV2HK.js → chunk-IOLKGV45.js} +3 -3
  18. package/dist/chunk-IOLKGV45.js.map +1 -0
  19. package/dist/{chunk-KADB3OKE.js → chunk-VFBQVUL4.js} +2 -2
  20. package/dist/{chunk-X2VM6VKM.js → chunk-WL7XUYPH.js} +19 -20
  21. package/dist/chunk-WL7XUYPH.js.map +1 -0
  22. package/dist/{chunk-N26VGVGB.js → chunk-ZSMI63N3.js} +109 -37
  23. package/dist/chunk-ZSMI63N3.js.map +1 -0
  24. package/dist/client-REDY6K7J.js +14 -0
  25. package/dist/{completion-PK74S3EZ.js → completion-MXTJYK3D.js} +4 -4
  26. package/dist/{config-T5U6E6KU.js → config-TIJXUJ5N.js} +32 -23
  27. package/dist/config-TIJXUJ5N.js.map +1 -0
  28. package/dist/{config-store-UTFDUCKW.js → config-store-INJY4DDT.js} +6 -4
  29. package/dist/{docs-VA7CJ2ZF.js → docs-M5RZAQ6P.js} +5 -5
  30. package/dist/{eoa-RL3NLN3H.js → eoa-N55DYIN3.js} +18 -16
  31. package/dist/eoa-N55DYIN3.js.map +1 -0
  32. package/dist/{errors-2NNXRNES.js → errors-SMR7X5DU.js} +2 -2
  33. package/dist/{explain-3SPMWDYX.js → explain-HIDEZVLV.js} +31 -8
  34. package/dist/explain-HIDEZVLV.js.map +1 -0
  35. package/dist/{global-options-WFQ6CEFK.js → global-options-YONBFB7N.js} +4 -4
  36. package/dist/{health-2KD6XUTJ.js → health-LSJKP3NH.js} +9 -9
  37. package/dist/index.js +31 -28
  38. package/dist/index.js.map +1 -1
  39. package/dist/{markets-H6EK2XDE.js → markets-AGL6Q2ES.js} +23 -12
  40. package/dist/markets-AGL6Q2ES.js.map +1 -0
  41. package/dist/{output-FGTXXZEQ.js → output-M4NFSWGW.js} +4 -4
  42. package/dist/{portfolio-R63D5QB2.js → portfolio-RBRVUEYP.js} +11 -11
  43. package/dist/{portfolio-R63D5QB2.js.map → portfolio-RBRVUEYP.js.map} +1 -1
  44. package/dist/{protocol-ZB6R25IM.js → protocol-WYQAKN6N.js} +18 -16
  45. package/dist/protocol-WYQAKN6N.js.map +1 -0
  46. package/dist/{quote-OF6BTAPQ.js → quote-6CNHU36A.js} +10 -10
  47. package/dist/redeem-JESSTZ46.js +108 -0
  48. package/dist/redeem-JESSTZ46.js.map +1 -0
  49. package/dist/{schema-3HQN4RFL.js → schema-6EXADLRW.js} +12 -8
  50. package/dist/{schema-3HQN4RFL.js.map → schema-6EXADLRW.js.map} +1 -1
  51. package/dist/{setup-IIPQXLPL.js → setup-H46GTSVW.js} +8 -8
  52. package/dist/{trace-WMO3KDHS.js → trace-VDBWWTYL.js} +10 -10
  53. package/dist/{trade-YBCI6XD2.js → trade-FTSY23QG.js} +10 -10
  54. package/dist/trade-FTSY23QG.js.map +1 -0
  55. package/dist/{version-WB2ACHMU.js → version-JTLF3464.js} +7 -7
  56. package/dist/{version-check-PRAVPFC6.js → version-check-7JGBY6FZ.js} +4 -4
  57. package/dist/{webhooks-DVS55O4T.js → webhooks-JEWNX5HZ.js} +10 -10
  58. package/dist/{webhooks-DVS55O4T.js.map → webhooks-JEWNX5HZ.js.map} +1 -1
  59. package/dist/{with-retry-2MD2CNK2.js → with-retry-DYSHNLG7.js} +12 -6
  60. package/dist/with-retry-DYSHNLG7.js.map +1 -0
  61. package/package.json +5 -5
  62. package/dist/chunk-A3IH5HUV.js.map +0 -1
  63. package/dist/chunk-BVFDUI73.js.map +0 -1
  64. package/dist/chunk-KAM6KOFD.js +0 -9
  65. package/dist/chunk-L4AFV2HK.js.map +0 -1
  66. package/dist/chunk-N26VGVGB.js.map +0 -1
  67. package/dist/chunk-QALDZHTX.js.map +0 -1
  68. package/dist/chunk-R4NGUZKN.js.map +0 -1
  69. package/dist/chunk-X2VM6VKM.js.map +0 -1
  70. package/dist/client-75FVHGOH.js +0 -14
  71. package/dist/config-T5U6E6KU.js.map +0 -1
  72. package/dist/eoa-RL3NLN3H.js.map +0 -1
  73. package/dist/explain-3SPMWDYX.js.map +0 -1
  74. package/dist/markets-H6EK2XDE.js.map +0 -1
  75. package/dist/protocol-ZB6R25IM.js.map +0 -1
  76. package/dist/trade-YBCI6XD2.js.map +0 -1
  77. package/dist/with-retry-2MD2CNK2.js.map +0 -1
  78. /package/dist/{account-CVJZ3HVT.js.map → account-QHPOIZ6I.js.map} +0 -0
  79. /package/dist/{chunk-MQUJG224.js.map → chunk-2HFKULGG.js.map} +0 -0
  80. /package/dist/{chunk-KADB3OKE.js.map → chunk-VFBQVUL4.js.map} +0 -0
  81. /package/dist/{client-75FVHGOH.js.map → client-REDY6K7J.js.map} +0 -0
  82. /package/dist/{completion-PK74S3EZ.js.map → completion-MXTJYK3D.js.map} +0 -0
  83. /package/dist/{config-store-UTFDUCKW.js.map → config-store-INJY4DDT.js.map} +0 -0
  84. /package/dist/{docs-VA7CJ2ZF.js.map → docs-M5RZAQ6P.js.map} +0 -0
  85. /package/dist/{errors-2NNXRNES.js.map → errors-SMR7X5DU.js.map} +0 -0
  86. /package/dist/{global-options-WFQ6CEFK.js.map → global-options-YONBFB7N.js.map} +0 -0
  87. /package/dist/{health-2KD6XUTJ.js.map → health-LSJKP3NH.js.map} +0 -0
  88. /package/dist/{output-FGTXXZEQ.js.map → output-M4NFSWGW.js.map} +0 -0
  89. /package/dist/{quote-OF6BTAPQ.js.map → quote-6CNHU36A.js.map} +0 -0
  90. /package/dist/{setup-IIPQXLPL.js.map → setup-H46GTSVW.js.map} +0 -0
  91. /package/dist/{trace-WMO3KDHS.js.map → trace-VDBWWTYL.js.map} +0 -0
  92. /package/dist/{version-WB2ACHMU.js.map → version-JTLF3464.js.map} +0 -0
  93. /package/dist/{version-check-PRAVPFC6.js.map → version-check-7JGBY6FZ.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/explain.ts","../src/api-error-bundle.generated.ts"],"sourcesContent":["/**\n * `kash explain <code>` — translate an error `code` into a structured\n * description, recovery steps, and a docs URL.\n *\n * Designed to be called by AI agents that hit an error with\n * `--json --quiet`, parse the `code` from the envelope, and want\n * deterministic, machine-readable next steps. The same data feeds\n * the human-mode error suggestion.\n *\n * `kash explain` (no argument) lists every code the CLI emits — useful\n * for agents at startup that want to learn the catalog up front.\n */\n\nimport { Command } from 'commander';\n\nimport { API_ERROR_DOCS } from '../api-error-bundle.generated.js';\nimport { ERROR_CATALOG, lookupErrorCode } from '../error-catalog.js';\nimport { CliError, type CliErrorAction } from '../errors.js';\nimport { createTable, truncate } from '../utils/formatting.js';\nimport { readGlobals } from '../utils/global-options.js';\nimport { print, printJson, style } from '../utils/output.js';\n\nconst API_DOCS_URL_BASE = 'https://docs.kash.bot/developer-docs/api-errors';\n\n/**\n * Fallback for API server-side codes that aren't in the hand-curated\n * CLI ERROR_CATALOG. Returns the markdown body bundled at build time\n * from `docs/api-errors/<CODE>.md` so `kash explain MARKET_NOT_TRADEABLE`\n * works the same as `kash explain RATE_LIMITED` even though the latter\n * has rich CliError metadata and the former is server-only.\n */\nfunction lookupApiErrorBody(code: string): string | undefined {\n return API_ERROR_DOCS[code];\n}\n\nexport const explainCommand = new Command('explain')\n .description('Look up one or more error codes and their recommended recovery steps.')\n .argument('[codes...]', 'error codes to explain (omit to list every known code)')\n .addHelpText(\n 'after',\n `\nExamples:\n $ kash explain # list every known error code\n $ kash explain RATE_LIMITED\n $ kash explain RATE_LIMITED NOT_FOUND --json # bulk lookup for AI agents\n`\n )\n .action((codes: readonly string[], _opts, cmd: Command) => {\n const globals = readGlobals(cmd);\n\n if (codes.length === 0) {\n if (globals.json) {\n printJson({ codes: ERROR_CATALOG });\n return;\n }\n const table = createTable(['Code', 'Summary', 'Recoverable']);\n for (const entry of ERROR_CATALOG) {\n table.push([\n entry.code,\n truncate(entry.summary, 60),\n entry.recoverable ? style.success('yes') : style.dim('no'),\n ]);\n }\n print(table.toString());\n return;\n }\n\n // Resolve every code first so we fail before printing anything if\n // any are unknown — agents iterating a list shouldn't get a\n // half-finished response.\n type Resolved =\n | { readonly source: 'cli'; readonly entry: ReturnType<typeof lookupErrorCode> & object }\n | { readonly source: 'api'; readonly code: string; readonly body: string };\n const entries: Resolved[] = codes.map((code) => {\n const entry = lookupErrorCode(code);\n if (entry) return { source: 'cli', entry };\n // Fall back to the bundled docs/api-errors/<CODE>.md content so\n // server-side API codes (MARKET_NOT_TRADEABLE, INSUFFICIENT_BALANCE,\n // CONFIRMATION_TOKEN_USED, …) work even though they don't have\n // hand-curated CLI metadata. Agents calling `--json` get a\n // distinct `source: 'api'` envelope so they can differentiate.\n const body = lookupApiErrorBody(code);\n if (body) return { source: 'api', code, body };\n throw new CliError(`Unknown error code: ${code}`, {\n code: 'INVALID_INPUT',\n recoverable: true,\n suggestion: 'Run `kash explain` (no argument) to list every known code.',\n });\n });\n\n if (globals.json) {\n // Single code: emit the entry directly (back-compat with the\n // historical single-arg shape).\n // Multiple codes: emit a `codes` array so consumers can branch.\n const payload = entries.map((r) =>\n r.source === 'cli'\n ? r.entry\n : {\n code: r.code,\n source: 'api' as const,\n docsUrl: `${API_DOCS_URL_BASE}/${r.code}`,\n body: r.body,\n }\n );\n printJson(payload.length === 1 ? payload[0] : { codes: payload });\n return;\n }\n\n for (const [i, resolved] of entries.entries()) {\n if (i > 0) print('');\n print('');\n if (resolved.source === 'api') {\n // Render the bundled markdown verbatim — it's already formatted\n // for human reading (per-code page template).\n print(resolved.body);\n print(style.dim(`Docs: ${API_DOCS_URL_BASE}/${resolved.code}`));\n continue;\n }\n const { entry } = resolved;\n print(`${style.bold(entry.code)}`);\n print(` ${style.dim('Summary ')} ${entry.summary}`);\n print(\n ` ${style.dim('Recoverable')} ${entry.recoverable ? style.success('yes') : style.dim('no')}`\n );\n if (entry.docsUrl) {\n print(` ${style.dim('Docs ')} ${entry.docsUrl}`);\n }\n print('');\n print(entry.description);\n if (entry.actions.length > 0) {\n print('');\n print(style.bold('Recovery actions:'));\n for (const action of entry.actions) {\n print(` - ${formatAction(action)}`);\n }\n }\n }\n });\n\nfunction formatAction(action: CliErrorAction): string {\n switch (action.type) {\n case 'run_command':\n return `${style.cyan(action.command)} — ${action.description}`;\n case 'set_env':\n return `${style.cyan(action.variable)} (env var) — ${action.description}`;\n case 'wait_and_retry':\n return `${style.cyan(`wait ${String(Math.round(action.delayMs / 1000))}s`)} — ${action.description}`;\n case 'open_url':\n return `${style.cyan(action.url)} — ${action.description}`;\n case 'check_input':\n return `${style.cyan(action.field)} (input field) — ${action.description}`;\n }\n}\n","/**\n * AUTO-GENERATED by scripts/build-api-error-bundle.ts. DO NOT EDIT.\n *\n * Per-code markdown bodies extracted from docs/api-errors/<CODE>.md at\n * build time so `kash explain <CODE>` can render the full docs page\n * offline. Re-run `pnpm gen:api-error-bundle` (or `pnpm build`,\n * which runs it as a prebuild step) to refresh.\n *\n * Generated at 2026-06-19T14:33:09.728Z; 38 codes covered.\n */\n\nexport const API_ERROR_DOCS: Readonly<Record<string, string>> = Object.freeze({\n \"ACTIVE_KEY_LIMIT_REACHED\": \"# `ACTIVE_KEY_LIMIT_REACHED`\\n\\n**HTTP status:** 409 · **Title:** \\\"Active key limit reached\\\"\\n\\n## When it fires\\n\\nThe user has hit `MAX_ACTIVE_KEYS_PER_USER` (5) and `POST /api/account/api-keys` in the webapp (or `kash-admin api-keys issue`) was called to issue another. The cap is enforced both at the application layer and via the `trg_api_keys_enforce_max_active_per_user` BEFORE INSERT trigger (which closes a TOCTOU window that the app-level check alone leaves open).\\n\\n## Why it happens\\n\\n- A genuine ceiling — most users only need 2-3 keys (one per environment, maybe a CI key). The cap exists to prevent runaway issuance from compromising audit hygiene.\\n- A bot that issues a fresh key per run instead of reusing one (anti-pattern).\\n\\n## How to fix\\n\\n- Revoke an existing key first — Settings → API Keys → Revoke (or `kash-admin api-keys revoke <id>`).\\n- Reuse keys across environments where appropriate: one `kash_live_…` for production code, one `kash_test_…` for everything else.\\n- For mm/enterprise tiers, the cap is higher — contact support if your usage genuinely needs more.\\n\\n## Related codes\\n\\n- [`API_KEY_REVOKED`](./API_KEY_REVOKED.md) — what happens after revocation if you keep using the old key\\n\",\n \"AMOUNT_TOO_LARGE\": \"# `AMOUNT_TOO_LARGE`\\n\\n**HTTP status:** 400 · **Title:** \\\"Amount too large\\\"\\n\\n## When it fires\\n\\n`amount` exceeds `MAX_USDC_PER_TRADE`. This is a defence-in-depth check distinct from your key's per-trade and daily spending limits — it catches obvious mistakes regardless of your tier.\\n\\n## Why it happens\\n\\nThe most common cause is a **decimal-place mistake**: passing `1000000000000000000` (\\\"1 USDC in 18-decimal atomic units\\\") instead of `1` (\\\"1 USDC in human units\\\"). The public API takes amounts in **human units** (the same string a person would type), not 18-decimal atomic units.\\n\\n## How to fix\\n\\n- Pass `amount` as a string of the human-unit USDC value: `\\\"100\\\"`, `\\\"0.50\\\"`, `\\\"2500\\\"`.\\n- If you have an atomic value, divide by 10^6 (USDC is 6 decimals on-chain, but our API normalises to \\\"USDC the user thinks about\\\").\\n- For sustained high-value flows above `MAX_USDC_PER_TRADE`, request a tier upgrade — your key's `per_trade_limit_usdc` can be raised, but the absolute cap is a platform-level safety net.\\n\\n## Related codes\\n\\n- [`SPENDING_LIMIT_EXCEEDED`](./SPENDING_LIMIT_EXCEEDED.md) — your key's per-trade or daily limit, separate from the platform cap\\n- [`VALIDATION_FAILED`](./VALIDATION_FAILED.md) — generic validation failure\\n\",\n \"API_KEY_EXPIRED\": \"# `API_KEY_EXPIRED`\\n\\n**HTTP status:** 401 · **Title:** \\\"API key expired\\\"\\n\\n## When it fires\\n\\nThe key has a non-null `expires_at` and the current time is past it.\\n\\n## Why it happens\\n\\n- You requested a time-limited key at issuance (recommended for CI keys, contractor access, demos).\\n- An operator set an expiry on a long-lived key during a security review.\\n- The key is unchanged; only the wall clock moved.\\n\\n## How to fix\\n\\n- Issue a new key via Settings → API Keys (self-service, free/developer tiers) or `kash-admin api-keys issue` (mm/enterprise tiers).\\n- For automated rotation, schedule a rotation job that issues + activates the new key 24 h before the old one expires.\\n- The new key will have a different `id` and prefix; update every consumer.\\n\\n## Related codes\\n\\n- [`API_KEY_REVOKED`](./API_KEY_REVOKED.md) — explicit operator action, distinct from time-based expiry\\n\",\n \"API_KEY_INVALID\": \"# `API_KEY_INVALID`\\n\\n**HTTP status:** 401 · **Title:** \\\"Authentication required\\\"\\n\\n## When it fires\\n\\nThe `X-API-Key` header is well-formed but no row in the API key store matches its prefix or HMAC.\\n\\n## Why it happens\\n\\n- The key was deleted (not just revoked — see [`API_KEY_REVOKED`](./API_KEY_REVOKED.md) for that distinct case).\\n- A character was modified in transit or storage (e.g., copy-paste truncation that still happened to land on the right length).\\n- Wrong environment — a `kash_test_…` key sent to production, or vice versa. Production never accepts test keys.\\n- The HMAC pepper has been rotated and the rotation grace period has elapsed for an old issuance.\\n\\n## How to fix\\n\\n- Compare the stored value to what the webapp Settings → API Keys page shows for the prefix (`kash_live_xxxx…`).\\n- If the prefix doesn't match anything in your account, the key was never yours or has been deleted — issue a new one.\\n- If the prefix matches but auth still fails, contact support with the prefix and your `X-Request-ID` from a recent failed call.\\n\\n## Related codes\\n\\n- [`API_KEY_MISSING`](./API_KEY_MISSING.md), [`API_KEY_MALFORMED`](./API_KEY_MALFORMED.md) — earlier failure points\\n- [`API_KEY_REVOKED`](./API_KEY_REVOKED.md) — key existed but was explicitly revoked\\n- [`API_KEY_EXPIRED`](./API_KEY_EXPIRED.md) — key existed but is past `expires_at`\\n\",\n \"API_KEY_MALFORMED\": \"# `API_KEY_MALFORMED`\\n\\n**HTTP status:** 401 · **Title:** \\\"Authentication required\\\"\\n\\n## When it fires\\n\\nThe `X-API-Key` header is present but does not match the expected `kash_(live|test)_<32 alphanumeric>` shape.\\n\\n## Why it happens\\n\\n- A leading or trailing whitespace character (e.g., from a copy-paste with a trailing newline).\\n- The wrong env var was substituted (e.g., a Privy token or a bare UUID instead of a Kash API key).\\n- Truncation by a logging or proxy layer that capped header values.\\n\\n## How to fix\\n\\n- The format is `kash_<env>_<32 alphanumeric>` (base62 — `A-Z`, `a-z`, `0-9`, no dashes or underscores after the prefix). The `<env>` segment is `live` or `test`.\\n- `live` keys hit production; `test` keys hit staging. Don't mix.\\n- If you stored the key in an env var, double-check the substitution: `echo $KASH_API_KEY | head -c 16` should print `kash_live_…` or `kash_test_…`.\\n\\n## Related codes\\n\\n- [`API_KEY_MISSING`](./API_KEY_MISSING.md) — no header at all\\n- [`API_KEY_INVALID`](./API_KEY_INVALID.md) — well-formed but unknown\\n\",\n \"API_KEY_MISSING\": \"# `API_KEY_MISSING`\\n\\n**HTTP status:** 401 · **Title:** \\\"Authentication required\\\"\\n\\n## When it fires\\n\\nA route that requires authentication received a request with no `X-API-Key` header.\\n\\n## Why it happens\\n\\n- The request was sent without the header (most common — first integration).\\n- A reverse proxy or HTTP client stripped the header.\\n- The wrong base URL — the documented endpoints live under `/v1/*`; some other route may not require auth.\\n\\n## How to fix\\n\\n```http\\nGET /v1/portfolio HTTP/1.1\\nHost: api.kash.bot\\nX-API-Key: kash_live_<your-key-here>\\n```\\n\\n- Pass the key on every authenticated request. Keys are issued via the webapp Settings → API Keys page or `kash-admin api-keys issue`.\\n- The plaintext is shown once at issuance. If you've lost it, revoke and re-issue.\\n\\n## Related codes\\n\\n- [`API_KEY_MALFORMED`](./API_KEY_MALFORMED.md) — header present but doesn't match the `kash_(live|test)_*` shape\\n- [`API_KEY_INVALID`](./API_KEY_INVALID.md) — header well-formed but no row matches\\n\",\n \"API_KEY_REVOKED\": \"# `API_KEY_REVOKED`\\n\\n**HTTP status:** 401 · **Title:** \\\"API key revoked\\\"\\n\\n## When it fires\\n\\nThe key is well-formed and recognised, but its `revoked_at` column is set. The auth middleware fails closed.\\n\\n## Why it happens\\n\\n- A user (you or a teammate) explicitly revoked the key via Settings → API Keys → Revoke.\\n- An operator revoked the key via `kash-admin api-keys revoke <id>` (e.g., suspected leak).\\n- A security automation revoked it (e.g., per-key velocity anomaly tripped a kill switch).\\n\\n## How to fix\\n\\n- If revocation was unintentional, ask the operator who ran it (the audit log records who/when/why).\\n- If revocation was intentional and you need to keep working, **issue a new key**. Revoked keys cannot be un-revoked — that's the security property.\\n- Update every place the old key was stored (env vars, secret stores, CI configs) before the new key goes live.\\n\\n## Related codes\\n\\n- [`API_KEY_INVALID`](./API_KEY_INVALID.md) — key was deleted, not revoked\\n- [`API_KEY_EXPIRED`](./API_KEY_EXPIRED.md) — key reached its `expires_at` (no operator action)\\n\",\n \"API_TRADE_PROCESSING_HALTED\": \"# `API_TRADE_PROCESSING_HALTED`\\n\\n**HTTP status:** 503 · **Title:** \\\"Service unavailable\\\" · **Retry-After:** 300s\\n\\n## When it fires\\n\\nThe coarse `API_TRADE_PROCESSING` kill switch is active. Ops uses this to halt all trade-write traffic platform-wide during incidents (e.g., RPC outage, oracle failure, security investigation).\\n\\nRead endpoints (markets, portfolio, trade lookup) stay available throughout — only the write path is blocked.\\n\\n## Why it happens\\n\\n- Active incident under operator response.\\n- Pre-deploy lockdown for a high-risk migration.\\n- A security-driven freeze in response to anomaly detection.\\n\\n## How to fix\\n\\n- Honour `Retry-After: 300` and back off. Do NOT poll faster — the kill switch is binary, polling won't unblock you sooner.\\n- Subscribe to the status page or our incident webhook to know when service resumes.\\n- In the meantime, your read paths still work — surface a \\\"trading temporarily paused\\\" banner in your UI rather than failing silently.\\n\\n## Related codes\\n\\n- [`ROUTE_DISABLED`](./ROUTE_DISABLED.md) — single-route kill switch (more granular than the coarse halt)\\n- [`DEPENDENCY_UNAVAILABLE`](./DEPENDENCY_UNAVAILABLE.md) — specific dependency rather than platform-wide\\n\",\n \"API_VERSION_UNSUPPORTED\": \"# `API_VERSION_UNSUPPORTED`\\n\\n**HTTP status:** 410 · **Title:** \\\"API version unsupported\\\"\\n\\n## When it fires\\n\\nYour request sent an `X-Kash-Api-Version` header whose value is not in\\n`SUPPORTED_PUBLIC_API_VERSIONS`. The runtime accepts only\\ndate-string values that the API has actively published as a supported\\ncontract version. Unrecognized values — typos, future-dated guesses,\\nversions long past their sunset window — return this error.\\n\\n## Why 410?\\n\\n`410 Gone` is the right semantic: the version was either once\\naccepted (an old date past its 12-month deprecation window) or never\\nhas been (a typo, a future date). Either way, sending the request\\nagain with the same value will not succeed. `400` would imply the\\nclient could fix syntax and retry without changing the value — which\\nis not the case here. `406 Not Acceptable` is closer but is reserved\\nfor content-type negotiation.\\n\\n## Why it happens\\n\\n- **Typo in the pin** — sent `2026-04-30` when the canonical version\\n is `2026-04-29`.\\n- **Pinned to a sunsetted version** — the date you pinned against\\n passed its 12-month `Sunset` window and was removed from the\\n supported set.\\n- **Pinned to a future version** — your client was upgraded with a\\n version pin that the production API hasn't shipped yet (canary\\n drift between client release and server deploy).\\n- **Multi-valued header confusion** — a load balancer or proxy\\n appended a second `X-Kash-Api-Version` value (`,`-joined) and the\\n runtime correctly refuses to silently pick one.\\n\\n## How to recover\\n\\nThe response body's `metadata.supported` field carries the full list\\nof accepted versions, in canonical-default-first order:\\n\\n```json\\n{\\n \\\"type\\\": \\\"https://docs.kash.bot/developer-docs/api-errors/API_VERSION_UNSUPPORTED\\\",\\n \\\"title\\\": \\\"API version unsupported\\\",\\n \\\"status\\\": 410,\\n \\\"code\\\": \\\"API_VERSION_UNSUPPORTED\\\",\\n \\\"detail\\\": \\\"Requested API version '2099-01-01' is not supported. Send no header to use the current default (2026-04-29), or pick a value from the 'supported' list.\\\",\\n \\\"instance\\\": \\\"/v1/markets\\\",\\n \\\"requestId\\\": \\\"01HQGY8K2N3X4Z5C6D7E8F9G0H\\\",\\n \\\"requested\\\": \\\"2099-01-01\\\",\\n \\\"supported\\\": [\\\"2026-04-29\\\"],\\n \\\"current\\\": \\\"2026-04-29\\\"\\n}\\n```\\n\\nPick a value from `supported` and resend the request. The simplest\\nrecovery is to **drop the header** entirely and let the runtime\\ndefault to `current` — that's the recommended consumer mode unless\\nyou have a specific reason to pin.\\n\\n## Migration policy\\n\\nWhen the API ships a new version, the previous version stays in\\n`SUPPORTED_PUBLIC_API_VERSIONS` for **12 months** (per AD-15 / RFC\\n8594). During that window, every response from the deprecated\\nversion carries `Sunset: <date>` and `Deprecation: true` headers so\\nyour monitoring can flag the impending expiry well before it hits.\\n\\nIf you're seeing this error on a date that is older than 12 months\\nsince its `Sunset` was advertised, that's working as intended — it's\\ntime to update the pin.\\n\\n## Best practice\\n\\nDon't pin if you don't have to. The default contract (no header)\\nruns against the current `PUBLIC_API_VERSION`, and we promise\\nadditive, non-breaking changes within a date version. Pin only when\\nyou're locking down a release for compliance or contract-test\\nreasons.\\n\\nIf you do pin, follow the registry: read\\n`https://api.kash.bot/v1/openapi.json` (or the live OpenAPI route)\\nand let your client library auto-select the highest version it\\nrecognises.\\n\\n## See also\\n\\n- `apps/public-api/src/plugins/api-version.ts` — the negotiation\\n plugin source.\\n- `packages/constants/src/public-api-version.ts` — the canonical\\n registry.\\n- `apps/public-api/openapi/index.json` — the snapshot index, listing\\n every published version.\\n- `docs/runbooks/hmac-algorithm-rotation.md` — example of a version\\n bump driven by a security event.\\n\",\n \"CLIENT_REQUEST_ID_CONFLICT\": \"# `CLIENT_REQUEST_ID_CONFLICT`\\n\\n**HTTP status:** 409 · **Title:** \\\"Client request id conflict\\\"\\n\\n## When it fires\\n\\nThe same `(user_id, clientRequestId)` body pair was used for an earlier trade with a **different body**. The trade row is unique on `(user_id, clientRequestId)` once you opt in.\\n\\n## Why it happens\\n\\n- Power-user mistake: `clientRequestId` is a body field with stricter conflict semantics than the HTTP `Idempotency-Key` header. Most callers should use the header; opt into `clientRequestId` only if you specifically want trade-row-scoped dedup.\\n- A bug regenerated the body but kept the `clientRequestId` constant.\\n\\n## How to fix\\n\\n- For most use cases, drop `clientRequestId` and use only `Idempotency-Key`. See `apps/public-api/README.md` § Idempotency.\\n- If you need `clientRequestId`'s row-scoped dedup, generate a fresh value per logical operation.\\n- The conflicting trade row is referenced in the `detail` field — fetch it via `GET /v1/trades/:id` to see what was previously submitted.\\n\\n## Related codes\\n\\n- [`IDEMPOTENCY_KEY_CONFLICT`](./IDEMPOTENCY_KEY_CONFLICT.md) — same idea, header-level\\n\",\n \"CONFIRMATION_EXPIRED\": \"# `CONFIRMATION_EXPIRED`\\n\\n**HTTP status:** 409 · **Title:** \\\"Confirmation expired\\\"\\n\\n## When it fires\\n\\nThe confirmation token is past its `confirmation_expires_at`. High-value trades have a short confirmation window (60 seconds by default; configurable per-tier).\\n\\n## Why it happens\\n\\n- A human-in-the-loop confirmation flow took longer than the window allows.\\n- A queue/worker latency between `POST /v1/trades` returning the token and the consumer calling confirm.\\n\\n## How to fix\\n\\n- Tighten the consumer's confirm call — ideally fire it immediately after receiving the token.\\n- For human-in-the-loop flows that need longer, request a per-key window extension (mm tier customers who pipeline trades through human review get longer windows).\\n- The trade is automatically cancelled when the window expires — re-create it to retry.\\n\\n## Related codes\\n\\n- [`TRADE_NOT_AWAITING_CONFIRMATION`](./TRADE_NOT_AWAITING_CONFIRMATION.md), [`CONFIRMATION_TOKEN_INVALID`](./CONFIRMATION_TOKEN_INVALID.md)\\n\",\n \"CONFIRMATION_TOKEN_INVALID\": \"# `CONFIRMATION_TOKEN_INVALID`\\n\\n**HTTP status:** 409 · **Title:** \\\"Confirmation token invalid\\\"\\n\\n## When it fires\\n\\nThe token you sent in `POST /v1/trades/:id/confirm` doesn't match the stored hash for that trade.\\n\\n## Why it happens\\n\\n- Wrong trade id — the token is one-time and tied to a specific trade.\\n- Token was truncated or modified in transit/storage.\\n- Replay against a different trade than the one that issued the token.\\n\\nThe token plaintext is **never persisted server-side** — only the HMAC. We compare your candidate via `timingSafeEqual` to prevent per-byte timing attacks.\\n\\n## How to fix\\n\\n- Re-confirm that the trade id in the URL matches the trade id from the create response.\\n- Capture the token verbatim from `confirmation.token` in the create response — the SDK does this automatically; raw HTTP callers must preserve case and length (43 chars, base64url).\\n- If you've lost the token (only shown once in the create response), the trade can't be confirmed — wait for it to auto-expire and re-create.\\n\\n## Related codes\\n\\n- [`CONFIRMATION_EXPIRED`](./CONFIRMATION_EXPIRED.md), [`CONFIRMATION_TOKEN_USED`](./CONFIRMATION_TOKEN_USED.md), [`TRADE_NOT_AWAITING_CONFIRMATION`](./TRADE_NOT_AWAITING_CONFIRMATION.md)\\n\",\n \"CONFIRMATION_TOKEN_USED\": \"# `CONFIRMATION_TOKEN_USED`\\n\\n**HTTP status:** 409 · **Title:** \\\"Confirmation token used\\\"\\n\\n## When it fires\\n\\nThe token has already been redeemed. Confirmation tokens are **one-time use** — the first successful confirm clears the stored hash so a replay can't re-fire the trade.\\n\\n## Why it happens\\n\\n- A retry layer that doesn't check the trade's status before re-confirming (most common).\\n- Two parallel confirmation attempts from the same consumer (race condition in the caller).\\n- A double-click in a human-in-the-loop UI.\\n\\n## How to fix\\n\\n- Check the trade's status via `GET /v1/trades/:id` — if it's anything past `pending_confirmation`, the confirm already succeeded.\\n- Make your retry loop idempotent: poll trade status first, only confirm if `status === 'pending_confirmation'`.\\n- For UI flows: disable the confirm button immediately on click to prevent double-submission.\\n\\n## Related codes\\n\\n- [`TRADE_NOT_AWAITING_CONFIRMATION`](./TRADE_NOT_AWAITING_CONFIRMATION.md) — same outcome via different state-check path\\n\",\n \"DEPENDENCY_UNAVAILABLE\": \"# `DEPENDENCY_UNAVAILABLE`\\n\\n**HTTP status:** 503 · **Title:** \\\"Service unavailable\\\" · **Retry-After:** 30s\\n\\n## When it fires\\n\\nA required external dependency (Postgres, Secrets Manager, Redis, blockchain RPC) is unreachable, and the route can't degrade further.\\n\\nDistinct from [`INTERNAL_ERROR`](./INTERNAL_ERROR.md) (which is \\\"we don't know what happened\\\") and [`ROUTE_DISABLED`](./ROUTE_DISABLED.md) (which is \\\"ops disabled this on purpose\\\").\\n\\n## Why it happens\\n\\n- Transient infrastructure blip (most common — clears in seconds).\\n- Sustained dependency outage under operator response.\\n- A rare cascade where one dependency degraded and another can't compensate.\\n\\n## How to fix\\n\\n- Honour `Retry-After: 30` and back off with jitter. Most occurrences resolve within one retry.\\n- If retries keep failing past 5 minutes, check the status page.\\n- The TS SDK handles this automatically (`KashServerError`, retried with backoff up to its retry budget).\\n\\n## Related codes\\n\\n- [`API_TRADE_PROCESSING_HALTED`](./API_TRADE_PROCESSING_HALTED.md) — ops-driven, not infra-driven\\n- [`REQUEST_TIMEOUT`](./REQUEST_TIMEOUT.md), [`INTERNAL_ERROR`](./INTERNAL_ERROR.md)\\n\",\n \"IDEMPOTENCY_KEY_CONFLICT\": \"# `IDEMPOTENCY_KEY_CONFLICT`\\n\\n**HTTP status:** 409 · **Title:** \\\"Idempotency key conflict\\\"\\n\\n## When it fires\\n\\nThe same `Idempotency-Key` was used for two requests with **different bodies**. The server refuses to either re-execute (would violate idempotency) or replay the cached response (would mislead the caller about which request \\\"won\\\").\\n\\n## Why it happens\\n\\n- Most common: a retry layer regenerated the body on each attempt instead of capturing it once and replaying.\\n- A bug in the caller that mutates the body in-place between the request being prepared and the request being sent.\\n- Two distinct logical operations accidentally sharing a key (e.g., a global key generator that didn't account for concurrency).\\n\\n## How to fix\\n\\n- Pin the request body before generating the idempotency key. Either:\\n - Capture body + key together in your retry wrapper and re-send the exact pair on each attempt.\\n - Generate a fresh key per logical operation (one trade = one key).\\n- For genuinely retryable bodies that legitimately change between attempts (e.g., updated timestamps), generate a fresh key per attempt — that's the contract.\\n\\n## Related codes\\n\\n- [`CLIENT_REQUEST_ID_CONFLICT`](./CLIENT_REQUEST_ID_CONFLICT.md) — analogous conflict, but on the body-level `clientRequestId` field rather than the HTTP header\\n- [`IDEMPOTENCY_KEY_EXPIRED`](./IDEMPOTENCY_KEY_EXPIRED.md) — key valid earlier, now past TTL\\n\",\n \"IDEMPOTENCY_KEY_EXPIRED\": \"# `IDEMPOTENCY_KEY_EXPIRED`\\n\\n**HTTP status:** 410 · **Title:** \\\"Idempotency key expired\\\"\\n\\n## When it fires\\n\\nThe `Idempotency-Key` you sent matches a row in the idempotency store but that row is past its 24-hour TTL.\\n\\n## Why it happens\\n\\n- A retry that took longer than 24 hours to fire (e.g., a job that stalled in a queue and retried days later).\\n- An offline-first client that buffered the request locally and only got online after the TTL.\\n\\nThe 410 (rather than re-executing or returning the cached response) is intentional: by 24 h, the original response is gone and the system gives you a clear \\\"this key is no longer valid\\\" signal so you can decide whether the operation is still desired.\\n\\n## How to fix\\n\\n- Generate a fresh `Idempotency-Key` for the retry.\\n- Before retrying, check whether the original operation actually completed — query `GET /v1/trades/:id` (using a `clientRequestId` you stored, if applicable) so you don't double-execute.\\n- For long-tail retries, prefer the body-level `clientRequestId` field over the header — it has the same conflict semantics but no TTL.\\n\\n## Related codes\\n\\n- [`IDEMPOTENCY_KEY_CONFLICT`](./IDEMPOTENCY_KEY_CONFLICT.md), [`CLIENT_REQUEST_ID_CONFLICT`](./CLIENT_REQUEST_ID_CONFLICT.md)\\n\",\n \"IDEMPOTENCY_KEY_FORMAT_INVALID\": \"# `IDEMPOTENCY_KEY_FORMAT_INVALID`\\n\\n**HTTP status:** 400 · **Title:** \\\"Idempotency key format invalid\\\"\\n\\n## When it fires\\n\\n`Idempotency-Key` header contains a character outside the allowed set: `[A-Za-z0-9_\\\\-:.]`.\\n\\n## Why it happens\\n\\n- The key contained whitespace, a slash, or a non-ASCII character.\\n- Control characters (newlines, NULs) sneaked in from a copy-paste.\\n- An emoji or Unicode separator accidentally landed in the key.\\n\\nThe strict allowlist exists because the value flows through structured logs, Redis keys, and PG rows — non-printable / control characters could poison log shippers or downstream systems that key on the value.\\n\\n## How to fix\\n\\n- Stick to UUIDs (`crypto.randomUUID()` in Node, `uuidgen` in shell) — they're always conforming.\\n- If you must derive the key from external input, sanitise: `key.replace(/[^A-Za-z0-9_\\\\-:.]/g, '')` then check it's still unique.\\n\\n## Related codes\\n\\n- [`IDEMPOTENCY_KEY_TOO_LONG`](./IDEMPOTENCY_KEY_TOO_LONG.md), [`IDEMPOTENCY_KEY_CONFLICT`](./IDEMPOTENCY_KEY_CONFLICT.md)\\n\",\n \"IDEMPOTENCY_KEY_TOO_LONG\": \"# `IDEMPOTENCY_KEY_TOO_LONG`\\n\\n**HTTP status:** 400 · **Title:** \\\"Idempotency key too long\\\"\\n\\n## When it fires\\n\\n`Idempotency-Key` header value exceeds the 255-character cap.\\n\\n## Why it happens\\n\\n- You concatenated several identifiers into the key (user id + market id + timestamp + nonce) and the result blew past 255 chars.\\n- A library generated an unusually long token (e.g., a JWT instead of a UUID).\\n\\n## How to fix\\n\\n- Use a UUID v4 (`uuidgen`, `crypto.randomUUID()`) or a ULID — both are 26–36 chars and unique enough, well under the 255 cap.\\n- If you need to embed semantic information, hash it: `sha256(your-blob).slice(0, 32)` instead of the raw concatenation.\\n- Acceptable character set: `[A-Za-z0-9_\\\\-:.]` — see [`IDEMPOTENCY_KEY_FORMAT_INVALID`](./IDEMPOTENCY_KEY_FORMAT_INVALID.md).\\n\\n## Related codes\\n\\n- [`IDEMPOTENCY_KEY_FORMAT_INVALID`](./IDEMPOTENCY_KEY_FORMAT_INVALID.md) — disallowed characters\\n- [`IDEMPOTENCY_KEY_CONFLICT`](./IDEMPOTENCY_KEY_CONFLICT.md) — same key, different body\\n\",\n \"INSUFFICIENT_BALANCE\": \"# `INSUFFICIENT_BALANCE`\\n\\n**HTTP status:** 409 · **Title:** \\\"Insufficient balance\\\"\\n\\n## When it fires\\n\\nThe actor's smart-account USDC balance is below the requested `amount`.\\n\\n## Why it happens\\n\\n- You haven't funded the account yet.\\n- A previous trade consumed more than expected (gas + slippage) and left a sub-threshold balance.\\n- The auto-funding pipeline is backed up — common during very high-throughput windows.\\n- Org account: trade is being charged to the user but the org policy expected the org to pay (or vice versa). Check `feePayerType`.\\n\\n## How to fix\\n\\n- Check the current balance via `GET /v1/portfolio` — `usdcBalance` field.\\n- For users: fund via the webapp's onramp flow (or transfer USDC into the smart account directly).\\n- For orgs: the org admin tops up the org wallet.\\n- For staging/sandbox: use the testnet faucet flow.\\n\\n## Related codes\\n\\n- [`SMART_ACCOUNT_NOT_PROVISIONED`](./SMART_ACCOUNT_NOT_PROVISIONED.md), [`SPENDING_LIMIT_EXCEEDED`](./SPENDING_LIMIT_EXCEEDED.md)\\n\",\n \"INSUFFICIENT_SCOPE\": \"# `INSUFFICIENT_SCOPE`\\n\\n**HTTP status:** 403 · **Title:** \\\"Insufficient scope\\\"\\n\\n## When it fires\\n\\nThe key authenticated successfully but lacks one of the scopes the route requires.\\n\\n## Why it happens\\n\\n- The key was issued with a narrower scope set than the route needs (e.g., a `markets:read` key calling `POST /v1/trades` which requires `trades:write`).\\n- A new endpoint was added that requires a scope your existing key doesn't carry.\\n\\n## How to fix\\n\\n- Look up the route's required scopes in `apps/public-api/README.md` → Authentication → Scopes table.\\n- Issue a new key with the needed scopes (or revoke + re-issue with a broader scope set).\\n- Principle of least privilege: don't add scopes you don't actually need — narrow keys reduce blast radius if leaked.\\n\\n| Scope | Routes |\\n| ----------------- | ----------------------------------------------------- |\\n| `markets:read` | `GET /v1/markets*`, `GET /v1/markets/:id/predictions` |\\n| `markets:quote` | `GET /v1/markets/:id/quote` |\\n| `trades:read` | `GET /v1/trades(/:id)` |\\n| `trades:write` | `POST /v1/trades`, `POST /v1/trades/:id/confirm` |\\n| `portfolio:read` | `GET /v1/portfolio*` |\\n| `webhooks:manage` | webhook URL/secret rotation, replay endpoint |\\n| `auth:manage` | self-service key CRUD |\\n\\n## Related codes\\n\\n- [`IP_NOT_ALLOWED`](./IP_NOT_ALLOWED.md) — also 403, but driven by IP allowlist rather than scope\\n\",\n \"INTERNAL_ERROR\": \"# `INTERNAL_ERROR`\\n\\n**HTTP status:** 500 · **Title:** \\\"Internal Server Error\\\"\\n\\n## When it fires\\n\\nThe error handler caught something it didn't recognise. The actual cause is logged + Sentry-captured server-side; nothing leaks to the caller.\\n\\nThis is the catch-all — any other code in this catalogue is a structured, anticipated failure. `INTERNAL_ERROR` means we hit something we hadn't categorised.\\n\\n## Why it happens\\n\\n- A genuinely unexpected condition (the most common reason this fires).\\n- A new code path that hasn't been instrumented with a typed error yet — please report it so we can add a proper code.\\n\\n## How to fix\\n\\n- **Always include `requestId` in any support ticket.** It's our handle into the trace, the logs, and the Sentry capture.\\n- Retry once — if it was a transient bug, you may get past it.\\n- If it's reproducible from a specific request, tell us the exact request shape (with secrets redacted) and we'll trace it.\\n- The TS SDK exposes `requestId` on `KashServerError`; raw HTTP callers should pull it from the `requestId` field on the problem response.\\n\\n## Related codes\\n\\nEvery other code in this catalogue is preferable — if you see `INTERNAL_ERROR` consistently for one operation, the right fix is for us to add a new typed code, not for you to work around it.\\n\",\n \"IP_NOT_ALLOWED\": \"# `IP_NOT_ALLOWED`\\n\\n**HTTP status:** 403 · **Title:** \\\"IP not allowed\\\"\\n\\n## When it fires\\n\\nThe key has a non-empty `ip_allowlist` configured AND the request's source IP isn't in it.\\n\\nEmpty allowlist (the default) means any IP is allowed — this code only fires when an allowlist is configured AND the caller's IP doesn't match.\\n\\n## Why it happens\\n\\n- The key is locked to a specific egress IP (common for MM and enterprise tier keys) and the call originated from elsewhere — your laptop, a CI runner, a proxy with a different egress.\\n- The egress IP changed (cloud provider rotated NAT gateway, your home ISP's dynamic IP rolled).\\n\\n## How to fix\\n\\n- Find the request's IP in the `requestId`'s Loki logs — search `requestId=\\\"<value>\\\"`, the structured log carries the source IP.\\n- If the new IP is legitimate, add it to the key's allowlist via Settings → API Keys → Edit (or `kash-admin api-keys` ops command).\\n- If it's not, this code is a successful detection of an exfiltration attempt — investigate.\\n\\n## Related codes\\n\\n- [`INSUFFICIENT_SCOPE`](./INSUFFICIENT_SCOPE.md) — also 403, scope rather than IP\\n\",\n \"MARKET_NOT_FOUND\": \"# `MARKET_NOT_FOUND`\\n\\n**HTTP status:** 404 · **Title:** \\\"Market not found\\\"\\n\\n## When it fires\\n\\nThe `marketId` (UUID) you passed doesn't match any market.\\n\\n## Why it happens\\n\\n- Typo in the market id.\\n- Cross-environment confusion: a staging market id sent to production, or vice versa. Markets do not exist across environments.\\n- The market was never created — you may have a placeholder id from documentation rather than a real one.\\n\\n## How to fix\\n\\n- Look up real market ids via `GET /v1/markets?status=active` (filterable by status).\\n- Cache the id once you've found it; markets are immutable in their identity.\\n- If you suspect the market should exist (e.g., you saw it in the webapp), confirm you're hitting the same environment.\\n\\n## Related codes\\n\\n- [`MARKET_NOT_TRADEABLE`](./MARKET_NOT_TRADEABLE.md) — market exists but is FROZEN/RESOLVED\\n\",\n \"MARKET_NOT_TRADEABLE\": \"# `MARKET_NOT_TRADEABLE`\\n\\n**HTTP status:** 409 · **Title:** \\\"Market not tradeable\\\"\\n\\n## When it fires\\n\\nThe market exists but is in a state that doesn't accept trades — typically `FROZEN` (admin paused trading) or `RESOLVED` (outcome decided, only redemptions allowed).\\n\\n## Why it happens\\n\\n- Market reached its `resolve_time` and froze automatically.\\n- An admin froze the market manually (e.g., pending an oracle dispute).\\n- The market was resolved between your quote call and your trade call.\\n\\n## How to fix\\n\\n- Check the market's current `status` via `GET /v1/markets/:id` before retrying.\\n- If the market was just resolved, your existing positions are still redeemable (handled automatically by the payout pipeline) — you don't need to do anything.\\n- For freeze-then-resume scenarios, retry once the market reopens; subscribe to the `market.resumed` webhook (when streaming lands) to know exactly when.\\n\\n## Related codes\\n\\n- [`MARKET_NOT_FOUND`](./MARKET_NOT_FOUND.md), [`OUTCOME_INDEX_INVALID`](./OUTCOME_INDEX_INVALID.md)\\n\",\n \"OUTCOME_INDEX_INVALID\": \"# `OUTCOME_INDEX_INVALID`\\n\\n**HTTP status:** 400 · **Title:** \\\"Outcome index invalid\\\"\\n\\n## When it fires\\n\\n`outcomeIndex` is greater than or equal to the market's outcome count, or negative.\\n\\n## Why it happens\\n\\n- You hard-coded `outcomeIndex: 1` (assuming a binary market) and pointed at a multi-outcome market.\\n- Off-by-one: the field is **zero-indexed** — first outcome is `0`, not `1`.\\n- A bug computed the index from a label without bounds-checking.\\n\\n## How to fix\\n\\n- Look up the market via `GET /v1/markets/:id` and check `outcomes.length` — valid range is `[0, length - 1]`.\\n- Map outcome labels to indices once when you fetch the market, then use the index throughout your code.\\n\\n## Related codes\\n\\n- [`MARKET_NOT_FOUND`](./MARKET_NOT_FOUND.md), [`MARKET_NOT_TRADEABLE`](./MARKET_NOT_TRADEABLE.md), [`VALIDATION_FAILED`](./VALIDATION_FAILED.md)\\n\",\n \"RATE_LIMIT_EXCEEDED\": \"# `RATE_LIMIT_EXCEEDED`\\n\\n**HTTP status:** 429 · **Title:** \\\"Too Many Requests\\\"\\n\\n## When it fires\\n\\nPer-user (authenticated) or per-IP (anonymous reads) rate limit was exceeded. Limits are enforced as a sliding window in Redis.\\n\\nFor authenticated requests, the limit is **tier-differentiated** — 60 req/min on `free`, 300 req/min on `developer`, custom (admin-set) on `enterprise` and `mm`. See [`docs/api-tiers.md`](../api-tiers.md) for the full matrix.\\n\\n## Response headers\\n\\nEvery 429 response carries:\\n\\n- `Retry-After: <seconds>` — wait at least this long before the next request\\n- `X-RateLimit-Limit: <n>` — the limit that applied\\n- `X-RateLimit-Remaining: 0` — confirms you're capped\\n- `X-RateLimit-Reset: <unix-timestamp>` — when the window resets\\n\\n## Why it happens\\n\\n- Burst traffic spike (e.g., a polling loop without backoff).\\n- A retry storm — every consumer retried at the same instant after a transient failure.\\n- Genuine sustained traffic above your tier's quota.\\n\\n## How to fix\\n\\n- Honour `Retry-After`. The TS SDK does this automatically (`KashRateLimitError.retryAfterSeconds`).\\n- Add jitter to retry timing so multiple consumers don't synchronise.\\n- For polling, switch to webhooks — every poll is a wasted request.\\n- If you consistently bump against the limit during normal operation, upgrade your tier — see [`docs/api-tiers.md`](../api-tiers.md) for the upgrade paths. The 60 → 300 req/min jump from `free` → `developer` is 5×, and `enterprise`/`mm` have no application-level cap.\\n\\n## Related codes\\n\\n- [`RATE_LIMIT_UNAVAILABLE`](./RATE_LIMIT_UNAVAILABLE.md) — 503; the rate-limit subsystem itself is temporarily unavailable. Distinct from `EXCEEDED`: `UNAVAILABLE` means we couldn't check your quota; `EXCEEDED` means we checked and you're over.\\n- [`WEBHOOK_REPLAY_LIMIT_REACHED`](./WEBHOOK_REPLAY_LIMIT_REACHED.md) — also 429, but specific to the webhook replay endpoint's amplification cap\\n\",\n \"RATE_LIMIT_UNAVAILABLE\": \"# `RATE_LIMIT_UNAVAILABLE`\\n\\n**HTTP status:** 503 · **Title:** \\\"Rate limit subsystem unavailable\\\" · **Retry-After:** 1s\\n\\n## When it fires\\n\\nThe rate-limit subsystem (Redis-backed token bucket / sliding window) is temporarily unavailable, and the per-task circuit breaker is still in its CLOSED state — i.e., this is a transient Redis blip, not a sustained outage.\\n\\nThe API fails CLOSED here because your rate limit IS your per-tier quota (a paid product feature). Serving traffic without enforcing the cap during a blip would silently leak quota to free-tier callers. The safe-for-business default is to refuse the request, surface a typed retryable error, and let your client retry.\\n\\nThis is the **transient blip** counterpart to the sustained-outage [`DEPENDENCY_UNAVAILABLE`](./DEPENDENCY_UNAVAILABLE.md) — same family, different policy: a transient blip in the limiter is fail-CLOSED (we know the limit must apply but can't check), while a sustained outage causes the circuit breaker to open and the API to fail-OPEN (serve traffic without quota enforcement, paged to ops).\\n\\n## Why it happens\\n\\n- A momentary ElastiCache Redis network blip — typically clears in `<100ms`.\\n- Pool acquisition contention under burst — a Lua call queued for a free connection past the per-call timeout.\\n- A momentary failover during a Redis cluster maintenance window.\\n\\nIf Redis stays unhealthy past the circuit breaker's failure threshold (10 consecutive failures), the breaker OPENs and requests start passing through fail-OPEN instead of returning 503. Ops gets paged on `kash_public_api_rate_limit_redis_circuit_state == 2`.\\n\\n## How to fix\\n\\n- **Honour `Retry-After: 1`.** The TS SDK's default retry policy already does this — it auto-retries 5xx responses with exponential backoff, so most blips are invisible to your application code. If you've disabled SDK retries (`maxRetries: 0`), wire your own backoff loop.\\n- **Don't treat this as quota exhaustion.** Distinct from [`RATE_LIMIT_EXCEEDED`](./RATE_LIMIT_EXCEEDED.md) (429): `EXCEEDED` is \\\"you're over your tier's cap\\\"; `UNAVAILABLE` is \\\"we couldn't check, so we won't risk leaking your cap.\\\" Your dashboards / billing UI should NOT surface `RATE_LIMIT_UNAVAILABLE` as a quota event.\\n- If you see a sustained rate of these in your client logs (>1/min over several minutes), that's the threshold where Kash ops should already be paged — file a bug at https://github.com/KashDAO/sdk-typescript/issues with the requestId if you want a status check.\\n\\n## Response headers\\n\\n- `Retry-After: 1` — Stripe-style short retry; SDK respects it automatically.\\n- `X-API-Version`, `X-Request-Id` — standard cross-cutting headers.\\n- The `X-RateLimit-*` family is NOT emitted on a 503 (we don't have a quota answer to attach).\\n\\n## Related codes\\n\\n- [`RATE_LIMIT_EXCEEDED`](./RATE_LIMIT_EXCEEDED.md) — 429, you went over your quota.\\n- [`DEPENDENCY_UNAVAILABLE`](./DEPENDENCY_UNAVAILABLE.md) — 503, infrastructure-level dependency outage outside the rate-limit path.\\n\",\n \"REQUEST_SIGNATURE_INVALID\": \"# `REQUEST_SIGNATURE_INVALID`\\n\\n**HTTP status:** 401 · **Title:** \\\"Request signature invalid\\\"\\n\\n## When it fires\\n\\n`X-Kash-Signature` was present but did not verify against the API key plaintext over the canonical signing input `${ts}.${method}.${path}.${body}`.\\n\\nSigning is **opt-in**: requests without `X-Kash-Signature` skip this check entirely. Once present, it MUST verify.\\n\\n## Why it happens\\n\\n- The body was modified in transit (a transparent proxy that re-encoded JSON, an HTTP client that renormalised whitespace).\\n- The timestamp is outside the ±5 min tolerance (clock skew).\\n- The signature was computed over the wrong input — common mistake: signing the URL instead of the path-only, or omitting the leading slash on `path`.\\n- The wrong secret was used (e.g., the `webhook_secret` instead of the API key plaintext).\\n\\n## How to fix\\n\\n- Canonical input format: `${unixMillis}.${UPPERCASE_METHOD}.${pathWithLeadingSlash}.${rawBody}` (raw body bytes, not re-serialised JSON).\\n- Key the HMAC with the API key plaintext (the same value as `X-API-Key`).\\n- Header format: `X-Kash-Signature: t=<unixMillis>,v1=<hexHmacSha256>`.\\n- Sync your clock — NTP. If you're consistently 6+ minutes off, fix the host clock.\\n- Check the `signatureReason` extension field on the problem response — it pinpoints which check failed (`stale`, `mismatch`, `malformed`).\\n\\nSee `apps/public-api/README.md` § Optional request body signing for the full reference.\\n\\n## Related codes\\n\\n- [`API_KEY_MISSING`](./API_KEY_MISSING.md) / [`API_KEY_INVALID`](./API_KEY_INVALID.md) — earlier failure points\\n\",\n \"REQUEST_TIMEOUT\": \"# `REQUEST_TIMEOUT`\\n\\n**HTTP status:** 504 · **Title:** \\\"Gateway timeout\\\" · **Retry-After:** 5s\\n\\n## When it fires\\n\\nThe per-request server timeout fired (default 30 s). Bounded by `bodyLimit` + Fastify timeout config to keep slow upstreams from blocking healthy traffic.\\n\\n## Why it happens\\n\\n- An unusually slow downstream call (Postgres lock contention, RPC latency spike, etc.).\\n- A request that does too much work in one call — most reads complete in <100 ms.\\n- Network path degradation between you and our edge (rare but possible).\\n\\n## How to fix\\n\\n- Retry once with backoff. Most timeouts are transient.\\n- If you're consistently timing out on the same endpoint, narrow the request — pass `limit` parameters, fetch one resource at a time.\\n- For long-running operations, use webhooks instead of waiting on the response.\\n\\n## Related codes\\n\\n- [`DEPENDENCY_UNAVAILABLE`](./DEPENDENCY_UNAVAILABLE.md), [`INTERNAL_ERROR`](./INTERNAL_ERROR.md)\\n\",\n \"RESOURCE_NOT_FOUND\": \"# `RESOURCE_NOT_FOUND`\\n\\n**HTTP status:** 404 · **Title:** \\\"Not Found\\\"\\n\\n## When it fires\\n\\nA request for a specific resource (trade, key, webhook event, etc.) didn't find a matching row that the caller is authorised to see.\\n\\nThis is the generic catch-all 404. Specific resource types may have their own dedicated codes (e.g., [`MARKET_NOT_FOUND`](./MARKET_NOT_FOUND.md)) where there's value in distinguishing the resource type to the caller.\\n\\n## Why it happens\\n\\n- The id is wrong (typo, cross-environment confusion).\\n- The resource exists but belongs to a different user — we return 404 (not 403) deliberately, so attackers can't probe for the existence of resources they don't own.\\n- The resource was deleted.\\n\\n## How to fix\\n\\n- Re-check the id (capitalisation, hyphens, environment).\\n- If the resource should exist but you can't see it, confirm you're authenticated as the owner.\\n- For webhook events: events are retained for 90 days; older events return 404.\\n\\n## Related codes\\n\\n- [`MARKET_NOT_FOUND`](./MARKET_NOT_FOUND.md) — specific case for markets\\n\",\n \"ROUTE_DISABLED\": \"# `ROUTE_DISABLED`\\n\\n**HTTP status:** 503 · **Title:** \\\"Route disabled\\\" · **Retry-After:** 60s\\n\\n## When it fires\\n\\nA single route is disabled by ops via a per-route kill switch. Distinct from the coarse [`API_TRADE_PROCESSING_HALTED`](./API_TRADE_PROCESSING_HALTED.md) so SDK consumers can branch on \\\"my entire trading capability is offline\\\" vs \\\"just one endpoint.\\\"\\n\\nThe Problem detail's `extensions.flag` field carries the kill-switch name (e.g., `\\\"api-quotes-read\\\"`) so you can tell exactly which route is gated.\\n\\n## Why it happens\\n\\n- Targeted rollback after a route-specific bug shipped.\\n- Pre-deploy lockdown of one endpoint while the rest of the API stays live.\\n- Capacity-driven shedding (rare — usually we'd raise rate limits first).\\n\\n## How to fix\\n\\n- Honour `Retry-After`. The flag is binary; polling won't help.\\n- Read the `extensions.flag` field — if it's an endpoint you don't actually need, ignore it; other endpoints are fine.\\n- For mission-critical endpoints, contact support to understand the ETA.\\n\\n## Related codes\\n\\n- [`API_TRADE_PROCESSING_HALTED`](./API_TRADE_PROCESSING_HALTED.md) — coarser kill switch covering all trade writes\\n- [`DEPENDENCY_UNAVAILABLE`](./DEPENDENCY_UNAVAILABLE.md) — distinct: this is \\\"ops chose to disable\\\", that's \\\"infra is broken\\\"\\n\",\n \"SMART_ACCOUNT_NOT_PROVISIONED\": \"# `SMART_ACCOUNT_NOT_PROVISIONED`\\n\\n**HTTP status:** 409 · **Title:** \\\"Smart account not provisioned\\\"\\n\\n## When it fires\\n\\nThe actor (user or organization) doesn't have a smart account row yet, so trades can't execute on-chain.\\n\\n## Why it happens\\n\\n- New account that hasn't completed the wallet-creation step in the webapp.\\n- An organization that's enabled the API but hasn't provisioned its own org-level smart account.\\n- The smart-account worker is backlogged — provisioning is async.\\n\\n## How to fix\\n\\n- For users: complete the wallet setup flow in the webapp (Settings → Wallet). Smart account provisioning is async — typically a few seconds.\\n- For orgs: an admin needs to provision the org smart account via the org settings page.\\n- If you provisioned recently and still see this error, retry after 30 s. If it persists past a minute, contact support with your `requestId`.\\n\\n## Related codes\\n\\n- [`WALLET_DELEGATION_NOT_ENABLED`](./WALLET_DELEGATION_NOT_ENABLED.md) — smart account exists but Privy delegation is off\\n- [`INSUFFICIENT_BALANCE`](./INSUFFICIENT_BALANCE.md) — smart account provisioned but no USDC\\n\",\n \"SPENDING_LIMIT_EXCEEDED\": \"# `SPENDING_LIMIT_EXCEEDED`\\n\\n**HTTP status:** 409 · **Title:** \\\"Spending limit exceeded\\\"\\n\\n## When it fires\\n\\nThe trade would exceed one of the API key's spending caps:\\n\\n- `per_trade_limit_usdc` — single-trade maximum\\n- `daily_spend_limit_usdc` — rolling 24-hour cumulative maximum across all trades\\n\\nThe `detail` field specifies which cap fired and by how much.\\n\\n## Why it happens\\n\\n- A bot iteration that computed a larger order than expected (e.g., signal scaling factor was off).\\n- Cumulative drift over a busy day finally pushed a moderate trade over the daily cap.\\n- The cap was lowered (by you or an admin) since you last designed your sizing logic.\\n\\n## How to fix\\n\\n- Inspect your key's caps in Settings → API Keys → Edit.\\n- For per-trade overruns: split the trade into smaller chunks under the cap.\\n- For daily overruns: wait for the rolling window to clear, or upgrade your tier (see \\\"How to raise the cap\\\" below).\\n- Programmatically: every key's caps are returned in the issuance response — cache them so your client knows the headroom.\\n\\n## How to raise the cap\\n\\nThe cap is set by your API key's tier. See [`docs/api-tiers.md`](../api-tiers.md) for the full tier matrix and rationale, then:\\n\\n- **`free` → `developer`** (10× headroom — $1k → $10k daily, $500 → $2.5k per-trade): email [support@kash.bot](mailto:support@kash.bot) for early access. Self-serve via Stripe is planned ([`docs/todo/public-surface/PUBLIC_API_TIER_BILLING.md`](../todo/public-surface/PUBLIC_API_TIER_BILLING.md)).\\n- **`developer` → `enterprise`** ($100k daily, $25k per-trade, custom rate limit): [contact sales](mailto:sales@kash.bot) — pricing is contractual.\\n- **MM-tier counterparty terms** ($1M daily, $50k per-trade): [contact partnerships](mailto:partnerships@kash.bot) — KYB and ToS attestation required; this is a relationship, not a price tier.\\n\\nThe caps are not punitive — they exist for blast-radius and AMM-stability reasons documented in [`docs/api-tiers.md`](../api-tiers.md). When you outgrow your tier, the cap is the signal to upgrade, not a problem to work around.\\n\\n## Related codes\\n\\n- [`AMOUNT_TOO_LARGE`](./AMOUNT_TOO_LARGE.md) — platform-wide cap, separate from your key's caps\\n- [`INSUFFICIENT_BALANCE`](./INSUFFICIENT_BALANCE.md) — wallet balance too low (different failure surface)\\n\",\n \"TRADE_NOT_AWAITING_CONFIRMATION\": \"# `TRADE_NOT_AWAITING_CONFIRMATION`\\n\\n**HTTP status:** 409 · **Title:** \\\"Trade not awaiting confirmation\\\"\\n\\n## When it fires\\n\\n`POST /v1/trades/:id/confirm` was called for a trade that's not in `pending_confirmation` status.\\n\\n## Why it happens\\n\\n- The trade was already confirmed (you'll see this if you accidentally call confirm twice) — see also [`CONFIRMATION_TOKEN_USED`](./CONFIRMATION_TOKEN_USED.md).\\n- The trade was below your tier's high-value threshold and never required confirmation in the first place.\\n- The trade has progressed past confirmation into `pending` / `executing` / a terminal state.\\n- The confirmation window expired and the trade was auto-cancelled — see [`CONFIRMATION_EXPIRED`](./CONFIRMATION_EXPIRED.md).\\n\\n## How to fix\\n\\n- Check the trade's current `status` via `GET /v1/trades/:id`. The lifecycle is: `pending_confirmation` → `pending` → `executing` → `completed`/`failed`.\\n- If the trade is `completed`, there's nothing more to do.\\n- If the trade is `cancelled`, re-create it and confirm within the new window.\\n\\n## Related codes\\n\\n- [`CONFIRMATION_EXPIRED`](./CONFIRMATION_EXPIRED.md), [`CONFIRMATION_TOKEN_INVALID`](./CONFIRMATION_TOKEN_INVALID.md), [`CONFIRMATION_TOKEN_USED`](./CONFIRMATION_TOKEN_USED.md)\\n\",\n \"VALIDATION_FAILED\": \"# `VALIDATION_FAILED`\\n\\n**HTTP status:** 400 · **Title:** \\\"Validation failed\\\"\\n\\n## When it fires\\n\\nThe request body failed Zod schema parse. One or more fields are missing, malformed, or out of range.\\n\\n## Why it happens\\n\\n- Required field is missing or `null`.\\n- Field has the wrong type (e.g., `amount` sent as a number instead of a string — we use string for arbitrary-precision USDC amounts).\\n- Field violates a constraint (UUID format, enum value, min/max length).\\n- An unknown extra field was sent — we accept extras (`.passthrough()`) so this is rarely the cause; if it is, you'll see it called out in `detail`.\\n\\n## How to fix\\n\\n- The `detail` field carries the path of the first offending field (e.g., `body.outcomeIndex must be a non-negative integer`).\\n- Cross-reference with the OpenAPI spec at `https://api.kash.bot/v1/openapi.json` — every endpoint's request body is fully typed there.\\n- If you're using the TS SDK, you'd have caught this client-side via `KashValidationError` before the request went out.\\n\\n## Example\\n\\n```json\\n{\\n \\\"type\\\": \\\"https://docs.kash.bot/developer-docs/api-errors/VALIDATION_FAILED\\\",\\n \\\"title\\\": \\\"Validation failed\\\",\\n \\\"status\\\": 400,\\n \\\"code\\\": \\\"VALIDATION_FAILED\\\",\\n \\\"detail\\\": \\\"body.amount must be a string matching ^[0-9]+(\\\\\\\\.[0-9]+)?$\\\",\\n \\\"instance\\\": \\\"/v1/trades\\\",\\n \\\"requestId\\\": \\\"01HX-...\\\"\\n}\\n```\\n\\n## Related codes\\n\\n- [`AMOUNT_TOO_LARGE`](./AMOUNT_TOO_LARGE.md) — specific case for `amount` exceeding the per-trade cap\\n- [`OUTCOME_INDEX_INVALID`](./OUTCOME_INDEX_INVALID.md) — specific case for invalid `outcomeIndex`\\n\",\n \"WALLET_DELEGATION_NOT_ENABLED\": \"# `WALLET_DELEGATION_NOT_ENABLED`\\n\\n**HTTP status:** 409 · **Title:** \\\"Wallet delegation not enabled\\\"\\n\\n## When it fires\\n\\nA smart account exists for the actor, but Privy server-side delegation is disabled. The platform can't sign user-operations on behalf of the user, so trades can't execute.\\n\\nWe surface this at the API layer as a preflight check rather than failing at execution — better UX for the consumer.\\n\\n## Why it happens\\n\\n- The user revoked delegation in Privy after onboarding.\\n- A Privy app config change disabled delegation for a class of users.\\n- An incomplete onboarding flow that skipped the delegation grant step.\\n\\n## How to fix\\n\\n- The user must re-grant delegation via the webapp (Settings → Wallet → Re-enable). One-click; uses the existing Privy session.\\n- For orgs, the org admin re-grants on behalf of the org wallet.\\n- If the issue is platform-wide (multiple users), check the Privy app config or the status page.\\n\\n## Related codes\\n\\n- [`SMART_ACCOUNT_NOT_PROVISIONED`](./SMART_ACCOUNT_NOT_PROVISIONED.md) — earlier failure point\\n\",\n \"WEBHOOK_REPLAY_LIMIT_REACHED\": \"# `WEBHOOK_REPLAY_LIMIT_REACHED`\\n\\n**HTTP status:** 429 · **Title:** \\\"Replay limit reached\\\"\\n\\n## When it fires\\n\\n`POST /v1/webhooks/events/{id}/redeliver` was called for an event that has already been replayed up to its cap (default 5).\\n\\n## Why it happens\\n\\n- A bug in the consumer kept calling the redeliver endpoint in a loop instead of fixing the underlying delivery problem.\\n- An automation re-replayed without checking past attempts.\\n- A genuinely persistent need to replay an event many times — uncommon and usually signals an upstream issue.\\n\\nThe cap exists to stop a compromised key from looping the replay endpoint to flood its own customer endpoint or our delivery worker.\\n\\n## How to fix\\n\\n- Stop calling the redeliver endpoint for this event id. The cap is per-event, so other events still replay normally.\\n- Fix the underlying delivery failure first — check the event's delivery status via `GET /v1/trades/:id` (the `webhookDelivery` field) or via `kash-admin webhooks trace --event-id <id>` (operator command).\\n- If you legitimately need more replays for one event (e.g., recovering from a long endpoint outage), contact support — we can clear the counter manually.\\n\\n## Related codes\\n\\n- [`RATE_LIMIT_EXCEEDED`](./RATE_LIMIT_EXCEEDED.md) — general per-key rate limit\\n\",\n \"WEBHOOK_SECRET_ROTATION_COOLDOWN\": \"# `WEBHOOK_SECRET_ROTATION_COOLDOWN`\\n\\n**HTTP status:** 429 · **Title:** \\\"Rotation cooldown active\\\"\\n\\n## When it fires\\n\\n`POST /v1/auth/api-keys/me/webhook-secret/rotate` was called within the 60-second cooldown that follows a previous successful rotation.\\n\\n## Why the cooldown exists\\n\\nThis is the most important error to read carefully — the cooldown is not a rate-limit, it is a **rollback-safety** guard.\\n\\nEvery successful rotation moves the previous secret into `webhook_secret_previous` so operations can roll back within 7 days if the rotation breaks the customer's verifier. If you rotate twice in quick succession, the second rotation overwrites that rollback slot with the FIRST rotation's brand-new secret — a secret you may have never actually received in your response (e.g., the first POST timed out, your HTTP client retried, and the new plaintext from the first attempt was lost in flight). Rolling back later would restore a secret no verifier was ever configured for.\\n\\nThe cooldown forces this dangerous case into a visible 429 instead of silently corrupting the rollback guarantee.\\n\\n## How to fix\\n\\n- **If you successfully captured the new secret from the previous rotation:** wait for the `Retry-After` window to expire and call again. The cooldown is per-key, so other keys are unaffected.\\n- **If you did NOT capture the new secret from the previous rotation** (network timeout, lost response, dropped connection): **do not retry**. Contact support so we can rotate via an operator path that preserves the rollback chain. Re-rotating yourself would replace `webhook_secret_previous` with the secret you never received, breaking the only recovery path.\\n\\n## Response headers\\n\\n- `Retry-After: <seconds>` — how long to wait before re-attempting (computed from the prior rotation's timestamp).\\n\\n## Related codes\\n\\n- [`RATE_LIMIT_EXCEEDED`](./RATE_LIMIT_EXCEEDED.md) — generic per-user/per-IP rate limit (volume-based, not safety-based)\\n- [`DEPENDENCY_UNAVAILABLE`](./DEPENDENCY_UNAVAILABLE.md) — Postgres or downstream temporarily unreachable; safe to retry\\n\",\n});\n\nexport type ApiErrorCode = keyof typeof API_ERROR_DOCS;\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/markets/index.ts","../src/commands/markets/get.ts","../src/commands/markets/list.ts","../src/commands/markets/predictions.ts"],"sourcesContent":["/**\n * `kash markets` — read-only market queries.\n *\n * Subcommands: `list`, `get`, `predictions`. All require an API key\n * with `markets:read` scope (granted by default on every tier). Quotes\n * are a separate command group (`kash quote buy|sell`) under the\n * `markets:quote` scope, split so customers can throttle RPC-heavy\n * quote traffic independently from cheap market reads.\n */\n\nimport { Command } from 'commander';\n\nimport { getMarketCommand } from './get.js';\nimport { listMarketsCommand } from './list.js';\nimport { predictionsCommand } from './predictions.js';\n\nexport const marketsCommand = new Command('markets')\n .description('List and inspect prediction markets.')\n .addCommand(listMarketsCommand)\n .addCommand(getMarketCommand)\n .addCommand(predictionsCommand);\n","/**\n * `kash markets get <id>` — fetch a single market.\n */\n\nimport { Command } from 'commander';\n\nimport { toCliError } from '../../errors.js';\nimport { buildClient } from '../../utils/client.js';\nimport {\n colorStatus,\n createTable,\n formatAddress,\n formatDate,\n formatProbability,\n} from '../../utils/formatting.js';\nimport { readGlobals } from '../../utils/global-options.js';\nimport { print, printJson, style } from '../../utils/output.js';\n\nexport const getMarketCommand = new Command('get')\n .description('Fetch a single market by id.')\n .argument('<id>', 'market UUID')\n .addHelpText(\n 'after',\n `\nExamples:\n $ kash markets get 9f0b...\n $ kash markets get 9f0b... --json | jq '.outcomes'\n $ kash markets get 9f0b... --json --quiet | jq -r '.outcomes[].label' # agent shape\n $ kash markets get 9f0b... --fields id,status,resolvedOutcomeIndex --json --quiet\n`\n )\n .action(async (id: string, _opts, cmd: Command) => {\n const globals = readGlobals(cmd);\n let market;\n try {\n const { client } = await buildClient({ requireAuth: true, globals });\n market = await client.markets.get(id);\n } catch (cause) {\n throw toCliError(cause);\n }\n\n if (globals.json) {\n printJson(market);\n return;\n }\n\n print('');\n print(`${style.bold(market.title ?? '(untitled)')}`);\n print(` ${style.dim('ID ')} ${market.id}`);\n print(` ${style.dim('Contract ')} ${formatAddress(market.contractAddress)}`);\n print(` ${style.dim('Chain ')} ${String(market.chainId)}`);\n print(` ${style.dim('Status ')} ${colorStatus(market.status ?? 'UNKNOWN')}`);\n print(` ${style.dim('Outcomes ')} ${String(market.outcomeCount)}`);\n print(` ${style.dim('Created ')} ${formatDate(market.createdAt)}`);\n if (market.expiresAt) {\n print(` ${style.dim('Expires ')} ${formatDate(market.expiresAt)}`);\n }\n if (market.resolvedAt) {\n print(` ${style.dim('Resolved ')} ${formatDate(market.resolvedAt)}`);\n }\n if (market.description) {\n print('');\n print(market.description);\n }\n\n print('');\n const table = createTable(['#', 'Outcome', 'Probability']);\n for (const outcome of market.outcomes) {\n table.push([String(outcome.index), outcome.label, formatProbability(outcome.probability)]);\n }\n print(table.toString());\n });\n","/**\n * `kash markets list` — page through markets.\n *\n * Default human output is a table of the first page. `--all` walks\n * the SDK's auto-paginator and prints every market — useful for\n * exporting to JSON. Status is uppercased before sending so users\n * don't have to remember the canonical casing.\n */\n\nimport { Command } from 'commander';\n\nimport { CliValidationError, toCliError } from '../../errors.js';\nimport { buildClient } from '../../utils/client.js';\nimport {\n colorStatus,\n createTable,\n formatProbability,\n shortId,\n truncate,\n} from '../../utils/formatting.js';\nimport { parsePositiveInt, readGlobals } from '../../utils/global-options.js';\nimport { log, print, printJson, writeNdjson } from '../../utils/output.js';\n\nimport type { MarketResource, MarketStatus } from '@kashdao/sdk';\n\ntype ListOptions = {\n status?: string;\n limit?: string;\n cursor?: string;\n all?: boolean;\n ndjson?: boolean;\n};\n\nconst ALLOWED_STATUSES: ReadonlySet<MarketStatus> = new Set(['UNSEEDED', 'ACTIVE', 'RESOLVED']);\n\nexport const listMarketsCommand = new Command('list')\n .description('List markets.')\n .option('-s, --status <status>', 'filter by status (UNSEEDED | ACTIVE | RESOLVED)')\n .option('-l, --limit <n>', 'page size (1-100)', '20')\n .option('-c, --cursor <cursor>', 'pagination cursor returned by a previous call')\n .option('-a, --all', 'walk every page (use with --json for export)')\n .option(\n '--ndjson',\n 'stream results as newline-delimited JSON (one record per line); implies --all'\n )\n .addHelpText(\n 'after',\n `\nExamples:\n $ kash markets list --status ACTIVE\n $ kash markets list --json --quiet | jq '.data[].id'\n $ kash markets list --ndjson | while read -r line; do echo \"$line\" | jq -r .id; done\n $ kash markets list --all --json --quiet > markets.json\n\nNotes:\n --ndjson emits one JSON record per line. Consumers must read\n line-by-line (\\`while read -r\\`, \\`jq -c\\`, \\`split('\\n')\\`) — DO NOT\n buffer-then-parse, as the stream may run for arbitrarily many pages.\n`\n )\n .action(async (options: ListOptions, cmd: Command) => {\n const globals = readGlobals(cmd);\n\n const limit = options.limit === undefined ? 20 : parsePositiveInt(options.limit, 'limit');\n if (limit < 1 || limit > 100) {\n throw new CliValidationError('--limit must be between 1 and 100.', undefined, 'limit');\n }\n\n const status = options.status ? normaliseStatus(options.status) : undefined;\n\n let response;\n try {\n const { client } = await buildClient({ requireAuth: true, globals });\n response = await client.markets.list({\n limit,\n ...(status === undefined ? {} : { status }),\n ...(options.cursor === undefined ? {} : { cursor: options.cursor }),\n });\n\n if (options.ndjson) {\n // Stream every record as one line of NDJSON to stdout. Avoids\n // buffering the full result set — the agent reads as we go.\n for await (const market of response) {\n writeNdjson(market);\n }\n return;\n }\n\n if (options.all) {\n const collected: MarketResource[] = [];\n for await (const market of response) collected.push(market);\n if (globals.json) {\n // Canonical list-envelope shape: `{data, pagination, count}`.\n // After walking every page, `pagination.hasMore` is false\n // and `cursor` is null — same fields, terminal values.\n // Agents pin to this single shape across both modes.\n printJson({\n data: collected,\n pagination: { hasMore: false, cursor: null },\n count: collected.length,\n });\n } else {\n renderTable(collected);\n }\n return;\n }\n } catch (cause) {\n throw toCliError(cause);\n }\n\n if (globals.json) {\n printJson({\n data: response.data,\n pagination: response.pagination,\n count: response.data.length,\n });\n return;\n }\n\n if (response.data.length === 0) {\n log.info('No markets matched the filter.');\n return;\n }\n renderTable(response.data);\n\n if (response.pagination.hasMore && response.pagination.cursor) {\n log.detail('Next page', `--cursor ${response.pagination.cursor}`);\n }\n });\n\nfunction renderTable(markets: readonly MarketResource[]): void {\n const table = createTable(['ID', 'Title', 'Status', 'Outcomes', 'Top outcome', 'Created']);\n for (const market of markets) {\n const outcomes = market.outcomes;\n const top = outcomes.reduce<(typeof outcomes)[number] | undefined>((acc, current) => {\n if (acc === undefined) return current;\n return current.probability > acc.probability ? current : acc;\n }, undefined);\n table.push([\n shortId(market.id),\n truncate(market.title ?? '(untitled)', 42),\n colorStatus(market.status ?? 'UNKNOWN'),\n String(market.outcomeCount),\n top ? `${truncate(top.label, 18)} (${formatProbability(top.probability)})` : '-',\n market.createdAt.slice(0, 10),\n ]);\n }\n print(table.toString());\n}\n\nfunction normaliseStatus(value: string): MarketStatus {\n const upper = value.toUpperCase() as MarketStatus;\n if (!ALLOWED_STATUSES.has(upper)) {\n throw new CliValidationError(\n `Unknown market status \"${value}\".`,\n 'Allowed: UNSEEDED, ACTIVE, RESOLVED.'\n );\n }\n return upper;\n}\n","/**\n * `kash markets predictions <market-id>` — paginated feed of recent\n * trades against a single market. Wraps `kash.markets.predictions`.\n *\n * Requires API key with `markets:read` scope (granted by default on every\n * tier). Pagination shape mirrors `kash markets list` and `kash trade list`:\n * default first-page render, `--all` to walk every page, `--ndjson`\n * to stream NDJSON one-record-per-line for agents.\n */\n\nimport { Command } from 'commander';\n\nimport { CliValidationError, toCliError } from '../../errors.js';\nimport { buildClient } from '../../utils/client.js';\nimport { createTable, formatDate, shortId } from '../../utils/formatting.js';\nimport { parsePositiveInt, readGlobals } from '../../utils/global-options.js';\nimport { log, print, printJson, writeNdjson } from '../../utils/output.js';\nimport { parseOutcomeIndex } from '../../utils/trade-input.js';\n\nimport type { PredictionResource } from '@kashdao/sdk';\n\ntype PredictionsOptions = {\n side?: string;\n outcome?: string;\n limit?: string;\n cursor?: string;\n all?: boolean;\n ndjson?: boolean;\n};\n\nexport const predictionsCommand = new Command('predictions')\n .description('Recent trades against a market (cursor-paginated, newest first).')\n .argument('<marketId>', 'market UUID')\n .option('-s, --side <side>', 'filter to a single side: buy | sell')\n .option('-o, --outcome <index>', 'filter to a single outcome index (0-based)')\n .option('-l, --limit <n>', 'page size (1-100)', '50')\n .option('-c, --cursor <cursor>', 'pagination cursor returned by a previous call')\n .option('-a, --all', 'walk every page (use with --json for export)')\n .option(\n '--ndjson',\n 'stream results as newline-delimited JSON (one record per line); implies --all'\n )\n .addHelpText(\n 'after',\n `\nExamples:\n $ kash markets predictions 9f0b...\n $ kash markets predictions 9f0b... --side buy --outcome 0\n $ kash markets predictions 9f0b... --json --quiet | jq -r '.data[].transactionHash'\n $ kash markets predictions 9f0b... --ndjson | head -100\n $ kash markets predictions 9f0b... --all --json --quiet > history.json\n`\n )\n .action(async (marketId: string, options: PredictionsOptions, cmd: Command) => {\n const globals = readGlobals(cmd);\n\n const limit = options.limit === undefined ? 50 : parsePositiveInt(options.limit, 'limit');\n if (limit < 1 || limit > 100) {\n throw new CliValidationError('--limit must be between 1 and 100.', undefined, 'limit');\n }\n\n const side = options.side ? validateSide(options.side) : undefined;\n const outcomeIndex = options.outcome ? parseOutcomeIndex(options.outcome) : undefined;\n\n let response;\n try {\n // Requires API key with `markets:read` scope (granted by default\n // on every tier). Fail fast at build time if no key is configured\n // rather than waiting for the server's 401.\n const { client } = await buildClient({ requireAuth: true, globals });\n response = await client.markets.predictions(marketId, {\n limit,\n ...(side === undefined ? {} : { side }),\n ...(outcomeIndex === undefined ? {} : { outcomeIndex }),\n ...(options.cursor === undefined ? {} : { cursor: options.cursor }),\n });\n\n if (options.ndjson) {\n for await (const prediction of response) {\n writeNdjson(prediction);\n }\n return;\n }\n\n if (options.all) {\n const collected: PredictionResource[] = [];\n for await (const prediction of response) collected.push(prediction);\n if (globals.json) {\n // Canonical `{data, pagination, count}` envelope — matches\n // every other list-shaped command (`markets list`,\n // `trade list`, `webhooks list`). After walking every\n // page, `pagination.hasMore` is false and `cursor` is null.\n printJson({\n data: collected,\n pagination: { hasMore: false, cursor: null },\n count: collected.length,\n });\n } else {\n renderTable(collected);\n }\n return;\n }\n } catch (cause) {\n throw toCliError(cause);\n }\n\n if (globals.json) {\n printJson({\n data: response.data,\n pagination: response.pagination,\n count: response.data.length,\n });\n return;\n }\n\n if (response.data.length === 0) {\n log.info('No predictions matched the filter.');\n return;\n }\n renderTable(response.data);\n\n if (response.pagination.hasMore && response.pagination.cursor) {\n log.detail('Next page', `--cursor ${response.pagination.cursor}`);\n }\n });\n\nfunction renderTable(predictions: readonly PredictionResource[]): void {\n const table = createTable(['Time', 'Side', 'Out#', 'Amount', 'Price', 'Tx']);\n for (const p of predictions) {\n const amount = p.side === 'buy' ? (p.usdcIn ?? '-') : (p.tokensIn ?? '-');\n table.push([\n formatDate(p.timestamp),\n p.side,\n String(p.outcomeIndex),\n amount,\n p.price,\n shortId(p.transactionHash),\n ]);\n }\n print(table.toString());\n}\n\nfunction validateSide(value: string): 'buy' | 'sell' {\n const lower = value.toLowerCase();\n if (lower !== 'buy' && lower !== 'sell') {\n throw new CliValidationError(`Unknown --side \"${value}\".`, 'Allowed: buy, sell.', 'side');\n }\n return lower;\n}\n"],"mappings":"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","names":["Command","Command","Command","Command","Command","renderTable","Command"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/commands/protocol/index.ts","../src/commands/protocol/allowance.ts","../src/utils/direct-client.ts","../src/commands/protocol/balance.ts","../src/commands/protocol/decode-revert.ts","../src/commands/protocol/fees.ts","../src/commands/protocol/market.ts","../src/commands/protocol/position.ts","../src/commands/protocol/quote.ts","../src/commands/protocol/smart-account.ts","../src/commands/protocol/token-id.ts","../src/commands/protocol/trade.ts","../src/utils/userop-json.ts","../src/commands/protocol/userop.ts","../src/commands/protocol/watch.ts"],"sourcesContent":["/**\n * `kash protocol …` — self-orchestrated direct-to-chain operations.\n *\n * Wraps `@kashdao/protocol-sdk`. Every command in this namespace\n * reads from the chain via the consumer's RPC and, for write paths,\n * signs UserOps locally with the configured signer. Zero Kash backend\n * dependency.\n *\n * Both this self-orchestrated mode and the default Kash-orchestrated\n * mode (`kash markets`, `kash trade`, …) are fully non-custodial —\n * user funds always live in Privy-managed MPC smart accounts the user\n * controls; Kash never holds keys on either path. The split is about\n * who builds and submits the UserOp, not who has custody.\n *\n * Required profile fields for any subcommand:\n *\n * - `rpcUrl` — consumer-owned RPC endpoint\n * - `smartAccount` — ERC-4337 account whose funds are used\n * - `defaultChainId`— chain to run on (8453 mainnet, 84532 sepolia)\n *\n * Read-only subcommands (`balance`, `market`, `quote`) use a no-op\n * signer and don't require `signerKeyRef`; write subcommands do.\n */\n\nimport { Command } from 'commander';\n\nimport { allowanceCommand } from './allowance.js';\nimport { balanceCommand } from './balance.js';\nimport { decodeRevertCommand } from './decode-revert.js';\nimport { feesCommand } from './fees.js';\nimport { marketCommand } from './market.js';\nimport { positionCommand } from './position.js';\nimport { quoteCommand } from './quote.js';\nimport { smartAccountCommand } from './smart-account.js';\nimport { tokenIdCommand } from './token-id.js';\nimport { tradeCommand } from './trade.js';\nimport { useropCommand } from './userop.js';\nimport { watchCommand } from './watch.js';\n\nexport const protocolCommand = new Command('protocol')\n .description(\n 'Self-orchestrated direct-to-chain operations (uses @kashdao/protocol-sdk). Like the default Kash-orchestrated mode, this path is non-custodial — the difference is who builds and submits trades.'\n )\n .addCommand(balanceCommand)\n .addCommand(marketCommand)\n .addCommand(quoteCommand)\n .addCommand(positionCommand)\n .addCommand(allowanceCommand)\n .addCommand(smartAccountCommand)\n .addCommand(feesCommand)\n .addCommand(tokenIdCommand)\n .addCommand(decodeRevertCommand)\n .addCommand(tradeCommand)\n .addCommand(useropCommand)\n .addCommand(watchCommand);\n","/**\n * `kash protocol allowance <spender> [account]` — read the on-chain\n * USDC allowance from `account` to `spender`. Used to skip `approve`\n * calls when an existing allowance is already sufficient (the\n * conventional first-trade pattern).\n *\n * Defaults `account` to the active profile's `smartAccount`.\n */\n\nimport { Command } from 'commander';\n\nimport { toCliError } from '../../errors.js';\nimport { buildDirectClient } from '../../utils/direct-client.js';\nimport { formatAddress, formatUsdcAtomic } from '../../utils/formatting.js';\nimport { readGlobals } from '../../utils/global-options.js';\nimport { print, printJson, style } from '../../utils/output.js';\nimport { validateAddress, validateAddressOptional } from '../../utils/trade-input.js';\n\nexport const allowanceCommand = new Command('allowance')\n .description('Read the on-chain USDC allowance from `account` to `spender`.')\n .argument('<spender>', 'spender contract address (e.g. a market) — 0x-prefixed')\n .argument('[account]', \"owner address (default: profile's smartAccount)\")\n .addHelpText(\n 'after',\n `\nExamples:\n $ kash protocol allowance 0xMarket...\n $ kash protocol allowance 0xMarket... 0xOwner...\n $ kash protocol allowance 0xMarket... --json --quiet | jq -r '.allowanceAtomic'\n\nNotes:\n - The allowance is returned in USDC atomic units (6 decimals). A\n value larger than the trade's atomic-USDC input means \\`approve\\`\n can be skipped on the next trade.\n`\n )\n .action(async (spender: string, account: string | undefined, _opts, cmd: Command) => {\n const globals = readGlobals(cmd);\n const spenderAddress = validateAddress(spender, 'spender');\n const accountAddress = validateAddressOptional(account, 'account');\n\n try {\n const resolved = await buildDirectClient({ globals });\n const owner = accountAddress ?? resolved.smartAccount;\n const allowance = await resolved.client.account.usdcAllowance(owner, spenderAddress);\n\n const payload = {\n owner,\n spender: spenderAddress,\n chainId: resolved.chainId,\n allowanceAtomic: allowance.toString(),\n };\n\n if (globals.json) {\n printJson(payload);\n return;\n }\n\n print('');\n print(` ${style.dim('Owner ')} ${formatAddress(owner, 10, 8)}`);\n print(` ${style.dim('Spender ')} ${formatAddress(spenderAddress, 10, 8)}`);\n print(\n ` ${style.dim('Allowance')} ${formatUsdcAtomic(allowance.toString())} ${style.dim(`(${allowance.toString()} atomic)`)}`\n );\n } catch (cause) {\n throw toCliError(cause);\n }\n });\n","/**\n * Build a `@kashdao/protocol-sdk` `SmartAccountClient` from the active\n * profile's direct-mode config.\n *\n * **Lazy-loaded.** This module dynamically imports\n * `@kashdao/protocol-sdk` (and viem) inside `buildDirectClient` so\n * the Kash-orchestrated code paths (markets / trade / portfolio /\n * webhooks / health) keep their fast cold start. Touching this\n * module at the module-top level — even in a `type` import — would\n * pull viem into every `kash --version` invocation.\n *\n * The CLI exposes the protocol-sdk through a single namespace\n * (`kash protocol …`); every command in that namespace calls\n * `buildDirectClient` to get a configured client and routes through\n * it. Read-only commands (`balance`, `market`, `quote`) use a\n * `noopSigner` that throws if a write path tries to sign — a\n * structural guarantee that read commands cannot accidentally\n * authorise spend.\n */\n\nimport { CliError, EXIT_CODES } from '../errors.js';\n\nimport { readConfig, type CliConfig } from './config-store.js';\nimport { resolveCliCustomChain } from './custom-chain.js';\nimport { loadRawPrivateKey } from './signer-key.js';\n\n// Type-only imports — TypeScript erases these at compile time, so\n// the protocol-sdk's runtime (and viem) is NOT pulled in via these\n// lines. The actual import happens lazily inside `buildDirectClient`\n// and `loadSigner` via dynamic `import()`.\nimport type { GlobalOptions } from './global-options.js';\nimport type {\n CustomChain,\n SmartAccountClient,\n SmartAccountClientConfigInput,\n SmartAccountSignerAdapter,\n} from '@kashdao/protocol-sdk';\n\n/**\n * Build a configured `DirectClient`. Caller passes the global\n * options so `--profile` / `--config` selection works uniformly with\n * the Kash-orchestrated path.\n *\n * `requireSigner: false` (default) constructs a no-op signer that\n * throws if anything actually tries to sign — fine for read-only\n * commands. Pass `true` for write-path commands (`build`, `submit`,\n * `simulate-write`).\n */\nexport async function buildDirectClient(opts: {\n readonly globals?: GlobalOptions;\n readonly requireSigner?: boolean;\n}): Promise<{\n readonly client: SmartAccountClient;\n readonly chainId: number;\n readonly smartAccount: `0x${string}`;\n}> {\n const globals = opts.globals;\n const config = await readConfig({\n ...(globals?.profile === undefined ? {} : { profile: globals.profile }),\n ...(globals?.configPath === undefined ? {} : { configPath: globals.configPath }),\n });\n\n // Foundational fields — required for *any* direct-mode command.\n const rpc = globals?.baseUrl ?? config.rpcUrl;\n if (!rpc) {\n throw missingDirectConfig('rpcUrl', '--rpc-url or `kash config set rpcUrl <url>`');\n }\n if (!config.smartAccount) {\n throw missingDirectConfig(\n 'smartAccount',\n '`kash config set smartAccount 0x…` (the ERC-4337 account address whose funds you trade with)'\n );\n }\n\n // Lazy-load — the dynamic import is the cold-start firewall.\n const { createSmartAccountClient } = await import('@kashdao/protocol-sdk');\n\n const signer = opts.requireSigner ? await loadSigner(config.signerKeyRef) : noopSigner();\n\n const bundlerConfig = resolveBundlerConfig(config);\n\n // If the profile has `customChain` configured, build the SDK\n // CustomChain (viem chain + protocol addresses + optional SA factory\n // config) so we work against chains outside the static registry —\n // local Anvil, forks, sidechains. SA mode requires\n // `customChain.smartAccount.{factory,implementation,entryPoint}`\n // when running on Anvil because anvil_setCode can't copy immutable\n // variables (the canonical permissionless.js SimpleAccount factory\n // relies on immutable EntryPoint binding) — see protocol-sdk's\n // TROUBLESHOOTING.md § AA23.\n const customChain = await maybeBuildCustomChain(config, rpc);\n if (customChain !== undefined && customChain.smartAccount === undefined) {\n throw missingDirectConfig(\n 'customChain.smartAccount',\n 'all three: `kash config set customChain.smartAccount.factoryAddress 0x…`, `customChain.smartAccount.implementationAddress 0x…`, `customChain.smartAccount.entryPointAddress 0x…` (SA mode requires the local SimpleAccount factory + EntryPoint addresses on a custom chain — Anvil deploys these to addresses that differ from the canonical permissionless.js defaults)'\n );\n }\n\n const client = createSmartAccountClient({\n chainId: config.defaultChainId,\n rpc,\n signer,\n ...(bundlerConfig === undefined ? {} : { bundler: bundlerConfig }),\n ...(customChain === undefined ? {} : { customChain }),\n });\n\n return {\n client,\n chainId: config.defaultChainId,\n smartAccount: config.smartAccount as `0x${string}`,\n };\n}\n\n/**\n * Read-only signer for commands that don't need to sign anything\n * (`kash protocol balance/market/quote`). The DirectClient\n * constructor requires a signer, but read paths never call\n * `signUserOpHash` — if something does, this implementation throws\n * with a clear \"this is a CLI bug\" message so the failure surfaces\n * during testing rather than silently producing a bad signature.\n */\nfunction noopSigner(): SmartAccountSignerAdapter {\n return {\n ownerAddress: '0x0000000000000000000000000000000000000000',\n async signUserOpHash() {\n throw new CliError('CLI bug: read-only direct-mode command attempted to sign a UserOp.', {\n code: 'UNEXPECTED',\n suggestion:\n 'File an issue at https://github.com/KashDAO/cli/issues — this should not happen.',\n });\n },\n };\n}\n\n/**\n * Load a signer from the configured `signerKeyRef`. Supports two\n * sources today, both delegated to `loadRawPrivateKey` for parity\n * with EOA-mode:\n *\n * - `file:<path>` — read the key from disk. POSIX file mode is\n * checked after a successful load; if the file\n * is readable by group or other, the CLI emits\n * a `chmod 600` warning (load is NOT refused —\n * advisory, like ssh and aws-cli).\n * - `env:<NAME>` — read the key from the named env var.\n *\n * Both return a `viem` `LocalAccount` wrapped via\n * `viemAccountSigner` from the protocol-sdk.\n */\nasync function loadSigner(ref: string | undefined): Promise<SmartAccountSignerAdapter> {\n const rawKey = await loadRawPrivateKey(ref);\n // Lazy-load viem and the signer adapter together — both pulled by\n // the same dynamic import boundary.\n const [{ privateKeyToAccount }, { viemAccountSigner }] = await Promise.all([\n import('viem/accounts'),\n import('@kashdao/protocol-sdk'),\n ]);\n return viemAccountSigner(privateKeyToAccount(rawKey));\n}\n\n/**\n * Translate the CLI's profile-level bundler config into the\n * protocol-sdk's `bundler` field. The protocol-sdk's structured\n * bundler config requires `url` for every preset (the URL for\n * `flashbots`/`pimlico`/`alchemy` is the provider's own RPC, not\n * the chain RPC). The CLI surfaces this constraint as a\n * configuration error rather than silently defaulting.\n */\nfunction resolveBundlerConfig(\n config: Awaited<ReturnType<typeof readConfig>>\n): SmartAccountClientConfigInput['bundler'] | undefined {\n if (config.bundlerProvider === undefined && config.bundlerUrl === undefined) {\n return undefined; // Use the protocol-sdk's default (Flashbots Protect).\n }\n if (config.bundlerProvider === undefined) {\n // URL only — treat as a generic bundler (string shorthand).\n return config.bundlerUrl;\n }\n // Provider preset — `url` is required by the protocol-sdk schema.\n if (config.bundlerUrl === undefined) {\n throw new CliError(\n `Direct-mode config: bundlerProvider=\"${config.bundlerProvider}\" requires a bundlerUrl.`,\n {\n code: 'DIRECT_CONFIG_MISSING',\n suggestion:\n '`kash config set bundlerUrl <provider-rpc-url>` (e.g. https://api.pimlico.io/v2/8453/rpc?apikey=…)',\n }\n );\n }\n return {\n provider: config.bundlerProvider,\n url: config.bundlerUrl,\n };\n}\n\n/**\n * Build an SDK `CustomChain` from the profile's `customChain` config,\n * if any. The CLI never asks the user to hand-construct a viem Chain\n * — we synthesise one from `defaultChainId + rpcUrl + customChain.name`,\n * which is exactly what the local-anvil quickstart in\n * `packages/protocol-sdk/examples/local-anvil/` does inline.\n */\nasync function maybeBuildCustomChain(\n config: CliConfig,\n rpc: string\n): Promise<CustomChain | undefined> {\n if (config.customChain === undefined) return undefined;\n if (config.defaultChainId === undefined) {\n throw missingDirectConfig(\n 'defaultChainId',\n '`kash config set defaultChainId <id>` (required when customChain is set so the CLI can construct the viem chain)'\n );\n }\n return resolveCliCustomChain({\n customChain: config.customChain,\n chainId: config.defaultChainId,\n rpc,\n });\n}\n\nfunction missingDirectConfig(field: string, hint: string): CliError {\n return new CliError(`Direct-mode config missing: ${field}.`, {\n code: 'DIRECT_CONFIG_MISSING',\n exitCode: EXIT_CODES.GENERIC,\n suggestion: `Set ${field} via ${hint}.`,\n actions: [\n {\n type: 'check_input',\n field,\n description: hint,\n },\n ],\n });\n}\n","/**\n * `kash protocol balance [account]` — read on-chain balances for a\n * smart account.\n *\n * Direct mode, read-only. Uses the protocol-sdk's `account.usdcBalance`\n * + `account.gasBalance`. Defaults to the active profile's\n * `smartAccount` when no argument is given so most operators run a\n * bare `kash protocol balance` for their own account.\n *\n * Output (JSON shape pinned via `OnChainBalanceSchema`):\n *\n * ```jsonc\n * {\n * \"account\": \"0x...\",\n * \"chainId\": 8453,\n * \"usdcAtomic\": \"12345000000\",\n * \"gasWei\": \"12300000000000000\"\n * }\n * ```\n */\n\nimport { Command } from 'commander';\n\nimport { toCliError } from '../../errors.js';\nimport { buildDirectClient } from '../../utils/direct-client.js';\nimport { formatAddress, formatBigDecimal, formatUsdcAtomic } from '../../utils/formatting.js';\nimport { readGlobals } from '../../utils/global-options.js';\nimport { print, printJson, style } from '../../utils/output.js';\nimport { validateAddressOptional } from '../../utils/trade-input.js';\n\nexport const balanceCommand = new Command('balance')\n .description(\"Read on-chain USDC + gas balance for a smart account (defaults to the profile's).\")\n .argument('[account]', \"smart-account address (defaults to the active profile's smartAccount)\")\n .addHelpText(\n 'after',\n `\nExamples:\n $ kash protocol balance\n $ kash protocol balance 0xabc...\n $ kash protocol balance --json --quiet | jq '.usdcAtomic'\n\nDirect-mode requires rpcUrl + smartAccount + signerKeyRef configured\non the active profile (signer is loaded but never invoked for reads).\n`\n )\n .action(async (account: string | undefined, _opts, cmd: Command) => {\n const globals = readGlobals(cmd);\n const accountOverride = validateAddressOptional(account, 'account');\n\n let resolved;\n try {\n resolved = await buildDirectClient({ globals });\n } catch (cause) {\n throw toCliError(cause);\n }\n const target = accountOverride ?? resolved.smartAccount;\n\n let usdcAtomic: bigint;\n let gasWei: bigint;\n try {\n [usdcAtomic, gasWei] = await Promise.all([\n resolved.client.account.usdcBalance(target),\n resolved.client.account.gasBalance(target),\n ]);\n } catch (cause) {\n throw toCliError(cause);\n }\n\n const payload = {\n account: target,\n chainId: resolved.chainId,\n usdcAtomic: usdcAtomic.toString(),\n gasWei: gasWei.toString(),\n };\n\n if (globals.json) {\n printJson(payload);\n return;\n }\n\n print('');\n print(` ${style.dim('Account ')} ${formatAddress(target, 10, 8)}`);\n print(` ${style.dim('Chain ')} ${String(resolved.chainId)}`);\n print(` ${style.dim('USDC ')} ${formatUsdcAtomic(usdcAtomic.toString())}`);\n print(\n ` ${style.dim('ETH (gas) ')} ${formatBigDecimal(gasWei, { baseDecimals: 18, displayDecimals: 6 })} ETH`\n );\n });\n","/**\n * `kash protocol decode-revert <0x…>` — decode raw revert data\n * emitted by the Market contract or EntryPoint into a human-readable\n * `(name, args)` pair.\n *\n * Pure offline operation: matches the first 4 bytes of revert data\n * against the custom errors in the vendored ABIs (Market first,\n * EntryPoint as fallback). No RPC required.\n *\n * Useful when debugging stuck UserOps: `getUserOperationReceipt`\n * returns hex revert data; pipe it into this command to identify\n * which custom error was thrown.\n */\n\nimport { Command } from 'commander';\n\nimport { CliValidationError, toCliError } from '../../errors.js';\nimport { readGlobals } from '../../utils/global-options.js';\nimport { print, printJson, style } from '../../utils/output.js';\n\nconst HEX_DATA_RE = /^0x[0-9a-fA-F]+$/;\n\nexport const decodeRevertCommand = new Command('decode-revert')\n .description('Decode raw revert data into (name, args) using the Market + EntryPoint ABIs.')\n .argument('<data>', 'raw revert data (0x-prefixed hex)')\n .addHelpText(\n 'after',\n `\nExamples:\n $ kash protocol decode-revert 0x4e487b710000000000000000000000000000000000000000000000000000000000000011\n $ kash protocol decode-revert 0x... --json --quiet | jq -r '.name'\n\nNotes:\n - Returns \\`null\\` if the selector doesn't match any known error\n (the data may be raw \\`Error(string)\\` or vendor-specific).\n - The \\`args\\` array stringifies bigint values to preserve precision.\n`\n )\n .action(async (data: string, _opts, cmd: Command) => {\n const globals = readGlobals(cmd);\n\n if (!HEX_DATA_RE.test(data) || data.length < 10) {\n throw new CliValidationError(\n '<data> must be 0x-prefixed hex with at least a 4-byte selector.',\n `Got \"${data}\".`,\n 'data'\n );\n }\n\n try {\n // Lazy-load protocol-sdk so this offline helper doesn't pull\n // viem on every CLI invocation.\n const { decodeMarketRevert } = await import('@kashdao/protocol-sdk');\n const decoded = decodeMarketRevert(data as `0x${string}`);\n\n // Stringify bigint args defensively — JSON.stringify chokes on\n // them and consumers can re-parse the strings if they need\n // precision.\n const args = decoded?.args.map((a) => (typeof a === 'bigint' ? a.toString() : a)) ?? null;\n\n const payload = decoded === null ? null : { name: decoded.name, args };\n\n if (globals.json) {\n printJson(payload);\n return;\n }\n\n if (decoded === null) {\n print('');\n print(` ${style.dim('No match — selector not in Market or EntryPoint ABIs.')}`);\n print(` ${style.dim('Data: ')}${data.slice(0, 10)}${data.length > 10 ? '…' : ''}`);\n return;\n }\n\n print('');\n print(` ${style.dim('Error ')} ${style.bold(decoded.name)}`);\n if (args && args.length > 0) {\n print(` ${style.dim('Args ')}`);\n for (const [i, arg] of args.entries()) {\n print(` [${String(i)}] ${String(arg)}`);\n }\n } else {\n print(` ${style.dim('Args ')} (none)`);\n }\n } catch (cause) {\n throw toCliError(cause);\n }\n });\n","/**\n * `kash protocol fees` — EIP-1559 fee estimation for the configured\n * chain. Wraps `client.bundler.estimateFees(options)` from the\n * protocol-sdk.\n *\n * Useful for direct-mode operators tuning their submit strategy:\n * compare what the SDK would suggest under different multipliers,\n * sample sizes, or percentile windows. The estimate is read-only and\n * uses `eth_feeHistory` against the configured RPC.\n */\n\nimport { Command } from 'commander';\n\nimport { CliValidationError, toCliError } from '../../errors.js';\nimport { buildDirectClient } from '../../utils/direct-client.js';\nimport { formatGwei } from '../../utils/formatting.js';\nimport {\n parseOptionalPositiveFloat,\n parseOptionalPositiveInt,\n readGlobals,\n} from '../../utils/global-options.js';\nimport { print, printJson, style } from '../../utils/output.js';\n\ntype FeesOptions = {\n blocks?: string;\n percentile?: string;\n baseMultiplier?: string;\n priorityFloorGwei?: string;\n};\n\nexport const feesCommand = new Command('fees')\n .description('EIP-1559 fee estimate for the configured chain (uses eth_feeHistory).')\n .option('--blocks <n>', 'number of recent blocks to sample (default 4)')\n .option(\n '--percentile <n>',\n 'priority-fee percentile to take from each sampled block (1-99, default 50)'\n )\n .option(\n '--base-multiplier <n>',\n 'multiplier applied to predicted next-block base fee (default 2.0; raise for congested chains)'\n )\n .option('--priority-floor-gwei <n>', 'floor for maxPriorityFeePerGas in gwei (default 1)')\n .addHelpText(\n 'after',\n `\nExamples:\n $ kash protocol fees\n $ kash protocol fees --base-multiplier 3 --json --quiet | jq -r '.maxFeePerGas'\n $ kash protocol fees --blocks 16 --percentile 75 # smoother, more conservative\n`\n )\n .action(async (options: FeesOptions, cmd: Command) => {\n const globals = readGlobals(cmd);\n\n const blocks = parseOptionalPositiveInt(options.blocks, 'blocks');\n const percentile = parseOptionalPositiveInt(options.percentile, 'percentile');\n if (percentile !== undefined && (percentile < 1 || percentile > 99)) {\n throw new CliValidationError(\n '--percentile must be between 1 and 99.',\n undefined,\n 'percentile'\n );\n }\n const baseMultiplier = parseOptionalPositiveFloat(options.baseMultiplier, 'base-multiplier');\n const priorityFloorGwei = parseOptionalPositiveInt(\n options.priorityFloorGwei,\n 'priority-floor-gwei'\n );\n\n try {\n const resolved = await buildDirectClient({ globals });\n const estimate = await resolved.client.bundler.estimateFees({\n ...(blocks === undefined ? {} : { blockCount: blocks }),\n ...(percentile === undefined ? {} : { rewardPercentile: percentile }),\n ...(baseMultiplier === undefined ? {} : { baseMultiplier }),\n ...(priorityFloorGwei === undefined\n ? {}\n : { priorityFeeFloorWei: BigInt(priorityFloorGwei) * 10n ** 9n }),\n });\n\n const payload = {\n chainId: resolved.chainId,\n maxFeePerGas: estimate.maxFeePerGas.toString(),\n maxPriorityFeePerGas: estimate.maxPriorityFeePerGas.toString(),\n };\n\n if (globals.json) {\n printJson(payload);\n return;\n }\n\n print('');\n print(` ${style.dim('Chain ')} ${String(resolved.chainId)}`);\n print(\n ` ${style.dim('maxFee ')} ${formatGwei(estimate.maxFeePerGas)} gwei ${style.dim(`(${estimate.maxFeePerGas.toString()} wei)`)}`\n );\n print(\n ` ${style.dim('maxPrio ')} ${formatGwei(estimate.maxPriorityFeePerGas)} gwei ${style.dim(`(${estimate.maxPriorityFeePerGas.toString()} wei)`)}`\n );\n } catch (cause) {\n throw toCliError(cause);\n }\n });\n\n// `formatGwei` lives in `utils/formatting.ts` — single source of\n// truth for the wei-to-gwei display format shared with `kash eoa fees`\n// and the balance commands.\n","/**\n * `kash protocol market <market-address>` — read on-chain market state.\n *\n * Direct mode, read-only. Uses the protocol-sdk's `markets.state`\n * which returns the aggregated reserves, supplies, weights, and\n * derived per-outcome probabilities.\n *\n * The Kash-orchestrated equivalent is `kash markets get <uuid>`. The two are\n * deliberately separate commands because the inputs differ (UUID vs\n * 0x address) and the outputs differ (API-projected `MarketResource`\n * vs on-chain `MarketState`). Operators using direct mode should\n * never confuse on-chain state with the API's denormalised view.\n */\n\nimport { Command } from 'commander';\n\nimport { toCliError } from '../../errors.js';\nimport { buildDirectClient } from '../../utils/direct-client.js';\nimport { formatAddress, formatWad } from '../../utils/formatting.js';\nimport { readGlobals } from '../../utils/global-options.js';\nimport { print, printJson, style } from '../../utils/output.js';\nimport { validateAddress } from '../../utils/trade-input.js';\n\nexport const marketCommand = new Command('market')\n .description('Read on-chain market state (reserves, supplies, weights, derived probabilities).')\n .argument('<address>', 'market contract address (0x-prefixed)')\n .addHelpText(\n 'after',\n `\nExamples:\n $ kash protocol market 0xabc...\n $ kash protocol market 0xabc... --json --quiet | jq '.outcomes'\n`\n )\n .action(async (address: string, _opts, cmd: Command) => {\n const globals = readGlobals(cmd);\n\n validateAddress(address, 'address');\n\n let resolved;\n let state;\n try {\n resolved = await buildDirectClient({ globals });\n state = await resolved.client.markets.state(address as `0x${string}`);\n } catch (cause) {\n throw toCliError(cause);\n }\n\n // Convert bigints to strings on the JSON path so consumers can\n // round-trip through `JSON.stringify` losslessly.\n const payload = {\n marketAddress: state.marketAddress,\n chainId: resolved.chainId,\n status: state.status,\n readAt: state.readAt.toString(),\n reserveWad: state.reserveWad.toString(),\n outcomes: state.outcomes.map((o) => ({\n index: o.index,\n outstandingTokensWad: o.outstandingTokensWad.toString(),\n weightWad: o.weightWad.toString(),\n probability: o.probability,\n })),\n };\n\n if (globals.json) {\n printJson(payload);\n return;\n }\n\n print('');\n print(` ${style.dim('Market ')} ${formatAddress(state.marketAddress, 10, 8)}`);\n print(` ${style.dim('Status ')} ${state.status}`);\n print(` ${style.dim('Outcomes ')} ${String(state.outcomes.length)}`);\n print('');\n for (const outcome of state.outcomes) {\n const pct = (outcome.probability * 100).toFixed(2);\n print(\n ` [${String(outcome.index)}] p=${pct}% outstanding=${formatWad(outcome.outstandingTokensWad)} weight=${formatWad(outcome.weightWad)}`\n );\n }\n });\n","/**\n * `kash protocol position <market-address> [account]` — read on-chain\n * outcome-token holdings (ERC-1155) for a single market.\n *\n * Direct mode, read-only. Uses the protocol-sdk's\n * `client.account.position(account, market)` which fans out a\n * `balanceOfBatch` against `OutcomeTokens1155`. Defaults `account` to\n * the active profile's `smartAccount`.\n *\n * Distinct from `kash portfolio positions` — that hits the public API\n * (Kash-orchestrated). This is on-chain truth, useful for direct-mode operators\n * verifying their balances independently.\n */\n\nimport { Command } from 'commander';\n\nimport { toCliError } from '../../errors.js';\nimport { buildDirectClient } from '../../utils/direct-client.js';\nimport { formatAddress, formatWad } from '../../utils/formatting.js';\nimport { readGlobals } from '../../utils/global-options.js';\nimport { print, printJson, style } from '../../utils/output.js';\nimport { validateAddress, validateAddressOptional } from '../../utils/trade-input.js';\n\nexport const positionCommand = new Command('position')\n .description('Read on-chain outcome-token holdings (ERC-1155) for a market.')\n .argument('<market>', 'market contract address (0x-prefixed)')\n .argument(\n '[account]',\n \"EOA or smart-account address whose holdings to read (default: profile's smartAccount)\"\n )\n .addHelpText(\n 'after',\n `\nExamples:\n $ kash protocol position 0xMarket...\n $ kash protocol position 0xMarket... 0xOther...\n $ kash protocol position 0xMarket... --json --quiet | jq '.holdings[].balanceWad'\n`\n )\n .action(async (market: string, account: string | undefined, _opts, cmd: Command) => {\n const globals = readGlobals(cmd);\n\n const marketAddr = validateAddress(market, 'market');\n const accountAddr = validateAddressOptional(account, 'account');\n\n let resolved;\n let position;\n try {\n resolved = await buildDirectClient({ globals });\n const target = accountAddr ?? resolved.smartAccount;\n position = await resolved.client.account.position(target, marketAddr);\n\n const payload = {\n account: target,\n marketAddress: position.marketAddress,\n chainId: resolved.chainId,\n numOutcomes: position.numOutcomes,\n holdings: position.holdings.map((h) => ({\n outcomeIndex: h.outcomeIndex,\n balanceWad: h.balanceWad.toString(),\n })),\n };\n\n if (globals.json) {\n printJson(payload);\n return;\n }\n\n print('');\n print(` ${style.dim('Account ')} ${formatAddress(target, 10, 8)}`);\n print(` ${style.dim('Market ')} ${formatAddress(position.marketAddress, 10, 8)}`);\n print(` ${style.dim('Outcomes ')} ${String(position.numOutcomes)}`);\n print('');\n for (const h of position.holdings) {\n const balanceLabel = formatWad(h.balanceWad);\n print(\n ` [${String(h.outcomeIndex)}] balance=${balanceLabel} ${style.dim(`(${h.balanceWad.toString()} WAD)`)}`\n );\n }\n } catch (cause) {\n throw toCliError(cause);\n }\n });\n","/**\n * `kash protocol quote <market-address>` — on-chain price quote.\n *\n * Direct mode, read-only. Calls `markets.quote` on the AMM contract.\n * The Kash-orchestrated equivalent is `kash quote buy/sell` which hits the\n * API; this version reads directly from chain via the configured RPC.\n *\n * Input units mirror the protocol-sdk's contract: `--amount` is\n * USDC (decimal, e.g. \"10\") on BUY, outcome tokens (decimal, e.g.\n * \"1.5\") on SELL. The CLI converts to atomic-6 / WAD-18 before\n * calling the SDK.\n *\n * Output:\n *\n * ```jsonc\n * {\n * \"side\": \"BUY\",\n * \"outcomeIndex\": 0,\n * \"amountIn\": \"10000000\", // atomic-6 USDC\n * \"amountOut\": \"16234567890123456\", // WAD-18 outcome tokens\n * \"reserveAfterWad\": \"...\",\n * \"pricesAfterWad\": [\"...\", \"...\"]\n * }\n * ```\n */\n\nimport { Command } from 'commander';\n\nimport { toCliError } from '../../errors.js';\nimport { buildDirectClient } from '../../utils/direct-client.js';\nimport { formatAddress, formatUsdcAtomic, formatWad } from '../../utils/formatting.js';\nimport { readGlobals } from '../../utils/global-options.js';\nimport { print, printJson, style } from '../../utils/output.js';\nimport {\n decimalToAtomicUsdc,\n decimalToAtomicWad,\n parseOutcomeIndex,\n parseUppercaseSide,\n validateAddress,\n} from '../../utils/trade-input.js';\n\ntype QuoteOptions = {\n side: string;\n outcome: string;\n amount: string;\n};\n\nexport const quoteCommand = new Command('quote')\n .description('On-chain price quote for buying or selling an outcome.')\n .argument('<address>', 'market contract address (0x-prefixed)')\n .requiredOption('-s, --side <buy|sell>', 'trade side: buy or sell')\n .requiredOption('-o, --outcome <index>', 'outcome index (0-based)')\n .requiredOption(\n '-a, --amount <decimal>',\n 'amount: USDC decimal for buy (e.g. \"10\"), outcome-token decimal for sell (e.g. \"1.5\")'\n )\n .addHelpText(\n 'after',\n `\nExamples:\n $ kash protocol quote 0xabc... --side buy --outcome 0 --amount 10\n $ kash protocol quote 0xabc... --side sell --outcome 1 --tokens 1.5 --json\n`\n )\n .action(async (address: string, options: QuoteOptions, cmd: Command) => {\n const globals = readGlobals(cmd);\n const marketAddress = validateAddress(address, 'address');\n const side = parseUppercaseSide(options.side, 'side');\n const outcome = parseOutcomeIndex(options.outcome);\n const amount =\n side === 'BUY'\n ? decimalToAtomicUsdc(options.amount, 'amount')\n : decimalToAtomicWad(options.amount, 'amount');\n\n let resolved;\n let quote;\n try {\n resolved = await buildDirectClient({ globals });\n quote = await resolved.client.markets.quote(marketAddress, {\n side,\n outcome,\n amount,\n });\n } catch (cause) {\n throw toCliError(cause);\n }\n\n const payload = {\n side: quote.side,\n outcomeIndex: quote.outcomeIndex,\n amountIn: quote.amountIn.toString(),\n amountOut: quote.amountOut.toString(),\n reserveAfterWad: quote.reserveAfterWad.toString(),\n pricesAfterWad: quote.pricesAfterWad.map((p) => p.toString()),\n };\n\n if (globals.json) {\n printJson(payload);\n return;\n }\n\n print('');\n print(` ${style.dim('Market ')} ${formatAddress(address, 10, 8)}`);\n print(` ${style.dim('Action ')} ${quote.side} outcome ${String(quote.outcomeIndex)}`);\n if (quote.side === 'BUY') {\n print(` ${style.dim('Spend ')} ${formatUsdcAtomic(quote.amountIn)}`);\n print(` ${style.dim('Tokens out')} ${formatWad(quote.amountOut)}`);\n } else {\n print(` ${style.dim('Tokens in ')} ${formatWad(quote.amountIn)}`);\n print(` ${style.dim('USDC out ')} ${formatUsdcAtomic(quote.amountOut)}`);\n }\n print(\n ` ${style.dim('Probs after')} [${quote.pricesAfterWad\n .map((p) => `${((Number(p) / 1e18) * 100).toFixed(2)}%`)\n .join(', ')}]`\n );\n });\n","/**\n * `kash protocol smart-account` — derive smart-account address +\n * check deployment status without sending a UserOp.\n *\n * Two read-only operations:\n *\n * - `compute --owner 0x… [--salt n]` — derive the deterministic\n * SimpleAccountFactory address for an EOA owner. Same address\n * whether deployed or not.\n * - `is-deployed [address]` — check whether a smart account has\n * bytecode at its address. A `false` result is normal for a\n * never-traded SA (the first UserOp deploys it via factory data).\n *\n * Wraps `client.account.computeAddress` and `client.account.isDeployed`\n * from `@kashdao/protocol-sdk`. Read-only — uses the existing\n * `noopSigner` plumbing.\n */\n\nimport { Command } from 'commander';\n\nimport { CliValidationError, toCliError } from '../../errors.js';\nimport { buildDirectClient } from '../../utils/direct-client.js';\nimport { formatAddress } from '../../utils/formatting.js';\nimport { readGlobals } from '../../utils/global-options.js';\nimport { print, printJson, style } from '../../utils/output.js';\nimport { validateAddress, validateAddressOptional } from '../../utils/trade-input.js';\n\ntype ComputeOptions = {\n owner: string;\n salt?: string;\n};\n\nconst computeCommand = new Command('compute')\n .description('Derive the deterministic smart-account address for an EOA owner.')\n .requiredOption('-o, --owner <address>', 'EOA owner address (0x-prefixed)')\n .option('-s, --salt <n>', 'optional salt as a non-negative integer (default 0)', '0')\n .addHelpText(\n 'after',\n `\nExamples:\n $ kash protocol smart-account compute --owner 0xEoa...\n $ kash protocol smart-account compute --owner 0xEoa... --salt 1\n $ kash protocol smart-account compute --owner 0xEoa... --json --quiet | jq -r '.address'\n`\n )\n .action(async (options: ComputeOptions, cmd: Command) => {\n const globals = readGlobals(cmd);\n const ownerAddress = validateAddress(options.owner, 'owner');\n\n let salt: bigint | undefined;\n if (options.salt !== undefined) {\n let parsed: bigint;\n try {\n parsed = BigInt(options.salt);\n } catch {\n throw new CliValidationError(\n '--salt must be a non-negative integer (decimal or 0x-hex).',\n `Got \"${options.salt}\".`,\n 'salt'\n );\n }\n if (parsed < 0n) {\n throw new CliValidationError(\n '--salt must be non-negative.',\n `Got \"${options.salt}\".`,\n 'salt'\n );\n }\n salt = parsed === 0n ? undefined : parsed;\n }\n\n try {\n const resolved = await buildDirectClient({ globals });\n const address = await resolved.client.account.computeAddress(ownerAddress, salt);\n\n const payload = {\n owner: ownerAddress,\n salt: (salt ?? 0n).toString(),\n chainId: resolved.chainId,\n address,\n };\n\n if (globals.json) {\n printJson(payload);\n return;\n }\n\n print('');\n print(` ${style.dim('Owner ')} ${formatAddress(ownerAddress, 10, 8)}`);\n print(` ${style.dim('Salt ')} ${(salt ?? 0n).toString()}`);\n print(` ${style.dim('Address')} ${address}`);\n } catch (cause) {\n throw toCliError(cause);\n }\n });\n\nconst isDeployedCommand = new Command('is-deployed')\n .description('Check whether a smart account has bytecode (i.e. has been deployed on-chain).')\n .argument('[address]', \"smart account address (default: profile's smartAccount)\")\n .addHelpText(\n 'after',\n `\nExamples:\n $ kash protocol smart-account is-deployed\n $ kash protocol smart-account is-deployed 0xSa...\n $ kash protocol smart-account is-deployed --json --quiet | jq -r '.deployed'\n`\n )\n .action(async (address: string | undefined, _opts, cmd: Command) => {\n const globals = readGlobals(cmd);\n const addressOverride = validateAddressOptional(address, 'address');\n\n try {\n const resolved = await buildDirectClient({ globals });\n const target = addressOverride ?? resolved.smartAccount;\n const deployed = await resolved.client.account.isDeployed(target);\n\n const payload = {\n address: target,\n chainId: resolved.chainId,\n deployed,\n };\n\n if (globals.json) {\n printJson(payload);\n return;\n }\n\n print('');\n print(` ${style.dim('Address ')} ${formatAddress(target, 10, 8)}`);\n print(\n ` ${style.dim('Deployed')} ${deployed ? style.success('yes') : style.dim('no — first UserOp will deploy')}`\n );\n } catch (cause) {\n throw toCliError(cause);\n }\n });\n\nexport const smartAccountCommand = new Command('smart-account')\n .description('Smart-account address derivation and deployment-status checks.')\n .addCommand(computeCommand)\n .addCommand(isDeployedCommand);\n","/**\n * `kash protocol token-id --market-id <bigint> --outcome <n>` —\n * compute the ERC-1155 token id for a `(marketId, outcomeIndex)`\n * pair. Pure offline computation; no RPC required.\n *\n * Wraps `tokenIdFor` from `@kashdao/protocol-sdk`. The `marketId`\n * argument is the on-chain numeric id (read from `IMarket.marketId()`)\n * — NOT the market's contract address.\n */\n\nimport { Command } from 'commander';\n\nimport { CliValidationError, toCliError } from '../../errors.js';\nimport { readGlobals } from '../../utils/global-options.js';\nimport { print, printJson, style } from '../../utils/output.js';\n\ntype TokenIdOptions = {\n marketId: string;\n outcome: string;\n};\n\nexport const tokenIdCommand = new Command('token-id')\n .description(\n 'Compute the ERC-1155 token id for a (marketId, outcomeIndex) pair (offline; no RPC).'\n )\n .requiredOption(\n '-m, --market-id <bigint>',\n 'on-chain numeric market id (decimal or 0x-prefixed hex)'\n )\n .requiredOption('-o, --outcome <index>', 'outcome index (0-255)')\n .addHelpText(\n 'after',\n `\nExamples:\n $ kash protocol token-id --market-id 42 --outcome 0\n $ kash protocol token-id --market-id 0x2a --outcome 1 --json --quiet | jq -r '.tokenId'\n\nNotes:\n - The numeric \\`marketId\\` is the on-chain id read from\n \\`IMarket(<addr>).marketId()\\`. It's NOT the same as the market\n contract address.\n - The token id encoding is \\`(marketId << 8) | outcomeIndex\\`,\n matching the on-chain \\`OutcomeTokens1155\\` contract.\n`\n )\n .action(async (options: TokenIdOptions, cmd: Command) => {\n const globals = readGlobals(cmd);\n\n let marketId: bigint;\n try {\n marketId = BigInt(options.marketId);\n } catch {\n throw new CliValidationError(\n '--market-id must be a non-negative integer (decimal or 0x-hex).',\n `Got \"${options.marketId}\".`,\n 'market-id'\n );\n }\n if (marketId < 0n) {\n throw new CliValidationError(\n '--market-id must be non-negative.',\n `Got \"${options.marketId}\".`,\n 'market-id'\n );\n }\n\n const outcomeIndex = Number.parseInt(options.outcome, 10);\n if (!Number.isFinite(outcomeIndex) || outcomeIndex < 0 || outcomeIndex > 255) {\n throw new CliValidationError(\n '--outcome must be an integer between 0 and 255.',\n `Got \"${options.outcome}\".`,\n 'outcome'\n );\n }\n\n try {\n // Lazy-import the protocol-sdk so this small offline helper\n // doesn't pull viem unnecessarily for the rest of the CLI.\n const { tokenIdFor } = await import('@kashdao/protocol-sdk');\n const tokenId = tokenIdFor(marketId, outcomeIndex);\n\n const payload = {\n marketId: marketId.toString(),\n outcomeIndex,\n tokenId: tokenId.toString(),\n tokenIdHex: `0x${tokenId.toString(16)}`,\n };\n\n if (globals.json) {\n printJson(payload);\n return;\n }\n\n print('');\n print(` ${style.dim('Market id ')} ${marketId.toString()}`);\n print(` ${style.dim('Outcome ')} ${String(outcomeIndex)}`);\n print(` ${style.dim('Token id ')} ${tokenId.toString()}`);\n print(` ${style.dim(' (hex) ')} 0x${tokenId.toString(16)}`);\n } catch (cause) {\n throw toCliError(cause);\n }\n });\n","/**\n * `kash protocol trade buy|sell|close|approve` — one-shot direct-mode\n * trade execution. Wraps `client.trades.send.{buy,sell,closePosition,approve}`\n * which prepares → simulates → signs → submits → (optionally) waits\n * for inclusion.\n *\n * **Real-money paths.** These commands sign and submit transactions\n * with the configured `signerKeyRef` against the configured\n * `bundlerUrl`/`bundlerProvider`. Use `--dry-run` to preview without\n * sending. Use `--no-wait` for fire-and-forget (returns userOpHash\n * immediately).\n *\n * **Safety:**\n * - The SDK's `prepare*` step always runs simulation (`eth_call`\n * preflight) before signing — pass `--no-simulate` to skip if\n * you've already validated and want the round-trip back.\n * - On simulation revert, throws `KashSimulationRevertedError`\n * before the consumer pays signer-infra round-trips.\n * - The signer's owner address is recovered from the signed hash\n * and compared to `signer.ownerAddress`; mismatches throw\n * `KashSignerError(STALE_USEROP_HASH)`.\n */\n\nimport { Command } from 'commander';\nimport ora from 'ora';\n\nimport { toCliError } from '../../errors.js';\nimport { buildDirectClient } from '../../utils/direct-client.js';\nimport { formatAddress } from '../../utils/formatting.js';\nimport { parsePositiveInt, readGlobals } from '../../utils/global-options.js';\nimport { isQuiet, log, print, printJson, style } from '../../utils/output.js';\nimport {\n DEFAULT_SLIPPAGE_BPS,\n MAX_UINT256,\n type TradeOpSide,\n decimalToAtomicUsdc,\n decimalToAtomicWad,\n extractPartialHash,\n parseDeadlineSec,\n parseOutcomeIndex,\n parseSlippageBps,\n validateAddress,\n} from '../../utils/trade-input.js';\nimport { serializeUserOp } from '../../utils/userop-json.js';\n\ntype SharedOptions = {\n outcome?: string;\n slippageBps?: string;\n deadlineSec?: string;\n dryRun?: boolean;\n // Commander stores `--no-simulate` as `{ simulate: false }` — the\n // default for a `--no-X` boolean is `true`, so the explicit `false`\n // means the user passed the negative flag.\n simulate?: boolean;\n wait?: boolean;\n waitTimeoutMs?: string;\n waitIntervalMs?: string;\n};\n\ntype BuyOptions = SharedOptions & { amount: string };\ntype SellOptions = SharedOptions & { tokens: string };\ntype CloseOptions = SharedOptions;\ntype ApproveOptions = {\n amount?: string;\n // Commander stores `--no-X` as `{ x: false }`. See SharedOptions.\n wait?: boolean;\n waitTimeoutMs?: string;\n waitIntervalMs?: string;\n dryRun?: boolean;\n simulate?: boolean;\n};\n\nconst buyCommand = new Command('buy')\n .description('One-shot BUY: prepare → simulate → sign → submit (and wait by default).')\n .argument('<market>', 'market contract address (0x-prefixed)')\n .requiredOption('-o, --outcome <index>', 'outcome index (0-based)')\n .requiredOption('-a, --amount <usdc>', 'USDC to spend (decimal — e.g. \"10\" or \"12.50\")')\n .option('--slippage-bps <n>', 'slippage tolerance in basis points (default 50 = 0.5%)')\n .option('--deadline-sec <n>', 'unix-seconds deadline (default now + 5min)')\n .option('--dry-run', 'prepare + simulate but DO NOT sign or submit; print the UserOp')\n .option('--no-simulate', 'skip the eth_call preflight (faster, riskier)')\n .option('--no-wait', 'fire-and-forget: return userOpHash without waiting for inclusion')\n .option('--wait-timeout-ms <n>', 'cap on the receipt wait (default 60000)')\n .option('--wait-interval-ms <n>', 'receipt poll interval (default 1500)')\n .addHelpText(\n 'after',\n `\nExamples:\n $ kash protocol trade buy 0xMarket... -o 0 -a 10\n $ kash protocol trade buy 0xMarket... -o 0 -a 10 --slippage-bps 100 # 1% slippage\n $ kash protocol trade buy 0xMarket... -o 0 -a 10 --dry-run --json\n $ kash protocol trade buy 0xMarket... -o 0 -a 10 --no-wait --json --quiet\n`\n )\n .action(async (market: string, options: BuyOptions, cmd: Command) => {\n await runTrade('buy', market, options, cmd);\n });\n\nconst sellCommand = new Command('sell')\n .description('One-shot SELL: prepare → simulate → sign → submit (and wait by default).')\n .argument('<market>', 'market contract address (0x-prefixed)')\n .requiredOption('-o, --outcome <index>', 'outcome index (0-based)')\n .requiredOption('-t, --tokens <amount>', 'outcome tokens to sell (decimal — WAD precision)')\n .option('--slippage-bps <n>', 'slippage tolerance in basis points (default 50 = 0.5%)')\n .option('--deadline-sec <n>', 'unix-seconds deadline (default now + 5min)')\n .option('--dry-run', 'prepare + simulate but DO NOT sign or submit; print the UserOp')\n .option('--no-simulate', 'skip the eth_call preflight (faster, riskier)')\n .option('--no-wait', 'fire-and-forget: return userOpHash without waiting for inclusion')\n .option('--wait-timeout-ms <n>', 'cap on the receipt wait (default 60000)')\n .option('--wait-interval-ms <n>', 'receipt poll interval (default 1500)')\n .addHelpText(\n 'after',\n `\nExamples:\n $ kash protocol trade sell 0xMarket... -o 0 -t 1.5\n $ kash protocol trade sell 0xMarket... -o 1 -t 0.5 --json --quiet\n`\n )\n .action(async (market: string, options: SellOptions, cmd: Command) => {\n await runTrade('sell', market, options, cmd);\n });\n\nconst closeCommand = new Command('close')\n .description('Sell the entire SA balance for an outcome (one-shot prepare → submit).')\n .argument('<market>', 'market contract address (0x-prefixed)')\n .requiredOption('-o, --outcome <index>', 'outcome index (0-based)')\n .option('--slippage-bps <n>', 'slippage tolerance in basis points (default 50 = 0.5%)')\n .option('--deadline-sec <n>', 'unix-seconds deadline (default now + 5min)')\n .option('--dry-run', 'prepare + simulate but DO NOT sign or submit; print the UserOp')\n .option('--no-simulate', 'skip the eth_call preflight (faster, riskier)')\n .option('--no-wait', 'fire-and-forget: return userOpHash without waiting for inclusion')\n .option('--wait-timeout-ms <n>', 'cap on the receipt wait (default 60000)')\n .option('--wait-interval-ms <n>', 'receipt poll interval (default 1500)')\n .addHelpText(\n 'after',\n `\nExamples:\n $ kash protocol trade close 0xMarket... -o 0\n $ kash protocol trade close 0xMarket... -o 1 --slippage-bps 200 --json\n`\n )\n .action(async (market: string, options: CloseOptions, cmd: Command) => {\n await runTrade('close', market, options, cmd);\n });\n\nconst approveCommand = new Command('approve')\n .description('USDC approval — required once before the first BUY.')\n .argument('<spender>', 'spender contract address (typically a Market) — 0x-prefixed')\n .option(\n '-a, --amount <usdc>',\n 'atomic-USDC amount to approve (decimal); default is unlimited (MAX_UINT256)'\n )\n .option('--dry-run', 'prepare + simulate but DO NOT sign or submit; print the UserOp')\n .option('--no-simulate', 'skip the eth_call preflight (faster, riskier)')\n .option('--no-wait', 'fire-and-forget: return userOpHash without waiting for inclusion')\n .option('--wait-timeout-ms <n>', 'cap on the receipt wait (default 60000)')\n .option('--wait-interval-ms <n>', 'receipt poll interval (default 1500)')\n .addHelpText(\n 'after',\n `\nExamples:\n $ kash protocol trade approve 0xMarket... # unlimited approval\n $ kash protocol trade approve 0xMarket... --amount 100 # cap at 100 USDC\n $ kash protocol trade approve 0xMarket... --dry-run --json # preview only\n`\n )\n .action(async (spender: string, options: ApproveOptions, cmd: Command) => {\n await runApprove(spender, options, cmd);\n });\n\nexport const tradeCommand = new Command('trade')\n .description('Direct-mode trade execution (UserOp signed locally, submitted via bundler).')\n .addCommand(buyCommand)\n .addCommand(sellCommand)\n .addCommand(closeCommand)\n .addCommand(approveCommand);\n\n// ---------------------------------------------------------------------------\n// Shared runners\n// ---------------------------------------------------------------------------\n\ntype Side = TradeOpSide;\n\nasync function runTrade(\n side: Side,\n market: string,\n options: BuyOptions | SellOptions | CloseOptions,\n cmd: Command\n): Promise<void> {\n const globals = readGlobals(cmd);\n const marketAddress = validateAddress(market, 'market');\n\n const outcome = parseOutcomeIndex(options.outcome);\n const slippageBps = options.slippageBps\n ? parseSlippageBps(options.slippageBps)\n : DEFAULT_SLIPPAGE_BPS;\n const deadline = options.deadlineSec ? parseDeadlineSec(options.deadlineSec) : undefined;\n const waitTimeoutMs = options.waitTimeoutMs\n ? parsePositiveInt(options.waitTimeoutMs, 'wait-timeout-ms')\n : undefined;\n const waitIntervalMs = options.waitIntervalMs\n ? parsePositiveInt(options.waitIntervalMs, 'wait-interval-ms')\n : undefined;\n\n // Side-specific amount parsing.\n let amountUsdc: bigint | undefined;\n let amountTokens: bigint | undefined;\n if (side === 'buy') {\n const buyOpts = options as BuyOptions;\n amountUsdc = decimalToAtomicUsdc(buyOpts.amount, 'amount');\n } else if (side === 'sell') {\n const sellOpts = options as SellOptions;\n amountTokens = decimalToAtomicWad(sellOpts.tokens, 'tokens');\n }\n\n try {\n const resolved = await buildDirectClient({ globals, requireSigner: true });\n\n // --dry-run path: prepare only, emit the populated UserOp + hash.\n // Doesn't sign or submit. Bypasses the wait/submit pipeline.\n if (options.dryRun === true) {\n const built = await prepareForSide(resolved.client, side, {\n market: marketAddress,\n smartAccount: resolved.smartAccount,\n outcome,\n slippageBps,\n ...(deadline === undefined ? {} : { deadline }),\n ...(amountUsdc === undefined ? {} : { amountUsdc }),\n ...(amountTokens === undefined ? {} : { amountTokens }),\n simulate: options.simulate !== false,\n });\n emitDryRun(built, side, market, globals.json);\n return;\n }\n\n const sendOptions = {\n simulate: options.simulate !== false,\n wait: options.wait !== false,\n ...(waitTimeoutMs === undefined ? {} : { waitTimeoutMs }),\n ...(waitIntervalMs === undefined ? {} : { waitIntervalMs }),\n };\n\n const spinner =\n !globals.json && !isQuiet()\n ? ora({\n text: `Preparing ${side} on ${formatAddress(market, 8, 6)}…`,\n stream: process.stderr,\n }).start()\n : undefined;\n\n let result;\n try {\n if (side === 'buy') {\n result = await resolved.client.trades.send.buy(\n marketAddress,\n {\n account: resolved.smartAccount,\n outcome,\n amountUsdc: amountUsdc!,\n maxSlippageBps: slippageBps,\n ...(deadline === undefined ? {} : { deadline }),\n },\n sendOptions\n );\n } else if (side === 'sell') {\n result = await resolved.client.trades.send.sell(\n marketAddress,\n {\n account: resolved.smartAccount,\n outcome,\n amountTokens: amountTokens!,\n maxSlippageBps: slippageBps,\n ...(deadline === undefined ? {} : { deadline }),\n },\n sendOptions\n );\n } else {\n result = await resolved.client.trades.send.closePosition(\n marketAddress,\n {\n account: resolved.smartAccount,\n outcome,\n maxSlippageBps: slippageBps,\n ...(deadline === undefined ? {} : { deadline }),\n },\n sendOptions\n );\n }\n } catch (cause) {\n spinner?.fail(`${side} failed.`);\n // Partial-completion guard. If the SDK's submit step succeeded\n // but the wait step timed out, the cause is a KashBundlerError\n // with `code: 'BUNDLER_RECEIPT_TIMEOUT'` whose `context.userOpHash`\n // carries the hash the bundler will eventually land. Surface\n // that hash so the operator can resume via\n // `kash protocol userop wait <hash>` rather than paying for\n // another sign/submit cycle. The discriminator is narrow on\n // purpose — KashSignerError ALSO carries `context.userOpHash`,\n // and a remote-signer failure would be actively misleading if\n // it was reported as \"submit succeeded, wait timed out\". See\n // `extractPartialUserOpHash` for the discrimination details.\n const partialHash = extractPartialUserOpHash(cause);\n if (partialHash !== undefined) {\n if (globals.json) {\n printJson({ userOpHash: partialHash, waited: false, partial: true });\n } else {\n log.warn(\n `Submit succeeded but wait timed out. UserOp is on the bundler queue — resume with: kash protocol userop wait ${partialHash}`\n );\n }\n }\n throw cause;\n }\n spinner?.succeed(`${side} submitted.`);\n emitSendResult(result, side, market, globals.json);\n } catch (cause) {\n throw toCliError(cause);\n }\n}\n\nasync function runApprove(spender: string, options: ApproveOptions, cmd: Command): Promise<void> {\n const globals = readGlobals(cmd);\n const spenderAddress = validateAddress(spender, 'spender');\n const amount = options.amount ? decimalToAtomicUsdc(options.amount, 'amount') : MAX_UINT256;\n const waitTimeoutMs = options.waitTimeoutMs\n ? parsePositiveInt(options.waitTimeoutMs, 'wait-timeout-ms')\n : undefined;\n const waitIntervalMs = options.waitIntervalMs\n ? parsePositiveInt(options.waitIntervalMs, 'wait-interval-ms')\n : undefined;\n\n try {\n const resolved = await buildDirectClient({ globals, requireSigner: true });\n const params = {\n account: resolved.smartAccount,\n spender: spenderAddress,\n amount,\n };\n\n if (options.dryRun === true) {\n const built = await resolved.client.trades.prepareApprove(params, {\n simulate: options.simulate !== false,\n });\n emitDryRun(built, 'approve', spender, globals.json);\n return;\n }\n\n const sendOptions = {\n simulate: options.simulate !== false,\n wait: options.wait !== false,\n ...(waitTimeoutMs === undefined ? {} : { waitTimeoutMs }),\n ...(waitIntervalMs === undefined ? {} : { waitIntervalMs }),\n };\n\n const spinner =\n !globals.json && !isQuiet()\n ? ora({\n text: `Approving ${formatAddress(spender, 8, 6)}…`,\n stream: process.stderr,\n }).start()\n : undefined;\n\n let result;\n try {\n result = await resolved.client.trades.send.approve(params, sendOptions);\n } catch (cause) {\n spinner?.fail('approve failed.');\n // Symmetric partial-completion guard. Approves cost gas; if\n // submit succeeded but wait timed out, surface `userOpHash`\n // so the operator can resume via `kash protocol userop wait\n // <hash>` rather than paying for a duplicate approve. See\n // `extractPartialUserOpHash` for the discrimination rule.\n const partialHash = extractPartialUserOpHash(cause);\n if (partialHash !== undefined) {\n if (globals.json) {\n printJson({ userOpHash: partialHash, waited: false, partial: true });\n } else {\n log.warn(\n `Submit succeeded but wait timed out. The approve UserOp is on the bundler queue — resume with: kash protocol userop wait ${partialHash}`\n );\n }\n }\n throw cause;\n }\n spinner?.succeed('approve submitted.');\n emitSendResult(result, 'approve', spender, globals.json);\n } catch (cause) {\n throw toCliError(cause);\n }\n}\n\n// ---------------------------------------------------------------------------\n// SDK call adapters\n// ---------------------------------------------------------------------------\n\n/**\n * Route prepare to the right SDK method by side. We pass the\n * intersection-typed params and let TypeScript narrow.\n */\nasync function prepareForSide(\n client: Awaited<ReturnType<typeof buildDirectClient>>['client'],\n side: Side,\n args: {\n market: `0x${string}`;\n /** SA address whose `execute()` will run the trade. Mapped to `account` on the SDK shape. */\n smartAccount: `0x${string}`;\n outcome: number;\n slippageBps: number;\n deadline?: bigint;\n amountUsdc?: bigint;\n amountTokens?: bigint;\n simulate: boolean;\n }\n): Promise<Awaited<ReturnType<typeof client.trades.prepareBuy>>> {\n const opts = { simulate: args.simulate };\n // The protocol-sdk's BuildBuy/Sell/ClosePositionParams use\n // `account` (the address that pays USDC and receives outcome\n // tokens). In SA mode, the operator-facing concept is \"the smart\n // account\" — we keep `smartAccount` as the local name and map at\n // the boundary so the rest of the file reads naturally.\n const baseParams = {\n account: args.smartAccount,\n outcome: args.outcome,\n maxSlippageBps: args.slippageBps,\n ...(args.deadline === undefined ? {} : { deadline: args.deadline }),\n };\n if (side === 'buy') {\n return await client.trades.prepareBuy(\n args.market,\n { ...baseParams, amountUsdc: args.amountUsdc! },\n opts\n );\n }\n if (side === 'sell') {\n return await client.trades.prepareSell(\n args.market,\n { ...baseParams, amountTokens: args.amountTokens! },\n opts\n );\n }\n return await client.trades.prepareClosePosition(args.market, baseParams, opts);\n}\n\n// ---------------------------------------------------------------------------\n// Output emitters\n// ---------------------------------------------------------------------------\n\ntype BuiltLike = Awaited<\n ReturnType<Awaited<ReturnType<typeof buildDirectClient>>['client']['trades']['prepareBuy']>\n>;\n\nfunction emitDryRun(built: BuiltLike, side: Side | 'approve', target: string, json: boolean): void {\n // Pre-convert bigints to decimal strings via the shared encoder.\n // `printJson`'s `jsonReplacer` would coerce these on the JSON branch\n // anyway, but the human branch below also reads `userOp.sender` and\n // `userOp.nonce` for the dry-run summary, so we need the converted\n // shape *before* we know which branch we're on. Don't add a third\n // bigint encoder here — `utils/userop-json.ts` is the canonical one.\n const userOp = serializeUserOp(built.userOp);\n if (json) {\n printJson({\n side,\n target,\n userOp,\n userOpHash: built.userOpHash,\n typedData: built.typedData,\n dryRun: true,\n });\n return;\n }\n print('');\n print(` ${style.bold('Dry run')} — UserOp prepared but NOT signed/submitted.`);\n print(` ${style.dim('Side ')} ${side}`);\n print(` ${style.dim('Target ')} ${formatAddress(target, 10, 8)}`);\n const senderRaw = userOp['sender'];\n const sender = typeof senderRaw === 'string' ? senderRaw : '';\n print(` ${style.dim('Sender ')} ${formatAddress(sender, 10, 8)}`);\n print(` ${style.dim('Nonce ')} ${String(userOp['nonce'])}`);\n print(` ${style.dim('Hash ')} ${built.userOpHash}`);\n print('');\n print(style.dim('Re-run without --dry-run to sign and submit.'));\n}\n\ntype SendResultLike =\n | { userOpHash: `0x${string}` }\n | {\n userOpHash: `0x${string}`;\n transactionHash: `0x${string}`;\n blockNumber: bigint;\n success: boolean;\n // SDK type is `gasUsed` (see protocol-sdk's SendResultWaited).\n // The earlier alias `actualGasUsed` here was a copy of the\n // bundler-receipt field name, but the SDK normalises that into\n // `gasUsed: BigInt(receipt.actualGasUsed)` before returning.\n gasUsed: bigint;\n };\n\nfunction emitSendResult(\n result: SendResultLike,\n side: Side | 'approve',\n target: string,\n json: boolean\n): void {\n const waited = 'transactionHash' in result;\n const payload = waited\n ? {\n side,\n target,\n userOpHash: result.userOpHash,\n transactionHash: result.transactionHash,\n blockNumber: result.blockNumber.toString(),\n success: result.success,\n actualGasUsed: result.gasUsed.toString(),\n }\n : {\n side,\n target,\n userOpHash: result.userOpHash,\n waited: false,\n };\n if (json) {\n printJson(payload);\n return;\n }\n print('');\n if (waited) {\n if (result.success) {\n log.success(`${side} included in block ${result.blockNumber.toString()}.`);\n } else {\n log.error(`${side} included but reverted on-chain.`);\n }\n print(` ${style.dim('UserOp ')} ${result.userOpHash}`);\n print(` ${style.dim('Tx ')} ${result.transactionHash}`);\n print(` ${style.dim('Block ')} ${result.blockNumber.toString()}`);\n print(` ${style.dim('Gas used ')} ${result.gasUsed.toString()}`);\n } else {\n log.success(`${side} submitted (fire-and-forget).`);\n print(` ${style.dim('UserOp ')} ${result.userOpHash}`);\n log.info(`Use \\`kash protocol userop wait ${result.userOpHash}\\` to poll for inclusion.`);\n }\n}\n\n/**\n * SA-mode wrapper around the canonical `extractPartialHash` factory\n * (`utils/trade-input.ts`). Pinned to the bundler-timeout code so\n * pre-submit failures (`KashSignerError SIGNER_SIGN_FAILED` carries\n * `context.userOpHash` too) don't masquerade as partial completions.\n *\n * SDK throw site: `protocol-sdk/src/smart-account/bundler/generic.ts:337-341`.\n * Counter-case: `protocol-sdk/src/smart-account/trades/send.ts:222-226`.\n */\nfunction extractPartialUserOpHash(cause: unknown): `0x${string}` | undefined {\n return extractPartialHash(cause, {\n code: 'BUNDLER_RECEIPT_TIMEOUT',\n contextKey: 'userOpHash',\n });\n}\n\n// All input parsers live in `utils/trade-input.ts` — single source of\n// truth so SA-mode (`kash protocol trade`), userop-build, and EOA-mode\n// (`kash eoa trade`) behaviour can never drift on real-money paths.\n//\n// The UserOp bigint→string encoder lives in `utils/userop-json.ts`;\n// the same encoder is used by `userop build / sign / submit`, so a\n// `--print-userop` payload round-trips through the offline signer\n// pipeline byte-for-byte.\n","/**\n * JSON (de)serialisation helpers for ERC-4337 v0.7 UserOps.\n *\n * Two consumers share this module:\n *\n * - `kash protocol trade` (SA mode) emits the prepared UserOp on the\n * `--print-userop` path so an external signer can consume it.\n * - `kash protocol userop build / sign / submit / wait` round-trips\n * UserOps through disk and stdin via the same JSON shape.\n *\n * Both entered the codebase with their own local copy of the bigint→\n * string encoder, which is a real-money divergence risk: a UserOp\n * round-tripped through `trade --print-userop | userop sign --in -`\n * is the textbook \"operator builds + offline signs\" flow, and any\n * field that one side stringifies but the other does not would silently\n * change the call's gas semantics.\n *\n * The encoder is the load-bearing primitive; the decoder lives in\n * `userop.ts` next to the `UnsignedUserOp` field-shape declarations\n * that drive its bigint-field whitelist.\n */\n\n/**\n * Convert a UserOp's bigint fields (`nonce`, `callGasLimit`, gas\n * limits, fees, etc.) to decimal strings so the envelope round-trips\n * through `JSON.stringify`. Non-bigint fields pass through untouched.\n *\n * The shape is the inverse of `userop.ts:deserializeUserOp` — keep\n * the two in lockstep when adding new bigint fields to the SDK's\n * UnsignedUserOp.\n */\nexport function serializeUserOp(userOp: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(userOp)) {\n out[k] = typeof v === 'bigint' ? v.toString() : v;\n }\n return out;\n}\n","/**\n * `kash protocol userop {build,simulate,submit,hash,receipt,wait}` —\n * granular UserOp lifecycle for direct-mode cold-storage flows.\n *\n * Pairs with `kash protocol trade` (the all-in-one path). Use this\n * namespace when you need to:\n * - Build a UserOp on machine A (no signer; `noopSigner` plumbing).\n * - Move the UserOp to machine B (signer-only).\n * - Submit from machine C against the bundler.\n *\n * **File format.** Each command that takes/emits a UserOp uses the\n * canonical JSON shape (bigints serialized as decimal strings).\n * Reading from stdin is supported (`-` argument or no argument);\n * writing goes to stdout (or `--out <path>`).\n *\n * **`build`** uses the SDK's `prepare*` under the hood (build + gas\n * estimation + fees + hash recompute) — the resulting UserOp is fully\n * populated and ready to sign. This matches the cold-storage flow\n * users expect: build once, sign offline, submit later.\n */\n\nimport { readFile, writeFile } from 'node:fs/promises';\n\nimport { Command } from 'commander';\n\nimport { CliError, CliValidationError, toCliError } from '../../errors.js';\nimport { buildDirectClient } from '../../utils/direct-client.js';\nimport { formatAddress } from '../../utils/formatting.js';\nimport { parsePositiveInt, readGlobals } from '../../utils/global-options.js';\nimport { log, print, printJson, style } from '../../utils/output.js';\nimport {\n DEFAULT_SLIPPAGE_BPS,\n HEX_HASH_REGEX,\n MAX_UINT256,\n decimalToAtomicUsdc,\n decimalToAtomicWad,\n parseDeadlineSec,\n parseOutcomeIndex,\n parseSlippageBps,\n validateAddress,\n} from '../../utils/trade-input.js';\nimport { serializeUserOp } from '../../utils/userop-json.js';\n\n// ---------------------------------------------------------------------------\n// `userop build buy|sell|close|approve`\n// ---------------------------------------------------------------------------\n\ntype BuildSharedOptions = {\n outcome?: string;\n slippageBps?: string;\n deadlineSec?: string;\n out?: string;\n // Commander stores `--no-simulate` as `{ simulate: false }`.\n simulate?: boolean;\n};\n\nconst buildBuyCommand = new Command('buy')\n .description('Build a fully-populated unsigned BUY UserOp ready for offline signing.')\n .argument('<market>', 'market contract address (0x-prefixed)')\n .requiredOption('-o, --outcome <index>', 'outcome index (0-based)')\n .requiredOption('-a, --amount <usdc>', 'USDC to spend (decimal)')\n .option('--slippage-bps <n>', 'slippage tolerance in bps (default 50 = 0.5%)')\n .option('--deadline-sec <n>', 'unix-seconds deadline (default now + 5min)')\n .option('--out <path>', 'write the UserOp envelope to a file (default stdout)')\n .option('--no-simulate', 'skip eth_call preflight in `prepare`')\n .action(\n async (market: string, options: BuildSharedOptions & { amount: string }, cmd: Command) => {\n await runBuild('buy', market, options, cmd);\n }\n );\n\nconst buildSellCommand = new Command('sell')\n .description('Build a fully-populated unsigned SELL UserOp ready for offline signing.')\n .argument('<market>', 'market contract address (0x-prefixed)')\n .requiredOption('-o, --outcome <index>', 'outcome index (0-based)')\n .requiredOption('-t, --tokens <amount>', 'outcome tokens to sell (WAD decimal)')\n .option('--slippage-bps <n>', 'slippage tolerance in bps (default 50 = 0.5%)')\n .option('--deadline-sec <n>', 'unix-seconds deadline (default now + 5min)')\n .option('--out <path>', 'write the UserOp envelope to a file (default stdout)')\n .option('--no-simulate', 'skip eth_call preflight in `prepare`')\n .action(\n async (market: string, options: BuildSharedOptions & { tokens: string }, cmd: Command) => {\n await runBuild('sell', market, options, cmd);\n }\n );\n\nconst buildCloseCommand = new Command('close')\n .description('Build a fully-populated unsigned UserOp that closes a position (full balance).')\n .argument('<market>', 'market contract address (0x-prefixed)')\n .requiredOption('-o, --outcome <index>', 'outcome index (0-based)')\n .option('--slippage-bps <n>', 'slippage tolerance in bps (default 50 = 0.5%)')\n .option('--deadline-sec <n>', 'unix-seconds deadline (default now + 5min)')\n .option('--out <path>', 'write the UserOp envelope to a file (default stdout)')\n .option('--no-simulate', 'skip eth_call preflight in `prepare`')\n .action(async (market: string, options: BuildSharedOptions, cmd: Command) => {\n await runBuild('close', market, options, cmd);\n });\n\nconst buildApproveCommand = new Command('approve')\n .description('Build a fully-populated unsigned approve UserOp ready for offline signing.')\n .argument('<spender>', 'spender contract address (typically a Market) — 0x-prefixed')\n .option('-a, --amount <usdc>', 'atomic-USDC amount (decimal); default unlimited (MAX_UINT256)')\n .option('--out <path>', 'write the UserOp envelope to a file (default stdout)')\n .option('--no-simulate', 'skip eth_call preflight in `prepare`')\n .action(\n async (\n spender: string,\n options: { amount?: string; out?: string; simulate?: boolean },\n cmd: Command\n ) => {\n await runBuildApprove(spender, options, cmd);\n }\n );\n\nconst buildCommand = new Command('build')\n .description('Build (prepare) a fully-populated unsigned UserOp ready for offline signing.')\n .addCommand(buildBuyCommand)\n .addCommand(buildSellCommand)\n .addCommand(buildCloseCommand)\n .addCommand(buildApproveCommand);\n\ntype BuildSide = 'buy' | 'sell' | 'close';\n\nasync function runBuild(\n side: BuildSide,\n market: string,\n options: BuildSharedOptions & { amount?: string; tokens?: string },\n cmd: Command\n): Promise<void> {\n const globals = readGlobals(cmd);\n const marketAddress = validateAddress(market, 'market');\n const outcome = parseOutcomeIndex(options.outcome);\n const slippageBps = options.slippageBps\n ? parseSlippageBps(options.slippageBps)\n : DEFAULT_SLIPPAGE_BPS;\n const deadline = options.deadlineSec ? parseDeadlineSec(options.deadlineSec) : undefined;\n\n let amountUsdc: bigint | undefined;\n let amountTokens: bigint | undefined;\n if (side === 'buy') {\n amountUsdc = decimalToAtomicUsdc(options.amount!, 'amount');\n } else if (side === 'sell') {\n amountTokens = decimalToAtomicWad(options.tokens!, 'tokens');\n }\n\n try {\n // `requireSigner: false` because build doesn't need to sign —\n // the noopSigner suffices. The cold-storage flow signs externally.\n const resolved = await buildDirectClient({ globals });\n // The protocol-sdk migrated `smartAccount` → `account` on its\n // BuildBuyParams / BuildSellParams / BuildClosePositionParams\n // shapes. The field still resolves to the same address (the SA\n // we configured); only the parameter name changed. EOA mode also\n // uses `account` (with a different invariant — owner must equal\n // signer.ownerAddress); SA mode is \"the SA whose execute() runs.\"\n const baseParams = {\n account: resolved.smartAccount,\n outcome,\n maxSlippageBps: slippageBps,\n ...(deadline === undefined ? {} : { deadline }),\n };\n const opts = { simulate: options.simulate !== false };\n\n let built;\n if (side === 'buy') {\n built = await resolved.client.trades.prepareBuy(\n marketAddress,\n { ...baseParams, amountUsdc: amountUsdc! },\n opts\n );\n } else if (side === 'sell') {\n built = await resolved.client.trades.prepareSell(\n marketAddress,\n { ...baseParams, amountTokens: amountTokens! },\n opts\n );\n } else {\n built = await resolved.client.trades.prepareClosePosition(marketAddress, baseParams, opts);\n }\n\n await emitBuildResult(built, side, market, options.out, globals.json);\n } catch (cause) {\n throw toCliError(cause);\n }\n}\n\nasync function runBuildApprove(\n spender: string,\n options: { amount?: string; out?: string; simulate?: boolean },\n cmd: Command\n): Promise<void> {\n const globals = readGlobals(cmd);\n const spenderAddress = validateAddress(spender, 'spender');\n const amount = options.amount ? decimalToAtomicUsdc(options.amount, 'amount') : MAX_UINT256;\n\n try {\n const resolved = await buildDirectClient({ globals });\n const built = await resolved.client.trades.prepareApprove(\n {\n account: resolved.smartAccount,\n spender: spenderAddress,\n amount,\n },\n { simulate: options.simulate !== false }\n );\n await emitBuildResult(built, 'approve', spender, options.out, globals.json);\n } catch (cause) {\n throw toCliError(cause);\n }\n}\n\n// ---------------------------------------------------------------------------\n// `userop simulate`\n// ---------------------------------------------------------------------------\n\nconst simulateCommand = new Command('simulate')\n .description('Simulate (eth_call) an UnsignedUserOp from a file or stdin.')\n .argument('[file]', 'path to a UserOp JSON file (omit or pass \"-\" for stdin)')\n .addHelpText(\n 'after',\n `\nExamples:\n $ kash protocol userop build buy 0xMarket... -o 0 -a 10 --out trade.json\n $ kash protocol userop simulate trade.json\n $ cat trade.json | kash protocol userop simulate\n`\n )\n .action(async (file: string | undefined, _opts, cmd: Command) => {\n const globals = readGlobals(cmd);\n try {\n const userOp = await readUnsignedUserOp(file);\n const resolved = await buildDirectClient({ globals });\n const result = await resolved.client.trades.simulate(userOp);\n\n if (globals.json) {\n printJson(serializeSimulationResult(result));\n return;\n }\n print('');\n if (result.willSucceed) {\n log.success('Simulation: would succeed.');\n if (result.gasEstimate !== undefined) {\n print(` ${style.dim('Gas estimate ')} ${result.gasEstimate.toString()}`);\n }\n } else {\n log.error('Simulation: would revert.');\n print(` ${style.dim('Reason ')} ${result.revertReason}`);\n if (result.decodedError) {\n print(` ${style.dim('Custom err')} ${result.decodedError.name}`);\n }\n }\n } catch (cause) {\n throw toCliError(cause);\n }\n });\n\n// ---------------------------------------------------------------------------\n// `userop submit`\n// ---------------------------------------------------------------------------\n\ntype SubmitOptions = {\n skipStalenessCheck?: boolean;\n wait?: boolean;\n waitTimeoutMs?: string;\n waitIntervalMs?: string;\n};\n\nconst submitCommand = new Command('submit')\n .description('Submit a SignedUserOp from a file or stdin to the configured bundler.')\n .argument('[file]', 'path to a SignedUserOp JSON file (omit or pass \"-\" for stdin)')\n .option('--skip-staleness-check', 'bypass the EIP-191 staleness check (for typed-data signers)')\n .option('--wait', 'wait for receipt after submitting')\n .option('--wait-timeout-ms <n>', 'cap on the receipt wait (default 60000)')\n .option('--wait-interval-ms <n>', 'receipt poll interval (default 1500)')\n .addHelpText(\n 'after',\n `\nExamples:\n $ kash protocol userop submit signed.json --json\n $ cat signed.json | kash protocol userop submit --wait\n`\n )\n .action(async (file: string | undefined, options: SubmitOptions, cmd: Command) => {\n const globals = readGlobals(cmd);\n const waitTimeoutMs = options.waitTimeoutMs\n ? parsePositiveInt(options.waitTimeoutMs, 'wait-timeout-ms')\n : undefined;\n const waitIntervalMs = options.waitIntervalMs\n ? parsePositiveInt(options.waitIntervalMs, 'wait-interval-ms')\n : undefined;\n\n try {\n const signed = await readSignedUserOp(file);\n const resolved = await buildDirectClient({ globals });\n const result = await resolved.client.trades.submit(signed, {\n skipStalenessCheck: options.skipStalenessCheck === true,\n });\n\n if (options.wait !== true) {\n if (globals.json) {\n printJson({ userOpHash: result.userOpHash, waited: false });\n return;\n }\n log.success('UserOp submitted.');\n print(` ${style.dim('Hash')} ${result.userOpHash}`);\n log.info(`Use \\`kash protocol userop wait ${result.userOpHash}\\` to poll for inclusion.`);\n return;\n }\n\n const waitOpts = {\n ...(waitTimeoutMs === undefined ? {} : { timeoutMs: waitTimeoutMs }),\n ...(waitIntervalMs === undefined ? {} : { intervalMs: waitIntervalMs }),\n };\n\n // Partial-completion guard. The submit() above succeeded — the\n // UserOp is on the bundler's queue and will eventually land\n // even if our local wait times out. Surface `userOpHash` on\n // BOTH stderr and (for --json) the error envelope before\n // rethrowing, so the operator can resume via\n // `kash protocol userop wait <hash>` instead of paying for\n // another sign/submit cycle. The hash MUST persist before the\n // receipt wait so we never lose track of an in-flight UserOp.\n let receipt: Awaited<ReturnType<typeof resolved.client.bundler.waitForReceipt>>;\n try {\n receipt = await resolved.client.bundler.waitForReceipt(result.userOpHash, waitOpts);\n } catch (waitCause) {\n if (globals.json) {\n // Emit the hash on stdout as a structured partial-success\n // record before letting toCliError build the error envelope.\n // Two NDJSON lines are easier for agents to parse than a\n // merged error+hash blob.\n printJson({ userOpHash: result.userOpHash, waited: false, partial: true });\n } else {\n log.warn(\n `Submit succeeded but wait failed. UserOp is on the bundler queue — resume with: kash protocol userop wait ${result.userOpHash}`\n );\n }\n throw toCliError(waitCause);\n }\n\n if (globals.json) {\n printJson(serializeReceipt(receipt));\n return;\n }\n emitReceiptHuman(receipt);\n } catch (cause) {\n throw toCliError(cause);\n }\n });\n\n// ---------------------------------------------------------------------------\n// `userop hash`\n// ---------------------------------------------------------------------------\n\nconst hashCommand = new Command('hash')\n .description('Recompute the canonical EIP-4337 v0.7 hash for a UnsignedUserOp.')\n .argument('[file]', 'path to a UserOp JSON file (omit or pass \"-\" for stdin)')\n .addHelpText(\n 'after',\n `\nExamples:\n $ kash protocol userop hash trade.json\n $ cat trade.json | kash protocol userop hash --json --quiet | jq -r '.userOpHash'\n\nNotes:\n - The hash baked into a freshly-built UserOp goes stale after gas\n fields are populated. Always recompute via this command (or\n \\`hashOf\\` in the SDK) before signing.\n`\n )\n .action(async (file: string | undefined, _opts, cmd: Command) => {\n const globals = readGlobals(cmd);\n try {\n const userOp = await readUnsignedUserOp(file);\n const resolved = await buildDirectClient({ globals });\n const userOpHash = resolved.client.trades.hashOf(userOp);\n\n if (globals.json) {\n printJson({ userOpHash });\n return;\n }\n print(userOpHash);\n } catch (cause) {\n throw toCliError(cause);\n }\n });\n\n// ---------------------------------------------------------------------------\n// `userop receipt` / `userop wait`\n// ---------------------------------------------------------------------------\n\nconst receiptCommand = new Command('receipt')\n .description('Fetch the bundler receipt for a UserOp hash (null if not yet included).')\n .argument('<hash>', 'UserOp hash (0x-prefixed, 32 bytes)')\n .addHelpText(\n 'after',\n `\nExamples:\n $ kash protocol userop receipt 0xabc...\n $ kash protocol userop receipt 0xabc... --json --quiet | jq -r '.success'\n`\n )\n .action(async (hash: string, _opts, cmd: Command) => {\n const globals = readGlobals(cmd);\n if (!HEX_HASH_REGEX.test(hash)) {\n throw new CliValidationError(\n '<hash> must be a 0x-prefixed 32-byte hex hash.',\n `Got \"${hash}\".`,\n 'hash'\n );\n }\n try {\n const resolved = await buildDirectClient({ globals });\n const receipt = await resolved.client.bundler.getReceipt(hash as `0x${string}`);\n\n if (globals.json) {\n printJson(receipt === null ? null : serializeReceipt(receipt));\n return;\n }\n if (receipt === null) {\n log.info('Not yet included (receipt is null).');\n return;\n }\n emitReceiptHuman(receipt);\n } catch (cause) {\n throw toCliError(cause);\n }\n });\n\nconst waitCommand = new Command('wait')\n .description('Wait for a UserOp to be included; polls with exponential backoff.')\n .argument('<hash>', 'UserOp hash (0x-prefixed, 32 bytes)')\n .option(\n '--wait-timeout-ms, --timeout-ms <n>',\n 'total time budget across polls (default 60000) — distinct from the global --timeout-ms (per-HTTP-request)'\n )\n .option('--interval-ms <n>', 'poll interval (default 1500)')\n .addHelpText(\n 'after',\n `\nExamples:\n $ kash protocol userop wait 0xabc...\n $ kash protocol userop wait 0xabc... --wait-timeout-ms 300000 # 5min budget\n`\n )\n .action(\n async (hash: string, options: { timeoutMs?: string; intervalMs?: string }, cmd: Command) => {\n const globals = readGlobals(cmd);\n if (!HEX_HASH_REGEX.test(hash)) {\n throw new CliValidationError(\n '<hash> must be a 0x-prefixed 32-byte hex hash.',\n `Got \"${hash}\".`,\n 'hash'\n );\n }\n const timeoutMs = options.timeoutMs\n ? parsePositiveInt(options.timeoutMs, 'timeout-ms')\n : undefined;\n const intervalMs = options.intervalMs\n ? parsePositiveInt(options.intervalMs, 'interval-ms')\n : undefined;\n\n try {\n const resolved = await buildDirectClient({ globals });\n const waitOpts = {\n ...(timeoutMs === undefined ? {} : { timeoutMs }),\n ...(intervalMs === undefined ? {} : { intervalMs }),\n };\n const receipt = await resolved.client.bundler.waitForReceipt(\n hash as `0x${string}`,\n waitOpts\n );\n if (globals.json) {\n printJson(serializeReceipt(receipt));\n return;\n }\n emitReceiptHuman(receipt);\n } catch (cause) {\n throw toCliError(cause);\n }\n }\n );\n\n// ---------------------------------------------------------------------------\n// Top-level userop namespace\n// ---------------------------------------------------------------------------\n\nexport const useropCommand = new Command('userop')\n .description('Granular UserOp lifecycle: build, simulate, submit, hash, receipt, wait.')\n .addCommand(buildCommand)\n .addCommand(simulateCommand)\n .addCommand(submitCommand)\n .addCommand(hashCommand)\n .addCommand(receiptCommand)\n .addCommand(waitCommand);\n\n// ---------------------------------------------------------------------------\n// File IO + serialization\n// ---------------------------------------------------------------------------\n\ntype UnsignedUserOp = Awaited<\n ReturnType<Awaited<ReturnType<typeof buildDirectClient>>['client']['trades']['prepareBuy']>\n>['userOp'];\n\ntype SignedUserOp = UnsignedUserOp & { signature: `0x${string}` };\n\nasync function emitBuildResult(\n built: { userOp: UnsignedUserOp; userOpHash: `0x${string}`; typedData: unknown },\n side: BuildSide | 'approve',\n target: string,\n outPath: string | undefined,\n json: boolean\n): Promise<void> {\n const payload = {\n side,\n target,\n userOp: serializeUserOp(built.userOp),\n userOpHash: built.userOpHash,\n typedData: built.typedData,\n };\n const serialized = JSON.stringify(payload, null, 2);\n\n if (outPath) {\n try {\n await writeFile(outPath, `${serialized}\\n`, { encoding: 'utf8', mode: 0o600 });\n } catch (cause) {\n throw new CliError(`Failed to write ${outPath}.`, {\n code: 'CONFIGURATION',\n recoverable: true,\n suggestion: 'Verify the path is writable and the parent directory exists.',\n cause,\n });\n }\n if (!json) {\n log.success(`Wrote ${outPath} (mode 0600).`);\n print(` ${style.dim('Side ')} ${side}`);\n print(` ${style.dim('Target')} ${formatAddress(target, 10, 8)}`);\n print(` ${style.dim('Hash ')} ${built.userOpHash}`);\n }\n return;\n }\n\n if (json) {\n printJson(payload);\n return;\n }\n // Human-mode without --out: emit a compact line + the JSON payload to\n // stderr-vs-stdout split. Keep stdout pure-JSON so it can pipe.\n log.success(`Built ${side} UserOp.`);\n log.detail('Hash', built.userOpHash);\n print(serialized);\n}\n\n/** Read a UserOp envelope (from `userop build`) and unpack the inner UserOp. */\nasync function readUnsignedUserOp(file: string | undefined): Promise<UnsignedUserOp> {\n const raw = await readSource(file);\n const parsed = parseEnvelope(raw);\n return deserializeUserOp(parsed.userOp) as UnsignedUserOp;\n}\n\n/**\n * Canonical 65-byte ECDSA signature shape: `0x` + 130 hex chars.\n * Some signers (Ledger, certain managed-signer / HSM flows) emit a\n * longer ERC-1271 / aggregate-style signature, so we accept any\n * 0x-prefixed hex string of even length ≥ 130 — but reject the empty\n * `0x` and sub-65-byte truncations early so the bundler doesn't have\n * to.\n */\nconst SIGNED_USEROP_SIG_REGEX = /^0x([0-9a-fA-F]{2})+$/;\n\n/** Read a signed UserOp; the signature must already be set. */\nasync function readSignedUserOp(file: string | undefined): Promise<SignedUserOp> {\n const raw = await readSource(file);\n const parsed = parseEnvelope(raw);\n const userOp = deserializeUserOp(parsed.userOp) as UnsignedUserOp;\n const signature = (userOp as unknown as { signature?: unknown }).signature;\n if (typeof signature !== 'string' || signature === '0x') {\n throw new CliValidationError(\n 'UserOp envelope is missing a non-empty `signature` field.',\n 'Sign the userOp externally and write the resulting signature into the `userOp.signature` field.'\n );\n }\n // Shape check first (catches typos, accidental truncation, base64\n // signatures that snuck in). Length check second (must be at least\n // a 65-byte ECDSA signature; longer signatures are accepted to\n // support ERC-1271 / aggregate signers).\n if (!SIGNED_USEROP_SIG_REGEX.test(signature)) {\n throw new CliValidationError(\n 'UserOp `signature` must be a 0x-prefixed hex string with even-length payload.',\n `Got ${String(signature.length)} characters. Expected at least 132 (0x + 130 hex chars for a 65-byte ECDSA signature).`\n );\n }\n if (signature.length < 132) {\n throw new CliValidationError(\n 'UserOp `signature` is too short to be a valid ECDSA signature.',\n `Got ${String(signature.length)} hex chars; canonical ECDSA signatures are 132 (0x + 130). Did the signer truncate output?`\n );\n }\n return userOp as SignedUserOp;\n}\n\nasync function readSource(file: string | undefined): Promise<string> {\n if (file !== undefined && file !== '-') {\n try {\n return await readFile(file, 'utf8');\n } catch (cause) {\n throw new CliError(`Failed to read ${file}.`, {\n code: 'CONFIGURATION',\n recoverable: true,\n suggestion: 'Verify the path exists and is readable.',\n cause,\n });\n }\n }\n // Stdin.\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n if (typeof chunk === 'string') chunks.push(Buffer.from(chunk));\n else if (chunk instanceof Buffer) chunks.push(chunk);\n else chunks.push(Buffer.from(chunk as Uint8Array));\n }\n if (chunks.length === 0) {\n throw new CliValidationError(\n 'No input received on stdin.',\n 'Pass a file path or pipe a UserOp JSON envelope into stdin.'\n );\n }\n // Strip a leading UTF-8 BOM. Required for files exported from\n // Notepad / VSCode-with-utf8bom — JSON.parse chokes on the leading\n // U+FEFF byte otherwise.\n const { stripBom } = await import('../../utils/stdin.js');\n return stripBom(Buffer.concat(chunks).toString('utf8'));\n}\n\nfunction parseEnvelope(raw: string): { userOp: Record<string, unknown> } {\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw new CliValidationError(\n 'Input is not valid JSON.',\n 'Expected the JSON output of `kash protocol userop build`.'\n );\n }\n if (\n typeof parsed !== 'object' ||\n parsed === null ||\n typeof (parsed as { userOp?: unknown }).userOp !== 'object' ||\n (parsed as { userOp?: unknown }).userOp === null\n ) {\n throw new CliValidationError(\n 'Input does not contain a `userOp` object.',\n 'The envelope must look like { userOp: {...}, userOpHash: \"0x…\", typedData: {...} }.'\n );\n }\n return parsed as { userOp: Record<string, unknown> };\n}\n\n/** Reverse of `serializeUserOp`. Bigint-shaped fields are decoded back. */\nfunction deserializeUserOp(input: Record<string, unknown>): Record<string, unknown> {\n // The bigint-typed fields per UnsignedUserOp's declaration.\n const BIGINT_FIELDS = new Set([\n 'nonce',\n 'callGasLimit',\n 'verificationGasLimit',\n 'preVerificationGas',\n 'maxFeePerGas',\n 'maxPriorityFeePerGas',\n 'paymasterVerificationGasLimit',\n 'paymasterPostOpGasLimit',\n ]);\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(input)) {\n if (BIGINT_FIELDS.has(k) && typeof v === 'string') {\n try {\n out[k] = BigInt(v);\n } catch {\n throw new CliValidationError(\n `UserOp field \"${k}\" is not a valid bigint string.`,\n `Got ${typeof v === 'string' ? `\"${v}\"` : String(v)}.`\n );\n }\n } else {\n out[k] = v;\n }\n }\n return out;\n}\n\ntype UserOpReceipt = {\n userOpHash: `0x${string}`;\n sender: `0x${string}`;\n nonce: `0x${string}`;\n success: boolean;\n actualGasCost: `0x${string}`;\n actualGasUsed: `0x${string}`;\n receipt: {\n transactionHash: `0x${string}`;\n blockNumber: `0x${string}`;\n status: `0x${string}`;\n };\n};\n\nfunction serializeReceipt(receipt: UserOpReceipt): Record<string, unknown> {\n return {\n userOpHash: receipt.userOpHash,\n sender: receipt.sender,\n nonce: receipt.nonce,\n success: receipt.success,\n actualGasCost: receipt.actualGasCost,\n actualGasUsed: receipt.actualGasUsed,\n receipt: {\n transactionHash: receipt.receipt.transactionHash,\n blockNumber: receipt.receipt.blockNumber,\n status: receipt.receipt.status,\n },\n };\n}\n\nfunction emitReceiptHuman(receipt: UserOpReceipt): void {\n print('');\n if (receipt.success) {\n log.success('UserOp included successfully.');\n } else {\n log.error('UserOp included but reverted on-chain.');\n }\n print(` ${style.dim('UserOp ')} ${receipt.userOpHash}`);\n print(` ${style.dim('Tx ')} ${receipt.receipt.transactionHash}`);\n print(` ${style.dim('Block ')} ${receipt.receipt.blockNumber}`);\n print(` ${style.dim('Gas ')} ${receipt.actualGasUsed}`);\n}\n\ntype SimulationResultLike =\n | { willSucceed: true; gasEstimate?: bigint }\n | {\n willSucceed: false;\n revertReason: string;\n decodedError: { name: string; args: readonly unknown[] } | undefined;\n };\n\nfunction serializeSimulationResult(result: SimulationResultLike): Record<string, unknown> {\n if (result.willSucceed) {\n return {\n willSucceed: true,\n ...(result.gasEstimate === undefined ? {} : { gasEstimate: result.gasEstimate.toString() }),\n };\n }\n return {\n willSucceed: false,\n revertReason: result.revertReason,\n ...(result.decodedError === undefined\n ? {}\n : {\n decodedError: {\n name: result.decodedError.name,\n args: result.decodedError.args.map((a) => (typeof a === 'bigint' ? a.toString() : a)),\n },\n }),\n };\n}\n\n// All input parsers (parseOutcomeIndex, parseSlippageBps,\n// parseDeadlineSec, decimalToAtomicUsdc, decimalToAtomicWad,\n// validateAddress) live in `utils/trade-input.ts`. Single source of\n// truth — userop / trade / eoa modes share the exact same validation\n// behaviour, keeping real-money paths in lockstep.\n","/**\n * `kash protocol watch <market>` — long-running subscription to\n * on-chain trade events for a market.\n *\n * Streams every `TRADE`, `RESOLVED`, and `FROZEN` event the SDK\n * decodes, one NDJSON record per line on stdout. Designed for piping\n * into `jq`, `awk`, or downstream collectors. SIGINT / Ctrl-C\n * terminates cleanly via `subscription.unsubscribe()`.\n *\n * **Best-effort delivery.** viem's `watchContractEvent` reconnects on\n * RPC drops but does NOT replay missed events. For gap-free coverage,\n * pair with `kash markets predictions` (the public-API trade feed)\n * which IS gap-free since it sources from our indexer.\n *\n * **Termination:**\n * - `--max-events <n>` exits cleanly after N events.\n * - `--timeout-ms <ms>` exits after a wall-clock budget.\n * - SIGINT / Ctrl-C unsubscribes and exits 0.\n *\n * **Output:**\n * - JSON mode (`--json`) emits NDJSON: each event = one line.\n * - Human mode prints a compact `[timestamp] TYPE side outcome amounts...` line.\n */\n\nimport { Command } from 'commander';\n\nimport { toCliError } from '../../errors.js';\nimport { buildDirectClient } from '../../utils/direct-client.js';\nimport { parsePositiveInt, readGlobals } from '../../utils/global-options.js';\nimport { log, print, style, writeNdjson } from '../../utils/output.js';\nimport { validateAddress } from '../../utils/trade-input.js';\n\ntype WatchOptions = {\n maxEvents?: string;\n timeoutMs?: string;\n};\n\nexport const watchCommand = new Command('watch')\n .description('Subscribe to on-chain trade events for a market (NDJSON stream).')\n .argument('<market>', 'market contract address (0x-prefixed)')\n .option('--max-events <n>', 'exit cleanly after observing N events')\n .option('--timeout-ms <n>', 'exit cleanly after this wall-clock budget (ms)')\n .addHelpText(\n 'after',\n `\nExamples:\n $ kash protocol watch 0xMarket... --json\n $ kash protocol watch 0xMarket... --json --quiet | jq -r '.transactionHash'\n $ kash protocol watch 0xMarket... --max-events 100 --json\n\nNotes:\n - Best-effort: on RPC reconnect, missed events are NOT replayed. For\n gap-free history, use \\`kash markets predictions <id>\\` (indexer-backed).\n - Press Ctrl-C to terminate cleanly. The subscription unsubscribes\n before the process exits.\n`\n )\n .action(async (market: string, options: WatchOptions, cmd: Command) => {\n const globals = readGlobals(cmd);\n\n const marketAddress = validateAddress(market, 'market');\n\n const maxEvents = options.maxEvents\n ? parsePositiveInt(options.maxEvents, 'max-events')\n : undefined;\n const timeoutMs = options.timeoutMs\n ? parsePositiveInt(options.timeoutMs, 'timeout-ms')\n : undefined;\n\n try {\n const resolved = await buildDirectClient({ globals });\n\n // **Lifecycle.** `markets.watch` returns a `subscription` that\n // holds an open RPC connection. We need to keep the process\n // alive until one of three signals fires (SIGINT / max-events /\n // timeout-ms), then tear down cleanly. We model the wait as a\n // Deferred so the await is reachable / collectable instead of\n // a never-resolving promise that leaks on any future post-\n // processing wrap.\n let resolveDone: ((reason: string) => void) | undefined;\n let count = 0;\n const done = new Promise<string>((resolve) => {\n resolveDone = resolve;\n });\n\n // Holder pattern so `teardown` (defined now) can reference the\n // subscription that `markets.watch` returns shortly. Today the\n // SDK's watch is async-only, but if a future implementation\n // synchronously fired `onEvent` during subscribe (or threw\n // before returning), referencing the binding directly would\n // throw. The `subscriptionHolder.current` indirection keeps the\n // closure stable and lets ESLint's `prefer-const` pass.\n const subscriptionHolder: {\n current: ReturnType<typeof resolved.client.markets.watch> | undefined;\n } = { current: undefined };\n let teardownTriggered = false;\n const teardown = (reason: string): void => {\n if (teardownTriggered) return;\n teardownTriggered = true;\n try {\n subscriptionHolder.current?.unsubscribe();\n } catch {\n // ignore — best-effort cleanup\n }\n resolveDone?.(reason);\n };\n\n subscriptionHolder.current = resolved.client.markets.watch(marketAddress, {\n onEvent: (event) => {\n if (globals.json) {\n // `writeNdjson`'s jsonReplacer is the single source of\n // truth for bigint→decimal-string encoding (incl. inside\n // arrays — `JSON.stringify` walks recursively). No\n // pre-conversion needed here.\n writeNdjson(event);\n } else {\n print(formatEventHuman(event));\n }\n count += 1;\n if (maxEvents !== undefined && count >= maxEvents) {\n teardown(`reached --max-events ${String(maxEvents)}`);\n }\n },\n onReconnect: () => {\n if (!globals.json) {\n log.warn('Watcher reconnecting — missed events will NOT be replayed.');\n }\n },\n onError: (err) => {\n // Non-fatal — viem will retry. Surface it on stderr in human mode.\n if (!globals.json) {\n log.warn(`Watcher error: ${err.message}`);\n }\n },\n });\n\n // SIGINT / SIGTERM tear down rather than process.exit so any\n // post-processing (rare today, but the seam matters) can run.\n const onSigint = (): void => teardown('SIGINT');\n const onSigterm = (): void => teardown('SIGTERM');\n process.on('SIGINT', onSigint);\n process.on('SIGTERM', onSigterm);\n\n // Wall-clock budget. `.unref()` so a quick exit (max-events\n // before the timer fires) doesn't keep the event loop alive.\n const timeoutHandle =\n timeoutMs !== undefined\n ? setTimeout(() => teardown(`reached --timeout-ms ${String(timeoutMs)}`), timeoutMs)\n : undefined;\n timeoutHandle?.unref();\n\n // Print a human-mode header so the user sees something while\n // waiting for the first event. JSON mode stays silent on stderr\n // so the pipe is pure NDJSON.\n if (!globals.json) {\n log.info(`Watching market ${marketAddress}…`);\n log.detail('Stop', 'Ctrl-C');\n if (maxEvents !== undefined) log.detail('Max events', String(maxEvents));\n if (timeoutMs !== undefined) log.detail('Timeout (ms)', String(timeoutMs));\n }\n\n const reason = await done;\n // Clean up signal handlers + timer so a wrapping caller doesn't\n // leak them.\n process.off('SIGINT', onSigint);\n process.off('SIGTERM', onSigterm);\n if (timeoutHandle !== undefined) clearTimeout(timeoutHandle);\n\n if (!globals.json) {\n log.info(`Watcher stopped (${reason}).`);\n }\n } catch (cause) {\n throw toCliError(cause);\n }\n });\n\n// ---------------------------------------------------------------------------\n// Event serialization\n// ---------------------------------------------------------------------------\n\nexport type WatchEventLike =\n | {\n type: 'TRADE';\n side: 'buy' | 'sell';\n outcome: number;\n receiver: `0x${string}`;\n assetsUsdc: bigint;\n tokensWad: bigint;\n reserveAfterWad: bigint;\n supplyAfterWad: readonly bigint[];\n blockNumber: bigint;\n transactionHash: `0x${string}`;\n logIndex: number;\n }\n | {\n type: 'RESOLVED';\n winningOutcome: number;\n evidenceHash: `0x${string}`;\n blockNumber: bigint;\n transactionHash: `0x${string}`;\n logIndex: number;\n }\n | {\n type: 'FROZEN';\n observedAt: bigint;\n blockNumber: bigint;\n transactionHash: `0x${string}`;\n logIndex: number;\n };\n\nexport function formatEventHuman(event: WatchEventLike): string {\n const time = new Date().toISOString().slice(11, 19); // HH:MM:SS\n if (event.type === 'TRADE') {\n return `${style.dim(time)} ${style.bold('TRADE')} side=${event.side} out=${String(event.outcome)} usdc=${event.assetsUsdc.toString()} tokens=${event.tokensWad.toString()} tx=${event.transactionHash.slice(0, 10)}…`;\n }\n if (event.type === 'RESOLVED') {\n return `${style.dim(time)} ${style.bold('RESOLVED')} winner=${String(event.winningOutcome)} tx=${event.transactionHash.slice(0, 10)}…`;\n }\n return `${style.dim(time)} ${style.bold('FROZEN')} observedAt=${event.observedAt.toString()} tx=${event.transactionHash.slice(0, 10)}…`;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwBA,SAAS,WAAAA,iBAAe;;;ACfxB,SAAS,eAAe;;;ACuCxB,eAAsB,kBAAkB,MAOrC;AACD,QAAM,UAAU,KAAK;AACrB,QAAM,SAAS,MAAM,WAAW;AAAA,IAC9B,GAAI,SAAS,YAAY,SAAY,CAAC,IAAI,EAAE,SAAS,QAAQ,QAAQ;AAAA,IACrE,GAAI,SAAS,eAAe,SAAY,CAAC,IAAI,EAAE,YAAY,QAAQ,WAAW;AAAA,EAChF,CAAC;AAGD,QAAM,MAAM,SAAS,WAAW,OAAO;AACvC,MAAI,CAAC,KAAK;AACR,UAAM,oBAAoB,UAAU,6CAA6C;AAAA,EACnF;AACA,MAAI,CAAC,OAAO,cAAc;AACxB,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAGA,QAAM,EAAE,yBAAyB,IAAI,MAAM,OAAO,uBAAuB;AAEzE,QAAM,SAAS,KAAK,gBAAgB,MAAM,WAAW,OAAO,YAAY,IAAI,WAAW;AAEvF,QAAM,gBAAgB,qBAAqB,MAAM;AAWjD,QAAM,cAAc,MAAM,sBAAsB,QAAQ,GAAG;AAC3D,MAAI,gBAAgB,UAAa,YAAY,iBAAiB,QAAW;AACvE,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAS,yBAAyB;AAAA,IACtC,SAAS,OAAO;AAAA,IAChB;AAAA,IACA;AAAA,IACA,GAAI,kBAAkB,SAAY,CAAC,IAAI,EAAE,SAAS,cAAc;AAAA,IAChE,GAAI,gBAAgB,SAAY,CAAC,IAAI,EAAE,YAAY;AAAA,EACrD,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA,SAAS,OAAO;AAAA,IAChB,cAAc,OAAO;AAAA,EACvB;AACF;AAUA,SAAS,aAAwC;AAC/C,SAAO;AAAA,IACL,cAAc;AAAA,IACd,MAAM,iBAAiB;AACrB,YAAM,IAAI,SAAS,sEAAsE;AAAA,QACvF,MAAM;AAAA,QACN,YACE;AAAA,MACJ,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAiBA,eAAe,WAAW,KAA6D;AACrF,QAAM,SAAS,MAAM,kBAAkB,GAAG;AAG1C,QAAM,CAAC,EAAE,oBAAoB,GAAG,EAAE,kBAAkB,CAAC,IAAI,MAAM,QAAQ,IAAI;AAAA,IACzE,OAAO,eAAe;AAAA,IACtB,OAAO,uBAAuB;AAAA,EAChC,CAAC;AACD,SAAO,kBAAkB,oBAAoB,MAAM,CAAC;AACtD;AAUA,SAAS,qBACP,QACsD;AACtD,MAAI,OAAO,oBAAoB,UAAa,OAAO,eAAe,QAAW;AAC3E,WAAO;AAAA,EACT;AACA,MAAI,OAAO,oBAAoB,QAAW;AAExC,WAAO,OAAO;AAAA,EAChB;AAEA,MAAI,OAAO,eAAe,QAAW;AACnC,UAAM,IAAI;AAAA,MACR,wCAAwC,OAAO,eAAe;AAAA,MAC9D;AAAA,QACE,MAAM;AAAA,QACN,YACE;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AACA,SAAO;AAAA,IACL,UAAU,OAAO;AAAA,IACjB,KAAK,OAAO;AAAA,EACd;AACF;AASA,eAAe,sBACb,QACA,KACkC;AAClC,MAAI,OAAO,gBAAgB,OAAW,QAAO;AAC7C,MAAI,OAAO,mBAAmB,QAAW;AACvC,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,SAAO,sBAAsB;AAAA,IAC3B,aAAa,OAAO;AAAA,IACpB,SAAS,OAAO;AAAA,IAChB;AAAA,EACF,CAAC;AACH;AAEA,SAAS,oBAAoB,OAAe,MAAwB;AAClE,SAAO,IAAI,SAAS,+BAA+B,KAAK,KAAK;AAAA,IAC3D,MAAM;AAAA,IACN,UAAU,WAAW;AAAA,IACrB,YAAY,OAAO,KAAK,QAAQ,IAAI;AAAA,IACpC,SAAS;AAAA,MACP;AAAA,QACE,MAAM;AAAA,QACN;AAAA,QACA,aAAa;AAAA,MACf;AAAA,IACF;AAAA,EACF,CAAC;AACH;;;ADvNO,IAAM,mBAAmB,IAAI,QAAQ,WAAW,EACpD,YAAY,+DAA+D,EAC3E,SAAS,aAAa,6DAAwD,EAC9E,SAAS,aAAa,iDAAiD,EACvE;AAAA,EACC;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWF,EACC,OAAO,OAAO,SAAiB,SAA6B,OAAO,QAAiB;AACnF,QAAM,UAAU,YAAY,GAAG;AAC/B,QAAM,iBAAiB,gBAAgB,SAAS,SAAS;AACzD,QAAM,iBAAiB,wBAAwB,SAAS,SAAS;AAEjE,MAAI;AACF,UAAM,WAAW,MAAM,kBAAkB,EAAE,QAAQ,CAAC;AACpD,UAAM,QAAQ,kBAAkB,SAAS;AACzC,UAAM,YAAY,MAAM,SAAS,OAAO,QAAQ,cAAc,OAAO,cAAc;AAEnF,UAAM,UAAU;AAAA,MACd;AAAA,MACA,SAAS;AAAA,MACT,SAAS,SAAS;AAAA,MAClB,iBAAiB,UAAU,SAAS;AAAA,IACtC;AAEA,QAAI,QAAQ,MAAM;AAChB,gBAAU,OAAO;AACjB;AAAA,IACF;AAEA,UAAM,EAAE;AACR,UAAM,KAAK,MAAM,IAAI,UAAU,CAAC,IAAI,cAAc,OAAO,IAAI,CAAC,CAAC,EAAE;AACjE,UAAM,KAAK,MAAM,IAAI,UAAU,CAAC,IAAI,cAAc,gBAAgB,IAAI,CAAC,CAAC,EAAE;AAC1E;AAAA,MACE,KAAK,MAAM,IAAI,WAAW,CAAC,IAAI,iBAAiB,UAAU,SAAS,CAAC,CAAC,IAAI,MAAM,IAAI,IAAI,UAAU,SAAS,CAAC,UAAU,CAAC;AAAA,IACxH;AAAA,EACF,SAAS,OAAO;AACd,UAAM,WAAW,KAAK;AAAA,EACxB;AACF,CAAC;;;AE9CH,SAAS,WAAAC,gBAAe;AASjB,IAAM,iBAAiB,IAAIC,SAAQ,SAAS,EAChD,YAAY,mFAAmF,EAC/F,SAAS,aAAa,uEAAuE,EAC7F;AAAA,EACC;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASF,EACC,OAAO,OAAO,SAA6B,OAAO,QAAiB;AAClE,QAAM,UAAU,YAAY,GAAG;AAC/B,QAAM,kBAAkB,wBAAwB,SAAS,SAAS;AAElE,MAAI;AACJ,MAAI;AACF,eAAW,MAAM,kBAAkB,EAAE,QAAQ,CAAC;AAAA,EAChD,SAAS,OAAO;AACd,UAAM,WAAW,KAAK;AAAA,EACxB;AACA,QAAM,SAAS,mBAAmB,SAAS;AAE3C,MAAI;AACJ,MAAI;AACJ,MAAI;AACF,KAAC,YAAY,MAAM,IAAI,MAAM,QAAQ,IAAI;AAAA,MACvC,SAAS,OAAO,QAAQ,YAAY,MAAM;AAAA,MAC1C,SAAS,OAAO,QAAQ,WAAW,MAAM;AAAA,IAC3C,CAAC;AAAA,EACH,SAAS,OAAO;AACd,UAAM,WAAW,KAAK;AAAA,EACxB;AAEA,QAAM,UAAU;AAAA,IACd,SAAS;AAAA,IACT,SAAS,SAAS;AAAA,IAClB,YAAY,WAAW,SAAS;AAAA,IAChC,QAAQ,OAAO,SAAS;AAAA,EAC1B;AAEA,MAAI,QAAQ,MAAM;AAChB,cAAU,OAAO;AACjB;AAAA,EACF;AAEA,QAAM,EAAE;AACR,QAAM,KAAK,MAAM,IAAI,cAAc,CAAC,IAAI,cAAc,QAAQ,IAAI,CAAC,CAAC,EAAE;AACtE,QAAM,KAAK,MAAM,IAAI,cAAc,CAAC,IAAI,OAAO,SAAS,OAAO,CAAC,EAAE;AAClE,QAAM,KAAK,MAAM,IAAI,cAAc,CAAC,IAAI,iBAAiB,WAAW,SAAS,CAAC,CAAC,EAAE;AACjF;AAAA,IACE,KAAK,MAAM,IAAI,cAAc,CAAC,IAAI,iBAAiB,QAAQ,EAAE,cAAc,IAAI,iBAAiB,EAAE,CAAC,CAAC;AAAA,EACtG;AACF,CAAC;;;ACzEH,SAAS,WAAAC,gBAAe;AAMxB,IAAM,cAAc;AAEb,IAAM,sBAAsB,IAAIC,SAAQ,eAAe,EAC3D,YAAY,8EAA8E,EAC1F,SAAS,UAAU,mCAAmC,EACtD;AAAA,EACC;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUF,EACC,OAAO,OAAO,MAAc,OAAO,QAAiB;AACnD,QAAM,UAAU,YAAY,GAAG;AAE/B,MAAI,CAAC,YAAY,KAAK,IAAI,KAAK,KAAK,SAAS,IAAI;AAC/C,UAAM,IAAI;AAAA,MACR;AAAA,MACA,QAAQ,IAAI;AAAA,MACZ;AAAA,IACF;AAAA,EACF;AAEA,MAAI;AAGF,UAAM,EAAE,mBAAmB,IAAI,MAAM,OAAO,uBAAuB;AACnE,UAAM,UAAU,mBAAmB,IAAqB;AAKxD,UAAM,OAAO,SAAS,KAAK,IAAI,CAAC,MAAO,OAAO,MAAM,WAAW,EAAE,SAAS,IAAI,CAAE,KAAK;AAErF,UAAM,UAAU,YAAY,OAAO,OAAO,EAAE,MAAM,QAAQ,MAAM,KAAK;AAErE,QAAI,QAAQ,MAAM;AAChB,gBAAU,OAAO;AACjB;AAAA,IACF;AAEA,QAAI,YAAY,MAAM;AACpB,YAAM,EAAE;AACR,YAAM,KAAK,MAAM,IAAI,4DAAuD,CAAC,EAAE;AAC/E,YAAM,KAAK,MAAM,IAAI,QAAQ,CAAC,GAAG,KAAK,MAAM,GAAG,EAAE,CAAC,GAAG,KAAK,SAAS,KAAK,WAAM,EAAE,EAAE;AAClF;AAAA,IACF;AAEA,UAAM,EAAE;AACR,UAAM,KAAK,MAAM,IAAI,SAAS,CAAC,IAAI,MAAM,KAAK,QAAQ,IAAI,CAAC,EAAE;AAC7D,QAAI,QAAQ,KAAK,SAAS,GAAG;AAC3B,YAAM,KAAK,MAAM,IAAI,SAAS,CAAC,EAAE;AACjC,iBAAW,CAAC,GAAG,GAAG,KAAK,KAAK,QAAQ,GAAG;AACrC,cAAM,QAAQ,OAAO,CAAC,CAAC,KAAK,OAAO,GAAG,CAAC,EAAE;AAAA,MAC3C;AAAA,IACF,OAAO;AACL,YAAM,KAAK,MAAM,IAAI,SAAS,CAAC,SAAS;AAAA,IAC1C;AAAA,EACF,SAAS,OAAO;AACd,UAAM,WAAW,KAAK;AAAA,EACxB;AACF,CAAC;;;AC5EH,SAAS,WAAAC,gBAAe;AAmBjB,IAAM,cAAc,IAAIC,SAAQ,MAAM,EAC1C,YAAY,uEAAuE,EACnF,OAAO,gBAAgB,+CAA+C,EACtE;AAAA,EACC;AAAA,EACA;AACF,EACC;AAAA,EACC;AAAA,EACA;AACF,EACC,OAAO,6BAA6B,oDAAoD,EACxF;AAAA,EACC;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAMF,EACC,OAAO,OAAO,SAAsB,QAAiB;AACpD,QAAM,UAAU,YAAY,GAAG;AAE/B,QAAM,SAAS,yBAAyB,QAAQ,QAAQ,QAAQ;AAChE,QAAM,aAAa,yBAAyB,QAAQ,YAAY,YAAY;AAC5E,MAAI,eAAe,WAAc,aAAa,KAAK,aAAa,KAAK;AACnE,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,QAAM,iBAAiB,2BAA2B,QAAQ,gBAAgB,iBAAiB;AAC3F,QAAM,oBAAoB;AAAA,IACxB,QAAQ;AAAA,IACR;AAAA,EACF;AAEA,MAAI;AACF,UAAM,WAAW,MAAM,kBAAkB,EAAE,QAAQ,CAAC;AACpD,UAAM,WAAW,MAAM,SAAS,OAAO,QAAQ,aAAa;AAAA,MAC1D,GAAI,WAAW,SAAY,CAAC,IAAI,EAAE,YAAY,OAAO;AAAA,MACrD,GAAI,eAAe,SAAY,CAAC,IAAI,EAAE,kBAAkB,WAAW;AAAA,MACnE,GAAI,mBAAmB,SAAY,CAAC,IAAI,EAAE,eAAe;AAAA,MACzD,GAAI,sBAAsB,SACtB,CAAC,IACD,EAAE,qBAAqB,OAAO,iBAAiB,IAAI,OAAO,GAAG;AAAA,IACnE,CAAC;AAED,UAAM,UAAU;AAAA,MACd,SAAS,SAAS;AAAA,MAClB,cAAc,SAAS,aAAa,SAAS;AAAA,MAC7C,sBAAsB,SAAS,qBAAqB,SAAS;AAAA,IAC/D;AAEA,QAAI,QAAQ,MAAM;AAChB,gBAAU,OAAO;AACjB;AAAA,IACF;AAEA,UAAM,EAAE;AACR,UAAM,KAAK,MAAM,IAAI,WAAW,CAAC,IAAI,OAAO,SAAS,OAAO,CAAC,EAAE;AAC/D;AAAA,MACE,KAAK,MAAM,IAAI,WAAW,CAAC,IAAI,WAAW,SAAS,YAAY,CAAC,SAAS,MAAM,IAAI,IAAI,SAAS,aAAa,SAAS,CAAC,OAAO,CAAC;AAAA,IACjI;AACA;AAAA,MACE,KAAK,MAAM,IAAI,WAAW,CAAC,IAAI,WAAW,SAAS,oBAAoB,CAAC,SAAS,MAAM,IAAI,IAAI,SAAS,qBAAqB,SAAS,CAAC,OAAO,CAAC;AAAA,IACjJ;AAAA,EACF,SAAS,OAAO;AACd,UAAM,WAAW,KAAK;AAAA,EACxB;AACF,CAAC;;;ACxFH,SAAS,WAAAC,gBAAe;AASjB,IAAM,gBAAgB,IAAIC,SAAQ,QAAQ,EAC9C,YAAY,kFAAkF,EAC9F,SAAS,aAAa,uCAAuC,EAC7D;AAAA,EACC;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAKF,EACC,OAAO,OAAO,SAAiB,OAAO,QAAiB;AACtD,QAAM,UAAU,YAAY,GAAG;AAE/B,kBAAgB,SAAS,SAAS;AAElC,MAAI;AACJ,MAAI;AACJ,MAAI;AACF,eAAW,MAAM,kBAAkB,EAAE,QAAQ,CAAC;AAC9C,YAAQ,MAAM,SAAS,OAAO,QAAQ,MAAM,OAAwB;AAAA,EACtE,SAAS,OAAO;AACd,UAAM,WAAW,KAAK;AAAA,EACxB;AAIA,QAAM,UAAU;AAAA,IACd,eAAe,MAAM;AAAA,IACrB,SAAS,SAAS;AAAA,IAClB,QAAQ,MAAM;AAAA,IACd,QAAQ,MAAM,OAAO,SAAS;AAAA,IAC9B,YAAY,MAAM,WAAW,SAAS;AAAA,IACtC,UAAU,MAAM,SAAS,IAAI,CAAC,OAAO;AAAA,MACnC,OAAO,EAAE;AAAA,MACT,sBAAsB,EAAE,qBAAqB,SAAS;AAAA,MACtD,WAAW,EAAE,UAAU,SAAS;AAAA,MAChC,aAAa,EAAE;AAAA,IACjB,EAAE;AAAA,EACJ;AAEA,MAAI,QAAQ,MAAM;AAChB,cAAU,OAAO;AACjB;AAAA,EACF;AAEA,QAAM,EAAE;AACR,QAAM,KAAK,MAAM,IAAI,WAAW,CAAC,IAAI,cAAc,MAAM,eAAe,IAAI,CAAC,CAAC,EAAE;AAChF,QAAM,KAAK,MAAM,IAAI,WAAW,CAAC,IAAI,MAAM,MAAM,EAAE;AACnD,QAAM,KAAK,MAAM,IAAI,WAAW,CAAC,IAAI,OAAO,MAAM,SAAS,MAAM,CAAC,EAAE;AACpE,QAAM,EAAE;AACR,aAAW,WAAW,MAAM,UAAU;AACpC,UAAM,OAAO,QAAQ,cAAc,KAAK,QAAQ,CAAC;AACjD;AAAA,MACE,MAAM,OAAO,QAAQ,KAAK,CAAC,OAAO,GAAG,kBAAkB,UAAU,QAAQ,oBAAoB,CAAC,YAAY,UAAU,QAAQ,SAAS,CAAC;AAAA,IACxI;AAAA,EACF;AACF,CAAC;;;AClEH,SAAS,WAAAC,gBAAe;AASjB,IAAM,kBAAkB,IAAIC,SAAQ,UAAU,EAClD,YAAY,+DAA+D,EAC3E,SAAS,YAAY,uCAAuC,EAC5D;AAAA,EACC;AAAA,EACA;AACF,EACC;AAAA,EACC;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAMF,EACC,OAAO,OAAO,QAAgB,SAA6B,OAAO,QAAiB;AAClF,QAAM,UAAU,YAAY,GAAG;AAE/B,QAAM,aAAa,gBAAgB,QAAQ,QAAQ;AACnD,QAAM,cAAc,wBAAwB,SAAS,SAAS;AAE9D,MAAI;AACJ,MAAI;AACJ,MAAI;AACF,eAAW,MAAM,kBAAkB,EAAE,QAAQ,CAAC;AAC9C,UAAM,SAAS,eAAe,SAAS;AACvC,eAAW,MAAM,SAAS,OAAO,QAAQ,SAAS,QAAQ,UAAU;AAEpE,UAAM,UAAU;AAAA,MACd,SAAS;AAAA,MACT,eAAe,SAAS;AAAA,MACxB,SAAS,SAAS;AAAA,MAClB,aAAa,SAAS;AAAA,MACtB,UAAU,SAAS,SAAS,IAAI,CAAC,OAAO;AAAA,QACtC,cAAc,EAAE;AAAA,QAChB,YAAY,EAAE,WAAW,SAAS;AAAA,MACpC,EAAE;AAAA,IACJ;AAEA,QAAI,QAAQ,MAAM;AAChB,gBAAU,OAAO;AACjB;AAAA,IACF;AAEA,UAAM,EAAE;AACR,UAAM,KAAK,MAAM,IAAI,WAAW,CAAC,IAAI,cAAc,QAAQ,IAAI,CAAC,CAAC,EAAE;AACnE,UAAM,KAAK,MAAM,IAAI,WAAW,CAAC,IAAI,cAAc,SAAS,eAAe,IAAI,CAAC,CAAC,EAAE;AACnF,UAAM,KAAK,MAAM,IAAI,WAAW,CAAC,IAAI,OAAO,SAAS,WAAW,CAAC,EAAE;AACnE,UAAM,EAAE;AACR,eAAW,KAAK,SAAS,UAAU;AACjC,YAAM,eAAe,UAAU,EAAE,UAAU;AAC3C;AAAA,QACE,MAAM,OAAO,EAAE,YAAY,CAAC,aAAa,YAAY,IAAI,MAAM,IAAI,IAAI,EAAE,WAAW,SAAS,CAAC,OAAO,CAAC;AAAA,MACxG;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,UAAM,WAAW,KAAK;AAAA,EACxB;AACF,CAAC;;;ACxDH,SAAS,WAAAC,gBAAe;AAqBjB,IAAM,eAAe,IAAIC,SAAQ,OAAO,EAC5C,YAAY,wDAAwD,EACpE,SAAS,aAAa,uCAAuC,EAC7D,eAAe,yBAAyB,yBAAyB,EACjE,eAAe,yBAAyB,yBAAyB,EACjE;AAAA,EACC;AAAA,EACA;AACF,EACC;AAAA,EACC;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAKF,EACC,OAAO,OAAO,SAAiB,SAAuB,QAAiB;AACtE,QAAM,UAAU,YAAY,GAAG;AAC/B,QAAM,gBAAgB,gBAAgB,SAAS,SAAS;AACxD,QAAM,OAAO,mBAAmB,QAAQ,MAAM,MAAM;AACpD,QAAM,UAAU,kBAAkB,QAAQ,OAAO;AACjD,QAAM,SACJ,SAAS,QACL,oBAAoB,QAAQ,QAAQ,QAAQ,IAC5C,mBAAmB,QAAQ,QAAQ,QAAQ;AAEjD,MAAI;AACJ,MAAI;AACJ,MAAI;AACF,eAAW,MAAM,kBAAkB,EAAE,QAAQ,CAAC;AAC9C,YAAQ,MAAM,SAAS,OAAO,QAAQ,MAAM,eAAe;AAAA,MACzD;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH,SAAS,OAAO;AACd,UAAM,WAAW,KAAK;AAAA,EACxB;AAEA,QAAM,UAAU;AAAA,IACd,MAAM,MAAM;AAAA,IACZ,cAAc,MAAM;AAAA,IACpB,UAAU,MAAM,SAAS,SAAS;AAAA,IAClC,WAAW,MAAM,UAAU,SAAS;AAAA,IACpC,iBAAiB,MAAM,gBAAgB,SAAS;AAAA,IAChD,gBAAgB,MAAM,eAAe,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC;AAAA,EAC9D;AAEA,MAAI,QAAQ,MAAM;AAChB,cAAU,OAAO;AACjB;AAAA,EACF;AAEA,QAAM,EAAE;AACR,QAAM,KAAK,MAAM,IAAI,YAAY,CAAC,IAAI,cAAc,SAAS,IAAI,CAAC,CAAC,EAAE;AACrE,QAAM,KAAK,MAAM,IAAI,YAAY,CAAC,IAAI,MAAM,IAAI,YAAY,OAAO,MAAM,YAAY,CAAC,EAAE;AACxF,MAAI,MAAM,SAAS,OAAO;AACxB,UAAM,KAAK,MAAM,IAAI,YAAY,CAAC,IAAI,iBAAiB,MAAM,QAAQ,CAAC,EAAE;AACxE,UAAM,KAAK,MAAM,IAAI,YAAY,CAAC,IAAI,UAAU,MAAM,SAAS,CAAC,EAAE;AAAA,EACpE,OAAO;AACL,UAAM,KAAK,MAAM,IAAI,YAAY,CAAC,IAAI,UAAU,MAAM,QAAQ,CAAC,EAAE;AACjE,UAAM,KAAK,MAAM,IAAI,YAAY,CAAC,IAAI,iBAAiB,MAAM,SAAS,CAAC,EAAE;AAAA,EAC3E;AACA;AAAA,IACE,KAAK,MAAM,IAAI,aAAa,CAAC,KAAK,MAAM,eACrC,IAAI,CAAC,MAAM,IAAK,OAAO,CAAC,IAAI,OAAQ,KAAK,QAAQ,CAAC,CAAC,GAAG,EACtD,KAAK,IAAI,CAAC;AAAA,EACf;AACF,CAAC;;;AClGH,SAAS,WAAAC,gBAAe;AAcxB,IAAM,iBAAiB,IAAIC,SAAQ,SAAS,EACzC,YAAY,kEAAkE,EAC9E,eAAe,yBAAyB,iCAAiC,EACzE,OAAO,kBAAkB,uDAAuD,GAAG,EACnF;AAAA,EACC;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAMF,EACC,OAAO,OAAO,SAAyB,QAAiB;AACvD,QAAM,UAAU,YAAY,GAAG;AAC/B,QAAM,eAAe,gBAAgB,QAAQ,OAAO,OAAO;AAE3D,MAAI;AACJ,MAAI,QAAQ,SAAS,QAAW;AAC9B,QAAI;AACJ,QAAI;AACF,eAAS,OAAO,QAAQ,IAAI;AAAA,IAC9B,QAAQ;AACN,YAAM,IAAI;AAAA,QACR;AAAA,QACA,QAAQ,QAAQ,IAAI;AAAA,QACpB;AAAA,MACF;AAAA,IACF;AACA,QAAI,SAAS,IAAI;AACf,YAAM,IAAI;AAAA,QACR;AAAA,QACA,QAAQ,QAAQ,IAAI;AAAA,QACpB;AAAA,MACF;AAAA,IACF;AACA,WAAO,WAAW,KAAK,SAAY;AAAA,EACrC;AAEA,MAAI;AACF,UAAM,WAAW,MAAM,kBAAkB,EAAE,QAAQ,CAAC;AACpD,UAAM,UAAU,MAAM,SAAS,OAAO,QAAQ,eAAe,cAAc,IAAI;AAE/E,UAAM,UAAU;AAAA,MACd,OAAO;AAAA,MACP,OAAO,QAAQ,IAAI,SAAS;AAAA,MAC5B,SAAS,SAAS;AAAA,MAClB;AAAA,IACF;AAEA,QAAI,QAAQ,MAAM;AAChB,gBAAU,OAAO;AACjB;AAAA,IACF;AAEA,UAAM,EAAE;AACR,UAAM,KAAK,MAAM,IAAI,SAAS,CAAC,IAAI,cAAc,cAAc,IAAI,CAAC,CAAC,EAAE;AACvE,UAAM,KAAK,MAAM,IAAI,SAAS,CAAC,KAAK,QAAQ,IAAI,SAAS,CAAC,EAAE;AAC5D,UAAM,KAAK,MAAM,IAAI,SAAS,CAAC,IAAI,OAAO,EAAE;AAAA,EAC9C,SAAS,OAAO;AACd,UAAM,WAAW,KAAK;AAAA,EACxB;AACF,CAAC;AAEH,IAAM,oBAAoB,IAAIA,SAAQ,aAAa,EAChD,YAAY,+EAA+E,EAC3F,SAAS,aAAa,yDAAyD,EAC/E;AAAA,EACC;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAMF,EACC,OAAO,OAAO,SAA6B,OAAO,QAAiB;AAClE,QAAM,UAAU,YAAY,GAAG;AAC/B,QAAM,kBAAkB,wBAAwB,SAAS,SAAS;AAElE,MAAI;AACF,UAAM,WAAW,MAAM,kBAAkB,EAAE,QAAQ,CAAC;AACpD,UAAM,SAAS,mBAAmB,SAAS;AAC3C,UAAM,WAAW,MAAM,SAAS,OAAO,QAAQ,WAAW,MAAM;AAEhE,UAAM,UAAU;AAAA,MACd,SAAS;AAAA,MACT,SAAS,SAAS;AAAA,MAClB;AAAA,IACF;AAEA,QAAI,QAAQ,MAAM;AAChB,gBAAU,OAAO;AACjB;AAAA,IACF;AAEA,UAAM,EAAE;AACR,UAAM,KAAK,MAAM,IAAI,UAAU,CAAC,IAAI,cAAc,QAAQ,IAAI,CAAC,CAAC,EAAE;AAClE;AAAA,MACE,KAAK,MAAM,IAAI,UAAU,CAAC,IAAI,WAAW,MAAM,QAAQ,KAAK,IAAI,MAAM,IAAI,oCAA+B,CAAC;AAAA,IAC5G;AAAA,EACF,SAAS,OAAO;AACd,UAAM,WAAW,KAAK;AAAA,EACxB;AACF,CAAC;AAEI,IAAM,sBAAsB,IAAIA,SAAQ,eAAe,EAC3D,YAAY,gEAAgE,EAC5E,WAAW,cAAc,EACzB,WAAW,iBAAiB;;;ACnI/B,SAAS,WAAAC,gBAAe;AAWjB,IAAM,iBAAiB,IAAIC,SAAQ,UAAU,EACjD;AAAA,EACC;AACF,EACC;AAAA,EACC;AAAA,EACA;AACF,EACC,eAAe,yBAAyB,uBAAuB,EAC/D;AAAA,EACC;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYF,EACC,OAAO,OAAO,SAAyB,QAAiB;AACvD,QAAM,UAAU,YAAY,GAAG;AAE/B,MAAI;AACJ,MAAI;AACF,eAAW,OAAO,QAAQ,QAAQ;AAAA,EACpC,QAAQ;AACN,UAAM,IAAI;AAAA,MACR;AAAA,MACA,QAAQ,QAAQ,QAAQ;AAAA,MACxB;AAAA,IACF;AAAA,EACF;AACA,MAAI,WAAW,IAAI;AACjB,UAAM,IAAI;AAAA,MACR;AAAA,MACA,QAAQ,QAAQ,QAAQ;AAAA,MACxB;AAAA,IACF;AAAA,EACF;AAEA,QAAM,eAAe,OAAO,SAAS,QAAQ,SAAS,EAAE;AACxD,MAAI,CAAC,OAAO,SAAS,YAAY,KAAK,eAAe,KAAK,eAAe,KAAK;AAC5E,UAAM,IAAI;AAAA,MACR;AAAA,MACA,QAAQ,QAAQ,OAAO;AAAA,MACvB;AAAA,IACF;AAAA,EACF;AAEA,MAAI;AAGF,UAAM,EAAE,WAAW,IAAI,MAAM,OAAO,uBAAuB;AAC3D,UAAM,UAAU,WAAW,UAAU,YAAY;AAEjD,UAAM,UAAU;AAAA,MACd,UAAU,SAAS,SAAS;AAAA,MAC5B;AAAA,MACA,SAAS,QAAQ,SAAS;AAAA,MAC1B,YAAY,KAAK,QAAQ,SAAS,EAAE,CAAC;AAAA,IACvC;AAEA,QAAI,QAAQ,MAAM;AAChB,gBAAU,OAAO;AACjB;AAAA,IACF;AAEA,UAAM,EAAE;AACR,UAAM,KAAK,MAAM,IAAI,aAAa,CAAC,IAAI,SAAS,SAAS,CAAC,EAAE;AAC5D,UAAM,KAAK,MAAM,IAAI,aAAa,CAAC,IAAI,OAAO,YAAY,CAAC,EAAE;AAC7D,UAAM,KAAK,MAAM,IAAI,aAAa,CAAC,IAAI,QAAQ,SAAS,CAAC,EAAE;AAC3D,UAAM,KAAK,MAAM,IAAI,aAAa,CAAC,MAAM,QAAQ,SAAS,EAAE,CAAC,EAAE;AAAA,EACjE,SAAS,OAAO;AACd,UAAM,WAAW,KAAK;AAAA,EACxB;AACF,CAAC;;;AC9EH,SAAS,WAAAC,iBAAe;AACxB,OAAO,SAAS;;;ACOT,SAAS,gBAAgB,QAA0D;AACxF,QAAM,MAA+B,CAAC;AACtC,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,MAAM,GAAG;AAC3C,QAAI,CAAC,IAAI,OAAO,MAAM,WAAW,EAAE,SAAS,IAAI;AAAA,EAClD;AACA,SAAO;AACT;;;ADmCA,IAAM,aAAa,IAAIC,UAAQ,KAAK,EACjC,YAAY,wFAAyE,EACrF,SAAS,YAAY,uCAAuC,EAC5D,eAAe,yBAAyB,yBAAyB,EACjE,eAAe,uBAAuB,qDAAgD,EACtF,OAAO,sBAAsB,wDAAwD,EACrF,OAAO,sBAAsB,4CAA4C,EACzE,OAAO,aAAa,gEAAgE,EACpF,OAAO,iBAAiB,+CAA+C,EACvE,OAAO,aAAa,kEAAkE,EACtF,OAAO,yBAAyB,yCAAyC,EACzE,OAAO,0BAA0B,sCAAsC,EACvE;AAAA,EACC;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOF,EACC,OAAO,OAAO,QAAgB,SAAqB,QAAiB;AACnE,QAAM,SAAS,OAAO,QAAQ,SAAS,GAAG;AAC5C,CAAC;AAEH,IAAM,cAAc,IAAIA,UAAQ,MAAM,EACnC,YAAY,yFAA0E,EACtF,SAAS,YAAY,uCAAuC,EAC5D,eAAe,yBAAyB,yBAAyB,EACjE,eAAe,yBAAyB,uDAAkD,EAC1F,OAAO,sBAAsB,wDAAwD,EACrF,OAAO,sBAAsB,4CAA4C,EACzE,OAAO,aAAa,gEAAgE,EACpF,OAAO,iBAAiB,+CAA+C,EACvE,OAAO,aAAa,kEAAkE,EACtF,OAAO,yBAAyB,yCAAyC,EACzE,OAAO,0BAA0B,sCAAsC,EACvE;AAAA,EACC;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAKF,EACC,OAAO,OAAO,QAAgB,SAAsB,QAAiB;AACpE,QAAM,SAAS,QAAQ,QAAQ,SAAS,GAAG;AAC7C,CAAC;AAEH,IAAM,eAAe,IAAIA,UAAQ,OAAO,EACrC,YAAY,6EAAwE,EACpF,SAAS,YAAY,uCAAuC,EAC5D,eAAe,yBAAyB,yBAAyB,EACjE,OAAO,sBAAsB,wDAAwD,EACrF,OAAO,sBAAsB,4CAA4C,EACzE,OAAO,aAAa,gEAAgE,EACpF,OAAO,iBAAiB,+CAA+C,EACvE,OAAO,aAAa,kEAAkE,EACtF,OAAO,yBAAyB,yCAAyC,EACzE,OAAO,0BAA0B,sCAAsC,EACvE;AAAA,EACC;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAKF,EACC,OAAO,OAAO,QAAgB,SAAuB,QAAiB;AACrE,QAAM,SAAS,SAAS,QAAQ,SAAS,GAAG;AAC9C,CAAC;AAEH,IAAM,iBAAiB,IAAIA,UAAQ,SAAS,EACzC,YAAY,0DAAqD,EACjE,SAAS,aAAa,kEAA6D,EACnF;AAAA,EACC;AAAA,EACA;AACF,EACC,OAAO,aAAa,gEAAgE,EACpF,OAAO,iBAAiB,+CAA+C,EACvE,OAAO,aAAa,kEAAkE,EACtF,OAAO,yBAAyB,yCAAyC,EACzE,OAAO,0BAA0B,sCAAsC,EACvE;AAAA,EACC;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAMF,EACC,OAAO,OAAO,SAAiB,SAAyB,QAAiB;AACxE,QAAM,WAAW,SAAS,SAAS,GAAG;AACxC,CAAC;AAEI,IAAM,eAAe,IAAIA,UAAQ,OAAO,EAC5C,YAAY,6EAA6E,EACzF,WAAW,UAAU,EACrB,WAAW,WAAW,EACtB,WAAW,YAAY,EACvB,WAAW,cAAc;AAQ5B,eAAe,SACb,MACA,QACA,SACA,KACe;AACf,QAAM,UAAU,YAAY,GAAG;AAC/B,QAAM,gBAAgB,gBAAgB,QAAQ,QAAQ;AAEtD,QAAM,UAAU,kBAAkB,QAAQ,OAAO;AACjD,QAAM,cAAc,QAAQ,cACxB,iBAAiB,QAAQ,WAAW,IACpC;AACJ,QAAM,WAAW,QAAQ,cAAc,iBAAiB,QAAQ,WAAW,IAAI;AAC/E,QAAM,gBAAgB,QAAQ,gBAC1B,iBAAiB,QAAQ,eAAe,iBAAiB,IACzD;AACJ,QAAM,iBAAiB,QAAQ,iBAC3B,iBAAiB,QAAQ,gBAAgB,kBAAkB,IAC3D;AAGJ,MAAI;AACJ,MAAI;AACJ,MAAI,SAAS,OAAO;AAClB,UAAM,UAAU;AAChB,iBAAa,oBAAoB,QAAQ,QAAQ,QAAQ;AAAA,EAC3D,WAAW,SAAS,QAAQ;AAC1B,UAAM,WAAW;AACjB,mBAAe,mBAAmB,SAAS,QAAQ,QAAQ;AAAA,EAC7D;AAEA,MAAI;AACF,UAAM,WAAW,MAAM,kBAAkB,EAAE,SAAS,eAAe,KAAK,CAAC;AAIzE,QAAI,QAAQ,WAAW,MAAM;AAC3B,YAAM,QAAQ,MAAM,eAAe,SAAS,QAAQ,MAAM;AAAA,QACxD,QAAQ;AAAA,QACR,cAAc,SAAS;AAAA,QACvB;AAAA,QACA;AAAA,QACA,GAAI,aAAa,SAAY,CAAC,IAAI,EAAE,SAAS;AAAA,QAC7C,GAAI,eAAe,SAAY,CAAC,IAAI,EAAE,WAAW;AAAA,QACjD,GAAI,iBAAiB,SAAY,CAAC,IAAI,EAAE,aAAa;AAAA,QACrD,UAAU,QAAQ,aAAa;AAAA,MACjC,CAAC;AACD,iBAAW,OAAO,MAAM,QAAQ,QAAQ,IAAI;AAC5C;AAAA,IACF;AAEA,UAAM,cAAc;AAAA,MAClB,UAAU,QAAQ,aAAa;AAAA,MAC/B,MAAM,QAAQ,SAAS;AAAA,MACvB,GAAI,kBAAkB,SAAY,CAAC,IAAI,EAAE,cAAc;AAAA,MACvD,GAAI,mBAAmB,SAAY,CAAC,IAAI,EAAE,eAAe;AAAA,IAC3D;AAEA,UAAM,UACJ,CAAC,QAAQ,QAAQ,CAAC,QAAQ,IACtB,IAAI;AAAA,MACF,MAAM,aAAa,IAAI,OAAO,cAAc,QAAQ,GAAG,CAAC,CAAC;AAAA,MACzD,QAAQ,QAAQ;AAAA,IAClB,CAAC,EAAE,MAAM,IACT;AAEN,QAAI;AACJ,QAAI;AACF,UAAI,SAAS,OAAO;AAClB,iBAAS,MAAM,SAAS,OAAO,OAAO,KAAK;AAAA,UACzC;AAAA,UACA;AAAA,YACE,SAAS,SAAS;AAAA,YAClB;AAAA,YACA;AAAA,YACA,gBAAgB;AAAA,YAChB,GAAI,aAAa,SAAY,CAAC,IAAI,EAAE,SAAS;AAAA,UAC/C;AAAA,UACA;AAAA,QACF;AAAA,MACF,WAAW,SAAS,QAAQ;AAC1B,iBAAS,MAAM,SAAS,OAAO,OAAO,KAAK;AAAA,UACzC;AAAA,UACA;AAAA,YACE,SAAS,SAAS;AAAA,YAClB;AAAA,YACA;AAAA,YACA,gBAAgB;AAAA,YAChB,GAAI,aAAa,SAAY,CAAC,IAAI,EAAE,SAAS;AAAA,UAC/C;AAAA,UACA;AAAA,QACF;AAAA,MACF,OAAO;AACL,iBAAS,MAAM,SAAS,OAAO,OAAO,KAAK;AAAA,UACzC;AAAA,UACA;AAAA,YACE,SAAS,SAAS;AAAA,YAClB;AAAA,YACA,gBAAgB;AAAA,YAChB,GAAI,aAAa,SAAY,CAAC,IAAI,EAAE,SAAS;AAAA,UAC/C;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,eAAS,KAAK,GAAG,IAAI,UAAU;AAY/B,YAAM,cAAc,yBAAyB,KAAK;AAClD,UAAI,gBAAgB,QAAW;AAC7B,YAAI,QAAQ,MAAM;AAChB,oBAAU,EAAE,YAAY,aAAa,QAAQ,OAAO,SAAS,KAAK,CAAC;AAAA,QACrE,OAAO;AACL,cAAI;AAAA,YACF,qHAAgH,WAAW;AAAA,UAC7H;AAAA,QACF;AAAA,MACF;AACA,YAAM;AAAA,IACR;AACA,aAAS,QAAQ,GAAG,IAAI,aAAa;AACrC,mBAAe,QAAQ,MAAM,QAAQ,QAAQ,IAAI;AAAA,EACnD,SAAS,OAAO;AACd,UAAM,WAAW,KAAK;AAAA,EACxB;AACF;AAEA,eAAe,WAAW,SAAiB,SAAyB,KAA6B;AAC/F,QAAM,UAAU,YAAY,GAAG;AAC/B,QAAM,iBAAiB,gBAAgB,SAAS,SAAS;AACzD,QAAM,SAAS,QAAQ,SAAS,oBAAoB,QAAQ,QAAQ,QAAQ,IAAI;AAChF,QAAM,gBAAgB,QAAQ,gBAC1B,iBAAiB,QAAQ,eAAe,iBAAiB,IACzD;AACJ,QAAM,iBAAiB,QAAQ,iBAC3B,iBAAiB,QAAQ,gBAAgB,kBAAkB,IAC3D;AAEJ,MAAI;AACF,UAAM,WAAW,MAAM,kBAAkB,EAAE,SAAS,eAAe,KAAK,CAAC;AACzE,UAAM,SAAS;AAAA,MACb,SAAS,SAAS;AAAA,MAClB,SAAS;AAAA,MACT;AAAA,IACF;AAEA,QAAI,QAAQ,WAAW,MAAM;AAC3B,YAAM,QAAQ,MAAM,SAAS,OAAO,OAAO,eAAe,QAAQ;AAAA,QAChE,UAAU,QAAQ,aAAa;AAAA,MACjC,CAAC;AACD,iBAAW,OAAO,WAAW,SAAS,QAAQ,IAAI;AAClD;AAAA,IACF;AAEA,UAAM,cAAc;AAAA,MAClB,UAAU,QAAQ,aAAa;AAAA,MAC/B,MAAM,QAAQ,SAAS;AAAA,MACvB,GAAI,kBAAkB,SAAY,CAAC,IAAI,EAAE,cAAc;AAAA,MACvD,GAAI,mBAAmB,SAAY,CAAC,IAAI,EAAE,eAAe;AAAA,IAC3D;AAEA,UAAM,UACJ,CAAC,QAAQ,QAAQ,CAAC,QAAQ,IACtB,IAAI;AAAA,MACF,MAAM,aAAa,cAAc,SAAS,GAAG,CAAC,CAAC;AAAA,MAC/C,QAAQ,QAAQ;AAAA,IAClB,CAAC,EAAE,MAAM,IACT;AAEN,QAAI;AACJ,QAAI;AACF,eAAS,MAAM,SAAS,OAAO,OAAO,KAAK,QAAQ,QAAQ,WAAW;AAAA,IACxE,SAAS,OAAO;AACd,eAAS,KAAK,iBAAiB;AAM/B,YAAM,cAAc,yBAAyB,KAAK;AAClD,UAAI,gBAAgB,QAAW;AAC7B,YAAI,QAAQ,MAAM;AAChB,oBAAU,EAAE,YAAY,aAAa,QAAQ,OAAO,SAAS,KAAK,CAAC;AAAA,QACrE,OAAO;AACL,cAAI;AAAA,YACF,iIAA4H,WAAW;AAAA,UACzI;AAAA,QACF;AAAA,MACF;AACA,YAAM;AAAA,IACR;AACA,aAAS,QAAQ,oBAAoB;AACrC,mBAAe,QAAQ,WAAW,SAAS,QAAQ,IAAI;AAAA,EACzD,SAAS,OAAO;AACd,UAAM,WAAW,KAAK;AAAA,EACxB;AACF;AAUA,eAAe,eACb,QACA,MACA,MAW+D;AAC/D,QAAM,OAAO,EAAE,UAAU,KAAK,SAAS;AAMvC,QAAM,aAAa;AAAA,IACjB,SAAS,KAAK;AAAA,IACd,SAAS,KAAK;AAAA,IACd,gBAAgB,KAAK;AAAA,IACrB,GAAI,KAAK,aAAa,SAAY,CAAC,IAAI,EAAE,UAAU,KAAK,SAAS;AAAA,EACnE;AACA,MAAI,SAAS,OAAO;AAClB,WAAO,MAAM,OAAO,OAAO;AAAA,MACzB,KAAK;AAAA,MACL,EAAE,GAAG,YAAY,YAAY,KAAK,WAAY;AAAA,MAC9C;AAAA,IACF;AAAA,EACF;AACA,MAAI,SAAS,QAAQ;AACnB,WAAO,MAAM,OAAO,OAAO;AAAA,MACzB,KAAK;AAAA,MACL,EAAE,GAAG,YAAY,cAAc,KAAK,aAAc;AAAA,MAClD;AAAA,IACF;AAAA,EACF;AACA,SAAO,MAAM,OAAO,OAAO,qBAAqB,KAAK,QAAQ,YAAY,IAAI;AAC/E;AAUA,SAAS,WAAW,OAAkB,MAAwB,QAAgB,MAAqB;AAOjG,QAAM,SAAS,gBAAgB,MAAM,MAAM;AAC3C,MAAI,MAAM;AACR,cAAU;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,MACA,YAAY,MAAM;AAAA,MAClB,WAAW,MAAM;AAAA,MACjB,QAAQ;AAAA,IACV,CAAC;AACD;AAAA,EACF;AACA,QAAM,EAAE;AACR,QAAM,KAAK,MAAM,KAAK,SAAS,CAAC,mDAA8C;AAC9E,QAAM,KAAK,MAAM,IAAI,UAAU,CAAC,IAAI,IAAI,EAAE;AAC1C,QAAM,KAAK,MAAM,IAAI,UAAU,CAAC,IAAI,cAAc,QAAQ,IAAI,CAAC,CAAC,EAAE;AAClE,QAAM,YAAY,OAAO,QAAQ;AACjC,QAAM,SAAS,OAAO,cAAc,WAAW,YAAY;AAC3D,QAAM,KAAK,MAAM,IAAI,UAAU,CAAC,IAAI,cAAc,QAAQ,IAAI,CAAC,CAAC,EAAE;AAClE,QAAM,KAAK,MAAM,IAAI,UAAU,CAAC,IAAI,OAAO,OAAO,OAAO,CAAC,CAAC,EAAE;AAC7D,QAAM,KAAK,MAAM,IAAI,UAAU,CAAC,IAAI,MAAM,UAAU,EAAE;AACtD,QAAM,EAAE;AACR,QAAM,MAAM,IAAI,8CAA8C,CAAC;AACjE;AAgBA,SAAS,eACP,QACA,MACA,QACA,MACM;AACN,QAAM,SAAS,qBAAqB;AACpC,QAAM,UAAU,SACZ;AAAA,IACE;AAAA,IACA;AAAA,IACA,YAAY,OAAO;AAAA,IACnB,iBAAiB,OAAO;AAAA,IACxB,aAAa,OAAO,YAAY,SAAS;AAAA,IACzC,SAAS,OAAO;AAAA,IAChB,eAAe,OAAO,QAAQ,SAAS;AAAA,EACzC,IACA;AAAA,IACE;AAAA,IACA;AAAA,IACA,YAAY,OAAO;AAAA,IACnB,QAAQ;AAAA,EACV;AACJ,MAAI,MAAM;AACR,cAAU,OAAO;AACjB;AAAA,EACF;AACA,QAAM,EAAE;AACR,MAAI,QAAQ;AACV,QAAI,OAAO,SAAS;AAClB,UAAI,QAAQ,GAAG,IAAI,sBAAsB,OAAO,YAAY,SAAS,CAAC,GAAG;AAAA,IAC3E,OAAO;AACL,UAAI,MAAM,GAAG,IAAI,kCAAkC;AAAA,IACrD;AACA,UAAM,KAAK,MAAM,IAAI,WAAW,CAAC,IAAI,OAAO,UAAU,EAAE;AACxD,UAAM,KAAK,MAAM,IAAI,WAAW,CAAC,IAAI,OAAO,eAAe,EAAE;AAC7D,UAAM,KAAK,MAAM,IAAI,WAAW,CAAC,IAAI,OAAO,YAAY,SAAS,CAAC,EAAE;AACpE,UAAM,KAAK,MAAM,IAAI,WAAW,CAAC,IAAI,OAAO,QAAQ,SAAS,CAAC,EAAE;AAAA,EAClE,OAAO;AACL,QAAI,QAAQ,GAAG,IAAI,+BAA+B;AAClD,UAAM,KAAK,MAAM,IAAI,SAAS,CAAC,IAAI,OAAO,UAAU,EAAE;AACtD,QAAI,KAAK,mCAAmC,OAAO,UAAU,2BAA2B;AAAA,EAC1F;AACF;AAWA,SAAS,yBAAyB,OAA2C;AAC3E,SAAO,mBAAmB,OAAO;AAAA,IAC/B,MAAM;AAAA,IACN,YAAY;AAAA,EACd,CAAC;AACH;;;AEvhBA,SAAS,UAAU,iBAAiB;AAEpC,SAAS,WAAAC,iBAAe;AAiCxB,IAAM,kBAAkB,IAAIC,UAAQ,KAAK,EACtC,YAAY,wEAAwE,EACpF,SAAS,YAAY,uCAAuC,EAC5D,eAAe,yBAAyB,yBAAyB,EACjE,eAAe,uBAAuB,yBAAyB,EAC/D,OAAO,sBAAsB,+CAA+C,EAC5E,OAAO,sBAAsB,4CAA4C,EACzE,OAAO,gBAAgB,sDAAsD,EAC7E,OAAO,iBAAiB,sCAAsC,EAC9D;AAAA,EACC,OAAO,QAAgB,SAAkD,QAAiB;AACxF,UAAM,SAAS,OAAO,QAAQ,SAAS,GAAG;AAAA,EAC5C;AACF;AAEF,IAAM,mBAAmB,IAAIA,UAAQ,MAAM,EACxC,YAAY,yEAAyE,EACrF,SAAS,YAAY,uCAAuC,EAC5D,eAAe,yBAAyB,yBAAyB,EACjE,eAAe,yBAAyB,sCAAsC,EAC9E,OAAO,sBAAsB,+CAA+C,EAC5E,OAAO,sBAAsB,4CAA4C,EACzE,OAAO,gBAAgB,sDAAsD,EAC7E,OAAO,iBAAiB,sCAAsC,EAC9D;AAAA,EACC,OAAO,QAAgB,SAAkD,QAAiB;AACxF,UAAM,SAAS,QAAQ,QAAQ,SAAS,GAAG;AAAA,EAC7C;AACF;AAEF,IAAM,oBAAoB,IAAIA,UAAQ,OAAO,EAC1C,YAAY,gFAAgF,EAC5F,SAAS,YAAY,uCAAuC,EAC5D,eAAe,yBAAyB,yBAAyB,EACjE,OAAO,sBAAsB,+CAA+C,EAC5E,OAAO,sBAAsB,4CAA4C,EACzE,OAAO,gBAAgB,sDAAsD,EAC7E,OAAO,iBAAiB,sCAAsC,EAC9D,OAAO,OAAO,QAAgB,SAA6B,QAAiB;AAC3E,QAAM,SAAS,SAAS,QAAQ,SAAS,GAAG;AAC9C,CAAC;AAEH,IAAM,sBAAsB,IAAIA,UAAQ,SAAS,EAC9C,YAAY,4EAA4E,EACxF,SAAS,aAAa,kEAA6D,EACnF,OAAO,uBAAuB,+DAA+D,EAC7F,OAAO,gBAAgB,sDAAsD,EAC7E,OAAO,iBAAiB,sCAAsC,EAC9D;AAAA,EACC,OACE,SACA,SACA,QACG;AACH,UAAM,gBAAgB,SAAS,SAAS,GAAG;AAAA,EAC7C;AACF;AAEF,IAAM,eAAe,IAAIA,UAAQ,OAAO,EACrC,YAAY,8EAA8E,EAC1F,WAAW,eAAe,EAC1B,WAAW,gBAAgB,EAC3B,WAAW,iBAAiB,EAC5B,WAAW,mBAAmB;AAIjC,eAAe,SACb,MACA,QACA,SACA,KACe;AACf,QAAM,UAAU,YAAY,GAAG;AAC/B,QAAM,gBAAgB,gBAAgB,QAAQ,QAAQ;AACtD,QAAM,UAAU,kBAAkB,QAAQ,OAAO;AACjD,QAAM,cAAc,QAAQ,cACxB,iBAAiB,QAAQ,WAAW,IACpC;AACJ,QAAM,WAAW,QAAQ,cAAc,iBAAiB,QAAQ,WAAW,IAAI;AAE/E,MAAI;AACJ,MAAI;AACJ,MAAI,SAAS,OAAO;AAClB,iBAAa,oBAAoB,QAAQ,QAAS,QAAQ;AAAA,EAC5D,WAAW,SAAS,QAAQ;AAC1B,mBAAe,mBAAmB,QAAQ,QAAS,QAAQ;AAAA,EAC7D;AAEA,MAAI;AAGF,UAAM,WAAW,MAAM,kBAAkB,EAAE,QAAQ,CAAC;AAOpD,UAAM,aAAa;AAAA,MACjB,SAAS,SAAS;AAAA,MAClB;AAAA,MACA,gBAAgB;AAAA,MAChB,GAAI,aAAa,SAAY,CAAC,IAAI,EAAE,SAAS;AAAA,IAC/C;AACA,UAAM,OAAO,EAAE,UAAU,QAAQ,aAAa,MAAM;AAEpD,QAAI;AACJ,QAAI,SAAS,OAAO;AAClB,cAAQ,MAAM,SAAS,OAAO,OAAO;AAAA,QACnC;AAAA,QACA,EAAE,GAAG,YAAY,WAAwB;AAAA,QACzC;AAAA,MACF;AAAA,IACF,WAAW,SAAS,QAAQ;AAC1B,cAAQ,MAAM,SAAS,OAAO,OAAO;AAAA,QACnC;AAAA,QACA,EAAE,GAAG,YAAY,aAA4B;AAAA,QAC7C;AAAA,MACF;AAAA,IACF,OAAO;AACL,cAAQ,MAAM,SAAS,OAAO,OAAO,qBAAqB,eAAe,YAAY,IAAI;AAAA,IAC3F;AAEA,UAAM,gBAAgB,OAAO,MAAM,QAAQ,QAAQ,KAAK,QAAQ,IAAI;AAAA,EACtE,SAAS,OAAO;AACd,UAAM,WAAW,KAAK;AAAA,EACxB;AACF;AAEA,eAAe,gBACb,SACA,SACA,KACe;AACf,QAAM,UAAU,YAAY,GAAG;AAC/B,QAAM,iBAAiB,gBAAgB,SAAS,SAAS;AACzD,QAAM,SAAS,QAAQ,SAAS,oBAAoB,QAAQ,QAAQ,QAAQ,IAAI;AAEhF,MAAI;AACF,UAAM,WAAW,MAAM,kBAAkB,EAAE,QAAQ,CAAC;AACpD,UAAM,QAAQ,MAAM,SAAS,OAAO,OAAO;AAAA,MACzC;AAAA,QACE,SAAS,SAAS;AAAA,QAClB,SAAS;AAAA,QACT;AAAA,MACF;AAAA,MACA,EAAE,UAAU,QAAQ,aAAa,MAAM;AAAA,IACzC;AACA,UAAM,gBAAgB,OAAO,WAAW,SAAS,QAAQ,KAAK,QAAQ,IAAI;AAAA,EAC5E,SAAS,OAAO;AACd,UAAM,WAAW,KAAK;AAAA,EACxB;AACF;AAMA,IAAM,kBAAkB,IAAIA,UAAQ,UAAU,EAC3C,YAAY,6DAA6D,EACzE,SAAS,UAAU,yDAAyD,EAC5E;AAAA,EACC;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAMF,EACC,OAAO,OAAO,MAA0B,OAAO,QAAiB;AAC/D,QAAM,UAAU,YAAY,GAAG;AAC/B,MAAI;AACF,UAAM,SAAS,MAAM,mBAAmB,IAAI;AAC5C,UAAM,WAAW,MAAM,kBAAkB,EAAE,QAAQ,CAAC;AACpD,UAAM,SAAS,MAAM,SAAS,OAAO,OAAO,SAAS,MAAM;AAE3D,QAAI,QAAQ,MAAM;AAChB,gBAAU,0BAA0B,MAAM,CAAC;AAC3C;AAAA,IACF;AACA,UAAM,EAAE;AACR,QAAI,OAAO,aAAa;AACtB,UAAI,QAAQ,4BAA4B;AACxC,UAAI,OAAO,gBAAgB,QAAW;AACpC,cAAM,KAAK,MAAM,IAAI,eAAe,CAAC,IAAI,OAAO,YAAY,SAAS,CAAC,EAAE;AAAA,MAC1E;AAAA,IACF,OAAO;AACL,UAAI,MAAM,2BAA2B;AACrC,YAAM,KAAK,MAAM,IAAI,WAAW,CAAC,IAAI,OAAO,YAAY,EAAE;AAC1D,UAAI,OAAO,cAAc;AACvB,cAAM,KAAK,MAAM,IAAI,YAAY,CAAC,IAAI,OAAO,aAAa,IAAI,EAAE;AAAA,MAClE;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,UAAM,WAAW,KAAK;AAAA,EACxB;AACF,CAAC;AAaH,IAAM,gBAAgB,IAAIA,UAAQ,QAAQ,EACvC,YAAY,uEAAuE,EACnF,SAAS,UAAU,+DAA+D,EAClF,OAAO,0BAA0B,6DAA6D,EAC9F,OAAO,UAAU,mCAAmC,EACpD,OAAO,yBAAyB,yCAAyC,EACzE,OAAO,0BAA0B,sCAAsC,EACvE;AAAA,EACC;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAKF,EACC,OAAO,OAAO,MAA0B,SAAwB,QAAiB;AAChF,QAAM,UAAU,YAAY,GAAG;AAC/B,QAAM,gBAAgB,QAAQ,gBAC1B,iBAAiB,QAAQ,eAAe,iBAAiB,IACzD;AACJ,QAAM,iBAAiB,QAAQ,iBAC3B,iBAAiB,QAAQ,gBAAgB,kBAAkB,IAC3D;AAEJ,MAAI;AACF,UAAM,SAAS,MAAM,iBAAiB,IAAI;AAC1C,UAAM,WAAW,MAAM,kBAAkB,EAAE,QAAQ,CAAC;AACpD,UAAM,SAAS,MAAM,SAAS,OAAO,OAAO,OAAO,QAAQ;AAAA,MACzD,oBAAoB,QAAQ,uBAAuB;AAAA,IACrD,CAAC;AAED,QAAI,QAAQ,SAAS,MAAM;AACzB,UAAI,QAAQ,MAAM;AAChB,kBAAU,EAAE,YAAY,OAAO,YAAY,QAAQ,MAAM,CAAC;AAC1D;AAAA,MACF;AACA,UAAI,QAAQ,mBAAmB;AAC/B,YAAM,KAAK,MAAM,IAAI,MAAM,CAAC,IAAI,OAAO,UAAU,EAAE;AACnD,UAAI,KAAK,mCAAmC,OAAO,UAAU,2BAA2B;AACxF;AAAA,IACF;AAEA,UAAM,WAAW;AAAA,MACf,GAAI,kBAAkB,SAAY,CAAC,IAAI,EAAE,WAAW,cAAc;AAAA,MAClE,GAAI,mBAAmB,SAAY,CAAC,IAAI,EAAE,YAAY,eAAe;AAAA,IACvE;AAUA,QAAI;AACJ,QAAI;AACF,gBAAU,MAAM,SAAS,OAAO,QAAQ,eAAe,OAAO,YAAY,QAAQ;AAAA,IACpF,SAAS,WAAW;AAClB,UAAI,QAAQ,MAAM;AAKhB,kBAAU,EAAE,YAAY,OAAO,YAAY,QAAQ,OAAO,SAAS,KAAK,CAAC;AAAA,MAC3E,OAAO;AACL,YAAI;AAAA,UACF,kHAA6G,OAAO,UAAU;AAAA,QAChI;AAAA,MACF;AACA,YAAM,WAAW,SAAS;AAAA,IAC5B;AAEA,QAAI,QAAQ,MAAM;AAChB,gBAAU,iBAAiB,OAAO,CAAC;AACnC;AAAA,IACF;AACA,qBAAiB,OAAO;AAAA,EAC1B,SAAS,OAAO;AACd,UAAM,WAAW,KAAK;AAAA,EACxB;AACF,CAAC;AAMH,IAAM,cAAc,IAAIA,UAAQ,MAAM,EACnC,YAAY,kEAAkE,EAC9E,SAAS,UAAU,yDAAyD,EAC5E;AAAA,EACC;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUF,EACC,OAAO,OAAO,MAA0B,OAAO,QAAiB;AAC/D,QAAM,UAAU,YAAY,GAAG;AAC/B,MAAI;AACF,UAAM,SAAS,MAAM,mBAAmB,IAAI;AAC5C,UAAM,WAAW,MAAM,kBAAkB,EAAE,QAAQ,CAAC;AACpD,UAAM,aAAa,SAAS,OAAO,OAAO,OAAO,MAAM;AAEvD,QAAI,QAAQ,MAAM;AAChB,gBAAU,EAAE,WAAW,CAAC;AACxB;AAAA,IACF;AACA,UAAM,UAAU;AAAA,EAClB,SAAS,OAAO;AACd,UAAM,WAAW,KAAK;AAAA,EACxB;AACF,CAAC;AAMH,IAAM,iBAAiB,IAAIA,UAAQ,SAAS,EACzC,YAAY,yEAAyE,EACrF,SAAS,UAAU,qCAAqC,EACxD;AAAA,EACC;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAKF,EACC,OAAO,OAAO,MAAc,OAAO,QAAiB;AACnD,QAAM,UAAU,YAAY,GAAG;AAC/B,MAAI,CAAC,eAAe,KAAK,IAAI,GAAG;AAC9B,UAAM,IAAI;AAAA,MACR;AAAA,MACA,QAAQ,IAAI;AAAA,MACZ;AAAA,IACF;AAAA,EACF;AACA,MAAI;AACF,UAAM,WAAW,MAAM,kBAAkB,EAAE,QAAQ,CAAC;AACpD,UAAM,UAAU,MAAM,SAAS,OAAO,QAAQ,WAAW,IAAqB;AAE9E,QAAI,QAAQ,MAAM;AAChB,gBAAU,YAAY,OAAO,OAAO,iBAAiB,OAAO,CAAC;AAC7D;AAAA,IACF;AACA,QAAI,YAAY,MAAM;AACpB,UAAI,KAAK,qCAAqC;AAC9C;AAAA,IACF;AACA,qBAAiB,OAAO;AAAA,EAC1B,SAAS,OAAO;AACd,UAAM,WAAW,KAAK;AAAA,EACxB;AACF,CAAC;AAEH,IAAM,cAAc,IAAIA,UAAQ,MAAM,EACnC,YAAY,mEAAmE,EAC/E,SAAS,UAAU,qCAAqC,EACxD;AAAA,EACC;AAAA,EACA;AACF,EACC,OAAO,qBAAqB,8BAA8B,EAC1D;AAAA,EACC;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAKF,EACC;AAAA,EACC,OAAO,MAAc,SAAsD,QAAiB;AAC1F,UAAM,UAAU,YAAY,GAAG;AAC/B,QAAI,CAAC,eAAe,KAAK,IAAI,GAAG;AAC9B,YAAM,IAAI;AAAA,QACR;AAAA,QACA,QAAQ,IAAI;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AACA,UAAM,YAAY,QAAQ,YACtB,iBAAiB,QAAQ,WAAW,YAAY,IAChD;AACJ,UAAM,aAAa,QAAQ,aACvB,iBAAiB,QAAQ,YAAY,aAAa,IAClD;AAEJ,QAAI;AACF,YAAM,WAAW,MAAM,kBAAkB,EAAE,QAAQ,CAAC;AACpD,YAAM,WAAW;AAAA,QACf,GAAI,cAAc,SAAY,CAAC,IAAI,EAAE,UAAU;AAAA,QAC/C,GAAI,eAAe,SAAY,CAAC,IAAI,EAAE,WAAW;AAAA,MACnD;AACA,YAAM,UAAU,MAAM,SAAS,OAAO,QAAQ;AAAA,QAC5C;AAAA,QACA;AAAA,MACF;AACA,UAAI,QAAQ,MAAM;AAChB,kBAAU,iBAAiB,OAAO,CAAC;AACnC;AAAA,MACF;AACA,uBAAiB,OAAO;AAAA,IAC1B,SAAS,OAAO;AACd,YAAM,WAAW,KAAK;AAAA,IACxB;AAAA,EACF;AACF;AAMK,IAAM,gBAAgB,IAAIA,UAAQ,QAAQ,EAC9C,YAAY,0EAA0E,EACtF,WAAW,YAAY,EACvB,WAAW,eAAe,EAC1B,WAAW,aAAa,EACxB,WAAW,WAAW,EACtB,WAAW,cAAc,EACzB,WAAW,WAAW;AAYzB,eAAe,gBACb,OACA,MACA,QACA,SACA,MACe;AACf,QAAM,UAAU;AAAA,IACd;AAAA,IACA;AAAA,IACA,QAAQ,gBAAgB,MAAM,MAAM;AAAA,IACpC,YAAY,MAAM;AAAA,IAClB,WAAW,MAAM;AAAA,EACnB;AACA,QAAM,aAAa,KAAK,UAAU,SAAS,MAAM,CAAC;AAElD,MAAI,SAAS;AACX,QAAI;AACF,YAAM,UAAU,SAAS,GAAG,UAAU;AAAA,GAAM,EAAE,UAAU,QAAQ,MAAM,IAAM,CAAC;AAAA,IAC/E,SAAS,OAAO;AACd,YAAM,IAAI,SAAS,mBAAmB,OAAO,KAAK;AAAA,QAChD,MAAM;AAAA,QACN,aAAa;AAAA,QACb,YAAY;AAAA,QACZ;AAAA,MACF,CAAC;AAAA,IACH;AACA,QAAI,CAAC,MAAM;AACT,UAAI,QAAQ,SAAS,OAAO,eAAe;AAC3C,YAAM,KAAK,MAAM,IAAI,QAAQ,CAAC,IAAI,IAAI,EAAE;AACxC,YAAM,KAAK,MAAM,IAAI,QAAQ,CAAC,IAAI,cAAc,QAAQ,IAAI,CAAC,CAAC,EAAE;AAChE,YAAM,KAAK,MAAM,IAAI,QAAQ,CAAC,IAAI,MAAM,UAAU,EAAE;AAAA,IACtD;AACA;AAAA,EACF;AAEA,MAAI,MAAM;AACR,cAAU,OAAO;AACjB;AAAA,EACF;AAGA,MAAI,QAAQ,SAAS,IAAI,UAAU;AACnC,MAAI,OAAO,QAAQ,MAAM,UAAU;AACnC,QAAM,UAAU;AAClB;AAGA,eAAe,mBAAmB,MAAmD;AACnF,QAAM,MAAM,MAAM,WAAW,IAAI;AACjC,QAAM,SAAS,cAAc,GAAG;AAChC,SAAO,kBAAkB,OAAO,MAAM;AACxC;AAUA,IAAM,0BAA0B;AAGhC,eAAe,iBAAiB,MAAiD;AAC/E,QAAM,MAAM,MAAM,WAAW,IAAI;AACjC,QAAM,SAAS,cAAc,GAAG;AAChC,QAAM,SAAS,kBAAkB,OAAO,MAAM;AAC9C,QAAM,YAAa,OAA8C;AACjE,MAAI,OAAO,cAAc,YAAY,cAAc,MAAM;AACvD,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAKA,MAAI,CAAC,wBAAwB,KAAK,SAAS,GAAG;AAC5C,UAAM,IAAI;AAAA,MACR;AAAA,MACA,OAAO,OAAO,UAAU,MAAM,CAAC;AAAA,IACjC;AAAA,EACF;AACA,MAAI,UAAU,SAAS,KAAK;AAC1B,UAAM,IAAI;AAAA,MACR;AAAA,MACA,OAAO,OAAO,UAAU,MAAM,CAAC;AAAA,IACjC;AAAA,EACF;AACA,SAAO;AACT;AAEA,eAAe,WAAW,MAA2C;AACnE,MAAI,SAAS,UAAa,SAAS,KAAK;AACtC,QAAI;AACF,aAAO,MAAM,SAAS,MAAM,MAAM;AAAA,IACpC,SAAS,OAAO;AACd,YAAM,IAAI,SAAS,kBAAkB,IAAI,KAAK;AAAA,QAC5C,MAAM;AAAA,QACN,aAAa;AAAA,QACb,YAAY;AAAA,QACZ;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAEA,QAAM,SAAmB,CAAC;AAC1B,mBAAiB,SAAS,QAAQ,OAAO;AACvC,QAAI,OAAO,UAAU,SAAU,QAAO,KAAK,OAAO,KAAK,KAAK,CAAC;AAAA,aACpD,iBAAiB,OAAQ,QAAO,KAAK,KAAK;AAAA,QAC9C,QAAO,KAAK,OAAO,KAAK,KAAmB,CAAC;AAAA,EACnD;AACA,MAAI,OAAO,WAAW,GAAG;AACvB,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAIA,QAAM,EAAE,SAAS,IAAI,MAAM,OAAO,qBAAsB;AACxD,SAAO,SAAS,OAAO,OAAO,MAAM,EAAE,SAAS,MAAM,CAAC;AACxD;AAEA,SAAS,cAAc,KAAkD;AACvE,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,GAAG;AAAA,EACzB,QAAQ;AACN,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,MACE,OAAO,WAAW,YAClB,WAAW,QACX,OAAQ,OAAgC,WAAW,YAClD,OAAgC,WAAW,MAC5C;AACA,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAGA,SAAS,kBAAkB,OAAyD;AAElF,QAAM,gBAAgB,oBAAI,IAAI;AAAA,IAC5B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AACD,QAAM,MAA+B,CAAC;AACtC,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,KAAK,GAAG;AAC1C,QAAI,cAAc,IAAI,CAAC,KAAK,OAAO,MAAM,UAAU;AACjD,UAAI;AACF,YAAI,CAAC,IAAI,OAAO,CAAC;AAAA,MACnB,QAAQ;AACN,cAAM,IAAI;AAAA,UACR,iBAAiB,CAAC;AAAA,UAClB,OAAO,OAAO,MAAM,WAAW,IAAI,CAAC,MAAM,OAAO,CAAC,CAAC;AAAA,QACrD;AAAA,MACF;AAAA,IACF,OAAO;AACL,UAAI,CAAC,IAAI;AAAA,IACX;AAAA,EACF;AACA,SAAO;AACT;AAgBA,SAAS,iBAAiB,SAAiD;AACzE,SAAO;AAAA,IACL,YAAY,QAAQ;AAAA,IACpB,QAAQ,QAAQ;AAAA,IAChB,OAAO,QAAQ;AAAA,IACf,SAAS,QAAQ;AAAA,IACjB,eAAe,QAAQ;AAAA,IACvB,eAAe,QAAQ;AAAA,IACvB,SAAS;AAAA,MACP,iBAAiB,QAAQ,QAAQ;AAAA,MACjC,aAAa,QAAQ,QAAQ;AAAA,MAC7B,QAAQ,QAAQ,QAAQ;AAAA,IAC1B;AAAA,EACF;AACF;AAEA,SAAS,iBAAiB,SAA8B;AACtD,QAAM,EAAE;AACR,MAAI,QAAQ,SAAS;AACnB,QAAI,QAAQ,+BAA+B;AAAA,EAC7C,OAAO;AACL,QAAI,MAAM,wCAAwC;AAAA,EACpD;AACA,QAAM,KAAK,MAAM,IAAI,SAAS,CAAC,IAAI,QAAQ,UAAU,EAAE;AACvD,QAAM,KAAK,MAAM,IAAI,SAAS,CAAC,IAAI,QAAQ,QAAQ,eAAe,EAAE;AACpE,QAAM,KAAK,MAAM,IAAI,SAAS,CAAC,IAAI,QAAQ,QAAQ,WAAW,EAAE;AAChE,QAAM,KAAK,MAAM,IAAI,SAAS,CAAC,IAAI,QAAQ,aAAa,EAAE;AAC5D;AAUA,SAAS,0BAA0B,QAAuD;AACxF,MAAI,OAAO,aAAa;AACtB,WAAO;AAAA,MACL,aAAa;AAAA,MACb,GAAI,OAAO,gBAAgB,SAAY,CAAC,IAAI,EAAE,aAAa,OAAO,YAAY,SAAS,EAAE;AAAA,IAC3F;AAAA,EACF;AACA,SAAO;AAAA,IACL,aAAa;AAAA,IACb,cAAc,OAAO;AAAA,IACrB,GAAI,OAAO,iBAAiB,SACxB,CAAC,IACD;AAAA,MACE,cAAc;AAAA,QACZ,MAAM,OAAO,aAAa;AAAA,QAC1B,MAAM,OAAO,aAAa,KAAK,IAAI,CAAC,MAAO,OAAO,MAAM,WAAW,EAAE,SAAS,IAAI,CAAE;AAAA,MACtF;AAAA,IACF;AAAA,EACN;AACF;;;AC/tBA,SAAS,WAAAC,iBAAe;AAajB,IAAM,eAAe,IAAIC,UAAQ,OAAO,EAC5C,YAAY,kEAAkE,EAC9E,SAAS,YAAY,uCAAuC,EAC5D,OAAO,oBAAoB,uCAAuC,EAClE,OAAO,oBAAoB,gDAAgD,EAC3E;AAAA,EACC;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYF,EACC,OAAO,OAAO,QAAgB,SAAuB,QAAiB;AACrE,QAAM,UAAU,YAAY,GAAG;AAE/B,QAAM,gBAAgB,gBAAgB,QAAQ,QAAQ;AAEtD,QAAM,YAAY,QAAQ,YACtB,iBAAiB,QAAQ,WAAW,YAAY,IAChD;AACJ,QAAM,YAAY,QAAQ,YACtB,iBAAiB,QAAQ,WAAW,YAAY,IAChD;AAEJ,MAAI;AACF,UAAM,WAAW,MAAM,kBAAkB,EAAE,QAAQ,CAAC;AASpD,QAAI;AACJ,QAAI,QAAQ;AACZ,UAAM,OAAO,IAAI,QAAgB,CAAC,YAAY;AAC5C,oBAAc;AAAA,IAChB,CAAC;AASD,UAAM,qBAEF,EAAE,SAAS,OAAU;AACzB,QAAI,oBAAoB;AACxB,UAAM,WAAW,CAACC,YAAyB;AACzC,UAAI,kBAAmB;AACvB,0BAAoB;AACpB,UAAI;AACF,2BAAmB,SAAS,YAAY;AAAA,MAC1C,QAAQ;AAAA,MAER;AACA,oBAAcA,OAAM;AAAA,IACtB;AAEA,uBAAmB,UAAU,SAAS,OAAO,QAAQ,MAAM,eAAe;AAAA,MACxE,SAAS,CAAC,UAAU;AAClB,YAAI,QAAQ,MAAM;AAKhB,sBAAY,KAAK;AAAA,QACnB,OAAO;AACL,gBAAM,iBAAiB,KAAK,CAAC;AAAA,QAC/B;AACA,iBAAS;AACT,YAAI,cAAc,UAAa,SAAS,WAAW;AACjD,mBAAS,wBAAwB,OAAO,SAAS,CAAC,EAAE;AAAA,QACtD;AAAA,MACF;AAAA,MACA,aAAa,MAAM;AACjB,YAAI,CAAC,QAAQ,MAAM;AACjB,cAAI,KAAK,iEAA4D;AAAA,QACvE;AAAA,MACF;AAAA,MACA,SAAS,CAAC,QAAQ;AAEhB,YAAI,CAAC,QAAQ,MAAM;AACjB,cAAI,KAAK,kBAAkB,IAAI,OAAO,EAAE;AAAA,QAC1C;AAAA,MACF;AAAA,IACF,CAAC;AAID,UAAM,WAAW,MAAY,SAAS,QAAQ;AAC9C,UAAM,YAAY,MAAY,SAAS,SAAS;AAChD,YAAQ,GAAG,UAAU,QAAQ;AAC7B,YAAQ,GAAG,WAAW,SAAS;AAI/B,UAAM,gBACJ,cAAc,SACV,WAAW,MAAM,SAAS,wBAAwB,OAAO,SAAS,CAAC,EAAE,GAAG,SAAS,IACjF;AACN,mBAAe,MAAM;AAKrB,QAAI,CAAC,QAAQ,MAAM;AACjB,UAAI,KAAK,mBAAmB,aAAa,QAAG;AAC5C,UAAI,OAAO,QAAQ,QAAQ;AAC3B,UAAI,cAAc,OAAW,KAAI,OAAO,cAAc,OAAO,SAAS,CAAC;AACvE,UAAI,cAAc,OAAW,KAAI,OAAO,gBAAgB,OAAO,SAAS,CAAC;AAAA,IAC3E;AAEA,UAAM,SAAS,MAAM;AAGrB,YAAQ,IAAI,UAAU,QAAQ;AAC9B,YAAQ,IAAI,WAAW,SAAS;AAChC,QAAI,kBAAkB,OAAW,cAAa,aAAa;AAE3D,QAAI,CAAC,QAAQ,MAAM;AACjB,UAAI,KAAK,oBAAoB,MAAM,IAAI;AAAA,IACzC;AAAA,EACF,SAAS,OAAO;AACd,UAAM,WAAW,KAAK;AAAA,EACxB;AACF,CAAC;AAoCI,SAAS,iBAAiB,OAA+B;AAC9D,QAAM,QAAO,oBAAI,KAAK,GAAE,YAAY,EAAE,MAAM,IAAI,EAAE;AAClD,MAAI,MAAM,SAAS,SAAS;AAC1B,WAAO,GAAG,MAAM,IAAI,IAAI,CAAC,KAAK,MAAM,KAAK,OAAO,CAAC,YAAY,MAAM,IAAI,QAAQ,OAAO,MAAM,OAAO,CAAC,SAAS,MAAM,WAAW,SAAS,CAAC,WAAW,MAAM,UAAU,SAAS,CAAC,OAAO,MAAM,gBAAgB,MAAM,GAAG,EAAE,CAAC;AAAA,EACxN;AACA,MAAI,MAAM,SAAS,YAAY;AAC7B,WAAO,GAAG,MAAM,IAAI,IAAI,CAAC,KAAK,MAAM,KAAK,UAAU,CAAC,WAAW,OAAO,MAAM,cAAc,CAAC,OAAO,MAAM,gBAAgB,MAAM,GAAG,EAAE,CAAC;AAAA,EACtI;AACA,SAAO,GAAG,MAAM,IAAI,IAAI,CAAC,KAAK,MAAM,KAAK,QAAQ,CAAC,iBAAiB,MAAM,WAAW,SAAS,CAAC,OAAO,MAAM,gBAAgB,MAAM,GAAG,EAAE,CAAC;AACzI;;;AdpLO,IAAM,kBAAkB,IAAIC,UAAQ,UAAU,EAClD;AAAA,EACC;AACF,EACC,WAAW,cAAc,EACzB,WAAW,aAAa,EACxB,WAAW,YAAY,EACvB,WAAW,eAAe,EAC1B,WAAW,gBAAgB,EAC3B,WAAW,mBAAmB,EAC9B,WAAW,WAAW,EACtB,WAAW,cAAc,EACzB,WAAW,mBAAmB,EAC9B,WAAW,YAAY,EACvB,WAAW,aAAa,EACxB,WAAW,YAAY;","names":["Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","Command","reason","Command"]}