hornerosssp 0.2.0 → 0.3.1
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/index.js +527 -0
- package/package.json +13 -2
|
@@ -0,0 +1,527 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
18
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
19
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
20
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
21
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
22
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
23
|
+
mod
|
|
24
|
+
));
|
|
25
|
+
|
|
26
|
+
// src/cli/index.ts
|
|
27
|
+
var import_commander7 = require("commander");
|
|
28
|
+
var import_chalk8 = __toESM(require("chalk"));
|
|
29
|
+
|
|
30
|
+
// src/cli/commands/login.ts
|
|
31
|
+
var import_commander = require("commander");
|
|
32
|
+
var import_chalk2 = __toESM(require("chalk"));
|
|
33
|
+
var import_inquirer = __toESM(require("inquirer"));
|
|
34
|
+
var import_open = __toESM(require("open"));
|
|
35
|
+
|
|
36
|
+
// src/cli/config.ts
|
|
37
|
+
var fs = __toESM(require("fs"));
|
|
38
|
+
var path = __toESM(require("path"));
|
|
39
|
+
var os = __toESM(require("os"));
|
|
40
|
+
var CONFIG_DIR = path.join(os.homedir(), ".hornerosssp");
|
|
41
|
+
var CONFIG_FILE = path.join(CONFIG_DIR, "userData.json");
|
|
42
|
+
function ensureConfigDir() {
|
|
43
|
+
if (!fs.existsSync(CONFIG_DIR)) {
|
|
44
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function getUserData() {
|
|
48
|
+
try {
|
|
49
|
+
if (fs.existsSync(CONFIG_FILE)) {
|
|
50
|
+
const content = fs.readFileSync(CONFIG_FILE, "utf-8");
|
|
51
|
+
return JSON.parse(content);
|
|
52
|
+
}
|
|
53
|
+
} catch {
|
|
54
|
+
}
|
|
55
|
+
return {};
|
|
56
|
+
}
|
|
57
|
+
function saveUserData(data) {
|
|
58
|
+
ensureConfigDir();
|
|
59
|
+
const existing = getUserData();
|
|
60
|
+
const merged = { ...existing, ...data };
|
|
61
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(merged, null, 2));
|
|
62
|
+
}
|
|
63
|
+
function clearUserData() {
|
|
64
|
+
if (fs.existsSync(CONFIG_FILE)) {
|
|
65
|
+
fs.unlinkSync(CONFIG_FILE);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function getApiKey() {
|
|
69
|
+
return process.env.HORNEROS_API_KEY || getUserData().api_key;
|
|
70
|
+
}
|
|
71
|
+
function getBaseUrl() {
|
|
72
|
+
return process.env.HORNEROS_BASE_URL || getUserData().base_url || "http://localhost:3000";
|
|
73
|
+
}
|
|
74
|
+
function setCliConfig(apiKey, baseUrl) {
|
|
75
|
+
const data = { api_key: apiKey };
|
|
76
|
+
if (baseUrl) {
|
|
77
|
+
data.base_url = baseUrl;
|
|
78
|
+
}
|
|
79
|
+
saveUserData(data);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// src/cli/client.ts
|
|
83
|
+
var import_chalk = __toESM(require("chalk"));
|
|
84
|
+
var ApiClient = class {
|
|
85
|
+
constructor() {
|
|
86
|
+
this.baseUrl = getBaseUrl();
|
|
87
|
+
this.apiKey = getApiKey();
|
|
88
|
+
}
|
|
89
|
+
async fetch(path2, options = {}) {
|
|
90
|
+
const url = `${this.baseUrl}/api/v1${path2}`;
|
|
91
|
+
const headers = {
|
|
92
|
+
"Content-Type": "application/json",
|
|
93
|
+
"X-Source": "cli",
|
|
94
|
+
...options.headers
|
|
95
|
+
};
|
|
96
|
+
if (this.apiKey) {
|
|
97
|
+
headers["X-Api-Key"] = this.apiKey;
|
|
98
|
+
}
|
|
99
|
+
const res = await globalThis.fetch(url, {
|
|
100
|
+
...options,
|
|
101
|
+
headers
|
|
102
|
+
});
|
|
103
|
+
if (!res.ok) {
|
|
104
|
+
let body;
|
|
105
|
+
try {
|
|
106
|
+
body = await res.json();
|
|
107
|
+
} catch {
|
|
108
|
+
body = await res.text().catch(() => null);
|
|
109
|
+
}
|
|
110
|
+
const message = (body && typeof body === "object" && "error" in body ? body.error : null) || `HTTP ${res.status}`;
|
|
111
|
+
throw new Error(message);
|
|
112
|
+
}
|
|
113
|
+
if (res.status === 204) {
|
|
114
|
+
return void 0;
|
|
115
|
+
}
|
|
116
|
+
const json = await res.json();
|
|
117
|
+
return json.data !== void 0 ? json.data : json;
|
|
118
|
+
}
|
|
119
|
+
// CLI Auth endpoints
|
|
120
|
+
async generateCliSession() {
|
|
121
|
+
return this.fetch("/cli/session", { method: "POST" });
|
|
122
|
+
}
|
|
123
|
+
async verifyCliCode(key, code) {
|
|
124
|
+
return this.fetch(`/cli/verify?key=${encodeURIComponent(key)}&code=${encodeURIComponent(code)}`);
|
|
125
|
+
}
|
|
126
|
+
// User endpoints
|
|
127
|
+
async getUserInfo() {
|
|
128
|
+
return this.fetch("/auth/me");
|
|
129
|
+
}
|
|
130
|
+
// Apps/MCPs endpoints
|
|
131
|
+
async listApps() {
|
|
132
|
+
return this.fetch("/mcps");
|
|
133
|
+
}
|
|
134
|
+
async getApp(slug) {
|
|
135
|
+
return this.fetch(`/mcps/${encodeURIComponent(slug)}`);
|
|
136
|
+
}
|
|
137
|
+
// Connections endpoints
|
|
138
|
+
async listConnections() {
|
|
139
|
+
return this.fetch("/connections");
|
|
140
|
+
}
|
|
141
|
+
async getConnection(id) {
|
|
142
|
+
return this.fetch(`/connections/${encodeURIComponent(id)}`);
|
|
143
|
+
}
|
|
144
|
+
async initiateConnection(mcpSlug, params) {
|
|
145
|
+
return this.fetch("/connections", {
|
|
146
|
+
method: "POST",
|
|
147
|
+
body: JSON.stringify({
|
|
148
|
+
mcp_slug: mcpSlug,
|
|
149
|
+
...params?.appName && { app_name: params.appName },
|
|
150
|
+
...params?.userId && { user_id: params.userId }
|
|
151
|
+
})
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
async revokeConnection(id) {
|
|
155
|
+
return this.fetch(`/connections/${encodeURIComponent(id)}`, { method: "DELETE" });
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
function getClient() {
|
|
159
|
+
return new ApiClient();
|
|
160
|
+
}
|
|
161
|
+
function requireAuth() {
|
|
162
|
+
const apiKey = getApiKey();
|
|
163
|
+
if (!apiKey) {
|
|
164
|
+
console.log(import_chalk.default.red("You are not authenticated. Please run `hornerosssp login` to authenticate."));
|
|
165
|
+
process.exit(1);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// src/cli/commands/login.ts
|
|
170
|
+
var FRONTEND_BASE_URL = "http://localhost:3000";
|
|
171
|
+
var loginCommand = new import_commander.Command("login").description("Authenticate and login to HornerosSSP").option("-n, --no-browser", "Don't open browser, manually copy the link").option("-k, --api-key <key>", "Provide API key directly").option("-u, --base-url <url>", "Base URL of HornerosSSP server").action(async (options) => {
|
|
172
|
+
if (options.apiKey) {
|
|
173
|
+
setCliConfig(options.apiKey, options.baseUrl);
|
|
174
|
+
console.log(import_chalk2.default.green("\n API key saved successfully!\n"));
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
const existingKey = getApiKey();
|
|
178
|
+
if (existingKey) {
|
|
179
|
+
console.log(import_chalk2.default.yellow("\n You are already authenticated!\n"));
|
|
180
|
+
const { shouldReauth } = await import_inquirer.default.prompt([{
|
|
181
|
+
type: "confirm",
|
|
182
|
+
name: "shouldReauth",
|
|
183
|
+
message: "Do you want to re-authenticate?",
|
|
184
|
+
default: false
|
|
185
|
+
}]);
|
|
186
|
+
if (!shouldReauth) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
try {
|
|
191
|
+
const client = getClient();
|
|
192
|
+
console.log(import_chalk2.default.dim("\n Generating login session...\n"));
|
|
193
|
+
const session = await client.generateCliSession();
|
|
194
|
+
const cliKey = session.key;
|
|
195
|
+
const baseUrl = options.baseUrl || getBaseUrl() || FRONTEND_BASE_URL;
|
|
196
|
+
const loginUrl = `${baseUrl}/cli-auth?cliKey=${cliKey}`;
|
|
197
|
+
console.log(import_chalk2.default.bold(" Please login using the following link:\n"));
|
|
198
|
+
console.log(` ${import_chalk2.default.cyan(loginUrl)}
|
|
199
|
+
`);
|
|
200
|
+
if (options.browser !== false) {
|
|
201
|
+
console.log(import_chalk2.default.dim(" Opening browser...\n"));
|
|
202
|
+
await (0, import_open.default)(loginUrl);
|
|
203
|
+
}
|
|
204
|
+
const { authCode } = await import_inquirer.default.prompt([{
|
|
205
|
+
type: "input",
|
|
206
|
+
name: "authCode",
|
|
207
|
+
message: "Enter the authentication code:"
|
|
208
|
+
}]);
|
|
209
|
+
console.log(import_chalk2.default.dim("\n Verifying code...\n"));
|
|
210
|
+
const result = await client.verifyCliCode(cliKey, authCode);
|
|
211
|
+
setCliConfig(result.apiKey, options.baseUrl);
|
|
212
|
+
console.log(import_chalk2.default.green(" You are now authenticated and ready to use HornerosSSP!\n"));
|
|
213
|
+
} catch (error) {
|
|
214
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
215
|
+
console.log(import_chalk2.default.red(`
|
|
216
|
+
Login failed: ${message}
|
|
217
|
+
`));
|
|
218
|
+
process.exit(1);
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
// src/cli/commands/logout.ts
|
|
223
|
+
var import_commander2 = require("commander");
|
|
224
|
+
var import_chalk3 = __toESM(require("chalk"));
|
|
225
|
+
var logoutCommand = new import_commander2.Command("logout").description("Clear authentication and logout from HornerosSSP").action(() => {
|
|
226
|
+
clearUserData();
|
|
227
|
+
console.log(import_chalk3.default.yellow("\n You have been logged out from HornerosSSP.\n"));
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
// src/cli/commands/whoami.ts
|
|
231
|
+
var import_commander3 = require("commander");
|
|
232
|
+
var import_chalk4 = __toESM(require("chalk"));
|
|
233
|
+
var whoamiCommand = new import_commander3.Command("whoami").description("Show current user info").action(async () => {
|
|
234
|
+
requireAuth();
|
|
235
|
+
try {
|
|
236
|
+
const client = getClient();
|
|
237
|
+
const user = await client.getUserInfo();
|
|
238
|
+
console.log(import_chalk4.default.bold("\n Current User\n"));
|
|
239
|
+
console.log(` ${import_chalk4.default.cyan("ID:")} ${user.id}`);
|
|
240
|
+
console.log(` ${import_chalk4.default.cyan("Email:")} ${user.email}`);
|
|
241
|
+
if (user.name) {
|
|
242
|
+
console.log(` ${import_chalk4.default.cyan("Name:")} ${user.name}`);
|
|
243
|
+
}
|
|
244
|
+
console.log(` ${import_chalk4.default.cyan("Server:")} ${getBaseUrl()}`);
|
|
245
|
+
console.log();
|
|
246
|
+
} catch (error) {
|
|
247
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
248
|
+
console.log(import_chalk4.default.red(`
|
|
249
|
+
Failed to get user info: ${message}
|
|
250
|
+
`));
|
|
251
|
+
process.exit(1);
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
// src/cli/commands/apps.ts
|
|
256
|
+
var import_commander4 = require("commander");
|
|
257
|
+
var import_chalk5 = __toESM(require("chalk"));
|
|
258
|
+
var appsCommand = new import_commander4.Command("apps").description("List available MCPs/apps").option("-s, --search <query>", "Search apps by name").action(async (options) => {
|
|
259
|
+
requireAuth();
|
|
260
|
+
try {
|
|
261
|
+
const client = getClient();
|
|
262
|
+
let apps = await client.listApps();
|
|
263
|
+
if (options.search) {
|
|
264
|
+
const query = options.search.toLowerCase();
|
|
265
|
+
apps = apps.filter(
|
|
266
|
+
(app) => app.name.toLowerCase().includes(query) || app.slug.toLowerCase().includes(query) || app.description && app.description.toLowerCase().includes(query)
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
if (apps.length === 0) {
|
|
270
|
+
console.log(import_chalk5.default.yellow("\n No apps found.\n"));
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
console.log(import_chalk5.default.bold(`
|
|
274
|
+
Available Apps (${apps.length})
|
|
275
|
+
`));
|
|
276
|
+
for (const app of apps) {
|
|
277
|
+
console.log(` ${import_chalk5.default.cyan(app.name)} ${import_chalk5.default.dim(`(${app.slug})`)}`);
|
|
278
|
+
if (app.description) {
|
|
279
|
+
console.log(` ${import_chalk5.default.dim(app.description)}`);
|
|
280
|
+
}
|
|
281
|
+
console.log(` ${import_chalk5.default.green(`${app.toolCount} tools`)} | ${import_chalk5.default.blue(`${app.activeConnections} connections`)}`);
|
|
282
|
+
console.log();
|
|
283
|
+
}
|
|
284
|
+
console.log(import_chalk5.default.dim(` Run ${import_chalk5.default.cyan("hornerosssp add <app-slug>")} to connect an app.
|
|
285
|
+
`));
|
|
286
|
+
} catch (error) {
|
|
287
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
288
|
+
console.log(import_chalk5.default.red(`
|
|
289
|
+
Failed to list apps: ${message}
|
|
290
|
+
`));
|
|
291
|
+
process.exit(1);
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
// src/cli/commands/add.ts
|
|
296
|
+
var import_commander5 = require("commander");
|
|
297
|
+
var import_chalk6 = __toESM(require("chalk"));
|
|
298
|
+
var import_inquirer2 = __toESM(require("inquirer"));
|
|
299
|
+
var import_open2 = __toESM(require("open"));
|
|
300
|
+
var addCommand = new import_commander5.Command("add").description("Connect a new app/MCP").argument("<app-slug>", "The slug of the app to connect (e.g., gmail, slack)").option("-n, --no-browser", "Don't open browser for OAuth").option("-l, --label <label>", "Label for this connection").option("-u, --user-id <userId>", "User ID for multi-tenant apps").action(async (appSlug, options) => {
|
|
301
|
+
requireAuth();
|
|
302
|
+
try {
|
|
303
|
+
const client = getClient();
|
|
304
|
+
console.log(import_chalk6.default.dim(`
|
|
305
|
+
Checking app "${appSlug}"...
|
|
306
|
+
`));
|
|
307
|
+
let app;
|
|
308
|
+
try {
|
|
309
|
+
app = await client.getApp(appSlug);
|
|
310
|
+
} catch {
|
|
311
|
+
console.log(import_chalk6.default.red(` App "${appSlug}" not found.
|
|
312
|
+
`));
|
|
313
|
+
console.log(import_chalk6.default.dim(` Run ${import_chalk6.default.cyan("hornerosssp apps")} to see available apps.
|
|
314
|
+
`));
|
|
315
|
+
process.exit(1);
|
|
316
|
+
}
|
|
317
|
+
console.log(` Connecting ${import_chalk6.default.cyan(app.name)}...
|
|
318
|
+
`);
|
|
319
|
+
const connections = await client.listConnections();
|
|
320
|
+
const existingConnection = connections.find((c) => c.mcpSlug === appSlug && c.status === "active");
|
|
321
|
+
if (existingConnection) {
|
|
322
|
+
const { shouldReconnect } = await import_inquirer2.default.prompt([{
|
|
323
|
+
type: "confirm",
|
|
324
|
+
name: "shouldReconnect",
|
|
325
|
+
message: `You already have an active connection to ${app.name}. Create a new one?`,
|
|
326
|
+
default: false
|
|
327
|
+
}]);
|
|
328
|
+
if (!shouldReconnect) {
|
|
329
|
+
console.log(import_chalk6.default.yellow("\n Connection cancelled.\n"));
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
const connectionRequest = await client.initiateConnection(appSlug, {
|
|
334
|
+
appName: options.label,
|
|
335
|
+
userId: options.userId
|
|
336
|
+
});
|
|
337
|
+
if (connectionRequest.redirectUrl) {
|
|
338
|
+
console.log(import_chalk6.default.bold(" Please authorize the connection:\n"));
|
|
339
|
+
console.log(` ${import_chalk6.default.cyan(connectionRequest.redirectUrl)}
|
|
340
|
+
`);
|
|
341
|
+
if (options.browser !== false) {
|
|
342
|
+
console.log(import_chalk6.default.dim(" Opening browser...\n"));
|
|
343
|
+
await (0, import_open2.default)(connectionRequest.redirectUrl);
|
|
344
|
+
}
|
|
345
|
+
console.log(import_chalk6.default.dim(" Waiting for authorization..."));
|
|
346
|
+
const timeout = 12e4;
|
|
347
|
+
const pollInterval = 3e3;
|
|
348
|
+
const startTime = Date.now();
|
|
349
|
+
while (Date.now() - startTime < timeout) {
|
|
350
|
+
await sleep(pollInterval);
|
|
351
|
+
try {
|
|
352
|
+
const connection = await client.getConnection(connectionRequest.id);
|
|
353
|
+
if (connection.status === "active") {
|
|
354
|
+
console.log(import_chalk6.default.green(`
|
|
355
|
+
Successfully connected to ${app.name}!
|
|
356
|
+
`));
|
|
357
|
+
console.log(` ${import_chalk6.default.cyan("Connection ID:")} ${connection.id}`);
|
|
358
|
+
console.log(` ${import_chalk6.default.cyan("MCP URL:")} ${connection.mcpUrl}
|
|
359
|
+
`);
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
} catch {
|
|
363
|
+
}
|
|
364
|
+
process.stdout.write(".");
|
|
365
|
+
}
|
|
366
|
+
console.log(import_chalk6.default.red("\n\n Connection timed out. Please try again.\n"));
|
|
367
|
+
process.exit(1);
|
|
368
|
+
} else {
|
|
369
|
+
console.log(import_chalk6.default.green(`
|
|
370
|
+
Successfully connected to ${app.name}!
|
|
371
|
+
`));
|
|
372
|
+
console.log(` ${import_chalk6.default.cyan("Connection ID:")} ${connectionRequest.id}`);
|
|
373
|
+
if (connectionRequest.mcpUrl) {
|
|
374
|
+
console.log(` ${import_chalk6.default.cyan("MCP URL:")} ${connectionRequest.mcpUrl}
|
|
375
|
+
`);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
} catch (error) {
|
|
379
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
380
|
+
console.log(import_chalk6.default.red(`
|
|
381
|
+
Failed to connect app: ${message}
|
|
382
|
+
`));
|
|
383
|
+
process.exit(1);
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
function sleep(ms) {
|
|
387
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// src/cli/commands/connections.ts
|
|
391
|
+
var import_commander6 = require("commander");
|
|
392
|
+
var import_chalk7 = __toESM(require("chalk"));
|
|
393
|
+
var import_inquirer3 = __toESM(require("inquirer"));
|
|
394
|
+
var connectionsCommand = new import_commander6.Command("connections").description("Manage your connections").action(async () => {
|
|
395
|
+
requireAuth();
|
|
396
|
+
try {
|
|
397
|
+
const client = getClient();
|
|
398
|
+
const connections = await client.listConnections();
|
|
399
|
+
if (connections.length === 0) {
|
|
400
|
+
console.log(import_chalk7.default.yellow("\n No connections found.\n"));
|
|
401
|
+
console.log(import_chalk7.default.dim(` Run ${import_chalk7.default.cyan("hornerosssp add <app>")} to connect an app.
|
|
402
|
+
`));
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
console.log(import_chalk7.default.bold(`
|
|
406
|
+
Your Connections (${connections.length})
|
|
407
|
+
`));
|
|
408
|
+
for (const conn of connections) {
|
|
409
|
+
const statusColor = conn.status === "active" ? import_chalk7.default.green : import_chalk7.default.red;
|
|
410
|
+
const statusIcon = conn.status === "active" ? "\u25CF" : "\u25CB";
|
|
411
|
+
console.log(` ${statusColor(statusIcon)} ${import_chalk7.default.cyan(conn.mcpName)} ${import_chalk7.default.dim(`(${conn.mcpSlug})`)}`);
|
|
412
|
+
console.log(` ${import_chalk7.default.dim("ID:")} ${conn.id}`);
|
|
413
|
+
if (conn.appName) {
|
|
414
|
+
console.log(` ${import_chalk7.default.dim("Label:")} ${conn.appName}`);
|
|
415
|
+
}
|
|
416
|
+
console.log(` ${import_chalk7.default.dim("Status:")} ${statusColor(conn.status)}`);
|
|
417
|
+
console.log(` ${import_chalk7.default.dim("Created:")} ${new Date(conn.createdAt).toLocaleDateString()}`);
|
|
418
|
+
if (conn.lastUsedAt) {
|
|
419
|
+
console.log(` ${import_chalk7.default.dim("Last used:")} ${new Date(conn.lastUsedAt).toLocaleDateString()}`);
|
|
420
|
+
}
|
|
421
|
+
console.log();
|
|
422
|
+
}
|
|
423
|
+
} catch (error) {
|
|
424
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
425
|
+
console.log(import_chalk7.default.red(`
|
|
426
|
+
Failed to list connections: ${message}
|
|
427
|
+
`));
|
|
428
|
+
process.exit(1);
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
connectionsCommand.command("get <id>").description("Get details of a specific connection").action(async (id) => {
|
|
432
|
+
requireAuth();
|
|
433
|
+
try {
|
|
434
|
+
const client = getClient();
|
|
435
|
+
const conn = await client.getConnection(id);
|
|
436
|
+
const statusColor = conn.status === "active" ? import_chalk7.default.green : import_chalk7.default.red;
|
|
437
|
+
console.log(import_chalk7.default.bold(`
|
|
438
|
+
Connection Details
|
|
439
|
+
`));
|
|
440
|
+
console.log(` ${import_chalk7.default.cyan("ID:")} ${conn.id}`);
|
|
441
|
+
console.log(` ${import_chalk7.default.cyan("App:")} ${conn.mcpName} (${conn.mcpSlug})`);
|
|
442
|
+
console.log(` ${import_chalk7.default.cyan("Status:")} ${statusColor(conn.status)}`);
|
|
443
|
+
if (conn.appName) {
|
|
444
|
+
console.log(` ${import_chalk7.default.cyan("Label:")} ${conn.appName}`);
|
|
445
|
+
}
|
|
446
|
+
if (conn.userId) {
|
|
447
|
+
console.log(` ${import_chalk7.default.cyan("User ID:")} ${conn.userId}`);
|
|
448
|
+
}
|
|
449
|
+
console.log(` ${import_chalk7.default.cyan("MCP URL:")} ${conn.mcpUrl}`);
|
|
450
|
+
console.log(` ${import_chalk7.default.cyan("Token:")} ${conn.token.substring(0, 20)}...`);
|
|
451
|
+
console.log(` ${import_chalk7.default.cyan("Created:")} ${new Date(conn.createdAt).toLocaleString()}`);
|
|
452
|
+
if (conn.lastUsedAt) {
|
|
453
|
+
console.log(` ${import_chalk7.default.cyan("Last used:")} ${new Date(conn.lastUsedAt).toLocaleString()}`);
|
|
454
|
+
}
|
|
455
|
+
if (conn.expiresAt) {
|
|
456
|
+
console.log(` ${import_chalk7.default.cyan("Expires:")} ${new Date(conn.expiresAt).toLocaleString()}`);
|
|
457
|
+
}
|
|
458
|
+
console.log();
|
|
459
|
+
} catch (error) {
|
|
460
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
461
|
+
console.log(import_chalk7.default.red(`
|
|
462
|
+
Failed to get connection: ${message}
|
|
463
|
+
`));
|
|
464
|
+
process.exit(1);
|
|
465
|
+
}
|
|
466
|
+
});
|
|
467
|
+
connectionsCommand.command("revoke <id>").description("Revoke a connection").option("-f, --force", "Skip confirmation").action(async (id, options) => {
|
|
468
|
+
requireAuth();
|
|
469
|
+
try {
|
|
470
|
+
const client = getClient();
|
|
471
|
+
const conn = await client.getConnection(id);
|
|
472
|
+
if (!options.force) {
|
|
473
|
+
const { confirm } = await import_inquirer3.default.prompt([{
|
|
474
|
+
type: "confirm",
|
|
475
|
+
name: "confirm",
|
|
476
|
+
message: `Are you sure you want to revoke the connection to ${conn.mcpName}?`,
|
|
477
|
+
default: false
|
|
478
|
+
}]);
|
|
479
|
+
if (!confirm) {
|
|
480
|
+
console.log(import_chalk7.default.yellow("\n Revoke cancelled.\n"));
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
await client.revokeConnection(id);
|
|
485
|
+
console.log(import_chalk7.default.green(`
|
|
486
|
+
Connection to ${conn.mcpName} has been revoked.
|
|
487
|
+
`));
|
|
488
|
+
} catch (error) {
|
|
489
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
490
|
+
console.log(import_chalk7.default.red(`
|
|
491
|
+
Failed to revoke connection: ${message}
|
|
492
|
+
`));
|
|
493
|
+
process.exit(1);
|
|
494
|
+
}
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
// src/cli/index.ts
|
|
498
|
+
var program = new import_commander7.Command();
|
|
499
|
+
program.name("hornerosssp").description("CLI for HornerosSSP - Connect MCPs to any app").version("0.3.1");
|
|
500
|
+
program.addCommand(loginCommand);
|
|
501
|
+
program.addCommand(logoutCommand);
|
|
502
|
+
program.addCommand(whoamiCommand);
|
|
503
|
+
program.addCommand(appsCommand);
|
|
504
|
+
program.addCommand(addCommand);
|
|
505
|
+
program.addCommand(connectionsCommand);
|
|
506
|
+
program.on("command:*", () => {
|
|
507
|
+
console.error(import_chalk8.default.red(`
|
|
508
|
+
Unknown command: ${program.args.join(" ")}`));
|
|
509
|
+
console.log(`Run ${import_chalk8.default.cyan("hornerosssp --help")} to see available commands.
|
|
510
|
+
`);
|
|
511
|
+
process.exit(1);
|
|
512
|
+
});
|
|
513
|
+
program.parse(process.argv);
|
|
514
|
+
if (!process.argv.slice(2).length) {
|
|
515
|
+
console.log(import_chalk8.default.bold("\n HornerosSSP CLI\n"));
|
|
516
|
+
console.log(" Connect MCPs to any application.\n");
|
|
517
|
+
console.log(import_chalk8.default.dim(" Commands:"));
|
|
518
|
+
console.log(` ${import_chalk8.default.cyan("login")} Authenticate with HornerosSSP`);
|
|
519
|
+
console.log(` ${import_chalk8.default.cyan("logout")} Remove stored credentials`);
|
|
520
|
+
console.log(` ${import_chalk8.default.cyan("whoami")} Show current user info`);
|
|
521
|
+
console.log(` ${import_chalk8.default.cyan("apps")} List available MCPs`);
|
|
522
|
+
console.log(` ${import_chalk8.default.cyan("add")} Connect a new app (OAuth flow)`);
|
|
523
|
+
console.log(` ${import_chalk8.default.cyan("connections")} Manage your connections
|
|
524
|
+
`);
|
|
525
|
+
console.log(` Run ${import_chalk8.default.cyan("hornerosssp <command> --help")} for more info.
|
|
526
|
+
`);
|
|
527
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hornerosssp",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "SDK for HornerosSSP - integrate MCPs into any app",
|
|
3
|
+
"version": "0.3.1",
|
|
4
|
+
"description": "SDK and CLI for HornerosSSP - integrate MCPs into any app",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
@@ -12,6 +12,9 @@
|
|
|
12
12
|
"require": "./dist/index.js"
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
|
+
"bin": {
|
|
16
|
+
"hornerosssp": "./dist/cli/index.js"
|
|
17
|
+
},
|
|
15
18
|
"files": [
|
|
16
19
|
"dist"
|
|
17
20
|
],
|
|
@@ -19,7 +22,15 @@
|
|
|
19
22
|
"build": "tsup",
|
|
20
23
|
"dev": "tsup --watch"
|
|
21
24
|
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"chalk": "^4.1.2",
|
|
27
|
+
"commander": "^12.1.0",
|
|
28
|
+
"inquirer": "^10.2.2",
|
|
29
|
+
"open": "^8.4.0"
|
|
30
|
+
},
|
|
22
31
|
"devDependencies": {
|
|
32
|
+
"@types/inquirer": "^9.0.7",
|
|
33
|
+
"composio-core": "^0.5.39",
|
|
23
34
|
"tsup": "^8.0.0",
|
|
24
35
|
"typescript": "^5.0.0"
|
|
25
36
|
},
|