@caplets/core 0.18.8 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/attach/options.d.ts +10 -0
- package/dist/attach/server.d.ts +5 -0
- package/dist/caplet-files-bundle.d.ts +415 -0
- package/dist/caplet-files.d.ts +3 -266
- package/dist/caplet-source/bundle.d.ts +7 -0
- package/dist/caplet-source/filesystem.d.ts +7 -0
- package/dist/caplet-source/filesystem.js +2 -0
- package/dist/caplet-source/index.d.ts +4 -0
- package/dist/caplet-source/parse.d.ts +35 -0
- package/dist/caplet-source/types.d.ts +9 -0
- package/dist/caplet-source.js +11231 -0
- package/dist/cli/commands.d.ts +9 -2
- package/dist/cli/doctor.d.ts +18 -0
- package/dist/cli/setup-caplet.d.ts +12 -0
- package/dist/cli/setup.d.ts +23 -0
- package/dist/cli.d.ts +9 -1
- package/dist/cloud/apply.d.ts +36 -0
- package/dist/cloud/client.d.ts +30 -0
- package/dist/cloud/presence.d.ts +29 -0
- package/dist/cloud/project-root.d.ts +2 -0
- package/dist/cloud/runtime-adapter.d.ts +23 -0
- package/dist/cloud/runtime-http.d.ts +6 -0
- package/dist/cloud/sync.d.ts +10 -0
- package/dist/cloud-auth/client.d.ts +42 -0
- package/dist/cloud-auth/errors.d.ts +11 -0
- package/dist/cloud-auth/open-url.d.ts +7 -0
- package/dist/cloud-auth/store.d.ts +35 -0
- package/dist/cloud-auth/types.d.ts +66 -0
- package/dist/{completion-DvWQk5qR.js → completion-brgziz4L.js} +32 -6
- package/dist/config-runtime.d.ts +174 -0
- package/dist/config-runtime.js +392 -0
- package/dist/config.d.ts +42 -0
- package/dist/filesystem-Kkg32TOJ.js +66 -0
- package/dist/generated-tool-input-schema.d.ts +9 -9
- package/dist/generated-tool-input-schema.js +161 -1
- package/dist/index.d.ts +35 -0
- package/dist/index.js +6132 -3196
- package/dist/native/options.d.ts +22 -3
- package/dist/native/remote.d.ts +2 -1
- package/dist/native/service.d.ts +7 -3
- package/dist/native.js +2 -430
- package/dist/project-binding/attach.d.ts +46 -0
- package/dist/project-binding/errors.d.ts +17 -0
- package/dist/project-binding/gitignore.d.ts +5 -0
- package/dist/project-binding/mutagen.d.ts +65 -0
- package/dist/project-binding/routes.d.ts +9 -0
- package/dist/project-binding/session.d.ts +82 -0
- package/dist/project-binding/sync-filter.d.ts +19 -0
- package/dist/project-binding/sync-size.d.ts +27 -0
- package/dist/project-binding/transport.d.ts +21 -0
- package/dist/project-binding/types.d.ts +31 -0
- package/dist/project-binding/workspaces.d.ts +60 -0
- package/dist/remote/options.d.ts +42 -0
- package/dist/remote/selection.d.ts +26 -0
- package/dist/remote-control/types.d.ts +1 -1
- package/dist/runtime-plan/features.d.ts +7 -0
- package/dist/runtime-plan/index.d.ts +4 -0
- package/dist/runtime-plan/planner.d.ts +5 -0
- package/dist/runtime-plan/resources.d.ts +11 -0
- package/dist/runtime-plan/types.d.ts +82 -0
- package/dist/runtime-plan.js +275 -0
- package/dist/{generated-tool-input-schema-MbYF5jMW.js → schemas-BZ6BBrh7.js} +1 -161
- package/dist/serve/daemon/config.d.ts +8 -0
- package/dist/serve/daemon/index.d.ts +16 -0
- package/dist/serve/daemon/paths.d.ts +3 -0
- package/dist/serve/daemon/platform-darwin.d.ts +2 -0
- package/dist/serve/daemon/platform-linux.d.ts +2 -0
- package/dist/serve/daemon/platform-windows.d.ts +2 -0
- package/dist/serve/daemon/platform.d.ts +9 -0
- package/dist/serve/daemon/process.d.ts +5 -0
- package/dist/serve/daemon/types.d.ts +86 -0
- package/dist/serve/http.d.ts +8 -0
- package/dist/serve/index.d.ts +5 -1
- package/dist/serve/native-session.d.ts +19 -0
- package/dist/serve/options.d.ts +1 -0
- package/dist/server/options.d.ts +1 -1
- package/dist/{options--RoZwWjs.js → service-BXcE4Rv8.js} +9932 -2218
- package/dist/setup/hash.d.ts +3 -0
- package/dist/setup/local-store.d.ts +34 -0
- package/dist/setup/runner.d.ts +40 -0
- package/dist/setup/types.d.ts +52 -0
- package/dist/tools.d.ts +17 -2
- package/dist/validation-BBG4skZf.js +153 -0
- package/package.json +21 -5
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
export type RemoteAuthConfig = {
|
|
2
|
+
type: "none";
|
|
3
|
+
} | {
|
|
4
|
+
type: "bearer";
|
|
5
|
+
token: string;
|
|
6
|
+
} | {
|
|
7
|
+
type: "headers";
|
|
8
|
+
headers: Record<string, string>;
|
|
9
|
+
} | {
|
|
10
|
+
type: "oauth2" | "oidc";
|
|
11
|
+
authorizationUrl?: string | undefined;
|
|
12
|
+
tokenUrl?: string | undefined;
|
|
13
|
+
issuer?: string | undefined;
|
|
14
|
+
resourceMetadataUrl?: string | undefined;
|
|
15
|
+
authorizationServerMetadataUrl?: string | undefined;
|
|
16
|
+
openidConfigurationUrl?: string | undefined;
|
|
17
|
+
clientMetadataUrl?: string | undefined;
|
|
18
|
+
clientId?: string | undefined;
|
|
19
|
+
clientSecret?: string | undefined;
|
|
20
|
+
scopes?: string[] | undefined;
|
|
21
|
+
redirectUri?: string | undefined;
|
|
22
|
+
};
|
|
23
|
+
export type CapletSetupCommandConfig = {
|
|
24
|
+
label: string;
|
|
25
|
+
command: string;
|
|
26
|
+
args?: string[] | undefined;
|
|
27
|
+
env?: Record<string, string> | undefined;
|
|
28
|
+
cwd?: string | undefined;
|
|
29
|
+
timeoutMs?: number | undefined;
|
|
30
|
+
maxOutputBytes?: number | undefined;
|
|
31
|
+
};
|
|
32
|
+
export type CapletSetupConfig = {
|
|
33
|
+
commands?: CapletSetupCommandConfig[] | undefined;
|
|
34
|
+
verify?: CapletSetupCommandConfig[] | undefined;
|
|
35
|
+
};
|
|
36
|
+
export type ProjectBindingConfig = {
|
|
37
|
+
required: true;
|
|
38
|
+
};
|
|
39
|
+
export type RuntimeFeature = "docker" | "browser";
|
|
40
|
+
export type RuntimeResourceClass = "standard" | "large" | "heavy";
|
|
41
|
+
export type RuntimeRequirementsConfig = {
|
|
42
|
+
features?: RuntimeFeature[] | undefined;
|
|
43
|
+
resources?: {
|
|
44
|
+
class?: RuntimeResourceClass | undefined;
|
|
45
|
+
} | undefined;
|
|
46
|
+
};
|
|
47
|
+
export type CapletServerConfig = CommonCapletConfig & {
|
|
48
|
+
backend: "mcp";
|
|
49
|
+
transport: "stdio" | "http" | "sse";
|
|
50
|
+
command?: string | undefined;
|
|
51
|
+
args?: string[] | undefined;
|
|
52
|
+
env?: Record<string, string> | undefined;
|
|
53
|
+
cwd?: string | undefined;
|
|
54
|
+
url?: string | undefined;
|
|
55
|
+
auth?: RemoteAuthConfig | undefined;
|
|
56
|
+
startupTimeoutMs: number;
|
|
57
|
+
callTimeoutMs: number;
|
|
58
|
+
toolCacheTtlMs: number;
|
|
59
|
+
};
|
|
60
|
+
export type OpenApiAuthConfig = RemoteAuthConfig;
|
|
61
|
+
export type OpenApiEndpointConfig = CommonCapletConfig & {
|
|
62
|
+
backend: "openapi";
|
|
63
|
+
specPath?: string | undefined;
|
|
64
|
+
specUrl?: string | undefined;
|
|
65
|
+
baseUrl?: string | undefined;
|
|
66
|
+
auth: OpenApiAuthConfig;
|
|
67
|
+
requestTimeoutMs: number;
|
|
68
|
+
operationCacheTtlMs: number;
|
|
69
|
+
};
|
|
70
|
+
export type GraphQlOperationConfig = {
|
|
71
|
+
document?: string | undefined;
|
|
72
|
+
documentPath?: string | undefined;
|
|
73
|
+
operationName?: string | undefined;
|
|
74
|
+
description?: string | undefined;
|
|
75
|
+
};
|
|
76
|
+
export type GraphQlEndpointConfig = CommonCapletConfig & {
|
|
77
|
+
backend: "graphql";
|
|
78
|
+
endpointUrl: string;
|
|
79
|
+
schemaPath?: string | undefined;
|
|
80
|
+
schemaUrl?: string | undefined;
|
|
81
|
+
introspection?: true | undefined;
|
|
82
|
+
operations?: Record<string, GraphQlOperationConfig> | undefined;
|
|
83
|
+
auth: OpenApiAuthConfig;
|
|
84
|
+
requestTimeoutMs: number;
|
|
85
|
+
operationCacheTtlMs: number;
|
|
86
|
+
selectionDepth: number;
|
|
87
|
+
};
|
|
88
|
+
export type HttpActionConfig = {
|
|
89
|
+
method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
90
|
+
path: string;
|
|
91
|
+
description?: string | undefined;
|
|
92
|
+
inputSchema?: Record<string, unknown> | undefined;
|
|
93
|
+
outputSchema?: Record<string, unknown> | undefined;
|
|
94
|
+
query?: Record<string, string | number | boolean> | undefined;
|
|
95
|
+
headers?: Record<string, string | number | boolean> | undefined;
|
|
96
|
+
jsonBody?: unknown;
|
|
97
|
+
};
|
|
98
|
+
export type HttpApiConfig = CommonCapletConfig & {
|
|
99
|
+
backend: "http";
|
|
100
|
+
baseUrl: string;
|
|
101
|
+
auth: OpenApiAuthConfig;
|
|
102
|
+
actions: Record<string, HttpActionConfig>;
|
|
103
|
+
requestTimeoutMs: number;
|
|
104
|
+
maxResponseBytes: number;
|
|
105
|
+
};
|
|
106
|
+
export type CliToolActionConfig = {
|
|
107
|
+
description?: string | undefined;
|
|
108
|
+
inputSchema?: Record<string, unknown> | undefined;
|
|
109
|
+
outputSchema?: Record<string, unknown> | undefined;
|
|
110
|
+
command: string;
|
|
111
|
+
args?: string[] | undefined;
|
|
112
|
+
env?: Record<string, string> | undefined;
|
|
113
|
+
cwd?: string | undefined;
|
|
114
|
+
timeoutMs?: number | undefined;
|
|
115
|
+
maxOutputBytes?: number | undefined;
|
|
116
|
+
output?: {
|
|
117
|
+
type: "text" | "json";
|
|
118
|
+
} | undefined;
|
|
119
|
+
annotations?: {
|
|
120
|
+
readOnlyHint?: boolean | undefined;
|
|
121
|
+
destructiveHint?: boolean | undefined;
|
|
122
|
+
idempotentHint?: boolean | undefined;
|
|
123
|
+
openWorldHint?: boolean | undefined;
|
|
124
|
+
} | undefined;
|
|
125
|
+
};
|
|
126
|
+
export type CliToolsConfig = CommonCapletConfig & {
|
|
127
|
+
backend: "cli";
|
|
128
|
+
actions: Record<string, CliToolActionConfig>;
|
|
129
|
+
cwd?: string | undefined;
|
|
130
|
+
env?: Record<string, string> | undefined;
|
|
131
|
+
timeoutMs: number;
|
|
132
|
+
maxOutputBytes: number;
|
|
133
|
+
};
|
|
134
|
+
export type CapletSetConfig = CommonCapletConfig & {
|
|
135
|
+
backend: "caplets";
|
|
136
|
+
configPath?: string | undefined;
|
|
137
|
+
capletsRoot?: string | undefined;
|
|
138
|
+
defaultSearchLimit: number;
|
|
139
|
+
maxSearchLimit: number;
|
|
140
|
+
toolCacheTtlMs: number;
|
|
141
|
+
};
|
|
142
|
+
export type CapletConfig = CapletServerConfig | OpenApiEndpointConfig | GraphQlEndpointConfig | HttpApiConfig | CliToolsConfig | CapletSetConfig;
|
|
143
|
+
export type CapletsConfig = {
|
|
144
|
+
version: 1;
|
|
145
|
+
options: {
|
|
146
|
+
defaultSearchLimit: number;
|
|
147
|
+
maxSearchLimit: number;
|
|
148
|
+
completion: {
|
|
149
|
+
discoveryTimeoutMs: number;
|
|
150
|
+
overallTimeoutMs: number;
|
|
151
|
+
cacheTtlMs: number;
|
|
152
|
+
negativeCacheTtlMs: number;
|
|
153
|
+
};
|
|
154
|
+
};
|
|
155
|
+
mcpServers: Record<string, CapletServerConfig>;
|
|
156
|
+
openapiEndpoints: Record<string, OpenApiEndpointConfig>;
|
|
157
|
+
graphqlEndpoints: Record<string, GraphQlEndpointConfig>;
|
|
158
|
+
httpApis: Record<string, HttpApiConfig>;
|
|
159
|
+
cliTools: Record<string, CliToolsConfig>;
|
|
160
|
+
capletSets: Record<string, CapletSetConfig>;
|
|
161
|
+
};
|
|
162
|
+
type CommonCapletConfig = {
|
|
163
|
+
server: string;
|
|
164
|
+
name: string;
|
|
165
|
+
description: string;
|
|
166
|
+
tags?: string[] | undefined;
|
|
167
|
+
body?: string | undefined;
|
|
168
|
+
setup?: CapletSetupConfig | undefined;
|
|
169
|
+
projectBinding?: ProjectBindingConfig | undefined;
|
|
170
|
+
runtime?: RuntimeRequirementsConfig | undefined;
|
|
171
|
+
disabled: boolean;
|
|
172
|
+
};
|
|
173
|
+
export declare function parseConfig(input: unknown): CapletsConfig;
|
|
174
|
+
export {};
|
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
import { a as isAllowedHttpBaseUrl, c as validateHttpActionHeaders, i as SERVER_ID_PATTERN, n as HEADER_NAME_PATTERN, o as isAllowedRemoteUrl, r as HTTP_BASE_URL_PATTERN, s as isUrl, t as FORBIDDEN_HEADERS, u as CapletsError } from "./validation-BBG4skZf.js";
|
|
2
|
+
import { _ as record, b as unknown, d as literal, l as discriminatedUnion, m as object, o as array, p as number, r as _enum, s as boolean, v as string, y as union } from "./schemas-BZ6BBrh7.js";
|
|
3
|
+
//#region src/config-runtime.ts
|
|
4
|
+
const stringMapSchema = record(string(), string());
|
|
5
|
+
const authSchema = discriminatedUnion("type", [
|
|
6
|
+
object({ type: literal("none") }).strict(),
|
|
7
|
+
object({
|
|
8
|
+
type: literal("bearer"),
|
|
9
|
+
token: string().min(1)
|
|
10
|
+
}).strict(),
|
|
11
|
+
object({
|
|
12
|
+
type: literal("headers"),
|
|
13
|
+
headers: stringMapSchema
|
|
14
|
+
}).strict(),
|
|
15
|
+
oauthLikeSchema("oauth2"),
|
|
16
|
+
oauthLikeSchema("oidc")
|
|
17
|
+
]);
|
|
18
|
+
const setupCommandSchema = object({
|
|
19
|
+
label: string().min(1),
|
|
20
|
+
command: string().min(1),
|
|
21
|
+
args: array(string()).optional(),
|
|
22
|
+
env: stringMapSchema.optional(),
|
|
23
|
+
cwd: string().min(1).optional(),
|
|
24
|
+
timeoutMs: number().int().positive().optional(),
|
|
25
|
+
maxOutputBytes: number().int().positive().optional()
|
|
26
|
+
}).strict();
|
|
27
|
+
const setupSchema = object({
|
|
28
|
+
commands: array(setupCommandSchema).optional(),
|
|
29
|
+
verify: array(setupCommandSchema).optional()
|
|
30
|
+
}).strict().refine((setup) => (setup.commands?.length ?? 0) > 0 || (setup.verify?.length ?? 0) > 0, "setup must define at least one command or verify step");
|
|
31
|
+
const projectBindingSchema = object({ required: literal(true) }).strict();
|
|
32
|
+
const runtimeRequirementsSchema = object({
|
|
33
|
+
features: array(_enum(["docker", "browser"])).refine((features) => new Set(features).size === features.length, { message: "runtime.features must not contain duplicate feature names" }).optional(),
|
|
34
|
+
resources: object({ class: _enum([
|
|
35
|
+
"standard",
|
|
36
|
+
"large",
|
|
37
|
+
"heavy"
|
|
38
|
+
]).optional() }).strict().optional()
|
|
39
|
+
}).strict();
|
|
40
|
+
const commonSchema = {
|
|
41
|
+
name: string().trim().min(1).max(80),
|
|
42
|
+
description: string().refine((value) => value.trim().length >= 10, "description must contain at least 10 non-whitespace characters").refine((value) => value.length <= 1500, "description must be at most 1500 characters"),
|
|
43
|
+
tags: array(string().trim().min(1).max(80)).optional(),
|
|
44
|
+
body: string().optional(),
|
|
45
|
+
setup: setupSchema.optional(),
|
|
46
|
+
projectBinding: projectBindingSchema.optional(),
|
|
47
|
+
runtime: runtimeRequirementsSchema.optional(),
|
|
48
|
+
disabled: boolean().default(false)
|
|
49
|
+
};
|
|
50
|
+
const mcpServerSchema = object({
|
|
51
|
+
...commonSchema,
|
|
52
|
+
transport: _enum([
|
|
53
|
+
"stdio",
|
|
54
|
+
"http",
|
|
55
|
+
"sse"
|
|
56
|
+
]).optional(),
|
|
57
|
+
command: string().min(1).optional(),
|
|
58
|
+
args: array(string()).optional(),
|
|
59
|
+
env: stringMapSchema.optional(),
|
|
60
|
+
cwd: string().min(1).optional(),
|
|
61
|
+
url: string().min(1).optional(),
|
|
62
|
+
auth: authSchema.optional(),
|
|
63
|
+
startupTimeoutMs: number().int().positive().default(1e4),
|
|
64
|
+
callTimeoutMs: number().int().positive().default(6e4),
|
|
65
|
+
toolCacheTtlMs: number().int().nonnegative().default(3e4)
|
|
66
|
+
}).strict();
|
|
67
|
+
const openApiEndpointSchema = object({
|
|
68
|
+
...commonSchema,
|
|
69
|
+
specPath: string().min(1).optional(),
|
|
70
|
+
specUrl: string().min(1).optional(),
|
|
71
|
+
baseUrl: string().min(1).optional(),
|
|
72
|
+
auth: authSchema,
|
|
73
|
+
requestTimeoutMs: number().int().positive().default(6e4),
|
|
74
|
+
operationCacheTtlMs: number().int().nonnegative().default(3e4)
|
|
75
|
+
}).strict();
|
|
76
|
+
const graphQlOperationSchema = object({
|
|
77
|
+
document: string().min(1).optional(),
|
|
78
|
+
documentPath: string().min(1).optional(),
|
|
79
|
+
operationName: string().min(1).optional(),
|
|
80
|
+
description: string().min(1).optional()
|
|
81
|
+
}).strict().refine((operation) => Boolean(operation.document) !== Boolean(operation.documentPath), { message: "GraphQL operation must define exactly one document source" });
|
|
82
|
+
const graphQlEndpointSchema = object({
|
|
83
|
+
...commonSchema,
|
|
84
|
+
endpointUrl: string().min(1),
|
|
85
|
+
schemaPath: string().min(1).optional(),
|
|
86
|
+
schemaUrl: string().min(1).optional(),
|
|
87
|
+
introspection: literal(true).optional(),
|
|
88
|
+
operations: record(string().regex(SERVER_ID_PATTERN), graphQlOperationSchema).optional(),
|
|
89
|
+
auth: authSchema,
|
|
90
|
+
requestTimeoutMs: number().int().positive().default(6e4),
|
|
91
|
+
operationCacheTtlMs: number().int().nonnegative().default(3e4),
|
|
92
|
+
selectionDepth: number().int().positive().max(5).default(2)
|
|
93
|
+
}).strict();
|
|
94
|
+
const scalarMapSchema = record(string(), union([
|
|
95
|
+
string(),
|
|
96
|
+
number(),
|
|
97
|
+
boolean()
|
|
98
|
+
]));
|
|
99
|
+
const httpActionSchema = object({
|
|
100
|
+
method: _enum([
|
|
101
|
+
"GET",
|
|
102
|
+
"POST",
|
|
103
|
+
"PUT",
|
|
104
|
+
"PATCH",
|
|
105
|
+
"DELETE"
|
|
106
|
+
]),
|
|
107
|
+
path: string().min(1).regex(/^\//, "HTTP action path must start with /").refine((value) => !value.startsWith("//"), "HTTP action path must not start with //").refine((value) => !isUrl(value), "HTTP action path must be a URL path, not a URL"),
|
|
108
|
+
description: string().min(1).optional(),
|
|
109
|
+
inputSchema: record(string(), unknown()).optional(),
|
|
110
|
+
outputSchema: record(string(), unknown()).optional(),
|
|
111
|
+
query: scalarMapSchema.optional(),
|
|
112
|
+
headers: scalarMapSchema.optional(),
|
|
113
|
+
jsonBody: unknown().optional()
|
|
114
|
+
}).strict().refine((action) => action.method !== "GET" || action.jsonBody === void 0, {
|
|
115
|
+
path: ["jsonBody"],
|
|
116
|
+
message: "HTTP GET actions must not define jsonBody"
|
|
117
|
+
});
|
|
118
|
+
const httpApiSchema = object({
|
|
119
|
+
...commonSchema,
|
|
120
|
+
baseUrl: string().min(1).regex(HTTP_BASE_URL_PATTERN, "HTTP API baseUrl must not include credentials, query, or fragment"),
|
|
121
|
+
auth: authSchema,
|
|
122
|
+
actions: record(string().regex(SERVER_ID_PATTERN), httpActionSchema).refine((actions) => Object.keys(actions).length > 0, "HTTP API must define at least one action"),
|
|
123
|
+
requestTimeoutMs: number().int().positive().default(6e4),
|
|
124
|
+
maxResponseBytes: number().int().positive().default(2e5)
|
|
125
|
+
}).strict();
|
|
126
|
+
const cliActionSchema = object({
|
|
127
|
+
description: string().min(1).optional(),
|
|
128
|
+
inputSchema: record(string(), unknown()).optional(),
|
|
129
|
+
outputSchema: record(string(), unknown()).optional(),
|
|
130
|
+
command: string().min(1),
|
|
131
|
+
args: array(string()).optional(),
|
|
132
|
+
env: stringMapSchema.optional(),
|
|
133
|
+
cwd: string().min(1).optional(),
|
|
134
|
+
timeoutMs: number().int().positive().optional(),
|
|
135
|
+
maxOutputBytes: number().int().positive().optional(),
|
|
136
|
+
output: object({ type: _enum(["text", "json"]).default("text") }).strict().optional(),
|
|
137
|
+
annotations: object({
|
|
138
|
+
readOnlyHint: boolean().optional(),
|
|
139
|
+
destructiveHint: boolean().optional(),
|
|
140
|
+
idempotentHint: boolean().optional(),
|
|
141
|
+
openWorldHint: boolean().optional()
|
|
142
|
+
}).strict().optional()
|
|
143
|
+
}).strict();
|
|
144
|
+
const cliToolsSchema = object({
|
|
145
|
+
...commonSchema,
|
|
146
|
+
actions: record(string().regex(SERVER_ID_PATTERN), cliActionSchema).refine((actions) => Object.keys(actions).length > 0, "CLI tools backend must define at least one action"),
|
|
147
|
+
cwd: string().min(1).optional(),
|
|
148
|
+
env: stringMapSchema.optional(),
|
|
149
|
+
timeoutMs: number().int().positive().default(6e4),
|
|
150
|
+
maxOutputBytes: number().int().positive().default(2e5)
|
|
151
|
+
}).strict();
|
|
152
|
+
const capletSetSchema = object({
|
|
153
|
+
...commonSchema,
|
|
154
|
+
configPath: string().min(1).optional(),
|
|
155
|
+
capletsRoot: string().min(1).optional(),
|
|
156
|
+
defaultSearchLimit: number().int().positive().default(20),
|
|
157
|
+
maxSearchLimit: number().int().positive().max(50).default(50),
|
|
158
|
+
toolCacheTtlMs: number().int().nonnegative().default(3e4)
|
|
159
|
+
}).strict();
|
|
160
|
+
const configSchema = object({
|
|
161
|
+
version: literal(1).default(1),
|
|
162
|
+
defaultSearchLimit: number().int().positive().default(20),
|
|
163
|
+
maxSearchLimit: number().int().positive().max(50).default(50),
|
|
164
|
+
completion: object({
|
|
165
|
+
discoveryTimeoutMs: number().int().positive().default(750),
|
|
166
|
+
overallTimeoutMs: number().int().positive().default(1500),
|
|
167
|
+
cacheTtlMs: number().int().nonnegative().default(3e5),
|
|
168
|
+
negativeCacheTtlMs: number().int().nonnegative().default(3e4)
|
|
169
|
+
}).strict().default({
|
|
170
|
+
discoveryTimeoutMs: 750,
|
|
171
|
+
overallTimeoutMs: 1500,
|
|
172
|
+
cacheTtlMs: 3e5,
|
|
173
|
+
negativeCacheTtlMs: 3e4
|
|
174
|
+
}),
|
|
175
|
+
mcpServers: record(string().regex(SERVER_ID_PATTERN), mcpServerSchema).default({}),
|
|
176
|
+
openapiEndpoints: record(string().regex(SERVER_ID_PATTERN), openApiEndpointSchema).default({}),
|
|
177
|
+
graphqlEndpoints: record(string().regex(SERVER_ID_PATTERN), graphQlEndpointSchema).default({}),
|
|
178
|
+
httpApis: record(string().regex(SERVER_ID_PATTERN), httpApiSchema).default({}),
|
|
179
|
+
cliTools: record(string().regex(SERVER_ID_PATTERN), cliToolsSchema).default({}),
|
|
180
|
+
capletSets: record(string().regex(SERVER_ID_PATTERN), capletSetSchema).default({})
|
|
181
|
+
}).strict().superRefine((config, ctx) => {
|
|
182
|
+
if (config.defaultSearchLimit > config.maxSearchLimit) ctx.addIssue({
|
|
183
|
+
code: "custom",
|
|
184
|
+
path: ["defaultSearchLimit"],
|
|
185
|
+
message: "defaultSearchLimit must be <= maxSearchLimit"
|
|
186
|
+
});
|
|
187
|
+
validateBackends(config, ctx);
|
|
188
|
+
});
|
|
189
|
+
function parseConfig(input) {
|
|
190
|
+
const parsed = configSchema.safeParse(input);
|
|
191
|
+
if (!parsed.success) throw new CapletsError("CONFIG_INVALID", "Caplets config is invalid", parsed.error.issues);
|
|
192
|
+
const config = parsed.data;
|
|
193
|
+
return {
|
|
194
|
+
version: 1,
|
|
195
|
+
options: {
|
|
196
|
+
defaultSearchLimit: config.defaultSearchLimit,
|
|
197
|
+
maxSearchLimit: config.maxSearchLimit,
|
|
198
|
+
completion: config.completion
|
|
199
|
+
},
|
|
200
|
+
mcpServers: mapBackend(config.mcpServers, "mcp", (id, raw) => {
|
|
201
|
+
const server = raw;
|
|
202
|
+
return {
|
|
203
|
+
...server,
|
|
204
|
+
server: id,
|
|
205
|
+
transport: server.transport ?? (server.command ? "stdio" : "http")
|
|
206
|
+
};
|
|
207
|
+
}),
|
|
208
|
+
openapiEndpoints: mapBackend(config.openapiEndpoints, "openapi"),
|
|
209
|
+
graphqlEndpoints: mapBackend(config.graphqlEndpoints, "graphql"),
|
|
210
|
+
httpApis: mapBackend(config.httpApis, "http"),
|
|
211
|
+
cliTools: mapBackend(config.cliTools, "cli"),
|
|
212
|
+
capletSets: mapBackend(config.capletSets, "caplets")
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
function oauthLikeSchema(type) {
|
|
216
|
+
return object({
|
|
217
|
+
type: literal(type),
|
|
218
|
+
authorizationUrl: string().min(1).optional(),
|
|
219
|
+
tokenUrl: string().min(1).optional(),
|
|
220
|
+
issuer: string().min(1).optional(),
|
|
221
|
+
resourceMetadataUrl: string().min(1).optional(),
|
|
222
|
+
authorizationServerMetadataUrl: string().min(1).optional(),
|
|
223
|
+
openidConfigurationUrl: string().min(1).optional(),
|
|
224
|
+
clientMetadataUrl: string().min(1).optional(),
|
|
225
|
+
clientId: string().min(1).optional(),
|
|
226
|
+
clientSecret: string().min(1).optional(),
|
|
227
|
+
scopes: array(string().min(1)).optional(),
|
|
228
|
+
redirectUri: string().min(1).optional()
|
|
229
|
+
}).strict();
|
|
230
|
+
}
|
|
231
|
+
function validateBackends(config, ctx) {
|
|
232
|
+
for (const [server, raw] of Object.entries(config.mcpServers)) {
|
|
233
|
+
const effectiveTransport = raw.transport ?? (raw.command ? "stdio" : void 0);
|
|
234
|
+
if (Boolean(raw.command) === Boolean(raw.url)) ctx.addIssue({
|
|
235
|
+
code: "custom",
|
|
236
|
+
path: ["mcpServers", server],
|
|
237
|
+
message: "MCP server must define exactly one connection shape: command or url"
|
|
238
|
+
});
|
|
239
|
+
if (effectiveTransport === "stdio" && !raw.command) ctx.addIssue({
|
|
240
|
+
code: "custom",
|
|
241
|
+
path: [
|
|
242
|
+
"mcpServers",
|
|
243
|
+
server,
|
|
244
|
+
"command"
|
|
245
|
+
],
|
|
246
|
+
message: "stdio servers require command"
|
|
247
|
+
});
|
|
248
|
+
if ((effectiveTransport === "http" || effectiveTransport === "sse") && !raw.url) ctx.addIssue({
|
|
249
|
+
code: "custom",
|
|
250
|
+
path: [
|
|
251
|
+
"mcpServers",
|
|
252
|
+
server,
|
|
253
|
+
"url"
|
|
254
|
+
],
|
|
255
|
+
message: "remote servers require url"
|
|
256
|
+
});
|
|
257
|
+
if (raw.url && !hasEnvReference(raw.url) && !isAllowedRemoteUrl(raw.url)) ctx.addIssue({
|
|
258
|
+
code: "custom",
|
|
259
|
+
path: [
|
|
260
|
+
"mcpServers",
|
|
261
|
+
server,
|
|
262
|
+
"url"
|
|
263
|
+
],
|
|
264
|
+
message: "remote url must use https except loopback development urls"
|
|
265
|
+
});
|
|
266
|
+
validateAuthHeaders(raw.auth, ctx, [
|
|
267
|
+
"mcpServers",
|
|
268
|
+
server,
|
|
269
|
+
"auth"
|
|
270
|
+
]);
|
|
271
|
+
}
|
|
272
|
+
for (const [server, raw] of Object.entries(config.openapiEndpoints)) {
|
|
273
|
+
if (Boolean(raw.specPath) === Boolean(raw.specUrl)) ctx.addIssue({
|
|
274
|
+
code: "custom",
|
|
275
|
+
path: ["openapiEndpoints", server],
|
|
276
|
+
message: "OpenAPI endpoint must define exactly one spec source: specPath or specUrl"
|
|
277
|
+
});
|
|
278
|
+
if (raw.specUrl && !hasEnvReference(raw.specUrl) && !isAllowedRemoteUrl(raw.specUrl)) ctx.addIssue({
|
|
279
|
+
code: "custom",
|
|
280
|
+
path: [
|
|
281
|
+
"openapiEndpoints",
|
|
282
|
+
server,
|
|
283
|
+
"specUrl"
|
|
284
|
+
],
|
|
285
|
+
message: "OpenAPI specUrl must use https except loopback development urls"
|
|
286
|
+
});
|
|
287
|
+
if (raw.baseUrl && !hasEnvReference(raw.baseUrl) && !isAllowedRemoteUrl(raw.baseUrl)) ctx.addIssue({
|
|
288
|
+
code: "custom",
|
|
289
|
+
path: [
|
|
290
|
+
"openapiEndpoints",
|
|
291
|
+
server,
|
|
292
|
+
"baseUrl"
|
|
293
|
+
],
|
|
294
|
+
message: "OpenAPI baseUrl must use https except loopback development urls"
|
|
295
|
+
});
|
|
296
|
+
validateAuthHeaders(raw.auth, ctx, [
|
|
297
|
+
"openapiEndpoints",
|
|
298
|
+
server,
|
|
299
|
+
"auth"
|
|
300
|
+
]);
|
|
301
|
+
}
|
|
302
|
+
for (const [server, raw] of Object.entries(config.graphqlEndpoints)) {
|
|
303
|
+
if (Number(Boolean(raw.schemaPath)) + Number(Boolean(raw.schemaUrl)) + Number(raw.introspection === true) !== 1) ctx.addIssue({
|
|
304
|
+
code: "custom",
|
|
305
|
+
path: ["graphqlEndpoints", server],
|
|
306
|
+
message: "GraphQL endpoint must define exactly one schema source"
|
|
307
|
+
});
|
|
308
|
+
if (raw.endpointUrl && !hasEnvReference(raw.endpointUrl) && !isAllowedRemoteUrl(raw.endpointUrl)) ctx.addIssue({
|
|
309
|
+
code: "custom",
|
|
310
|
+
path: [
|
|
311
|
+
"graphqlEndpoints",
|
|
312
|
+
server,
|
|
313
|
+
"endpointUrl"
|
|
314
|
+
],
|
|
315
|
+
message: "GraphQL endpointUrl must use https except loopback development urls"
|
|
316
|
+
});
|
|
317
|
+
validateAuthHeaders(raw.auth, ctx, [
|
|
318
|
+
"graphqlEndpoints",
|
|
319
|
+
server,
|
|
320
|
+
"auth"
|
|
321
|
+
]);
|
|
322
|
+
}
|
|
323
|
+
for (const [server, raw] of Object.entries(config.httpApis)) {
|
|
324
|
+
if (raw.baseUrl && !hasEnvReference(raw.baseUrl) && !isAllowedHttpBaseUrl(raw.baseUrl)) ctx.addIssue({
|
|
325
|
+
code: "custom",
|
|
326
|
+
path: [
|
|
327
|
+
"httpApis",
|
|
328
|
+
server,
|
|
329
|
+
"baseUrl"
|
|
330
|
+
],
|
|
331
|
+
message: "HTTP API baseUrl must use https except loopback development urls and must not include credentials, query, or fragment"
|
|
332
|
+
});
|
|
333
|
+
validateAuthHeaders(raw.auth, ctx, [
|
|
334
|
+
"httpApis",
|
|
335
|
+
server,
|
|
336
|
+
"auth"
|
|
337
|
+
]);
|
|
338
|
+
for (const [actionName, action] of Object.entries(raw.actions)) if (action.headers) validateHttpActionHeaders(action.headers, ctx, [
|
|
339
|
+
"httpApis",
|
|
340
|
+
server,
|
|
341
|
+
"actions",
|
|
342
|
+
actionName,
|
|
343
|
+
"headers"
|
|
344
|
+
]);
|
|
345
|
+
}
|
|
346
|
+
for (const [server, raw] of Object.entries(config.capletSets)) {
|
|
347
|
+
if (!raw.configPath && !raw.capletsRoot) ctx.addIssue({
|
|
348
|
+
code: "custom",
|
|
349
|
+
path: ["capletSets", server],
|
|
350
|
+
message: "Caplet set must define at least one source: configPath or capletsRoot"
|
|
351
|
+
});
|
|
352
|
+
if (raw.defaultSearchLimit > raw.maxSearchLimit) ctx.addIssue({
|
|
353
|
+
code: "custom",
|
|
354
|
+
path: [
|
|
355
|
+
"capletSets",
|
|
356
|
+
server,
|
|
357
|
+
"defaultSearchLimit"
|
|
358
|
+
],
|
|
359
|
+
message: "defaultSearchLimit must be <= maxSearchLimit"
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
function validateAuthHeaders(auth, ctx, path) {
|
|
364
|
+
if (auth?.type !== "headers") return;
|
|
365
|
+
for (const headerName of Object.keys(auth.headers)) {
|
|
366
|
+
const normalized = headerName.toLowerCase();
|
|
367
|
+
if (!HEADER_NAME_PATTERN.test(headerName) || FORBIDDEN_HEADERS.has(normalized)) ctx.addIssue({
|
|
368
|
+
code: "custom",
|
|
369
|
+
path: [
|
|
370
|
+
...path,
|
|
371
|
+
"headers",
|
|
372
|
+
headerName
|
|
373
|
+
],
|
|
374
|
+
message: `header ${headerName} is not allowed`
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
function mapBackend(records, backend, prepare) {
|
|
379
|
+
return Object.fromEntries(Object.entries(records).map(([id, raw]) => [id, stripUndefined({
|
|
380
|
+
...prepare ? prepare(id, raw) : raw,
|
|
381
|
+
server: id,
|
|
382
|
+
backend
|
|
383
|
+
})]));
|
|
384
|
+
}
|
|
385
|
+
function stripUndefined(value) {
|
|
386
|
+
return Object.fromEntries(Object.entries(value).filter(([, nested]) => nested !== void 0));
|
|
387
|
+
}
|
|
388
|
+
function hasEnvReference(value) {
|
|
389
|
+
return /\$\{?[A-Z_][A-Z0-9_]*\}?|\$env:[A-Z_][A-Z0-9_]*/u.test(value);
|
|
390
|
+
}
|
|
391
|
+
//#endregion
|
|
392
|
+
export { parseConfig };
|
package/dist/config.d.ts
CHANGED
|
@@ -35,6 +35,30 @@ export type RemoteAuthConfig = {
|
|
|
35
35
|
scopes?: string[] | undefined;
|
|
36
36
|
redirectUri?: string | undefined;
|
|
37
37
|
};
|
|
38
|
+
export type CapletSetupCommandConfig = {
|
|
39
|
+
label: string;
|
|
40
|
+
command: string;
|
|
41
|
+
args?: string[] | undefined;
|
|
42
|
+
env?: Record<string, string> | undefined;
|
|
43
|
+
cwd?: string | undefined;
|
|
44
|
+
timeoutMs?: number | undefined;
|
|
45
|
+
maxOutputBytes?: number | undefined;
|
|
46
|
+
};
|
|
47
|
+
export type CapletSetupConfig = {
|
|
48
|
+
commands?: CapletSetupCommandConfig[] | undefined;
|
|
49
|
+
verify?: CapletSetupCommandConfig[] | undefined;
|
|
50
|
+
};
|
|
51
|
+
export type ProjectBindingConfig = {
|
|
52
|
+
required: true;
|
|
53
|
+
};
|
|
54
|
+
export type RuntimeFeature = "docker" | "browser";
|
|
55
|
+
export type RuntimeResourceClass = "standard" | "large" | "heavy";
|
|
56
|
+
export type RuntimeRequirementsConfig = {
|
|
57
|
+
features?: RuntimeFeature[] | undefined;
|
|
58
|
+
resources?: {
|
|
59
|
+
class?: RuntimeResourceClass | undefined;
|
|
60
|
+
} | undefined;
|
|
61
|
+
};
|
|
38
62
|
export type CapletServerConfig = {
|
|
39
63
|
server: string;
|
|
40
64
|
backend: "mcp";
|
|
@@ -53,6 +77,9 @@ export type CapletServerConfig = {
|
|
|
53
77
|
callTimeoutMs: number;
|
|
54
78
|
toolCacheTtlMs: number;
|
|
55
79
|
disabled: boolean;
|
|
80
|
+
setup?: CapletSetupConfig | undefined;
|
|
81
|
+
projectBinding?: ProjectBindingConfig | undefined;
|
|
82
|
+
runtime?: RuntimeRequirementsConfig | undefined;
|
|
56
83
|
};
|
|
57
84
|
export type OpenApiAuthConfig = {
|
|
58
85
|
type: "none";
|
|
@@ -79,6 +106,9 @@ export type OpenApiEndpointConfig = {
|
|
|
79
106
|
requestTimeoutMs: number;
|
|
80
107
|
operationCacheTtlMs: number;
|
|
81
108
|
disabled: boolean;
|
|
109
|
+
setup?: CapletSetupConfig | undefined;
|
|
110
|
+
projectBinding?: ProjectBindingConfig | undefined;
|
|
111
|
+
runtime?: RuntimeRequirementsConfig | undefined;
|
|
82
112
|
};
|
|
83
113
|
export type GraphQlOperationConfig = {
|
|
84
114
|
document?: string | undefined;
|
|
@@ -103,6 +133,9 @@ export type GraphQlEndpointConfig = {
|
|
|
103
133
|
operationCacheTtlMs: number;
|
|
104
134
|
selectionDepth: number;
|
|
105
135
|
disabled: boolean;
|
|
136
|
+
setup?: CapletSetupConfig | undefined;
|
|
137
|
+
projectBinding?: ProjectBindingConfig | undefined;
|
|
138
|
+
runtime?: RuntimeRequirementsConfig | undefined;
|
|
106
139
|
};
|
|
107
140
|
export type HttpActionConfig = {
|
|
108
141
|
method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
@@ -127,6 +160,9 @@ export type HttpApiConfig = {
|
|
|
127
160
|
requestTimeoutMs: number;
|
|
128
161
|
maxResponseBytes: number;
|
|
129
162
|
disabled: boolean;
|
|
163
|
+
setup?: CapletSetupConfig | undefined;
|
|
164
|
+
projectBinding?: ProjectBindingConfig | undefined;
|
|
165
|
+
runtime?: RuntimeRequirementsConfig | undefined;
|
|
130
166
|
};
|
|
131
167
|
export type CliToolOutputConfig = {
|
|
132
168
|
type: "text" | "json";
|
|
@@ -162,6 +198,9 @@ export type CliToolsConfig = {
|
|
|
162
198
|
timeoutMs: number;
|
|
163
199
|
maxOutputBytes: number;
|
|
164
200
|
disabled: boolean;
|
|
201
|
+
setup?: CapletSetupConfig | undefined;
|
|
202
|
+
projectBinding?: ProjectBindingConfig | undefined;
|
|
203
|
+
runtime?: RuntimeRequirementsConfig | undefined;
|
|
165
204
|
};
|
|
166
205
|
export type CapletSetConfig = {
|
|
167
206
|
server: string;
|
|
@@ -176,6 +215,9 @@ export type CapletSetConfig = {
|
|
|
176
215
|
maxSearchLimit: number;
|
|
177
216
|
toolCacheTtlMs: number;
|
|
178
217
|
disabled: boolean;
|
|
218
|
+
setup?: CapletSetupConfig | undefined;
|
|
219
|
+
projectBinding?: ProjectBindingConfig | undefined;
|
|
220
|
+
runtime?: RuntimeRequirementsConfig | undefined;
|
|
179
221
|
};
|
|
180
222
|
export type CapletConfig = CapletServerConfig | OpenApiEndpointConfig | GraphQlEndpointConfig | HttpApiConfig | CliToolsConfig | CapletSetConfig;
|
|
181
223
|
export type CapletsOptions = {
|