@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.
Files changed (84) hide show
  1. package/dist/attach/options.d.ts +10 -0
  2. package/dist/attach/server.d.ts +5 -0
  3. package/dist/caplet-files-bundle.d.ts +415 -0
  4. package/dist/caplet-files.d.ts +3 -266
  5. package/dist/caplet-source/bundle.d.ts +7 -0
  6. package/dist/caplet-source/filesystem.d.ts +7 -0
  7. package/dist/caplet-source/filesystem.js +2 -0
  8. package/dist/caplet-source/index.d.ts +4 -0
  9. package/dist/caplet-source/parse.d.ts +35 -0
  10. package/dist/caplet-source/types.d.ts +9 -0
  11. package/dist/caplet-source.js +11231 -0
  12. package/dist/cli/commands.d.ts +9 -2
  13. package/dist/cli/doctor.d.ts +18 -0
  14. package/dist/cli/setup-caplet.d.ts +12 -0
  15. package/dist/cli/setup.d.ts +23 -0
  16. package/dist/cli.d.ts +9 -1
  17. package/dist/cloud/apply.d.ts +36 -0
  18. package/dist/cloud/client.d.ts +30 -0
  19. package/dist/cloud/presence.d.ts +29 -0
  20. package/dist/cloud/project-root.d.ts +2 -0
  21. package/dist/cloud/runtime-adapter.d.ts +23 -0
  22. package/dist/cloud/runtime-http.d.ts +6 -0
  23. package/dist/cloud/sync.d.ts +10 -0
  24. package/dist/cloud-auth/client.d.ts +42 -0
  25. package/dist/cloud-auth/errors.d.ts +11 -0
  26. package/dist/cloud-auth/open-url.d.ts +7 -0
  27. package/dist/cloud-auth/store.d.ts +35 -0
  28. package/dist/cloud-auth/types.d.ts +66 -0
  29. package/dist/{completion-DvWQk5qR.js → completion-brgziz4L.js} +32 -6
  30. package/dist/config-runtime.d.ts +174 -0
  31. package/dist/config-runtime.js +392 -0
  32. package/dist/config.d.ts +42 -0
  33. package/dist/filesystem-Kkg32TOJ.js +66 -0
  34. package/dist/generated-tool-input-schema.d.ts +9 -9
  35. package/dist/generated-tool-input-schema.js +161 -1
  36. package/dist/index.d.ts +35 -0
  37. package/dist/index.js +6132 -3196
  38. package/dist/native/options.d.ts +22 -3
  39. package/dist/native/remote.d.ts +2 -1
  40. package/dist/native/service.d.ts +7 -3
  41. package/dist/native.js +2 -430
  42. package/dist/project-binding/attach.d.ts +46 -0
  43. package/dist/project-binding/errors.d.ts +17 -0
  44. package/dist/project-binding/gitignore.d.ts +5 -0
  45. package/dist/project-binding/mutagen.d.ts +65 -0
  46. package/dist/project-binding/routes.d.ts +9 -0
  47. package/dist/project-binding/session.d.ts +82 -0
  48. package/dist/project-binding/sync-filter.d.ts +19 -0
  49. package/dist/project-binding/sync-size.d.ts +27 -0
  50. package/dist/project-binding/transport.d.ts +21 -0
  51. package/dist/project-binding/types.d.ts +31 -0
  52. package/dist/project-binding/workspaces.d.ts +60 -0
  53. package/dist/remote/options.d.ts +42 -0
  54. package/dist/remote/selection.d.ts +26 -0
  55. package/dist/remote-control/types.d.ts +1 -1
  56. package/dist/runtime-plan/features.d.ts +7 -0
  57. package/dist/runtime-plan/index.d.ts +4 -0
  58. package/dist/runtime-plan/planner.d.ts +5 -0
  59. package/dist/runtime-plan/resources.d.ts +11 -0
  60. package/dist/runtime-plan/types.d.ts +82 -0
  61. package/dist/runtime-plan.js +275 -0
  62. package/dist/{generated-tool-input-schema-MbYF5jMW.js → schemas-BZ6BBrh7.js} +1 -161
  63. package/dist/serve/daemon/config.d.ts +8 -0
  64. package/dist/serve/daemon/index.d.ts +16 -0
  65. package/dist/serve/daemon/paths.d.ts +3 -0
  66. package/dist/serve/daemon/platform-darwin.d.ts +2 -0
  67. package/dist/serve/daemon/platform-linux.d.ts +2 -0
  68. package/dist/serve/daemon/platform-windows.d.ts +2 -0
  69. package/dist/serve/daemon/platform.d.ts +9 -0
  70. package/dist/serve/daemon/process.d.ts +5 -0
  71. package/dist/serve/daemon/types.d.ts +86 -0
  72. package/dist/serve/http.d.ts +8 -0
  73. package/dist/serve/index.d.ts +5 -1
  74. package/dist/serve/native-session.d.ts +19 -0
  75. package/dist/serve/options.d.ts +1 -0
  76. package/dist/server/options.d.ts +1 -1
  77. package/dist/{options--RoZwWjs.js → service-BXcE4Rv8.js} +9932 -2218
  78. package/dist/setup/hash.d.ts +3 -0
  79. package/dist/setup/local-store.d.ts +34 -0
  80. package/dist/setup/runner.d.ts +40 -0
  81. package/dist/setup/types.d.ts +52 -0
  82. package/dist/tools.d.ts +17 -2
  83. package/dist/validation-BBG4skZf.js +153 -0
  84. 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 = {