@asnd/skill-creator 0.1.1 → 0.1.3

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 (88) hide show
  1. package/README.md +64 -125
  2. package/dist/cli/dynamic.d.ts +26 -0
  3. package/dist/cli/dynamic.js +136 -0
  4. package/dist/cli/dynamic.js.map +1 -0
  5. package/dist/cli/main.d.ts +2 -4
  6. package/dist/cli/main.js +376 -1530
  7. package/dist/cli/main.js.map +1 -1
  8. package/dist/cli/parse.d.ts +9 -0
  9. package/dist/cli/parse.js +38 -0
  10. package/dist/cli/parse.js.map +1 -0
  11. package/dist/commands/agents.d.ts +96 -0
  12. package/dist/commands/agents.js +116 -0
  13. package/dist/commands/agents.js.map +1 -0
  14. package/dist/commands/install.d.ts +12 -0
  15. package/dist/commands/install.js +229 -0
  16. package/dist/commands/install.js.map +1 -0
  17. package/dist/core/cache.d.ts +3 -0
  18. package/dist/core/cache.js +52 -0
  19. package/dist/core/cache.js.map +1 -0
  20. package/dist/core/coerce.d.ts +8 -0
  21. package/dist/core/coerce.js +128 -0
  22. package/dist/core/coerce.js.map +1 -0
  23. package/dist/core/filter.d.ts +7 -0
  24. package/dist/core/filter.js +16 -0
  25. package/dist/core/filter.js.map +1 -0
  26. package/dist/core/listing.d.ts +11 -0
  27. package/dist/core/listing.js +31 -0
  28. package/dist/core/listing.js.map +1 -0
  29. package/dist/core/names.d.ts +1 -0
  30. package/dist/core/names.js +7 -0
  31. package/dist/core/names.js.map +1 -0
  32. package/dist/core/output.d.ts +12 -0
  33. package/dist/core/output.js +34 -0
  34. package/dist/core/output.js.map +1 -0
  35. package/dist/core/secrets.d.ts +1 -0
  36. package/dist/core/secrets.js +21 -0
  37. package/dist/core/secrets.js.map +1 -0
  38. package/dist/core/types.d.ts +37 -0
  39. package/dist/core/types.js +2 -0
  40. package/dist/core/types.js.map +1 -0
  41. package/dist/core/usage.d.ts +13 -0
  42. package/dist/core/usage.js +33 -0
  43. package/dist/core/usage.js.map +1 -0
  44. package/dist/graphql/execute.d.ts +8 -0
  45. package/dist/graphql/execute.js +133 -0
  46. package/dist/graphql/execute.js.map +1 -0
  47. package/dist/graphql/extract.d.ts +6 -0
  48. package/dist/graphql/extract.js +109 -0
  49. package/dist/graphql/extract.js.map +1 -0
  50. package/dist/graphql/load.d.ts +11 -0
  51. package/dist/graphql/load.js +95 -0
  52. package/dist/graphql/load.js.map +1 -0
  53. package/dist/mcp/extract.d.ts +8 -0
  54. package/dist/mcp/extract.js +40 -0
  55. package/dist/mcp/extract.js.map +1 -0
  56. package/dist/mcp/http.d.ts +8 -0
  57. package/dist/mcp/http.js +80 -0
  58. package/dist/mcp/http.js.map +1 -0
  59. package/dist/mcp/stdio.d.ts +9 -0
  60. package/dist/mcp/stdio.js +67 -0
  61. package/dist/mcp/stdio.js.map +1 -0
  62. package/dist/openapi/execute.d.ts +12 -0
  63. package/dist/openapi/execute.js +44 -0
  64. package/dist/openapi/execute.js.map +1 -0
  65. package/dist/openapi/extract.d.ts +2 -0
  66. package/dist/openapi/extract.js +123 -0
  67. package/dist/openapi/extract.js.map +1 -0
  68. package/dist/openapi/load.d.ts +11 -0
  69. package/dist/openapi/load.js +52 -0
  70. package/dist/openapi/load.js.map +1 -0
  71. package/dist/openapi/params.d.ts +12 -0
  72. package/dist/openapi/params.js +47 -0
  73. package/dist/openapi/params.js.map +1 -0
  74. package/dist/openapi/refs.d.ts +1 -0
  75. package/dist/openapi/refs.js +8 -0
  76. package/dist/openapi/refs.js.map +1 -0
  77. package/dist/skills/agents.d.ts +77 -0
  78. package/dist/skills/agents.js +85 -0
  79. package/dist/skills/agents.js.map +1 -0
  80. package/dist/skills/generate.d.ts +1 -0
  81. package/dist/skills/generate.js +494 -0
  82. package/dist/skills/generate.js.map +1 -0
  83. package/package.json +7 -11
  84. package/prompts/skill-creator.md +169 -0
  85. package/dist/cli/package-4N3JKWJZ.js +0 -90
  86. package/dist/cli/package-4N3JKWJZ.js.map +0 -1
  87. package/prompts/generate-skill.md +0 -22
  88. package/skills/skill-creator/SKILL.md +0 -260
package/dist/cli/main.js CHANGED
@@ -1,1583 +1,431 @@
1
1
  #!/usr/bin/env node
