@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,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  style
4
- } from "./chunk-MQUJG224.js";
4
+ } from "./chunk-2HFKULGG.js";
5
5
 
6
6
  // src/utils/formatting.ts
7
7
  import Table from "cli-table3";
@@ -90,8 +90,10 @@ function formatBigDecimal(value, options) {
90
90
  const baseScale = 10n ** BigInt(baseDecimals);
91
91
  const whole = abs / baseScale;
92
92
  const frac = abs % baseScale;
93
- const truncated = (frac / 10n ** BigInt(baseDecimals - displayDecimals)).toString().padStart(displayDecimals, "0");
93
+ const shown = Math.min(Math.max(displayDecimals, 0), baseDecimals);
94
94
  const wholeStr = useThousandSeparator ? whole.toLocaleString("en-US") : whole.toString();
95
+ if (shown === 0) return `${negative ? "-" : ""}${wholeStr}`;
96
+ const truncated = (frac / 10n ** BigInt(baseDecimals - shown)).toString().padStart(shown, "0");
95
97
  return `${negative ? "-" : ""}${wholeStr}.${truncated}`;
96
98
  }
97
99
  function formatWad(wad) {
@@ -151,4 +153,4 @@ export {
151
153
  colorStatus,
152
154
  createTable
153
155
  };
154
- //# sourceMappingURL=chunk-R4NGUZKN.js.map
156
+ //# sourceMappingURL=chunk-6UU43MF5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/formatting.ts"],"sourcesContent":["/**\n * Display formatters: tables, addresses, USDC amounts, status colors.\n *\n * Atomic USDC values from the API are integer strings (6 decimals). The\n * SDK does not assume a math library, so we format with simple integer\n * division here — the precision constraint is purely cosmetic.\n */\n\nimport Table from 'cli-table3';\n\nimport { style } from './output.js';\n\n/**\n * ASCII ellipsis used for all truncation glyphs. We use three dots\n * rather than the Unicode horizontal-ellipsis (U+2026) because the\n * latter renders as `?` on Windows cmd.exe and in restricted locales\n * — `gh`, `aws`, and `stripe` all standardise on ASCII.\n */\nconst ELLIPSIS = '...';\n\n/**\n * Code-point-safe slice. `String.prototype.slice` operates on UTF-16\n * code units, so an emoji or other surrogate pair near a boundary\n * could split. None of the inputs we slice (API keys, hex addresses,\n * UUIDs) carry surrogates today — but defensive slicing matches\n * `gh`/`aws` and the cost is negligible.\n */\nfunction codepointSlice(s: string, start: number, end?: number): string {\n return Array.from(s).slice(start, end).join('');\n}\n\nfunction codepointLength(s: string): number {\n return Array.from(s).length;\n}\n\n/** Truncate a UUID/long ID to \"abcdef12...\" for tables. */\nexport function shortId(id: string, prefix = 8): string {\n if (codepointLength(id) <= prefix + ELLIPSIS.length) return id;\n return `${codepointSlice(id, 0, prefix)}${ELLIPSIS}`;\n}\n\n/**\n * Truncate a free-form string to fit within a column. Appends an\n * ellipsis when shortened so the user sees that data was elided.\n * Different from `shortId`, which uses a leading-prefix heuristic\n * suited to UUIDs and tx hashes.\n */\nexport function truncate(s: string, max: number): string {\n return codepointLength(s) > max ? `${codepointSlice(s, 0, max - ELLIPSIS.length)}${ELLIPSIS}` : s;\n}\n\n/**\n * Redact an API key for display. Always shows enough leading\n * characters (`kash_live_` / `kash_test_` prefix) to confirm the key\n * type, plus the last four characters so users can match it to a\n * value they have on record. Inputs shorter than 8 characters are\n * masked entirely so we never accidentally leak a partial key from\n * truncated input.\n */\nexport function redact(key: string): string {\n if (codepointLength(key) <= 8) return '***';\n return `${codepointSlice(key, 0, 8)}${ELLIPSIS}${codepointSlice(key, -4)}`;\n}\n\n/** Capitalise the first letter. Empty strings pass through. */\nexport function capitalize(s: string): string {\n if (s.length === 0) return s;\n return s.charAt(0).toUpperCase() + s.slice(1);\n}\n\n/** Format an EVM address as `0x1234...abcd`. */\nexport function formatAddress(address: string, lead = 6, tail = 4): string {\n if (codepointLength(address) <= lead + tail + ELLIPSIS.length) return address;\n return `${codepointSlice(address, 0, lead)}${ELLIPSIS}${codepointSlice(address, -tail)}`;\n}\n\n/** Format a UTC ISO string as a local-readable date+time. */\nexport function formatDate(value: string | Date | null | undefined): string {\n if (!value) return '-';\n const d = typeof value === 'string' ? new Date(value) : value;\n if (Number.isNaN(d.getTime())) return '-';\n return d.toLocaleString();\n}\n\n/**\n * Format a USDC value as `$1,234.56`.\n *\n * Two input shapes are accepted:\n *\n * 1. **Atomic** — bigint, integer string, or finite Number,\n * interpreted as micro-USDC (6 decimals). This is the canonical\n * shape on every API response (`totalCostBasisAtomic`,\n * `tokensOut`, etc.). Formatted with bigint math so values past\n * Number.MAX_SAFE_INTEGER round-trip exactly.\n * 2. **Decimal string** — only used by analytics endpoints that\n * return human-formatted dollar amounts (e.g. `\"1234.56\"`).\n * These pass through `Number.parseFloat`, which means values\n * with more than ~15 significant decimal digits round at IEEE-754\n * precision. This is acceptable for *display* (the underlying\n * authoritative value is always atomic), but consumers writing\n * reconciliation logic should call the upstream atomic field\n * directly rather than re-parsing a formatted decimal.\n *\n * The atomic branch rounds the cents column **toward zero** (cheaper\n * than half-even for tables; the trade engine reconciles to atomic\n * precision elsewhere). Cosmetic only.\n */\nexport function formatUsdcAtomic(atomic: string | bigint | number): string {\n if (typeof atomic === 'string' && atomic.includes('.')) {\n // Decimal-string branch (analytics only). Documented loss: values\n // > 15 significant digits round at parseFloat precision.\n // display only, and the loss is already documented two lines above for this analytics decimal-string branch.\n // eslint-disable-next-line @kashdao/no-parsefloat-monetary -- see above\n const n = Number.parseFloat(atomic);\n if (Number.isNaN(n)) return '$0.00';\n return n.toLocaleString('en-US', {\n style: 'currency',\n currency: 'USD',\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n });\n }\n let big: bigint;\n try {\n big = typeof atomic === 'bigint' ? atomic : BigInt(atomic);\n } catch {\n return '$0.00';\n }\n const negative = big < 0n;\n const abs = negative ? -big : big;\n const whole = abs / 1_000_000n;\n const frac = abs % 1_000_000n;\n const wholeStr = whole.toLocaleString('en-US');\n const cents = (frac / 10_000n).toString().padStart(2, '0');\n return `${negative ? '-' : ''}$${wholeStr}.${cents}`;\n}\n\n/**\n * Format a human USDC decimal string (e.g. `'12.5'`) as `$12.50`.\n * Used when the API hands back already-decimal amounts (the trade\n * resource's `amount` field).\n */\nexport function formatUsdcDecimal(value: string): string {\n const n = Number.parseFloat(value);\n if (Number.isNaN(n)) return value;\n return n.toLocaleString('en-US', {\n style: 'currency',\n currency: 'USD',\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n });\n}\n\n/** Format a probability in [0,1] as a percentage string. */\nexport function formatProbability(p: number | null | undefined): string {\n if (p === null || p === undefined || Number.isNaN(p)) return '-';\n return `${(p * 100).toFixed(1)}%`;\n}\n\n/**\n * Generic fixed-point bigint→decimal-display formatter. Used by every\n * CLI helper that needs to render an atomic-units bigint (WAD-18,\n * gwei-9, ETH-18, USDC-6) as a human-readable decimal string.\n *\n * Two parameters control shape:\n *\n * - `baseDecimals` — the unit's atomic precision (18 for WAD/ETH,\n * 9 for gwei, 6 for USDC).\n * - `displayDecimals` — how many fractional digits to emit. Must\n * be ≤ `baseDecimals`. Truncates rather than rounds — display\n * only, `--json` preserves the full atomic-string precision.\n *\n * Sign is extracted before the magnitude split so `-` rendering\n * lives at one site. The whole part is rendered with thousand-\n * separator commas via `toLocaleString` (consistent with\n * `formatUsdcAtomic`); call sites that need the raw integer-shape\n * (e.g. `formatGwei`'s historical \"no commas\" form) opt out via\n * `thousandSeparator: false`.\n *\n * Accepts `string | bigint` for the same reason `formatWad` did:\n * direct-mode SDKs return `bigint`, indexer-backed views return\n * integer-string. The `try/catch` around `BigInt(value)` is the\n * defensive never-throw guarantee on display paths — a malformed\n * input falls through to the input itself rather than crashing.\n */\nexport function formatBigDecimal(\n value: string | bigint,\n options: { baseDecimals: number; displayDecimals: number; thousandSeparator?: boolean }\n): string {\n const { baseDecimals, displayDecimals } = options;\n const useThousandSeparator = options.thousandSeparator ?? true;\n let big: bigint;\n try {\n big = typeof value === 'bigint' ? value : BigInt(value);\n } catch {\n return typeof value === 'string' ? value : '0';\n }\n const negative = big < 0n;\n const abs = negative ? -big : big;\n const baseScale = 10n ** BigInt(baseDecimals);\n const whole = abs / baseScale;\n const frac = abs % baseScale;\n /*\n * CLAMPED, and the point dropped at zero, so this agrees with the canonical\n * primitive it is the published twin of.\n *\n * `@kashdao/utils`' `formatAtomicUnits` already does exactly this — `const\n * shown = Math.min(displayDecimals, decimals)` — and the two disagreed on the\n * same inputs until 2026-09-09:\n *\n * | (baseDecimals, displayDecimals) | formatAtomicUnits | this, before |\n * | ------------------------------- | ----------------- | -------------- |\n * | 6, 8 | `12.500000` | **RangeError** |\n * | 6, 0 | `12` | `12.0` |\n *\n * The throw is the one that matters: `10n ** BigInt(baseDecimals -\n * displayDecimals)` raises `RangeError: Exponent must be non-negative`, and it\n * sits OUTSIDE the `try` above — which guards the `BigInt(value)` parse only.\n * The docblock's \"≤ baseDecimals\" was a contract on the caller with nothing\n * enforcing it.\n *\n * Unobservable for every caller today (`formatWad` 18/4, `formatGwei` 9/3, and\n * `protocol/balance` 18/6 all satisfy the old contract), which is why the\n * alignment is cheap now rather than after someone hits it. Showing precision\n * a unit does not have is the same lie `formatAtomicUnits` documents refusing\n * to tell.\n */\n const shown = Math.min(Math.max(displayDecimals, 0), baseDecimals);\n const wholeStr = useThousandSeparator ? whole.toLocaleString('en-US') : whole.toString();\n if (shown === 0) return `${negative ? '-' : ''}${wholeStr}`;\n const truncated = (frac / 10n ** BigInt(baseDecimals - shown)).toString().padStart(shown, '0');\n return `${negative ? '-' : ''}${wholeStr}.${truncated}`;\n}\n\n/**\n * Format a WAD-18 (1e18) value as a 4-decimal token display string.\n * Twin of `formatUsdcAtomic` but for outcome-token quantities.\n * Direct-mode SDK returns bigint; indexer-backed views return string.\n */\nexport function formatWad(wad: string | bigint): string {\n return formatBigDecimal(wad, { baseDecimals: 18, displayDecimals: 4 });\n}\n\n/**\n * Format a wei bigint as a 3-decimal gwei display string. Used by\n * direct-mode commands that emit gas balances and fee estimates.\n * Truncates rather than rounds — fees are display-only and operators\n * who need exact wei should use `--json` (which preserves the bigint\n * as a decimal string).\n *\n * No thousand-separator on the whole part: the gwei convention in\n * the broader EVM ecosystem (etherscan, foundry, viem's display\n * helpers) renders bare integers, and operators piping our output\n * through `awk '{print $2 + 0}'` or similar rely on it.\n */\nexport function formatGwei(wei: bigint): string {\n return formatBigDecimal(wei, {\n baseDecimals: 9,\n displayDecimals: 3,\n thousandSeparator: false,\n });\n}\n\n/** Apply a status color (green/yellow/red/blue/gray) by status string. */\nexport function colorStatus(value: string | null | undefined): string {\n if (!value) return style.dim('-');\n switch (value.toUpperCase()) {\n case 'ACTIVE':\n case 'COMPLETED':\n return style.success(value);\n case 'EXECUTING':\n case 'VALIDATING':\n case 'PENDING':\n return style.cyan(value);\n case 'PENDING_CONFIRMATION':\n return style.warn(value);\n case 'RESOLVED':\n return style.info(value);\n case 'REJECTED':\n case 'FAILED':\n return style.error(value);\n case 'UNSEEDED':\n case 'FROZEN':\n return style.dim(value);\n default:\n return value;\n }\n}\n\n/** Build a cli-table3 with bold headers and consistent style. */\nexport function createTable(headers: string[]): Table.Table {\n return new Table({\n head: headers.map((h) => style.bold(h)),\n style: { head: [], border: [] },\n });\n}\n"],"mappings":"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","names":[]}
@@ -2,10 +2,10 @@
2
2
  import {
3
3
  parseFieldsList,
4
4
  parseFilter
5
- } from "./chunk-KADB3OKE.js";
5
+ } from "./chunk-VFBQVUL4.js";
6
6
  import {
7
7
  CliValidationError
8
- } from "./chunk-X2VM6VKM.js";
8
+ } from "./chunk-WL7XUYPH.js";
9
9
 
