padrone 1.4.0 → 1.6.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 (141) hide show
  1. package/CHANGELOG.md +115 -0
  2. package/README.md +108 -283
  3. package/dist/args-Cnq0nwSM.mjs +272 -0
  4. package/dist/args-Cnq0nwSM.mjs.map +1 -0
  5. package/dist/codegen/index.d.mts +28 -3
  6. package/dist/codegen/index.d.mts.map +1 -1
  7. package/dist/codegen/index.mjs +169 -19
  8. package/dist/codegen/index.mjs.map +1 -1
  9. package/dist/commands-B_gufyR9.mjs +514 -0
  10. package/dist/commands-B_gufyR9.mjs.map +1 -0
  11. package/dist/{completion.mjs → completion-BEuflbDO.mjs} +86 -108
  12. package/dist/completion-BEuflbDO.mjs.map +1 -0
  13. package/dist/docs/index.d.mts +22 -2
  14. package/dist/docs/index.d.mts.map +1 -1
  15. package/dist/docs/index.mjs +92 -7
  16. package/dist/docs/index.mjs.map +1 -1
  17. package/dist/errors-CL63UOzt.mjs +137 -0
  18. package/dist/errors-CL63UOzt.mjs.map +1 -0
  19. package/dist/{formatter-ClUK5hcQ.d.mts → formatter-DrvhDMrq.d.mts} +35 -6
  20. package/dist/formatter-DrvhDMrq.d.mts.map +1 -0
  21. package/dist/help-B5Kk83of.mjs +849 -0
  22. package/dist/help-B5Kk83of.mjs.map +1 -0
  23. package/dist/index-BaU3X6dY.d.mts +1178 -0
  24. package/dist/index-BaU3X6dY.d.mts.map +1 -0
  25. package/dist/index.d.mts +763 -36
  26. package/dist/index.d.mts.map +1 -1
  27. package/dist/index.mjs +3608 -1534
  28. package/dist/index.mjs.map +1 -1
  29. package/dist/mcp-BM-d0nZi.mjs +377 -0
  30. package/dist/mcp-BM-d0nZi.mjs.map +1 -0
  31. package/dist/serve-Bk0JUlCj.mjs +402 -0
  32. package/dist/serve-Bk0JUlCj.mjs.map +1 -0
  33. package/dist/stream-DC4H8YTx.mjs +77 -0
  34. package/dist/stream-DC4H8YTx.mjs.map +1 -0
  35. package/dist/test.d.mts +5 -8
  36. package/dist/test.d.mts.map +1 -1
  37. package/dist/test.mjs +5 -27
  38. package/dist/test.mjs.map +1 -1
  39. package/dist/{update-check-EbNDkzyV.mjs → update-check-CZ2VqjnV.mjs} +16 -17
  40. package/dist/update-check-CZ2VqjnV.mjs.map +1 -0
  41. package/dist/zod.d.mts +32 -0
  42. package/dist/zod.d.mts.map +1 -0
  43. package/dist/zod.mjs +50 -0
  44. package/dist/zod.mjs.map +1 -0
  45. package/package.json +20 -9
  46. package/src/cli/completions.ts +14 -11
  47. package/src/cli/docs.ts +13 -16
  48. package/src/cli/doctor.ts +213 -24
  49. package/src/cli/index.ts +28 -82
  50. package/src/cli/init.ts +12 -10
  51. package/src/cli/link.ts +22 -18
  52. package/src/cli/wrap.ts +14 -11
  53. package/src/codegen/discovery.ts +80 -28
  54. package/src/codegen/index.ts +2 -1
  55. package/src/codegen/parsers/bash.ts +179 -0
  56. package/src/codegen/schema-to-code.ts +2 -1
  57. package/src/core/args.ts +296 -0
  58. package/src/core/commands.ts +373 -0
  59. package/src/core/create.ts +268 -0
  60. package/src/{runtime.ts → core/default-runtime.ts} +70 -135
  61. package/src/{errors.ts → core/errors.ts} +22 -0
  62. package/src/core/exec.ts +259 -0
  63. package/src/core/interceptors.ts +302 -0
  64. package/src/{parse.ts → core/parse.ts} +36 -89
  65. package/src/core/program-methods.ts +301 -0
  66. package/src/core/results.ts +229 -0
  67. package/src/core/runtime.ts +246 -0
  68. package/src/core/validate.ts +247 -0
  69. package/src/docs/index.ts +124 -11
  70. package/src/extension/auto-output.ts +95 -0
  71. package/src/extension/color.ts +38 -0
  72. package/src/extension/completion.ts +49 -0
  73. package/src/extension/config.ts +262 -0
  74. package/src/extension/env.ts +101 -0
  75. package/src/extension/help.ts +192 -0
  76. package/src/extension/index.ts +43 -0
  77. package/src/extension/ink.ts +93 -0
  78. package/src/extension/interactive.ts +106 -0
  79. package/src/extension/logger.ts +214 -0
  80. package/src/extension/man.ts +51 -0
  81. package/src/extension/mcp.ts +52 -0
  82. package/src/extension/progress-renderer.ts +338 -0
  83. package/src/extension/progress.ts +299 -0
  84. package/src/extension/repl.ts +94 -0
  85. package/src/extension/serve.ts +48 -0
  86. package/src/extension/signal.ts +87 -0
  87. package/src/extension/stdin.ts +62 -0
  88. package/src/extension/suggestions.ts +114 -0
  89. package/src/extension/timing.ts +81 -0
  90. package/src/extension/tracing.ts +175 -0
  91. package/src/extension/update-check.ts +77 -0
  92. package/src/extension/utils.ts +51 -0
  93. package/src/extension/version.ts +63 -0
  94. package/src/{completion.ts → feature/completion.ts} +130 -57
  95. package/src/{interactive.ts → feature/interactive.ts} +47 -6
  96. package/src/feature/mcp.ts +387 -0
  97. package/src/{repl-loop.ts → feature/repl-loop.ts} +26 -16
  98. package/src/feature/serve.ts +438 -0
  99. package/src/feature/test.ts +262 -0
  100. package/src/{update-check.ts → feature/update-check.ts} +16 -16
  101. package/src/{wrap.ts → feature/wrap.ts} +27 -27
  102. package/src/index.ts +120 -11
  103. package/src/output/colorizer.ts +154 -0
  104. package/src/{formatter.ts → output/formatter.ts} +281 -135
  105. package/src/{help.ts → output/help.ts} +62 -15
  106. package/src/{zod.d.ts → schema/zod.d.ts} +1 -1
  107. package/src/schema/zod.ts +50 -0
  108. package/src/test.ts +2 -285
  109. package/src/types/args-meta.ts +151 -0
  110. package/src/types/builder.ts +697 -0
  111. package/src/types/command.ts +157 -0
  112. package/src/types/index.ts +59 -0
  113. package/src/types/interceptor.ts +296 -0
  114. package/src/types/preferences.ts +83 -0
  115. package/src/types/result.ts +71 -0
  116. package/src/types/schema.ts +19 -0
  117. package/src/util/dotenv.ts +244 -0
  118. package/src/{shell-utils.ts → util/shell-utils.ts} +26 -9
  119. package/src/util/stream.ts +101 -0
  120. package/src/{type-helpers.ts → util/type-helpers.ts} +23 -16
  121. package/src/{type-utils.ts → util/type-utils.ts} +99 -37
  122. package/src/util/utils.ts +51 -0
  123. package/src/zod.ts +1 -0
  124. package/dist/args-CVDbyyzG.mjs +0 -199
  125. package/dist/args-CVDbyyzG.mjs.map +0 -1
  126. package/dist/chunk-y_GBKt04.mjs +0 -5
  127. package/dist/completion.d.mts +0 -64
  128. package/dist/completion.d.mts.map +0 -1
  129. package/dist/completion.mjs.map +0 -1
  130. package/dist/formatter-ClUK5hcQ.d.mts.map +0 -1
  131. package/dist/help-CcBe91bV.mjs +0 -1254
  132. package/dist/help-CcBe91bV.mjs.map +0 -1
  133. package/dist/types-DjIdJN5G.d.mts +0 -1059
  134. package/dist/types-DjIdJN5G.d.mts.map +0 -1
  135. package/dist/update-check-EbNDkzyV.mjs.map +0 -1
  136. package/src/args.ts +0 -461
  137. package/src/colorizer.ts +0 -41
  138. package/src/command-utils.ts +0 -532
  139. package/src/create.ts +0 -1477
  140. package/src/types.ts +0 -1109
  141. package/src/utils.ts +0 -140
