padrone 1.8.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (333) hide show
  1. package/CHANGELOG.md +20 -1
  2. package/README.md +2 -2
  3. package/dist/codegen/code-builder.d.mts +10 -0
  4. package/dist/codegen/code-builder.d.mts.map +1 -0
  5. package/dist/codegen/code-builder.mjs +185 -0
  6. package/dist/codegen/code-builder.mjs.map +1 -0
  7. package/dist/codegen/discovery.d.mts +44 -0
  8. package/dist/codegen/discovery.d.mts.map +1 -0
  9. package/dist/codegen/discovery.mjs +179 -0
  10. package/dist/codegen/discovery.mjs.map +1 -0
  11. package/dist/codegen/file-emitter.d.mts +10 -0
  12. package/dist/codegen/file-emitter.d.mts.map +1 -0
  13. package/dist/codegen/file-emitter.mjs +58 -0
  14. package/dist/codegen/file-emitter.mjs.map +1 -0
  15. package/dist/codegen/generators/barrel-file.d.mts +10 -0
  16. package/dist/codegen/generators/barrel-file.d.mts.map +1 -0
  17. package/dist/codegen/generators/barrel-file.mjs +16 -0
  18. package/dist/codegen/generators/barrel-file.mjs.map +1 -0
  19. package/dist/codegen/generators/command-file.d.mts +25 -0
  20. package/dist/codegen/generators/command-file.d.mts.map +1 -0
  21. package/dist/codegen/generators/command-file.mjs +130 -0
  22. package/dist/codegen/generators/command-file.mjs.map +1 -0
  23. package/dist/codegen/generators/command-tree.d.mts +17 -0
  24. package/dist/codegen/generators/command-tree.d.mts.map +1 -0
  25. package/dist/codegen/generators/command-tree.mjs +72 -0
  26. package/dist/codegen/generators/command-tree.mjs.map +1 -0
  27. package/dist/codegen/index.d.mts +15 -330
  28. package/dist/codegen/index.mjs +13 -1507
  29. package/dist/codegen/parsers/bash.d.mts +19 -0
  30. package/dist/codegen/parsers/bash.d.mts.map +1 -0
  31. package/dist/codegen/parsers/bash.mjs +112 -0
  32. package/dist/codegen/parsers/bash.mjs.map +1 -0
  33. package/dist/codegen/parsers/fish.d.mts +13 -0
  34. package/dist/codegen/parsers/fish.d.mts.map +1 -0
  35. package/dist/codegen/parsers/fish.mjs +108 -0
  36. package/dist/codegen/parsers/fish.mjs.map +1 -0
  37. package/dist/codegen/parsers/help.d.mts +15 -0
  38. package/dist/codegen/parsers/help.d.mts.map +1 -0
  39. package/dist/codegen/parsers/help.mjs +271 -0
  40. package/dist/codegen/parsers/help.mjs.map +1 -0
  41. package/dist/codegen/parsers/merge.d.mts +14 -0
  42. package/dist/codegen/parsers/merge.d.mts.map +1 -0
  43. package/dist/codegen/parsers/merge.mjs +76 -0
  44. package/dist/codegen/parsers/merge.mjs.map +1 -0
  45. package/dist/codegen/parsers/zsh.d.mts +16 -0
  46. package/dist/codegen/parsers/zsh.d.mts.map +1 -0
  47. package/dist/codegen/parsers/zsh.mjs +161 -0
  48. package/dist/codegen/parsers/zsh.mjs.map +1 -0
  49. package/dist/codegen/schema-to-code.d.mts +24 -0
  50. package/dist/codegen/schema-to-code.d.mts.map +1 -0
  51. package/dist/codegen/schema-to-code.mjs +147 -0
  52. package/dist/codegen/schema-to-code.mjs.map +1 -0
  53. package/dist/codegen/template.d.mts +18 -0
  54. package/dist/codegen/template.d.mts.map +1 -0
  55. package/dist/codegen/template.mjs +37 -0
  56. package/dist/codegen/template.mjs.map +1 -0
  57. package/dist/codegen/types.d.mts +144 -0
  58. package/dist/codegen/types.d.mts.map +1 -0
  59. package/dist/completion.d.mts +2 -0
  60. package/dist/completion.mjs +2 -0
  61. package/dist/core/args.d.mts +3 -0
  62. package/dist/{args-DrCXxXeP.mjs → core/args.mjs} +49 -113
  63. package/dist/core/args.mjs.map +1 -0
  64. package/dist/core/commands.d.mts +13 -0
  65. package/dist/core/commands.d.mts.map +1 -0
  66. package/dist/{commands-DLR0rFgq.mjs → core/commands.mjs} +4 -232
  67. package/dist/core/commands.mjs.map +1 -0
  68. package/dist/core/create.d.mts +63 -0
  69. package/dist/core/create.d.mts.map +1 -0
  70. package/dist/core/create.mjs +230 -0
  71. package/dist/core/create.mjs.map +1 -0
  72. package/dist/core/default-runtime.mjs +198 -0
  73. package/dist/core/default-runtime.mjs.map +1 -0
  74. package/dist/core/errors.d.mts +107 -0
  75. package/dist/core/errors.d.mts.map +1 -0
  76. package/dist/{errors-DA4KzK1M.mjs → core/errors.mjs} +2 -2
  77. package/dist/core/errors.mjs.map +1 -0
  78. package/dist/core/exec.mjs +191 -0
  79. package/dist/core/exec.mjs.map +1 -0
  80. package/dist/core/interceptors.d.mts +33 -0
  81. package/dist/core/interceptors.d.mts.map +1 -0
  82. package/dist/core/interceptors.mjs +253 -0
  83. package/dist/core/interceptors.mjs.map +1 -0
  84. package/dist/core/parse.mjs +181 -0
  85. package/dist/core/parse.mjs.map +1 -0
  86. package/dist/core/program-methods.mjs +256 -0
  87. package/dist/core/program-methods.mjs.map +1 -0
  88. package/dist/core/results.d.mts +13 -0
  89. package/dist/core/results.d.mts.map +1 -0
  90. package/dist/core/results.mjs +150 -0
  91. package/dist/core/results.mjs.map +1 -0
  92. package/dist/core/runtime.d.mts +213 -0
  93. package/dist/core/runtime.d.mts.map +1 -0
  94. package/dist/core/runtime.mjs +10 -0
  95. package/dist/core/runtime.mjs.map +1 -0
  96. package/dist/core/validate.mjs +220 -0
  97. package/dist/core/validate.mjs.map +1 -0
  98. package/dist/docs/index.d.mts +1 -1
  99. package/dist/docs/index.d.mts.map +1 -1
  100. package/dist/docs/index.mjs +2 -2
  101. package/dist/docs/index.mjs.map +1 -1
  102. package/dist/extension/auto-output.d.mts +53 -0
  103. package/dist/extension/auto-output.d.mts.map +1 -0
  104. package/dist/extension/auto-output.mjs +116 -0
  105. package/dist/extension/auto-output.mjs.map +1 -0
  106. package/dist/extension/color.d.mts +19 -0
  107. package/dist/extension/color.d.mts.map +1 -0
  108. package/dist/extension/color.mjs +37 -0
  109. package/dist/extension/color.mjs.map +1 -0
  110. package/dist/extension/completion.d.mts +25 -0
  111. package/dist/extension/completion.d.mts.map +1 -0
  112. package/dist/extension/completion.mjs +40 -0
  113. package/dist/extension/completion.mjs.map +1 -0
  114. package/dist/extension/config.d.mts +55 -0
  115. package/dist/extension/config.d.mts.map +1 -0
  116. package/dist/extension/config.mjs +162 -0
  117. package/dist/extension/config.mjs.map +1 -0
  118. package/dist/extension/env.d.mts +42 -0
  119. package/dist/extension/env.d.mts.map +1 -0
  120. package/dist/extension/env.mjs +44 -0
  121. package/dist/extension/env.mjs.map +1 -0
  122. package/dist/extension/help.d.mts +29 -0
  123. package/dist/extension/help.d.mts.map +1 -0
  124. package/dist/extension/help.mjs +161 -0
  125. package/dist/extension/help.mjs.map +1 -0
  126. package/dist/extension/index.d.mts +18 -0
  127. package/dist/extension/ink.d.mts +31 -0
  128. package/dist/extension/ink.d.mts.map +1 -0
  129. package/dist/extension/ink.mjs +69 -0
  130. package/dist/extension/ink.mjs.map +1 -0
  131. package/dist/extension/interactive.d.mts +16 -0
  132. package/dist/extension/interactive.d.mts.map +1 -0
  133. package/dist/extension/interactive.mjs +89 -0
  134. package/dist/extension/interactive.mjs.map +1 -0
  135. package/dist/extension/logger.d.mts +67 -0
  136. package/dist/extension/logger.d.mts.map +1 -0
  137. package/dist/extension/logger.mjs +188 -0
  138. package/dist/extension/logger.mjs.map +1 -0
  139. package/dist/extension/man.d.mts +25 -0
  140. package/dist/extension/man.d.mts.map +1 -0
  141. package/dist/extension/man.mjs +41 -0
  142. package/dist/extension/man.mjs.map +1 -0
  143. package/dist/extension/mcp.d.mts +28 -0
  144. package/dist/extension/mcp.d.mts.map +1 -0
  145. package/dist/extension/mcp.mjs +44 -0
  146. package/dist/extension/mcp.mjs.map +1 -0
  147. package/dist/extension/progress-renderer.d.mts +13 -0
  148. package/dist/extension/progress-renderer.d.mts.map +1 -0
  149. package/dist/extension/progress-renderer.mjs +351 -0
  150. package/dist/extension/progress-renderer.mjs.map +1 -0
  151. package/dist/extension/progress.d.mts +76 -0
  152. package/dist/extension/progress.d.mts.map +1 -0
  153. package/dist/extension/progress.mjs +225 -0
  154. package/dist/extension/progress.mjs.map +1 -0
  155. package/dist/extension/repl.d.mts +26 -0
  156. package/dist/extension/repl.d.mts.map +1 -0
  157. package/dist/extension/repl.mjs +67 -0
  158. package/dist/extension/repl.mjs.map +1 -0
  159. package/dist/extension/serve.d.mts +27 -0
  160. package/dist/extension/serve.d.mts.map +1 -0
  161. package/dist/extension/serve.mjs +41 -0
  162. package/dist/extension/serve.mjs.map +1 -0
  163. package/dist/extension/signal.d.mts +19 -0
  164. package/dist/extension/signal.d.mts.map +1 -0
  165. package/dist/extension/signal.mjs +81 -0
  166. package/dist/extension/signal.mjs.map +1 -0
  167. package/dist/extension/stdin.d.mts +19 -0
  168. package/dist/extension/stdin.d.mts.map +1 -0
  169. package/dist/extension/stdin.mjs +52 -0
  170. package/dist/extension/stdin.mjs.map +1 -0
  171. package/dist/extension/suggestions.d.mts +6 -0
  172. package/dist/extension/suggestions.d.mts.map +1 -0
  173. package/dist/extension/suggestions.mjs +113 -0
  174. package/dist/extension/suggestions.mjs.map +1 -0
  175. package/dist/extension/timing.d.mts +27 -0
  176. package/dist/extension/timing.d.mts.map +1 -0
  177. package/dist/extension/timing.mjs +71 -0
  178. package/dist/extension/timing.mjs.map +1 -0
  179. package/dist/extension/tracing.d.mts +85 -0
  180. package/dist/extension/tracing.d.mts.map +1 -0
  181. package/dist/extension/tracing.mjs +107 -0
  182. package/dist/extension/tracing.mjs.map +1 -0
  183. package/dist/extension/update-check.d.mts +20 -0
  184. package/dist/extension/update-check.d.mts.map +1 -0
  185. package/dist/extension/update-check.mjs +62 -0
  186. package/dist/extension/update-check.mjs.map +1 -0
  187. package/dist/extension/utils.mjs +43 -0
  188. package/dist/extension/utils.mjs.map +1 -0
  189. package/dist/extension/version.d.mts +20 -0
  190. package/dist/extension/version.d.mts.map +1 -0
  191. package/dist/extension/version.mjs +51 -0
  192. package/dist/extension/version.mjs.map +1 -0
  193. package/dist/{completion-UnBKfGuk.mjs → feature/completion.mjs} +4 -3
  194. package/dist/feature/completion.mjs.map +1 -0
  195. package/dist/feature/interactive.mjs +145 -0
  196. package/dist/feature/interactive.mjs.map +1 -0
  197. package/dist/feature/mcp.d.mts +18 -0
  198. package/dist/feature/mcp.d.mts.map +1 -0
  199. package/dist/{mcp-D6PdtjIs.mjs → feature/mcp.mjs} +6 -6
  200. package/dist/feature/mcp.mjs.map +1 -0
  201. package/dist/feature/repl-loop.mjs +217 -0
  202. package/dist/feature/repl-loop.mjs.map +1 -0
  203. package/dist/feature/serve.d.mts +18 -0
  204. package/dist/feature/serve.d.mts.map +1 -0
  205. package/dist/{serve-PaCLsNoD.mjs → feature/serve.mjs} +7 -7
  206. package/dist/feature/serve.mjs.map +1 -0
  207. package/dist/feature/test.d.mts +109 -0
  208. package/dist/feature/test.d.mts.map +1 -0
  209. package/dist/feature/test.mjs +116 -0
  210. package/dist/feature/test.mjs.map +1 -0
  211. package/dist/feature/update-check.d.mts +35 -0
  212. package/dist/feature/update-check.d.mts.map +1 -0
  213. package/dist/{update-check-CZ2VqjnV.mjs → feature/update-check.mjs} +2 -2
  214. package/dist/feature/update-check.mjs.map +1 -0
  215. package/dist/feature/wrap.d.mts +58 -0
  216. package/dist/feature/wrap.d.mts.map +1 -0
  217. package/dist/feature/wrap.mjs +77 -0
  218. package/dist/feature/wrap.mjs.map +1 -0
  219. package/dist/index.d.mts +38 -901
  220. package/dist/index.mjs +25 -4337
  221. package/dist/ink.d.mts +2 -0
  222. package/dist/ink.mjs +2 -0
  223. package/dist/man.d.mts +2 -0
  224. package/dist/man.mjs +2 -0
  225. package/dist/mcp.d.mts +3 -0
  226. package/dist/mcp.mjs +2 -0
  227. package/dist/output/colorizer.d.mts +28 -0
  228. package/dist/output/colorizer.d.mts.map +1 -0
  229. package/dist/output/colorizer.mjs +94 -0
  230. package/dist/output/colorizer.mjs.map +1 -0
  231. package/dist/{formatter-CY3KrOEd.d.mts → output/formatter.d.mts} +2 -28
  232. package/dist/output/formatter.d.mts.map +1 -0
  233. package/dist/output/formatter.mjs +360 -0
  234. package/dist/output/formatter.mjs.map +1 -0
  235. package/dist/output/help.d.mts +18 -0
  236. package/dist/output/help.d.mts.map +1 -0
  237. package/dist/output/help.mjs +267 -0
  238. package/dist/output/help.mjs.map +1 -0
  239. package/dist/output/output-indicator.d.mts +27 -0
  240. package/dist/output/output-indicator.d.mts.map +1 -0
  241. package/dist/output/output-indicator.mjs +54 -0
  242. package/dist/output/output-indicator.mjs.map +1 -0
  243. package/dist/output/primitives.d.mts +33 -0
  244. package/dist/output/primitives.d.mts.map +1 -0
  245. package/dist/output/primitives.mjs +206 -0
  246. package/dist/output/primitives.mjs.map +1 -0
  247. package/dist/output/styling.d.mts +38 -0
  248. package/dist/output/styling.d.mts.map +1 -0
  249. package/dist/output/styling.mjs +146 -0
  250. package/dist/output/styling.mjs.map +1 -0
  251. package/dist/schema/zod.d.mts +6 -0
  252. package/dist/schema/zod.d.mts.map +1 -0
  253. package/dist/schema/zod.mjs +50 -0
  254. package/dist/schema/zod.mjs.map +1 -0
  255. package/dist/serve.d.mts +2 -0
  256. package/dist/serve.mjs +2 -0
  257. package/dist/test.d.mts +2 -109
  258. package/dist/test.mjs +1 -115
  259. package/dist/tracing.d.mts +2 -0
  260. package/dist/tracing.mjs +2 -0
  261. package/dist/types/args-meta.d.mts +129 -0
  262. package/dist/types/args-meta.d.mts.map +1 -0
  263. package/dist/types/builder.d.mts +212 -0
  264. package/dist/types/builder.d.mts.map +1 -0
  265. package/dist/types/command.d.mts +112 -0
  266. package/dist/types/command.d.mts.map +1 -0
  267. package/dist/types/index.d.mts +8 -0
  268. package/dist/types/interceptor.d.mts +232 -0
  269. package/dist/types/interceptor.d.mts.map +1 -0
  270. package/dist/types/preferences.d.mts +79 -0
  271. package/dist/types/preferences.d.mts.map +1 -0
  272. package/dist/types/result.d.mts +61 -0
  273. package/dist/types/result.d.mts.map +1 -0
  274. package/dist/types/schema.d.mts +24 -0
  275. package/dist/types/schema.d.mts.map +1 -0
  276. package/dist/util/dotenv.mjs +174 -0
  277. package/dist/util/dotenv.mjs.map +1 -0
  278. package/dist/util/shell-utils.mjs +80 -0
  279. package/dist/util/shell-utils.mjs.map +1 -0
  280. package/dist/util/stream.d.mts +33 -0
  281. package/dist/util/stream.d.mts.map +1 -0
  282. package/dist/{stream-DC4H8YTx.mjs → util/stream.mjs} +2 -2
  283. package/dist/util/stream.mjs.map +1 -0
  284. package/dist/util/type-helpers.d.mts +74 -0
  285. package/dist/util/type-helpers.d.mts.map +1 -0
  286. package/dist/util/type-utils.d.mts +186 -0
  287. package/dist/util/type-utils.d.mts.map +1 -0
  288. package/dist/util/utils.mjs +43 -0
  289. package/dist/util/utils.mjs.map +1 -0
  290. package/dist/zod.d.mts +1 -32
  291. package/dist/zod.mjs +1 -49
  292. package/package.json +65 -17
  293. package/src/completion.ts +2 -0
  294. package/src/core/args.ts +63 -37
  295. package/src/core/runtime.ts +11 -2
  296. package/src/extension/completion.ts +3 -0
  297. package/src/extension/index.ts +0 -12
  298. package/src/extension/ink.ts +2 -1
  299. package/src/extension/man.ts +3 -0
  300. package/src/extension/mcp.ts +3 -0
  301. package/src/extension/progress-renderer.ts +32 -8
  302. package/src/extension/progress.ts +19 -9
  303. package/src/extension/serve.ts +3 -0
  304. package/src/extension/tracing.ts +2 -0
  305. package/src/index.ts +1 -20
  306. package/src/ink.ts +2 -0
  307. package/src/man.ts +2 -0
  308. package/src/mcp.ts +3 -0
  309. package/src/serve.ts +2 -0
  310. package/src/tracing.ts +9 -0
  311. package/src/types/builder.ts +2 -2
  312. package/src/zod.ts +1 -1
  313. package/dist/args-DrCXxXeP.mjs.map +0 -1
  314. package/dist/codegen/index.d.mts.map +0 -1
  315. package/dist/codegen/index.mjs.map +0 -1
  316. package/dist/commands-DLR0rFgq.mjs.map +0 -1
  317. package/dist/completion-UnBKfGuk.mjs.map +0 -1
  318. package/dist/errors-DA4KzK1M.mjs.map +0 -1
  319. package/dist/formatter-CY3KrOEd.d.mts.map +0 -1
  320. package/dist/help-B-ZMYyn-.mjs +0 -892
  321. package/dist/help-B-ZMYyn-.mjs.map +0 -1
  322. package/dist/index-D-Dpz7l_.d.mts +0 -1427
  323. package/dist/index-D-Dpz7l_.d.mts.map +0 -1
  324. package/dist/index.d.mts.map +0 -1
  325. package/dist/index.mjs.map +0 -1
  326. package/dist/mcp-D6PdtjIs.mjs.map +0 -1
  327. package/dist/serve-PaCLsNoD.mjs.map +0 -1
  328. package/dist/stream-DC4H8YTx.mjs.map +0 -1
  329. package/dist/test.d.mts.map +0 -1
  330. package/dist/test.mjs.map +0 -1
  331. package/dist/update-check-CZ2VqjnV.mjs.map +0 -1
  332. package/dist/zod.d.mts.map +0 -1
  333. package/dist/zod.mjs.map +0 -1