10
10
  // src/utils/global-options.ts
11
11
  function readGlobals(cmd) {
@@ -130,4 +130,4 @@ export {
130
130
  parsePositiveFloat,
131
131
  parseOptionalPositiveFloat
132
132
  };
133
- //# sourceMappingURL=chunk-A3IH5HUV.js.map
133
+ //# sourceMappingURL=chunk-AROIP4EQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/global-options.ts"],"sourcesContent":["/**\n * Global option resolution.\n *\n * Commander 13 makes the root program's options available on every\n * subcommand via `cmd.optsWithGlobals()`. This helper centralises the\n * shape so command modules type their access to it once.\n *\n * The flags fall into three buckets:\n *\n * 1. **Output controls** — `--json`, `--quiet`, `--no-color`, `--debug`.\n * Drive how output and traces are rendered.\n * 2. **Config selection** — `--profile`, `--config`. Decide which\n * credentials get loaded.\n * 3. **SDK overrides** — `--base-url`, `--max-retries`, `--timeout-ms`.\n * Per-invocation overrides for the SDK config; useful for CI\n * matrix builds and ad-hoc staging tests.\n */\n\nimport { CliValidationError } from '../errors.js';\n\nimport { parseFieldsList } from './fields.js';\nimport { parseFilter, type FilterAst } from './filter.js';\n\nimport type { Command } from 'commander';\n\nexport type GlobalOptions = {\n /** `--json` — emit machine-readable JSON instead of human output. */\n readonly json: boolean;\n /** `--quiet` — suppress informational human-mode output. */\n readonly quiet: boolean;\n /** `--no-color` — disable ANSI escapes (also honors `NO_COLOR`). */\n readonly noColor: boolean;\n /** `--debug` — emit SDK lifecycle traces (request/response/retry/error) to stderr. */\n readonly debug: boolean;\n /** `--profile <name>` — pick a named profile from `~/.kash/config.json`. */\n readonly profile: string | undefined;\n /** `--config <path>` — explicit config file path; overrides default + env. */\n readonly configPath: string | undefined;\n /** `--base-url <url>` — override the API base URL for this invocation. */\n readonly baseUrl: string | undefined;\n /** `--max-retries <n>` — override SDK retry budget for this invocation. */\n readonly maxRetries: number | undefined;\n /** `--timeout-ms <n>` — override SDK request timeout for this invocation. */\n readonly timeoutMs: number | undefined;\n /**\n * `--api-version <date>` — pin against a public-API contract date.\n * The value is sent as `X-Kash-Api-Version` on every request. The\n * server runs a version-appropriate code path; sending an\n * unrecognised date returns `410 API_VERSION_UNSUPPORTED`. Omit\n * (`undefined`) → the profile's `apiVersion`, `KASH_API_VERSION`, or\n * the version the bundled `@kashdao/sdk` pins.\n */\n readonly apiVersion: string | undefined;\n /**\n * `--fields <list>` — gh-style projection on `--json` output. Parsed\n * into dot-segmented paths; `undefined` when the flag was not passed\n * (commands then emit the full payload).\n */\n readonly fields: ReadonlyArray<readonly string[]> | undefined;\n /**\n * `--filter <expr>` — boolean DSL applied before `--fields`\n * projection. Filters list/get-style payloads to entries matching\n * the predicate. `undefined` when the flag was not passed.\n */\n readonly filter: FilterAst | undefined;\n};\n\ntype RawGlobalOptions = {\n json?: boolean;\n quiet?: boolean;\n // Commander stores `--no-color` as `{ color: false }` — the default for a\n // `--no-X` boolean is `true`, so the explicit `false` means \"disabled.\"\n color?: boolean;\n debug?: boolean;\n profile?: string;\n config?: string;\n baseUrl?: string;\n maxRetries?: string;\n timeoutMs?: string;\n apiVersion?: string;\n fields?: string;\n filter?: string;\n};\n\n/**\n * Pull the globals from the active command. Falls back to defaults\n * for any flag the user did not pass. Validates numeric inputs with\n * structured errors (so an agent gets a `INVALID_INPUT` code, not a\n * cryptic NaN cascade).\n */\nexport function readGlobals(cmd: Command): GlobalOptions {\n const opts = cmd.optsWithGlobals<RawGlobalOptions>();\n return {\n json: opts.json === true,\n quiet: opts.quiet === true,\n noColor: opts.color === false,\n // `KASH_DEBUG=1` (or any truthy value) mirrors `--debug`. Common\n // case: CI matrix configs and parent processes that can't easily\n // edit the invocation. Explicit `--debug` always wins (a user can\n // force it on even when the env says off).\n debug: opts.debug === true || isTruthyEnv(process.env['KASH_DEBUG']),\n profile: opts.profile,\n configPath: opts.config,\n baseUrl: opts.baseUrl === undefined ? undefined : parseUrl(opts.baseUrl, 'base-url'),\n maxRetries:\n opts.maxRetries === undefined\n ? undefined\n : // Cap at 10 to match the SDK's `kashClientConfigSchema`\n // (`maxRetries: z.number().int().min(0).max(10)`). Bouncing\n // out-of-range values here gives the agent an `INVALID_INPUT`\n // with a clear field, instead of a cryptic SDK\n // `KashConfigurationError` after the client tries to construct.\n parseBoundedUnsigned(opts.maxRetries, 'max-retries', 0, 10),\n timeoutMs:\n opts.timeoutMs === undefined ? undefined : parsePositive(opts.timeoutMs, 'timeout-ms'),\n // `--api-version` is forwarded to the SDK as `apiVersion`. Format\n // validation (`YYYY-MM-DD`) is enforced by the SDK's\n // `kashClientConfigSchema`. We don't pre-validate here — letting\n // the SDK be the single source of truth keeps the format rule in\n // one place. A malformed value surfaces as\n // `KashConfigurationError` from client construction, which the\n // CLI's error mapper converts to a structured envelope.\n apiVersion: opts.apiVersion,\n fields: opts.fields === undefined ? undefined : parseFieldsList(opts.fields),\n filter: opts.filter === undefined ? undefined : parseFilter(opts.filter),\n };\n}\n\nfunction parseBoundedUnsigned(raw: string, name: string, min: number, max: number): number {\n // Same strict-shape rationale as `parsePositiveInt`: reject decimals\n // and scientific notation BEFORE `parseInt`'s silent precision loss\n // (`1.5 → 1`, `1e3 → 1`). Bounded numeric flags like `--max-retries`\n // shouldn't accept either form.\n if (!/^\\+?\\d+$/.test(raw)) {\n throw new CliValidationError(\n `--${name} must be an integer between ${String(min)} and ${String(max)}.`,\n `Got \"${raw}\". Pass digits only — no decimals or scientific notation.`,\n name\n );\n }\n const n = Number.parseInt(raw, 10);\n if (!Number.isFinite(n) || n < min || n > max) {\n throw new CliValidationError(\n `--${name} must be an integer between ${String(min)} and ${String(max)}.`,\n `Got \"${raw}\".`,\n name\n );\n }\n return n;\n}\n\nfunction parseUrl(raw: string, name: string): string {\n let url: URL;\n try {\n // `new URL()` catches \"no scheme\", \"no host\", \"malformed escape\",\n // etc. — but it's permissive about the scheme. `file:`, `data:`,\n // `javascript:`, `about:` all parse cleanly. For an HTTP API\n // base URL, restricting to http/https is the right invariant\n // (defence-in-depth: even if the SDK forwards the URL to fetch\n // and refuses non-http schemes, we surface the error with a\n // clear field name).\n url = new URL(raw);\n } catch {\n throw new CliValidationError(\n `--${name} must be a valid URL.`,\n `Got \"${raw}\". Include the scheme, e.g. https://api.kash.bot/v1.`,\n name\n );\n }\n if (url.protocol !== 'http:' && url.protocol !== 'https:') {\n throw new CliValidationError(\n `--${name} must use http:// or https:// (got \"${url.protocol}\").`,\n `Schemes like file:, data:, javascript:, and about: are rejected — they would either silently fail in the SDK or open an attack vector.`,\n name\n );\n }\n return raw;\n}\n\n/**\n * Parse a CLI flag value as a strictly positive integer.\n *\n * Throws a structured `CliValidationError` (with a `check_input`\n * action naming the bad field) so an AI agent gets `INVALID_INPUT`\n * with a concrete recovery hint instead of a NaN cascade.\n *\n * Exported because every command that takes a positive-integer flag\n * (`--limit`, `--timeout`, `--poll-interval`, …) routes through it\n * — keeps validation messages and error envelopes uniform.\n */\nexport function parsePositiveInt(raw: string, name: string): number {\n // `Number.parseInt('1.5', 10)` returns 1 and `Number.parseInt('1e3', 10)`\n // returns 1 — both are silent precision losses for what looks like\n // a typo. Reject the raw shape first (bare digits only, optional\n // leading +) so the user sees an explicit error instead of a value\n // they didn't type.\n if (!/^\\+?\\d+$/.test(raw)) {\n throw new CliValidationError(\n `--${name} must be a positive integer.`,\n `Got \"${raw}\". Pass digits only — no decimals, scientific notation, or sign except a leading +.`,\n name\n );\n }\n const n = Number.parseInt(raw, 10);\n if (!Number.isFinite(n) || n <= 0) {\n throw new CliValidationError(\n `--${name} must be a positive integer.`,\n `Got \"${raw}\". Pass an integer > 0.`,\n name\n );\n }\n return n;\n}\n\n// Internal alias kept so the existing call sites in this file don't\n// need to change. New consumers should import `parsePositiveInt`.\nconst parsePositive = parsePositiveInt;\n\n/**\n * Optional variant of {@link parsePositiveInt}. Returns `undefined`\n * when the flag is absent (the common \"default to SDK behaviour\"\n * pattern); otherwise validates and returns the integer.\n *\n * Hoisted from per-command copies so flag wording, bounds, and\n * envelope shape stay uniform across `--wait-timeout-ms`,\n * `--poll-interval-ms`, etc.\n */\nexport function parseOptionalPositiveInt(\n raw: string | undefined,\n name: string\n): number | undefined {\n return raw === undefined ? undefined : parsePositiveInt(raw, name);\n}\n\n/**\n * Positive-finite-float variant of {@link parsePositiveInt}. Used by\n * gas-percentile flags and similar continuous-quantity bounds where\n * an integer-only parser would surprise operators (e.g.\n * `--max-tip-gwei 1.5`).\n */\nexport function parsePositiveFloat(raw: string, name: string): number {\n const n = Number.parseFloat(raw);\n if (!Number.isFinite(n) || n <= 0) {\n throw new CliValidationError(\n `--${name} must be a positive number.`,\n `Got \"${raw}\". Pass a finite number > 0.`,\n name\n );\n }\n return n;\n}\n\n/** Optional variant of {@link parsePositiveFloat}. */\nexport function parseOptionalPositiveFloat(\n raw: string | undefined,\n name: string\n): number | undefined {\n return raw === undefined ? undefined : parsePositiveFloat(raw, name);\n}\n\n/**\n * Recognise truthy env values the way every other tool does: `1`,\n * `true`, `yes`, `on` (case-insensitive). Empty string and `0` are\n * falsy. Anything else is a no-op rather than an error — env\n * pollution is common and shouldn't fail builds.\n */\nfunction isTruthyEnv(value: string | undefined): boolean {\n if (value === undefined) return false;\n const v = value.trim().toLowerCase();\n return v === '1' || v === 'true' || v === 'yes' || v === 'on';\n}\n"],"mappings":"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","names":[]}
@@ -1,17 +1,17 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  readConfig
4
- } from "./chunk-N26VGVGB.js";
4
+ } from "./chunk-ZSMI63N3.js";
5
5
  import {
6
6
  CLI_VERSION
7
- } from "./chunk-KAM6KOFD.js";
7
+ } from "./chunk-6QSTFU4R.js";
8
8
  import {
9
9
  style
10
- } from "./chunk-MQUJG224.js";
10
+ } from "./chunk-2HFKULGG.js";
11
11
  import {
12
12
  CliError,
13
13
  EXIT_CODES
14
- } from "./chunk-X2VM6VKM.js";
14
+ } from "./chunk-WL7XUYPH.js";
15
15
 
