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,174 @@
1
+ //#region src/util/dotenv.ts
2
+ /** Returns ordered list of `.env` file names to load (no fs access). */
3
+ function resolveEnvFiles(modes = [], local = true, base = true) {
4
+ const files = [];
5
+ if (base) {
6
+ files.push(".env");
7
+ if (local) files.push(".env.local");
8
+ }
9
+ for (const mode of modes) {
10
+ files.push(`.env.${mode}`);
11
+ if (local) files.push(`.env.${mode}.local`);
12
+ }
13
+ return files;
14
+ }
15
+ /** Parse a `.env` file string into key-value pairs. */
16
+ function parseEnvFile(content) {
17
+ const result = {};
18
+ const lines = content.split("\n");
19
+ let i = 0;
20
+ while (i < lines.length) {
21
+ const line = lines[i].trim();
22
+ i++;
23
+ if (!line || line.startsWith("#")) continue;
24
+ const stripped = line.startsWith("export ") ? line.slice(7) : line;
25
+ const eqIndex = stripped.indexOf("=");
26
+ if (eqIndex === -1) continue;
27
+ const key = stripped.slice(0, eqIndex).trim();
28
+ let raw = stripped.slice(eqIndex + 1);
29
+ const trimmedRaw = raw.trimStart();
30
+ const quote = trimmedRaw[0];
31
+ if (quote === "\"" || quote === "'" || quote === "`") {
32
+ let value = trimmedRaw.slice(1);
33
+ const closeIndex = findClosingQuote(value, quote);
34
+ if (closeIndex !== -1) value = value.slice(0, closeIndex);
35
+ else while (i < lines.length) {
36
+ const nextLine = lines[i];
37
+ i++;
38
+ const ci = findClosingQuote(nextLine, quote);
39
+ if (ci !== -1) {
40
+ value += `\n${nextLine.slice(0, ci)}`;
41
+ break;
42
+ }
43
+ value += `\n${nextLine}`;
44
+ }
45
+ if (quote === "\"") value = unescapeDoubleQuoted(value);
46
+ result[key] = value;
47
+ } else {
48
+ const commentIndex = raw.indexOf(" #");
49
+ if (commentIndex !== -1) raw = raw.slice(0, commentIndex);
50
+ result[key] = raw.trim();
51
+ }
52
+ }
53
+ return result;
54
+ }
55
+ function findClosingQuote(s, quote) {
56
+ let i = 0;
57
+ while (i < s.length) {
58
+ if (s[i] === "\\" && quote === "\"") {
59
+ i += 2;
60
+ continue;
61
+ }
62
+ if (s[i] === quote) return i;
63
+ i++;
64
+ }
65
+ return -1;
66
+ }
67
+ function unescapeDoubleQuoted(s) {
68
+ return s.replace(/\\n/g, "\n").replace(/\\r/g, "\r").replace(/\\t/g, " ").replace(/\\"/g, "\"").replace(/\\\\/g, "\\");
69
+ }
70
+ /**
71
+ * Expand `$VAR`, `${VAR}`, `${VAR:-default}`, `${VAR-default}` in a string.
72
+ * Escaped `\$` produces a literal `$`. Undefined variables resolve to `""`.
73
+ */
74
+ function expandVariables(value, env) {
75
+ let result = "";
76
+ let i = 0;
77
+ while (i < value.length) {
78
+ if (value[i] === "\\" && value[i + 1] === "$") {
79
+ result += "$";
80
+ i += 2;
81
+ continue;
82
+ }
83
+ if (value[i] === "$") {
84
+ i++;
85
+ if (i >= value.length) {
86
+ result += "$";
87
+ break;
88
+ }
89
+ if (value[i] === "{") {
90
+ i++;
91
+ const closeIdx = value.indexOf("}", i);
92
+ if (closeIdx === -1) {
93
+ result += `\${${value.slice(i)}`;
94
+ break;
95
+ }
96
+ const expr = value.slice(i, closeIdx);
97
+ i = closeIdx + 1;
98
+ const colonDashIdx = expr.indexOf(":-");
99
+ const dashIdx = colonDashIdx === -1 ? expr.indexOf("-") : -1;
100
+ if (colonDashIdx !== -1) {
101
+ const varName = expr.slice(0, colonDashIdx);
102
+ const fallback = expr.slice(colonDashIdx + 2);
103
+ const val = env[varName];
104
+ result += val ? val : expandVariables(fallback, env);
105
+ } else if (dashIdx !== -1) {
106
+ const varName = expr.slice(0, dashIdx);
107
+ const fallback = expr.slice(dashIdx + 1);
108
+ const val = env[varName];
109
+ result += val !== void 0 ? val : expandVariables(fallback, env);
110
+ } else result += env[expr] ?? "";
111
+ } else {
112
+ let varName = "";
113
+ while (i < value.length && /[\w]/.test(value[i])) {
114
+ varName += value[i];
115
+ i++;
116
+ }
117
+ if (varName) result += env[varName] ?? "";
118
+ else result += "$";
119
+ }
120
+ continue;
121
+ }
122
+ result += value[i];
123
+ i++;
124
+ }
125
+ return result;
126
+ }
127
+ /**
128
+ * Load and merge `.env` files, returning the combined key-value map.
129
+ * Variable expansion uses the merged file values + process env as lookup.
130
+ *
131
+ * Returns synchronously when `node:fs`/`node:path` are already cached (typical),
132
+ * or a Promise on the very first call.
133
+ */
134
+ function loadEnvFiles(options, processEnv) {
135
+ if (typeof process === "undefined") return {};
136
+ try {
137
+ if (_fs && _path) return loadEnvFilesSync(_fs, _path, options, processEnv);
138
+ return initNodeModules().then(() => loadEnvFilesSync(_fs, _path, options, processEnv)).catch(() => ({}));
139
+ } catch {
140
+ return {};
141
+ }
142
+ }
143
+ let _fs;
144
+ let _path;
145
+ async function initNodeModules() {
146
+ if (_fs && _path) return;
147
+ _fs = await import("node:fs");
148
+ _path = await import("node:path");
149
+ }
150
+ if (typeof process !== "undefined") initNodeModules();
151
+ function loadEnvFilesSync(fs, path, options, processEnv) {
152
+ const dir = options.dir ?? process.cwd();
153
+ const fileNames = resolveEnvFiles(options.modes, options.local ?? true, options.base ?? true);
154
+ const merged = {};
155
+ for (const name of fileNames) {
156
+ const filePath = path.resolve(dir, name);
157
+ if (!fs.existsSync(filePath)) continue;
158
+ const parsed = parseEnvFile(fs.readFileSync(filePath, "utf-8"));
159
+ Object.assign(merged, parsed);
160
+ }
161
+ const lookup = options.override ? {
162
+ ...processEnv,
163
+ ...merged
164
+ } : {
165
+ ...merged,
166
+ ...processEnv
167
+ };
168
+ for (const key of Object.keys(merged)) merged[key] = expandVariables(merged[key], lookup);
169
+ return merged;
170
+ }
171
+ //#endregion
172
+ export { expandVariables, loadEnvFiles, parseEnvFile, resolveEnvFiles };
173
+
174
+ //# sourceMappingURL=dotenv.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dotenv.mjs","names":[],"sources":["../../src/util/dotenv.ts"],"sourcesContent":["// ── File resolution ─────────────────────────────────────────────────────\n\n/** Returns ordered list of `.env` file names to load (no fs access). */\nexport function resolveEnvFiles(modes: string[] = [], local = true, base = true): string[] {\n const files: string[] = [];\n if (base) {\n files.push('.env');\n if (local) files.push('.env.local');\n }\n for (const mode of modes) {\n files.push(`.env.${mode}`);\n if (local) files.push(`.env.${mode}.local`);\n }\n return files;\n}\n\n// ── Parser ──────────────────────────────────────────────────────────────\n\n/** Parse a `.env` file string into key-value pairs. */\nexport function parseEnvFile(content: string): Record<string, string> {\n const result: Record<string, string> = {};\n const lines = content.split('\\n');\n let i = 0;\n\n while (i < lines.length) {\n const line = lines[i]!.trim();\n i++;\n\n // Skip empty lines and comments\n if (!line || line.startsWith('#')) continue;\n\n // Strip optional `export ` prefix\n const stripped = line.startsWith('export ') ? line.slice(7) : line;\n\n const eqIndex = stripped.indexOf('=');\n if (eqIndex === -1) continue;\n\n const key = stripped.slice(0, eqIndex).trim();\n let raw = stripped.slice(eqIndex + 1);\n\n // Detect quoted values\n const trimmedRaw = raw.trimStart();\n const quote = trimmedRaw[0];\n\n if (quote === '\"' || quote === \"'\" || quote === '`') {\n let value = trimmedRaw.slice(1);\n\n // Check for closing quote on the same line\n const closeIndex = findClosingQuote(value, quote);\n if (closeIndex !== -1) {\n value = value.slice(0, closeIndex);\n } else {\n // Multiline: accumulate until closing quote\n while (i < lines.length) {\n const nextLine = lines[i]!;\n i++;\n const ci = findClosingQuote(nextLine, quote);\n if (ci !== -1) {\n value += `\\n${nextLine.slice(0, ci)}`;\n break;\n }\n value += `\\n${nextLine}`;\n }\n }\n\n if (quote === '\"') value = unescapeDoubleQuoted(value);\n result[key] = value;\n } else {\n // Unquoted: strip inline comments, trim\n const commentIndex = raw.indexOf(' #');\n if (commentIndex !== -1) raw = raw.slice(0, commentIndex);\n result[key] = raw.trim();\n }\n }\n\n return result;\n}\n\nfunction findClosingQuote(s: string, quote: string): number {\n let i = 0;\n while (i < s.length) {\n if (s[i] === '\\\\' && quote === '\"') {\n i += 2; // skip escaped char\n continue;\n }\n if (s[i] === quote) return i;\n i++;\n }\n return -1;\n}\n\nfunction unescapeDoubleQuoted(s: string): string {\n return s.replace(/\\\\n/g, '\\n').replace(/\\\\r/g, '\\r').replace(/\\\\t/g, '\\t').replace(/\\\\\"/g, '\"').replace(/\\\\\\\\/g, '\\\\');\n}\n\n// ── Variable expansion ──────────────────────────────────────────────────\n\n/**\n * Expand `$VAR`, `${VAR}`, `${VAR:-default}`, `${VAR-default}` in a string.\n * Escaped `\\$` produces a literal `$`. Undefined variables resolve to `\"\"`.\n */\nexport function expandVariables(value: string, env: Record<string, string | undefined>): string {\n let result = '';\n let i = 0;\n\n while (i < value.length) {\n if (value[i] === '\\\\' && value[i + 1] === '$') {\n result += '$';\n i += 2;\n continue;\n }\n\n if (value[i] === '$') {\n i++;\n if (i >= value.length) {\n result += '$';\n break;\n }\n\n if (value[i] === '{') {\n // ${VAR}, ${VAR:-default}, ${VAR-default}\n i++;\n const closeIdx = value.indexOf('}', i);\n if (closeIdx === -1) {\n result += `\\${${value.slice(i)}`;\n break;\n }\n\n const expr = value.slice(i, closeIdx);\n i = closeIdx + 1;\n\n const colonDashIdx = expr.indexOf(':-');\n const dashIdx = colonDashIdx === -1 ? expr.indexOf('-') : -1;\n\n if (colonDashIdx !== -1) {\n // ${VAR:-default} — use default if unset or empty\n const varName = expr.slice(0, colonDashIdx);\n const fallback = expr.slice(colonDashIdx + 2);\n const val = env[varName];\n result += val ? val : expandVariables(fallback, env);\n } else if (dashIdx !== -1) {\n // ${VAR-default} — use default only if unset\n const varName = expr.slice(0, dashIdx);\n const fallback = expr.slice(dashIdx + 1);\n const val = env[varName];\n result += val !== undefined ? val : expandVariables(fallback, env);\n } else {\n result += env[expr] ?? '';\n }\n } else {\n // $VAR — collect word chars\n let varName = '';\n while (i < value.length && /[\\w]/.test(value[i]!)) {\n varName += value[i];\n i++;\n }\n if (varName) {\n result += env[varName] ?? '';\n } else {\n result += '$';\n }\n }\n continue;\n }\n\n result += value[i];\n i++;\n }\n\n return result;\n}\n\n// ── File loading ────────────────────────────────────────────────────────\n\nexport type LoadEnvFilesOptions = {\n dir?: string;\n modes?: string[];\n local?: boolean;\n override?: boolean;\n base?: boolean;\n};\n\n/**\n * Load and merge `.env` files, returning the combined key-value map.\n * Variable expansion uses the merged file values + process env as lookup.\n *\n * Returns synchronously when `node:fs`/`node:path` are already cached (typical),\n * or a Promise on the very first call.\n */\nexport function loadEnvFiles(\n options: LoadEnvFilesOptions,\n processEnv: Record<string, string | undefined>,\n): Record<string, string> | Promise<Record<string, string>> {\n if (typeof process === 'undefined') return {};\n\n try {\n if (_fs && _path) return loadEnvFilesSync(_fs, _path, options, processEnv);\n return initNodeModules()\n .then(() => loadEnvFilesSync(_fs!, _path!, options, processEnv))\n .catch(() => ({}) as Record<string, string>);\n } catch {\n return {};\n }\n}\n\n// ── Internals ───────────────────────────────────────────────────────────\n\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\nif (typeof process !== 'undefined') initNodeModules();\n\nfunction loadEnvFilesSync(\n fs: typeof import('node:fs'),\n path: typeof import('node:path'),\n options: LoadEnvFilesOptions,\n processEnv: Record<string, string | undefined>,\n): Record<string, string> {\n const dir = options.dir ?? process.cwd();\n const fileNames = resolveEnvFiles(options.modes, options.local ?? true, options.base ?? true);\n const merged: Record<string, string> = {};\n\n for (const name of fileNames) {\n const filePath = path.resolve(dir, name);\n if (!fs.existsSync(filePath)) continue;\n const content = fs.readFileSync(filePath, 'utf-8');\n const parsed = parseEnvFile(content);\n Object.assign(merged, parsed);\n }\n\n // Expand variables: file values + processEnv as lookup (processEnv wins in lookup unless override)\n const lookup = options.override ? { ...processEnv, ...merged } : { ...merged, ...processEnv };\n for (const key of Object.keys(merged)) {\n merged[key] = expandVariables(merged[key]!, lookup);\n }\n\n return merged;\n}\n"],"mappings":"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"}
@@ -0,0 +1,80 @@
1
+ //#region src/util/shell-utils.ts
2
+ /**
3
+ * Convert a camelCase string to kebab-case.
4
+ * Returns null if the string has no uppercase letters (no conversion needed).
5
+ */
6
+ function camelToKebab(str) {
7
+ if (!/[A-Z]/.test(str)) return null;
8
+ return str.replace(/[A-Z]/g, (ch) => `-${ch.toLowerCase()}`);
9
+ }
10
+ /**
11
+ * Detects the current shell from environment variables and process info.
12
+ * @returns The detected shell type, or undefined if unknown
13
+ */
14
+ async function detectShell() {
15
+ if (typeof process === "undefined") return void 0;
16
+ const shellEnv = process.env.SHELL || "";
17
+ if (shellEnv.includes("zsh")) return "zsh";
18
+ if (shellEnv.includes("bash")) return "bash";
19
+ if (shellEnv.includes("fish")) return "fish";
20
+ if (process.env.PSModulePath || process.env.POWERSHELL_DISTRIBUTION_CHANNEL) return "powershell";
21
+ try {
22
+ const ppid = process.ppid;
23
+ if (ppid) {
24
+ const { execSync } = await import("node:child_process");
25
+ const processName = execSync(`ps -p ${ppid} -o comm=`, {
26
+ encoding: "utf-8",
27
+ stdio: [
28
+ "pipe",
29
+ "pipe",
30
+ "ignore"
31
+ ]
32
+ }).trim();
33
+ if (processName.includes("zsh")) return "zsh";
34
+ if (processName.includes("bash")) return "bash";
35
+ if (processName.includes("fish")) return "fish";
36
+ }
37
+ } catch {}
38
+ }
39
+ async function getRcFile(shell, home) {
40
+ const { homedir } = await import("node:os");
41
+ const { join } = await import("node:path");
42
+ const h = home ?? homedir();
43
+ switch (shell) {
44
+ case "bash": return join(h, ".bashrc");
45
+ case "zsh": return join(h, ".zshrc");
46
+ case "fish": return join(h, ".config", "fish", "config.fish");
47
+ case "powershell": return (typeof process !== "undefined" ? process.env.PROFILE : void 0) || join(h, "Documents", "PowerShell", "Microsoft.PowerShell_profile.ps1");
48
+ default: return null;
49
+ }
50
+ }
51
+ function escapeRegExp(str) {
52
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
53
+ }
54
+ /**
55
+ * Writes a snippet to a shell config file using begin/end markers for idempotency.
56
+ * If a block with the same begin marker exists, it is replaced. Otherwise the snippet is appended.
57
+ */
58
+ async function writeToRcFile(rcFile, snippet, beginMarker, endMarker) {
59
+ const { existsSync, mkdirSync, readFileSync, writeFileSync } = await import("node:fs");
60
+ const { dirname } = await import("node:path");
61
+ const existing = existsSync(rcFile) ? readFileSync(rcFile, "utf-8") : "";
62
+ if (existing.includes(beginMarker)) {
63
+ const pattern = new RegExp(`${escapeRegExp(beginMarker)}[\\s\\S]*?${escapeRegExp(endMarker)}`);
64
+ writeFileSync(rcFile, existing.replace(pattern, snippet));
65
+ return {
66
+ file: rcFile,
67
+ updated: true
68
+ };
69
+ }
70
+ mkdirSync(dirname(rcFile), { recursive: true });
71
+ writeFileSync(rcFile, `${existing}${existing.length > 0 && !existing.endsWith("\n") ? "\n" : ""}\n${snippet}\n`);
72
+ return {
73
+ file: rcFile,
74
+ updated: false
75
+ };
76
+ }
77
+ //#endregion
78
+ export { camelToKebab, detectShell, escapeRegExp, getRcFile, writeToRcFile };
79
+
80
+ //# sourceMappingURL=shell-utils.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell-utils.mjs","names":[],"sources":["../../src/util/shell-utils.ts"],"sourcesContent":["/**\n * Convert a camelCase string to kebab-case.\n * Returns null if the string has no uppercase letters (no conversion needed).\n */\nexport function camelToKebab(str: string): string | null {\n if (!/[A-Z]/.test(str)) return null;\n return str.replace(/[A-Z]/g, (ch) => `-${ch.toLowerCase()}`);\n}\n\nexport type ShellType = 'bash' | 'zsh' | 'fish' | 'powershell';\n\n/**\n * Detects the current shell from environment variables and process info.\n * @returns The detected shell type, or undefined if unknown\n */\nexport async function detectShell(): Promise<ShellType | undefined> {\n if (typeof process === 'undefined') return undefined;\n\n // Method 1: Check SHELL environment variable (most common)\n const shellEnv = process.env.SHELL || '';\n if (shellEnv.includes('zsh')) return 'zsh';\n if (shellEnv.includes('bash')) return 'bash';\n if (shellEnv.includes('fish')) return 'fish';\n\n // Method 2: Check Windows-specific shells\n if (process.env.PSModulePath || process.env.POWERSHELL_DISTRIBUTION_CHANNEL) {\n return 'powershell';\n }\n\n // Method 3: Check parent process on Unix-like systems\n try {\n const ppid = process.ppid;\n if (ppid) {\n const { execSync } = (await import('node:child_process')) as typeof import('node:child_process');\n const processName = execSync(`ps -p ${ppid} -o comm=`, {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'ignore'],\n }).trim();\n\n if (processName.includes('zsh')) return 'zsh';\n if (processName.includes('bash')) return 'bash';\n if (processName.includes('fish')) return 'fish';\n }\n } catch {\n // Ignore errors (e.g., ps not available)\n }\n\n return undefined;\n}\n\nexport async function getRcFile(shell: ShellType, home?: string): Promise<string | null> {\n const { homedir } = await import('node:os');\n const { join } = await import('node:path');\n const h = home ?? homedir();\n switch (shell) {\n case 'bash':\n return join(h, '.bashrc');\n case 'zsh':\n return join(h, '.zshrc');\n case 'fish':\n return join(h, '.config', 'fish', 'config.fish');\n case 'powershell':\n return (\n (typeof process !== 'undefined' ? process.env.PROFILE : undefined) ||\n join(h, 'Documents', 'PowerShell', 'Microsoft.PowerShell_profile.ps1')\n );\n default:\n return null;\n }\n}\n\nexport function escapeRegExp(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/**\n * Writes a snippet to a shell config file using begin/end markers for idempotency.\n * If a block with the same begin marker exists, it is replaced. Otherwise the snippet is appended.\n */\nexport async function writeToRcFile(\n rcFile: string,\n snippet: string,\n beginMarker: string,\n endMarker: string,\n): Promise<{ file: string; updated: boolean }> {\n const { existsSync, mkdirSync, readFileSync, writeFileSync } = await import('node:fs');\n const { dirname } = await import('node:path');\n const existing = existsSync(rcFile) ? readFileSync(rcFile, 'utf-8') : '';\n\n if (existing.includes(beginMarker)) {\n const pattern = new RegExp(`${escapeRegExp(beginMarker)}[\\\\s\\\\S]*?${escapeRegExp(endMarker)}`);\n writeFileSync(rcFile, existing.replace(pattern, snippet));\n return { file: rcFile, updated: true };\n }\n\n mkdirSync(dirname(rcFile), { recursive: true });\n const separator = existing.length > 0 && !existing.endsWith('\\n') ? '\\n' : '';\n writeFileSync(rcFile, `${existing}${separator}\\n${snippet}\\n`);\n return { file: rcFile, updated: false };\n}\n"],"mappings":";;;;;AAIA,SAAgB,aAAa,KAA4B;CACvD,IAAI,CAAC,QAAQ,KAAK,GAAG,GAAG,OAAO;CAC/B,OAAO,IAAI,QAAQ,WAAW,OAAO,IAAI,GAAG,YAAY,GAAG;AAC7D;;;;;AAQA,eAAsB,cAA8C;CAClE,IAAI,OAAO,YAAY,aAAa,OAAO,KAAA;CAG3C,MAAM,WAAW,QAAQ,IAAI,SAAS;CACtC,IAAI,SAAS,SAAS,KAAK,GAAG,OAAO;CACrC,IAAI,SAAS,SAAS,MAAM,GAAG,OAAO;CACtC,IAAI,SAAS,SAAS,MAAM,GAAG,OAAO;CAGtC,IAAI,QAAQ,IAAI,gBAAgB,QAAQ,IAAI,iCAC1C,OAAO;CAIT,IAAI;EACF,MAAM,OAAO,QAAQ;EACrB,IAAI,MAAM;GACR,MAAM,EAAE,aAAc,MAAM,OAAO;GACnC,MAAM,cAAc,SAAS,SAAS,KAAK,YAAY;IACrD,UAAU;IACV,OAAO;KAAC;KAAQ;KAAQ;IAAQ;GAClC,CAAC,CAAC,CAAC,KAAK;GAER,IAAI,YAAY,SAAS,KAAK,GAAG,OAAO;GACxC,IAAI,YAAY,SAAS,MAAM,GAAG,OAAO;GACzC,IAAI,YAAY,SAAS,MAAM,GAAG,OAAO;EAC3C;CACF,QAAQ,CAER;AAGF;AAEA,eAAsB,UAAU,OAAkB,MAAuC;CACvF,MAAM,EAAE,YAAY,MAAM,OAAO;CACjC,MAAM,EAAE,SAAS,MAAM,OAAO;CAC9B,MAAM,IAAI,QAAQ,QAAQ;CAC1B,QAAQ,OAAR;EACE,KAAK,QACH,OAAO,KAAK,GAAG,SAAS;EAC1B,KAAK,OACH,OAAO,KAAK,GAAG,QAAQ;EACzB,KAAK,QACH,OAAO,KAAK,GAAG,WAAW,QAAQ,aAAa;EACjD,KAAK,cACH,QACG,OAAO,YAAY,cAAc,QAAQ,IAAI,UAAU,KAAA,MACxD,KAAK,GAAG,aAAa,cAAc,kCAAkC;EAEzE,SACE,OAAO;CACX;AACF;AAEA,SAAgB,aAAa,KAAqB;CAChD,OAAO,IAAI,QAAQ,uBAAuB,MAAM;AAClD;;;;;AAMA,eAAsB,cACpB,QACA,SACA,aACA,WAC6C;CAC7C,MAAM,EAAE,YAAY,WAAW,cAAc,kBAAkB,MAAM,OAAO;CAC5E,MAAM,EAAE,YAAY,MAAM,OAAO;CACjC,MAAM,WAAW,WAAW,MAAM,IAAI,aAAa,QAAQ,OAAO,IAAI;CAEtE,IAAI,SAAS,SAAS,WAAW,GAAG;EAClC,MAAM,UAAU,IAAI,OAAO,GAAG,aAAa,WAAW,EAAE,YAAY,aAAa,SAAS,GAAG;EAC7F,cAAc,QAAQ,SAAS,QAAQ,SAAS,OAAO,CAAC;EACxD,OAAO;GAAE,MAAM;GAAQ,SAAS;EAAK;CACvC;CAEA,UAAU,QAAQ,MAAM,GAAG,EAAE,WAAW,KAAK,CAAC;CAE9C,cAAc,QAAQ,GAAG,WADP,SAAS,SAAS,KAAK,CAAC,SAAS,SAAS,IAAI,IAAI,OAAO,GAC7B,IAAI,QAAQ,GAAG;CAC7D,OAAO;EAAE,MAAM;EAAQ,SAAS;CAAM;AACxC"}
@@ -0,0 +1,33 @@
1
+ import { PadroneSchema } from "../types/schema.mjs";
2
+ import { StandardSchemaV1 } from "@standard-schema/spec";
3
+
4
+ //#region src/util/stream.d.ts
5
+ interface AsyncStreamMeta {
6
+ [x: string]: unknown;
7
+ readonly asyncStream: number;
8
+ readonly itemSchema?: StandardSchemaV1;
9
+ }
10
+ /**
11
+ * Returns metadata to mark a schema field as an async stream via `.meta()`.
12
+ *
13
+ * When used with `stdin`, padrone pipes stdin data as an `AsyncIterable` instead of
14
+ * buffering it. Each line is validated against the item schema (if provided) as it arrives.
15
+ *
16
+ * @param itemSchema - Optional item schema for per-item validation.
17
+ * Non-string schemas cause each stdin line to be `JSON.parse`'d before validation.
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * import { asyncStream } from 'padrone';
22
+ *
23
+ * // String lines
24
+ * z.object({ lines: z.custom<AsyncIterable<string>>().meta(asyncStream()) })
25
+ *
26
+ * // Typed items — each line JSON.parse'd and validated
27
+ * z.object({ records: z.custom<AsyncIterable<{ name: string }>>().meta(asyncStream(recordSchema)) })
28
+ * ```
29
+ */
30
+ declare function asyncStream<T = string>(itemSchema?: PadroneSchema<T>): AsyncStreamMeta;
31
+ //#endregion
32
+ export { AsyncStreamMeta, asyncStream };
33
+ //# sourceMappingURL=stream.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream.d.mts","names":[],"sources":["../../src/util/stream.ts"],"mappings":";;;;UAGiB,eAAA;EAAA,CACd,CAAA;EAAA,SACQ,WAAA;EAAA,SACA,UAAA,GAAa,gBAAgB;AAAA;;;;;;;AAAA;AA0BxC;;;;;;;;;;;;;iBAAgB,WAAA,aAAwB,UAAA,GAAa,aAAA,CAAc,CAAA,IAAK,eAAA"}
@@ -72,6 +72,6 @@ async function readStreamAsText(stream) {
72
72
  return textDecoder.decode(concatBytes(chunks));
73
73
  }
