premanmcp 0.5.0 → 0.7.0
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 +34 -16
- package/bin/api_tools.js +215 -0
- package/bin/cli.js +28 -2
- package/bin/connect.js +307 -24
- package/bin/integrations.js +367 -0
- package/bin/shared.js +5 -2
- package/dist/server.js +121 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ PreMan is agent-first API infrastructure. It lets backend teams expose endpoints
|
|
|
7
7
|
## Connect
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
|
|
10
|
+
npm exec -y premanmcp@latest -- connect
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
Pick your coding agent from the list — Cursor, Claude Code, or Codex — and PreMan
|
|
@@ -29,8 +29,8 @@ agent actually reads (`~/.cursor/mcp.json`, Claude Code's MCP config, or
|
|
|
29
29
|
{
|
|
30
30
|
"mcpServers": {
|
|
31
31
|
"preman": {
|
|
32
|
-
"command": "
|
|
33
|
-
"args": ["-y", "premanmcp@latest"],
|
|
32
|
+
"command": "npm",
|
|
33
|
+
"args": ["exec", "-y", "premanmcp@latest", "--"],
|
|
34
34
|
"env": {
|
|
35
35
|
"PREMAN_BACKEND": "https://api.preman.live",
|
|
36
36
|
"PREMAN_FRONTEND": "https://app.preman.live"
|
|
@@ -42,8 +42,21 @@ agent actually reads (`~/.cursor/mcp.json`, Claude Code's MCP config, or
|
|
|
42
42
|
|
|
43
43
|
Restart your agent afterwards, then ask it to `run preman_status` to finish linking.
|
|
44
44
|
|
|
45
|
+
`connect` reads the config back after writing it, and prints a copy-paste snippet if it
|
|
46
|
+
cannot confirm the entry landed. It then waits for your agent to check in — that
|
|
47
|
+
check-in is the only real proof the agent loaded the server.
|
|
48
|
+
|
|
49
|
+
Once the agent has checked in, `connect` walks you into your first test: it runs one
|
|
50
|
+
against an endpoint you already have, or prints the discovery brief to hand your agent,
|
|
51
|
+
followed by `preman endpoints setup` and `preman test`. Pass `--no-guide` to skip it.
|
|
52
|
+
|
|
45
53
|
Useful flags: `--agent cursor|claude-code|codex` skips the picker, `--project` writes
|
|
46
|
-
project-local config, `--print` shows the config without writing it
|
|
54
|
+
project-local config, `--print` shows the config without writing it, `--no-guide` skips
|
|
55
|
+
the guided first run.
|
|
56
|
+
|
|
57
|
+
In CI or any non-interactive shell, run `connect --agent <name> --api-key pm_live_…`.
|
|
58
|
+
Without `--agent` there is nothing to prompt on, so `connect` prints ready-to-paste
|
|
59
|
+
setup blocks for all three agents and exits 2.
|
|
47
60
|
|
|
48
61
|
`preman install` still exists and does the Cursor-only half of this.
|
|
49
62
|
|
|
@@ -63,13 +76,13 @@ npm exec -y premanmcp@latest -- login
|
|
|
63
76
|
You can also pass the key directly:
|
|
64
77
|
|
|
65
78
|
```bash
|
|
66
|
-
|
|
79
|
+
npm exec -y premanmcp@latest -- connect --api-key pm_live_xxx
|
|
67
80
|
```
|
|
68
81
|
|
|
69
82
|
For project-local config:
|
|
70
83
|
|
|
71
84
|
```bash
|
|
72
|
-
|
|
85
|
+
npm exec -y premanmcp@latest -- connect --project
|
|
73
86
|
```
|
|
74
87
|
|
|
75
88
|
## What It Does
|
|
@@ -82,6 +95,7 @@ npx premanmcp@latest connect --project
|
|
|
82
95
|
- Supports hosted MCPs with consumer tokens for customer-facing agent access.
|
|
83
96
|
- Records per-call observability so teams can audit which agent did what.
|
|
84
97
|
- Hands failing-endpoint alerts to your agent as fix tasks (`preman_get_fix_task` → repro curl → `preman_complete_fix_task`).
|
|
98
|
+
- Connects your production logs from the terminal (`connect_logs`): your agent asks where the logs live, then deploys a read-only CloudFormation role for AWS, or wires a shipper to the ingest endpoint for everything else.
|
|
85
99
|
|
|
86
100
|
## Common Agent Commands
|
|
87
101
|
|
|
@@ -111,10 +125,14 @@ Show me the audit log for this hosted MCP.
|
|
|
111
125
|
Pull my pending PreMan fix tasks and fix the failing endpoint.
|
|
112
126
|
```
|
|
113
127
|
|
|
128
|
+
```text
|
|
129
|
+
Connect my production logs to PreMan.
|
|
130
|
+
```
|
|
131
|
+
|
|
114
132
|
## Cursor
|
|
115
133
|
|
|
116
134
|
```bash
|
|
117
|
-
|
|
135
|
+
npm exec -y premanmcp@latest -- connect --agent cursor
|
|
118
136
|
```
|
|
119
137
|
|
|
120
138
|
Manual Cursor config, if you would rather write it yourself:
|
|
@@ -123,8 +141,8 @@ Manual Cursor config, if you would rather write it yourself:
|
|
|
123
141
|
{
|
|
124
142
|
"mcpServers": {
|
|
125
143
|
"preman": {
|
|
126
|
-
"command": "
|
|
127
|
-
"args": ["-y", "premanmcp@latest"]
|
|
144
|
+
"command": "npm",
|
|
145
|
+
"args": ["exec", "-y", "premanmcp@latest", "--"]
|
|
128
146
|
}
|
|
129
147
|
}
|
|
130
148
|
}
|
|
@@ -133,19 +151,19 @@ Manual Cursor config, if you would rather write it yourself:
|
|
|
133
151
|
## Claude Code
|
|
134
152
|
|
|
135
153
|
```bash
|
|
136
|
-
|
|
154
|
+
npm exec -y premanmcp@latest -- connect --agent claude-code
|
|
137
155
|
```
|
|
138
156
|
|
|
139
157
|
Equivalent manual command:
|
|
140
158
|
|
|
141
159
|
```bash
|
|
142
|
-
claude mcp add preman --
|
|
160
|
+
claude mcp add preman -- npm exec -y premanmcp@latest --
|
|
143
161
|
```
|
|
144
162
|
|
|
145
163
|
## Codex
|
|
146
164
|
|
|
147
165
|
```bash
|
|
148
|
-
|
|
166
|
+
npm exec -y premanmcp@latest -- connect --agent codex
|
|
149
167
|
```
|
|
150
168
|
|
|
151
169
|
Writes an `[mcp_servers.preman]` block into `~/.codex/config.toml`.
|
|
@@ -153,10 +171,10 @@ Writes an `[mcp_servers.preman]` block into `~/.codex/config.toml`.
|
|
|
153
171
|
## CLI
|
|
154
172
|
|
|
155
173
|
```bash
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
174
|
+
npm exec -y premanmcp@latest -- connect # Pick an agent and connect it
|
|
175
|
+
npm exec -y premanmcp@latest -- connect --agent codex # Skip the picker
|
|
176
|
+
npm exec -y premanmcp@latest -- connect --project # Write project-local config
|
|
177
|
+
npm exec -y premanmcp@latest -- connect --print # Print config without writing
|
|
160
178
|
npm exec -y premanmcp@latest -- # Start the MCP server
|
|
161
179
|
npm exec -y premanmcp@latest -- login # Create/login and generate a PreMan API key
|
|
162
180
|
npm exec -y premanmcp@latest -- install # Cursor-only installer (legacy)
|
package/bin/api_tools.js
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `preman endpoints` and `preman test` — the API-testing surface of the CLI.
|
|
3
|
+
*
|
|
4
|
+
* Both are thin proxies over `POST /mcp/call-tool`, exactly like the MCP
|
|
5
|
+
* server's tools, so the CLI and an agent calling the same tool see identical
|
|
6
|
+
* behaviour. Requires a pm_live_ key (flag, env, or stored credentials).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { readFileSync } from "node:fs";
|
|
10
|
+
|
|
11
|
+
import { callBackendJson, makeArgs, resolveApiKey } from "./shared.js";
|
|
12
|
+
|
|
13
|
+
export const ENDPOINTS_HELP = `
|
|
14
|
+
Endpoints:
|
|
15
|
+
preman endpoints list [--status s] [--method m] [--workbench] [--json-out]
|
|
16
|
+
List endpoints saved in PreMan (add --workbench for runnable requests).
|
|
17
|
+
preman endpoints discover [--framework hint]
|
|
18
|
+
Print the codebase-discovery brief for your coding agent to execute.
|
|
19
|
+
preman endpoints setup (--file endpoints.json | --ids id1,id2) [--base-url url] [--no-workbench]
|
|
20
|
+
Register discovered endpoints and set them up as runnable requests.
|
|
21
|
+
`;
|
|
22
|
+
|
|
23
|
+
export const TEST_HELP = `
|
|
24
|
+
Testing:
|
|
25
|
+
preman test <request-or-endpoint-id> [options]
|
|
26
|
+
Generate scenario tests for one endpoint and run them.
|
|
27
|
+
--scenario "..." Add a described scenario (repeatable)
|
|
28
|
+
--no-run Generate only, don't execute
|
|
29
|
+
--allow-writes Permit mutating cases / write endpoints
|
|
30
|
+
--code Emit unit-test files (prints filename + content)
|
|
31
|
+
--framework pytest|jest Framework for --code (default pytest)
|
|
32
|
+
--stress Run a bounded load test instead
|
|
33
|
+
--duration n --rps n --concurrency n Stress parameters
|
|
34
|
+
--json-out Print the raw JSON result
|
|
35
|
+
`;
|
|
36
|
+
|
|
37
|
+
class CliError extends Error {
|
|
38
|
+
constructor(message, exitCode = 1) {
|
|
39
|
+
super(message);
|
|
40
|
+
this.exitCode = exitCode;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export async function callTool(args, tool, toolArguments) {
|
|
45
|
+
const token = resolveApiKey(args);
|
|
46
|
+
if (!token) {
|
|
47
|
+
throw new CliError(
|
|
48
|
+
"No PreMan API key. Run `preman login` or pass --api-key pm_live_...",
|
|
49
|
+
2,
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
const result = await callBackendJson(args, "POST", "/mcp/call-tool", {
|
|
53
|
+
json: { tool, arguments: toolArguments },
|
|
54
|
+
token,
|
|
55
|
+
});
|
|
56
|
+
if (!result.ok) {
|
|
57
|
+
const detail = result.detail || result.message || result.raw || "backend error";
|
|
58
|
+
throw new CliError(`${tool} failed: ${result.status_code} ${detail}`);
|
|
59
|
+
}
|
|
60
|
+
return result;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function printJson(value) {
|
|
64
|
+
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function collectRepeated(commandArgs, flag) {
|
|
68
|
+
const out = [];
|
|
69
|
+
for (let i = 0; i < commandArgs.length; i += 1) {
|
|
70
|
+
if (commandArgs[i] === flag && commandArgs[i + 1]) out.push(commandArgs[i + 1]);
|
|
71
|
+
}
|
|
72
|
+
return out;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export async function endpointsCommand(commandArgs) {
|
|
76
|
+
const sub = commandArgs[0] && !commandArgs[0].startsWith("-") ? commandArgs[0] : "list";
|
|
77
|
+
const rest = sub === commandArgs[0] ? commandArgs.slice(1) : commandArgs;
|
|
78
|
+
const args = makeArgs(rest);
|
|
79
|
+
|
|
80
|
+
if (sub === "list") {
|
|
81
|
+
const toolArguments = {
|
|
82
|
+
status: args.value("--status", "") || undefined,
|
|
83
|
+
method: args.value("--method", "") || undefined,
|
|
84
|
+
include_workbench: args.has("--workbench"),
|
|
85
|
+
limit: Number(args.value("--limit", "50")),
|
|
86
|
+
};
|
|
87
|
+
const result = await callTool(args, "get_endpoints", toolArguments);
|
|
88
|
+
if (args.has("--json-out")) return printJson(result);
|
|
89
|
+
const rows = result.endpoints || [];
|
|
90
|
+
process.stdout.write(`${rows.length} registry endpoint(s)\n`);
|
|
91
|
+
for (const ep of rows) {
|
|
92
|
+
const status = ep.status ? ` [${ep.status}]` : "";
|
|
93
|
+
process.stdout.write(` ${ep.method || "GET"} ${ep.path_template || ep.url || ""}${status} ${ep.id || ""}\n`);
|
|
94
|
+
}
|
|
95
|
+
const workbench = result.workbench_requests || [];
|
|
96
|
+
if (workbench.length) {
|
|
97
|
+
process.stdout.write(`${workbench.length} runnable workbench request(s)\n`);
|
|
98
|
+
for (const r of workbench) {
|
|
99
|
+
process.stdout.write(` ${r.method} ${r.url} ${r.id}\n`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return undefined;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (sub === "discover") {
|
|
106
|
+
const result = await callTool(args, "discover_endpoints_from_codebase", {
|
|
107
|
+
base_path: args.value("--path", "."),
|
|
108
|
+
framework_hint: args.value("--framework", "") || undefined,
|
|
109
|
+
});
|
|
110
|
+
if (args.has("--json-out")) return printJson(result);
|
|
111
|
+
for (const line of result.instructions || []) process.stdout.write(`${line}\n`);
|
|
112
|
+
process.stdout.write(
|
|
113
|
+
"\nHand this brief to your coding agent, then run `preman endpoints setup --file endpoints.json`.\n",
|
|
114
|
+
);
|
|
115
|
+
return undefined;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (sub === "setup") {
|
|
119
|
+
const file = args.value("--file", "");
|
|
120
|
+
const ids = args.value("--ids", "");
|
|
121
|
+
const toolArguments = {
|
|
122
|
+
base_url: args.value("--base-url", "") || undefined,
|
|
123
|
+
setup_workbench: !args.has("--no-workbench"),
|
|
124
|
+
};
|
|
125
|
+
if (file) {
|
|
126
|
+
let parsed;
|
|
127
|
+
try {
|
|
128
|
+
parsed = JSON.parse(readFileSync(file, "utf8"));
|
|
129
|
+
} catch (error) {
|
|
130
|
+
throw new CliError(`could not read ${file}: ${error.message}`, 2);
|
|
131
|
+
}
|
|
132
|
+
toolArguments.endpoints = Array.isArray(parsed) ? parsed : parsed.endpoints;
|
|
133
|
+
} else if (ids) {
|
|
134
|
+
toolArguments.endpoint_ids = ids.split(",").map((s) => s.trim()).filter(Boolean);
|
|
135
|
+
} else {
|
|
136
|
+
throw new CliError("pass --file endpoints.json or --ids id1,id2", 2);
|
|
137
|
+
}
|
|
138
|
+
const result = await callTool(args, "register_discovered_endpoints", toolArguments);
|
|
139
|
+
if (args.has("--json-out")) return printJson(result);
|
|
140
|
+
process.stdout.write(
|
|
141
|
+
`registered ${result.registered || 0} endpoint(s), skipped ${result.skipped || 0}\n`,
|
|
142
|
+
);
|
|
143
|
+
const requests = result.workbench_request_ids || [];
|
|
144
|
+
if (requests.length) {
|
|
145
|
+
process.stdout.write(`runnable as: ${requests.join(", ")}\n`);
|
|
146
|
+
}
|
|
147
|
+
return undefined;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
throw new CliError(`unknown endpoints subcommand: ${sub}${ENDPOINTS_HELP}`, 2);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** Print the scenario list and run outcome from generate_endpoint_tests. */
|
|
154
|
+
export function printTestSummary(result) {
|
|
155
|
+
process.stdout.write(`${result.count || 0} scenario(s) for ${result.request_id}\n`);
|
|
156
|
+
for (const c of result.cases || []) {
|
|
157
|
+
process.stdout.write(` - ${c.name} (${c.kind})\n`);
|
|
158
|
+
}
|
|
159
|
+
const run = result.run;
|
|
160
|
+
if (!run) return;
|
|
161
|
+
process.stdout.write(
|
|
162
|
+
`run ${run.status}: ${run.passed}/${run.total} passed, ${run.skipped} skipped` +
|
|
163
|
+
`${run.aborted_reason ? `, aborted: ${run.aborted_reason}` : ""}\n`,
|
|
164
|
+
);
|
|
165
|
+
for (const o of run.outcomes || []) {
|
|
166
|
+
if (o.status !== "passed") {
|
|
167
|
+
process.stdout.write(` FAIL ${o.case_name}: ${o.response_status ?? o.error ?? ""}\n`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export async function testCommand(commandArgs) {
|
|
173
|
+
const target = commandArgs[0] && !commandArgs[0].startsWith("-") ? commandArgs[0] : "";
|
|
174
|
+
const rest = target ? commandArgs.slice(1) : commandArgs;
|
|
175
|
+
const args = makeArgs(rest);
|
|
176
|
+
if (!target) {
|
|
177
|
+
throw new CliError(`pass a request or endpoint id${TEST_HELP}`, 2);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (args.has("--stress")) {
|
|
181
|
+
const result = await callTool(args, "run_stress_test", {
|
|
182
|
+
target,
|
|
183
|
+
duration_seconds: Number(args.value("--duration", "15")),
|
|
184
|
+
rps: Number(args.value("--rps", "5")),
|
|
185
|
+
concurrency: Number(args.value("--concurrency", "5")),
|
|
186
|
+
allow_writes: args.has("--allow-writes"),
|
|
187
|
+
});
|
|
188
|
+
if (args.has("--json-out")) return printJson(result);
|
|
189
|
+
process.stdout.write(
|
|
190
|
+
`stress ${result.status}: ${result.total_requests} requests, ` +
|
|
191
|
+
`${Math.round((result.error_rate || 0) * 1000) / 10}% errors, ` +
|
|
192
|
+
`p50 ${result.p50_ms ?? "n/a"}ms p95 ${result.p95_ms ?? "n/a"}ms p99 ${result.p99_ms ?? "n/a"}ms, ` +
|
|
193
|
+
`${Math.round((result.throughput_rps || 0) * 10) / 10} rps\n`,
|
|
194
|
+
);
|
|
195
|
+
if (result.aborted_reason) process.stdout.write(`aborted: ${result.aborted_reason}\n`);
|
|
196
|
+
return undefined;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const result = await callTool(args, "generate_endpoint_tests", {
|
|
200
|
+
target,
|
|
201
|
+
scenarios: collectRepeated(rest, "--scenario"),
|
|
202
|
+
run: !args.has("--no-run"),
|
|
203
|
+
allow_writes: args.has("--allow-writes"),
|
|
204
|
+
max_cases: Number(args.value("--max-cases", "10")),
|
|
205
|
+
include_code: args.has("--code"),
|
|
206
|
+
test_framework: args.value("--framework", "pytest"),
|
|
207
|
+
});
|
|
208
|
+
if (args.has("--json-out")) return printJson(result);
|
|
209
|
+
|
|
210
|
+
printTestSummary(result);
|
|
211
|
+
for (const artifact of result.code_artifacts || []) {
|
|
212
|
+
process.stdout.write(`\n===== ${artifact.filename} =====\n${artifact.content}\n`);
|
|
213
|
+
}
|
|
214
|
+
return undefined;
|
|
215
|
+
}
|
package/bin/cli.js
CHANGED
|
@@ -16,7 +16,15 @@ import os from "node:os";
|
|
|
16
16
|
import path from "node:path";
|
|
17
17
|
import { fileURLToPath } from "node:url";
|
|
18
18
|
|
|
19
|
+
import { ENDPOINTS_HELP, TEST_HELP, endpointsCommand, testCommand } from "./api_tools.js";
|
|
19
20
|
import { CONNECT_HELP, connectCommand, writeCursorConfig } from "./connect.js";
|
|
21
|
+
import {
|
|
22
|
+
INTEGRATIONS_HELP,
|
|
23
|
+
awsCommand,
|
|
24
|
+
githubCommand,
|
|
25
|
+
onboardCommand,
|
|
26
|
+
slackCommand,
|
|
27
|
+
} from "./integrations.js";
|
|
20
28
|
import { HOSTED_HELP, linkCommand, runCommand, toolsCommand } from "./hosted.js";
|
|
21
29
|
import {
|
|
22
30
|
CREDENTIALS_FILE,
|
|
@@ -53,12 +61,16 @@ function printHelp() {
|
|
|
53
61
|
process.stdout.write(`PreMan MCP
|
|
54
62
|
|
|
55
63
|
Usage:
|
|
64
|
+
preman onboard Sign in, then connect agent, GitHub, AWS, Slack
|
|
56
65
|
preman connect [options] Pick a coding agent and connect it
|
|
66
|
+
preman aws | github | slack Connect one integration on its own
|
|
57
67
|
npm exec -y premanmcp@latest -- login Create/login to PreMan from the terminal
|
|
58
68
|
npm exec -y premanmcp@latest -- install [options] Install PreMan into Cursor MCP config
|
|
59
69
|
npm exec -y premanmcp@latest -- Start the PreMan MCP server
|
|
60
70
|
preman link|tools|run ... Drive a published hosted MCP
|
|
61
|
-
|
|
71
|
+
preman endpoints list|discover|setup ... Discover, list, and set up API endpoints
|
|
72
|
+
preman test <id> [--scenario ...] [--stress] Generate + run tests for an endpoint
|
|
73
|
+
${INTEGRATIONS_HELP}${CONNECT_HELP}${ENDPOINTS_HELP}${TEST_HELP}
|
|
62
74
|
Login options:
|
|
63
75
|
--email <email> Pre-fill the email prompt
|
|
64
76
|
--backend <url> PreMan backend URL. Defaults to ${DEFAULT_BACKEND}
|
|
@@ -74,7 +86,7 @@ Install options (Cursor only — prefer 'preman connect'):
|
|
|
74
86
|
--print Print the config instead of writing it
|
|
75
87
|
|
|
76
88
|
Examples:
|
|
77
|
-
|
|
89
|
+
npm exec -y premanmcp@latest -- connect
|
|
78
90
|
preman connect --agent claude-code
|
|
79
91
|
npm exec -y premanmcp@latest -- login
|
|
80
92
|
npm exec -y premanmcp@latest -- install --project --backend http://127.0.0.1:8000
|
|
@@ -167,6 +179,16 @@ async function main() {
|
|
|
167
179
|
await loginCommand();
|
|
168
180
|
} else if (command === "connect") {
|
|
169
181
|
await connectCommand(commandArgs);
|
|
182
|
+
} else if (command === "onboard" || command === "setup") {
|
|
183
|
+
// makeArgs/authenticateTerminal/connectCommand are injected rather than
|
|
184
|
+
// imported there, so integrations.js stays free of a cycle back into the CLI.
|
|
185
|
+
await onboardCommand(commandArgs, { makeArgs, authenticateTerminal, connectCommand });
|
|
186
|
+
} else if (command === "aws") {
|
|
187
|
+
await awsCommand(makeArgs(commandArgs));
|
|
188
|
+
} else if (command === "github") {
|
|
189
|
+
await githubCommand(makeArgs(commandArgs));
|
|
190
|
+
} else if (command === "slack") {
|
|
191
|
+
await slackCommand(makeArgs(commandArgs));
|
|
170
192
|
} else if (command === "install") {
|
|
171
193
|
await installCursorMcp();
|
|
172
194
|
} else if (command === "link") {
|
|
@@ -175,6 +197,10 @@ async function main() {
|
|
|
175
197
|
await toolsCommand(commandArgs);
|
|
176
198
|
} else if (command === "run") {
|
|
177
199
|
await runCommand(commandArgs);
|
|
200
|
+
} else if (command === "endpoints") {
|
|
201
|
+
await endpointsCommand(commandArgs);
|
|
202
|
+
} else if (command === "test") {
|
|
203
|
+
await testCommand(commandArgs);
|
|
178
204
|
} else if (command === "help" || command === "--help" || command === "-h") {
|
|
179
205
|
printHelp();
|
|
180
206
|
} else if (command === "start") {
|