@politty/zod 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +561 -0
  3. package/bin/cli.mjs +3 -0
  4. package/dist/arg-registry-YaWTVu_x.d.ts +1025 -0
  5. package/dist/augment.d.ts +15 -0
  6. package/dist/augment.js +1 -0
  7. package/dist/cli-main-Dn88vIyn.js +84 -0
  8. package/dist/cli-run-eibUcgys.js +7 -0
  9. package/dist/cli.d.ts +1 -0
  10. package/dist/cli.js +16 -0
  11. package/dist/command-k-4yAz4J.js +42 -0
  12. package/dist/compile-cache-Ct41pWGL.js +100 -0
  13. package/dist/compile-cache.d.ts +78 -0
  14. package/dist/compile-cache.js +3 -0
  15. package/dist/completion-gtWX3mwP.js +5608 -0
  16. package/dist/completion.d.ts +242 -0
  17. package/dist/completion.js +4 -0
  18. package/dist/docs.d.ts +770 -0
  19. package/dist/docs.js +3044 -0
  20. package/dist/field-meta-DMy5BcRr.js +146 -0
  21. package/dist/index-CvhsecfS.d.ts +455 -0
  22. package/dist/index.d.ts +799 -0
  23. package/dist/index.js +17 -0
  24. package/dist/log-collector-CoUkLVJB.js +114 -0
  25. package/dist/logger-i_bb-Jhc.js +133 -0
  26. package/dist/prompt-CEIZ-7H1.js +171 -0
  27. package/dist/prompt-clack.d.ts +16 -0
  28. package/dist/prompt-clack.js +32 -0
  29. package/dist/prompt-inquirer.d.ts +16 -0
  30. package/dist/prompt-inquirer.js +47 -0
  31. package/dist/prompt.d.ts +106 -0
  32. package/dist/prompt.js +4 -0
  33. package/dist/register-Bk0K83W2.js +439 -0
  34. package/dist/runner-D72I7wvK.js +2956 -0
  35. package/dist/runner-FvUwOHyE.js +3 -0
  36. package/dist/schema-extractor-DMSozq40.js +250 -0
  37. package/dist/skill.d.ts +608 -0
  38. package/dist/skill.js +1832 -0
  39. package/dist/src-KzC0g5CS.js +191 -0
  40. package/dist/subcommand-router-Cskpofdk.js +134 -0
  41. package/package.json +103 -0
