specli 0.0.4 → 0.0.7
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/cli.ts +13 -4
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +2331 -0
- package/dist/cli.js.map +53 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2032 -0
- package/dist/index.js.map +48 -0
- package/dist/src/ai/tools.d.ts +139 -0
- package/dist/src/ai/tools.d.ts.map +1 -0
- package/dist/src/ai/tools.js +1656 -0
- package/dist/src/ai/tools.js.map +45 -0
- package/dist/src/cli/auth-requirements.d.ts +10 -0
- package/dist/src/cli/auth-requirements.d.ts.map +1 -0
- package/dist/src/cli/auth-requirements.js +66 -0
- package/dist/src/cli/auth-requirements.js.map +10 -0
- package/dist/src/cli/auth-schemes.d.ts +22 -0
- package/dist/src/cli/auth-schemes.d.ts.map +1 -0
- package/dist/src/cli/auth-schemes.js +116 -0
- package/dist/src/cli/auth-schemes.js.map +11 -0
- package/dist/src/cli/capabilities.d.ts +32 -0
- package/dist/src/cli/capabilities.d.ts.map +1 -0
- package/dist/src/cli/capabilities.js +45 -0
- package/dist/src/cli/capabilities.js.map +10 -0
- package/dist/src/cli/command-id.d.ts +8 -0
- package/dist/src/cli/command-id.d.ts.map +1 -0
- package/dist/src/cli/command-id.js +18 -0
- package/dist/src/cli/command-id.js.map +11 -0
- package/dist/src/cli/command-index.d.ts +6 -0
- package/dist/src/cli/command-index.d.ts.map +1 -0
- package/dist/src/cli/command-index.js +15 -0
- package/dist/src/cli/command-index.js.map +10 -0
- package/dist/src/cli/command-model.d.ts +40 -0
- package/dist/src/cli/command-model.d.ts.map +1 -0
- package/dist/src/cli/command-model.js +274 -0
- package/dist/src/cli/command-model.js.map +18 -0
- package/dist/src/cli/compile.d.ts +15 -0
- package/dist/src/cli/compile.d.ts.map +1 -0
- package/dist/src/cli/compile.js +146 -0
- package/dist/src/cli/compile.js.map +11 -0
- package/dist/src/cli/crypto.d.ts +2 -0
- package/dist/src/cli/crypto.d.ts.map +1 -0
- package/dist/src/cli/crypto.js +15 -0
- package/dist/src/cli/crypto.js.map +10 -0
- package/dist/src/cli/derive-name.d.ts +9 -0
- package/dist/src/cli/derive-name.d.ts.map +1 -0
- package/dist/src/cli/derive-name.js +70 -0
- package/dist/src/cli/derive-name.js.map +10 -0
- package/dist/src/cli/exec.d.ts +14 -0
- package/dist/src/cli/exec.d.ts.map +1 -0
- package/dist/src/cli/exec.js +2077 -0
- package/dist/src/cli/exec.js.map +49 -0
- package/dist/src/cli/main.d.ts +10 -0
- package/dist/src/cli/main.d.ts.map +1 -0
- package/dist/src/cli/main.js +2032 -0
- package/dist/src/cli/main.js.map +48 -0
- package/dist/src/cli/naming.d.ts +12 -0
- package/dist/src/cli/naming.d.ts.map +1 -0
- package/dist/src/cli/naming.js +216 -0
- package/dist/src/cli/naming.js.map +12 -0
- package/dist/src/cli/operations.d.ts +3 -0
- package/dist/src/cli/operations.d.ts.map +1 -0
- package/dist/src/cli/operations.js +103 -0
- package/dist/src/cli/operations.js.map +10 -0
- package/dist/src/cli/params.d.ts +19 -0
- package/dist/src/cli/params.d.ts.map +1 -0
- package/dist/src/cli/params.js +79 -0
- package/dist/src/cli/params.js.map +12 -0
- package/dist/src/cli/pluralize.d.ts +2 -0
- package/dist/src/cli/pluralize.d.ts.map +1 -0
- package/dist/src/cli/pluralize.js +43 -0
- package/dist/src/cli/pluralize.js.map +10 -0
- package/dist/src/cli/positional.d.ts +19 -0
- package/dist/src/cli/positional.d.ts.map +1 -0
- package/dist/src/cli/positional.js +39 -0
- package/dist/src/cli/positional.js.map +10 -0
- package/dist/src/cli/request-body.d.ts +20 -0
- package/dist/src/cli/request-body.d.ts.map +1 -0
- package/dist/src/cli/request-body.js +82 -0
- package/dist/src/cli/request-body.js.map +12 -0
- package/dist/src/cli/runtime/argv.d.ts +3 -0
- package/dist/src/cli/runtime/argv.d.ts.map +1 -0
- package/dist/src/cli/runtime/argv.js +22 -0
- package/dist/src/cli/runtime/argv.js.map +10 -0
- package/dist/src/cli/runtime/auth/resolve.d.ts +9 -0
- package/dist/src/cli/runtime/auth/resolve.d.ts.map +1 -0
- package/dist/src/cli/runtime/auth/resolve.js +38 -0
- package/dist/src/cli/runtime/auth/resolve.js.map +10 -0
- package/dist/src/cli/runtime/body-flags.d.ts +41 -0
- package/dist/src/cli/runtime/body-flags.d.ts.map +1 -0
- package/dist/src/cli/runtime/body-flags.js +86 -0
- package/dist/src/cli/runtime/body-flags.js.map +10 -0
- package/dist/src/cli/runtime/body.d.ts +15 -0
- package/dist/src/cli/runtime/body.d.ts.map +1 -0
- package/dist/src/cli/runtime/body.js +40 -0
- package/dist/src/cli/runtime/body.js.map +11 -0
- package/dist/src/cli/runtime/collect.d.ts +2 -0
- package/dist/src/cli/runtime/collect.d.ts.map +1 -0
- package/dist/src/cli/runtime/collect.js +9 -0
- package/dist/src/cli/runtime/collect.js.map +10 -0
- package/dist/src/cli/runtime/compat.d.ts +35 -0
- package/dist/src/cli/runtime/compat.d.ts.map +1 -0
- package/dist/src/cli/runtime/compat.js +62 -0
- package/dist/src/cli/runtime/compat.js.map +10 -0
- package/dist/src/cli/runtime/context.d.ts +16 -0
- package/dist/src/cli/runtime/context.d.ts.map +1 -0
- package/dist/src/cli/runtime/context.js +936 -0
- package/dist/src/cli/runtime/context.js.map +32 -0
- package/dist/src/cli/runtime/execute.d.ts +33 -0
- package/dist/src/cli/runtime/execute.d.ts.map +1 -0
- package/dist/src/cli/runtime/execute.js +670 -0
- package/dist/src/cli/runtime/execute.js.map +22 -0
- package/dist/src/cli/runtime/generated.d.ts +14 -0
- package/dist/src/cli/runtime/generated.d.ts.map +1 -0
- package/dist/src/cli/runtime/generated.js +869 -0
- package/dist/src/cli/runtime/generated.js.map +23 -0
- package/dist/src/cli/runtime/headers.d.ts +9 -0
- package/dist/src/cli/runtime/headers.d.ts.map +1 -0
- package/dist/src/cli/runtime/headers.js +36 -0
- package/dist/src/cli/runtime/headers.js.map +10 -0
- package/dist/src/cli/runtime/index.d.ts +4 -0
- package/dist/src/cli/runtime/index.d.ts.map +1 -0
- package/dist/src/cli/runtime/index.js +1808 -0
- package/dist/src/cli/runtime/index.js.map +46 -0
- package/dist/src/cli/runtime/profile/secrets.d.ts +25 -0
- package/dist/src/cli/runtime/profile/secrets.d.ts.map +1 -0
- package/dist/src/cli/runtime/profile/secrets.js +51 -0
- package/dist/src/cli/runtime/profile/secrets.js.map +11 -0
- package/dist/src/cli/runtime/profile/store.d.ts +15 -0
- package/dist/src/cli/runtime/profile/store.d.ts.map +1 -0
- package/dist/src/cli/runtime/profile/store.js +102 -0
- package/dist/src/cli/runtime/profile/store.js.map +11 -0
- package/dist/src/cli/runtime/request.d.ts +36 -0
- package/dist/src/cli/runtime/request.d.ts.map +1 -0
- package/dist/src/cli/runtime/request.js +571 -0
- package/dist/src/cli/runtime/request.js.map +21 -0
- package/dist/src/cli/runtime/server-url.d.ts +8 -0
- package/dist/src/cli/runtime/server-url.d.ts.map +1 -0
- package/dist/src/cli/runtime/server-url.js +55 -0
- package/dist/src/cli/runtime/server-url.js.map +11 -0
- package/dist/src/cli/runtime/template.d.ts +5 -0
- package/dist/src/cli/runtime/template.d.ts.map +1 -0
- package/dist/src/cli/runtime/template.js +29 -0
- package/dist/src/cli/runtime/template.js.map +10 -0
- package/dist/src/cli/runtime/validate/ajv.d.ts +3 -0
- package/dist/src/cli/runtime/validate/ajv.d.ts.map +1 -0
- package/dist/src/cli/runtime/validate/ajv.js +17 -0
- package/dist/src/cli/runtime/validate/ajv.js.map +10 -0
- package/dist/src/cli/runtime/validate/coerce.d.ts +4 -0
- package/dist/src/cli/runtime/validate/coerce.d.ts.map +1 -0
- package/dist/src/cli/runtime/validate/coerce.js +60 -0
- package/dist/src/cli/runtime/validate/coerce.js.map +10 -0
- package/dist/src/cli/runtime/validate/error.d.ts +3 -0
- package/dist/src/cli/runtime/validate/error.d.ts.map +1 -0
- package/dist/src/cli/runtime/validate/error.js +21 -0
- package/dist/src/cli/runtime/validate/error.js.map +10 -0
- package/dist/src/cli/runtime/validate/index.d.ts +5 -0
- package/dist/src/cli/runtime/validate/index.d.ts.map +1 -0
- package/dist/src/cli/runtime/validate/index.js +122 -0
- package/dist/src/cli/runtime/validate/index.js.map +13 -0
- package/dist/src/cli/runtime/validate/schema.d.ts +9 -0
- package/dist/src/cli/runtime/validate/schema.d.ts.map +1 -0
- package/dist/src/cli/runtime/validate/schema.js +36 -0
- package/dist/src/cli/runtime/validate/schema.js.map +10 -0
- package/dist/src/cli/schema-shape.d.ts +5 -0
- package/dist/src/cli/schema-shape.d.ts.map +1 -0
- package/dist/src/cli/schema-shape.js +41 -0
- package/dist/src/cli/schema-shape.js.map +10 -0
- package/dist/src/cli/schema.d.ts +30 -0
- package/dist/src/cli/schema.d.ts.map +1 -0
- package/dist/src/cli/schema.js +38 -0
- package/dist/src/cli/schema.js.map +10 -0
- package/dist/src/cli/server.d.ts +16 -0
- package/dist/src/cli/server.d.ts.map +1 -0
- package/dist/src/cli/server.js +64 -0
- package/dist/src/cli/server.js.map +11 -0
- package/dist/src/cli/spec-id.d.ts +3 -0
- package/dist/src/cli/spec-id.d.ts.map +1 -0
- package/dist/src/cli/spec-id.js +21 -0
- package/dist/src/cli/spec-id.js.map +11 -0
- package/dist/src/cli/spec-loader.d.ts +7 -0
- package/dist/src/cli/spec-loader.d.ts.map +1 -0
- package/dist/src/cli/spec-loader.js +110 -0
- package/dist/src/cli/spec-loader.js.map +15 -0
- package/dist/src/cli/stable-json.d.ts +4 -0
- package/dist/src/cli/stable-json.d.ts.map +1 -0
- package/dist/src/cli/stable-json.js +35 -0
- package/dist/src/cli/stable-json.js.map +10 -0
- package/dist/src/cli/strings.d.ts +3 -0
- package/dist/src/cli/strings.d.ts.map +1 -0
- package/dist/src/cli/strings.js +16 -0
- package/dist/src/cli/strings.js.map +10 -0
- package/dist/src/cli/types.d.ts +53 -0
- package/dist/src/cli/types.d.ts.map +1 -0
- package/dist/src/cli/types.js +9 -0
- package/dist/src/cli/types.js.map +10 -0
- package/package.json +31 -4
- package/src/ai/tools.ts +211 -0
- package/src/cli/main.ts +73 -163
- package/src/cli/runtime/auth/resolve.ts +20 -0
- package/src/cli/runtime/body.ts +3 -3
- package/src/cli/runtime/compat.ts +89 -0
- package/src/cli/runtime/execute.ts +98 -39
- package/src/cli/runtime/generated.ts +111 -4
- package/src/cli/runtime/profile/secrets.ts +42 -1
- package/src/cli/runtime/profile/store.ts +15 -13
- package/src/cli/runtime/request.ts +22 -11
- package/src/cli/spec-loader.ts +2 -2
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export type SpecSource = "embedded" | "file" | "url";
|
|
2
|
+
export type SecurityRequirement = Record<string, string[]>;
|
|
3
|
+
export type OpenApiDoc = {
|
|
4
|
+
openapi: string;
|
|
5
|
+
info?: {
|
|
6
|
+
title?: string;
|
|
7
|
+
version?: string;
|
|
8
|
+
};
|
|
9
|
+
servers?: Array<{
|
|
10
|
+
url: string;
|
|
11
|
+
description?: string;
|
|
12
|
+
variables?: unknown;
|
|
13
|
+
}>;
|
|
14
|
+
security?: SecurityRequirement[];
|
|
15
|
+
components?: {
|
|
16
|
+
securitySchemes?: Record<string, unknown>;
|
|
17
|
+
};
|
|
18
|
+
paths?: Record<string, unknown>;
|
|
19
|
+
};
|
|
20
|
+
export type NormalizedParameter = {
|
|
21
|
+
in: "path" | "query" | "header" | "cookie";
|
|
22
|
+
name: string;
|
|
23
|
+
required: boolean;
|
|
24
|
+
description?: string;
|
|
25
|
+
schema?: unknown;
|
|
26
|
+
};
|
|
27
|
+
export type JsonSchema = Record<string, unknown>;
|
|
28
|
+
export declare function isJsonSchema(value: unknown): value is JsonSchema;
|
|
29
|
+
export type NormalizedRequestBody = {
|
|
30
|
+
required: boolean;
|
|
31
|
+
contentTypes: string[];
|
|
32
|
+
schemasByContentType: Record<string, unknown | undefined>;
|
|
33
|
+
};
|
|
34
|
+
export type NormalizedOperation = {
|
|
35
|
+
key: string;
|
|
36
|
+
method: string;
|
|
37
|
+
path: string;
|
|
38
|
+
operationId?: string;
|
|
39
|
+
tags: string[];
|
|
40
|
+
summary?: string;
|
|
41
|
+
description?: string;
|
|
42
|
+
deprecated?: boolean;
|
|
43
|
+
security?: SecurityRequirement[];
|
|
44
|
+
parameters: NormalizedParameter[];
|
|
45
|
+
requestBody?: NormalizedRequestBody;
|
|
46
|
+
};
|
|
47
|
+
export type LoadedSpec = {
|
|
48
|
+
source: SpecSource;
|
|
49
|
+
id: string;
|
|
50
|
+
fingerprint: string;
|
|
51
|
+
doc: OpenApiDoc;
|
|
52
|
+
};
|
|
53
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/cli/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG,MAAM,GAAG,KAAK,CAAC;AAErD,MAAM,MAAM,mBAAmB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;AAE3D,MAAM,MAAM,UAAU,GAAG;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE;QACN,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,OAAO,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IAC5E,QAAQ,CAAC,EAAE,mBAAmB,EAAE,CAAC;IACjC,UAAU,CAAC,EAAE;QACZ,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KAC1C,CAAC;IACF,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IACjC,EAAE,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AAGF,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAEjD,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,UAAU,CAEhE;AAED,MAAM,MAAM,qBAAqB,GAAG;IACnC,QAAQ,EAAE,OAAO,CAAC;IAClB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,SAAS,CAAC,CAAC;CAC1D,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,mBAAmB,EAAE,CAAC;IACjC,UAAU,EAAE,mBAAmB,EAAE,CAAC;IAClC,WAAW,CAAC,EAAE,qBAAqB,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACxB,MAAM,EAAE,UAAU,CAAC;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,UAAU,CAAC;CAChB,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/cli/types.ts"],
|
|
4
|
+
"sourcesContent": [
|
|
5
|
+
"export type SpecSource = \"embedded\" | \"file\" | \"url\";\n\nexport type SecurityRequirement = Record<string, string[]>;\n\nexport type OpenApiDoc = {\n\topenapi: string;\n\tinfo?: {\n\t\ttitle?: string;\n\t\tversion?: string;\n\t};\n\tservers?: Array<{ url: string; description?: string; variables?: unknown }>;\n\tsecurity?: SecurityRequirement[];\n\tcomponents?: {\n\t\tsecuritySchemes?: Record<string, unknown>;\n\t};\n\tpaths?: Record<string, unknown>;\n};\n\nexport type NormalizedParameter = {\n\tin: \"path\" | \"query\" | \"header\" | \"cookie\";\n\tname: string;\n\trequired: boolean;\n\tdescription?: string;\n\tschema?: unknown;\n};\n\n// Minimal JSON Schema-like shape for validation and flag expansion.\nexport type JsonSchema = Record<string, unknown>;\n\nexport function isJsonSchema(value: unknown): value is JsonSchema {\n\treturn Boolean(value) && typeof value === \"object\" && !Array.isArray(value);\n}\n\nexport type NormalizedRequestBody = {\n\trequired: boolean;\n\tcontentTypes: string[];\n\tschemasByContentType: Record<string, unknown | undefined>;\n};\n\nexport type NormalizedOperation = {\n\tkey: string;\n\tmethod: string;\n\tpath: string;\n\toperationId?: string;\n\ttags: string[];\n\tsummary?: string;\n\tdescription?: string;\n\tdeprecated?: boolean;\n\tsecurity?: SecurityRequirement[];\n\tparameters: NormalizedParameter[];\n\trequestBody?: NormalizedRequestBody;\n};\n\nexport type LoadedSpec = {\n\tsource: SpecSource;\n\tid: string;\n\tfingerprint: string;\n\tdoc: OpenApiDoc;\n};\n"
|
|
6
|
+
],
|
|
7
|
+
"mappings": ";AA6BO,SAAS,YAAY,CAAC,OAAqC;AAAA,EACjE,OAAO,QAAQ,KAAK,KAAK,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK;AAAA;",
|
|
8
|
+
"debugId": "D591F75F6084972664756E2164756E21",
|
|
9
|
+
"names": []
|
|
10
|
+
}
|
package/package.json
CHANGED
|
@@ -1,18 +1,39 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "specli",
|
|
3
|
-
"
|
|
3
|
+
"version": "0.0.7",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
6
8
|
"bin": {
|
|
7
|
-
"specli": "./cli.
|
|
9
|
+
"specli": "./dist/cli.js"
|
|
10
|
+
},
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"bun": "./index.ts",
|
|
14
|
+
"import": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"default": "./dist/index.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"./ai/tools": {
|
|
20
|
+
"bun": "./src/ai/tools.ts",
|
|
21
|
+
"import": {
|
|
22
|
+
"types": "./dist/src/ai/tools.d.ts",
|
|
23
|
+
"default": "./dist/src/ai/tools.js"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
8
26
|
},
|
|
9
27
|
"files": [
|
|
28
|
+
"dist",
|
|
10
29
|
"cli.ts",
|
|
11
30
|
"index.ts",
|
|
12
31
|
"src",
|
|
13
32
|
"!**/*.test.ts"
|
|
14
33
|
],
|
|
15
34
|
"scripts": {
|
|
35
|
+
"build": "bun run scripts/build.ts",
|
|
36
|
+
"prepublishOnly": "bun run build",
|
|
16
37
|
"lint": "biome ci",
|
|
17
38
|
"lint:check": "biome check --write --unsafe",
|
|
18
39
|
"lint:format": "biome format --write",
|
|
@@ -21,6 +42,7 @@
|
|
|
21
42
|
"devDependencies": {
|
|
22
43
|
"@biomejs/biome": "^2.3.11",
|
|
23
44
|
"@types/bun": "^1.3.6",
|
|
45
|
+
"@types/node": "^22.19.7",
|
|
24
46
|
"@typescript/native-preview": "^7.0.0-dev.20260120.1"
|
|
25
47
|
},
|
|
26
48
|
"dependencies": {
|
|
@@ -28,6 +50,11 @@
|
|
|
28
50
|
"ajv": "^8.17.1",
|
|
29
51
|
"ajv-formats": "^3.0.1",
|
|
30
52
|
"commander": "^14.0.2",
|
|
31
|
-
"openapi-types": "^12.1.3"
|
|
53
|
+
"openapi-types": "^12.1.3",
|
|
54
|
+
"yaml": "^2.8.2"
|
|
55
|
+
},
|
|
56
|
+
"peerDependencies": {
|
|
57
|
+
"ai": "^6.0.42",
|
|
58
|
+
"zod": "^4.3.5"
|
|
32
59
|
}
|
|
33
60
|
}
|
package/src/ai/tools.ts
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI SDK tools for specli
|
|
3
|
+
*
|
|
4
|
+
* Provides tools for AI agents to explore and execute OpenAPI specs.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* import { specli } from "specli/ai";
|
|
9
|
+
* import { generateText } from "ai";
|
|
10
|
+
*
|
|
11
|
+
* const result = await generateText({
|
|
12
|
+
* model: yourModel,
|
|
13
|
+
* tools: {
|
|
14
|
+
* api: specli({ spec: "https://api.example.com/openapi.json" }),
|
|
15
|
+
* },
|
|
16
|
+
* prompt: "List all users",
|
|
17
|
+
* });
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { tool } from "ai";
|
|
22
|
+
import { z } from "zod";
|
|
23
|
+
|
|
24
|
+
import type { CommandAction } from "../cli/command-model.ts";
|
|
25
|
+
import { buildRuntimeContext } from "../cli/runtime/context.ts";
|
|
26
|
+
import { execute } from "../cli/runtime/execute.ts";
|
|
27
|
+
import type { RuntimeGlobals } from "../cli/runtime/request.ts";
|
|
28
|
+
|
|
29
|
+
export type SpecliToolOptions = {
|
|
30
|
+
/** The OpenAPI spec URL or file path */
|
|
31
|
+
spec: string;
|
|
32
|
+
/** Override the server/base URL */
|
|
33
|
+
server?: string;
|
|
34
|
+
/** Server URL template variables */
|
|
35
|
+
serverVars?: Record<string, string>;
|
|
36
|
+
/** Bearer token for authentication */
|
|
37
|
+
bearerToken?: string;
|
|
38
|
+
/** API key for authentication */
|
|
39
|
+
apiKey?: string;
|
|
40
|
+
/** Basic auth credentials */
|
|
41
|
+
basicAuth?: { username: string; password: string };
|
|
42
|
+
/** Auth scheme to use (if multiple are available) */
|
|
43
|
+
authScheme?: string;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// Cache contexts to avoid reloading spec on every call
|
|
47
|
+
const contextCache = new Map<
|
|
48
|
+
string,
|
|
49
|
+
Awaited<ReturnType<typeof buildRuntimeContext>>
|
|
50
|
+
>();
|
|
51
|
+
|
|
52
|
+
async function getContext(spec: string) {
|
|
53
|
+
let ctx = contextCache.get(spec);
|
|
54
|
+
if (!ctx) {
|
|
55
|
+
ctx = await buildRuntimeContext({ spec });
|
|
56
|
+
contextCache.set(spec, ctx);
|
|
57
|
+
}
|
|
58
|
+
return ctx;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function findAction(
|
|
62
|
+
ctx: Awaited<ReturnType<typeof buildRuntimeContext>>,
|
|
63
|
+
resource: string,
|
|
64
|
+
action: string,
|
|
65
|
+
): CommandAction | undefined {
|
|
66
|
+
const r = ctx.commands.resources.find(
|
|
67
|
+
(r) => r.resource.toLowerCase() === resource.toLowerCase(),
|
|
68
|
+
);
|
|
69
|
+
return r?.actions.find(
|
|
70
|
+
(a) => a.action.toLowerCase() === action.toLowerCase(),
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Create an AI SDK tool for interacting with an OpenAPI spec.
|
|
76
|
+
*/
|
|
77
|
+
export function specli(options: SpecliToolOptions) {
|
|
78
|
+
const {
|
|
79
|
+
spec,
|
|
80
|
+
server,
|
|
81
|
+
serverVars,
|
|
82
|
+
bearerToken,
|
|
83
|
+
apiKey,
|
|
84
|
+
basicAuth,
|
|
85
|
+
authScheme,
|
|
86
|
+
} = options;
|
|
87
|
+
|
|
88
|
+
return tool({
|
|
89
|
+
description: `Execute API operations. Commands: "list" (show resources/actions), "help" (action details), "exec" (call API).`,
|
|
90
|
+
inputSchema: z.object({
|
|
91
|
+
command: z.enum(["list", "help", "exec"]).describe("Command to run"),
|
|
92
|
+
resource: z.string().optional().describe("Resource name (e.g. users)"),
|
|
93
|
+
action: z
|
|
94
|
+
.string()
|
|
95
|
+
.optional()
|
|
96
|
+
.describe("Action name (e.g. list, get, create)"),
|
|
97
|
+
args: z.array(z.string()).optional().describe("Positional arguments"),
|
|
98
|
+
flags: z
|
|
99
|
+
.record(z.string(), z.unknown())
|
|
100
|
+
.optional()
|
|
101
|
+
.describe("Named flags"),
|
|
102
|
+
}),
|
|
103
|
+
execute: async ({ command, resource, action, args, flags }) => {
|
|
104
|
+
const ctx = await getContext(spec);
|
|
105
|
+
|
|
106
|
+
if (command === "list") {
|
|
107
|
+
return {
|
|
108
|
+
resources: ctx.commands.resources.map((r) => ({
|
|
109
|
+
name: r.resource,
|
|
110
|
+
actions: r.actions.map((a) => ({
|
|
111
|
+
name: a.action,
|
|
112
|
+
summary: a.summary,
|
|
113
|
+
method: a.method,
|
|
114
|
+
path: a.path,
|
|
115
|
+
args: a.positionals.map((p) => p.name),
|
|
116
|
+
requiredFlags: a.flags
|
|
117
|
+
.filter((f) => f.required)
|
|
118
|
+
.map((f) => f.flag),
|
|
119
|
+
})),
|
|
120
|
+
})),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (command === "help") {
|
|
125
|
+
if (!resource) return { error: "Missing resource" };
|
|
126
|
+
const r = ctx.commands.resources.find(
|
|
127
|
+
(r) => r.resource.toLowerCase() === resource.toLowerCase(),
|
|
128
|
+
);
|
|
129
|
+
if (!r) return { error: `Unknown resource: ${resource}` };
|
|
130
|
+
if (!action) {
|
|
131
|
+
return {
|
|
132
|
+
resource: r.resource,
|
|
133
|
+
actions: r.actions.map((a) => a.action),
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
const a = r.actions.find(
|
|
137
|
+
(a) => a.action.toLowerCase() === action.toLowerCase(),
|
|
138
|
+
);
|
|
139
|
+
if (!a) return { error: `Unknown action: ${action}` };
|
|
140
|
+
return {
|
|
141
|
+
action: a.action,
|
|
142
|
+
method: a.method,
|
|
143
|
+
path: a.path,
|
|
144
|
+
summary: a.summary,
|
|
145
|
+
args: a.positionals.map((p) => ({
|
|
146
|
+
name: p.name,
|
|
147
|
+
description: p.description,
|
|
148
|
+
})),
|
|
149
|
+
flags: a.flags.map((f) => ({
|
|
150
|
+
name: f.flag,
|
|
151
|
+
type: f.type,
|
|
152
|
+
required: f.required,
|
|
153
|
+
description: f.description,
|
|
154
|
+
})),
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (command === "exec") {
|
|
159
|
+
if (!resource || !action)
|
|
160
|
+
return { error: "Missing resource or action" };
|
|
161
|
+
const actionDef = findAction(ctx, resource, action);
|
|
162
|
+
if (!actionDef) return { error: `Unknown: ${resource} ${action}` };
|
|
163
|
+
|
|
164
|
+
const positionalValues = args ?? [];
|
|
165
|
+
if (positionalValues.length < actionDef.positionals.length) {
|
|
166
|
+
return {
|
|
167
|
+
error: `Missing args: ${actionDef.positionals
|
|
168
|
+
.slice(positionalValues.length)
|
|
169
|
+
.map((p) => p.name)
|
|
170
|
+
.join(", ")}`,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const globals: RuntimeGlobals = {
|
|
175
|
+
server,
|
|
176
|
+
serverVar: serverVars
|
|
177
|
+
? Object.entries(serverVars).map(([k, v]) => `${k}=${v}`)
|
|
178
|
+
: undefined,
|
|
179
|
+
auth: authScheme,
|
|
180
|
+
bearerToken,
|
|
181
|
+
apiKey,
|
|
182
|
+
username: basicAuth?.username,
|
|
183
|
+
password: basicAuth?.password,
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
try {
|
|
187
|
+
const result = await execute({
|
|
188
|
+
specId: ctx.loaded.id,
|
|
189
|
+
action: actionDef,
|
|
190
|
+
positionalValues,
|
|
191
|
+
flagValues: flags ?? {},
|
|
192
|
+
globals,
|
|
193
|
+
servers: ctx.servers,
|
|
194
|
+
authSchemes: ctx.authSchemes,
|
|
195
|
+
});
|
|
196
|
+
return { status: result.status, ok: result.ok, body: result.body };
|
|
197
|
+
} catch (err) {
|
|
198
|
+
return { error: err instanceof Error ? err.message : String(err) };
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return { error: `Unknown command: ${command}` };
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/** Clear cached spec context */
|
|
208
|
+
export function clearSpecliCache(spec?: string): void {
|
|
209
|
+
if (spec) contextCache.delete(spec);
|
|
210
|
+
else contextCache.clear();
|
|
211
|
+
}
|
package/src/cli/main.ts
CHANGED
|
@@ -2,13 +2,12 @@ import { Command } from "commander";
|
|
|
2
2
|
|
|
3
3
|
import { getArgValue, hasAnyArg } from "./runtime/argv.ts";
|
|
4
4
|
import { collectRepeatable } from "./runtime/collect.ts";
|
|
5
|
+
import { readStdinText } from "./runtime/compat.ts";
|
|
5
6
|
import { buildRuntimeContext } from "./runtime/context.ts";
|
|
6
7
|
import { addGeneratedCommands } from "./runtime/generated.ts";
|
|
7
8
|
import { deleteToken, getToken, setToken } from "./runtime/profile/secrets.ts";
|
|
8
9
|
import {
|
|
9
|
-
getProfile,
|
|
10
10
|
readProfiles,
|
|
11
|
-
removeProfile,
|
|
12
11
|
upsertProfile,
|
|
13
12
|
writeProfiles,
|
|
14
13
|
} from "./runtime/profile/store.ts";
|
|
@@ -42,7 +41,6 @@ export async function main(argv: string[], options: MainOptions = {}) {
|
|
|
42
41
|
.option("--username <username>", "Basic auth username")
|
|
43
42
|
.option("--password <password>", "Basic auth password")
|
|
44
43
|
.option("--api-key <key>", "API key value")
|
|
45
|
-
.option("--profile <name>", "Profile name (stored under ~/.config/specli)")
|
|
46
44
|
.option("--json", "Machine-readable output")
|
|
47
45
|
.showHelpAfterError();
|
|
48
46
|
|
|
@@ -63,197 +61,109 @@ export async function main(argv: string[], options: MainOptions = {}) {
|
|
|
63
61
|
embeddedSpecText: options.embeddedSpecText,
|
|
64
62
|
});
|
|
65
63
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
.description("Manage specli profiles");
|
|
64
|
+
// Simple auth commands
|
|
65
|
+
const defaultProfileName = "default";
|
|
69
66
|
|
|
70
|
-
|
|
71
|
-
.command("
|
|
72
|
-
.description("
|
|
73
|
-
.action(async (_opts, command) => {
|
|
67
|
+
program
|
|
68
|
+
.command("login [token]")
|
|
69
|
+
.description("Store a bearer token for authentication")
|
|
70
|
+
.action(async (tokenArg: string | undefined, _opts, command) => {
|
|
74
71
|
const globals = command.optsWithGlobals() as { json?: boolean };
|
|
75
|
-
const file = await readProfiles();
|
|
76
|
-
|
|
77
|
-
const payload = {
|
|
78
|
-
defaultProfile: file.defaultProfile,
|
|
79
|
-
profiles: file.profiles.map((p) => ({
|
|
80
|
-
name: p.name,
|
|
81
|
-
server: p.server,
|
|
82
|
-
authScheme: p.authScheme,
|
|
83
|
-
})),
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
if (globals.json) {
|
|
87
|
-
process.stdout.write(`${JSON.stringify(payload)}\n`);
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
72
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
process.
|
|
96
|
-
if (
|
|
97
|
-
|
|
98
|
-
process.stdout.write(
|
|
73
|
+
let token = tokenArg;
|
|
74
|
+
|
|
75
|
+
// If no token argument, try to read from stdin (for piping)
|
|
76
|
+
if (!token) {
|
|
77
|
+
const isTTY = process.stdin.isTTY;
|
|
78
|
+
if (isTTY) {
|
|
79
|
+
// Interactive mode - prompt user
|
|
80
|
+
process.stdout.write("Enter token: ");
|
|
81
|
+
const reader = process.stdin;
|
|
82
|
+
const chunks: Buffer[] = [];
|
|
83
|
+
for await (const chunk of reader) {
|
|
84
|
+
chunks.push(chunk);
|
|
85
|
+
// Read one line only
|
|
86
|
+
if (chunk.includes(10)) break; // newline
|
|
87
|
+
}
|
|
88
|
+
token = Buffer.concat(chunks).toString().trim();
|
|
89
|
+
} else {
|
|
90
|
+
// Piped input - use cross-runtime stdin reading
|
|
91
|
+
const text = await readStdinText();
|
|
92
|
+
token = text.trim();
|
|
93
|
+
}
|
|
99
94
|
}
|
|
100
|
-
});
|
|
101
95
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
.requiredOption("--name <name>", "Profile name")
|
|
106
|
-
.option("--server <url>", "Default server/base URL")
|
|
107
|
-
.option("--auth <scheme>", "Default auth scheme key")
|
|
108
|
-
.option("--default", "Set as default profile")
|
|
109
|
-
.action(async (opts, command) => {
|
|
110
|
-
const globals = command.optsWithGlobals() as {
|
|
111
|
-
json?: boolean;
|
|
112
|
-
server?: string;
|
|
113
|
-
auth?: string;
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
const file = await readProfiles();
|
|
117
|
-
const next = upsertProfile(file, {
|
|
118
|
-
name: String(opts.name),
|
|
119
|
-
server:
|
|
120
|
-
typeof opts.server === "string"
|
|
121
|
-
? opts.server
|
|
122
|
-
: typeof globals.server === "string"
|
|
123
|
-
? globals.server
|
|
124
|
-
: undefined,
|
|
125
|
-
authScheme:
|
|
126
|
-
typeof opts.auth === "string"
|
|
127
|
-
? opts.auth
|
|
128
|
-
: typeof globals.auth === "string"
|
|
129
|
-
? globals.auth
|
|
130
|
-
: undefined,
|
|
131
|
-
});
|
|
132
|
-
const final = opts.default
|
|
133
|
-
? { ...next, defaultProfile: String(opts.name) }
|
|
134
|
-
: next;
|
|
135
|
-
await writeProfiles(final);
|
|
136
|
-
|
|
137
|
-
if (globals.json) {
|
|
138
|
-
process.stdout.write(
|
|
139
|
-
`${JSON.stringify({ ok: true, profile: String(opts.name) })}\n`,
|
|
96
|
+
if (!token) {
|
|
97
|
+
throw new Error(
|
|
98
|
+
"No token provided. Usage: login <token> or echo $TOKEN | login",
|
|
140
99
|
);
|
|
141
|
-
return;
|
|
142
100
|
}
|
|
143
|
-
process.stdout.write(`ok: profile ${String(opts.name)}\n`);
|
|
144
|
-
});
|
|
145
101
|
|
|
146
|
-
|
|
147
|
-
.command("rm")
|
|
148
|
-
.description("Remove a profile")
|
|
149
|
-
.requiredOption("--name <name>", "Profile name")
|
|
150
|
-
.action(async (opts, command) => {
|
|
151
|
-
const globals = command.optsWithGlobals() as { json?: boolean };
|
|
102
|
+
// Ensure default profile exists
|
|
152
103
|
const file = await readProfiles();
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
104
|
+
if (!file.profiles.find((p) => p.name === defaultProfileName)) {
|
|
105
|
+
const updated = upsertProfile(file, { name: defaultProfileName });
|
|
106
|
+
await writeProfiles({ ...updated, defaultProfile: defaultProfileName });
|
|
107
|
+
} else if (!file.defaultProfile) {
|
|
108
|
+
await writeProfiles({ ...file, defaultProfile: defaultProfileName });
|
|
109
|
+
}
|
|
159
110
|
|
|
160
|
-
await
|
|
111
|
+
await setToken(ctx.loaded.id, defaultProfileName, token);
|
|
161
112
|
|
|
162
113
|
if (globals.json) {
|
|
163
|
-
process.stdout.write(
|
|
164
|
-
`${JSON.stringify({ ok: true, profile: String(opts.name) })}\n`,
|
|
165
|
-
);
|
|
114
|
+
process.stdout.write(`${JSON.stringify({ ok: true })}\n`);
|
|
166
115
|
return;
|
|
167
116
|
}
|
|
168
|
-
|
|
169
|
-
process.stdout.write(`ok: removed ${String(opts.name)}\n`);
|
|
117
|
+
process.stdout.write("ok: logged in\n");
|
|
170
118
|
});
|
|
171
119
|
|
|
172
|
-
|
|
173
|
-
.command("
|
|
174
|
-
.description("
|
|
175
|
-
.
|
|
176
|
-
.action(async (opts, command) => {
|
|
120
|
+
program
|
|
121
|
+
.command("logout")
|
|
122
|
+
.description("Clear stored authentication token")
|
|
123
|
+
.action(async (_opts, command) => {
|
|
177
124
|
const globals = command.optsWithGlobals() as { json?: boolean };
|
|
178
|
-
const file = await readProfiles();
|
|
179
|
-
const profile = getProfile(file, String(opts.name));
|
|
180
|
-
if (!profile) throw new Error(`Profile not found: ${String(opts.name)}`);
|
|
181
125
|
|
|
182
|
-
|
|
126
|
+
const deleted = await deleteToken(ctx.loaded.id, defaultProfileName);
|
|
183
127
|
|
|
184
128
|
if (globals.json) {
|
|
185
|
-
process.stdout.write(
|
|
186
|
-
`${JSON.stringify({ ok: true, defaultProfile: String(opts.name) })}\n`,
|
|
187
|
-
);
|
|
129
|
+
process.stdout.write(`${JSON.stringify({ ok: deleted })}\n`);
|
|
188
130
|
return;
|
|
189
131
|
}
|
|
190
|
-
process.stdout.write(
|
|
132
|
+
process.stdout.write(
|
|
133
|
+
deleted ? "ok: logged out\n" : "ok: not logged in\n",
|
|
134
|
+
);
|
|
191
135
|
});
|
|
192
136
|
|
|
193
|
-
|
|
137
|
+
program
|
|
138
|
+
.command("whoami")
|
|
139
|
+
.description("Show current authentication status")
|
|
140
|
+
.action(async (_opts, command) => {
|
|
141
|
+
const globals = command.optsWithGlobals() as { json?: boolean };
|
|
194
142
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
.description("Set or get bearer token for a profile")
|
|
198
|
-
.option("--name <name>", "Profile name (defaults to global --profile)")
|
|
199
|
-
.option("--set <token>", "Set token")
|
|
200
|
-
.option("--get", "Get token")
|
|
201
|
-
.option("--delete", "Delete token")
|
|
202
|
-
.action(async (opts, command) => {
|
|
203
|
-
const globals = command.optsWithGlobals() as {
|
|
204
|
-
json?: boolean;
|
|
205
|
-
profile?: string;
|
|
206
|
-
};
|
|
143
|
+
const token = await getToken(ctx.loaded.id, defaultProfileName);
|
|
144
|
+
const hasToken = Boolean(token);
|
|
207
145
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
if (opts.set && (opts.get || opts.delete)) {
|
|
215
|
-
throw new Error("Use only one of --set, --get, --delete");
|
|
216
|
-
}
|
|
217
|
-
if (opts.get && opts.delete) {
|
|
218
|
-
throw new Error("Use only one of --get or --delete");
|
|
219
|
-
}
|
|
220
|
-
if (!opts.set && !opts.get && !opts.delete) {
|
|
221
|
-
throw new Error("Provide one of --set, --get, --delete");
|
|
146
|
+
// Mask the token for display (show first 8 and last 4 chars)
|
|
147
|
+
let maskedToken: string | null = null;
|
|
148
|
+
if (token && token.length > 16) {
|
|
149
|
+
maskedToken = `${token.slice(0, 8)}...${token.slice(-4)}`;
|
|
150
|
+
} else if (token) {
|
|
151
|
+
maskedToken = `${token.slice(0, 4)}...`;
|
|
222
152
|
}
|
|
223
153
|
|
|
224
|
-
if (
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
`${JSON.stringify({ ok: true, profile: profileName })}\n`,
|
|
229
|
-
);
|
|
230
|
-
return;
|
|
231
|
-
}
|
|
232
|
-
process.stdout.write(`ok: token set for ${profileName}\n`);
|
|
233
|
-
return;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
if (opts.get) {
|
|
237
|
-
const token = await getToken(ctx.loaded.id, profileName);
|
|
238
|
-
if (globals.json) {
|
|
239
|
-
process.stdout.write(
|
|
240
|
-
`${JSON.stringify({ profile: profileName, token })}\n`,
|
|
241
|
-
);
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
process.stdout.write(`${token ?? ""}\n`);
|
|
154
|
+
if (globals.json) {
|
|
155
|
+
process.stdout.write(
|
|
156
|
+
`${JSON.stringify({ authenticated: hasToken, token: maskedToken })}\n`,
|
|
157
|
+
);
|
|
245
158
|
return;
|
|
246
159
|
}
|
|
247
160
|
|
|
248
|
-
if (
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
return;
|
|
255
|
-
}
|
|
256
|
-
process.stdout.write(`ok: ${ok ? "deleted" : "not-found"}\n`);
|
|
161
|
+
if (hasToken) {
|
|
162
|
+
process.stdout.write(`authenticated: yes\n`);
|
|
163
|
+
process.stdout.write(`token: ${maskedToken}\n`);
|
|
164
|
+
} else {
|
|
165
|
+
process.stdout.write(`authenticated: no\n`);
|
|
166
|
+
process.stdout.write(`Run 'login <token>' to authenticate.\n`);
|
|
257
167
|
}
|
|
258
168
|
});
|
|
259
169
|
|
|
@@ -4,8 +4,15 @@ export type AuthInputs = {
|
|
|
4
4
|
flagAuthScheme?: string;
|
|
5
5
|
profileAuthScheme?: string;
|
|
6
6
|
embeddedAuthScheme?: string;
|
|
7
|
+
hasStoredToken?: boolean;
|
|
7
8
|
};
|
|
8
9
|
|
|
10
|
+
const BEARER_COMPATIBLE_KINDS = new Set([
|
|
11
|
+
"http-bearer",
|
|
12
|
+
"oauth2",
|
|
13
|
+
"openIdConnect",
|
|
14
|
+
]);
|
|
15
|
+
|
|
9
16
|
export function resolveAuthScheme(
|
|
10
17
|
authSchemes: AuthScheme[],
|
|
11
18
|
required: import("../../auth-requirements.ts").AuthSummary,
|
|
@@ -35,5 +42,18 @@ export function resolveAuthScheme(
|
|
|
35
42
|
// Otherwise if there is only one scheme in spec, pick it.
|
|
36
43
|
if (authSchemes.length === 1) return authSchemes[0]?.key;
|
|
37
44
|
|
|
45
|
+
// If user has a stored token and operation accepts a bearer-compatible scheme,
|
|
46
|
+
// automatically pick the first one that matches.
|
|
47
|
+
if (inputs.hasStoredToken && alts.length > 0) {
|
|
48
|
+
for (const alt of alts) {
|
|
49
|
+
if (alt.length !== 1) continue;
|
|
50
|
+
const key = alt[0]?.key;
|
|
51
|
+
const scheme = authSchemes.find((s) => s.key === key);
|
|
52
|
+
if (scheme && BEARER_COMPATIBLE_KINDS.has(scheme.kind)) {
|
|
53
|
+
return key;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
38
58
|
return undefined;
|
|
39
59
|
}
|