stpr 1.0.6 → 1.0.8

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 (3) hide show
  1. package/dist/cli.js +82 -23
  2. package/package.json +1 -1
  3. package/README.md +0 -159
package/dist/cli.js CHANGED
@@ -2,19 +2,54 @@
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(
23
+ os.homedir(),
24
+ ".config",
25
+ "stepper-skillsets",
26
+ "cache"
27
+ );
28
+ var CACHE_TTL_MS = 5 * 60 * 1e3;
29
+ function getCachePath(key) {
30
+ const hash = crypto.createHash("sha256").update(key).digest("hex").slice(0, 16);
31
+ return path.join(CACHE_DIR, `${hash}.json`);
32
+ }
33
+ function readCache(key) {
34
+ try {
35
+ const filePath = getCachePath(key);
36
+ const raw = fs.readFileSync(filePath, "utf-8");
37
+ const entry = JSON.parse(raw);
38
+ if (Date.now() - entry.timestamp < CACHE_TTL_MS) {
39
+ return entry.data;
40
+ }
41
+ } catch {
42
+ }
43
+ return null;
44
+ }
45
+ function writeCache(key, data) {
46
+ try {
47
+ fs.mkdirSync(CACHE_DIR, { recursive: true, mode: 448 });
48
+ const entry = { timestamp: Date.now(), data };
49
+ fs.writeFileSync(getCachePath(key), JSON.stringify(entry), { mode: 384 });
50
+ } catch {
51
+ }
52
+ }
18
53
  var StepperClient = class {
19
54
  token;
20
55
  baseUrl;
@@ -63,20 +98,36 @@ var StepperClient = class {
63
98
  version: serverInfo.version ?? "1.0.0"
64
99
  };
65
100
  }