@@ -0,0 +1,191 @@
1
+ import "./completion-gtWX3mwP.js";
2
+ import "./runner-D72I7wvK.js";
3
+ import "./logger-i_bb-Jhc.js";
4
+ import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
5
+ import { basename, dirname, extname, isAbsolute, join, relative, resolve } from "node:path";
6
+ import { fileURLToPath } from "node:url";
7
+
8
+ //#region ../core/src/compile-cache-shim.ts
9
+ /**
10
+ * Generator for compile-cache bin shims.
11
+ *
12
+ * Emits the minimal entry file described in docs/recipes.md ("Faster
13
+ * Startup"): a shim that enables the Node.js on-disk compile cache via
14
+ * `politty/compile-cache` and then loads the real CLI with a dynamic
15
+ * import. Meant to be wired into a `postbuild` or `prepack` script via
16
+ * `politty generate-shim` so the shim never has to live in source.
17
+ */
18
+ /**
19
+ * Marker identifying files this generator wrote (overwrite guard). Must be
20
+ * shim-specific: other politty artifacts (e.g. completion scripts) also say
21
+ * "Generated by politty", and those must never be treated as overwritable.
22
+ */
23
+ const SHIM_MARKER = "Generated by politty: compile-cache bin shim";
24
+ /** Entry candidates tried, in order, when `entry` is omitted. */
25
+ const DEFAULT_ENTRY_CANDIDATES = [
26
+ "./cli.js",
27
+ "./cli.mjs",
28
+ "./index.js",
29
+ "./index.mjs"
30
+ ];
31
+ /**
32
+ * Read the nearest `package.json`, walking up from `startDir` to the
33
+ * filesystem root. A malformed file is a real error and propagates.
34
+ */
35
+ function readNearestPackageJson(startDir) {
36
+ let dir = resolve(startDir);
37
+ for (;;) {
38
+ const candidate = join(dir, "package.json");
39
+ if (existsSync(candidate)) return {
40
+ pkg: JSON.parse(readFileSync(candidate, "utf8")),
41
+ dir
42
+ };
43
+ const parent = dirname(dir);
44
+ if (parent === dir) return void 0;
45
+ dir = parent;
46
+ }
47
+ }
48
+ /**
49
+ * `bin` entries as `[name, path]` pairs: the object form's entries in
50
+ * declaration order, or the string form as a single pair named after the
51
+ * package (npm's own convention for `"bin": "path"`).
52
+ */
53
+ function binEntries(pkg) {
54
+ if (!pkg) return [];
55
+ if (typeof pkg.bin === "string" && pkg.bin) {
56
+ const name = defaultProgramName(pkg);
57
+ return name ? [[name, pkg.bin]] : [];
58
+ }
59
+ if (typeof pkg.bin === "object" && pkg.bin !== null) return Object.entries(pkg.bin).filter((pair) => typeof pair[1] === "string" && pair[1] !== "");
60
+ return [];
61
+ }
62
+ /**
63
+ * Derive the fallback program name from a package.json: the first `bin`
64
+ * command name when present (that is the name users type in their shell),
65
+ * else the package name without its scope.
66
+ */
67
+ function defaultProgramName(pkg) {
68
+ if (!pkg) return void 0;
69
+ if (typeof pkg.bin === "object" && pkg.bin !== null) {
70
+ const [first] = Object.keys(pkg.bin);
71
+ if (first) return first;
72
+ }
73
+ if (typeof pkg.name === "string" && pkg.name) {
74
+ const name = pkg.name;
75
+ return name.startsWith("@") ? name.split("/")[1] ?? name : name;
76
+ }
77
+ }
78
+ /**
79
+ * Pick the default entry: the first {@link DEFAULT_ENTRY_CANDIDATES} that
80
+ * exists next to the shim (never the shim itself).
81
+ */
82
+ function defaultEntry(outputPath) {
83
+ const dir = dirname(outputPath);
84
+ const self = basename(outputPath);
85
+ for (const candidate of DEFAULT_ENTRY_CANDIDATES) {
86
+ if (basename(candidate) === self) continue;
87
+ if (existsSync(join(dir, candidate))) return candidate;
88
+ }
89
+ }
90
+ function shimContent(program, entry) {
91
+ return [
92
+ "#!/usr/bin/env node",
93
+ "",
94
+ `// ${SHIM_MARKER}.`,
95
+ "// Enables the Node.js on-disk compile cache (V8 code cache) before the",
96
+ "// CLI module graph is compiled, so warm starts skip recompilation",
97
+ "// (Node >= 22.8.0; silent no-op otherwise).",
98
+ "try {",
99
+ " const { enableCompileCache } = await import(\"politty/compile-cache\");",
100
+ ` enableCompileCache(${JSON.stringify(program)});`,
101
+ "} catch {",
102
+ " // politty is not resolvable from here (e.g. a fully bundled CLI) —",
103
+ " // start without the compile cache rather than failing the CLI.",
104
+ "}",
105
+ `await import(${JSON.stringify(entry)});`,
106
+ ""
107
+ ].join("\n");
108
+ }
109
+ function toArray(value) {
110
+ if (value === void 0) return [];
111
+ return Array.isArray(value) ? value : [value];
112
+ }
113
+ /**
114
+ * Generate executable compile-cache bin shims.
115
+ *
116
+ * With no explicit paths, one shim is generated per `bin` entry of the
117
+ * nearest `package.json`, each importing a conventional built module next
118
+ * to it — so a bare `politty generate-shim` in a `postbuild` script is
119
+ * usually enough. Explicit `entry` values are paired in order with the
120
+ * `bin` entries (or with explicit `out` values of the same count).
121
+ *
122
+ * The generated files are ESM (they use top-level `await import`), so `.js`
123
+ * output requires `"type": "module"` in the package; use a `.mjs` extension
124
+ * otherwise. Refuses to overwrite an existing file it did not generate, so
125
+ * a `bin` path still pointing at the real CLI entry fails loudly instead of
126
+ * clobbering the build output.
127
+ */
128
+ function generateCompileCacheShim(options = {}) {
129
+ const cwd = options.cwd ?? process.cwd();
130
+ const found = readNearestPackageJson(cwd);
131
+ const pkg = found?.pkg;
132
+ const entries = toArray(options.entry);
133
+ const outs = toArray(options.out);
134
+ const bins = binEntries(pkg);
135
+ let outputPaths;
136
+ if (outs.length > 0) {
137
+ if (entries.length > 0 && entries.length !== outs.length) throw new Error(`--entry count (${entries.length}) does not match --out count (${outs.length}); pass one --out per --entry or omit --out entirely.`);
138
+ outputPaths = outs.map((out) => isAbsolute(out) ? out : resolve(cwd, out));
139
+ } else {
140
+ if (bins.length === 0 || found === void 0) throw new Error("Cannot derive the output path: no bin entry in package.json. Pass --out explicitly.");
141
+ if (entries.length > 0 && entries.length !== bins.length) throw new Error(`--entry count (${entries.length}) does not match the package's bin entries (${bins.length}); pass one --entry per bin (in declaration order) or matching --out paths.`);
142
+ outputPaths = bins.map(([, path]) => resolve(found.dir, path));
143
+ }
144
+ if (new Set(outputPaths).size !== outputPaths.length) throw new Error("Duplicate output paths; each shim needs a distinct output file. Check the --out values (or the bin paths in package.json when --out is omitted).");
145
+ const binNameByPath = /* @__PURE__ */ new Map();
146
+ if (found) for (const [name, path] of bins) binNameByPath.set(resolve(found.dir, path), name);
147
+ const warnings = [];
148
+ const plans = outputPaths.map((outputPath, index) => {
149
+ const matchedBinName = binNameByPath.get(outputPath);
150
+ const program = options.program ?? matchedBinName ?? defaultProgramName(pkg);
151
+ if (!program) throw new Error("Cannot derive a program name: no bin or name in package.json. Pass --program explicitly.");
152
+ if (options.program === void 0 && matchedBinName === void 0 && outs.length > 0) warnings.push(`Warning: ${formatShimPath(outputPath, cwd)} does not match any bin path in package.json, so its cache directory uses the program name ${JSON.stringify(program)}. Pass --program to override.`);
153
+ if (outputPath.endsWith(".cjs")) throw new Error("The generated shim is an ES module and cannot be written to a .cjs file. Use a .mjs (or .js in a \"type\": \"module\" package) output path.");
154
+ if (extname(outputPath) === "") throw new Error("The generated shim is an ES module and cannot be written to an extensionless file (it would not load on every supported Node.js version). Use a .mjs (or .js in a \"type\": \"module\" package) output path.");
155
+ if (outputPath.endsWith(".js") && pkg?.type !== "module") throw new Error(pkg === void 0 ? "The generated shim is an ES module, and no package.json was found to confirm .js files are treated as ESM. Write it to a .mjs file instead (e.g. --out dist/bin.mjs)." : "The generated shim is an ES module, but the package is not \"type\": \"module\". Write it to a .mjs file instead (e.g. --out dist/bin.mjs).");
156
+ const entry = entries[index] ?? defaultEntry(outputPath);
157
+ if (entry === void 0) throw new Error(`Cannot derive an entry: none of ${DEFAULT_ENTRY_CANDIDATES.join(", ")} exist next to ${outputPath}. Pass --entry explicitly.`);
158
+ if (!entry.startsWith("./") && !entry.startsWith("../") && !entry.startsWith("file:")) throw new Error(`Invalid entry ${entry}: pass a specifier relative to the shim file ("./..." or "../...") or a file: URL.`);
159
+ let entryPath;
160
+ if (entry.startsWith("file:")) try {
161
+ entryPath = fileURLToPath(entry);
162
+ } catch {
163
+ entryPath = void 0;
164
+ }
165
+ else entryPath = resolve(dirname(outputPath), entry);
166
+ if (entryPath === outputPath) throw new Error(`The shim at ${outputPath} would import itself (entry ${entry}). Point bin at a separate shim path (e.g. dist/bin.js) or pass a different --entry.`);
167
+ if (existsSync(outputPath) && !readFileSync(outputPath, "utf8").includes(SHIM_MARKER)) throw new Error(`Refusing to overwrite ${outputPath}: it exists and was not generated by politty. If bin currently points at your real CLI entry, point it at a separate shim path (e.g. dist/bin.js) or pass --out explicitly.`);
168
+ return {
169
+ outputPath,
170
+ program,
171
+ entry
172
+ };
173
+ });
174
+ for (const warning of warnings) console.warn(warning);
175
+ for (const { outputPath, program, entry } of plans) {
176
+ mkdirSync(dirname(outputPath), { recursive: true });
177
+ writeFileSync(outputPath, shimContent(program, entry));
178
+ chmodSync(outputPath, 493);
179
+ }
180
+ return plans;
181
+ }
182
+ /**
183
+ * Format a generated path for CLI output: relative to `cwd` when inside it.
184
+ */
185
+ function formatShimPath(outputPath, cwd) {
186
+ const rel = relative(cwd, outputPath);
187
+ return rel && !rel.startsWith("..") ? rel : outputPath;
188
+ }
189
+
190
+ //#endregion
191
+ export { generateCompileCacheShim as n, formatShimPath as t };
@@ -0,0 +1,134 @@
1
+ //#region ../core/src/lazy.ts
2
+ /**
3
+ * Marker property for LazyCommand identification
4
+ */
5
+ const LAZY_BRAND = "__politty_lazy__";
6
+ /**
7
+ * Type guard: check if a value is a LazyCommand
8
+ */
9
+ function isLazyCommand(value) {
10
+ return typeof value === "object" && value !== null && LAZY_BRAND in value && value[LAZY_BRAND] === true;
11
+ }
12
+ /**
13
+ * Create a lazily-loaded subcommand with synchronous metadata.
14
+ *
15
+ * The `meta` command provides names, descriptions, and args schema
16
+ * for static analysis (completion scripts, help text) without loading
17
+ * the full command module.
18
+ *
19
+ * The `load` function is called only at execution time.
20
+ *
21
+ * @example
22
+ * ```ts
23
+ * import { lazy, defineCommand } from "politty";
24
+ *
25
+ * const cli = defineCommand({
26
+ * name: "mycli",
27
+ * subCommands: {
28
+ * deploy: lazy(
29
+ * defineCommand({
30
+ * name: "deploy",
31
+ * description: "Deploy the application",
32
+ * args: z.object({ env: arg(z.string()) }),
33
+ * }),
34
+ * () => import("./deploy.js").then((m) => m.deployCommand),
35
+ * ),
36
+ * },
37
+ * });
38
+ * ```
39
+ */
40
+ function lazy(meta, load) {
41
+ return {
42
+ [LAZY_BRAND]: true,
43
+ meta,
44
+ load
45
+ };
46
+ }
47
+ /**
48
+ * Resolve synchronous metadata from a SubCommandValue.
49
+ * Returns null for legacy async subcommands whose metadata is unavailable.
50
+ */
51
+ function resolveSubCommandMeta(subCmd) {
52
+ if (isLazyCommand(subCmd)) return subCmd.meta;
53
+ if (typeof subCmd === "function") return null;
54
+ return subCmd;
55
+ }
56
+
57
+ //#endregion
58
+ //#region ../core/src/executor/subcommand-router.ts
59
+ /**
60
+ * Resolve a lazy-loaded command (sync or async)
61
+ *
62
+ * @param cmd - The command or lazy loader function
63
+ * @returns The resolved command
64
+ */
65
+ async function resolveLazyCommand(cmd) {
66
+ if (isLazyCommand(cmd)) return await cmd.load();
67
+ if (typeof cmd === "function") return await cmd();
68
+ return cmd;
69
+ }
70
+ /**
71
+ * Resolve a subcommand by name (including alias lookup) and return both the
72
+ * resolved command and the canonical name if accessed via alias.
73
+ *
74
+ * This avoids a redundant alias scan when the caller needs both pieces of info.
75
+ */
76
+ async function resolveSubcommandWithAlias(command, name) {
77
+ if (!command.subCommands) return;
78
+ const subCmd = Object.hasOwn(command.subCommands, name) ? command.subCommands[name] : void 0;
79
+ if (subCmd) return {
80
+ command: await resolveLazyCommand(subCmd),
81
+ aliasFor: void 0
82
+ };
83
+ const canonicalName = resolveSubCommandAlias(command, name);
84
+ if (canonicalName) return {
85
+ command: await resolveLazyCommand(command.subCommands[canonicalName]),
86
+ aliasFor: canonicalName
87
+ };
88
+ }
89
+ /**
90
+ * Resolve an alias to the canonical subcommand name.
91
+ * Returns the canonical name if the given name is an alias, or undefined.
92
+ *
93
+ * Note: Aliases are only recognized for eagerly-defined commands and
94
+ * `lazy()` commands (which carry synchronous metadata). Pure async
95
+ * subcommand functions do not expose metadata synchronously, so their
96
+ * aliases cannot be resolved without loading the module.
97
+ *
98
+ * @param command - The parent command
99
+ * @param alias - The alias to look up
100
+ * @returns The canonical subcommand name, or undefined
101
+ */
102
+ function resolveSubCommandAlias(command, alias) {
103
+ if (!command.subCommands) return void 0;
104
+ for (const [name, subCmd] of Object.entries(command.subCommands)) if (resolveSubCommandMeta(subCmd)?.aliases?.includes(alias)) return name;
105
+ }
106
+ /**
107
+ * Build a set of all recognized subcommand names including aliases.
108
+ *
109
+ * @param command - The parent command
110
+ * @returns Set of all names (canonical + aliases)
111
+ */
112
+ function listSubCommandNamesWithAliases(command) {
113
+ const names = /* @__PURE__ */ new Set();
114
+ if (!command.subCommands) return names;
115
+ for (const [name, subCmd] of Object.entries(command.subCommands)) {
116
+ names.add(name);
117
+ const meta = resolveSubCommandMeta(subCmd);
118
+ if (meta?.aliases) for (const alias of meta.aliases) names.add(alias);
119
+ }
120
+ return names;
121
+ }
122
+ /**
123
+ * List all subcommand names for a command
124
+ *
125
+ * @param command - The parent command
126
+ * @returns Array of subcommand names
127
+ */
128
+ function listSubCommands(command) {
129
+ if (!command.subCommands) return [];
130
+ return Object.keys(command.subCommands);
131
+ }
132
+
133
+ //#endregion
134
+ export { resolveSubcommandWithAlias as a, resolveSubCommandMeta as c, resolveSubCommandAlias as i, listSubCommands as n, isLazyCommand as o, resolveLazyCommand as r, lazy as s, listSubCommandNamesWithAliases as t };
package/package.json ADDED
@@ -0,0 +1,103 @@
1
+ {
2
+ "name": "@politty/zod",
3
+ "version": "0.0.0",
4
+ "description": "A lightweight CLI framework inspired by citty with zod v4 registry integration for type-safe metadata management",
5
+ "keywords": [
6
+ "argument-parser",
7
+ "cli",
8
+ "command-line",
9
+ "type-safe",
10
+ "typescript",
11
+ "zod"
12
+ ],
13
+ "license": "MIT",
14
+ "author": "toiroakr",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "https://github.com/toiroakr/politty.git",
18
+ "directory": "packages/zod"
19
+ },
20
+ "bin": {
21
+ "politty": "./bin/cli.mjs"
22
+ },
23
+ "files": [
24
+ "bin/cli.mjs",
25
+ "dist/**/*.js",
26
+ "dist/**/*.d.ts"
27
+ ],
28
+ "type": "module",
29
+ "main": "./dist/index.js",
30
+ "types": "./dist/index.d.ts",
31
+ "exports": {
32
+ ".": {
33
+ "types": "./dist/index.d.ts",
34
+ "default": "./dist/index.js"
35
+ },
36
+ "./augment": {
37
+ "types": "./dist/augment.d.ts",
38
+ "default": "./dist/augment.js"
39
+ },
40
+ "./compile-cache": {
41
+ "types": "./dist/compile-cache.d.ts",
42
+ "default": "./dist/compile-cache.js"
43
+ },
44
+ "./docs": {
45
+ "types": "./dist/docs.d.ts",
46
+ "default": "./dist/docs.js"
47
+ },
48
+ "./completion": {
49
+ "types": "./dist/completion.d.ts",
50
+ "default": "./dist/completion.js"
51
+ },
52
+ "./skill": {
53
+ "types": "./dist/skill.d.ts",
54
+ "default": "./dist/skill.js"
55
+ },
56
+ "./prompt": {
57
+ "types": "./dist/prompt.d.ts",
58
+ "default": "./dist/prompt.js"
59
+ },
60
+ "./prompt/clack": {
61
+ "types": "./dist/prompt-clack.d.ts",
62
+ "default": "./dist/prompt-clack.js"
63
+ },
64
+ "./prompt/inquirer": {
65
+ "types": "./dist/prompt-inquirer.d.ts",
66
+ "default": "./dist/prompt-inquirer.js"
67
+ },
68
+ "./cli": {
69
+ "types": "./dist/cli.d.ts",
70
+ "default": "./dist/cli.js"
71
+ }
72
+ },
73
+ "dependencies": {
74
+ "yaml": "^2.8.3"
75
+ },
76
+ "devDependencies": {
77
+ "@types/node": "25.9.5",
78
+ "@typescript/native-preview": "7.0.0-dev.20260707.2",
79
+ "tsdown": "0.22.14",
80
+ "typescript": "7.0.2",
81
+ "zod": "4.4.3",
82
+ "@politty/core": "0.1.0"
83
+ },
84
+ "peerDependencies": {
85
+ "@clack/prompts": "^0.10.0 || ^0.11.0 || ^1.0.0",
86
+ "@inquirer/prompts": "^8.3.2",
87
+ "zod": "^4.2.1"
88
+ },
89
+ "peerDependenciesMeta": {
90
+ "@clack/prompts": {
91
+ "optional": true
92
+ },
93
+ "@inquirer/prompts": {
94
+ "optional": true
95
+ }
96
+ },
97
+ "engines": {
98
+ "node": ">=20.12.0 <21.0.0 || >=21.7.0"
99
+ },
100
+ "scripts": {
101
+ "build": "tsdown"
102
+ }
103
+ }