stpr 1.0.6 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +72 -26
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -2,19 +2,49 @@
|
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
4
|
import { createRequire } from "module";
|
|
5
|
-
import * as
|
|
5
|
+
import * as path3 from "path";
|
|
6
6
|
import { fileURLToPath } from "url";
|
|
7
7
|
|
|
8
8
|
// src/auth.ts
|
|
9
9
|
import * as childProcess from "child_process";
|
|
10
|
+
import * as crypto2 from "crypto";
|
|
11
|
+
import * as fs2 from "fs";
|
|
12
|
+
import * as os2 from "os";
|
|
13
|
+
import * as path2 from "path";
|
|
14
|
+
import { createServer } from "http";
|
|
15
|
+
|
|
16
|
+
// src/client.ts
|
|
10
17
|
import * as crypto from "crypto";
|
|
11
18
|
import * as fs from "fs";
|
|
12
19
|
import * as os from "os";
|
|
13
20
|
import * as path from "path";
|
|
14
|
-
import { createServer } from "http";
|
|
15
|
-
|
|
16
|
-
// src/client.ts
|
|
17
21
|
var DEFAULT_BASE_URL = "https://mcp.stepper.io";
|
|
22
|
+
var CACHE_DIR = path.join(os.homedir(), ".config", "stepper-skillsets", "cache");
|
|
23
|
+
var CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
24
|
+
function getCachePath(key) {
|
|
25
|
+
const hash = crypto.createHash("sha256").update(key).digest("hex").slice(0, 16);
|
|
26
|
+
return path.join(CACHE_DIR, `${hash}.json`);
|
|
27
|
+
}
|
|
28
|
+
function readCache(key) {
|
|
29
|
+
try {
|
|
30
|
+
const filePath = getCachePath(key);
|
|
31
|
+
const raw = fs.readFileSync(filePath, "utf-8");
|
|
32
|
+
const entry = JSON.parse(raw);
|
|
33
|
+
if (Date.now() - entry.timestamp < CACHE_TTL_MS) {
|
|
34
|
+
return entry.data;
|
|
35
|
+
}
|
|
36
|
+
} catch {
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
function writeCache(key, data) {
|
|
41
|
+
try {
|
|
42
|
+
fs.mkdirSync(CACHE_DIR, { recursive: true, mode: 448 });
|
|
43
|
+
const entry = { timestamp: Date.now(), data };
|
|
44
|
+
fs.writeFileSync(getCachePath(key), JSON.stringify(entry), { mode: 384 });
|
|
45
|
+
} catch {
|
|
46
|
+
}
|
|
47
|
+
}
|
|
18
48
|
var StepperClient = class {
|
|
19
49
|
token;
|
|
20
50
|
baseUrl;
|
|
@@ -63,20 +93,31 @@ var StepperClient = class {
|
|
|
63
93
|
version: serverInfo.version ?? "1.0.0"
|
|
64
94
|
};
|
|
65
95
|
}
|
|
66
|
-
async listTools({ service }) {
|
|
96
|
+
async listTools({ service, noCache }) {
|
|
97
|
+
const cacheKey = `tools-list:${this.baseUrl}:${this.token}`;
|
|
98
|
+
let allTools;
|
|
99
|
+
if (!noCache) {
|
|
100
|
+
const cached = readCache(cacheKey);
|
|
101
|
+
if (cached) {
|
|
102
|
+
allTools = cached;
|
|
103
|
+
return allTools.filter(
|
|
104
|
+
(tool) => service ? tool.service === service : !tool.service.startsWith("__")
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
67
108
|
const res = await this.rpc("tools/list");
|
|
68
109
|
if (res.error) {
|
|
69
110
|
throw new Error(`tools/list failed: ${res.error.message}`);
|
|
70
111
|
}
|
|
71
112
|
const tools = res.result.tools;
|
|
72
|
-
|
|
73
|
-
(
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
113
|
+
allTools = tools.map((tool) => ({
|
|
114
|
+
service: tool.name.split(".")[0],
|
|
115
|
+
action: tool.name.split(".")[1],
|
|
116
|
+
description: tool.description,
|
|
117
|
+
inputSchema: tool.inputSchema
|
|
118
|
+
}));
|
|
119
|
+
writeCache(cacheKey, allTools);
|
|
120
|
+
return allTools.filter(
|
|
80
121
|
(tool) => service ? tool.service === service : !tool.service.startsWith("__")
|
|
81
122
|
);
|
|
82
123
|
}
|
|
@@ -121,7 +162,7 @@ var StepperClient = class {
|
|
|
121
162
|
|
|
122
163
|
// src/auth.ts
|
|
123
164
|
function openBrowser(url) {
|
|
124
|
-
const platform2 =
|
|
165
|
+
const platform2 = os2.platform();
|
|
125
166
|
if (platform2 === "darwin") {
|
|
126
167
|
childProcess.spawn("open", [url], { stdio: "ignore", detached: true });
|
|
127
168
|
} else if (platform2 === "win32") {
|
|
@@ -136,24 +177,24 @@ function openBrowser(url) {
|
|
|
136
177
|
var DEFAULT_BASE_URL2 = "https://mcp.stepper.io";
|
|
137
178
|
var OAUTH_CALLBACK_PORT = 3847;
|
|
138
179
|
var CALLBACK_PATH = "/callback";
|
|
139
|
-
var CONFIG_DIR =
|
|
140
|
-
var CONFIG_FILE =
|
|
180
|
+
var CONFIG_DIR = path2.join(os2.homedir(), ".config", "stepper-skillsets");
|
|
181
|
+
var CONFIG_FILE = path2.join(CONFIG_DIR, "config.json");
|
|
141
182
|
function generatePKCE() {
|
|
142
|
-
const codeVerifier =
|
|
143
|
-
const codeChallenge =
|
|
183
|
+
const codeVerifier = crypto2.randomBytes(32).toString("base64url");
|
|
184
|
+
const codeChallenge = crypto2.createHash("sha256").update(codeVerifier).digest().toString("base64url");
|
|
144
185
|
return { codeVerifier, codeChallenge };
|
|
145
186
|
}
|
|
146
187
|
function loadConfig() {
|
|
147
188
|
try {
|
|
148
|
-
const data =
|
|
189
|
+
const data = fs2.readFileSync(CONFIG_FILE, "utf-8");
|
|
149
190
|
return JSON.parse(data);
|
|
150
191
|
} catch {
|
|
151
192
|
return { active: null, skillsets: {} };
|
|
152
193
|
}
|
|
153
194
|
}
|
|
154
195
|
function saveConfig(config) {
|
|
155
|
-
|
|
156
|
-
|
|
196
|
+
fs2.mkdirSync(CONFIG_DIR, { recursive: true, mode: 448 });
|
|
197
|
+
fs2.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), {
|
|
157
198
|
mode: 384
|
|
158
199
|
});
|
|
159
200
|
}
|
|
@@ -282,7 +323,7 @@ async function runLoginFlow(baseUrl) {
|
|
|
282
323
|
const metadata = await fetchMetadata(normalizedBaseUrl);
|
|
283
324
|
const { codeVerifier, codeChallenge } = generatePKCE();
|
|
284
325
|
const clientId = await registerClient(normalizedBaseUrl, redirectUri);
|
|
285
|
-
const state =
|
|
326
|
+
const state = crypto2.randomBytes(16).toString("hex");
|
|
286
327
|
const authUrl = new URL(metadata.authorization_endpoint);
|
|
287
328
|
authUrl.searchParams.set("response_type", "code");
|
|
288
329
|
authUrl.searchParams.set("client_id", clientId);
|
|
@@ -452,9 +493,9 @@ async function getValidToken(skillsetName, baseUrl) {
|
|
|
452
493
|
}
|
|
453
494
|
|
|
454
495
|
// src/cli.ts
|
|
455
|
-
var __dirname =
|
|
496
|
+
var __dirname = path3.dirname(fileURLToPath(import.meta.url));
|
|
456
497
|
var pkg = createRequire(import.meta.url)(
|
|
457
|
-
|
|
498
|
+
path3.join(__dirname, "..", "package.json")
|
|
458
499
|
);
|
|
459
500
|
var VERSION = pkg.version ?? "0.0.0";
|
|
460
501
|
function readStdin() {
|
|
@@ -491,6 +532,8 @@ function parseArgs(argv) {
|
|
|
491
532
|
flags.cursor = argv[++i];
|
|
492
533
|
} else if (arg === "--call") {
|
|
493
534
|
boolFlags.call = true;
|
|
535
|
+
} else if (arg === "--no-cache") {
|
|
536
|
+
boolFlags.noCache = true;
|
|
494
537
|
} else if (arg === "--verbose") {
|
|
495
538
|
boolFlags.verbose = true;
|
|
496
539
|
} else if (arg === "--options" && i + 1 < argv.length) {
|
|
@@ -514,6 +557,7 @@ function parseArgs(argv) {
|
|
|
514
557
|
cursor: flags.cursor,
|
|
515
558
|
call: boolFlags.call ?? false,
|
|
516
559
|
verbose: boolFlags.verbose ?? false,
|
|
560
|
+
noCache: boolFlags.noCache ?? false,
|
|
517
561
|
options: flags.options
|
|
518
562
|
};
|
|
519
563
|
}
|
|
@@ -558,6 +602,7 @@ Options:
|
|
|
558
602
|
--skillset <name> Use a specific skill set
|
|
559
603
|
--call Execute the skill (default is to fetch parameters only)
|
|
560
604
|
--verbose Include inputSchema when listing skills
|
|
605
|
+
--no-cache Bypass the 5-minute tools list cache
|
|
561
606
|
-i, --input <json> JSON input for call, parameters or options (alternative to stdin)
|
|
562
607
|
--search <query> Search query for dynamic dropdown options
|
|
563
608
|
--cursor <cursor> Pagination cursor for dynamic dropdown options
|
|
@@ -605,6 +650,7 @@ async function main() {
|
|
|
605
650
|
cursor: cursorFlag,
|
|
606
651
|
call: callFlag,
|
|
607
652
|
verbose: verboseFlag,
|
|
653
|
+
noCache: noCacheFlag,
|
|
608
654
|
options: optionsFlag
|
|
609
655
|
} = parseArgs(process.argv.slice(2));
|
|
610
656
|
if (subcommand === "help") {
|
|
@@ -758,7 +804,7 @@ async function main() {
|
|
|
758
804
|
}
|
|
759
805
|
if (subcommand === "list") {
|
|
760
806
|
const service2 = args[0];
|
|
761
|
-
const tools = await client.listTools({ service: service2 ?? void 0 });
|
|
807
|
+
const tools = await client.listTools({ service: service2 ?? void 0, noCache: noCacheFlag });
|
|
762
808
|
const formatted = formatToolsForList(tools, verboseFlag);
|
|
763
809
|
if (!tools.length) {
|
|
764
810
|
die(
|
|
@@ -776,7 +822,7 @@ async function main() {
|
|
|
776
822
|
return;
|
|
777
823
|
}
|
|
778
824
|
if (!action) {
|
|
779
|
-
const tools = await client.listTools({ service });
|
|
825
|
+
const tools = await client.listTools({ service, noCache: noCacheFlag });
|
|
780
826
|
if (!tools.length) {
|
|
781
827
|
die(
|
|
782
828
|
service ? `No skills found for service "${service}".` : "No skills found."
|