caplets 0.17.2 → 0.17.4
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 +47 -14
- package/dist/index.js +730 -138
- package/package.json +6 -5
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-BlNyqF_E.js
|
|
4713
4713
|
var __create = Object.create;
|
|
4714
4714
|
var __defProp = Object.defineProperty;
|
|
4715
4715
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -12911,6 +12911,82 @@ function loadCapletFilesWithPaths(root) {
|
|
|
12911
12911
|
paths
|
|
12912
12912
|
} : void 0;
|
|
12913
12913
|
}
|
|
12914
|
+
function loadCapletFilesWithPathsBestEffort(root) {
|
|
12915
|
+
if (!existsSync(root)) return;
|
|
12916
|
+
const warnings = [];
|
|
12917
|
+
return buildCapletFileLoadResult(root, discoverCapletFilesBestEffort(root, warnings), warnings);
|
|
12918
|
+
}
|
|
12919
|
+
function buildCapletFileLoadResult(root, candidates, warnings) {
|
|
12920
|
+
const servers = {};
|
|
12921
|
+
const openapiEndpoints = {};
|
|
12922
|
+
const graphqlEndpoints = {};
|
|
12923
|
+
const httpApis = {};
|
|
12924
|
+
const cliTools = {};
|
|
12925
|
+
const capletSets = {};
|
|
12926
|
+
const paths = {};
|
|
12927
|
+
function hasId(id) {
|
|
12928
|
+
return Boolean(servers[id] || openapiEndpoints[id] || graphqlEndpoints[id] || httpApis[id] || cliTools[id] || capletSets[id]);
|
|
12929
|
+
}
|
|
12930
|
+
for (const candidate of candidates) {
|
|
12931
|
+
if (hasId(candidate.id)) {
|
|
12932
|
+
const message = `Duplicate Caplet ID ${candidate.id} under ${root}`;
|
|
12933
|
+
if (!warnings) throw new CapletsError("CONFIG_INVALID", message);
|
|
12934
|
+
warnings.push({
|
|
12935
|
+
path: candidate.path,
|
|
12936
|
+
message: `${message}; skipping duplicate at ${candidate.path}`
|
|
12937
|
+
});
|
|
12938
|
+
continue;
|
|
12939
|
+
}
|
|
12940
|
+
let config;
|
|
12941
|
+
try {
|
|
12942
|
+
config = readCapletFile(candidate.path);
|
|
12943
|
+
} catch (error) {
|
|
12944
|
+
if (!warnings) throw error;
|
|
12945
|
+
warnings.push({
|
|
12946
|
+
path: candidate.path,
|
|
12947
|
+
message: `Skipping invalid Caplet file at ${candidate.path}: ${errorMessage$1(error)}`
|
|
12948
|
+
});
|
|
12949
|
+
continue;
|
|
12950
|
+
}
|
|
12951
|
+
paths[candidate.id] = candidate.path;
|
|
12952
|
+
if (isPlainObject$5(config) && config.backend === "openapi") {
|
|
12953
|
+
const { backend: _backend, ...endpoint } = config;
|
|
12954
|
+
openapiEndpoints[candidate.id] = endpoint;
|
|
12955
|
+
} else if (isPlainObject$5(config) && config.backend === "graphql") {
|
|
12956
|
+
const { backend: _backend, ...endpoint } = config;
|
|
12957
|
+
graphqlEndpoints[candidate.id] = endpoint;
|
|
12958
|
+
} else if (isPlainObject$5(config) && config.backend === "http") {
|
|
12959
|
+
const { backend: _backend, ...endpoint } = config;
|
|
12960
|
+
httpApis[candidate.id] = endpoint;
|
|
12961
|
+
} else if (isPlainObject$5(config) && config.backend === "cli") {
|
|
12962
|
+
const { backend: _backend, ...endpoint } = config;
|
|
12963
|
+
cliTools[candidate.id] = endpoint;
|
|
12964
|
+
} else if (isPlainObject$5(config) && config.backend === "caplets") {
|
|
12965
|
+
const { backend: _backend, ...endpoint } = config;
|
|
12966
|
+
capletSets[candidate.id] = endpoint;
|
|
12967
|
+
} else servers[candidate.id] = config;
|
|
12968
|
+
}
|
|
12969
|
+
const hasServers = Object.keys(servers).length > 0;
|
|
12970
|
+
const hasOpenApi = Object.keys(openapiEndpoints).length > 0;
|
|
12971
|
+
const hasGraphQl = Object.keys(graphqlEndpoints).length > 0;
|
|
12972
|
+
const hasHttpApis = Object.keys(httpApis).length > 0;
|
|
12973
|
+
const hasCliTools = Object.keys(cliTools).length > 0;
|
|
12974
|
+
const hasCapletSets = Object.keys(capletSets).length > 0;
|
|
12975
|
+
const config = {
|
|
12976
|
+
...hasServers ? { mcpServers: servers } : {},
|
|
12977
|
+
...hasOpenApi ? { openapiEndpoints } : {},
|
|
12978
|
+
...hasGraphQl ? { graphqlEndpoints } : {},
|
|
12979
|
+
...hasHttpApis ? { httpApis } : {},
|
|
12980
|
+
...hasCliTools ? { cliTools } : {},
|
|
12981
|
+
...hasCapletSets ? { capletSets } : {}
|
|
12982
|
+
};
|
|
12983
|
+
if (!(Object.keys(config).length > 0) && warnings?.length === 0) return;
|
|
12984
|
+
return {
|
|
12985
|
+
config,
|
|
12986
|
+
paths,
|
|
12987
|
+
warnings: warnings ?? []
|
|
12988
|
+
};
|
|
12989
|
+
}
|
|
12914
12990
|
function discoverCapletFiles(root) {
|
|
12915
12991
|
const entries = readdirSync(root, { withFileTypes: true }).sort((left, right) => left.name.localeCompare(right.name));
|
|
12916
12992
|
const candidates = [];
|
|
@@ -12935,6 +13011,82 @@ function discoverCapletFiles(root) {
|
|
|
12935
13011
|
}
|
|
12936
13012
|
return candidates;
|
|
12937
13013
|
}
|
|
13014
|
+
function discoverCapletFilesBestEffort(root, warnings) {
|
|
13015
|
+
const entries = readdirSync(root, { withFileTypes: true }).sort((left, right) => left.name.localeCompare(right.name));
|
|
13016
|
+
const byId = /* @__PURE__ */ new Map();
|
|
13017
|
+
const duplicateIds = /* @__PURE__ */ new Set();
|
|
13018
|
+
function addCandidate(id, path, isDirectoryCaplet) {
|
|
13019
|
+
try {
|
|
13020
|
+
validateCapletId(id, path);
|
|
13021
|
+
} catch (error) {
|
|
13022
|
+
warnings.push({
|
|
13023
|
+
path,
|
|
13024
|
+
message: `Skipping invalid Caplet file at ${path}: ${errorMessage$1(error)}`
|
|
13025
|
+
});
|
|
13026
|
+
return;
|
|
13027
|
+
}
|
|
13028
|
+
if (duplicateIds.has(id)) {
|
|
13029
|
+
warnings.push({
|
|
13030
|
+
path,
|
|
13031
|
+
message: `Duplicate Caplet ID ${id} under ${root}; skipping duplicate at ${path}`
|
|
13032
|
+
});
|
|
13033
|
+
return;
|
|
13034
|
+
}
|
|
13035
|
+
const existing = byId.get(id);
|
|
13036
|
+
if (!existing) {
|
|
13037
|
+
byId.set(id, {
|
|
13038
|
+
id,
|
|
13039
|
+
path,
|
|
13040
|
+
isDirectoryCaplet
|
|
13041
|
+
});
|
|
13042
|
+
return;
|
|
13043
|
+
}
|
|
13044
|
+
if (isDirectoryCaplet && !existing.isDirectoryCaplet) {
|
|
13045
|
+
warnings.push({
|
|
13046
|
+
path: existing.path,
|
|
13047
|
+
message: `Caplet file at ${existing.path} was shadowed by ${path}`
|
|
13048
|
+
});
|
|
13049
|
+
byId.set(id, {
|
|
13050
|
+
id,
|
|
13051
|
+
path,
|
|
13052
|
+
isDirectoryCaplet
|
|
13053
|
+
});
|
|
13054
|
+
return;
|
|
13055
|
+
}
|
|
13056
|
+
if (!isDirectoryCaplet && existing.isDirectoryCaplet) {
|
|
13057
|
+
warnings.push({
|
|
13058
|
+
path,
|
|
13059
|
+
message: `Caplet file at ${path} was shadowed by ${existing.path}`
|
|
13060
|
+
});
|
|
13061
|
+
return;
|
|
13062
|
+
}
|
|
13063
|
+
warnings.push({
|
|
13064
|
+
path,
|
|
13065
|
+
message: `Duplicate Caplet ID ${id} under ${root}; skipping ${existing.path} and ${path}`
|
|
13066
|
+
});
|
|
13067
|
+
byId.delete(id);
|
|
13068
|
+
duplicateIds.add(id);
|
|
13069
|
+
}
|
|
13070
|
+
for (const entry of entries) {
|
|
13071
|
+
if (entry.name === "auth" || entry.name === "config.json") continue;
|
|
13072
|
+
const path = join(root, entry.name);
|
|
13073
|
+
if (entry.isFile() && extname(entry.name).toLowerCase() === ".md") {
|
|
13074
|
+
addCandidate(basename(entry.name, extname(entry.name)), path, false);
|
|
13075
|
+
continue;
|
|
13076
|
+
}
|
|
13077
|
+
if (entry.isDirectory()) {
|
|
13078
|
+
const capletPath = join(path, "CAPLET.md");
|
|
13079
|
+
if (existsSync(capletPath) && statSync(capletPath).isFile()) addCandidate(entry.name, capletPath, true);
|
|
13080
|
+
}
|
|
13081
|
+
}
|
|
13082
|
+
return Array.from(byId.values()).map(({ id, path }) => ({
|
|
13083
|
+
id,
|
|
13084
|
+
path
|
|
13085
|
+
}));
|
|
13086
|
+
}
|
|
13087
|
+
function errorMessage$1(error) {
|
|
13088
|
+
return error instanceof Error ? error.message : String(error);
|
|
13089
|
+
}
|
|
12938
13090
|
function readCapletFile(path) {
|
|
12939
13091
|
if (statSync(path).size > MAX_CAPLET_FILE_BYTES) throw new CapletsError("CONFIG_INVALID", `Caplet file at ${path} exceeds the ${MAX_CAPLET_FILE_BYTES} byte limit`);
|
|
12940
13092
|
const { frontmatter, body } = parseFrontmatter(readFileSync(path, "utf8"), path);
|
|
@@ -13611,35 +13763,78 @@ function loadConfigWithSources(path = resolveConfigPath(), projectPath = resolve
|
|
|
13611
13763
|
const projectConfig = hasProjectConfig ? rejectProjectConfigExecutableBackendMaps(readPublicConfigInput(projectPath), projectPath) : void 0;
|
|
13612
13764
|
const projectCapletsRoot = resolveProjectCapletsRootForConfigPath$1(projectPath);
|
|
13613
13765
|
const projectCaplets = projectCapletsRoot ? loadCapletFilesWithPaths(projectCapletsRoot) : void 0;
|
|
13614
|
-
|
|
13615
|
-
|
|
13616
|
-
const { input, sources, shadows } = mergeConfigInputsWithSources({
|
|
13766
|
+
return buildConfigWithSources([
|
|
13767
|
+
{
|
|
13617
13768
|
input: userConfig,
|
|
13618
13769
|
source: {
|
|
13619
13770
|
kind: "global-config",
|
|
13620
13771
|
path
|
|
13621
13772
|
}
|
|
13622
|
-
},
|
|
13773
|
+
},
|
|
13774
|
+
userCaplets ? {
|
|
13623
13775
|
input: userCaplets.config,
|
|
13624
13776
|
source: {
|
|
13625
13777
|
kind: "global-file",
|
|
13626
13778
|
path: userCaplets.paths
|
|
13627
13779
|
}
|
|
13628
|
-
} : void 0,
|
|
13780
|
+
} : void 0,
|
|
13781
|
+
{
|
|
13629
13782
|
input: projectConfig,
|
|
13630
13783
|
source: {
|
|
13631
13784
|
kind: "project-config",
|
|
13632
13785
|
path: projectPath
|
|
13633
13786
|
}
|
|
13634
|
-
},
|
|
13787
|
+
},
|
|
13788
|
+
projectCaplets ? {
|
|
13635
13789
|
input: projectCaplets.config,
|
|
13636
13790
|
source: {
|
|
13637
13791
|
kind: "project-file",
|
|
13638
13792
|
path: projectCaplets.paths
|
|
13639
13793
|
}
|
|
13640
|
-
} : void 0
|
|
13794
|
+
} : void 0
|
|
13795
|
+
], `Caplets config not found at ${path} or ${projectPath}`, "Caplets config must define at least one MCP server, OpenAPI endpoint, GraphQL endpoint, HTTP API, CLI tools backend, or Caplet set");
|
|
13796
|
+
}
|
|
13797
|
+
function loadGlobalConfig(path = resolveConfigPath()) {
|
|
13798
|
+
const userConfig = existsSync(path) ? readPublicConfigInput(path) : void 0;
|
|
13799
|
+
const userCaplets = loadCapletFilesWithPaths(resolveCapletsRoot(path));
|
|
13800
|
+
return buildConfigWithSources([{
|
|
13801
|
+
input: userConfig,
|
|
13802
|
+
source: {
|
|
13803
|
+
kind: "global-config",
|
|
13804
|
+
path
|
|
13805
|
+
}
|
|
13806
|
+
}, userCaplets ? {
|
|
13807
|
+
input: userCaplets.config,
|
|
13808
|
+
source: {
|
|
13809
|
+
kind: "global-file",
|
|
13810
|
+
path: userCaplets.paths
|
|
13811
|
+
}
|
|
13812
|
+
} : void 0], `Caplets user config not found at ${path}`, void 0).config;
|
|
13813
|
+
}
|
|
13814
|
+
function loadProjectConfig(projectPath = resolveProjectConfigPath()) {
|
|
13815
|
+
const projectConfig = existsSync(projectPath) ? rejectProjectConfigExecutableBackendMaps(readPublicConfigInput(projectPath), projectPath) : void 0;
|
|
13816
|
+
const projectCapletsRoot = resolveProjectCapletsRootForConfigPath$1(projectPath);
|
|
13817
|
+
const projectCaplets = projectCapletsRoot ? loadCapletFilesWithPaths(projectCapletsRoot) : void 0;
|
|
13818
|
+
return buildConfigWithSources([{
|
|
13819
|
+
input: projectConfig,
|
|
13820
|
+
source: {
|
|
13821
|
+
kind: "project-config",
|
|
13822
|
+
path: projectPath
|
|
13823
|
+
}
|
|
13824
|
+
}, projectCaplets ? {
|
|
13825
|
+
input: projectCaplets.config,
|
|
13826
|
+
source: {
|
|
13827
|
+
kind: "project-file",
|
|
13828
|
+
path: projectCaplets.paths
|
|
13829
|
+
}
|
|
13830
|
+
} : void 0], `Caplets project config not found at ${projectPath}`, void 0).config;
|
|
13831
|
+
}
|
|
13832
|
+
function buildConfigWithSources(inputs, notFoundMessage, emptyMessage) {
|
|
13833
|
+
if (!inputs.some((entry) => entry?.input !== void 0)) throw new CapletsError("CONFIG_NOT_FOUND", notFoundMessage);
|
|
13834
|
+
try {
|
|
13835
|
+
const { input, sources, shadows } = mergeConfigInputsWithSources(...inputs);
|
|
13641
13836
|
const config = parseConfig(input);
|
|
13642
|
-
if (Object.keys(config.mcpServers).length === 0 && Object.keys(config.openapiEndpoints).length === 0 && Object.keys(config.graphqlEndpoints).length === 0 && Object.keys(config.httpApis).length === 0 && Object.keys(config.cliTools).length === 0 && Object.keys(config.capletSets).length === 0) throw new CapletsError("CONFIG_INVALID",
|
|
13837
|
+
if (emptyMessage && Object.keys(config.mcpServers).length === 0 && Object.keys(config.openapiEndpoints).length === 0 && Object.keys(config.graphqlEndpoints).length === 0 && Object.keys(config.httpApis).length === 0 && Object.keys(config.cliTools).length === 0 && Object.keys(config.capletSets).length === 0) throw new CapletsError("CONFIG_INVALID", emptyMessage);
|
|
13643
13838
|
return {
|
|
13644
13839
|
config,
|
|
13645
13840
|
sources,
|
|
@@ -13650,6 +13845,74 @@ function loadConfigWithSources(path = resolveConfigPath(), projectPath = resolve
|
|
|
13650
13845
|
throw new CapletsError("CONFIG_INVALID", "Caplets config is not valid JSON", redactSecrets(error));
|
|
13651
13846
|
}
|
|
13652
13847
|
}
|
|
13848
|
+
function loadLocalOverlayConfigWithSources(path = resolveConfigPath(), projectPath = resolveProjectConfigPath()) {
|
|
13849
|
+
const warnings = [];
|
|
13850
|
+
const userConfig = existsSync(path) ? readBestEffortConfigInput(path, "global-config", warnings) : void 0;
|
|
13851
|
+
const userCaplets = loadBestEffortCapletFiles(resolveCapletsRoot(path), "global-file", warnings);
|
|
13852
|
+
const projectConfig = existsSync(projectPath) ? readBestEffortConfigInput(projectPath, "project-config", warnings, (input) => rejectProjectConfigExecutableBackendMaps(input, projectPath)) : void 0;
|
|
13853
|
+
const projectCapletsRoot = resolveProjectCapletsRootForConfigPath$1(projectPath);
|
|
13854
|
+
const projectCaplets = projectCapletsRoot ? loadBestEffortCapletFiles(projectCapletsRoot, "project-file", warnings) : void 0;
|
|
13855
|
+
const { input, sources, shadows } = mergeConfigInputsWithSources({
|
|
13856
|
+
input: userConfig,
|
|
13857
|
+
source: {
|
|
13858
|
+
kind: "global-config",
|
|
13859
|
+
path
|
|
13860
|
+
}
|
|
13861
|
+
}, userCaplets ? {
|
|
13862
|
+
input: userCaplets.config,
|
|
13863
|
+
source: {
|
|
13864
|
+
kind: "global-file",
|
|
13865
|
+
path: userCaplets.paths
|
|
13866
|
+
}
|
|
13867
|
+
} : void 0, {
|
|
13868
|
+
input: projectConfig,
|
|
13869
|
+
source: {
|
|
13870
|
+
kind: "project-config",
|
|
13871
|
+
path: projectPath
|
|
13872
|
+
}
|
|
13873
|
+
}, projectCaplets ? {
|
|
13874
|
+
input: projectCaplets.config,
|
|
13875
|
+
source: {
|
|
13876
|
+
kind: "project-file",
|
|
13877
|
+
path: projectCaplets.paths
|
|
13878
|
+
}
|
|
13879
|
+
} : void 0);
|
|
13880
|
+
return {
|
|
13881
|
+
config: parseConfig(input),
|
|
13882
|
+
sources,
|
|
13883
|
+
shadows,
|
|
13884
|
+
warnings
|
|
13885
|
+
};
|
|
13886
|
+
}
|
|
13887
|
+
function readBestEffortConfigInput(path, kind, warnings, transform) {
|
|
13888
|
+
try {
|
|
13889
|
+
const input = readPublicConfigInput(path);
|
|
13890
|
+
return transform ? transform(input) : input;
|
|
13891
|
+
} catch (error) {
|
|
13892
|
+
warnings.push({
|
|
13893
|
+
kind,
|
|
13894
|
+
path,
|
|
13895
|
+
message: errorMessage(error)
|
|
13896
|
+
});
|
|
13897
|
+
return;
|
|
13898
|
+
}
|
|
13899
|
+
}
|
|
13900
|
+
function loadBestEffortCapletFiles(root, kind, warnings) {
|
|
13901
|
+
const result = loadCapletFilesWithPathsBestEffort(root);
|
|
13902
|
+
if (!result) return;
|
|
13903
|
+
for (const warning of result.warnings) warnings.push({
|
|
13904
|
+
kind,
|
|
13905
|
+
path: warning.path ?? root,
|
|
13906
|
+
message: warning.message
|
|
13907
|
+
});
|
|
13908
|
+
return {
|
|
13909
|
+
config: result.config,
|
|
13910
|
+
paths: result.paths
|
|
13911
|
+
};
|
|
13912
|
+
}
|
|
13913
|
+
function errorMessage(error) {
|
|
13914
|
+
return error instanceof Error ? error.message : String(error);
|
|
13915
|
+
}
|
|
13653
13916
|
function loadIsolatedConfig(options) {
|
|
13654
13917
|
if (!options.configPath && !options.capletsRoot) throw new CapletsError("CONFIG_INVALID", "Nested Caplet set must define at least one source: configPath or capletsRoot");
|
|
13655
13918
|
const configInput = options.configPath ? readPublicConfigInput(options.configPath) : void 0;
|
|
@@ -56439,8 +56702,21 @@ async function loadOpenApiSource(endpoint, authDir) {
|
|
|
56439
56702
|
if (endpoint.specPath) return endpoint.specPath;
|
|
56440
56703
|
if (!endpoint.specUrl) throw new CapletsError("CONFIG_INVALID", `${endpoint.server} is missing OpenAPI spec source`);
|
|
56441
56704
|
if (!endpoint.baseUrl) throw new CapletsError("CONFIG_INVALID", `${endpoint.server} must configure baseUrl when using remote specUrl`);
|
|
56442
|
-
|
|
56443
|
-
|
|
56705
|
+
return parseOpenApiSourceText(await fetchWithLimit(endpoint.specUrl, endpoint.requestTimeoutMs, shouldSendSpecAuth(endpoint) ? authHeaders(endpoint, authDir) : {}));
|
|
56706
|
+
}
|
|
56707
|
+
function parseOpenApiSourceText(source) {
|
|
56708
|
+
let parsed;
|
|
56709
|
+
try {
|
|
56710
|
+
parsed = JSON.parse(source);
|
|
56711
|
+
} catch (jsonError) {
|
|
56712
|
+
try {
|
|
56713
|
+
parsed = (0, import_dist$1.parse)(source);
|
|
56714
|
+
} catch {
|
|
56715
|
+
throw jsonError instanceof Error ? jsonError : new Error(String(jsonError));
|
|
56716
|
+
}
|
|
56717
|
+
}
|
|
56718
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("OpenAPI source must parse to an object");
|
|
56719
|
+
return parsed;
|
|
56444
56720
|
}
|
|
56445
56721
|
function extractOperations(endpoint, document) {
|
|
56446
56722
|
const operations = [];
|
|
@@ -56458,6 +56734,7 @@ function extractOperations(endpoint, document) {
|
|
|
56458
56734
|
const requestBody = requestBodyFor(operation);
|
|
56459
56735
|
const outputSchema = outputSchemaFor(operation);
|
|
56460
56736
|
const baseUrl = endpoint.baseUrl ?? firstServerUrl(document);
|
|
56737
|
+
const staticHeaders = staticHeaderDefaultsFor(endpoint, parameters);
|
|
56461
56738
|
validateOperationBaseUrl(endpoint, baseUrl);
|
|
56462
56739
|
operations.push({
|
|
56463
56740
|
name,
|
|
@@ -56465,15 +56742,32 @@ function extractOperations(endpoint, document) {
|
|
|
56465
56742
|
path,
|
|
56466
56743
|
...typeof operation.summary === "string" ? { summary: operation.summary } : {},
|
|
56467
56744
|
...typeof operation.description === "string" ? { description: operation.description } : {},
|
|
56468
|
-
inputSchema: inputSchemaFor(parameters, requestBody),
|
|
56745
|
+
inputSchema: inputSchemaFor(parameters, requestBody, staticHeaders),
|
|
56469
56746
|
...outputSchema ? { outputSchema } : {},
|
|
56470
56747
|
...requestBody?.contentType ? { requestBodyContentType: requestBody.contentType } : {},
|
|
56471
|
-
...baseUrl ? { baseUrl } : {}
|
|
56748
|
+
...baseUrl ? { baseUrl } : {},
|
|
56749
|
+
...Object.keys(staticHeaders).length ? { staticHeaders } : {}
|
|
56472
56750
|
});
|
|
56473
56751
|
}
|
|
56474
56752
|
}
|
|
56475
56753
|
return operations.sort((left, right) => left.name.localeCompare(right.name));
|
|
56476
56754
|
}
|
|
56755
|
+
function staticHeaderDefaultsFor(endpoint, parameters) {
|
|
56756
|
+
const configuredHeaderNames = configuredAuthHeaderNames(endpoint);
|
|
56757
|
+
const headers = {};
|
|
56758
|
+
for (const parameter of parameters) {
|
|
56759
|
+
if (parameter?.in !== "header" || typeof parameter.name !== "string") continue;
|
|
56760
|
+
const normalized = parameter.name.toLowerCase();
|
|
56761
|
+
if (configuredHeaderNames.has(normalized) || FORBIDDEN_ARGUMENT_HEADERS.has(normalized) && normalized !== "accept") continue;
|
|
56762
|
+
const defaultValue = parameter.schema?.default;
|
|
56763
|
+
if ([
|
|
56764
|
+
"string",
|
|
56765
|
+
"number",
|
|
56766
|
+
"boolean"
|
|
56767
|
+
].includes(typeof defaultValue)) headers[parameter.name] = String(defaultValue);
|
|
56768
|
+
}
|
|
56769
|
+
return headers;
|
|
56770
|
+
}
|
|
56477
56771
|
function requestBodyFor(operation) {
|
|
56478
56772
|
const requestBody = operation.requestBody;
|
|
56479
56773
|
if (!requestBody || typeof requestBody !== "object") return;
|
|
@@ -56534,19 +56828,20 @@ function structuredOutputSchema(bodySchema) {
|
|
|
56534
56828
|
}
|
|
56535
56829
|
};
|
|
56536
56830
|
}
|
|
56537
|
-
function inputSchemaFor(parameters, requestBody) {
|
|
56831
|
+
function inputSchemaFor(parameters, requestBody, staticHeaders = {}) {
|
|
56538
56832
|
const schema = {
|
|
56539
56833
|
type: "object",
|
|
56540
56834
|
additionalProperties: false,
|
|
56541
56835
|
properties: {}
|
|
56542
56836
|
};
|
|
56543
56837
|
const required = [];
|
|
56838
|
+
const protectedStaticHeaders = new Set(Object.keys(staticHeaders).map((key) => key.toLowerCase()).filter((key) => FORBIDDEN_ARGUMENT_HEADERS.has(key)));
|
|
56544
56839
|
for (const location of [
|
|
56545
56840
|
"path",
|
|
56546
56841
|
"query",
|
|
56547
56842
|
"header"
|
|
56548
56843
|
]) {
|
|
56549
|
-
const locationParameters = parameters.filter((parameter) => parameter?.in === location);
|
|
56844
|
+
const locationParameters = parameters.filter((parameter) => parameter?.in === location && !(location === "header" && protectedStaticHeaders.has(parameter.name?.toLowerCase())));
|
|
56550
56845
|
if (locationParameters.length === 0) continue;
|
|
56551
56846
|
const nestedRequired = locationParameters.filter((parameter) => parameter.required === true || location === "path").map((parameter) => parameter.name);
|
|
56552
56847
|
schema.properties[location] = {
|
|
@@ -56585,7 +56880,8 @@ function buildRequest(endpoint, operation, args, authDir) {
|
|
|
56585
56880
|
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
56881
|
const headers = new Headers();
|
|
56587
56882
|
applyAuth(headers, endpoint, authDir);
|
|
56588
|
-
const configuredHeaderNames =
|
|
56883
|
+
const configuredHeaderNames = configuredAuthHeaderNames(endpoint);
|
|
56884
|
+
for (const [key, value] of Object.entries(operation.staticHeaders ?? {})) if (!headers.has(key) && !configuredHeaderNames.has(key.toLowerCase())) headers.set(key, value);
|
|
56589
56885
|
for (const [key, value] of Object.entries(asRecord(args.header))) if (value !== void 0 && value !== null) {
|
|
56590
56886
|
const normalized = key.toLowerCase();
|
|
56591
56887
|
if (FORBIDDEN_ARGUMENT_HEADERS.has(normalized) || configuredHeaderNames.has(normalized)) throw new CapletsError("REQUEST_INVALID", `Header ${key} cannot be supplied by arguments`);
|
|
@@ -56631,6 +56927,9 @@ function asRecord(value) {
|
|
|
56631
56927
|
function applyAuth(headers, endpoint, authDir) {
|
|
56632
56928
|
for (const [key, value] of Object.entries(authHeaders(endpoint, authDir))) headers.set(key, value);
|
|
56633
56929
|
}
|
|
56930
|
+
function configuredAuthHeaderNames(endpoint) {
|
|
56931
|
+
return endpoint.auth.type === "headers" ? new Set(Object.keys(endpoint.auth.headers).map((key) => key.toLowerCase())) : /* @__PURE__ */ new Set();
|
|
56932
|
+
}
|
|
56634
56933
|
function authHeaders(endpoint, authDir) {
|
|
56635
56934
|
switch (endpoint.auth.type) {
|
|
56636
56935
|
case "none": return {};
|
|
@@ -57558,6 +57857,7 @@ var CapletsEngine = class {
|
|
|
57558
57857
|
watchDebounceMs;
|
|
57559
57858
|
watchEnabled;
|
|
57560
57859
|
writeErr;
|
|
57860
|
+
configLoader;
|
|
57561
57861
|
reloadListeners = /* @__PURE__ */ new Set();
|
|
57562
57862
|
watchers = [];
|
|
57563
57863
|
reloadTimer;
|
|
@@ -57570,7 +57870,8 @@ var CapletsEngine = class {
|
|
|
57570
57870
|
configPath: resolveConfigPath(options.configPath),
|
|
57571
57871
|
projectConfigPath: options.projectConfigPath ?? resolveProjectConfigPath()
|
|
57572
57872
|
};
|
|
57573
|
-
|
|
57873
|
+
this.configLoader = options.configLoader ?? loadConfig;
|
|
57874
|
+
const config = this.configLoader(this.paths.configPath, this.paths.projectConfigPath);
|
|
57574
57875
|
this.registry = new ServerRegistry(config);
|
|
57575
57876
|
this.downstream = new DownstreamManager(this.registry, selectAuthOptions(options.authDir));
|
|
57576
57877
|
this.openapi = new OpenApiManager(this.registry, selectAuthOptions(options.authDir));
|
|
@@ -57625,7 +57926,7 @@ var CapletsEngine = class {
|
|
|
57625
57926
|
}
|
|
57626
57927
|
}
|
|
57627
57928
|
async completeCliWords(words) {
|
|
57628
|
-
const { completeCliWords } = await Promise.resolve().then(() =>
|
|
57929
|
+
const { completeCliWords } = await Promise.resolve().then(() => completion_DRPTunQd_exports).then((n) => n.r);
|
|
57629
57930
|
return await completeCliWords(words, {
|
|
57630
57931
|
config: this.registry.config,
|
|
57631
57932
|
managers: {
|
|
@@ -57685,7 +57986,7 @@ var CapletsEngine = class {
|
|
|
57685
57986
|
if (this.closed) return false;
|
|
57686
57987
|
let nextConfig;
|
|
57687
57988
|
try {
|
|
57688
|
-
nextConfig =
|
|
57989
|
+
nextConfig = this.configLoader(this.paths.configPath, this.paths.projectConfigPath);
|
|
57689
57990
|
} catch (error) {
|
|
57690
57991
|
this.writeErr(`Caplets config reload failed; keeping last known-good config.\n`);
|
|
57691
57992
|
this.writeErr(`${JSON.stringify(toSafeError(error, "CONFIG_INVALID"), null, 2)}\n`);
|
|
@@ -57963,8 +58264,8 @@ function hasEnv$1(value) {
|
|
|
57963
58264
|
return value !== void 0 && value.trim() !== "";
|
|
57964
58265
|
}
|
|
57965
58266
|
//#endregion
|
|
57966
|
-
//#region ../core/dist/completion-
|
|
57967
|
-
var
|
|
58267
|
+
//#region ../core/dist/completion-DRPTunQd.js
|
|
58268
|
+
var completion_DRPTunQd_exports = /* @__PURE__ */ __exportAll$1({
|
|
57968
58269
|
a: () => formatCapletList,
|
|
57969
58270
|
c: () => resolveCliConfigPaths,
|
|
57970
58271
|
i: () => trailingSpaceCompletionToken,
|
|
@@ -58086,7 +58387,8 @@ function allCaplets(config) {
|
|
|
58086
58387
|
...Object.values(config.openapiEndpoints),
|
|
58087
58388
|
...Object.values(config.graphqlEndpoints),
|
|
58088
58389
|
...Object.values(config.httpApis),
|
|
58089
|
-
...Object.values(config.cliTools)
|
|
58390
|
+
...Object.values(config.cliTools),
|
|
58391
|
+
...Object.values(config.capletSets)
|
|
58090
58392
|
];
|
|
58091
58393
|
}
|
|
58092
58394
|
function formatCapletList(rows, format = "plain") {
|
|
@@ -58138,15 +58440,15 @@ function formatSourceKind(kind) {
|
|
|
58138
58440
|
if (kind.startsWith("global")) return "global";
|
|
58139
58441
|
return kind;
|
|
58140
58442
|
}
|
|
58141
|
-
function resolveCliConfigPaths(envConfigPath, authDir) {
|
|
58443
|
+
function resolveCliConfigPaths(envConfigPath, projectConfigPath = resolveProjectConfigPath(), authDir) {
|
|
58142
58444
|
const configPath = resolveConfigPath(envConfigPath);
|
|
58143
58445
|
const effectiveAuthDir = authDir ?? DEFAULT_AUTH_DIR;
|
|
58144
58446
|
return {
|
|
58145
58447
|
userConfig: configPath,
|
|
58146
|
-
projectConfig:
|
|
58448
|
+
projectConfig: projectConfigPath,
|
|
58147
58449
|
userRoot: resolveCapletsRoot(configPath),
|
|
58148
58450
|
stateRoot: dirname(effectiveAuthDir),
|
|
58149
|
-
projectRoot:
|
|
58451
|
+
projectRoot: dirname(projectConfigPath),
|
|
58150
58452
|
authDir: effectiveAuthDir,
|
|
58151
58453
|
envConfig: envConfigPath ?? null
|
|
58152
58454
|
};
|
|
@@ -59827,7 +60129,7 @@ const EMPTY_COMPLETION_RESULT = { completion: {
|
|
|
59827
60129
|
values: [],
|
|
59828
60130
|
hasMore: false
|
|
59829
60131
|
} };
|
|
59830
|
-
var version$1 = "0.18.
|
|
60132
|
+
var version$1 = "0.18.4";
|
|
59831
60133
|
var CapletsMcpSession = class {
|
|
59832
60134
|
engine;
|
|
59833
60135
|
server;
|
|
@@ -63343,7 +63645,7 @@ function isUrlLike(value) {
|
|
|
63343
63645
|
return /^https?:\/\//i.test(value);
|
|
63344
63646
|
}
|
|
63345
63647
|
async function loginAuth(serverId, options) {
|
|
63346
|
-
const server = findAuthTarget(serverId, loadConfig(options.configPath));
|
|
63648
|
+
const server = findAuthTarget(serverId, options.config ?? loadConfig(options.configPath));
|
|
63347
63649
|
assertLoginTarget(server, serverId);
|
|
63348
63650
|
try {
|
|
63349
63651
|
const flowOptions = {
|
|
@@ -63365,40 +63667,64 @@ function logoutAuth(serverId, options) {
|
|
|
63365
63667
|
else options.writeOut(`No OAuth credentials found for \`${serverId}\`.\n`);
|
|
63366
63668
|
}
|
|
63367
63669
|
function logoutAuthResult(serverId, options) {
|
|
63368
|
-
assertLoginTarget(findAuthTarget(serverId, loadConfig(options.configPath)), serverId);
|
|
63670
|
+
assertLoginTarget(findAuthTarget(serverId, options.config ?? loadConfig(options.configPath)), serverId);
|
|
63369
63671
|
return {
|
|
63370
63672
|
server: serverId,
|
|
63371
63673
|
deleted: deleteTokenBundle(serverId, options.authDir)
|
|
63372
63674
|
};
|
|
63373
63675
|
}
|
|
63374
|
-
function
|
|
63375
|
-
|
|
63376
|
-
|
|
63377
|
-
|
|
63378
|
-
|
|
63379
|
-
|
|
63676
|
+
function listAuthRows(options) {
|
|
63677
|
+
return authRowsForTargets(authTargets(loadConfig(options.configPath)), options.authDir);
|
|
63678
|
+
}
|
|
63679
|
+
function listLocalAuthRows(options) {
|
|
63680
|
+
return authRowsForTargets(localAuthTargets(options), options.authDir);
|
|
63681
|
+
}
|
|
63682
|
+
function localAuthTargets(options) {
|
|
63683
|
+
return [...options.source === "project" ? [] : authTargetsForSource("global", options), ...options.source === "global" ? [] : authTargetsForSource("project", options)].filter((target) => !options.source || target.source === options.source);
|
|
63684
|
+
}
|
|
63685
|
+
function localAuthConfigForTarget(options) {
|
|
63686
|
+
assertLoginTarget(localAuthTargets(options).find((candidate) => candidate.server === options.serverId), options.serverId);
|
|
63687
|
+
return loadConfigForSource(options.source, options);
|
|
63688
|
+
}
|
|
63689
|
+
function authTargetsForSource(source, options) {
|
|
63690
|
+
try {
|
|
63691
|
+
return authTargets(loadConfigForSource(source, options)).map((target) => ({
|
|
63692
|
+
...target,
|
|
63693
|
+
source
|
|
63694
|
+
}));
|
|
63695
|
+
} catch (error) {
|
|
63696
|
+
if (error instanceof CapletsError && error.code === "CONFIG_NOT_FOUND") return [];
|
|
63697
|
+
throw error;
|
|
63380
63698
|
}
|
|
63381
|
-
options.writeOut(formatAuthRows(rows, format));
|
|
63382
63699
|
}
|
|
63383
|
-
function
|
|
63384
|
-
|
|
63385
|
-
|
|
63700
|
+
function loadConfigForSource(source, options) {
|
|
63701
|
+
if (source === "global") return loadGlobalConfig(options.configPath);
|
|
63702
|
+
return loadProjectConfig(options.projectConfigPath);
|
|
63703
|
+
}
|
|
63704
|
+
function authRowsForTargets(targets, authDir) {
|
|
63705
|
+
return targets.sort((left, right) => left.server.localeCompare(right.server)).map((server) => {
|
|
63706
|
+
const bundle = readTokenBundle(server.server, authDir);
|
|
63386
63707
|
const status = !bundle ? "missing" : isTokenBundleExpired(bundle) ? "expired" : "authenticated";
|
|
63387
63708
|
return {
|
|
63388
63709
|
server: server.server,
|
|
63389
63710
|
status,
|
|
63390
63711
|
...bundle?.expiresAt ? { expiresAt: bundle.expiresAt } : {},
|
|
63391
|
-
...bundle?.scope ? { scope: bundle.scope } : {}
|
|
63712
|
+
...bundle?.scope ? { scope: bundle.scope } : {},
|
|
63713
|
+
...server.source ? { source: server.source } : {}
|
|
63392
63714
|
};
|
|
63393
63715
|
});
|
|
63394
63716
|
}
|
|
63395
63717
|
function formatAuthRows(rows, format) {
|
|
63396
|
-
if (rows.length === 0) return format === "markdown" ? "## OAuth credentials\n\nNo configured
|
|
63718
|
+
if (rows.length === 0) return format === "markdown" ? "## OAuth credentials\n\nNo configured OAuth servers found.\n" : "No configured OAuth servers found.\n";
|
|
63397
63719
|
let output = "";
|
|
63398
63720
|
if (format === "markdown") output += "## OAuth credentials\n\n";
|
|
63399
63721
|
else output += "OAuth credentials\n\n";
|
|
63400
63722
|
for (const row of rows) {
|
|
63401
|
-
const details = [
|
|
63723
|
+
const details = [
|
|
63724
|
+
row.source ? `source ${row.source}` : void 0,
|
|
63725
|
+
row.expiresAt ? `expires ${row.expiresAt}` : void 0,
|
|
63726
|
+
row.scope ? `scope ${row.scope}` : void 0
|
|
63727
|
+
].filter(Boolean).join("; ");
|
|
63402
63728
|
if (format === "markdown") {
|
|
63403
63729
|
output += `- \`${row.server}\` — ${row.status}${details ? ` (${details})` : ""}\n`;
|
|
63404
63730
|
continue;
|
|
@@ -63406,6 +63732,7 @@ function formatAuthRows(rows, format) {
|
|
|
63406
63732
|
output += [
|
|
63407
63733
|
row.server,
|
|
63408
63734
|
` Status: ${row.status}`,
|
|
63735
|
+
...row.source ? [` Source: ${row.source}`] : [],
|
|
63409
63736
|
...row.expiresAt ? [` Expires: ${row.expiresAt}`] : [],
|
|
63410
63737
|
...row.scope ? [` Scope: ${row.scope}`] : []
|
|
63411
63738
|
].join("\n") + "\n\n";
|
|
@@ -63626,12 +63953,14 @@ function rejectCrossKindDestinationCollision(plan, destinationRoot) {
|
|
|
63626
63953
|
function installPlan(caplet, options) {
|
|
63627
63954
|
const isDirectory = basename(caplet.path) === "CAPLET.md";
|
|
63628
63955
|
const sourcePath = isDirectory ? dirname(caplet.path) : caplet.path;
|
|
63956
|
+
const sourceBoundary = dirname(sourcePath);
|
|
63629
63957
|
const sourcePathRelative = relative(options.repoRoot, sourcePath);
|
|
63630
63958
|
const destination = isDirectory ? join(options.destinationRoot, caplet.id) : join(options.destinationRoot, `${caplet.id}.md`);
|
|
63631
63959
|
return {
|
|
63632
63960
|
id: caplet.id,
|
|
63633
63961
|
source: `${options.sourceId}#${sourcePathRelative}`,
|
|
63634
63962
|
sourcePath,
|
|
63963
|
+
sourceBoundary,
|
|
63635
63964
|
destination,
|
|
63636
63965
|
kind: isDirectory ? "directory" : "file"
|
|
63637
63966
|
};
|
|
@@ -63693,16 +64022,40 @@ function removeInstallPath(path, label, force) {
|
|
|
63693
64022
|
}
|
|
63694
64023
|
function copyInstallPath(plan) {
|
|
63695
64024
|
try {
|
|
64025
|
+
if (plan.kind === "directory") {
|
|
64026
|
+
copyDirectoryCaplet(plan.sourcePath, plan.destination, realpathSync(plan.sourceBoundary));
|
|
64027
|
+
return;
|
|
64028
|
+
}
|
|
63696
64029
|
cpSync(plan.sourcePath, plan.destination, {
|
|
63697
|
-
recursive:
|
|
64030
|
+
recursive: false,
|
|
63698
64031
|
force: false,
|
|
63699
64032
|
errorOnExist: true
|
|
63700
64033
|
});
|
|
63701
64034
|
} catch (error) {
|
|
64035
|
+
if (error instanceof CapletsError) throw error;
|
|
63702
64036
|
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
64037
|
throw new CapletsError("CONFIG_INVALID", `Could not install Caplet ${plan.id} to ${plan.destination}`, toSafeError(error));
|
|
63704
64038
|
}
|
|
63705
64039
|
}
|
|
64040
|
+
function copyDirectoryCaplet(source, destination, sourceBoundary, seenDirectories = /* @__PURE__ */ new Set()) {
|
|
64041
|
+
const resolvedSource = lstatSync(source).isSymbolicLink() ? resolveDirectoryCapletSymlink(source, sourceBoundary) : source;
|
|
64042
|
+
if (statSync(resolvedSource).isDirectory()) {
|
|
64043
|
+
const realDirectory = realpathSync(resolvedSource);
|
|
64044
|
+
if (seenDirectories.has(realDirectory)) throw new CapletsError("CONFIG_INVALID", `Directory Caplet symlink ${source} creates a copy cycle`);
|
|
64045
|
+
const childSeenDirectories = new Set(seenDirectories);
|
|
64046
|
+
childSeenDirectories.add(realDirectory);
|
|
64047
|
+
mkdirSync(destination);
|
|
64048
|
+
for (const entry of readdirSync(resolvedSource)) copyDirectoryCaplet(join(resolvedSource, entry), join(destination, entry), sourceBoundary, childSeenDirectories);
|
|
64049
|
+
return;
|
|
64050
|
+
}
|
|
64051
|
+
copyFileSync(resolvedSource, destination);
|
|
64052
|
+
}
|
|
64053
|
+
function resolveDirectoryCapletSymlink(source, sourceBoundary) {
|
|
64054
|
+
const target = readlinkSync(source);
|
|
64055
|
+
const resolvedTarget = realpathSync(isAbsolute(target) ? target : resolve(dirname(source), target));
|
|
64056
|
+
if (resolvedTarget !== sourceBoundary && !resolvedTarget.startsWith(`${sourceBoundary}${sep}`)) throw new CapletsError("CONFIG_INVALID", `Directory Caplet symlink ${source} resolves outside source Caplets boundary`);
|
|
64057
|
+
return resolvedTarget;
|
|
64058
|
+
}
|
|
63706
64059
|
function isFsError(error, code) {
|
|
63707
64060
|
return typeof error === "object" && error !== null && "code" in error && error.code === code;
|
|
63708
64061
|
}
|
|
@@ -67880,15 +68233,29 @@ function createProgram(io = {}) {
|
|
|
67880
68233
|
const completionWords = normalizeCompletionWords(words);
|
|
67881
68234
|
let suggestions = [];
|
|
67882
68235
|
try {
|
|
67883
|
-
|
|
67884
|
-
|
|
67885
|
-
|
|
67886
|
-
|
|
68236
|
+
if (remote) {
|
|
68237
|
+
const localOverlay = loadLocalOverlayForCli(io, () => {});
|
|
68238
|
+
const localSuggestions = await completeCliWordsLocally(completionWords, {
|
|
68239
|
+
...configPath ? { configPath } : {},
|
|
68240
|
+
projectConfigPath: envProjectConfigPath(env),
|
|
68241
|
+
...io.authDir ? { authDir: io.authDir } : {},
|
|
68242
|
+
config: localOverlay.config
|
|
68243
|
+
});
|
|
68244
|
+
if (localShadowedCompletionTarget(completionWords, localOverlay.config)) suggestions = localSuggestions;
|
|
68245
|
+
else suggestions = mergeCompletionSuggestions(localSuggestions, await remote.request("complete_cli", {
|
|
68246
|
+
shell,
|
|
68247
|
+
words: completionWords
|
|
68248
|
+
}));
|
|
68249
|
+
} else suggestions = await completeCliWordsLocally(completionWords, {
|
|
67887
68250
|
...configPath ? { configPath } : {},
|
|
68251
|
+
projectConfigPath: envProjectConfigPath(env),
|
|
67888
68252
|
...io.authDir ? { authDir: io.authDir } : {}
|
|
67889
68253
|
});
|
|
67890
68254
|
} catch {
|
|
67891
|
-
suggestions = remote ? [] : await completeCliWords(completionWords,
|
|
68255
|
+
suggestions = remote ? [] : await completeCliWords(completionWords, {
|
|
68256
|
+
...configPath ? { configPath } : {},
|
|
68257
|
+
projectConfigPath: envProjectConfigPath(env)
|
|
68258
|
+
});
|
|
67892
68259
|
}
|
|
67893
68260
|
if (suggestions.length > 0) writeOut(`${suggestions.join("\n")}\n`);
|
|
67894
68261
|
});
|
|
@@ -67900,23 +68267,26 @@ function createProgram(io = {}) {
|
|
|
67900
68267
|
...io.authDir ? { authDir: io.authDir } : {}
|
|
67901
68268
|
}, writeErr)))(resolved);
|
|
67902
68269
|
});
|
|
67903
|
-
program.command(cliCommands.init).description("Create a starter Caplets config file.").option("--force", "overwrite an existing config file").action(async (options) => {
|
|
67904
|
-
const
|
|
67905
|
-
if (remote) {
|
|
67906
|
-
writeOut(`Created remote Caplets config at ${(await
|
|
68270
|
+
program.command(cliCommands.init).description("Create a starter Caplets config file.").option("--project", "create the project Caplets config").option("-g, --global", "create the user Caplets config").option("--remote", "create the remote Caplets config").option("--force", "overwrite an existing config file").action(async (options) => {
|
|
68271
|
+
const target = parseMutationTarget(options);
|
|
68272
|
+
if (target === "remote") {
|
|
68273
|
+
writeOut(`Created remote Caplets config at ${(await requireRemoteClientForTarget(io).request("init", { force: Boolean(options.force) })).path}\n`);
|
|
67907
68274
|
return;
|
|
67908
68275
|
}
|
|
67909
|
-
const
|
|
67910
|
-
|
|
67911
|
-
...configPath ? { path: configPath } : {},
|
|
68276
|
+
const path = initConfig({
|
|
68277
|
+
path: target === "global" ? resolveConfigPath(currentConfigPath()) : envProjectConfigPath(env),
|
|
67912
68278
|
force: Boolean(options.force)
|
|
67913
|
-
})
|
|
68279
|
+
});
|
|
68280
|
+
writeOut(`Created ${localMutationTargetLabel(target, io)}Caplets config at ${path}\n`);
|
|
67914
68281
|
});
|
|
67915
68282
|
program.command(cliCommands.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(async (options) => {
|
|
67916
68283
|
const includeDisabled = Boolean(options.all);
|
|
67917
68284
|
const remote = remoteClientForCli(io);
|
|
67918
68285
|
if (remote) {
|
|
67919
|
-
const rows = await remote.request("list", { includeDisabled })
|
|
68286
|
+
const rows = mergeRemoteAndLocalRows(await remote.request("list", { includeDisabled }), tryLoadLocalOverlayForCli(io, writeErr), {
|
|
68287
|
+
includeDisabled,
|
|
68288
|
+
writeErr
|
|
68289
|
+
});
|
|
67920
68290
|
if (options.json || options.format === "json") {
|
|
67921
68291
|
writeOut(`${JSON.stringify(rows, null, 2)}\n`);
|
|
67922
68292
|
return;
|
|
@@ -67924,18 +68294,17 @@ function createProgram(io = {}) {
|
|
|
67924
68294
|
writeOut(formatCapletList(rows, options.format ?? "plain"));
|
|
67925
68295
|
return;
|
|
67926
68296
|
}
|
|
67927
|
-
const rows = listCaplets(loadConfigWithSources(currentConfigPath()), { includeDisabled });
|
|
68297
|
+
const rows = listCaplets(loadConfigWithSources(currentConfigPath(), envProjectConfigPath(env)), { includeDisabled });
|
|
67928
68298
|
if (options.json || options.format === "json") {
|
|
67929
68299
|
writeOut(`${JSON.stringify(rows, null, 2)}\n`);
|
|
67930
68300
|
return;
|
|
67931
68301
|
}
|
|
67932
68302
|
writeOut(formatCapletList(rows, options.format ?? "plain"));
|
|
67933
68303
|
});
|
|
67934
|
-
program.command(cliCommands.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(async (repo, capletIds, options) => {
|
|
67935
|
-
const
|
|
67936
|
-
if (remote) {
|
|
67937
|
-
|
|
67938
|
-
const result = await remote.request("install", {
|
|
68304
|
+
program.command(cliCommands.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("--project", "install to the project Caplets root").option("-g, --global", "install to the user Caplets root").option("--remote", "install through remote control").option("--force", "overwrite installed Caplets").action(async (repo, capletIds, options) => {
|
|
68305
|
+
const target = parseMutationTarget(options);
|
|
68306
|
+
if (target === "remote") {
|
|
68307
|
+
const result = await requireRemoteClientForTarget(io).request("install", {
|
|
67939
68308
|
repo,
|
|
67940
68309
|
capletIds,
|
|
67941
68310
|
force: Boolean(options.force)
|
|
@@ -67946,15 +68315,15 @@ function createProgram(io = {}) {
|
|
|
67946
68315
|
const result = installCaplets(repo, {
|
|
67947
68316
|
capletIds,
|
|
67948
68317
|
force: Boolean(options.force),
|
|
67949
|
-
destinationRoot:
|
|
68318
|
+
destinationRoot: target === "global" ? resolveCapletsRoot(resolveConfigPath(currentConfigPath())) : envProjectCapletsRoot(env)
|
|
67950
68319
|
});
|
|
67951
|
-
for (const caplet of result.installed) writeOut(`Installed ${caplet.id} to ${caplet.destination}\n`);
|
|
68320
|
+
for (const caplet of result.installed) writeOut(`Installed ${caplet.id} to ${localMutationTargetLabel(target, io)}${caplet.destination}\n`);
|
|
67952
68321
|
});
|
|
67953
68322
|
const add = program.command(cliCommands.add).description("Add generated Caplet files.");
|
|
67954
|
-
add.command("cli").description("Add a CLI tools Caplet.").argument("<id>", "Caplet ID/display seed").option("--repo <path>", "repository path to inspect").option("--include <items>", "comma-separated generators to include: git,gh,package").option("--command <name>", "single CLI command template to generate").option("-g, --global", "write to the user Caplets root").option("--print", "print generated Caplet text without writing a file").option("--output <path>", "output path").option("--force", "overwrite an existing destination file").action(async (id, options) => {
|
|
67955
|
-
const
|
|
67956
|
-
if (remote) {
|
|
67957
|
-
writeAddResult(writeOut, "CLI", await
|
|
68323
|
+
add.command("cli").description("Add a CLI tools Caplet.").argument("<id>", "Caplet ID/display seed").option("--repo <path>", "repository path to inspect").option("--include <items>", "comma-separated generators to include: git,gh,package").option("--command <name>", "single CLI command template to generate").option("--project", "write to the project Caplets root").option("-g, --global", "write to the user Caplets root").option("--remote", "add through remote control").option("--print", "print generated Caplet text without writing a file").option("--output <path>", "output path").option("--force", "overwrite an existing destination file").action(async (id, options) => {
|
|
68324
|
+
const target = parseMutationTarget(options);
|
|
68325
|
+
if (target === "remote") {
|
|
68326
|
+
writeAddResult(writeOut, "CLI", await requireRemoteClientForTarget(io).request("add", {
|
|
67958
68327
|
kind: "cli",
|
|
67959
68328
|
id,
|
|
67960
68329
|
options: remoteAddOptions(options)
|
|
@@ -67963,73 +68332,77 @@ function createProgram(io = {}) {
|
|
|
67963
68332
|
}
|
|
67964
68333
|
const result = addCliCaplet(id, {
|
|
67965
68334
|
...options,
|
|
67966
|
-
destinationRoot:
|
|
68335
|
+
destinationRoot: target === "global" ? resolveCapletsRoot(resolveConfigPath(currentConfigPath())) : envProjectCapletsRoot(env)
|
|
67967
68336
|
});
|
|
67968
68337
|
if (result.path) {
|
|
67969
|
-
writeOut(`Wrote CLI Caplet to ${result.path}\n`);
|
|
68338
|
+
writeOut(`Wrote ${localMutationTargetLabel(target, io)}CLI Caplet to ${result.path}\n`);
|
|
67970
68339
|
return;
|
|
67971
68340
|
}
|
|
67972
68341
|
writeOut(result.text);
|
|
67973
68342
|
});
|
|
67974
|
-
add.command("mcp").description("Add an MCP backend Caplet.").argument("<id>", "Caplet ID/display seed").option("--command <name>", "stdio command").option("--arg <value>", "stdio command argument", collect, []).option("--cwd <path>", "stdio working directory").option("--env <KEY=VALUE>", "stdio environment variable", collect, []).option("--url <url>", "remote MCP server URL").option("--transport <transport>", "remote transport: http or sse").option("--token-env <ENV>", "bearer token environment variable reference").option("-g, --global", "write to the user Caplets root").option("--print", "print generated Caplet text without writing a file").option("--output <path>", "output path").option("--force", "overwrite an existing destination file").action(async (id, options) => {
|
|
67975
|
-
const
|
|
67976
|
-
if (remote) {
|
|
67977
|
-
writeAddResult(writeOut, "MCP", await
|
|
68343
|
+
add.command("mcp").description("Add an MCP backend Caplet.").argument("<id>", "Caplet ID/display seed").option("--command <name>", "stdio command").option("--arg <value>", "stdio command argument", collect, []).option("--cwd <path>", "stdio working directory").option("--env <KEY=VALUE>", "stdio environment variable", collect, []).option("--url <url>", "remote MCP server URL").option("--transport <transport>", "remote transport: http or sse").option("--token-env <ENV>", "bearer token environment variable reference").option("--project", "write to the project Caplets root").option("-g, --global", "write to the user Caplets root").option("--remote", "add through remote control").option("--print", "print generated Caplet text without writing a file").option("--output <path>", "output path").option("--force", "overwrite an existing destination file").action(async (id, options) => {
|
|
68344
|
+
const target = parseMutationTarget(options);
|
|
68345
|
+
if (target === "remote") {
|
|
68346
|
+
writeAddResult(writeOut, "MCP", await requireRemoteClientForTarget(io).request("add", {
|
|
67978
68347
|
kind: "mcp",
|
|
67979
68348
|
id,
|
|
67980
68349
|
options: remoteAddOptions(options)
|
|
67981
68350
|
}));
|
|
67982
68351
|
return;
|
|
67983
68352
|
}
|
|
67984
|
-
|
|
68353
|
+
const result = addMcpCaplet(id, {
|
|
67985
68354
|
...options,
|
|
67986
|
-
destinationRoot: addDestinationRoot(
|
|
67987
|
-
})
|
|
68355
|
+
destinationRoot: addDestinationRoot(target, currentConfigPath(), env)
|
|
68356
|
+
});
|
|
68357
|
+
writeAddResult(writeOut, `${localMutationTargetLabel(target, io)}MCP`, result);
|
|
67988
68358
|
});
|
|
67989
|
-
add.command("openapi").description("Add an OpenAPI backend Caplet.").argument("<id>", "Caplet ID/display seed").option("--spec <path-or-url>", "OpenAPI spec path or URL").option("--base-url <url>", "request base URL override").option("--token-env <ENV>", "bearer token environment variable reference").option("-g, --global", "write to the user Caplets root").option("--print", "print generated Caplet text without writing a file").option("--output <path>", "output path").option("--force", "overwrite an existing destination file").action(async (id, options) => {
|
|
67990
|
-
const
|
|
67991
|
-
if (remote) {
|
|
67992
|
-
writeAddResult(writeOut, "OpenAPI", await
|
|
68359
|
+
add.command("openapi").description("Add an OpenAPI backend Caplet.").argument("<id>", "Caplet ID/display seed").option("--spec <path-or-url>", "OpenAPI spec path or URL").option("--base-url <url>", "request base URL override").option("--token-env <ENV>", "bearer token environment variable reference").option("--project", "write to the project Caplets root").option("-g, --global", "write to the user Caplets root").option("--remote", "add through remote control").option("--print", "print generated Caplet text without writing a file").option("--output <path>", "output path").option("--force", "overwrite an existing destination file").action(async (id, options) => {
|
|
68360
|
+
const target = parseMutationTarget(options);
|
|
68361
|
+
if (target === "remote") {
|
|
68362
|
+
writeAddResult(writeOut, "OpenAPI", await requireRemoteClientForTarget(io).request("add", {
|
|
67993
68363
|
kind: "openapi",
|
|
67994
68364
|
id,
|
|
67995
68365
|
options: remoteAddOptions(options)
|
|
67996
68366
|
}));
|
|
67997
68367
|
return;
|
|
67998
68368
|
}
|
|
67999
|
-
|
|
68369
|
+
const result = addOpenApiCaplet(id, {
|
|
68000
68370
|
...options,
|
|
68001
|
-
destinationRoot: addDestinationRoot(
|
|
68002
|
-
})
|
|
68371
|
+
destinationRoot: addDestinationRoot(target, currentConfigPath(), env)
|
|
68372
|
+
});
|
|
68373
|
+
writeAddResult(writeOut, `${localMutationTargetLabel(target, io)}OpenAPI`, result);
|
|
68003
68374
|
});
|
|
68004
|
-
add.command("graphql").description("Add a GraphQL backend Caplet.").argument("<id>", "Caplet ID/display seed").option("--endpoint-url <url>", "GraphQL endpoint URL").option("--schema <path-or-url>", "GraphQL schema path or URL").option("--introspection", "load schema through endpoint introspection").option("--token-env <ENV>", "bearer token environment variable reference").option("-g, --global", "write to the user Caplets root").option("--print", "print generated Caplet text without writing a file").option("--output <path>", "output path").option("--force", "overwrite an existing destination file").action(async (id, options) => {
|
|
68005
|
-
const
|
|
68006
|
-
if (remote) {
|
|
68007
|
-
writeAddResult(writeOut, "GraphQL", await
|
|
68375
|
+
add.command("graphql").description("Add a GraphQL backend Caplet.").argument("<id>", "Caplet ID/display seed").option("--endpoint-url <url>", "GraphQL endpoint URL").option("--schema <path-or-url>", "GraphQL schema path or URL").option("--introspection", "load schema through endpoint introspection").option("--token-env <ENV>", "bearer token environment variable reference").option("--project", "write to the project Caplets root").option("-g, --global", "write to the user Caplets root").option("--remote", "add through remote control").option("--print", "print generated Caplet text without writing a file").option("--output <path>", "output path").option("--force", "overwrite an existing destination file").action(async (id, options) => {
|
|
68376
|
+
const target = parseMutationTarget(options);
|
|
68377
|
+
if (target === "remote") {
|
|
68378
|
+
writeAddResult(writeOut, "GraphQL", await requireRemoteClientForTarget(io).request("add", {
|
|
68008
68379
|
kind: "graphql",
|
|
68009
68380
|
id,
|
|
68010
68381
|
options: remoteAddOptions(options)
|
|
68011
68382
|
}));
|
|
68012
68383
|
return;
|
|
68013
68384
|
}
|
|
68014
|
-
|
|
68385
|
+
const result = addGraphqlCaplet(id, {
|
|
68015
68386
|
...options,
|
|
68016
|
-
destinationRoot: addDestinationRoot(
|
|
68017
|
-
})
|
|
68387
|
+
destinationRoot: addDestinationRoot(target, currentConfigPath(), env)
|
|
68388
|
+
});
|
|
68389
|
+
writeAddResult(writeOut, `${localMutationTargetLabel(target, io)}GraphQL`, result);
|
|
68018
68390
|
});
|
|
68019
|
-
add.command("http").description("Add an HTTP actions backend Caplet.").argument("<id>", "Caplet ID/display seed").option("--base-url <url>", "HTTP API base URL").option("--action <name:METHOD:/path>", "HTTP action", collect, []).option("--token-env <ENV>", "bearer token environment variable reference").option("-g, --global", "write to the user Caplets root").option("--print", "print generated Caplet text without writing a file").option("--output <path>", "output path").option("--force", "overwrite an existing destination file").action(async (id, options) => {
|
|
68020
|
-
const
|
|
68021
|
-
if (remote) {
|
|
68022
|
-
writeAddResult(writeOut, "HTTP", await
|
|
68391
|
+
add.command("http").description("Add an HTTP actions backend Caplet.").argument("<id>", "Caplet ID/display seed").option("--base-url <url>", "HTTP API base URL").option("--action <name:METHOD:/path>", "HTTP action", collect, []).option("--token-env <ENV>", "bearer token environment variable reference").option("--project", "write to the project Caplets root").option("-g, --global", "write to the user Caplets root").option("--remote", "add through remote control").option("--print", "print generated Caplet text without writing a file").option("--output <path>", "output path").option("--force", "overwrite an existing destination file").action(async (id, options) => {
|
|
68392
|
+
const target = parseMutationTarget(options);
|
|
68393
|
+
if (target === "remote") {
|
|
68394
|
+
writeAddResult(writeOut, "HTTP", await requireRemoteClientForTarget(io).request("add", {
|
|
68023
68395
|
kind: "http",
|
|
68024
68396
|
id,
|
|
68025
68397
|
options: remoteAddOptions(options)
|
|
68026
68398
|
}));
|
|
68027
68399
|
return;
|
|
68028
68400
|
}
|
|
68029
|
-
|
|
68401
|
+
const result = addHttpCaplet(id, {
|
|
68030
68402
|
...options,
|
|
68031
|
-
destinationRoot: addDestinationRoot(
|
|
68032
|
-
})
|
|
68403
|
+
destinationRoot: addDestinationRoot(target, currentConfigPath(), env)
|
|
68404
|
+
});
|
|
68405
|
+
writeAddResult(writeOut, `${localMutationTargetLabel(target, io)}HTTP`, result);
|
|
68033
68406
|
});
|
|
68034
68407
|
program.command(cliCommands.getCaplet).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) => {
|
|
68035
68408
|
await executeOperation(caplet, { operation: "get_caplet" }, {
|
|
@@ -68231,7 +68604,7 @@ function createProgram(io = {}) {
|
|
|
68231
68604
|
writeOut(`${resolveConfigPath(currentConfigPath())}\n`);
|
|
68232
68605
|
});
|
|
68233
68606
|
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) => {
|
|
68234
|
-
const paths = resolveCliConfigPaths(currentConfigPath(), io.authDir);
|
|
68607
|
+
const paths = resolveCliConfigPaths(currentConfigPath(), envProjectConfigPath(env), io.authDir);
|
|
68235
68608
|
if (options.json || options.format === "json") {
|
|
68236
68609
|
writeOut(`${JSON.stringify(paths, null, 2)}\n`);
|
|
68237
68610
|
return;
|
|
@@ -68239,60 +68612,59 @@ function createProgram(io = {}) {
|
|
|
68239
68612
|
writeOut(formatConfigPaths(paths, options.format ?? "plain"));
|
|
68240
68613
|
});
|
|
68241
68614
|
const auth = program.command(cliCommands.auth).description("Manage OAuth credentials for remote servers.");
|
|
68242
|
-
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) => {
|
|
68243
|
-
const
|
|
68244
|
-
if (remote) {
|
|
68245
|
-
|
|
68246
|
-
if (started.authorizationUrl) {
|
|
68247
|
-
writeOut(`Open this URL to authorize ${serverId}:\n${started.authorizationUrl}\n`);
|
|
68248
|
-
if (options.open !== false) await openBrowser(started.authorizationUrl);
|
|
68249
|
-
writeOut("Complete authentication in your browser. The server callback will store credentials.\n");
|
|
68250
|
-
return;
|
|
68251
|
-
}
|
|
68252
|
-
if (started.authenticated) writeOut(`Authenticated \`${serverId}\`.\n`);
|
|
68615
|
+
auth.command("login").description("Authenticate a configured remote OAuth server.").argument("<server>", "configured server ID").option("--project", "authenticate using the project Caplets config").option("-g, --global", "authenticate using the user Caplets config").option("--remote", "authenticate using the remote server auth store").option("--no-open", "print the authorization URL without opening a browser").action(async (serverId, options) => {
|
|
68616
|
+
const target = await resolveAuthTarget(serverId, options, io);
|
|
68617
|
+
if (target === "remote") {
|
|
68618
|
+
await remoteAuthLogin(requireRemoteClientForTarget(io), serverId, options.open !== false, writeOut);
|
|
68253
68619
|
return;
|
|
68254
68620
|
}
|
|
68255
68621
|
const configPath = currentConfigPath();
|
|
68622
|
+
const projectConfigPath = envProjectConfigPath(env);
|
|
68256
68623
|
await loginAuth(serverId, {
|
|
68257
68624
|
noOpen: options.open === false,
|
|
68258
68625
|
writeOut,
|
|
68259
68626
|
writeErr,
|
|
68260
68627
|
...configPath ? { configPath } : {},
|
|
68628
|
+
...projectConfigPath ? { projectConfigPath } : {},
|
|
68629
|
+
config: localAuthConfigForTarget({
|
|
68630
|
+
serverId,
|
|
68631
|
+
...configPath ? { configPath } : {},
|
|
68632
|
+
...projectConfigPath ? { projectConfigPath } : {},
|
|
68633
|
+
source: target
|
|
68634
|
+
}),
|
|
68261
68635
|
...io.authDir ? { authDir: io.authDir } : {}
|
|
68262
68636
|
});
|
|
68263
68637
|
});
|
|
68264
|
-
auth.command("logout").description("Delete stored OAuth credentials for a server.").argument("<server>", "configured server ID").action(async (serverId) => {
|
|
68265
|
-
const
|
|
68266
|
-
if (remote) {
|
|
68267
|
-
writeOut((await
|
|
68638
|
+
auth.command("logout").description("Delete stored OAuth credentials for a server.").argument("<server>", "configured server ID").option("--project", "delete credentials for the project Caplets config target").option("-g, --global", "delete credentials for the user Caplets config target").option("--remote", "delete credentials from the remote server auth store").action(async (serverId, options) => {
|
|
68639
|
+
const target = await resolveAuthTarget(serverId, options, io);
|
|
68640
|
+
if (target === "remote") {
|
|
68641
|
+
writeOut((await requireRemoteClientForTarget(io).request("auth_logout", { server: serverId })).deleted ? `Deleted remote OAuth credentials for \`${serverId}\`.\n` : `No remote OAuth credentials found for \`${serverId}\`.\n`);
|
|
68268
68642
|
return;
|
|
68269
68643
|
}
|
|
68270
68644
|
const configPath = currentConfigPath();
|
|
68645
|
+
const projectConfigPath = envProjectConfigPath(env);
|
|
68271
68646
|
logoutAuth(serverId, {
|
|
68272
68647
|
writeOut,
|
|
68273
68648
|
...configPath ? { configPath } : {},
|
|
68649
|
+
config: localAuthConfigForTarget({
|
|
68650
|
+
serverId,
|
|
68651
|
+
...configPath ? { configPath } : {},
|
|
68652
|
+
...projectConfigPath ? { projectConfigPath } : {},
|
|
68653
|
+
source: target
|
|
68654
|
+
}),
|
|
68274
68655
|
...io.authDir ? { authDir: io.authDir } : {}
|
|
68275
68656
|
});
|
|
68276
68657
|
});
|
|
68277
|
-
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(async (options) => {
|
|
68658
|
+
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).option("--project", "list auth targets from the project Caplets config").option("-g, --global", "list auth targets from the user Caplets config").option("--remote", "list auth targets from the remote server auth store").action(async (options) => {
|
|
68278
68659
|
const configPath = currentConfigPath();
|
|
68660
|
+
const projectConfigPath = envProjectConfigPath(env);
|
|
68279
68661
|
const format = options.json || options.format === "json" ? "json" : options.format ?? "plain";
|
|
68280
|
-
const
|
|
68281
|
-
if (
|
|
68282
|
-
|
|
68283
|
-
if (format === "json") {
|
|
68284
|
-
writeOut(`${JSON.stringify(rows, null, 2)}\n`);
|
|
68285
|
-
return;
|
|
68286
|
-
}
|
|
68287
|
-
writeOut(formatAuthRows(rows, format));
|
|
68662
|
+
const rows = await authListRowsForCli(parseAuthFlagTarget(options), io, configPath, projectConfigPath);
|
|
68663
|
+
if (format === "json") {
|
|
68664
|
+
writeOut(`${JSON.stringify(rows, null, 2)}\n`);
|
|
68288
68665
|
return;
|
|
68289
68666
|
}
|
|
68290
|
-
|
|
68291
|
-
writeOut,
|
|
68292
|
-
format,
|
|
68293
|
-
...configPath ? { configPath } : {},
|
|
68294
|
-
...io.authDir ? { authDir: io.authDir } : {}
|
|
68295
|
-
});
|
|
68667
|
+
writeOut(formatAuthRows(rows, format));
|
|
68296
68668
|
});
|
|
68297
68669
|
return program;
|
|
68298
68670
|
}
|
|
@@ -68336,12 +68708,90 @@ function remoteCommandForOperation(operation) {
|
|
|
68336
68708
|
}
|
|
68337
68709
|
}
|
|
68338
68710
|
function remoteAddOptions(options) {
|
|
68339
|
-
const { output, print, global, destinationRoot, ...remoteOptions } = options;
|
|
68340
|
-
if (global) throw new CapletsError("REQUEST_INVALID", "--global is not supported in remote mode; the server controls the add destination.");
|
|
68711
|
+
const { output, print, global, project, remote, destinationRoot, ...remoteOptions } = options;
|
|
68341
68712
|
if (print) throw new CapletsError("REQUEST_INVALID", "--print is not supported in remote mode; the server controls add output.");
|
|
68342
68713
|
if (output !== void 0) throw new CapletsError("REQUEST_INVALID", "--output is not supported in remote mode; the server controls the add destination.");
|
|
68343
68714
|
return remoteOptions;
|
|
68344
68715
|
}
|
|
68716
|
+
function parseMutationTarget(options) {
|
|
68717
|
+
const selected = [
|
|
68718
|
+
options.project ? "--project" : void 0,
|
|
68719
|
+
options.global ? "--global" : void 0,
|
|
68720
|
+
options.remote ? "--remote" : void 0
|
|
68721
|
+
].filter((value) => value !== void 0);
|
|
68722
|
+
if (selected.length > 1) throw new CapletsError("REQUEST_INVALID", `Cannot combine mutation target flags: ${selected.join(", ")}`);
|
|
68723
|
+
if (options.global) return "global";
|
|
68724
|
+
if (options.remote) return "remote";
|
|
68725
|
+
return "project";
|
|
68726
|
+
}
|
|
68727
|
+
function localMutationTargetLabel(target, io) {
|
|
68728
|
+
return remoteClientForCli(io) ? `${target} ` : "";
|
|
68729
|
+
}
|
|
68730
|
+
function parseAuthFlagTarget(options) {
|
|
68731
|
+
const selected = [
|
|
68732
|
+
options.project ? "--project" : void 0,
|
|
68733
|
+
options.global ? "--global" : void 0,
|
|
68734
|
+
options.remote ? "--remote" : void 0
|
|
68735
|
+
].filter((value) => value !== void 0);
|
|
68736
|
+
if (selected.length > 1) throw new CapletsError("REQUEST_INVALID", `Cannot combine auth target flags: ${selected.join(", ")}`);
|
|
68737
|
+
if (options.project) return "project";
|
|
68738
|
+
if (options.global) return "global";
|
|
68739
|
+
if (options.remote) return "remote";
|
|
68740
|
+
}
|
|
68741
|
+
async function resolveAuthTarget(serverId, options, io) {
|
|
68742
|
+
const explicit = parseAuthFlagTarget(options);
|
|
68743
|
+
if (explicit) return explicit;
|
|
68744
|
+
const env = io.env ?? process.env;
|
|
68745
|
+
const configPath = envConfigPath(env);
|
|
68746
|
+
const projectConfigPath = envProjectConfigPath(env);
|
|
68747
|
+
const matches = localAuthTargets({
|
|
68748
|
+
...configPath ? { configPath } : {},
|
|
68749
|
+
...projectConfigPath ? { projectConfigPath } : {}
|
|
68750
|
+
}).filter((target) => target.server === serverId).map((target) => target.source);
|
|
68751
|
+
const remote = remoteClientForCli(io);
|
|
68752
|
+
if (remote) {
|
|
68753
|
+
if (matches.length === 0) matches.push("remote");
|
|
68754
|
+
else if ((await remoteAuthRows(remote)).some((row) => row.server === serverId)) matches.push("remote");
|
|
68755
|
+
}
|
|
68756
|
+
const unique = [...new Set(matches)];
|
|
68757
|
+
if (unique.length === 1) return unique[0];
|
|
68758
|
+
if (unique.length > 1) throw new CapletsError("REQUEST_INVALID", `Auth target \`${serverId}\` exists in multiple scopes. Pass --project, --global, or --remote.`);
|
|
68759
|
+
throw new CapletsError("SERVER_NOT_FOUND", `Server ${serverId} is not configured for OAuth`);
|
|
68760
|
+
}
|
|
68761
|
+
async function authListRowsForCli(target, io, configPath, projectConfigPath) {
|
|
68762
|
+
if (target === "remote") return remoteAuthRows(requireRemoteClientForTarget(io));
|
|
68763
|
+
const localRows = listLocalAuthRows({
|
|
68764
|
+
...configPath ? { configPath } : {},
|
|
68765
|
+
...projectConfigPath ? { projectConfigPath } : {},
|
|
68766
|
+
...io.authDir ? { authDir: io.authDir } : {},
|
|
68767
|
+
...target ? { source: target } : {}
|
|
68768
|
+
});
|
|
68769
|
+
if (target) return localRows;
|
|
68770
|
+
const remote = remoteClientForCli(io);
|
|
68771
|
+
if (!remote) return localRows;
|
|
68772
|
+
return [...localRows, ...await remoteAuthRows(remote)].sort((left, right) => left.server.localeCompare(right.server));
|
|
68773
|
+
}
|
|
68774
|
+
async function remoteAuthRows(remote) {
|
|
68775
|
+
return (await remote.request("auth_list", {})).map((row) => ({
|
|
68776
|
+
...row,
|
|
68777
|
+
source: "remote"
|
|
68778
|
+
}));
|
|
68779
|
+
}
|
|
68780
|
+
async function remoteAuthLogin(remote, serverId, open, writeOut) {
|
|
68781
|
+
const started = await remote.request("auth_login_start", { server: serverId });
|
|
68782
|
+
if (started.authorizationUrl) {
|
|
68783
|
+
writeOut(`Open this URL to authorize ${serverId}:\n${started.authorizationUrl}\n`);
|
|
68784
|
+
if (open) await openBrowser(started.authorizationUrl);
|
|
68785
|
+
writeOut("Complete authentication in your browser. The server callback will store credentials.\n");
|
|
68786
|
+
return;
|
|
68787
|
+
}
|
|
68788
|
+
if (started.authenticated) writeOut(`Authenticated \`${serverId}\`.\n`);
|
|
68789
|
+
}
|
|
68790
|
+
function requireRemoteClientForTarget(io) {
|
|
68791
|
+
const remote = remoteClientForCli(io);
|
|
68792
|
+
if (!remote) throw new CapletsError("REQUEST_INVALID", "--remote requires CAPLETS_MODE=remote and CAPLETS_SERVER_URL");
|
|
68793
|
+
return remote;
|
|
68794
|
+
}
|
|
68345
68795
|
function collect(value, previous) {
|
|
68346
68796
|
previous.push(value);
|
|
68347
68797
|
return previous;
|
|
@@ -68378,8 +68828,10 @@ function parseQualifiedTarget(capletOrTarget, toolArgument) {
|
|
|
68378
68828
|
async function completeCliWordsLocally(words, options) {
|
|
68379
68829
|
const engine = new CapletsEngine({
|
|
68380
68830
|
...options.configPath ? { configPath: options.configPath } : {},
|
|
68831
|
+
...options.projectConfigPath ? { projectConfigPath: options.projectConfigPath } : {},
|
|
68381
68832
|
...options.authDir ? { authDir: options.authDir } : {},
|
|
68382
|
-
watch: false
|
|
68833
|
+
watch: false,
|
|
68834
|
+
...options.config ? { configLoader: () => options.config } : {}
|
|
68383
68835
|
});
|
|
68384
68836
|
try {
|
|
68385
68837
|
return await engine.completeCliWords(words);
|
|
@@ -68387,6 +68839,34 @@ async function completeCliWordsLocally(words, options) {
|
|
|
68387
68839
|
await engine.close();
|
|
68388
68840
|
}
|
|
68389
68841
|
}
|
|
68842
|
+
function mergeCompletionSuggestions(...groups) {
|
|
68843
|
+
return [...new Set(groups.flat())];
|
|
68844
|
+
}
|
|
68845
|
+
function localShadowedCompletionTarget(words, config) {
|
|
68846
|
+
const command = words[0];
|
|
68847
|
+
const target = words[1];
|
|
68848
|
+
if (!command || !target || target.startsWith("-")) return;
|
|
68849
|
+
const qualifiedCommands = new Set([
|
|
68850
|
+
cliCommands.getTool,
|
|
68851
|
+
cliCommands.callTool,
|
|
68852
|
+
cliCommands.getPrompt
|
|
68853
|
+
]);
|
|
68854
|
+
const capletCommands = new Set([
|
|
68855
|
+
cliCommands.getCaplet,
|
|
68856
|
+
cliCommands.checkBackend,
|
|
68857
|
+
cliCommands.listTools,
|
|
68858
|
+
cliCommands.searchTools,
|
|
68859
|
+
cliCommands.listResources,
|
|
68860
|
+
cliCommands.searchResources,
|
|
68861
|
+
cliCommands.listResourceTemplates,
|
|
68862
|
+
cliCommands.readResource,
|
|
68863
|
+
cliCommands.listPrompts,
|
|
68864
|
+
cliCommands.searchPrompts,
|
|
68865
|
+
cliCommands.complete
|
|
68866
|
+
]);
|
|
68867
|
+
const caplet = qualifiedCommands.has(command) ? target.slice(0, target.includes(".") ? target.indexOf(".") : target.length) : capletCommands.has(command) ? target : void 0;
|
|
68868
|
+
return caplet && hasEnabledCaplet(config, caplet) ? caplet : void 0;
|
|
68869
|
+
}
|
|
68390
68870
|
function parseCallToolArgs(value) {
|
|
68391
68871
|
if (value === void 0) return {};
|
|
68392
68872
|
let parsed;
|
|
@@ -68427,6 +68907,11 @@ function isPlainObject(value) {
|
|
|
68427
68907
|
async function executeOperation(caplet, request, io) {
|
|
68428
68908
|
const command = remoteCommandForOperation(request.operation);
|
|
68429
68909
|
if (io.remote && command) {
|
|
68910
|
+
const localOverlay = tryLoadLocalOverlayForCli(io, io.writeErr);
|
|
68911
|
+
if (localOverlay && hasEnabledCaplet(localOverlay.config, caplet)) {
|
|
68912
|
+
await executeLocalOperation(caplet, request, io, localOverlay.config);
|
|
68913
|
+
return;
|
|
68914
|
+
}
|
|
68430
68915
|
const result = await io.remote.request(command, {
|
|
68431
68916
|
caplet,
|
|
68432
68917
|
request
|
|
@@ -68439,12 +68924,119 @@ async function executeOperation(caplet, request, io) {
|
|
|
68439
68924
|
if (isPlainObject(result) && result.isError === true) io.setExitCode(1);
|
|
68440
68925
|
return;
|
|
68441
68926
|
}
|
|
68927
|
+
await executeLocalOperation(caplet, request, io);
|
|
68928
|
+
}
|
|
68929
|
+
function loadLocalOverlayForCli(io, writeErr) {
|
|
68930
|
+
const env = io.env ?? process.env;
|
|
68931
|
+
const overlay = loadLocalOverlayConfigWithSources(resolveConfigPath(envConfigPath(env)), envProjectConfigPath(env));
|
|
68932
|
+
for (const warning of overlay.warnings) writeErr(`Warning: ${warning.kind} at ${warning.path}: ${warning.message}\n`);
|
|
68933
|
+
return overlay;
|
|
68934
|
+
}
|
|
68935
|
+
function tryLoadLocalOverlayForCli(io, writeErr) {
|
|
68936
|
+
try {
|
|
68937
|
+
return loadLocalOverlayForCli(io, writeErr);
|
|
68938
|
+
} catch (error) {
|
|
68939
|
+
writeErr(`Warning: Could not load local Caplets overlay: ${formatErrorMessage(error)}\n`);
|
|
68940
|
+
return loadPartialLocalOverlayForCli(io, writeErr);
|
|
68941
|
+
}
|
|
68942
|
+
}
|
|
68943
|
+
function loadPartialLocalOverlayForCli(io, writeErr) {
|
|
68944
|
+
const env = io.env ?? process.env;
|
|
68945
|
+
const configPath = resolveConfigPath(envConfigPath(env));
|
|
68946
|
+
const projectConfigPath = envProjectConfigPath(env);
|
|
68947
|
+
const absentProjectPath = join(dirname(configPath), ".caplets-overlay-recovery", "config.json");
|
|
68948
|
+
const absentGlobalPath = join(dirname(projectConfigPath), ".caplets-overlay-recovery", "config.json");
|
|
68949
|
+
const globalOverlay = tryLoadPartialOverlayLayer("global", configPath, absentProjectPath, writeErr);
|
|
68950
|
+
const projectOverlay = tryLoadPartialOverlayLayer("project", absentGlobalPath, projectConfigPath, writeErr);
|
|
68951
|
+
if (!globalOverlay) return projectOverlay;
|
|
68952
|
+
if (!projectOverlay) return globalOverlay;
|
|
68953
|
+
return mergePartialLocalOverlays(globalOverlay, projectOverlay);
|
|
68954
|
+
}
|
|
68955
|
+
function tryLoadPartialOverlayLayer(label, configPath, projectConfigPath, writeErr) {
|
|
68956
|
+
try {
|
|
68957
|
+
const overlay = loadLocalOverlayConfigWithSources(configPath, projectConfigPath);
|
|
68958
|
+
for (const warning of overlay.warnings) writeErr(`Warning: ${warning.kind} at ${warning.path}: ${warning.message}\n`);
|
|
68959
|
+
return overlay;
|
|
68960
|
+
} catch (error) {
|
|
68961
|
+
writeErr(`Warning: Could not load ${label} Caplets overlay: ${formatErrorMessage(error)}\n`);
|
|
68962
|
+
return;
|
|
68963
|
+
}
|
|
68964
|
+
}
|
|
68965
|
+
function mergePartialLocalOverlays(globalOverlay, projectOverlay) {
|
|
68966
|
+
const config = { ...globalOverlay.config };
|
|
68967
|
+
const sources = { ...globalOverlay.sources };
|
|
68968
|
+
const shadows = { ...globalOverlay.shadows };
|
|
68969
|
+
for (const kind of capletConfigKinds) config[kind] = { ...globalOverlay.config[kind] };
|
|
68970
|
+
for (const kind of capletConfigKinds) for (const id of Object.keys(projectOverlay.config[kind])) {
|
|
68971
|
+
removeCapletFromPartialOverlay(config, sources, shadows, id);
|
|
68972
|
+
config[kind][id] = projectOverlay.config[kind][id];
|
|
68973
|
+
}
|
|
68974
|
+
for (const [id, source] of Object.entries(projectOverlay.sources)) sources[id] = source;
|
|
68975
|
+
for (const [id, shadowedSources] of Object.entries(projectOverlay.shadows)) shadows[id] = [...shadows[id] ?? [], ...shadowedSources];
|
|
68976
|
+
return {
|
|
68977
|
+
config,
|
|
68978
|
+
sources,
|
|
68979
|
+
shadows,
|
|
68980
|
+
warnings: [...globalOverlay.warnings, ...projectOverlay.warnings]
|
|
68981
|
+
};
|
|
68982
|
+
}
|
|
68983
|
+
const capletConfigKinds = [
|
|
68984
|
+
"mcpServers",
|
|
68985
|
+
"openapiEndpoints",
|
|
68986
|
+
"graphqlEndpoints",
|
|
68987
|
+
"httpApis",
|
|
68988
|
+
"cliTools",
|
|
68989
|
+
"capletSets"
|
|
68990
|
+
];
|
|
68991
|
+
function removeCapletFromPartialOverlay(config, sources, shadows, id) {
|
|
68992
|
+
for (const kind of capletConfigKinds) delete config[kind][id];
|
|
68993
|
+
if (sources[id]) shadows[id] = [...shadows[id] ?? [], sources[id]];
|
|
68994
|
+
delete sources[id];
|
|
68995
|
+
}
|
|
68996
|
+
function formatErrorMessage(error) {
|
|
68997
|
+
return error instanceof Error ? error.message : String(error);
|
|
68998
|
+
}
|
|
68999
|
+
function envProjectConfigPath(env) {
|
|
69000
|
+
return env.CAPLETS_PROJECT_CONFIG?.trim() || resolveProjectConfigPath();
|
|
69001
|
+
}
|
|
69002
|
+
function envProjectCapletsRoot(env) {
|
|
69003
|
+
const projectConfigPath = env.CAPLETS_PROJECT_CONFIG?.trim();
|
|
69004
|
+
return projectConfigPath ? dirname(projectConfigPath) : resolveProjectCapletsRoot();
|
|
69005
|
+
}
|
|
69006
|
+
function mergeRemoteAndLocalRows(remoteRows, localOverlay, options) {
|
|
69007
|
+
const rows = /* @__PURE__ */ new Map();
|
|
69008
|
+
for (const row of remoteRows) rows.set(row.server, {
|
|
69009
|
+
...row,
|
|
69010
|
+
source: "remote"
|
|
69011
|
+
});
|
|
69012
|
+
if (!localOverlay) return [...rows.values()].filter((row) => options.includeDisabled || !row.disabled).sort((left, right) => left.server.localeCompare(right.server));
|
|
69013
|
+
for (const row of listCaplets(localOverlay, { includeDisabled: true })) {
|
|
69014
|
+
if (rows.get(row.server)) {
|
|
69015
|
+
if (row.disabled) continue;
|
|
69016
|
+
options.writeErr(`Warning: ${formatOverlaySource(row.source)} Caplet ${row.server} shadows remote Caplet\n`);
|
|
69017
|
+
}
|
|
69018
|
+
rows.set(row.server, row);
|
|
69019
|
+
}
|
|
69020
|
+
return [...rows.values()].filter((row) => options.includeDisabled || !row.disabled).sort((left, right) => left.server.localeCompare(right.server));
|
|
69021
|
+
}
|
|
69022
|
+
function formatOverlaySource(kind) {
|
|
69023
|
+
if (kind.startsWith("project")) return "project";
|
|
69024
|
+
if (kind.startsWith("global")) return "global";
|
|
69025
|
+
return kind;
|
|
69026
|
+
}
|
|
69027
|
+
function hasEnabledCaplet(config, id) {
|
|
69028
|
+
const caplet = config.mcpServers[id] ?? config.openapiEndpoints[id] ?? config.graphqlEndpoints[id] ?? config.httpApis[id] ?? config.cliTools[id] ?? config.capletSets[id];
|
|
69029
|
+
return Boolean(caplet && !caplet.disabled);
|
|
69030
|
+
}
|
|
69031
|
+
async function executeLocalOperation(caplet, request, io, config) {
|
|
68442
69032
|
const configPath = envConfigPath(io.env ?? process.env);
|
|
68443
69033
|
const engine = new CapletsEngine({
|
|
68444
69034
|
...configPath ? { configPath } : {},
|
|
69035
|
+
projectConfigPath: envProjectConfigPath(io.env ?? process.env),
|
|
68445
69036
|
...io.authDir ? { authDir: io.authDir } : {},
|
|
68446
69037
|
watch: false,
|
|
68447
|
-
writeErr: io.writeErr
|
|
69038
|
+
writeErr: io.writeErr,
|
|
69039
|
+
...config ? { configLoader: () => config } : {}
|
|
68448
69040
|
});
|
|
68449
69041
|
try {
|
|
68450
69042
|
const result = await engine.execute(caplet, request);
|
|
@@ -68799,8 +69391,8 @@ function schemaSummary(schema) {
|
|
|
68799
69391
|
required.length > 0 ? `required ${required.join(", ")}` : "no required fields"
|
|
68800
69392
|
].filter((part) => Boolean(part)).join("; ");
|
|
68801
69393
|
}
|
|
68802
|
-
function addDestinationRoot(
|
|
68803
|
-
return
|
|
69394
|
+
function addDestinationRoot(target, configPath, env) {
|
|
69395
|
+
return target === "global" ? resolveCapletsRoot(resolveConfigPath(configPath)) : envProjectCapletsRoot(env);
|
|
68804
69396
|
}
|
|
68805
69397
|
function writeAddResult(writeOut, label, result) {
|
|
68806
69398
|
if (result.path) {
|
|
@@ -68811,7 +69403,7 @@ function writeAddResult(writeOut, label, result) {
|
|
|
68811
69403
|
}
|
|
68812
69404
|
//#endregion
|
|
68813
69405
|
//#region package.json
|
|
68814
|
-
var version = "0.17.
|
|
69406
|
+
var version = "0.17.4";
|
|
68815
69407
|
//#endregion
|
|
68816
69408
|
//#region src/index.ts
|
|
68817
69409
|
async function main() {
|