@to-skills/cli 0.2.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024-present Pradeep Mouli
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,36 @@
1
+ # @to-skills/cli
2
+
3
+ > Extract CLI command structure from commander/yargs for AI agent skill generation.
4
+
5
+ Part of the [to-skills](https://github.com/pradeepmouli/to-skills) ecosystem.
6
+
7
+ ## Features
8
+
9
+ - **Commander introspection** — enumerate commands, options, arguments from a Program object
10
+ - **`--help` fallback** — parse standard help text for any CLI framework
11
+ - **Flag-to-property correlation** — merge JSDoc tags from typed options interfaces into CLI metadata
12
+ - **Token-budgeted output** — generated skills fit LLM context windows
13
+
14
+ ## Install
15
+
16
+ ```bash
17
+ pnpm add -D @to-skills/cli
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ ```typescript
23
+ import { extractCliSkill } from '@to-skills/cli';
24
+ import { renderSkill } from '@to-skills/core';
25
+
26
+ const skill = await extractCliSkill({
27
+ program, // commander Program object
28
+ metadata: { name: 'my-tool', keywords: ['build', 'deploy'] }
29
+ });
30
+
31
+ const rendered = renderSkill(skill);
32
+ ```
33
+
34
+ ## License
35
+
36
+ MIT
@@ -0,0 +1,16 @@
1
+ import type { ExtractedConfigSurface } from '@to-skills/core';
2
+ /**
3
+ * Merges JSDoc tag metadata from a typed config interface surface into CLI
4
+ * option metadata extracted from commander/--help output.
5
+ *
6
+ * The CLI surface is treated as authoritative for structural fields (flags,
7
+ * description, required, defaultValue). The config surface contributes rich
8
+ * JSDoc metadata (remarks, useWhen, avoidWhen, pitfalls, category) that the
9
+ * CLI help text does not capture.
10
+ *
11
+ * @param cliSurface - The surface extracted from CLI introspection/help parsing
12
+ * @param configSurface - The surface extracted from a typed config interface (optional)
13
+ * @returns A new ExtractedConfigSurface combining both sources
14
+ */
15
+ export declare function correlateFlags(cliSurface: ExtractedConfigSurface, configSurface: ExtractedConfigSurface | undefined): ExtractedConfigSurface;
16
+ //# sourceMappingURL=correlator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"correlator.d.ts","sourceRoot":"","sources":["../src/correlator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAyB,MAAM,iBAAiB,CAAC;AAErF;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAC5B,UAAU,EAAE,sBAAsB,EAClC,aAAa,EAAE,sBAAsB,GAAG,SAAS,GAChD,sBAAsB,CAqCxB"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Merges JSDoc tag metadata from a typed config interface surface into CLI
3
+ * option metadata extracted from commander/--help output.
4
+ *
5
+ * The CLI surface is treated as authoritative for structural fields (flags,
6
+ * description, required, defaultValue). The config surface contributes rich
7
+ * JSDoc metadata (remarks, useWhen, avoidWhen, pitfalls, category) that the
8
+ * CLI help text does not capture.
9
+ *
10
+ * @param cliSurface - The surface extracted from CLI introspection/help parsing
11
+ * @param configSurface - The surface extracted from a typed config interface (optional)
12
+ * @returns A new ExtractedConfigSurface combining both sources
13
+ */
14
+ export function correlateFlags(cliSurface, configSurface) {
15
+ if (!configSurface)
16
+ return cliSurface;
17
+ // Build lookup: lowercase property name → config option
18
+ const configLookup = new Map();
19
+ for (const opt of configSurface.options) {
20
+ configLookup.set(opt.name.toLowerCase(), opt);
21
+ }
22
+ // Merge each CLI option with matching config property
23
+ const mergedOptions = cliSurface.options.map((cliOpt) => {
24
+ const configOpt = configLookup.get(cliOpt.name.toLowerCase());
25
+ if (!configOpt)
26
+ return cliOpt;
27
+ return {
28
+ // CLI is authoritative for structural/presentation fields
29
+ ...cliOpt,
30
+ // Use config description as fallback when CLI description is empty
31
+ description: cliOpt.description || configOpt.description,
32
+ // Config provides JSDoc-enriched metadata
33
+ remarks: cliOpt.remarks ?? configOpt.remarks,
34
+ useWhen: cliOpt.useWhen ?? configOpt.useWhen,
35
+ avoidWhen: cliOpt.avoidWhen ?? configOpt.avoidWhen,
36
+ pitfalls: cliOpt.pitfalls ?? configOpt.pitfalls,
37
+ category: cliOpt.category ?? configOpt.category,
38
+ };
39
+ });
40
+ // Merge command-level tags from config surface into CLI surface
41
+ return {
42
+ ...cliSurface,
43
+ options: mergedOptions,
44
+ useWhen: cliSurface.useWhen ?? configSurface.useWhen,
45
+ avoidWhen: cliSurface.avoidWhen ?? configSurface.avoidWhen,
46
+ pitfalls: cliSurface.pitfalls ?? configSurface.pitfalls,
47
+ remarks: cliSurface.remarks ?? configSurface.remarks,
48
+ };
49
+ }
50
+ //# sourceMappingURL=correlator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"correlator.js","sourceRoot":"","sources":["../src/correlator.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,cAAc,CAC5B,UAAkC,EAClC,aAAiD;IAEjD,IAAI,CAAC,aAAa;QAAE,OAAO,UAAU,CAAC;IAEtC,wDAAwD;IACxD,MAAM,YAAY,GAAG,IAAI,GAAG,EAAiC,CAAC;IAC9D,KAAK,MAAM,GAAG,IAAI,aAAa,CAAC,OAAO,EAAE,CAAC;QACxC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,GAAG,CAAC,CAAC;IAChD,CAAC;IAED,sDAAsD;IACtD,MAAM,aAAa,GAA4B,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;QAC/E,MAAM,SAAS,GAAG,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;QAC9D,IAAI,CAAC,SAAS;YAAE,OAAO,MAAM,CAAC;QAE9B,OAAO;YACL,0DAA0D;YAC1D,GAAG,MAAM;YACT,mEAAmE;YACnE,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,SAAS,CAAC,WAAW;YACxD,0CAA0C;YAC1C,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,SAAS,CAAC,OAAO;YAC5C,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,SAAS,CAAC,OAAO;YAC5C,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,SAAS,CAAC,SAAS;YAClD,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,SAAS,CAAC,QAAQ;YAC/C,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,SAAS,CAAC,QAAQ;SAChD,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,gEAAgE;IAChE,OAAO;QACL,GAAG,UAAU;QACb,OAAO,EAAE,aAAa;QACtB,OAAO,EAAE,UAAU,CAAC,OAAO,IAAI,aAAa,CAAC,OAAO;QACpD,SAAS,EAAE,UAAU,CAAC,SAAS,IAAI,aAAa,CAAC,SAAS;QAC1D,QAAQ,EAAE,UAAU,CAAC,QAAQ,IAAI,aAAa,CAAC,QAAQ;QACvD,OAAO,EAAE,UAAU,CAAC,OAAO,IAAI,aAAa,CAAC,OAAO;KACrD,CAAC;AACJ,CAAC"}
@@ -0,0 +1,19 @@
1
+ import type { ExtractedSkill, ExtractedConfigSurface } from '@to-skills/core';
2
+ export interface CliExtractionOptions {
3
+ /** Commander program object (preferred) */
4
+ program?: any;
5
+ /** Help text per command (fallback) */
6
+ helpTexts?: Record<string, string>;
7
+ /** Package metadata */
8
+ metadata?: {
9
+ name?: string;
10
+ description?: string;
11
+ keywords?: string[];
12
+ repository?: string;
13
+ author?: string;
14
+ };
15
+ /** Config surfaces from TypeDoc for JSDoc correlation */
16
+ configSurfaces?: ExtractedConfigSurface[];
17
+ }
18
+ export declare function extractCliSkill(options: CliExtractionOptions): Promise<ExtractedSkill>;
19
+ //# sourceMappingURL=extract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract.d.ts","sourceRoot":"","sources":["../src/extract.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAK9E,MAAM,WAAW,oBAAoB;IACnC,2CAA2C;IAC3C,OAAO,CAAC,EAAE,GAAG,CAAC;IACd,uCAAuC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,uBAAuB;IACvB,QAAQ,CAAC,EAAE;QACT,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QACpB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,yDAAyD;IACzD,cAAc,CAAC,EAAE,sBAAsB,EAAE,CAAC;CAC3C;AAED,wBAAsB,eAAe,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,cAAc,CAAC,CAiE5F"}
@@ -0,0 +1,58 @@
1
+ import { introspectCommander } from './introspect-commander.js';
2
+ import { parseHelpOutput } from './help-parser.js';
3
+ import { correlateFlags } from './correlator.js';
4
+ export async function extractCliSkill(options) {
5
+ const { program, helpTexts, metadata = {}, configSurfaces = [] } = options;
6
+ // Phase 1: Extract command structure (introspection or help)
7
+ let cliSurfaces = [];
8
+ if (program !== undefined) {
9
+ cliSurfaces = introspectCommander(program);
10
+ }
11
+ else if (helpTexts !== undefined) {
12
+ cliSurfaces = Object.entries(helpTexts).map(([commandName, text]) => parseHelpOutput(text, commandName));
13
+ }
14
+ // Phase 2: Correlate with typed interfaces
15
+ // Build lookup from config surfaces by their name (case-insensitive)
16
+ const configSurfaceLookup = new Map();
17
+ for (const surface of configSurfaces) {
18
+ configSurfaceLookup.set(surface.name.toLowerCase(), surface);
19
+ }
20
+ // For each CLI surface, find a matching config surface by convention:
21
+ // command "generate" → look for "GenerateOptions" or "generateoptions" (case-insensitive)
22
+ const correlatedCliSurfaces = cliSurfaces.map((cliSurface) => {
23
+ const commandNameLower = cliSurface.name.toLowerCase();
24
+ // Try exact name match first
25
+ let matchingConfig = configSurfaceLookup.get(commandNameLower);
26
+ // If not found, try "<commandName>options" convention
27
+ if (!matchingConfig) {
28
+ matchingConfig = configSurfaceLookup.get(`${commandNameLower}options`);
29
+ }
30
+ // Phase 3: Call correlateFlags to merge JSDoc
31
+ return correlateFlags(cliSurface, matchingConfig);
32
+ });
33
+ // Collect non-CLI config surfaces (sourceType === 'config') from configSurfaces
34
+ const nonCliConfigSurfaces = configSurfaces.filter((s) => s.sourceType !== 'cli');
35
+ // Build the final configSurfaces array: correlated CLI surfaces + non-CLI config surfaces
36
+ const allConfigSurfaces = [
37
+ ...correlatedCliSurfaces,
38
+ ...nonCliConfigSurfaces
39
+ ];
40
+ // Phase 3: Build ExtractedSkill with empty functions/classes/types/enums/variables
41
+ // but populated configSurfaces
42
+ const skill = {
43
+ name: metadata.name ?? '',
44
+ description: metadata.description ?? '',
45
+ keywords: metadata.keywords,
46
+ repository: metadata.repository,
47
+ author: metadata.author,
48
+ functions: [],
49
+ classes: [],
50
+ types: [],
51
+ enums: [],
52
+ variables: [],
53
+ examples: [],
54
+ ...(allConfigSurfaces.length > 0 ? { configSurfaces: allConfigSurfaces } : {})
55
+ };
56
+ return skill;
57
+ }
58
+ //# sourceMappingURL=extract.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract.js","sourceRoot":"","sources":["../src/extract.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAmBjD,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAA6B;IACjE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,GAAG,EAAE,EAAE,cAAc,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC;IAE3E,6DAA6D;IAC7D,IAAI,WAAW,GAA6B,EAAE,CAAC;IAE/C,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,WAAW,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC;IAC7C,CAAC;SAAM,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QACnC,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,IAAI,CAAC,EAAE,EAAE,CAClE,eAAe,CAAC,IAAI,EAAE,WAAW,CAAC,CACnC,CAAC;IACJ,CAAC;IAED,2CAA2C;IAC3C,qEAAqE;IACrE,MAAM,mBAAmB,GAAG,IAAI,GAAG,EAAkC,CAAC;IACtE,KAAK,MAAM,OAAO,IAAI,cAAc,EAAE,CAAC;QACrC,mBAAmB,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,OAAO,CAAC,CAAC;IAC/D,CAAC;IAED,sEAAsE;IACtE,0FAA0F;IAC1F,MAAM,qBAAqB,GAA6B,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE;QACrF,MAAM,gBAAgB,GAAG,UAAU,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;QAEvD,6BAA6B;QAC7B,IAAI,cAAc,GAAG,mBAAmB,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;QAE/D,sDAAsD;QACtD,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,cAAc,GAAG,mBAAmB,CAAC,GAAG,CAAC,GAAG,gBAAgB,SAAS,CAAC,CAAC;QACzE,CAAC;QAED,8CAA8C;QAC9C,OAAO,cAAc,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,gFAAgF;IAChF,MAAM,oBAAoB,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,KAAK,CAAC,CAAC;IAElF,0FAA0F;IAC1F,MAAM,iBAAiB,GAA6B;QAClD,GAAG,qBAAqB;QACxB,GAAG,oBAAoB;KACxB,CAAC;IAEF,mFAAmF;IACnF,+BAA+B;IAC/B,MAAM,KAAK,GAAmB;QAC5B,IAAI,EAAE,QAAQ,CAAC,IAAI,IAAI,EAAE;QACzB,WAAW,EAAE,QAAQ,CAAC,WAAW,IAAI,EAAE;QACvC,QAAQ,EAAE,QAAQ,CAAC,QAAQ;QAC3B,UAAU,EAAE,QAAQ,CAAC,UAAU;QAC/B,MAAM,EAAE,QAAQ,CAAC,MAAM;QACvB,SAAS,EAAE,EAAE;QACb,OAAO,EAAE,EAAE;QACX,KAAK,EAAE,EAAE;QACT,KAAK,EAAE,EAAE;QACT,SAAS,EAAE,EAAE;QACb,QAAQ,EAAE,EAAE;QACZ,GAAG,CAAC,iBAAiB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,iBAAiB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC/E,CAAC;IAEF,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { ExtractedConfigSurface } from '@to-skills/core';
2
+ /**
3
+ * Parse standard `--help` text output into an {@link ExtractedConfigSurface}.
4
+ *
5
+ * This is the framework-agnostic fallback used when runtime introspection of a
6
+ * commander/yargs program is not available.
7
+ *
8
+ * @param text Raw text emitted by `program --help`
9
+ * @param commandName Canonical name for this surface (e.g. `"generate"`)
10
+ */
11
+ export declare function parseHelpOutput(text: string, commandName: string): ExtractedConfigSurface;
12
+ //# sourceMappingURL=help-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help-parser.d.ts","sourceRoot":"","sources":["../src/help-parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,sBAAsB,EAGvB,MAAM,iBAAiB,CAAC;AAEzB;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,sBAAsB,CAwGzF"}
@@ -0,0 +1,249 @@
1
+ /**
2
+ * Parse standard `--help` text output into an {@link ExtractedConfigSurface}.
3
+ *
4
+ * This is the framework-agnostic fallback used when runtime introspection of a
5
+ * commander/yargs program is not available.
6
+ *
7
+ * @param text Raw text emitted by `program --help`
8
+ * @param commandName Canonical name for this surface (e.g. `"generate"`)
9
+ */
10
+ export function parseHelpOutput(text, commandName) {
11
+ if (!text.trim()) {
12
+ return {
13
+ name: commandName,
14
+ description: '',
15
+ sourceType: 'cli',
16
+ options: [],
17
+ arguments: []
18
+ };
19
+ }
20
+ const lines = text.split('\n');
21
+ let usageString;
22
+ let description = '';
23
+ let inOptionsBlock = false;
24
+ const options = [];
25
+ const args = [];
26
+ // Track whether we have seen the first non-usage, non-blank line for
27
+ // the description. We stop collecting description lines once we hit an
28
+ // options block or another section header.
29
+ let descriptionCandidateIndex = -1;
30
+ for (let i = 0; i < lines.length; i++) {
31
+ const raw = lines[i] ?? '';
32
+ const trimmed = raw.trim();
33
+ // -----------------------------------------------------------------------
34
+ // Usage line
35
+ // -----------------------------------------------------------------------
36
+ if (trimmed.startsWith('Usage:')) {
37
+ usageString = trimmed.slice('Usage:'.length).trim();
38
+ args.push(...parsePositionalArgs(usageString));
39
+ inOptionsBlock = false;
40
+ descriptionCandidateIndex = i + 1; // description may follow
41
+ continue;
42
+ }
43
+ // -----------------------------------------------------------------------
44
+ // Options block header
45
+ // -----------------------------------------------------------------------
46
+ if (/^Options\s*:/i.test(trimmed) || trimmed === 'Options') {
47
+ inOptionsBlock = true;
48
+ continue;
49
+ }
50
+ // -----------------------------------------------------------------------
51
+ // Any other section header (Arguments:, Commands:, Examples:, …) ends
52
+ // the options block and description collection.
53
+ // -----------------------------------------------------------------------
54
+ if (/^[A-Z][A-Za-z ]+:/.test(trimmed) && !trimmed.startsWith('-')) {
55
+ inOptionsBlock = false;
56
+ descriptionCandidateIndex = -1;
57
+ continue;
58
+ }
59
+ // -----------------------------------------------------------------------
60
+ // Description: first non-empty line after Usage that is not a section
61
+ // -----------------------------------------------------------------------
62
+ if (!inOptionsBlock &&
63
+ description === '' &&
64
+ descriptionCandidateIndex >= 0 &&
65
+ i === descriptionCandidateIndex &&
66
+ trimmed !== '' &&
67
+ !trimmed.startsWith('-')) {
68
+ description = trimmed;
69
+ continue;
70
+ }
71
+ // Advance the candidate index over blank lines between Usage and desc
72
+ if (!inOptionsBlock &&
73
+ description === '' &&
74
+ descriptionCandidateIndex >= 0 &&
75
+ i === descriptionCandidateIndex &&
76
+ trimmed === '') {
77
+ descriptionCandidateIndex++;
78
+ continue;
79
+ }
80
+ // -----------------------------------------------------------------------
81
+ // Option line inside Options block
82
+ // -----------------------------------------------------------------------
83
+ if (inOptionsBlock && trimmed.startsWith('-')) {
84
+ const opt = parseOptionLine(raw);
85
+ if (opt) {
86
+ options.push(opt);
87
+ }
88
+ }
89
+ }
90
+ return {
91
+ name: commandName,
92
+ description,
93
+ sourceType: 'cli',
94
+ ...(usageString !== undefined ? { usage: usageString } : {}),
95
+ options,
96
+ arguments: args
97
+ };
98
+ }
99
+ // ---------------------------------------------------------------------------
100
+ // Internal helpers
101
+ // ---------------------------------------------------------------------------
102
+ /**
103
+ * Parse positional arguments from a usage string.
104
+ *
105
+ * Recognises:
106
+ * `<required-arg>` → required, non-variadic
107
+ * `[optional-arg]` → optional, non-variadic
108
+ * `<arg...>` / `<...arg>` / `[arg...]` → variadic variants
109
+ *
110
+ * Flags (`-f` / `--flag`) and meta-tokens like `[options]` / `[command]` are
111
+ * ignored.
112
+ */
113
+ function parsePositionalArgs(usage) {
114
+ const result = [];
115
+ // Match <name> or [name] tokens, capturing the inner text
116
+ const re = /(<([^>]+)>|\[([^\]]+)\])/g;
117
+ let match;
118
+ while ((match = re.exec(usage)) !== null) {
119
+ const full = match[0];
120
+ const inner = (match[2] ?? match[3] ?? '').trim();
121
+ // Skip meta-placeholders that aren't real positional args
122
+ if (/^options?$/i.test(inner) || /^commands?$/i.test(inner)) {
123
+ continue;
124
+ }
125
+ // Skip flag-like tokens (shouldn't appear here, but be defensive)
126
+ if (inner.startsWith('-')) {
127
+ continue;
128
+ }
129
+ const required = full.startsWith('<');
130
+ const variadic = inner.endsWith('...') || inner.startsWith('...');
131
+ const name = inner.replace(/\.{3}/g, '').trim();
132
+ result.push({
133
+ name,
134
+ description: '',
135
+ required,
136
+ variadic
137
+ });
138
+ }
139
+ return result;
140
+ }
141
+ /**
142
+ * Parse a single option line from a `--help` block.
143
+ *
144
+ * Handles formats:
145
+ * `-c, --config <path> Description text (required)`
146
+ * `--dry-run Preview mode (default: false)`
147
+ * ` --verbose Verbose output`
148
+ *
149
+ * Returns `null` if the line should be skipped (e.g. `-h, --help` or
150
+ * `--version`).
151
+ */
152
+ function parseOptionLine(raw) {
153
+ const trimmed = raw.trim();
154
+ // -------------------------------------------------------------------------
155
+ // Extract flags portion vs description portion.
156
+ //
157
+ // Flags appear at the start; description follows after ≥2 spaces (or a tab).
158
+ // We split on the first run of 2+ spaces after the flags/arg portion.
159
+ // -------------------------------------------------------------------------
160
+ // 1. Strip leading whitespace
161
+ // 2. Match the flags+arg group: everything up to 2+ spaces or tab
162
+ const flagsAndRest = trimmed.match(/^(-[^\s].*?)(?:\s{2,}|\t)(.*)$/) ?? null;
163
+ let flagsPart;
164
+ let descPart;
165
+ if (flagsAndRest) {
166
+ flagsPart = (flagsAndRest[1] ?? '').trim();
167
+ descPart = (flagsAndRest[2] ?? '').trim();
168
+ }
169
+ else {
170
+ // No description separator found — the whole trimmed line is the flags
171
+ flagsPart = trimmed;
172
+ descPart = '';
173
+ }
174
+ // -------------------------------------------------------------------------
175
+ // Parse flags: optional short flag, long flag, optional argument
176
+ // -c, --config <path>
177
+ // --dry-run
178
+ // -o, --out <dir>
179
+ // -------------------------------------------------------------------------
180
+ let cliShort;
181
+ let cliFlag;
182
+ let argName; // <arg> after the flag
183
+ // Match short flag
184
+ const shortMatch = flagsPart.match(/^(-[a-zA-Z]),?\s*/);
185
+ if (shortMatch) {
186
+ cliShort = shortMatch[1];
187
+ flagsPart = flagsPart.slice(shortMatch[0].length);
188
+ }
189
+ // Match long flag (with optional argument)
190
+ const longMatch = flagsPart.match(/^(--[a-zA-Z][\w-]*)(?:\s+<([^>]+)>)?/);
191
+ if (!longMatch) {
192
+ // No long flag found — not a valid option line
193
+ return null;
194
+ }
195
+ cliFlag = longMatch[1];
196
+ argName = longMatch[2]; // undefined when flag is boolean
197
+ // -------------------------------------------------------------------------
198
+ // Skip internal / noise flags
199
+ // -------------------------------------------------------------------------
200
+ if (cliFlag === '--help' || cliFlag === '--version') {
201
+ return null;
202
+ }
203
+ if (cliShort === '-h' || cliShort === '-V') {
204
+ return null;
205
+ }
206
+ // -------------------------------------------------------------------------
207
+ // Extract default value from description: (default: value)
208
+ // -------------------------------------------------------------------------
209
+ let defaultValue;
210
+ const defaultMatch = descPart.match(/\(default:\s*([^)]+)\)/i);
211
+ if (defaultMatch) {
212
+ defaultValue = defaultMatch[1]?.trim();
213
+ descPart = descPart.replace(defaultMatch[0], '').trim();
214
+ }
215
+ // -------------------------------------------------------------------------
216
+ // Detect required flag from description: (required)
217
+ // -------------------------------------------------------------------------
218
+ let required = false;
219
+ const requiredMatch = descPart.match(/\(required\)/i);
220
+ if (requiredMatch) {
221
+ required = true;
222
+ descPart = descPart.replace(requiredMatch[0], '').trim();
223
+ }
224
+ // Clean up any trailing punctuation left after stripping annotations
225
+ descPart = descPart.replace(/\s+$/, '');
226
+ // -------------------------------------------------------------------------
227
+ // Infer type: boolean when no <arg>, string otherwise
228
+ // -------------------------------------------------------------------------
229
+ const type = argName ? 'string' : 'boolean';
230
+ // -------------------------------------------------------------------------
231
+ // Derive canonical name from long flag (strip leading --)
232
+ // -------------------------------------------------------------------------
233
+ const name = cliFlag ? cliFlag.replace(/^--/, '') : '';
234
+ const option = {
235
+ name,
236
+ cliFlag,
237
+ type,
238
+ description: descPart,
239
+ required
240
+ };
241
+ if (cliShort !== undefined) {
242
+ option.cliShort = cliShort;
243
+ }
244
+ if (defaultValue !== undefined) {
245
+ option.defaultValue = defaultValue;
246
+ }
247
+ return option;
248
+ }
249
+ //# sourceMappingURL=help-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help-parser.js","sourceRoot":"","sources":["../src/help-parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export { introspectCommander } from './introspect-commander.js';
2
+ export { parseHelpOutput } from './help-parser.js';
3
+ export { correlateFlags } from './correlator.js';
4
+ export { extractCliSkill } from './extract.js';
5
+ export type { CliExtractionOptions } from './extract.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,YAAY,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ // CLI extraction for commander/yargs programs
2
+ export { introspectCommander } from './introspect-commander.js';
3
+ export { parseHelpOutput } from './help-parser.js';
4
+ export { correlateFlags } from './correlator.js';
5
+ export { extractCliSkill } from './extract.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { ExtractedConfigSurface } from '@to-skills/core';
2
+ /**
3
+ * Introspects a commander Program object and extracts all top-level command
4
+ * definitions as ExtractedConfigSurface[].
5
+ *
6
+ * @param program - A commander `Command` instance (typed as `any` to avoid
7
+ * a hard dependency on the commander package at the call site).
8
+ * @returns An array of extracted config surfaces, one per top-level command.
9
+ * Returns an empty array if the program has no subcommands.
10
+ */
11
+ export declare function introspectCommander(program: any): ExtractedConfigSurface[];
12
+ //# sourceMappingURL=introspect-commander.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"introspect-commander.d.ts","sourceRoot":"","sources":["../src/introspect-commander.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,sBAAsB,EAGvB,MAAM,iBAAiB,CAAC;AAwFzB;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,GAAG,GAAG,sBAAsB,EAAE,CAI1E"}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Converts a kebab-case string to camelCase.
3
+ * e.g. "output-dir" → "outputDir"
4
+ */
5
+ function kebabToCamelCase(str) {
6
+ return str.replace(/-([a-z])/g, (_, char) => char.toUpperCase());
7
+ }
8
+ /**
9
+ * Infers the type of a CLI option from its flags string.
10
+ * If the flags contain `<` or `[`, it accepts a value → 'string'.
11
+ * Otherwise it is a boolean toggle.
12
+ */
13
+ function inferType(flags) {
14
+ return flags.includes('<') || flags.includes('[') ? 'string' : 'boolean';
15
+ }
16
+ /**
17
+ * Extracts a single commander Command into an ExtractedConfigSurface.
18
+ */
19
+ function extractCommand(cmd, parentName) {
20
+ const name = cmd.name?.() ?? '';
21
+ const fullName = parentName ? `${parentName} ${name}` : name;
22
+ const options = (cmd.options ?? []).map((opt) => {
23
+ const longFlag = opt.long ?? '';
24
+ const canonicalName = kebabToCamelCase(longFlag.replace(/^--/, ''));
25
+ const result = {
26
+ name: canonicalName,
27
+ cliFlag: longFlag || undefined,
28
+ cliShort: opt.short ?? undefined,
29
+ type: inferType(opt.flags ?? ''),
30
+ description: opt.description ?? '',
31
+ required: !!(opt.required || opt.mandatory)
32
+ };
33
+ if (opt.defaultValue !== undefined) {
34
+ result.defaultValue = String(opt.defaultValue);
35
+ }
36
+ if (opt.envVar) {
37
+ result.envVar = opt.envVar;
38
+ }
39
+ return result;
40
+ });
41
+ const args = (cmd.registeredArguments ?? []).map((arg) => {
42
+ const result = {
43
+ name: arg.name?.() ?? '',
44
+ description: arg.description ?? '',
45
+ required: !!arg.required,
46
+ variadic: !!arg.variadic
47
+ };
48
+ if (arg.defaultValue !== undefined) {
49
+ result.defaultValue = String(arg.defaultValue);
50
+ }
51
+ return result;
52
+ });
53
+ const subcommands = (cmd.commands ?? []).map((sub) => extractCommand(sub, fullName));
54
+ const surface = {
55
+ name,
56
+ description: cmd.description?.() ?? '',
57
+ sourceType: 'cli',
58
+ usage: cmd.usage?.() ?? undefined,
59
+ options
60
+ };
61
+ if (args.length > 0) {
62
+ surface.arguments = args;
63
+ }
64
+ if (subcommands.length > 0) {
65
+ surface.subcommands = subcommands;
66
+ }
67
+ return surface;
68
+ }
69
+ /**
70
+ * Introspects a commander Program object and extracts all top-level command
71
+ * definitions as ExtractedConfigSurface[].
72
+ *
73
+ * @param program - A commander `Command` instance (typed as `any` to avoid
74
+ * a hard dependency on the commander package at the call site).
75
+ * @returns An array of extracted config surfaces, one per top-level command.
76
+ * Returns an empty array if the program has no subcommands.
77
+ */
78
+ export function introspectCommander(program) {
79
+ const commands = program.commands ?? [];
80
+ if (commands.length === 0)
81
+ return [];
82
+ return commands.map((cmd) => extractCommand(cmd, program.name?.() ?? ''));
83
+ }
84
+ //# sourceMappingURL=introspect-commander.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"introspect-commander.js","sourceRoot":"","sources":["../src/introspect-commander.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@to-skills/cli",
3
+ "version": "0.2.1",
4
+ "description": "Extract CLI command structure from commander/yargs for AI agent skill generation",
5
+ "keywords": [
6
+ "agent-skills",
7
+ "cli",
8
+ "commander",
9
+ "documentation",
10
+ "skill-generation",
11
+ "yargs"
12
+ ],
13
+ "license": "MIT",
14
+ "author": "Pradeep Mouli",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "https://github.com/pradeepmouli/to-skills.git",
18
+ "directory": "packages/cli"
19
+ },
20
+ "funding": {
21
+ "type": "github",
22
+ "url": "https://github.com/sponsors/pradeepmouli"
23
+ },
24
+ "files": [
25
+ "dist",
26
+ "README.md"
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
+ "import": "./dist/index.js"
35
+ }
36
+ },
37
+ "dependencies": {
38
+ "@to-skills/core": "0.10.0"
39
+ },
40
+ "devDependencies": {
41
+ "commander": "^14.0.0"
42
+ },
43
+ "peerDependencies": {
44
+ "commander": ">=12.0.0"
45
+ },
46
+ "peerDependenciesMeta": {
47
+ "commander": {
48
+ "optional": true
49
+ }
50
+ },
51
+ "scripts": {
52
+ "build": "tsgo -p tsconfig.build.json",
53
+ "type-check": "tsgo --noEmit"
54
+ }
55
+ }