16
16
  // src/utils/client.ts
17
17
  import { KashClient } from "@kashdao/sdk";
@@ -34,12 +34,10 @@ async function buildClient(opts = {}) {
34
34
  baseUrl,
35
35
  ...globals?.maxRetries === void 0 ? {} : { maxRetries: globals.maxRetries },
36
36
  ...globals?.timeoutMs === void 0 ? {} : { timeoutMs: globals.timeoutMs },
37
- // Forward the public-API contract pin from `--api-version` (or
38
- // `KASH_API_VERSION` env, if a future iteration plumbs it). The
39
- // SDK validates the date format and sends the value as the
40
- // `X-Kash-Api-Version` request header; the public-api routes the
41
- // request through a version-appropriate code path.
42
- ...globals?.apiVersion === void 0 ? {} : { apiVersion: globals.apiVersion },
37
+ // Public-API contract pin: `--api-version` wins, then the resolved
38
+ // `KASH_API_VERSION` / profile `apiVersion` / default. The SDK
39
+ // validates the date format and sends it as `X-Kash-Api-Version`.
40
+ apiVersion: globals?.apiVersion ?? config.apiVersion,
43
41
  userAgentSuffix: `kash-cli/${CLI_VERSION}`,
44
42
  ...globals?.debug === true ? { hooks: buildDebugHooks(globals.json) } : {}
45
43
  });
@@ -126,4 +124,4 @@ function buildDebugHooks(json) {
126
124
  export {
127
125
  buildClient
128
126
  };
129
- //# sourceMappingURL=chunk-QALDZHTX.js.map
127
+ //# sourceMappingURL=chunk-H2QGFDZP.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/client.ts"],"sourcesContent":["/**\n * Build a `KashClient` from the resolved CLI configuration plus\n * per-invocation global flag overrides.\n *\n * Centralised here so command modules don't each have to know how to\n * read config, surface \"missing API key\" errors, or thread base URLs.\n * Every command that hits `api.kash.bot` must pass `requireAuth: true`\n * so a missing API key fails fast at the call site with a structured\n * `CliError` pointing the user at `kash auth set-key`. Only the offline\n * commands (`kash explain`, `kash --version`, `kash --help`) and the\n * `kash health` probe construct a client without `requireAuth`.\n *\n * Three layers feed the final SDK config:\n *\n * 1. The active profile + env vars (resolved by config-store).\n * 2. Per-invocation `--profile` / `--config` overrides (which select\n * *which* profile and file feed step 1).\n * 3. Per-invocation `--base-url` / `--max-retries` / `--timeout-ms`\n * flags, which override the SDK's runtime config directly.\n *\n * `--debug` wires a stderr-emitting hook into the SDK's lifecycle so\n * a developer or AI agent can see request/response/retry/error\n * traces without instrumenting the SDK.\n */\n\nimport { KashClient, type KashClientHooks } from '@kashdao/sdk';\n\nimport { CliError, EXIT_CODES } from '../errors.js';\nimport { CLI_VERSION } from '../version.js';\n\nimport { readConfig, type ResolvedConfig } from './config-store.js';\nimport { style } from './output.js';\n\nimport type { GlobalOptions } from './global-options.js';\n\nexport type ClientOptions = {\n /** When true, throw `CliError` if no API key is configured. */\n readonly requireAuth?: boolean;\n /**\n * Global flags from the root program. Optional so internal callers\n * (and tests) can build a client without going through Commander.\n */\n readonly globals?: GlobalOptions;\n};\n\nexport type BuiltClient = {\n readonly client: KashClient;\n readonly config: ResolvedConfig;\n};\n\nexport async function buildClient(opts: ClientOptions = {}): Promise<BuiltClient> {\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 if (opts.requireAuth && !config.apiKey) {\n throw new CliError('No API key configured.', {\n code: 'AUTH_REQUIRED',\n exitCode: EXIT_CODES.AUTH,\n suggestion:\n \"First-time setup: run 'kash setup' (interactive wizard). Otherwise: 'kash auth set-key' or set KASH_API_KEY.\",\n });\n }\n\n // Per-invocation overrides win over the resolved profile+env config.\n const baseUrl = globals?.baseUrl ?? config.baseUrl;\n\n const client = new KashClient({\n ...(config.apiKey === undefined ? {} : { apiKey: config.apiKey }),\n baseUrl,\n ...(globals?.maxRetries === undefined ? {} : { maxRetries: globals.maxRetries }),\n ...(globals?.timeoutMs === undefined ? {} : { timeoutMs: globals.timeoutMs }),\n // Public-API contract pin: `--api-version` wins, then the resolved\n // `KASH_API_VERSION` / profile `apiVersion` / default. The SDK\n // validates the date format and sends it as `X-Kash-Api-Version`.\n apiVersion: globals?.apiVersion ?? config.apiVersion,\n userAgentSuffix: `kash-cli/${CLI_VERSION}`,\n ...(globals?.debug === true ? { hooks: buildDebugHooks(globals.json) } : {}),\n });\n\n return { client, config };\n}\n\n/**\n * Build SDK lifecycle hooks that emit traces to stderr.\n *\n * In `--debug --json` mode each event is a one-line JSON record so an\n * AI agent can stream-parse them. In human mode they're a compact\n * prefix plus method/path/status — close to what an HTTP client like\n * `curl -v` would surface, but at the SDK boundary so retries are\n * visible.\n *\n * Quiet mode silences nothing here: `--debug` is opt-in and the user\n * who passed it wants to see traces, full stop.\n */\nfunction buildDebugHooks(json: boolean): KashClientHooks {\n // Use stderr directly rather than the `log` helpers because the\n // hooks fire synchronously inside the SDK and we want zero overhead\n // in the common case (no quiet check, no chalk wrapping).\n const emit = (record: Record<string, unknown>): void => {\n if (json) {\n process.stderr.write(`${JSON.stringify(record)}\\n`);\n return;\n }\n const { event, method, url, status, attempt, durationMs, reason, delayMs, code } = record;\n const prefix = style.dim('[debug]');\n const path = typeof url === 'string' ? url : '';\n const tag = String(event);\n if (event === 'request') {\n process.stderr.write(\n `${prefix} ${tag} ${String(method)} ${path} (attempt ${String(attempt)})\\n`\n );\n } else if (event === 'response') {\n process.stderr.write(\n `${prefix} ${tag} ${String(status)} ${String(method)} ${path} ${String(durationMs)}ms\\n`\n );\n } else if (event === 'retry') {\n process.stderr.write(\n `${prefix} ${tag} ${String(method)} ${path} reason=${String(reason)} delay=${String(delayMs)}ms\\n`\n );\n } else if (event === 'error') {\n process.stderr.write(\n `${prefix} ${tag} ${String(code)} ${String(method)} ${path} ${String(status ?? '-')} ${String(durationMs)}ms\\n`\n );\n }\n };\n\n return {\n onRequest: (event) => {\n emit({\n event: 'request',\n method: event.method,\n url: event.url,\n attempt: event.attempt,\n idempotencyKey: event.idempotencyKey ?? null,\n });\n },\n onResponse: (event) => {\n emit({\n event: 'response',\n method: event.method,\n url: event.url,\n attempt: event.attempt,\n status: event.status,\n durationMs: event.durationMs,\n requestId: event.requestId ?? null,\n });\n },\n onRetry: (event) => {\n emit({\n event: 'retry',\n method: event.method,\n url: event.url,\n attempt: event.attempt,\n reason: event.reason,\n delayMs: event.delayMs,\n });\n },\n onError: (event) => {\n emit({\n event: 'error',\n method: event.method,\n url: event.url,\n attempt: event.attempt,\n status: event.status ?? null,\n code: event.code,\n durationMs: event.durationMs,\n });\n },\n };\n}\n"],"mappings":"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","names":[]}
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  log
4
- } from "./chunk-MQUJG224.js";
4
+ } from "./chunk-2HFKULGG.js";
5
5
  import {
6
6
  CliError,
7
7
  EXIT_CODES
8
- } from "./chunk-X2VM6VKM.js";
8
+ } from "./chunk-WL7XUYPH.js";
9
9
 
10
10
  // src/utils/custom-chain.ts
