@kashdao/cli 0.1.0 → 0.1.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 (80) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +13 -14
  3. package/dist/{account-AVFLEM5D.js → account-CVJZ3HVT.js} +9 -9
  4. package/dist/{auth-GUJCVKTD.js → auth-V5WVZBCO.js} +9 -9
  5. package/dist/auth-V5WVZBCO.js.map +1 -0
  6. package/dist/{chunk-LBIRQHX5.js → chunk-A3IH5HUV.js} +3 -3
  7. package/dist/{chunk-YHCG2SUC.js → chunk-BVFDUI73.js} +2 -2
  8. package/dist/{chunk-MIXOZU2S.js → chunk-KADB3OKE.js} +2 -2
  9. package/dist/chunk-KAM6KOFD.js +9 -0
  10. package/dist/{chunk-BN2CUM42.js.map → chunk-KAM6KOFD.js.map} +1 -1
  11. package/dist/{chunk-YJX3JJ4M.js → chunk-L4AFV2HK.js} +3 -3
  12. package/dist/{chunk-VIADBYFY.js → chunk-MQUJG224.js} +2 -2
  13. package/dist/{chunk-KMBMQIZ7.js → chunk-N26VGVGB.js} +3 -3
  14. package/dist/{chunk-KMBMQIZ7.js.map → chunk-N26VGVGB.js.map} +1 -1
  15. package/dist/{chunk-QJMF73M5.js → chunk-QALDZHTX.js} +5 -5
  16. package/dist/{chunk-BRK7KJ4O.js → chunk-R4NGUZKN.js} +2 -2
  17. package/dist/{chunk-UZNSYATZ.js → chunk-X2VM6VKM.js} +7 -7
  18. package/dist/chunk-X2VM6VKM.js.map +1 -0
  19. package/dist/client-75FVHGOH.js +14 -0
  20. package/dist/{completion-ZZGX5BQC.js → completion-PK74S3EZ.js} +4 -4
  21. package/dist/{config-XJL5TSYK.js → config-T5U6E6KU.js} +8 -8
  22. package/dist/{config-store-3ZSYGXMQ.js → config-store-UTFDUCKW.js} +4 -4
  23. package/dist/{docs-MDKKSJDC.js → docs-VA7CJ2ZF.js} +5 -5
  24. package/dist/{eoa-IQ72EIHR.js → eoa-RL3NLN3H.js} +9 -9
  25. package/dist/{errors-WMZIEGQI.js → errors-2NNXRNES.js} +2 -2
  26. package/dist/{explain-H4EH3KH3.js → explain-3SPMWDYX.js} +7 -7
  27. package/dist/{explain-H4EH3KH3.js.map → explain-3SPMWDYX.js.map} +1 -1
  28. package/dist/{global-options-XOLJUPTT.js → global-options-WFQ6CEFK.js} +4 -4
  29. package/dist/{health-VZEIII74.js → health-2KD6XUTJ.js} +10 -10
  30. package/dist/health-2KD6XUTJ.js.map +1 -0
  31. package/dist/index.js +27 -27
  32. package/dist/{markets-C37JZDPE.js → markets-H6EK2XDE.js} +10 -10
  33. package/dist/{output-VCBZ3FM7.js → output-FGTXXZEQ.js} +4 -4
  34. package/dist/{portfolio-2AEPIJIG.js → portfolio-R63D5QB2.js} +10 -10
  35. package/dist/{protocol-XEQXF2GW.js → protocol-ZB6R25IM.js} +9 -9
  36. package/dist/{quote-I4DVJ7ZB.js → quote-OF6BTAPQ.js} +10 -10
  37. package/dist/{schema-PIFQ65TS.js → schema-3HQN4RFL.js} +6 -6
  38. package/dist/{setup-USZ6IODD.js → setup-IIPQXLPL.js} +12 -12
  39. package/dist/setup-IIPQXLPL.js.map +1 -0
  40. package/dist/{trace-IZBYTUFO.js → trace-WMO3KDHS.js} +10 -10
  41. package/dist/{trade-IIZSEXEI.js → trade-YBCI6XD2.js} +10 -10
  42. package/dist/{version-JDK3PEP5.js → version-WB2ACHMU.js} +7 -7
  43. package/dist/{version-check-TDCION37.js → version-check-PRAVPFC6.js} +4 -4
  44. package/dist/{webhooks-PTVRKICZ.js → webhooks-DVS55O4T.js} +10 -10
  45. package/dist/{with-retry-4FIZG3A7.js → with-retry-2MD2CNK2.js} +5 -5
  46. package/package.json +3 -3
  47. package/dist/auth-GUJCVKTD.js.map +0 -1
  48. package/dist/chunk-BN2CUM42.js +0 -9
  49. package/dist/chunk-UZNSYATZ.js.map +0 -1
  50. package/dist/client-IOM55ZCS.js +0 -14
  51. package/dist/health-VZEIII74.js.map +0 -1
  52. package/dist/setup-USZ6IODD.js.map +0 -1
  53. /package/dist/{account-AVFLEM5D.js.map → account-CVJZ3HVT.js.map} +0 -0
  54. /package/dist/{chunk-LBIRQHX5.js.map → chunk-A3IH5HUV.js.map} +0 -0
  55. /package/dist/{chunk-YHCG2SUC.js.map → chunk-BVFDUI73.js.map} +0 -0
  56. /package/dist/{chunk-MIXOZU2S.js.map → chunk-KADB3OKE.js.map} +0 -0
  57. /package/dist/{chunk-YJX3JJ4M.js.map → chunk-L4AFV2HK.js.map} +0 -0
  58. /package/dist/{chunk-VIADBYFY.js.map → chunk-MQUJG224.js.map} +0 -0
  59. /package/dist/{chunk-QJMF73M5.js.map → chunk-QALDZHTX.js.map} +0 -0
  60. /package/dist/{chunk-BRK7KJ4O.js.map → chunk-R4NGUZKN.js.map} +0 -0
  61. /package/dist/{client-IOM55ZCS.js.map → client-75FVHGOH.js.map} +0 -0
  62. /package/dist/{completion-ZZGX5BQC.js.map → completion-PK74S3EZ.js.map} +0 -0
  63. /package/dist/{config-XJL5TSYK.js.map → config-T5U6E6KU.js.map} +0 -0
  64. /package/dist/{config-store-3ZSYGXMQ.js.map → config-store-UTFDUCKW.js.map} +0 -0
  65. /package/dist/{docs-MDKKSJDC.js.map → docs-VA7CJ2ZF.js.map} +0 -0
  66. /package/dist/{eoa-IQ72EIHR.js.map → eoa-RL3NLN3H.js.map} +0 -0
  67. /package/dist/{errors-WMZIEGQI.js.map → errors-2NNXRNES.js.map} +0 -0
  68. /package/dist/{global-options-XOLJUPTT.js.map → global-options-WFQ6CEFK.js.map} +0 -0
  69. /package/dist/{markets-C37JZDPE.js.map → markets-H6EK2XDE.js.map} +0 -0
  70. /package/dist/{output-VCBZ3FM7.js.map → output-FGTXXZEQ.js.map} +0 -0
  71. /package/dist/{portfolio-2AEPIJIG.js.map → portfolio-R63D5QB2.js.map} +0 -0
  72. /package/dist/{protocol-XEQXF2GW.js.map → protocol-ZB6R25IM.js.map} +0 -0
  73. /package/dist/{quote-I4DVJ7ZB.js.map → quote-OF6BTAPQ.js.map} +0 -0
  74. /package/dist/{schema-PIFQ65TS.js.map → schema-3HQN4RFL.js.map} +0 -0
  75. /package/dist/{trace-IZBYTUFO.js.map → trace-WMO3KDHS.js.map} +0 -0
  76. /package/dist/{trade-IIZSEXEI.js.map → trade-YBCI6XD2.js.map} +0 -0
  77. /package/dist/{version-JDK3PEP5.js.map → version-WB2ACHMU.js.map} +0 -0
  78. /package/dist/{version-check-TDCION37.js.map → version-check-PRAVPFC6.js.map} +0 -0
  79. /package/dist/{webhooks-PTVRKICZ.js.map → webhooks-DVS55O4T.js.map} +0 -0
  80. /package/dist/{with-retry-4FIZG3A7.js.map → with-retry-2MD2CNK2.js.map} +0 -0
package/CHANGELOG.md CHANGED
@@ -17,6 +17,18 @@ the test, which surfaces in this changelog.
17
17
 
18
18
  ## [Unreleased]
19
19
 
20
+ ## [0.1.1] — 2026-06-18
21
+
22
+ ### Changed
23
+
24
+ - **Mainnet GA.** The production API (`api.kash.bot`) is live and API
25
+ keys are issued self-service under **Settings → API Keys** in the Kash
26
+ app. Onboarding text, `kash setup`, error suggestions
27
+ (`AUTH_REQUIRED`, `INSUFFICIENT_SCOPE`), `kash health`, and the README
28
+ no longer reference the staging-only release or email-based key
29
+ requests. No behaviour change: a `kash_live_*` key already auto-routes
30
+ to production and `kash_test_*` to staging.
31
+
20
32
  ## [0.1.0] — 2026-05-20
21
33
 
22
34
  Initial public release.
package/README.md CHANGED
@@ -63,12 +63,11 @@ kash trade buy <market-id> --outcome 0 --amount 10 --wait
63
63
 
64
64
  ---
65
65
 