74
74
  //#endregion
75
- export { readStreamAsText as a, createStdinStream as i, asyncStreamRegistry as n, concatBytes as r, asyncStream as t };
75
+ export { asyncStream, asyncStreamRegistry, concatBytes, createStdinStream, readStreamAsText };
76
76
 
77
- //# sourceMappingURL=stream-DC4H8YTx.mjs.map
77
+ //# sourceMappingURL=stream.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream.mjs","names":[],"sources":["../../src/util/stream.ts"],"sourcesContent":["import type { StandardSchemaV1 } from '@standard-schema/spec';\nimport type { PadroneSchema } from '../types/index.ts';\n\nexport interface AsyncStreamMeta {\n [x: string]: unknown;\n readonly asyncStream: number;\n readonly itemSchema?: StandardSchemaV1;\n}\n\nlet asyncStreamIdCounter = 1;\nexport const asyncStreamRegistry = new Map<number, AsyncStreamMeta>();\n\n/**\n * Returns metadata to mark a schema field as an async stream via `.meta()`.\n *\n * When used with `stdin`, padrone pipes stdin data as an `AsyncIterable` instead of\n * buffering it. Each line is validated against the item schema (if provided) as it arrives.\n *\n * @param itemSchema - Optional item schema for per-item validation.\n * Non-string schemas cause each stdin line to be `JSON.parse`'d before validation.\n *\n * @example\n * ```ts\n * import { asyncStream } from 'padrone';\n *\n * // String lines\n * z.object({ lines: z.custom<AsyncIterable<string>>().meta(asyncStream()) })\n *\n * // Typed items — each line JSON.parse'd and validated\n * z.object({ records: z.custom<AsyncIterable<{ name: string }>>().meta(asyncStream(recordSchema)) })\n * ```\n */\nexport function asyncStream<T = string>(itemSchema?: PadroneSchema<T>): AsyncStreamMeta {\n const id = asyncStreamIdCounter++;\n const meta: AsyncStreamMeta = itemSchema ? { asyncStream: id, itemSchema } : { asyncStream: id };\n asyncStreamRegistry.set(id, meta);\n return meta;\n}\n\n/** Stdin interface matching PadroneRuntime.stdin */\ninterface StdinSource {\n isTTY?: boolean;\n text(): Promise<string>;\n lines(): AsyncIterable<string>;\n}\n\n/**\n * Creates an `AsyncIterable` from a stdin source, optionally validating each item.\n * When no stdin is available (TTY / undefined), yields nothing.\n *\n * - No item schema: yields raw string lines\n * - With item schema: `JSON.parse`s each line, validates, then yields\n */\nexport function createStdinStream(stdin: StdinSource | undefined, itemSchema?: StandardSchemaV1): AsyncIterable<unknown> {\n if (!stdin) return emptyAsyncIterable;\n\n if (!itemSchema) return stdin.lines();\n\n return {\n async *[Symbol.asyncIterator]() {\n for await (const line of stdin.lines()) {\n const result = itemSchema['~standard'].validate(line);\n const resolved = result instanceof Promise ? await result : result;\n if ('issues' in resolved && resolved.issues) {\n throw new Error(`Stream item validation failed: ${resolved.issues.map((i) => i.message).join(', ')}`);\n }\n yield (resolved as { value: unknown }).value;\n }\n },\n };\n}\n\nconst emptyAsyncIterable: AsyncIterable<never> = {\n async *[Symbol.asyncIterator]() {},\n};\n\nconst textEncoder = /* @__PURE__ */ new TextEncoder();\nconst textDecoder = /* @__PURE__ */ new TextDecoder();\n\n/** Concatenate multiple `Uint8Array` chunks into a single array. */\nexport function concatBytes(chunks: Uint8Array[]): Uint8Array {\n if (chunks.length === 1) return chunks[0]!;\n let totalLength = 0;\n for (const chunk of chunks) totalLength += chunk.byteLength;\n const result = new Uint8Array(totalLength);\n let offset = 0;\n for (const chunk of chunks) {\n result.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return result;\n}\n\n/** Read an async iterable of chunks into a UTF-8 string. */\nexport async function readStreamAsText(stream: AsyncIterable<Uint8Array | string>): Promise<string> {\n const chunks: Uint8Array[] = [];\n for await (const chunk of stream) {\n chunks.push(typeof chunk === 'string' ? textEncoder.encode(chunk) : chunk);\n }\n return textDecoder.decode(concatBytes(chunks));\n}\n"],"mappings":";AASA,IAAI,uBAAuB;AAC3B,MAAa,sCAAsB,IAAI,IAA6B;;;;;;;;;;;;;;;;;;;;;AAsBpE,SAAgB,YAAwB,YAAgD;CACtF,MAAM,KAAK;CACX,MAAM,OAAwB,aAAa;EAAE,aAAa;EAAI;CAAW,IAAI,EAAE,aAAa,GAAG;CAC/F,oBAAoB,IAAI,IAAI,IAAI;CAChC,OAAO;AACT;;;;;;;;AAgBA,SAAgB,kBAAkB,OAAgC,YAAuD;CACvH,IAAI,CAAC,OAAO,OAAO;CAEnB,IAAI,CAAC,YAAY,OAAO,MAAM,MAAM;CAEpC,OAAO,EACL,QAAQ,OAAO,iBAAiB;EAC9B,WAAW,MAAM,QAAQ,MAAM,MAAM,GAAG;GACtC,MAAM,SAAS,WAAW,YAAY,CAAC,SAAS,IAAI;GACpD,MAAM,WAAW,kBAAkB,UAAU,MAAM,SAAS;GAC5D,IAAI,YAAY,YAAY,SAAS,QACnC,MAAM,IAAI,MAAM,kCAAkC,SAAS,OAAO,KAAK,MAAM,EAAE,OAAO,CAAC,CAAC,KAAK,IAAI,GAAG;GAEtG,MAAO,SAAgC;EACzC;CACF,EACF;AACF;AAEA,MAAM,qBAA2C,EAC/C,QAAQ,OAAO,iBAAiB,CAAC,EACnC;AAEA,MAAM,8BAA8B,IAAI,YAAY;AACpD,MAAM,8BAA8B,IAAI,YAAY;;AAGpD,SAAgB,YAAY,QAAkC;CAC5D,IAAI,OAAO,WAAW,GAAG,OAAO,OAAO;CACvC,IAAI,cAAc;CAClB,KAAK,MAAM,SAAS,QAAQ,eAAe,MAAM;CACjD,MAAM,SAAS,IAAI,WAAW,WAAW;CACzC,IAAI,SAAS;CACb,KAAK,MAAM,SAAS,QAAQ;EAC1B,OAAO,IAAI,OAAO,MAAM;EACxB,UAAU,MAAM;CAClB;CACA,OAAO;AACT;;AAGA,eAAsB,iBAAiB,QAA6D;CAClG,MAAM,SAAuB,CAAC;CAC9B,WAAW,MAAM,SAAS,QACxB,OAAO,KAAK,OAAO,UAAU,WAAW,YAAY,OAAO,KAAK,IAAI,KAAK;CAE3E,OAAO,YAAY,OAAO,YAAY,MAAM,CAAC;AAC/C"}
@@ -0,0 +1,74 @@
1
+ import { PickCommandByName, PossibleCommands } from "./type-utils.mjs";
2
+ import { PadroneContextInterceptor, PadroneInterceptorFn } from "../types/interceptor.mjs";
3
+ import { AnyPadroneCommand, PadroneCommand } from "../types/command.mjs";
4
+ import { AnyPadroneProgram } from "../types/builder.mjs";
5
+ //#region src/util/type-helpers.d.ts
6
+ /**
7
+ * Extracts the input type of the arguments schema from a command.
8
+ * @example
9
+ * ```ts
10
+ * type Args = InferArgsInput<typeof myCommand>;
11
+ * ```
12
+ */
13
+ type InferArgsInput<T extends AnyPadroneCommand> = T['~types']['argsInput'];
14
+ /**
15
+ * Extracts the output type of the arguments schema from a command.
16
+ * @example
17
+ * ```ts
18
+ * type Args = InferArgsOutput<typeof myCommand>;
19
+ * ```
20
+ */
21
+ type InferArgsOutput<T extends AnyPadroneCommand> = T['~types']['argsOutput'];
22
+ /**
23
+ * Extracts the user-defined context type from a command (excludes interceptor-provided context).
24
+ * @example
25
+ * ```ts
26
+ * type Ctx = InferContext<typeof myCommand>;
27
+ * ```
28
+ */
29
+ type InferContext<T extends AnyPadroneCommand> = T['~types']['context'];
30
+ /**
31
+ * Extracts the interceptor-provided context type from a command.
32
+ * @example
33
+ * ```ts
34
+ * type Provided = InferContextProvided<typeof myCommand>;
35
+ * ```
36
+ */
37
+ type InferContextProvided<T extends AnyPadroneCommand> = T['~types']['contextProvided'];
38
+ /**
39
+ * Extracts the context type that a context-providing interceptor injects.
40
+ * @example
41
+ * ```ts
42
+ * type AuthCtx = InferInterceptorContext<typeof withAuth>;
43
+ * ```
44
+ */
45
+ type InferInterceptorContext<T extends PadroneContextInterceptor<any>> = T['~context'];
46
+ /**
47
+ * Extracts the required context type from an interceptor with `.requires()`.
48
+ * @example
49
+ * ```ts
50
+ * type Requires = InferInterceptorRequires<typeof withAuth>;
51
+ * ```
52
+ */
53
+ type InferInterceptorRequires<T extends PadroneInterceptorFn & {
54
+ '~contextRequires': any;
55
+ }> = T['~contextRequires'] extends ((ctx: infer R) => void) ? R : unknown;
56
+ /**
57
+ * Gets a command type by its path from a program or command tree.
58
+ * Supports both full paths (e.g., "config set") and alias paths.
59
+ * @example
60
+ * ```ts
61
+ * const program = createPadrone('cli')
62
+ * .command('config', c => c
63
+ * .command('set', c => c.arguments(...).action(...))
64
+ * .command('get', c => c.arguments(...).action(...))
65
+ * );
66
+ *
67
+ * type SetCommand = InferCommand<typeof program, 'config set'>;
68
+ * type GetCommand = InferCommand<typeof program, 'config get'>;
69
+ * ```
70
+ */
71
+ type InferCommand<T extends AnyPadroneCommand | AnyPadroneProgram, TPath extends PossibleCommands<T extends AnyPadroneCommand ? [T] : T['~types']['commands'], true, true>> = T extends AnyPadroneProgram ? PickCommandByName<[PadroneCommand<'', '', any, any, T['~types']['commands']>], TPath> : T extends AnyPadroneCommand ? PickCommandByName<[T], TPath> : never;
72
+ //#endregion
73
+ export { InferArgsInput, InferArgsOutput, InferCommand, InferContext, InferContextProvided, InferInterceptorContext, InferInterceptorRequires };
74
+ //# sourceMappingURL=type-helpers.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"type-helpers.d.mts","names":[],"sources":["../../src/util/type-helpers.ts"],"mappings":";;;;;;;;;;AAgBA;;KAAY,cAAA,WAAyB,iBAAA,IAAqB,CAAC;;;;;;AAAA;AAS3D;KAAY,eAAA,WAA0B,iBAAA,IAAqB,CAAC;;;;;;;AAAA;KAShD,YAAA,WAAuB,iBAAA,IAAqB,CAAC;;;;;;;;KAS7C,oBAAA,WAA+B,iBAAA,IAAqB,CAAC;AAAjE;;;;;;;AAAA,KASY,uBAAA,WAAkC,yBAAA,SAAkC,CAAC;AAThB;AASjE;;;;;;AATiE,KAkBrD,wBAAA,WAAmC,oBAAA;EAAyB,kBAAA;AAAA,KAA6B,CAAC,+BACpG,GAAA,sBAEE,CAAA;AAHJ;;;;;;;;;;;;AAGK;AAkBL;;AArBA,KAqBY,YAAA,WACA,iBAAA,GAAoB,iBAAA,gBAChB,gBAAA,CAAiB,CAAA,SAAU,iBAAA,IAAqB,CAAA,IAAK,CAAA,uCACjE,CAAA,SAAU,iBAAA,GACV,iBAAA,EAAmB,cAAA,mBAAiC,CAAA,0BAA2B,KAAA,IAC/E,CAAA,SAAU,iBAAA,GACR,iBAAA,EAAmB,CAAA,GAAI,KAAA"}
@@ -0,0 +1,186 @@
1
+ import { PadroneSchema } from "../types/schema.mjs";
2
+ import { AnyPadroneCommand, PadroneCommand } from "../types/command.mjs";
3
+ import { PadroneBuilder, PadroneProgram } from "../types/builder.mjs";
4
+ //#region src/util/type-utils.d.ts
5
+ type SafeString = string & {};
6
+ type IsUnknown<T> = unknown extends T ? true : false;
7
+ type IsAny<T> = any extends T ? true : false;
8
+ type IsNever<T> = [T] extends [never] ? true : false;
9
+ type IsGeneric<T> = IsAny<T> extends true ? true : IsUnknown<T> extends true ? true : IsNever<T> extends true ? true : false;
10
+ /**
11
+ * Detects whether a schema has been branded as async via the `'~async'` property.
12
+ * Standard Schema V1's `validate()` always types its return as `Result | Promise<Result>`
13
+ * regardless of whether the schema is actually async, so we rely on an explicit brand instead.
14
+ *
15
+ * Use `asyncSchema(schema)` to brand a schema, or check for the `{ '~async': true }` property.
16
+ */
17
+ type IsAsyncSchema<T> = IsAny<T> extends true ? false : T extends {
18
+ '~async': true;
19
+ } ? true : false;
20
+ /**
21
+ * Computes the new TAsync flag when a schema is added to a builder.
22
+ * Once TAsync is `true`, it stays `true`. Otherwise, checks if the new schema is branded async.
23
+ */
24
+ type OrAsync<TExisting extends boolean, TSchema> = TExisting extends true ? true : IsAsyncSchema<TSchema> extends true ? true : false;
25
+ /**
26
+ * Detects whether argument meta contains interactive or optionalInteractive configuration.
27
+ * When either is `true` or a `string[]`, the command requires async execution for prompting.
28
+ */
29
+ type HasInteractive<TMeta> = TMeta extends {
30
+ interactive: true | readonly string[];
31
+ } ? true : TMeta extends {
32
+ optionalInteractive: true | readonly string[];
33
+ } ? true : false;
34
+ /**
35
+ * Combines schema-level async detection with meta-level interactive detection.
36
+ * Returns `true` if the existing async flag is set, the schema is branded async, or the meta has interactive fields.
37
+ */
38
+ type OrAsyncMeta<TExisting extends boolean, TMeta> = TExisting extends true ? true : HasInteractive<TMeta> extends true ? true : false;
39
+ /**
40
+ * Unwraps a result type by resolving Promises and collecting iterables into arrays.
41
+ * - `AsyncIterable<U>` → `U[]`
42
+ * - `Iterable<U>` (excluding strings) → `U[]`
43
+ * - `Promise<U>` → `Drained<U>` (recursively unwraps)
44
+ * - `T` → `T`
45
+ */
46
+ type Drained<T> = T extends Promise<infer U> ? Drained<U> : T extends AsyncIterable<infer U> ? U[] : T extends string ? T : T extends Iterable<infer U> ? U[] : T;
47
+ /**
48
+ * A sync value augmented with Promise-like methods (.then, .catch, .finally).
49
+ * Unlike a real Promise, properties of T are accessible synchronously.
50
+ */
51
+ type Thenable<T> = T & PromiseLike<T> & {
52
+ catch: Promise<T>['catch'];
53
+ finally: Promise<T>['finally'];
54
+ };
55
+ /**
56
+ * Conditionally wraps a type in Promise based on the TAsync flag.
57
+ * - `true` → `Promise<T>`
58
+ * - `false` → `T & Thenable<T>` (thenable: supports `.then()`, `.catch()`, `.finally()`, and `await`)
59
+ * - `boolean` (union of true|false) → `Promise<T>` (safe default when async-ness is uncertain)
60
+ * - `any` → `T` (for generic/any typed commands like AnyPadroneCommand)
61
+ */
62
+ type MaybePromise<T, TAsync> = IsAny<TAsync> extends true ? T : true extends TAsync ? Promise<T> : Thenable<T>;
63
+ type SplitString<TName extends string, TSplitBy extends string = ' '> = TName extends `${infer FirstPart}${TSplitBy}${infer RestParts}` ? [FirstPart, ...SplitString<RestParts, TSplitBy>] : [TName];
64
+ type JoinString<TParts extends string[], TJoinBy extends string = ' '> = TParts extends [infer FirstPart extends string, ...infer RestParts extends string[]] ? RestParts extends [] ? FirstPart : `${FirstPart}${TJoinBy}${JoinString<RestParts, TJoinBy>}` : TParts extends [] ? '' : TParts[number];
65
+ type SplitLastSpace<S extends string> = SplitString<S> extends [...infer Init extends string[], infer Last extends string] ? Init extends [] ? [S, never] : [JoinString<Init>, Last] : [S, never];
66
+ type AnyPartExtends<U, T> = [U] extends [never] ? false : U extends any ? (U extends T ? true : never) : never extends true ? true : false;
67
+ type FullCommandName<TName extends string, TParentName extends string = ''> = TParentName extends '' ? TName : `${TParentName} ${TName}`;
68
+ /**
69
+ * Generate full alias paths by combining parent path with each alias.
70
+ */
71
+ type FullAliasPaths<TAliases extends string[], TParentName extends string = ''> = TAliases extends [infer First extends string, ...infer Rest extends string[]] ? FullCommandName<First, TParentName> | FullAliasPaths<Rest, TParentName> : never;
72
+ /**
73
+ * Get all paths for a command including its primary path and all alias paths.
74
+ */
75
+ type GetCommandPathsAndAliases<TCommand extends AnyPadroneCommand> = TCommand['~types']['path'] extends infer Path extends string ? TCommand['~types']['aliases'] extends infer Aliases extends string[] ? TCommand['~types']['parentName'] extends infer ParentName extends string ? Path | FullAliasPaths<Aliases, ParentName> : Path : Path : never;
76
+ /**
77
+ * Find a direct child command in a tuple by name.
78
+ * Unlike PickCommandByName, this does NOT flatten — it only checks direct children by their `name` field.
79
+ * Uses indexed access (O(1) depth) instead of recursive tuple walking.
80
+ */
81
+ type FindDirectChild<TCommands extends AnyPadroneCommand[], TName extends string> = Extract<TCommands[number], {
82
+ '~types': {
83
+ name: TName;
84
+ };
85
+ }>;
86
+ /**
87
+ * Replace a command in a tuple by name, or append if not found.
88
+ * Used by `.command()` override semantics: re-registering a name replaces that entry.
89
+ * Uses mapped type (O(1) depth) instead of recursive tuple walking.
90
+ */
91
+ type ReplaceOrAppendCommand<TCommands extends [...AnyPadroneCommand[]], TName extends string, TNew extends AnyPadroneCommand> = HasDirectChild<TCommands, TName> extends true ? ReplaceInTuple<TCommands, TName, TNew> : [...TCommands, TNew];
92
+ type HasDirectChild<TCommands extends AnyPadroneCommand[], TName extends string> = TName extends TCommands[number]['~types']['name'] ? true : false;
93
+ type ReplaceInTuple<TCommands extends AnyPadroneCommand[], TName extends string, TNew extends AnyPadroneCommand> = { [K in keyof TCommands]: TCommands[K] extends AnyPadroneCommand ? TCommands[K]['~types']['name'] extends TName ? TNew : TCommands[K] : TCommands[K] };
94
+ /**
95
+ * Utility type for extensions that add a command to a builder/program.
96
+ * Replaces the boilerplate `With*<T>` pattern used across all extension files.
97
+ */
98
+ type WithCommand<T, TName extends string, TCmd extends AnyPadroneCommand> = T extends {
99
+ '~types': {
100
+ programName: infer PN extends string;
101
+ name: infer N extends string;
102
+ parentName: infer PaN extends string;
103
+ argsSchema: infer A extends PadroneSchema;
104
+ result: infer R;
105
+ commands: infer C extends [...AnyPadroneCommand[]];
106
+ async: infer AS extends boolean;
107
+ context: infer CTX;
108
+ contextProvided: infer CTXP;
109
+ };
110
+ } ? T extends {
111
+ run: any;
112
+ } ? PadroneProgram<PN, N, PaN, A, R, ReplaceOrAppendCommand<C, TName, TCmd>, any, AS, CTX, CTXP> : PadroneBuilder<PN, N, PaN, A, R, ReplaceOrAppendCommand<C, TName, TCmd>, any, AS, CTX, CTXP> : T;
113
+ /**
114
+ * Utility type for extensions that register a context-providing interceptor.
115
+ * Extends `TContextProvided` with `TProvides` while preserving all other builder/program type params.
116
+ */
117
+ type WithInterceptor<T, TProvides> = T extends {
118
+ '~types': {
119
+ programName: infer PN extends string;
120
+ name: infer N extends string;
121
+ parentName: infer PaN extends string;
122
+ argsSchema: infer A extends PadroneSchema;
123
+ result: infer R;
124
+ commands: infer C extends [...AnyPadroneCommand[]];
125
+ async: infer AS extends boolean;
126
+ context: infer CTX;
127
+ contextProvided: infer CTXP;
128
+ };
129
+ } ? T extends {
130
+ run: any;
131
+ } ? PadroneProgram<PN, N, PaN, A, R, C, any, AS, CTX, CTXP & TProvides> : PadroneBuilder<PN, N, PaN, A, R, C, any, AS, CTX, CTXP & TProvides> : T;
132
+ /**
133
+ * Utility type for extensions that force the builder/program into async mode.
134
+ * Sets `TAsync` to `true` while preserving all other type params.
135
+ */
136
+ type WithAsync<T> = T extends {
137
+ '~types': {
138
+ programName: infer PN extends string;
139
+ name: infer N extends string;
140
+ parentName: infer PaN extends string;
141
+ argsSchema: infer A extends PadroneSchema;
142
+ result: infer R;
143
+ commands: infer C extends [...AnyPadroneCommand[]];
144
+ async: any;
145
+ context: infer CTX;
146
+ contextProvided: infer CTXP;
147
+ };
148
+ } ? T extends {
149
+ run: any;
150
+ } ? PadroneProgram<PN, N, PaN, A, R, C, any, true, CTX, CTXP> : PadroneBuilder<PN, N, PaN, A, R, C, any, true, CTX, CTXP> : T;
151
+ type PickCommandByName<TCommands extends AnyPadroneCommand[], TName extends string | AnyPadroneCommand> = TName extends AnyPadroneCommand ? TName : FlattenCommands<TCommands> extends infer Cmd extends AnyPadroneCommand ? Cmd extends AnyPadroneCommand ? TName extends GetCommandPathsAndAliases<Cmd> ? Cmd : never : never : never;
152
+ type FlattenCommands<TCommands extends AnyPadroneCommand[]> = TCommands extends [] ? never : number extends TCommands['length'] ? IsAny<TCommands[number]> extends true ? never : TCommands[number] : TCommands[number] extends infer Cmd extends AnyPadroneCommand ? Cmd | FlattenCommands<Cmd['~types']['commands']> : never;
153
+ /**
154
+ * Get all command paths including alias paths for all commands.
155
+ */
156
+ type GetCommandPathsOrAliases<TCommands extends AnyPadroneCommand[]> = GetCommandPathsAndAliases<FlattenCommands<TCommands>>;
157
+ /**
158
+ * Find all the commands that are prefixed with a command name or alias.
159
+ * This is needed to avoid matching other commands when followed by a space and another word.
160
+ * For example, let's say `level1` and `level1 level2` are commands.
161
+ * Then `level1 ${string}` would also match `level1 level2`,
162
+ * and it would cause `level1 level2` to not show up in the autocomplete.
163
+ * By excluding those cases, we can ensure autocomplete works correctly.
164
+ */
165
+ type PrefixedCommands<TCommands extends AnyPadroneCommand[]> = GetCommandPathsOrAliases<TCommands> extends infer CommandNames ? CommandNames extends string ? AnyPartExtends<GetCommandPathsOrAliases<TCommands>, `${CommandNames} ${string}`> extends true ? never : `${CommandNames} ${string}` : never : never;
166
+ /**
167
+ * The possible commands are the commands that can be parsed by the program.
168
+ * This includes the string that are exact matches to a command name or alias, and strings that are prefixed with a command name or alias.
169
+ */
170
+ type PossibleCommands<TCommands extends AnyPadroneCommand[], TWithPrefixed extends boolean = false, TWithObjects extends boolean = false, TWithFallback extends boolean = true> = GetCommandPathsOrAliases<TCommands> | (TWithPrefixed extends true ? PrefixedCommands<TCommands> : never) | (TWithObjects extends true ? FlattenCommands<TCommands> : never) | (TWithFallback extends true ? SafeString : never);
171
+ type CommandIsUnknownable<TCommand> = IsGeneric<TCommand> extends true ? true : string extends TCommand ? true : SafeString extends TCommand ? true : false;
172
+ /**
173
+ * Match a string to a command by the possible commands.
174
+ * This is done by recursively splitting the string by the last space, and then checking if the prefix is a valid command name or alias.
175
+ * This is needed to avoid matching the top-level command when there are nested commands.
176
+ */
177
+ /**
178
+ * Recursively re-paths a command's children under a new parent path.
179
+ * Used by `mount()` to update all nested command paths when a program is mounted as a subcommand.
180
+ */
181
+ type RepathCommands<TCommands extends [...AnyPadroneCommand[]], TNewParentPath extends string> = TCommands extends [infer First extends AnyPadroneCommand, ...infer Rest extends AnyPadroneCommand[]] ? [RepathCommand<First, TNewParentPath>, ...RepathCommands<Rest, TNewParentPath>] : [];
182
+ type RepathCommand<TCommand extends AnyPadroneCommand, TNewParentName extends string> = PadroneCommand<TCommand['~types']['name'], TNewParentName, TCommand['~types']['argsSchema'], TCommand['~types']['result'], RepathCommands<TCommand['~types']['commands'], FullCommandName<TCommand['~types']['name'], TNewParentName>>, TCommand['~types']['aliases'], TCommand['~types']['async'], TCommand['~types']['context'], TCommand['~types']['contextProvided']>;
183
+ type PickCommandByPossibleCommands<TCommands extends AnyPadroneCommand[], TCommand extends PossibleCommands<TCommands, true, true> | SafeString> = CommandIsUnknownable<TCommand> extends true ? FlattenCommands<TCommands> : TCommand extends AnyPadroneCommand ? TCommand : TCommand extends string ? TCommand extends GetCommandPathsOrAliases<TCommands> ? PickCommandByName<TCommands, TCommand> : SplitLastSpace<TCommand> extends [infer Prefix extends string, infer Rest] ? IsNever<Rest> extends true ? PickCommandByName<TCommands, Prefix> : PickCommandByPossibleCommands<TCommands, Prefix> : never : never;
184
+ //#endregion
185
+ export { Drained, FindDirectChild, FlattenCommands, FullCommandName, HasInteractive, IsAsyncSchema, IsGeneric, MaybePromise, OrAsync, OrAsyncMeta, PickCommandByName, PickCommandByPossibleCommands, PossibleCommands, RepathCommands, ReplaceOrAppendCommand, SafeString, Thenable, WithAsync, WithCommand, WithInterceptor };
186
+ //# sourceMappingURL=type-utils.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"type-utils.d.mts","names":[],"sources":["../../src/util/type-utils.ts"],"mappings":"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"}