@kashdao/cli 0.1.0
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.
- package/CHANGELOG.md +78 -0
- package/CONTRIBUTING.md +159 -0
- package/LICENSE +21 -0
- package/README.md +868 -0
- package/SECURITY.md +110 -0
- package/dist/account-AVFLEM5D.js +90 -0
- package/dist/account-AVFLEM5D.js.map +1 -0
- package/dist/auth-GUJCVKTD.js +239 -0
- package/dist/auth-GUJCVKTD.js.map +1 -0
- package/dist/chunk-BN2CUM42.js +9 -0
- package/dist/chunk-BN2CUM42.js.map +1 -0
- package/dist/chunk-BRK7KJ4O.js +154 -0
- package/dist/chunk-BRK7KJ4O.js.map +1 -0
- package/dist/chunk-KMBMQIZ7.js +393 -0
- package/dist/chunk-KMBMQIZ7.js.map +1 -0
- package/dist/chunk-LBIRQHX5.js +133 -0
- package/dist/chunk-LBIRQHX5.js.map +1 -0
- package/dist/chunk-MIXOZU2S.js +366 -0
- package/dist/chunk-MIXOZU2S.js.map +1 -0
- package/dist/chunk-QJMF73M5.js +129 -0
- package/dist/chunk-QJMF73M5.js.map +1 -0
- package/dist/chunk-UZNSYATZ.js +680 -0
- package/dist/chunk-UZNSYATZ.js.map +1 -0
- package/dist/chunk-VIADBYFY.js +94 -0
- package/dist/chunk-VIADBYFY.js.map +1 -0
- package/dist/chunk-YHCG2SUC.js +159 -0
- package/dist/chunk-YHCG2SUC.js.map +1 -0
- package/dist/chunk-YJX3JJ4M.js +174 -0
- package/dist/chunk-YJX3JJ4M.js.map +1 -0
- package/dist/client-IOM55ZCS.js +14 -0
- package/dist/client-IOM55ZCS.js.map +1 -0
- package/dist/completion-ZZGX5BQC.js +100 -0
- package/dist/completion-ZZGX5BQC.js.map +1 -0
- package/dist/config-XJL5TSYK.js +690 -0
- package/dist/config-XJL5TSYK.js.map +1 -0
- package/dist/config-store-3ZSYGXMQ.js +44 -0
- package/dist/config-store-3ZSYGXMQ.js.map +1 -0
- package/dist/docs-MDKKSJDC.js +102 -0
- package/dist/docs-MDKKSJDC.js.map +1 -0
- package/dist/eoa-IQ72EIHR.js +551 -0
- package/dist/eoa-IQ72EIHR.js.map +1 -0
- package/dist/errors-WMZIEGQI.js +18 -0
- package/dist/errors-WMZIEGQI.js.map +1 -0
- package/dist/explain-H4EH3KH3.js +165 -0
- package/dist/explain-H4EH3KH3.js.map +1 -0
- package/dist/global-options-XOLJUPTT.js +18 -0
- package/dist/global-options-XOLJUPTT.js.map +1 -0
- package/dist/health-VZEIII74.js +98 -0
- package/dist/health-VZEIII74.js.map +1 -0
- package/dist/help-footer-GTANVDNP.js +43 -0
- package/dist/help-footer-GTANVDNP.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +251 -0
- package/dist/index.js.map +1 -0
- package/dist/intro-PQQTYWR7.js +41 -0
- package/dist/intro-PQQTYWR7.js.map +1 -0
- package/dist/markets-C37JZDPE.js +295 -0
- package/dist/markets-C37JZDPE.js.map +1 -0
- package/dist/output-VCBZ3FM7.js +22 -0
- package/dist/output-VCBZ3FM7.js.map +1 -0
- package/dist/portfolio-2AEPIJIG.js +115 -0
- package/dist/portfolio-2AEPIJIG.js.map +1 -0
- package/dist/protocol-XEQXF2GW.js +1572 -0
- package/dist/protocol-XEQXF2GW.js.map +1 -0
- package/dist/quote-I4DVJ7ZB.js +144 -0
- package/dist/quote-I4DVJ7ZB.js.map +1 -0
- package/dist/schema-PIFQ65TS.js +410 -0
- package/dist/schema-PIFQ65TS.js.map +1 -0
- package/dist/setup-USZ6IODD.js +260 -0
- package/dist/setup-USZ6IODD.js.map +1 -0
- package/dist/stdin-YW2CEQXU.js +28 -0
- package/dist/stdin-YW2CEQXU.js.map +1 -0
- package/dist/trace-IZBYTUFO.js +103 -0
- package/dist/trace-IZBYTUFO.js.map +1 -0
- package/dist/trade-IIZSEXEI.js +586 -0
- package/dist/trade-IIZSEXEI.js.map +1 -0
- package/dist/version-JDK3PEP5.js +117 -0
- package/dist/version-JDK3PEP5.js.map +1 -0
- package/dist/version-check-TDCION37.js +138 -0
- package/dist/version-check-TDCION37.js.map +1 -0
- package/dist/webhooks-PTVRKICZ.js +680 -0
- package/dist/webhooks-PTVRKICZ.js.map +1 -0
- package/dist/with-retry-4FIZG3A7.js +223 -0
- package/dist/with-retry-4FIZG3A7.js.map +1 -0
- package/package.json +99 -0
|
@@ -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. Email `engineering@kash.bot` to request a key with broader scope.',\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. The most common\n // failure mode pre-mainnet-launch is \"configured for production\n // but production isn't deployed yet\" — point them at staging via\n // their test key rather than 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 'For staging, use a `kash_test_*` key — the CLI auto-routes to ' +\n '`https://api-staging.kash.bot/v1`. ' +\n 'For a custom host, pass `--base-url <url>` or set `KASH_BASE_URL`. ' +\n 'Production (`https://api.kash.bot/v1`) is not yet live; track launch ' +\n 'status at https://docs.kash.bot.'\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, defaultChainId).',\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\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: 'mailto:engineering@kash.bot?subject=Kash%20staging%20API%20key%20request',\n description:\n 'Email `engineering@kash.bot` to request a `kash_test_*` staging key (self-service issuance ships with the production launch).',\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: 'mailto:engineering@kash.bot?subject=Kash%20API%20key%20scope%20request',\n description: 'Email `engineering@kash.bot` for a key with broader scope.',\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_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.\",\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 {\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 {\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 const entry = CATALOG_BY_CODE.get(code);\n if (entry) return entry;\n // The UNEXPECTED entry is always present; safe to assert.\n return CATALOG_BY_CODE.get('UNEXPECTED')!;\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":";;;AAgCA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA,0BAA0B;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;;;ACNA,IAAM,gBAA8C;AAAA,EACzD;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,IACT,aACE;AAAA,IACF,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,MACP;AAAA,QACE,MAAM;AAAA,QACN,SAAS;AAAA,QACT,aAAa;AAAA,MACf;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,SAAS;AAAA,QACT,aACE;AAAA,MACJ;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,UAAU;AAAA,QACV,aAAa;AAAA,MACf;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,KAAK;AAAA,QACL,aACE;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,IACT,aACE;AAAA,IACF,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,MACP;AAAA,QACE,MAAM;AAAA,QACN,KAAK;AAAA,QACL,aAAa;AAAA,MACf;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,IACT,aACE;AAAA,IACF,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,MACP;AAAA,QACE,MAAM;AAAA,QACN,KAAK;AAAA,QACL,aAAa;AAAA,MACf;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,IACT,aACE;AAAA,IACF,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS,CAAC;AAAA,EACZ;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,IACT,aACE;AAAA,IACF,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,MACP;AAAA,QACE,MAAM;AAAA,QACN,SAAS;AAAA,QACT,aAAa;AAAA,QACb,UAAU;AAAA,MACZ;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,IACT,aACE;AAAA,IACF,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,MACP;AAAA,QACE,MAAM;AAAA,QACN,SAAS;AAAA,QACT,aACE;AAAA,QACF,UAAU;AAAA,MACZ;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,SAAS;AAAA,QACT,aACE;AAAA,QACF,UAAU;AAAA,MACZ;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,IACT,aACE;AAAA,IACF,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,MACP;AAAA,QACE,MAAM;AAAA,QACN,SAAS;AAAA,QACT,aAAa;AAAA,MACf;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,IACT,aACE;AAAA,IACF,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,MACP;AAAA,QACE,MAAM;AAAA,QACN,SAAS;AAAA,QACT,aACE;AAAA,QACF,UAAU;AAAA,MACZ;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,IACT,aACE;AAAA,IACF,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS,CAAC;AAAA,EACZ;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,IACT,aACE;AAAA,IACF,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS,CAAC;AAAA,EACZ;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,IACT,aACE;AAAA,IACF,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,MACP;AAAA,QACE,MAAM;AAAA,QACN,SAAS;AAAA,QACT,aAAa;AAAA,MACf;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,IACT,aACE;AAAA,IACF,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,MACP;AAAA,QACE,MAAM;AAAA,QACN,SAAS;AAAA,QACT,aAAa;AAAA,MACf;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAEA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,IACT,aACE;AAAA,IACF,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,MACP;AAAA,QACE,MAAM;AAAA,QACN,SAAS;AAAA,QACT,aAAa;AAAA,MACf;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,SAAS;AAAA,QACT,aAAa;AAAA,MACf;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,IACT,aACE;AAAA,IACF,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,MACP;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aAAa;AAAA,MACf;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,IACT,aACE;AAAA,IACF,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,MACP;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aAAa;AAAA,MACf;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,IACT,aACE;AAAA,IACF,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS,CAAC;AAAA,EACZ;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,IACT,aACE;AAAA,IACF,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,MACP;AAAA,QACE,MAAM;AAAA,QACN,SACE;AAAA,QACF,aACE;AAAA,QACF,UAAU;AAAA,MACZ;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,IACT,aACE;AAAA,IACF,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,MACP;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aAAa;AAAA,MACf;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,IACT,aACE;AAAA,IACF,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS;AAAA,MACP;AAAA,QACE,MAAM;AAAA,QACN,SAAS;AAAA,QACT,aAAa;AAAA,MACf;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS;AAAA,IACT,aACE;AAAA,IACF,aAAa;AAAA,IACb,SAAS;AAAA,IACT,SAAS,CAAC;AAAA,EACZ;AACF;AAEA,IAAM,kBAAkB,IAAI;AAAA,EAC1B,cAAc,IAAI,CAAC,UAAU,CAAC,MAAM,MAAM,KAAK,CAAC;AAClD;AAEO,SAAS,gBAAgB,MAA6C;AAC3E,SAAO,gBAAgB,IAAI,IAAI;AACjC;AAYO,SAAS,4BAA4B,MAAiC;AAC3E,QAAM,QAAQ,gBAAgB,IAAI,IAAI;AACtC,MAAI,MAAO,QAAO;AAElB,SAAO,gBAAgB,IAAI,YAAY;AACzC;AAGO,IAAM,cAAmC,IAAI,IAAI,cAAc,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;;;ADtUjF,IAAM,aAAa;AAAA,EACxB,IAAI;AAAA,EACJ,SAAS;AAAA,EACT,MAAM;AACR;AAuEO,IAAM,WAAN,cAAuB,MAAM;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA,EACS;AAAA,EAElB,YAAY,SAAiB,SAA0B;AACrD,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,UAAM,eAAe,4BAA4B,QAAQ,IAAI;AAC7D,SAAK,OAAO,QAAQ;AACpB,SAAK,aAAa,QAAQ;AAC1B,SAAK,WAAW,QAAQ,YAAY,WAAW;AAC/C,SAAK,YAAY,QAAQ;AACzB,SAAK,cAAc,QAAQ,eAAe,aAAa;AACvD,SAAK,eAAe,QAAQ;AAC5B,SAAK,UAAU,QAAQ,WAAW,aAAa;AAC/C,QAAI,QAAQ,oBAAoB,QAAW;AACzC,WAAK,UAAU,QAAQ;AAAA,IACzB,OAAO;AAML,WAAK,UAAU,CAAC,GAAI,QAAQ,WAAW,CAAC,GAAI,GAAG,aAAa,OAAO;AAAA,IACrE;AACA,SAAK,QAAQ,QAAQ;AACrB,UAAM,oBAAoB,MAAM,KAAK,WAAW;AAAA,EAClD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,aAAsC;AACpC,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,OAAO;AAAA,QACL,MAAM,KAAK;AAAA,QACX,SAAS,KAAK;AAAA,QACd,aAAa,KAAK;AAAA,QAClB,GAAI,KAAK,eAAe,SAAY,CAAC,IAAI,EAAE,YAAY,KAAK,WAAW;AAAA,QACvE,GAAI,KAAK,iBAAiB,SAAY,CAAC,IAAI,EAAE,cAAc,KAAK,aAAa;AAAA,QAC7E,GAAI,KAAK,YAAY,SAAY,CAAC,IAAI,EAAE,SAAS,KAAK,QAAQ;AAAA,QAC9D,GAAI,KAAK,cAAc,SAAY,CAAC,IAAI,EAAE,WAAW,KAAK,UAAU;AAAA,QACpE,SAAS,KAAK;AAAA,MAChB;AAAA,IACF;AAAA,EACF;AACF;AAEO,IAAM,qBAAN,cAAiC,SAAS;AAAA,EAC/C,YAAY,SAAiB,YAAqB,OAAgB;AAChE,UAAM,SAAS;AAAA,MACb,MAAM;AAAA,MACN,GAAI,eAAe,SAAY,CAAC,IAAI,EAAE,WAAW;AAAA,MACjD,GAAI,UAAU,SACV,CAAC,IACD;AAAA,QACE,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN;AAAA,YACA,aAAa,wBAAwB,KAAK;AAAA,UAC5C;AAAA,QACF;AAAA,MACF;AAAA,IACN,CAAC;AACD,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,wBAAN,cAAoC,SAAS;AAAA,EAClD,YAAY,SAAiB,YAAqB;AAChD,UAAM,SAAS;AAAA,MACb,MAAM;AAAA,MACN,GAAI,eAAe,SAAY,CAAC,IAAI,EAAE,WAAW;AAAA,IACnD,CAAC;AACD,SAAK,OAAO;AAAA,EACd;AACF;AAYO,SAAS,WAAW,KAAwB;AACjD,MAAI,eAAe,UAAU;AAC3B,WAAO;AAAA,EACT;AAKA,QAAM,YAAY,kBAAkB,GAAG;AACvC,MAAI,UAAW,QAAO;AACtB,MAAI,eAAe,yBAAyB;AAC1C,WAAO,IAAI,SAAS,IAAI,SAAS;AAAA,MAC/B,MAAM;AAAA,MACN,UAAU,WAAW;AAAA,MACrB,YACE;AAAA,MACF,GAAI,IAAI,cAAc,SAAY,CAAC,IAAI,EAAE,WAAW,IAAI,UAAU;AAAA,MAClE,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AACA,MAAI,eAAe,wBAAwB;AACzC,WAAO,IAAI,SAAS,IAAI,SAAS;AAAA,MAC/B,MAAM;AAAA,MACN,UAAU,WAAW;AAAA,MACrB,YACE;AAAA,MACF,GAAI,IAAI,cAAc,SAAY,CAAC,IAAI,EAAE,WAAW,IAAI,UAAU;AAAA,MAClE,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AACA,MAAI,eAAe,oBAAoB;AACrC,UAAM,WAAW,IAAI;AACrB,UAAM,eAAe,aAAa,SAAY,SAAY,WAAW;AACrE,UAAM,aACJ,aAAa,SACT,YAAY,OAAO,QAAQ,CAAC,2DAC5B;AACN,WAAO,IAAI,SAAS,IAAI,SAAS;AAAA,MAC/B,MAAM;AAAA,MACN;AAAA,MACA,GAAI,iBAAiB,SAAY,CAAC,IAAI,EAAE,aAAa;AAAA,MACrD,GAAI,iBAAiB,SACjB,CAAC,IACD;AAAA,QACE,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,SAAS;AAAA,YACT,aAAa,QAAQ,OAAO,QAAQ,CAAC;AAAA,UACvC;AAAA,QACF;AAAA,MACF;AAAA,MACJ,GAAI,IAAI,cAAc,SAAY,CAAC,IAAI,EAAE,WAAW,IAAI,UAAU;AAAA,MAClE,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AACA,MAAI,eAAe,mBAAmB;AACpC,WAAO,IAAI,SAAS,IAAI,SAAS;AAAA,MAC/B,MAAM;AAAA,MACN,YAAY;AAAA,MACZ,GAAI,IAAI,cAAc,SAAY,CAAC,IAAI,EAAE,WAAW,IAAI,UAAU;AAAA,MAClE,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AACA,MAAI,eAAe,mBAAmB;AACpC,WAAO,IAAI,SAAS,IAAI,SAAS;AAAA,MAC/B,MAAM;AAAA,MACN,YACE;AAAA,MACF,GAAI,IAAI,cAAc,SAAY,CAAC,IAAI,EAAE,WAAW,IAAI,UAAU;AAAA,MAClE,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AACA,MAAI,eAAe,qBAAqB;AACtC,WAAO,IAAI,SAAS,IAAI,SAAS;AAAA,MAC/B,MAAM;AAAA,MACN,YAAY;AAAA,MACZ,GAAI,IAAI,cAAc,SAAY,CAAC,IAAI,EAAE,WAAW,IAAI,UAAU;AAAA,MAClE,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AACA,MAAI,eAAe,sBAAsB;AACvC,UAAM,WAAW,IAAI;AACrB,UAAM,eAAe,aAAa,SAAY,SAAY,WAAW;AACrE,WAAO,IAAI,SAAS,IAAI,SAAS;AAAA,MAC/B,MAAM;AAAA,MACN,YACE;AAAA,MACF,GAAI,iBAAiB,SAAY,CAAC,IAAI,EAAE,aAAa;AAAA,MACrD,GAAI,iBAAiB,SACjB,CAAC,IACD;AAAA,QACE,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,SAAS;AAAA,YACT,aAAa,QAAQ,OAAO,QAAQ,CAAC;AAAA,UACvC;AAAA,QACF;AAAA,MACF;AAAA,MACJ,GAAI,IAAI,cAAc,SAAY,CAAC,IAAI,EAAE,WAAW,IAAI,UAAU;AAAA,MAClE,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AACA,MAAI,eAAe,kBAAkB;AACnC,WAAO,IAAI,SAAS,IAAI,SAAS;AAAA,MAC/B,MAAM;AAAA,MACN,YACE;AAAA,MACF,GAAI,IAAI,cAAc,SAAY,CAAC,IAAI,EAAE,WAAW,IAAI,UAAU;AAAA,MAClE,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AACA,MAAI,eAAe,kBAAkB;AAMnC,UAAM,WAAW,GAAG,OAAO,IAAI,WAAW,EAAE,CAAC,IAAI,OAAQ,IAAI,OAAiB,WAAW,EAAE,CAAC;AAC5F,UAAM,aACJ,SAAS,SAAS,WAAW,KAC7B,SAAS,SAAS,aAAa,KAC/B,SAAS,SAAS,WAAW,KAC7B,SAAS,SAAS,mBAAmB;AACvC,UAAM,aAAa,aACf,mUAMA;AACJ,WAAO,IAAI,SAAS,IAAI,SAAS;AAAA,MAC/B,MAAM;AAAA,MACN;AAAA,MACA,GAAI,IAAI,cAAc,SAAY,CAAC,IAAI,EAAE,WAAW,IAAI,UAAU;AAAA,MAClE,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AACA,MAAI,eAAe,kBAAkB;AACnC,WAAO,IAAI,SAAS,IAAI,SAAS;AAAA,MAC/B,MAAM;AAAA,MACN,YACE;AAAA,MACF,GAAI,IAAI,cAAc,SAAY,CAAC,IAAI,EAAE,WAAW,IAAI,UAAU;AAAA,MAClE,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AACA,MAAI,eAAe,iBAAiB;AAClC,WAAO,IAAI,SAAS,IAAI,SAAS;AAAA,MAC/B,MAAM;AAAA,MACN,YACE;AAAA,MACF,GAAI,IAAI,cAAc,SAAY,CAAC,IAAI,EAAE,WAAW,IAAI,UAAU;AAAA,MAClE,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AACA,MAAI,eAAe,2BAA2B;AAG5C,UAAM,aAAa,IAAI,OAAO,CAAC;AAC/B,UAAM,YAAY,YAAY,KAAK,KAAK,GAAG,KAAK;AAChD,WAAO,IAAI,SAAS,IAAI,SAAS;AAAA,MAC/B,MAAM;AAAA,MACN,YACE,eAAe,SACX,gBAAgB,aAAa,QAAQ,KAAK,WAAW,OAAO,KAC5D;AAAA,MACN,GAAI,YACA;AAAA,QACE,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,OAAO;AAAA,YACP,aAAa,qBAAqB,SAAS;AAAA,UAC7C;AAAA,QACF;AAAA,MACF,IACA,CAAC;AAAA,MACL,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AAMA,QAAM,uBAAuB,iBAAiB,GAAG;AACjD,MAAI,yBAAyB,QAAW;AACtC,WAAO;AAAA,EACT;AACA,MAAI,eAAe,WAAW;AAK5B,WAAO,IAAI,SAAS,IAAI,SAAS;AAAA,MAC/B,MAAM;AAAA,MACN,aAAa,IAAI;AAAA,MACjB,GAAI,IAAI,cAAc,SAAY,CAAC,IAAI,EAAE,WAAW,IAAI,UAAU;AAAA,MAClE,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AACA,MAAI,eAAe,OAAO;AACxB,WAAO,IAAI,SAAS,IAAI,SAAS,EAAE,MAAM,cAAc,OAAO,IAAI,CAAC;AAAA,EACrE;AACA,SAAO,IAAI,SAAS,OAAO,GAAG,GAAG,EAAE,MAAM,cAAc,OAAO,IAAI,CAAC;AACrE;AAyBO,SAAS,iBAAiB,KAAyC;AACxE,MAAI,EAAE,eAAe,OAAQ,QAAO;AACpC,QAAM,YAAY;AAClB,SACE,OAAO,UAAU,SAAS,YAC1B,UAAU,KAAK,WAAW,YAAY,KACtC,OAAO,UAAU,YAAY;AAEjC;AAQA,SAAS,kBAAkB,KAAoC;AAC7D,MAAI,CAAC,iBAAiB,GAAG,EAAG,QAAO;AACnC,QAAM,EAAE,MAAM,QAAQ,IAAI;AAO1B,MACE,SAAS,oBACT,SAAS,6BACT,SAAS,qBACT;AACA,WAAO,IAAI,SAAS,IAAI;AAAA,MACtB,MAAM;AAAA,MACN,UAAU,WAAW;AAAA,MACrB,aAAa;AAAA,MACb,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AAMA,MAAI,SAAS,4BAA4B;AACvC,UAAM,QAAQ,8BAA8B,KAAK,OAAO;AACxD,UAAM,YAAY,QAAQ,CAAC;AAC3B,UAAM,aAAa,YACf,uBAAuB,SAAS,uDAChC;AACJ,WAAO,IAAI,SAAS,sBAAsB,OAAO,GAAG;AAAA,MAClD,MAAM;AAAA,MACN,aAAa;AAAA,MACb;AAAA,MACA,GAAI,cAAc,SACd,CAAC,IACD;AAAA,QACE,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,SAAS,QAAQ,SAAS;AAAA,YAC1B,aAAa;AAAA,UACf;AAAA,QACF;AAAA,MACF;AAAA,MACJ,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AAIA,MAAI,SAAS,2BAA2B;AACtC,WAAO,IAAI,SAAS,sBAAsB,OAAO,GAAG;AAAA,MAClD,MAAM;AAAA,MACN,aAAa;AAAA,MACb,YACE;AAAA,MACF,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AAKA,MACE,SAAS,+BACT,SAAS,2CACT,SAAS,mCACT;AACA,WAAO,IAAI,SAAS,sBAAsB,OAAO,GAAG;AAAA,MAClD,MAAM;AAAA,MACN,aAAa;AAAA,MACb,YAAY;AAAA,MACZ,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AAIA,SAAO,IAAI,SAAS,sBAAsB,OAAO,GAAG;AAAA,IAClD,MAAM;AAAA,IACN,aAAa;AAAA,IACb,OAAO;AAAA,EACT,CAAC;AACH;AAGA,SAAS,sBAAsB,GAAmB;AAChD,SAAO,EAAE,QAAQ,QAAQ,EAAE;AAC7B;AAeA,SAAS,iBAAiB,KAAoC;AAC5D,MAAI,EAAE,eAAe,OAAQ,QAAO;AACpC,UAAQ,IAAI,MAAM;AAAA,IAChB,KAAK,mBAAmB;AACtB,YAAM,SAAS,IAAI,SAAS,IAAI,SAAS;AAAA,QACvC,MAAM;AAAA,QACN,YACE;AAAA,QACF,OAAO;AAAA,MACT,CAAC;AACD,aAAO;AAAA,IACT;AAAA,IACA,KAAK;AACH,aAAO,IAAI,SAAS,IAAI,SAAS;AAAA,QAC/B,MAAM;AAAA,QACN,YAAY;AAAA,QACZ,OAAO;AAAA,MACT,CAAC;AAAA,IACH,KAAK;AACH,aAAO,IAAI,SAAS,IAAI,SAAS;AAAA,QAC/B,MAAM;AAAA,QACN,YAAY;AAAA,QACZ,OAAO;AAAA,MACT,CAAC;AAAA,IACH,KAAK;AACH,aAAO,IAAI,SAAS,IAAI,SAAS;AAAA,QAC/B,MAAM;AAAA,QACN,YAAY;AAAA,QACZ,OAAO;AAAA,MACT,CAAC;AAAA,IACH,KAAK;AACH,aAAO,IAAI,SAAS,IAAI,SAAS;AAAA,QAC/B,MAAM;AAAA,QACN,YAAY;AAAA,QACZ,OAAO;AAAA,MACT,CAAC;AAAA,IACH,KAAK;AAGH,aAAO,IAAI,SAAS,IAAI,SAAS;AAAA,QAC/B,MAAM;AAAA,QACN,YAAY;AAAA,QACZ,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AACE,aAAO;AAAA,EACX;AACF;","names":[]}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
applyFilter,
|
|
4
|
+
projectFields
|
|
5
|
+
} from "./chunk-MIXOZU2S.js";
|
|
6
|
+
|
|
7
|
+
// src/utils/output.ts
|
|
8
|
+
import chalk from "chalk";
|
|
9
|
+
var quiet = false;
|
|
10
|
+
var noColor = false;
|
|
11
|
+
var fields;
|
|
12
|
+
var filter;
|
|
13
|
+
var ORIGINAL_CHALK_LEVEL = chalk.level;
|
|
14
|
+
function configureOutput(opts) {
|
|
15
|
+
quiet = opts.quiet ?? false;
|
|
16
|
+
noColor = opts.noColor ?? false;
|
|
17
|
+
fields = opts.fields;
|
|
18
|
+
filter = opts.filter;
|
|
19
|
+
if (noColor || process.env["NO_COLOR"]) {
|
|
20
|
+
chalk.level = 0;
|
|
21
|
+
} else {
|
|
22
|
+
chalk.level = ORIGINAL_CHALK_LEVEL;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
var style = {
|
|
26
|
+
info: (s) => style.style(chalk.blue, s),
|
|
27
|
+
success: (s) => style.style(chalk.green, s),
|
|
28
|
+
warn: (s) => style.style(chalk.yellow, s),
|
|
29
|
+
error: (s) => style.style(chalk.red, s),
|
|
30
|
+
dim: (s) => style.style(chalk.gray, s),
|
|
31
|
+
bold: (s) => style.style(chalk.bold, s),
|
|
32
|
+
cyan: (s) => style.style(chalk.cyan, s),
|
|
33
|
+
magenta: (s) => style.style(chalk.magenta, s),
|
|
34
|
+
style: (fn, s) => noColor ? s : fn(s)
|
|
35
|
+
};
|
|
36
|
+
var log = {
|
|
37
|
+
info: (msg) => {
|
|
38
|
+
if (!quiet) process.stderr.write(`${style.info("\u2139")} ${msg}
|
|
39
|
+
`);
|
|
40
|
+
},
|
|
41
|
+
success: (msg) => {
|
|
42
|
+
if (!quiet) process.stderr.write(`${style.success("\u2713")} ${msg}
|
|
43
|
+
`);
|
|
44
|
+
},
|
|
45
|
+
warn: (msg) => {
|
|
46
|
+
if (!quiet) process.stderr.write(`${style.warn("\u26A0")} ${msg}
|
|
47
|
+
`);
|
|
48
|
+
},
|
|
49
|
+
error: (msg) => {
|
|
50
|
+
process.stderr.write(`${style.error("\u2717")} ${msg}
|
|
51
|
+
`);
|
|
52
|
+
},
|
|
53
|
+
detail: (label, value) => {
|
|
54
|
+
if (!quiet) process.stderr.write(` ${style.dim(label)}: ${value}
|
|
55
|
+
`);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
function print(line) {
|
|
59
|
+
if (!quiet) process.stdout.write(`${line}
|
|
60
|
+
`);
|
|
61
|
+
}
|
|
62
|
+
function printJson(value) {
|
|
63
|
+
const indent = quiet ? void 0 : 2;
|
|
64
|
+
const filtered = filter === void 0 ? value : applyFilter(value, filter);
|
|
65
|
+
const projected = fields === void 0 ? filtered : projectFields(filtered, fields);
|
|
66
|
+
process.stdout.write(`${JSON.stringify(projected, jsonReplacer, indent)}
|
|
67
|
+
`);
|
|
68
|
+
}
|
|
69
|
+
function jsonReplacer(_key, value) {
|
|
70
|
+
if (typeof value === "bigint") return value.toString();
|
|
71
|
+
if (typeof value === "number" && !Number.isFinite(value)) return null;
|
|
72
|
+
return value;
|
|
73
|
+
}
|
|
74
|
+
function isQuiet() {
|
|
75
|
+
return quiet;
|
|
76
|
+
}
|
|
77
|
+
function writeNdjson(value) {
|
|
78
|
+
const filtered = filter === void 0 ? value : applyFilter(value, filter);
|
|
79
|
+
if (filtered === null && filter !== void 0) return;
|
|
80
|
+
const projected = fields === void 0 ? filtered : projectFields(filtered, fields);
|
|
81
|
+
process.stdout.write(`${JSON.stringify(projected, jsonReplacer)}
|
|
82
|
+
`);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export {
|
|
86
|
+
configureOutput,
|
|
87
|
+
style,
|
|
88
|
+
log,
|
|
89
|
+
print,
|
|
90
|
+
printJson,
|
|
91
|
+
isQuiet,
|
|
92
|
+
writeNdjson
|
|
93
|
+
};
|
|
94
|
+
//# sourceMappingURL=chunk-VIADBYFY.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/output.ts"],"sourcesContent":["/**\n * Centralised stdout/stderr writes for the CLI.\n *\n * `output` exposes both human-mode (`print`, `log.success`, …) and a\n * `json` writer that always goes to stdout for AI-agent integration\n * (`--json --quiet`). Quiet mode silences the human-mode writers but\n * leaves `json` and `error` alone — scripts still see structured\n * output and errors when they pass `--quiet`.\n *\n * All chalk usage funnels through `Style` so the global `--no-color`\n * flag (or NO_COLOR env var per https://no-color.org) takes effect\n * uniformly.\n */\n\nimport chalk, { type ChalkInstance } from 'chalk';\n\nimport { projectFields } from './fields.js';\nimport { applyFilter, type FilterAst } from './filter.js';\n\nlet quiet = false;\nlet noColor = false;\nlet fields: ReadonlyArray<readonly string[]> | undefined;\nlet filter: FilterAst | undefined;\n\n/**\n * Cache chalk's auto-detected color level once at module load.\n * `configureOutput` flips between this value and `0` so a later call\n * with `noColor: false` actually restores color (instead of being a\n * no-op because the previous call set it to 0). Important for tests\n * that toggle `noColor` between cases.\n */\nconst ORIGINAL_CHALK_LEVEL = chalk.level;\n\n/** Wire global flags once, at startup, from the resolved global options. */\nexport function configureOutput(opts: {\n quiet?: boolean;\n noColor?: boolean;\n fields?: ReadonlyArray<readonly string[]> | undefined;\n filter?: FilterAst | undefined;\n}): void {\n quiet = opts.quiet ?? false;\n noColor = opts.noColor ?? false;\n // `fields` and `filter` are intentionally rebound on every call\n // (including undefined) so test setups that toggle them between\n // cases see the change. Same pattern as `quiet`/`noColor` above.\n fields = opts.fields;\n filter = opts.filter;\n if (noColor || process.env['NO_COLOR']) {\n chalk.level = 0;\n } else {\n chalk.level = ORIGINAL_CHALK_LEVEL;\n }\n}\n\n/** Lightweight chalk wrapper that respects `--no-color`. */\nexport const style = {\n info: (s: string): string => style.style(chalk.blue, s),\n success: (s: string): string => style.style(chalk.green, s),\n warn: (s: string): string => style.style(chalk.yellow, s),\n error: (s: string): string => style.style(chalk.red, s),\n dim: (s: string): string => style.style(chalk.gray, s),\n bold: (s: string): string => style.style(chalk.bold, s),\n cyan: (s: string): string => style.style(chalk.cyan, s),\n magenta: (s: string): string => style.style(chalk.magenta, s),\n style: (fn: ChalkInstance, s: string): string => (noColor ? s : fn(s)),\n};\n\n/** Generic writers — go to stderr for human noise, stdout for data. */\nexport const log = {\n info: (msg: string): void => {\n if (!quiet) process.stderr.write(`${style.info('ℹ')} ${msg}\\n`);\n },\n success: (msg: string): void => {\n if (!quiet) process.stderr.write(`${style.success('✓')} ${msg}\\n`);\n },\n warn: (msg: string): void => {\n if (!quiet) process.stderr.write(`${style.warn('⚠')} ${msg}\\n`);\n },\n error: (msg: string): void => {\n // Errors are never silenced — even in --quiet mode the user needs\n // to know things failed.\n process.stderr.write(`${style.error('✗')} ${msg}\\n`);\n },\n detail: (label: string, value: string): void => {\n if (!quiet) process.stderr.write(` ${style.dim(label)}: ${value}\\n`);\n },\n};\n\n/** Print a chunk of human output to stdout (a table, a header, etc.). */\nexport function print(line: string): void {\n if (!quiet) process.stdout.write(`${line}\\n`);\n}\n\n/**\n * Print a JSON payload to stdout. Always runs, regardless of quiet\n * mode — `--json --quiet` is the recommended AI-agent shape and\n * silently dropping the data would be the worst possible failure.\n *\n * Output mode:\n * - `--json` alone: pretty-printed with 2-space indent (humans\n * piping through `less` or eyeballing the response benefit).\n * - `--json --quiet`: single-line compact JSON. Cheaper to stream\n * through `xargs`/`jq -c` and matches the NDJSON shape consumers\n * are already wired up for.\n *\n * BigInts are coerced to strings (the SDK never returns BigInts at\n * the time of writing, but the helper is defensive). Non-finite\n * numbers (`NaN`, `Infinity`, `-Infinity`) are coerced to `null` —\n * `JSON.stringify` would silently emit `null` for them anyway, but\n * the explicit branch documents the choice + makes the contract\n * stable across Node versions.\n */\nexport function printJson(value: unknown): void {\n const indent = quiet ? undefined : 2;\n // Order matters: filter narrows the entries first, then fields\n // projects the surviving ones. The reverse would project fields\n // OFF the records the filter then can't see — confusing for users\n // (`--filter status==ACTIVE --fields id` should still filter on\n // status, even though the projected output drops it).\n const filtered = filter === undefined ? value : applyFilter(value, filter);\n const projected = fields === undefined ? filtered : projectFields(filtered, fields);\n process.stdout.write(`${JSON.stringify(projected, jsonReplacer, indent)}\\n`);\n}\n\n/**\n * Single source of truth for the JSON replacer. Handles:\n *\n * - `bigint` → decimal string (lossless representation; JSON has\n * no native bigint type).\n * - `NaN` / `Infinity` / `-Infinity` → `null` (explicit; matches\n * JSON.stringify's silent default but is documented here).\n *\n * **Date handling.** `Date` instances reach the replacer *after*\n * `JSON.stringify` has already invoked their `toJSON()` method\n * (returning the ISO-8601 string). The replacer receives a string,\n * not a `Date`, so dates are emitted as ISO-8601 — the same shape\n * the API returns for `created_at` / `resolved_at` style fields.\n * Callers that need a different format must transform the value\n * before reaching `printJson`.\n *\n * Returns the original value otherwise. Stable contract — agents\n * pinning to the JSON shape can rely on these substitutions.\n */\nfunction jsonReplacer(_key: string, value: unknown): unknown {\n if (typeof value === 'bigint') return value.toString();\n if (typeof value === 'number' && !Number.isFinite(value)) return null;\n return value;\n}\n\nexport function isQuiet(): boolean {\n return quiet;\n}\n\n/**\n * Emit a single record as one line of newline-delimited JSON\n * (NDJSON). Used by `--ndjson` paginated commands so an AI agent can\n * stream-process arbitrarily large result sets without buffering the\n * full array.\n *\n * BigInts are coerced to strings — same defensive policy as\n * {@link printJson}.\n */\nexport function writeNdjson(value: unknown): void {\n // NDJSON emits one record at a time. Filter on a single-record\n // value returns `null` when the predicate fails; we skip those\n // entirely (don't emit a `null` line — that would corrupt the\n // stream for consumers expecting one record per line).\n const filtered = filter === undefined ? value : applyFilter(value, filter);\n if (filtered === null && filter !== undefined) return;\n const projected = fields === undefined ? filtered : projectFields(filtered, fields);\n process.stdout.write(`${JSON.stringify(projected, jsonReplacer)}\\n`);\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
CliValidationError
|
|
4
|
+
} from "./chunk-UZNSYATZ.js";
|
|
5
|
+
|
|
6
|
+
// src/utils/trade-input.ts
|
|
7
|
+
var HEX_ADDRESS_REGEX = /^0x[0-9a-fA-F]{40}$/;
|
|
8
|
+
var HEX_HASH_REGEX = /^0x[0-9a-fA-F]{64}$/;
|
|
9
|
+
var BIGINT_STRING_REGEX = /^\d+$/;
|
|
10
|
+
var USDC_DECIMAL_REGEX = /^\d+(\.\d{1,6})?$/;
|
|
11
|
+
var DEFAULT_SLIPPAGE_BPS = 50;
|
|
12
|
+
var MAX_UINT256 = 2n ** 256n - 1n;
|
|
13
|
+
function validateAddress(value, field) {
|
|
14
|
+
if (!HEX_ADDRESS_REGEX.test(value)) {
|
|
15
|
+
throw new CliValidationError(
|
|
16
|
+
`<${field}> must be a 0x-prefixed 40-char hex address.`,
|
|
17
|
+
`Got "${value}".`,
|
|
18
|
+
field
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
function validateAddressOptional(value, field) {
|
|
24
|
+
return value === void 0 ? void 0 : validateAddress(value, field);
|
|
25
|
+
}
|
|
26
|
+
var UNSIGNED_INT_REGEX = /^\+?\d+$/;
|
|
27
|
+
function parseOutcomeIndex(raw) {
|
|
28
|
+
if (raw === void 0) {
|
|
29
|
+
throw new CliValidationError("--outcome is required.", void 0, "outcome");
|
|
30
|
+
}
|
|
31
|
+
if (!UNSIGNED_INT_REGEX.test(raw)) {
|
|
32
|
+
throw new CliValidationError(
|
|
33
|
+
"--outcome must be an integer between 0 and 7.",
|
|
34
|
+
`Got "${raw}". Pass digits only \u2014 no decimals (\`1.5\` would silently round to 1) or scientific notation.`,
|
|
35
|
+
"outcome"
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
const n = Number.parseInt(raw, 10);
|
|
39
|
+
if (!Number.isFinite(n) || n < 0 || n > 7) {
|
|
40
|
+
throw new CliValidationError(
|
|
41
|
+
"--outcome must be an integer between 0 and 7.",
|
|
42
|
+
"Markets carry 2-8 outcomes; the index is 0-based.",
|
|
43
|
+
"outcome"
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
return n;
|
|
47
|
+
}
|
|
48
|
+
function parseUppercaseSide(raw, name = "side") {
|
|
49
|
+
const upper = raw.toUpperCase();
|
|
50
|
+
if (upper !== "BUY" && upper !== "SELL") {
|
|
51
|
+
throw new CliValidationError(
|
|
52
|
+
`--${name} must be one of: BUY, SELL (case-insensitive).`,
|
|
53
|
+
`Got "${raw}".`,
|
|
54
|
+
name
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
return upper;
|
|
58
|
+
}
|
|
59
|
+
function parseSlippageBps(raw) {
|
|
60
|
+
if (!UNSIGNED_INT_REGEX.test(raw)) {
|
|
61
|
+
throw new CliValidationError(
|
|
62
|
+
"--slippage-bps must be an integer between 0 and 10000.",
|
|
63
|
+
`Got "${raw}". Pass digits only \u2014 \`1e3\` would silently parse as 1 (0.01%) instead of 1000 (10%).`,
|
|
64
|
+
"slippage-bps"
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
const n = Number.parseInt(raw, 10);
|
|
68
|
+
if (!Number.isFinite(n) || n < 0 || n > 1e4) {
|
|
69
|
+
throw new CliValidationError(
|
|
70
|
+
"--slippage-bps must be an integer between 0 and 10000.",
|
|
71
|
+
`Got "${raw}". 50 = 0.5%, 100 = 1%, 10000 = 100%.`,
|
|
72
|
+
"slippage-bps"
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
return n;
|
|
76
|
+
}
|
|
77
|
+
function parseDeadlineSec(raw) {
|
|
78
|
+
let parsed;
|
|
79
|
+
try {
|
|
80
|
+
parsed = BigInt(raw);
|
|
81
|
+
} catch {
|
|
82
|
+
throw new CliValidationError(
|
|
83
|
+
"--deadline-sec must be a unix timestamp in seconds.",
|
|
84
|
+
`Got "${raw}".`,
|
|
85
|
+
"deadline-sec"
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
if (parsed <= 0n) {
|
|
89
|
+
throw new CliValidationError(
|
|
90
|
+
"--deadline-sec must be positive.",
|
|
91
|
+
`Got "${raw}".`,
|
|
92
|
+
"deadline-sec"
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
if (parsed > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
96
|
+
throw new CliValidationError(
|
|
97
|
+
"--deadline-sec is impossibly far in the future.",
|
|
98
|
+
`Got ${String(parsed)}. Did you pass milliseconds by mistake? Convert to seconds first.`,
|
|
99
|
+
"deadline-sec"
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
return parsed;
|
|
103
|
+
}
|
|
104
|
+
function validateUsdcDecimalShape(decimal, name) {
|
|
105
|
+
if (!USDC_DECIMAL_REGEX.test(decimal)) {
|
|
106
|
+
throw new CliValidationError(
|
|
107
|
+
`--${name} must be a USDC decimal with up to 6 fractional digits.`,
|
|
108
|
+
`Got "${decimal}". USDC accepts up to 6 fractional digits (e.g. "10", "12.50", "0.000001").`,
|
|
109
|
+
name
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function extractPartialHash(cause, options) {
|
|
114
|
+
if (cause === null || typeof cause !== "object") return void 0;
|
|
115
|
+
const code = cause.code;
|
|
116
|
+
if (code !== options.code) return void 0;
|
|
117
|
+
const ctx = cause.context;
|
|
118
|
+
if (ctx === null || typeof ctx !== "object") return void 0;
|
|
119
|
+
const hash = ctx[options.contextKey];
|
|
120
|
+
return typeof hash === "string" && HEX_HASH_REGEX.test(hash) ? hash : void 0;
|
|
121
|
+
}
|
|
122
|
+
function decimalToAtomicUsdc(decimal, name) {
|
|
123
|
+
validateUsdcDecimalShape(decimal, name);
|
|
124
|
+
const [whole, frac = ""] = decimal.split(".");
|
|
125
|
+
const fracPadded = frac.padEnd(6, "0");
|
|
126
|
+
return BigInt(`${whole}${fracPadded}`);
|
|
127
|
+
}
|
|
128
|
+
function decimalToAtomicWad(decimal, name) {
|
|
129
|
+
if (!/^\d+(\.\d{1,18})?$/.test(decimal)) {
|
|
130
|
+
throw new CliValidationError(
|
|
131
|
+
`--${name} must be a token decimal with up to 18 fractional digits.`,
|
|
132
|
+
`Got "${decimal}". Outcome tokens use WAD-18 precision.`,
|
|
133
|
+
name
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
const [whole, frac = ""] = decimal.split(".");
|
|
137
|
+
const fracPadded = frac.padEnd(18, "0");
|
|
138
|
+
return BigInt(`${whole}${fracPadded}`);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export {
|
|
142
|
+
HEX_ADDRESS_REGEX,
|
|
143
|
+
HEX_HASH_REGEX,
|
|
144
|
+
BIGINT_STRING_REGEX,
|
|
145
|
+
USDC_DECIMAL_REGEX,
|
|
146
|
+
DEFAULT_SLIPPAGE_BPS,
|
|
147
|
+
MAX_UINT256,
|
|
148
|
+
validateAddress,
|
|
149
|
+
validateAddressOptional,
|
|
150
|
+
parseOutcomeIndex,
|
|
151
|
+
parseUppercaseSide,
|
|
152
|
+
parseSlippageBps,
|
|
153
|
+
parseDeadlineSec,
|
|
154
|
+
validateUsdcDecimalShape,
|
|
155
|
+
extractPartialHash,
|
|
156
|
+
decimalToAtomicUsdc,
|
|
157
|
+
decimalToAtomicWad
|
|
158
|
+
};
|
|
159
|
+
//# sourceMappingURL=chunk-YHCG2SUC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/trade-input.ts"],"sourcesContent":["/**\n * Shared input parsers for every trade-execution command.\n *\n * Three modes share these primitives:\n *\n * - SA mode (`kash protocol trade …`, `kash protocol userop build …`)\n * — converts to atomic units (bigint) for the protocol-sdk.\n * - EOA mode (`kash eoa trade …`) — same atomic-unit conversion.\n * - Public-API mode (`kash trade buy/sell`) — ships the raw string\n * to the hosted-API SDK, so it uses the shape validators\n * (`validateUsdcDecimalShape`, `parseOutcomeIndex`) rather than\n * the atomic-unit converters.\n *\n * Centralising the parsers eliminates three sources of drift:\n *\n * 1. **Validation messages** — the same flag should produce the\n * same error wording regardless of mode.\n * 2. **Bounds** — slippage caps, outcome-index ceilings, USDC\n * decimal precision must be identical across modes (otherwise\n * operators get different errors for the same value).\n * 3. **Real-money correctness** — these inputs feed the SDK's\n * atomic-unit math (or the API's server-side conversion); one\n * drift between modes would silently change a trade's effective\n * amount.\n */\n\nimport { CliValidationError } from '../errors.js';\n\n/** Standard 0x-prefixed 40-char EVM address. */\nexport const HEX_ADDRESS_REGEX = /^0x[0-9a-fA-F]{40}$/;\n/** 32-byte hash (UserOp hashes, tx hashes). */\nexport const HEX_HASH_REGEX = /^0x[0-9a-fA-F]{64}$/;\n/**\n * Stringified non-negative bigint (canonical decimal). Used by Zod\n * envelopes that must round-trip a `bigint` field through JSON without\n * losing precision — the wire shape is \"every digit, no scientific\n * notation, no leading sign\". Single source of truth so the SA-mode\n * direct-client envelopes (`OnChainBalanceSchema`, `MarketStateSchema`,\n * `QuoteSchema`) can't drift on what counts as a valid encoding.\n */\nexport const BIGINT_STRING_REGEX = /^\\d+$/;\n/**\n * Human USDC decimal: whole digits with up to 6 fractional digits.\n * Backs both the `validateUsdcDecimalShape` runtime check and the\n * `kash trade buy/sell --dry-run --json` envelope schema, so the\n * runtime parser and the JSON contract can't disagree on what\n * counts as a valid amount.\n */\nexport const USDC_DECIMAL_REGEX = /^\\d+(\\.\\d{1,6})?$/;\n\n/** Default slippage tolerance in basis points (50 = 0.5%). */\nexport const DEFAULT_SLIPPAGE_BPS = 50;\n/** ERC-20's `MAX_UINT256` — sentinel for \"infinite\" approval. */\nexport const MAX_UINT256 = 2n ** 256n - 1n;\n\n/**\n * Validate a market / spender / account address. Throws\n * `INVALID_INPUT` with the supplied field name (so the structured\n * error envelope's `check_input` action points at the right flag).\n */\nexport function validateAddress(value: string, field: string): `0x${string}` {\n if (!HEX_ADDRESS_REGEX.test(value)) {\n throw new CliValidationError(\n `<${field}> must be a 0x-prefixed 40-char hex address.`,\n `Got \"${value}\".`,\n field\n );\n }\n return value as `0x${string}`;\n}\n\n/**\n * Optional variant of {@link validateAddress}. Returns `undefined`\n * when the input is `undefined` (the common \"default to active\n * profile's account\" pattern); otherwise validates and returns the\n * narrowed type.\n */\nexport function validateAddressOptional(\n value: string | undefined,\n field: string\n): `0x${string}` | undefined {\n return value === undefined ? undefined : validateAddress(value, field);\n}\n\n/**\n * Strict-shape regex for unsigned integer flag values. Bare digits\n * only (with optional leading `+`). Anything else — `1.5`, `1e3`,\n * `0x10`, ` 42`, `42 `, `1 2` — must be rejected.\n *\n * Plain `Number.parseInt('1.5', 10)` returns `1` and\n * `Number.parseInt('1e3', 10)` returns `1` too. Both are silent\n * precision losses on inputs that look like real-money typos:\n * - `--outcome 1.5` would buy outcome 1 (wrong outcome).\n * - `--slippage-bps 1e3` would use 1 bps instead of 1000 (10%\n * slippage clipped to 0.01% — catastrophic).\n *\n * Every flag-parser in this module that consumes integers MUST\n * gate its `Number.parseInt` call on this regex.\n */\nconst UNSIGNED_INT_REGEX = /^\\+?\\d+$/;\n\n/**\n * Outcome index in `[0, 7]` (Pythagorean AMM ceiling — markets carry\n * 2-8 outcomes). Throws `INVALID_INPUT` on missing or out-of-range.\n */\nexport function parseOutcomeIndex(raw: string | undefined): number {\n if (raw === undefined) {\n throw new CliValidationError('--outcome is required.', undefined, 'outcome');\n }\n if (!UNSIGNED_INT_REGEX.test(raw)) {\n throw new CliValidationError(\n '--outcome must be an integer between 0 and 7.',\n `Got \"${raw}\". Pass digits only — no decimals (\\`1.5\\` would silently round to 1) or scientific notation.`,\n 'outcome'\n );\n }\n const n = Number.parseInt(raw, 10);\n if (!Number.isFinite(n) || n < 0 || n > 7) {\n throw new CliValidationError(\n '--outcome must be an integer between 0 and 7.',\n 'Markets carry 2-8 outcomes; the index is 0-based.',\n 'outcome'\n );\n }\n return n;\n}\n\n/**\n * `--side` parser shared by `kash protocol quote` and `kash eoa trade`.\n * Returns the canonical uppercase form (`'BUY' | 'SELL'`) the SDKs\n * expect. Case-insensitive on input.\n *\n * The lowercase variant (`'buy' | 'sell'`) used by the public-API\n * predictions feed (`kash markets predictions --side buy`) lives at\n * its sole call site — it has different semantics (filter rather\n * than execute) and routes through a separate API endpoint.\n */\nexport function parseUppercaseSide(raw: string, name = 'side'): 'BUY' | 'SELL' {\n const upper = raw.toUpperCase();\n if (upper !== 'BUY' && upper !== 'SELL') {\n throw new CliValidationError(\n `--${name} must be one of: BUY, SELL (case-insensitive).`,\n `Got \"${raw}\".`,\n name\n );\n }\n return upper;\n}\n\n/**\n * One-shot trade-execution side. SA mode (`kash protocol trade …`)\n * and EOA mode (`kash eoa trade …`) share this enum — `close` is the\n * \"sell my entire balance for outcome N\" sugar.\n */\nexport type TradeOpSide = 'buy' | 'sell' | 'close';\n\n/**\n * Slippage in basis points (0..10000 → 0%..100%).\n *\n * Strict integer shape: `parseInt('1e3', 10)` returns 1, which would\n * silently clip 10% slippage to 0.01% (catastrophic for any real\n * trade). The shape check rejects any non-bare-integer before the\n * range check runs.\n */\nexport function parseSlippageBps(raw: string): number {\n if (!UNSIGNED_INT_REGEX.test(raw)) {\n throw new CliValidationError(\n '--slippage-bps must be an integer between 0 and 10000.',\n `Got \"${raw}\". Pass digits only — \\`1e3\\` would silently parse as 1 (0.01%) instead of 1000 (10%).`,\n 'slippage-bps'\n );\n }\n const n = Number.parseInt(raw, 10);\n if (!Number.isFinite(n) || n < 0 || n > 10_000) {\n throw new CliValidationError(\n '--slippage-bps must be an integer between 0 and 10000.',\n `Got \"${raw}\". 50 = 0.5%, 100 = 1%, 10000 = 100%.`,\n 'slippage-bps'\n );\n }\n return n;\n}\n\n/**\n * Unix-seconds deadline as a bigint. Caps the value at\n * `Number.MAX_SAFE_INTEGER` to catch the common ms-vs-sec confusion\n * (a JS `Date.now()` value passed verbatim would overflow into the\n * year 50000+ AD, which the AMM treats as \"no deadline\" and is\n * indistinguishable from the user's intent).\n */\nexport function parseDeadlineSec(raw: string): bigint {\n let parsed: bigint;\n try {\n parsed = BigInt(raw);\n } catch {\n throw new CliValidationError(\n '--deadline-sec must be a unix timestamp in seconds.',\n `Got \"${raw}\".`,\n 'deadline-sec'\n );\n }\n if (parsed <= 0n) {\n throw new CliValidationError(\n '--deadline-sec must be positive.',\n `Got \"${raw}\".`,\n 'deadline-sec'\n );\n }\n // Sanity check: the largest value that fits in a JS safe integer is\n // ~9e15. Anything above that is almost certainly the user passing\n // milliseconds instead of seconds, and `Number(parsed)` would lose\n // precision in downstream code.\n if (parsed > BigInt(Number.MAX_SAFE_INTEGER)) {\n throw new CliValidationError(\n '--deadline-sec is impossibly far in the future.',\n `Got ${String(parsed)}. Did you pass milliseconds by mistake? Convert to seconds first.`,\n 'deadline-sec'\n );\n }\n return parsed;\n}\n\n/**\n * Validate that a string is a well-formed USDC decimal (whole or up\n * to 6 fractional digits). Used by call sites that need the\n * shape check but pass the raw string downstream rather than\n * converting to atomic units (e.g. `kash trade buy/sell` ships the\n * decimal verbatim to the public-API SDK, which handles atomic\n * conversion server-side).\n */\nexport function validateUsdcDecimalShape(decimal: string, name: string): void {\n if (!USDC_DECIMAL_REGEX.test(decimal)) {\n throw new CliValidationError(\n `--${name} must be a USDC decimal with up to 6 fractional digits.`,\n `Got \"${decimal}\". USDC accepts up to 6 fractional digits (e.g. \"10\", \"12.50\", \"0.000001\").`,\n name\n );\n }\n}\n\n/**\n * Generic partial-completion hash extractor. SA-mode and EOA-mode\n * trade runners catch SDK errors that may carry an already-landed\n * hash (`userOpHash` for SA, `transactionHash` for EOA) in the\n * cause's `context` field — we surface that hash so the operator\n * can resume rather than pay for a duplicate sign/submit cycle.\n *\n * **Discrimination matters here.** Multiple SDK error classes\n * populate `context.<hash>` with the same shape, so we narrow on\n * the SDK's own `code` enum first:\n *\n * - SA mode: `code === 'BUNDLER_RECEIPT_TIMEOUT'` (genuine partial\n * completion — submit succeeded, wait timed out). Other SA\n * errors like `KashSignerError` (`SIGNER_SIGN_FAILED`) ALSO\n * carry `context.userOpHash` but happen pre-submit, so reporting\n * them as partial completions would be actively misleading.\n * - EOA mode: `code === 'WAIT_RECEIPT_FAILED'` (post-submit wait\n * timeout). Other `KashChainError` variants like\n * `CHAIN_RPC_FAILED` carry no transactionHash and would fail\n * the `contextKey` lookup anyway, but the code-narrow catches\n * them earlier.\n *\n * The `cause` argument is `unknown` because it crosses the SDK ↔\n * CLI boundary; reads are defensive at every step.\n */\nexport function extractPartialHash(\n cause: unknown,\n options: { code: string; contextKey: 'userOpHash' | 'transactionHash' }\n): `0x${string}` | undefined {\n if (cause === null || typeof cause !== 'object') return undefined;\n const code = (cause as { code?: unknown }).code;\n if (code !== options.code) return undefined;\n const ctx = (cause as { context?: unknown }).context;\n if (ctx === null || typeof ctx !== 'object') return undefined;\n const hash = (ctx as Record<string, unknown>)[options.contextKey];\n return typeof hash === 'string' && HEX_HASH_REGEX.test(hash)\n ? (hash as `0x${string}`)\n : undefined;\n}\n\n/**\n * Convert a USDC decimal string (`\"10\"`, `\"12.50\"`, `\"0.000001\"`)\n * to the 6-decimal atomic representation the AMM expects.\n *\n * Rejects strings with more than 6 fractional digits — silently\n * truncating could lose precision the user expected to preserve.\n */\nexport function decimalToAtomicUsdc(decimal: string, name: string): bigint {\n validateUsdcDecimalShape(decimal, name);\n const [whole, frac = ''] = decimal.split('.');\n const fracPadded = frac.padEnd(6, '0');\n return BigInt(`${whole}${fracPadded}`);\n}\n\n/**\n * Convert a token decimal string (`\"1.5\"`, `\"0.0001\"`) to WAD-18\n * atomic units. Outcome tokens use 18-decimal precision throughout\n * the protocol.\n */\nexport function decimalToAtomicWad(decimal: string, name: string): bigint {\n if (!/^\\d+(\\.\\d{1,18})?$/.test(decimal)) {\n throw new CliValidationError(\n `--${name} must be a token decimal with up to 18 fractional digits.`,\n `Got \"${decimal}\". Outcome tokens use WAD-18 precision.`,\n name\n );\n }\n const [whole, frac = ''] = decimal.split('.');\n const fracPadded = frac.padEnd(18, '0');\n return BigInt(`${whole}${fracPadded}`);\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
log
|
|
4
|
+
} from "./chunk-VIADBYFY.js";
|
|
5
|
+
import {
|
|
6
|
+
CliError,
|
|
7
|
+
EXIT_CODES
|
|
8
|
+
} from "./chunk-UZNSYATZ.js";
|
|
9
|
+
|
|
10
|
+
// src/utils/custom-chain.ts
|
|
11
|
+
async function resolveCliCustomChain(opts) {
|
|
12
|
+
const { customChain, chainId, rpc } = opts;
|
|
13
|
+
if (customChain.name === void 0) {
|
|
14
|
+
throw missingCustomChainField(
|
|
15
|
+
"customChain.name",
|
|
16
|
+
'`kash config set customChain.name "Anvil local"` (or whatever label you want surfaced on client.addresses.name)'
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
if (customChain.factoryAddress === void 0) {
|
|
20
|
+
throw missingCustomChainField(
|
|
21
|
+
"customChain.factoryAddress",
|
|
22
|
+
"`kash config set customChain.factoryAddress 0x\u2026` (the deployed Kash factory address on this chain)"
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
if (customChain.usdcAddress === void 0) {
|
|
26
|
+
throw missingCustomChainField(
|
|
27
|
+
"customChain.usdcAddress",
|
|
28
|
+
"`kash config set customChain.usdcAddress 0x\u2026` (the deployed USDC token address on this chain)"
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
let smartAccount;
|
|
32
|
+
if (customChain.smartAccount !== void 0) {
|
|
33
|
+
const sa = customChain.smartAccount;
|
|
34
|
+
if (sa.factoryAddress !== void 0 || sa.implementationAddress !== void 0 || sa.entryPointAddress !== void 0) {
|
|
35
|
+
if (sa.factoryAddress === void 0) {
|
|
36
|
+
throw missingCustomChainField(
|
|
37
|
+
"customChain.smartAccount.factoryAddress",
|
|
38
|
+
"`kash config set customChain.smartAccount.factoryAddress 0x\u2026`"
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
if (sa.implementationAddress === void 0) {
|
|
42
|
+
throw missingCustomChainField(
|
|
43
|
+
"customChain.smartAccount.implementationAddress",
|
|
44
|
+
"`kash config set customChain.smartAccount.implementationAddress 0x\u2026`"
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
if (sa.entryPointAddress === void 0) {
|
|
48
|
+
throw missingCustomChainField(
|
|
49
|
+
"customChain.smartAccount.entryPointAddress",
|
|
50
|
+
"`kash config set customChain.smartAccount.entryPointAddress 0x\u2026`"
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
smartAccount = {
|
|
54
|
+
factoryAddress: sa.factoryAddress,
|
|
55
|
+
implementationAddress: sa.implementationAddress,
|
|
56
|
+
entryPointAddress: sa.entryPointAddress
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const { defineChain } = await import("viem");
|
|
61
|
+
return {
|
|
62
|
+
name: customChain.name,
|
|
63
|
+
viemChain: defineChain({
|
|
64
|
+
id: chainId,
|
|
65
|
+
name: customChain.name,
|
|
66
|
+
nativeCurrency: { name: "Ether", symbol: "ETH", decimals: 18 },
|
|
67
|
+
rpcUrls: { default: { http: [rpc] } }
|
|
68
|
+
}),
|
|
69
|
+
addresses: {
|
|
70
|
+
factory: customChain.factoryAddress,
|
|
71
|
+
usdc: customChain.usdcAddress,
|
|
72
|
+
...customChain.oracleAddress === void 0 ? {} : { oracle: customChain.oracleAddress },
|
|
73
|
+
...customChain.vaultAddress === void 0 ? {} : { vault: customChain.vaultAddress },
|
|
74
|
+
...customChain.tokens1155Address === void 0 ? {} : { tokens1155: customChain.tokens1155Address },
|
|
75
|
+
...customChain.paramRegistryAddress === void 0 ? {} : { paramRegistry: customChain.paramRegistryAddress }
|
|
76
|
+
},
|
|
77
|
+
...smartAccount === void 0 ? {} : { smartAccount }
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function missingCustomChainField(field, hint) {
|
|
81
|
+
return new CliError(`Custom-chain config missing: ${field}.`, {
|
|
82
|
+
code: "DIRECT_CONFIG_MISSING",
|
|
83
|
+
exitCode: EXIT_CODES.GENERIC,
|
|
84
|
+
suggestion: `Set ${field} via ${hint}.`,
|
|
85
|
+
actions: [
|
|
86
|
+
{
|
|
87
|
+
type: "check_input",
|
|
88
|
+
field,
|
|
89
|
+
description: hint
|
|
90
|
+
}
|
|
91
|
+
]
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// src/utils/signer-key.ts
|
|
96
|
+
import { readFile, stat } from "fs/promises";
|
|
97
|
+
var PRIVATE_KEY_REGEX = /^0x[0-9a-fA-F]{64}$/;
|
|
98
|
+
async function loadRawPrivateKey(ref) {
|
|
99
|
+
if (!ref) {
|
|
100
|
+
throw new CliError("signerKeyRef is required.", {
|
|
101
|
+
code: "SIGNER_FAILED",
|
|
102
|
+
suggestion: "`kash config set signerKeyRef file:<path>` or `env:<NAME>` (CLI never persists raw keys)."
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
const [scheme, ...rest] = ref.split(":");
|
|
106
|
+
const target = rest.join(":");
|
|
107
|
+
let rawKey;
|
|
108
|
+
if (scheme === "file") {
|
|
109
|
+
if (target === "") {
|
|
110
|
+
throw new CliError("signerKeyRef: file path is empty.", {
|
|
111
|
+
code: "SIGNER_FAILED",
|
|
112
|
+
suggestion: "Use `signerKeyRef = file:<absolute-path>` with a path to the private key."
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
try {
|
|
116
|
+
rawKey = (await readFile(target, "utf8")).trim();
|
|
117
|
+
} catch (cause) {
|
|
118
|
+
throw new CliError(`signerKeyRef: failed to read ${target}.`, {
|
|
119
|
+
code: "SIGNER_FAILED",
|
|
120
|
+
suggestion: "Verify the file exists, is readable, and contains a 0x-prefixed hex key.",
|
|
121
|
+
cause
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
await warnIfWorldReadable(target);
|
|
125
|
+
} else if (scheme === "env") {
|
|
126
|
+
if (target === "") {
|
|
127
|
+
throw new CliError("signerKeyRef: env variable name is empty.", {
|
|
128
|
+
code: "SIGNER_FAILED",
|
|
129
|
+
suggestion: "Use `signerKeyRef = env:<NAME>` referencing an environment variable."
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
const fromEnv = process.env[target];
|
|
133
|
+
if (!fromEnv) {
|
|
134
|
+
throw new CliError(`signerKeyRef: environment variable ${target} is not set or empty.`, {
|
|
135
|
+
code: "SIGNER_FAILED",
|
|
136
|
+
suggestion: `Set ${target} to a 0x-prefixed hex private key, or rotate to a file:<path> reference.`
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
rawKey = fromEnv.trim();
|
|
140
|
+
} else {
|
|
141
|
+
throw new CliError(`signerKeyRef: unknown scheme "${scheme ?? ""}".`, {
|
|
142
|
+
code: "SIGNER_FAILED",
|
|
143
|
+
suggestion: "Supported schemes: `file:<path>`, `env:<NAME>`."
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
if (!PRIVATE_KEY_REGEX.test(rawKey)) {
|
|
147
|
+
throw new CliError("signerKeyRef target is not a 0x-prefixed 32-byte hex private key.", {
|
|
148
|
+
code: "SIGNER_FAILED",
|
|
149
|
+
suggestion: "The key must be exactly 0x followed by 64 hex characters (32 bytes)."
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
return rawKey;
|
|
153
|
+
}
|
|
154
|
+
async function warnIfWorldReadable(path) {
|
|
155
|
+
if (process.platform === "win32") return;
|
|
156
|
+
let mode;
|
|
157
|
+
try {
|
|
158
|
+
const info = await stat(path);
|
|
159
|
+
mode = info.mode;
|
|
160
|
+
} catch {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
if ((mode & 63) !== 0) {
|
|
164
|
+
log.warn(
|
|
165
|
+
`signerKeyRef file mode is 0${(mode & 511).toString(8)} (group/other readable). Run \`chmod 600 ${path}\` to restrict access. (warning only \u2014 load succeeded.)`
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export {
|
|
171
|
+
resolveCliCustomChain,
|
|
172
|
+
loadRawPrivateKey
|
|
173
|
+
};
|
|
174
|
+
//# sourceMappingURL=chunk-YJX3JJ4M.js.map
|