66
- > 🧪 **Staging release.** Production endpoints (`api.kash.bot`) are
67
- > not yet live. Today only `kash_test_*` keys work — the CLI
68
- > auto-routes them to staging (`api-staging.kash.bot`). To request a
69
- > staging key, email [`engineering@kash.bot`](mailto:engineering@kash.bot)
70
- > with your intended use case. Self-service key issuance, production
71
- > endpoints, and the Homebrew tap all land with the production launch.
66
+ > 🚀 **Live on mainnet.** The production API (`api.kash.bot`) is live.
67
+ > Create an API key under **Settings → API Keys** in the
68
+ > [Kash app](https://app.kash.bot): a `kash_live_*` key auto-routes to
69
+ > production (Base mainnet), a `kash_test_*` key auto-routes to staging
70
+ > (`api-staging.kash.bot`, Base Sepolia) for dry-runs.
72
71
 
73
72
  ## Install
74
73
 
@@ -89,7 +88,7 @@ npx -y @kashdao/cli@latest --version
89
88
  npx -y @kashdao/cli@latest markets list --json
90
89
  ```
91
90
 
92
- A `kashdao/tap` Homebrew tap is planned for the production launch.
91
+ A `kashdao/tap` Homebrew tap is planned. Until it lands, use one of the installers above.
93
92
 
94
93
  The package installs a `kash` binary. (The internal admin tooling that previously
95
94
  shipped under the same name is now `kash-admin`.)
@@ -104,8 +103,8 @@ and `--dry-run` if you want to inspect the resolved command before running it.
104
103
  ## Quickstart
105
104
 
106
105
  ```sh
107
- # 1. Configure an API key (request a `kash_test_*` staging key by emailing engineering@kash.bot)
108
- kash auth set-key kash_test_…
106
+ # 1. Configure an API key (create one under Settings → API Keys at https://app.kash.bot)
107
+ kash auth set-key kash_live_…
109
108
 
110
109
  # 2. Browse markets
111
110
  kash markets list --status ACTIVE
@@ -120,9 +119,9 @@ kash portfolio positions
120
119
 
121
120
  ## Authentication
122
121
 
123
- Request a `kash_test_*` staging key by emailing
124
- [`engineering@kash.bot`](mailto:engineering@kash.bot) with your
125
- intended use case, then store it locally with one of:
122
+ Create an API key under **Settings → API Keys** in the
123
+ [Kash app](https://app.kash.bot) — `kash_live_*` for Base mainnet or
124
+ `kash_test_*` for Base Sepolia — then store it locally with one of:
126
125
 
127
126
  ```sh
128
127
  # Persisted in ~/.kash/config.json (mode 0600)
@@ -743,8 +742,8 @@ without warning. Anything that does will:
743
742
 
744
743
  ### `[AUTH_REQUIRED] No API key configured.`
745
744
 
746
- You haven't set an API key. Run `kash auth set-key kash_test_…`
747
- (request a staging key by emailing `engineering@kash.bot`) or set
745
+ You haven't set an API key. Run `kash auth set-key kash_live_…`
746
+ (create a key under Settings → API Keys at https://app.kash.bot) or set
748
747
  `KASH_API_KEY` in your environment. Every authenticated command needs
749
748
  a key — only `kash --version`, `kash --help`, and `kash explain <code>`
750
749
  work fully offline.
@@ -1,22 +1,22 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  buildClient
4
- } from "./chunk-QJMF73M5.js";
5
- import "./chunk-KMBMQIZ7.js";
6
- import "./chunk-YHCG2SUC.js";
7
- import "./chunk-BN2CUM42.js";
4
+ } from "./chunk-QALDZHTX.js";
5
+ import "./chunk-N26VGVGB.js";
6
+ import "./chunk-BVFDUI73.js";
7
+ import "./chunk-KAM6KOFD.js";
8
8
  import {
9
9
  readGlobals
10
- } from "./chunk-LBIRQHX5.js";
10
+ } from "./chunk-A3IH5HUV.js";
11
11
  import {
12
12
  print,
13
13
  printJson,
14
14
  style
15
- } from "./chunk-VIADBYFY.js";
16
- import "./chunk-MIXOZU2S.js";
15
+ } from "./chunk-MQUJG224.js";
16
+ import "./chunk-KADB3OKE.js";
17
17
  import {
18
18
  toCliError
19
- } from "./chunk-UZNSYATZ.js";
19
+ } from "./chunk-X2VM6VKM.js";
20
20
 
21
21
  // src/commands/account/index.ts
22
22
  import { Command as Command2 } from "commander";
@@ -87,4 +87,4 @@ var accountCommand = new Command2("account").description("Read-only account surf
87
87
  export {
88
88
  accountCommand
89
89
  };
90
- //# sourceMappingURL=account-AVFLEM5D.js.map
90
+ //# sourceMappingURL=account-CVJZ3HVT.js.map
@@ -1,28 +1,28 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  redact
4
- } from "./chunk-BRK7KJ4O.js";
4
+ } from "./chunk-R4NGUZKN.js";
5
5
  import {
6
6
  clearConfigField,
7
7
  readConfig,
8
8
  setCurrentProfile,
9
9
  updateConfig
10
- } from "./chunk-KMBMQIZ7.js";
11
- import "./chunk-YHCG2SUC.js";
10
+ } from "./chunk-N26VGVGB.js";
11
+ import "./chunk-BVFDUI73.js";
12
12
  import {
13
13
  readGlobals
14
- } from "./chunk-LBIRQHX5.js";
14
+ } from "./chunk-A3IH5HUV.js";
15
15
  import {
16
16
  log,
17
17
  print,
18
18
  printJson,
19
19
  style
20
- } from "./chunk-VIADBYFY.js";
21
- import "./chunk-MIXOZU2S.js";
20
+ } from "./chunk-MQUJG224.js";
21
+ import "./chunk-KADB3OKE.js";
22
22
  import {
23
23
  CliValidationError,
24
24
  toCliError
25
- } from "./chunk-UZNSYATZ.js";
25
+ } from "./chunk-X2VM6VKM.js";
26
26
 
27
27
  // src/commands/auth/index.ts
28
28
  import { Command as Command4 } from "commander";
@@ -90,7 +90,7 @@ Examples:
90
90
  if (!key.startsWith("kash_")) {
91
91
  throw new CliValidationError(
92
92
  'API keys must start with "kash_".',
93
- "Request a `kash_test_*` staging key by emailing `engineering@kash.bot` with your intended use case. Self-service issuance and `kash_live_*` keys land with the production launch."
93
+ "Create a key under Settings \u2192 API Keys at https://app.kash.bot \u2014 `kash_live_*` for Base mainnet or `kash_test_*` for Base Sepolia."
94
94
  );
95
95
  }
96
96
  let result;
@@ -236,4 +236,4 @@ var authCommand = new Command4("auth").description("Manage local API credentials
236
236
  export {
237
237
  authCommand
238
238
  };
239
- //# sourceMappingURL=auth-GUJCVKTD.js.map
239
+ //# sourceMappingURL=auth-V5WVZBCO.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/auth/index.ts","../src/commands/auth/logout.ts","../src/commands/auth/set-key.ts","../src/commands/auth/status.ts"],"sourcesContent":["/**\n * `kash auth` — credential management.\n *\n * Users issue a key from the Kash dashboard and run `auth set-key`\n * (or set `KASH_API_KEY` in their environment). A future browser-based\n * login flow may be added; for now, key issuance lives on the dashboard.\n */\n\nimport { Command } from 'commander';\n\nimport { logoutCommand } from './logout.js';\nimport { setKeyCommand } from './set-key.js';\nimport { statusCommand } from './status.js';\n\nexport const authCommand = new Command('auth')\n .description('Manage local API credentials.')\n .addCommand(setKeyCommand)\n .addCommand(statusCommand)\n .addCommand(logoutCommand);\n","/**\n * `kash auth logout` — remove the stored API key.\n *\n * Only clears the `apiKey` field; the rest of the config (baseUrl,\n * chain id) survives so logging back in doesn't lose unrelated\n * preferences. If `KASH_API_KEY` is set in the environment, we warn\n * the user that env vars take precedence so the \"logout\" is partial.\n */\n\nimport { Command } from 'commander';\n\nimport { clearConfigField, readConfig } from '../../utils/config-store.js';\nimport { readGlobals } from '../../utils/global-options.js';\nimport { log, printJson } from '../../utils/output.js';\n\nexport const logoutCommand = new Command('logout')\n .description('Remove the stored API key from ~/.kash/config.json.')\n .addHelpText(\n 'after',\n `\nExamples:\n $ kash auth logout\n $ kash auth logout --profile staging\n`\n )\n .action(async (_opts, cmd: Command) => {\n const globals = readGlobals(cmd);\n const scope = {\n ...(globals.profile === undefined ? {} : { profile: globals.profile }),\n ...(globals.configPath === undefined ? {} : { configPath: globals.configPath }),\n };\n const before = await readConfig(scope);\n await clearConfigField('apiKey', scope);\n\n const envWillOverride = Boolean(process.env['KASH_API_KEY']);\n\n if (globals.json) {\n printJson({\n ok: true,\n profile: before.profile,\n cleared: Boolean(before.apiKey && before.sources.apiKey === 'file'),\n envOverride: envWillOverride,\n });\n return;\n }\n\n if (before.apiKey === undefined) {\n log.info(`No API key was stored for profile \"${before.profile}\".`);\n } else {\n log.success(`API key cleared from profile \"${before.profile}\".`);\n }\n if (envWillOverride) {\n log.warn('KASH_API_KEY is still set in your environment. Unset it to fully log out.');\n }\n });\n","/**\n * `kash auth set-key [key]` — store an API key in `~/.kash/config.json`.\n *\n * Three input paths, each leaves no trace of the key in shell history:\n *\n * 1. Positional `<key>` — convenient for one-off use, but shows up\n * in `~/.bash_history`. Kept for backward compat.\n * 2. `--from-stdin` — pipe a key from a secret-store (`pass kash`,\n * `1password read`, `aws secretsmanager`, …). The key is\n * `.trim()`-ed so trailing newlines from the source are ignored.\n * 3. Interactive prompt (no positional, no flag, TTY available) —\n * reads from stderr-bound readline so the prompt doesn't taint\n * stdout pipes. Single newline of input.\n *\n * Validates the prefix client-side (the SDK's config schema enforces\n * the same shape, but failing here gives a clearer error than the\n * generic config error chain). The persisted file is `0600`.\n */\n\nimport { Command } from 'commander';\n\nimport { CliValidationError, toCliError } from '../../errors.js';\nimport { setCurrentProfile, updateConfig } from '../../utils/config-store.js';\nimport { redact } from '../../utils/formatting.js';\nimport { readGlobals } from '../../utils/global-options.js';\nimport { log, printJson } from '../../utils/output.js';\n\ntype SetKeyOptions = {\n fromStdin?: boolean;\n activate?: boolean;\n};\n\nexport const setKeyCommand = new Command('set-key')\n .description('Store an API key in ~/.kash/config.json (mode 0600).')\n .argument('[key]', 'API key starting with \"kash_\" (omit to read from stdin or prompt)')\n .option('--from-stdin', 'read the key from stdin (preferred for secret-store integration)')\n .option(\n '--activate',\n \"also switch the active profile to the one being written (default: leave the active profile unchanged — `kash auth set-key --profile staging` updates 'staging' but doesn't make it active; pass --activate or run `kash config use staging` separately)\"\n )\n .addHelpText(\n 'after',\n `\nExamples:\n # Interactive prompt (no shell history footprint).\n $ kash auth set-key\n\n # Pipe from a secret store.\n $ pass show kash/api-key | kash auth set-key --from-stdin\n $ op read \"op://Private/kash/api-key\" | kash auth set-key --from-stdin\n\n # Positional (convenient but shows up in ~/.bash_history).\n $ kash auth set-key kash_live_abc...\n $ kash auth set-key kash_test_abc... --profile staging\n`\n )\n .action(async (positional: string | undefined, options: SetKeyOptions, cmd: Command) => {\n const globals = readGlobals(cmd);\n const key = await resolveKey(positional, options);\n\n if (!key.startsWith('kash_')) {\n throw new CliValidationError(\n 'API keys must start with \"kash_\".',\n 'Create a key under Settings → API Keys at https://app.kash.bot — `kash_live_*` for Base mainnet or `kash_test_*` for Base Sepolia.'\n );\n }\n let result;\n try {\n result = await updateConfig(\n { apiKey: key },\n {\n ...(globals.profile === undefined ? {} : { profile: globals.profile }),\n ...(globals.configPath === undefined ? {} : { configPath: globals.configPath }),\n }\n );\n // `--activate` flips the file's `currentProfile` so the next\n // command picks up this profile without needing\n // `kash config use <name>`. Mirrors the all-in-one wizard\n // behaviour of `kash setup`.\n if (options.activate === true) {\n await setCurrentProfile(\n result.profile,\n globals.configPath === undefined ? undefined : { configPath: globals.configPath }\n );\n }\n } catch (cause) {\n throw toCliError(cause);\n }\n\n if (globals.json) {\n // Surface the actually-written profile (resolved from --profile,\n // KASH_PROFILE, file's currentProfile, or \"default\") so the JSON\n // contract reports truth, not the unresolved flag value.\n printJson({\n ok: true,\n apiKey: redact(key),\n profile: result.profile,\n // Whether this run also flipped the file's currentProfile.\n // Agents driving multi-profile workflows can chain off this\n // to know if a follow-up `kash config use` is needed.\n activated: options.activate === true,\n });\n return;\n }\n log.success(`API key saved to profile \"${result.profile}\" (${redact(key)}).`);\n log.detail('Location', globals.configPath ?? '~/.kash/config.json (mode 0600)');\n if (options.activate === true) {\n log.success(`Active profile is now \"${result.profile}\".`);\n }\n });\n\n/**\n * Resolve the API key from the three supported sources. Order:\n * 1. Positional argument (legacy, less secure — still works).\n * 2. `--from-stdin` (read until EOF, trim, single key per stream).\n * 3. Interactive prompt (TTY only).\n *\n * **Mutual-exclusion guard.** Pre-fix, `kash auth set-key <key>\n * --from-stdin` silently used the positional and dropped the piped\n * secret. That's a real footgun: the operator sees \"API key saved\"\n * for the WRONG key (the one on argv, possibly a stale value from\n * shell history). We refuse to guess and require the operator to\n * pick one source.\n */\nasync function resolveKey(positional: string | undefined, options: SetKeyOptions): Promise<string> {\n if (positional !== undefined && positional !== '' && options.fromStdin === true) {\n throw new CliValidationError(\n 'Pass either the positional <key> OR --from-stdin, not both.',\n 'The positional key would silently win and the piped value would be dropped.'\n );\n }\n if (positional !== undefined && positional !== '') {\n return positional;\n }\n if (options.fromStdin === true) {\n return readFromStdin();\n }\n if (process.stdin.isTTY) {\n return promptInteractively();\n }\n // No positional, no --from-stdin, no TTY — caller's intent is\n // ambiguous. Surface a clear validation error rather than reading\n // stdin silently (which would surprise CI runs that pipe other\n // data into the command).\n throw new CliValidationError(\n 'No API key provided.',\n 'Pass the key positionally, use --from-stdin to read it from a pipe, or run interactively for a prompt.'\n );\n}\n\nasync function readFromStdin(): Promise<string> {\n // Use the shared BOM-aware reader. Notepad-saved files (and VSCode\n // with `files.encoding=utf8bom`) prepend U+FEFF; without the strip,\n // the leading three bytes leak into the API key and fail the\n // `kash_` prefix check.\n const { readStdinTrimmed } = await import('../../utils/stdin.js');\n return readStdinTrimmed();\n}\n\nasync function promptInteractively(): Promise<string> {\n // Use the masked-input prompt so the key never echoes to the\n // terminal (defends against shoulder-surfing, screen recordings,\n // and scroll-back capture). The previous `readline.question` path\n // echoed every keystroke which defeated the \"no shell history\"\n // promise of this command. Lazy-load `@inquirer/prompts` to keep\n // it off the cold path for non-interactive invocations.\n const { password } = await import('@inquirer/prompts');\n const answer = await password({\n message: 'Paste your API key (kash_live_… or kash_test_…):',\n mask: '*',\n });\n return answer.trim();\n}\n","/**\n * `kash auth status` — report the locally-stored credentials.\n *\n * Does NOT call the API. There is no `whoami` endpoint on the public\n * API today (the only auth-flavoured route is webhook-secret rotation,\n * which is a write). Reporting purely-local state keeps the command\n * cheap and side-effect-free; the moment the user issues a real call\n * (e.g. `kash markets list`) the SDK raises `KashAuthenticationError`\n * if the key is invalid.\n */\n\nimport { Command } from 'commander';\n\nimport { readConfig } from '../../utils/config-store.js';\nimport { redact } from '../../utils/formatting.js';\nimport { readGlobals } from '../../utils/global-options.js';\nimport { log, print, printJson, style } from '../../utils/output.js';\n\nexport const statusCommand = new Command('status')\n .description('Show locally-configured credentials. Does not call the API.')\n .addHelpText(\n 'after',\n `\nExamples:\n $ kash auth status\n $ kash auth status --profile prod\n $ kash auth status --json --quiet | jq -r '.apiKey'\n`\n )\n .action(async (_opts, cmd: Command) => {\n const globals = readGlobals(cmd);\n const config = await readConfig({\n ...(globals.profile === undefined ? {} : { profile: globals.profile }),\n ...(globals.configPath === undefined ? {} : { configPath: globals.configPath }),\n });\n\n if (globals.json) {\n printJson({\n // Pure local-state field. `true` means \"an API key is in\n // scope for this profile\" (file or env), NOT \"this key is\n // accepted by the server\" — `kash auth status` is offline by\n // design. Use `kash health --json --quiet | jq .ok` for a\n // server-side check.\n configured: Boolean(config.apiKey),\n // Backward-compat alias. Same value as `configured`. Kept\n // for downstream scripts that pin to the old field name —\n // will be removed in a major bump after the rename has\n // burned in.\n authenticated: Boolean(config.apiKey),\n apiKey: config.apiKey ? redact(config.apiKey) : null,\n profile: config.profile,\n baseUrl: config.baseUrl,\n defaultChainId: config.defaultChainId,\n // Direct-mode fields (`kash protocol …` / `kash eoa …`). Always\n // emitted (`null` when unset) so direct-mode operators can\n // introspect their own profile via JSON without falling back\n // to reading `~/.kash/config.json` directly. The signerKeyRef\n // is the reference shape (`file:<path>` / `env:<NAME>`),\n // never the raw private key — the CLI never persists keys.\n rpcUrl: config.rpcUrl ?? null,\n smartAccount: config.smartAccount ?? null,\n bundlerUrl: config.bundlerUrl ?? null,\n bundlerProvider: config.bundlerProvider ?? null,\n signerKeyRef: config.signerKeyRef ?? null,\n sources: config.sources,\n });\n return;\n }\n\n if (!config.apiKey) {\n log.warn(`No API key configured for profile \"${config.profile}\".`);\n log.detail(\n 'Hint',\n \"Run 'kash setup' for the wizard, or 'kash auth set-key' for the bare key. Or set KASH_API_KEY.\"\n );\n return;\n }\n\n print(`${style.success('✓')} API key configured (profile: ${config.profile})`);\n print(\n ` ${style.dim('Note ')} not verified against the server — run \\`kash health\\` to probe`\n );\n print(` ${style.dim('API key ')} ${redact(config.apiKey)} (${config.sources.apiKey})`);\n print(` ${style.dim('Profile ')} ${config.profile} (${config.sources.profile})`);\n print(` ${style.dim('Base URL ')} ${config.baseUrl} (${config.sources.baseUrl})`);\n print(\n ` ${style.dim('Chain id ')} ${String(config.defaultChainId)} (${config.sources.defaultChainId})`\n );\n });\n"],"mappings":"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","names":["Command","Command","Command","Command","Command","Command"]}
@@ -2,10 +2,10 @@
2
2
  import {
3
3
  parseFieldsList,
4
4
  parseFilter
5
- } from "./chunk-MIXOZU2S.js";
5
+ } from "./chunk-KADB3OKE.js";
6
6
  import {
7
7
  CliValidationError
8
- } from "./chunk-UZNSYATZ.js";
8
+ } from "./chunk-X2VM6VKM.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-LBIRQHX5.js.map
133
+ //# sourceMappingURL=chunk-A3IH5HUV.js.map
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  CliValidationError
4
- } from "./chunk-UZNSYATZ.js";
4
+ } from "./chunk-X2VM6VKM.js";
5
5
 
