padrone 1.9.0 → 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 +13 -0
- 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-WmyGc59s.mjs → core/args.mjs} +5 -81
- 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-ohEApqIw.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-D8qkAinX.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-wCoVFTXz.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-ICZFl3xr.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 -902
- package/dist/index.mjs +25 -4377
- 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/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/serve.ts +3 -0
- package/src/extension/tracing.ts +2 -0
- package/src/index.ts +0 -19
- 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/zod.ts +1 -1
- package/dist/args-WmyGc59s.mjs.map +0 -1
- package/dist/codegen/index.d.mts.map +0 -1
- package/dist/codegen/index.mjs.map +0 -1
- package/dist/commands-ohEApqIw.mjs.map +0 -1
- package/dist/completion-D8qkAinX.mjs.map +0 -1
- package/dist/errors-DA4KzK1M.mjs.map +0 -1
- package/dist/formatter-CY3KrOEd.d.mts.map +0 -1
- package/dist/help-CeI45CJx.mjs +0 -892
- package/dist/help-CeI45CJx.mjs.map +0 -1
- package/dist/index-C3Ed1LYN.d.mts +0 -1432
- package/dist/index-C3Ed1LYN.d.mts.map +0 -1
- package/dist/index.d.mts.map +0 -1
- package/dist/index.mjs.map +0 -1
- package/dist/mcp-wCoVFTXz.mjs.map +0 -1
- package/dist/serve-ICZFl3xr.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
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
## padrone@2.0.0
|
|
2
|
+
|
|
3
|
+
### Externalize optional integrations to dedicated subpath entry points
|
|
4
|
+
|
|
5
|
+
Optional integrations are now exported from dedicated subpath entry points so bundlers that don't tree-shake re-exports keep their dependencies out of the main bundle. Update imports as follows:
|
|
6
|
+
|
|
7
|
+
- `padroneInk`, `isReactElement`, `InkOptions` → `'padrone/ink'`
|
|
8
|
+
- `padroneMcp`, `WithMcp`, `PadroneMcpPreferences` → `'padrone/mcp'`
|
|
9
|
+
- `padroneServe`, `WithServe` → `'padrone/serve'`
|
|
10
|
+
- `padroneTracing`, `WithTracing`, `PadroneTracer`, `PadroneTracingConfig`, `OtelSpan`, `OtelTracer`, `OtelTracerProvider` → `'padrone/tracing'`
|
|
11
|
+
- `padroneCompletion`, `WithCompletion` → `'padrone/completion'`
|
|
12
|
+
- `padroneMan`, `WithMan` → `'padrone/man'`
|
|
13
|
+
|
|
1
14
|
# padrone
|
|
2
15
|
|
|
3
16
|
## 1.9.0
|
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
<p align="center">
|
|
10
10
|
<a href="https://www.npmjs.com/package/padrone"><img src="https://img.shields.io/npm/v/padrone.svg" alt="npm version"></a>
|
|
11
11
|
<a href="https://www.npmjs.com/package/padrone"><img src="https://img.shields.io/npm/dm/padrone.svg" alt="npm downloads"></a>
|
|
12
|
-
<a href="https://github.com/
|
|
12
|
+
<a href="https://github.com/gkurt/padrone/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/padrone.svg" alt="license"></a>
|
|
13
13
|
</p>
|
|
14
14
|
|
|
15
15
|
---
|
|
@@ -185,7 +185,7 @@ program.help('greet', { format: 'json' }); // json, markdown, html, ansi
|
|
|
185
185
|
Give your AI coding agent knowledge of the Padrone API:
|
|
186
186
|
|
|
187
187
|
```bash
|
|
188
|
-
npx skills add
|
|
188
|
+
npx skills add gkurt/padrone
|
|
189
189
|
```
|
|
190
190
|
|
|
191
191
|
## Requirements
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { CodeBuilder } from "./types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/codegen/code-builder.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Create a new CodeBuilder for constructing TypeScript source files.
|
|
6
|
+
*/
|
|
7
|
+
declare function createCodeBuilder(): CodeBuilder;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { createCodeBuilder };
|
|
10
|
+
//# sourceMappingURL=code-builder.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code-builder.d.mts","names":[],"sources":["../../src/codegen/code-builder.ts"],"mappings":";;;;;AA+NA;iBAAgB,iBAAA,IAAqB,WAAW"}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
//#region src/codegen/code-builder.ts
|
|
2
|
+
var CodeBuilderImpl = class CodeBuilderImpl {
|
|
3
|
+
imports = /* @__PURE__ */ new Map();
|
|
4
|
+
lines = [];
|
|
5
|
+
indent;
|
|
6
|
+
constructor(indent = 0) {
|
|
7
|
+
this.indent = indent;
|
|
8
|
+
}
|
|
9
|
+
import(specifier, source) {
|
|
10
|
+
const specs = Array.isArray(specifier) ? specifier : [specifier];
|
|
11
|
+
const existing = this.imports.get(source);
|
|
12
|
+
if (existing) {
|
|
13
|
+
for (const s of specs) existing.specifiers.add(s);
|
|
14
|
+
existing.typeOnly = false;
|
|
15
|
+
} else this.imports.set(source, {
|
|
16
|
+
specifiers: new Set(specs),
|
|
17
|
+
typeOnly: false
|
|
18
|
+
});
|
|
19
|
+
return this;
|
|
20
|
+
}
|
|
21
|
+
importDefault(name, source) {
|
|
22
|
+
const existing = this.imports.get(source);
|
|
23
|
+
if (existing) {
|
|
24
|
+
existing.defaultSpecifier = name;
|
|
25
|
+
existing.typeOnly = false;
|
|
26
|
+
} else this.imports.set(source, {
|
|
27
|
+
specifiers: /* @__PURE__ */ new Set(),
|
|
28
|
+
defaultSpecifier: name,
|
|
29
|
+
typeOnly: false
|
|
30
|
+
});
|
|
31
|
+
return this;
|
|
32
|
+
}
|
|
33
|
+
importType(specifier, source) {
|
|
34
|
+
const specs = Array.isArray(specifier) ? specifier : [specifier];
|
|
35
|
+
const existing = this.imports.get(source);
|
|
36
|
+
if (existing) for (const s of specs) existing.specifiers.add(s);
|
|
37
|
+
else this.imports.set(source, {
|
|
38
|
+
specifiers: new Set(specs),
|
|
39
|
+
typeOnly: true
|
|
40
|
+
});
|
|
41
|
+
return this;
|
|
42
|
+
}
|
|
43
|
+
line(code) {
|
|
44
|
+
this.lines.push({
|
|
45
|
+
type: "line",
|
|
46
|
+
content: code ?? ""
|
|
47
|
+
});
|
|
48
|
+
return this;
|
|
49
|
+
}
|
|
50
|
+
block(openOrBuilder, builderOrClose, closeOrBuilder) {
|
|
51
|
+
let open;
|
|
52
|
+
let close;
|
|
53
|
+
let builder;
|
|
54
|
+
if (typeof openOrBuilder === "function") builder = openOrBuilder;
|
|
55
|
+
else if (typeof builderOrClose === "function") {
|
|
56
|
+
open = openOrBuilder;
|
|
57
|
+
builder = builderOrClose;
|
|
58
|
+
close = typeof closeOrBuilder === "string" ? closeOrBuilder : void 0;
|
|
59
|
+
} else if (typeof closeOrBuilder === "function") {
|
|
60
|
+
open = openOrBuilder;
|
|
61
|
+
close = typeof builderOrClose === "string" ? builderOrClose : void 0;
|
|
62
|
+
builder = closeOrBuilder;
|
|
63
|
+
} else throw new Error("Invalid block() arguments");
|
|
64
|
+
this.lines.push({
|
|
65
|
+
type: "block-open",
|
|
66
|
+
content: open ?? ""
|
|
67
|
+
});
|
|
68
|
+
const inner = new CodeBuilderImpl(this.indent + 1);
|
|
69
|
+
builder(inner);
|
|
70
|
+
for (const [source, entry] of inner.imports) {
|
|
71
|
+
const existing = this.imports.get(source);
|
|
72
|
+
if (existing) {
|
|
73
|
+
for (const s of entry.specifiers) existing.specifiers.add(s);
|
|
74
|
+
if (entry.defaultSpecifier) existing.defaultSpecifier = entry.defaultSpecifier;
|
|
75
|
+
if (!entry.typeOnly) existing.typeOnly = false;
|
|
76
|
+
} else this.imports.set(source, {
|
|
77
|
+
specifiers: new Set(entry.specifiers),
|
|
78
|
+
defaultSpecifier: entry.defaultSpecifier,
|
|
79
|
+
typeOnly: entry.typeOnly
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
for (const line of inner.lines) this.lines.push(line);
|
|
83
|
+
this.lines.push({
|
|
84
|
+
type: "block-close",
|
|
85
|
+
content: close ?? ""
|
|
86
|
+
});
|
|
87
|
+
return this;
|
|
88
|
+
}
|
|
89
|
+
comment(text) {
|
|
90
|
+
this.lines.push({
|
|
91
|
+
type: "line",
|
|
92
|
+
content: `// ${text}`
|
|
93
|
+
});
|
|
94
|
+
return this;
|
|
95
|
+
}
|
|
96
|
+
docComment(text) {
|
|
97
|
+
const lines = text.split("\n");
|
|
98
|
+
if (lines.length === 1) this.lines.push({
|
|
99
|
+
type: "line",
|
|
100
|
+
content: `/** ${text} */`
|
|
101
|
+
});
|
|
102
|
+
else {
|
|
103
|
+
this.lines.push({
|
|
104
|
+
type: "line",
|
|
105
|
+
content: "/**"
|
|
106
|
+
});
|
|
107
|
+
for (const line of lines) this.lines.push({
|
|
108
|
+
type: "line",
|
|
109
|
+
content: ` * ${line}`
|
|
110
|
+
});
|
|
111
|
+
this.lines.push({
|
|
112
|
+
type: "line",
|
|
113
|
+
content: " */"
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
return this;
|
|
117
|
+
}
|
|
118
|
+
todoComment(text) {
|
|
119
|
+
this.lines.push({
|
|
120
|
+
type: "line",
|
|
121
|
+
content: `// TODO: ${text}`
|
|
122
|
+
});
|
|
123
|
+
return this;
|
|
124
|
+
}
|
|
125
|
+
raw(code) {
|
|
126
|
+
this.lines.push({
|
|
127
|
+
type: "raw",
|
|
128
|
+
content: code
|
|
129
|
+
});
|
|
130
|
+
return this;
|
|
131
|
+
}
|
|
132
|
+
build() {
|
|
133
|
+
const parts = [];
|
|
134
|
+
if (this.imports.size > 0) {
|
|
135
|
+
const typeImports = [];
|
|
136
|
+
const valueImports = [];
|
|
137
|
+
for (const [source, entry] of this.imports) {
|
|
138
|
+
const specs = [...entry.specifiers].sort();
|
|
139
|
+
const namedPart = specs.length > 0 ? specs.length === 1 && !specs[0].includes(" ") ? `{ ${specs[0]} }` : `{ ${specs.join(", ")} }` : null;
|
|
140
|
+
const specStr = entry.defaultSpecifier ? namedPart ? `${entry.defaultSpecifier}, ${namedPart}` : entry.defaultSpecifier : namedPart;
|
|
141
|
+
const line = entry.typeOnly ? `import type ${specStr} from '${source}'` : `import ${specStr} from '${source}'`;
|
|
142
|
+
if (entry.typeOnly) typeImports.push(line);
|
|
143
|
+
else valueImports.push(line);
|
|
144
|
+
}
|
|
145
|
+
parts.push([...valueImports, ...typeImports].join("\n"));
|
|
146
|
+
parts.push("");
|
|
147
|
+
}
|
|
148
|
+
let currentIndent = this.indent;
|
|
149
|
+
for (const line of this.lines) if (line.type === "raw") parts.push(line.content);
|
|
150
|
+
else if (line.type === "block-open") {
|
|
151
|
+
if (line.content) {
|
|
152
|
+
const indent = " ".repeat(currentIndent);
|
|
153
|
+
parts.push(`${indent}${line.content}`);
|
|
154
|
+
}
|
|
155
|
+
currentIndent++;
|
|
156
|
+
} else if (line.type === "block-close") {
|
|
157
|
+
currentIndent--;
|
|
158
|
+
if (line.content) {
|
|
159
|
+
const indent = " ".repeat(currentIndent);
|
|
160
|
+
parts.push(`${indent}${line.content}`);
|
|
161
|
+
}
|
|
162
|
+
} else if (line.content === "") parts.push("");
|
|
163
|
+
else {
|
|
164
|
+
const indent = " ".repeat(currentIndent);
|
|
165
|
+
parts.push(`${indent}${line.content}`);
|
|
166
|
+
}
|
|
167
|
+
return {
|
|
168
|
+
text: parts.join("\n"),
|
|
169
|
+
imports: new Map([...this.imports].map(([source, entry]) => [source, {
|
|
170
|
+
specifiers: new Set(entry.specifiers),
|
|
171
|
+
typeOnly: entry.typeOnly
|
|
172
|
+
}]))
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
/**
|
|
177
|
+
* Create a new CodeBuilder for constructing TypeScript source files.
|
|
178
|
+
*/
|
|
179
|
+
function createCodeBuilder() {
|
|
180
|
+
return new CodeBuilderImpl();
|
|
181
|
+
}
|
|
182
|
+
//#endregion
|
|
183
|
+
export { createCodeBuilder };
|
|
184
|
+
|
|
185
|
+
//# sourceMappingURL=code-builder.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code-builder.mjs","names":[],"sources":["../../src/codegen/code-builder.ts"],"sourcesContent":["import type { CodeBuilder, CodeBuildResult } from './types.ts';\n\ninterface ImportEntry {\n specifiers: Set<string>;\n defaultSpecifier?: string;\n typeOnly: boolean;\n}\n\ninterface CodeLine {\n type: 'line' | 'raw' | 'block-open' | 'block-close';\n content: string;\n}\n\nclass CodeBuilderImpl implements CodeBuilder {\n private imports = new Map<string, ImportEntry>();\n private lines: CodeLine[] = [];\n private indent: number;\n\n constructor(indent = 0) {\n this.indent = indent;\n }\n\n import(specifier: string | string[], source: string): CodeBuilder {\n const specs = Array.isArray(specifier) ? specifier : [specifier];\n const existing = this.imports.get(source);\n if (existing) {\n for (const s of specs) existing.specifiers.add(s);\n // If we're adding a value import and existing was type-only, downgrade to value\n existing.typeOnly = false;\n } else {\n this.imports.set(source, { specifiers: new Set(specs), typeOnly: false });\n }\n return this;\n }\n\n importDefault(name: string, source: string): CodeBuilder {\n const existing = this.imports.get(source);\n if (existing) {\n existing.defaultSpecifier = name;\n existing.typeOnly = false;\n } else {\n this.imports.set(source, { specifiers: new Set(), defaultSpecifier: name, typeOnly: false });\n }\n return this;\n }\n\n importType(specifier: string | string[], source: string): CodeBuilder {\n const specs = Array.isArray(specifier) ? specifier : [specifier];\n const existing = this.imports.get(source);\n if (existing) {\n for (const s of specs) existing.specifiers.add(s);\n // Don't downgrade: if existing is value import, keep it as value\n } else {\n this.imports.set(source, { specifiers: new Set(specs), typeOnly: true });\n }\n return this;\n }\n\n line(code?: string): CodeBuilder {\n this.lines.push({ type: 'line', content: code ?? '' });\n return this;\n }\n\n block(\n openOrBuilder: string | ((b: CodeBuilder) => CodeBuilder),\n builderOrClose?: string | ((b: CodeBuilder) => CodeBuilder),\n closeOrBuilder?: string | ((b: CodeBuilder) => CodeBuilder),\n ): CodeBuilder {\n let open: string | undefined;\n let close: string | undefined;\n let builder: (b: CodeBuilder) => CodeBuilder;\n\n if (typeof openOrBuilder === 'function') {\n // block(builder)\n builder = openOrBuilder;\n } else if (typeof builderOrClose === 'function') {\n // block(open, builder, close?)\n open = openOrBuilder;\n builder = builderOrClose;\n close = typeof closeOrBuilder === 'string' ? closeOrBuilder : undefined;\n } else if (typeof closeOrBuilder === 'function') {\n // block(open, close, builder)\n open = openOrBuilder;\n close = typeof builderOrClose === 'string' ? builderOrClose : undefined;\n builder = closeOrBuilder;\n } else {\n throw new Error('Invalid block() arguments');\n }\n\n // Always push block-open to increment indent\n this.lines.push({ type: 'block-open', content: open ?? '' });\n\n const inner = new CodeBuilderImpl(this.indent + 1);\n builder(inner);\n\n // Merge inner imports into ours\n for (const [source, entry] of inner.imports) {\n const existing = this.imports.get(source);\n if (existing) {\n for (const s of entry.specifiers) existing.specifiers.add(s);\n if (entry.defaultSpecifier) existing.defaultSpecifier = entry.defaultSpecifier;\n if (!entry.typeOnly) existing.typeOnly = false;\n } else {\n this.imports.set(source, {\n specifiers: new Set(entry.specifiers),\n defaultSpecifier: entry.defaultSpecifier,\n typeOnly: entry.typeOnly,\n });\n }\n }\n\n // Merge inner lines with extra indentation\n for (const line of inner.lines) {\n this.lines.push(line);\n }\n\n // Always push block-close to decrement indent\n this.lines.push({ type: 'block-close', content: close ?? '' });\n\n return this;\n }\n\n comment(text: string): CodeBuilder {\n this.lines.push({ type: 'line', content: `// ${text}` });\n return this;\n }\n\n docComment(text: string): CodeBuilder {\n const lines = text.split('\\n');\n if (lines.length === 1) {\n this.lines.push({ type: 'line', content: `/** ${text} */` });\n } else {\n this.lines.push({ type: 'line', content: '/**' });\n for (const line of lines) {\n this.lines.push({ type: 'line', content: ` * ${line}` });\n }\n this.lines.push({ type: 'line', content: ' */' });\n }\n return this;\n }\n\n todoComment(text: string): CodeBuilder {\n this.lines.push({ type: 'line', content: `// TODO: ${text}` });\n return this;\n }\n\n raw(code: string): CodeBuilder {\n this.lines.push({ type: 'raw', content: code });\n return this;\n }\n\n build(): CodeBuildResult {\n const parts: string[] = [];\n\n // Emit imports first\n if (this.imports.size > 0) {\n const typeImports: string[] = [];\n const valueImports: string[] = [];\n\n for (const [source, entry] of this.imports) {\n const specs = [...entry.specifiers].sort();\n const namedPart =\n specs.length > 0 ? (specs.length === 1 && !specs[0]!.includes(' ') ? `{ ${specs[0]} }` : `{ ${specs.join(', ')} }`) : null;\n const specStr = entry.defaultSpecifier\n ? namedPart\n ? `${entry.defaultSpecifier}, ${namedPart}`\n : entry.defaultSpecifier\n : namedPart!;\n\n const line = entry.typeOnly ? `import type ${specStr} from '${source}'` : `import ${specStr} from '${source}'`;\n\n if (entry.typeOnly) {\n typeImports.push(line);\n } else {\n valueImports.push(line);\n }\n }\n\n // Value imports first, then type imports\n parts.push([...valueImports, ...typeImports].join('\\n'));\n parts.push('');\n }\n\n // Emit code lines\n let currentIndent = this.indent;\n for (const line of this.lines) {\n if (line.type === 'raw') {\n parts.push(line.content);\n } else if (line.type === 'block-open') {\n if (line.content) {\n const indent = ' '.repeat(currentIndent);\n parts.push(`${indent}${line.content}`);\n }\n currentIndent++;\n } else if (line.type === 'block-close') {\n currentIndent--;\n if (line.content) {\n const indent = ' '.repeat(currentIndent);\n parts.push(`${indent}${line.content}`);\n }\n } else {\n // Regular line\n if (line.content === '') {\n parts.push('');\n } else {\n const indent = ' '.repeat(currentIndent);\n parts.push(`${indent}${line.content}`);\n }\n }\n }\n\n return {\n text: parts.join('\\n'),\n imports: new Map(\n [...this.imports].map(([source, entry]) => [source, { specifiers: new Set(entry.specifiers), typeOnly: entry.typeOnly }]),\n ),\n };\n }\n}\n\n/**\n * Create a new CodeBuilder for constructing TypeScript source files.\n */\nexport function createCodeBuilder(): CodeBuilder {\n return new CodeBuilderImpl();\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { CommandMeta, GeneratorLogger } from "./types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/codegen/discovery.d.ts
|
|
4
|
+
type DiscoverySource = 'help' | 'completion' | 'bash' | 'fish' | 'zsh';
|
|
5
|
+
interface DiscoveryOptions {
|
|
6
|
+
/** The command to discover (e.g. 'gh', 'docker', 'kubectl'). */
|
|
7
|
+
command: string;
|
|
8
|
+
/**
|
|
9
|
+
* Which parsing sources to use. Default: ['help'].
|
|
10
|
+
* Use `'completion'` to auto-detect the best shell completion source
|
|
11
|
+
* by probing `<cmd> completion <shell>` (bash → fish → zsh).
|
|
12
|
+
*/
|
|
13
|
+
sources?: DiscoverySource[];
|
|
14
|
+
/** Max subcommand depth. 0 = root only, undefined = unlimited. */
|
|
15
|
+
depth?: number;
|
|
16
|
+
/** Delay in ms between help invocations. Default: 50 */
|
|
17
|
+
delay?: number;
|
|
18
|
+
/** Logger for progress reporting. */
|
|
19
|
+
log?: GeneratorLogger;
|
|
20
|
+
/** Timeout per help invocation in ms. Default: 10000 */
|
|
21
|
+
timeout?: number;
|
|
22
|
+
}
|
|
23
|
+
interface DiscoveryResult {
|
|
24
|
+
/** The discovered command tree. */
|
|
25
|
+
command: CommandMeta;
|
|
26
|
+
/** Number of help invocations made. */
|
|
27
|
+
invocations: number;
|
|
28
|
+
/** Errors encountered (non-fatal). */
|
|
29
|
+
warnings: string[];
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Discover CLI structure by running --help recursively and optionally
|
|
33
|
+
* parsing shell completion scripts.
|
|
34
|
+
*/
|
|
35
|
+
declare function discoverCli(options: DiscoveryOptions): Promise<DiscoveryResult>;
|
|
36
|
+
/**
|
|
37
|
+
* Detect the best shell for completion parsing by probing the command.
|
|
38
|
+
* Tries `<cmd> completion <shell>` for bash, fish, zsh (in that order).
|
|
39
|
+
* Returns the shell name if successful, or null if no completion command exists.
|
|
40
|
+
*/
|
|
41
|
+
declare function detectCompletionShell(command: string, timeout?: number): Promise<'bash' | 'fish' | 'zsh' | null>;
|
|
42
|
+
//#endregion
|
|
43
|
+
export { DiscoveryOptions, DiscoveryResult, DiscoverySource, detectCompletionShell, discoverCli };
|
|
44
|
+
//# sourceMappingURL=discovery.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.d.mts","names":[],"sources":["../../src/codegen/discovery.ts"],"mappings":";;;KAUY,eAAA;AAAA,UAEK,gBAAA;EAFL;EAIV,OAAA;;;AAJyB;AAE3B;;EAQE,OAAA,GAAU,eAAA;EAMW;EAJrB,KAAA;EAFA;EAIA,KAAA;EAFA;EAIA,GAAA,GAAM,eAAe;EAArB;EAEA,OAAA;AAAA;AAAA,UAGe,eAAA;EAHR;EAKP,OAAA,EAAS,WAAW;EAFU;EAI9B,WAAA;EAFoB;EAIpB,QAAA;AAAA;;;;AAAQ;iBAOY,WAAA,CAAY,OAAA,EAAS,gBAAA,GAAmB,OAAA,CAAQ,eAAA;;;;;;iBA2MhD,qBAAA,CAAsB,OAAA,UAAiB,OAAA,YAAiB,OAAO"}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { parseBashCompletions } from "./parsers/bash.mjs";
|
|
2
|
+
import { parseFishCompletions } from "./parsers/fish.mjs";
|
|
3
|
+
import { parseHelpOutput } from "./parsers/help.mjs";
|
|
4
|
+
import { mergeCommandMeta } from "./parsers/merge.mjs";
|
|
5
|
+
import { parseZshCompletions } from "./parsers/zsh.mjs";
|
|
6
|
+
import { execFile } from "node:child_process";
|
|
7
|
+
import { readFile } from "node:fs/promises";
|
|
8
|
+
//#region src/codegen/discovery.ts
|
|
9
|
+
/**
|
|
10
|
+
* Discover CLI structure by running --help recursively and optionally
|
|
11
|
+
* parsing shell completion scripts.
|
|
12
|
+
*/
|
|
13
|
+
async function discoverCli(options) {
|
|
14
|
+
const { command, sources: rawSources = ["help"], depth, delay = 50, log, timeout = 1e4 } = options;
|
|
15
|
+
const sources = await resolveSources(rawSources, command, timeout, log);
|
|
16
|
+
const warnings = [];
|
|
17
|
+
let invocations = 0;
|
|
18
|
+
const results = [];
|
|
19
|
+
if (sources.includes("help")) {
|
|
20
|
+
log?.info(`Discovering ${command} via --help...`);
|
|
21
|
+
const helpResult = await crawlHelp(command, [], {
|
|
22
|
+
depth,
|
|
23
|
+
delay,
|
|
24
|
+
timeout,
|
|
25
|
+
log,
|
|
26
|
+
onInvocation: () => {
|
|
27
|
+
invocations++;
|
|
28
|
+
},
|
|
29
|
+
onWarning: (msg) => {
|
|
30
|
+
warnings.push(msg);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
results.push(helpResult);
|
|
34
|
+
}
|
|
35
|
+
if (sources.includes("bash")) {
|
|
36
|
+
log?.info(`Parsing bash completions for ${command}...`);
|
|
37
|
+
const bashText = await getCompletionScript(command, "bash", timeout);
|
|
38
|
+
if (bashText) results.push(parseBashCompletions(bashText));
|
|
39
|
+
else warnings.push("Could not obtain bash completion script");
|
|
40
|
+
}
|
|
41
|
+
if (sources.includes("fish")) {
|
|
42
|
+
log?.info(`Parsing fish completions for ${command}...`);
|
|
43
|
+
const fishText = await getCompletionScript(command, "fish", timeout);
|
|
44
|
+
if (fishText) results.push(parseFishCompletions(fishText));
|
|
45
|
+
else warnings.push("Could not obtain fish completion script");
|
|
46
|
+
}
|
|
47
|
+
if (sources.includes("zsh")) {
|
|
48
|
+
log?.info(`Parsing zsh completions for ${command}...`);
|
|
49
|
+
const zshText = await getCompletionScript(command, "zsh", timeout);
|
|
50
|
+
if (zshText) results.push(parseZshCompletions(zshText));
|
|
51
|
+
else warnings.push("Could not obtain zsh completion script");
|
|
52
|
+
}
|
|
53
|
+
const merged = results.length > 0 ? mergeCommandMeta(...results) : { name: command };
|
|
54
|
+
if (!merged.name) merged.name = command;
|
|
55
|
+
return {
|
|
56
|
+
command: merged,
|
|
57
|
+
invocations,
|
|
58
|
+
warnings
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Breadth-first crawl of --help output.
|
|
63
|
+
*/
|
|
64
|
+
async function crawlHelp(command, prefixArgs, options) {
|
|
65
|
+
const fullCmd = [command, ...prefixArgs].join(" ");
|
|
66
|
+
options.onInvocation();
|
|
67
|
+
const helpText = await runHelp(command, prefixArgs, options.timeout);
|
|
68
|
+
if (!helpText) {
|
|
69
|
+
options.onWarning(`No help output from: ${fullCmd} --help`);
|
|
70
|
+
return { name: prefixArgs[prefixArgs.length - 1] || command };
|
|
71
|
+
}
|
|
72
|
+
const parsed = parseHelpOutput(helpText, { name: prefixArgs[prefixArgs.length - 1] || command });
|
|
73
|
+
options.log?.info(` ${fullCmd}: ${parsed.subcommands?.length || 0} subcommands, ${parsed.arguments?.length || 0} options`);
|
|
74
|
+
const currentDepth = prefixArgs.length;
|
|
75
|
+
if (parsed.subcommands && parsed.subcommands.length > 0 && (options.depth === void 0 || currentDepth < options.depth)) {
|
|
76
|
+
const resolvedSubs = [];
|
|
77
|
+
for (const sub of parsed.subcommands) {
|
|
78
|
+
if (options.delay > 0) await sleep(options.delay);
|
|
79
|
+
const resolved = await crawlHelp(command, [...prefixArgs, sub.name], options);
|
|
80
|
+
if (!resolved.description && sub.description) resolved.description = sub.description;
|
|
81
|
+
resolvedSubs.push(resolved);
|
|
82
|
+
}
|
|
83
|
+
parsed.subcommands = resolvedSubs;
|
|
84
|
+
}
|
|
85
|
+
return parsed;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Run `<cmd> --help` or `<cmd> help` and return combined stdout+stderr.
|
|
89
|
+
*/
|
|
90
|
+
async function runHelp(command, args, timeout) {
|
|
91
|
+
let result = await runCommand(command, [...args, "--help"], timeout);
|
|
92
|
+
if (result) return result;
|
|
93
|
+
if (args.length > 0) {
|
|
94
|
+
result = await runCommand(command, ["help", ...args], timeout);
|
|
95
|
+
if (result) return result;
|
|
96
|
+
}
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Run a command and return its combined output, or null on failure.
|
|
101
|
+
*/
|
|
102
|
+
async function runCommand(command, args, timeout) {
|
|
103
|
+
try {
|
|
104
|
+
const { stdout, stderr } = await new Promise((resolve) => {
|
|
105
|
+
execFile(command, args, {
|
|
106
|
+
timeout,
|
|
107
|
+
maxBuffer: 10 * 1024 * 1024
|
|
108
|
+
}, (_error, stdout, stderr) => {
|
|
109
|
+
resolve({
|
|
110
|
+
stdout: (stdout ?? "").trim(),
|
|
111
|
+
stderr: (stderr ?? "").trim()
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
const combined = stdout || stderr;
|
|
116
|
+
if (!combined) return null;
|
|
117
|
+
if (combined.length < 10) return null;
|
|
118
|
+
return combined;
|
|
119
|
+
} catch {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Try to get a shell completion script for a command.
|
|
125
|
+
* Checks both `<cmd> completion <shell>` and well-known file paths.
|
|
126
|
+
*/
|
|
127
|
+
async function getCompletionScript(command, shell, timeout) {
|
|
128
|
+
let result = await runCommand(command, ["completion", shell], timeout);
|
|
129
|
+
if (result) return result;
|
|
130
|
+
result = await runCommand(command, ["completions", shell], timeout);
|
|
131
|
+
if (result) return result;
|
|
132
|
+
const paths = shell === "fish" ? [`/usr/share/fish/vendor_completions.d/${command}.fish`, `/usr/local/share/fish/vendor_completions.d/${command}.fish`] : shell === "bash" ? [
|
|
133
|
+
`/usr/share/bash-completion/completions/${command}`,
|
|
134
|
+
`/usr/local/share/bash-completion/completions/${command}`,
|
|
135
|
+
`/etc/bash_completion.d/${command}`
|
|
136
|
+
] : [`/usr/share/zsh/site-functions/_${command}`, `/usr/local/share/zsh/site-functions/_${command}`];
|
|
137
|
+
for (const path of paths) try {
|
|
138
|
+
return await readFile(path, "utf-8");
|
|
139
|
+
} catch {}
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Detect the best shell for completion parsing by probing the command.
|
|
144
|
+
* Tries `<cmd> completion <shell>` for bash, fish, zsh (in that order).
|
|
145
|
+
* Returns the shell name if successful, or null if no completion command exists.
|
|
146
|
+
*/
|
|
147
|
+
async function detectCompletionShell(command, timeout = 5e3) {
|
|
148
|
+
for (const shell of [
|
|
149
|
+
"bash",
|
|
150
|
+
"fish",
|
|
151
|
+
"zsh"
|
|
152
|
+
]) if (await getCompletionScript(command, shell, timeout)) return shell;
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Resolve 'completion' entries in the sources array by probing for the best available shell.
|
|
157
|
+
* Other sources are passed through unchanged.
|
|
158
|
+
*/
|
|
159
|
+
async function resolveSources(sources, command, timeout, log) {
|
|
160
|
+
if (!sources.includes("completion")) return sources;
|
|
161
|
+
log?.info(`Probing ${command} for completion command...`);
|
|
162
|
+
const shell = await detectCompletionShell(command, timeout);
|
|
163
|
+
return sources.flatMap((s) => {
|
|
164
|
+
if (s !== "completion") return s;
|
|
165
|
+
if (shell) {
|
|
166
|
+
log?.info(` Found ${shell} completion support`);
|
|
167
|
+
return shell;
|
|
168
|
+
}
|
|
169
|
+
log?.info(" No completion command found, skipping");
|
|
170
|
+
return [];
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
function sleep(ms) {
|
|
174
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
175
|
+
}
|
|
176
|
+
//#endregion
|
|
177
|
+
export { detectCompletionShell, discoverCli };
|
|
178
|
+
|
|
179
|
+
//# sourceMappingURL=discovery.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.mjs","names":[],"sources":["../../src/codegen/discovery.ts"],"sourcesContent":["import { execFile } from 'node:child_process';\nimport { readFile } from 'node:fs/promises';\n\nimport { parseBashCompletions } from './parsers/bash.ts';\nimport { parseFishCompletions } from './parsers/fish.ts';\nimport { parseHelpOutput } from './parsers/help.ts';\nimport { mergeCommandMeta } from './parsers/merge.ts';\nimport { parseZshCompletions } from './parsers/zsh.ts';\nimport type { CommandMeta, GeneratorLogger } from './types.ts';\n\nexport type DiscoverySource = 'help' | 'completion' | 'bash' | 'fish' | 'zsh';\n\nexport interface DiscoveryOptions {\n /** The command to discover (e.g. 'gh', 'docker', 'kubectl'). */\n command: string;\n /**\n * Which parsing sources to use. Default: ['help'].\n * Use `'completion'` to auto-detect the best shell completion source\n * by probing `<cmd> completion <shell>` (bash → fish → zsh).\n */\n sources?: DiscoverySource[];\n /** Max subcommand depth. 0 = root only, undefined = unlimited. */\n depth?: number;\n /** Delay in ms between help invocations. Default: 50 */\n delay?: number;\n /** Logger for progress reporting. */\n log?: GeneratorLogger;\n /** Timeout per help invocation in ms. Default: 10000 */\n timeout?: number;\n}\n\nexport interface DiscoveryResult {\n /** The discovered command tree. */\n command: CommandMeta;\n /** Number of help invocations made. */\n invocations: number;\n /** Errors encountered (non-fatal). */\n warnings: string[];\n}\n\n/**\n * Discover CLI structure by running --help recursively and optionally\n * parsing shell completion scripts.\n */\nexport async function discoverCli(options: DiscoveryOptions): Promise<DiscoveryResult> {\n const { command, sources: rawSources = ['help'], depth, delay = 50, log, timeout = 10000 } = options;\n\n // Resolve 'completion' source by probing for the best available shell\n const sources = await resolveSources(rawSources, command, timeout, log);\n\n const warnings: string[] = [];\n let invocations = 0;\n\n const results: CommandMeta[] = [];\n\n // Source 1: --help recursive crawl\n if (sources.includes('help')) {\n log?.info(`Discovering ${command} via --help...`);\n const helpResult = await crawlHelp(command, [], {\n depth,\n delay,\n timeout,\n log,\n onInvocation: () => {\n invocations++;\n },\n onWarning: (msg) => {\n warnings.push(msg);\n },\n });\n results.push(helpResult);\n }\n\n // Source 2: Bash completions\n if (sources.includes('bash')) {\n log?.info(`Parsing bash completions for ${command}...`);\n const bashText = await getCompletionScript(command, 'bash', timeout);\n if (bashText) {\n results.push(parseBashCompletions(bashText));\n } else {\n warnings.push('Could not obtain bash completion script');\n }\n }\n\n // Source 3: Fish completions\n if (sources.includes('fish')) {\n log?.info(`Parsing fish completions for ${command}...`);\n const fishText = await getCompletionScript(command, 'fish', timeout);\n if (fishText) {\n results.push(parseFishCompletions(fishText));\n } else {\n warnings.push('Could not obtain fish completion script');\n }\n }\n\n // Source 4: Zsh completions\n if (sources.includes('zsh')) {\n log?.info(`Parsing zsh completions for ${command}...`);\n const zshText = await getCompletionScript(command, 'zsh', timeout);\n if (zshText) {\n results.push(parseZshCompletions(zshText));\n } else {\n warnings.push('Could not obtain zsh completion script');\n }\n }\n\n const merged = results.length > 0 ? mergeCommandMeta(...results) : { name: command };\n\n // Ensure the root has the correct name\n if (!merged.name) merged.name = command;\n\n return { command: merged, invocations, warnings };\n}\n\ninterface CrawlOptions {\n depth?: number;\n delay: number;\n timeout: number;\n log?: GeneratorLogger;\n onInvocation: () => void;\n onWarning: (msg: string) => void;\n}\n\n/**\n * Breadth-first crawl of --help output.\n */\nasync function crawlHelp(command: string, prefixArgs: string[], options: CrawlOptions): Promise<CommandMeta> {\n const fullCmd = [command, ...prefixArgs].join(' ');\n\n options.onInvocation();\n const helpText = await runHelp(command, prefixArgs, options.timeout);\n\n if (!helpText) {\n options.onWarning(`No help output from: ${fullCmd} --help`);\n return { name: prefixArgs[prefixArgs.length - 1] || command };\n }\n\n const name = prefixArgs[prefixArgs.length - 1] || command;\n const parsed = parseHelpOutput(helpText, { name });\n\n options.log?.info(` ${fullCmd}: ${parsed.subcommands?.length || 0} subcommands, ${parsed.arguments?.length || 0} options`);\n\n // Recurse into subcommands breadth-first\n const currentDepth = prefixArgs.length;\n if (parsed.subcommands && parsed.subcommands.length > 0 && (options.depth === undefined || currentDepth < options.depth)) {\n const resolvedSubs: CommandMeta[] = [];\n\n for (const sub of parsed.subcommands) {\n if (options.delay > 0) {\n await sleep(options.delay);\n }\n const resolved = await crawlHelp(command, [...prefixArgs, sub.name], options);\n // Preserve description from parent's subcommand list if child didn't have one\n if (!resolved.description && sub.description) {\n resolved.description = sub.description;\n }\n resolvedSubs.push(resolved);\n }\n\n parsed.subcommands = resolvedSubs;\n }\n\n return parsed;\n}\n\n/**\n * Run `<cmd> --help` or `<cmd> help` and return combined stdout+stderr.\n */\nasync function runHelp(command: string, args: string[], timeout: number): Promise<string | null> {\n // Try --help first\n let result = await runCommand(command, [...args, '--help'], timeout);\n if (result) return result;\n\n // Some CLIs use `help <cmd>` instead\n if (args.length > 0) {\n result = await runCommand(command, ['help', ...args], timeout);\n if (result) return result;\n }\n\n return null;\n}\n\n/**\n * Run a command and return its combined output, or null on failure.\n */\nasync function runCommand(command: string, args: string[], timeout: number): Promise<string | null> {\n try {\n const { stdout, stderr } = await new Promise<{ stdout: string; stderr: string }>((resolve) => {\n execFile(command, args, { timeout, maxBuffer: 10 * 1024 * 1024 }, (_error, stdout, stderr) => {\n // Resolve even on non-zero exit — many CLIs exit non-zero on --help\n resolve({ stdout: (stdout ?? '').trim(), stderr: (stderr ?? '').trim() });\n });\n });\n\n // Some CLIs output help to stderr, some exit non-zero on --help\n const combined = stdout || stderr;\n if (!combined) return null;\n\n // Basic sanity check: help text usually has some structure\n if (combined.length < 10) return null;\n\n return combined;\n } catch {\n return null;\n }\n}\n\n/**\n * Try to get a shell completion script for a command.\n * Checks both `<cmd> completion <shell>` and well-known file paths.\n */\nasync function getCompletionScript(command: string, shell: 'bash' | 'fish' | 'zsh', timeout: number): Promise<string | null> {\n // Try `<cmd> completion <shell>`\n const completionArgs = ['completion', shell];\n let result = await runCommand(command, completionArgs, timeout);\n if (result) return result;\n\n // Try `<cmd> completions <shell>`\n result = await runCommand(command, ['completions', shell], timeout);\n if (result) return result;\n\n // Try reading from well-known paths\n const paths =\n shell === 'fish'\n ? [`/usr/share/fish/vendor_completions.d/${command}.fish`, `/usr/local/share/fish/vendor_completions.d/${command}.fish`]\n : shell === 'bash'\n ? [\n `/usr/share/bash-completion/completions/${command}`,\n `/usr/local/share/bash-completion/completions/${command}`,\n `/etc/bash_completion.d/${command}`,\n ]\n : [`/usr/share/zsh/site-functions/_${command}`, `/usr/local/share/zsh/site-functions/_${command}`];\n\n for (const path of paths) {\n try {\n return await readFile(path, 'utf-8');\n } catch {}\n }\n\n return null;\n}\n\n/**\n * Detect the best shell for completion parsing by probing the command.\n * Tries `<cmd> completion <shell>` for bash, fish, zsh (in that order).\n * Returns the shell name if successful, or null if no completion command exists.\n */\nexport async function detectCompletionShell(command: string, timeout = 5000): Promise<'bash' | 'fish' | 'zsh' | null> {\n for (const shell of ['bash', 'fish', 'zsh'] as const) {\n const result = await getCompletionScript(command, shell, timeout);\n if (result) return shell;\n }\n return null;\n}\n\n/**\n * Resolve 'completion' entries in the sources array by probing for the best available shell.\n * Other sources are passed through unchanged.\n */\nasync function resolveSources(\n sources: DiscoverySource[],\n command: string,\n timeout: number,\n log?: GeneratorLogger,\n): Promise<DiscoverySource[]> {\n if (!sources.includes('completion')) return sources;\n\n log?.info(`Probing ${command} for completion command...`);\n const shell = await detectCompletionShell(command, timeout);\n\n return sources.flatMap((s) => {\n if (s !== 'completion') return s;\n if (shell) {\n log?.info(` Found ${shell} completion support`);\n return shell;\n }\n log?.info(' No completion command found, skipping');\n return [];\n });\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { FileEmitter, FileEmitterOptions } from "./types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/codegen/file-emitter.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Create a FileEmitter for writing multiple generated files to disk.
|
|
6
|
+
*/
|
|
7
|
+
declare function createFileEmitter(options: FileEmitterOptions): FileEmitter;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { createFileEmitter };
|
|
10
|
+
//# sourceMappingURL=file-emitter.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-emitter.d.mts","names":[],"sources":["../../src/codegen/file-emitter.ts"],"mappings":";;;;;AAsEA;iBAAgB,iBAAA,CAAkB,OAAA,EAAS,kBAAA,GAAqB,WAAW"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join, resolve } from "node:path";
|
|
3
|
+
//#region src/codegen/file-emitter.ts
|
|
4
|
+
var FileEmitterImpl = class {
|
|
5
|
+
files = [];
|
|
6
|
+
options;
|
|
7
|
+
constructor(options) {
|
|
8
|
+
this.options = options;
|
|
9
|
+
}
|
|
10
|
+
addFile(path, content) {
|
|
11
|
+
const text = typeof content === "string" ? content : content.text;
|
|
12
|
+
const fullContent = this.options.header ? `${this.options.header}\n\n${text}` : text;
|
|
13
|
+
this.files.push({
|
|
14
|
+
path,
|
|
15
|
+
content: fullContent
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
async emit() {
|
|
19
|
+
const result = {
|
|
20
|
+
written: [],
|
|
21
|
+
skipped: [],
|
|
22
|
+
errors: []
|
|
23
|
+
};
|
|
24
|
+
const outDir = resolve(this.options.outDir);
|
|
25
|
+
for (const file of this.files) {
|
|
26
|
+
const fullPath = join(outDir, file.path);
|
|
27
|
+
try {
|
|
28
|
+
if (existsSync(fullPath) && !this.options.overwrite) {
|
|
29
|
+
result.skipped.push(file.path);
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
if (this.options.dryRun) {
|
|
33
|
+
result.written.push(file.path);
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
mkdirSync(dirname(fullPath), { recursive: true });
|
|
37
|
+
writeFileSync(fullPath, file.content, "utf-8");
|
|
38
|
+
result.written.push(file.path);
|
|
39
|
+
} catch (err) {
|
|
40
|
+
result.errors.push({
|
|
41
|
+
file: file.path,
|
|
42
|
+
error: err instanceof Error ? err : new Error(String(err))
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return result;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Create a FileEmitter for writing multiple generated files to disk.
|
|
51
|
+
*/
|
|
52
|
+
function createFileEmitter(options) {
|
|
53
|
+
return new FileEmitterImpl(options);
|
|
54
|
+
}
|
|
55
|
+
//#endregion
|
|
56
|
+
export { createFileEmitter };
|
|
57
|
+
|
|
58
|
+
//# sourceMappingURL=file-emitter.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-emitter.mjs","names":[],"sources":["../../src/codegen/file-emitter.ts"],"sourcesContent":["import { existsSync, mkdirSync, writeFileSync } from 'node:fs';\nimport { dirname, join, resolve } from 'node:path';\nimport type { CodeBuildResult, EmitResult, FileEmitter, FileEmitterOptions } from './types.ts';\n\ninterface QueuedFile {\n path: string;\n content: string;\n}\n\nclass FileEmitterImpl implements FileEmitter {\n private files: QueuedFile[] = [];\n private options: FileEmitterOptions;\n\n constructor(options: FileEmitterOptions) {\n this.options = options;\n }\n\n addFile(path: string, content: string | CodeBuildResult): void {\n const text = typeof content === 'string' ? content : content.text;\n const fullContent = this.options.header ? `${this.options.header}\\n\\n${text}` : text;\n\n this.files.push({ path, content: fullContent });\n }\n\n async emit(): Promise<EmitResult> {\n const result: EmitResult = {\n written: [],\n skipped: [],\n errors: [],\n };\n\n const outDir = resolve(this.options.outDir);\n\n for (const file of this.files) {\n const fullPath = join(outDir, file.path);\n\n try {\n // Check if file already exists\n if (existsSync(fullPath) && !this.options.overwrite) {\n result.skipped.push(file.path);\n continue;\n }\n\n if (this.options.dryRun) {\n result.written.push(file.path);\n continue;\n }\n\n // Ensure directory exists\n const dir = dirname(fullPath);\n mkdirSync(dir, { recursive: true });\n\n // Write the file\n writeFileSync(fullPath, file.content, 'utf-8');\n result.written.push(file.path);\n } catch (err) {\n result.errors.push({\n file: file.path,\n error: err instanceof Error ? err : new Error(String(err)),\n });\n }\n }\n\n return result;\n }\n}\n\n/**\n * Create a FileEmitter for writing multiple generated files to disk.\n */\nexport function createFileEmitter(options: FileEmitterOptions): FileEmitter {\n return new FileEmitterImpl(options);\n}\n"],"mappings":";;;AASA,IAAM,kBAAN,MAA6C;CAC3C,QAA8B,CAAC;CAC/B;CAEA,YAAY,SAA6B;EACvC,KAAK,UAAU;CACjB;CAEA,QAAQ,MAAc,SAAyC;EAC7D,MAAM,OAAO,OAAO,YAAY,WAAW,UAAU,QAAQ;EAC7D,MAAM,cAAc,KAAK,QAAQ,SAAS,GAAG,KAAK,QAAQ,OAAO,MAAM,SAAS;EAEhF,KAAK,MAAM,KAAK;GAAE;GAAM,SAAS;EAAY,CAAC;CAChD;CAEA,MAAM,OAA4B;EAChC,MAAM,SAAqB;GACzB,SAAS,CAAC;GACV,SAAS,CAAC;GACV,QAAQ,CAAC;EACX;EAEA,MAAM,SAAS,QAAQ,KAAK,QAAQ,MAAM;EAE1C,KAAK,MAAM,QAAQ,KAAK,OAAO;GAC7B,MAAM,WAAW,KAAK,QAAQ,KAAK,IAAI;GAEvC,IAAI;IAEF,IAAI,WAAW,QAAQ,KAAK,CAAC,KAAK,QAAQ,WAAW;KACnD,OAAO,QAAQ,KAAK,KAAK,IAAI;KAC7B;IACF;IAEA,IAAI,KAAK,QAAQ,QAAQ;KACvB,OAAO,QAAQ,KAAK,KAAK,IAAI;KAC7B;IACF;IAIA,UADY,QAAQ,QACR,GAAG,EAAE,WAAW,KAAK,CAAC;IAGlC,cAAc,UAAU,KAAK,SAAS,OAAO;IAC7C,OAAO,QAAQ,KAAK,KAAK,IAAI;GAC/B,SAAS,KAAK;IACZ,OAAO,OAAO,KAAK;KACjB,MAAM,KAAK;KACX,OAAO,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;IAC3D,CAAC;GACH;EACF;EAEA,OAAO;CACT;AACF;;;;AAKA,SAAgB,kBAAkB,SAA0C;CAC1E,OAAO,IAAI,gBAAgB,OAAO;AACpC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { CodeBuilder, GeneratorContext } from "../types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/codegen/generators/barrel-file.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Generate an index.ts barrel file that re-exports all given files.
|
|
6
|
+
*/
|
|
7
|
+
declare function generateBarrelFile(files: string[], ctx: GeneratorContext): CodeBuilder;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { generateBarrelFile };
|
|
10
|
+
//# sourceMappingURL=barrel-file.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"barrel-file.d.mts","names":[],"sources":["../../../src/codegen/generators/barrel-file.ts"],"mappings":";;;;;AAKA;iBAAgB,kBAAA,CAAmB,KAAA,YAAiB,GAAA,EAAK,gBAAA,GAAmB,WAAW"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
//#region src/codegen/generators/barrel-file.ts
|
|
2
|
+
/**
|
|
3
|
+
* Generate an index.ts barrel file that re-exports all given files.
|
|
4
|
+
*/
|
|
5
|
+
function generateBarrelFile(files, ctx) {
|
|
6
|
+
const code = ctx.createCodeBuilder();
|
|
7
|
+
for (const file of files) {
|
|
8
|
+
const importPath = file.startsWith("./") ? file : `./${file}`;
|
|
9
|
+
code.line(`export * from '${importPath}'`);
|
|
10
|
+
}
|
|
11
|
+
return code;
|
|
12
|
+
}
|
|
13
|
+
//#endregion
|
|
14
|
+
export { generateBarrelFile };
|
|
15
|
+
|
|
16
|
+
//# sourceMappingURL=barrel-file.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"barrel-file.mjs","names":[],"sources":["../../../src/codegen/generators/barrel-file.ts"],"sourcesContent":["import type { CodeBuilder, GeneratorContext } from '../types.ts';\n\n/**\n * Generate an index.ts barrel file that re-exports all given files.\n */\nexport function generateBarrelFile(files: string[], ctx: GeneratorContext): CodeBuilder {\n const code = ctx.createCodeBuilder();\n\n for (const file of files) {\n // Strip .ts extension for the import path and ensure relative path\n const importPath = file.startsWith('./') ? file : `./${file}`;\n code.line(`export * from '${importPath}'`);\n }\n\n return code;\n}\n"],"mappings":";;;;AAKA,SAAgB,mBAAmB,OAAiB,KAAoC;CACtF,MAAM,OAAO,IAAI,kBAAkB;CAEnC,KAAK,MAAM,QAAQ,OAAO;EAExB,MAAM,aAAa,KAAK,WAAW,IAAI,IAAI,OAAO,KAAK;EACvD,KAAK,KAAK,kBAAkB,WAAW,EAAE;CAC3C;CAEA,OAAO;AACT"}
|