caplets 0.12.7 → 0.13.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/README.md +17 -3
- package/dist/index.js +505 -105
- package/package.json +8 -6
package/README.md
CHANGED
|
@@ -68,6 +68,18 @@ Connect Caplets to any MCP client:
|
|
|
68
68
|
Ask your agent to use Caplets. It will see a compact capability list first, then inspect
|
|
69
69
|
only the backend it needs.
|
|
70
70
|
|
|
71
|
+
You can also invoke configured Caplets directly from the CLI for agent-friendly scripts and smoke tests:
|
|
72
|
+
|
|
73
|
+
```sh
|
|
74
|
+
caplets get-caplet context7
|
|
75
|
+
caplets list-tools context7
|
|
76
|
+
caplets get-tool context7.resolve-library-id
|
|
77
|
+
caplets call-tool context7.resolve-library-id --args '{"libraryName":"react"}'
|
|
78
|
+
caplets call-tool context7.resolve-library-id --args '{"libraryName":"react"}' --field result.id --format json
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Direct CLI operation commands print Markdown summaries by default. Add `--format plain` for plain text or `--format json` for machine-readable JSON (`md` is accepted as an alias for `markdown`). If a downstream tool returns `isError: true`, Caplets still exits with status code 1.
|
|
82
|
+
|
|
71
83
|
## Agent Plugins
|
|
72
84
|
|
|
73
85
|
Use Caplets as a normal MCP server everywhere, or install a native agent integration when
|
|
@@ -610,7 +622,10 @@ shell snippets.
|
|
|
610
622
|
"description": "Fetch status for one service.",
|
|
611
623
|
"inputSchema": {
|
|
612
624
|
"type": "object",
|
|
613
|
-
"properties": {
|
|
625
|
+
"properties": {
|
|
626
|
+
"service": { "type": "string" },
|
|
627
|
+
"verbose": { "type": "boolean" }
|
|
628
|
+
},
|
|
614
629
|
"required": ["service"]
|
|
615
630
|
},
|
|
616
631
|
"query": { "verbose": "$input.verbose" }
|
|
@@ -693,7 +708,7 @@ an existing destination file.
|
|
|
693
708
|
|
|
694
709
|
Use `capletSets` to expose another Caplets collection as nested Caplets. Each child Caplet appears
|
|
695
710
|
as one downstream tool and supports the full Caplets operation set: `get_caplet`, `check_backend`,
|
|
696
|
-
`
|
|
711
|
+
`list_tools`, `search_tools`, `get_tool`, and `call_tool`.
|
|
697
712
|
|
|
698
713
|
```json
|
|
699
714
|
{
|
|
@@ -891,7 +906,6 @@ Available operations:
|
|
|
891
906
|
|
|
892
907
|
- `get_caplet`: return the configured capability card without starting the downstream server.
|
|
893
908
|
- `check_backend`: verify the selected backend, whether MCP, OpenAPI, GraphQL, HTTP, CLI, or nested Caplets.
|
|
894
|
-
- `check_mcp_server`: start or connect to an MCP server and verify its tool list.
|
|
895
909
|
- `list_tools`: return compact downstream tool metadata.
|
|
896
910
|
- `search_tools`: search downstream tool names and descriptions within this Caplet.
|
|
897
911
|
- `get_tool`: return full metadata for one exact downstream tool.
|
package/dist/index.js
CHANGED
|
@@ -180,7 +180,7 @@ const allowsEval = /* @__PURE__ */ cached(() => {
|
|
|
180
180
|
return false;
|
|
181
181
|
}
|
|
182
182
|
});
|
|
183
|
-
function isPlainObject$
|
|
183
|
+
function isPlainObject$8(o) {
|
|
184
184
|
if (isObject(o) === false) return false;
|
|
185
185
|
const ctor = o.constructor;
|
|
186
186
|
if (ctor === void 0) return true;
|
|
@@ -191,7 +191,7 @@ function isPlainObject$7(o) {
|
|
|
191
191
|
return true;
|
|
192
192
|
}
|
|
193
193
|
function shallowClone(o) {
|
|
194
|
-
if (isPlainObject$
|
|
194
|
+
if (isPlainObject$8(o)) return { ...o };
|
|
195
195
|
if (Array.isArray(o)) return [...o];
|
|
196
196
|
if (o instanceof Map) return new Map(o);
|
|
197
197
|
if (o instanceof Set) return new Set(o);
|
|
@@ -274,7 +274,7 @@ function omit(schema, mask) {
|
|
|
274
274
|
}));
|
|
275
275
|
}
|
|
276
276
|
function extend(schema, shape) {
|
|
277
|
-
if (!isPlainObject$
|
|
277
|
+
if (!isPlainObject$8(shape)) throw new Error("Invalid input to extend: expected a plain object");
|
|
278
278
|
const checks = schema._zod.def.checks;
|
|
279
279
|
if (checks && checks.length > 0) {
|
|
280
280
|
const existingShape = schema._zod.def.shape;
|
|
@@ -290,7 +290,7 @@ function extend(schema, shape) {
|
|
|
290
290
|
} }));
|
|
291
291
|
}
|
|
292
292
|
function safeExtend(schema, shape) {
|
|
293
|
-
if (!isPlainObject$
|
|
293
|
+
if (!isPlainObject$8(shape)) throw new Error("Invalid input to safeExtend: expected a plain object");
|
|
294
294
|
return clone(schema, mergeDefs(schema._zod.def, { get shape() {
|
|
295
295
|
const _shape = {
|
|
296
296
|
...schema._zod.def.shape,
|
|
@@ -1904,7 +1904,7 @@ function mergeValues$1(a, b) {
|
|
|
1904
1904
|
valid: true,
|
|
1905
1905
|
data: a
|
|
1906
1906
|
};
|
|
1907
|
-
if (isPlainObject$
|
|
1907
|
+
if (isPlainObject$8(a) && isPlainObject$8(b)) {
|
|
1908
1908
|
const bKeys = Object.keys(b);
|
|
1909
1909
|
const sharedKeys = Object.keys(a).filter((key) => bKeys.indexOf(key) !== -1);
|
|
1910
1910
|
const newObj = {
|
|
@@ -1980,7 +1980,7 @@ const $ZodRecord = /* @__PURE__ */ $constructor("$ZodRecord", (inst, def) => {
|
|
|
1980
1980
|
$ZodType.init(inst, def);
|
|
1981
1981
|
inst._zod.parse = (payload, ctx) => {
|
|
1982
1982
|
const input = payload.value;
|
|
1983
|
-
if (!isPlainObject$
|
|
1983
|
+
if (!isPlainObject$8(input)) {
|
|
1984
1984
|
payload.issues.push({
|
|
1985
1985
|
expected: "record",
|
|
1986
1986
|
code: "invalid_type",
|
|
@@ -12268,7 +12268,7 @@ var Protocol = class {
|
|
|
12268
12268
|
};
|
|
12269
12269
|
}
|
|
12270
12270
|
};
|
|
12271
|
-
function isPlainObject$
|
|
12271
|
+
function isPlainObject$7(value) {
|
|
12272
12272
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
12273
12273
|
}
|
|
12274
12274
|
function mergeCapabilities(base, additional) {
|
|
@@ -12278,7 +12278,7 @@ function mergeCapabilities(base, additional) {
|
|
|
12278
12278
|
const addValue = additional[k];
|
|
12279
12279
|
if (addValue === void 0) continue;
|
|
12280
12280
|
const baseValue = result[k];
|
|
12281
|
-
if (isPlainObject$
|
|
12281
|
+
if (isPlainObject$7(baseValue) && isPlainObject$7(addValue)) result[k] = {
|
|
12282
12282
|
...baseValue,
|
|
12283
12283
|
...addValue
|
|
12284
12284
|
};
|
|
@@ -19930,7 +19930,7 @@ const EMPTY_COMPLETION_RESULT = { completion: {
|
|
|
19930
19930
|
} };
|
|
19931
19931
|
//#endregion
|
|
19932
19932
|
//#region ../core/package.json
|
|
19933
|
-
var version$1 = "0.
|
|
19933
|
+
var version$1 = "0.14.0";
|
|
19934
19934
|
//#endregion
|
|
19935
19935
|
//#region ../../node_modules/.pnpm/unist-util-stringify-position@4.0.0/node_modules/unist-util-stringify-position/lib/index.js
|
|
19936
19936
|
/**
|
|
@@ -27877,19 +27877,19 @@ function loadCapletFilesWithPaths(root) {
|
|
|
27877
27877
|
if (servers[candidate.id] || openapiEndpoints[candidate.id] || graphqlEndpoints[candidate.id] || httpApis[candidate.id] || cliTools[candidate.id] || capletSets[candidate.id]) throw new CapletsError("CONFIG_INVALID", `Duplicate Caplet ID ${candidate.id} under ${root}`);
|
|
27878
27878
|
paths[candidate.id] = candidate.path;
|
|
27879
27879
|
const config = readCapletFile(candidate.path);
|
|
27880
|
-
if (isPlainObject$
|
|
27880
|
+
if (isPlainObject$6(config) && config.backend === "openapi") {
|
|
27881
27881
|
const { backend: _backend, ...endpoint } = config;
|
|
27882
27882
|
openapiEndpoints[candidate.id] = endpoint;
|
|
27883
|
-
} else if (isPlainObject$
|
|
27883
|
+
} else if (isPlainObject$6(config) && config.backend === "graphql") {
|
|
27884
27884
|
const { backend: _backend, ...endpoint } = config;
|
|
27885
27885
|
graphqlEndpoints[candidate.id] = endpoint;
|
|
27886
|
-
} else if (isPlainObject$
|
|
27886
|
+
} else if (isPlainObject$6(config) && config.backend === "http") {
|
|
27887
27887
|
const { backend: _backend, ...endpoint } = config;
|
|
27888
27888
|
httpApis[candidate.id] = endpoint;
|
|
27889
|
-
} else if (isPlainObject$
|
|
27889
|
+
} else if (isPlainObject$6(config) && config.backend === "cli") {
|
|
27890
27890
|
const { backend: _backend, ...endpoint } = config;
|
|
27891
27891
|
cliTools[candidate.id] = endpoint;
|
|
27892
|
-
} else if (isPlainObject$
|
|
27892
|
+
} else if (isPlainObject$6(config) && config.backend === "caplets") {
|
|
27893
27893
|
const { backend: _backend, ...endpoint } = config;
|
|
27894
27894
|
capletSets[candidate.id] = endpoint;
|
|
27895
27895
|
} else servers[candidate.id] = config;
|
|
@@ -28043,7 +28043,7 @@ function parseFrontmatter(text, path) {
|
|
|
28043
28043
|
value: text
|
|
28044
28044
|
});
|
|
28045
28045
|
matter(file, { strip: true });
|
|
28046
|
-
if (!isPlainObject$
|
|
28046
|
+
if (!isPlainObject$6(file.data.matter) || Object.keys(file.data.matter).length === 0) throw new Error("empty frontmatter");
|
|
28047
28047
|
return {
|
|
28048
28048
|
frontmatter: file.data.matter,
|
|
28049
28049
|
body: String(file)
|
|
@@ -28052,7 +28052,7 @@ function parseFrontmatter(text, path) {
|
|
|
28052
28052
|
throw new CapletsError("CONFIG_INVALID", `Caplet file at ${path} has invalid YAML frontmatter`, redactSecrets(error));
|
|
28053
28053
|
}
|
|
28054
28054
|
}
|
|
28055
|
-
function isPlainObject$
|
|
28055
|
+
function isPlainObject$6(value) {
|
|
28056
28056
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
28057
28057
|
}
|
|
28058
28058
|
function validateCapletId(id, path) {
|
|
@@ -28673,7 +28673,7 @@ function normalizeLocalPaths(input, baseDir) {
|
|
|
28673
28673
|
}
|
|
28674
28674
|
function normalizeEndpointPaths(endpoints, baseDir, normalize) {
|
|
28675
28675
|
if (!endpoints) return;
|
|
28676
|
-
return Object.fromEntries(Object.entries(endpoints).map(([id, endpoint]) => [id, isPlainObject$
|
|
28676
|
+
return Object.fromEntries(Object.entries(endpoints).map(([id, endpoint]) => [id, isPlainObject$5(endpoint) ? normalize(endpoint, baseDir) : endpoint]));
|
|
28677
28677
|
}
|
|
28678
28678
|
function normalizeOpenApiPath(endpoint, baseDir) {
|
|
28679
28679
|
return {
|
|
@@ -28682,7 +28682,7 @@ function normalizeOpenApiPath(endpoint, baseDir) {
|
|
|
28682
28682
|
};
|
|
28683
28683
|
}
|
|
28684
28684
|
function normalizeGraphQlPath(endpoint, baseDir) {
|
|
28685
|
-
const operations = isPlainObject$
|
|
28685
|
+
const operations = isPlainObject$5(endpoint.operations) ? Object.fromEntries(Object.entries(endpoint.operations).map(([name, operation]) => [name, isPlainObject$5(operation) ? {
|
|
28686
28686
|
...operation,
|
|
28687
28687
|
documentPath: normalizeLocalPath(operation.documentPath, baseDir)
|
|
28688
28688
|
} : operation])) : endpoint.operations;
|
|
@@ -28693,7 +28693,7 @@ function normalizeGraphQlPath(endpoint, baseDir) {
|
|
|
28693
28693
|
};
|
|
28694
28694
|
}
|
|
28695
28695
|
function normalizeCliToolsPaths(endpoint, baseDir) {
|
|
28696
|
-
const actions = isPlainObject$
|
|
28696
|
+
const actions = isPlainObject$5(endpoint.actions) ? Object.fromEntries(Object.entries(endpoint.actions).map(([name, action]) => [name, isPlainObject$5(action) ? {
|
|
28697
28697
|
...action,
|
|
28698
28698
|
cwd: normalizeLocalPath(action.cwd, baseDir)
|
|
28699
28699
|
} : action])) : endpoint.actions;
|
|
@@ -28896,7 +28896,7 @@ function isPublicMetadataPath(path) {
|
|
|
28896
28896
|
if (path.length < 3 || path[0] !== "mcpServers" && path[0] !== "openapiEndpoints" && path[0] !== "graphqlEndpoints" && path[0] !== "httpApis" && path[0] !== "cliTools" && path[0] !== "capletSets") return false;
|
|
28897
28897
|
return NON_INTERPOLATED_SERVER_FIELDS.has(path[2] ?? "");
|
|
28898
28898
|
}
|
|
28899
|
-
function isPlainObject$
|
|
28899
|
+
function isPlainObject$5(value) {
|
|
28900
28900
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
28901
28901
|
}
|
|
28902
28902
|
function hasEnvReference(value) {
|
|
@@ -29066,9 +29066,9 @@ function validateInput(action, input) {
|
|
|
29066
29066
|
if (!schema) return;
|
|
29067
29067
|
const required = Array.isArray(schema.required) ? schema.required : [];
|
|
29068
29068
|
for (const key of required) if (typeof key === "string" && (input[key] === void 0 || input[key] === null)) throw new CapletsError("REQUEST_INVALID", `CLI tool ${action.name} requires input ${key}`);
|
|
29069
|
-
const properties = isPlainObject$
|
|
29069
|
+
const properties = isPlainObject$4(schema.properties) ? schema.properties : {};
|
|
29070
29070
|
for (const [key, property] of Object.entries(properties)) {
|
|
29071
|
-
if (input[key] === void 0 || !isPlainObject$
|
|
29071
|
+
if (input[key] === void 0 || !isPlainObject$4(property) || typeof property.type !== "string") continue;
|
|
29072
29072
|
if (!matchesJsonType(input[key], property.type)) throw new CapletsError("REQUEST_INVALID", `CLI tool ${action.name} input ${key} must be ${property.type}`);
|
|
29073
29073
|
}
|
|
29074
29074
|
}
|
|
@@ -29078,7 +29078,7 @@ function matchesJsonType(value, type) {
|
|
|
29078
29078
|
case "number":
|
|
29079
29079
|
case "integer": return typeof value === "number" && (type === "number" || Number.isInteger(value));
|
|
29080
29080
|
case "boolean": return typeof value === "boolean";
|
|
29081
|
-
case "object": return isPlainObject$
|
|
29081
|
+
case "object": return isPlainObject$4(value);
|
|
29082
29082
|
case "array": return Array.isArray(value);
|
|
29083
29083
|
case "null": return value === null;
|
|
29084
29084
|
default: return true;
|
|
@@ -29169,7 +29169,7 @@ function isExecutable(path) {
|
|
|
29169
29169
|
function isAbortError$1(error) {
|
|
29170
29170
|
return error instanceof Error && error.name === "AbortError";
|
|
29171
29171
|
}
|
|
29172
|
-
function isPlainObject$
|
|
29172
|
+
function isPlainObject$4(value) {
|
|
29173
29173
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
29174
29174
|
}
|
|
29175
29175
|
//#endregion
|
|
@@ -48425,7 +48425,7 @@ function resolveMapping(mapping, input) {
|
|
|
48425
48425
|
function resolveMappingToRecord(mapping, input, name) {
|
|
48426
48426
|
if (mapping === void 0) return {};
|
|
48427
48427
|
const resolved = resolveMapping(mapping, input);
|
|
48428
|
-
if (!isPlainObject$
|
|
48428
|
+
if (!isPlainObject$3(resolved)) throw new CapletsError("REQUEST_INVALID", `HTTP action ${name} mapping must resolve to an object`);
|
|
48429
48429
|
return resolved;
|
|
48430
48430
|
}
|
|
48431
48431
|
function valueAtPath(input, path) {
|
|
@@ -48520,9 +48520,9 @@ function buildActionUrl(base, actionPath, options = {}) {
|
|
|
48520
48520
|
return baseUrl;
|
|
48521
48521
|
}
|
|
48522
48522
|
function asRecord$1(value) {
|
|
48523
|
-
return isPlainObject$
|
|
48523
|
+
return isPlainObject$3(value) ? value : {};
|
|
48524
48524
|
}
|
|
48525
|
-
function isPlainObject$
|
|
48525
|
+
function isPlainObject$3(value) {
|
|
48526
48526
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
48527
48527
|
}
|
|
48528
48528
|
//#endregion
|
|
@@ -58455,14 +58455,12 @@ function openApiCacheKey(endpoint) {
|
|
|
58455
58455
|
//#endregion
|
|
58456
58456
|
//#region ../core/src/capability-description.ts
|
|
58457
58457
|
function capabilityDescription(server) {
|
|
58458
|
-
const backendName = server.backend === "mcp" ? "MCP server" : server.backend === "openapi" ? "OpenAPI endpoint" : server.backend === "graphql" ? "GraphQL endpoint" : server.backend === "http" ? "HTTP API" : server.backend === "cli" ? "CLI tools" : server.backend === "caplets" ? "nested Caplets" : "backend";
|
|
58459
|
-
const checkOperation = server.backend === "mcp" ? "check_mcp_server" : "check_backend";
|
|
58460
58458
|
const hint = [
|
|
58461
|
-
`Use this Caplet to inspect and call tools from its ${
|
|
58459
|
+
`Use this Caplet to inspect and call tools from its ${server.backend === "mcp" ? "MCP server" : server.backend === "openapi" ? "OpenAPI endpoint" : server.backend === "graphql" ? "GraphQL endpoint" : server.backend === "http" ? "HTTP API" : server.backend === "cli" ? "CLI tools" : server.backend === "caplets" ? "nested Caplets" : "backend"} backend.`,
|
|
58462
58460
|
"",
|
|
58463
58461
|
"Recommended flow:",
|
|
58464
58462
|
"- Read the full Caplet card: {\"operation\":\"get_caplet\"}",
|
|
58465
|
-
|
|
58463
|
+
"- Check the backend: {\"operation\":\"check_backend\"}",
|
|
58466
58464
|
"- Discover tools: {\"operation\":\"list_tools\"} or {\"operation\":\"search_tools\",\"query\":\"<what you need>\"}",
|
|
58467
58465
|
"- Read one tool schema: {\"operation\":\"get_tool\",\"tool\":\"<tool name>\"}",
|
|
58468
58466
|
"- Invoke one downstream tool: {\"operation\":\"call_tool\",\"tool\":\"<tool name>\",\"arguments\":{...}}",
|
|
@@ -58599,7 +58597,6 @@ function graphQlSource(server) {
|
|
|
58599
58597
|
const operations = [
|
|
58600
58598
|
"get_caplet",
|
|
58601
58599
|
"check_backend",
|
|
58602
|
-
"check_mcp_server",
|
|
58603
58600
|
"list_tools",
|
|
58604
58601
|
"search_tools",
|
|
58605
58602
|
"get_tool",
|
|
@@ -58608,7 +58605,7 @@ const operations = [
|
|
|
58608
58605
|
const generatedToolInputDescriptions = {
|
|
58609
58606
|
operation: [
|
|
58610
58607
|
"Caplets wrapper operation to perform for this configured Caplet backend.",
|
|
58611
|
-
"Use get_caplet to read the full Caplet card, check_backend to check
|
|
58608
|
+
"Use get_caplet to read the full Caplet card, check_backend to check backend availability, list_tools or search_tools to discover downstream tools, get_tool to read a downstream input schema, and call_tool to run one downstream tool, operation, action, CLI command, or child Caplet.",
|
|
58612
58609
|
"For call_tool, pass downstream inputs only inside the top-level \"arguments\" object."
|
|
58613
58610
|
].join(" "),
|
|
58614
58611
|
query: "Required only for search_tools. Example: {\"operation\":\"search_tools\",\"query\":\"web search\",\"limit\":5}. Do not use query for call_tool; put downstream query values under arguments.query.",
|
|
@@ -58661,7 +58658,7 @@ function generatedToolInputJsonSchema() {
|
|
|
58661
58658
|
//#region ../core/src/field-selection.ts
|
|
58662
58659
|
function projectStructuredContent(value, outputSchema, fields) {
|
|
58663
58660
|
validateFieldSelection(outputSchema, fields);
|
|
58664
|
-
if (!isPlainObject$
|
|
58661
|
+
if (!isPlainObject$2(value)) throwInvalid("Field selection requires object structured content");
|
|
58665
58662
|
const result = createJsonObject();
|
|
58666
58663
|
for (const field of fields) {
|
|
58667
58664
|
const projected = projectPath(value, outputSchema, field.split("."));
|
|
@@ -58670,7 +58667,7 @@ function projectStructuredContent(value, outputSchema, fields) {
|
|
|
58670
58667
|
return result;
|
|
58671
58668
|
}
|
|
58672
58669
|
function validateFieldSelection(outputSchema, fields) {
|
|
58673
|
-
if (!isPlainObject$
|
|
58670
|
+
if (!isPlainObject$2(outputSchema)) throwInvalid("Field selection requires an output schema");
|
|
58674
58671
|
if (!Array.isArray(fields) || fields.some((field) => typeof field !== "string")) throwInvalid("Field selection requires an array of field paths");
|
|
58675
58672
|
for (const field of fields) validateSchemaPath(outputSchema, field.split("."), field);
|
|
58676
58673
|
}
|
|
@@ -58694,7 +58691,7 @@ function projectPath(value, schema, path) {
|
|
|
58694
58691
|
return value.map((item) => projectPath(item, itemSchema, path) ?? {});
|
|
58695
58692
|
}
|
|
58696
58693
|
const segment = path[0];
|
|
58697
|
-
if (!isPlainObject$
|
|
58694
|
+
if (!isPlainObject$2(value) || !Object.prototype.hasOwnProperty.call(value, segment)) return;
|
|
58698
58695
|
const rest = path.slice(1);
|
|
58699
58696
|
const propertySchema = getSchemaProperty(schema, segment);
|
|
58700
58697
|
const projected = projectPath(value[segment], propertySchema, rest);
|
|
@@ -58706,24 +58703,24 @@ function pruneToSchema(value, schema) {
|
|
|
58706
58703
|
const itemSchema = arrayItemSchema(schema);
|
|
58707
58704
|
return value.map((item) => pruneToSchema(item, itemSchema));
|
|
58708
58705
|
}
|
|
58709
|
-
if (!isPlainObject$
|
|
58710
|
-
const properties = isPlainObject$
|
|
58711
|
-
if (!isPlainObject$
|
|
58706
|
+
if (!isPlainObject$2(value)) return cloneJsonValue(value);
|
|
58707
|
+
const properties = isPlainObject$2(schema) ? schema.properties : void 0;
|
|
58708
|
+
if (!isPlainObject$2(properties)) return cloneJsonValue(value);
|
|
58712
58709
|
const result = createJsonObject();
|
|
58713
58710
|
for (const [key, nestedSchema] of Object.entries(properties)) if (isSupportedSegment(key) && Object.prototype.hasOwnProperty.call(value, key)) result[key] = pruneToSchema(value[key], nestedSchema);
|
|
58714
58711
|
return result;
|
|
58715
58712
|
}
|
|
58716
58713
|
function getSchemaProperty(schema, segment) {
|
|
58717
|
-
const properties = isPlainObject$
|
|
58714
|
+
const properties = isPlainObject$2(schema) ? schema.properties : void 0;
|
|
58718
58715
|
if (!properties || !Object.prototype.hasOwnProperty.call(properties, segment)) return;
|
|
58719
58716
|
return properties[segment];
|
|
58720
58717
|
}
|
|
58721
58718
|
function arrayItemSchema(schema) {
|
|
58722
|
-
if (!isPlainObject$
|
|
58719
|
+
if (!isPlainObject$2(schema) || Array.isArray(schema.items)) return;
|
|
58723
58720
|
return schema.items;
|
|
58724
58721
|
}
|
|
58725
58722
|
function mergeValue(target, value) {
|
|
58726
|
-
if (!isPlainObject$
|
|
58723
|
+
if (!isPlainObject$2(value)) return;
|
|
58727
58724
|
for (const [key, nested] of Object.entries(value)) {
|
|
58728
58725
|
if (!isSupportedSegment(key)) continue;
|
|
58729
58726
|
target[key] = mergeNested(target[key], nested);
|
|
@@ -58732,7 +58729,7 @@ function mergeValue(target, value) {
|
|
|
58732
58729
|
function mergeNested(existing, next) {
|
|
58733
58730
|
if (next === void 0) return existing;
|
|
58734
58731
|
if (Array.isArray(existing) && Array.isArray(next)) return Array.from({ length: Math.max(existing.length, next.length) }, (_, index) => mergeNested(existing[index], next[index]));
|
|
58735
|
-
if (isPlainObject$
|
|
58732
|
+
if (isPlainObject$2(existing) && isPlainObject$2(next)) {
|
|
58736
58733
|
const merged = Object.assign(createJsonObject(), existing);
|
|
58737
58734
|
mergeValue(merged, next);
|
|
58738
58735
|
return merged;
|
|
@@ -58742,7 +58739,7 @@ function mergeNested(existing, next) {
|
|
|
58742
58739
|
function isSupportedSegment(segment) {
|
|
58743
58740
|
return segment !== "" && segment !== "*" && segment !== "__proto__" && segment !== "prototype" && segment !== "constructor" && !/^\d+$/.test(segment);
|
|
58744
58741
|
}
|
|
58745
|
-
function isPlainObject$
|
|
58742
|
+
function isPlainObject$2(value) {
|
|
58746
58743
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
58747
58744
|
}
|
|
58748
58745
|
function createJsonObject() {
|
|
@@ -58750,7 +58747,7 @@ function createJsonObject() {
|
|
|
58750
58747
|
}
|
|
58751
58748
|
function cloneJsonValue(value) {
|
|
58752
58749
|
if (Array.isArray(value)) return value.map(cloneJsonValue);
|
|
58753
|
-
if (isPlainObject$
|
|
58750
|
+
if (isPlainObject$2(value)) {
|
|
58754
58751
|
const result = createJsonObject();
|
|
58755
58752
|
for (const [key, nested] of Object.entries(value)) if (isSupportedSegment(key)) result[key] = cloneJsonValue(nested);
|
|
58756
58753
|
return result;
|
|
@@ -58773,9 +58770,6 @@ async function handleServerTool(server, request, registry, downstream, openapi,
|
|
|
58773
58770
|
switch (parsed.operation) {
|
|
58774
58771
|
case "get_caplet": return jsonResult(registry.detail(server));
|
|
58775
58772
|
case "check_backend": return jsonResult(await backendFor(server, downstream, openapi, graphql, http, cli, caplets).check(server));
|
|
58776
|
-
case "check_mcp_server":
|
|
58777
|
-
if (server.backend !== "mcp") throw new CapletsError("REQUEST_INVALID", "check_mcp_server is only valid for MCP-backed Caplets; use check_backend");
|
|
58778
|
-
return jsonResult(await downstream.checkServer(server));
|
|
58779
58773
|
case "list_tools": {
|
|
58780
58774
|
const backend = backendFor(server, downstream, openapi, graphql, http, cli, caplets);
|
|
58781
58775
|
const tools = await backend.listTools(server);
|
|
@@ -58826,7 +58820,6 @@ function validateOperationRequest(request, maxSearchLimit) {
|
|
|
58826
58820
|
switch (value.operation) {
|
|
58827
58821
|
case "get_caplet":
|
|
58828
58822
|
case "check_backend":
|
|
58829
|
-
case "check_mcp_server":
|
|
58830
58823
|
case "list_tools":
|
|
58831
58824
|
allowed([]);
|
|
58832
58825
|
return { operation: value.operation };
|
|
@@ -58856,7 +58849,7 @@ function validateOperationRequest(request, maxSearchLimit) {
|
|
|
58856
58849
|
"fields"
|
|
58857
58850
|
]);
|
|
58858
58851
|
if (!value.tool) throw new CapletsError("REQUEST_INVALID", "call_tool requires tool");
|
|
58859
|
-
if (!isPlainObject(value.arguments)) throw new CapletsError("REQUEST_INVALID", "call_tool.arguments must be a JSON object");
|
|
58852
|
+
if (!isPlainObject$1(value.arguments)) throw new CapletsError("REQUEST_INVALID", "call_tool.arguments must be a JSON object");
|
|
58860
58853
|
return value.fields === void 0 ? {
|
|
58861
58854
|
operation: "call_tool",
|
|
58862
58855
|
tool: value.tool,
|
|
@@ -58877,7 +58870,7 @@ function jsonResult(value) {
|
|
|
58877
58870
|
return {
|
|
58878
58871
|
content: [{
|
|
58879
58872
|
type: "text",
|
|
58880
|
-
text:
|
|
58873
|
+
text: "Result available in structuredContent.result."
|
|
58881
58874
|
}],
|
|
58882
58875
|
structuredContent: { result: value }
|
|
58883
58876
|
};
|
|
@@ -58885,7 +58878,7 @@ function jsonResult(value) {
|
|
|
58885
58878
|
function projectCallToolResult(result, outputSchema, fields) {
|
|
58886
58879
|
if (result.isError === true) return result;
|
|
58887
58880
|
const structuredContent = result.structuredContent;
|
|
58888
|
-
if (!isPlainObject(structuredContent)) throw new CapletsError("DOWNSTREAM_PROTOCOL_ERROR", "Field selection requires the downstream tool to return object structuredContent");
|
|
58881
|
+
if (!isPlainObject$1(structuredContent)) throw new CapletsError("DOWNSTREAM_PROTOCOL_ERROR", "Field selection requires the downstream tool to return object structuredContent");
|
|
58889
58882
|
const projected = projectStructuredContent(structuredContent, outputSchema, fields);
|
|
58890
58883
|
return {
|
|
58891
58884
|
...result,
|
|
@@ -58896,7 +58889,7 @@ function projectCallToolResult(result, outputSchema, fields) {
|
|
|
58896
58889
|
structuredContent: projected
|
|
58897
58890
|
};
|
|
58898
58891
|
}
|
|
58899
|
-
function isPlainObject(value) {
|
|
58892
|
+
function isPlainObject$1(value) {
|
|
58900
58893
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
58901
58894
|
}
|
|
58902
58895
|
function backendFor(server, downstream, openapi, graphql, http, cli, caplets) {
|
|
@@ -62992,7 +62985,7 @@ async function loginAuth(serverId, options) {
|
|
|
62992
62985
|
};
|
|
62993
62986
|
if (server.backend === "mcp") await runOAuthFlow(server, flowOptions);
|
|
62994
62987
|
else await runGenericOAuthFlow(server, flowOptions);
|
|
62995
|
-
options.writeOut(`Authenticated
|
|
62988
|
+
options.writeOut(`Authenticated \`${serverId}\`.\n`);
|
|
62996
62989
|
} catch (error) {
|
|
62997
62990
|
options.writeErr(`${JSON.stringify(toSafeError(error, "AUTH_FAILED"), null, 2)}\n`);
|
|
62998
62991
|
process.exitCode = 1;
|
|
@@ -63000,25 +62993,47 @@ async function loginAuth(serverId, options) {
|
|
|
63000
62993
|
}
|
|
63001
62994
|
function logoutAuth(serverId, options) {
|
|
63002
62995
|
assertLoginTarget(findAuthTarget(serverId, loadConfig(options.configPath)), serverId);
|
|
63003
|
-
if (deleteTokenBundle(serverId, options.authDir)) options.writeOut(`Deleted OAuth credentials for
|
|
63004
|
-
else options.writeOut(`No OAuth credentials found for
|
|
62996
|
+
if (deleteTokenBundle(serverId, options.authDir)) options.writeOut(`Deleted OAuth credentials for \`${serverId}\`.\n`);
|
|
62997
|
+
else options.writeOut(`No OAuth credentials found for \`${serverId}\`.\n`);
|
|
63005
62998
|
}
|
|
63006
62999
|
function listAuth(options) {
|
|
63007
63000
|
const servers = authTargets(loadConfig(options.configPath)).sort((left, right) => left.server.localeCompare(right.server));
|
|
63001
|
+
const format = options.format ?? "plain";
|
|
63002
|
+
if (format === "json") {
|
|
63003
|
+
const rows = servers.map((server) => {
|
|
63004
|
+
const bundle = readTokenBundle(server.server, options.authDir);
|
|
63005
|
+
const status = !bundle ? "missing" : isTokenBundleExpired(bundle) ? "expired" : "authenticated";
|
|
63006
|
+
return {
|
|
63007
|
+
server: server.server,
|
|
63008
|
+
status,
|
|
63009
|
+
...bundle?.expiresAt ? { expiresAt: bundle.expiresAt } : {},
|
|
63010
|
+
...bundle?.scope ? { scope: bundle.scope } : {}
|
|
63011
|
+
};
|
|
63012
|
+
});
|
|
63013
|
+
options.writeOut(`${JSON.stringify(rows, null, 2)}\n`);
|
|
63014
|
+
return;
|
|
63015
|
+
}
|
|
63008
63016
|
if (servers.length === 0) {
|
|
63009
|
-
options.writeOut("No configured remote OAuth servers found.\n");
|
|
63017
|
+
options.writeOut(format === "markdown" ? "## OAuth credentials\n\nNo configured remote OAuth servers found.\n" : "No configured remote OAuth servers found.\n");
|
|
63010
63018
|
return;
|
|
63011
63019
|
}
|
|
63020
|
+
if (format === "markdown") options.writeOut("## OAuth credentials\n\n");
|
|
63021
|
+
else options.writeOut("OAuth credentials\n\n");
|
|
63012
63022
|
for (const server of servers) {
|
|
63013
63023
|
const bundle = readTokenBundle(server.server, options.authDir);
|
|
63014
63024
|
const status = !bundle ? "missing" : isTokenBundleExpired(bundle) ? "expired" : "authenticated";
|
|
63025
|
+
const details = [bundle?.expiresAt ? `expires ${bundle.expiresAt}` : void 0, bundle?.scope ? `scope ${bundle.scope}` : void 0].filter(Boolean).join("; ");
|
|
63026
|
+
if (format === "markdown") {
|
|
63027
|
+
options.writeOut(`- \`${server.server}\` — ${status}${details ? ` (${details})` : ""}\n`);
|
|
63028
|
+
continue;
|
|
63029
|
+
}
|
|
63015
63030
|
options.writeOut([
|
|
63016
63031
|
server.server,
|
|
63017
|
-
status
|
|
63018
|
-
bundle?.expiresAt ? `
|
|
63019
|
-
bundle?.scope ? `
|
|
63020
|
-
].
|
|
63021
|
-
options.writeOut("\n");
|
|
63032
|
+
` Status: ${status}`,
|
|
63033
|
+
...bundle?.expiresAt ? [` Expires: ${bundle.expiresAt}`] : [],
|
|
63034
|
+
...bundle?.scope ? [` Scope: ${bundle.scope}`] : []
|
|
63035
|
+
].join("\n"));
|
|
63036
|
+
options.writeOut("\n\n");
|
|
63022
63037
|
}
|
|
63023
63038
|
}
|
|
63024
63039
|
function findAuthTarget(serverId, config = loadConfig()) {
|
|
@@ -63118,24 +63133,49 @@ function allCaplets(config) {
|
|
|
63118
63133
|
...Object.values(config.cliTools)
|
|
63119
63134
|
];
|
|
63120
63135
|
}
|
|
63121
|
-
function formatCapletList(rows) {
|
|
63136
|
+
function formatCapletList(rows, format = "plain") {
|
|
63137
|
+
return format === "markdown" ? formatCapletListMarkdown(rows) : formatCapletListPlain(rows);
|
|
63138
|
+
}
|
|
63139
|
+
function formatCapletListMarkdown(rows) {
|
|
63140
|
+
if (rows.length === 0) return "## Configured Caplets\n\nNo configured Caplets found.\n";
|
|
63141
|
+
const heading = [
|
|
63142
|
+
"## Configured Caplets",
|
|
63143
|
+
"",
|
|
63144
|
+
`${rows.length} ${rows.length === 1 ? "Caplet" : "Caplets"} shown.`,
|
|
63145
|
+
""
|
|
63146
|
+
];
|
|
63147
|
+
const entries = rows.flatMap((row) => [
|
|
63148
|
+
`- \`${row.server}\` — ${row.name}`,
|
|
63149
|
+
` - Backend: ${row.backend}`,
|
|
63150
|
+
` - Status: ${row.status}`,
|
|
63151
|
+
` - Source: ${row.source}`,
|
|
63152
|
+
...row.disabled ? [" - Disabled: true"] : [],
|
|
63153
|
+
...row.path ? [` - Path: ${row.path}`] : []
|
|
63154
|
+
]);
|
|
63155
|
+
const warnings = rows.flatMap((row) => row.shadows.map((shadow) => `Warning: ${formatSourceKind(row.source)} Caplet ${row.server} shadows ${formatSourceKind(shadow.kind)} Caplet at ${shadow.path}`));
|
|
63156
|
+
if (warnings.length === 0) return `${[...heading, ...entries].join("\n")}\n`;
|
|
63157
|
+
return `${[
|
|
63158
|
+
...heading,
|
|
63159
|
+
...entries,
|
|
63160
|
+
"",
|
|
63161
|
+
"Warnings:",
|
|
63162
|
+
...warnings.map((warning) => `- ${warning}`)
|
|
63163
|
+
].join("\n")}\n`;
|
|
63164
|
+
}
|
|
63165
|
+
function formatCapletListPlain(rows) {
|
|
63122
63166
|
if (rows.length === 0) return "No configured Caplets found.\n";
|
|
63123
|
-
const
|
|
63124
|
-
"server",
|
|
63125
|
-
"backend",
|
|
63126
|
-
"status",
|
|
63127
|
-
"source",
|
|
63128
|
-
"name"
|
|
63129
|
-
], ...rows.map((row) => [
|
|
63167
|
+
const entries = rows.map((row) => [
|
|
63130
63168
|
row.server,
|
|
63131
|
-
row.
|
|
63132
|
-
row.
|
|
63133
|
-
row.
|
|
63134
|
-
row.
|
|
63135
|
-
|
|
63169
|
+
` Name: ${row.name}`,
|
|
63170
|
+
` Backend: ${row.backend}`,
|
|
63171
|
+
` Status: ${row.status}`,
|
|
63172
|
+
` Source: ${row.source}`,
|
|
63173
|
+
...row.disabled ? [" Disabled: true"] : [],
|
|
63174
|
+
...row.path ? [` Path: ${row.path}`] : []
|
|
63175
|
+
].join("\n")).join("\n\n");
|
|
63136
63176
|
const warnings = rows.flatMap((row) => row.shadows.map((shadow) => `Warning: ${formatSourceKind(row.source)} Caplet ${row.server} shadows ${formatSourceKind(shadow.kind)} Caplet at ${shadow.path}`));
|
|
63137
|
-
if (warnings.length === 0) return
|
|
63138
|
-
return
|
|
63177
|
+
if (warnings.length === 0) return `Configured Caplets (${rows.length})\n\n${entries}\n`;
|
|
63178
|
+
return `Configured Caplets (${rows.length})\n\n${entries}\n\n${warnings.join("\n")}\n`;
|
|
63139
63179
|
}
|
|
63140
63180
|
function formatSourceKind(kind) {
|
|
63141
63181
|
if (kind.startsWith("project")) return "project";
|
|
@@ -63155,28 +63195,35 @@ function resolveCliConfigPaths(envConfigPath, authDir) {
|
|
|
63155
63195
|
envConfig: envConfigPath ?? null
|
|
63156
63196
|
};
|
|
63157
63197
|
}
|
|
63158
|
-
function formatConfigPaths(paths) {
|
|
63198
|
+
function formatConfigPaths(paths, format = "plain") {
|
|
63199
|
+
if (format === "markdown") return formatConfigPathsMarkdown(paths);
|
|
63200
|
+
return formatConfigPathsPlain(paths);
|
|
63201
|
+
}
|
|
63202
|
+
function formatConfigPathsMarkdown(paths) {
|
|
63159
63203
|
return [
|
|
63160
|
-
|
|
63161
|
-
|
|
63162
|
-
|
|
63163
|
-
|
|
63164
|
-
|
|
63165
|
-
|
|
63166
|
-
|
|
63204
|
+
"## Caplets paths",
|
|
63205
|
+
"",
|
|
63206
|
+
`- User config: ${paths.userConfig}`,
|
|
63207
|
+
`- Project config: ${paths.projectConfig}`,
|
|
63208
|
+
`- User Caplets root: ${paths.userRoot}`,
|
|
63209
|
+
`- State root: ${paths.stateRoot}`,
|
|
63210
|
+
`- Project Caplets root: ${paths.projectRoot}`,
|
|
63211
|
+
`- Auth directory: ${paths.authDir}`,
|
|
63212
|
+
`- CAPLETS_CONFIG: ${paths.envConfig ?? "unset"}`
|
|
63167
63213
|
].join("\n") + "\n";
|
|
63168
63214
|
}
|
|
63169
|
-
function
|
|
63170
|
-
|
|
63171
|
-
|
|
63172
|
-
|
|
63173
|
-
|
|
63174
|
-
}
|
|
63175
|
-
|
|
63176
|
-
|
|
63177
|
-
|
|
63178
|
-
|
|
63179
|
-
|
|
63215
|
+
function formatConfigPathsPlain(paths) {
|
|
63216
|
+
return [
|
|
63217
|
+
"Caplets paths",
|
|
63218
|
+
"",
|
|
63219
|
+
`User config: ${paths.userConfig}`,
|
|
63220
|
+
`Project config: ${paths.projectConfig}`,
|
|
63221
|
+
`User root: ${paths.userRoot}`,
|
|
63222
|
+
`State root: ${paths.stateRoot}`,
|
|
63223
|
+
`Project root: ${paths.projectRoot}`,
|
|
63224
|
+
`Auth directory: ${paths.authDir}`,
|
|
63225
|
+
`CAPLETS_CONFIG: ${paths.envConfig ?? "unset"}`
|
|
63226
|
+
].join("\n") + "\n";
|
|
63180
63227
|
}
|
|
63181
63228
|
//#endregion
|
|
63182
63229
|
//#region ../core/src/cli/install.ts
|
|
@@ -63425,7 +63472,7 @@ async function runCli(args, io = {}) {
|
|
|
63425
63472
|
]);
|
|
63426
63473
|
} catch (error) {
|
|
63427
63474
|
if (error instanceof CommanderError) {
|
|
63428
|
-
if (error.code === "commander.helpDisplayed" || error.code === "commander.version") return;
|
|
63475
|
+
if (error.code === "commander.helpDisplayed" || error.code === "commander.version" || error.message === "(outputHelp)") return;
|
|
63429
63476
|
throw new CapletsError("REQUEST_INVALID", error.message);
|
|
63430
63477
|
}
|
|
63431
63478
|
throw error;
|
|
@@ -63434,6 +63481,9 @@ async function runCli(args, io = {}) {
|
|
|
63434
63481
|
function createProgram(io = {}) {
|
|
63435
63482
|
const writeOut = io.writeOut ?? ((value) => process.stdout.write(value));
|
|
63436
63483
|
const writeErr = io.writeErr ?? ((value) => process.stderr.write(value));
|
|
63484
|
+
const setExitCode = io.setExitCode ?? ((code) => {
|
|
63485
|
+
process.exitCode = code;
|
|
63486
|
+
});
|
|
63437
63487
|
const program = new Command();
|
|
63438
63488
|
program.name("caplets").description("Progressive-disclosure gateway for MCP servers.").version(io.version ?? version$1).exitOverride().configureOutput({
|
|
63439
63489
|
writeOut,
|
|
@@ -63447,13 +63497,13 @@ function createProgram(io = {}) {
|
|
|
63447
63497
|
force: Boolean(options.force)
|
|
63448
63498
|
})}\n`);
|
|
63449
63499
|
});
|
|
63450
|
-
program.command("list").description("List configured Caplets.").option("--all", "include disabled Caplets").option("--json", "print JSON output").action((options) => {
|
|
63500
|
+
program.command("list").description("List configured Caplets.").option("--all", "include disabled Caplets").option("--json", "print JSON output").option("--format <format>", "output format: plain, markdown, md, or json", parseOutputFormat).action((options) => {
|
|
63451
63501
|
const rows = listCaplets(loadConfigWithSources(envConfigPath()), { includeDisabled: Boolean(options.all) });
|
|
63452
|
-
if (options.json) {
|
|
63502
|
+
if (options.json || options.format === "json") {
|
|
63453
63503
|
writeOut(`${JSON.stringify(rows, null, 2)}\n`);
|
|
63454
63504
|
return;
|
|
63455
63505
|
}
|
|
63456
|
-
writeOut(formatCapletList(rows));
|
|
63506
|
+
writeOut(formatCapletList(rows, options.format ?? "plain"));
|
|
63457
63507
|
});
|
|
63458
63508
|
program.command("install").description("Install Caplets from a repo's caplets directory.").argument("<repo>", "local repo path, Git URL, or GitHub owner/repo").argument("[caplets...]", "optional Caplet IDs to install").option("-g, --global", "install to the user Caplets root").option("--force", "overwrite installed Caplets").action((repo, capletIds, options) => {
|
|
63459
63509
|
const result = installCaplets(repo, {
|
|
@@ -63499,17 +63549,88 @@ function createProgram(io = {}) {
|
|
|
63499
63549
|
destinationRoot: addDestinationRoot(options)
|
|
63500
63550
|
}));
|
|
63501
63551
|
});
|
|
63552
|
+
program.command("get-caplet").description("Print a configured Caplet card.").argument("<caplet>", "configured Caplet ID").option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (caplet, options) => {
|
|
63553
|
+
await executeOperation(caplet, { operation: "get_caplet" }, {
|
|
63554
|
+
writeOut,
|
|
63555
|
+
writeErr,
|
|
63556
|
+
setExitCode,
|
|
63557
|
+
authDir: io.authDir,
|
|
63558
|
+
format: options.format
|
|
63559
|
+
});
|
|
63560
|
+
});
|
|
63561
|
+
program.command("check-backend").description("Check backend availability for a configured Caplet.").argument("<caplet>", "configured Caplet ID").option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (caplet, options) => {
|
|
63562
|
+
await executeOperation(caplet, { operation: "check_backend" }, {
|
|
63563
|
+
writeOut,
|
|
63564
|
+
writeErr,
|
|
63565
|
+
setExitCode,
|
|
63566
|
+
authDir: io.authDir,
|
|
63567
|
+
format: options.format
|
|
63568
|
+
});
|
|
63569
|
+
});
|
|
63570
|
+
program.command("list-tools").description("List downstream tools for a configured Caplet.").argument("<caplet>", "configured Caplet ID").option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (caplet, options) => {
|
|
63571
|
+
await executeOperation(caplet, { operation: "list_tools" }, {
|
|
63572
|
+
writeOut,
|
|
63573
|
+
writeErr,
|
|
63574
|
+
setExitCode,
|
|
63575
|
+
authDir: io.authDir,
|
|
63576
|
+
format: options.format
|
|
63577
|
+
});
|
|
63578
|
+
});
|
|
63579
|
+
program.command("search-tools").description("Search downstream tools for a configured Caplet.").argument("<caplet>", "configured Caplet ID").argument("<query>", "search query").option("--limit <n>", "maximum number of tools to return", parsePositiveInteger).option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (caplet, query, options) => {
|
|
63580
|
+
await executeOperation(caplet, options.limit === void 0 ? {
|
|
63581
|
+
operation: "search_tools",
|
|
63582
|
+
query
|
|
63583
|
+
} : {
|
|
63584
|
+
operation: "search_tools",
|
|
63585
|
+
query,
|
|
63586
|
+
limit: options.limit
|
|
63587
|
+
}, {
|
|
63588
|
+
writeOut,
|
|
63589
|
+
writeErr,
|
|
63590
|
+
setExitCode,
|
|
63591
|
+
authDir: io.authDir,
|
|
63592
|
+
format: options.format
|
|
63593
|
+
});
|
|
63594
|
+
});
|
|
63595
|
+
program.command("get-tool").description("Print one downstream tool schema.").argument("<caplet.tool>", "qualified target, split on the first dot").option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (target, options) => {
|
|
63596
|
+
const { caplet, tool } = parseQualifiedTarget(target);
|
|
63597
|
+
await executeOperation(caplet, {
|
|
63598
|
+
operation: "get_tool",
|
|
63599
|
+
tool
|
|
63600
|
+
}, {
|
|
63601
|
+
writeOut,
|
|
63602
|
+
writeErr,
|
|
63603
|
+
setExitCode,
|
|
63604
|
+
authDir: io.authDir,
|
|
63605
|
+
format: options.format
|
|
63606
|
+
});
|
|
63607
|
+
});
|
|
63608
|
+
program.command("call-tool").description("Call one downstream tool.").argument("<caplet.tool>", "qualified target, split on the first dot").option("--args <json-object>", "JSON object of downstream tool arguments").option("--field <path>", "project a field from structured output", collect, []).option("--format <format>", "output format: markdown, md, plain, or json", parseOutputFormat).action(async (target, options) => {
|
|
63609
|
+
const { caplet, tool } = parseQualifiedTarget(target);
|
|
63610
|
+
await executeOperation(caplet, {
|
|
63611
|
+
operation: "call_tool",
|
|
63612
|
+
tool,
|
|
63613
|
+
arguments: parseCallToolArgs(options.args),
|
|
63614
|
+
...options.field && options.field.length > 0 ? { fields: options.field } : {}
|
|
63615
|
+
}, {
|
|
63616
|
+
writeOut,
|
|
63617
|
+
writeErr,
|
|
63618
|
+
setExitCode,
|
|
63619
|
+
authDir: io.authDir,
|
|
63620
|
+
format: options.format
|
|
63621
|
+
});
|
|
63622
|
+
});
|
|
63502
63623
|
const config = program.command("config").description("Inspect Caplets config locations.");
|
|
63503
63624
|
config.command("path").description("Print the effective user config path.").action(() => {
|
|
63504
63625
|
writeOut(`${resolveConfigPath(envConfigPath())}\n`);
|
|
63505
63626
|
});
|
|
63506
|
-
config.command("paths").description("Print resolved Caplets config, root, and auth paths.").option("--json", "print JSON output").action((options) => {
|
|
63627
|
+
config.command("paths").description("Print resolved Caplets config, root, and auth paths.").option("--json", "print JSON output").option("--format <format>", "output format: plain, markdown, md, or json", parseOutputFormat).action((options) => {
|
|
63507
63628
|
const paths = resolveCliConfigPaths(envConfigPath(), io.authDir);
|
|
63508
|
-
if (options.json) {
|
|
63629
|
+
if (options.json || options.format === "json") {
|
|
63509
63630
|
writeOut(`${JSON.stringify(paths, null, 2)}\n`);
|
|
63510
63631
|
return;
|
|
63511
63632
|
}
|
|
63512
|
-
writeOut(formatConfigPaths(paths));
|
|
63633
|
+
writeOut(formatConfigPaths(paths, options.format ?? "plain"));
|
|
63513
63634
|
});
|
|
63514
63635
|
const auth = program.command("auth").description("Manage OAuth credentials for remote servers.");
|
|
63515
63636
|
auth.command("login").description("Authenticate a configured remote OAuth server.").argument("<server>", "configured server ID").option("--no-open", "print the authorization URL without opening a browser").action(async (serverId, options) => {
|
|
@@ -63530,10 +63651,11 @@ function createProgram(io = {}) {
|
|
|
63530
63651
|
...io.authDir ? { authDir: io.authDir } : {}
|
|
63531
63652
|
});
|
|
63532
63653
|
});
|
|
63533
|
-
auth.command("list").description("List servers with stored OAuth credentials.").action(() => {
|
|
63654
|
+
auth.command("list").description("List servers with stored OAuth credentials.").option("--json", "print JSON output").option("--format <format>", "output format: plain, markdown, md, or json", parseOutputFormat).action((options) => {
|
|
63534
63655
|
const configPath = envConfigPath();
|
|
63535
63656
|
listAuth({
|
|
63536
63657
|
writeOut,
|
|
63658
|
+
format: options.json || options.format === "json" ? "json" : options.format ?? "plain",
|
|
63537
63659
|
...configPath ? { configPath } : {},
|
|
63538
63660
|
...io.authDir ? { authDir: io.authDir } : {}
|
|
63539
63661
|
});
|
|
@@ -63547,6 +63669,284 @@ function collect(value, previous) {
|
|
|
63547
63669
|
previous.push(value);
|
|
63548
63670
|
return previous;
|
|
63549
63671
|
}
|
|
63672
|
+
function parsePositiveInteger(value) {
|
|
63673
|
+
const parsed = Number(value);
|
|
63674
|
+
if (!Number.isInteger(parsed) || parsed <= 0) throw new CapletsError("REQUEST_INVALID", `Expected a positive integer, got ${value}`);
|
|
63675
|
+
return parsed;
|
|
63676
|
+
}
|
|
63677
|
+
function parseOutputFormat(value) {
|
|
63678
|
+
switch (value.toLocaleLowerCase()) {
|
|
63679
|
+
case "markdown":
|
|
63680
|
+
case "md": return "markdown";
|
|
63681
|
+
case "plain": return "plain";
|
|
63682
|
+
case "json": return "json";
|
|
63683
|
+
default: throw new CapletsError("REQUEST_INVALID", `Expected output format markdown, md, plain, or json; got ${value}`);
|
|
63684
|
+
}
|
|
63685
|
+
}
|
|
63686
|
+
function parseQualifiedTarget(target) {
|
|
63687
|
+
const dot = target.indexOf(".");
|
|
63688
|
+
if (dot <= 0 || dot === target.length - 1) throw new CapletsError("REQUEST_INVALID", "Expected qualified target in the form <caplet>.<tool>");
|
|
63689
|
+
return {
|
|
63690
|
+
caplet: target.slice(0, dot),
|
|
63691
|
+
tool: target.slice(dot + 1)
|
|
63692
|
+
};
|
|
63693
|
+
}
|
|
63694
|
+
function parseCallToolArgs(value) {
|
|
63695
|
+
if (value === void 0) return {};
|
|
63696
|
+
let parsed;
|
|
63697
|
+
try {
|
|
63698
|
+
parsed = JSON.parse(value);
|
|
63699
|
+
} catch (error) {
|
|
63700
|
+
throw new CapletsError("REQUEST_INVALID", "call-tool --args must be valid JSON", error);
|
|
63701
|
+
}
|
|
63702
|
+
if (!isPlainObject(parsed)) throw new CapletsError("REQUEST_INVALID", "call-tool --args must be a JSON object");
|
|
63703
|
+
return parsed;
|
|
63704
|
+
}
|
|
63705
|
+
function isPlainObject(value) {
|
|
63706
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
63707
|
+
}
|
|
63708
|
+
async function executeOperation(caplet, request, io) {
|
|
63709
|
+
const configPath = envConfigPath();
|
|
63710
|
+
const engine = new CapletsEngine({
|
|
63711
|
+
...configPath ? { configPath } : {},
|
|
63712
|
+
...io.authDir ? { authDir: io.authDir } : {},
|
|
63713
|
+
watch: false,
|
|
63714
|
+
writeErr: io.writeErr
|
|
63715
|
+
});
|
|
63716
|
+
try {
|
|
63717
|
+
const result = await engine.execute(caplet, request);
|
|
63718
|
+
const output = cliOutputForOperation(result, {
|
|
63719
|
+
...request,
|
|
63720
|
+
caplet
|
|
63721
|
+
}, io.format ?? "markdown");
|
|
63722
|
+
io.writeOut(typeof output === "string" ? `${output}\n` : `${JSON.stringify(output, null, 2)}\n`);
|
|
63723
|
+
if (isPlainObject(result) && result.isError === true) io.setExitCode(1);
|
|
63724
|
+
} finally {
|
|
63725
|
+
await engine.close();
|
|
63726
|
+
}
|
|
63727
|
+
}
|
|
63728
|
+
function cliOutputForOperation(result, request, format) {
|
|
63729
|
+
if (format === "json" || !isPlainObject(result)) return jsonPayloadForOperation(result, request.operation);
|
|
63730
|
+
return format === "markdown" ? markdownSummaryForOperation(result, request) : plainSummaryForOperation(result, request);
|
|
63731
|
+
}
|
|
63732
|
+
function jsonPayloadForOperation(result, operation) {
|
|
63733
|
+
if (operation === "call_tool" || !isPlainObject(result)) return result;
|
|
63734
|
+
const structuredContent = result.structuredContent;
|
|
63735
|
+
if (!isPlainObject(structuredContent) || !("result" in structuredContent)) return result;
|
|
63736
|
+
return structuredContent.result;
|
|
63737
|
+
}
|
|
63738
|
+
function markdownSummaryForOperation(result, request) {
|
|
63739
|
+
const operation = request.operation;
|
|
63740
|
+
const payload = jsonPayloadForOperation(result, operation);
|
|
63741
|
+
if (!isPlainObject(payload)) return String(payload);
|
|
63742
|
+
switch (operation) {
|
|
63743
|
+
case "get_caplet": return [
|
|
63744
|
+
`## Caplet \`${String(payload.caplet ?? "unknown")}\``,
|
|
63745
|
+
"",
|
|
63746
|
+
`**Name:** ${String(payload.name ?? "Unnamed")}`,
|
|
63747
|
+
`**Description:** ${String(payload.description ?? "No description.")}`,
|
|
63748
|
+
payload.backend ? `**Backend:** ${backendType(payload.backend)}` : void 0,
|
|
63749
|
+
"",
|
|
63750
|
+
"Next:",
|
|
63751
|
+
`- List tools: \`caplets list-tools ${String(payload.caplet ?? "<caplet>")}\``,
|
|
63752
|
+
`- Search tools: \`caplets search-tools ${String(payload.caplet ?? "<caplet>")} <query>\``
|
|
63753
|
+
].filter((line) => line !== void 0).join("\n");
|
|
63754
|
+
case "check_backend": return [
|
|
63755
|
+
`## Backend \`${String(payload.server ?? "caplet")}\``,
|
|
63756
|
+
"",
|
|
63757
|
+
`- Status: ${String(payload.status ?? "unknown")}`,
|
|
63758
|
+
typeof payload.toolCount === "number" ? `- Tools: ${payload.toolCount}` : void 0,
|
|
63759
|
+
typeof payload.elapsedMs === "number" ? `- Elapsed: ${payload.elapsedMs}ms` : void 0,
|
|
63760
|
+
"",
|
|
63761
|
+
"Next:",
|
|
63762
|
+
`- List tools: \`caplets list-tools ${String(payload.server ?? "<caplet>")}\``
|
|
63763
|
+
].filter((line) => line !== void 0).join("\n");
|
|
63764
|
+
case "list_tools": {
|
|
63765
|
+
const tools = Array.isArray(payload.tools) ? payload.tools : [];
|
|
63766
|
+
return [
|
|
63767
|
+
`## Tools for \`${String(payload.server ?? "caplet")}\``,
|
|
63768
|
+
"",
|
|
63769
|
+
`${tools.length} ${tools.length === 1 ? "tool" : "tools"} found.`,
|
|
63770
|
+
"",
|
|
63771
|
+
...formatToolLines(tools, "markdown"),
|
|
63772
|
+
"",
|
|
63773
|
+
"Next:",
|
|
63774
|
+
`- Inspect a tool: \`caplets get-tool ${String(payload.server ?? "<caplet>")}.<tool>\``,
|
|
63775
|
+
`- Call a tool: \`caplets call-tool ${String(payload.server ?? "<caplet>")}.<tool> --args '{...}'\``,
|
|
63776
|
+
"- Machine output: add `--format json`"
|
|
63777
|
+
].join("\n");
|
|
63778
|
+
}
|
|
63779
|
+
case "search_tools": {
|
|
63780
|
+
const tools = Array.isArray(payload.tools) ? payload.tools : [];
|
|
63781
|
+
return [
|
|
63782
|
+
`## Matches for ${JSON.stringify(String(payload.query ?? ""))} in \`${String(payload.server ?? "caplet")}\``,
|
|
63783
|
+
"",
|
|
63784
|
+
`${tools.length} ${tools.length === 1 ? "match" : "matches"} found.`,
|
|
63785
|
+
"",
|
|
63786
|
+
...formatToolLines(tools, "markdown"),
|
|
63787
|
+
"",
|
|
63788
|
+
"Next:",
|
|
63789
|
+
tools.length > 0 ? `- Inspect the first match: \`caplets get-tool ${String(payload.server ?? "<caplet>")}.${firstToolName(tools) ?? "<tool>"}\`` : `- Try a broader query or list tools: \`caplets list-tools ${String(payload.server ?? "<caplet>")}\``
|
|
63790
|
+
].join("\n");
|
|
63791
|
+
}
|
|
63792
|
+
case "get_tool": {
|
|
63793
|
+
const tool = isPlainObject(payload.tool) ? payload.tool : {};
|
|
63794
|
+
const target = `${String(payload.server ?? "<caplet>")}.${String(tool.name ?? "<tool>")}`;
|
|
63795
|
+
return [
|
|
63796
|
+
`## Tool \`${target}\``,
|
|
63797
|
+
"",
|
|
63798
|
+
tool.description ? compactDescription(String(tool.description)) : void 0,
|
|
63799
|
+
"",
|
|
63800
|
+
"Input:",
|
|
63801
|
+
`- ${schemaSummary(tool.inputSchema)}`,
|
|
63802
|
+
"",
|
|
63803
|
+
"Output:",
|
|
63804
|
+
`- ${tool.outputSchema ? schemaSummary(tool.outputSchema) : "not declared"}`,
|
|
63805
|
+
"",
|
|
63806
|
+
"Next:",
|
|
63807
|
+
`- Call: \`caplets call-tool ${target} --args '{...}'\``,
|
|
63808
|
+
"- Full schema: add `--format json`"
|
|
63809
|
+
].filter((line) => line !== void 0).join("\n");
|
|
63810
|
+
}
|
|
63811
|
+
case "call_tool": return [
|
|
63812
|
+
`## Call \`${`${String(request.caplet ?? "<caplet>")}.${String(request.tool ?? "unknown")}`}\``,
|
|
63813
|
+
"",
|
|
63814
|
+
`- Status: ${payload.isError === true ? "failed" : "succeeded"}`,
|
|
63815
|
+
callStatusLine(payload) ? `- ${callStatusLine(payload)}` : void 0,
|
|
63816
|
+
`- Result: ${summarizeCallResult(payload)}`,
|
|
63817
|
+
"",
|
|
63818
|
+
"Use `--format json` to inspect the full structured result."
|
|
63819
|
+
].filter((line) => line !== void 0).join("\n");
|
|
63820
|
+
default: return JSON.stringify(payload, null, 2);
|
|
63821
|
+
}
|
|
63822
|
+
}
|
|
63823
|
+
function plainSummaryForOperation(result, request) {
|
|
63824
|
+
const operation = request.operation;
|
|
63825
|
+
const payload = jsonPayloadForOperation(result, operation);
|
|
63826
|
+
if (!isPlainObject(payload)) return String(payload);
|
|
63827
|
+
switch (operation) {
|
|
63828
|
+
case "get_caplet": return [
|
|
63829
|
+
`Caplet: ${String(payload.caplet ?? "unknown")}`,
|
|
63830
|
+
`Name: ${String(payload.name ?? "Unnamed")}`,
|
|
63831
|
+
`Description: ${String(payload.description ?? "No description.")}`,
|
|
63832
|
+
payload.backend ? `Backend: ${backendType(payload.backend)}` : void 0,
|
|
63833
|
+
`Next: caplets list-tools ${String(payload.caplet ?? "<caplet>")} or caplets search-tools ${String(payload.caplet ?? "<caplet>")} <query>`
|
|
63834
|
+
].filter((line) => Boolean(line)).join("\n");
|
|
63835
|
+
case "check_backend": return [
|
|
63836
|
+
`Backend: ${String(payload.server ?? "caplet")} is ${String(payload.status ?? "unknown")}`,
|
|
63837
|
+
typeof payload.toolCount === "number" ? `Tools: ${payload.toolCount}` : void 0,
|
|
63838
|
+
typeof payload.elapsedMs === "number" ? `Elapsed: ${payload.elapsedMs}ms` : void 0,
|
|
63839
|
+
`Next: caplets list-tools ${String(payload.server ?? "<caplet>")}`
|
|
63840
|
+
].filter((line) => Boolean(line)).join("\n");
|
|
63841
|
+
case "list_tools": {
|
|
63842
|
+
const tools = Array.isArray(payload.tools) ? payload.tools : [];
|
|
63843
|
+
return [
|
|
63844
|
+
`Tools for ${String(payload.server ?? "caplet")} (${tools.length}):`,
|
|
63845
|
+
...formatToolLines(tools, "plain"),
|
|
63846
|
+
`Next: caplets get-tool ${String(payload.server ?? "<caplet>")}.<tool> or caplets call-tool ${String(payload.server ?? "<caplet>")}.<tool> --args '{...}'`
|
|
63847
|
+
].join("\n");
|
|
63848
|
+
}
|
|
63849
|
+
case "search_tools": {
|
|
63850
|
+
const tools = Array.isArray(payload.tools) ? payload.tools : [];
|
|
63851
|
+
return [
|
|
63852
|
+
`Matches for ${JSON.stringify(String(payload.query ?? ""))} in ${String(payload.server ?? "caplet")} (${tools.length}):`,
|
|
63853
|
+
...formatToolLines(tools, "plain"),
|
|
63854
|
+
tools.length > 0 ? `Next: caplets get-tool ${String(payload.server ?? "<caplet>")}.${firstToolName(tools) ?? "<tool>"}` : `Next: try caplets list-tools ${String(payload.server ?? "<caplet>")} or a broader query.`
|
|
63855
|
+
].join("\n");
|
|
63856
|
+
}
|
|
63857
|
+
case "get_tool": {
|
|
63858
|
+
const tool = isPlainObject(payload.tool) ? payload.tool : {};
|
|
63859
|
+
const target = `${String(payload.server ?? "<caplet>")}.${String(tool.name ?? "<tool>")}`;
|
|
63860
|
+
return [
|
|
63861
|
+
`Tool: ${target}`,
|
|
63862
|
+
tool.description ? `Description: ${compactDescription(String(tool.description))}` : void 0,
|
|
63863
|
+
`Input: ${schemaSummary(tool.inputSchema)}`,
|
|
63864
|
+
`Output: ${tool.outputSchema ? schemaSummary(tool.outputSchema) : "not declared"}`,
|
|
63865
|
+
`Next: caplets call-tool ${target} --args '{...}'`,
|
|
63866
|
+
"Use --format json to inspect full schemas and descriptions."
|
|
63867
|
+
].filter((line) => Boolean(line)).join("\n");
|
|
63868
|
+
}
|
|
63869
|
+
case "call_tool": return [
|
|
63870
|
+
`Call ${`${String(request.caplet ?? "<caplet>")}.${String(request.tool ?? "unknown")}`} ${payload.isError === true ? "failed" : "succeeded"}.`,
|
|
63871
|
+
callStatusLine(payload),
|
|
63872
|
+
`Result: ${summarizeCallResult(payload)}`,
|
|
63873
|
+
"Use --format json to inspect the full structured result."
|
|
63874
|
+
].filter((line) => Boolean(line)).join("\n");
|
|
63875
|
+
default: return JSON.stringify(payload, null, 2);
|
|
63876
|
+
}
|
|
63877
|
+
}
|
|
63878
|
+
function formatToolLines(tools, format) {
|
|
63879
|
+
if (tools.length === 0) return ["- none"];
|
|
63880
|
+
return tools.map((tool) => {
|
|
63881
|
+
if (!isPlainObject(tool)) return `- ${String(tool)}`;
|
|
63882
|
+
const name = String(tool.tool ?? tool.name ?? "unknown");
|
|
63883
|
+
const displayName = format === "markdown" ? `\`${name}\`` : name;
|
|
63884
|
+
const flags = [tool.hasInputSchema ? "input" : void 0, tool.hasOutputSchema ? "output" : void 0].filter(Boolean).join(", ");
|
|
63885
|
+
return `- ${displayName}${flags ? ` (${flags})` : ""}${tool.description ? ` — ${compactDescription(String(tool.description))}` : ""}`;
|
|
63886
|
+
});
|
|
63887
|
+
}
|
|
63888
|
+
function compactDescription(value) {
|
|
63889
|
+
const firstParagraph = value.trim().split(/\n\s*\n/u)[0] ?? "";
|
|
63890
|
+
const collapsed = (firstParagraph.match(/^.*?(?:[.!?](?=\s|$)|$)/u)?.[0] ?? firstParagraph).replace(/\s+/gu, " ").trim();
|
|
63891
|
+
return collapsed.length > 140 ? `${collapsed.slice(0, 137).trimEnd()}...` : collapsed;
|
|
63892
|
+
}
|
|
63893
|
+
function firstToolName(tools) {
|
|
63894
|
+
const first = tools[0];
|
|
63895
|
+
return isPlainObject(first) && typeof first.tool === "string" ? first.tool : void 0;
|
|
63896
|
+
}
|
|
63897
|
+
function backendType(value) {
|
|
63898
|
+
return isPlainObject(value) && typeof value.type === "string" ? value.type : "unknown";
|
|
63899
|
+
}
|
|
63900
|
+
function callStatusLine(payload) {
|
|
63901
|
+
const structured = isPlainObject(payload.structuredContent) ? payload.structuredContent : payload;
|
|
63902
|
+
return typeof structured.exitCode === "number" ? `Exit code: ${structured.exitCode}` : void 0;
|
|
63903
|
+
}
|
|
63904
|
+
function summarizeCallResult(payload) {
|
|
63905
|
+
const structured = isPlainObject(payload.structuredContent) ? payload.structuredContent : payload;
|
|
63906
|
+
const preview = previewValue(preferredPreviewValue(structured));
|
|
63907
|
+
if (preview) return preview;
|
|
63908
|
+
const keys = Object.keys(structured).filter((key) => key !== "elapsedMs");
|
|
63909
|
+
return keys.length > 0 ? `structured keys: ${keys.join(", ")}` : "no structured content";
|
|
63910
|
+
}
|
|
63911
|
+
function preferredPreviewValue(value) {
|
|
63912
|
+
if (!isPlainObject(value)) return value;
|
|
63913
|
+
if ("result" in value) return value.result;
|
|
63914
|
+
if ("json" in value) return value.json;
|
|
63915
|
+
if (typeof value.text === "string") return value.text;
|
|
63916
|
+
if (typeof value.stdout === "string" && value.stdout.trim()) return value.stdout.trim();
|
|
63917
|
+
return value;
|
|
63918
|
+
}
|
|
63919
|
+
function previewValue(value) {
|
|
63920
|
+
if (typeof value === "string") return truncatePreview(value);
|
|
63921
|
+
if (typeof value === "number" || typeof value === "boolean" || value === null) return String(value);
|
|
63922
|
+
if (Array.isArray(value)) return truncatePreview(JSON.stringify(value));
|
|
63923
|
+
if (isPlainObject(value)) {
|
|
63924
|
+
const entries = Object.entries(value).slice(0, 4);
|
|
63925
|
+
if (entries.length === 0) return "empty object";
|
|
63926
|
+
return truncatePreview(entries.map(([key, entryValue]) => `${key}: ${previewScalar(entryValue)}`).join(", "));
|
|
63927
|
+
}
|
|
63928
|
+
}
|
|
63929
|
+
function previewScalar(value) {
|
|
63930
|
+
if (typeof value === "string") return JSON.stringify(truncatePreview(value, 80));
|
|
63931
|
+
if (typeof value === "number" || typeof value === "boolean" || value === null) return String(value);
|
|
63932
|
+
if (Array.isArray(value)) return `[${value.length} item${value.length === 1 ? "" : "s"}]`;
|
|
63933
|
+
if (isPlainObject(value)) return `{${Object.keys(value).slice(0, 3).join(", ")}${Object.keys(value).length > 3 ? ", ..." : ""}}`;
|
|
63934
|
+
return typeof value;
|
|
63935
|
+
}
|
|
63936
|
+
function truncatePreview(value, maxLength = 180) {
|
|
63937
|
+
const collapsed = value.replace(/\s+/gu, " ").trim();
|
|
63938
|
+
return collapsed.length > maxLength ? `${collapsed.slice(0, maxLength - 3).trimEnd()}...` : collapsed;
|
|
63939
|
+
}
|
|
63940
|
+
function schemaSummary(schema) {
|
|
63941
|
+
if (!isPlainObject(schema)) return "not declared";
|
|
63942
|
+
const properties = isPlainObject(schema.properties) ? Object.keys(schema.properties) : [];
|
|
63943
|
+
const required = Array.isArray(schema.required) ? schema.required.filter((value) => typeof value === "string") : [];
|
|
63944
|
+
return [
|
|
63945
|
+
typeof schema.type === "string" ? `type ${schema.type}` : void 0,
|
|
63946
|
+
properties.length > 0 ? `properties ${properties.join(", ")}` : "no declared properties",
|
|
63947
|
+
required.length > 0 ? `required ${required.join(", ")}` : "no required fields"
|
|
63948
|
+
].filter((part) => Boolean(part)).join("; ");
|
|
63949
|
+
}
|
|
63550
63950
|
function addDestinationRoot(options) {
|
|
63551
63951
|
return options.global ? resolveCapletsRoot(resolveConfigPath(envConfigPath())) : resolveProjectCapletsRoot();
|
|
63552
63952
|
}
|
|
@@ -63559,7 +63959,7 @@ function writeAddResult(writeOut, label, result) {
|
|
|
63559
63959
|
}
|
|
63560
63960
|
//#endregion
|
|
63561
63961
|
//#region package.json
|
|
63562
|
-
var version = "0.
|
|
63962
|
+
var version = "0.13.0";
|
|
63563
63963
|
//#endregion
|
|
63564
63964
|
//#region src/index.ts
|
|
63565
63965
|
async function main() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "caplets",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "Progressive disclosure gateway CLI for MCP servers and native Caplets adapters.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"caplets",
|
|
@@ -33,21 +33,23 @@
|
|
|
33
33
|
"access": "public"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@modelcontextprotocol/sdk": "^1.29.0"
|
|
37
|
-
"@caplets/core": "0.13.1"
|
|
36
|
+
"@modelcontextprotocol/sdk": "^1.29.0"
|
|
38
37
|
},
|
|
39
38
|
"devDependencies": {
|
|
40
39
|
"@types/node": "^25.7.0",
|
|
40
|
+
"@typescript/native-preview": "7.0.0-dev.20260515.1",
|
|
41
41
|
"rolldown": "^1.0.0",
|
|
42
42
|
"typescript": "^6.0.3",
|
|
43
|
-
"vitest": "^4.1.6"
|
|
43
|
+
"vitest": "^4.1.6",
|
|
44
|
+
"@caplets/core": "0.14.0"
|
|
44
45
|
},
|
|
45
46
|
"engines": {
|
|
46
47
|
"node": ">=22"
|
|
47
48
|
},
|
|
48
49
|
"scripts": {
|
|
49
50
|
"build": "rm -rf dist && rolldown -c",
|
|
50
|
-
"
|
|
51
|
-
"
|
|
51
|
+
"build:watch": "rm -rf dist && rolldown -c --watch",
|
|
52
|
+
"typecheck": "tsgo --noEmit",
|
|
53
|
+
"test": "vitest run"
|
|
52
54
|
}
|
|
53
55
|
}
|