6
6
  // src/utils/trade-input.ts
7
7
  var HEX_ADDRESS_REGEX = /^0x[0-9a-fA-F]{40}$/;
@@ -156,4 +156,4 @@ export {
156
156
  decimalToAtomicUsdc,
157
157
  decimalToAtomicWad
158
158
  };
159
- //# sourceMappingURL=chunk-YHCG2SUC.js.map
159
+ //# sourceMappingURL=chunk-BVFDUI73.js.map
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  CliValidationError
4
- } from "./chunk-UZNSYATZ.js";
4
+ } from "./chunk-X2VM6VKM.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-MIXOZU2S.js.map
366
+ //# sourceMappingURL=chunk-KADB3OKE.js.map
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/version.ts
4
+ var CLI_VERSION = "0.1.1";
5
+
6
+ export {
7
+ CLI_VERSION
8
+ };
9
+ //# sourceMappingURL=chunk-KAM6KOFD.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/version.ts"],"sourcesContent":["/**\n * Package version stamp.\n *\n * Hardcoded rather than imported from `package.json` because:\n *\n * 1. JSON imports vary across runtimes; the bundled CLI must work\n * under Node 22+ regardless of how the consumer's tsconfig is\n * shaped.\n * 2. tsup's JSON-bundling behaviour is bundler-version-specific and\n * we'd rather not depend on it.\n * 3. A simple constant is auditable: `git grep CLI_VERSION` finds\n * every reference instantly.\n *\n * **Maintenance**: bumped in lockstep with `package.json#version` by\n * the changesets release flow. The unit test in\n * `tests/unit/version.test.ts` reads `package.json` and asserts the\n * two stay in sync, so a forgotten bump fails CI before the bad\n * release ships to npm.\n */\nexport const CLI_VERSION = '0.1.0';\n"],"mappings":";;;AAmBO,IAAM,cAAc;","names":[]}
1
+ {"version":3,"sources":["../src/version.ts"],"sourcesContent":["/**\n * Package version stamp.\n *\n * Hardcoded rather than imported from `package.json` because:\n *\n * 1. JSON imports vary across runtimes; the bundled CLI must work\n * under Node 22+ regardless of how the consumer's tsconfig is\n * shaped.\n * 2. tsup's JSON-bundling behaviour is bundler-version-specific and\n * we'd rather not depend on it.\n * 3. A simple constant is auditable: `git grep CLI_VERSION` finds\n * every reference instantly.\n *\n * **Maintenance**: bumped in lockstep with `package.json#version` by\n * the changesets release flow. The unit test in\n * `tests/unit/version.test.ts` reads `package.json` and asserts the\n * two stay in sync, so a forgotten bump fails CI before the bad\n * release ships to npm.\n */\nexport const CLI_VERSION = '0.1.1';\n"],"mappings":";;;AAmBO,IAAM,cAAc;","names":[]}
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  log
4
- } from "./chunk-VIADBYFY.js";
4
+ } from "./chunk-MQUJG224.js";
5
5
  import {
6
6
  CliError,
7
7
  EXIT_CODES
8
- } from "./chunk-UZNSYATZ.js";
8
+ } from "./chunk-X2VM6VKM.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-YJX3JJ4M.js.map
174
+ //# sourceMappingURL=chunk-L4AFV2HK.js.map
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  applyFilter,
4
4
  projectFields
5
- } from "./chunk-MIXOZU2S.js";
5
+ } from "./chunk-KADB3OKE.js";
6
6
 
7
7
  // src/utils/output.ts
8
8
  import chalk from "chalk";
@@ -91,4 +91,4 @@ export {
91
91
  isQuiet,
92
92
  writeNdjson
93
93
  };
94
- //# sourceMappingURL=chunk-VIADBYFY.js.map
94
+ //# sourceMappingURL=chunk-MQUJG224.js.map
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  HEX_ADDRESS_REGEX
4
- } from "./chunk-YHCG2SUC.js";
4
+ } from "./chunk-BVFDUI73.js";
5
5
  import {
6
6
  CliConfigurationError
7
- } from "./chunk-UZNSYATZ.js";
7
+ } from "./chunk-X2VM6VKM.js";
8
8
 
9
9
  // src/utils/config-store.ts
10
10
  import { existsSync } from "fs";
@@ -390,4 +390,4 @@ export {
390
390
  readWholeFile,
391
391
  writeWholeFile
392
392
  };
