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.
- package/CHANGELOG.md +20 -1
- package/README.md +2 -2
- package/dist/codegen/code-builder.d.mts +10 -0
- package/dist/codegen/code-builder.d.mts.map +1 -0
- package/dist/codegen/code-builder.mjs +185 -0
- package/dist/codegen/code-builder.mjs.map +1 -0
- package/dist/codegen/discovery.d.mts +44 -0
- package/dist/codegen/discovery.d.mts.map +1 -0
- package/dist/codegen/discovery.mjs +179 -0
- package/dist/codegen/discovery.mjs.map +1 -0
- package/dist/codegen/file-emitter.d.mts +10 -0
- package/dist/codegen/file-emitter.d.mts.map +1 -0
- package/dist/codegen/file-emitter.mjs +58 -0
- package/dist/codegen/file-emitter.mjs.map +1 -0
- package/dist/codegen/generators/barrel-file.d.mts +10 -0
- package/dist/codegen/generators/barrel-file.d.mts.map +1 -0
- package/dist/codegen/generators/barrel-file.mjs +16 -0
- package/dist/codegen/generators/barrel-file.mjs.map +1 -0
- package/dist/codegen/generators/command-file.d.mts +25 -0
- package/dist/codegen/generators/command-file.d.mts.map +1 -0
- package/dist/codegen/generators/command-file.mjs +130 -0
- package/dist/codegen/generators/command-file.mjs.map +1 -0
- package/dist/codegen/generators/command-tree.d.mts +17 -0
- package/dist/codegen/generators/command-tree.d.mts.map +1 -0
- package/dist/codegen/generators/command-tree.mjs +72 -0
- package/dist/codegen/generators/command-tree.mjs.map +1 -0
- package/dist/codegen/index.d.mts +15 -330
- package/dist/codegen/index.mjs +13 -1507
- package/dist/codegen/parsers/bash.d.mts +19 -0
- package/dist/codegen/parsers/bash.d.mts.map +1 -0
- package/dist/codegen/parsers/bash.mjs +112 -0
- package/dist/codegen/parsers/bash.mjs.map +1 -0
- package/dist/codegen/parsers/fish.d.mts +13 -0
- package/dist/codegen/parsers/fish.d.mts.map +1 -0
- package/dist/codegen/parsers/fish.mjs +108 -0
- package/dist/codegen/parsers/fish.mjs.map +1 -0
- package/dist/codegen/parsers/help.d.mts +15 -0
- package/dist/codegen/parsers/help.d.mts.map +1 -0
- package/dist/codegen/parsers/help.mjs +271 -0
- package/dist/codegen/parsers/help.mjs.map +1 -0
- package/dist/codegen/parsers/merge.d.mts +14 -0
- package/dist/codegen/parsers/merge.d.mts.map +1 -0
- package/dist/codegen/parsers/merge.mjs +76 -0
- package/dist/codegen/parsers/merge.mjs.map +1 -0
- package/dist/codegen/parsers/zsh.d.mts +16 -0
- package/dist/codegen/parsers/zsh.d.mts.map +1 -0
- package/dist/codegen/parsers/zsh.mjs +161 -0
- package/dist/codegen/parsers/zsh.mjs.map +1 -0
- package/dist/codegen/schema-to-code.d.mts +24 -0
- package/dist/codegen/schema-to-code.d.mts.map +1 -0
- package/dist/codegen/schema-to-code.mjs +147 -0
- package/dist/codegen/schema-to-code.mjs.map +1 -0
- package/dist/codegen/template.d.mts +18 -0
- package/dist/codegen/template.d.mts.map +1 -0
- package/dist/codegen/template.mjs +37 -0
- package/dist/codegen/template.mjs.map +1 -0
- package/dist/codegen/types.d.mts +144 -0
- package/dist/codegen/types.d.mts.map +1 -0
- package/dist/completion.d.mts +2 -0
- package/dist/completion.mjs +2 -0
- package/dist/core/args.d.mts +3 -0
- package/dist/{args-DrCXxXeP.mjs → core/args.mjs} +49 -113
- package/dist/core/args.mjs.map +1 -0
- package/dist/core/commands.d.mts +13 -0
- package/dist/core/commands.d.mts.map +1 -0
- package/dist/{commands-DLR0rFgq.mjs → core/commands.mjs} +4 -232
- package/dist/core/commands.mjs.map +1 -0
- package/dist/core/create.d.mts +63 -0
- package/dist/core/create.d.mts.map +1 -0
- package/dist/core/create.mjs +230 -0
- package/dist/core/create.mjs.map +1 -0
- package/dist/core/default-runtime.mjs +198 -0
- package/dist/core/default-runtime.mjs.map +1 -0
- package/dist/core/errors.d.mts +107 -0
- package/dist/core/errors.d.mts.map +1 -0
- package/dist/{errors-DA4KzK1M.mjs → core/errors.mjs} +2 -2
- package/dist/core/errors.mjs.map +1 -0
- package/dist/core/exec.mjs +191 -0
- package/dist/core/exec.mjs.map +1 -0
- package/dist/core/interceptors.d.mts +33 -0
- package/dist/core/interceptors.d.mts.map +1 -0
- package/dist/core/interceptors.mjs +253 -0
- package/dist/core/interceptors.mjs.map +1 -0
- package/dist/core/parse.mjs +181 -0
- package/dist/core/parse.mjs.map +1 -0
- package/dist/core/program-methods.mjs +256 -0
- package/dist/core/program-methods.mjs.map +1 -0
- package/dist/core/results.d.mts +13 -0
- package/dist/core/results.d.mts.map +1 -0
- package/dist/core/results.mjs +150 -0
- package/dist/core/results.mjs.map +1 -0
- package/dist/core/runtime.d.mts +213 -0
- package/dist/core/runtime.d.mts.map +1 -0
- package/dist/core/runtime.mjs +10 -0
- package/dist/core/runtime.mjs.map +1 -0
- package/dist/core/validate.mjs +220 -0
- package/dist/core/validate.mjs.map +1 -0
- package/dist/docs/index.d.mts +1 -1
- package/dist/docs/index.d.mts.map +1 -1
- package/dist/docs/index.mjs +2 -2
- package/dist/docs/index.mjs.map +1 -1
- package/dist/extension/auto-output.d.mts +53 -0
- package/dist/extension/auto-output.d.mts.map +1 -0
- package/dist/extension/auto-output.mjs +116 -0
- package/dist/extension/auto-output.mjs.map +1 -0
- package/dist/extension/color.d.mts +19 -0
- package/dist/extension/color.d.mts.map +1 -0
- package/dist/extension/color.mjs +37 -0
- package/dist/extension/color.mjs.map +1 -0
- package/dist/extension/completion.d.mts +25 -0
- package/dist/extension/completion.d.mts.map +1 -0
- package/dist/extension/completion.mjs +40 -0
- package/dist/extension/completion.mjs.map +1 -0
- package/dist/extension/config.d.mts +55 -0
- package/dist/extension/config.d.mts.map +1 -0
- package/dist/extension/config.mjs +162 -0
- package/dist/extension/config.mjs.map +1 -0
- package/dist/extension/env.d.mts +42 -0
- package/dist/extension/env.d.mts.map +1 -0
- package/dist/extension/env.mjs +44 -0
- package/dist/extension/env.mjs.map +1 -0
- package/dist/extension/help.d.mts +29 -0
- package/dist/extension/help.d.mts.map +1 -0
- package/dist/extension/help.mjs +161 -0
- package/dist/extension/help.mjs.map +1 -0
- package/dist/extension/index.d.mts +18 -0
- package/dist/extension/ink.d.mts +31 -0
- package/dist/extension/ink.d.mts.map +1 -0
- package/dist/extension/ink.mjs +69 -0
- package/dist/extension/ink.mjs.map +1 -0
- package/dist/extension/interactive.d.mts +16 -0
- package/dist/extension/interactive.d.mts.map +1 -0
- package/dist/extension/interactive.mjs +89 -0
- package/dist/extension/interactive.mjs.map +1 -0
- package/dist/extension/logger.d.mts +67 -0
- package/dist/extension/logger.d.mts.map +1 -0
- package/dist/extension/logger.mjs +188 -0
- package/dist/extension/logger.mjs.map +1 -0
- package/dist/extension/man.d.mts +25 -0
- package/dist/extension/man.d.mts.map +1 -0
- package/dist/extension/man.mjs +41 -0
- package/dist/extension/man.mjs.map +1 -0
- package/dist/extension/mcp.d.mts +28 -0
- package/dist/extension/mcp.d.mts.map +1 -0
- package/dist/extension/mcp.mjs +44 -0
- package/dist/extension/mcp.mjs.map +1 -0
- package/dist/extension/progress-renderer.d.mts +13 -0
- package/dist/extension/progress-renderer.d.mts.map +1 -0
- package/dist/extension/progress-renderer.mjs +351 -0
- package/dist/extension/progress-renderer.mjs.map +1 -0
- package/dist/extension/progress.d.mts +76 -0
- package/dist/extension/progress.d.mts.map +1 -0
- package/dist/extension/progress.mjs +225 -0
- package/dist/extension/progress.mjs.map +1 -0
- package/dist/extension/repl.d.mts +26 -0
- package/dist/extension/repl.d.mts.map +1 -0
- package/dist/extension/repl.mjs +67 -0
- package/dist/extension/repl.mjs.map +1 -0
- package/dist/extension/serve.d.mts +27 -0
- package/dist/extension/serve.d.mts.map +1 -0
- package/dist/extension/serve.mjs +41 -0
- package/dist/extension/serve.mjs.map +1 -0
- package/dist/extension/signal.d.mts +19 -0
- package/dist/extension/signal.d.mts.map +1 -0
- package/dist/extension/signal.mjs +81 -0
- package/dist/extension/signal.mjs.map +1 -0
- package/dist/extension/stdin.d.mts +19 -0
- package/dist/extension/stdin.d.mts.map +1 -0
- package/dist/extension/stdin.mjs +52 -0
- package/dist/extension/stdin.mjs.map +1 -0
- package/dist/extension/suggestions.d.mts +6 -0
- package/dist/extension/suggestions.d.mts.map +1 -0
- package/dist/extension/suggestions.mjs +113 -0
- package/dist/extension/suggestions.mjs.map +1 -0
- package/dist/extension/timing.d.mts +27 -0
- package/dist/extension/timing.d.mts.map +1 -0
- package/dist/extension/timing.mjs +71 -0
- package/dist/extension/timing.mjs.map +1 -0
- package/dist/extension/tracing.d.mts +85 -0
- package/dist/extension/tracing.d.mts.map +1 -0
- package/dist/extension/tracing.mjs +107 -0
- package/dist/extension/tracing.mjs.map +1 -0
- package/dist/extension/update-check.d.mts +20 -0
- package/dist/extension/update-check.d.mts.map +1 -0
- package/dist/extension/update-check.mjs +62 -0
- package/dist/extension/update-check.mjs.map +1 -0
- package/dist/extension/utils.mjs +43 -0
- package/dist/extension/utils.mjs.map +1 -0
- package/dist/extension/version.d.mts +20 -0
- package/dist/extension/version.d.mts.map +1 -0
- package/dist/extension/version.mjs +51 -0
- package/dist/extension/version.mjs.map +1 -0
- package/dist/{completion-UnBKfGuk.mjs → feature/completion.mjs} +4 -3
- package/dist/feature/completion.mjs.map +1 -0
- package/dist/feature/interactive.mjs +145 -0
- package/dist/feature/interactive.mjs.map +1 -0
- package/dist/feature/mcp.d.mts +18 -0
- package/dist/feature/mcp.d.mts.map +1 -0
- package/dist/{mcp-D6PdtjIs.mjs → feature/mcp.mjs} +6 -6
- package/dist/feature/mcp.mjs.map +1 -0
- package/dist/feature/repl-loop.mjs +217 -0
- package/dist/feature/repl-loop.mjs.map +1 -0
- package/dist/feature/serve.d.mts +18 -0
- package/dist/feature/serve.d.mts.map +1 -0
- package/dist/{serve-PaCLsNoD.mjs → feature/serve.mjs} +7 -7
- package/dist/feature/serve.mjs.map +1 -0
- package/dist/feature/test.d.mts +109 -0
- package/dist/feature/test.d.mts.map +1 -0
- package/dist/feature/test.mjs +116 -0
- package/dist/feature/test.mjs.map +1 -0
- package/dist/feature/update-check.d.mts +35 -0
- package/dist/feature/update-check.d.mts.map +1 -0
- package/dist/{update-check-CZ2VqjnV.mjs → feature/update-check.mjs} +2 -2
- package/dist/feature/update-check.mjs.map +1 -0
- package/dist/feature/wrap.d.mts +58 -0
- package/dist/feature/wrap.d.mts.map +1 -0
- package/dist/feature/wrap.mjs +77 -0
- package/dist/feature/wrap.mjs.map +1 -0
- package/dist/index.d.mts +38 -901
- package/dist/index.mjs +25 -4337
- package/dist/ink.d.mts +2 -0
- package/dist/ink.mjs +2 -0
- package/dist/man.d.mts +2 -0
- package/dist/man.mjs +2 -0
- package/dist/mcp.d.mts +3 -0
- package/dist/mcp.mjs +2 -0
- package/dist/output/colorizer.d.mts +28 -0
- package/dist/output/colorizer.d.mts.map +1 -0
- package/dist/output/colorizer.mjs +94 -0
- package/dist/output/colorizer.mjs.map +1 -0
- package/dist/{formatter-CY3KrOEd.d.mts → output/formatter.d.mts} +2 -28
- package/dist/output/formatter.d.mts.map +1 -0
- package/dist/output/formatter.mjs +360 -0
- package/dist/output/formatter.mjs.map +1 -0
- package/dist/output/help.d.mts +18 -0
- package/dist/output/help.d.mts.map +1 -0
- package/dist/output/help.mjs +267 -0
- package/dist/output/help.mjs.map +1 -0
- package/dist/output/output-indicator.d.mts +27 -0
- package/dist/output/output-indicator.d.mts.map +1 -0
- package/dist/output/output-indicator.mjs +54 -0
- package/dist/output/output-indicator.mjs.map +1 -0
- package/dist/output/primitives.d.mts +33 -0
- package/dist/output/primitives.d.mts.map +1 -0
- package/dist/output/primitives.mjs +206 -0
- package/dist/output/primitives.mjs.map +1 -0
- package/dist/output/styling.d.mts +38 -0
- package/dist/output/styling.d.mts.map +1 -0
- package/dist/output/styling.mjs +146 -0
- package/dist/output/styling.mjs.map +1 -0
- package/dist/schema/zod.d.mts +6 -0
- package/dist/schema/zod.d.mts.map +1 -0
- package/dist/schema/zod.mjs +50 -0
- package/dist/schema/zod.mjs.map +1 -0
- package/dist/serve.d.mts +2 -0
- package/dist/serve.mjs +2 -0
- package/dist/test.d.mts +2 -109
- package/dist/test.mjs +1 -115
- package/dist/tracing.d.mts +2 -0
- package/dist/tracing.mjs +2 -0
- package/dist/types/args-meta.d.mts +129 -0
- package/dist/types/args-meta.d.mts.map +1 -0
- package/dist/types/builder.d.mts +212 -0
- package/dist/types/builder.d.mts.map +1 -0
- package/dist/types/command.d.mts +112 -0
- package/dist/types/command.d.mts.map +1 -0
- package/dist/types/index.d.mts +8 -0
- package/dist/types/interceptor.d.mts +232 -0
- package/dist/types/interceptor.d.mts.map +1 -0
- package/dist/types/preferences.d.mts +79 -0
- package/dist/types/preferences.d.mts.map +1 -0
- package/dist/types/result.d.mts +61 -0
- package/dist/types/result.d.mts.map +1 -0
- package/dist/types/schema.d.mts +24 -0
- package/dist/types/schema.d.mts.map +1 -0
- package/dist/util/dotenv.mjs +174 -0
- package/dist/util/dotenv.mjs.map +1 -0
- package/dist/util/shell-utils.mjs +80 -0
- package/dist/util/shell-utils.mjs.map +1 -0
- package/dist/util/stream.d.mts +33 -0
- package/dist/util/stream.d.mts.map +1 -0
- package/dist/{stream-DC4H8YTx.mjs → util/stream.mjs} +2 -2
- package/dist/util/stream.mjs.map +1 -0
- package/dist/util/type-helpers.d.mts +74 -0
- package/dist/util/type-helpers.d.mts.map +1 -0
- package/dist/util/type-utils.d.mts +186 -0
- package/dist/util/type-utils.d.mts.map +1 -0
- package/dist/util/utils.mjs +43 -0
- package/dist/util/utils.mjs.map +1 -0
- package/dist/zod.d.mts +1 -32
- package/dist/zod.mjs +1 -49
- package/package.json +65 -17
- package/src/completion.ts +2 -0
- package/src/core/args.ts +63 -37
- package/src/core/runtime.ts +11 -2
- package/src/extension/completion.ts +3 -0
- package/src/extension/index.ts +0 -12
- package/src/extension/ink.ts +2 -1
- package/src/extension/man.ts +3 -0
- package/src/extension/mcp.ts +3 -0
- package/src/extension/progress-renderer.ts +32 -8
- package/src/extension/progress.ts +19 -9
- package/src/extension/serve.ts +3 -0
- package/src/extension/tracing.ts +2 -0
- package/src/index.ts +1 -20
- package/src/ink.ts +2 -0
- package/src/man.ts +2 -0
- package/src/mcp.ts +3 -0
- package/src/serve.ts +2 -0
- package/src/tracing.ts +9 -0
- package/src/types/builder.ts +2 -2
- package/src/zod.ts +1 -1
- package/dist/args-DrCXxXeP.mjs.map +0 -1
- package/dist/codegen/index.d.mts.map +0 -1
- package/dist/codegen/index.mjs.map +0 -1
- package/dist/commands-DLR0rFgq.mjs.map +0 -1
- package/dist/completion-UnBKfGuk.mjs.map +0 -1
- package/dist/errors-DA4KzK1M.mjs.map +0 -1
- package/dist/formatter-CY3KrOEd.d.mts.map +0 -1
- package/dist/help-B-ZMYyn-.mjs +0 -892
- package/dist/help-B-ZMYyn-.mjs.map +0 -1
- package/dist/index-D-Dpz7l_.d.mts +0 -1427
- package/dist/index-D-Dpz7l_.d.mts.map +0 -1
- package/dist/index.d.mts.map +0 -1
- package/dist/index.mjs.map +0 -1
- package/dist/mcp-D6PdtjIs.mjs.map +0 -1
- package/dist/serve-PaCLsNoD.mjs.map +0 -1
- package/dist/stream-DC4H8YTx.mjs.map +0 -1
- package/dist/test.d.mts.map +0 -1
- package/dist/test.mjs.map +0 -1
- package/dist/update-check-CZ2VqjnV.mjs.map +0 -1
- package/dist/zod.d.mts.map +0 -1
- package/dist/zod.mjs.map +0 -1
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { defineInterceptor } from "../core/interceptors.mjs";
|
|
2
|
+
//#region src/extension/ink.ts
|
|
3
|
+
const reactElement = Symbol.for("react.element");
|
|
4
|
+
const reactTransitional = Symbol.for("react.transitional.element");
|
|
5
|
+
/** Checks whether a value is a React element (JSX) by inspecting its `$$typeof` symbol. */
|
|
6
|
+
function isReactElement(value) {
|
|
7
|
+
if (value === null || typeof value !== "object") return false;
|
|
8
|
+
const tag = value.$$typeof;
|
|
9
|
+
return tag === reactElement || tag === reactTransitional;
|
|
10
|
+
}
|
|
11
|
+
const inkMeta = {
|
|
12
|
+
id: "padrone:ink",
|
|
13
|
+
name: "padrone:ink",
|
|
14
|
+
order: -1050
|
|
15
|
+
};
|
|
16
|
+
function createInkInterceptor(rawOptions) {
|
|
17
|
+
return defineInterceptor(inkMeta).requires().factory(() => ({ execute(ctx, next) {
|
|
18
|
+
const options = {
|
|
19
|
+
...ctx.context?.inkConfig,
|
|
20
|
+
...rawOptions
|
|
21
|
+
};
|
|
22
|
+
const { waitUntilExit = true } = options;
|
|
23
|
+
const handleResult = async (e) => {
|
|
24
|
+
let value = e.result;
|
|
25
|
+
if (value instanceof Promise) value = await value;
|
|
26
|
+
if (!isReactElement(value)) return e;
|
|
27
|
+
const { render } = await import("ink");
|
|
28
|
+
const instance = render(value, options.render);
|
|
29
|
+
const onAbort = () => instance.unmount();
|
|
30
|
+
ctx.signal.addEventListener("abort", onAbort, { once: true });
|
|
31
|
+
if (waitUntilExit) try {
|
|
32
|
+
await instance.waitUntilExit();
|
|
33
|
+
} finally {
|
|
34
|
+
ctx.signal.removeEventListener("abort", onAbort);
|
|
35
|
+
}
|
|
36
|
+
return { result: void 0 };
|
|
37
|
+
};
|
|
38
|
+
const executedOrPromise = next();
|
|
39
|
+
if (executedOrPromise instanceof Promise) return executedOrPromise.then(handleResult);
|
|
40
|
+
return handleResult(executedOrPromise);
|
|
41
|
+
} }));
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Extension that renders React (Ink) components returned from command actions.
|
|
45
|
+
*
|
|
46
|
+
* When a command's action returns a React element (JSX), this extension
|
|
47
|
+
* renders it using Ink instead of passing it to the normal output path.
|
|
48
|
+
*
|
|
49
|
+
* Requires `ink` and `react` as peer dependencies.
|
|
50
|
+
*
|
|
51
|
+
* ```ts
|
|
52
|
+
* import { createPadrone } from 'padrone';
|
|
53
|
+
* import { padroneInk } from 'padrone/ink';
|
|
54
|
+
*
|
|
55
|
+
* const program = createPadrone('my-tui')
|
|
56
|
+
* .extend(padroneInk())
|
|
57
|
+
* .command('dashboard', (c) =>
|
|
58
|
+
* c.action(() => <Dashboard />)
|
|
59
|
+
* );
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
function padroneInk(options) {
|
|
63
|
+
const interceptor = createInkInterceptor(options);
|
|
64
|
+
return ((builder) => builder.intercept(interceptor));
|
|
65
|
+
}
|
|
66
|
+
//#endregion
|
|
67
|
+
export { isReactElement, padroneInk };
|
|
68
|
+
|
|
69
|
+
//# sourceMappingURL=ink.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ink.mjs","names":[],"sources":["../../src/extension/ink.ts"],"sourcesContent":["import { defineInterceptor } from '../core/interceptors.ts';\nimport type { AnyPadroneBuilder, CommandTypesBase } from '../types/index.ts';\nimport type { InterceptorExecuteResult } from '../types/interceptor.ts';\n\n// ── React element detection ─────────────────────────────────────────────\n\nconst reactElement = Symbol.for('react.element');\nconst reactTransitional = Symbol.for('react.transitional.element');\n\n/** Checks whether a value is a React element (JSX) by inspecting its `$$typeof` symbol. */\nexport function isReactElement(value: unknown): boolean {\n if (value === null || typeof value !== 'object') return false;\n const tag = (value as Record<string | symbol, unknown>).$$typeof;\n return tag === reactElement || tag === reactTransitional;\n}\n\n// ── Types ───────────────────────────────────────────────────────────────\n\nexport type InkOptions = {\n /** Whether to wait for the Ink app to unmount before resolving. Defaults to `true`. */\n waitUntilExit?: boolean;\n /** Options forwarded to Ink's `render()`. */\n render?: import('ink').RenderOptions;\n};\n\n// ── Interceptor ─────────────────────────────────────────────────────────\n\nconst inkMeta = { id: 'padrone:ink', name: 'padrone:ink', order: -1050 } as const;\n\nfunction createInkInterceptor(rawOptions?: InkOptions) {\n return defineInterceptor(inkMeta)\n .requires<{ inkConfig?: InkOptions }>()\n .factory(() => ({\n execute(ctx, next) {\n const ctxCfg = (ctx.context as Record<string, unknown> | undefined)?.inkConfig as InkOptions | undefined;\n const options: InkOptions = { ...ctxCfg, ...rawOptions };\n const { waitUntilExit = true } = options;\n\n const handleResult = async (e: InterceptorExecuteResult): Promise<InterceptorExecuteResult> => {\n let value = e.result;\n if (value instanceof Promise) value = await value;\n if (!isReactElement(value)) return e;\n\n const { render } = await import('ink');\n const instance = render(value as import('react').ReactElement, options.render);\n\n // Unmount on abort so Ink cleans up stdin/stdout\n const onAbort = () => instance.unmount();\n ctx.signal.addEventListener('abort', onAbort, { once: true });\n\n if (waitUntilExit) {\n try {\n await instance.waitUntilExit();\n } finally {\n ctx.signal.removeEventListener('abort', onAbort);\n }\n }\n\n // Return undefined so auto-output skips this result\n return { result: undefined };\n };\n\n const executedOrPromise = next();\n if (executedOrPromise instanceof Promise) return executedOrPromise.then(handleResult);\n return handleResult(executedOrPromise);\n },\n }));\n}\n\n// ── Extension ───────────────────────────────────────────────────────────\n\n/**\n * Extension that renders React (Ink) components returned from command actions.\n *\n * When a command's action returns a React element (JSX), this extension\n * renders it using Ink instead of passing it to the normal output path.\n *\n * Requires `ink` and `react` as peer dependencies.\n *\n * ```ts\n * import { createPadrone } from 'padrone';\n * import { padroneInk } from 'padrone/ink';\n *\n * const program = createPadrone('my-tui')\n * .extend(padroneInk())\n * .command('dashboard', (c) =>\n * c.action(() => <Dashboard />)\n * );\n * ```\n */\nexport function padroneInk(options?: InkOptions): <T extends CommandTypesBase>(builder: T) => T {\n const interceptor = createInkInterceptor(options);\n return ((builder: AnyPadroneBuilder) => builder.intercept(interceptor)) as any;\n}\n"],"mappings":";;AAMA,MAAM,eAAe,OAAO,IAAI,eAAe;AAC/C,MAAM,oBAAoB,OAAO,IAAI,4BAA4B;;AAGjE,SAAgB,eAAe,OAAyB;CACtD,IAAI,UAAU,QAAQ,OAAO,UAAU,UAAU,OAAO;CACxD,MAAM,MAAO,MAA2C;CACxD,OAAO,QAAQ,gBAAgB,QAAQ;AACzC;AAaA,MAAM,UAAU;CAAE,IAAI;CAAe,MAAM;CAAe,OAAO;AAAM;AAEvE,SAAS,qBAAqB,YAAyB;CACrD,OAAO,kBAAkB,OAAO,CAAC,CAC9B,SAAqC,CAAC,CACtC,eAAe,EACd,QAAQ,KAAK,MAAM;EAEjB,MAAM,UAAsB;GAAE,GADd,IAAI,SAAiD;GAC5B,GAAG;EAAW;EACvD,MAAM,EAAE,gBAAgB,SAAS;EAEjC,MAAM,eAAe,OAAO,MAAmE;GAC7F,IAAI,QAAQ,EAAE;GACd,IAAI,iBAAiB,SAAS,QAAQ,MAAM;GAC5C,IAAI,CAAC,eAAe,KAAK,GAAG,OAAO;GAEnC,MAAM,EAAE,WAAW,MAAM,OAAO;GAChC,MAAM,WAAW,OAAO,OAAuC,QAAQ,MAAM;GAG7E,MAAM,gBAAgB,SAAS,QAAQ;GACvC,IAAI,OAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;GAE5D,IAAI,eACF,IAAI;IACF,MAAM,SAAS,cAAc;GAC/B,UAAU;IACR,IAAI,OAAO,oBAAoB,SAAS,OAAO;GACjD;GAIF,OAAO,EAAE,QAAQ,KAAA,EAAU;EAC7B;EAEA,MAAM,oBAAoB,KAAK;EAC/B,IAAI,6BAA6B,SAAS,OAAO,kBAAkB,KAAK,YAAY;EACpF,OAAO,aAAa,iBAAiB;CACvC,EACF,EAAE;AACN;;;;;;;;;;;;;;;;;;;;AAuBA,SAAgB,WAAW,SAAqE;CAC9F,MAAM,cAAc,qBAAqB,OAAO;CAChD,SAAS,YAA+B,QAAQ,UAAU,WAAW;AACvE"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { CommandTypesBase } from "../types/command.mjs";
|
|
2
|
+
//#region src/extension/interactive.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Extension that handles interactive prompting for missing arguments.
|
|
5
|
+
* Extracts `--interactive` / `-i` flags, resolves effective interactivity,
|
|
6
|
+
* and prompts for missing fields before passing filled args to validation.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* ```ts
|
|
10
|
+
* createPadrone('my-cli').extend(padroneInteractive())
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
declare function padroneInteractive(): <T extends CommandTypesBase>(builder: T) => T;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { padroneInteractive };
|
|
16
|
+
//# sourceMappingURL=interactive.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactive.d.mts","names":[],"sources":["../../src/extension/interactive.ts"],"mappings":";;;;;AAwGA;;;;;;;iBAAgB,kBAAA,eAAiC,gBAAA,EAAkB,OAAA,EAAS,CAAA,KAAM,CAAA"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { hasInteractiveConfig, thenMaybe } from "../core/results.mjs";
|
|
2
|
+
import { defineInterceptor } from "../core/interceptors.mjs";
|
|
3
|
+
import { buildCommandArgs, checkUnknownArgs } from "../core/validate.mjs";
|
|
4
|
+
import { promptInteractiveFields } from "../feature/interactive.mjs";
|
|
5
|
+
//#region src/extension/interactive.ts
|
|
6
|
+
const interactiveInterceptor = defineInterceptor({
|
|
7
|
+
id: "padrone:interactive",
|
|
8
|
+
name: "padrone:interactive",
|
|
9
|
+
order: -999
|
|
10
|
+
}, () => ({ validate(ctx, next) {
|
|
11
|
+
let flagInteractive;
|
|
12
|
+
if (hasInteractiveConfig(ctx.command.meta)) {
|
|
13
|
+
if (ctx.rawArgs.interactive !== void 0) {
|
|
14
|
+
flagInteractive = ctx.rawArgs.interactive !== false && ctx.rawArgs.interactive !== "false";
|
|
15
|
+
delete ctx.rawArgs.interactive;
|
|
16
|
+
}
|
|
17
|
+
if (ctx.rawArgs.i !== void 0) {
|
|
18
|
+
flagInteractive = ctx.rawArgs.i !== false && ctx.rawArgs.i !== "false";
|
|
19
|
+
delete ctx.rawArgs.i;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
const { runtime, command } = ctx;
|
|
23
|
+
const runtimeDefault = runtime.interactive === "forced" ? true : runtime.interactive === "disabled" ? false : void 0;
|
|
24
|
+
const effectiveInteractive = flagInteractive ?? ctx.evalInteractive ?? runtimeDefault;
|
|
25
|
+
const stdinIsPiped = !!command.meta?.stdin && (runtime.stdin ? !runtime.stdin.isTTY : runtime.terminal?.isTTY !== true);
|
|
26
|
+
const interactivitySuppressed = runtime.interactive === "unsupported" || effectiveInteractive === false || stdinIsPiped && effectiveInteractive !== true;
|
|
27
|
+
const forceInteractive = !interactivitySuppressed && effectiveInteractive === true;
|
|
28
|
+
if (!(!interactivitySuppressed && runtime.prompt && hasInteractiveConfig(command.meta))) return next();
|
|
29
|
+
const { args: preprocessedArgs, issues: positionalIssues } = buildCommandArgs(command, ctx.rawArgs, ctx.positionalArgs);
|
|
30
|
+
if (positionalIssues) return {
|
|
31
|
+
args: void 0,
|
|
32
|
+
argsResult: { issues: positionalIssues }
|
|
33
|
+
};
|
|
34
|
+
const unknowns = checkUnknownArgs(command, preprocessedArgs);
|
|
35
|
+
if (unknowns.length > 0) return {
|
|
36
|
+
args: void 0,
|
|
37
|
+
argsResult: { issues: unknowns.map(({ key }) => ({
|
|
38
|
+
path: [key],
|
|
39
|
+
message: `Unknown option: "${key}"`
|
|
40
|
+
})) }
|
|
41
|
+
};
|
|
42
|
+
const earlyValidateAndPrompt = () => {
|
|
43
|
+
if (command.argsSchema) {
|
|
44
|
+
const providedKeys = new Set(Object.keys(preprocessedArgs).filter((k) => preprocessedArgs[k] !== void 0));
|
|
45
|
+
const earlyCheck = command.argsSchema["~standard"].validate(preprocessedArgs);
|
|
46
|
+
const checkForProvidedFieldErrors = (result) => {
|
|
47
|
+
if (!result.issues) return void 0;
|
|
48
|
+
const providedFieldIssues = result.issues.filter((issue) => {
|
|
49
|
+
const rootKey = issue.path?.[0];
|
|
50
|
+
return rootKey !== void 0 && providedKeys.has(String(rootKey));
|
|
51
|
+
});
|
|
52
|
+
if (providedFieldIssues.length > 0) return {
|
|
53
|
+
args: void 0,
|
|
54
|
+
argsResult: { issues: providedFieldIssues }
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
const earlyResult = thenMaybe(earlyCheck, (result) => checkForProvidedFieldErrors(result) ?? void 0);
|
|
58
|
+
if (earlyResult instanceof Promise) return earlyResult.then((err) => err ? err : doPrompt());
|
|
59
|
+
if (earlyResult) return earlyResult;
|
|
60
|
+
}
|
|
61
|
+
return doPrompt();
|
|
62
|
+
};
|
|
63
|
+
const doPrompt = () => {
|
|
64
|
+
return thenMaybe(promptInteractiveFields(preprocessedArgs, command, runtime, forceInteractive || void 0), (filledArgs) => {
|
|
65
|
+
return next({
|
|
66
|
+
rawArgs: filledArgs,
|
|
67
|
+
positionalArgs: []
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
};
|
|
71
|
+
return earlyValidateAndPrompt();
|
|
72
|
+
} }));
|
|
73
|
+
/**
|
|
74
|
+
* Extension that handles interactive prompting for missing arguments.
|
|
75
|
+
* Extracts `--interactive` / `-i` flags, resolves effective interactivity,
|
|
76
|
+
* and prompts for missing fields before passing filled args to validation.
|
|
77
|
+
*
|
|
78
|
+
* Usage:
|
|
79
|
+
* ```ts
|
|
80
|
+
* createPadrone('my-cli').extend(padroneInteractive())
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
function padroneInteractive() {
|
|
84
|
+
return ((builder) => builder.intercept(interactiveInterceptor));
|
|
85
|
+
}
|
|
86
|
+
//#endregion
|
|
87
|
+
export { padroneInteractive };
|
|
88
|
+
|
|
89
|
+
//# sourceMappingURL=interactive.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interactive.mjs","names":[],"sources":["../../src/extension/interactive.ts"],"sourcesContent":["import type { StandardSchemaV1 } from '@standard-schema/spec';\nimport { defineInterceptor } from '../core/interceptors.ts';\nimport { hasInteractiveConfig, thenMaybe } from '../core/results.ts';\nimport { buildCommandArgs, checkUnknownArgs } from '../core/validate.ts';\nimport { promptInteractiveFields } from '../feature/interactive.ts';\nimport type { AnyPadroneBuilder, CommandTypesBase, InterceptorValidateContext, InterceptorValidateResult } from '../types/index.ts';\n\n// ── Interceptor ─────────────────────────────────────────────────────────\n\nconst interactiveInterceptor = defineInterceptor({ id: 'padrone:interactive', name: 'padrone:interactive', order: -999 }, () => ({\n validate(ctx: InterceptorValidateContext, next) {\n // Extract --interactive / -i flags from rawArgs\n let flagInteractive: boolean | undefined;\n if (hasInteractiveConfig(ctx.command.meta)) {\n if (ctx.rawArgs.interactive !== undefined) {\n flagInteractive = ctx.rawArgs.interactive !== false && ctx.rawArgs.interactive !== 'false';\n delete ctx.rawArgs.interactive;\n }\n if (ctx.rawArgs.i !== undefined) {\n flagInteractive = ctx.rawArgs.i !== false && ctx.rawArgs.i !== 'false';\n delete ctx.rawArgs.i;\n }\n }\n\n // Resolve effective interactivity\n const { runtime, command } = ctx;\n const runtimeDefault: boolean | undefined =\n runtime.interactive === 'forced' ? true : runtime.interactive === 'disabled' ? false : undefined;\n const effectiveInteractive: boolean | undefined = flagInteractive ?? ctx.evalInteractive ?? runtimeDefault;\n const commandUsesStdin = !!command.meta?.stdin;\n const stdinIsPiped = commandUsesStdin && (runtime.stdin ? !runtime.stdin.isTTY : runtime.terminal?.isTTY !== true);\n const interactivitySuppressed =\n runtime.interactive === 'unsupported' || effectiveInteractive === false || (stdinIsPiped && effectiveInteractive !== true);\n const forceInteractive = !interactivitySuppressed && effectiveInteractive === true;\n\n const willPrompt = !interactivitySuppressed && runtime.prompt && hasInteractiveConfig(command.meta);\n if (!willPrompt) return next();\n\n // Preprocess args to determine what's missing\n const { args: preprocessedArgs, issues: positionalIssues } = buildCommandArgs(command, ctx.rawArgs, ctx.positionalArgs);\n if (positionalIssues) return { args: undefined, argsResult: { issues: positionalIssues } } as any;\n\n // Check for unknown args before prompting\n const unknowns = checkUnknownArgs(command, preprocessedArgs);\n if (unknowns.length > 0) {\n const issues: StandardSchemaV1.Issue[] = unknowns.map(({ key }) => ({\n path: [key],\n message: `Unknown option: \"${key}\"`,\n }));\n return { args: undefined, argsResult: { issues } } as any;\n }\n\n // Early-validate provided fields — fail fast on user-supplied errors before prompting\n const earlyValidateAndPrompt = (): InterceptorValidateResult | Promise<InterceptorValidateResult> => {\n if (command.argsSchema) {\n const providedKeys = new Set(Object.keys(preprocessedArgs).filter((k) => preprocessedArgs[k] !== undefined));\n const earlyCheck = command.argsSchema['~standard'].validate(preprocessedArgs);\n\n const checkForProvidedFieldErrors = (result: StandardSchemaV1.Result<unknown>): InterceptorValidateResult | undefined => {\n if (!result.issues) return undefined;\n const providedFieldIssues = result.issues.filter((issue: StandardSchemaV1.Issue) => {\n const rootKey = issue.path?.[0];\n return rootKey !== undefined && providedKeys.has(String(rootKey));\n });\n if (providedFieldIssues.length > 0) return { args: undefined, argsResult: { issues: providedFieldIssues } as any };\n return undefined;\n };\n\n const earlyResult = thenMaybe(earlyCheck, (result) => checkForProvidedFieldErrors(result) ?? undefined);\n if (earlyResult instanceof Promise) {\n return earlyResult.then((err) => (err ? err : doPrompt()));\n }\n if (earlyResult) return earlyResult;\n }\n\n return doPrompt();\n };\n\n // Prompt for missing fields, then pass filled args to downstream validation via next()\n const doPrompt = (): InterceptorValidateResult | Promise<InterceptorValidateResult> => {\n const afterInteractive = promptInteractiveFields(preprocessedArgs, command, runtime, forceInteractive || undefined);\n\n return thenMaybe(afterInteractive, (filledArgs) => {\n // Pass preprocessed+prompted args downstream with empty positionalArgs (already mapped)\n return next({ rawArgs: filledArgs, positionalArgs: [] });\n });\n };\n\n return earlyValidateAndPrompt();\n },\n}));\n\n// ── Extension ────────────────────────────────────────────────────────────\n\n/**\n * Extension that handles interactive prompting for missing arguments.\n * Extracts `--interactive` / `-i` flags, resolves effective interactivity,\n * and prompts for missing fields before passing filled args to validation.\n *\n * Usage:\n * ```ts\n * createPadrone('my-cli').extend(padroneInteractive())\n * ```\n */\nexport function padroneInteractive(): <T extends CommandTypesBase>(builder: T) => T {\n return ((builder: AnyPadroneBuilder) => builder.intercept(interactiveInterceptor)) as any;\n}\n"],"mappings":";;;;;AASA,MAAM,yBAAyB,kBAAkB;CAAE,IAAI;CAAuB,MAAM;CAAuB,OAAO;AAAK,UAAU,EAC/H,SAAS,KAAiC,MAAM;CAE9C,IAAI;CACJ,IAAI,qBAAqB,IAAI,QAAQ,IAAI,GAAG;EAC1C,IAAI,IAAI,QAAQ,gBAAgB,KAAA,GAAW;GACzC,kBAAkB,IAAI,QAAQ,gBAAgB,SAAS,IAAI,QAAQ,gBAAgB;GACnF,OAAO,IAAI,QAAQ;EACrB;EACA,IAAI,IAAI,QAAQ,MAAM,KAAA,GAAW;GAC/B,kBAAkB,IAAI,QAAQ,MAAM,SAAS,IAAI,QAAQ,MAAM;GAC/D,OAAO,IAAI,QAAQ;EACrB;CACF;CAGA,MAAM,EAAE,SAAS,YAAY;CAC7B,MAAM,iBACJ,QAAQ,gBAAgB,WAAW,OAAO,QAAQ,gBAAgB,aAAa,QAAQ,KAAA;CACzF,MAAM,uBAA4C,mBAAmB,IAAI,mBAAmB;CAE5F,MAAM,eAAe,CADK,CAAC,QAAQ,MAAM,UACC,QAAQ,QAAQ,CAAC,QAAQ,MAAM,QAAQ,QAAQ,UAAU,UAAU;CAC7G,MAAM,0BACJ,QAAQ,gBAAgB,iBAAiB,yBAAyB,SAAU,gBAAgB,yBAAyB;CACvH,MAAM,mBAAmB,CAAC,2BAA2B,yBAAyB;CAG9E,IAAI,EADe,CAAC,2BAA2B,QAAQ,UAAU,qBAAqB,QAAQ,IAAI,IACjF,OAAO,KAAK;CAG7B,MAAM,EAAE,MAAM,kBAAkB,QAAQ,qBAAqB,iBAAiB,SAAS,IAAI,SAAS,IAAI,cAAc;CACtH,IAAI,kBAAkB,OAAO;EAAE,MAAM,KAAA;EAAW,YAAY,EAAE,QAAQ,iBAAiB;CAAE;CAGzF,MAAM,WAAW,iBAAiB,SAAS,gBAAgB;CAC3D,IAAI,SAAS,SAAS,GAKpB,OAAO;EAAE,MAAM,KAAA;EAAW,YAAY,EAAE,QAJC,SAAS,KAAK,EAAE,WAAW;GAClE,MAAM,CAAC,GAAG;GACV,SAAS,oBAAoB,IAAI;EACnC,EAC6C,EAAE;CAAE;CAInD,MAAM,+BAA+F;EACnG,IAAI,QAAQ,YAAY;GACtB,MAAM,eAAe,IAAI,IAAI,OAAO,KAAK,gBAAgB,CAAC,CAAC,QAAQ,MAAM,iBAAiB,OAAO,KAAA,CAAS,CAAC;GAC3G,MAAM,aAAa,QAAQ,WAAW,YAAY,CAAC,SAAS,gBAAgB;GAE5E,MAAM,+BAA+B,WAAoF;IACvH,IAAI,CAAC,OAAO,QAAQ,OAAO,KAAA;IAC3B,MAAM,sBAAsB,OAAO,OAAO,QAAQ,UAAkC;KAClF,MAAM,UAAU,MAAM,OAAO;KAC7B,OAAO,YAAY,KAAA,KAAa,aAAa,IAAI,OAAO,OAAO,CAAC;IAClE,CAAC;IACD,IAAI,oBAAoB,SAAS,GAAG,OAAO;KAAE,MAAM,KAAA;KAAW,YAAY,EAAE,QAAQ,oBAAoB;IAAS;GAEnH;GAEA,MAAM,cAAc,UAAU,aAAa,WAAW,4BAA4B,MAAM,KAAK,KAAA,CAAS;GACtG,IAAI,uBAAuB,SACzB,OAAO,YAAY,MAAM,QAAS,MAAM,MAAM,SAAS,CAAE;GAE3D,IAAI,aAAa,OAAO;EAC1B;EAEA,OAAO,SAAS;CAClB;CAGA,MAAM,iBAAiF;EAGrF,OAAO,UAFkB,wBAAwB,kBAAkB,SAAS,SAAS,oBAAoB,KAAA,CAEzE,IAAI,eAAe;GAEjD,OAAO,KAAK;IAAE,SAAS;IAAY,gBAAgB,CAAC;GAAE,CAAC;EACzD,CAAC;CACH;CAEA,OAAO,uBAAuB;AAChC,EACF,EAAE;;;;;;;;;;;AAcF,SAAgB,qBAAoE;CAClF,SAAS,YAA+B,QAAQ,UAAU,sBAAsB;AAClF"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { WithInterceptor } from "../util/type-utils.mjs";
|
|
2
|
+
import { CommandTypesBase } from "../types/command.mjs";
|
|
3
|
+
//#region src/extension/logger.d.ts
|
|
4
|
+
/** Log level values ordered by severity. */
|
|
5
|
+
type PadroneLogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'silent';
|
|
6
|
+
/** Logger instance injected into the command context. */
|
|
7
|
+
type PadroneLogger = {
|
|
8
|
+
trace: (...args: unknown[]) => void;
|
|
9
|
+
debug: (...args: unknown[]) => void;
|
|
10
|
+
info: (...args: unknown[]) => void;
|
|
11
|
+
warn: (...args: unknown[]) => void;
|
|
12
|
+
error: (...args: unknown[]) => void; /** The current effective log level. */
|
|
13
|
+
level: PadroneLogLevel; /** Create a child logger with a prefix label. */
|
|
14
|
+
child: (label: string) => PadroneLogger;
|
|
15
|
+
};
|
|
16
|
+
/** Configuration for the logger extension. */
|
|
17
|
+
type PadroneLoggerConfig = {
|
|
18
|
+
/** Minimum log level to output. Defaults to `'info'`. */level?: PadroneLogLevel; /** Prefix prepended to every log message. */
|
|
19
|
+
prefix?: string; /** Include timestamps in log output. Defaults to `false`. */
|
|
20
|
+
timestamps?: boolean;
|
|
21
|
+
};
|
|
22
|
+
/** Builder/program type after applying `padroneLogger()`. Adds `{ logger: PadroneLogger }` to the command context. */
|
|
23
|
+
type WithLogger<T> = WithInterceptor<T, {
|
|
24
|
+
logger: PadroneLogger;
|
|
25
|
+
}>;
|
|
26
|
+
/**
|
|
27
|
+
* Extension that injects a structured logger into the command context.
|
|
28
|
+
*
|
|
29
|
+
* The logger respects a configurable log level threshold, supports prefixed
|
|
30
|
+
* child loggers, and routes output through the runtime's `output`/`error`
|
|
31
|
+
* functions so it works in any environment (terminal, test, web).
|
|
32
|
+
*
|
|
33
|
+
* Supports CLI flags for runtime level overrides:
|
|
34
|
+
* - `--trace` → sets level to `trace`
|
|
35
|
+
* - `--verbose` or `--debug` → sets level to `debug`
|
|
36
|
+
* - `--silent` or `--quiet` → sets level to `silent`
|
|
37
|
+
* - `--log-level=<level>` → sets an explicit level (`trace`, `debug`, `info`, `warn`, `error`, `silent`)
|
|
38
|
+
*
|
|
39
|
+
* CLI flags take precedence over the programmatic config.
|
|
40
|
+
*
|
|
41
|
+
* Provides `{ logger: PadroneLogger }` on the command context.
|
|
42
|
+
* Access it in action handlers as `ctx.context.logger`.
|
|
43
|
+
*
|
|
44
|
+
* Usage:
|
|
45
|
+
* ```ts
|
|
46
|
+
* createPadrone('my-cli')
|
|
47
|
+
* .extend(padroneLogger({ level: 'info' }))
|
|
48
|
+
* .command('sync', (c) =>
|
|
49
|
+
* c.action((_args, ctx) => {
|
|
50
|
+
* ctx.context.logger.info('starting sync');
|
|
51
|
+
* const db = ctx.context.logger.child('db');
|
|
52
|
+
* db.debug('connecting...');
|
|
53
|
+
* })
|
|
54
|
+
* )
|
|
55
|
+
* ```
|
|
56
|
+
*
|
|
57
|
+
* Then run:
|
|
58
|
+
* ```sh
|
|
59
|
+
* my-cli sync --verbose # debug level
|
|
60
|
+
* my-cli sync --quiet # silent
|
|
61
|
+
* my-cli sync --log-level=warn
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
declare function padroneLogger<T extends CommandTypesBase>(config?: PadroneLoggerConfig): (builder: T) => WithLogger<T>;
|
|
65
|
+
//#endregion
|
|
66
|
+
export { PadroneLogLevel, PadroneLogger, PadroneLoggerConfig, WithLogger, padroneLogger };
|
|
67
|
+
//# sourceMappingURL=logger.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.mts","names":[],"sources":["../../src/extension/logger.ts"],"mappings":";;;;KAYY,eAAA;;KAGA,aAAA;EACV,KAAA,MAAW,IAAA;EACX,KAAA,MAAW,IAAA;EACX,IAAA,MAAU,IAAA;EACV,IAAA,MAAU,IAAA;EACV,KAAA,MAAW,IAAA,sBALY;EAOvB,KAAA,EAAO,eAAA,EAEgC;EAAvC,KAAA,GAAQ,KAAA,aAAkB,aAAa;AAAA;;KAI7B,mBAAA;EAVV,yDAYA,KAAA,GAAQ,eAAe,EAXvB;EAaA,MAAA,WAZA;EAcA,UAAA;AAAA;;KAIU,UAAA,MAAgB,eAAA,CAAgB,CAAA;EAAK,MAAA,EAAQ,aAAA;AAAA;;AAdhB;AAIzC;;;;;;;;;AAMY;AAIZ;;;;;;;;;;;;;;AAAsE;AA6NtE;;;;;;;;;;;iBAAgB,aAAA,WAAwB,gBAAA,EAAkB,MAAA,GAAS,mBAAA,IAAuB,OAAA,EAAS,CAAA,KAAM,UAAA,CAAW,CAAA"}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { thenMaybe } from "../core/results.mjs";
|
|
2
|
+
import { defineInterceptor } from "../core/interceptors.mjs";
|
|
3
|
+
//#region src/extension/logger.ts
|
|
4
|
+
const LEVEL_ORDER = {
|
|
5
|
+
trace: 0,
|
|
6
|
+
debug: 1,
|
|
7
|
+
info: 2,
|
|
8
|
+
warn: 3,
|
|
9
|
+
error: 4,
|
|
10
|
+
silent: 5
|
|
11
|
+
};
|
|
12
|
+
const LEVEL_LABELS = {
|
|
13
|
+
trace: "TRACE",
|
|
14
|
+
debug: "DEBUG",
|
|
15
|
+
info: "INFO",
|
|
16
|
+
warn: "WARN",
|
|
17
|
+
error: "ERROR"
|
|
18
|
+
};
|
|
19
|
+
const VALID_LEVELS = new Set(Object.keys(LEVEL_ORDER));
|
|
20
|
+
/** Format specifier pattern: matches %s, %d, %i, %f, %o, %O, %j, %% */
|
|
21
|
+
const FORMAT_PATTERN = /%%|%[sdifjoO]/g;
|
|
22
|
+
/**
|
|
23
|
+
* Applies printf-style format specifiers to args, following the WHATWG Console Standard
|
|
24
|
+
* and Node.js `util.format` conventions. Remaining args are appended space-separated.
|
|
25
|
+
*/
|
|
26
|
+
function formatArgs(args) {
|
|
27
|
+
if (args.length === 0) return "";
|
|
28
|
+
if (typeof args[0] !== "string" || !FORMAT_PATTERN.test(args[0])) return args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ");
|
|
29
|
+
const template = args[0];
|
|
30
|
+
let argIndex = 1;
|
|
31
|
+
const result = template.replace(FORMAT_PATTERN, (token) => {
|
|
32
|
+
if (token === "%%") return "%";
|
|
33
|
+
if (argIndex >= args.length) return token;
|
|
34
|
+
const val = args[argIndex++];
|
|
35
|
+
switch (token) {
|
|
36
|
+
case "%s": return String(val);
|
|
37
|
+
case "%d":
|
|
38
|
+
case "%i": return String(Math.trunc(Number(val)));
|
|
39
|
+
case "%f": return String(Number(val));
|
|
40
|
+
case "%j": try {
|
|
41
|
+
return JSON.stringify(val);
|
|
42
|
+
} catch {
|
|
43
|
+
return "[Circular]";
|
|
44
|
+
}
|
|
45
|
+
case "%o":
|
|
46
|
+
case "%O": return typeof val === "string" ? val : JSON.stringify(val);
|
|
47
|
+
default: return token;
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
const remaining = args.slice(argIndex);
|
|
51
|
+
if (remaining.length === 0) return result;
|
|
52
|
+
return `${result} ${remaining.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ")}`;
|
|
53
|
+
}
|
|
54
|
+
function resolveCliLevel(rawArgs) {
|
|
55
|
+
if ("trace" in rawArgs) {
|
|
56
|
+
const t = rawArgs.trace;
|
|
57
|
+
delete rawArgs.trace;
|
|
58
|
+
if (t !== false) return "trace";
|
|
59
|
+
}
|
|
60
|
+
if ("verbose" in rawArgs) {
|
|
61
|
+
const v = rawArgs.verbose;
|
|
62
|
+
delete rawArgs.verbose;
|
|
63
|
+
if (v !== false) return "debug";
|
|
64
|
+
}
|
|
65
|
+
if ("debug" in rawArgs) {
|
|
66
|
+
const d = rawArgs.debug;
|
|
67
|
+
delete rawArgs.debug;
|
|
68
|
+
if (d !== false) return "debug";
|
|
69
|
+
}
|
|
70
|
+
if ("silent" in rawArgs) {
|
|
71
|
+
const s = rawArgs.silent;
|
|
72
|
+
delete rawArgs.silent;
|
|
73
|
+
if (s !== false) return "silent";
|
|
74
|
+
}
|
|
75
|
+
if ("quiet" in rawArgs) {
|
|
76
|
+
const q = rawArgs.quiet;
|
|
77
|
+
delete rawArgs.quiet;
|
|
78
|
+
if (q !== false) return "silent";
|
|
79
|
+
}
|
|
80
|
+
if ("log-level" in rawArgs) {
|
|
81
|
+
const val = rawArgs["log-level"];
|
|
82
|
+
delete rawArgs["log-level"];
|
|
83
|
+
if (typeof val === "string" && VALID_LEVELS.has(val)) return val;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function createLogger(runtime, level, config, tracing) {
|
|
87
|
+
const threshold = LEVEL_ORDER[level];
|
|
88
|
+
function format(lvl, prefix, args) {
|
|
89
|
+
const parts = [];
|
|
90
|
+
if (config.timestamps) parts.push((/* @__PURE__ */ new Date()).toISOString());
|
|
91
|
+
parts.push(`[${LEVEL_LABELS[lvl]}]`);
|
|
92
|
+
if (prefix) parts.push(prefix);
|
|
93
|
+
parts.push(formatArgs(args));
|
|
94
|
+
return parts.join(" ");
|
|
95
|
+
}
|
|
96
|
+
function makeLogger(prefix) {
|
|
97
|
+
const emit = (lvl, args) => {
|
|
98
|
+
if (LEVEL_ORDER[lvl] < threshold) return;
|
|
99
|
+
const message = format(lvl, prefix, args);
|
|
100
|
+
tracing?.rootSpan.addEvent("log", {
|
|
101
|
+
"log.level": lvl,
|
|
102
|
+
"log.message": args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ")
|
|
103
|
+
});
|
|
104
|
+
if (lvl === "error" || lvl === "warn") runtime.error(message);
|
|
105
|
+
else runtime.output(message);
|
|
106
|
+
};
|
|
107
|
+
return {
|
|
108
|
+
trace: (...args) => emit("trace", args),
|
|
109
|
+
debug: (...args) => emit("debug", args),
|
|
110
|
+
info: (...args) => emit("info", args),
|
|
111
|
+
warn: (...args) => emit("warn", args),
|
|
112
|
+
error: (...args) => emit("error", args),
|
|
113
|
+
level,
|
|
114
|
+
child: (label) => makeLogger(prefix ? `${prefix} [${label}]` : `[${label}]`)
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
return makeLogger(config.prefix);
|
|
118
|
+
}
|
|
119
|
+
function loggerInterceptor(rawConfig) {
|
|
120
|
+
return defineInterceptor({
|
|
121
|
+
id: "padrone:logger",
|
|
122
|
+
name: "padrone:logger"
|
|
123
|
+
}).requires().factory(() => {
|
|
124
|
+
let cliLevel;
|
|
125
|
+
return {
|
|
126
|
+
parse(_ctx, next) {
|
|
127
|
+
return thenMaybe(next(), (res) => {
|
|
128
|
+
cliLevel = resolveCliLevel(res.rawArgs);
|
|
129
|
+
return res;
|
|
130
|
+
});
|
|
131
|
+
},
|
|
132
|
+
execute(ctx, next) {
|
|
133
|
+
const ctxCfg = ctx.context?.loggerConfig;
|
|
134
|
+
const resolved = {
|
|
135
|
+
level: cliLevel ?? rawConfig?.level ?? ctxCfg?.level ?? "info",
|
|
136
|
+
prefix: rawConfig?.prefix ?? "",
|
|
137
|
+
timestamps: rawConfig?.timestamps ?? ctxCfg?.timestamps ?? false
|
|
138
|
+
};
|
|
139
|
+
return next({ context: { logger: createLogger(ctx.runtime, resolved.level, resolved, ctx.context?.tracing) } });
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Extension that injects a structured logger into the command context.
|
|
146
|
+
*
|
|
147
|
+
* The logger respects a configurable log level threshold, supports prefixed
|
|
148
|
+
* child loggers, and routes output through the runtime's `output`/`error`
|
|
149
|
+
* functions so it works in any environment (terminal, test, web).
|
|
150
|
+
*
|
|
151
|
+
* Supports CLI flags for runtime level overrides:
|
|
152
|
+
* - `--trace` → sets level to `trace`
|
|
153
|
+
* - `--verbose` or `--debug` → sets level to `debug`
|
|
154
|
+
* - `--silent` or `--quiet` → sets level to `silent`
|
|
155
|
+
* - `--log-level=<level>` → sets an explicit level (`trace`, `debug`, `info`, `warn`, `error`, `silent`)
|
|
156
|
+
*
|
|
157
|
+
* CLI flags take precedence over the programmatic config.
|
|
158
|
+
*
|
|
159
|
+
* Provides `{ logger: PadroneLogger }` on the command context.
|
|
160
|
+
* Access it in action handlers as `ctx.context.logger`.
|
|
161
|
+
*
|
|
162
|
+
* Usage:
|
|
163
|
+
* ```ts
|
|
164
|
+
* createPadrone('my-cli')
|
|
165
|
+
* .extend(padroneLogger({ level: 'info' }))
|
|
166
|
+
* .command('sync', (c) =>
|
|
167
|
+
* c.action((_args, ctx) => {
|
|
168
|
+
* ctx.context.logger.info('starting sync');
|
|
169
|
+
* const db = ctx.context.logger.child('db');
|
|
170
|
+
* db.debug('connecting...');
|
|
171
|
+
* })
|
|
172
|
+
* )
|
|
173
|
+
* ```
|
|
174
|
+
*
|
|
175
|
+
* Then run:
|
|
176
|
+
* ```sh
|
|
177
|
+
* my-cli sync --verbose # debug level
|
|
178
|
+
* my-cli sync --quiet # silent
|
|
179
|
+
* my-cli sync --log-level=warn
|
|
180
|
+
* ```
|
|
181
|
+
*/
|
|
182
|
+
function padroneLogger(config) {
|
|
183
|
+
return ((builder) => builder.intercept(loggerInterceptor(config)));
|
|
184
|
+
}
|
|
185
|
+
//#endregion
|
|
186
|
+
export { padroneLogger };
|
|
187
|
+
|
|
188
|
+
//# sourceMappingURL=logger.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.mjs","names":[],"sources":["../../src/extension/logger.ts"],"sourcesContent":["import { defineInterceptor } from '#src/core/interceptors.ts';\nimport { thenMaybe } from '#src/core/results.ts';\nimport type { ResolvedPadroneRuntime } from '#src/core/runtime.ts';\nimport type { AnyPadroneBuilder, CommandTypesBase } from '#src/types/index.ts';\nimport type { WithInterceptor } from '#src/util/type-utils.ts';\nimport type { PadroneTracer } from './tracing.ts';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** Log level values ordered by severity. */\nexport type PadroneLogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'silent';\n\n/** Logger instance injected into the command context. */\nexport type PadroneLogger = {\n trace: (...args: unknown[]) => void;\n debug: (...args: unknown[]) => void;\n info: (...args: unknown[]) => void;\n warn: (...args: unknown[]) => void;\n error: (...args: unknown[]) => void;\n /** The current effective log level. */\n level: PadroneLogLevel;\n /** Create a child logger with a prefix label. */\n child: (label: string) => PadroneLogger;\n};\n\n/** Configuration for the logger extension. */\nexport type PadroneLoggerConfig = {\n /** Minimum log level to output. Defaults to `'info'`. */\n level?: PadroneLogLevel;\n /** Prefix prepended to every log message. */\n prefix?: string;\n /** Include timestamps in log output. Defaults to `false`. */\n timestamps?: boolean;\n};\n\n/** Builder/program type after applying `padroneLogger()`. Adds `{ logger: PadroneLogger }` to the command context. */\nexport type WithLogger<T> = WithInterceptor<T, { logger: PadroneLogger }>;\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\nconst LEVEL_ORDER: Record<PadroneLogLevel, number> = { trace: 0, debug: 1, info: 2, warn: 3, error: 4, silent: 5 };\nconst LEVEL_LABELS: Record<Exclude<PadroneLogLevel, 'silent'>, string> = {\n trace: 'TRACE',\n debug: 'DEBUG',\n info: 'INFO',\n warn: 'WARN',\n error: 'ERROR',\n};\nconst VALID_LEVELS = new Set<string>(Object.keys(LEVEL_ORDER));\n\n/** Format specifier pattern: matches %s, %d, %i, %f, %o, %O, %j, %% */\nconst FORMAT_PATTERN = /%%|%[sdifjoO]/g;\n\n/**\n * Applies printf-style format specifiers to args, following the WHATWG Console Standard\n * and Node.js `util.format` conventions. Remaining args are appended space-separated.\n */\nfunction formatArgs(args: unknown[]): string {\n if (args.length === 0) return '';\n if (typeof args[0] !== 'string' || !FORMAT_PATTERN.test(args[0])) {\n return args.map((a) => (typeof a === 'string' ? a : JSON.stringify(a))).join(' ');\n }\n\n const template = args[0];\n let argIndex = 1;\n const result = template.replace(FORMAT_PATTERN, (token) => {\n if (token === '%%') return '%';\n if (argIndex >= args.length) return token;\n const val = args[argIndex++];\n switch (token) {\n case '%s':\n return String(val);\n case '%d':\n case '%i':\n return String(Math.trunc(Number(val)));\n case '%f':\n return String(Number(val));\n case '%j':\n try {\n return JSON.stringify(val);\n } catch {\n return '[Circular]';\n }\n case '%o':\n case '%O':\n return typeof val === 'string' ? val : JSON.stringify(val);\n default:\n return token;\n }\n });\n\n // Append remaining args that weren't consumed by specifiers\n const remaining = args.slice(argIndex);\n if (remaining.length === 0) return result;\n const tail = remaining.map((a) => (typeof a === 'string' ? a : JSON.stringify(a))).join(' ');\n return `${result} ${tail}`;\n}\n\nfunction resolveCliLevel(rawArgs: Record<string, unknown>): PadroneLogLevel | undefined {\n // --trace → trace level\n if ('trace' in rawArgs) {\n const t = rawArgs.trace;\n delete rawArgs.trace;\n if (t !== false) return 'trace';\n }\n // --verbose / --debug → debug level\n if ('verbose' in rawArgs) {\n const v = rawArgs.verbose;\n delete rawArgs.verbose;\n if (v !== false) return 'debug';\n }\n if ('debug' in rawArgs) {\n const d = rawArgs.debug;\n delete rawArgs.debug;\n if (d !== false) return 'debug';\n }\n // --silent / --quiet → suppress all output\n if ('silent' in rawArgs) {\n const s = rawArgs.silent;\n delete rawArgs.silent;\n if (s !== false) return 'silent';\n }\n if ('quiet' in rawArgs) {\n const q = rawArgs.quiet;\n delete rawArgs.quiet;\n if (q !== false) return 'silent';\n }\n // --log-level=<level> → explicit level (parser keeps kebab-case)\n if ('log-level' in rawArgs) {\n const val = rawArgs['log-level'];\n delete rawArgs['log-level'];\n if (typeof val === 'string' && VALID_LEVELS.has(val)) return val as PadroneLogLevel;\n }\n return undefined;\n}\n\nfunction createLogger(\n runtime: ResolvedPadroneRuntime,\n level: PadroneLogLevel,\n config: ResolvedLoggerConfig,\n tracing?: PadroneTracer,\n): PadroneLogger {\n const threshold = LEVEL_ORDER[level];\n\n function format(lvl: Exclude<PadroneLogLevel, 'silent'>, prefix: string, args: unknown[]): string {\n const parts: string[] = [];\n if (config.timestamps) parts.push(new Date().toISOString());\n parts.push(`[${LEVEL_LABELS[lvl]}]`);\n if (prefix) parts.push(prefix);\n parts.push(formatArgs(args));\n return parts.join(' ');\n }\n\n function makeLogger(prefix: string): PadroneLogger {\n const emit = (lvl: Exclude<PadroneLogLevel, 'silent'>, args: unknown[]) => {\n if (LEVEL_ORDER[lvl] < threshold) return;\n const message = format(lvl, prefix, args);\n tracing?.rootSpan.addEvent('log', {\n 'log.level': lvl,\n 'log.message': args.map((a) => (typeof a === 'string' ? a : JSON.stringify(a))).join(' '),\n });\n if (lvl === 'error' || lvl === 'warn') runtime.error(message);\n else runtime.output(message);\n };\n\n return {\n trace: (...args) => emit('trace', args),\n debug: (...args) => emit('debug', args),\n info: (...args) => emit('info', args),\n warn: (...args) => emit('warn', args),\n error: (...args) => emit('error', args),\n level,\n child: (label) => makeLogger(prefix ? `${prefix} [${label}]` : `[${label}]`),\n };\n }\n\n return makeLogger(config.prefix);\n}\n\n// ---------------------------------------------------------------------------\n// Interceptor\n// ---------------------------------------------------------------------------\n\ntype ResolvedLoggerConfig = { level: PadroneLogLevel; prefix: string; timestamps: boolean };\n\nfunction loggerInterceptor(rawConfig?: PadroneLoggerConfig) {\n return defineInterceptor({ id: 'padrone:logger', name: 'padrone:logger' })\n .requires<{ tracing?: PadroneTracer; loggerConfig?: PadroneLoggerConfig }>()\n .factory(() => {\n let cliLevel: PadroneLogLevel | undefined;\n\n return {\n parse(_ctx, next) {\n return thenMaybe(next(), (res) => {\n cliLevel = resolveCliLevel(res.rawArgs);\n return res;\n });\n },\n\n execute(ctx, next) {\n const ctxCfg = (ctx.context as Record<string, unknown> | undefined)?.loggerConfig as PadroneLoggerConfig | undefined;\n const resolved: ResolvedLoggerConfig = {\n level: cliLevel ?? rawConfig?.level ?? ctxCfg?.level ?? 'info',\n prefix: rawConfig?.prefix ?? '',\n timestamps: rawConfig?.timestamps ?? ctxCfg?.timestamps ?? false,\n };\n const logger = createLogger(ctx.runtime, resolved.level, resolved, ctx.context?.tracing);\n return next({ context: { logger } });\n },\n };\n });\n}\n\n// ---------------------------------------------------------------------------\n// Extension\n// ---------------------------------------------------------------------------\n\n/**\n * Extension that injects a structured logger into the command context.\n *\n * The logger respects a configurable log level threshold, supports prefixed\n * child loggers, and routes output through the runtime's `output`/`error`\n * functions so it works in any environment (terminal, test, web).\n *\n * Supports CLI flags for runtime level overrides:\n * - `--trace` → sets level to `trace`\n * - `--verbose` or `--debug` → sets level to `debug`\n * - `--silent` or `--quiet` → sets level to `silent`\n * - `--log-level=<level>` → sets an explicit level (`trace`, `debug`, `info`, `warn`, `error`, `silent`)\n *\n * CLI flags take precedence over the programmatic config.\n *\n * Provides `{ logger: PadroneLogger }` on the command context.\n * Access it in action handlers as `ctx.context.logger`.\n *\n * Usage:\n * ```ts\n * createPadrone('my-cli')\n * .extend(padroneLogger({ level: 'info' }))\n * .command('sync', (c) =>\n * c.action((_args, ctx) => {\n * ctx.context.logger.info('starting sync');\n * const db = ctx.context.logger.child('db');\n * db.debug('connecting...');\n * })\n * )\n * ```\n *\n * Then run:\n * ```sh\n * my-cli sync --verbose # debug level\n * my-cli sync --quiet # silent\n * my-cli sync --log-level=warn\n * ```\n */\nexport function padroneLogger<T extends CommandTypesBase>(config?: PadroneLoggerConfig): (builder: T) => WithLogger<T> {\n return ((builder: AnyPadroneBuilder) => builder.intercept(loggerInterceptor(config))) as any;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { PadroneSchema } from "../types/schema.mjs";
|
|
2
|
+
import { WithCommand } from "../util/type-utils.mjs";
|
|
3
|
+
import { CommandTypesBase, PadroneCommand } from "../types/command.mjs";
|
|
4
|
+
//#region src/extension/man.d.ts
|
|
5
|
+
type ManArgs = {
|
|
6
|
+
setup?: boolean;
|
|
7
|
+
remove?: boolean;
|
|
8
|
+
};
|
|
9
|
+
type ManCommand = PadroneCommand<'man', '', PadroneSchema<ManArgs>, string, [], [], true>;
|
|
10
|
+
type WithMan<T> = WithCommand<T, 'man', ManCommand>;
|
|
11
|
+
/**
|
|
12
|
+
* Extension that adds the `man` command for man page generation.
|
|
13
|
+
*
|
|
14
|
+
* Usage:
|
|
15
|
+
* ```ts
|
|
16
|
+
* import { createPadrone } from 'padrone';
|
|
17
|
+
* import { padroneMan } from 'padrone/man';
|
|
18
|
+
*
|
|
19
|
+
* createPadrone('my-cli').extend(padroneMan())
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
declare function padroneMan(): <T extends CommandTypesBase>(builder: T) => WithMan<T>;
|
|
23
|
+
//#endregion
|
|
24
|
+
export { WithMan, padroneMan };
|
|
25
|
+
//# sourceMappingURL=man.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"man.d.mts","names":[],"sources":["../../src/extension/man.ts"],"mappings":";;;;KASK,OAAA;EAAY,KAAA;EAAiB,MAAM;AAAA;AAAA,KAEnC,UAAA,GAAa,cAAA,YAA0B,aAAA,CAAc,OAAA;AAAA,KAE9C,OAAA,MAAa,WAAA,CAAY,CAAA,SAAU,UAAA;;AAJP;AAAA;;;;;;;;;iBAmBxB,UAAA,eAAyB,gBAAA,EAAkB,OAAA,EAAS,CAAA,KAAM,OAAA,CAAQ,CAAA"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { resolveAllCommands } from "../core/commands.mjs";
|
|
2
|
+
import { getRootCommand } from "../util/utils.mjs";
|
|
3
|
+
import { passthroughSchema } from "./utils.mjs";
|
|
4
|
+
//#region src/extension/man.ts
|
|
5
|
+
/**
|
|
6
|
+
* Extension that adds the `man` command for man page generation.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { createPadrone } from 'padrone';
|
|
11
|
+
* import { padroneMan } from 'padrone/man';
|
|
12
|
+
*
|
|
13
|
+
* createPadrone('my-cli').extend(padroneMan())
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
function padroneMan() {
|
|
17
|
+
return ((builder) => builder.command("man", (c) => c.configure({
|
|
18
|
+
description: "Generate man pages",
|
|
19
|
+
hidden: true
|
|
20
|
+
}).arguments(passthroughSchema({
|
|
21
|
+
setup: "boolean",
|
|
22
|
+
remove: "boolean"
|
|
23
|
+
})).async().action(async (args, ctx) => {
|
|
24
|
+
const rootCommand = getRootCommand(ctx.command);
|
|
25
|
+
resolveAllCommands(rootCommand);
|
|
26
|
+
const { setupManPages, removeManPages, generateDocs } = await import("../docs/index.mjs");
|
|
27
|
+
if (args.setup) {
|
|
28
|
+
const setupResult = await setupManPages(rootCommand);
|
|
29
|
+
return `${setupResult.updated ? "Updated" : "Installed"} ${setupResult.written.length} man page(s) in ${setupResult.dir}`;
|
|
30
|
+
}
|
|
31
|
+
if (args.remove) {
|
|
32
|
+
const removeResult = await removeManPages(rootCommand);
|
|
33
|
+
return removeResult.removed.length > 0 ? `Removed ${removeResult.removed.length} man page(s) from ${removeResult.dir}` : "No man pages found to remove.";
|
|
34
|
+
}
|
|
35
|
+
return generateDocs(rootCommand, { format: "man" }).pages[0]?.content ?? "";
|
|
36
|
+
})));
|
|
37
|
+
}
|
|
38
|
+
//#endregion
|
|
39
|
+
export { padroneMan };
|
|
40
|
+
|
|
41
|
+
//# sourceMappingURL=man.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"man.mjs","names":[],"sources":["../../src/extension/man.ts"],"sourcesContent":["import { resolveAllCommands } from '../core/commands.ts';\nimport type { AnyPadroneBuilder, CommandTypesBase, PadroneCommand } from '../types/index.ts';\nimport type { PadroneSchema } from '../types/schema.ts';\nimport type { WithCommand } from '../util/type-utils.ts';\nimport { getRootCommand } from '../util/utils.ts';\nimport { passthroughSchema } from './utils.ts';\n\n// ── Types ────────────────────────────────────────────────────────────────\n\ntype ManArgs = { setup?: boolean; remove?: boolean };\n\ntype ManCommand = PadroneCommand<'man', '', PadroneSchema<ManArgs>, string, [], [], true>;\n\nexport type WithMan<T> = WithCommand<T, 'man', ManCommand>;\n\n// ── Extension ────────────────────────────────────────────────────────────\n\n/**\n * Extension that adds the `man` command for man page generation.\n *\n * Usage:\n * ```ts\n * import { createPadrone } from 'padrone';\n * import { padroneMan } from 'padrone/man';\n *\n * createPadrone('my-cli').extend(padroneMan())\n * ```\n */\nexport function padroneMan(): <T extends CommandTypesBase>(builder: T) => WithMan<T> {\n return ((builder: AnyPadroneBuilder) =>\n builder.command('man', (c) =>\n c\n .configure({ description: 'Generate man pages', hidden: true })\n .arguments(passthroughSchema({ setup: 'boolean', remove: 'boolean' }))\n .async()\n .action(async (args, ctx) => {\n const rootCommand = getRootCommand(ctx.command);\n resolveAllCommands(rootCommand);\n const { setupManPages, removeManPages, generateDocs } = await import('../docs/index.ts');\n if (args.setup) {\n const setupResult = await setupManPages(rootCommand);\n return `${setupResult.updated ? 'Updated' : 'Installed'} ${setupResult.written.length} man page(s) in ${setupResult.dir}`;\n }\n if (args.remove) {\n const removeResult = await removeManPages(rootCommand);\n return removeResult.removed.length > 0\n ? `Removed ${removeResult.removed.length} man page(s) from ${removeResult.dir}`\n : 'No man pages found to remove.';\n }\n const docsResult = generateDocs(rootCommand, { format: 'man' });\n return docsResult.pages[0]?.content ?? '';\n }),\n )) as any;\n}\n"],"mappings":";;;;;;;;;;;;;;;AA4BA,SAAgB,aAAqE;CACnF,SAAS,YACP,QAAQ,QAAQ,QAAQ,MACtB,EACG,UAAU;EAAE,aAAa;EAAsB,QAAQ;CAAK,CAAC,CAAC,CAC9D,UAAU,kBAAkB;EAAE,OAAO;EAAW,QAAQ;CAAU,CAAC,CAAC,CAAC,CACrE,MAAM,CAAC,CACP,OAAO,OAAO,MAAM,QAAQ;EAC3B,MAAM,cAAc,eAAe,IAAI,OAAO;EAC9C,mBAAmB,WAAW;EAC9B,MAAM,EAAE,eAAe,gBAAgB,iBAAiB,MAAM,OAAO;EACrE,IAAI,KAAK,OAAO;GACd,MAAM,cAAc,MAAM,cAAc,WAAW;GACnD,OAAO,GAAG,YAAY,UAAU,YAAY,YAAY,GAAG,YAAY,QAAQ,OAAO,kBAAkB,YAAY;EACtH;EACA,IAAI,KAAK,QAAQ;GACf,MAAM,eAAe,MAAM,eAAe,WAAW;GACrD,OAAO,aAAa,QAAQ,SAAS,IACjC,WAAW,aAAa,QAAQ,OAAO,oBAAoB,aAAa,QACxE;EACN;EAEA,OADmB,aAAa,aAAa,EAAE,QAAQ,MAAM,CAC7C,CAAC,CAAC,MAAM,EAAE,EAAE,WAAW;CACzC,CAAC,CACL;AACJ"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { PadroneSchema } from "../types/schema.mjs";
|
|
2
|
+
import { WithCommand } from "../util/type-utils.mjs";
|
|
3
|
+
import { PadroneMcpPreferences } from "../feature/mcp.mjs";
|
|
4
|
+
import { CommandTypesBase, PadroneCommand } from "../types/command.mjs";
|
|
5
|
+
//#region src/extension/mcp.d.ts
|
|
6
|
+
type McpArgs = {
|
|
7
|
+
transport?: string;
|
|
8
|
+
port?: string;
|
|
9
|
+
host?: string;
|
|
10
|
+
basePath?: string;
|
|
11
|
+
};
|
|
12
|
+
type McpCommand = PadroneCommand<'mcp', '', PadroneSchema<McpArgs>, void, [], [], true>;
|
|
13
|
+
type WithMcp<T> = WithCommand<T, 'mcp', McpCommand>;
|
|
14
|
+
/**
|
|
15
|
+
* Extension that adds the `mcp` command for starting a Model Context Protocol server.
|
|
16
|
+
*
|
|
17
|
+
* Usage:
|
|
18
|
+
* ```ts
|
|
19
|
+
* import { createPadrone } from 'padrone';
|
|
20
|
+
* import { padroneMcp } from 'padrone/mcp';
|
|
21
|
+
*
|
|
22
|
+
* createPadrone('my-cli').extend(padroneMcp())
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
declare function padroneMcp(defaults?: PadroneMcpPreferences): <T extends CommandTypesBase>(builder: T) => WithMcp<T>;
|
|
26
|
+
//#endregion
|
|
27
|
+
export { WithMcp, padroneMcp };
|
|
28
|
+
//# sourceMappingURL=mcp.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.d.mts","names":[],"sources":["../../src/extension/mcp.ts"],"mappings":";;;;;KAUK,OAAA;EAAY,SAAA;EAAoB,IAAA;EAAe,IAAA;EAAe,QAAA;AAAA;AAAA,KAE9D,UAAA,GAAa,cAAA,YAA0B,aAAA,CAAc,OAAA;AAAA,KAE9C,OAAA,MAAa,WAAA,CAAY,CAAA,SAAU,UAAA;;;;;AAJ4B;AAAA;;;;;;iBAmB3D,UAAA,CAAW,QAAA,GAAW,qBAAA,cAAmC,gBAAA,EAAkB,OAAA,EAAS,CAAA,KAAM,OAAA,CAAQ,CAAA"}
|