@@ -0,0 +1,402 @@
1
+ import { m as serializeArgsToFlags, r as collectEndpoints, t as buildInputSchema } from "./commands-B_gufyR9.mjs";
2
+ import { a as readStreamAsText } from "./stream-DC4H8YTx.mjs";
3
+ import { i as RoutingError, o as ValidationError } from "./errors-CL63UOzt.mjs";
4
+ import { t as generateHelp } from "./help-B5Kk83of.mjs";
5
+ //#region src/feature/serve.ts
6
+ /** Convert an endpoint dot-path to a URL path segment. */
7
+ function toUrlPath(name) {
8
+ return name.replace(/\./g, "/");
9
+ }
10
+ /** Convert a URL path segment back to a command path (slash → space). */
11
+ function toCommandPath(urlPath) {
12
+ return urlPath.replace(/\//g, " ");
13
+ }
14
+ function jsonResponse(body, status = 200, headers) {
15
+ return new Response(JSON.stringify(body), {
16
+ status,
17
+ headers: {
18
+ "Content-Type": "application/json",
19
+ ...headers
20
+ }
21
+ });
22
+ }
23
+ function errorToStatus(error) {
24
+ if (error instanceof RoutingError) return 404;
25
+ if (error instanceof ValidationError) return 400;
26
+ return 500;
27
+ }
28
+ function errorToResponse(error) {
29
+ const status = errorToStatus(error);
30
+ if (error instanceof ValidationError) return jsonResponse({
31
+ ok: false,
32
+ error: "validation",
33
+ message: error.message,
34
+ issues: error.issues.map((i) => ({
35
+ path: i.path?.map(String),
36
+ message: i.message
37
+ }))
38
+ }, status);
39
+ if (error instanceof RoutingError) return jsonResponse({
40
+ ok: false,
41
+ error: "not_found",
42
+ message: error.message,
43
+ suggestions: error.suggestions
44
+ }, status);
45
+ return jsonResponse({
46
+ ok: false,
47
+ error: "action_error",
48
+ message: error instanceof Error ? error.message : String(error)
49
+ }, status);
50
+ }
51
+ /** Generate an OpenAPI 3.1.0 spec from the command tree. */
52
+ function buildOpenApiSpec(existingCommand, endpoints, basePath) {
53
+ const paths = {};
54
+ const responseSchema = {
55
+ "200": {
56
+ description: "Successful response",
57
+ content: { "application/json": { schema: {
58
+ type: "object",
59
+ properties: {
60
+ ok: {
61
+ type: "boolean",
62
+ const: true
63
+ },
64
+ result: {}
65
+ }
66
+ } } }
67
+ },
68
+ "400": {
69
+ description: "Validation error",
70
+ content: { "application/json": { schema: {
71
+ type: "object",
72
+ properties: {
73
+ ok: {
74
+ type: "boolean",
75
+ const: false
76
+ },
77
+ error: {
78
+ type: "string",
79
+ const: "validation"
80
+ },
81
+ message: { type: "string" },
82
+ issues: {
83
+ type: "array",
84
+ items: {
85
+ type: "object",
86
+ properties: {
87
+ path: { type: "array" },
88
+ message: { type: "string" }
89
+ }
90
+ }
91
+ }
92
+ }
93
+ } } }
94
+ },
95
+ "404": {
96
+ description: "Command not found",
97
+ content: { "application/json": { schema: {
98
+ type: "object",
99
+ properties: {
100
+ ok: {
101
+ type: "boolean",
102
+ const: false
103
+ },
104
+ error: {
105
+ type: "string",
106
+ const: "not_found"
107
+ },
108
+ message: { type: "string" }
109
+ }
110
+ } } }
111
+ },
112
+ "500": {
113
+ description: "Action error",
114
+ content: { "application/json": { schema: {
115
+ type: "object",
116
+ properties: {
117
+ ok: {
118
+ type: "boolean",
119
+ const: false
120
+ },
121
+ error: {
122
+ type: "string",
123
+ const: "action_error"
124
+ },
125
+ message: { type: "string" }
126
+ }
127
+ } } }
128
+ }
129
+ };
130
+ for (const { name, command: cmd } of endpoints) {
131
+ const urlPath = `${basePath}${toUrlPath(name)}`;
132
+ const inputSchema = buildInputSchema(cmd);
133
+ const description = cmd.description || cmd.title || `Run the "${name}" command`;
134
+ const pathItem = {};
135
+ const postOp = {
136
+ summary: cmd.title || name,
137
+ description,
138
+ operationId: `post_${name.replace(/\./g, "_")}`,
139
+ requestBody: { content: { "application/json": { schema: inputSchema } } },
140
+ responses: responseSchema
141
+ };
142
+ if (cmd.mutation) pathItem.post = postOp;
143
+ else {
144
+ const properties = inputSchema.properties ?? {};
145
+ const queryParams = Object.entries(properties).map(([key, schema]) => ({
146
+ name: key,
147
+ in: "query",
148
+ schema,
149
+ required: inputSchema.required?.includes(key) ?? false
150
+ }));
151
+ pathItem.get = {
152
+ summary: cmd.title || name,
153
+ description,
154
+ operationId: `get_${name.replace(/\./g, "_")}`,
155
+ parameters: queryParams,
156
+ responses: responseSchema
157
+ };
158
+ pathItem.post = postOp;
159
+ }
160
+ paths[urlPath] = pathItem;
161
+ }
162
+ return {
163
+ openapi: "3.1.0",
164
+ info: {
165
+ title: existingCommand.title || existingCommand.name,
166
+ description: existingCommand.description,
167
+ version: existingCommand.version ?? "0.0.0"
168
+ },
169
+ paths
170
+ };
171
+ }
172
+ function scalarDocsHtml(openapiUrl, title) {
173
+ return `<!doctype html>
174
+ <html>
175
+ <head>
176
+ <title>${title} — API Docs</title>
177
+ <meta charset="utf-8" />
178
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
179
+ </head>
180
+ <body>
181
+ <script id="api-reference" data-url="${openapiUrl}"><\/script>
182
+ <script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"><\/script>
183
+ </body>
184
+ </html>`;
185
+ }
186
+ /** Create the serve request handler. */
187
+ function createServeHandler(existingCommand, evalCommand, prefs) {
188
+ const basePath = (prefs?.basePath ?? "/").replace(/\/$/, "/");
189
+ const corsOrigin = prefs?.cors !== false ? prefs?.cors ?? "*" : void 0;
190
+ const builtins = {
191
+ health: true,
192
+ help: true,
193
+ schema: true,
194
+ docs: true,
195
+ ...prefs?.builtins
196
+ };
197
+ const endpoints = collectEndpoints(existingCommand.commands, "");
198
+ if (existingCommand.action || existingCommand.argsSchema) endpoints.unshift({
199
+ name: "",
200
+ command: existingCommand
201
+ });
202
+ const routeMap = /* @__PURE__ */ new Map();
203
+ for (const ep of endpoints) routeMap.set(toUrlPath(ep.name), ep);
204
+ let cachedOpenApiSpec;
205
+ const getOpenApiSpec = () => cachedOpenApiSpec ??= buildOpenApiSpec(existingCommand, endpoints, basePath);
206
+ function addCorsHeaders(res) {
207
+ if (!corsOrigin) return res;
208
+ const headers = new Headers(res.headers);
209
+ headers.set("Access-Control-Allow-Origin", corsOrigin);
210
+ headers.set("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
211
+ headers.set("Access-Control-Allow-Headers", "Content-Type");
212
+ return new Response(res.body, {
213
+ status: res.status,
214
+ statusText: res.statusText,
215
+ headers
216
+ });
217
+ }
218
+ async function evalAndRespond(commandString, request) {
219
+ const output = [];
220
+ const errors = [];
221
+ const result = await evalCommand(commandString || void 0, {
222
+ caller: "serve",
223
+ runtime: {
224
+ output: (...args) => output.push(args.map(String).join(" ")),
225
+ error: (text) => errors.push(text),
226
+ interactive: "unsupported",
227
+ format: "json"
228
+ }
229
+ });
230
+ if (result.error) return prefs?.onError ? prefs.onError(result.error, request) : errorToResponse(result.error);
231
+ if (result.argsResult?.issues) return jsonResponse({
232
+ ok: false,
233
+ error: "validation",
234
+ issues: result.argsResult.issues.map((i) => ({
235
+ path: i.path?.map(String),
236
+ message: i.message
237
+ }))
238
+ }, 400);
239
+ return jsonResponse({
240
+ ok: true,
241
+ result: result.result ?? null
242
+ });
243
+ }
244
+ return async function handleRequest(req) {
245
+ if (req.method === "OPTIONS") return addCorsHeaders(new Response(null, { status: corsOrigin ? 204 : 405 }));
246
+ if (prefs?.onRequest) {
247
+ const hookResponse = await prefs.onRequest(req);
248
+ if (hookResponse) return addCorsHeaders(hookResponse);
249
+ }
250
+ const url = new URL(req.url, "http://localhost");
251
+ let pathname = url.pathname;
252
+ if (basePath !== "/" && pathname.startsWith(basePath)) pathname = pathname.slice(basePath.length - 1);
253
+ const routePath = pathname.replace(/^\//, "");
254
+ if (req.method === "GET") {
255
+ if (builtins.health && routePath === "_health") return addCorsHeaders(jsonResponse({ status: "ok" }));
256
+ if (builtins.schema && routePath === "_schema") {
257
+ const schemaMap = {};
258
+ for (const ep of endpoints) schemaMap[toUrlPath(ep.name) || "/"] = buildInputSchema(ep.command);
259
+ return addCorsHeaders(jsonResponse(schemaMap));
260
+ }
261
+ if (builtins.schema && routePath.startsWith("_schema/")) {
262
+ const cmdPath = routePath.slice(8);
263
+ const ep = routeMap.get(cmdPath);
264
+ if (!ep) return addCorsHeaders(jsonResponse({
265
+ ok: false,
266
+ error: "not_found",
267
+ message: `Command not found: ${cmdPath}`
268
+ }, 404));
269
+ return addCorsHeaders(jsonResponse(buildInputSchema(ep.command)));
270
+ }
271
+ if (builtins.help && routePath === "_help") {
272
+ const format = (req.headers.get("accept") ?? "").includes("application/json") ? "json" : "markdown";
273
+ const helpText = generateHelp(existingCommand, existingCommand, {
274
+ format,
275
+ detail: "full"
276
+ });
277
+ if (format === "json") return addCorsHeaders(jsonResponse(JSON.parse(helpText)));
278
+ return addCorsHeaders(new Response(helpText, {
279
+ status: 200,
280
+ headers: { "Content-Type": "text/markdown" }
281
+ }));
282
+ }
283
+ if (builtins.help && routePath.startsWith("_help/")) {
284
+ const cmdPath = routePath.slice(6);
285
+ const ep = routeMap.get(cmdPath);
286
+ if (!ep) return addCorsHeaders(jsonResponse({
287
+ ok: false,
288
+ error: "not_found",
289
+ message: `Command not found: ${cmdPath}`
290
+ }, 404));
291
+ const format = (req.headers.get("accept") ?? "").includes("application/json") ? "json" : "markdown";
292
+ const helpText = generateHelp(existingCommand, ep.command, {
293
+ format,
294
+ detail: "full"
295
+ });
296
+ if (format === "json") return addCorsHeaders(jsonResponse(JSON.parse(helpText)));
297
+ return addCorsHeaders(new Response(helpText, {
298
+ status: 200,
299
+ headers: { "Content-Type": "text/markdown" }
300
+ }));
301
+ }
302
+ if (builtins.docs && routePath === "_openapi") return addCorsHeaders(jsonResponse(getOpenApiSpec()));
303
+ if (builtins.docs && routePath === "_docs") {
304
+ const html = scalarDocsHtml(`${basePath}_openapi`, existingCommand.title || existingCommand.name);
305
+ return addCorsHeaders(new Response(html, {
306
+ status: 200,
307
+ headers: { "Content-Type": "text/html" }
308
+ }));
309
+ }
310
+ }
311
+ const endpoint = routeMap.get(routePath);
312
+ if (!endpoint) return addCorsHeaders(jsonResponse({
313
+ ok: false,
314
+ error: "not_found",
315
+ message: `Command not found: ${routePath || "/"}`
316
+ }, 404));
317
+ if (endpoint.command.mutation && req.method === "GET") return addCorsHeaders(new Response(JSON.stringify({
318
+ ok: false,
319
+ error: "method_not_allowed",
320
+ message: "Mutation commands only accept POST"
321
+ }), {
322
+ status: 405,
323
+ headers: {
324
+ "Content-Type": "application/json",
325
+ Allow: "POST"
326
+ }
327
+ }));
328
+ if (req.method !== "GET" && req.method !== "POST") return addCorsHeaders(new Response(null, {
329
+ status: 405,
330
+ headers: { Allow: endpoint.command.mutation ? "POST" : "GET, POST" }
331
+ }));
332
+ const commandPath = toCommandPath(routePath);
333
+ let argParts;
334
+ if (req.method === "POST") try {
335
+ argParts = serializeArgsToFlags(await req.json());
336
+ } catch {
337
+ return addCorsHeaders(jsonResponse({
338
+ ok: false,
339
+ error: "bad_request",
340
+ message: "Invalid JSON body"
341
+ }, 400));
342
+ }
343
+ else {
344
+ argParts = [];
345
+ for (const [key, value] of url.searchParams.entries()) if (key === "_") argParts.push(value);
346
+ else argParts.push(value === "" ? `--${key}` : `--${key}=${value}`);
347
+ }
348
+ return addCorsHeaders(await evalAndRespond([commandPath, ...argParts].filter(Boolean).join(" "), req));
349
+ };
350
+ }
351
+ /** Start the serve HTTP server. */
352
+ async function startServeServer(_program, existingCommand, evalCommand, prefs) {
353
+ const handler = createServeHandler(existingCommand, evalCommand, prefs);
354
+ const http = await import("node:http");
355
+ const port = prefs?.port ?? 3e3;
356
+ const host = prefs?.host ?? "127.0.0.1";
357
+ const basePath = (prefs?.basePath ?? "/").replace(/\/$/, "/");
358
+ const server = http.createServer(async (req, res) => {
359
+ const url = `http://${host}:${port}${req.url}`;
360
+ const headers = new Headers();
361
+ for (const [key, value] of Object.entries(req.headers)) if (value) headers.set(key, Array.isArray(value) ? value.join(", ") : value);
362
+ const response = await handler(new Request(url, {
363
+ method: req.method,
364
+ headers,
365
+ body: req.method !== "GET" && req.method !== "HEAD" ? await readBody(req) : void 0
366
+ }));
367
+ const resHeaders = {};
368
+ response.headers.forEach((v, k) => {
369
+ resHeaders[k] = v;
370
+ });
371
+ res.writeHead(response.status, resHeaders);
372
+ const body = await response.text();
373
+ res.end(body);
374
+ });
375
+ const { getCommandRuntime } = await import("./commands-B_gufyR9.mjs").then((n) => n.a);
376
+ const runtime = getCommandRuntime(existingCommand);
377
+ return new Promise((resolve, reject) => {
378
+ server.listen(port, host, () => {
379
+ runtime.error(`REST server listening on http://${host}:${port}${basePath}`);
380
+ if ({
381
+ health: true,
382
+ help: true,
383
+ schema: true,
384
+ docs: true,
385
+ ...prefs?.builtins
386
+ }.docs) runtime.error(`API docs: http://${host}:${port}${basePath}_docs`);
387
+ });
388
+ server.on("error", reject);
389
+ const unsubscribe = runtime.onSignal?.(() => {
390
+ server.close(() => resolve());
391
+ });
392
+ server.on("close", () => unsubscribe?.());
393
+ });
394
+ }
395
+ /** Read the full body from a Node.js IncomingMessage. */
396
+ async function readBody(req) {
397
+ return readStreamAsText(req);
398
+ }
399
+ //#endregion
400
+ export { startServeServer };
401
+
402
+ //# sourceMappingURL=serve-Bk0JUlCj.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serve-Bk0JUlCj.mjs","names":[],"sources":["../src/feature/serve.ts"],"sourcesContent":["import { buildInputSchema, type CollectedEndpoint, collectEndpoints, serializeArgsToFlags } from '../core/commands.ts';\nimport { RoutingError, ValidationError } from '../core/errors.ts';\nimport { generateHelp } from '../output/help.ts';\nimport type { AnyPadroneCommand, AnyPadroneProgram } from '../types/index.ts';\nimport { readStreamAsText } from '../util/stream.ts';\n\nexport type PadroneServePreferences = {\n /** Port to listen on. Default: 3000 */\n port?: number;\n /** Host to bind to. Default: '127.0.0.1' */\n host?: string;\n /** Base path prefix for all routes. Default: '/' */\n basePath?: string;\n /** CORS allowed origin. Default: '*'. Set to `false` to disable CORS headers. */\n cors?: string | false;\n /** Control built-in utility endpoints. All enabled by default. */\n builtins?: {\n /** GET /_health — returns 200 OK. */\n health?: boolean;\n /** GET /_help and GET /_help/:command — returns help text. */\n help?: boolean;\n /** GET /_schema and GET /_schema/:command — returns JSON Schema. */\n schema?: boolean;\n /** GET /_docs — Scalar OpenAPI docs viewer. */\n docs?: boolean;\n };\n /** Hook to run before each request. Return a Response to short-circuit. */\n onRequest?: (req: Request) => Response | void | Promise<Response | void>;\n /** Transform errors into responses. */\n onError?: (error: unknown, req: Request) => Response;\n};\n\n/** Convert an endpoint dot-path to a URL path segment. */\nfunction toUrlPath(name: string): string {\n return name.replace(/\\./g, '/');\n}\n\n/** Convert a URL path segment back to a command path (slash → space). */\nfunction toCommandPath(urlPath: string): string {\n return urlPath.replace(/\\//g, ' ');\n}\n\nfunction jsonResponse(body: unknown, status = 200, headers?: Record<string, string>): Response {\n return new Response(JSON.stringify(body), {\n status,\n headers: { 'Content-Type': 'application/json', ...headers },\n });\n}\n\nfunction errorToStatus(error: unknown): number {\n if (error instanceof RoutingError) return 404;\n if (error instanceof ValidationError) return 400;\n return 500;\n}\n\nfunction errorToResponse(error: unknown): Response {\n const status = errorToStatus(error);\n if (error instanceof ValidationError) {\n return jsonResponse(\n {\n ok: false,\n error: 'validation',\n message: error.message,\n issues: error.issues.map((i) => ({ path: i.path?.map(String), message: i.message })),\n },\n status,\n );\n }\n if (error instanceof RoutingError) {\n return jsonResponse({ ok: false, error: 'not_found', message: error.message, suggestions: error.suggestions }, status);\n }\n const message = error instanceof Error ? error.message : String(error);\n return jsonResponse({ ok: false, error: 'action_error', message }, status);\n}\n\n/** Generate an OpenAPI 3.1.0 spec from the command tree. */\nfunction buildOpenApiSpec(existingCommand: AnyPadroneCommand, endpoints: CollectedEndpoint[], basePath: string): Record<string, unknown> {\n const paths: Record<string, unknown> = {};\n\n const responseSchema = {\n '200': {\n description: 'Successful response',\n content: { 'application/json': { schema: { type: 'object', properties: { ok: { type: 'boolean', const: true }, result: {} } } } },\n },\n '400': {\n description: 'Validation error',\n content: {\n 'application/json': {\n schema: {\n type: 'object',\n properties: {\n ok: { type: 'boolean', const: false },\n error: { type: 'string', const: 'validation' },\n message: { type: 'string' },\n issues: { type: 'array', items: { type: 'object', properties: { path: { type: 'array' }, message: { type: 'string' } } } },\n },\n },\n },\n },\n },\n '404': {\n description: 'Command not found',\n content: {\n 'application/json': {\n schema: {\n type: 'object',\n properties: {\n ok: { type: 'boolean', const: false },\n error: { type: 'string', const: 'not_found' },\n message: { type: 'string' },\n },\n },\n },\n },\n },\n '500': {\n description: 'Action error',\n content: {\n 'application/json': {\n schema: {\n type: 'object',\n properties: {\n ok: { type: 'boolean', const: false },\n error: { type: 'string', const: 'action_error' },\n message: { type: 'string' },\n },\n },\n },\n },\n },\n };\n\n for (const { name, command: cmd } of endpoints) {\n const urlPath = `${basePath}${toUrlPath(name)}`;\n const inputSchema = buildInputSchema(cmd);\n const description = cmd.description || cmd.title || `Run the \"${name}\" command`;\n const pathItem: Record<string, unknown> = {};\n\n const postOp = {\n summary: cmd.title || name,\n description,\n operationId: `post_${name.replace(/\\./g, '_')}`,\n requestBody: { content: { 'application/json': { schema: inputSchema } } },\n responses: responseSchema,\n };\n\n if (cmd.mutation) {\n pathItem.post = postOp;\n } else {\n // GET: args as query parameters\n const properties = (inputSchema.properties ?? {}) as Record<string, Record<string, unknown>>;\n const queryParams = Object.entries(properties).map(([key, schema]) => ({\n name: key,\n in: 'query',\n schema,\n required: (inputSchema.required as string[] | undefined)?.includes(key) ?? false,\n }));\n pathItem.get = {\n summary: cmd.title || name,\n description,\n operationId: `get_${name.replace(/\\./g, '_')}`,\n parameters: queryParams,\n responses: responseSchema,\n };\n pathItem.post = postOp;\n }\n\n paths[urlPath] = pathItem;\n }\n\n return {\n openapi: '3.1.0',\n info: {\n title: existingCommand.title || existingCommand.name,\n description: existingCommand.description,\n version: existingCommand.version ?? '0.0.0',\n },\n paths,\n };\n}\n\nfunction scalarDocsHtml(openapiUrl: string, title: string): string {\n return `<!doctype html>\n<html>\n<head>\n <title>${title} — API Docs</title>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n</head>\n<body>\n <script id=\"api-reference\" data-url=\"${openapiUrl}\"></script>\n <script src=\"https://cdn.jsdelivr.net/npm/@scalar/api-reference\"></script>\n</body>\n</html>`;\n}\n\n/** Create the serve request handler. */\nexport function createServeHandler(\n existingCommand: AnyPadroneCommand,\n evalCommand: AnyPadroneProgram['eval'],\n prefs?: PadroneServePreferences,\n): (req: Request) => Promise<Response> {\n const basePath = (prefs?.basePath ?? '/').replace(/\\/$/, '/');\n const corsOrigin = prefs?.cors !== false ? (prefs?.cors ?? '*') : undefined;\n const builtins = { health: true, help: true, schema: true, docs: true, ...prefs?.builtins };\n\n const endpoints = collectEndpoints(existingCommand.commands, '');\n if (existingCommand.action || existingCommand.argsSchema) {\n endpoints.unshift({ name: '', command: existingCommand });\n }\n\n const routeMap = new Map<string, CollectedEndpoint>();\n for (const ep of endpoints) {\n routeMap.set(toUrlPath(ep.name), ep);\n }\n\n let cachedOpenApiSpec: Record<string, unknown> | undefined;\n const getOpenApiSpec = () => (cachedOpenApiSpec ??= buildOpenApiSpec(existingCommand, endpoints, basePath));\n\n function addCorsHeaders(res: Response): Response {\n if (!corsOrigin) return res;\n const headers = new Headers(res.headers);\n headers.set('Access-Control-Allow-Origin', corsOrigin);\n headers.set('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');\n headers.set('Access-Control-Allow-Headers', 'Content-Type');\n return new Response(res.body, { status: res.status, statusText: res.statusText, headers });\n }\n\n async function evalAndRespond(commandString: string, request: Request): Promise<Response> {\n const output: string[] = [];\n const errors: string[] = [];\n const result = await evalCommand(commandString || (undefined as any), {\n caller: 'serve',\n runtime: {\n output: (...args: unknown[]) => output.push(args.map(String).join(' ')),\n error: (text: string) => errors.push(text),\n interactive: 'unsupported',\n format: 'json',\n },\n });\n\n if (result.error) {\n return prefs?.onError ? prefs.onError(result.error, request) : errorToResponse(result.error);\n }\n\n if (result.argsResult?.issues) {\n const issues = (result.argsResult.issues as { path?: PropertyKey[]; message: string }[]).map((i) => ({\n path: i.path?.map(String),\n message: i.message,\n }));\n return jsonResponse({ ok: false, error: 'validation', issues }, 400);\n }\n\n return jsonResponse({ ok: true, result: result.result ?? null });\n }\n\n return async function handleRequest(req: Request): Promise<Response> {\n // CORS preflight\n if (req.method === 'OPTIONS') {\n return addCorsHeaders(new Response(null, { status: corsOrigin ? 204 : 405 }));\n }\n\n // onRequest hook\n if (prefs?.onRequest) {\n const hookResponse = await prefs.onRequest(req);\n if (hookResponse) return addCorsHeaders(hookResponse);\n }\n\n const url = new URL(req.url, 'http://localhost');\n let pathname = url.pathname;\n\n // Strip basePath prefix\n if (basePath !== '/' && pathname.startsWith(basePath)) {\n pathname = pathname.slice(basePath.length - 1);\n }\n // Remove leading slash for route matching\n const routePath = pathname.replace(/^\\//, '');\n\n // Built-in endpoints\n if (req.method === 'GET') {\n if (builtins.health && routePath === '_health') {\n return addCorsHeaders(jsonResponse({ status: 'ok' }));\n }\n\n if (builtins.schema && routePath === '_schema') {\n const schemaMap: Record<string, unknown> = {};\n for (const ep of endpoints) {\n schemaMap[toUrlPath(ep.name) || '/'] = buildInputSchema(ep.command);\n }\n return addCorsHeaders(jsonResponse(schemaMap));\n }\n\n if (builtins.schema && routePath.startsWith('_schema/')) {\n const cmdPath = routePath.slice('_schema/'.length);\n const ep = routeMap.get(cmdPath);\n if (!ep) return addCorsHeaders(jsonResponse({ ok: false, error: 'not_found', message: `Command not found: ${cmdPath}` }, 404));\n return addCorsHeaders(jsonResponse(buildInputSchema(ep.command)));\n }\n\n if (builtins.help && routePath === '_help') {\n const accept = req.headers.get('accept') ?? '';\n const format = accept.includes('application/json') ? 'json' : 'markdown';\n const helpText = generateHelp(existingCommand, existingCommand, { format, detail: 'full' });\n if (format === 'json') return addCorsHeaders(jsonResponse(JSON.parse(helpText)));\n return addCorsHeaders(new Response(helpText, { status: 200, headers: { 'Content-Type': 'text/markdown' } }));\n }\n\n if (builtins.help && routePath.startsWith('_help/')) {\n const cmdPath = routePath.slice('_help/'.length);\n const ep = routeMap.get(cmdPath);\n if (!ep) return addCorsHeaders(jsonResponse({ ok: false, error: 'not_found', message: `Command not found: ${cmdPath}` }, 404));\n const accept = req.headers.get('accept') ?? '';\n const format = accept.includes('application/json') ? 'json' : 'markdown';\n const helpText = generateHelp(existingCommand, ep.command, { format, detail: 'full' });\n if (format === 'json') return addCorsHeaders(jsonResponse(JSON.parse(helpText)));\n return addCorsHeaders(new Response(helpText, { status: 200, headers: { 'Content-Type': 'text/markdown' } }));\n }\n\n if (builtins.docs && routePath === '_openapi') {\n return addCorsHeaders(jsonResponse(getOpenApiSpec()));\n }\n\n if (builtins.docs && routePath === '_docs') {\n const openapiUrl = `${basePath}_openapi`;\n const title = existingCommand.title || existingCommand.name;\n const html = scalarDocsHtml(openapiUrl, title);\n return addCorsHeaders(new Response(html, { status: 200, headers: { 'Content-Type': 'text/html' } }));\n }\n }\n\n // Route to command\n const endpoint = routeMap.get(routePath);\n if (!endpoint) {\n return addCorsHeaders(jsonResponse({ ok: false, error: 'not_found', message: `Command not found: ${routePath || '/'}` }, 404));\n }\n\n // Enforce method based on mutation flag\n if (endpoint.command.mutation && req.method === 'GET') {\n return addCorsHeaders(\n new Response(JSON.stringify({ ok: false, error: 'method_not_allowed', message: 'Mutation commands only accept POST' }), {\n status: 405,\n headers: { 'Content-Type': 'application/json', Allow: 'POST' },\n }),\n );\n }\n\n if (req.method !== 'GET' && req.method !== 'POST') {\n return addCorsHeaders(new Response(null, { status: 405, headers: { Allow: endpoint.command.mutation ? 'POST' : 'GET, POST' } }));\n }\n\n // Build command string from request\n const commandPath = toCommandPath(routePath);\n let argParts: string[];\n\n if (req.method === 'POST') {\n try {\n const body = (await req.json()) as Record<string, unknown>;\n argParts = serializeArgsToFlags(body);\n } catch {\n return addCorsHeaders(jsonResponse({ ok: false, error: 'bad_request', message: 'Invalid JSON body' }, 400));\n }\n } else {\n // GET: query string → flags\n argParts = [];\n for (const [key, value] of url.searchParams.entries()) {\n if (key === '_') {\n // Positional args\n argParts.push(value);\n } else {\n argParts.push(value === '' ? `--${key}` : `--${key}=${value}`);\n }\n }\n }\n\n const commandString = [commandPath, ...argParts].filter(Boolean).join(' ');\n const response = await evalAndRespond(commandString, req);\n return addCorsHeaders(response);\n };\n}\n\n/** Start the serve HTTP server. */\nexport async function startServeServer(\n _program: AnyPadroneProgram,\n existingCommand: AnyPadroneCommand,\n evalCommand: AnyPadroneProgram['eval'],\n prefs?: PadroneServePreferences,\n): Promise<void> {\n const handler = createServeHandler(existingCommand, evalCommand, prefs);\n const http = await import('node:http');\n\n const port = prefs?.port ?? 3000;\n const host = prefs?.host ?? '127.0.0.1';\n const basePath = (prefs?.basePath ?? '/').replace(/\\/$/, '/');\n\n const server = http.createServer(async (req, res) => {\n const url = `http://${host}:${port}${req.url}`;\n const headers = new Headers();\n for (const [key, value] of Object.entries(req.headers)) {\n if (value) headers.set(key, Array.isArray(value) ? value.join(', ') : value);\n }\n\n const fetchReq = new Request(url, {\n method: req.method,\n headers,\n body: req.method !== 'GET' && req.method !== 'HEAD' ? await readBody(req) : undefined,\n });\n\n const response = await handler(fetchReq);\n const resHeaders: Record<string, string> = {};\n response.headers.forEach((v, k) => {\n resHeaders[k] = v;\n });\n res.writeHead(response.status, resHeaders);\n const body = await response.text();\n res.end(body);\n });\n\n const { getCommandRuntime } = await import('../core/commands.ts');\n const runtime = getCommandRuntime(existingCommand);\n\n return new Promise<void>((resolve, reject) => {\n server.listen(port, host, () => {\n runtime.error(`REST server listening on http://${host}:${port}${basePath}`);\n const builtins = { health: true, help: true, schema: true, docs: true, ...prefs?.builtins };\n if (builtins.docs) runtime.error(`API docs: http://${host}:${port}${basePath}_docs`);\n });\n server.on('error', reject);\n const unsubscribe = runtime.onSignal?.(() => {\n server.close(() => resolve());\n });\n server.on('close', () => unsubscribe?.());\n });\n}\n\n/** Read the full body from a Node.js IncomingMessage. */\nasync function readBody(req: import('node:http').IncomingMessage): Promise<string> {\n return readStreamAsText(req as AsyncIterable<Uint8Array>);\n}\n"],"mappings":"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"}
@@ -0,0 +1,77 @@
1
+ //#region src/util/stream.ts
2
+ let asyncStreamIdCounter = 1;
3
+ const asyncStreamRegistry = /* @__PURE__ */ new Map();
4
+ /**
5
+ * Returns metadata to mark a schema field as an async stream via `.meta()`.
6
+ *
7
+ * When used with `stdin`, padrone pipes stdin data as an `AsyncIterable` instead of
8
+ * buffering it. Each line is validated against the item schema (if provided) as it arrives.
9
+ *
10
+ * @param itemSchema - Optional item schema for per-item validation.
11
+ * Non-string schemas cause each stdin line to be `JSON.parse`'d before validation.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * import { asyncStream } from 'padrone';
16
+ *
17
+ * // String lines
18
+ * z.object({ lines: z.custom<AsyncIterable<string>>().meta(asyncStream()) })
19
+ *
20
+ * // Typed items — each line JSON.parse'd and validated
21
+ * z.object({ records: z.custom<AsyncIterable<{ name: string }>>().meta(asyncStream(recordSchema)) })
22
+ * ```
23
+ */
24
+ function asyncStream(itemSchema) {
25
+ const id = asyncStreamIdCounter++;
26
+ const meta = itemSchema ? {
27
+ asyncStream: id,
28
+ itemSchema
29
+ } : { asyncStream: id };
30
+ asyncStreamRegistry.set(id, meta);
31
+ return meta;
32
+ }
33
+ /**
34
+ * Creates an `AsyncIterable` from a stdin source, optionally validating each item.
35
+ * When no stdin is available (TTY / undefined), yields nothing.
36
+ *
37
+ * - No item schema: yields raw string lines
38
+ * - With item schema: `JSON.parse`s each line, validates, then yields
39
+ */
40
+ function createStdinStream(stdin, itemSchema) {
41
+ if (!stdin) return emptyAsyncIterable;
42
+ if (!itemSchema) return stdin.lines();
43
+ return { async *[Symbol.asyncIterator]() {
44
+ for await (const line of stdin.lines()) {
45
+ const result = itemSchema["~standard"].validate(line);
46
+ const resolved = result instanceof Promise ? await result : result;
47
+ if ("issues" in resolved && resolved.issues) throw new Error(`Stream item validation failed: ${resolved.issues.map((i) => i.message).join(", ")}`);
48
+ yield resolved.value;
49
+ }
50
+ } };
51
+ }
52
+ const emptyAsyncIterable = { async *[Symbol.asyncIterator]() {} };
53
+ const textEncoder = /* @__PURE__ */ new TextEncoder();
54
+ const textDecoder = /* @__PURE__ */ new TextDecoder();
55
+ /** Concatenate multiple `Uint8Array` chunks into a single array. */
56
+ function concatBytes(chunks) {
57
+ if (chunks.length === 1) return chunks[0];
58
+ let totalLength = 0;
59
+ for (const chunk of chunks) totalLength += chunk.byteLength;
60
+ const result = new Uint8Array(totalLength);
61
+ let offset = 0;
62
+ for (const chunk of chunks) {
63
+ result.set(chunk, offset);
64
+ offset += chunk.byteLength;
65
+ }
66
+ return result;
67
+ }
68
+ /** Read an async iterable of chunks into a UTF-8 string. */
69
+ async function readStreamAsText(stream) {
70
+ const chunks = [];
71
+ for await (const chunk of stream) chunks.push(typeof chunk === "string" ? textEncoder.encode(chunk) : chunk);
72
+ return textDecoder.decode(concatBytes(chunks));
73
+ }
74
+ //#endregion
75
+ export { readStreamAsText as a, createStdinStream as i, asyncStreamRegistry as n, concatBytes as r, asyncStream as t };
76
+
77
+ //# sourceMappingURL=stream-DC4H8YTx.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream-DC4H8YTx.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,KAA8B;;;;;;;;;;;;;;;;;;;;;AAsBrE,SAAgB,YAAwB,YAAgD;CACtF,MAAM,KAAK;CACX,MAAM,OAAwB,aAAa;EAAE,aAAa;EAAI;EAAY,GAAG,EAAE,aAAa,IAAI;AAChG,qBAAoB,IAAI,IAAI,KAAK;AACjC,QAAO;;;;;;;;;AAiBT,SAAgB,kBAAkB,OAAgC,YAAuD;AACvH,KAAI,CAAC,MAAO,QAAO;AAEnB,KAAI,CAAC,WAAY,QAAO,MAAM,OAAO;AAErC,QAAO,EACL,QAAQ,OAAO,iBAAiB;AAC9B,aAAW,MAAM,QAAQ,MAAM,OAAO,EAAE;GACtC,MAAM,SAAS,WAAW,aAAa,SAAS,KAAK;GACrD,MAAM,WAAW,kBAAkB,UAAU,MAAM,SAAS;AAC5D,OAAI,YAAY,YAAY,SAAS,OACnC,OAAM,IAAI,MAAM,kCAAkC,SAAS,OAAO,KAAK,MAAM,EAAE,QAAQ,CAAC,KAAK,KAAK,GAAG;AAEvG,SAAO,SAAgC;;IAG5C;;AAGH,MAAM,qBAA2C,EAC/C,QAAQ,OAAO,iBAAiB,IACjC;AAED,MAAM,8BAA8B,IAAI,aAAa;AACrD,MAAM,8BAA8B,IAAI,aAAa;;AAGrD,SAAgB,YAAY,QAAkC;AAC5D,KAAI,OAAO,WAAW,EAAG,QAAO,OAAO;CACvC,IAAI,cAAc;AAClB,MAAK,MAAM,SAAS,OAAQ,gBAAe,MAAM;CACjD,MAAM,SAAS,IAAI,WAAW,YAAY;CAC1C,IAAI,SAAS;AACb,MAAK,MAAM,SAAS,QAAQ;AAC1B,SAAO,IAAI,OAAO,OAAO;AACzB,YAAU,MAAM;;AAElB,QAAO;;;AAIT,eAAsB,iBAAiB,QAA6D;CAClG,MAAM,SAAuB,EAAE;AAC/B,YAAW,MAAM,SAAS,OACxB,QAAO,KAAK,OAAO,UAAU,WAAW,YAAY,OAAO,MAAM,GAAG,MAAM;AAE5E,QAAO,YAAY,OAAO,YAAY,OAAO,CAAC"}
package/dist/test.d.mts CHANGED
@@ -1,6 +1,6 @@
1
- import { b as PadroneRuntime, n as AnyPadroneCommand } from "./types-DjIdJN5G.mjs";
1
+ import { nt as PadroneRuntime, u as AnyPadroneCommand } from "./index-BaU3X6dY.mjs";
2
2
 
3
- //#region src/test.d.ts
3
+ //#region src/feature/test.d.ts
4
4
  /**
5
5
  * Result from a single command execution in test mode.
6
6
  * Extends the standard PadroneCommandResult with captured I/O.
@@ -31,8 +31,7 @@ type TestReplResult = {
31
31
  type TestCliBuilder = {
32
32
  /** Set the CLI input string (e.g. `'deploy --env production'`). */args(input: string): TestCliBuilder; /** Set environment variables visible to the command. */
33
33
  env(vars: Record<string, string | undefined>): TestCliBuilder; /** Provide mock answers for interactive prompts. Keys are field names. */
34
- prompt(answers: Record<string, unknown>): TestCliBuilder; /** Provide mock config files. Keys are file paths, values are parsed config objects. */
35
- config(files: Record<string, Record<string, unknown>>): TestCliBuilder; /** Provide mock stdin data (simulates piped input). */
34
+ prompt(answers: Record<string, unknown>): TestCliBuilder; /** Provide mock stdin data (simulates piped input). */
36
35
  stdin(data: string): TestCliBuilder;
37
36
  /**
38
37
  * Execute a single command via `eval()` and return the result with captured I/O.
@@ -97,9 +96,7 @@ type TestCliBuilder = {
97
96
  * Avoids strict variance issues with `AnyPadroneProgram`.
98
97
  */
99
98
  type TestableProgram = {
100
- eval: (input: string, prefs?: {
101
- autoOutput?: boolean;
102
- }) => any;
99
+ eval: (input: string, prefs?: Record<string, unknown>) => any;
103
100
  runtime: (runtime: PadroneRuntime) => TestableProgram;
104
101
  repl: (options?: {
105
102
  greeting?: false;
@@ -108,5 +105,5 @@ type TestableProgram = {
108
105
  };
109
106
  declare function testCli(program: TestableProgram): TestCliBuilder;
110
107
  //#endregion
111
- export { TestCliBuilder, TestCliResult, TestReplResult, testCli };
108
+ export { type TestCliBuilder, type TestCliResult, type TestReplResult, testCli };
112
109
  //# sourceMappingURL=test.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"test.d.mts","names":[],"sources":["../src/test.ts"],"mappings":";;;;AAOA;;;KAAY,aAAA;EAEV,2BAAA,OAAA,EAAS,iBAAA,EAET;EAAA,IAAA,WAIA;EAFA,MAAA,WAE2B;EAA3B,MAAA;IAAU,OAAA;IAAiB,IAAA,GAAO,WAAA;EAAA,iBAM7B;EAJL,MAAA,aAUU;EARV,MAAA;EAEA,KAAA;AAAA;;;;KAMU,cAAA;EAMJ,wGAJN,OAAA,EAAS,IAAA,CAAK,aAAA,0BAUJ;EARV,MAAA;EAEA,MAAA;AAAA;;;;KAMU,cAAA;EAQI,mEANd,IAAA,CAAK,KAAA,WAAgB,cAAA,EAQA;EANrB,GAAA,CAAI,IAAA,EAAM,MAAA,+BAAqC,cAAA,EAW1B;EATrB,MAAA,CAAO,OAAA,EAAS,MAAA,oBAA0B,cAAA,EAelB;EAbxB,MAAA,CAAO,KAAA,EAAO,MAAA,SAAe,MAAA,qBAA2B,cAAA,EAazB;EAX/B,KAAA,CAAM,IAAA,WAAe,cAAA;EARhB;;;;EAaL,GAAA,CAAI,KAAA,YAAiB,OAAA,CAAQ,aAAA;EAXkB;;;;;EAiB/C,IAAA,CAAK,MAAA,aAAmB,OAAA,CAAQ,cAAA;AAAA;;;;;;;;;;;;;;;;;AAChC;;;;;;;;;;;;;;;;;;;;;;;AA0DF;;;;;;;;;;;KANK,eAAA;EACH,IAAA,GAAO,KAAA,UAAe,KAAA;IAAU,UAAA;EAAA;EAChC,OAAA,GAAU,OAAA,EAAS,cAAA,KAAmB,eAAA;EACtC,IAAA,GAAO,OAAA;IAAY,QAAA;IAAkB,IAAA;EAAA,MAAmB,aAAA;AAAA;AAAA,iBAG1C,OAAA,CAAQ,OAAA,EAAS,eAAA,GAAkB,cAAA"}
1
+ {"version":3,"file":"test.d.mts","names":[],"sources":["../src/feature/test.ts"],"mappings":";;;;AAOA;;;KAAY,aAAA;EAEV,2BAAA,OAAA,EAAS,iBAAA,EAET;EAAA,IAAA,WAIA;EAFA,MAAA,WAE2B;EAA3B,MAAA;IAAU,OAAA;IAAiB,IAAA,GAAO,WAAA;EAAA,iBAM7B;EAJL,MAAA,aAUU;EARV,MAAA;EAEA,KAAA;AAAA;;;;KAMU,cAAA;EAMJ,wGAJN,OAAA,EAAS,IAAA,CAAK,aAAA,0BAUJ;EARV,MAAA;EAEA,MAAA;AAAA;;;;KAMU,cAAA;EAamB,mEAX7B,IAAA,CAAK,KAAA,WAAgB,cAAA,EAiBW;EAfhC,GAAA,CAAI,IAAA,EAAM,MAAA,+BAAqC,cAAA,EAehB;EAb/B,MAAA,CAAO,OAAA,EAAS,MAAA,oBAA0B,cAAA,EAJ1C;EAMA,KAAA,CAAM,IAAA,WAAe,cAAA;EANA;;;;EAWrB,GAAA,CAAI,KAAA,YAAiB,OAAA,CAAQ,aAAA;EAP7B;;;;;EAaA,IAAA,CAAK,MAAA,aAAmB,OAAA,CAAQ,cAAA;AAAA;;;;;;;;;;;AAChC;;;;;;;;;;;;;;;;;;;;;;;;AA0DF;;;;;;;;;;;;;;;;KANK,eAAA;EACH,IAAA,GAAO,KAAA,UAAe,KAAA,GAAQ,MAAA;EAC9B,OAAA,GAAU,OAAA,EAAS,cAAA,KAAmB,eAAA;EACtC,IAAA,GAAO,OAAA;IAAY,QAAA;IAAkB,IAAA;EAAA,MAAmB,aAAA;AAAA;AAAA,iBAG1C,OAAA,CAAQ,OAAA,EAAS,eAAA,GAAkB,cAAA"}
package/dist/test.mjs CHANGED
@@ -1,9 +1,8 @@
1
- //#region src/test.ts
1
+ //#region src/feature/test.ts
2
2
  function testCli(program) {
3
3
  let input;
4
4
  let envVars;
5
5
  let promptAnswers;
6
- let configFiles;
7
6
  let stdinData;
8
7
  const builder = {
9
8
  args(args) {
@@ -18,10 +17,6 @@ function testCli(program) {
18
17
  promptAnswers = answers;
19
18
  return builder;
20
19
  },
21
- config(files) {
22
- configFiles = files;
23
- return builder;
24
- },
25
20
  stdin(data) {
26
21
  stdinData = data;
27
22
  return builder;
@@ -32,24 +27,11 @@ function testCli(program) {
32
27
  const runtime = buildRuntime(stdout, stderr, {
33
28
  envVars,
34
29
  promptAnswers,
35
- configFiles,
36
30
  stdinData
37
31
  });
38
- const testProgram = program.runtime(runtime);
39
- try {
40
- return toTestResult(await testProgram.eval(runInput ?? input ?? "", { autoOutput: false }), stdout, stderr);
41
- } catch (err) {
42
- stderr.push(err instanceof Error ? err.message : String(err));
43
- return {
44
- command: void 0,
45
- args: void 0,
46
- result: void 0,
47
- issues: void 0,
48
- stdout,
49
- stderr,
50
- error: err
51
- };
52
- }
32
+ const evalResult = await program.runtime(runtime).eval(runInput ?? input ?? "", {});
33
+ if (evalResult.error) stderr.push(evalResult.error instanceof Error ? evalResult.error.message : String(evalResult.error));
34
+ return toTestResult(evalResult, stdout, stderr);
53
35
  },
54
36
  async repl(inputs) {
55
37
  const stdout = [];
@@ -57,7 +39,6 @@ function testCli(program) {
57
39
  const runtime = buildRuntime(stdout, stderr, {
58
40
  envVars,
59
41
  promptAnswers,
60
- configFiles,
61
42
  readLine: createMockReadLine(inputs)
62
43
  });
63
44
  const testProgram = program.runtime(runtime);
@@ -85,6 +66,7 @@ function toTestResult(evalResult, stdout, stderr) {
85
66
  command: evalResult.command,
86
67
  args: evalResult.args,
87
68
  result: evalResult.result,
69
+ error: evalResult.error,
88
70
  issues: evalResult.argsResult?.issues,
89
71
  stdout,
90
72
  stderr
@@ -100,10 +82,6 @@ function buildRuntime(stdout, stderr, opts) {
100
82
  runtime.interactive = "supported";
101
83
  runtime.prompt = async (config) => opts.promptAnswers[config.name];
102
84
  }
103
- if (opts.configFiles) {
104
- runtime.loadConfigFile = (path) => opts.configFiles[path];
105
- runtime.findFile = (names) => names.find((n) => n in opts.configFiles);
106
- }
107
85
  if (opts.readLine) runtime.readLine = opts.readLine;
108
86
  if (opts.stdinData !== void 0) runtime.stdin = {
109
87
  isTTY: false,