padrone 1.5.0 → 1.7.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 +44 -0
- package/README.md +15 -11
- package/dist/{args-D5PNDyNu.mjs → args-Cnq0nwSM.mjs} +91 -41
- package/dist/args-Cnq0nwSM.mjs.map +1 -0
- package/dist/codegen/index.mjs +4 -4
- package/dist/codegen/index.mjs.map +1 -1
- package/dist/commands-B_gufyR9.mjs +514 -0
- package/dist/commands-B_gufyR9.mjs.map +1 -0
- package/dist/{completion.mjs → completion-BEuflbDO.mjs} +12 -82
- package/dist/completion-BEuflbDO.mjs.map +1 -0
- package/dist/docs/index.d.mts +4 -4
- package/dist/docs/index.d.mts.map +1 -1
- package/dist/docs/index.mjs +10 -12
- package/dist/docs/index.mjs.map +1 -1
- package/dist/{errors-BiVrBgi6.mjs → errors-DA4KzK1M.mjs} +26 -3
- package/dist/errors-DA4KzK1M.mjs.map +1 -0
- package/dist/{formatter-DtHzbP22.d.mts → formatter-DrvhDMrq.d.mts} +3 -3
- package/dist/formatter-DrvhDMrq.d.mts.map +1 -0
- package/dist/{help-bbmu9-qd.mjs → help-BtxLgrF_.mjs} +190 -43
- package/dist/help-BtxLgrF_.mjs.map +1 -0
- package/dist/{types-Ch8Mk6Qb.d.mts → index-D6-7dz0l.d.mts} +634 -745
- package/dist/index-D6-7dz0l.d.mts.map +1 -0
- package/dist/index.d.mts +869 -36
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +3884 -1699
- package/dist/index.mjs.map +1 -1
- package/dist/{mcp-mLWIdUIu.mjs → mcp-6-Jw4Bpq.mjs} +13 -15
- package/dist/mcp-6-Jw4Bpq.mjs.map +1 -0
- package/dist/{serve-B0u43DK7.mjs → serve-YVTPzBCl.mjs} +12 -14
- package/dist/serve-YVTPzBCl.mjs.map +1 -0
- package/dist/{stream-BcC146Ud.mjs → stream-DC4H8YTx.mjs} +24 -3
- package/dist/stream-DC4H8YTx.mjs.map +1 -0
- package/dist/test.d.mts +5 -8
- package/dist/test.d.mts.map +1 -1
- package/dist/test.mjs +2 -13
- package/dist/test.mjs.map +1 -1
- package/dist/{update-check-CFX1FV3v.mjs → update-check-CZ2VqjnV.mjs} +16 -17
- package/dist/update-check-CZ2VqjnV.mjs.map +1 -0
- package/dist/zod.d.mts +2 -2
- package/dist/zod.d.mts.map +1 -1
- package/dist/zod.mjs +2 -2
- package/dist/zod.mjs.map +1 -1
- package/package.json +15 -12
- package/src/cli/completions.ts +14 -11
- package/src/cli/docs.ts +13 -10
- package/src/cli/doctor.ts +22 -18
- package/src/cli/index.ts +28 -82
- package/src/cli/init.ts +10 -7
- package/src/cli/link.ts +20 -16
- package/src/cli/wrap.ts +14 -11
- package/src/codegen/schema-to-code.ts +2 -2
- package/src/{args.ts → core/args.ts} +32 -225
- package/src/core/commands.ts +373 -0
- package/src/core/create.ts +301 -0
- package/src/core/default-runtime.ts +239 -0
- package/src/{errors.ts → core/errors.ts} +22 -0
- package/src/core/exec.ts +259 -0
- package/src/core/interceptors.ts +302 -0
- package/src/{parse.ts → core/parse.ts} +36 -89
- package/src/core/program-methods.ts +301 -0
- package/src/core/results.ts +229 -0
- package/src/core/runtime.ts +246 -0
- package/src/core/validate.ts +247 -0
- package/src/docs/index.ts +12 -13
- package/src/extension/auto-output.ts +146 -0
- package/src/extension/color.ts +38 -0
- package/src/extension/completion.ts +49 -0
- package/src/extension/config.ts +262 -0
- package/src/extension/env.ts +101 -0
- package/src/extension/help.ts +192 -0
- package/src/extension/index.ts +44 -0
- package/src/extension/ink.ts +93 -0
- package/src/extension/interactive.ts +106 -0
- package/src/extension/logger.ts +262 -0
- package/src/extension/man.ts +51 -0
- package/src/extension/mcp.ts +52 -0
- package/src/extension/progress-renderer.ts +338 -0
- package/src/extension/progress.ts +299 -0
- package/src/extension/repl.ts +94 -0
- package/src/extension/serve.ts +48 -0
- package/src/extension/signal.ts +87 -0
- package/src/extension/stdin.ts +62 -0
- package/src/extension/suggestions.ts +114 -0
- package/src/extension/timing.ts +81 -0
- package/src/extension/tracing.ts +175 -0
- package/src/extension/update-check.ts +77 -0
- package/src/extension/utils.ts +51 -0
- package/src/extension/version.ts +63 -0
- package/src/{completion.ts → feature/completion.ts} +12 -12
- package/src/{interactive.ts → feature/interactive.ts} +4 -4
- package/src/{mcp.ts → feature/mcp.ts} +12 -15
- package/src/{repl-loop.ts → feature/repl-loop.ts} +10 -13
- package/src/{serve.ts → feature/serve.ts} +11 -15
- package/src/feature/test.ts +262 -0
- package/src/{update-check.ts → feature/update-check.ts} +16 -16
- package/src/{wrap.ts → feature/wrap.ts} +10 -8
- package/src/index.ts +115 -30
- package/src/{formatter.ts → output/formatter.ts} +124 -176
- package/src/{help.ts → output/help.ts} +22 -8
- package/src/output/output-indicator.ts +87 -0
- package/src/output/primitives.ts +335 -0
- package/src/output/styling.ts +221 -0
- package/src/{zod.d.ts → schema/zod.d.ts} +1 -1
- package/src/schema/zod.ts +50 -0
- package/src/test.ts +2 -276
- package/src/types/args-meta.ts +151 -0
- package/src/types/builder.ts +718 -0
- package/src/types/command.ts +157 -0
- package/src/types/index.ts +60 -0
- package/src/types/interceptor.ts +296 -0
- package/src/types/preferences.ts +83 -0
- package/src/types/result.ts +71 -0
- package/src/types/schema.ts +19 -0
- package/src/util/dotenv.ts +244 -0
- package/src/{shell-utils.ts → util/shell-utils.ts} +26 -9
- package/src/{stream.ts → util/stream.ts} +27 -1
- package/src/{type-helpers.ts → util/type-helpers.ts} +23 -16
- package/src/{type-utils.ts → util/type-utils.ts} +71 -33
- package/src/util/utils.ts +51 -0
- package/src/zod.ts +1 -50
- package/dist/args-D5PNDyNu.mjs.map +0 -1
- package/dist/chunk-CjcI7cDX.mjs +0 -15
- package/dist/command-utils-B1D-HqCd.mjs +0 -1117
- package/dist/command-utils-B1D-HqCd.mjs.map +0 -1
- package/dist/completion.d.mts +0 -64
- package/dist/completion.d.mts.map +0 -1
- package/dist/completion.mjs.map +0 -1
- package/dist/errors-BiVrBgi6.mjs.map +0 -1
- package/dist/formatter-DtHzbP22.d.mts.map +0 -1
- package/dist/help-bbmu9-qd.mjs.map +0 -1
- package/dist/mcp-mLWIdUIu.mjs.map +0 -1
- package/dist/serve-B0u43DK7.mjs.map +0 -1
- package/dist/stream-BcC146Ud.mjs.map +0 -1
- package/dist/types-Ch8Mk6Qb.d.mts.map +0 -1
- package/dist/update-check-CFX1FV3v.mjs.map +0 -1
- package/src/command-utils.ts +0 -882
- package/src/create.ts +0 -1829
- package/src/runtime.ts +0 -497
- package/src/types.ts +0 -1291
- package/src/utils.ts +0 -140
- /package/src/{colorizer.ts → output/colorizer.ts} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "padrone",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"description": "Create type-safe, interactive CLI apps with Zod schemas",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -89,18 +89,10 @@
|
|
|
89
89
|
},
|
|
90
90
|
"source": "./src/zod.ts"
|
|
91
91
|
},
|
|
92
|
-
"./completion": {
|
|
93
|
-
"padrone@dev": "./src/completion.ts",
|
|
94
|
-
"import": {
|
|
95
|
-
"types": "./dist/completion.d.mts",
|
|
96
|
-
"default": "./dist/completion.mjs"
|
|
97
|
-
},
|
|
98
|
-
"source": "./src/completion.ts"
|
|
99
|
-
},
|
|
100
92
|
"./package.json": "./package.json"
|
|
101
93
|
},
|
|
102
94
|
"scripts": {
|
|
103
|
-
"build": "tsdown src/index.ts src/test.ts src/zod.ts src/codegen/index.ts src/docs/index.ts
|
|
95
|
+
"build": "tsdown src/index.ts src/test.ts src/zod.ts src/codegen/index.ts src/docs/index.ts --dts --sourcemap",
|
|
104
96
|
"start": "bun --conditions=padrone@dev src/cli/index.ts",
|
|
105
97
|
"dev": "bun --conditions=padrone@dev --watch src/cli/index.ts",
|
|
106
98
|
"test": "bun test --conditions=padrone@dev",
|
|
@@ -113,18 +105,29 @@
|
|
|
113
105
|
"enquirer": "^2.4.1"
|
|
114
106
|
},
|
|
115
107
|
"devDependencies": {
|
|
116
|
-
"
|
|
117
|
-
"
|
|
108
|
+
"@types/react": "^19.2.14",
|
|
109
|
+
"ai": "^6.0.141",
|
|
110
|
+
"ink": "^6.8.0",
|
|
111
|
+
"react": "^19.2.4",
|
|
112
|
+
"tsdown": "^0.21.6",
|
|
118
113
|
"zod": "^4.3.6"
|
|
119
114
|
},
|
|
120
115
|
"peerDependencies": {
|
|
121
116
|
"ai": "5 || 6",
|
|
117
|
+
"ink": "^6.0.0",
|
|
118
|
+
"react": ">=18.0.0",
|
|
122
119
|
"zod": "^3.25.0 || ^4.0.0"
|
|
123
120
|
},
|
|
124
121
|
"peerDependenciesMeta": {
|
|
125
122
|
"ai": {
|
|
126
123
|
"optional": true
|
|
127
124
|
},
|
|
125
|
+
"ink": {
|
|
126
|
+
"optional": true
|
|
127
|
+
},
|
|
128
|
+
"react": {
|
|
129
|
+
"optional": true
|
|
130
|
+
},
|
|
128
131
|
"zod": {
|
|
129
132
|
"optional": true
|
|
130
133
|
}
|
package/src/cli/completions.ts
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { detectShell, getCompletionInstallInstructions,
|
|
3
|
-
import type { PadroneActionContext } from '../types.ts';
|
|
1
|
+
import * as z from 'zod/v4';
|
|
2
|
+
import { detectShell, getCompletionInstallInstructions, setupCompletions } from '../feature/completion.ts';
|
|
3
|
+
import type { PadroneActionContext } from '../types/index.ts';
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
appPath
|
|
7
|
-
for
|
|
8
|
-
setup
|
|
9
|
-
}
|
|
5
|
+
export const completionsSchema = z.object({
|
|
6
|
+
appPath: z.string().optional().describe('Path or name of the CLI program (defaults to padrone)'),
|
|
7
|
+
for: z.enum(['bash', 'zsh', 'fish', 'powershell']).optional().describe('Target shell (auto-detected if omitted)'),
|
|
8
|
+
setup: z.boolean().optional().default(false).describe('Write completions to shell config file'),
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
type CompletionsArgs = z.infer<typeof completionsSchema>;
|
|
10
12
|
|
|
11
|
-
export function runCompletions(args: CompletionsArgs, _ctx: PadroneActionContext) {
|
|
13
|
+
export async function runCompletions(args: CompletionsArgs, _ctx: PadroneActionContext) {
|
|
14
|
+
const { basename } = await import('node:path');
|
|
12
15
|
const programName = args.appPath ? basename(args.appPath).replace(/\.[cm]?[jt]sx?$/, '') : 'padrone';
|
|
13
|
-
const shell = args.for ?? detectShell();
|
|
16
|
+
const shell = args.for ?? (await detectShell());
|
|
14
17
|
|
|
15
18
|
if (!shell) {
|
|
16
19
|
console.error('Could not detect shell. Use --for to specify one: bash, zsh, fish, powershell');
|
|
@@ -18,7 +21,7 @@ export function runCompletions(args: CompletionsArgs, _ctx: PadroneActionContext
|
|
|
18
21
|
}
|
|
19
22
|
|
|
20
23
|
if (args.setup) {
|
|
21
|
-
const result = setupCompletions(programName, shell);
|
|
24
|
+
const result = await setupCompletions(programName, shell);
|
|
22
25
|
const verb = result.updated ? 'Updated' : 'Added';
|
|
23
26
|
console.log(`${verb} ${programName} completions in ${result.file}`);
|
|
24
27
|
return;
|
package/src/cli/docs.ts
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { resolve } from 'node:path';
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
2
|
+
import * as z from 'zod/v4';
|
|
3
|
+
import { isPadroneProgram } from '../core/commands.ts';
|
|
4
|
+
import { generateDocs } from '../docs/index.ts';
|
|
5
|
+
import type { PadroneActionContext } from '../types/index.ts';
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
entry: string
|
|
8
|
-
output
|
|
9
|
-
format
|
|
10
|
-
includeHidden
|
|
11
|
-
dryRun
|
|
12
|
-
}
|
|
7
|
+
export const docsSchema = z.object({
|
|
8
|
+
entry: z.string().describe('Entry file that exports a Padrone program'),
|
|
9
|
+
output: z.string().optional().default('./docs/cli').describe('Output directory'),
|
|
10
|
+
format: z.enum(['markdown', 'html', 'man', 'json']).optional().default('markdown').describe('Output format'),
|
|
11
|
+
includeHidden: z.boolean().optional().default(false).describe('Include hidden commands and options'),
|
|
12
|
+
dryRun: z.boolean().optional().default(false).describe('Print what would be generated without writing'),
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
type DocsArgs = z.infer<typeof docsSchema>;
|
|
13
16
|
|
|
14
17
|
export async function runDocs(args: DocsArgs, _ctx: PadroneActionContext) {
|
|
15
18
|
const entryPath = resolve(args.entry);
|
package/src/cli/doctor.ts
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { resolve } from 'node:path';
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
2
|
+
import * as z from 'zod/v4';
|
|
3
|
+
import { getJsonSchema } from '../core/args.ts';
|
|
4
|
+
import { getCommand, isPadroneProgram } from '../core/commands.ts';
|
|
5
|
+
import type { AnyPadroneCommand, PadroneActionContext } from '../types/index.ts';
|
|
5
6
|
import { detectEntry } from './link.ts';
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
entry
|
|
9
|
-
}
|
|
8
|
+
export const doctorSchema = z.object({
|
|
9
|
+
entry: z.string().optional().describe('Entry file that exports a Padrone program (auto-detected from package.json if omitted)'),
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
type DoctorArgs = z.infer<typeof doctorSchema>;
|
|
10
13
|
|
|
11
14
|
type Severity = 'error' | 'warning';
|
|
12
15
|
|
|
@@ -85,7 +88,7 @@ function collectDiagnostics(cmd: AnyPadroneCommand, diagnostics: Diagnostic[]) {
|
|
|
85
88
|
checkCommandsWithoutActions(allCommands, diagnostics);
|
|
86
89
|
checkSchemasWithoutDescriptions(allCommands, diagnostics);
|
|
87
90
|
checkConflictingPositionals(allCommands, diagnostics);
|
|
88
|
-
|
|
91
|
+
checkUnusedInterceptors(allCommands, diagnostics);
|
|
89
92
|
checkDuplicateOptionFlagsAndAliases(allCommands, diagnostics);
|
|
90
93
|
checkUnreachableCommands(allCommands, diagnostics);
|
|
91
94
|
checkMissingCommandDescriptions(allCommands, diagnostics);
|
|
@@ -107,10 +110,10 @@ function commandDisplayName(cmd: AnyPadroneCommand): string {
|
|
|
107
110
|
return cmd.path || cmd.name || '<root>';
|
|
108
111
|
}
|
|
109
112
|
|
|
110
|
-
function
|
|
113
|
+
function getCommandJsonSchema(cmd: AnyPadroneCommand): Record<string, any> | null {
|
|
111
114
|
try {
|
|
112
115
|
if (!cmd.argsSchema) return null;
|
|
113
|
-
return cmd.argsSchema
|
|
116
|
+
return getJsonSchema(cmd.argsSchema) as Record<string, any>;
|
|
114
117
|
} catch {
|
|
115
118
|
return null;
|
|
116
119
|
}
|
|
@@ -167,7 +170,7 @@ function checkShadowedOptionNames(commands: AnyPadroneCommand[], diagnostics: Di
|
|
|
167
170
|
}
|
|
168
171
|
|
|
169
172
|
// Check option names in schema
|
|
170
|
-
const jsonSchema =
|
|
173
|
+
const jsonSchema = getCommandJsonSchema(cmd);
|
|
171
174
|
if (!jsonSchema?.properties) continue;
|
|
172
175
|
|
|
173
176
|
for (const propName of Object.keys(jsonSchema.properties)) {
|
|
@@ -240,7 +243,7 @@ function checkCommandsWithoutActions(commands: AnyPadroneCommand[], diagnostics:
|
|
|
240
243
|
*/
|
|
241
244
|
function checkSchemasWithoutDescriptions(commands: AnyPadroneCommand[], diagnostics: Diagnostic[]) {
|
|
242
245
|
for (const cmd of commands) {
|
|
243
|
-
const jsonSchema =
|
|
246
|
+
const jsonSchema = getCommandJsonSchema(cmd);
|
|
244
247
|
if (!jsonSchema?.properties) continue;
|
|
245
248
|
|
|
246
249
|
for (const [propName, propSchema] of Object.entries(jsonSchema.properties as Record<string, any>)) {
|
|
@@ -295,7 +298,7 @@ function checkConflictingPositionals(commands: AnyPadroneCommand[], diagnostics:
|
|
|
295
298
|
}
|
|
296
299
|
|
|
297
300
|
// Check for positional names that don't exist in schema
|
|
298
|
-
const jsonSchema =
|
|
301
|
+
const jsonSchema = getCommandJsonSchema(cmd);
|
|
299
302
|
if (jsonSchema?.properties) {
|
|
300
303
|
for (const p of positional) {
|
|
301
304
|
const name = (p as string).replace(/^\.\.\./, '');
|
|
@@ -312,21 +315,22 @@ function checkConflictingPositionals(commands: AnyPadroneCommand[], diagnostics:
|
|
|
312
315
|
}
|
|
313
316
|
|
|
314
317
|
/**
|
|
315
|
-
* Check for
|
|
318
|
+
* Check for interceptors that don't define any phase handlers.
|
|
316
319
|
*/
|
|
317
|
-
function
|
|
320
|
+
function checkUnusedInterceptors(commands: AnyPadroneCommand[], diagnostics: Diagnostic[]) {
|
|
318
321
|
const phases = ['start', 'parse', 'validate', 'execute', 'error', 'shutdown'] as const;
|
|
319
322
|
|
|
320
323
|
for (const cmd of commands) {
|
|
321
|
-
if (!cmd.
|
|
324
|
+
if (!cmd.interceptors) continue;
|
|
322
325
|
|
|
323
|
-
for (const
|
|
324
|
-
const
|
|
326
|
+
for (const interceptor of cmd.interceptors) {
|
|
327
|
+
const phases_obj = interceptor.factory();
|
|
328
|
+
const hasHandler = phases.some((phase) => typeof (phases_obj as any)[phase] === 'function');
|
|
325
329
|
if (!hasHandler) {
|
|
326
330
|
diagnostics.push({
|
|
327
331
|
severity: 'warning',
|
|
328
332
|
command: commandDisplayName(cmd),
|
|
329
|
-
message: `
|
|
333
|
+
message: `Interceptor "${interceptor.meta.name}" has no phase handlers.`,
|
|
330
334
|
});
|
|
331
335
|
}
|
|
332
336
|
}
|
package/src/cli/index.ts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { createPadrone } from 'padrone';
|
|
2
2
|
import pkg from 'padrone/package.json' with { type: 'json' };
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { runWrap } from './wrap.ts';
|
|
3
|
+
import { completionsSchema, runCompletions } from './completions.ts';
|
|
4
|
+
import { docsSchema, runDocs } from './docs.ts';
|
|
5
|
+
import { doctorSchema, runDoctor } from './doctor.ts';
|
|
6
|
+
import { initSchema, runInit } from './init.ts';
|
|
7
|
+
import { linkSchema, runLink, runUnlink, unlinkSchema } from './link.ts';
|
|
8
|
+
import { runWrap, wrapSchema } from './wrap.ts';
|
|
10
9
|
|
|
11
10
|
const PadroneCLI = createPadrone('padrone')
|
|
12
11
|
.configure({
|
|
@@ -19,17 +18,9 @@ const PadroneCLI = createPadrone('padrone')
|
|
|
19
18
|
.configure({
|
|
20
19
|
description: 'Scaffold a new Padrone CLI project',
|
|
21
20
|
})
|
|
22
|
-
.arguments(
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
description: z.string().optional().describe('Project description'),
|
|
26
|
-
version: z.string().optional().default('0.1.0').describe('Initial version'),
|
|
27
|
-
dir: z.string().optional().describe('Target directory (defaults to current directory)'),
|
|
28
|
-
}),
|
|
29
|
-
{
|
|
30
|
-
positional: ['dir'],
|
|
31
|
-
},
|
|
32
|
-
)
|
|
21
|
+
.arguments(initSchema, {
|
|
22
|
+
positional: ['dir'],
|
|
23
|
+
})
|
|
33
24
|
.async()
|
|
34
25
|
.action(runInit),
|
|
35
26
|
)
|
|
@@ -38,18 +29,9 @@ const PadroneCLI = createPadrone('padrone')
|
|
|
38
29
|
.configure({
|
|
39
30
|
description: 'Generate documentation for a Padrone CLI program',
|
|
40
31
|
})
|
|
41
|
-
.arguments(
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
output: z.string().optional().default('./docs/cli').describe('Output directory'),
|
|
45
|
-
format: z.enum(['markdown', 'html', 'man', 'json']).optional().default('markdown').describe('Output format'),
|
|
46
|
-
includeHidden: z.boolean().optional().default(false).describe('Include hidden commands and options'),
|
|
47
|
-
dryRun: z.boolean().optional().default(false).describe('Print what would be generated without writing'),
|
|
48
|
-
}),
|
|
49
|
-
{
|
|
50
|
-
positional: ['entry'],
|
|
51
|
-
},
|
|
52
|
-
)
|
|
32
|
+
.arguments(docsSchema, {
|
|
33
|
+
positional: ['entry'],
|
|
34
|
+
})
|
|
53
35
|
.async()
|
|
54
36
|
.action(runDocs),
|
|
55
37
|
)
|
|
@@ -58,14 +40,9 @@ const PadroneCLI = createPadrone('padrone')
|
|
|
58
40
|
.configure({
|
|
59
41
|
description: 'Lint and validate a Padrone CLI program definition',
|
|
60
42
|
})
|
|
61
|
-
.arguments(
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}),
|
|
65
|
-
{
|
|
66
|
-
positional: ['entry'],
|
|
67
|
-
},
|
|
68
|
-
)
|
|
43
|
+
.arguments(doctorSchema, {
|
|
44
|
+
positional: ['entry'],
|
|
45
|
+
})
|
|
69
46
|
.async()
|
|
70
47
|
.action(runDoctor),
|
|
71
48
|
)
|
|
@@ -74,16 +51,9 @@ const PadroneCLI = createPadrone('padrone')
|
|
|
74
51
|
.configure({
|
|
75
52
|
description: 'Show shell completion install instructions for a Padrone CLI program',
|
|
76
53
|
})
|
|
77
|
-
.arguments(
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
for: z.enum(['bash', 'zsh', 'fish', 'powershell']).optional().describe('Target shell (auto-detected if omitted)'),
|
|
81
|
-
setup: z.boolean().optional().default(false).describe('Write completions to shell config file'),
|
|
82
|
-
}),
|
|
83
|
-
{
|
|
84
|
-
positional: ['appPath'],
|
|
85
|
-
},
|
|
86
|
-
)
|
|
54
|
+
.arguments(completionsSchema, {
|
|
55
|
+
positional: ['appPath'],
|
|
56
|
+
})
|
|
87
57
|
.action(runCompletions),
|
|
88
58
|
)
|
|
89
59
|
.command('link', (cmd) =>
|
|
@@ -91,17 +61,9 @@ const PadroneCLI = createPadrone('padrone')
|
|
|
91
61
|
.configure({
|
|
92
62
|
description: 'Link a Padrone CLI program for global use during development',
|
|
93
63
|
})
|
|
94
|
-
.arguments(
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
name: z.string().optional().describe('Command name (auto-detected from package.json)'),
|
|
98
|
-
list: z.boolean().optional().default(false).describe('List all linked programs'),
|
|
99
|
-
setup: z.boolean().optional().default(false).describe('Add ~/.padrone/bin to PATH in shell config'),
|
|
100
|
-
}),
|
|
101
|
-
{
|
|
102
|
-
positional: ['entry'],
|
|
103
|
-
},
|
|
104
|
-
)
|
|
64
|
+
.arguments(linkSchema, {
|
|
65
|
+
positional: ['entry'],
|
|
66
|
+
})
|
|
105
67
|
.async()
|
|
106
68
|
.action(runLink),
|
|
107
69
|
)
|
|
@@ -110,14 +72,9 @@ const PadroneCLI = createPadrone('padrone')
|
|
|
110
72
|
.configure({
|
|
111
73
|
description: 'Remove a previously linked Padrone CLI program',
|
|
112
74
|
})
|
|
113
|
-
.arguments(
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}),
|
|
117
|
-
{
|
|
118
|
-
positional: ['name'],
|
|
119
|
-
},
|
|
120
|
-
)
|
|
75
|
+
.arguments(unlinkSchema, {
|
|
76
|
+
positional: ['name'],
|
|
77
|
+
})
|
|
121
78
|
.async()
|
|
122
79
|
.action(runUnlink),
|
|
123
80
|
)
|
|
@@ -126,21 +83,10 @@ const PadroneCLI = createPadrone('padrone')
|
|
|
126
83
|
.configure({
|
|
127
84
|
description: 'Generate a Padrone wrapper for an existing CLI tool',
|
|
128
85
|
})
|
|
129
|
-
.arguments(
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
output: z.string().optional().describe('Output directory (default: ./src/<command>)'),
|
|
134
|
-
depth: z.number().default(4).optional().describe('Max subcommand depth'),
|
|
135
|
-
dryRun: z.boolean().optional().default(false).describe('Print what would be generated without writing'),
|
|
136
|
-
overwrite: z.boolean().optional().default(false).describe('Overwrite existing files'),
|
|
137
|
-
yes: z.boolean().optional().default(false).describe('Skip confirmation prompt'),
|
|
138
|
-
}),
|
|
139
|
-
{
|
|
140
|
-
positional: ['command'],
|
|
141
|
-
fields: { yes: { alias: 'y' } },
|
|
142
|
-
},
|
|
143
|
-
)
|
|
86
|
+
.arguments(wrapSchema, {
|
|
87
|
+
positional: ['command'],
|
|
88
|
+
fields: { yes: { alias: 'y' } },
|
|
89
|
+
})
|
|
144
90
|
.async()
|
|
145
91
|
.action(runWrap),
|
|
146
92
|
);
|
package/src/cli/init.ts
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs';
|
|
2
2
|
import { basename, resolve } from 'node:path';
|
|
3
3
|
import { createFileEmitter, template } from 'padrone/codegen';
|
|
4
|
-
import
|
|
4
|
+
import * as z from 'zod/v4';
|
|
5
|
+
import type { PadroneActionContext } from '../types/index.ts';
|
|
5
6
|
|
|
6
|
-
|
|
7
|
-
name
|
|
8
|
-
description
|
|
9
|
-
version
|
|
10
|
-
dir
|
|
11
|
-
}
|
|
7
|
+
export const initSchema = z.object({
|
|
8
|
+
name: z.string().optional().describe('Project name (defaults to directory name)'),
|
|
9
|
+
description: z.string().optional().describe('Project description'),
|
|
10
|
+
version: z.string().optional().default('0.1.0').describe('Initial version'),
|
|
11
|
+
dir: z.string().optional().describe('Target directory (defaults to current directory)'),
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
type InitArgs = z.infer<typeof initSchema>;
|
|
12
15
|
|
|
13
16
|
const packageJsonTemplate = template(`{
|
|
14
17
|
"name": "{{name}}",
|
package/src/cli/link.ts
CHANGED
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
import { chmodSync, existsSync, mkdirSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { homedir } from 'node:os';
|
|
3
3
|
import { basename, dirname, resolve } from 'node:path';
|
|
4
|
-
import
|
|
5
|
-
import type { PadroneActionContext } from '../types.ts';
|
|
6
|
-
|
|
7
|
-
interface LinkArgs {
|
|
8
|
-
entry?: string;
|
|
9
|
-
name?: string;
|
|
10
|
-
list?: boolean;
|
|
11
|
-
setup?: boolean;
|
|
12
|
-
}
|
|
4
|
+
import * as z from 'zod/v4';
|
|
5
|
+
import type { PadroneActionContext } from '../types/index.ts';
|
|
6
|
+
import { detectShell, getRcFile, type ShellType, writeToRcFile } from '../util/shell-utils.ts';
|
|
13
7
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
8
|
+
export const linkSchema = z.object({
|
|
9
|
+
entry: z.string().optional().describe('Entry file (auto-detected from package.json bin field)'),
|
|
10
|
+
name: z.string().optional().describe('Command name (auto-detected from package.json)'),
|
|
11
|
+
list: z.boolean().optional().default(false).describe('List all linked programs'),
|
|
12
|
+
setup: z.boolean().optional().default(false).describe('Add ~/.padrone/bin to PATH in shell config'),
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export const unlinkSchema = z.object({
|
|
16
|
+
name: z.string().optional().describe('Program name to unlink (auto-detected from current directory)'),
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
type LinkArgs = z.infer<typeof linkSchema>;
|
|
20
|
+
type UnlinkArgs = z.infer<typeof unlinkSchema>;
|
|
17
21
|
|
|
18
22
|
interface LinkEntry {
|
|
19
23
|
name: string;
|
|
@@ -143,8 +147,8 @@ function buildPathSnippet(shell: ShellType, binDir: string): string {
|
|
|
143
147
|
}
|
|
144
148
|
}
|
|
145
149
|
|
|
146
|
-
function setupPath(shell: ShellType): { file: string; updated: boolean } {
|
|
147
|
-
const rcFile = getRcFile(shell);
|
|
150
|
+
async function setupPath(shell: ShellType): Promise<{ file: string; updated: boolean }> {
|
|
151
|
+
const rcFile = await getRcFile(shell);
|
|
148
152
|
if (!rcFile) {
|
|
149
153
|
throw new Error(`Could not determine config file for ${shell}.`);
|
|
150
154
|
}
|
|
@@ -268,13 +272,13 @@ export async function runLink(args: LinkArgs, ctx: PadroneActionContext) {
|
|
|
268
272
|
|
|
269
273
|
if (!isInPath(BIN_DIR)) {
|
|
270
274
|
if (args.setup) {
|
|
271
|
-
const shell = detectShell();
|
|
275
|
+
const shell = await detectShell();
|
|
272
276
|
if (!shell) {
|
|
273
277
|
error('Could not detect shell. Add the PATH manually:');
|
|
274
278
|
error(` export PATH="${BIN_DIR}:$PATH"`);
|
|
275
279
|
return;
|
|
276
280
|
}
|
|
277
|
-
const result = setupPath(shell);
|
|
281
|
+
const result = await setupPath(shell);
|
|
278
282
|
const verb = result.updated ? 'Updated' : 'Added';
|
|
279
283
|
output(`${verb} PATH in ${result.file}`);
|
|
280
284
|
output('Restart your shell or run:');
|
package/src/cli/wrap.ts
CHANGED
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
import { resolve } from 'node:path';
|
|
2
2
|
import { createCodeBuilder, createFileEmitter, generateCommandTree } from 'padrone/codegen';
|
|
3
|
+
import * as z from 'zod/v4';
|
|
3
4
|
import type { DiscoverySource } from '../codegen/discovery.ts';
|
|
4
5
|
import { discoverCli } from '../codegen/discovery.ts';
|
|
5
6
|
import { template } from '../codegen/template.ts';
|
|
6
7
|
import type { GeneratorContext } from '../codegen/types.ts';
|
|
7
|
-
import type { PadroneActionContext } from '../types.ts';
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
command: string
|
|
11
|
-
source
|
|
12
|
-
output
|
|
13
|
-
depth
|
|
14
|
-
dryRun
|
|
15
|
-
overwrite
|
|
16
|
-
yes
|
|
17
|
-
}
|
|
8
|
+
import type { PadroneActionContext } from '../types/index.ts';
|
|
9
|
+
|
|
10
|
+
export const wrapSchema = z.object({
|
|
11
|
+
command: z.string().describe('CLI command to wrap (e.g. gh, docker, kubectl)'),
|
|
12
|
+
source: z.enum(['help', 'fish', 'zsh']).optional().default('help').describe('Parsing source (default: help)'),
|
|
13
|
+
output: z.string().optional().describe('Output directory (default: ./src/<command>)'),
|
|
14
|
+
depth: z.number().default(4).optional().describe('Max subcommand depth'),
|
|
15
|
+
dryRun: z.boolean().optional().default(false).describe('Print what would be generated without writing'),
|
|
16
|
+
overwrite: z.boolean().optional().default(false).describe('Overwrite existing files'),
|
|
17
|
+
yes: z.boolean().optional().default(false).describe('Skip confirmation prompt'),
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
type WrapArgs = z.infer<typeof wrapSchema>;
|
|
18
21
|
|
|
19
22
|
export async function runWrap(args: WrapArgs, ctx: PadroneActionContext) {
|
|
20
23
|
const { output, error } = ctx.runtime;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { StandardSchemaV1 } from '@standard-schema/spec';
|
|
2
|
-
import {
|
|
2
|
+
import { getJsonSchema } from '../core/args.ts';
|
|
3
3
|
import type { FieldMeta } from './types.ts';
|
|
4
4
|
|
|
5
5
|
interface SchemaToCodeResult {
|
|
@@ -58,7 +58,7 @@ function jsonSchemaPropertyToZod(prop: Record<string, any>, required: boolean, a
|
|
|
58
58
|
*/
|
|
59
59
|
export function schemaToCode(schema: StandardSchemaV1): SchemaToCodeResult {
|
|
60
60
|
try {
|
|
61
|
-
const jsonSchema = (schema as any)
|
|
61
|
+
const jsonSchema = getJsonSchema(schema as any) as Record<string, any>;
|
|
62
62
|
return jsonSchemaToCode(jsonSchema);
|
|
63
63
|
} catch {
|
|
64
64
|
return { code: 'z.unknown()', imports: ['z'] };
|