66
- async listTools({ service }) {
101
+ async listTools({
102
+ service,
103
+ noCache
104
+ }) {
105
+ const cacheKey = `tools-list:${this.baseUrl}:${this.token}`;
106
+ let allTools;
107
+ if (!noCache) {
108
+ const cached = readCache(cacheKey);
109
+ if (cached) {
110
+ allTools = cached;
111
+ return allTools.filter(
112
+ (tool) => service ? tool.service === service : !tool.service.startsWith("__")
113
+ );
114
+ }
115
+ }
67
116
  const res = await this.rpc("tools/list");
68
117
  if (res.error) {
69
118
  throw new Error(`tools/list failed: ${res.error.message}`);
70
119
  }
71
120
  const tools = res.result.tools;
72
- return tools.map(
121
+ allTools = tools.map(
73
122
  (tool) => ({
74
- service: tool.name.split(".")[0],
75
- action: tool.name.split(".")[1],
123
+ service: tool.name.split("__")[0],
124
+ action: tool.name.split("__")[1],
76
125
  description: tool.description,
77
126
  inputSchema: tool.inputSchema
78
127
  })
79
- ).filter(
128
+ );
129
+ writeCache(cacheKey, allTools);
130
+ return allTools.filter(
80
131
  (tool) => service ? tool.service === service : !tool.service.startsWith("__")
81
132
  );
82
133
  }
@@ -121,7 +172,7 @@ var StepperClient = class {
121
172
 
122
173
  // src/auth.ts
123
174
  function openBrowser(url) {
124
- const platform2 = os.platform();
175
+ const platform2 = os2.platform();
125
176
  if (platform2 === "darwin") {
126
177
  childProcess.spawn("open", [url], { stdio: "ignore", detached: true });
127
178
  } else if (platform2 === "win32") {
@@ -136,24 +187,24 @@ function openBrowser(url) {
136
187
  var DEFAULT_BASE_URL2 = "https://mcp.stepper.io";
137
188
  var OAUTH_CALLBACK_PORT = 3847;
138
189
  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");
190
+ var CONFIG_DIR = path2.join(os2.homedir(), ".config", "stepper-skillsets");
191
+ var CONFIG_FILE = path2.join(CONFIG_DIR, "config.json");
141
192
  function generatePKCE() {
142
- const codeVerifier = crypto.randomBytes(32).toString("base64url");
143
- const codeChallenge = crypto.createHash("sha256").update(codeVerifier).digest().toString("base64url");
193
+ const codeVerifier = crypto2.randomBytes(32).toString("base64url");
194
+ const codeChallenge = crypto2.createHash("sha256").update(codeVerifier).digest().toString("base64url");
144
195
  return { codeVerifier, codeChallenge };
145
196
  }
146
197
  function loadConfig() {
147
198
  try {
148
- const data = fs.readFileSync(CONFIG_FILE, "utf-8");
199
+ const data = fs2.readFileSync(CONFIG_FILE, "utf-8");
149
200
  return JSON.parse(data);
150
201
  } catch {
151
202
  return { active: null, skillsets: {} };
152
203
  }
153
204
  }
154
205
  function saveConfig(config) {
155
- fs.mkdirSync(CONFIG_DIR, { recursive: true, mode: 448 });
156
- fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), {
206
+ fs2.mkdirSync(CONFIG_DIR, { recursive: true, mode: 448 });
207
+ fs2.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), {
157
208
  mode: 384
158
209
  });
159
210
  }
@@ -282,7 +333,7 @@ async function runLoginFlow(baseUrl) {
282
333
  const metadata = await fetchMetadata(normalizedBaseUrl);
283
334
  const { codeVerifier, codeChallenge } = generatePKCE();
284
335
  const clientId = await registerClient(normalizedBaseUrl, redirectUri);
285
- const state = crypto.randomBytes(16).toString("hex");
336
+ const state = crypto2.randomBytes(16).toString("hex");
286
337
  const authUrl = new URL(metadata.authorization_endpoint);
287
338
  authUrl.searchParams.set("response_type", "code");
288
339
  authUrl.searchParams.set("client_id", clientId);
@@ -452,9 +503,9 @@ async function getValidToken(skillsetName, baseUrl) {
452
503
  }
453
504
 
454
505
  // src/cli.ts
455
- var __dirname = path2.dirname(fileURLToPath(import.meta.url));
506
+ var __dirname = path3.dirname(fileURLToPath(import.meta.url));
456
507
  var pkg = createRequire(import.meta.url)(
457
- path2.join(__dirname, "..", "package.json")
508
+ path3.join(__dirname, "..", "package.json")
458
509
  );
459
510
  var VERSION = pkg.version ?? "0.0.0";
460
511
  function readStdin() {
@@ -491,6 +542,8 @@ function parseArgs(argv) {
491
542
  flags.cursor = argv[++i];
492
543
  } else if (arg === "--call") {
493
544
  boolFlags.call = true;
545
+ } else if (arg === "--no-cache") {
546
+ boolFlags.noCache = true;
494
547
  } else if (arg === "--verbose") {
495
548
  boolFlags.verbose = true;
496
549
  } else if (arg === "--options" && i + 1 < argv.length) {
@@ -514,11 +567,12 @@ function parseArgs(argv) {
514
567
  cursor: flags.cursor,
515
568
  call: boolFlags.call ?? false,
516
569
  verbose: boolFlags.verbose ?? false,
570
+ noCache: boolFlags.noCache ?? false,
517
571
  options: flags.options
518
572
  };
519
573
  }
520
574
  function toToolName(service, action) {
521
- return `${service}.${action}`;
575
+ return `${service}__${action}`;
522
576
  }
523
577
  function formatToolsForList(tools, verbose) {
524
578
  if (verbose) {
@@ -558,6 +612,7 @@ Options:
558
612
  --skillset <name> Use a specific skill set
559
613
  --call Execute the skill (default is to fetch parameters only)
560
614
  --verbose Include inputSchema when listing skills
615
+ --no-cache Bypass the 5-minute tools list cache
561
616
  -i, --input <json> JSON input for call, parameters or options (alternative to stdin)
562
617
  --search <query> Search query for dynamic dropdown options
563
618
  --cursor <cursor> Pagination cursor for dynamic dropdown options
@@ -605,6 +660,7 @@ async function main() {
605
660
  cursor: cursorFlag,
606
661
  call: callFlag,
607
662
  verbose: verboseFlag,
663
+ noCache: noCacheFlag,
608
664
  options: optionsFlag
609
665
  } = parseArgs(process.argv.slice(2));
610
666
  if (subcommand === "help") {
@@ -758,7 +814,10 @@ async function main() {
758
814
  }
759
815
  if (subcommand === "list") {
760
816
  const service2 = args[0];
761
- const tools = await client.listTools({ service: service2 ?? void 0 });
817
+ const tools = await client.listTools({
818
+ service: service2 ?? void 0,
819
+ noCache: noCacheFlag
820
+ });
762
821
  const formatted = formatToolsForList(tools, verboseFlag);
763
822
  if (!tools.length) {
764
823
  die(
@@ -776,7 +835,7 @@ async function main() {
776
835
  return;
777
836
  }
778
837
  if (!action) {
779
- const tools = await client.listTools({ service });
838
+ const tools = await client.listTools({ service, noCache: noCacheFlag });
780
839
  if (!tools.length) {
781
840
  die(
782
841
  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.8",
4
4
  "description": "CLI for Stepper skill sets",
5
5
  "type": "module",
6
6
  "files": [
package/README.md DELETED
@@ -1,159 +0,0 @@
1
- # stpr — Stepper Skills CLI
2
-
3
- Skill Sets are a Stepper feature that let you bundle integration actions into curated, authenticated toolkits — and expose them to AI agents, CLIs, and any MCP-compatible client.
4
-
5
- `stpr` is a command-line interface for interacting with [Stepper](https://stepper.io) Skill Sets. Discover, inspect, and execute integration actions directly from your terminal. This is perfect for OpenClaw or agents that can interact with a CLI, or for developers who want to use skills in their own scripts.
6
-
7
- If you prefer, you can directly use the Stepper MCP server at `https://mcp.stepper.io/skill-sets/mcp`instead of the CLI.
8
-
9
- ## Installation
10
-
11
- ```bash
12
- npm install -g stpr
13
- ```
14
-
15
- ## Authentication
16
-
17
- The CLI supports three authentication methods:
18
-
19
- ### OAuth Login (recommended)
20
-
21
- ```bash
22
- stpr login
23
- ```
24
-
25
- Opens your browser to authenticate and select a Skill Set. Credentials are saved to `~/.config/stepper-skillsets/config.json` and automatically refreshed when they expire.
26
-
27
- ### Static Token
28
-
29
- Generate a token from [Stepper](https://app.stepper.io/flow/skill-sets) and pass it directly:
30
-
31
- ```bash
32
- stpr --token sst_your_token_here list
33
- ```
34
-
35
- ### Environment Variable
36
-
37
- ```bash
38
- export STEPPER_SKILL_TOKEN=sst_your_token_here
39
- stpr list
40
- ```
41
-
42
- ## Commands
43
-
44
- ### Profile Management
45
-
46
- ```bash
47
- stpr login # Authenticate via OAuth (opens browser)
48
- stpr logout [name] # Remove a saved profile, or all profiles if no name given
49
- stpr profiles # List all saved profiles
50
- stpr use <name> # Switch the active profile
51
- stpr whoami # Show active profile and server info
52
- ```
53
-
54
- ### Discovering Skills
55
-
56
- ```bash
57
- stpr list # List all available skills, grouped by service
58
- stpr list --verbose # Include full input schemas
59
- stpr list <service> # List skills for a specific service
60
- stpr <service> # Shorthand for listing a service's skills
61
- ```
62
-
63
- ### Inspecting Parameters
64
-
65
- Many skills have dynamic parameters — fields that change based on the values of other fields. Calling a skill without `--call` returns its current parameter schema.
66
-
67
- ```bash
68
- # See what fields are needed for add_row, given a spreadsheet
69
- stpr google-sheets add_row -i '{"spreadsheet_id": "abc123"}'
70
- ```
71
-
72
- Some parameters have dynamic dropdown options. Fetch them with `--options`:
73
-
74
- ```bash
75
- stpr google-sheets add_row --options worksheet_id \
76
- -i '{"spreadsheet_id": "abc123"}' \
77
- --search "Sheet" \
78
- --cursor "next_page"
79
- ```
80
-
81
- ### Calling Skills
82
-
83
- Use the `--call` flag to execute an action:
84
-
85
- ```bash
86
- stpr google-sheets create_sheet --call \
87
- -i '{"name": "Q1 Report", "columns": "Name, Email, Phone"}'
88
- ```
89
-
90
- ### Polling Async Results
91
-
92
- Component library tools run asynchronously. Poll for results with:
93
-
94
- ```bash
95
- stpr status <statusId>
96
- ```
97
-
98
- ## Input
99
-
100
- Pass JSON input via the `-i` / `--input` flag or pipe it through stdin:
101
-
102
- ```bash
103
- # Flag
104
- stpr slack send_message --call -i '{"channel": "#general", "text": "Hello!"}'
105
-
106
- # Stdin
107
- echo '{"channel": "#general", "text": "Hello!"}' | stpr slack send_message --call
108
- ```
109
-
110
- ## Options Reference
111
-
112
- | Flag | Description |
113
- | -------------------- | --------------------------------------------------------------- |
114
- | `--token <token>` | Auth token (overrides saved profiles and `STEPPER_SKILL_TOKEN`) |
115
- | `--base-url <url>` | Override MCP server URL (default: `https://mcp.stepper.io`) |
116
- | `--skillset <name>` | Use a specific saved profile instead of the active one |
117
- | `--call` | Execute the skill (default behavior is parameter inspection) |
118
- | `--verbose` | Include full `inputSchema` when listing skills |
119
- | `-i, --input <json>` | JSON input for calls, parameter fetches, or option queries |
120
- | `--options <param>` | Fetch dynamic dropdown options for a parameter |
121
- | `--search <query>` | Filter dropdown options by search term |
122
- | `--cursor <cursor>` | Pagination cursor for dropdown options |
123
- | `-h, --help` | Show help |
124
- | `-v, --version` | Show version |
125
-
126
- ## Environment Variables
127
-
128
- | Variable | Description |
129
- | --------------------- | ------------------------------------------------------------- |
130
- | `STEPPER_SKILL_TOKEN` | Auth token (used when no `--token` flag and no saved profile) |
131
- | `STEPPER_URL` | Override the MCP server base URL |
132
-
133
- ## Examples
134
-
135
- ```bash
136
- # Authenticate
137
- stpr login
138
-
139
- # List everything available
140
- stpr list
141
-
142
- # Explore a service
143
- stpr google-sheets
144
-
145
- # Inspect dynamic parameters step by step
146
- stpr google-sheets add_row -i '{}'
147
- stpr google-sheets add_row -i '{"spreadsheet_id": "abc123"}'
148
-
149
- # Fetch dropdown options
150
- stpr google-sheets add_row --options worksheet_id -i '{"spreadsheet_id": "abc123"}'
151
-
152
- # Execute
153
- stpr google-sheets add_row --call -i '{"spreadsheet_id": "abc123", "worksheet_id": "Sheet1", "values": {"Name": "Alice"}}'
154
-
155
- # Switch between skill sets
156
- stpr profiles
157
- stpr use "Production Tools"
158
- stpr list
159
- ```