@caplets/core 0.19.0 → 0.20.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth.d.ts +2 -2
- package/dist/caplet-files-bundle.d.ts +24 -9
- package/dist/caplet-source.js +368 -4588
- package/dist/cli/auth.d.ts +40 -2
- package/dist/cli/cloud-add.d.ts +8 -0
- package/dist/cli/code-mode.d.ts +16 -0
- package/dist/cli/commands.d.ts +3 -1
- package/dist/cli/doctor.d.ts +3 -0
- package/dist/cli/setup.d.ts +7 -0
- package/dist/cli-tools.d.ts +1 -1
- package/dist/cli.d.ts +1 -0
- package/dist/cloud-auth/client.d.ts +15 -0
- package/dist/cloud-auth/types.d.ts +2 -1
- package/dist/code-mode/api.d.ts +32 -0
- package/dist/code-mode/declarations.d.ts +5 -0
- package/dist/code-mode/diagnostics.d.ts +8 -0
- package/dist/code-mode/index.d.ts +4 -0
- package/dist/code-mode/logs.d.ts +21 -0
- package/dist/code-mode/runner.d.ts +15 -0
- package/dist/code-mode/runtime-api.generated.d.ts +1 -0
- package/dist/code-mode/sandbox.d.ts +28 -0
- package/dist/code-mode/static-analysis.d.ts +2 -0
- package/dist/code-mode/tool.d.ts +11 -0
- package/dist/code-mode/types.d.ts +120 -0
- package/dist/code-mode.js +147855 -0
- package/dist/{completion-brgziz4L.js → completion-D-kuyArL.js} +5 -2
- package/dist/config/paths.d.ts +2 -0
- package/dist/config-runtime.d.ts +13 -4
- package/dist/config-runtime.js +31 -2
- package/dist/config.d.ts +34 -9
- package/dist/downstream.d.ts +20 -2
- package/dist/engine.d.ts +20 -0
- package/dist/exposure/direct-names.d.ts +9 -0
- package/dist/exposure/discovery.d.ts +75 -0
- package/dist/exposure/policy.d.ts +8 -0
- package/dist/generated-tool-input-schema.d.ts +89 -59
- package/dist/generated-tool-input-schema.js +38 -27
- package/dist/graphql.d.ts +1 -1
- package/dist/http-actions.d.ts +1 -1
- package/dist/index.d.ts +13 -0
- package/dist/index.js +1096 -154
- package/dist/native/service.d.ts +6 -0
- package/dist/native/tools.d.ts +2 -0
- package/dist/native.d.ts +1 -1
- package/dist/native.js +2 -2
- package/dist/observed-output-shapes/extract.d.ts +5 -0
- package/dist/observed-output-shapes/file-store.d.ts +17 -0
- package/dist/observed-output-shapes/index.d.ts +7 -0
- package/dist/observed-output-shapes/key.d.ts +14 -0
- package/dist/observed-output-shapes/merge.d.ts +2 -0
- package/dist/observed-output-shapes/pure.d.ts +5 -0
- package/dist/observed-output-shapes/pure.js +241 -0
- package/dist/observed-output-shapes/schema.d.ts +1 -0
- package/dist/observed-output-shapes/types.d.ts +84 -0
- package/dist/observed-output-shapes/typescript.d.ts +7 -0
- package/dist/observed-output-shapes-uzAMQPhg.js +485 -0
- package/dist/observed-output-shapes.js +2 -0
- package/dist/openapi.d.ts +1 -1
- package/dist/project-binding/index.d.ts +2 -0
- package/dist/project-binding.js +22 -0
- package/dist/redaction.d.ts +14 -0
- package/dist/redaction.js +30 -0
- package/dist/registry.d.ts +4 -0
- package/dist/remote/options.d.ts +2 -0
- package/dist/remote-control/types.d.ts +1 -1
- package/dist/runtime-plan/resources.d.ts +2 -0
- package/dist/runtime-plan.js +8 -2
- package/dist/schemas-1HZ0kFpx.js +4270 -0
- package/dist/serve/session.d.ts +15 -3
- package/dist/{service-BXcE4Rv8.js → service-Bsq7R0mt.js} +29312 -26554
- package/dist/stable-json.d.ts +3 -0
- package/dist/stable-json.js +26 -0
- package/dist/tools.d.ts +22 -11
- package/dist/{validation-BBG4skZf.js → validation-CdqbI2zN.js} +25 -4
- package/package.json +29 -3
|
@@ -0,0 +1,485 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
4
|
+
//#region src/observed-output-shapes/types.ts
|
|
5
|
+
const OBSERVED_OUTPUT_SHAPE_VERSION = 1;
|
|
6
|
+
const OBSERVED_OUTPUT_SHAPE_LIMITS = {
|
|
7
|
+
maxDepth: 6,
|
|
8
|
+
maxObjectFields: 40,
|
|
9
|
+
maxArrayElements: 20,
|
|
10
|
+
maxUnionVariants: 4,
|
|
11
|
+
maxTypeScriptChars: 4e3,
|
|
12
|
+
maxStoredJsonBytes: 16e3,
|
|
13
|
+
ttlMs: 720 * 60 * 60 * 1e3,
|
|
14
|
+
maxLocalEntries: 2e3
|
|
15
|
+
};
|
|
16
|
+
//#endregion
|
|
17
|
+
//#region src/stable-json.ts
|
|
18
|
+
function stableJsonValue(value) {
|
|
19
|
+
if (Array.isArray(value)) return value.map((item) => stableJsonValue(item));
|
|
20
|
+
if (isPlainObject$2(value)) {
|
|
21
|
+
const sorted = {};
|
|
22
|
+
for (const key of Object.keys(value).sort()) {
|
|
23
|
+
const item = value[key];
|
|
24
|
+
if (item !== void 0) sorted[key] = stableJsonValue(item);
|
|
25
|
+
}
|
|
26
|
+
return sorted;
|
|
27
|
+
}
|
|
28
|
+
return value;
|
|
29
|
+
}
|
|
30
|
+
function stableJsonStringify(value) {
|
|
31
|
+
return JSON.stringify(stableJsonValue(value));
|
|
32
|
+
}
|
|
33
|
+
function isPlainObject$2(value) {
|
|
34
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
35
|
+
}
|
|
36
|
+
//#endregion
|
|
37
|
+
//#region src/schema-hash.ts
|
|
38
|
+
function schemaHash(schema) {
|
|
39
|
+
if (schema === void 0 || schema === null) return null;
|
|
40
|
+
const json = stableJsonStringify(schema);
|
|
41
|
+
return `sha256:${createHash("sha256").update(json).digest("hex")}`;
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
//#region src/observed-output-shapes/key.ts
|
|
45
|
+
function observedOutputShapeStorageKey(key) {
|
|
46
|
+
return stableHash(key);
|
|
47
|
+
}
|
|
48
|
+
function observedOutputShapeKey(input) {
|
|
49
|
+
const toolDescriptorHash = input.toolDescriptor ? stableHash(input.toolDescriptor) : void 0;
|
|
50
|
+
const outputSchemaHash = schemaHash(input.outputSchema) ?? void 0;
|
|
51
|
+
return {
|
|
52
|
+
scope: input.scope,
|
|
53
|
+
...input.workspaceId ? { workspaceId: input.workspaceId } : {},
|
|
54
|
+
...input.projectFingerprint ? { projectFingerprint: input.projectFingerprint } : {},
|
|
55
|
+
capletId: input.caplet.server,
|
|
56
|
+
backendKind: input.caplet.backend,
|
|
57
|
+
backendFingerprint: backendFingerprint(input.caplet),
|
|
58
|
+
toolName: input.toolName,
|
|
59
|
+
...toolDescriptorHash ? { toolDescriptorHash } : {},
|
|
60
|
+
...outputSchemaHash ? { outputSchemaHash } : {},
|
|
61
|
+
resultVersion: 1
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function backendFingerprint(caplet) {
|
|
65
|
+
return stableHash(nonSecretBackendIdentity(caplet));
|
|
66
|
+
}
|
|
67
|
+
function stableHash(value) {
|
|
68
|
+
return createHash("sha256").update(stableJsonStringify(value)).digest("hex");
|
|
69
|
+
}
|
|
70
|
+
function nonSecretBackendIdentity(caplet) {
|
|
71
|
+
switch (caplet.backend) {
|
|
72
|
+
case "mcp": return caplet.transport === "stdio" ? {
|
|
73
|
+
backend: caplet.backend,
|
|
74
|
+
server: caplet.server,
|
|
75
|
+
transport: caplet.transport,
|
|
76
|
+
command: caplet.command,
|
|
77
|
+
args: caplet.args,
|
|
78
|
+
cwd: caplet.cwd
|
|
79
|
+
} : {
|
|
80
|
+
backend: caplet.backend,
|
|
81
|
+
server: caplet.server,
|
|
82
|
+
transport: caplet.transport,
|
|
83
|
+
url: caplet.url
|
|
84
|
+
};
|
|
85
|
+
case "openapi": return {
|
|
86
|
+
backend: caplet.backend,
|
|
87
|
+
server: caplet.server,
|
|
88
|
+
specPath: caplet.specPath,
|
|
89
|
+
specUrl: caplet.specUrl,
|
|
90
|
+
baseUrl: caplet.baseUrl
|
|
91
|
+
};
|
|
92
|
+
case "graphql": return {
|
|
93
|
+
backend: caplet.backend,
|
|
94
|
+
server: caplet.server,
|
|
95
|
+
endpointUrl: caplet.endpointUrl,
|
|
96
|
+
schemaPath: caplet.schemaPath,
|
|
97
|
+
schemaUrl: caplet.schemaUrl,
|
|
98
|
+
introspection: caplet.introspection,
|
|
99
|
+
operations: caplet.operations
|
|
100
|
+
};
|
|
101
|
+
case "http": return {
|
|
102
|
+
backend: caplet.backend,
|
|
103
|
+
server: caplet.server,
|
|
104
|
+
baseUrl: caplet.baseUrl,
|
|
105
|
+
actions: Object.fromEntries(Object.entries(caplet.actions).map(([name, action]) => [name, {
|
|
106
|
+
method: action.method,
|
|
107
|
+
path: action.path,
|
|
108
|
+
query: action.query,
|
|
109
|
+
hasJsonBody: action.jsonBody !== void 0
|
|
110
|
+
}]))
|
|
111
|
+
};
|
|
112
|
+
case "cli": return {
|
|
113
|
+
backend: caplet.backend,
|
|
114
|
+
server: caplet.server,
|
|
115
|
+
cwd: caplet.cwd,
|
|
116
|
+
actions: Object.fromEntries(Object.entries(caplet.actions).map(([name, action]) => [name, {
|
|
117
|
+
command: action.command,
|
|
118
|
+
args: action.args,
|
|
119
|
+
cwd: action.cwd,
|
|
120
|
+
output: action.output
|
|
121
|
+
}]))
|
|
122
|
+
};
|
|
123
|
+
case "caplets": return {
|
|
124
|
+
backend: caplet.backend,
|
|
125
|
+
server: caplet.server,
|
|
126
|
+
configPath: caplet.configPath,
|
|
127
|
+
capletsRoot: caplet.capletsRoot
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
//#endregion
|
|
132
|
+
//#region src/observed-output-shapes/file-store.ts
|
|
133
|
+
var FileObservedOutputShapeStore = class {
|
|
134
|
+
cacheDir;
|
|
135
|
+
options;
|
|
136
|
+
constructor(cacheDir, options = {}) {
|
|
137
|
+
this.cacheDir = cacheDir;
|
|
138
|
+
this.options = options;
|
|
139
|
+
}
|
|
140
|
+
async read(key) {
|
|
141
|
+
try {
|
|
142
|
+
const parsed = JSON.parse(readFileSync(this.pathFor(key), "utf8"));
|
|
143
|
+
if (Date.now() > Date.parse(parsed.expiresAt)) return void 0;
|
|
144
|
+
if (!isObservedOutputShape(parsed.shape)) return void 0;
|
|
145
|
+
return parsed.shape;
|
|
146
|
+
} catch {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
async write(key, shape) {
|
|
151
|
+
const payload = {
|
|
152
|
+
key,
|
|
153
|
+
shape,
|
|
154
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
155
|
+
expiresAt: new Date(Date.now() + this.ttlMs()).toISOString()
|
|
156
|
+
};
|
|
157
|
+
if (new TextEncoder().encode(JSON.stringify(payload)).byteLength > OBSERVED_OUTPUT_SHAPE_LIMITS.maxStoredJsonBytes) return;
|
|
158
|
+
mkdirSync(this.cacheDir, { recursive: true });
|
|
159
|
+
const path = this.pathFor(key);
|
|
160
|
+
const tempPath = `${path}.${process.pid}.tmp`;
|
|
161
|
+
writeFileSync(tempPath, JSON.stringify(payload), { mode: 384 });
|
|
162
|
+
renameSync(tempPath, path);
|
|
163
|
+
this.prune().catch(() => void 0);
|
|
164
|
+
}
|
|
165
|
+
async prune(now = /* @__PURE__ */ new Date()) {
|
|
166
|
+
if (!existsSync(this.cacheDir)) return {
|
|
167
|
+
removed: 0,
|
|
168
|
+
remaining: 0
|
|
169
|
+
};
|
|
170
|
+
const files = this.entries();
|
|
171
|
+
let removed = 0;
|
|
172
|
+
const live = [];
|
|
173
|
+
for (const file of files) try {
|
|
174
|
+
const parsed = JSON.parse(readFileSync(file.path, "utf8"));
|
|
175
|
+
const expiresAt = Date.parse(parsed.expiresAt);
|
|
176
|
+
if (!Number.isFinite(expiresAt) || now.getTime() > expiresAt || !isObservedOutputShape(parsed.shape)) {
|
|
177
|
+
rmSync(file.path, { force: true });
|
|
178
|
+
removed++;
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
live.push({
|
|
182
|
+
path: file.path,
|
|
183
|
+
expiresAt,
|
|
184
|
+
mtimeMs: file.mtimeMs
|
|
185
|
+
});
|
|
186
|
+
} catch {
|
|
187
|
+
rmSync(file.path, { force: true });
|
|
188
|
+
removed++;
|
|
189
|
+
}
|
|
190
|
+
const maxEntries = this.maxEntries();
|
|
191
|
+
const overflow = Math.max(0, live.length - maxEntries);
|
|
192
|
+
if (overflow > 0) for (const entry of live.sort((a, b) => a.mtimeMs - b.mtimeMs).slice(0, overflow)) {
|
|
193
|
+
rmSync(entry.path, { force: true });
|
|
194
|
+
removed++;
|
|
195
|
+
}
|
|
196
|
+
return {
|
|
197
|
+
removed,
|
|
198
|
+
remaining: Math.max(0, live.length - overflow)
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
async health() {
|
|
202
|
+
try {
|
|
203
|
+
mkdirSync(this.cacheDir, { recursive: true });
|
|
204
|
+
const probe = join(this.cacheDir, `.health-${process.pid}.json`);
|
|
205
|
+
writeFileSync(probe, "{}", { mode: 384 });
|
|
206
|
+
rmSync(probe, { force: true });
|
|
207
|
+
const prune = await this.prune();
|
|
208
|
+
return {
|
|
209
|
+
path: this.cacheDir,
|
|
210
|
+
readable: true,
|
|
211
|
+
writable: true,
|
|
212
|
+
entryCount: this.entries().length,
|
|
213
|
+
prune
|
|
214
|
+
};
|
|
215
|
+
} catch (error) {
|
|
216
|
+
return {
|
|
217
|
+
path: this.cacheDir,
|
|
218
|
+
readable: false,
|
|
219
|
+
writable: false,
|
|
220
|
+
error: error instanceof Error ? error.message : String(error)
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
pathFor(key) {
|
|
225
|
+
return join(this.cacheDir, `${observedOutputShapeStorageKey(key)}.json`);
|
|
226
|
+
}
|
|
227
|
+
entries() {
|
|
228
|
+
try {
|
|
229
|
+
return readdirSync(this.cacheDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => {
|
|
230
|
+
const path = join(this.cacheDir, entry.name);
|
|
231
|
+
return {
|
|
232
|
+
path,
|
|
233
|
+
mtimeMs: readMtimeMs(path)
|
|
234
|
+
};
|
|
235
|
+
});
|
|
236
|
+
} catch {
|
|
237
|
+
return [];
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
ttlMs() {
|
|
241
|
+
return this.options.ttlMs ?? OBSERVED_OUTPUT_SHAPE_LIMITS.ttlMs;
|
|
242
|
+
}
|
|
243
|
+
maxEntries() {
|
|
244
|
+
return this.options.maxEntries ?? OBSERVED_OUTPUT_SHAPE_LIMITS.maxLocalEntries;
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
function readMtimeMs(path) {
|
|
248
|
+
try {
|
|
249
|
+
return statSync(path).mtimeMs;
|
|
250
|
+
} catch {
|
|
251
|
+
return 0;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
function isObservedOutputShape(value) {
|
|
255
|
+
return Boolean(value && typeof value === "object" && value.version === 1 && value.source === "observed" && typeof value.typeScript === "string" && typeof value.sampleCount === "number");
|
|
256
|
+
}
|
|
257
|
+
//#endregion
|
|
258
|
+
//#region src/observed-output-shapes/merge.ts
|
|
259
|
+
function mergeJsonShapes(left, right) {
|
|
260
|
+
if (left.kind === "unknown" || right.kind === "unknown") return { kind: "unknown" };
|
|
261
|
+
if (left.kind === right.kind) {
|
|
262
|
+
if (left.kind === "object" && right.kind === "object") return mergeObjects(left, right);
|
|
263
|
+
if (left.kind === "array" && right.kind === "array") return mergeArrays(left, right);
|
|
264
|
+
if (left.kind === "union" && right.kind === "union") return boundedUnion([...left.variants, ...right.variants]);
|
|
265
|
+
return left;
|
|
266
|
+
}
|
|
267
|
+
return boundedUnion([...left.kind === "union" ? left.variants : [left], ...right.kind === "union" ? right.variants : [right]]);
|
|
268
|
+
}
|
|
269
|
+
function mergeObjects(left, right) {
|
|
270
|
+
const fields = {};
|
|
271
|
+
const keys = [...new Set([...Object.keys(left.fields), ...Object.keys(right.fields)])].sort();
|
|
272
|
+
let truncated = left.truncated === true || right.truncated === true;
|
|
273
|
+
const selected = keys.slice(0, OBSERVED_OUTPUT_SHAPE_LIMITS.maxObjectFields);
|
|
274
|
+
truncated = truncated || keys.length > selected.length;
|
|
275
|
+
for (const key of selected) {
|
|
276
|
+
const leftField = left.fields[key];
|
|
277
|
+
const rightField = right.fields[key];
|
|
278
|
+
if (leftField && rightField) fields[key] = {
|
|
279
|
+
optional: true,
|
|
280
|
+
shape: mergeJsonShapes(leftField.shape, rightField.shape)
|
|
281
|
+
};
|
|
282
|
+
else fields[key] = {
|
|
283
|
+
optional: true,
|
|
284
|
+
shape: (leftField ?? rightField).shape
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
return {
|
|
288
|
+
kind: "object",
|
|
289
|
+
fields,
|
|
290
|
+
...truncated ? { truncated: true } : {}
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
function mergeArrays(left, right) {
|
|
294
|
+
const element = left.element && right.element ? mergeJsonShapes(left.element, right.element) : left.element ?? right.element;
|
|
295
|
+
return {
|
|
296
|
+
kind: "array",
|
|
297
|
+
...element ? { element } : {},
|
|
298
|
+
...left.truncated === true || right.truncated === true ? { truncated: true } : {}
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
function boundedUnion(variants) {
|
|
302
|
+
const flattened = variants.flatMap((variant) => variant.kind === "union" ? variant.variants : [variant]);
|
|
303
|
+
const unique = [];
|
|
304
|
+
for (const variant of flattened) {
|
|
305
|
+
if (variant.kind === "unknown") return { kind: "unknown" };
|
|
306
|
+
const key = JSON.stringify(variant);
|
|
307
|
+
if (!unique.some((existing) => JSON.stringify(existing) === key)) unique.push(variant);
|
|
308
|
+
}
|
|
309
|
+
if (unique.length === 1) return unique[0];
|
|
310
|
+
if (unique.length > OBSERVED_OUTPUT_SHAPE_LIMITS.maxUnionVariants) return { kind: "unknown" };
|
|
311
|
+
return {
|
|
312
|
+
kind: "union",
|
|
313
|
+
variants: unique.sort((a, b) => a.kind.localeCompare(b.kind))
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
//#endregion
|
|
317
|
+
//#region src/observed-output-shapes/typescript.ts
|
|
318
|
+
function shapeToTypeScript(shape, typeName = "ObservedOutput", maxChars = OBSERVED_OUTPUT_SHAPE_LIMITS.maxTypeScriptChars) {
|
|
319
|
+
const typeScript = `type ${typeName} = ${shapeType(shape)};`;
|
|
320
|
+
if (typeScript.length <= maxChars) return {
|
|
321
|
+
typeScript,
|
|
322
|
+
truncated: hasTruncatedShape(shape)
|
|
323
|
+
};
|
|
324
|
+
return {
|
|
325
|
+
typeScript: `type ${typeName} = unknown;`,
|
|
326
|
+
truncated: true
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
function shapeType(shape) {
|
|
330
|
+
switch (shape.kind) {
|
|
331
|
+
case "null": return "null";
|
|
332
|
+
case "boolean": return "boolean";
|
|
333
|
+
case "number": return "number";
|
|
334
|
+
case "string": return "string";
|
|
335
|
+
case "unknown": return "unknown";
|
|
336
|
+
case "array": return `${shape.element ? wrapArrayElement(shapeType(shape.element)) : "unknown"}[]`;
|
|
337
|
+
case "object": return objectType(shape);
|
|
338
|
+
case "union": return unionType(shape.variants);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
function hasTruncatedShape(shape) {
|
|
342
|
+
if ("truncated" in shape && shape.truncated === true) return true;
|
|
343
|
+
if (shape.kind === "array") return shape.element ? hasTruncatedShape(shape.element) : false;
|
|
344
|
+
if (shape.kind === "object") return Object.values(shape.fields).some((field) => hasTruncatedShape(field.shape));
|
|
345
|
+
if (shape.kind === "union") return shape.variants.some((variant) => hasTruncatedShape(variant));
|
|
346
|
+
return false;
|
|
347
|
+
}
|
|
348
|
+
function objectType(shape) {
|
|
349
|
+
const entries = Object.entries(shape.fields);
|
|
350
|
+
if (entries.length === 0) return "Record<string, unknown>";
|
|
351
|
+
return `{ ${entries.map(([key, field]) => `${propertyName(key)}?: ${shapeType(field.shape)};`).join(" ")} }`;
|
|
352
|
+
}
|
|
353
|
+
function unionType(variants) {
|
|
354
|
+
const rendered = [...new Set(variants.map((variant) => shapeType(variant)))];
|
|
355
|
+
return rendered.length === 0 ? "unknown" : rendered.join(" | ");
|
|
356
|
+
}
|
|
357
|
+
function wrapArrayElement(value) {
|
|
358
|
+
return value.includes(" | ") ? `(${value})` : value;
|
|
359
|
+
}
|
|
360
|
+
function propertyName(key) {
|
|
361
|
+
return /^[A-Za-z_$][\w$]*$/u.test(key) ? key : JSON.stringify(key);
|
|
362
|
+
}
|
|
363
|
+
//#endregion
|
|
364
|
+
//#region src/observed-output-shapes/extract.ts
|
|
365
|
+
function observeOutputShape(input) {
|
|
366
|
+
const shape = extractJsonShape(input.value);
|
|
367
|
+
if (!shape) return void 0;
|
|
368
|
+
const merged = input.existing ? mergeJsonShapes(input.existing.jsonShape, shape) : shape;
|
|
369
|
+
const emitted = shapeToTypeScript(merged);
|
|
370
|
+
const observed = {
|
|
371
|
+
version: 1,
|
|
372
|
+
source: "observed",
|
|
373
|
+
observedAt: (input.now ?? /* @__PURE__ */ new Date()).toISOString(),
|
|
374
|
+
sampleCount: (input.existing?.sampleCount ?? 0) + 1,
|
|
375
|
+
typeScript: emitted.typeScript,
|
|
376
|
+
jsonShape: merged,
|
|
377
|
+
truncated: emitted.truncated || hasTruncatedShape(merged)
|
|
378
|
+
};
|
|
379
|
+
return storedBytes(observed) > OBSERVED_OUTPUT_SHAPE_LIMITS.maxStoredJsonBytes ? {
|
|
380
|
+
...observed,
|
|
381
|
+
typeScript: "type ObservedOutput = unknown;",
|
|
382
|
+
jsonShape: { kind: "unknown" },
|
|
383
|
+
truncated: true
|
|
384
|
+
} : observed;
|
|
385
|
+
}
|
|
386
|
+
function extractJsonShape(value) {
|
|
387
|
+
if (!isShapeableJsonRoot(value)) return void 0;
|
|
388
|
+
return shapeFor(value, 0);
|
|
389
|
+
}
|
|
390
|
+
function parseShapeableJsonText(value) {
|
|
391
|
+
if (!isPlainObject$1(value) || !Array.isArray(value.content) || value.content.length !== 1) return;
|
|
392
|
+
const [item] = value.content;
|
|
393
|
+
if (!isPlainObject$1(item) || item.type !== "text" || typeof item.text !== "string") return;
|
|
394
|
+
const text = item.text.trim();
|
|
395
|
+
if (!text || !text.startsWith("{") && !text.startsWith("[")) return void 0;
|
|
396
|
+
try {
|
|
397
|
+
const parsed = JSON.parse(text);
|
|
398
|
+
return isShapeableJsonRoot(parsed) ? parsed : void 0;
|
|
399
|
+
} catch {
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
function normalizedObservableValue(result) {
|
|
404
|
+
if (isPlainObject$1(result)) {
|
|
405
|
+
const structured = result.structuredContent;
|
|
406
|
+
if (structured !== void 0) {
|
|
407
|
+
if (isPlainObject$1(structured) && "caplets" in structured && "result" in structured) return isShapeableJsonRoot(structured.result) ? structured.result : void 0;
|
|
408
|
+
return isShapeableJsonRoot(structured) ? structured : void 0;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
return parseShapeableJsonText(result);
|
|
412
|
+
}
|
|
413
|
+
function shapeFor(value, depth) {
|
|
414
|
+
if (depth >= OBSERVED_OUTPUT_SHAPE_LIMITS.maxDepth) return { kind: "unknown" };
|
|
415
|
+
if (value === null) return { kind: "null" };
|
|
416
|
+
if (typeof value === "boolean") return { kind: "boolean" };
|
|
417
|
+
if (typeof value === "number") return { kind: "number" };
|
|
418
|
+
if (typeof value === "string") return { kind: "string" };
|
|
419
|
+
if (Array.isArray(value)) return arrayShape(value, depth);
|
|
420
|
+
if (isPlainObject$1(value)) return objectShape(value, depth);
|
|
421
|
+
return { kind: "unknown" };
|
|
422
|
+
}
|
|
423
|
+
function arrayShape(value, depth) {
|
|
424
|
+
const sampled = value.slice(0, OBSERVED_OUTPUT_SHAPE_LIMITS.maxArrayElements);
|
|
425
|
+
let element;
|
|
426
|
+
for (const item of sampled) {
|
|
427
|
+
const itemShape = shapeFor(item, depth + 1);
|
|
428
|
+
element = element ? mergeJsonShapes(element, itemShape) : itemShape;
|
|
429
|
+
}
|
|
430
|
+
return {
|
|
431
|
+
kind: "array",
|
|
432
|
+
...element ? { element } : {},
|
|
433
|
+
...value.length > sampled.length ? { truncated: true } : {}
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
function objectShape(value, depth) {
|
|
437
|
+
const keys = Object.keys(value).sort();
|
|
438
|
+
const selected = keys.slice(0, OBSERVED_OUTPUT_SHAPE_LIMITS.maxObjectFields);
|
|
439
|
+
const fields = {};
|
|
440
|
+
for (const key of selected) fields[key] = {
|
|
441
|
+
optional: true,
|
|
442
|
+
shape: shapeFor(value[key], depth + 1)
|
|
443
|
+
};
|
|
444
|
+
return {
|
|
445
|
+
kind: "object",
|
|
446
|
+
fields,
|
|
447
|
+
...keys.length > selected.length ? { truncated: true } : {}
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
function isShapeableJsonRoot(value) {
|
|
451
|
+
return Array.isArray(value) || isPlainObject$1(value);
|
|
452
|
+
}
|
|
453
|
+
function isPlainObject$1(value) {
|
|
454
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
455
|
+
}
|
|
456
|
+
function storedBytes(value) {
|
|
457
|
+
return new TextEncoder().encode(JSON.stringify(value)).byteLength;
|
|
458
|
+
}
|
|
459
|
+
//#endregion
|
|
460
|
+
//#region src/observed-output-shapes/schema.ts
|
|
461
|
+
function usefulOutputSchema(schema) {
|
|
462
|
+
if (!isPlainObject(schema)) return false;
|
|
463
|
+
if (Object.keys(schema).length === 0) return false;
|
|
464
|
+
if ("const" in schema || Array.isArray(schema.enum)) return true;
|
|
465
|
+
const type = schema.type;
|
|
466
|
+
if (Array.isArray(type)) return type.some((item) => usefulOutputSchema({
|
|
467
|
+
...schema,
|
|
468
|
+
type: item
|
|
469
|
+
}));
|
|
470
|
+
if (type === "object" || isPlainObject(schema.properties)) {
|
|
471
|
+
if (isPlainObject(schema.properties) && Object.keys(schema.properties).length > 0) return true;
|
|
472
|
+
if (schema.additionalProperties === false) return true;
|
|
473
|
+
if (isPlainObject(schema.additionalProperties)) return true;
|
|
474
|
+
return false;
|
|
475
|
+
}
|
|
476
|
+
if (type === "array") return usefulOutputSchema(schema.items);
|
|
477
|
+
if (typeof type === "string") return true;
|
|
478
|
+
if (Array.isArray(schema.oneOf) || Array.isArray(schema.anyOf) || Array.isArray(schema.allOf)) return true;
|
|
479
|
+
return false;
|
|
480
|
+
}
|
|
481
|
+
function isPlainObject(value) {
|
|
482
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
483
|
+
}
|
|
484
|
+
//#endregion
|
|
485
|
+
export { parseShapeableJsonText as a, shapeType as c, backendFingerprint as d, observedOutputShapeKey as f, OBSERVED_OUTPUT_SHAPE_VERSION as g, OBSERVED_OUTPUT_SHAPE_LIMITS as h, observeOutputShape as i, mergeJsonShapes as l, stableHash as m, extractJsonShape as n, hasTruncatedShape as o, observedOutputShapeStorageKey as p, normalizedObservableValue as r, shapeToTypeScript as s, usefulOutputSchema as t, FileObservedOutputShapeStore as u };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as parseShapeableJsonText, c as shapeType, d as backendFingerprint, f as observedOutputShapeKey, g as OBSERVED_OUTPUT_SHAPE_VERSION, h as OBSERVED_OUTPUT_SHAPE_LIMITS, i as observeOutputShape, l as mergeJsonShapes, m as stableHash, n as extractJsonShape, o as hasTruncatedShape, p as observedOutputShapeStorageKey, r as normalizedObservableValue, s as shapeToTypeScript, t as usefulOutputSchema, u as FileObservedOutputShapeStore } from "./observed-output-shapes-uzAMQPhg.js";
|
|
2
|
+
export { FileObservedOutputShapeStore, OBSERVED_OUTPUT_SHAPE_LIMITS, OBSERVED_OUTPUT_SHAPE_VERSION, backendFingerprint, extractJsonShape, hasTruncatedShape, mergeJsonShapes, normalizedObservableValue, observeOutputShape, observedOutputShapeKey, observedOutputShapeStorageKey, parseShapeableJsonText, shapeToTypeScript, shapeType, stableHash, usefulOutputSchema };
|
package/dist/openapi.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { CompatibilityCallToolResult, Tool } from "@modelcontextprotocol/sdk/types";
|
|
2
2
|
import type { OpenApiEndpointConfig } from "./config";
|
|
3
|
-
import type
|
|
3
|
+
import { type CompactTool } from "./downstream";
|
|
4
4
|
import type { ServerRegistry } from "./registry";
|
|
5
5
|
export declare class OpenApiManager {
|
|
6
6
|
private registry;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
//#region src/project-binding/types.ts
|
|
2
|
+
const PROJECT_BINDING_STATES = [
|
|
3
|
+
"not_attached",
|
|
4
|
+
"attaching",
|
|
5
|
+
"syncing",
|
|
6
|
+
"ready",
|
|
7
|
+
"degraded",
|
|
8
|
+
"blocked",
|
|
9
|
+
"offline",
|
|
10
|
+
"cleaning_up",
|
|
11
|
+
"ended",
|
|
12
|
+
"expired"
|
|
13
|
+
];
|
|
14
|
+
const PROJECT_BINDING_SYNC_STATES = [
|
|
15
|
+
"not_started",
|
|
16
|
+
"pending",
|
|
17
|
+
"syncing",
|
|
18
|
+
"idle",
|
|
19
|
+
"failed"
|
|
20
|
+
];
|
|
21
|
+
//#endregion
|
|
22
|
+
export { PROJECT_BINDING_STATES, PROJECT_BINDING_SYNC_STATES };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare const SECRET_KEY_PATTERN: RegExp;
|
|
2
|
+
export declare const SECRET_TEXT_PATTERNS: readonly [RegExp, RegExp, RegExp];
|
|
3
|
+
export type RedactionResult = {
|
|
4
|
+
text: string;
|
|
5
|
+
redacted: boolean;
|
|
6
|
+
};
|
|
7
|
+
export type RedactionOptions = {
|
|
8
|
+
patterns?: readonly RegExp[] | undefined;
|
|
9
|
+
additionalSecrets?: readonly string[] | undefined;
|
|
10
|
+
replacement?: string | undefined;
|
|
11
|
+
};
|
|
12
|
+
export declare function isSecretKey(key: string): boolean;
|
|
13
|
+
export declare function redactSecretText(value: string, options?: RedactionOptions): RedactionResult;
|
|
14
|
+
export declare function redactUnknownSecrets<T>(value: T, options?: RedactionOptions): T;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
//#region src/redaction.ts
|
|
2
|
+
const SECRET_KEY_PATTERN = /(token|secret|authorization|auth|api[-_]?key|password|credential|clientsecret|client_secret|code|refresh)/iu;
|
|
3
|
+
const SECRET_TEXT_PATTERNS = [
|
|
4
|
+
/(Authorization:\s*Bearer\s+)[0-9A-Za-z._~+/=-]+/giu,
|
|
5
|
+
/(bearer\s+)[a-z0-9._~+/=-]+/giu,
|
|
6
|
+
/([?&](?:access_token|refresh_token|token|code)=)[^&\s]+/giu
|
|
7
|
+
];
|
|
8
|
+
function isSecretKey(key) {
|
|
9
|
+
return SECRET_KEY_PATTERN.test(key);
|
|
10
|
+
}
|
|
11
|
+
function redactSecretText(value, options = {}) {
|
|
12
|
+
const replacement = options.replacement ?? "[REDACTED]";
|
|
13
|
+
let text = value;
|
|
14
|
+
for (const pattern of [...options.patterns ?? [], ...SECRET_TEXT_PATTERNS]) text = text.replace(pattern, (...args) => {
|
|
15
|
+
return `${typeof args[1] === "string" ? args[1] : ""}${replacement}`;
|
|
16
|
+
});
|
|
17
|
+
for (const secret of options.additionalSecrets?.filter(Boolean) ?? []) text = text.split(secret).join(replacement);
|
|
18
|
+
return {
|
|
19
|
+
text,
|
|
20
|
+
redacted: text !== value
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function redactUnknownSecrets(value, options = {}) {
|
|
24
|
+
if (typeof value === "string") return redactSecretText(value, options).text;
|
|
25
|
+
if (Array.isArray(value)) return value.map((item) => redactUnknownSecrets(item, options));
|
|
26
|
+
if (!value || typeof value !== "object") return value;
|
|
27
|
+
return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, isSecretKey(key) ? "[REDACTED]" : redactUnknownSecrets(entry, options)]));
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
export { SECRET_KEY_PATTERN, SECRET_TEXT_PATTERNS, isSecretKey, redactSecretText, redactUnknownSecrets };
|
package/dist/registry.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ export type CapletServerSummary = {
|
|
|
6
6
|
id: string;
|
|
7
7
|
name: string;
|
|
8
8
|
description: string;
|
|
9
|
+
useWhen?: string;
|
|
10
|
+
avoidWhen?: string;
|
|
9
11
|
disabled?: boolean;
|
|
10
12
|
status: ServerStatus;
|
|
11
13
|
lastError?: SafeErrorSummary;
|
|
@@ -14,6 +16,8 @@ export type CapletServerDetail = {
|
|
|
14
16
|
id: string;
|
|
15
17
|
name: string;
|
|
16
18
|
description: string;
|
|
19
|
+
useWhen?: string;
|
|
20
|
+
avoidWhen?: string;
|
|
17
21
|
tags?: string[];
|
|
18
22
|
backend: {
|
|
19
23
|
type: "mcp";
|
package/dist/remote/options.d.ts
CHANGED
|
@@ -38,5 +38,7 @@ export declare function resolveRemoteMode(input?: CapletsRemoteModeInput, env?:
|
|
|
38
38
|
mode: CapletsRemoteMode;
|
|
39
39
|
};
|
|
40
40
|
export declare function resolveCapletsRemote(input?: CapletsRemoteInput, env?: CapletsRemoteEnv): ResolvedCapletsRemote;
|
|
41
|
+
export declare function resolveHostedCloudRemote(input?: CapletsRemoteInput, env?: CapletsRemoteEnv): ResolvedCapletsRemote;
|
|
42
|
+
export declare function hostedCloudWorkspaceFromRemoteUrl(value: string): string | undefined;
|
|
41
43
|
export declare function projectBindingWebSocketUrlForBase(baseUrl: URL): URL;
|
|
42
44
|
export declare function isCapletsCloudUrl(value: string): boolean;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CapletsErrorCode } from "../errors";
|
|
2
|
-
export type RemoteCliCommand = "list" | "inspect" | "
|
|
2
|
+
export type RemoteCliCommand = "list" | "inspect" | "check" | "tools" | "search_tools" | "describe_tool" | "call_tool" | "resources" | "search_resources" | "resource_templates" | "read_resource" | "prompts" | "search_prompts" | "get_prompt" | "complete" | "init" | "add" | "install" | "complete_cli" | "auth_login_start" | "auth_login_complete" | "auth_logout" | "auth_list";
|
|
3
3
|
export type RemoteCliRequest = {
|
|
4
4
|
command: RemoteCliCommand;
|
|
5
5
|
arguments: Record<string, unknown>;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { HostedRuntimeResourceClass, RuntimeResourcePolicy, RuntimeResourceResolution } from "./types";
|
|
2
|
+
export declare function resourceClassRank(value: string): number;
|
|
3
|
+
export declare function isRuntimeResourceClassAllowed(requested: string, maximum: string): boolean;
|
|
2
4
|
type ResourceInput = {
|
|
3
5
|
backend?: string | undefined;
|
|
4
6
|
features: string[];
|
package/dist/runtime-plan.js
CHANGED
|
@@ -171,6 +171,12 @@ const rank = {
|
|
|
171
171
|
large: 2,
|
|
172
172
|
heavy: 3
|
|
173
173
|
};
|
|
174
|
+
function resourceClassRank(value) {
|
|
175
|
+
return rank[value] ?? 0;
|
|
176
|
+
}
|
|
177
|
+
function isRuntimeResourceClassAllowed(requested, maximum) {
|
|
178
|
+
return resourceClassRank(requested) <= resourceClassRank(maximum);
|
|
179
|
+
}
|
|
174
180
|
function resolveRuntimeResources(inputOrCaplet, features, policy) {
|
|
175
181
|
const caplet = inputOrCaplet;
|
|
176
182
|
const input = features === void 0 ? inputOrCaplet : {
|
|
@@ -205,7 +211,7 @@ function explicitResourceClass$1(caplet) {
|
|
|
205
211
|
}
|
|
206
212
|
function capClass(requested, maxClass) {
|
|
207
213
|
if (!maxClass) return requested;
|
|
208
|
-
return (
|
|
214
|
+
return isRuntimeResourceClassAllowed(requested, maxClass) ? requested : maxClass;
|
|
209
215
|
}
|
|
210
216
|
//#endregion
|
|
211
217
|
//#region src/runtime-plan/planner.ts
|
|
@@ -272,4 +278,4 @@ function explicitResourceClass(caplet) {
|
|
|
272
278
|
return value === "small" || value === "medium" || value === "standard" || value === "large" || value === "heavy" ? value : void 0;
|
|
273
279
|
}
|
|
274
280
|
//#endregion
|
|
275
|
-
export { HIDDEN_REASON_CODES, classifyCapletRuntimeRoute, inferRuntimeFeatures, planCapletRuntimeRoute, planCapletRuntimeRoutes, resolveRuntimeResources };
|
|
281
|
+
export { HIDDEN_REASON_CODES, classifyCapletRuntimeRoute, inferRuntimeFeatures, isRuntimeResourceClassAllowed, planCapletRuntimeRoute, planCapletRuntimeRoutes, resolveRuntimeResources, resourceClassRank };
|