2
-
3
- // src/cli/main.ts
4
- import { realpathSync } from "fs";
5
- import { homedir } from "os";
6
- import { join, resolve } from "path";
7
- import { fileURLToPath } from "url";
8
- import { parseArgs as parseArgs2 } from "util";
9
-
10
- // src/core/cache.ts
11
- import { createHash } from "crypto";
12
- import * as cacache from "cacache";
13
- var CACHE_IGNORED_FIELDS = /* @__PURE__ */ new Set([
14
- "cacheTtl",
15
- "cache_ttl",
16
- "description",
17
- "include",
18
- "exclude",
19
- "methods"
20
- ]);
21
- function cacheKeyFor(config) {
22
- const normalized = normalizeConfig(config);
23
- return createHash("sha256").update(JSON.stringify(normalized)).digest("hex").slice(0, 16);
24
- }
25
- async function loadCached(cacheDir, key, ttlSeconds) {
26
- try {
27
- const info = await cacache.get.info(cacheDir, key);
28
- if (info === null) return null;
29
- const ageSeconds = (Date.now() - info.time) / 1e3;
30
- if (ageSeconds >= ttlSeconds) return null;
31
- const entry = await cacache.get(cacheDir, key);
32
- return JSON.parse(entry.data.toString("utf8"));
33
- } catch {
34
- return null;
35
- }
36
- }
37
- async function saveCache(cacheDir, key, data) {
38
- await cacache.put(cacheDir, key, JSON.stringify(data));
39
- }
40
- function normalizeConfig(input) {
41
- const output = {};
42
- for (const [key, value] of Object.entries(input)) {
43
- if (CACHE_IGNORED_FIELDS.has(key)) continue;
44
- if (key === "authHeaders" || key === "auth_headers") {
45
- output[key] = normalizeAuthHeaders(value);
46
- } else {
47
- output[key] = value;
48
- }
49
- }
50
- return Object.fromEntries(Object.entries(output).sort(([a], [b]) => a.localeCompare(b)));
51
- }
52
- function normalizeAuthHeaders(value) {
53
- if (!Array.isArray(value)) return value;
54
- return [...value].sort((a, b) => JSON.stringify(a).localeCompare(JSON.stringify(b)));
55
- }
56
-
57
- // src/core/coerce.ts
58
- import { Ajv } from "ajv";
59
- import addFormatsPlugin from "ajv-formats";
60
- var ajv = new Ajv({ allErrors: true, strict: false });
61
- var addFormats = addFormatsPlugin;
62
- addFormats(ajv);
63
- var validatorCache = /* @__PURE__ */ new WeakMap();
64
- function schemaTypeToCliType(schema) {
65
- switch (schema.type) {
66
- case "integer":
67
- return { type: "integer", suffix: "" };
68
- case "number":
69
- return { type: "number", suffix: "" };
70
- case "boolean":
71
- return { type: "boolean", suffix: "" };
72
- case "array":
73
- return { type: "string", suffix: " (JSON array)" };
74
- case "object":
75
- return { type: "string", suffix: " (JSON object)" };
76
- default:
77
- return { type: "string", suffix: "" };
78
- }
79
- }
80
- function coerceAndValidateValue(value, schema = {}, label = "value") {
81
- const coerced = coerceValue(value, schema);
82
- validateValue(coerced, schema, label);
83
- return coerced;
84
- }
85
- function validateValue(value, schema = {}, label = "value") {
86
- if (Object.keys(schema).length === 0) return;
87
- const validate = validatorFor(schema);
88
- if (validate(value)) return;
89
- throw new Error(`${label} failed validation: ${formatAjvErrors(validate.errors ?? [], label)}`);
90
- }
91
- function validatorFor(schema) {
92
- const cached = validatorCache.get(schema);
93
- if (cached !== void 0) return cached;
94
- const validate = ajv.compile(normalizeSchema(schema));
95
- validatorCache.set(schema, validate);
96
- return validate;
97
- }
98
- function normalizeSchema(schema) {
99
- if (schema.nullable === true && typeof schema.type === "string") {
100
- return { ...schema, type: [schema.type, "null"] };
101
- }
102
- return schema;
103
- }
104
- function formatAjvErrors(errors, label) {
105
- return errors.map((error) => {
106
- const path = error.instancePath.length > 0 ? `${label}${error.instancePath}` : label;
107
- return `${path} ${error.message ?? "is invalid"}`;
108
- }).join("; ");
109
- }
110
- function coerceValue(value, schema = {}) {
111
- if (value === null || value === void 0) return null;
112
- switch (schema.type) {
113
- case "array":
114
- return coerceArray(value, schema.items);
115
- case "object":
116
- return coerceObject(value);
117
- case "boolean":
118
- return Boolean(value);
119
- case "integer":
120
- return typeof value === "number" ? Math.trunc(value) : Number.parseInt(String(value), 10);
121
- case "number":
122
- return typeof value === "number" ? value : Number.parseFloat(String(value));
123
- default:
124
- return coerceSchemaless(value);
125
- }
126
- }
127
- function coerceArray(value, itemSchema) {
128
- if (Array.isArray(value)) return value;
129
- if (typeof value !== "string") return value;
130
- try {
131
- const parsed = JSON.parse(value);
132
- if (Array.isArray(parsed)) return parsed;
133
- } catch {
134
- }
135
- const values = value.includes(",") ? value.split(",").map((part) => part.trim()) : [value];
136
- return values.map((item) => coerceItem(item, itemSchema?.type));
137
- }
138
- function coerceItem(value, type) {
139
- switch (type) {
140
- case "integer":
141
- return Number.parseInt(value, 10);
142
- case "number":
143
- return Number.parseFloat(value);
144
- case "boolean":
145
- return ["true", "1", "yes"].includes(value.toLowerCase());
146
- default:
147
- return value;
148
- }
149
- }
150
- function coerceObject(value) {
151
- if (typeof value !== "string") return value;
152
- try {
153
- return JSON.parse(value);
154
- } catch {
155
- return value;
156
- }
157
- }
158
- function coerceSchemaless(value) {
159
- if (typeof value !== "string") return value;
160
- const trimmed = value.trim();
161
- if (!trimmed || !["{", "["].includes(trimmed[0] ?? "")) return value;
162
- try {
163
- const parsed = JSON.parse(trimmed);
164
- return typeof parsed === "object" && parsed !== null ? parsed : value;
165
- } catch {
166
- return value;
167
- }
168
- }
169
-
170
- // src/core/secrets.ts
171
- import { readFile } from "fs/promises";
172
- async function resolveSecret(value) {
173
- if (value.startsWith("env:")) {
174
- const name = value.slice(4);
175
- const resolved = process.env[name];
176
- if (resolved === void 0)
177
- throw new Error(`environment variable ${JSON.stringify(name)} is not set`);
178
- return resolved;
179
- }
180
- if (value.startsWith("file:")) {
181
- const path = value.slice(5);
182
- try {
183
- return (await readFile(path, "utf8")).replace(/\n$/, "");
184
- } catch {
185
- throw new Error(`secret file not found: ${path}`);
186
- }
187
- }
188
- return value;
189
- }
190
-
191
- // src/graphql/execute.ts
192
- import {
193
- Kind,
194
- OperationTypeNode,
195
- parse,
196
- print
197
- } from "graphql";
198
- import { ClientError, GraphQLClient } from "graphql-request";
199
-
200
- // src/graphql/extract.ts
201
- import {
202
- getNamedType,
203
- isEnumType,
204
- isInputObjectType,
205
- isInterfaceType,
206
- isListType,
207
- isNonNullType,
208
- isObjectType,
209
- isScalarType
210
- } from "graphql";
211
-
212
- // src/core/names.ts
213
- function toKebab(name) {
214
- return name.replace(/([a-z0-9])([A-Z])/g, "$1-$2").replace(/_/g, "-").toLowerCase();
215
- }
216
-
217
- // src/graphql/extract.ts
218
- function extractGraphqlCommands(schema) {
219
- const commands = [];
220
- addRootFields(commands, schema.getQueryType()?.getFields(), "query");
221
- addRootFields(commands, schema.getMutationType()?.getFields(), "mutation");
222
- return commands;
223
- }
224
- function buildGraphqlSelectionSet(type, fields, depth = 2) {
225
- if (fields !== void 0 && fields.trim().length > 0) return `{ ${fields.trim()} }`;
226
- return buildDefaultSelectionSet(type, depth, /* @__PURE__ */ new Set());
227
- }
228
- function addRootFields(commands, fields, operationType) {
229
- if (fields === void 0) return;
230
- for (const field of Object.values(fields)) {
231
- const description = optionalString(field.description);
232
- commands.push({
233
- name: toKebab(field.name),
234
- ...description === void 0 ? {} : { description },
235
- params: field.args.map(
236
- (arg) => graphqlArgToParam(arg.name, arg.type, optionalString(arg.description))
237
- ),
238
- graphqlOperationType: operationType,
239
- graphqlFieldName: field.name,
240
- graphqlReturnType: field.type
241
- });
242
- }
243
- }
244
- function graphqlArgToParam(name, type, description) {
245
- const schema = graphqlInputTypeToJsonSchema(type);
246
- const cliType = schemaTypeToCliType(schema).type;
247
- return {
248
- name: toKebab(name),
249
- originalName: name,
250
- type: cliType,
251
- required: isNonNullType(type),
252
- ...description === void 0 ? {} : { description },
253
- location: "graphql_arg",
254
- schema
255
- };
256
- }
257
- function graphqlInputTypeToJsonSchema(type) {
258
- if (isNonNullType(type)) {
259
- return { ...graphqlInputTypeToJsonSchema(type.ofType), graphqlType: graphqlTypeToString(type) };
260
- }
261
- if (isListType(type)) {
262
- return {
263
- type: "array",
264
- items: graphqlInputTypeToJsonSchema(type.ofType),
265
- graphqlType: graphqlTypeToString(type)
266
- };
267
- }
268
- const namedType = getNamedType(type);
269
- const base = { graphqlType: graphqlTypeToString(type) };
270
- if (isEnumType(namedType)) {
271
- return { ...base, type: "string", enum: namedType.getValues().map((value) => value.name) };
272
- }
273
- if (isInputObjectType(namedType)) return { ...base, type: "object" };
274
- if (isScalarType(namedType)) {
275
- switch (namedType.name) {
276
- case "Int":
277
- return { ...base, type: "integer" };
278
- case "Float":
279
- return { ...base, type: "number" };
280
- case "Boolean":
281
- return { ...base, type: "boolean" };
282
- default:
283
- return { ...base, type: "string" };
284
- }
285
- }
286
- return { ...base, type: "string" };
287
- }
288
- function graphqlTypeToString(type) {
289
- if (isNonNullType(type)) return `${graphqlTypeToString(type.ofType)}!`;
290
- if (isListType(type)) return `[${graphqlTypeToString(type.ofType)}]`;
291
- return getNamedType(type).name;
292
- }
293
- function optionalString(value) {
294
- return value ?? void 0;
295
- }
296
- function buildDefaultSelectionSet(type, depth, seenTypes) {
297
- const namedType = getNamedType(type);
298
- if (isScalarType(namedType) || isEnumType(namedType)) return "";
299
- if (depth <= 0) return "";
300
- if (!isObjectType(namedType) && !isInterfaceType(namedType)) return "{ __typename }";
301
- if (seenTypes.has(namedType.name)) return "";
302
- const nextSeen = new Set(seenTypes);
303
- nextSeen.add(namedType.name);
304
- const selections = Object.values(namedType.getFields()).filter((field) => field.args.length === 0).map((field) => {
305
- const fieldNamedType = getNamedType(field.type);
306
- if (isScalarType(fieldNamedType) || isEnumType(fieldNamedType)) return field.name;
307
- const nested = buildDefaultSelectionSet(field.type, depth - 1, nextSeen);
308
- return nested ? `${field.name} ${nested}` : "";
309
- }).filter((field) => field.length > 0);
310
- return selections.length === 0 ? "" : `{ ${selections.join(" ")} }`;
311
- }
312
-
313
- // src/graphql/execute.ts
314
- async function executeGraphql(command, values, options) {
315
- const fieldName = command.graphqlFieldName ?? command.name;
316
- const variables = collectVariables(command, values);
317
- const query = buildGraphqlOperation(
318
- command,
319
- fieldName,
320
- variables,
321
- options.fields,
322
- options.selectionDepth ?? 2
323
- );
324
- const client = new GraphQLClient(options.endpoint, {
325
- headers: Object.fromEntries(options.authHeaders ?? [])
326
- });
327
- try {
328
- const data = await client.request(query, variables);
329
- if (!isRecord(data)) return data;
330
- return data[fieldName];
331
- } catch (error) {
332
- throw normalizeGraphqlRequestError(error);
333
- }
334
- }
335
- function collectVariables(command, values) {
336
- const variables = {};
337
- for (const param of command.params) {
338
- const value = values[param.name] ?? values[param.originalName];
339
- if (value !== void 0) {
340
- variables[param.originalName] = coerceAndValidateValue(
341
- value,
342
- param.schema ?? {},
343
- `--${param.name}`
344
- );
345
- }
346
- }
347
- return variables;
348
- }
349
- function buildGraphqlOperation(command, fieldName, variables, fields, selectionDepth) {
350
- const activeParams = command.params.filter(
351
- (param) => param.required || variables[param.originalName] !== void 0
352
- );
353
- const variableDefinitions = activeParams.map(
354
- (param) => ({
355
- kind: Kind.VARIABLE_DEFINITION,
356
- variable: {
357
- kind: Kind.VARIABLE,
358
- name: { kind: Kind.NAME, value: param.originalName }
359
- },
360
- type: parseGraphqlType(graphqlParamType(param))
361
- })
362
- );
363
- const selectionSet = buildSelectionSetNode(command, fields, selectionDepth);
364
- const field = {
365
- kind: Kind.FIELD,
366
- name: { kind: Kind.NAME, value: fieldName },
367
- arguments: activeParams.map((param) => ({
368
- kind: Kind.ARGUMENT,
369
- name: { kind: Kind.NAME, value: param.originalName },
370
- value: {
371
- kind: Kind.VARIABLE,
372
- name: { kind: Kind.NAME, value: param.originalName }
373
- }
374
- })),
375
- ...selectionSet === void 0 ? {} : { selectionSet }
376
- };
377
- const operation = {
378
- kind: Kind.OPERATION_DEFINITION,
379
- operation: command.graphqlOperationType === "mutation" ? OperationTypeNode.MUTATION : OperationTypeNode.QUERY,
380
- name: { kind: Kind.NAME, value: commandName(command) },
381
- ...variableDefinitions.length === 0 ? {} : { variableDefinitions },
382
- selectionSet: { kind: Kind.SELECTION_SET, selections: [field] }
383
- };
384
- const document = { kind: Kind.DOCUMENT, definitions: [operation] };
385
- return print(document);
386
- }
387
- function buildSelectionSetNode(command, fields, selectionDepth) {
388
- if (command.graphqlReturnType === void 0) return void 0;
389
- const selectionSet = buildGraphqlSelectionSet(
390
- command.graphqlReturnType,
391
- fields,
392
- selectionDepth
393
- );
394
- if (selectionSet.length === 0) return void 0;
395
- return parseSelectionSet(selectionSet);
396
- }
397
- function parseGraphqlType(type) {
398
- const operation = parseSingleOperation(`query __Type($value: ${type}) { __typename }`);
399
- const variable = operation.variableDefinitions?.[0];
400
- if (variable === void 0) throw new Error(`invalid GraphQL variable type: ${type}`);
401
- return variable.type;
402
- }
403
- function parseSelectionSet(selectionSet) {
404
- const operation = parseSingleOperation(`query __Selection { _selection ${selectionSet} }`);
405
- const selection = operation.selectionSet.selections[0];
406
- if (selection?.kind !== Kind.FIELD || selection.selectionSet === void 0) {
407
- throw new Error("invalid GraphQL selection set");
408
- }
409
- return selection.selectionSet;
410
- }
411
- function parseSingleOperation(source) {
412
- const document = parse(source);
413
- const definition = document.definitions[0];
414
- if (definition?.kind !== Kind.OPERATION_DEFINITION) {
415
- throw new Error("failed to build GraphQL operation");
416
- }
417
- return definition;
418
- }
419
- function graphqlParamType(param) {
420
- const type = param.schema?.graphqlType;
421
- return typeof type === "string" ? type : jsonSchemaToGraphqlType(param.schema?.type);
422
- }
423
- function jsonSchemaToGraphqlType(type) {
424
- switch (type) {
425
- case "integer":
426
- return "Int";
427
- case "number":
428
- return "Float";
429
- case "boolean":
430
- return "Boolean";
431
- default:
432
- return "String";
433
- }
434
- }
435
- function commandName(command) {
436
- return `${command.graphqlOperationType ?? "query"}_${command.graphqlFieldName ?? command.name}`.replace(
437
- /[^_0-9A-Za-z]/g,
438
- "_"
439
- );
440
- }
441
- function normalizeGraphqlRequestError(error) {
442
- if (error instanceof ClientError) {
443
- if (error.response.errors !== void 0 && error.response.errors.length > 0) {
444
- return new Error(`GraphQL error: ${formatGraphqlErrors(error.response.errors)}`);
445
- }
446
- return new Error(
447
- `GraphQL HTTP ${error.response.status}: ${JSON.stringify(error.response, null, 0)}`
448
- );
449
- }
450
- return error instanceof Error ? error : new Error(String(error));
451
- }
452
- function formatGraphqlErrors(errors) {
453
- return errors.map((error) => error.message ?? "unknown error").join("; ");
454
- }
455
- function isRecord(value) {
456
- return typeof value === "object" && value !== null && !Array.isArray(value);
457
- }
458
-
459
- // src/graphql/load.ts
460
- import { readFile as readFile2 } from "fs/promises";
461
- import { GraphQLFileLoader } from "@graphql-tools/graphql-file-loader";
462
- import ky from "ky";
463
- import { JsonFileLoader } from "@graphql-tools/json-file-loader";
464
- import { loadSchema } from "@graphql-tools/load";
465
- import { UrlLoader } from "@graphql-tools/url-loader";
466
- import {
467
- buildClientSchema,
468
- buildSchema,
469
- getIntrospectionQuery,
470
- introspectionFromSchema
471
- } from "graphql";
472
- import { GraphQLClient as GraphQLClient2 } from "graphql-request";
473
- async function loadGraphqlSchema(endpoint, options = {}) {
474
- const authHeaders = options.authHeaders ?? [];
475
- if (options.schemaSource !== void 0) {
476
- return loadProvidedGraphqlSchema(options.schemaSource, authHeaders);
477
- }
478
- const cacheKey = `graphql-${options.cacheKey ?? cacheKeyFor({ endpoint, authHeaders: options.authHeaders ?? [] })}`;
479
- const ttlSeconds = options.ttlSeconds ?? 3600;
480
- if (options.cacheDir !== void 0 && !options.refresh) {
481
- const cached = await loadCached(options.cacheDir, cacheKey, ttlSeconds);
482
- if (cached !== null) return buildClientSchema(cached);
483
- }
484
- try {
485
- const schema = await loadRemoteGraphqlSchema(endpoint, authHeaders);
486
- if (options.cacheDir !== void 0) {
487
- await saveCache(options.cacheDir, cacheKey, introspectionFromSchema(schema));
488
- }
489
- return schema;
490
- } catch (error) {
491
- if (options.cacheDir !== void 0) {
492
- const stale = await loadCached(
493
- options.cacheDir,
494
- cacheKey,
495
- Number.POSITIVE_INFINITY
496
- );
497
- if (stale !== null) {
498
- options.onWarning?.(
499
- `Warning: using stale cached GraphQL schema because introspection failed: ${formatError(error)}`
500
- );
501
- return buildClientSchema(stale);
502
- }
2
+ import { realpathSync } from 'node:fs';
3
+ import { homedir } from 'node:os';
4
+ import { join, resolve } from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { parseArgs } from 'node:util';
7
+ import { runInstallCommand } from '../commands/install.js';
8
+ import { cacheKeyFor, loadCached, saveCache } from '../core/cache.js';
9
+ import { coerceAndValidateValue } from '../core/coerce.js';
10
+ import { resolveSecret } from '../core/secrets.js';
11
+ import { executeGraphql } from '../graphql/execute.js';
12
+ import { extractGraphqlCommands } from '../graphql/extract.js';
13
+ import { loadGraphqlSchema } from '../graphql/load.js';
14
+ import { extractMcpCommands } from '../mcp/extract.js';
15
+ import { callHttpTool, listHttpTools } from '../mcp/http.js';
16
+ import { callStdioTool, listStdioTools } from '../mcp/stdio.js';
17
+ import { executeOpenApi } from '../openapi/execute.js';
18
+ import { extractOpenApiCommands } from '../openapi/extract.js';
19
+ import { loadOpenApiSpec } from '../openapi/load.js';
20
+ import { runGenerate } from '../skills/generate.js';
21
+ import { runDynamicMode } from './dynamic.js';
22
+ import { splitAtSubcommand } from './parse.js';
23
+ const GLOBAL_OPTION_SPEC = {
24
+ valueOptions: [
25
+ '--spec',
26
+ '--mcp',
27
+ '--mcp-stdio',
28
+ '--graphql',
29
+ '--graphql-schema',
30
+ '--base-url',
31
+ '--auth-header',
32
+ '--transport',
33
+ '--cache-key',
34
+ '--cache-ttl',
35
+ '--search',
36
+ '--include',
37
+ '--exclude',
38
+ '--methods',
39
+ '--fields',
40
+ '--selection-depth',
41
+ '--head',
42
+ ],
43
+ boolOptions: ['--list', '--pretty', '--raw', '--refresh', '--stdin', '--version', '--help', '-h'],
44
+ };
45
+ export async function run(argv = process.argv.slice(2)) {
46
+ if (argv[0] === '--')
47
+ argv = argv.slice(1);
48
+ if (argv[0] === 'generate') {
49
+ try {
50
+ await runGenerate(argv.slice(1));
51
+ return 0;
52
+ }
53
+ catch (error) {
54
+ console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
55
+ return 1;
56
+ }
503
57
  }
504
- throw new Error(
505
- `GraphQL introspection is disabled or unavailable. Provide a schema with --graphql-schema ./schema.graphql or --graphql-schema ./introspection.json. (${formatError(error)})`
506
- );
507
- }
508
- }
509
- async function loadRemoteGraphqlSchema(endpoint, authHeaders) {
510
- const client = new GraphQLClient2(endpoint, {
511
- headers: Object.fromEntries(authHeaders)
512
- });
513
- const introspection = await client.request(getIntrospectionQuery());
514
- return buildClientSchema(introspection);
515
- }
516
- async function loadProvidedGraphqlSchema(source, authHeaders) {
517
- try {
518
- const schema = await loadSchema(source, {
519
- loaders: [new UrlLoader(), new GraphQLFileLoader(), new JsonFileLoader()],
520
- headers: Object.fromEntries(authHeaders)
521
- });
522
- return buildClientSchema(introspectionFromSchema(schema));
523
- } catch {
524
- return loadProvidedGraphqlSchemaFallback(source, authHeaders);
525
- }
526
- }
527
- async function loadProvidedGraphqlSchemaFallback(source, authHeaders) {
528
- const text = await readSchemaSource(source, authHeaders);
529
- const trimmed = text.trim();
530
- if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
531
- const parsed = JSON.parse(trimmed);
532
- return buildClientSchema(extractIntrospection(parsed));
533
- }
534
- return buildSchema(text);
535
- }
536
- async function readSchemaSource(source, authHeaders) {
537
- if (source.startsWith("http://") || source.startsWith("https://")) {
538
- const response = await ky.get(source, {
539
- headers: Object.fromEntries(authHeaders),
540
- throwHttpErrors: false
541
- });
542
- if (!response.ok) throw new Error(`failed to fetch GraphQL schema: HTTP ${response.status}`);
543
- return response.text();
544
- }
545
- return readFile2(source, "utf8");
546
- }
547
- function extractIntrospection(value) {
548
- if (!isRecord2(value)) throw new Error("GraphQL schema JSON must be an object");
549
- if (isRecord2(value.data)) return extractIntrospection(value.data);
550
- if (isRecord2(value.__schema)) return value;
551
- throw new Error("GraphQL schema JSON must contain an introspection __schema object");
552
- }
553
- function formatError(error) {
554
- return error instanceof Error ? error.message : String(error);
555
- }
556
- function isRecord2(value) {
557
- return typeof value === "object" && value !== null && !Array.isArray(value);
558
- }
559
-
560
- // src/openapi/load.ts
561
- import { readFile as readFile3 } from "fs/promises";
562
- import ky2 from "ky";
563
- import YAML from "yaml";
564
-
565
- // src/openapi/refs.ts
566
- import $RefParser from "@apidevtools/json-schema-ref-parser";
567
- async function resolveRefs(input) {
568
- return await $RefParser.dereference(input, {
569
- mutateInputSchema: false,
570
- dereference: { circular: "ignore" }
571
- });
572
- }
573
-
574
- // src/openapi/load.ts
575
- async function loadOpenApiSpec(source, options = {}) {
576
- const isUrl = source.startsWith("http://") || source.startsWith("https://");
577
- const ttlSeconds = options.ttlSeconds ?? 3600;
578
- const key = options.cacheKey ?? cacheKeyFor({ source, authHeaders: options.authHeaders ?? [] });
579
- if (isUrl && options.cacheDir !== void 0 && !options.refresh) {
580
- const cached = await loadCached(options.cacheDir, key, ttlSeconds);
581
- if (cached !== null) return cached;
582
- }
583
- const raw = isUrl ? await fetchRemoteSpec(source, options.authHeaders ?? []) : await readFile3(source, "utf8");
584
- const parsed = parseSpec(raw);
585
- const spec = await resolveRefs(parsed);
586
- if (!isOpenApiSpec(spec)) {
587
- throw new Error("spec must contain 'paths'");
588
- }
589
- if (isUrl && options.cacheDir !== void 0) {
590
- await saveCache(options.cacheDir, key, spec);
591
- }
592
- return spec;
593
- }
594
- async function fetchRemoteSpec(source, authHeaders) {
595
- const response = await ky2.get(source, {
596
- headers: Object.fromEntries(authHeaders),
597
- throwHttpErrors: false
598
- });
599
- if (!response.ok) throw new Error(`failed to fetch spec: HTTP ${response.status}`);
600
- return response.text();
601
- }
602
- function parseSpec(raw) {
603
- try {
604
- return JSON.parse(raw);
605
- } catch {
606
- return YAML.parse(raw);
607
- }
608
- }
609
- function isOpenApiSpec(value) {
610
- return typeof value === "object" && value !== null && !Array.isArray(value) && "paths" in value && typeof value.paths === "object";
611
- }
612
-
613
- // src/openapi/extract.ts
614
- var HTTP_METHODS = /* @__PURE__ */ new Set(["get", "post", "put", "delete", "patch"]);
615
- function extractOpenApiCommands(spec) {
616
- const commands = [];
617
- const seenNames = /* @__PURE__ */ new Map();
618
- const paths = isObject(spec) && isObject(spec.paths) ? spec.paths : {};
619
- for (const [path, methods] of Object.entries(paths)) {
620
- if (!isObject(methods)) continue;
621
- for (const [method, operation] of Object.entries(methods)) {
622
- if (!HTTP_METHODS.has(method) || !isObject(operation)) continue;
623
- let name = operation.operationId !== void 0 ? toKebab(String(operation.operationId)) : fallbackName(method, path);
624
- const seen = seenNames.get(name) ?? 0;
625
- seenNames.set(name, seen + 1);
626
- if (seen > 0) name = `${name}-${method}`;
627
- const params = extractParameters(operation);
628
- const body = extractRequestBodyParams(operation);
629
- params.push(...body.params);
630
- commands.push({
631
- name,
632
- description: String(
633
- operation.summary ?? operation.description ?? `${method.toUpperCase()} ${path}`
634
- ),
635
- params,
636
- hasBody: body.params.length > 0,
637
- method,
638
- path,
639
- ...body.contentType === void 0 ? {} : { contentType: body.contentType }
640
- });
58
+ if (argv[0] === 'command' || argv[0] === 'commands' || argv[0] === 'install-command') {
59
+ try {
60
+ await runInstallCommand(argv.slice(1));
61
+ return 0;
62
+ }
63
+ catch (error) {
64
+ console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
65
+ return 1;
66
+ }
641
67
  }
642
- }
643
- return commands;
644
- }
645
- function extractParameters(operation) {
646
- const rawParams = Array.isArray(operation.parameters) ? operation.parameters : [];
647
- return rawParams.filter(isObject).map((param) => {
648
- const schema = getSchema(param.schema);
649
- const { type, suffix } = schemaTypeToCliType(schema);
650
- const choices = Array.isArray(schema.enum) ? { choices: schema.enum } : {};
651
- return {
652
- name: toKebab(String(param.name)),
653
- originalName: String(param.name),
654
- type,
655
- required: Boolean(param.required),
656
- description: `${String(param.description ?? param.name)}${suffix}`,
657
- ...choices,
658
- location: normalizeLocation(param.in),
659
- schema
660
- };
661
- });
662
- }
663
- function extractRequestBodyParams(operation) {
664
- const requestBody = isObject(operation.requestBody) ? operation.requestBody : void 0;
665
- const content = requestBody !== void 0 && isObject(requestBody.content) ? requestBody.content : {};
666
- const multipartSchema = getContentSchema(content, "multipart/form-data");
667
- const jsonSchema = getContentSchema(content, "application/json");
668
- const multipartProps = getProperties(multipartSchema);
669
- const hasBinary = Object.values(multipartProps).some((schema2) => schema2.format === "binary");
670
- let schema = {};
671
- let contentType;
672
- if (hasBinary) {
673
- schema = multipartSchema;
674
- contentType = "multipart/form-data";
675
- } else if (Object.keys(getProperties(jsonSchema)).length > 0) {
676
- schema = jsonSchema;
677
- } else if (Object.keys(multipartProps).length > 0) {
678
- schema = multipartSchema;
679
- contentType = "multipart/form-data";
680
- }
681
- const required = new Set(Array.isArray(schema.required) ? schema.required : []);
682
- const properties = getProperties(schema);
683
- const params = Object.entries(properties).map(([propName, propSchema]) => {
684
- const isBinary = contentType === "multipart/form-data" && propSchema.format === "binary";
685
- const { type, suffix } = isBinary ? { type: "string", suffix: " (file path)" } : schemaTypeToCliType(propSchema);
686
- const choices = Array.isArray(propSchema.enum) ? { choices: propSchema.enum } : {};
687
- return {
688
- name: toKebab(propName),
689
- originalName: propName,
690
- type,
691
- required: required.has(propName),
692
- description: `${String(propSchema.description ?? propName)}${suffix}`,
693
- ...choices,
694
- location: isBinary ? "file" : "body",
695
- schema: propSchema
696
- };
697
- });
698
- return contentType === void 0 ? { params } : { params, contentType };
699
- }
700
- function getContentSchema(content, contentType) {
701
- const item = content[contentType];
702
- return isObject(item) ? getSchema(item.schema) : {};
703
- }
704
- function getProperties(schema) {
705
- return isObject(schema.properties) ? Object.fromEntries(
706
- Object.entries(schema.properties).filter(
707
- (entry) => isObject(entry[1])
708
- )
709
- ) : {};
710
- }
711
- function getSchema(value) {
712
- return isObject(value) ? value : {};
713
- }
714
- function normalizeLocation(value) {
715
- return value === "path" || value === "header" || value === "body" || value === "file" ? value : "query";
716
- }
717
- function fallbackName(method, path) {
718
- const slug = path.replace(/^\/+|\/+$/g, "").replace(/[{}]/g, "").replace(/\//g, "-");
719
- return slug ? `${method}-${slug}` : method;
720
- }
721
- function isObject(value) {
722
- return typeof value === "object" && value !== null && !Array.isArray(value);
723
- }
724
-
725
- // src/openapi/execute.ts
726
- import ky3 from "ky";
727
-
728
- // src/openapi/params.ts
729
- function collectOpenApiParams(command, values, options = {}) {
730
- let path = command.path ?? "";
731
- const queryParams = {};
732
- const headers = {};
733
- let body = null;
734
- const files = null;
735
- for (const param of command.params) {
736
- if (param.location !== "path") continue;
737
- const value = values[param.name];
738
- if (value !== void 0 && value !== null) {
739
- path = path.replace(`{${param.originalName}}`, encodeURIComponent(String(value)));
68
+ const { globalArgv, commandArgv } = splitAtSubcommand(argv, GLOBAL_OPTION_SPEC);
69
+ const globals = parseGlobalArgs(globalArgv);
70
+ if (globals.version) {
71
+ const pkg = await import('../../package.json', { with: { type: 'json' } });
72
+ writeStdout(`skill-creator ${pkg.default.version}\n`);
73
+ return 0;
740
74
  }
741
- }
742
- for (const param of command.params) {
743
- const value = values[param.name];
744
- if (value === void 0 || value === null) continue;
745
- if (param.location === "query") {
746
- queryParams[param.originalName] = coerceAndValidateValue(
747
- value,
748
- param.schema ?? {},
749
- `--${param.name}`
750
- );
751
- } else if (param.location === "header") {
752
- headers[param.originalName] = String(value);
75
+ if (globals.help && commandArgv.length === 0) {
76
+ printHelp();
77
+ return 0;
753
78
  }
754
- }
755
- const method = command.method?.toLowerCase() ?? "get";
756
- if (method !== "get") {
757
- if (options.stdinBody !== void 0) {
758
- body = options.stdinBody;
759
- } else {
760
- const collectedBody = {};
761
- for (const param of command.params) {
762
- if (param.location !== "body") continue;
763
- const value = values[param.name];
764
- if (value !== void 0 && value !== null) {
765
- collectedBody[param.originalName] = coerceAndValidateValue(
766
- value,
767
- param.schema ?? {},
768
- `--${param.name}`
769
- );
79
+ try {
80
+ validateSourceModes(globals);
81
+ globals.authHeaders = await resolveAuthHeaders(globals.authHeaders);
82
+ if (globals.spec !== undefined) {
83
+ await handleOpenApiMode(globals, commandArgv);
84
+ return 0;
770
85
  }
771
- }
772
- body = Object.keys(collectedBody).length > 0 ? collectedBody : null;
86
+ if (globals.mcpStdio !== undefined) {
87
+ await handleMcpStdioMode(globals, commandArgv);
88
+ return 0;
89
+ }
90
+ if (globals.mcp !== undefined) {
91
+ await handleMcpHttpMode(globals, commandArgv);
92
+ return 0;
93
+ }
94
+ if (globals.graphql !== undefined) {
95
+ await handleGraphqlMode(globals, commandArgv);
96
+ return 0;
97
+ }
98
+ console.error('Error: only --spec, --mcp-stdio, --mcp, and --graphql modes are implemented in this TypeScript port so far.');
99
+ return 1;
773
100
  }
774
- }
775
- return { path, queryParams, headers, body, files };
776
- }
777
-
778
- // src/openapi/execute.ts
779
- async function executeOpenApi(command, values, options) {
780
- const collected = collectOpenApiParams(command, values, {
781
- stdinBody: options.stdinBody
782
- });
783
- const url = buildUrl(options.baseUrl, collected.path, collected.queryParams);
784
- const method = (command.method ?? "get").toUpperCase();
785
- const headers = {
786
- ...Object.fromEntries(options.authHeaders ?? []),
787
- ...collected.headers
788
- };
789
- const body = method !== "GET" && collected.body !== null ? JSON.stringify(collected.body) : void 0;
790
- if (body !== void 0) headers["Content-Type"] ??= "application/json";
791
- const response = await ky3(url, {
792
- method,
793
- headers,
794
- ...body === void 0 ? {} : { body },
795
- throwHttpErrors: false
796
- });
797
- return {
798
- status: response.status,
799
- ok: response.ok,
800
- text: await response.text(),
801
- contentType: response.headers.get("content-type") ?? ""
802
- };
803
- }
804
- function buildUrl(baseUrl, path, queryParams) {
805
- const url = new URL(`${baseUrl.replace(/\/$/, "")}${path}`);
806
- for (const [key, value] of Object.entries(queryParams)) {
807
- if (value === void 0 || value === null) continue;
808
- if (Array.isArray(value)) {
809
- for (const item of value) url.searchParams.append(key, String(item));
810
- } else {
811
- url.searchParams.set(key, String(value));
101
+ catch (error) {
102
+ console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
103
+ return 1;
812
104
  }
813
- }
814
- return url.toString();
815
105
  }
816
-
817
- // src/mcp/extract.ts
818
- function extractMcpCommands(tools) {
819
- return tools.map((tool) => {
820
- const schema = isJsonSchema(tool.inputSchema) ? tool.inputSchema : {};
821
- const required = new Set(Array.isArray(schema.required) ? schema.required : []);
822
- const properties = getProperties2(schema);
823
- const params = Object.entries(properties).map(([name, propSchema]) => {
824
- const { type, suffix } = schemaTypeToCliType(propSchema);
825
- const choices = Array.isArray(propSchema.enum) ? { choices: propSchema.enum } : {};
826
- return {
827
- name: toKebab(name),
828
- originalName: name,
829
- type,
830
- required: required.has(name),
831
- description: `${String(propSchema.description ?? name)}${suffix}`,
832
- ...choices,
833
- location: "tool_input",
834
- schema: propSchema
835
- };
106
+ async function handleOpenApiMode(globals, commandArgv) {
107
+ if (globals.spec === undefined)
108
+ throw new Error('--spec is required');
109
+ const source = globals.spec;
110
+ const spec = await loadOpenApiSpec(source, {
111
+ authHeaders: globals.authHeaders,
112
+ cacheDir: defaultCacheDir(),
113
+ ...(globals.cacheKey === undefined ? {} : { cacheKey: globals.cacheKey }),
114
+ ttlSeconds: globals.cacheTtl,
115
+ refresh: globals.refresh,
836
116
  });
837
- return {
838
- name: toKebab(tool.name),
839
- description: tool.description ?? "",
840
- params,
841
- hasBody: params.length > 0,
842
- toolName: tool.name
843
- };
844
- });
845
- }
846
- function getProperties2(schema) {
847
- const properties = schema.properties;
848
- if (typeof properties !== "object" || properties === null || Array.isArray(properties)) return {};
849
- return Object.fromEntries(
850
- Object.entries(properties).filter(
851
- (entry) => isJsonSchema(entry[1])
852
- )
853
- );
854
- }
855
- function isJsonSchema(value) {
856
- return typeof value === "object" && value !== null && !Array.isArray(value);
857
- }
858
-
859
- // src/mcp/http.ts
860
- import { Client as Client2 } from "@modelcontextprotocol/sdk/client/index.js";
861
- import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
862
- import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
863
-
864
- // src/mcp/stdio.ts
865
- import { Client } from "@modelcontextprotocol/sdk/client/index.js";
866
- import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
867
- import stringArgv from "string-argv";
868
- async function listStdioTools(commandLine) {
869
- return withStdioClient(commandLine, async (client) => {
870
- const result = await client.listTools();
871
- return result.tools.map((tool) => ({
872
- name: tool.name,
873
- ...tool.description === void 0 ? {} : { description: tool.description },
874
- inputSchema: tool.inputSchema
875
- }));
876
- });
877
- }
878
- async function callStdioTool(commandLine, toolName, args) {
879
- return withStdioClient(commandLine, async (client) => {
880
- const result = await client.callTool({ name: toolName, arguments: args });
881
- return extractMcpContent(result.content);
882
- });
883
- }
884
- async function withStdioClient(commandLine, fn) {
885
- const [command, ...args] = splitCommandLine(commandLine);
886
- if (command === void 0) throw new Error("--mcp-stdio command cannot be empty");
887
- const client = new Client({ name: "skill-creator", version: "0.1.0" });
888
- const transport = new StdioClientTransport({ command, args, stderr: "pipe" });
889
- await client.connect(transport);
890
- try {
891
- return await fn(client);
892
- } finally {
893
- await client.close();
894
- }
895
- }
896
- function splitCommandLine(commandLine) {
897
- return stringArgv(commandLine);
898
- }
899
- function extractMcpContent(content) {
900
- if (!Array.isArray(content)) return content;
901
- const parts = content.map((part) => extractContentPart(part)).filter((part) => part !== void 0);
902
- if (parts.length === 0) return "";
903
- if (parts.every((part) => typeof part === "string")) return parts.join("\n");
904
- return parts;
905
- }
906
- function extractContentPart(part) {
907
- if (!isObject2(part)) return void 0;
908
- if (part.type === "text" && typeof part.text === "string") return part.text;
909
- if (typeof part.data === "string") return part.data;
910
- if (part.type === "resource" && isObject2(part.resource)) {
911
- if (typeof part.resource.text === "string") return part.resource.text;
912
- if (typeof part.resource.blob === "string") return part.resource.blob;
913
- }
914
- return part;
915
- }
916
- function isObject2(value) {
917
- return typeof value === "object" && value !== null && !Array.isArray(value);
918
- }
919
-
920
- // src/mcp/http.ts
921
- async function listHttpTools(url, optionsOrHeaders = {}) {
922
- const options = normalizeOptions(optionsOrHeaders);
923
- return withHttpClient(url, options, async (client) => {
924
- const result = await client.listTools();
925
- return result.tools.map((tool) => ({
926
- name: tool.name,
927
- ...tool.description === void 0 ? {} : { description: tool.description },
928
- inputSchema: tool.inputSchema
929
- }));
930
- });
931
- }
932
- async function callHttpTool(url, toolName, args, optionsOrHeaders = {}) {
933
- const options = normalizeOptions(optionsOrHeaders);
934
- return withHttpClient(url, options, async (client) => {
935
- const result = await client.callTool({ name: toolName, arguments: args });
936
- return extractMcpContent(result.content);
937
- });
938
- }
939
- async function withHttpClient(url, options, fn) {
940
- if (options.transport === "auto") {
941
- try {
942
- return await withSingleHttpClient(url, { ...options, transport: "streamable" }, fn);
943
- } catch (streamableError) {
944
- try {
945
- return await withSingleHttpClient(url, { ...options, transport: "sse" }, fn);
946
- } catch (sseError) {
947
- throw new Error(
948
- `failed to connect using streamable HTTP or SSE (${formatError2(streamableError)}; ${formatError2(sseError)})`
949
- );
950
- }
951
- }
952
- }
953
- return withSingleHttpClient(url, options, fn);
954
- }
955
- async function withSingleHttpClient(url, options, fn) {
956
- const client = new Client2({ name: "skill-creator", version: "0.1.0" });
957
- const transport = createTransport(url, options);
958
- await client.connect(transport);
959
- try {
960
- return await fn(client);
961
- } finally {
962
- await client.close();
963
- }
964
- }
965
- function createTransport(url, options) {
966
- const headers = Object.fromEntries(options.headers);
967
- if (options.transport === "sse") {
968
- const fetchWithHeaders = (input, init) => fetch(input, { ...init, headers: { ...headers, ...headersToObject(init?.headers) } });
969
- return new SSEClientTransport(new URL(url), {
970
- eventSourceInit: { fetch: fetchWithHeaders },
971
- requestInit: { headers }
117
+ await runDynamicMode({
118
+ globals,
119
+ commandArgv,
120
+ loadCommands: () => extractOpenApiCommands(spec),
121
+ renderCommands: renderOpenApiCommands,
122
+ onEmptyCommand: () => {
123
+ printHelp();
124
+ throw new Error('provide a subcommand, or use --list to see available commands');
125
+ },
126
+ executeCommand: async (command, values) => {
127
+ const baseUrl = determineBaseUrl(spec, source, globals.baseUrl);
128
+ const response = await executeOpenApi(command, values, {
129
+ baseUrl,
130
+ authHeaders: globals.authHeaders,
131
+ });
132
+ if (!response.ok)
133
+ throw new Error(`HTTP ${response.status}: ${response.text}`);
134
+ return response.text;
135
+ },
972
136
  });
973
- }
974
- return new StreamableHTTPClientTransport(new URL(url), {
975
- requestInit: { headers }
976
- });
977
- }
978
- function normalizeOptions(optionsOrHeaders) {
979
- if (Array.isArray(optionsOrHeaders)) {
980
- return { headers: optionsOrHeaders, transport: "auto" };
981
- }
982
- return {
983
- headers: optionsOrHeaders.headers ?? [],
984
- transport: optionsOrHeaders.transport ?? "auto"
985
- };
986
- }
987
- function headersToObject(headers) {
988
- if (headers === void 0) return {};
989
- return Object.fromEntries(new Headers(headers).entries());
990
- }
991
- function formatError2(error) {
992
- return error instanceof Error ? error.message : String(error);
993
- }
994
-
995
- // src/cli/dynamic.ts
996
- import { parseArgs } from "util";
997
-
998
- // src/core/filter.ts
999
- import { minimatch } from "minimatch";
1000
- function filterCommands(commands, filters = {}) {
1001
- let result = commands;
1002
- if (filters.methods?.length) {
1003
- const allowed = new Set(filters.methods.map((method) => method.toUpperCase()));
1004
- result = result.filter(
1005
- (command) => command.method === void 0 || allowed.has(command.method.toUpperCase())
1006
- );
1007
- }
1008
- if (filters.include?.length) {
1009
- result = result.filter(
1010
- (command) => filters.include?.some((pattern) => minimatch(command.name, pattern)) ?? false
1011
- );
1012
- }
1013
- if (filters.exclude?.length) {
1014
- result = result.filter(
1015
- (command) => !(filters.exclude?.some((pattern) => minimatch(command.name, pattern)) ?? false)
1016
- );
1017
- }
1018
- return result;
1019
- }
1020
-
1021
- // src/core/output.ts
1022
- function applyHead(data, n) {
1023
- if (Array.isArray(data)) return data.slice(0, n);
1024
- return data;
1025
- }
1026
- function formatOutput(data, options = {}) {
1027
- if (options.raw) {
1028
- return {
1029
- stdout: `${typeof data === "string" ? data : JSON.stringify(data)}
1030
- `,
1031
- stderr: ""
1032
- };
1033
- }
1034
- let value = parseJsonStringIfPossible(data);
1035
- if (options.head !== void 0) value = applyHead(value, options.head);
1036
- if (typeof value === "string") {
1037
- return { stdout: `${value}
1038
- `, stderr: "" };
1039
- }
1040
- return {
1041
- stdout: `${JSON.stringify(value, null, options.pretty ? 2 : 0)}
1042
- `,
1043
- stderr: ""
1044
- };
1045
- }
1046
- function parseJsonStringIfPossible(data) {
1047
- if (typeof data !== "string") return data;
1048
- try {
1049
- return JSON.parse(data);
1050
- } catch {
1051
- return data;
1052
- }
1053
- }
1054
-
1055
- // src/cli/dynamic.ts
1056
- async function runDynamicMode(options) {
1057
- let commands = filterCommands(await options.loadCommands(), options.globals);
1058
- if (options.globals.search !== void 0) {
1059
- commands = searchCommands(commands, options.globals.search);
1060
- }
1061
- if (options.globals.list || options.globals.search !== void 0) {
1062
- writeStdout(options.renderCommands(commands));
1063
- return;
1064
- }
1065
- if (options.commandArgv.length === 0) {
1066
- if (options.onEmptyCommand !== void 0) {
1067
- await options.onEmptyCommand(commands);
1068
- return;
1069
- }
1070
- writeStdout(options.renderCommands(commands));
1071
- return;
1072
- }
1073
- const commandName2 = options.commandArgv[0];
1074
- if (commandName2 === void 0) throw new Error("missing subcommand");
1075
- const command = commands.find((candidate) => candidate.name === commandName2);
1076
- if (command === void 0) throw new Error(`unknown subcommand: ${commandName2}`);
1077
- if (options.commandArgv.includes("--help") || options.commandArgv.includes("-h")) {
1078
- writeStdout(renderCommandHelp(command));
1079
- return;
1080
- }
1081
- const prepared = await prepareCommandArgs(options, options.commandArgv.slice(1));
1082
- const values = parseCommandValues(command, prepared.argv, prepared.initialValues ?? {});
1083
- const result = await options.executeCommand(command, values, prepared.argv);
1084
- writeFormattedOutput(result, options.globals);
1085
- }
1086
- function searchCommands(commands, search) {
1087
- const pattern = search.toLowerCase();
1088
- return commands.filter(
1089
- (command) => command.name.toLowerCase().includes(pattern) || (command.description ?? "").toLowerCase().includes(pattern)
1090
- );
1091
- }
1092
- async function prepareCommandArgs(options, argv) {
1093
- return options.prepareCommandArgs === void 0 ? { argv } : await options.prepareCommandArgs(argv);
1094
- }
1095
- function parseCommandValues(command, argv, initialValues = {}) {
1096
- const values = { ...initialValues };
1097
- const params = new Map(command.params.map((param) => [param.name, param]));
1098
- validateCommandOptions(command, argv, params);
1099
- const { values: parsedValues } = parseArgs({
1100
- args: normalizeStringOptionValues(argv, stringParamNames(command)),
1101
- options: commandOptionSpec(command),
1102
- strict: true,
1103
- allowPositionals: true
1104
- });
1105
- for (const param of command.params) {
1106
- const value = parsedValues[param.name];
1107
- if (value !== void 0) values[param.name] = value;
1108
- }
1109
- for (const param of command.params) {
1110
- if (param.required && values[param.name] === void 0 && values[param.originalName] === void 0 && param.location !== "body") {
1111
- throw new Error(`missing required option --${param.name}`);
1112
- }
1113
- }
1114
- return values;
1115
- }
1116
- function validateCommandOptions(command, argv, params) {
1117
- for (let index = 0; index < argv.length; index += 1) {
1118
- const token = argv[index];
1119
- if (token === void 0 || !token.startsWith("--")) continue;
1120
- const rawFlag = token.slice(2);
1121
- const flag = rawFlag.includes("=") ? rawFlag.slice(0, rawFlag.indexOf("=")) : rawFlag;
1122
- const param = params.get(flag);
1123
- if (param === void 0) throw new Error(`unknown option for ${command.name}: --${flag}`);
1124
- if (param.type !== "boolean" && !rawFlag.includes("=") && argv[index + 1] === void 0) {
1125
- throw new Error(`missing value for --${flag}`);
1126
- }
1127
- }
1128
- }
1129
- function commandOptionSpec(command) {
1130
- return Object.fromEntries(
1131
- command.params.map((param) => [
1132
- param.name,
1133
- { type: param.type === "boolean" ? "boolean" : "string" }
1134
- ])
1135
- );
1136
- }
1137
- function stringParamNames(command) {
1138
- return new Set(
1139
- command.params.filter((param) => param.type !== "boolean").map((param) => param.name)
1140
- );
1141
- }
1142
- function normalizeStringOptionValues(argv, optionNames) {
1143
- const result = [];
1144
- for (let index = 0; index < argv.length; index += 1) {
1145
- const token = argv[index];
1146
- const next = argv[index + 1];
1147
- if (token !== void 0 && next !== void 0 && token.startsWith("--") && !token.includes("=") && optionNames.has(token.slice(2)) && next.startsWith("-")) {
1148
- result.push(`${token}=${next}`);
1149
- index += 1;
1150
- } else if (token !== void 0) {
1151
- result.push(token);
1152
- }
1153
- }
1154
- return result;
1155
- }
1156
- function renderCommandHelp(command) {
1157
- const lines = [`${command.name}: ${command.description ?? ""}`, "", "Options:"];
1158
- for (const param of command.params) {
1159
- const required = param.required ? " (required)" : "";
1160
- lines.push(
1161
- ` --${param.name.padEnd(24)} ${param.description ?? param.originalName}${required}`
1162
- );
1163
- }
1164
- return `${lines.join("\n")}
1165
- `;
1166
- }
1167
- function writeFormattedOutput(data, globals) {
1168
- const output = formatOutput(data, {
1169
- pretty: globals.pretty,
1170
- raw: globals.raw,
1171
- ...globals.head === void 0 ? {} : { head: globals.head }
1172
- });
1173
- if (output.stderr) console.error(output.stderr.replace(/\n$/, ""));
1174
- writeStdout(output.stdout);
1175
- }
1176
- function writeStdout(text) {
1177
- console.log(text.replace(/\n$/, ""));
1178
- }
1179
-
1180
- // src/cli/parse.ts
1181
- function splitAtSubcommand(argv, spec) {
1182
- const valueOptions = new Set(spec.valueOptions);
1183
- const boolOptions = new Set(spec.boolOptions);
1184
- let index = 0;
1185
- while (index < argv.length) {
1186
- const arg = argv[index];
1187
- if (arg === void 0) break;
1188
- if (arg === "--") {
1189
- return {
1190
- globalArgv: argv.slice(0, index),
1191
- commandArgv: argv.slice(index + 1)
1192
- };
1193
- }
1194
- if (arg.startsWith("-")) {
1195
- const optionName = arg.startsWith("--") && arg.includes("=") ? arg.slice(0, arg.indexOf("=")) : arg;
1196
- if (arg.startsWith("--") && arg.includes("=")) {
1197
- index += 1;
1198
- } else if (valueOptions.has(optionName)) {
1199
- index += 2;
1200
- } else if (boolOptions.has(optionName)) {
1201
- index += 1;
1202
- } else {
1203
- index += 1;
1204
- }
1205
- continue;
1206
- }
1207
- return {
1208
- globalArgv: argv.slice(0, index),
1209
- commandArgv: argv.slice(index)
1210
- };
1211
- }
1212
- return { globalArgv: argv, commandArgv: [] };
1213
- }
1214
-
1215
- // src/cli/main.ts
1216
- var GLOBAL_OPTION_SPEC = {
1217
- valueOptions: [
1218
- "--spec",
1219
- "--mcp",
1220
- "--mcp-stdio",
1221
- "--graphql",
1222
- "--graphql-schema",
1223
- "--base-url",
1224
- "--auth-header",
1225
- "--transport",
1226
- "--cache-key",
1227
- "--cache-ttl",
1228
- "--search",
1229
- "--include",
1230
- "--exclude",
1231
- "--methods",
1232
- "--fields",
1233
- "--selection-depth",
1234
- "--head"
1235
- ],
1236
- boolOptions: ["--list", "--pretty", "--raw", "--refresh", "--stdin", "--version", "--help", "-h"]
1237
- };
1238
- async function run(argv = process.argv.slice(2)) {
1239
- if (argv[0] === "--") argv = argv.slice(1);
1240
- const { globalArgv, commandArgv } = splitAtSubcommand(argv, GLOBAL_OPTION_SPEC);
1241
- const globals = parseGlobalArgs(globalArgv);
1242
- if (globals.version) {
1243
- const pkg = await import("./package-4N3JKWJZ.js");
1244
- writeStdout2(`skill-creator ${pkg.default.version}
1245
- `);
1246
- return 0;
1247
- }
1248
- if (globals.help && commandArgv.length === 0) {
1249
- printHelp();
1250
- return 0;
1251
- }
1252
- try {
1253
- validateSourceModes(globals);
1254
- globals.authHeaders = await resolveAuthHeaders(globals.authHeaders);
1255
- if (globals.spec !== void 0) {
1256
- await handleOpenApiMode(globals, commandArgv);
1257
- return 0;
1258
- }
1259
- if (globals.mcpStdio !== void 0) {
1260
- await handleMcpStdioMode(globals, commandArgv);
1261
- return 0;
1262
- }
1263
- if (globals.mcp !== void 0) {
1264
- await handleMcpHttpMode(globals, commandArgv);
1265
- return 0;
1266
- }
1267
- if (globals.graphql !== void 0) {
1268
- await handleGraphqlMode(globals, commandArgv);
1269
- return 0;
1270
- }
1271
- console.error(
1272
- "Error: only --spec, --mcp-stdio, --mcp, and --graphql modes are implemented in this TypeScript port so far."
1273
- );
1274
- return 1;
1275
- } catch (error) {
1276
- console.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
1277
- return 1;
1278
- }
1279
- }
1280
- async function handleOpenApiMode(globals, commandArgv) {
1281
- if (globals.spec === void 0) throw new Error("--spec is required");
1282
- const source = globals.spec;
1283
- const spec = await loadOpenApiSpec(source, {
1284
- authHeaders: globals.authHeaders,
1285
- cacheDir: defaultCacheDir(),
1286
- ...globals.cacheKey === void 0 ? {} : { cacheKey: globals.cacheKey },
1287
- ttlSeconds: globals.cacheTtl,
1288
- refresh: globals.refresh
1289
- });
1290
- await runDynamicMode({
1291
- globals,
1292
- commandArgv,
1293
- loadCommands: () => extractOpenApiCommands(spec),
1294
- renderCommands: renderOpenApiCommands,
1295
- onEmptyCommand: () => {
1296
- printHelp();
1297
- throw new Error("provide a subcommand, or use --list to see available commands");
1298
- },
1299
- executeCommand: async (command, values) => {
1300
- const baseUrl = determineBaseUrl(spec, source, globals.baseUrl);
1301
- const response = await executeOpenApi(command, values, {
1302
- baseUrl,
1303
- authHeaders: globals.authHeaders
1304
- });
1305
- if (!response.ok) throw new Error(`HTTP ${response.status}: ${response.text}`);
1306
- return response.text;
1307
- }
1308
- });
1309
137
  }
1310
138
  async function handleGraphqlMode(globals, commandArgv) {
1311
- if (globals.graphql === void 0) throw new Error("--graphql is required");
1312
- const endpoint = globals.graphql;
1313
- const schema = await loadGraphqlSchema(endpoint, {
1314
- authHeaders: globals.authHeaders,
1315
- cacheDir: defaultCacheDir(),
1316
- ...globals.cacheKey === void 0 ? {} : { cacheKey: globals.cacheKey },
1317
- ttlSeconds: globals.cacheTtl,
1318
- refresh: globals.refresh,
1319
- ...globals.graphqlSchema === void 0 ? {} : { schemaSource: globals.graphqlSchema },
1320
- onWarning: (message) => console.error(message)
1321
- });
1322
- await runDynamicMode({
1323
- globals,
1324
- commandArgv,
1325
- loadCommands: () => extractGraphqlCommands(schema),
1326
- renderCommands: renderGraphqlCommands,
1327
- prepareCommandArgs: async (argv) => {
1328
- const stdinFlag = stripFlag(argv, "--stdin");
1329
- const stdinValues = globals.stdin || stdinFlag.enabled ? await readStdinJson() : {};
1330
- return { argv: stdinFlag.argv, initialValues: stdinValues };
1331
- },
1332
- executeCommand: (command, values) => executeGraphql(command, values, {
1333
- endpoint,
1334
- authHeaders: globals.authHeaders,
1335
- ...globals.fields === void 0 ? {} : { fields: globals.fields },
1336
- selectionDepth: globals.selectionDepth
1337
- })
1338
- });
139
+ if (globals.graphql === undefined)
140
+ throw new Error('--graphql is required');
141
+ const endpoint = globals.graphql;
142
+ const schema = await loadGraphqlSchema(endpoint, {
143
+ authHeaders: globals.authHeaders,
144
+ cacheDir: defaultCacheDir(),
145
+ ...(globals.cacheKey === undefined ? {} : { cacheKey: globals.cacheKey }),
146
+ ttlSeconds: globals.cacheTtl,
147
+ refresh: globals.refresh,
148
+ ...(globals.graphqlSchema === undefined ? {} : { schemaSource: globals.graphqlSchema }),
149
+ onWarning: (message) => console.error(message),
150
+ });
151
+ await runDynamicMode({
152
+ globals,
153
+ commandArgv,
154
+ loadCommands: () => extractGraphqlCommands(schema),
155
+ renderCommands: renderGraphqlCommands,
156
+ prepareCommandArgs: async (argv) => {
157
+ const stdinFlag = stripFlag(argv, '--stdin');
158
+ const stdinValues = globals.stdin || stdinFlag.enabled ? await readStdinJson() : {};
159
+ return { argv: stdinFlag.argv, initialValues: stdinValues };
160
+ },
161
+ executeCommand: (command, values) => executeGraphql(command, values, {
162
+ endpoint,
163
+ authHeaders: globals.authHeaders,
164
+ ...(globals.fields === undefined ? {} : { fields: globals.fields }),
165
+ selectionDepth: globals.selectionDepth,
166
+ }),
167
+ });
1339
168
  }
1340
169
  async function handleMcpHttpMode(globals, commandArgv) {
1341
- if (globals.mcp === void 0) throw new Error("--mcp is required");
1342
- const endpoint = globals.mcp;
1343
- await runDynamicMode({
1344
- globals,
1345
- commandArgv,
1346
- loadCommands: async () => extractMcpCommands(await loadMcpHttpTools(globals)),
1347
- renderCommands: renderMcpCommands,
1348
- executeCommand: async (command, values) => {
1349
- const toolArgs = collectMcpToolArgs(command, values);
1350
- return callHttpTool(endpoint, command.toolName ?? command.name, toolArgs, {
1351
- headers: globals.authHeaders,
1352
- transport: globals.transport
1353
- });
1354
- }
1355
- });
170
+ if (globals.mcp === undefined)
171
+ throw new Error('--mcp is required');
172
+ const endpoint = globals.mcp;
173
+ await runDynamicMode({
174
+ globals,
175
+ commandArgv,
176
+ loadCommands: async () => extractMcpCommands(await loadMcpHttpTools(globals)),
177
+ renderCommands: renderMcpCommands,
178
+ executeCommand: async (command, values) => {
179
+ const toolArgs = collectMcpToolArgs(command, values);
180
+ return callHttpTool(endpoint, command.toolName ?? command.name, toolArgs, {
181
+ headers: globals.authHeaders,
182
+ transport: globals.transport,
183
+ });
184
+ },
185
+ });
1356
186
  }
1357
187
  async function loadMcpHttpTools(globals) {
1358
- if (globals.mcp === void 0) throw new Error("--mcp is required");
1359
- const cacheKey = `mcp-${globals.cacheKey ?? cacheKeyFor({
1360
- source: globals.mcp,
1361
- authHeaders: globals.authHeaders,
1362
- transport: globals.transport
1363
- })}`;
1364
- const cacheDir = defaultCacheDir();
1365
- if (!globals.refresh) {
1366
- const cached = await loadCached(cacheDir, cacheKey, globals.cacheTtl);
1367
- if (cached !== null) return cached;
1368
- }
1369
- const tools = await listHttpTools(globals.mcp, {
1370
- headers: globals.authHeaders,
1371
- transport: globals.transport
1372
- });
1373
- await saveCache(cacheDir, cacheKey, tools);
1374
- return tools;
188
+ if (globals.mcp === undefined)
189
+ throw new Error('--mcp is required');
190
+ const cacheKey = `mcp-${globals.cacheKey ??
191
+ cacheKeyFor({
192
+ source: globals.mcp,
193
+ authHeaders: globals.authHeaders,
194
+ transport: globals.transport,
195
+ })}`;
196
+ const cacheDir = defaultCacheDir();
197
+ if (!globals.refresh) {
198
+ const cached = await loadCached(cacheDir, cacheKey, globals.cacheTtl);
199
+ if (cached !== null)
200
+ return cached;
201
+ }
202
+ const tools = await listHttpTools(globals.mcp, {
203
+ headers: globals.authHeaders,
204
+ transport: globals.transport,
205
+ });
206
+ await saveCache(cacheDir, cacheKey, tools);
207
+ return tools;
1375
208
  }
1376
209
  async function handleMcpStdioMode(globals, commandArgv) {
1377
- if (globals.mcpStdio === void 0) throw new Error("--mcp-stdio is required");
1378
- const commandLine = globals.mcpStdio;
1379
- await runDynamicMode({
1380
- globals,
1381
- commandArgv,
1382
- loadCommands: async () => extractMcpCommands(await listStdioTools(commandLine)),
1383
- renderCommands: renderMcpCommands,
1384
- executeCommand: async (command, values) => {
1385
- const toolArgs = collectMcpToolArgs(command, values);
1386
- return callStdioTool(commandLine, command.toolName ?? command.name, toolArgs);
1387
- }
1388
- });
210
+ if (globals.mcpStdio === undefined)
211
+ throw new Error('--mcp-stdio is required');
212
+ const commandLine = globals.mcpStdio;
213
+ await runDynamicMode({
214
+ globals,
215
+ commandArgv,
216
+ loadCommands: async () => extractMcpCommands(await listStdioTools(commandLine)),
217
+ renderCommands: renderMcpCommands,
218
+ executeCommand: async (command, values) => {
219
+ const toolArgs = collectMcpToolArgs(command, values);
220
+ return callStdioTool(commandLine, command.toolName ?? command.name, toolArgs);
221
+ },
222
+ });
1389
223
  }
1390
224
  function collectMcpToolArgs(command, values) {
1391
- const args = {};
1392
- for (const param of command.params) {
1393
- if (values[param.name] !== void 0) {
1394
- args[param.originalName] = coerceAndValidateValue(
1395
- values[param.name],
1396
- param.schema ?? {},
1397
- `--${param.name}`
1398
- );
225
+ const args = {};
226
+ for (const param of command.params) {
227
+ if (values[param.name] !== undefined) {
228
+ args[param.originalName] = coerceAndValidateValue(values[param.name], param.schema ?? {}, `--${param.name}`);
229
+ }
1399
230
  }
1400
- }
1401
- return args;
231
+ return args;
1402
232
  }
1403
233
  function parseGlobalArgs(argv) {
1404
- assertKnownValueOptionsHaveValues(argv, GLOBAL_OPTION_SPEC.valueOptions);
1405
- const { values } = parseArgs2({
1406
- args: argv,
1407
- options: {
1408
- spec: { type: "string" },
1409
- mcp: { type: "string" },
1410
- "mcp-stdio": { type: "string" },
1411
- graphql: { type: "string" },
1412
- "graphql-schema": { type: "string" },
1413
- "base-url": { type: "string" },
1414
- "auth-header": { type: "string", multiple: true },
1415
- transport: { type: "string" },
1416
- "cache-key": { type: "string" },
1417
- "cache-ttl": { type: "string" },
1418
- search: { type: "string" },
1419
- include: { type: "string" },
1420
- exclude: { type: "string" },
1421
- methods: { type: "string" },
1422
- fields: { type: "string" },
1423
- "selection-depth": { type: "string" },
1424
- head: { type: "string" },
1425
- list: { type: "boolean" },
1426
- pretty: { type: "boolean" },
1427
- raw: { type: "boolean" },
1428
- refresh: { type: "boolean" },
1429
- stdin: { type: "boolean" },
1430
- version: { type: "boolean" },
1431
- help: { type: "boolean", short: "h" }
1432
- },
1433
- strict: false,
1434
- allowPositionals: false
1435
- });
1436
- const authHeaders = stringListOption(values["auth-header"]).map(parseHeader);
1437
- const search = stringOption(values.search);
1438
- return {
1439
- ...optionalStringProperty("spec", stringOption(values.spec)),
1440
- ...optionalStringProperty("mcp", stringOption(values.mcp)),
1441
- ...optionalStringProperty("mcpStdio", stringOption(values["mcp-stdio"])),
1442
- ...optionalStringProperty("graphql", stringOption(values.graphql)),
1443
- ...optionalStringProperty("graphqlSchema", stringOption(values["graphql-schema"])),
1444
- ...optionalStringProperty("baseUrl", stringOption(values["base-url"])),
1445
- authHeaders,
1446
- transport: parseTransport(stringOption(values.transport) ?? "auto"),
1447
- ...optionalStringProperty("cacheKey", stringOption(values["cache-key"])),
1448
- cacheTtl: Number.parseInt(stringOption(values["cache-ttl"]) ?? "3600", 10),
1449
- refresh: values.refresh === true,
1450
- list: values.list === true || search !== void 0,
1451
- ...optionalStringProperty("search", search),
1452
- ...optionalStringArrayProperty("include", parseOptionalCommaList(values.include)),
1453
- ...optionalStringArrayProperty("exclude", parseOptionalCommaList(values.exclude)),
1454
- ...optionalStringArrayProperty("methods", parseOptionalCommaList(values.methods)),
1455
- ...optionalStringProperty("fields", stringOption(values.fields)),
1456
- selectionDepth: Number.parseInt(stringOption(values["selection-depth"]) ?? "2", 10),
1457
- stdin: values.stdin === true,
1458
- pretty: values.pretty === true,
1459
- raw: values.raw === true,
1460
- ...optionalNumberProperty("head", parseOptionalInteger(values.head)),
1461
- help: values.help === true,
1462
- version: values.version === true
1463
- };
234
+ assertKnownValueOptionsHaveValues(argv, GLOBAL_OPTION_SPEC.valueOptions);
235
+ const { values } = parseArgs({
236
+ args: argv,
237
+ options: {
238
+ spec: { type: 'string' },
239
+ mcp: { type: 'string' },
240
+ 'mcp-stdio': { type: 'string' },
241
+ graphql: { type: 'string' },
242
+ 'graphql-schema': { type: 'string' },
243
+ 'base-url': { type: 'string' },
244
+ 'auth-header': { type: 'string', multiple: true },
245
+ transport: { type: 'string' },
246
+ 'cache-key': { type: 'string' },
247
+ 'cache-ttl': { type: 'string' },
248
+ search: { type: 'string' },
249
+ include: { type: 'string' },
250
+ exclude: { type: 'string' },
251
+ methods: { type: 'string' },
252
+ fields: { type: 'string' },
253
+ 'selection-depth': { type: 'string' },
254
+ head: { type: 'string' },
255
+ list: { type: 'boolean' },
256
+ pretty: { type: 'boolean' },
257
+ raw: { type: 'boolean' },
258
+ refresh: { type: 'boolean' },
259
+ stdin: { type: 'boolean' },
260
+ version: { type: 'boolean' },
261
+ help: { type: 'boolean', short: 'h' },
262
+ },
263
+ strict: false,
264
+ allowPositionals: false,
265
+ });
266
+ const authHeaders = stringListOption(values['auth-header']).map(parseHeader);
267
+ const search = stringOption(values.search);
268
+ return {
269
+ ...optionalStringProperty('spec', stringOption(values.spec)),
270
+ ...optionalStringProperty('mcp', stringOption(values.mcp)),
271
+ ...optionalStringProperty('mcpStdio', stringOption(values['mcp-stdio'])),
272
+ ...optionalStringProperty('graphql', stringOption(values.graphql)),
273
+ ...optionalStringProperty('graphqlSchema', stringOption(values['graphql-schema'])),
274
+ ...optionalStringProperty('baseUrl', stringOption(values['base-url'])),
275
+ authHeaders,
276
+ transport: parseTransport(stringOption(values.transport) ?? 'auto'),
277
+ ...optionalStringProperty('cacheKey', stringOption(values['cache-key'])),
278
+ cacheTtl: Number.parseInt(stringOption(values['cache-ttl']) ?? '3600', 10),
279
+ refresh: values.refresh === true,
280
+ list: values.list === true || search !== undefined,
281
+ ...optionalStringProperty('search', search),
282
+ ...optionalStringArrayProperty('include', parseOptionalCommaList(values.include)),
283
+ ...optionalStringArrayProperty('exclude', parseOptionalCommaList(values.exclude)),
284
+ ...optionalStringArrayProperty('methods', parseOptionalCommaList(values.methods)),
285
+ ...optionalStringProperty('fields', stringOption(values.fields)),
286
+ selectionDepth: Number.parseInt(stringOption(values['selection-depth']) ?? '2', 10),
287
+ stdin: values.stdin === true,
288
+ pretty: values.pretty === true,
289
+ raw: values.raw === true,
290
+ ...optionalNumberProperty('head', parseOptionalInteger(values.head)),
291
+ help: values.help === true,
292
+ version: values.version === true,
293
+ };
1464
294
  }
1465
295
  function renderOpenApiCommands(commands) {
1466
- if (commands.length === 0) return "No commands found.\n";
1467
- return `${commands.map(
1468
- (command) => `${command.name.padEnd(32)} ${(command.method ?? "").toUpperCase().padEnd(6)} ${command.description ?? ""}`.trimEnd()
1469
- ).join("\n")}
1470
- `;
296
+ if (commands.length === 0)
297
+ return 'No commands found.\n';
298
+ return `${commands
299
+ .map((command) => `${command.name.padEnd(32)} ${(command.method ?? '').toUpperCase().padEnd(6)} ${command.description ?? ''}`.trimEnd())
300
+ .join('\n')}\n`;
1471
301
  }
1472
302
  function renderMcpCommands(commands) {
1473
- if (commands.length === 0) return "No tools found.\n";
1474
- return `${commands.map((command) => `${command.name.padEnd(32)} ${command.description ?? ""}`.trimEnd()).join("\n")}
1475
- `;
303
+ if (commands.length === 0)
304
+ return 'No tools found.\n';
305
+ return `${commands
306
+ .map((command) => `${command.name.padEnd(32)} ${command.description ?? ''}`.trimEnd())
307
+ .join('\n')}\n`;
1476
308
  }
1477
309
  function renderGraphqlCommands(commands) {
1478
- if (commands.length === 0) return "No GraphQL operations found.\n";
1479
- return `${commands.map(
1480
- (command) => `${command.name.padEnd(32)} ${(command.graphqlOperationType ?? "").padEnd(8)} ${command.description ?? ""}`.trimEnd()
1481
- ).join("\n")}
1482
- `;
310
+ if (commands.length === 0)
311
+ return 'No GraphQL operations found.\n';
312
+ return `${commands
313
+ .map((command) => `${command.name.padEnd(32)} ${(command.graphqlOperationType ?? '').padEnd(8)} ${command.description ?? ''}`.trimEnd())
314
+ .join('\n')}\n`;
1483
315
  }
1484
316
  function determineBaseUrl(spec, source, override) {
1485
- if (override !== void 0) return override;
1486
- const servers = Array.isArray(spec.servers) ? spec.servers : [];
1487
- const firstServer = servers[0];
1488
- const serverUrl = typeof firstServer === "object" && firstServer !== null && "url" in firstServer ? String(firstServer.url) : "";
1489
- if (serverUrl.startsWith("http://") || serverUrl.startsWith("https://")) return serverUrl;
1490
- if (source.startsWith("http://") || source.startsWith("https://")) {
1491
- const origin = new URL(source).origin;
1492
- return serverUrl ? `${origin}${serverUrl}` : origin;
1493
- }
1494
- throw new Error("cannot determine base URL. Use --base-url.");
317
+ if (override !== undefined)
318
+ return override;
319
+ const servers = Array.isArray(spec.servers) ? spec.servers : [];
320
+ const firstServer = servers[0];
321
+ const serverUrl = typeof firstServer === 'object' && firstServer !== null && 'url' in firstServer
322
+ ? String(firstServer.url)
323
+ : '';
324
+ if (serverUrl.startsWith('http://') || serverUrl.startsWith('https://'))
325
+ return serverUrl;
326
+ if (source.startsWith('http://') || source.startsWith('https://')) {
327
+ const origin = new URL(source).origin;
328
+ return serverUrl ? `${origin}${serverUrl}` : origin;
329
+ }
330
+ throw new Error('cannot determine base URL. Use --base-url.');
1495
331
  }
1496
332
  function validateSourceModes(globals) {
1497
- const active = [globals.spec, globals.mcp, globals.mcpStdio, globals.graphql].filter(
1498
- (value) => value !== void 0
1499
- ).length;
1500
- if (active === 0) {
1501
- printHelp();
1502
- throw new Error("one of --spec, --mcp, --mcp-stdio, or --graphql is required.");
1503
- }
1504
- if (active > 1)
1505
- throw new Error("--spec, --mcp, --mcp-stdio, and --graphql are mutually exclusive.");
333
+ const active = [globals.spec, globals.mcp, globals.mcpStdio, globals.graphql].filter((value) => value !== undefined).length;
334
+ if (active === 0) {
335
+ printHelp();
336
+ throw new Error('one of --spec, --mcp, --mcp-stdio, or --graphql is required.');
337
+ }
338
+ if (active > 1)
339
+ throw new Error('--spec, --mcp, --mcp-stdio, and --graphql are mutually exclusive.');
1506
340
  }
1507
341
  function assertKnownValueOptionsHaveValues(argv, options) {
1508
- const valueOptions = new Set(options);
1509
- for (let index = 0; index < argv.length; index += 1) {
1510
- const token = argv[index];
1511
- if (token === void 0 || !token.startsWith("--")) continue;
1512
- const option = token.includes("=") ? token.slice(0, token.indexOf("=")) : token;
1513
- if (!valueOptions.has(option) || token.includes("=")) continue;
1514
- if (argv[index + 1] === void 0) throw new Error(`missing value for ${option}`);
1515
- }
342
+ const valueOptions = new Set(options);
343
+ for (let index = 0; index < argv.length; index += 1) {
344
+ const token = argv[index];
345
+ if (token === undefined || !token.startsWith('--'))
346
+ continue;
347
+ const option = token.includes('=') ? token.slice(0, token.indexOf('=')) : token;
348
+ if (!valueOptions.has(option) || token.includes('='))
349
+ continue;
350
+ if (argv[index + 1] === undefined)
351
+ throw new Error(`missing value for ${option}`);
352
+ }
1516
353
  }
1517
354
  function stringOption(value) {
1518
- return typeof value === "string" ? value : void 0;
355
+ return typeof value === 'string' ? value : undefined;
1519
356
  }
1520
357
  function stringListOption(value) {
1521
- if (Array.isArray(value)) return value.filter((item) => typeof item === "string");
1522
- const single = stringOption(value);
1523
- return single === void 0 ? [] : [single];
358
+ if (Array.isArray(value))
359
+ return value.filter((item) => typeof item === 'string');
360
+ const single = stringOption(value);
361
+ return single === undefined ? [] : [single];
1524
362
  }
1525
363
  function optionalStringProperty(key, value) {
1526
- return value === void 0 ? {} : { [key]: value };
364
+ return value === undefined ? {} : { [key]: value };
1527
365
  }
1528
366
  function optionalStringArrayProperty(key, value) {
1529
- return value === void 0 ? {} : { [key]: value };
367
+ return value === undefined ? {} : { [key]: value };
1530
368
  }
1531
369
  function optionalNumberProperty(key, value) {
1532
- return value === void 0 ? {} : { [key]: value };
370
+ return value === undefined ? {} : { [key]: value };
1533
371
  }
1534
372
  function parseOptionalCommaList(value) {
1535
- const raw = stringOption(value);
1536
- return raw === void 0 ? void 0 : parseCommaList(raw);
373
+ const raw = stringOption(value);
374
+ return raw === undefined ? undefined : parseCommaList(raw);
1537
375
  }
1538
376
  function parseOptionalInteger(value) {
1539
- const raw = stringOption(value);
1540
- return raw === void 0 ? void 0 : Number.parseInt(raw, 10);
377
+ const raw = stringOption(value);
378
+ return raw === undefined ? undefined : Number.parseInt(raw, 10);
1541
379
  }
1542
380
  function stripFlag(argv, flag) {
1543
- let enabled = false;
1544
- const filtered = argv.filter((token) => {
1545
- if (token !== flag) return true;
1546
- enabled = true;
1547
- return false;
1548
- });
1549
- return { argv: filtered, enabled };
381
+ let enabled = false;
382
+ const filtered = argv.filter((token) => {
383
+ if (token !== flag)
384
+ return true;
385
+ enabled = true;
386
+ return false;
387
+ });
388
+ return { argv: filtered, enabled };
1550
389
  }
1551
390
  async function readStdinJson() {
1552
- let raw = "";
1553
- for await (const chunk of process.stdin) raw += String(chunk);
1554
- if (raw.trim().length === 0) return {};
1555
- const parsed = JSON.parse(raw);
1556
- if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
1557
- throw new Error("--stdin must contain a JSON object");
1558
- }
1559
- return parsed;
391
+ let raw = '';
392
+ for await (const chunk of process.stdin)
393
+ raw += String(chunk);
394
+ if (raw.trim().length === 0)
395
+ return {};
396
+ const parsed = JSON.parse(raw);
397
+ if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
398
+ throw new Error('--stdin must contain a JSON object');
399
+ }
400
+ return parsed;
1560
401
  }
1561
402
  function parseCommaList(value) {
1562
- return value.split(",").map((part) => part.trim()).filter((part) => part.length > 0);
403
+ return value
404
+ .split(',')
405
+ .map((part) => part.trim())
406
+ .filter((part) => part.length > 0);
1563
407
  }
1564
408
  function parseTransport(value) {
1565
- if (value === "auto" || value === "streamable" || value === "sse") return value;
1566
- throw new Error("--transport must be one of: auto, streamable, sse");
409
+ if (value === 'auto' || value === 'streamable' || value === 'sse')
410
+ return value;
411
+ throw new Error('--transport must be one of: auto, streamable, sse');
1567
412
  }
1568
413
  function parseHeader(header) {
1569
- const colon = header.indexOf(":");
1570
- if (colon === -1) throw new Error(`invalid auth header format: ${header}`);
1571
- return [header.slice(0, colon).trim(), header.slice(colon + 1).trim()];
414
+ const colon = header.indexOf(':');
415
+ if (colon === -1)
416
+ throw new Error(`invalid auth header format: ${header}`);
417
+ return [header.slice(0, colon).trim(), header.slice(colon + 1).trim()];
1572
418
  }
1573
419
  async function resolveAuthHeaders(headers) {
1574
- return Promise.all(headers.map(async ([key, value]) => [key, await resolveSecret(value)]));
420
+ return Promise.all(headers.map(async ([key, value]) => [key, await resolveSecret(value)]));
1575
421
  }
1576
422
  function defaultCacheDir() {
1577
- return process.env.SKILL_CREATOR_CACHE_DIR ?? join(homedir(), ".cache", "skill-creator");
423
+ return process.env.SKILL_CREATOR_CACHE_DIR ?? join(homedir(), '.cache', 'skill-creator');
1578
424
  }
1579
425
  function printHelp() {
1580
- writeStdout2(`skill-creator [global options] <subcommand> [command options]
426
+ writeStdout(`npx @asnd/skill-creator [global options] <subcommand> [command options]
427
+ npx @asnd/skill-creator generate --template openapi --name NAME --spec URL|FILE --agent AGENT --scope project|global
428
+ npx @asnd/skill-creator command install --agent AGENT --scope project|global
1581
429
 
1582
430
  Source (mutually exclusive, one required):
1583
431
  --spec URL|FILE OpenAPI spec (JSON or YAML, local or remote)
@@ -1608,24 +456,22 @@ Options:
1608
456
  --version Show version
1609
457
  `);
1610
458
  }
1611
- function writeStdout2(text) {
1612
- console.log(text.replace(/\n$/, ""));
459
+ function writeStdout(text) {
460
+ console.log(text.replace(/\n$/, ''));
1613
461
  }
1614
- function isCliEntrypoint(metaUrl, argv1 = process.argv[1]) {
1615
- if (!argv1) return false;
1616
- const modulePath = fileURLToPath(metaUrl);
1617
- try {
1618
- return realpathSync(argv1) === realpathSync(modulePath);
1619
- } catch {
1620
- return resolve(argv1) === modulePath;
1621
- }
462
+ export function isCliEntrypoint(metaUrl, argv1 = process.argv[1]) {
463
+ if (!argv1)
464
+ return false;
465
+ const modulePath = fileURLToPath(metaUrl);
466
+ try {
467
+ return realpathSync(argv1) === realpathSync(modulePath);
468
+ }
469
+ catch {
470
+ return resolve(argv1) === modulePath;
471
+ }
1622
472
  }
1623
473
  if (isCliEntrypoint(import.meta.url)) {
1624
- const code = await run();
1625
- process.exitCode = code;
474
+ const code = await run();
475
+ process.exitCode = code;
1626
476
  }
1627
- export {
1628
- isCliEntrypoint,
1629
- run
1630
- };
1631
477
  //# sourceMappingURL=main.js.map