11
11
  async function resolveCliCustomChain(opts) {
@@ -171,4 +171,4 @@ export {
171
171
  resolveCliCustomChain,
172
172
  loadRawPrivateKey
173
173
  };
174
- //# sourceMappingURL=chunk-L4AFV2HK.js.map
174
+ //# sourceMappingURL=chunk-IOLKGV45.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/custom-chain.ts","../src/utils/signer-key.ts"],"sourcesContent":["/**\n * Translate the CLI's profile-level `customChain` config into the\n * `@kashdao/protocol-sdk` `CustomChain` shape (viem chain + protocol\n * addresses + optional smart-account factory config).\n *\n * The CLI never asks the user to hand-construct a viem Chain object —\n * we synthesise one from the profile's `defaultChain + rpcUrl +\n * customChain.name`, matching what the\n * `packages/protocol-sdk/examples/local-anvil/` quickstarts do inline.\n *\n * This is the only place in the CLI that imports `viem.defineChain`.\n * The dynamic import keeps viem off the cold-start path for non-direct\n * commands (markets list / trade buy / portfolio / health all skip\n * this module).\n *\n * @module utils/custom-chain\n */\n\nimport { CliError, EXIT_CODES } from '../errors.js';\n\nimport type { CliConfig } from './config-store.js';\nimport type { CustomChain } from '@kashdao/protocol-sdk';\n\nexport type ResolveCustomChainOptions = {\n /** The profile's `customChain` block — required, validated by Zod upstream. */\n readonly customChain: NonNullable<CliConfig['customChain']>;\n /**\n * EVM chain id of the profile's `defaultChain`. The caller raises\n * `DIRECT_CONFIG_MISSING` when the profile names a non-EVM chain, so\n * this helper is total.\n */\n readonly chainId: number;\n /**\n * RPC URL used to construct the viem chain's `rpcUrls.default.http`.\n * Same URL the CLI passes as the SDK's `rpc` field — duplicated\n * because the viem chain object carries its own RPC array for any\n * downstream callers that read from `chain.rpcUrls` rather than the\n * `transport`.\n */\n readonly rpc: string;\n};\n\n/**\n * Materialise a CustomChain. Use it like:\n *\n * ```ts\n * const customChain = await resolveCliCustomChain({ customChain, chainId, rpc });\n * createEoaClient({ ..., customChain });\n * ```\n *\n * The viem chain is given `Ether` as the native currency by default —\n * which is correct for every chain the protocol-sdk supports today\n * (Base + Anvil derivatives). If we ever launch on a chain whose\n * native currency isn't ETH-shaped, surface that as a separate\n * `customChain.nativeCurrency` config field; for now the constant\n * keeps the config minimal.\n */\nexport async function resolveCliCustomChain(opts: ResolveCustomChainOptions): Promise<CustomChain> {\n const { customChain, chainId, rpc } = opts;\n\n // Required-at-use validation. The persisted schema marks every field\n // optional so `kash config set customChain.<leaf>` can build the\n // object up one leaf at a time. The SDK's CustomChain shape requires\n // `name + addresses.factory + addresses.usdc`. We surface the\n // missing field here, where the consumer just tried to run an\n // `eoa`/`protocol` command, with the exact `kash config set` line\n // they need to fix it.\n if (customChain.name === undefined) {\n throw missingCustomChainField(\n 'customChain.name',\n '`kash config set customChain.name \"Anvil local\"` (or whatever label you want surfaced on client.addresses.name)'\n );\n }\n if (customChain.factoryAddress === undefined) {\n throw missingCustomChainField(\n 'customChain.factoryAddress',\n '`kash config set customChain.factoryAddress 0x…` (the deployed Kash factory address on this chain)'\n );\n }\n if (customChain.usdcAddress === undefined) {\n throw missingCustomChainField(\n 'customChain.usdcAddress',\n '`kash config set customChain.usdcAddress 0x…` (the deployed USDC token address on this chain)'\n );\n }\n\n // Smart-account triple is all-or-nothing — surfacing each missing\n // leaf separately is more actionable than \"smartAccount is incomplete\".\n let smartAccount: CustomChain['smartAccount'];\n if (customChain.smartAccount !== undefined) {\n const sa = customChain.smartAccount;\n if (\n sa.factoryAddress !== undefined ||\n sa.implementationAddress !== undefined ||\n sa.entryPointAddress !== undefined\n ) {\n if (sa.factoryAddress === undefined) {\n throw missingCustomChainField(\n 'customChain.smartAccount.factoryAddress',\n '`kash config set customChain.smartAccount.factoryAddress 0x…`'\n );\n }\n if (sa.implementationAddress === undefined) {\n throw missingCustomChainField(\n 'customChain.smartAccount.implementationAddress',\n '`kash config set customChain.smartAccount.implementationAddress 0x…`'\n );\n }\n if (sa.entryPointAddress === undefined) {\n throw missingCustomChainField(\n 'customChain.smartAccount.entryPointAddress',\n '`kash config set customChain.smartAccount.entryPointAddress 0x…`'\n );\n }\n smartAccount = {\n factoryAddress: sa.factoryAddress as `0x${string}`,\n implementationAddress: sa.implementationAddress as `0x${string}`,\n entryPointAddress: sa.entryPointAddress as `0x${string}`,\n };\n }\n }\n\n // Lazy-load viem so this module's import doesn't drag viem onto the\n // non-direct command paths. Same firewall pattern as the\n // `eoa-client.ts` / `direct-client.ts` `await import('@kashdao/protocol-sdk')`.\n const { defineChain } = await import('viem');\n\n return {\n name: customChain.name,\n viemChain: defineChain({\n id: chainId,\n name: customChain.name,\n nativeCurrency: { name: 'Ether', symbol: 'ETH', decimals: 18 },\n rpcUrls: { default: { http: [rpc] } },\n }),\n addresses: {\n factory: customChain.factoryAddress as `0x${string}`,\n usdc: customChain.usdcAddress as `0x${string}`,\n ...(customChain.oracleAddress === undefined\n ? {}\n : { oracle: customChain.oracleAddress as `0x${string}` }),\n ...(customChain.vaultAddress === undefined\n ? {}\n : { vault: customChain.vaultAddress as `0x${string}` }),\n ...(customChain.tokens1155Address === undefined\n ? {}\n : { tokens1155: customChain.tokens1155Address as `0x${string}` }),\n ...(customChain.paramRegistryAddress === undefined\n ? {}\n : { paramRegistry: customChain.paramRegistryAddress as `0x${string}` }),\n },\n ...(smartAccount === undefined ? {} : { smartAccount }),\n };\n}\n\nfunction missingCustomChainField(field: string, hint: string): CliError {\n return new CliError(`Custom-chain 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 * Shared `signerKeyRef` resolution for direct-mode + EOA-mode clients.\n *\n * Both modes pull the EOA's private key from the same place:\n *\n * - `file:<absolute-path>` — read a 0x-prefixed hex key from disk.\n * On POSIX, the file mode is checked and\n * a warning is emitted (but the load is\n * not refused) if the file is readable\n * by group or other — the same discipline\n * as ssh / aws-cli warning on\n * `~/.ssh/id_rsa` permissions, but\n * non-fatal because a CI runner may\n * legitimately stage keys with broader\n * modes inside an ephemeral container.\n * - `env:<NAME>` — read a 0x-prefixed hex key from a\n * process env var. (No mode check\n * applies — the OS does not expose\n * env-var ACLs.)\n *\n * The CLI never persists raw keys (the config schema only stores the\n * reference, not the key itself). This helper validates the format\n * and resolves the raw bytes; the caller wraps them in the right\n * adapter for its mode (`viemAccountSigner` for SA UserOps,\n * `viemAccountEoaSigner` for vanilla EIP-1559 txs).\n *\n * Centralised so the SA and EOA paths can never drift on the\n * file/env reading, hex validation, or error wording — drift here is\n * a real-money risk.\n */\n\nimport { readFile, stat } from 'node:fs/promises';\n\nimport { CliError } from '../errors.js';\n\nimport { log } from './output.js';\n\n/** 0x-prefixed 32-byte hex private key. */\nexport type RawPrivateKey = `0x${string}`;\n\n/** Loosely-typed regex for a private key — not a cryptographic check. */\nconst PRIVATE_KEY_REGEX = /^0x[0-9a-fA-F]{64}$/;\n\n/**\n * Resolve a `signerKeyRef` to its raw 0x-prefixed hex private key.\n * Throws `CliError(SIGNER_FAILED)` for every failure mode (missing\n * scheme, missing file/env, malformed key) so callers get a uniform\n * structured envelope.\n */\nexport async function loadRawPrivateKey(ref: string | undefined): Promise<RawPrivateKey> {\n if (!ref) {\n throw new CliError('signerKeyRef is required.', {\n code: 'SIGNER_FAILED',\n suggestion:\n '`kash config set signerKeyRef file:<path>` or `env:<NAME>` (CLI never persists raw keys).',\n });\n }\n\n const [scheme, ...rest] = ref.split(':');\n const target = rest.join(':');\n\n let rawKey: string;\n if (scheme === 'file') {\n if (target === '') {\n throw new CliError('signerKeyRef: file path is empty.', {\n code: 'SIGNER_FAILED',\n suggestion: 'Use `signerKeyRef = file:<absolute-path>` with a path to the private key.',\n });\n }\n try {\n rawKey = (await readFile(target, 'utf8')).trim();\n } catch (cause) {\n throw new CliError(`signerKeyRef: failed to read ${target}.`, {\n code: 'SIGNER_FAILED',\n suggestion: 'Verify the file exists, is readable, and contains a 0x-prefixed hex key.',\n cause,\n });\n }\n await warnIfWorldReadable(target);\n } else if (scheme === 'env') {\n if (target === '') {\n throw new CliError('signerKeyRef: env variable name is empty.', {\n code: 'SIGNER_FAILED',\n suggestion: 'Use `signerKeyRef = env:<NAME>` referencing an environment variable.',\n });\n }\n const fromEnv = process.env[target];\n if (!fromEnv) {\n throw new CliError(`signerKeyRef: environment variable ${target} is not set or empty.`, {\n code: 'SIGNER_FAILED',\n suggestion: `Set ${target} to a 0x-prefixed hex private key, or rotate to a file:<path> reference.`,\n });\n }\n rawKey = fromEnv.trim();\n } else {\n throw new CliError(`signerKeyRef: unknown scheme \"${scheme ?? ''}\".`, {\n code: 'SIGNER_FAILED',\n suggestion: 'Supported schemes: `file:<path>`, `env:<NAME>`.',\n });\n }\n\n if (!PRIVATE_KEY_REGEX.test(rawKey)) {\n throw new CliError('signerKeyRef target is not a 0x-prefixed 32-byte hex private key.', {\n code: 'SIGNER_FAILED',\n suggestion: 'The key must be exactly 0x followed by 64 hex characters (32 bytes).',\n });\n }\n\n return rawKey as RawPrivateKey;\n}\n\n/**\n * POSIX-only: warn (don't refuse) if the key file is readable by\n * group or other. Mirrors ssh / aws-cli's \"you should `chmod 600`\"\n * banner on `~/.ssh/id_rsa`. Skipped on Windows (no-op) because\n * Windows uses ACLs rather than POSIX modes — `mode & 0o077` is\n * meaningless. Skipped on stat failure because we just successfully\n * read the file; the stat is purely advisory.\n */\nasync function warnIfWorldReadable(path: string): Promise<void> {\n if (process.platform === 'win32') return;\n let mode: number;\n try {\n const info = await stat(path);\n mode = info.mode;\n } catch {\n return; // advisory only — we already loaded the key successfully\n }\n // Lower 9 bits are rwxrwxrwx. Group + other read bits are 0o044.\n // Lower 6 bits (group + other rwx) are 0o077 — anything set in\n // those positions means somebody other than the owner can touch\n // the key.\n if ((mode & 0o077) !== 0) {\n log.warn(\n `signerKeyRef file mode is 0${(mode & 0o777).toString(8)} (group/other readable). ` +\n `Run \\`chmod 600 ${path}\\` to restrict access. (warning only — load succeeded.)`\n );\n }\n}\n"],"mappings":";;;;;;;;;;AAyDA,eAAsB,sBAAsB,MAAuD;AACjG,QAAM,EAAE,aAAa,SAAS,IAAI,IAAI;AAStC,MAAI,YAAY,SAAS,QAAW;AAClC,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,MAAI,YAAY,mBAAmB,QAAW;AAC5C,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,MAAI,YAAY,gBAAgB,QAAW;AACzC,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAIA,MAAI;AACJ,MAAI,YAAY,iBAAiB,QAAW;AAC1C,UAAM,KAAK,YAAY;AACvB,QACE,GAAG,mBAAmB,UACtB,GAAG,0BAA0B,UAC7B,GAAG,sBAAsB,QACzB;AACA,UAAI,GAAG,mBAAmB,QAAW;AACnC,cAAM;AAAA,UACJ;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA,UAAI,GAAG,0BAA0B,QAAW;AAC1C,cAAM;AAAA,UACJ;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA,UAAI,GAAG,sBAAsB,QAAW;AACtC,cAAM;AAAA,UACJ;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA,qBAAe;AAAA,QACb,gBAAgB,GAAG;AAAA,QACnB,uBAAuB,GAAG;AAAA,QAC1B,mBAAmB,GAAG;AAAA,MACxB;AAAA,IACF;AAAA,EACF;AAKA,QAAM,EAAE,YAAY,IAAI,MAAM,OAAO,MAAM;AAE3C,SAAO;AAAA,IACL,MAAM,YAAY;AAAA,IAClB,WAAW,YAAY;AAAA,MACrB,IAAI;AAAA,MACJ,MAAM,YAAY;AAAA,MAClB,gBAAgB,EAAE,MAAM,SAAS,QAAQ,OAAO,UAAU,GAAG;AAAA,MAC7D,SAAS,EAAE,SAAS,EAAE,MAAM,CAAC,GAAG,EAAE,EAAE;AAAA,IACtC,CAAC;AAAA,IACD,WAAW;AAAA,MACT,SAAS,YAAY;AAAA,MACrB,MAAM,YAAY;AAAA,MAClB,GAAI,YAAY,kBAAkB,SAC9B,CAAC,IACD,EAAE,QAAQ,YAAY,cAA+B;AAAA,MACzD,GAAI,YAAY,iBAAiB,SAC7B,CAAC,IACD,EAAE,OAAO,YAAY,aAA8B;AAAA,MACvD,GAAI,YAAY,sBAAsB,SAClC,CAAC,IACD,EAAE,YAAY,YAAY,kBAAmC;AAAA,MACjE,GAAI,YAAY,yBAAyB,SACrC,CAAC,IACD,EAAE,eAAe,YAAY,qBAAsC;AAAA,IACzE;AAAA,IACA,GAAI,iBAAiB,SAAY,CAAC,IAAI,EAAE,aAAa;AAAA,EACvD;AACF;AAEA,SAAS,wBAAwB,OAAe,MAAwB;AACtE,SAAO,IAAI,SAAS,gCAAgC,KAAK,KAAK;AAAA,IAC5D,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;;;ACzIA,SAAS,UAAU,YAAY;AAU/B,IAAM,oBAAoB;AAQ1B,eAAsB,kBAAkB,KAAiD;AACvF,MAAI,CAAC,KAAK;AACR,UAAM,IAAI,SAAS,6BAA6B;AAAA,MAC9C,MAAM;AAAA,MACN,YACE;AAAA,IACJ,CAAC;AAAA,EACH;AAEA,QAAM,CAAC,QAAQ,GAAG,IAAI,IAAI,IAAI,MAAM,GAAG;AACvC,QAAM,SAAS,KAAK,KAAK,GAAG;AAE5B,MAAI;AACJ,MAAI,WAAW,QAAQ;AACrB,QAAI,WAAW,IAAI;AACjB,YAAM,IAAI,SAAS,qCAAqC;AAAA,QACtD,MAAM;AAAA,QACN,YAAY;AAAA,MACd,CAAC;AAAA,IACH;AACA,QAAI;AACF,gBAAU,MAAM,SAAS,QAAQ,MAAM,GAAG,KAAK;AAAA,IACjD,SAAS,OAAO;AACd,YAAM,IAAI,SAAS,gCAAgC,MAAM,KAAK;AAAA,QAC5D,MAAM;AAAA,QACN,YAAY;AAAA,QACZ;AAAA,MACF,CAAC;AAAA,IACH;AACA,UAAM,oBAAoB,MAAM;AAAA,EAClC,WAAW,WAAW,OAAO;AAC3B,QAAI,WAAW,IAAI;AACjB,YAAM,IAAI,SAAS,6CAA6C;AAAA,QAC9D,MAAM;AAAA,QACN,YAAY;AAAA,MACd,CAAC;AAAA,IACH;AACA,UAAM,UAAU,QAAQ,IAAI,MAAM;AAClC,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,SAAS,sCAAsC,MAAM,yBAAyB;AAAA,QACtF,MAAM;AAAA,QACN,YAAY,OAAO,MAAM;AAAA,MAC3B,CAAC;AAAA,IACH;AACA,aAAS,QAAQ,KAAK;AAAA,EACxB,OAAO;AACL,UAAM,IAAI,SAAS,iCAAiC,UAAU,EAAE,MAAM;AAAA,MACpE,MAAM;AAAA,MACN,YAAY;AAAA,IACd,CAAC;AAAA,EACH;AAEA,MAAI,CAAC,kBAAkB,KAAK,MAAM,GAAG;AACnC,UAAM,IAAI,SAAS,qEAAqE;AAAA,MACtF,MAAM;AAAA,MACN,YAAY;AAAA,IACd,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAUA,eAAe,oBAAoB,MAA6B;AAC9D,MAAI,QAAQ,aAAa,QAAS;AAClC,MAAI;AACJ,MAAI;AACF,UAAM,OAAO,MAAM,KAAK,IAAI;AAC5B,WAAO,KAAK;AAAA,EACd,QAAQ;AACN;AAAA,EACF;AAKA,OAAK,OAAO,QAAW,GAAG;AACxB,QAAI;AAAA,MACF,+BAA+B,OAAO,KAAO,SAAS,CAAC,CAAC,4CACnC,IAAI;AAAA,IAC3B;AAAA,EACF;AACF;","names":[]}
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  CliValidationError
4
- } from "./chunk-X2VM6VKM.js";
4
+ } from "./chunk-WL7XUYPH.js";
5
5
 
