@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 +21 -0
- package/README.md +36 -0
- package/dist/correlator.d.ts +16 -0
- package/dist/correlator.d.ts.map +1 -0
- package/dist/correlator.js +50 -0
- package/dist/correlator.js.map +1 -0
- package/dist/extract.d.ts +19 -0
- package/dist/extract.d.ts.map +1 -0
- package/dist/extract.js +58 -0
- package/dist/extract.js.map +1 -0
- package/dist/help-parser.d.ts +12 -0
- package/dist/help-parser.d.ts.map +1 -0
- package/dist/help-parser.js +249 -0
- package/dist/help-parser.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/introspect-commander.d.ts +12 -0
- package/dist/introspect-commander.d.ts.map +1 -0
- package/dist/introspect-commander.js +84 -0
- package/dist/introspect-commander.js.map +1 -0
- package/package.json +55 -0
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"}
|
package/dist/extract.js
ADDED
|
@@ -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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"}
|
package/dist/index.d.ts
ADDED
|
@@ -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
|
+
}
|