393
- //# sourceMappingURL=chunk-KMBMQIZ7.js.map
393
+ //# sourceMappingURL=chunk-N26VGVGB.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils/config-store.ts"],"sourcesContent":["/**\n * Persistent CLI configuration with multi-profile support.\n *\n * The on-disk shape (v1+):\n *\n * {\n * \"version\": 1,\n * \"currentProfile\": \"default\",\n * \"profiles\": {\n * \"default\": { \"apiKey\": \"kash_live_…\", \"baseUrl\": \"…\", \"defaultChainId\": 8453 },\n * \"test\": { \"apiKey\": \"kash_test_…\" }\n * }\n * }\n *\n * Flat-shape configs from earlier CLI versions are migrated transparently\n * on first read into a `default` profile. The on-disk file is rewritten\n * in the new shape only on the next write — readers don't mutate state.\n *\n * The file is created and re-written at mode `0600` on POSIX. The\n * directory is created with `0700`. chmod is best-effort — Windows and\n * some network filesystems silently ignore it.\n *\n * Resolution order (highest precedence first):\n *\n * 1. Environment variables: `KASH_API_KEY`, `KASH_BASE_URL`,\n * `KASH_CHAIN_ID`. Always win.\n * 2. The active profile's fields.\n * 3. Built-in defaults (api.kash.bot/v1, chain 8453).\n *\n * Active-profile resolution (highest precedence first):\n *\n * 1. Explicit `--profile <name>` flag (via `options.profile`).\n * 2. `KASH_PROFILE` env var.\n * 3. `currentProfile` field in the config file.\n * 4. `'default'`.\n *\n * Pinning env-var precedence makes CI runs predictable and lets a\n * human override a profile field without editing the file.\n */\n\nimport { existsSync } from 'node:fs';\nimport { chmod, mkdir, readFile, unlink, writeFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { dirname, join } from 'node:path';\n\nimport { z } from 'zod';\n\nimport { CliConfigurationError } from '../errors.js';\n\nimport { HEX_ADDRESS_REGEX } from './trade-input.js';\n\n/**\n * Return a shallow copy of `obj` without the named property. Cleaner\n * than the `const { [k]: _removed, ...rest } = obj` rest-spread idiom\n * because it avoids the unused-variable lint dance.\n */\nfunction omitKey<T extends Record<string, unknown>, K extends keyof T>(obj: T, key: K): Omit<T, K> {\n const result: Record<string, unknown> = {};\n for (const k of Object.keys(obj)) {\n if (k !== key) result[k] = obj[k];\n }\n return result as Omit<T, K>;\n}\n\n/** Filesystem layout for the config — exposed for tests to override `home`. */\nexport type ConfigPaths = {\n readonly home: string;\n readonly dir: string;\n readonly file: string;\n};\n\nexport function resolveConfigPaths(home: string = homedir()): ConfigPaths {\n const dir = join(home, '.kash');\n return { home, dir, file: join(dir, 'config.json') };\n}\n\n/**\n * Resolve config paths with an optional explicit override path\n * (typically from the `--config` flag or `KASH_CONFIG` env var). The\n * explicit override sets the file directly and derives `dir`/`home`\n * from it for chmod-on-write.\n */\nexport function resolveConfigPathsForOverride(\n override: string | undefined,\n envOverride: string | undefined = process.env['KASH_CONFIG']\n): ConfigPaths {\n const explicit = override ?? envOverride;\n if (explicit) {\n const dir = dirname(explicit);\n return { home: dirname(dir), dir, file: explicit };\n }\n return resolveConfigPaths();\n}\n\nexport const DEFAULT_PROFILE = 'default';\n\n/**\n * Profile-name reserved words. Even though the regex below already\n * blocks the most-dangerous shapes (no `[`, no `<`, no whitespace),\n * the `__proto__` / `constructor` / `prototype` strings ARE allowed\n * by `[A-Za-z0-9_.-]+` — and using them as keys on a plain object\n * (`file.profiles`) walks the prototype chain on read. The denylist\n * makes the prototype-walk impossible at the schema layer.\n *\n * Defence-in-depth: the file format already uses `Object.create(null)`\n * boundaries downstream where possible, but pinning the validator\n * here makes the invariant grep-discoverable.\n */\nconst RESERVED_PROFILE_NAMES = new Set(['__proto__', 'constructor', 'prototype']);\n\n/** Profile name validator — keeps file structure deterministic. */\nconst profileNameSchema = z\n .string()\n .min(1, 'profile name cannot be empty')\n .max(64, 'profile name must be ≤ 64 characters')\n .regex(/^[A-Za-z0-9_.-]+$/, 'profile name allows letters, digits, underscore, dot, and dash only')\n .refine((name) => !RESERVED_PROFILE_NAMES.has(name), {\n message:\n 'profile name uses a reserved word (__proto__, constructor, prototype) — would walk the object prototype chain',\n });\n\n/**\n * Schema for a single profile. Every field is optional so the profile\n * can hold partial state — e.g. only override `baseUrl` while\n * inheriting the API key from env.\n */\n/**\n * Reference to a private key the CLI will load when constructing the\n * direct-mode signer. We never persist the raw key — only a reference\n * to where to read it from at invocation time:\n *\n * - `file:<path>` — read the key from a file (mode 0600 enforced\n * at read time, not write).\n * - `env:<name>` — read the key from an environment variable.\n *\n * This keeps `~/.kash/config.json` free of secret material; the\n * config file itself is only `0600`-protected for the API key, not\n * for arbitrary private keys that could fund-drain a smart account.\n *\n * Future extensions: `keystore:<path>`, `aws-kms:<key-id>`,\n * `gcp-kms:<resource>`, `ledger:<derivation-path>`.\n */\nconst signerKeyRefSchema = z\n .string()\n .regex(/^(file:|env:)\\S+$/, 'signerKeyRef must start with \"file:<path>\" or \"env:<NAME>\"');\n\n/** Bundler provider preset. */\nconst bundlerProviderSchema = z.enum(['flashbots', 'pimlico', 'alchemy', 'generic']);\n\nconst hexAddressSchema = z\n .string()\n .regex(HEX_ADDRESS_REGEX, 'must be a 0x-prefixed 40-char hex address');\n\n/**\n * Custom-chain config — bypasses the protocol-sdk's static chain\n * registry. Required for any chain Kash hasn't deployed canonical\n * contracts on (local Anvil, Hardhat, Tenderly forks, sidechains).\n *\n * The CLI derives the `viemChain` argument the SDK needs from the\n * profile's `defaultChainId` + `rpcUrl` + `customChain.name`; the\n * consumer never has to hand-construct a viem Chain. `addresses`\n * mirrors the SDK's `CustomChainAddresses`. `smartAccount` is required\n * only when the consumer is using SA mode (`kash protocol …`) on a\n * custom chain — EOA mode ignores it.\n */\n/**\n * Custom-chain schema. Every field is optional at the persistence\n * layer because `kash config set customChain.<leaf>` writes one leaf\n * at a time — requiring the full shape at write time would force the\n * user into a single mega-set call. Completeness (name +\n * factoryAddress + usdcAddress required, smartAccount triple all-or-\n * nothing) is enforced at use time in `resolveCliCustomChain`,\n * where the missing field has actionable error context (the SDK call\n * that needs it).\n */\nconst customChainSchema = z\n .object({\n /** Human-readable label, surfaced on `client.addresses.name`. */\n name: z.string().min(1, 'customChain.name must not be empty').optional(),\n factoryAddress: hexAddressSchema.optional(),\n usdcAddress: hexAddressSchema.optional(),\n oracleAddress: hexAddressSchema.optional(),\n vaultAddress: hexAddressSchema.optional(),\n tokens1155Address: hexAddressSchema.optional(),\n paramRegistryAddress: hexAddressSchema.optional(),\n /** Smart-account factory + EntryPoint config (SA mode only). */\n smartAccount: z\n .object({\n factoryAddress: hexAddressSchema.optional(),\n implementationAddress: hexAddressSchema.optional(),\n entryPointAddress: hexAddressSchema.optional(),\n })\n .strict()\n .optional(),\n })\n .strict();\n\nexport const cliConfigSchema = z\n .object({\n // ── Kash-orchestrated mode (API-backed) ─────────────────────────────\n apiKey: z\n .string()\n .startsWith('kash_', 'API keys start with \"kash_\"')\n .min(16, 'API key looks too short')\n .optional(),\n baseUrl: z.string().url('baseUrl must be a valid URL').optional(),\n defaultChainId: z.number().int().positive().optional(),\n\n // ── Direct mode (`kash protocol …`, on-chain) ───────────────\n /** RPC endpoint for the chain. Consumer-owned; the CLI never proxies. */\n rpcUrl: z.string().url('rpcUrl must be a valid URL').optional(),\n /** Smart account address (the ERC-4337 account whose funds are used). */\n smartAccount: z\n .string()\n .regex(HEX_ADDRESS_REGEX, 'smartAccount must be a 0x-prefixed 40-char hex address')\n .optional(),\n /** Bundler URL (overrides the protocol-sdk's Flashbots Protect default). */\n bundlerUrl: z.string().url('bundlerUrl must be a valid URL').optional(),\n /** Bundler provider preset (selects the right header dialect). */\n bundlerProvider: bundlerProviderSchema.optional(),\n /** Reference to the EOA private key that owns the smart account. */\n signerKeyRef: signerKeyRefSchema.optional(),\n /**\n * Custom-chain addresses for chains outside the static registry\n * (local Anvil, forks, sidechains). When present, the CLI's\n * direct-mode and EOA-mode commands use these addresses instead\n * of looking the chain up in the registry. Required for chainId\n * 31337 (Anvil); optional for Base mainnet/testnet (registry covers them).\n */\n customChain: customChainSchema.optional(),\n })\n .strict();\n\nexport type CliConfig = z.infer<typeof cliConfigSchema>;\n\n/**\n * Schema for the v1 multi-profile file shape.\n *\n * `currentProfile` is intentionally optional (no `.default()`) so the\n * source-attribution logic in `pickProfileName` can distinguish\n * \"user explicitly persisted `default` via `kash config use default`\"\n * (source: 'file') from \"we fell through to the built-in default\n * because the file didn't carry a `currentProfile` field\" (source:\n * 'default'). Both result in `'default'` as the active profile, but\n * the source attribution they report is different.\n */\nconst cliFileSchema = z\n .object({\n version: z.literal(1),\n currentProfile: profileNameSchema.optional(),\n profiles: z.record(profileNameSchema, cliConfigSchema).default({}),\n })\n .strict();\n\nexport type CliFile = z.infer<typeof cliFileSchema>;\n\n/**\n * Canonical API base URLs by environment. The CLI auto-routes based on\n * the API-key prefix: a `kash_test_*` key targets staging, a\n * `kash_live_*` key (or no key) targets production. An explicit\n * `baseUrl` config or `KASH_BASE_URL` env var always wins so consumers\n * can target a private mirror, a local mock, or a future region.\n *\n * Mirrors the `inferBaseUrlFromApiKey()` logic in `@kashdao/sdk`'s\n * `internal/config.ts` so the CLI and the SDK route a given key to the\n * same environment without the user having to configure two places.\n */\nexport const PRODUCTION_BASE_URL = 'https://api.kash.bot/v1' as const;\nexport const STAGING_BASE_URL = 'https://api-staging.kash.bot/v1' as const;\n\n/**\n * Derive the API base URL from an API key when neither config nor env\n * sets one explicitly. Returns `undefined` if the key shape isn't\n * recognised — the caller then falls back to {@link DEFAULTS.baseUrl}.\n */\nexport function inferBaseUrlFromApiKey(apiKey: string | undefined): string | undefined {\n if (!apiKey) return undefined;\n if (apiKey.startsWith('kash_test_')) return STAGING_BASE_URL;\n if (apiKey.startsWith('kash_live_')) return PRODUCTION_BASE_URL;\n return undefined;\n}\n\n/** Default values applied when a field is missing from both file and env. */\nexport const DEFAULTS = {\n baseUrl: PRODUCTION_BASE_URL,\n defaultChainId: 8453,\n} as const;\n\nexport type ResolvedConfig = {\n // ── Kash-orchestrated fields ──────────────────────────────────────────\n readonly apiKey: string | undefined;\n readonly baseUrl: string;\n readonly defaultChainId: number;\n // ── Direct-mode fields (`kash protocol …`) ────────────────────\n readonly rpcUrl: string | undefined;\n readonly smartAccount: string | undefined;\n readonly bundlerUrl: string | undefined;\n readonly bundlerProvider: 'flashbots' | 'pimlico' | 'alchemy' | 'generic' | undefined;\n readonly signerKeyRef: string | undefined;\n /**\n * Custom-chain config — present only when the profile explicitly sets\n * `customChain.*`. Bypasses the protocol-sdk's static chain registry\n * and is required for chains the registry doesn't cover (Anvil,\n * forks, sidechains).\n */\n readonly customChain: CliConfig['customChain'];\n // ── Meta ──────────────────────────────────────────────────────\n /** Active profile name. */\n readonly profile: string;\n /** Where each non-default value came from — useful for `kash config show`. */\n readonly sources: {\n readonly apiKey: 'env' | 'file' | 'unset';\n readonly baseUrl: 'env' | 'file' | 'inferred' | 'default';\n readonly defaultChainId: 'env' | 'file' | 'default';\n readonly profile: 'flag' | 'env' | 'file' | 'default';\n readonly rpcUrl: 'env' | 'file' | 'unset';\n readonly smartAccount: 'env' | 'file' | 'unset';\n readonly bundlerUrl: 'env' | 'file' | 'unset';\n readonly bundlerProvider: 'env' | 'file' | 'unset';\n readonly signerKeyRef: 'env' | 'file' | 'unset';\n readonly customChain: 'file' | 'unset';\n };\n};\n\nexport type ReadConfigOptions = {\n /** Override which profile to read; takes precedence over env + file. */\n readonly profile?: string;\n /** Override the config file path; takes precedence over `KASH_CONFIG`. */\n readonly configPath?: string;\n};\n\n/**\n * Read the config file and return the resolved active profile merged\n * with environment variables and defaults.\n */\nexport async function readConfig(opts: ReadConfigOptions = {}): Promise<ResolvedConfig> {\n const paths = resolveConfigPathsForOverride(opts.configPath);\n const file = await readFileConfig(paths);\n return resolveActive(file, opts.profile);\n}\n\nasync function readFileConfig(paths: ConfigPaths): Promise<CliFile> {\n if (!existsSync(paths.file)) return emptyFile();\n let raw: string;\n try {\n raw = await readFile(paths.file, 'utf8');\n } catch (cause) {\n throw new CliConfigurationError(\n `Failed to read config file at ${paths.file}: ${(cause as Error).message}`,\n \"Run 'kash config reset' to start fresh.\"\n );\n }\n return parseFileContents(raw, paths.file);\n}\n\nfunction parseFileContents(raw: string, file: string): CliFile {\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (cause) {\n throw new CliConfigurationError(\n `Config file at ${file} is not valid JSON: ${(cause as Error).message}`,\n \"Run 'kash config reset' to overwrite it with defaults.\"\n );\n }\n // Guard against valid-JSON-but-wrong-top-level (e.g. someone wrote\n // a string, a number, an array, or `null` to the file). Without this,\n // the v1 schema's \"Expected object, received string\" Zod error\n // bubbles up with no actionable hint.\n if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new CliConfigurationError(\n `Config file at ${file} must contain a JSON object at the top level (got ${describeJsonRoot(parsed)}).`,\n \"Run 'kash config reset' to overwrite it with defaults.\"\n );\n }\n const migrated = migrateLegacyShape(parsed);\n const result = cliFileSchema.safeParse(migrated);\n if (!result.success) {\n const first = result.error.issues[0];\n const path = first?.path.join('.') ?? '(root)';\n throw new CliConfigurationError(\n `Config file at ${file} is invalid (${path}): ${first?.message ?? 'validation failed'}`,\n \"Run 'kash config reset' to overwrite it with defaults.\"\n );\n }\n return result.data;\n}\n\n/** Describe a non-object JSON root for the user-facing error message. */\nfunction describeJsonRoot(value: unknown): string {\n if (value === null) return 'null';\n if (Array.isArray(value)) return 'array';\n return typeof value;\n}\n\n/**\n * If the file looks like the legacy flat shape ({ apiKey?, baseUrl?,\n * defaultChainId? } at the root), wrap it as the default profile of a\n * v1 file. Otherwise pass through.\n */\nfunction migrateLegacyShape(parsed: unknown): unknown {\n if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {\n return parsed;\n }\n const obj = parsed as Record<string, unknown>;\n if ('version' in obj || 'profiles' in obj) {\n return parsed; // already in v1 shape\n }\n // Legacy flat shape — wrap it as the default profile.\n const flat = cliConfigSchema.safeParse(obj);\n if (!flat.success) {\n return parsed; // let the v1 schema raise the structured error\n }\n return {\n version: 1,\n currentProfile: DEFAULT_PROFILE,\n profiles: { [DEFAULT_PROFILE]: flat.data },\n };\n}\n\nfunction emptyFile(): CliFile {\n return cliFileSchema.parse({ version: 1 });\n}\n\n/**\n * Compute the active profile name. Order: explicit flag > env >\n * file's `currentProfile` (when present) > built-in `'default'`.\n *\n * Crucially, when the file persists `currentProfile: \"default\"`\n * (e.g. after `kash config use default`), source is `'file'` — not\n * `'default'`. That keeps the JSON contract honest: agents debugging\n * \"why is my profile X?\" need to know it came from a write, not a\n * fallback.\n */\nfunction pickProfileName(\n file: CliFile,\n flagOverride: string | undefined\n): { name: string; source: 'flag' | 'env' | 'file' | 'default' } {\n if (flagOverride !== undefined) {\n validateProfileName(flagOverride, '--profile flag');\n return { name: flagOverride, source: 'flag' };\n }\n const env = process.env['KASH_PROFILE'];\n if (env !== undefined && env.length > 0) {\n validateProfileName(env, 'KASH_PROFILE environment variable');\n return { name: env, source: 'env' };\n }\n if (file.currentProfile !== undefined) {\n return { name: file.currentProfile, source: 'file' };\n }\n return { name: DEFAULT_PROFILE, source: 'default' };\n}\n\n/**\n * Wrap `profileNameSchema.parse` so a malformed value surfaces as a\n * typed `CliConfigurationError` with a `check_input`-friendly\n * suggestion, instead of a raw `ZodError` that the top-level\n * boundary maps to `UNEXPECTED`.\n */\nfunction validateProfileName(value: string, source: string): void {\n const result = profileNameSchema.safeParse(value);\n if (!result.success) {\n const issue = result.error.issues[0];\n throw new CliConfigurationError(\n `Profile name from ${source} is invalid: ${issue?.message ?? 'validation failed'}.`,\n 'Profile names accept letters, digits, underscore, dot, and dash; must be 1-64 characters.'\n );\n }\n}\n\nfunction resolveActive(file: CliFile, flagOverride: string | undefined): ResolvedConfig {\n const { name: profileName, source: profileSource } = pickProfileName(file, flagOverride);\n const profile = file.profiles[profileName];\n // It's not an error to ask for a profile that isn't in the file —\n // env-only setups (CI, agents) are normal. We surface this via the\n // `sources.apiKey === 'unset'` value if no env var fills the gap.\n //\n // BUT: when the missing profile was named via `KASH_PROFILE` or\n // `--profile`, an intentional env-only setup is the rare case and\n // a typo (e.g. `KASH_PROFILE=staing` vs `staging`) is the common\n // case. The operator otherwise sees an empty config + a confusing\n // `AUTH_REQUIRED` later. Nudge them on stderr (no JSON pollution,\n // no behaviour change). `KASH_QUIET=1` mutes the warning for CI.\n if (\n profile === undefined &&\n (profileSource === 'env' || profileSource === 'flag') &&\n Object.keys(file.profiles).length > 0 &&\n !isTruthyEnv(process.env['KASH_QUIET'])\n ) {\n const known = Object.keys(file.profiles).sort().join(', ');\n const sourceLabel = profileSource === 'env' ? 'KASH_PROFILE' : '--profile';\n process.stderr.write(\n `\\u26a0 Profile \"${profileName}\" (${sourceLabel}) is not in the config file. ` +\n `Known profiles: ${known}. ` +\n `Did you typo the name? (Set KASH_QUIET=1 to mute this warning.)\\n`\n );\n }\n return mergeWithEnv(profile ?? {}, profileName, profileSource);\n}\n\n/** Same truthy-env recognizer as `utils/global-options.ts:isTruthyEnv`. */\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\nfunction mergeWithEnv(\n profile: CliConfig,\n profileName: string,\n profileSource: 'flag' | 'env' | 'file' | 'default'\n): ResolvedConfig {\n const envApiKey = process.env['KASH_API_KEY'];\n const envBaseUrl = process.env['KASH_BASE_URL'];\n const envChainIdRaw = process.env['KASH_CHAIN_ID'];\n // Direct-mode env vars\n const envRpcUrl = process.env['KASH_RPC_URL'];\n const envSmartAccount = process.env['KASH_SMART_ACCOUNT'];\n const envBundlerUrl = process.env['KASH_BUNDLER_URL'];\n const envBundlerProviderRaw = process.env['KASH_BUNDLER_PROVIDER'];\n const envSignerKeyRef = process.env['KASH_SIGNER_KEY_REF'];\n\n let envChainId: number | undefined;\n if (envChainIdRaw !== undefined) {\n const n = Number.parseInt(envChainIdRaw, 10);\n if (Number.isNaN(n) || n <= 0) {\n throw new CliConfigurationError(\n `KASH_CHAIN_ID is not a positive integer: ${envChainIdRaw}`,\n 'Set KASH_CHAIN_ID to a chain id like 8453 or 84532, or unset it to use the default.'\n );\n }\n envChainId = n;\n }\n\n let envBundlerProvider: ResolvedConfig['bundlerProvider'];\n if (envBundlerProviderRaw !== undefined) {\n const allowed = ['flashbots', 'pimlico', 'alchemy', 'generic'] as const;\n if (!(allowed as readonly string[]).includes(envBundlerProviderRaw)) {\n throw new CliConfigurationError(\n `KASH_BUNDLER_PROVIDER must be one of ${allowed.join(', ')} (got \"${envBundlerProviderRaw}\").`,\n 'Unset the variable or set it to a supported preset.'\n );\n }\n envBundlerProvider = envBundlerProviderRaw as ResolvedConfig['bundlerProvider'];\n }\n\n const apiKey = envApiKey ?? profile.apiKey;\n // Resolution order for `baseUrl`:\n // 1. KASH_BASE_URL env var — always wins\n // 2. profile.baseUrl — explicit profile config\n // 3. inferred from apiKey prefix — kash_test_* → staging, kash_live_* → production\n // 4. DEFAULTS.baseUrl — production (final fallback)\n //\n // Step 3 mirrors `@kashdao/sdk`'s `inferBaseUrlFromApiKey()` so the\n // CLI and the SDK route the same key to the same environment without\n // requiring the user to configure two places. Without this, a user\n // with only a `kash_test_*` key would hit production (and a DNS error\n // pre-launch) until they remembered to also set `--base-url`.\n const baseUrl =\n envBaseUrl ?? profile.baseUrl ?? inferBaseUrlFromApiKey(apiKey) ?? DEFAULTS.baseUrl;\n const defaultChainId = envChainId ?? profile.defaultChainId ?? DEFAULTS.defaultChainId;\n const rpcUrl = envRpcUrl ?? profile.rpcUrl;\n const smartAccount = envSmartAccount ?? profile.smartAccount;\n const bundlerUrl = envBundlerUrl ?? profile.bundlerUrl;\n const bundlerProvider = envBundlerProvider ?? profile.bundlerProvider;\n const signerKeyRef = envSignerKeyRef ?? profile.signerKeyRef;\n // customChain has no env-var override — it's a structured object,\n // not a single string, and the right place to set it is `kash\n // config set customChain.<leaf>` so partial sets compose. CI use\n // cases that need a custom chain mount the config file directly\n // (KASH_CONFIG=...).\n const customChain = profile.customChain;\n\n return {\n apiKey,\n baseUrl,\n defaultChainId,\n rpcUrl,\n smartAccount,\n bundlerUrl,\n bundlerProvider,\n signerKeyRef,\n customChain,\n profile: profileName,\n sources: {\n apiKey: envApiKey ? 'env' : profile.apiKey ? 'file' : 'unset',\n baseUrl: envBaseUrl\n ? 'env'\n : profile.baseUrl\n ? 'file'\n : inferBaseUrlFromApiKey(apiKey)\n ? 'inferred'\n : 'default',\n defaultChainId:\n envChainId !== undefined\n ? 'env'\n : profile.defaultChainId !== undefined\n ? 'file'\n : 'default',\n profile: profileSource,\n rpcUrl: envRpcUrl ? 'env' : profile.rpcUrl ? 'file' : 'unset',\n smartAccount: envSmartAccount ? 'env' : profile.smartAccount ? 'file' : 'unset',\n bundlerUrl: envBundlerUrl ? 'env' : profile.bundlerUrl ? 'file' : 'unset',\n bundlerProvider: envBundlerProvider ? 'env' : profile.bundlerProvider ? 'file' : 'unset',\n signerKeyRef: envSignerKeyRef ? 'env' : profile.signerKeyRef ? 'file' : 'unset',\n customChain: profile.customChain ? 'file' : 'unset',\n },\n };\n}\n\nexport type WriteConfigOptions = {\n /** Profile to write to. Defaults to the current active profile. */\n readonly profile?: string;\n /** Override the config file path. */\n readonly configPath?: string;\n};\n\n/**\n * Result of {@link updateConfig} / {@link clearConfigField}. Carries\n * the resolved profile name so callers can render an accurate\n * \"wrote to profile X\" message instead of guessing — important for\n * the JSON contract that `kash auth set-key --json` ships, since\n * `--profile` may be unset and we want to report the actually-written\n * profile (which falls back to the file's `currentProfile`).\n */\nexport type UpdateConfigResult = {\n readonly profile: string;\n readonly stored: CliConfig;\n};\n\n/**\n * Mutate (and persist) a single field of the active (or named) profile.\n * Used by `auth set-key`, `auth logout`, `config set`. Writes the file\n * with `0600` permissions.\n */\nexport async function updateConfig(\n patch: Partial<CliConfig>,\n opts: WriteConfigOptions = {}\n): Promise<UpdateConfigResult> {\n const paths = resolveConfigPathsForOverride(opts.configPath);\n const file = await readFileConfig(paths);\n const profileName = opts.profile ?? file.currentProfile ?? DEFAULT_PROFILE;\n profileNameSchema.parse(profileName);\n const current = file.profiles[profileName] ?? {};\n const next = cliConfigSchema.parse({ ...current, ...patch });\n const updated: CliFile = {\n ...file,\n profiles: { ...file.profiles, [profileName]: next },\n };\n await writeFileConfig(paths, updated);\n return { profile: profileName, stored: next };\n}\n\n/** Wipe a single field from a profile (used by `auth logout`). */\nexport async function clearConfigField(\n field: keyof CliConfig,\n opts: WriteConfigOptions = {}\n): Promise<UpdateConfigResult> {\n const paths = resolveConfigPathsForOverride(opts.configPath);\n const file = await readFileConfig(paths);\n const profileName = opts.profile ?? file.currentProfile ?? DEFAULT_PROFILE;\n const current = file.profiles[profileName] ?? {};\n if (!(field in current)) return { profile: profileName, stored: current };\n const next = cliConfigSchema.parse(omitKey(current, field));\n const updated: CliFile = {\n ...file,\n profiles: { ...file.profiles, [profileName]: next },\n };\n await writeFileConfig(paths, updated);\n return { profile: profileName, stored: next };\n}\n\n/** List every profile name present in the config file. */\nexport async function listProfiles(\n opts: { configPath?: string } = {}\n): Promise<{ readonly current: string; readonly profiles: readonly string[] }> {\n const paths = resolveConfigPathsForOverride(opts.configPath);\n const file = await readFileConfig(paths);\n return {\n current: file.currentProfile ?? DEFAULT_PROFILE,\n profiles: Object.keys(file.profiles).sort(),\n };\n}\n\n/** Set the file's `currentProfile` field. Validates the name. */\nexport async function setCurrentProfile(\n name: string,\n opts: { configPath?: string } = {}\n): Promise<CliFile> {\n profileNameSchema.parse(name);\n const paths = resolveConfigPathsForOverride(opts.configPath);\n const file = await readFileConfig(paths);\n const updated: CliFile = { ...file, currentProfile: name };\n await writeFileConfig(paths, updated);\n return updated;\n}\n\n/** Remove a named profile. Refuses to remove the active one. */\nexport async function deleteProfile(\n name: string,\n opts: { configPath?: string } = {}\n): Promise<CliFile> {\n profileNameSchema.parse(name);\n const paths = resolveConfigPathsForOverride(opts.configPath);\n const file = await readFileConfig(paths);\n if (file.currentProfile === name) {\n throw new CliConfigurationError(\n `Cannot delete the active profile \"${name}\".`,\n 'Switch to another profile first with `kash config use <name>`.'\n );\n }\n if (!(name in file.profiles)) {\n return file;\n }\n const updated: CliFile = { ...file, profiles: omitKey(file.profiles, name) };\n await writeFileConfig(paths, updated);\n return updated;\n}\n\n/** Delete the entire config file. Used by `config reset`. */\nexport async function deleteConfig(opts: { configPath?: string } = {}): Promise<void> {\n const paths = resolveConfigPathsForOverride(opts.configPath);\n if (!existsSync(paths.file)) return;\n await unlink(paths.file);\n}\n\n/**\n * Return the full multi-profile file as-is. Used by `kash config\n * export` to dump every profile (vs `readConfig` which resolves a\n * single active profile). When the file doesn't exist, returns an\n * empty file shape so callers don't have to special-case \"no config\n * yet\".\n */\nexport async function readWholeFile(opts: { configPath?: string } = {}): Promise<CliFile> {\n const paths = resolveConfigPathsForOverride(opts.configPath);\n return await readFileConfig(paths);\n}\n\n/**\n * Replace the entire on-disk file with the supplied shape. Used by\n * `kash config import`. Validates against the `cliFileSchema` to\n * prevent garbage from landing on disk.\n *\n * Caller-side concerns (merge vs. overwrite, redaction policy, etc.)\n * are handled in the import command — this helper is pure persistence.\n */\nexport async function writeWholeFile(\n file: CliFile,\n opts: { configPath?: string } = {}\n): Promise<void> {\n const paths = resolveConfigPathsForOverride(opts.configPath);\n const validated = cliFileSchema.parse(file);\n await writeFileConfig(paths, validated);\n}\n\n/** Public re-export of the file-level schema for the import command. */\nexport { cliFileSchema };\n\nasync function writeFileConfig(paths: ConfigPaths, file: CliFile): Promise<void> {\n await ensureDir(paths.dir);\n // Use writeFile + chmod rather than writeFile({mode}) because the\n // mode flag only takes effect on first creation; rewrites would\n // keep the old (potentially looser) permissions.\n await writeFile(paths.file, JSON.stringify(file, null, 2), 'utf8');\n await chmodSafe(paths.file, 0o600);\n}\n\nasync function ensureDir(dir: string): Promise<void> {\n await mkdir(dir, { recursive: true, mode: 0o700 });\n await chmodSafe(dir, 0o700);\n}\n\nasync function chmodSafe(target: string, mode: number | undefined): Promise<void> {\n if (mode === undefined) return;\n if (process.platform === 'win32') return;\n try {\n await chmod(target, mode);\n } catch {\n // chmod can fail on some filesystems (e.g. mounted FAT volumes,\n // network shares). Treat as best-effort — the user's data still\n // landed, we just couldn't tighten perms.\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/utils/config-store.ts"],"sourcesContent":["/**\n * Persistent CLI configuration with multi-profile support.\n *\n * The on-disk shape (v1+):\n *\n * {\n * \"version\": 1,\n * \"currentProfile\": \"default\",\n * \"profiles\": {\n * \"default\": { \"apiKey\": \"kash_live_…\", \"baseUrl\": \"…\", \"defaultChainId\": 8453 },\n * \"test\": { \"apiKey\": \"kash_test_…\" }\n * }\n * }\n *\n * Flat-shape configs from earlier CLI versions are migrated transparently\n * on first read into a `default` profile. The on-disk file is rewritten\n * in the new shape only on the next write — readers don't mutate state.\n *\n * The file is created and re-written at mode `0600` on POSIX. The\n * directory is created with `0700`. chmod is best-effort — Windows and\n * some network filesystems silently ignore it.\n *\n * Resolution order (highest precedence first):\n *\n * 1. Environment variables: `KASH_API_KEY`, `KASH_BASE_URL`,\n * `KASH_CHAIN_ID`. Always win.\n * 2. The active profile's fields.\n * 3. Built-in defaults (api.kash.bot/v1, chain 8453).\n *\n * Active-profile resolution (highest precedence first):\n *\n * 1. Explicit `--profile <name>` flag (via `options.profile`).\n * 2. `KASH_PROFILE` env var.\n * 3. `currentProfile` field in the config file.\n * 4. `'default'`.\n *\n * Pinning env-var precedence makes CI runs predictable and lets a\n * human override a profile field without editing the file.\n */\n\nimport { existsSync } from 'node:fs';\nimport { chmod, mkdir, readFile, unlink, writeFile } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport { dirname, join } from 'node:path';\n\nimport { z } from 'zod';\n\nimport { CliConfigurationError } from '../errors.js';\n\nimport { HEX_ADDRESS_REGEX } from './trade-input.js';\n\n/**\n * Return a shallow copy of `obj` without the named property. Cleaner\n * than the `const { [k]: _removed, ...rest } = obj` rest-spread idiom\n * because it avoids the unused-variable lint dance.\n */\nfunction omitKey<T extends Record<string, unknown>, K extends keyof T>(obj: T, key: K): Omit<T, K> {\n const result: Record<string, unknown> = {};\n for (const k of Object.keys(obj)) {\n if (k !== key) result[k] = obj[k];\n }\n return result as Omit<T, K>;\n}\n\n/** Filesystem layout for the config — exposed for tests to override `home`. */\nexport type ConfigPaths = {\n readonly home: string;\n readonly dir: string;\n readonly file: string;\n};\n\nexport function resolveConfigPaths(home: string = homedir()): ConfigPaths {\n const dir = join(home, '.kash');\n return { home, dir, file: join(dir, 'config.json') };\n}\n\n/**\n * Resolve config paths with an optional explicit override path\n * (typically from the `--config` flag or `KASH_CONFIG` env var). The\n * explicit override sets the file directly and derives `dir`/`home`\n * from it for chmod-on-write.\n */\nexport function resolveConfigPathsForOverride(\n override: string | undefined,\n envOverride: string | undefined = process.env['KASH_CONFIG']\n): ConfigPaths {\n const explicit = override ?? envOverride;\n if (explicit) {\n const dir = dirname(explicit);\n return { home: dirname(dir), dir, file: explicit };\n }\n return resolveConfigPaths();\n}\n\nexport const DEFAULT_PROFILE = 'default';\n\n/**\n * Profile-name reserved words. Even though the regex below already\n * blocks the most-dangerous shapes (no `[`, no `<`, no whitespace),\n * the `__proto__` / `constructor` / `prototype` strings ARE allowed\n * by `[A-Za-z0-9_.-]+` — and using them as keys on a plain object\n * (`file.profiles`) walks the prototype chain on read. The denylist\n * makes the prototype-walk impossible at the schema layer.\n *\n * Defence-in-depth: the file format already uses `Object.create(null)`\n * boundaries downstream where possible, but pinning the validator\n * here makes the invariant grep-discoverable.\n */\nconst RESERVED_PROFILE_NAMES = new Set(['__proto__', 'constructor', 'prototype']);\n\n/** Profile name validator — keeps file structure deterministic. */\nconst profileNameSchema = z\n .string()\n .min(1, 'profile name cannot be empty')\n .max(64, 'profile name must be ≤ 64 characters')\n .regex(/^[A-Za-z0-9_.-]+$/, 'profile name allows letters, digits, underscore, dot, and dash only')\n .refine((name) => !RESERVED_PROFILE_NAMES.has(name), {\n message:\n 'profile name uses a reserved word (__proto__, constructor, prototype) — would walk the object prototype chain',\n });\n\n/**\n * Schema for a single profile. Every field is optional so the profile\n * can hold partial state — e.g. only override `baseUrl` while\n * inheriting the API key from env.\n */\n/**\n * Reference to a private key the CLI will load when constructing the\n * direct-mode signer. We never persist the raw key — only a reference\n * to where to read it from at invocation time:\n *\n * - `file:<path>` — read the key from a file (mode 0600 enforced\n * at read time, not write).\n * - `env:<name>` — read the key from an environment variable.\n *\n * This keeps `~/.kash/config.json` free of secret material; the\n * config file itself is only `0600`-protected for the API key, not\n * for arbitrary private keys that could fund-drain a smart account.\n *\n * Future extensions: `keystore:<path>`, `aws-kms:<key-id>`,\n * `gcp-kms:<resource>`, `ledger:<derivation-path>`.\n */\nconst signerKeyRefSchema = z\n .string()\n .regex(/^(file:|env:)\\S+$/, 'signerKeyRef must start with \"file:<path>\" or \"env:<NAME>\"');\n\n/** Bundler provider preset. */\nconst bundlerProviderSchema = z.enum(['flashbots', 'pimlico', 'alchemy', 'generic']);\n\nconst hexAddressSchema = z\n .string()\n .regex(HEX_ADDRESS_REGEX, 'must be a 0x-prefixed 40-char hex address');\n\n/**\n * Custom-chain config — bypasses the protocol-sdk's static chain\n * registry. Required for any chain Kash hasn't deployed canonical\n * contracts on (local Anvil, Hardhat, Tenderly forks, sidechains).\n *\n * The CLI derives the `viemChain` argument the SDK needs from the\n * profile's `defaultChainId` + `rpcUrl` + `customChain.name`; the\n * consumer never has to hand-construct a viem Chain. `addresses`\n * mirrors the SDK's `CustomChainAddresses`. `smartAccount` is required\n * only when the consumer is using SA mode (`kash protocol …`) on a\n * custom chain — EOA mode ignores it.\n */\n/**\n * Custom-chain schema. Every field is optional at the persistence\n * layer because `kash config set customChain.<leaf>` writes one leaf\n * at a time — requiring the full shape at write time would force the\n * user into a single mega-set call. Completeness (name +\n * factoryAddress + usdcAddress required, smartAccount triple all-or-\n * nothing) is enforced at use time in `resolveCliCustomChain`,\n * where the missing field has actionable error context (the SDK call\n * that needs it).\n */\nconst customChainSchema = z\n .object({\n /** Human-readable label, surfaced on `client.addresses.name`. */\n name: z.string().min(1, 'customChain.name must not be empty').optional(),\n factoryAddress: hexAddressSchema.optional(),\n usdcAddress: hexAddressSchema.optional(),\n oracleAddress: hexAddressSchema.optional(),\n vaultAddress: hexAddressSchema.optional(),\n tokens1155Address: hexAddressSchema.optional(),\n paramRegistryAddress: hexAddressSchema.optional(),\n /** Smart-account factory + EntryPoint config (SA mode only). */\n smartAccount: z\n .object({\n factoryAddress: hexAddressSchema.optional(),\n implementationAddress: hexAddressSchema.optional(),\n entryPointAddress: hexAddressSchema.optional(),\n })\n .strict()\n .optional(),\n })\n .strict();\n\nexport const cliConfigSchema = z\n .object({\n // ── Kash-orchestrated mode (API-backed) ─────────────────────────────\n apiKey: z\n .string()\n .startsWith('kash_', 'API keys start with \"kash_\"')\n .min(16, 'API key looks too short')\n .optional(),\n baseUrl: z.string().url('baseUrl must be a valid URL').optional(),\n defaultChainId: z.number().int().positive().optional(),\n\n // ── Direct mode (`kash protocol …`, on-chain) ───────────────\n /** RPC endpoint for the chain. Consumer-owned; the CLI never proxies. */\n rpcUrl: z.string().url('rpcUrl must be a valid URL').optional(),\n /** Smart account address (the ERC-4337 account whose funds are used). */\n smartAccount: z\n .string()\n .regex(HEX_ADDRESS_REGEX, 'smartAccount must be a 0x-prefixed 40-char hex address')\n .optional(),\n /** Bundler URL (overrides the protocol-sdk's Flashbots Protect default). */\n bundlerUrl: z.string().url('bundlerUrl must be a valid URL').optional(),\n /** Bundler provider preset (selects the right header dialect). */\n bundlerProvider: bundlerProviderSchema.optional(),\n /** Reference to the EOA private key that owns the smart account. */\n signerKeyRef: signerKeyRefSchema.optional(),\n /**\n * Custom-chain addresses for chains outside the static registry\n * (local Anvil, forks, sidechains). When present, the CLI's\n * direct-mode and EOA-mode commands use these addresses instead\n * of looking the chain up in the registry. Required for chainId\n * 31337 (Anvil); optional for Base mainnet/testnet (registry covers them).\n */\n customChain: customChainSchema.optional(),\n })\n .strict();\n\nexport type CliConfig = z.infer<typeof cliConfigSchema>;\n\n/**\n * Schema for the v1 multi-profile file shape.\n *\n * `currentProfile` is intentionally optional (no `.default()`) so the\n * source-attribution logic in `pickProfileName` can distinguish\n * \"user explicitly persisted `default` via `kash config use default`\"\n * (source: 'file') from \"we fell through to the built-in default\n * because the file didn't carry a `currentProfile` field\" (source:\n * 'default'). Both result in `'default'` as the active profile, but\n * the source attribution they report is different.\n */\nconst cliFileSchema = z\n .object({\n version: z.literal(1),\n currentProfile: profileNameSchema.optional(),\n profiles: z.record(profileNameSchema, cliConfigSchema).default({}),\n })\n .strict();\n\nexport type CliFile = z.infer<typeof cliFileSchema>;\n\n/**\n * Canonical API base URLs by environment. The CLI auto-routes based on\n * the API-key prefix: a `kash_test_*` key targets staging, a\n * `kash_live_*` key (or no key) targets production. An explicit\n * `baseUrl` config or `KASH_BASE_URL` env var always wins so consumers\n * can target a private mirror, a local mock, or a future region.\n *\n * Mirrors the `inferBaseUrlFromApiKey()` logic in `@kashdao/sdk`'s\n * `internal/config.ts` so the CLI and the SDK route a given key to the\n * same environment without the user having to configure two places.\n */\nexport const PRODUCTION_BASE_URL = 'https://api.kash.bot/v1' as const;\nexport const STAGING_BASE_URL = 'https://api-staging.kash.bot/v1' as const;\n\n/**\n * Derive the API base URL from an API key when neither config nor env\n * sets one explicitly. Returns `undefined` if the key shape isn't\n * recognised — the caller then falls back to {@link DEFAULTS.baseUrl}.\n */\nexport function inferBaseUrlFromApiKey(apiKey: string | undefined): string | undefined {\n if (!apiKey) return undefined;\n if (apiKey.startsWith('kash_test_')) return STAGING_BASE_URL;\n if (apiKey.startsWith('kash_live_')) return PRODUCTION_BASE_URL;\n return undefined;\n}\n\n/** Default values applied when a field is missing from both file and env. */\nexport const DEFAULTS = {\n baseUrl: PRODUCTION_BASE_URL,\n defaultChainId: 8453,\n} as const;\n\nexport type ResolvedConfig = {\n // ── Kash-orchestrated fields ──────────────────────────────────────────\n readonly apiKey: string | undefined;\n readonly baseUrl: string;\n readonly defaultChainId: number;\n // ── Direct-mode fields (`kash protocol …`) ────────────────────\n readonly rpcUrl: string | undefined;\n readonly smartAccount: string | undefined;\n readonly bundlerUrl: string | undefined;\n readonly bundlerProvider: 'flashbots' | 'pimlico' | 'alchemy' | 'generic' | undefined;\n readonly signerKeyRef: string | undefined;\n /**\n * Custom-chain config — present only when the profile explicitly sets\n * `customChain.*`. Bypasses the protocol-sdk's static chain registry\n * and is required for chains the registry doesn't cover (Anvil,\n * forks, sidechains).\n */\n readonly customChain: CliConfig['customChain'];\n // ── Meta ──────────────────────────────────────────────────────\n /** Active profile name. */\n readonly profile: string;\n /** Where each non-default value came from — useful for `kash config show`. */\n readonly sources: {\n readonly apiKey: 'env' | 'file' | 'unset';\n readonly baseUrl: 'env' | 'file' | 'inferred' | 'default';\n readonly defaultChainId: 'env' | 'file' | 'default';\n readonly profile: 'flag' | 'env' | 'file' | 'default';\n readonly rpcUrl: 'env' | 'file' | 'unset';\n readonly smartAccount: 'env' | 'file' | 'unset';\n readonly bundlerUrl: 'env' | 'file' | 'unset';\n readonly bundlerProvider: 'env' | 'file' | 'unset';\n readonly signerKeyRef: 'env' | 'file' | 'unset';\n readonly customChain: 'file' | 'unset';\n };\n};\n\nexport type ReadConfigOptions = {\n /** Override which profile to read; takes precedence over env + file. */\n readonly profile?: string;\n /** Override the config file path; takes precedence over `KASH_CONFIG`. */\n readonly configPath?: string;\n};\n\n/**\n * Read the config file and return the resolved active profile merged\n * with environment variables and defaults.\n */\nexport async function readConfig(opts: ReadConfigOptions = {}): Promise<ResolvedConfig> {\n const paths = resolveConfigPathsForOverride(opts.configPath);\n const file = await readFileConfig(paths);\n return resolveActive(file, opts.profile);\n}\n\nasync function readFileConfig(paths: ConfigPaths): Promise<CliFile> {\n if (!existsSync(paths.file)) return emptyFile();\n let raw: string;\n try {\n raw = await readFile(paths.file, 'utf8');\n } catch (cause) {\n throw new CliConfigurationError(\n `Failed to read config file at ${paths.file}: ${(cause as Error).message}`,\n \"Run 'kash config reset' to start fresh.\"\n );\n }\n return parseFileContents(raw, paths.file);\n}\n\nfunction parseFileContents(raw: string, file: string): CliFile {\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch (cause) {\n throw new CliConfigurationError(\n `Config file at ${file} is not valid JSON: ${(cause as Error).message}`,\n \"Run 'kash config reset' to overwrite it with defaults.\"\n );\n }\n // Guard against valid-JSON-but-wrong-top-level (e.g. someone wrote\n // a string, a number, an array, or `null` to the file). Without this,\n // the v1 schema's \"Expected object, received string\" Zod error\n // bubbles up with no actionable hint.\n if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new CliConfigurationError(\n `Config file at ${file} must contain a JSON object at the top level (got ${describeJsonRoot(parsed)}).`,\n \"Run 'kash config reset' to overwrite it with defaults.\"\n );\n }\n const migrated = migrateLegacyShape(parsed);\n const result = cliFileSchema.safeParse(migrated);\n if (!result.success) {\n const first = result.error.issues[0];\n const path = first?.path.join('.') ?? '(root)';\n throw new CliConfigurationError(\n `Config file at ${file} is invalid (${path}): ${first?.message ?? 'validation failed'}`,\n \"Run 'kash config reset' to overwrite it with defaults.\"\n );\n }\n return result.data;\n}\n\n/** Describe a non-object JSON root for the user-facing error message. */\nfunction describeJsonRoot(value: unknown): string {\n if (value === null) return 'null';\n if (Array.isArray(value)) return 'array';\n return typeof value;\n}\n\n/**\n * If the file looks like the legacy flat shape ({ apiKey?, baseUrl?,\n * defaultChainId? } at the root), wrap it as the default profile of a\n * v1 file. Otherwise pass through.\n */\nfunction migrateLegacyShape(parsed: unknown): unknown {\n if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {\n return parsed;\n }\n const obj = parsed as Record<string, unknown>;\n if ('version' in obj || 'profiles' in obj) {\n return parsed; // already in v1 shape\n }\n // Legacy flat shape — wrap it as the default profile.\n const flat = cliConfigSchema.safeParse(obj);\n if (!flat.success) {\n return parsed; // let the v1 schema raise the structured error\n }\n return {\n version: 1,\n currentProfile: DEFAULT_PROFILE,\n profiles: { [DEFAULT_PROFILE]: flat.data },\n };\n}\n\nfunction emptyFile(): CliFile {\n return cliFileSchema.parse({ version: 1 });\n}\n\n/**\n * Compute the active profile name. Order: explicit flag > env >\n * file's `currentProfile` (when present) > built-in `'default'`.\n *\n * Crucially, when the file persists `currentProfile: \"default\"`\n * (e.g. after `kash config use default`), source is `'file'` — not\n * `'default'`. That keeps the JSON contract honest: agents debugging\n * \"why is my profile X?\" need to know it came from a write, not a\n * fallback.\n */\nfunction pickProfileName(\n file: CliFile,\n flagOverride: string | undefined\n): { name: string; source: 'flag' | 'env' | 'file' | 'default' } {\n if (flagOverride !== undefined) {\n validateProfileName(flagOverride, '--profile flag');\n return { name: flagOverride, source: 'flag' };\n }\n const env = process.env['KASH_PROFILE'];\n if (env !== undefined && env.length > 0) {\n validateProfileName(env, 'KASH_PROFILE environment variable');\n return { name: env, source: 'env' };\n }\n if (file.currentProfile !== undefined) {\n return { name: file.currentProfile, source: 'file' };\n }\n return { name: DEFAULT_PROFILE, source: 'default' };\n}\n\n/**\n * Wrap `profileNameSchema.parse` so a malformed value surfaces as a\n * typed `CliConfigurationError` with a `check_input`-friendly\n * suggestion, instead of a raw `ZodError` that the top-level\n * boundary maps to `UNEXPECTED`.\n */\nfunction validateProfileName(value: string, source: string): void {\n const result = profileNameSchema.safeParse(value);\n if (!result.success) {\n const issue = result.error.issues[0];\n throw new CliConfigurationError(\n `Profile name from ${source} is invalid: ${issue?.message ?? 'validation failed'}.`,\n 'Profile names accept letters, digits, underscore, dot, and dash; must be 1-64 characters.'\n );\n }\n}\n\nfunction resolveActive(file: CliFile, flagOverride: string | undefined): ResolvedConfig {\n const { name: profileName, source: profileSource } = pickProfileName(file, flagOverride);\n const profile = file.profiles[profileName];\n // It's not an error to ask for a profile that isn't in the file —\n // env-only setups (CI, agents) are normal. We surface this via the\n // `sources.apiKey === 'unset'` value if no env var fills the gap.\n //\n // BUT: when the missing profile was named via `KASH_PROFILE` or\n // `--profile`, an intentional env-only setup is the rare case and\n // a typo (e.g. `KASH_PROFILE=staing` vs `staging`) is the common\n // case. The operator otherwise sees an empty config + a confusing\n // `AUTH_REQUIRED` later. Nudge them on stderr (no JSON pollution,\n // no behaviour change). `KASH_QUIET=1` mutes the warning for CI.\n if (\n profile === undefined &&\n (profileSource === 'env' || profileSource === 'flag') &&\n Object.keys(file.profiles).length > 0 &&\n !isTruthyEnv(process.env['KASH_QUIET'])\n ) {\n const known = Object.keys(file.profiles).sort().join(', ');\n const sourceLabel = profileSource === 'env' ? 'KASH_PROFILE' : '--profile';\n process.stderr.write(\n `\\u26a0 Profile \"${profileName}\" (${sourceLabel}) is not in the config file. ` +\n `Known profiles: ${known}. ` +\n `Did you typo the name? (Set KASH_QUIET=1 to mute this warning.)\\n`\n );\n }\n return mergeWithEnv(profile ?? {}, profileName, profileSource);\n}\n\n/** Same truthy-env recognizer as `utils/global-options.ts:isTruthyEnv`. */\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\nfunction mergeWithEnv(\n profile: CliConfig,\n profileName: string,\n profileSource: 'flag' | 'env' | 'file' | 'default'\n): ResolvedConfig {\n const envApiKey = process.env['KASH_API_KEY'];\n const envBaseUrl = process.env['KASH_BASE_URL'];\n const envChainIdRaw = process.env['KASH_CHAIN_ID'];\n // Direct-mode env vars\n const envRpcUrl = process.env['KASH_RPC_URL'];\n const envSmartAccount = process.env['KASH_SMART_ACCOUNT'];\n const envBundlerUrl = process.env['KASH_BUNDLER_URL'];\n const envBundlerProviderRaw = process.env['KASH_BUNDLER_PROVIDER'];\n const envSignerKeyRef = process.env['KASH_SIGNER_KEY_REF'];\n\n let envChainId: number | undefined;\n if (envChainIdRaw !== undefined) {\n const n = Number.parseInt(envChainIdRaw, 10);\n if (Number.isNaN(n) || n <= 0) {\n throw new CliConfigurationError(\n `KASH_CHAIN_ID is not a positive integer: ${envChainIdRaw}`,\n 'Set KASH_CHAIN_ID to a chain id like 8453 or 84532, or unset it to use the default.'\n );\n }\n envChainId = n;\n }\n\n let envBundlerProvider: ResolvedConfig['bundlerProvider'];\n if (envBundlerProviderRaw !== undefined) {\n const allowed = ['flashbots', 'pimlico', 'alchemy', 'generic'] as const;\n if (!(allowed as readonly string[]).includes(envBundlerProviderRaw)) {\n throw new CliConfigurationError(\n `KASH_BUNDLER_PROVIDER must be one of ${allowed.join(', ')} (got \"${envBundlerProviderRaw}\").`,\n 'Unset the variable or set it to a supported preset.'\n );\n }\n envBundlerProvider = envBundlerProviderRaw as ResolvedConfig['bundlerProvider'];\n }\n\n const apiKey = envApiKey ?? profile.apiKey;\n // Resolution order for `baseUrl`:\n // 1. KASH_BASE_URL env var — always wins\n // 2. profile.baseUrl — explicit profile config\n // 3. inferred from apiKey prefix — kash_test_* → staging, kash_live_* → production\n // 4. DEFAULTS.baseUrl — production (final fallback)\n //\n // Step 3 mirrors `@kashdao/sdk`'s `inferBaseUrlFromApiKey()` so the\n // CLI and the SDK route the same key to the same environment without\n // requiring the user to configure two places. Without this, a user\n // with only a `kash_test_*` key would hit the production host until\n // they remembered to also set `--base-url`.\n const baseUrl =\n envBaseUrl ?? profile.baseUrl ?? inferBaseUrlFromApiKey(apiKey) ?? DEFAULTS.baseUrl;\n const defaultChainId = envChainId ?? profile.defaultChainId ?? DEFAULTS.defaultChainId;\n const rpcUrl = envRpcUrl ?? profile.rpcUrl;\n const smartAccount = envSmartAccount ?? profile.smartAccount;\n const bundlerUrl = envBundlerUrl ?? profile.bundlerUrl;\n const bundlerProvider = envBundlerProvider ?? profile.bundlerProvider;\n const signerKeyRef = envSignerKeyRef ?? profile.signerKeyRef;\n // customChain has no env-var override — it's a structured object,\n // not a single string, and the right place to set it is `kash\n // config set customChain.<leaf>` so partial sets compose. CI use\n // cases that need a custom chain mount the config file directly\n // (KASH_CONFIG=...).\n const customChain = profile.customChain;\n\n return {\n apiKey,\n baseUrl,\n defaultChainId,\n rpcUrl,\n smartAccount,\n bundlerUrl,\n bundlerProvider,\n signerKeyRef,\n customChain,\n profile: profileName,\n sources: {\n apiKey: envApiKey ? 'env' : profile.apiKey ? 'file' : 'unset',\n baseUrl: envBaseUrl\n ? 'env'\n : profile.baseUrl\n ? 'file'\n : inferBaseUrlFromApiKey(apiKey)\n ? 'inferred'\n : 'default',\n defaultChainId:\n envChainId !== undefined\n ? 'env'\n : profile.defaultChainId !== undefined\n ? 'file'\n : 'default',\n profile: profileSource,\n rpcUrl: envRpcUrl ? 'env' : profile.rpcUrl ? 'file' : 'unset',\n smartAccount: envSmartAccount ? 'env' : profile.smartAccount ? 'file' : 'unset',\n bundlerUrl: envBundlerUrl ? 'env' : profile.bundlerUrl ? 'file' : 'unset',\n bundlerProvider: envBundlerProvider ? 'env' : profile.bundlerProvider ? 'file' : 'unset',\n signerKeyRef: envSignerKeyRef ? 'env' : profile.signerKeyRef ? 'file' : 'unset',\n customChain: profile.customChain ? 'file' : 'unset',\n },\n };\n}\n\nexport type WriteConfigOptions = {\n /** Profile to write to. Defaults to the current active profile. */\n readonly profile?: string;\n /** Override the config file path. */\n readonly configPath?: string;\n};\n\n/**\n * Result of {@link updateConfig} / {@link clearConfigField}. Carries\n * the resolved profile name so callers can render an accurate\n * \"wrote to profile X\" message instead of guessing — important for\n * the JSON contract that `kash auth set-key --json` ships, since\n * `--profile` may be unset and we want to report the actually-written\n * profile (which falls back to the file's `currentProfile`).\n */\nexport type UpdateConfigResult = {\n readonly profile: string;\n readonly stored: CliConfig;\n};\n\n/**\n * Mutate (and persist) a single field of the active (or named) profile.\n * Used by `auth set-key`, `auth logout`, `config set`. Writes the file\n * with `0600` permissions.\n */\nexport async function updateConfig(\n patch: Partial<CliConfig>,\n opts: WriteConfigOptions = {}\n): Promise<UpdateConfigResult> {\n const paths = resolveConfigPathsForOverride(opts.configPath);\n const file = await readFileConfig(paths);\n const profileName = opts.profile ?? file.currentProfile ?? DEFAULT_PROFILE;\n profileNameSchema.parse(profileName);\n const current = file.profiles[profileName] ?? {};\n const next = cliConfigSchema.parse({ ...current, ...patch });\n const updated: CliFile = {\n ...file,\n profiles: { ...file.profiles, [profileName]: next },\n };\n await writeFileConfig(paths, updated);\n return { profile: profileName, stored: next };\n}\n\n/** Wipe a single field from a profile (used by `auth logout`). */\nexport async function clearConfigField(\n field: keyof CliConfig,\n opts: WriteConfigOptions = {}\n): Promise<UpdateConfigResult> {\n const paths = resolveConfigPathsForOverride(opts.configPath);\n const file = await readFileConfig(paths);\n const profileName = opts.profile ?? file.currentProfile ?? DEFAULT_PROFILE;\n const current = file.profiles[profileName] ?? {};\n if (!(field in current)) return { profile: profileName, stored: current };\n const next = cliConfigSchema.parse(omitKey(current, field));\n const updated: CliFile = {\n ...file,\n profiles: { ...file.profiles, [profileName]: next },\n };\n await writeFileConfig(paths, updated);\n return { profile: profileName, stored: next };\n}\n\n/** List every profile name present in the config file. */\nexport async function listProfiles(\n opts: { configPath?: string } = {}\n): Promise<{ readonly current: string; readonly profiles: readonly string[] }> {\n const paths = resolveConfigPathsForOverride(opts.configPath);\n const file = await readFileConfig(paths);\n return {\n current: file.currentProfile ?? DEFAULT_PROFILE,\n profiles: Object.keys(file.profiles).sort(),\n };\n}\n\n/** Set the file's `currentProfile` field. Validates the name. */\nexport async function setCurrentProfile(\n name: string,\n opts: { configPath?: string } = {}\n): Promise<CliFile> {\n profileNameSchema.parse(name);\n const paths = resolveConfigPathsForOverride(opts.configPath);\n const file = await readFileConfig(paths);\n const updated: CliFile = { ...file, currentProfile: name };\n await writeFileConfig(paths, updated);\n return updated;\n}\n\n/** Remove a named profile. Refuses to remove the active one. */\nexport async function deleteProfile(\n name: string,\n opts: { configPath?: string } = {}\n): Promise<CliFile> {\n profileNameSchema.parse(name);\n const paths = resolveConfigPathsForOverride(opts.configPath);\n const file = await readFileConfig(paths);\n if (file.currentProfile === name) {\n throw new CliConfigurationError(\n `Cannot delete the active profile \"${name}\".`,\n 'Switch to another profile first with `kash config use <name>`.'\n );\n }\n if (!(name in file.profiles)) {\n return file;\n }\n const updated: CliFile = { ...file, profiles: omitKey(file.profiles, name) };\n await writeFileConfig(paths, updated);\n return updated;\n}\n\n/** Delete the entire config file. Used by `config reset`. */\nexport async function deleteConfig(opts: { configPath?: string } = {}): Promise<void> {\n const paths = resolveConfigPathsForOverride(opts.configPath);\n if (!existsSync(paths.file)) return;\n await unlink(paths.file);\n}\n\n/**\n * Return the full multi-profile file as-is. Used by `kash config\n * export` to dump every profile (vs `readConfig` which resolves a\n * single active profile). When the file doesn't exist, returns an\n * empty file shape so callers don't have to special-case \"no config\n * yet\".\n */\nexport async function readWholeFile(opts: { configPath?: string } = {}): Promise<CliFile> {\n const paths = resolveConfigPathsForOverride(opts.configPath);\n return await readFileConfig(paths);\n}\n\n/**\n * Replace the entire on-disk file with the supplied shape. Used by\n * `kash config import`. Validates against the `cliFileSchema` to\n * prevent garbage from landing on disk.\n *\n * Caller-side concerns (merge vs. overwrite, redaction policy, etc.)\n * are handled in the import command — this helper is pure persistence.\n */\nexport async function writeWholeFile(\n file: CliFile,\n opts: { configPath?: string } = {}\n): Promise<void> {\n const paths = resolveConfigPathsForOverride(opts.configPath);\n const validated = cliFileSchema.parse(file);\n await writeFileConfig(paths, validated);\n}\n\n/** Public re-export of the file-level schema for the import command. */\nexport { cliFileSchema };\n\nasync function writeFileConfig(paths: ConfigPaths, file: CliFile): Promise<void> {\n await ensureDir(paths.dir);\n // Use writeFile + chmod rather than writeFile({mode}) because the\n // mode flag only takes effect on first creation; rewrites would\n // keep the old (potentially looser) permissions.\n await writeFile(paths.file, JSON.stringify(file, null, 2), 'utf8');\n await chmodSafe(paths.file, 0o600);\n}\n\nasync function ensureDir(dir: string): Promise<void> {\n await mkdir(dir, { recursive: true, mode: 0o700 });\n await chmodSafe(dir, 0o700);\n}\n\nasync function chmodSafe(target: string, mode: number | undefined): Promise<void> {\n if (mode === undefined) return;\n if (process.platform === 'win32') return;\n try {\n await chmod(target, mode);\n } catch {\n // chmod can fail on some filesystems (e.g. mounted FAT volumes,\n // network shares). Treat as best-effort — the user's data still\n // landed, we just couldn't tighten perms.\n }\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-KMBMQIZ7.js";
4
+ } from "./chunk-N26VGVGB.js";
5
5
  import {
6
6
  CLI_VERSION
7
- } from "./chunk-BN2CUM42.js";
7
+ } from "./chunk-KAM6KOFD.js";
8
8
  import {
9
9
  style
10
- } from "./chunk-VIADBYFY.js";
10
+ } from "./chunk-MQUJG224.js";
11
11
  import {
12
12
  CliError,
13
13
  EXIT_CODES
14
- } from "./chunk-UZNSYATZ.js";
14
+ } from "./chunk-X2VM6VKM.js";
15
15
 
16
16
  // src/utils/client.ts
17
17
  import { KashClient } from "@kashdao/sdk";
@@ -126,4 +126,4 @@ function buildDebugHooks(json) {
126
126
  export {
127
127
  buildClient
128
128
  };
129
- //# sourceMappingURL=chunk-QJMF73M5.js.map
129
+ //# sourceMappingURL=chunk-QALDZHTX.js.map
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  style
4
- } from "./chunk-VIADBYFY.js";
4
+ } from "./chunk-MQUJG224.js";
5
5
 
6
6
  // src/utils/formatting.ts
7
7
  import Table from "cli-table3";
@@ -151,4 +151,4 @@ export {
151
151
  colorStatus,
152
152
  createTable
153
153
  };
154
- //# sourceMappingURL=chunk-BRK7KJ4O.js.map
154
+ //# sourceMappingURL=chunk-R4NGUZKN.js.map