6
6
  // src/utils/fields.ts
7
7
  var SEGMENT_REGEX = /^[A-Za-z_][A-Za-z0-9_]*$/;
@@ -363,4 +363,4 @@ export {
363
363
  parseFilter,
364
364
  applyFilter
365
365
  };
366
- //# sourceMappingURL=chunk-KADB3OKE.js.map
366
+ //# sourceMappingURL=chunk-VFBQVUL4.js.map
@@ -18,6 +18,20 @@ import {
18
18
  } from "@kashdao/sdk";
19
19
 
20
20
  // src/error-catalog.ts
21
+ var UNEXPECTED_ENTRY = {
22
+ code: "UNEXPECTED",
23
+ summary: "An unrecognised error escaped the SDK or the CLI.",
24
+ description: "This means the CLI's error mapper didn't recognise the underlying failure \u2014 the most likely cause is an SDK or runtime issue. File an issue with the message, the command, and the runtime info from `kash version --json`.",
25
+ recoverable: false,
26
+ docsUrl: "https://github.com/KashDAO/cli/issues",
27
+ actions: [
28
+ {
29
+ type: "run_command",
30
+ command: "kash version --json",
31
+ description: "Capture runtime info to attach to the bug report."
32
+ }
33
+ ]
34
+ };
21
35
  var ERROR_CATALOG = [
22
36
  {
23
37
  code: "AUTH_REQUIRED",
@@ -182,7 +196,7 @@ var ERROR_CATALOG = [
182
196
  {
183
197
  code: "CONFIGURATION",
184
198
  summary: "The CLI configuration file or environment is invalid.",
185
- description: "The on-disk ~/.kash/config.json failed to parse, an env var (KASH_CHAIN_ID) doesn't match its expected shape, or a per-invocation flag (--max-retries, --timeout-ms, --base-url) was rejected by the SDK. Run `kash config show` to inspect what loaded.",
199
+ description: "The on-disk ~/.kash/config.json failed to parse, an env var (KASH_CHAIN, KASH_API_VERSION) doesn't match its expected shape, or a per-invocation flag (--max-retries, --timeout-ms, --base-url) was rejected by the SDK. Run `kash config show` to inspect what loaded.",
186
200
  recoverable: true,
187
201
  docsUrl: "https://kash.bot/docs/cli/configuration",
188
202
  actions: [
@@ -278,20 +292,7 @@ var ERROR_CATALOG = [
278
292
  }
279
293
  ]
280
294
  },
281
- {
282
- code: "UNEXPECTED",
283
- summary: "An unrecognised error escaped the SDK or the CLI.",
284
- description: "This means the CLI's error mapper didn't recognise the underlying failure \u2014 the most likely cause is an SDK or runtime issue. File an issue with the message, the command, and the runtime info from `kash version --json`.",
285
- recoverable: false,
286
- docsUrl: "https://github.com/KashDAO/cli/issues",
287
- actions: [
288
- {
289
- type: "run_command",
290
- command: "kash version --json",
291
- description: "Capture runtime info to attach to the bug report."
292
- }
293
- ]
294
- },
295
+ UNEXPECTED_ENTRY,
295
296
  {
296
297
  code: "NOOP",
297
298
  summary: "No-op exit (Commander emitted output and asked us to stop).",
@@ -308,9 +309,7 @@ function lookupErrorCode(code) {
308
309
  return CATALOG_BY_CODE.get(code);
309
310
  }
310
311
  function lookupErrorCodeWithFallback(code) {
311
- const entry = CATALOG_BY_CODE.get(code);
312
- if (entry) return entry;
313
- return CATALOG_BY_CODE.get("UNEXPECTED");
312
+ return CATALOG_BY_CODE.get(code) ?? UNEXPECTED_ENTRY;
314
313
  }
315
314
  var ERROR_CODES = new Set(ERROR_CATALOG.map((e) => e.code));
316
315
 
@@ -627,7 +626,7 @@ function mapProtocolError(err) {
627
626
  case "KashConfigError": {
628
627
  const cliErr = new CliError(err.message, {
629
628
  code: "DIRECT_CONFIG_MISSING",
630
- suggestion: "Set the missing field via `kash config set <field> <value>` (rpcUrl, smartAccount, signerKeyRef, defaultChainId).",
629
+ suggestion: "Set the missing field via `kash config set <field> <value>` (rpcUrl, smartAccount, signerKeyRef, defaultChain).",
631
630
  cause: err
632
631
  });
633
632
  return cliErr;
@@ -677,4 +676,4 @@ export {
677
676
  toCliError,
678
677
  isCommanderError
679
678
  };
680
- //# sourceMappingURL=chunk-X2VM6VKM.js.map
679
+ //# sourceMappingURL=chunk-WL7XUYPH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors.ts","../src/error-catalog.ts"],"sourcesContent":["/**\n * CLI error hierarchy + SDK-error mapper.\n *\n * The CliError shape is **the contract** between this CLI and any\n * agent or script that consumes it. The fields below are SemVer-stable\n * — additions are minor bumps, removals/renames are major bumps.\n *\n * Exit code convention:\n * 0 — success\n * 1 — generic error (validation, server, network, etc.)\n * 2 — auth failure (missing/invalid API key, missing scope)\n *\n * Mapping a `KashRateLimitError` to exit 1 is deliberate: a rate-limit\n * is recoverable, but the CLI should still fail loudly so scripts\n * don't silently move on. The `recoverable` boolean and `retryAfterMs`\n * field tell agents how to handle it.\n *\n * The `actions` array is the agent-friendly recovery path. Each entry\n * is one of a small, well-defined set of variants — agents can branch\n * on `actions[0].type` without parsing prose.\n *\n * **Catalog as source of truth.** Static fields (`recoverable`,\n * `docsUrl`, base `actions`) are read from\n * `error-catalog.ts#ERROR_CATALOG` based on the error's `code`, so\n * `kash explain RATE_LIMITED` always shows the same metadata as the\n * envelope on a real `RATE_LIMITED` failure. The `toCliError` mapper\n * adds runtime-only data (`retryAfterMs` from the server's\n * `Retry-After`, an extra `wait_and_retry` action derived from it).\n * Callers can override any field explicitly, but the default path\n * pulls from the catalog so drift is structurally impossible.\n */\n\nimport {\n KashAbortedError,\n KashAuthenticationError,\n KashAuthorizationError,\n KashConfigurationError as SdkKashConfigurationError,\n KashConflictError,\n KashError,\n KashMaintenanceError,\n KashNetworkError,\n KashNotFoundError,\n KashRateLimitError,\n KashServerError,\n KashTimeoutError,\n KashValidationError,\n} from '@kashdao/sdk';\n\nimport { lookupErrorCodeWithFallback } from './error-catalog.js';\n\n/** Exit codes used by the CLI. */\nexport const EXIT_CODES = {\n OK: 0,\n GENERIC: 1,\n AUTH: 2,\n} as const;\n\nexport type ExitCode = (typeof EXIT_CODES)[keyof typeof EXIT_CODES];\n\n/**\n * Machine-readable next-step hint. Agents inspect `type` and act\n * without parsing the human-prose `suggestion`. Adding new variants\n * is a minor bump (agents that don't recognise them ignore them);\n * removing or renaming is a major bump.\n *\n * **Templates.** A `run_command` action MAY carry `template: true` to\n * signal that `command` contains `<placeholder>` substrings that the\n * agent must substitute (or skip) before executing. Templates exist\n * because the static error catalog can't always know the concrete\n * command id / trade id / market id at the point the catalog is\n * authored — they're carved at runtime when the SDK error is mapped.\n * Agents that auto-execute `run_command` actions MUST honour the\n * `template` flag: substitute, prompt, or skip. Treating templated\n * commands as concrete will literally shell `kash trade status <id>`\n * (with the angle brackets) and fail.\n */\nexport type CliErrorAction =\n | {\n readonly type: 'run_command';\n readonly command: string;\n readonly description: string;\n /**\n * `true` when `command` contains `<placeholder>` tokens the\n * caller must substitute. Absent or `false` means the command\n * is concrete and safe to auto-execute. Agents that lack\n * substitution support should skip templated commands and fall\n * back to the catalog's `description` / `suggestion`.\n */\n readonly template?: boolean;\n }\n | { readonly type: 'set_env'; readonly variable: string; readonly description: string }\n | { readonly type: 'wait_and_retry'; readonly delayMs: number; readonly description: string }\n | { readonly type: 'open_url'; readonly url: string; readonly description: string }\n | { readonly type: 'check_input'; readonly field: string; readonly description: string };\n\nexport type CliErrorOptions = {\n readonly code: string;\n readonly suggestion?: string | undefined;\n readonly exitCode?: ExitCode;\n readonly requestId?: string | undefined;\n /**\n * Override the catalog's `recoverable`. If omitted the catalog's\n * value is used; if the code isn't in the catalog, defaults to\n * `false` via the UNEXPECTED fallback.\n */\n readonly recoverable?: boolean;\n /** Suggested delay before retrying. No catalog default. */\n readonly retryAfterMs?: number | undefined;\n /** Override the catalog's `docsUrl`. */\n readonly docsUrl?: string | undefined;\n /**\n * Additional `actions` to append to the catalog's static set. Use\n * this for runtime-derived hints (e.g. a `wait_and_retry` with the\n * server's exact Retry-After). Pass `actionsOverride` to replace\n * the catalog set entirely.\n */\n readonly actions?: readonly CliErrorAction[];\n /**\n * Replace the catalog's `actions` entirely (instead of appending\n * via `actions`). Use sparingly — the catalog is the source of\n * truth for static actions.\n */\n readonly actionsOverride?: readonly CliErrorAction[];\n readonly cause?: unknown;\n};\n\nexport class CliError extends Error {\n readonly code: string;\n readonly suggestion: string | undefined;\n readonly exitCode: ExitCode;\n readonly requestId: string | undefined;\n /** True iff a sensible retry/recovery path exists. */\n readonly recoverable: boolean;\n /** Suggested delay before retrying (rate limit, server error). */\n readonly retryAfterMs: number | undefined;\n /** Stable docs URL agents can fetch for richer context. */\n readonly docsUrl: string | undefined;\n /** Machine-readable next-step hints. Empty array if none. */\n readonly actions: readonly CliErrorAction[];\n override readonly cause: unknown;\n\n constructor(message: string, options: CliErrorOptions) {\n super(message);\n this.name = 'CliError';\n const catalogEntry = lookupErrorCodeWithFallback(options.code);\n this.code = options.code;\n this.suggestion = options.suggestion;\n this.exitCode = options.exitCode ?? EXIT_CODES.GENERIC;\n this.requestId = options.requestId;\n this.recoverable = options.recoverable ?? catalogEntry.recoverable;\n this.retryAfterMs = options.retryAfterMs;\n this.docsUrl = options.docsUrl ?? catalogEntry.docsUrl;\n if (options.actionsOverride !== undefined) {\n this.actions = options.actionsOverride;\n } else {\n // Caller-provided actions first (they're contextually specific:\n // a `wait_and_retry` derived from the server's actual\n // Retry-After, or a `check_input` naming a concrete bad field),\n // catalog actions second (generic fallbacks). Agents act on the\n // first applicable hint, so the more specific one needs to win.\n this.actions = [...(options.actions ?? []), ...catalogEntry.actions];\n }\n this.cause = options.cause;\n Error.captureStackTrace?.(this, this.constructor);\n }\n\n /**\n * Render the error as the stable JSON envelope agents pin to. Kept\n * as a method so the index.ts emitError can serialise consistently\n * regardless of caller.\n */\n toEnvelope(): Record<string, unknown> {\n return {\n ok: false,\n error: {\n code: this.code,\n message: this.message,\n recoverable: this.recoverable,\n ...(this.suggestion === undefined ? {} : { suggestion: this.suggestion }),\n ...(this.retryAfterMs === undefined ? {} : { retryAfterMs: this.retryAfterMs }),\n ...(this.docsUrl === undefined ? {} : { docsUrl: this.docsUrl }),\n ...(this.requestId === undefined ? {} : { requestId: this.requestId }),\n actions: this.actions,\n },\n };\n }\n}\n\nexport class CliValidationError extends CliError {\n constructor(message: string, suggestion?: string, field?: string) {\n super(message, {\n code: 'INVALID_INPUT',\n ...(suggestion === undefined ? {} : { suggestion }),\n ...(field === undefined\n ? {}\n : {\n actions: [\n {\n type: 'check_input' as const,\n field,\n description: `Verify the value of \"${field}\".`,\n },\n ],\n }),\n });\n this.name = 'CliValidationError';\n }\n}\n\nexport class CliConfigurationError extends CliError {\n constructor(message: string, suggestion?: string) {\n super(message, {\n code: 'CONFIGURATION',\n ...(suggestion === undefined ? {} : { suggestion }),\n });\n this.name = 'CliConfigurationError';\n }\n}\n\n/**\n * Translate any `unknown` error coming out of the SDK or the CLI\n * itself into a `CliError`. Pass-through for existing `CliError`\n * instances so callers can re-throw without re-wrapping.\n *\n * Each branch only sets runtime fields (suggestion, requestId,\n * retryAfterMs, runtime-derived actions). Static fields like\n * `recoverable`, `docsUrl`, and base `actions` come from the catalog\n * via the CliError constructor.\n */\nexport function toCliError(err: unknown): CliError {\n if (err instanceof CliError) {\n return err;\n }\n // Commander-thrown errors (we call `program.exitOverride()` so\n // unknown commands / unknown options surface here instead of\n // exiting via process.exit). Help and version short-circuits also\n // come through — they're not errors and exit cleanly.\n const commander = mapCommanderError(err);\n if (commander) return commander;\n if (err instanceof KashAuthenticationError) {\n return new CliError(err.message, {\n code: 'AUTH_REQUIRED',\n exitCode: EXIT_CODES.AUTH,\n suggestion:\n \"First-time setup: run 'kash setup' (interactive wizard). Otherwise: 'kash auth set-key' or set KASH_API_KEY.\",\n ...(err.requestId === undefined ? {} : { requestId: err.requestId }),\n cause: err,\n });\n }\n if (err instanceof KashAuthorizationError) {\n return new CliError(err.message, {\n code: 'INSUFFICIENT_SCOPE',\n exitCode: EXIT_CODES.AUTH,\n suggestion:\n 'The API key is valid but is missing the scope this command needs. Issue a key with broader scope under Settings → API Keys at https://app.kash.bot.',\n ...(err.requestId === undefined ? {} : { requestId: err.requestId }),\n cause: err,\n });\n }\n if (err instanceof KashRateLimitError) {\n const retrySec = err.retryAfterSeconds;\n const retryAfterMs = retrySec === undefined ? undefined : retrySec * 1000;\n const suggestion =\n retrySec !== undefined\n ? `Retry in ${String(retrySec)}s. Upgrade for higher limits: https://kash.bot/pricing`\n : 'Slow down request rate. Upgrade for higher limits: https://kash.bot/pricing';\n return new CliError(err.message, {\n code: 'RATE_LIMITED',\n suggestion,\n ...(retryAfterMs === undefined ? {} : { retryAfterMs }),\n ...(retryAfterMs === undefined\n ? {}\n : {\n actions: [\n {\n type: 'wait_and_retry' as const,\n delayMs: retryAfterMs,\n description: `Wait ${String(retrySec)}s then re-run the same command.`,\n },\n ],\n }),\n ...(err.requestId === undefined ? {} : { requestId: err.requestId }),\n cause: err,\n });\n }\n if (err instanceof KashNotFoundError) {\n return new CliError(err.message, {\n code: 'NOT_FOUND',\n suggestion: 'Double-check the resource id (markets and trades use UUIDs).',\n ...(err.requestId === undefined ? {} : { requestId: err.requestId }),\n cause: err,\n });\n }\n if (err instanceof KashConflictError) {\n return new CliError(err.message, {\n code: 'CONFLICT',\n suggestion:\n 'A conflicting request is already in flight or the resource state changed underneath you. Inspect the trade with `kash trade status <id>` before retrying.',\n ...(err.requestId === undefined ? {} : { requestId: err.requestId }),\n cause: err,\n });\n }\n if (err instanceof KashValidationError) {\n return new CliError(err.message, {\n code: 'INVALID_INPUT',\n suggestion: 'Verify the request shape matches `kash <command> --help`.',\n ...(err.requestId === undefined ? {} : { requestId: err.requestId }),\n cause: err,\n });\n }\n if (err instanceof KashMaintenanceError) {\n const retrySec = err.retryAfterSeconds;\n const retryAfterMs = retrySec === undefined ? undefined : retrySec * 1000;\n return new CliError(err.message, {\n code: 'MAINTENANCE',\n suggestion:\n 'The Kash trade pipeline is temporarily disabled (incident response or planned maintenance). Honor `retryAfterMs` and retry once the window closes.',\n ...(retryAfterMs === undefined ? {} : { retryAfterMs }),\n ...(retryAfterMs === undefined\n ? {}\n : {\n actions: [\n {\n type: 'wait_and_retry' as const,\n delayMs: retryAfterMs,\n description: `Wait ${String(retrySec)}s before retrying.`,\n },\n ],\n }),\n ...(err.requestId === undefined ? {} : { requestId: err.requestId }),\n cause: err,\n });\n }\n if (err instanceof KashTimeoutError) {\n return new CliError(err.message, {\n code: 'TIMEOUT',\n suggestion:\n 'The request exceeded the configured timeout. Retry, or pass --timeout-ms to raise the cap.',\n ...(err.requestId === undefined ? {} : { requestId: err.requestId }),\n cause: err,\n });\n }\n if (err instanceof KashNetworkError) {\n // Inspect the underlying cause for DNS-resolution failures so we\n // can route the user to the right recovery action — remind them that\n // the key prefix picks the host (live → production, test → staging)\n // rather than emitting a generic \"check connectivity\" line.\n const causeStr = `${String(err.message ?? '')} ${String((err.cause as Error)?.message ?? '')}`;\n const isDnsError =\n causeStr.includes('ENOTFOUND') ||\n causeStr.includes('getaddrinfo') ||\n causeStr.includes('EAI_AGAIN') ||\n causeStr.includes('Could not resolve');\n const suggestion = isDnsError\n ? 'The configured API host did not resolve in DNS. ' +\n 'A `kash_live_*` key auto-routes to production ' +\n '(`https://api.kash.bot/v1`); a `kash_test_*` key auto-routes to ' +\n 'staging (`https://api-staging.kash.bot/v1`). ' +\n 'For a custom host, pass `--base-url <url>` or set `KASH_BASE_URL`. ' +\n 'Check your network/DNS and retry.'\n : 'The request did not reach the API. Check network connectivity and retry.';\n return new CliError(err.message, {\n code: 'NETWORK',\n suggestion,\n ...(err.requestId === undefined ? {} : { requestId: err.requestId }),\n cause: err,\n });\n }\n if (err instanceof KashAbortedError) {\n return new CliError(err.message, {\n code: 'ABORTED',\n suggestion:\n 'The request was cancelled before it completed. If the command is idempotent, you can safely retry with the same Idempotency-Key.',\n ...(err.requestId === undefined ? {} : { requestId: err.requestId }),\n cause: err,\n });\n }\n if (err instanceof KashServerError) {\n return new CliError(err.message, {\n code: 'SERVER_ERROR',\n suggestion:\n 'The API returned a 5xx after retries. The request is safe to retry; if the failure persists, file a bug at https://github.com/KashDAO/cli/issues with the requestId.',\n ...(err.requestId === undefined ? {} : { requestId: err.requestId }),\n cause: err,\n });\n }\n if (err instanceof SdkKashConfigurationError) {\n // Surface the first Zod issue's path as a check_input action so\n // an agent can localise the broken field without parsing prose.\n const firstIssue = err.issues[0];\n const fieldPath = firstIssue?.path.join('.') ?? '';\n return new CliError(err.message, {\n code: 'CONFIGURATION',\n suggestion:\n firstIssue !== undefined\n ? `SDK rejected ${fieldPath || '(root)'}: ${firstIssue.message}`\n : 'The SDK rejected the configuration provided to the client.',\n ...(fieldPath\n ? {\n actions: [\n {\n type: 'check_input' as const,\n field: fieldPath,\n description: `Fix the value of \"${fieldPath}\" and re-run.`,\n },\n ],\n }\n : {}),\n cause: err,\n });\n }\n // ── Protocol-SDK (`@kashdao/protocol-sdk`) errors ───────────────\n // We don't eager-import the protocol-sdk just to use `instanceof`\n // checks (it pulls in viem). Duck-type on `err.name` instead — the\n // protocol-sdk's error classes set their `name` field deterministically\n // in the base constructor.\n const protocolErrorMapping = mapProtocolError(err);\n if (protocolErrorMapping !== undefined) {\n return protocolErrorMapping;\n }\n if (err instanceof KashError) {\n // Any KashError subclass we haven't enumerated above. Falls back\n // to the catalog's UNEXPECTED entry for `recoverable`/`docsUrl`\n // (so `kash explain` always returns *something*) but preserves\n // the SDK's `isRetryable` value.\n return new CliError(err.message, {\n code: 'UNEXPECTED',\n recoverable: err.isRetryable,\n ...(err.requestId === undefined ? {} : { requestId: err.requestId }),\n cause: err,\n });\n }\n if (err instanceof Error) {\n return new CliError(err.message, { code: 'UNEXPECTED', cause: err });\n }\n return new CliError(String(err), { code: 'UNEXPECTED', cause: err });\n}\n\n/**\n * Structural shape of Commander's `CommanderError`. Commander documents\n * `code` and `message` as stable public API and namespaces every code\n * with the `commander.` prefix (`commander.unknownCommand`,\n * `commander.help`, etc.).\n *\n * We type-guard against this shape rather than `instanceof CommanderError`\n * because importing the constructor here would force the Commander\n * module to load on the cold path even for invocations that never\n * touch it. Going through a structural check keeps the import lazy\n * AND keeps TypeScript safety at every use site.\n */\nexport type CommanderErrorLike = {\n readonly code: string;\n readonly message: string;\n};\n\n/**\n * Type guard — true iff `err` looks like a Commander-thrown error.\n * Commander always sets `code` to a string starting with `commander.`,\n * so the prefix check is the load-bearing test (filters out other\n * errors that happen to have a `code` field, e.g. `EACCES`).\n */\nexport function isCommanderError(err: unknown): err is CommanderErrorLike {\n if (!(err instanceof Error)) return false;\n const candidate = err as { code?: unknown; message?: unknown };\n return (\n typeof candidate.code === 'string' &&\n candidate.code.startsWith('commander.') &&\n typeof candidate.message === 'string'\n );\n}\n\n/**\n * Map a Commander-thrown error to either a clean exit (help/version)\n * or a structured `CliError` (unknown command, unknown option, missing\n * argument, etc.). Returns undefined for non-Commander errors so the\n * outer mapper can keep walking its switch.\n */\nfunction mapCommanderError(err: unknown): CliError | undefined {\n if (!isCommanderError(err)) return undefined;\n const { code, message } = err;\n\n // `commander.help`, `commander.helpDisplayed`, `commander.version` —\n // user asked for `--help` or `--version`. Commander already wrote\n // the output; surfacing this as a real error would be wrong. Use\n // `EXIT_CODES.OK` and code `'NOOP'` so the top-level boundary in\n // `index.ts` exits cleanly and prints nothing extra.\n if (\n code === 'commander.help' ||\n code === 'commander.helpDisplayed' ||\n code === 'commander.version'\n ) {\n return new CliError('', {\n code: 'NOOP',\n exitCode: EXIT_CODES.OK,\n recoverable: false,\n cause: err,\n });\n }\n\n // Unknown command — the most common typo case. Commander appends\n // a \"Did you mean X?\" suggestion to the message; we extract it so\n // the structured envelope carries a `run_command` recovery action\n // an agent can execute directly.\n if (code === 'commander.unknownCommand') {\n const match = /Did you mean (\\S+?)\\??\\)?$/m.exec(message);\n const suggested = match?.[1];\n const suggestion = suggested\n ? `Did you mean \\`kash ${suggested}\\`? Run \\`kash --help\\` for the full command tree.`\n : 'Run `kash --help` for the full command tree.';\n return new CliError(stripTrailingNewlines(message), {\n code: 'INVALID_INPUT',\n recoverable: true,\n suggestion,\n ...(suggested === undefined\n ? {}\n : {\n actions: [\n {\n type: 'run_command' as const,\n command: `kash ${suggested}`,\n description: 'Run the suggested command instead.',\n },\n ],\n }),\n cause: err,\n });\n }\n\n // Unknown option — adjacent typo case. Commander doesn't always\n // include a suggestion for options; fall back to a generic check.\n if (code === 'commander.unknownOption') {\n return new CliError(stripTrailingNewlines(message), {\n code: 'INVALID_INPUT',\n recoverable: true,\n suggestion:\n 'Run `kash <command> --help` for the supported flags, or `kash docs --json` for the full surface.',\n cause: err,\n });\n }\n\n // Missing required argument / option — Commander surfaces these\n // before the action runs. Keep the original message (it names the\n // flag) and add a generic check_input action.\n if (\n code === 'commander.missingArgument' ||\n code === 'commander.missingMandatoryOptionValue' ||\n code === 'commander.optionMissingArgument'\n ) {\n return new CliError(stripTrailingNewlines(message), {\n code: 'INVALID_INPUT',\n recoverable: true,\n suggestion: 'Run the command with `--help` to see required arguments.',\n cause: err,\n });\n }\n\n // Anything else from Commander (excess arguments, invalid choice,\n // etc.) — generic mapping with the original message preserved.\n return new CliError(stripTrailingNewlines(message), {\n code: 'INVALID_INPUT',\n recoverable: true,\n cause: err,\n });\n}\n\n/** Trim trailing newlines so error messages don't render double-spaced. */\nfunction stripTrailingNewlines(s: string): string {\n return s.replace(/\\n+$/, '');\n}\n\n/**\n * Map an `@kashdao/protocol-sdk` error to the corresponding CLI code,\n * by class name. Returns `undefined` if the error is not a recognised\n * protocol-sdk error.\n *\n * **Why duck-typing instead of `instanceof`?** Importing the\n * protocol-sdk eagerly here would defeat the cold-start optimisation\n * that lazy-loads `@kashdao/protocol-sdk` only when `kash protocol …`\n * commands run. Kash-orchestrated-only invocations (markets/trade/portfolio)\n * keep their fast path. The protocol-sdk's error base class sets\n * `name` to the constructor name in its constructor, so a name check\n * is reliable across module-instance boundaries.\n */\nfunction mapProtocolError(err: unknown): CliError | undefined {\n if (!(err instanceof Error)) return undefined;\n switch (err.name) {\n case 'KashConfigError': {\n const cliErr = new CliError(err.message, {\n code: 'DIRECT_CONFIG_MISSING',\n suggestion:\n 'Set the missing field via `kash config set <field> <value>` (rpcUrl, smartAccount, signerKeyRef, defaultChain).',\n cause: err,\n });\n return cliErr;\n }\n case 'KashSignerError':\n return new CliError(err.message, {\n code: 'SIGNER_FAILED',\n suggestion: 'Verify the signerKeyRef target is readable (file:<path>) or set (env:<NAME>).',\n cause: err,\n });\n case 'KashChainError':\n return new CliError(err.message, {\n code: 'CHAIN_ERROR',\n suggestion: 'On-chain read or contract interaction failed unexpectedly.',\n cause: err,\n });\n case 'KashBundlerError':\n return new CliError(err.message, {\n code: 'BUNDLER_REJECTED',\n suggestion: 'Inspect the bundler-specific reason in the message and adjust.',\n cause: err,\n });\n case 'KashSimulationRevertedError':\n return new CliError(err.message, {\n code: 'TRANSACTION_REVERTED',\n suggestion: 'Re-run with `kash protocol simulate` to see the decoded revert reason.',\n cause: err,\n });\n case 'KashProtocolError':\n // Base class — ChainError is the closest fallback for any\n // protocol-sdk error not covered above.\n return new CliError(err.message, {\n code: 'CHAIN_ERROR',\n suggestion: 'Unrecognised protocol-sdk error. File an issue with `kash version --json`.',\n cause: err,\n });\n default:\n return undefined;\n }\n}\n","/**\n * Single source of truth for every error `code` the CLI emits.\n *\n * Both `toCliError` (the SDK-error mapper) and `kash explain <code>`\n * read from this catalog so an AI agent that hits a `RATE_LIMITED`\n * error and asks `kash explain RATE_LIMITED --json` gets the same\n * `recoverable`, `docsUrl`, and `actions` it would have seen on the\n * error envelope.\n *\n * Adding a new code: append an entry. Removing one: major bump.\n * Renaming a field: major bump.\n *\n * Runtime-only data (the server's `retryAfterMs`, the specific\n * `requestId`, an extra `wait_and_retry` action computed from the\n * Retry-After header) is layered on top by `toCliError` — the\n * catalog is for static metadata only.\n */\n\nimport type { CliErrorAction } from './errors.js';\n\nexport type ErrorCatalogEntry = {\n /** Stable machine-readable code. */\n readonly code: string;\n /** One-sentence summary in plain English. */\n readonly summary: string;\n /** Longer explanation suitable for human troubleshooting. */\n readonly description: string;\n /** Whether retrying the original request might succeed. */\n readonly recoverable: boolean;\n /** Stable docs URL, when one exists. */\n readonly docsUrl?: string;\n /**\n * Concrete recovery steps the agent can take. These are the\n * *static* actions for this code; runtime-only actions (e.g. a\n * `wait_and_retry` derived from the server's Retry-After header)\n * are appended by `toCliError`.\n */\n readonly actions: readonly CliErrorAction[];\n};\n\n/**\n * The last-resort catalog entry, bound to a name rather than reached through\n * the code map.\n *\n * `lookupErrorCodeWithFallback` used to end `CATALOG_BY_CODE.get('UNEXPECTED')!`\n * on the strength of a comment — \"The UNEXPECTED entry is always present; safe\n * to assert.\" True, and the wrong thing to depend on: the assertion is what\n * stops the compiler noticing if this entry is ever renamed or removed, and the\n * function has no test. Its only caller is the CLI's error envelope, so the\n * `undefined` would be read as an `ErrorCatalogEntry` on the exact path that\n * exists to handle errors nobody recognised — a crash while already failing.\n *\n * Naming it costs nothing and makes the guarantee structural: the catalog\n * spreads this same object, so the two cannot disagree.\n */\nconst UNEXPECTED_ENTRY: ErrorCatalogEntry = {\n code: 'UNEXPECTED',\n summary: 'An unrecognised error escaped the SDK or the CLI.',\n description:\n \"This means the CLI's error mapper didn't recognise the underlying failure — the most likely cause is an SDK or runtime issue. File an issue with the message, the command, and the runtime info from `kash version --json`.\",\n recoverable: false,\n docsUrl: 'https://github.com/KashDAO/cli/issues',\n actions: [\n {\n type: 'run_command',\n command: 'kash version --json',\n description: 'Capture runtime info to attach to the bug report.',\n },\n ],\n};\n\nexport const ERROR_CATALOG: readonly ErrorCatalogEntry[] = [\n {\n code: 'AUTH_REQUIRED',\n summary: 'No API key was provided, or the key is invalid / expired / revoked.',\n description:\n 'The Kash public API requires a kash_live_… or kash_test_… key on every authenticated route. First-time users should run `kash setup` (interactive wizard). Existing users can `kash auth set-key`, set KASH_API_KEY, or pass --profile to switch to a stored profile.',\n recoverable: true,\n docsUrl: 'https://kash.bot/docs/cli/authentication',\n actions: [\n {\n type: 'run_command',\n command: 'kash setup',\n description: 'First-run wizard — issues a key, configures profile, validates it.',\n },\n {\n type: 'run_command',\n command: 'kash auth set-key',\n description:\n 'Store an API key for the active profile (paste interactively or pipe via stdin).',\n },\n {\n type: 'set_env',\n variable: 'KASH_API_KEY',\n description: 'Provide the key via environment variable.',\n },\n {\n type: 'open_url',\n url: 'https://app.kash.bot',\n description:\n 'Create an API key under Settings → API Keys in the Kash app (`Live` for Base mainnet, `Test` for Base Sepolia).',\n },\n ],\n },\n {\n code: 'INSUFFICIENT_SCOPE',\n summary: 'The API key is valid but lacks the scope this command requires.',\n description:\n \"Authentication succeeded but the key's scope (read-only / trade / admin) doesn't cover the route. Request a key with broader scope, or move to a tier that includes it.\",\n recoverable: true,\n docsUrl: 'https://docs.kash.bot/developer-docs/rest-api/authentication',\n actions: [\n {\n type: 'open_url',\n url: 'https://app.kash.bot',\n description: 'Issue a key with broader scope under Settings → API Keys in the Kash app.',\n },\n ],\n },\n {\n code: 'RATE_LIMITED',\n summary: 'You have exceeded the per-key rate limit for this tier.',\n description:\n 'Slow down or upgrade for higher limits. The error envelope carries `retryAfterMs`; honor it via `kash --max-retries` or back off in your application.',\n recoverable: true,\n docsUrl: 'https://kash.bot/docs/api/rate-limits',\n actions: [\n {\n type: 'open_url',\n url: 'https://kash.bot/pricing',\n description: 'Upgrade tier for higher rate limits.',\n },\n ],\n },\n {\n code: 'NOT_FOUND',\n summary: 'The requested resource (market, trade, position) does not exist.',\n description:\n 'Markets and trades are identified by UUID. Confirm the id is correct (especially after copy-paste truncation) and that the resource is visible to the active key.',\n recoverable: true,\n docsUrl: 'https://kash.bot/docs/api/errors',\n actions: [],\n },\n {\n code: 'CONFLICT',\n summary: 'A conflicting request is already in flight or the resource state changed.',\n description:\n 'Common cases: you sent a duplicate Idempotency-Key, the trade is awaiting high-value confirmation, or the market closed between fetch and trade. Inspect the resource before retrying.',\n recoverable: true,\n docsUrl: 'https://kash.bot/docs/api/errors',\n actions: [\n {\n type: 'run_command',\n command: 'kash trade status <id>',\n description: 'Inspect the conflicting trade resource. Substitute <id> with the trade UUID.',\n template: true,\n },\n ],\n },\n {\n code: 'INVALID_INPUT',\n summary: 'The request body or arguments failed validation.',\n description:\n 'Check the field names and types against `kash <command> --help` or `kash schema <command>`. USDC amounts are decimal strings with up to 6 fractional digits.',\n recoverable: true,\n docsUrl: 'https://kash.bot/docs/cli/commands',\n actions: [\n {\n type: 'run_command',\n command: 'kash <command> --help',\n description:\n 'Inspect the command signature. Substitute <command> with the failing path (e.g. `trade buy`, `markets list`).',\n template: true,\n },\n {\n type: 'run_command',\n command: 'kash schema <command>',\n description:\n 'Get the JSON Schema for the command inputs. Substitute <command> with the failing path.',\n template: true,\n },\n ],\n },\n {\n code: 'MAINTENANCE',\n summary: 'The Kash trade pipeline is temporarily disabled (kill switch).',\n description:\n 'API trade processing is halted, typically during incident response or planned maintenance. Read state is unaffected. Honor the `retryAfterMs` and retry once the window closes.',\n recoverable: true,\n docsUrl: 'https://docs.kash.bot/developer-docs/api-errors/API_TRADE_PROCESSING_HALTED',\n actions: [\n {\n type: 'wait_and_retry',\n delayMs: 30_000,\n description: 'Wait 30s then retry. Surface the requestId if the failure persists.',\n },\n ],\n },\n {\n code: 'TIMEOUT',\n summary: 'The request exceeded the SDK timeout (default 30s).',\n description:\n 'Either the server is slow or the network path is degraded. Retry, or pass --timeout-ms to raise the cap. Repeated timeouts are worth investigating against the status page.',\n recoverable: true,\n docsUrl: 'https://kash.bot/docs/cli/troubleshooting',\n actions: [\n {\n type: 'run_command',\n command: 'kash --timeout-ms 60000 <same command>',\n description:\n 'Re-run with a longer timeout. Substitute <same command> with the original invocation tail.',\n template: true,\n },\n ],\n },\n {\n code: 'NETWORK',\n summary: 'A transport-layer failure (DNS, TLS, connection refused) before any HTTP response.',\n description:\n 'The SDK never received a response. Check connectivity to api.kash.bot. The CLI retries network errors automatically; this means retries were exhausted.',\n recoverable: true,\n docsUrl: 'https://kash.bot/docs/cli/troubleshooting',\n actions: [],\n },\n {\n code: 'ABORTED',\n summary: 'The request was cancelled by the caller before it completed.',\n description:\n 'An AbortSignal you passed (or the spinner you cancelled) fired while the request was in flight. The server may or may not have processed the request — if it did, the side effect already landed. Idempotent requests can be safely retried with the same Idempotency-Key.',\n recoverable: false,\n docsUrl: 'https://kash.bot/docs/cli/troubleshooting',\n actions: [],\n },\n {\n code: 'SERVER_ERROR',\n summary: 'The API returned a 5xx response after retries.',\n description:\n 'The request is safe to retry. If the issue persists, file a bug at https://github.com/KashDAO/cli/issues with the requestId on the error envelope.',\n recoverable: true,\n docsUrl: 'https://docs.kash.bot/developer-docs/api-errors/DEPENDENCY_UNAVAILABLE',\n actions: [\n {\n type: 'wait_and_retry',\n delayMs: 5_000,\n description: 'Wait 5s and retry. The CLI may have already exhausted its retry budget.',\n },\n ],\n },\n {\n code: 'CONFIGURATION',\n summary: 'The CLI configuration file or environment is invalid.',\n description:\n \"The on-disk ~/.kash/config.json failed to parse, an env var (KASH_CHAIN, KASH_API_VERSION) doesn't match its expected shape, or a per-invocation flag (--max-retries, --timeout-ms, --base-url) was rejected by the SDK. Run `kash config show` to inspect what loaded.\",\n recoverable: true,\n docsUrl: 'https://kash.bot/docs/cli/configuration',\n actions: [\n {\n type: 'run_command',\n command: 'kash config show',\n description: 'Inspect the loaded configuration and its sources.',\n },\n ],\n },\n // ─── Direct-mode (kash protocol ...) ─────────────────────────────\n {\n code: 'DIRECT_CONFIG_MISSING',\n summary: 'Direct-mode configuration is incomplete.',\n description:\n \"Direct-mode commands (`kash protocol ...`) require RPC URL, smart account address, signer key reference, and chain ID. One or more of these is missing from the active profile and the environment. Run `kash config show` to see what's loaded; set the missing fields with `kash config set rpcUrl …`, `kash config set smartAccount 0x…`, etc.\",\n recoverable: true,\n docsUrl: 'https://kash.bot/docs/cli/direct-mode',\n actions: [\n {\n type: 'run_command',\n command: 'kash config show',\n description: 'Inspect the loaded configuration and source attribution.',\n },\n {\n type: 'run_command',\n command: 'kash config set rpcUrl https://your-rpc.example.com',\n description: 'Set the RPC URL for direct-mode operations.',\n },\n ],\n },\n {\n code: 'SIGNER_FAILED',\n summary: 'The configured signer (file/env/KMS) failed to load or sign.',\n description:\n \"The signer adapter referenced by `signerKeyRef` couldn't load the private key, or signing the UserOp hash failed. Common causes: missing/unreadable file, missing env var, malformed hex, or a KMS permission denial.\",\n recoverable: true,\n docsUrl: 'https://kash.bot/docs/cli/direct-mode',\n actions: [\n {\n type: 'check_input',\n field: 'signerKeyRef',\n description: 'Verify the signer reference (file:<path> or env:<VAR>) and its target.',\n },\n ],\n },\n {\n code: 'RPC_FAILED',\n summary: 'The RPC endpoint refused the request or timed out.',\n description:\n 'Network call to the configured `rpcUrl` failed. Could be a rate-limit at the RPC provider, a transient network issue, or a misconfigured URL. The protocol-sdk does NOT retry RPC calls — fail fast so the operator sees the issue.',\n recoverable: true,\n docsUrl: 'https://kash.bot/docs/cli/troubleshooting',\n actions: [\n {\n type: 'check_input',\n field: 'rpcUrl',\n description: 'Verify the RPC URL is reachable and the API key (if any) is valid.',\n },\n ],\n },\n {\n code: 'BUNDLER_REJECTED',\n summary: 'The bundler refused to relay the UserOp.',\n description:\n 'Common rejection reasons: replacement-underpriced, sender-mempool-full, gas estimation drift, or a UserOp that the bundler suspects will revert. The error message carries the bundler-specific reason verbatim.',\n recoverable: true,\n docsUrl: 'https://kash.bot/docs/cli/direct-mode',\n actions: [],\n },\n {\n code: 'TRANSACTION_REVERTED',\n summary: 'The UserOp executed but the on-chain call reverted.',\n description:\n 'The transaction landed on-chain but the contract call reverted. The error message carries the decoded revert reason when the protocol-sdk recognises it (e.g. `MarketFrozen`, `InsufficientReserve`). Re-running with `kash protocol simulate` first will catch most reverts before they cost gas.',\n recoverable: false,\n docsUrl: 'https://kash.bot/docs/cli/direct-mode',\n actions: [\n {\n type: 'run_command',\n command:\n 'kash protocol simulate <market-address> --action <buy|sell> --outcome <i> --amount <n>',\n description:\n 'Dry-run the trade against current chain state before re-submitting. Substitute every <placeholder>.',\n template: true,\n },\n ],\n },\n {\n code: 'CHAIN_ERROR',\n summary: 'A protocol-level chain interaction failed.',\n description:\n \"An on-chain read or simulation returned an unexpected shape, decoded to an unknown revert, or the contract addresses don't match the configured chain ID. Verify the chain ID and that the protocol contracts are deployed at the expected addresses for that chain.\",\n recoverable: false,\n docsUrl: 'https://kash.bot/docs/cli/direct-mode',\n actions: [\n {\n type: 'check_input',\n field: 'chainId',\n description: 'Confirm chainId matches the network your RPC and bundler target.',\n },\n ],\n },\n UNEXPECTED_ENTRY,\n {\n code: 'NOOP',\n summary: 'No-op exit (Commander emitted output and asked us to stop).',\n description:\n \"Commander's help/version paths don't represent a failure — it printed `--help` or `--version` output and signalled the CLI to exit cleanly. This code surfaces in JSON-output contexts so consumers know the run completed without doing real work; the human path exits 0 with no error envelope.\",\n recoverable: true,\n docsUrl: 'https://kash.bot/docs/cli/exit-codes',\n actions: [],\n },\n];\n\nconst CATALOG_BY_CODE = new Map<string, ErrorCatalogEntry>(\n ERROR_CATALOG.map((entry) => [entry.code, entry])\n);\n\nexport function lookupErrorCode(code: string): ErrorCatalogEntry | undefined {\n return CATALOG_BY_CODE.get(code);\n}\n\n/**\n * Resolve the catalog entry for a code, falling back to the\n * `UNEXPECTED` entry when the code isn't recognised.\n *\n * The fallback exists so opaque SDK codes (e.g. a new `KashError`\n * subclass that hasn't been mapped CLI-side yet) still produce a\n * usable `kash explain <code>` response — the agent learns \"we don't\n * recognise this code, file an issue\" instead of \"Unknown error\n * code\", which would be a dead end.\n */\nexport function lookupErrorCodeWithFallback(code: string): ErrorCatalogEntry {\n return CATALOG_BY_CODE.get(code) ?? UNEXPECTED_ENTRY;\n}\n\n/** Set of every catalog code, exposed for invariant tests. */\nexport const ERROR_CODES: ReadonlySet<string> = new Set(ERROR_CATALOG.map((e) => e.code));\n"],"mappings":"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","names":[]}