@@ -0,0 +1,55 @@
1
+ import { WithAsync } from "../util/type-utils.mjs";
2
+ import { CommandTypesBase } from "../types/command.mjs";
3
+ import { StandardSchemaV1 } from "@standard-schema/spec";
4
+
5
+ //#region src/extension/config.d.ts
6
+ type PadroneConfigOptions = {
7
+ /** Config file names to auto-detect (e.g. `['config.json', '.myapprc']`). First found is used. */files?: string | string[]; /** Schema to validate and transform config file data into the args shape. */
8
+ schema?: StandardSchemaV1; /** Disable this extension. */
9
+ disabled?: boolean; /** Whether to add `--config` / `-c` flag support. Defaults to `true`. */
10
+ flag?: boolean; /** Whether subcommands inherit this interceptor. Defaults to `true`. */
11
+ inherit?: boolean;
12
+ /**
13
+ * Search for config files in the user's platform-specific config directory.
14
+ * - `true` — use the program name as the subdirectory (e.g. program `'myapp'` → `~/.config/myapp/`).
15
+ * - `string` — use a custom app name as the subdirectory.
16
+ * - `false` — disable (default).
17
+ *
18
+ * Directories searched (after cwd):
19
+ * - **Linux**: `$XDG_CONFIG_HOME/<app>` or `~/.config/<app>`
20
+ * - **macOS**: `~/Library/Application Support/<app>` (or `$XDG_CONFIG_HOME/<app>` when set)
21
+ * - **Windows**: `%APPDATA%\<app>`
22
+ *
23
+ * Config files found in cwd always take precedence over XDG paths.
24
+ */
25
+ xdg?: string | boolean;
26
+ /**
27
+ * Custom config loader. When provided, replaces the built-in file system loader.
28
+ * Useful for testing or non-CLI environments.
29
+ */
30
+ loadConfig?: (files: string | string[], xdgAppName?: string) => Record<string, unknown> | undefined | Promise<Record<string, unknown> | undefined>;
31
+ };
32
+ /**
33
+ * Extension that handles config file loading, validation, and merging into command arguments.
34
+ *
35
+ * Features:
36
+ * - `--config` / `-c` flag for explicit config file path (can be disabled via `flag: false`)
37
+ * - Auto-detection of config files from a list of candidate names
38
+ * - Optional schema validation and transformation of config data
39
+ * - Directly accesses the file system (gracefully no-ops in non-CLI environments)
40
+ *
41
+ * Config values have the lowest precedence (CLI > stdin > env > config).
42
+ *
43
+ * Not included in the default built-in extensions — must be explicitly added:
44
+ * ```ts
45
+ * createPadrone('my-cli')
46
+ * .extend(padroneConfig({
47
+ * files: ['config.json', '.myapprc'],
48
+ * schema: z.object({ port: z.number(), host: z.string() }),
49
+ * }))
50
+ * ```
51
+ */
52
+ declare function padroneConfig(options?: PadroneConfigOptions): <T extends CommandTypesBase>(builder: T) => WithAsync<T>;
53
+ //#endregion
54
+ export { PadroneConfigOptions, padroneConfig };
55
+ //# sourceMappingURL=config.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.mts","names":[],"sources":["../../src/extension/config.ts"],"mappings":";;;;;KAWY,oBAAA;oGAEV,KAAA,sBAFU;EAIV,MAAA,GAAS,gBAAA;EAET,QAAA,YA0BK;EAxBL,IAAA,YAwB2C;EAtB3C,OAAA;EAsBkD;;;;;;;;;;;;;EARlD,GAAA;EAQyD;AAAA;AAqJ3D;;EAxJE,UAAA,IACE,KAAA,qBACA,UAAA,cACG,MAAA,gCAAsC,OAAA,CAAQ,MAAA;AAAA;;;;;;;;;;;;;;;;AAqJiE;;;;;iBAAtG,aAAA,CAAc,OAAA,GAAU,oBAAA,cAAkC,gBAAA,EAAkB,OAAA,EAAS,CAAA,KAAM,SAAA,CAAU,CAAA"}
@@ -0,0 +1,162 @@
1
+ import { applyValues } from "../core/args.mjs";
2
+ import { thenMaybe } from "../core/results.mjs";
3
+ import { defineInterceptor } from "../core/interceptors.mjs";
4
+ import { ConfigError } from "../core/errors.mjs";
5
+ import { getRootCommand } from "../util/utils.mjs";
6
+ //#region src/extension/config.ts
7
+ let _fs;
8
+ let _path;
9
+ async function initNodeModules() {
10
+ if (_fs && _path) return;
11
+ _fs = await import("node:fs");
12
+ _path = await import("node:path");
13
+ }
14
+ try {
15
+ if (typeof process !== "undefined") initNodeModules();
16
+ } catch {}
17
+ function getUserConfigDir(path, appName) {
18
+ const platform = process.platform;
19
+ const xdgHome = process.env.XDG_CONFIG_HOME;
20
+ if (xdgHome) return path.join(xdgHome, appName);
21
+ const home = process.env.HOME || process.env.USERPROFILE;
22
+ if (!home) return void 0;
23
+ if (platform === "win32") {
24
+ const appData = process.env.APPDATA;
25
+ return appData ? path.join(appData, appName) : path.join(home, "AppData", "Roaming", appName);
26
+ }
27
+ if (platform === "darwin") return path.join(home, "Library", "Application Support", appName);
28
+ return path.join(home, ".config", appName);
29
+ }
30
+ function resolveConfigPath(fs, path, cwd, files, xdgAppName) {
31
+ if (typeof files === "string") {
32
+ const abs = path.isAbsolute(files) ? files : path.resolve(cwd, files);
33
+ if (!fs.existsSync(abs)) {
34
+ console.error(`Config file not found: ${abs}`);
35
+ return;
36
+ }
37
+ return abs;
38
+ }
39
+ for (const candidate of files) {
40
+ const abs = path.isAbsolute(candidate) ? candidate : path.resolve(cwd, candidate);
41
+ if (fs.existsSync(abs)) return abs;
42
+ }
43
+ if (xdgAppName) {
44
+ const configDir = getUserConfigDir(path, xdgAppName);
45
+ if (configDir) for (const candidate of files) {
46
+ const abs = path.join(configDir, candidate);
47
+ if (fs.existsSync(abs)) return abs;
48
+ }
49
+ }
50
+ }
51
+ function loadConfigSync(fs, path, files, xdgAppName) {
52
+ const absolutePath = resolveConfigPath(fs, path, process.cwd(), files, xdgAppName);
53
+ if (!absolutePath) return void 0;
54
+ const getContent = () => fs.readFileSync(absolutePath, "utf-8");
55
+ const ext = path.extname(absolutePath).toLowerCase();
56
+ if (ext === ".yaml" || ext === ".yml") return Bun.YAML.parse(getContent());
57
+ if (ext === ".toml") return Bun.TOML.parse(getContent());
58
+ if (ext === ".jsonc") return Bun.JSONC.parse(getContent());
59
+ if (ext === ".json") {
60
+ if (Bun.JSONC) return Bun.JSONC.parse(getContent());
61
+ try {
62
+ return JSON.parse(getContent());
63
+ } catch {
64
+ return Bun.JSONC.parse(getContent());
65
+ }
66
+ }
67
+ if (ext === ".js" || ext === ".cjs" || ext === ".mjs" || ext === ".ts" || ext === ".cts" || ext === ".mts") return import(
68
+ /* @vite-ignore */
69
+ absolutePath
70
+ ).then((mod) => mod.default ?? mod);
71
+ try {
72
+ return JSON.parse(getContent());
73
+ } catch {
74
+ console.error(`Unable to parse config file: ${absolutePath}`);
75
+ return;
76
+ }
77
+ }
78
+ /**
79
+ * Built-in config file loader. Directly accesses the file system.
80
+ * Returns `undefined` in non-CLI environments where `node:fs` is unavailable.
81
+ */
82
+ function loadConfig(files, xdgAppName) {
83
+ if (typeof process === "undefined") return void 0;
84
+ try {
85
+ if (_fs && _path) return loadConfigSync(_fs, _path, files, xdgAppName);
86
+ return initNodeModules().then(() => loadConfigSync(_fs, _path, files, xdgAppName));
87
+ } catch {
88
+ return;
89
+ }
90
+ }
91
+ /**
92
+ * Extension that handles config file loading, validation, and merging into command arguments.
93
+ *
94
+ * Features:
95
+ * - `--config` / `-c` flag for explicit config file path (can be disabled via `flag: false`)
96
+ * - Auto-detection of config files from a list of candidate names
97
+ * - Optional schema validation and transformation of config data
98
+ * - Directly accesses the file system (gracefully no-ops in non-CLI environments)
99
+ *
100
+ * Config values have the lowest precedence (CLI > stdin > env > config).
101
+ *
102
+ * Not included in the default built-in extensions — must be explicitly added:
103
+ * ```ts
104
+ * createPadrone('my-cli')
105
+ * .extend(padroneConfig({
106
+ * files: ['config.json', '.myapprc'],
107
+ * schema: z.object({ port: z.number(), host: z.string() }),
108
+ * }))
109
+ * ```
110
+ */
111
+ function padroneConfig(options) {
112
+ if (options?.disabled) {
113
+ const disabled = defineInterceptor({
114
+ id: "padrone:config",
115
+ name: "padrone:config",
116
+ order: -999,
117
+ disabled: true
118
+ }, () => ({}));
119
+ return ((builder) => builder.intercept(disabled));
120
+ }
121
+ const configFiles = options?.files ? Array.isArray(options.files) ? options.files : [options.files] : void 0;
122
+ const configSchema = options?.schema;
123
+ const flagEnabled = options?.flag !== false;
124
+ const inherit = options?.inherit;
125
+ const xdgOption = options?.xdg;
126
+ const configLoader = options?.loadConfig ?? loadConfig;
127
+ const interceptor = defineInterceptor({
128
+ id: "padrone:config",
129
+ name: "padrone:config",
130
+ order: -999,
131
+ ...inherit === false && { inherit: false }
132
+ }, () => ({ validate(ctx, next) {
133
+ let explicitConfigPath;
134
+ if (flagEnabled) {
135
+ explicitConfigPath = ctx.rawArgs.config ?? ctx.rawArgs.c;
136
+ if (typeof explicitConfigPath === "string") {
137
+ delete ctx.rawArgs.config;
138
+ delete ctx.rawArgs.c;
139
+ }
140
+ }
141
+ if (!explicitConfigPath && !configFiles) return next();
142
+ let xdgAppName;
143
+ if (typeof xdgOption === "string") xdgAppName = xdgOption;
144
+ else if (xdgOption === true) xdgAppName = getRootCommand(ctx.command).name;
145
+ const configDataOrPromise = configLoader(explicitConfigPath ?? configFiles ?? [], xdgAppName);
146
+ const applyConfig = (configData) => {
147
+ if (!configData) return next();
148
+ if (configSchema) return thenMaybe(configSchema["~standard"].validate(configData), (result) => {
149
+ if (result.issues) throw new ConfigError(`Invalid config file:\n${result.issues.map((i) => ` - ${i.path?.join(".") || "root"}: ${i.message}`).join("\n")}`, { command: ctx.command.path || ctx.command.name });
150
+ const validatedData = result.value;
151
+ return next({ rawArgs: applyValues(ctx.rawArgs, validatedData) });
152
+ });
153
+ return next({ rawArgs: applyValues(ctx.rawArgs, configData) });
154
+ };
155
+ return thenMaybe(configDataOrPromise, applyConfig);
156
+ } }));
157
+ return ((builder) => builder.intercept(interceptor));
158
+ }
159
+ //#endregion
160
+ export { padroneConfig };
161
+
162
+ //# sourceMappingURL=config.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.mjs","names":[],"sources":["../../src/extension/config.ts"],"sourcesContent":["import type { StandardSchemaV1 } from '@standard-schema/spec';\nimport { applyValues } from '../core/args.ts';\nimport { ConfigError } from '../core/errors.ts';\nimport { defineInterceptor } from '../core/interceptors.ts';\nimport { thenMaybe } from '../core/results.ts';\nimport type { AnyPadroneBuilder, CommandTypesBase, InterceptorValidateContext } from '../types/index.ts';\nimport type { WithAsync } from '../util/type-utils.ts';\nimport { getRootCommand } from '../util/utils.ts';\n\n// ── Types ────────────────────────────────────────────────────────────────\n\nexport type PadroneConfigOptions = {\n /** Config file names to auto-detect (e.g. `['config.json', '.myapprc']`). First found is used. */\n files?: string | string[];\n /** Schema to validate and transform config file data into the args shape. */\n schema?: StandardSchemaV1;\n /** Disable this extension. */\n disabled?: boolean;\n /** Whether to add `--config` / `-c` flag support. Defaults to `true`. */\n flag?: boolean;\n /** Whether subcommands inherit this interceptor. Defaults to `true`. */\n inherit?: boolean;\n /**\n * Search for config files in the user's platform-specific config directory.\n * - `true` — use the program name as the subdirectory (e.g. program `'myapp'` → `~/.config/myapp/`).\n * - `string` — use a custom app name as the subdirectory.\n * - `false` — disable (default).\n *\n * Directories searched (after cwd):\n * - **Linux**: `$XDG_CONFIG_HOME/<app>` or `~/.config/<app>`\n * - **macOS**: `~/Library/Application Support/<app>` (or `$XDG_CONFIG_HOME/<app>` when set)\n * - **Windows**: `%APPDATA%\\<app>`\n *\n * Config files found in cwd always take precedence over XDG paths.\n */\n xdg?: string | boolean;\n /**\n * Custom config loader. When provided, replaces the built-in file system loader.\n * Useful for testing or non-CLI environments.\n */\n loadConfig?: (\n files: string | string[],\n xdgAppName?: string,\n ) => Record<string, unknown> | undefined | Promise<Record<string, unknown> | undefined>;\n};\n\n// ── File system config loader ───────────────────────────────────────────\n\n// Lazily resolved Node.js modules — cached after first import to keep loadConfig sync after initialization.\nlet _fs: typeof import('node:fs') | undefined;\nlet _path: typeof import('node:path') | undefined;\n\nasync function initNodeModules(): Promise<void> {\n if (_fs && _path) return;\n _fs = await import('node:fs');\n _path = await import('node:path');\n}\n\n// Eagerly start caching node modules so loadConfig is sync by the time it's called.\ntry {\n if (typeof process !== 'undefined') initNodeModules();\n} catch {\n // Non-CLI environments (browser, edge) — ignore\n}\n\nfunction getUserConfigDir(path: typeof import('node:path'), appName: string): string | undefined {\n const platform = process.platform;\n\n // Respect XDG_CONFIG_HOME on all platforms when explicitly set\n const xdgHome = process.env.XDG_CONFIG_HOME;\n if (xdgHome) return path.join(xdgHome, appName);\n\n const home = process.env.HOME || process.env.USERPROFILE;\n if (!home) return undefined;\n\n if (platform === 'win32') {\n const appData = process.env.APPDATA;\n return appData ? path.join(appData, appName) : path.join(home, 'AppData', 'Roaming', appName);\n }\n if (platform === 'darwin') return path.join(home, 'Library', 'Application Support', appName);\n\n // Linux and other Unix — default XDG path\n return path.join(home, '.config', appName);\n}\n\nfunction resolveConfigPath(fs: any, path: any, cwd: string, files: string | string[], xdgAppName?: string): string | undefined {\n if (typeof files === 'string') {\n const abs = path.isAbsolute(files) ? files : path.resolve(cwd, files);\n if (!fs.existsSync(abs)) {\n console.error(`Config file not found: ${abs}`);\n return undefined;\n }\n return abs;\n }\n\n // Search in cwd first\n for (const candidate of files) {\n const abs = path.isAbsolute(candidate) ? candidate : path.resolve(cwd, candidate);\n if (fs.existsSync(abs)) return abs;\n }\n\n // Then search in the user config directory (XDG / platform-specific)\n if (xdgAppName) {\n const configDir = getUserConfigDir(path, xdgAppName);\n if (configDir) {\n for (const candidate of files) {\n const abs = path.join(configDir, candidate);\n if (fs.existsSync(abs)) return abs;\n }\n }\n }\n\n return undefined;\n}\n\nfunction loadConfigSync(\n fs: typeof import('node:fs'),\n path: typeof import('node:path'),\n files: string | string[],\n xdgAppName?: string,\n): Record<string, unknown> | undefined | Promise<Record<string, unknown> | undefined> {\n const cwd = process.cwd();\n const absolutePath = resolveConfigPath(fs, path, cwd, files, xdgAppName);\n if (!absolutePath) return undefined;\n\n const getContent = () => fs.readFileSync(absolutePath, 'utf-8');\n const ext = path.extname(absolutePath).toLowerCase();\n\n if (ext === '.yaml' || ext === '.yml') return Bun.YAML.parse(getContent()) as any;\n if (ext === '.toml') return Bun.TOML.parse(getContent()) as any;\n if (ext === '.jsonc') return Bun.JSONC.parse(getContent()) as any;\n if (ext === '.json') {\n if (Bun.JSONC) return Bun.JSONC.parse(getContent()) as any;\n try {\n return JSON.parse(getContent());\n } catch {\n return Bun.JSONC.parse(getContent()) as any;\n }\n }\n if (ext === '.js' || ext === '.cjs' || ext === '.mjs' || ext === '.ts' || ext === '.cts' || ext === '.mts') {\n return import(/* @vite-ignore */ absolutePath).then((mod) => mod.default ?? mod);\n }\n\n // Unknown extension — try JSON\n try {\n return JSON.parse(getContent());\n } catch {\n console.error(`Unable to parse config file: ${absolutePath}`);\n return undefined;\n }\n}\n\n/**\n * Built-in config file loader. Directly accesses the file system.\n * Returns `undefined` in non-CLI environments where `node:fs` is unavailable.\n */\nfunction loadConfig(\n files: string | string[],\n xdgAppName?: string,\n): Record<string, unknown> | undefined | Promise<Record<string, unknown> | undefined> {\n if (typeof process === 'undefined') return undefined;\n\n try {\n if (_fs && _path) return loadConfigSync(_fs, _path, files, xdgAppName);\n return initNodeModules().then(() => loadConfigSync(_fs!, _path!, files, xdgAppName));\n } catch {\n return undefined;\n }\n}\n\n// ── Extension ────────────────────────────────────────────────────────────\n\n/**\n * Extension that handles config file loading, validation, and merging into command arguments.\n *\n * Features:\n * - `--config` / `-c` flag for explicit config file path (can be disabled via `flag: false`)\n * - Auto-detection of config files from a list of candidate names\n * - Optional schema validation and transformation of config data\n * - Directly accesses the file system (gracefully no-ops in non-CLI environments)\n *\n * Config values have the lowest precedence (CLI > stdin > env > config).\n *\n * Not included in the default built-in extensions — must be explicitly added:\n * ```ts\n * createPadrone('my-cli')\n * .extend(padroneConfig({\n * files: ['config.json', '.myapprc'],\n * schema: z.object({ port: z.number(), host: z.string() }),\n * }))\n * ```\n */\nexport function padroneConfig(options?: PadroneConfigOptions): <T extends CommandTypesBase>(builder: T) => WithAsync<T> {\n if (options?.disabled) {\n const disabled = defineInterceptor({ id: 'padrone:config', name: 'padrone:config', order: -999, disabled: true }, () => ({}));\n return ((builder: AnyPadroneBuilder) => builder.intercept(disabled)) as any;\n }\n\n const configFiles = options?.files ? (Array.isArray(options.files) ? options.files : [options.files]) : undefined;\n const configSchema = options?.schema;\n const flagEnabled = options?.flag !== false;\n const inherit = options?.inherit;\n const xdgOption = options?.xdg;\n const configLoader = options?.loadConfig ?? loadConfig;\n\n const interceptor = defineInterceptor(\n { id: 'padrone:config', name: 'padrone:config', order: -999, ...(inherit === false && { inherit: false }) },\n () => ({\n validate(ctx: InterceptorValidateContext, next) {\n // Extract --config / -c from rawArgs\n let explicitConfigPath: string | undefined;\n if (flagEnabled) {\n explicitConfigPath = (ctx.rawArgs.config ?? ctx.rawArgs.c) as string | undefined;\n if (typeof explicitConfigPath === 'string') {\n delete ctx.rawArgs.config;\n delete ctx.rawArgs.c;\n }\n }\n\n // Skip entirely when there's nothing to load\n if (!explicitConfigPath && !configFiles) return next();\n\n // Resolve XDG app name: true → derive from root command name, string → use as-is\n let xdgAppName: string | undefined;\n if (typeof xdgOption === 'string') xdgAppName = xdgOption;\n else if (xdgOption === true) xdgAppName = getRootCommand(ctx.command).name;\n\n // Load config data: explicit --config flag takes priority, then auto-detect\n const configDataOrPromise = configLoader(explicitConfigPath ?? configFiles ?? [], xdgAppName);\n\n const applyConfig = (configData: Record<string, unknown> | undefined) => {\n if (!configData) return next();\n\n // Validate against schema if provided\n if (configSchema) {\n const validated = configSchema['~standard'].validate(configData);\n return thenMaybe(validated, (result) => {\n if (result.issues) {\n const issueMessages = result.issues\n .map((i: StandardSchemaV1.Issue) => ` - ${i.path?.join('.') || 'root'}: ${i.message}`)\n .join('\\n');\n throw new ConfigError(`Invalid config file:\\n${issueMessages}`, {\n command: ctx.command.path || ctx.command.name,\n });\n }\n const validatedData = result.value as Record<string, unknown>;\n const mergedRawArgs = applyValues(ctx.rawArgs, validatedData);\n return next({ rawArgs: mergedRawArgs });\n });\n }\n\n // No schema — pass through as-is\n const mergedRawArgs = applyValues(ctx.rawArgs, configData);\n return next({ rawArgs: mergedRawArgs });\n };\n\n return thenMaybe(configDataOrPromise, applyConfig);\n },\n }),\n );\n\n return ((builder: AnyPadroneBuilder) => builder.intercept(interceptor)) as any;\n}\n"],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ import { WithAsync } from "../util/type-utils.mjs";
2
+ import { CommandTypesBase } from "../types/command.mjs";
3
+ import { StandardSchemaV1 } from "@standard-schema/spec";
4
+
5
+ //#region src/extension/env.d.ts
6
+ type PadroneEnvOptions = {
7
+ /** Env modes to load (e.g. `['production']`). Loads `.env.{mode}` files. */modes?: string[]; /** Whether to load `.env.local` and `.env.{mode}.local` files. @default true */
8
+ local?: boolean; /** Directory to search for `.env` files. @default process.cwd() */
9
+ dir?: string; /** When `true`, file values override `process.env` values. @default false */
10
+ override?: boolean; /** When `false`, the base `.env` (and `.env.local`) files are not loaded. @default true */
11
+ base?: boolean;
12
+ };
13
+ /**
14
+ * Extension that reads environment variables, validates them against a schema,
15
+ * and merges the transformed values into command arguments.
16
+ *
17
+ * Supports loading `.env` files with mode-based overrides and variable expansion.
18
+ *
19
+ * ```ts
20
+ * // Schema only (reads process.env)
21
+ * .extend(padroneEnv(
22
+ * z.object({ PORT: z.string() }).transform(e => ({ port: Number(e.PORT) }))
23
+ * ))
24
+ *
25
+ * // Schema + .env file loading
26
+ * .extend(padroneEnv(
27
+ * z.object({ PORT: z.string() }).transform(e => ({ port: Number(e.PORT) })),
28
+ * { modes: ['production'] }
29
+ * ))
30
+ *
31
+ * // .env file loading only (no schema validation)
32
+ * .extend(padroneEnv({ modes: ['production'] }))
33
+ * ```
34
+ *
35
+ * Env values have lower precedence than CLI args and stdin, but higher than config files.
36
+ */
37
+ declare function padroneEnv(schema: StandardSchemaV1): <T extends CommandTypesBase>(builder: T) => WithAsync<T>;
38
+ declare function padroneEnv(schema: StandardSchemaV1, options: PadroneEnvOptions): <T extends CommandTypesBase>(builder: T) => WithAsync<T>;
39
+ declare function padroneEnv(options: PadroneEnvOptions): <T extends CommandTypesBase>(builder: T) => WithAsync<T>;
40
+ //#endregion
41
+ export { PadroneEnvOptions, padroneEnv };
42
+ //# sourceMappingURL=env.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.d.mts","names":[],"sources":["../../src/extension/env.ts"],"mappings":";;;;;KAWY,iBAAA;8EAEV,KAAA,aAFU;EAIV,KAAA;EAEA,GAAA,WAJA;EAMA,QAAA,YAFA;EAIA,IAAA;AAAA;;AAAI;AAmCN;;;;;;;;;;;;;;;;;;;AAA6G;AAC7G;;iBADgB,UAAA,CAAW,MAAA,EAAQ,gBAAA,cAA8B,gBAAA,EAAkB,OAAA,EAAS,CAAA,KAAM,SAAA,CAAU,CAAA;AAAA,iBAC5F,UAAA,CAAW,MAAA,EAAQ,gBAAA,EAAkB,OAAA,EAAS,iBAAA,cAA+B,gBAAA,EAAkB,OAAA,EAAS,CAAA,KAAM,SAAA,CAAU,CAAA;AAAA,iBACxH,UAAA,CAAW,OAAA,EAAS,iBAAA,cAA+B,gBAAA,EAAkB,OAAA,EAAS,CAAA,KAAM,SAAA,CAAU,CAAA"}
@@ -0,0 +1,44 @@
1
+ import { applyValues } from "../core/args.mjs";
2
+ import { thenMaybe } from "../core/results.mjs";
3
+ import { defineInterceptor } from "../core/interceptors.mjs";
4
+ import { loadEnvFiles } from "../util/dotenv.mjs";
5
+ //#region src/extension/env.ts
6
+ function isSchema(value) {
7
+ return value != null && typeof value === "object" && "~standard" in value;
8
+ }
9
+ function padroneEnv(schemaOrOptions, maybeOptions) {
10
+ const schema = isSchema(schemaOrOptions) ? schemaOrOptions : void 0;
11
+ const options = isSchema(schemaOrOptions) ? maybeOptions : schemaOrOptions;
12
+ const hasFiles = options?.modes !== void 0;
13
+ const fileOptions = hasFiles ? options : void 0;
14
+ const override = options?.override ?? false;
15
+ const interceptor = defineInterceptor({
16
+ id: "padrone:env",
17
+ name: "padrone:env",
18
+ order: -1e3
19
+ }, () => ({ validate(ctx, next) {
20
+ const processEnv = ctx.runtime.env();
21
+ const applyEnv = (envFromFiles) => {
22
+ const rawEnv = override ? {
23
+ ...processEnv,
24
+ ...envFromFiles
25
+ } : {
26
+ ...envFromFiles,
27
+ ...processEnv
28
+ };
29
+ if (schema) return thenMaybe(schema["~standard"].validate(rawEnv), (result) => {
30
+ if (result.issues || !result.value) return next();
31
+ return next({ rawArgs: applyValues(ctx.rawArgs, result.value) });
32
+ });
33
+ if (Object.keys(envFromFiles).length > 0) return next({ rawArgs: applyValues(ctx.rawArgs, envFromFiles) });
34
+ return next();
35
+ };
36
+ if (hasFiles) return thenMaybe(loadEnvFiles(fileOptions, processEnv), applyEnv);
37
+ return applyEnv({});
38
+ } }));
39
+ return ((builder) => builder.intercept(interceptor));
40
+ }
41
+ //#endregion
42
+ export { padroneEnv };
43
+
44
+ //# sourceMappingURL=env.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.mjs","names":[],"sources":["../../src/extension/env.ts"],"sourcesContent":["import type { StandardSchemaV1 } from '@standard-schema/spec';\nimport { applyValues } from '../core/args.ts';\nimport { defineInterceptor } from '../core/interceptors.ts';\nimport { thenMaybe } from '../core/results.ts';\nimport type { AnyPadroneBuilder, CommandTypesBase, InterceptorValidateContext } from '../types/index.ts';\nimport type { LoadEnvFilesOptions } from '../util/dotenv.ts';\nimport { loadEnvFiles } from '../util/dotenv.ts';\nimport type { WithAsync } from '../util/type-utils.ts';\n\n// ── Types ────────────────────────────────────────────────────────────────\n\nexport type PadroneEnvOptions = {\n /** Env modes to load (e.g. `['production']`). Loads `.env.{mode}` files. */\n modes?: string[];\n /** Whether to load `.env.local` and `.env.{mode}.local` files. @default true */\n local?: boolean;\n /** Directory to search for `.env` files. @default process.cwd() */\n dir?: string;\n /** When `true`, file values override `process.env` values. @default false */\n override?: boolean;\n /** When `false`, the base `.env` (and `.env.local`) files are not loaded. @default true */\n base?: boolean;\n};\n\n// ── Helpers ──────────────────────────────────────────────────────────────\n\nfunction isSchema(value: unknown): value is StandardSchemaV1 {\n return value != null && typeof value === 'object' && '~standard' in value;\n}\n\n// ── Extension ────────────────────────────────────────────────────────────\n\n/**\n * Extension that reads environment variables, validates them against a schema,\n * and merges the transformed values into command arguments.\n *\n * Supports loading `.env` files with mode-based overrides and variable expansion.\n *\n * ```ts\n * // Schema only (reads process.env)\n * .extend(padroneEnv(\n * z.object({ PORT: z.string() }).transform(e => ({ port: Number(e.PORT) }))\n * ))\n *\n * // Schema + .env file loading\n * .extend(padroneEnv(\n * z.object({ PORT: z.string() }).transform(e => ({ port: Number(e.PORT) })),\n * { modes: ['production'] }\n * ))\n *\n * // .env file loading only (no schema validation)\n * .extend(padroneEnv({ modes: ['production'] }))\n * ```\n *\n * Env values have lower precedence than CLI args and stdin, but higher than config files.\n */\nexport function padroneEnv(schema: StandardSchemaV1): <T extends CommandTypesBase>(builder: T) => WithAsync<T>;\nexport function padroneEnv(schema: StandardSchemaV1, options: PadroneEnvOptions): <T extends CommandTypesBase>(builder: T) => WithAsync<T>;\nexport function padroneEnv(options: PadroneEnvOptions): <T extends CommandTypesBase>(builder: T) => WithAsync<T>;\nexport function padroneEnv(\n schemaOrOptions: StandardSchemaV1 | PadroneEnvOptions,\n maybeOptions?: PadroneEnvOptions,\n): <T extends CommandTypesBase>(builder: T) => WithAsync<T> {\n const schema = isSchema(schemaOrOptions) ? schemaOrOptions : undefined;\n const options = isSchema(schemaOrOptions) ? maybeOptions : schemaOrOptions;\n const hasFiles = options?.modes !== undefined;\n const fileOptions: LoadEnvFilesOptions | undefined = hasFiles ? options : undefined;\n const override = options?.override ?? false;\n\n const interceptor = defineInterceptor({ id: 'padrone:env', name: 'padrone:env', order: -1000 }, () => ({\n validate(ctx: InterceptorValidateContext, next) {\n const processEnv = ctx.runtime.env();\n\n const applyEnv = (envFromFiles: Record<string, string>) => {\n const rawEnv = override ? { ...processEnv, ...envFromFiles } : { ...envFromFiles, ...processEnv };\n\n if (schema) {\n const envValidated = schema['~standard'].validate(rawEnv);\n return thenMaybe(envValidated, (result) => {\n if (result.issues || !result.value) return next();\n return next({ rawArgs: applyValues(ctx.rawArgs, result.value as Record<string, unknown>) });\n });\n }\n\n // No schema — merge file env values directly into rawArgs\n if (Object.keys(envFromFiles).length > 0) {\n return next({ rawArgs: applyValues(ctx.rawArgs, envFromFiles) });\n }\n return next();\n };\n\n if (hasFiles) {\n const loaded = loadEnvFiles(fileOptions!, processEnv);\n return thenMaybe(loaded, applyEnv);\n }\n\n return applyEnv({});\n },\n }));\n\n return ((builder: AnyPadroneBuilder) => builder.intercept(interceptor)) as any;\n}\n"],"mappings":";;;;;AA0BA,SAAS,SAAS,OAA2C;CAC3D,OAAO,SAAS,QAAQ,OAAO,UAAU,YAAY,eAAe;AACtE;AA+BA,SAAgB,WACd,iBACA,cAC0D;CAC1D,MAAM,SAAS,SAAS,eAAe,IAAI,kBAAkB,KAAA;CAC7D,MAAM,UAAU,SAAS,eAAe,IAAI,eAAe;CAC3D,MAAM,WAAW,SAAS,UAAU,KAAA;CACpC,MAAM,cAA+C,WAAW,UAAU,KAAA;CAC1E,MAAM,WAAW,SAAS,YAAY;CAEtC,MAAM,cAAc,kBAAkB;EAAE,IAAI;EAAe,MAAM;EAAe,OAAO;CAAM,UAAU,EACrG,SAAS,KAAiC,MAAM;EAC9C,MAAM,aAAa,IAAI,QAAQ,IAAI;EAEnC,MAAM,YAAY,iBAAyC;GACzD,MAAM,SAAS,WAAW;IAAE,GAAG;IAAY,GAAG;GAAa,IAAI;IAAE,GAAG;IAAc,GAAG;GAAW;GAEhG,IAAI,QAEF,OAAO,UADc,OAAO,YAAY,CAAC,SAAS,MACtB,IAAI,WAAW;IACzC,IAAI,OAAO,UAAU,CAAC,OAAO,OAAO,OAAO,KAAK;IAChD,OAAO,KAAK,EAAE,SAAS,YAAY,IAAI,SAAS,OAAO,KAAgC,EAAE,CAAC;GAC5F,CAAC;GAIH,IAAI,OAAO,KAAK,YAAY,CAAC,CAAC,SAAS,GACrC,OAAO,KAAK,EAAE,SAAS,YAAY,IAAI,SAAS,YAAY,EAAE,CAAC;GAEjE,OAAO,KAAK;EACd;EAEA,IAAI,UAEF,OAAO,UADQ,aAAa,aAAc,UACpB,GAAG,QAAQ;EAGnC,OAAO,SAAS,CAAC,CAAC;CACpB,EACF,EAAE;CAEF,SAAS,YAA+B,QAAQ,UAAU,WAAW;AACvE"}
@@ -0,0 +1,29 @@
1
+ import { HelpDetail, HelpFormat } from "../output/formatter.mjs";
2
+ import { PadroneSchema } from "../types/schema.mjs";
3
+ import { WithCommand } from "../util/type-utils.mjs";
4
+ import { CommandTypesBase, PadroneCommand } from "../types/command.mjs";
5
+ //#region src/extension/help.d.ts
6
+ type HelpArgs = {
7
+ command?: string[];
8
+ detail?: HelpDetail;
9
+ format?: HelpFormat;
10
+ all?: boolean;
11
+ };
12
+ type HelpCommand = PadroneCommand<'help', '', PadroneSchema<HelpArgs>, string, [], ['h', ''], false>;
13
+ type WithHelp<T> = WithCommand<T, 'help', HelpCommand>;
14
+ /**
15
+ * Extension that adds help support:
16
+ * - `help` command with aliases `h` and `` (empty = executes on root when no subcommand matches)
17
+ * - `--help` / `-h` flags
18
+ * - `<cmd> help` reverse syntax
19
+ * - Default help display when a command has no action
20
+ *
21
+ * Usage:
22
+ * ```ts
23
+ * createPadrone('my-cli').extend(padroneHelp())
24
+ * ```
25
+ */
26
+ declare function padroneHelp(): <T extends CommandTypesBase>(builder: T) => WithHelp<T>;
27
+ //#endregion
28
+ export { HelpCommand, WithHelp, padroneHelp };
29
+ //# sourceMappingURL=help.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help.d.mts","names":[],"sources":["../../src/extension/help.ts"],"mappings":";;;;;KAeK,QAAA;EAAa,OAAA;EAAoB,MAAA,GAAS,UAAA;EAAY,MAAA,GAAS,UAAU;EAAE,GAAA;AAAA;AAAA,KAEpE,WAAA,GAAc,cAAA,aAA2B,aAAA,CAAc,QAAA;AAAA,KAEvD,QAAA,MAAc,WAAA,CAAY,CAAA,UAAW,WAAA;;;;;;;AAJkC;AAEnF;;;;;iBAqJgB,WAAA,eAA0B,gBAAA,EAAkB,OAAA,EAAS,CAAA,KAAM,QAAA,CAAS,CAAA"}
@@ -0,0 +1,161 @@
1
+ import { resolveAllCommands, resolveCommand } from "../core/commands.mjs";
2
+ import { thenMaybe } from "../core/results.mjs";
3
+ import { defineInterceptor } from "../core/interceptors.mjs";
4
+ import { RoutingError, ValidationError } from "../core/errors.mjs";
5
+ import { formatIssueMessages } from "../core/validate.mjs";
6
+ import { getRootCommand } from "../util/utils.mjs";
7
+ import { generateHelp } from "../output/help.mjs";
8
+ import { findCommandInTree, passthroughSchema } from "./utils.mjs";
9
+ //#region src/extension/help.ts
10
+ const helpInterceptor = defineInterceptor({
11
+ id: "padrone:help",
12
+ name: "padrone:help",
13
+ order: -1e3
14
+ }, () => {
15
+ let helpText;
16
+ let showDefaultHelp = false;
17
+ return {
18
+ parse(ctx, next) {
19
+ return thenMaybe(next(), (res) => {
20
+ const hasHelpFlag = res.rawArgs.help || res.rawArgs.h;
21
+ const reverseHelp = !hasHelpFlag && res.positionalArgs?.length > 0 && res.positionalArgs[res.positionalArgs.length - 1] === "help";
22
+ if (hasHelpFlag || reverseHelp) {
23
+ delete res.rawArgs.help;
24
+ delete res.rawArgs.h;
25
+ const detail = res.rawArgs.detail;
26
+ const format = res.rawArgs.format;
27
+ const all = res.rawArgs.all;
28
+ delete res.rawArgs.detail;
29
+ delete res.rawArgs.format;
30
+ delete res.rawArgs.all;
31
+ delete res.rawArgs.d;
32
+ delete res.rawArgs.f;
33
+ const rootCommand = getRootCommand(res.command);
34
+ resolveAllCommands(rootCommand);
35
+ helpText = generateHelp(rootCommand, res.command, {
36
+ detail,
37
+ format: format ?? ctx.runtime.format,
38
+ theme: ctx.runtime.theme,
39
+ all,
40
+ terminal: ctx.runtime.terminal,
41
+ env: ctx.runtime.env()
42
+ });
43
+ return res;
44
+ }
45
+ if (helpText === void 0) {
46
+ const { command } = res;
47
+ const hasSubcommands = command.commands && command.commands.length > 0;
48
+ const hasSchema = command.argsSchema != null;
49
+ const hasUnmatchedTerms = res.positionalArgs?.length > 0 && !command.meta?.positional?.length;
50
+ if (!command.action && (hasSubcommands || !hasSchema) && !hasUnmatchedTerms) showDefaultHelp = true;
51
+ }
52
+ return res;
53
+ });
54
+ },
55
+ validate(_ctx, next) {
56
+ if (helpText !== void 0) return {
57
+ args: void 0,
58
+ argsResult: { value: void 0 }
59
+ };
60
+ return next();
61
+ },
62
+ execute(ctx, next) {
63
+ if (helpText !== void 0) return { result: helpText };
64
+ if (showDefaultHelp) {
65
+ const rootCommand = getRootCommand(ctx.command);
66
+ resolveAllCommands(rootCommand);
67
+ return { result: generateHelp(rootCommand, ctx.command, {
68
+ format: ctx.runtime.format,
69
+ theme: ctx.runtime.theme,
70
+ terminal: ctx.runtime.terminal,
71
+ env: ctx.runtime.env()
72
+ }) };
73
+ }
74
+ return next();
75
+ },
76
+ error(ctx, next) {
77
+ return thenMaybe(next(), (er) => {
78
+ if (ctx.caller !== "cli" || !er.error) return er;
79
+ const rootCommand = getRootCommand(ctx.command);
80
+ if (er.error instanceof RoutingError) {
81
+ const targetPath = er.error.command;
82
+ const sourceCmd = (targetPath ? findCommandInTree(targetPath, rootCommand) : void 0) ?? rootCommand;
83
+ ctx.runtime.error(er.error.message);
84
+ if (er.error.suggestions.length > 0) {
85
+ const visibleCommands = (sourceCmd.commands ?? []).filter((c) => !c.hidden && c.name);
86
+ if (visibleCommands.length > 0) {
87
+ for (const cmd of visibleCommands) resolveCommand(cmd);
88
+ const cmdList = visibleCommands.map((c) => c.name).join(", ");
89
+ ctx.runtime.output(`\nAvailable commands: ${cmdList}`);
90
+ }
91
+ } else {
92
+ resolveAllCommands(rootCommand);
93
+ const helpText = generateHelp(rootCommand, sourceCmd, {
94
+ format: ctx.runtime.format,
95
+ theme: ctx.runtime.theme,
96
+ terminal: ctx.runtime.terminal,
97
+ env: ctx.runtime.env()
98
+ });
99
+ ctx.runtime.error(helpText);
100
+ }
101
+ return er;
102
+ }
103
+ if (er.error instanceof ValidationError) {
104
+ const targetPath = er.error.command;
105
+ const targetCommand = targetPath ? findCommandInTree(targetPath, rootCommand) : void 0;
106
+ const issueMessages = formatIssueMessages(er.error.issues);
107
+ resolveAllCommands(rootCommand);
108
+ const helpText = generateHelp(rootCommand, targetCommand ?? rootCommand, {
109
+ format: ctx.runtime.format,
110
+ theme: ctx.runtime.theme,
111
+ terminal: ctx.runtime.terminal,
112
+ env: ctx.runtime.env()
113
+ });
114
+ ctx.runtime.error(`Validation error:\n${issueMessages}`);
115
+ ctx.runtime.error(helpText);
116
+ return er;
117
+ }
118
+ return er;
119
+ });
120
+ }
121
+ };
122
+ });
123
+ /**
124
+ * Extension that adds help support:
125
+ * - `help` command with aliases `h` and `` (empty = executes on root when no subcommand matches)
126
+ * - `--help` / `-h` flags
127
+ * - `<cmd> help` reverse syntax
128
+ * - Default help display when a command has no action
129
+ *
130
+ * Usage:
131
+ * ```ts
132
+ * createPadrone('my-cli').extend(padroneHelp())
133
+ * ```
134
+ */
135
+ function padroneHelp() {
136
+ return ((builder) => builder.command(["help", "h"], (c) => c.configure({
137
+ description: "Display help for a command",
138
+ hidden: true
139
+ }).arguments(passthroughSchema({
140
+ command: "string[]",
141
+ detail: "string",
142
+ format: "string",
143
+ all: "boolean"
144
+ }), { positional: ["...command"] }).action((args, ctx) => {
145
+ const rootCommand = getRootCommand(ctx.command);
146
+ resolveAllCommands(rootCommand);
147
+ const commandName = args.command?.join(" ");
148
+ return generateHelp(rootCommand, (commandName ? findCommandInTree(commandName, rootCommand) : rootCommand) ?? rootCommand, {
149
+ detail: args.detail,
150
+ format: args.format ?? ctx.runtime.format,
151
+ theme: ctx.runtime.theme,
152
+ all: args.all,
153
+ terminal: ctx.runtime.terminal,
154
+ env: ctx.runtime.env()
155
+ });
156
+ })).intercept(helpInterceptor));
157
+ }
158
+ //#endregion
159
+ export { padroneHelp };
160
+
161
+ //# sourceMappingURL=help.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help.mjs","names":[],"sources":["../../src/extension/help.ts"],"sourcesContent":["import { resolveAllCommands, resolveCommand } from '../core/commands.ts';\nimport { RoutingError, ValidationError } from '../core/errors.ts';\nimport { defineInterceptor } from '../core/interceptors.ts';\nimport { thenMaybe } from '../core/results.ts';\nimport { formatIssueMessages } from '../core/validate.ts';\nimport type { HelpDetail, HelpFormat } from '../output/formatter.ts';\nimport { generateHelp } from '../output/help.ts';\nimport type { AnyPadroneBuilder, AnyPadroneCommand, CommandTypesBase, PadroneCommand } from '../types/index.ts';\nimport type { PadroneSchema } from '../types/schema.ts';\nimport type { WithCommand } from '../util/type-utils.ts';\nimport { getRootCommand } from '../util/utils.ts';\nimport { findCommandInTree, passthroughSchema } from './utils.ts';\n\n// ── Types ────────────────────────────────────────────────────────────────\n\ntype HelpArgs = { command?: string[]; detail?: HelpDetail; format?: HelpFormat; all?: boolean };\n\nexport type HelpCommand = PadroneCommand<'help', '', PadroneSchema<HelpArgs>, string, [], ['h', ''], false>;\n\nexport type WithHelp<T> = WithCommand<T, 'help', HelpCommand>;\n\n// ── Interceptor ─────────────────────────────────────────────────────────\n\nconst helpInterceptor = defineInterceptor({ id: 'padrone:help', name: 'padrone:help', order: -1000 }, () => {\n let helpText: string | undefined;\n let showDefaultHelp = false;\n\n return {\n parse(ctx, next) {\n return thenMaybe(next(), (res) => {\n const hasHelpFlag = res.rawArgs.help || res.rawArgs.h;\n const reverseHelp = !hasHelpFlag && res.positionalArgs?.length > 0 && res.positionalArgs[res.positionalArgs.length - 1] === 'help';\n\n if (hasHelpFlag || reverseHelp) {\n delete res.rawArgs.help;\n delete res.rawArgs.h;\n\n const detail = res.rawArgs.detail as HelpDetail | undefined;\n const format = res.rawArgs.format as HelpFormat | undefined;\n const all = res.rawArgs.all as boolean | undefined;\n delete res.rawArgs.detail;\n delete res.rawArgs.format;\n delete res.rawArgs.all;\n delete res.rawArgs.d;\n delete res.rawArgs.f;\n\n const rootCommand = getRootCommand(res.command);\n resolveAllCommands(rootCommand);\n\n helpText = generateHelp(rootCommand, res.command, {\n detail,\n format: format ?? ctx.runtime.format,\n theme: ctx.runtime.theme,\n all,\n terminal: ctx.runtime.terminal,\n env: ctx.runtime.env(),\n });\n return res;\n }\n\n // Track whether the parsed command has no action (for default help in execute phase)\n if (helpText === undefined) {\n const { command } = res;\n const hasSubcommands = command.commands && command.commands.length > 0;\n const hasSchema = command.argsSchema != null;\n const hasUnmatchedTerms = res.positionalArgs?.length > 0 && !command.meta?.positional?.length;\n if (!command.action && (hasSubcommands || !hasSchema) && !hasUnmatchedTerms) {\n showDefaultHelp = true;\n }\n }\n\n return res;\n });\n },\n validate(_ctx, next) {\n if (helpText !== undefined) return { args: undefined as any, argsResult: { value: undefined } as any };\n return next();\n },\n execute(ctx, next) {\n if (helpText !== undefined) return { result: helpText };\n if (showDefaultHelp) {\n const rootCommand = getRootCommand(ctx.command);\n resolveAllCommands(rootCommand);\n return {\n result: generateHelp(rootCommand, ctx.command, {\n format: ctx.runtime.format,\n theme: ctx.runtime.theme,\n terminal: ctx.runtime.terminal,\n env: ctx.runtime.env(),\n }),\n };\n }\n return next();\n },\n error(ctx, next) {\n return thenMaybe(next(), (er) => {\n if (ctx.caller !== 'cli' || !er.error) return er;\n\n const rootCommand = getRootCommand(ctx.command);\n\n if (er.error instanceof RoutingError) {\n const targetPath = er.error.command;\n const targetCommand = targetPath ? findCommandInTree(targetPath, rootCommand) : undefined;\n const sourceCmd = targetCommand ?? rootCommand;\n\n ctx.runtime.error(er.error.message);\n\n if (er.error.suggestions.length > 0) {\n const visibleCommands = (sourceCmd.commands ?? []).filter((c: AnyPadroneCommand) => !c.hidden && c.name);\n if (visibleCommands.length > 0) {\n for (const cmd of visibleCommands) resolveCommand(cmd);\n const cmdList = visibleCommands.map((c: AnyPadroneCommand) => c.name).join(', ');\n ctx.runtime.output(`\\nAvailable commands: ${cmdList}`);\n }\n } else {\n resolveAllCommands(rootCommand);\n const helpText = generateHelp(rootCommand, sourceCmd, {\n format: ctx.runtime.format,\n theme: ctx.runtime.theme,\n terminal: ctx.runtime.terminal,\n env: ctx.runtime.env(),\n });\n ctx.runtime.error(helpText);\n }\n\n return er;\n }\n\n if (er.error instanceof ValidationError) {\n const targetPath = er.error.command;\n const targetCommand = targetPath ? findCommandInTree(targetPath, rootCommand) : undefined;\n const issueMessages = formatIssueMessages(er.error.issues);\n\n resolveAllCommands(rootCommand);\n const helpText = generateHelp(rootCommand, targetCommand ?? rootCommand, {\n format: ctx.runtime.format,\n theme: ctx.runtime.theme,\n terminal: ctx.runtime.terminal,\n env: ctx.runtime.env(),\n });\n ctx.runtime.error(`Validation error:\\n${issueMessages}`);\n ctx.runtime.error(helpText);\n\n return er;\n }\n\n return er;\n });\n },\n };\n});\n\n// ── Extension ────────────────────────────────────────────────────────────\n\n/**\n * Extension that adds help support:\n * - `help` command with aliases `h` and `` (empty = executes on root when no subcommand matches)\n * - `--help` / `-h` flags\n * - `<cmd> help` reverse syntax\n * - Default help display when a command has no action\n *\n * Usage:\n * ```ts\n * createPadrone('my-cli').extend(padroneHelp())\n * ```\n */\nexport function padroneHelp(): <T extends CommandTypesBase>(builder: T) => WithHelp<T> {\n return ((builder: AnyPadroneBuilder) =>\n builder\n .command(['help', 'h'], (c) =>\n c\n .configure({ description: 'Display help for a command', hidden: true })\n .arguments(passthroughSchema({ command: 'string[]', detail: 'string', format: 'string', all: 'boolean' }), {\n positional: ['...command'],\n })\n .action((args, ctx) => {\n const rootCommand = getRootCommand(ctx.command);\n resolveAllCommands(rootCommand);\n const commandName = args.command?.join(' ');\n const targetCommand = commandName ? findCommandInTree(commandName, rootCommand) : rootCommand;\n return generateHelp(rootCommand, targetCommand ?? rootCommand, {\n detail: args.detail as HelpDetail,\n format: (args.format as HelpFormat) ?? ctx.runtime.format,\n theme: ctx.runtime.theme,\n all: args.all,\n terminal: ctx.runtime.terminal,\n env: ctx.runtime.env(),\n });\n }),\n )\n .intercept(helpInterceptor)) as any;\n}\n"],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import { WithAsync } from "../util/type-utils.mjs";
2
+ import { PadroneLogLevel, PadroneLogger, PadroneLoggerConfig, WithLogger, padroneLogger } from "./logger.mjs";
3
+ import { HelpCommand, WithHelp, padroneHelp } from "./help.mjs";
4
+ import { VersionCommand, WithVersion, padroneVersion } from "./version.mjs";
5
+ import { PadroneAutoOutputOptions, padroneAutoOutput } from "./auto-output.mjs";
6
+ import { padroneColor } from "./color.mjs";
7
+ import { PadroneConfigOptions, padroneConfig } from "./config.mjs";
8
+ import { PadroneEnvOptions, padroneEnv } from "./env.mjs";
9
+ import { padroneInteractive } from "./interactive.mjs";
10
+ import { PadroneProgressRenderer, createTerminalProgress } from "./progress-renderer.mjs";
11
+ import { PadroneProgressConfig, PadroneProgressDefaults, PadroneProgressMessage, PadroneProgressMessages, WithProgress, padroneProgress } from "./progress.mjs";
12
+ import { WithRepl, padroneRepl } from "./repl.mjs";
13
+ import { padroneSignalHandling } from "./signal.mjs";
14
+ import { padroneStdin } from "./stdin.mjs";
15
+ import { padroneSuggestions } from "./suggestions.mjs";
16
+ import { PadroneTimingOptions, padroneTiming } from "./timing.mjs";
17
+ import { padroneUpdateCheck } from "./update-check.mjs";
18
+ export { type HelpCommand, type PadroneLogLevel, type PadroneLogger, type PadroneLoggerConfig, type PadroneProgressConfig, type PadroneProgressDefaults, type PadroneProgressMessage, type PadroneProgressMessages, type PadroneProgressRenderer, type VersionCommand, type WithAsync, type WithHelp, type WithLogger, type WithProgress, type WithRepl, type WithVersion, createTerminalProgress, padroneAutoOutput, padroneColor, padroneConfig, padroneEnv, padroneHelp, padroneInteractive, padroneLogger, padroneProgress, padroneRepl, padroneSignalHandling, padroneStdin, padroneSuggestions, padroneTiming, padroneUpdateCheck, padroneVersion };
@@ -0,0 +1,31 @@
1
+ import { CommandTypesBase } from "../types/command.mjs";
2
+ //#region src/extension/ink.d.ts
3
+ /** Checks whether a value is a React element (JSX) by inspecting its `$$typeof` symbol. */
4
+ declare function isReactElement(value: unknown): boolean;
5
+ type InkOptions = {
6
+ /** Whether to wait for the Ink app to unmount before resolving. Defaults to `true`. */waitUntilExit?: boolean; /** Options forwarded to Ink's `render()`. */
7
+ render?: import('ink').RenderOptions;
8
+ };
9
+ /**
10
+ * Extension that renders React (Ink) components returned from command actions.
11
+ *
12
+ * When a command's action returns a React element (JSX), this extension
13
+ * renders it using Ink instead of passing it to the normal output path.
14
+ *
15
+ * Requires `ink` and `react` as peer dependencies.
16
+ *
17
+ * ```ts
18
+ * import { createPadrone } from 'padrone';
19
+ * import { padroneInk } from 'padrone/ink';
20
+ *
21
+ * const program = createPadrone('my-tui')
22
+ * .extend(padroneInk())
23
+ * .command('dashboard', (c) =>
24
+ * c.action(() => <Dashboard />)
25
+ * );
26
+ * ```
27
+ */
28
+ declare function padroneInk(options?: InkOptions): <T extends CommandTypesBase>(builder: T) => T;
29
+ //#endregion
30
+ export { InkOptions, isReactElement, padroneInk };
31
+ //# sourceMappingURL=ink.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ink.d.mts","names":[],"sources":["../../src/extension/ink.ts"],"mappings":";;;iBAUgB,cAAA,CAAe,KAAc;AAAA,KAQjC,UAAA;EARI,uFAUd,aAAA;EAEA,MAAA,iBAAuB,aAAA;AAAA;AAJzB;;;;;;;;AAIsC;AAoEtC;;;;;;;;;;AAxEA,iBAwEgB,UAAA,CAAW,OAAA,GAAU,UAAA,cAAwB,gBAAA,EAAkB,OAAA,EAAS,CAAA,KAAM,CAAA"}