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.
Files changed (2) hide show
  1. package/dist/cli.js +72 -26
  2. 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 path2 from "path";
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
- return tools.map(
73
- (tool) => ({
74
- service: tool.name.split(".")[0],
75
- action: tool.name.split(".")[1],
76
- description: tool.description,
77
- inputSchema: tool.inputSchema
78
- })
79
- ).filter(
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 = os.platform();
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 = path.join(os.homedir(), ".config", "stepper-skillsets");
140
- var CONFIG_FILE = path.join(CONFIG_DIR, "config.json");
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 = crypto.randomBytes(32).toString("base64url");
143
- const codeChallenge = crypto.createHash("sha256").update(codeVerifier).digest().toString("base64url");
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 = fs.readFileSync(CONFIG_FILE, "utf-8");
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
- fs.mkdirSync(CONFIG_DIR, { recursive: true, mode: 448 });
156
- fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), {
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 = crypto.randomBytes(16).toString("hex");
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 = path2.dirname(fileURLToPath(import.meta.url));
496
+ var __dirname = path3.dirname(fileURLToPath(import.meta.url));
456
497
  var pkg = createRequire(import.meta.url)(
457
- path2.join(__dirname, "..", "package.json")
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."
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stpr",
3
- "version": "1.0.6",
3
+ "version": "1.0.7",
4
4
  "description": "CLI for Stepper skill sets",
5
5
  "type": "module",
6
6
  "files": [