caplets 0.17.2 → 0.17.3
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 +12 -1
- package/dist/index.js +78 -16
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -548,7 +548,18 @@ This repository includes polished working examples under [`caplets/`](caplets/):
|
|
|
548
548
|
- `linear`: Linear's hosted OAuth MCP endpoint.
|
|
549
549
|
- `context7`: Context7 documentation lookup through `@upstash/context7-mcp`.
|
|
550
550
|
- `repo-cli`: Read-oriented repository CLI workflows through `git` and package scripts.
|
|
551
|
-
- `
|
|
551
|
+
- `ast-grep`: Structural code search, scan, rewrite, rule testing, and scaffolding through the `ast-grep` CLI.
|
|
552
|
+
- `osv`: OSV.dev vulnerability lookups through explicit read-only HTTP actions.
|
|
553
|
+
- `npm`: npm registry operations through npm's published OpenAPI spec URL.
|
|
554
|
+
- `pypi`: PyPI project metadata, release metadata, and Simple API JSON through a curated OpenAPI spec.
|
|
555
|
+
- `deepwiki`: Repository-focused documentation and architecture context through DeepWiki MCP.
|
|
556
|
+
- `sourcegraph`: Cross-repository code search and navigation through Sourcegraph MCP.
|
|
557
|
+
- `playwright`: Headless browser automation for frontend inspection and testing through Playwright MCP.
|
|
558
|
+
- `coding-agent-toolkit`: A CapletSet that bundles high-value coding-agent examples; source children are symlinks to canonical top-level examples and installed copies are materialized as self-contained files/directories.
|
|
559
|
+
- `github-cli`: Pre-existing secondary read-oriented GitHub workflows through the `gh` CLI; prefer the canonical `github` MCP example for the polished GitHub integration.
|
|
560
|
+
|
|
561
|
+
GraphQL is intentionally skipped in this showcase batch so the examples can focus on HTTP,
|
|
562
|
+
OpenAPI, MCP, CLI, and CapletSet coverage without duplicating GitHub or GitLab surfaces.
|
|
552
563
|
|
|
553
564
|
Install every example from a repo's `caplets/` directory into the current project's
|
|
554
565
|
`./.caplets` directory:
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
|
-
import { accessSync, chmodSync, closeSync, constants, cpSync, existsSync, lstatSync, mkdirSync, mkdtempSync, openSync, readFileSync, readdirSync, renameSync, rmSync, statSync, watch, writeFileSync, writeSync } from "node:fs";
|
|
4
|
-
import minpath, { basename, delimiter, dirname, extname, isAbsolute, join, parse, posix, relative, resolve, win32 } from "node:path";
|
|
3
|
+
import { accessSync, chmodSync, closeSync, constants, copyFileSync, cpSync, existsSync, lstatSync, mkdirSync, mkdtempSync, openSync, readFileSync, readdirSync, readlinkSync, realpathSync, renameSync, rmSync, statSync, watch, writeFileSync, writeSync } from "node:fs";
|
|
4
|
+
import minpath, { basename, delimiter, dirname, extname, isAbsolute, join, parse, posix, relative, resolve, sep, win32 } from "node:path";
|
|
5
5
|
import { execFileSync, spawn } from "node:child_process";
|
|
6
6
|
import process$1, { stdin, stdout } from "node:process";
|
|
7
7
|
import { fileURLToPath } from "node:url";
|
|
@@ -4709,7 +4709,7 @@ function generatedToolInputJsonSchema() {
|
|
|
4709
4709
|
return generatedToolInputJsonSchemaForCaplet({ backend: "tool" });
|
|
4710
4710
|
}
|
|
4711
4711
|
//#endregion
|
|
4712
|
-
//#region ../core/dist/options-
|
|
4712
|
+
//#region ../core/dist/options-j9p3L3r1.js
|
|
4713
4713
|
var __create = Object.create;
|
|
4714
4714
|
var __defProp = Object.defineProperty;
|
|
4715
4715
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -56439,8 +56439,21 @@ async function loadOpenApiSource(endpoint, authDir) {
|
|
|
56439
56439
|
if (endpoint.specPath) return endpoint.specPath;
|
|
56440
56440
|
if (!endpoint.specUrl) throw new CapletsError("CONFIG_INVALID", `${endpoint.server} is missing OpenAPI spec source`);
|
|
56441
56441
|
if (!endpoint.baseUrl) throw new CapletsError("CONFIG_INVALID", `${endpoint.server} must configure baseUrl when using remote specUrl`);
|
|
56442
|
-
|
|
56443
|
-
|
|
56442
|
+
return parseOpenApiSourceText(await fetchWithLimit(endpoint.specUrl, endpoint.requestTimeoutMs, shouldSendSpecAuth(endpoint) ? authHeaders(endpoint, authDir) : {}));
|
|
56443
|
+
}
|
|
56444
|
+
function parseOpenApiSourceText(source) {
|
|
56445
|
+
let parsed;
|
|
56446
|
+
try {
|
|
56447
|
+
parsed = JSON.parse(source);
|
|
56448
|
+
} catch (jsonError) {
|
|
56449
|
+
try {
|
|
56450
|
+
parsed = (0, import_dist$1.parse)(source);
|
|
56451
|
+
} catch {
|
|
56452
|
+
throw jsonError instanceof Error ? jsonError : new Error(String(jsonError));
|
|
56453
|
+
}
|
|
56454
|
+
}
|
|
56455
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("OpenAPI source must parse to an object");
|
|
56456
|
+
return parsed;
|
|
56444
56457
|
}
|
|
56445
56458
|
function extractOperations(endpoint, document) {
|
|
56446
56459
|
const operations = [];
|
|
@@ -56458,6 +56471,7 @@ function extractOperations(endpoint, document) {
|
|
|
56458
56471
|
const requestBody = requestBodyFor(operation);
|
|
56459
56472
|
const outputSchema = outputSchemaFor(operation);
|
|
56460
56473
|
const baseUrl = endpoint.baseUrl ?? firstServerUrl(document);
|
|
56474
|
+
const staticHeaders = staticHeaderDefaultsFor(endpoint, parameters);
|
|
56461
56475
|
validateOperationBaseUrl(endpoint, baseUrl);
|
|
56462
56476
|
operations.push({
|
|
56463
56477
|
name,
|
|
@@ -56465,15 +56479,32 @@ function extractOperations(endpoint, document) {
|
|
|
56465
56479
|
path,
|
|
56466
56480
|
...typeof operation.summary === "string" ? { summary: operation.summary } : {},
|
|
56467
56481
|
...typeof operation.description === "string" ? { description: operation.description } : {},
|
|
56468
|
-
inputSchema: inputSchemaFor(parameters, requestBody),
|
|
56482
|
+
inputSchema: inputSchemaFor(parameters, requestBody, staticHeaders),
|
|
56469
56483
|
...outputSchema ? { outputSchema } : {},
|
|
56470
56484
|
...requestBody?.contentType ? { requestBodyContentType: requestBody.contentType } : {},
|
|
56471
|
-
...baseUrl ? { baseUrl } : {}
|
|
56485
|
+
...baseUrl ? { baseUrl } : {},
|
|
56486
|
+
...Object.keys(staticHeaders).length ? { staticHeaders } : {}
|
|
56472
56487
|
});
|
|
56473
56488
|
}
|
|
56474
56489
|
}
|
|
56475
56490
|
return operations.sort((left, right) => left.name.localeCompare(right.name));
|
|
56476
56491
|
}
|
|
56492
|
+
function staticHeaderDefaultsFor(endpoint, parameters) {
|
|
56493
|
+
const configuredHeaderNames = configuredAuthHeaderNames(endpoint);
|
|
56494
|
+
const headers = {};
|
|
56495
|
+
for (const parameter of parameters) {
|
|
56496
|
+
if (parameter?.in !== "header" || typeof parameter.name !== "string") continue;
|
|
56497
|
+
const normalized = parameter.name.toLowerCase();
|
|
56498
|
+
if (configuredHeaderNames.has(normalized) || FORBIDDEN_ARGUMENT_HEADERS.has(normalized) && normalized !== "accept") continue;
|
|
56499
|
+
const defaultValue = parameter.schema?.default;
|
|
56500
|
+
if ([
|
|
56501
|
+
"string",
|
|
56502
|
+
"number",
|
|
56503
|
+
"boolean"
|
|
56504
|
+
].includes(typeof defaultValue)) headers[parameter.name] = String(defaultValue);
|
|
56505
|
+
}
|
|
56506
|
+
return headers;
|
|
56507
|
+
}
|
|
56477
56508
|
function requestBodyFor(operation) {
|
|
56478
56509
|
const requestBody = operation.requestBody;
|
|
56479
56510
|
if (!requestBody || typeof requestBody !== "object") return;
|
|
@@ -56534,19 +56565,20 @@ function structuredOutputSchema(bodySchema) {
|
|
|
56534
56565
|
}
|
|
56535
56566
|
};
|
|
56536
56567
|
}
|
|
56537
|
-
function inputSchemaFor(parameters, requestBody) {
|
|
56568
|
+
function inputSchemaFor(parameters, requestBody, staticHeaders = {}) {
|
|
56538
56569
|
const schema = {
|
|
56539
56570
|
type: "object",
|
|
56540
56571
|
additionalProperties: false,
|
|
56541
56572
|
properties: {}
|
|
56542
56573
|
};
|
|
56543
56574
|
const required = [];
|
|
56575
|
+
const protectedStaticHeaders = new Set(Object.keys(staticHeaders).map((key) => key.toLowerCase()).filter((key) => FORBIDDEN_ARGUMENT_HEADERS.has(key)));
|
|
56544
56576
|
for (const location of [
|
|
56545
56577
|
"path",
|
|
56546
56578
|
"query",
|
|
56547
56579
|
"header"
|
|
56548
56580
|
]) {
|
|
56549
|
-
const locationParameters = parameters.filter((parameter) => parameter?.in === location);
|
|
56581
|
+
const locationParameters = parameters.filter((parameter) => parameter?.in === location && !(location === "header" && protectedStaticHeaders.has(parameter.name?.toLowerCase())));
|
|
56550
56582
|
if (locationParameters.length === 0) continue;
|
|
56551
56583
|
const nestedRequired = locationParameters.filter((parameter) => parameter.required === true || location === "path").map((parameter) => parameter.name);
|
|
56552
56584
|
schema.properties[location] = {
|
|
@@ -56585,7 +56617,8 @@ function buildRequest(endpoint, operation, args, authDir) {
|
|
|
56585
56617
|
for (const [key, value] of Object.entries(asRecord(args.query))) if (value !== void 0 && value !== null) url.searchParams.append(key, serializeHttpValue("query", key, value));
|
|
56586
56618
|
const headers = new Headers();
|
|
56587
56619
|
applyAuth(headers, endpoint, authDir);
|
|
56588
|
-
const configuredHeaderNames =
|
|
56620
|
+
const configuredHeaderNames = configuredAuthHeaderNames(endpoint);
|
|
56621
|
+
for (const [key, value] of Object.entries(operation.staticHeaders ?? {})) if (!headers.has(key) && !configuredHeaderNames.has(key.toLowerCase())) headers.set(key, value);
|
|
56589
56622
|
for (const [key, value] of Object.entries(asRecord(args.header))) if (value !== void 0 && value !== null) {
|
|
56590
56623
|
const normalized = key.toLowerCase();
|
|
56591
56624
|
if (FORBIDDEN_ARGUMENT_HEADERS.has(normalized) || configuredHeaderNames.has(normalized)) throw new CapletsError("REQUEST_INVALID", `Header ${key} cannot be supplied by arguments`);
|
|
@@ -56631,6 +56664,9 @@ function asRecord(value) {
|
|
|
56631
56664
|
function applyAuth(headers, endpoint, authDir) {
|
|
56632
56665
|
for (const [key, value] of Object.entries(authHeaders(endpoint, authDir))) headers.set(key, value);
|
|
56633
56666
|
}
|
|
56667
|
+
function configuredAuthHeaderNames(endpoint) {
|
|
56668
|
+
return endpoint.auth.type === "headers" ? new Set(Object.keys(endpoint.auth.headers).map((key) => key.toLowerCase())) : /* @__PURE__ */ new Set();
|
|
56669
|
+
}
|
|
56634
56670
|
function authHeaders(endpoint, authDir) {
|
|
56635
56671
|
switch (endpoint.auth.type) {
|
|
56636
56672
|
case "none": return {};
|
|
@@ -57625,7 +57661,7 @@ var CapletsEngine = class {
|
|
|
57625
57661
|
}
|
|
57626
57662
|
}
|
|
57627
57663
|
async completeCliWords(words) {
|
|
57628
|
-
const { completeCliWords } = await Promise.resolve().then(() =>
|
|
57664
|
+
const { completeCliWords } = await Promise.resolve().then(() => completion_Cq1z7ci2_exports).then((n) => n.r);
|
|
57629
57665
|
return await completeCliWords(words, {
|
|
57630
57666
|
config: this.registry.config,
|
|
57631
57667
|
managers: {
|
|
@@ -57963,8 +57999,8 @@ function hasEnv$1(value) {
|
|
|
57963
57999
|
return value !== void 0 && value.trim() !== "";
|
|
57964
58000
|
}
|
|
57965
58001
|
//#endregion
|
|
57966
|
-
//#region ../core/dist/completion-
|
|
57967
|
-
var
|
|
58002
|
+
//#region ../core/dist/completion-Cq1z7ci2.js
|
|
58003
|
+
var completion_Cq1z7ci2_exports = /* @__PURE__ */ __exportAll$1({
|
|
57968
58004
|
a: () => formatCapletList,
|
|
57969
58005
|
c: () => resolveCliConfigPaths,
|
|
57970
58006
|
i: () => trailingSpaceCompletionToken,
|
|
@@ -59827,7 +59863,7 @@ const EMPTY_COMPLETION_RESULT = { completion: {
|
|
|
59827
59863
|
values: [],
|
|
59828
59864
|
hasMore: false
|
|
59829
59865
|
} };
|
|
59830
|
-
var version$1 = "0.18.
|
|
59866
|
+
var version$1 = "0.18.3";
|
|
59831
59867
|
var CapletsMcpSession = class {
|
|
59832
59868
|
engine;
|
|
59833
59869
|
server;
|
|
@@ -63626,12 +63662,14 @@ function rejectCrossKindDestinationCollision(plan, destinationRoot) {
|
|
|
63626
63662
|
function installPlan(caplet, options) {
|
|
63627
63663
|
const isDirectory = basename(caplet.path) === "CAPLET.md";
|
|
63628
63664
|
const sourcePath = isDirectory ? dirname(caplet.path) : caplet.path;
|
|
63665
|
+
const sourceBoundary = dirname(sourcePath);
|
|
63629
63666
|
const sourcePathRelative = relative(options.repoRoot, sourcePath);
|
|
63630
63667
|
const destination = isDirectory ? join(options.destinationRoot, caplet.id) : join(options.destinationRoot, `${caplet.id}.md`);
|
|
63631
63668
|
return {
|
|
63632
63669
|
id: caplet.id,
|
|
63633
63670
|
source: `${options.sourceId}#${sourcePathRelative}`,
|
|
63634
63671
|
sourcePath,
|
|
63672
|
+
sourceBoundary,
|
|
63635
63673
|
destination,
|
|
63636
63674
|
kind: isDirectory ? "directory" : "file"
|
|
63637
63675
|
};
|
|
@@ -63693,16 +63731,40 @@ function removeInstallPath(path, label, force) {
|
|
|
63693
63731
|
}
|
|
63694
63732
|
function copyInstallPath(plan) {
|
|
63695
63733
|
try {
|
|
63734
|
+
if (plan.kind === "directory") {
|
|
63735
|
+
copyDirectoryCaplet(plan.sourcePath, plan.destination, realpathSync(plan.sourceBoundary));
|
|
63736
|
+
return;
|
|
63737
|
+
}
|
|
63696
63738
|
cpSync(plan.sourcePath, plan.destination, {
|
|
63697
|
-
recursive:
|
|
63739
|
+
recursive: false,
|
|
63698
63740
|
force: false,
|
|
63699
63741
|
errorOnExist: true
|
|
63700
63742
|
});
|
|
63701
63743
|
} catch (error) {
|
|
63744
|
+
if (error instanceof CapletsError) throw error;
|
|
63702
63745
|
if (isFsError(error, "EEXIST") || isFsError(error, "EISDIR")) throw new CapletsError("CONFIG_EXISTS", `Caplet ${plan.id} already exists at ${plan.destination}; pass --force to overwrite it`, toSafeError(error));
|
|
63703
63746
|
throw new CapletsError("CONFIG_INVALID", `Could not install Caplet ${plan.id} to ${plan.destination}`, toSafeError(error));
|
|
63704
63747
|
}
|
|
63705
63748
|
}
|
|
63749
|
+
function copyDirectoryCaplet(source, destination, sourceBoundary, seenDirectories = /* @__PURE__ */ new Set()) {
|
|
63750
|
+
const resolvedSource = lstatSync(source).isSymbolicLink() ? resolveDirectoryCapletSymlink(source, sourceBoundary) : source;
|
|
63751
|
+
if (statSync(resolvedSource).isDirectory()) {
|
|
63752
|
+
const realDirectory = realpathSync(resolvedSource);
|
|
63753
|
+
if (seenDirectories.has(realDirectory)) throw new CapletsError("CONFIG_INVALID", `Directory Caplet symlink ${source} creates a copy cycle`);
|
|
63754
|
+
const childSeenDirectories = new Set(seenDirectories);
|
|
63755
|
+
childSeenDirectories.add(realDirectory);
|
|
63756
|
+
mkdirSync(destination);
|
|
63757
|
+
for (const entry of readdirSync(resolvedSource)) copyDirectoryCaplet(join(resolvedSource, entry), join(destination, entry), sourceBoundary, childSeenDirectories);
|
|
63758
|
+
return;
|
|
63759
|
+
}
|
|
63760
|
+
copyFileSync(resolvedSource, destination);
|
|
63761
|
+
}
|
|
63762
|
+
function resolveDirectoryCapletSymlink(source, sourceBoundary) {
|
|
63763
|
+
const target = readlinkSync(source);
|
|
63764
|
+
const resolvedTarget = realpathSync(isAbsolute(target) ? target : resolve(dirname(source), target));
|
|
63765
|
+
if (resolvedTarget !== sourceBoundary && !resolvedTarget.startsWith(`${sourceBoundary}${sep}`)) throw new CapletsError("CONFIG_INVALID", `Directory Caplet symlink ${source} resolves outside source Caplets boundary`);
|
|
63766
|
+
return resolvedTarget;
|
|
63767
|
+
}
|
|
63706
63768
|
function isFsError(error, code) {
|
|
63707
63769
|
return typeof error === "object" && error !== null && "code" in error && error.code === code;
|
|
63708
63770
|
}
|
|
@@ -68811,7 +68873,7 @@ function writeAddResult(writeOut, label, result) {
|
|
|
68811
68873
|
}
|
|
68812
68874
|
//#endregion
|
|
68813
68875
|
//#region package.json
|
|
68814
|
-
var version = "0.17.
|
|
68876
|
+
var version = "0.17.3";
|
|
68815
68877
|
//#endregion
|
|
68816
68878
|
//#region src/index.ts
|
|
68817
68879
|
async function main() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "caplets",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.3",
|
|
4
4
|
"description": "Progressive disclosure gateway CLI for MCP servers and native Caplets adapters.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"caplets",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
37
|
-
"@caplets/core": "0.18.
|
|
37
|
+
"@caplets/core": "0.18.3"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/node": "^25.9.1",
|