omnikey-cli 1.0.38 → 1.0.40

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.
@@ -0,0 +1,334 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.mcpAdd = mcpAdd;
7
+ exports.mcpList = mcpList;
8
+ exports.mcpRemove = mcpRemove;
9
+ exports.mcpToggle = mcpToggle;
10
+ exports.mcpUpdate = mcpUpdate;
11
+ const axios_1 = __importDefault(require("axios"));
12
+ const inquirer_1 = __importDefault(require("inquirer"));
13
+ const utils_1 = require("./utils");
14
+ async function getJwt() {
15
+ const config = (0, utils_1.readConfig)();
16
+ const port = (0, utils_1.getPort)();
17
+ const licenseKey = config.OMNIKEY_LICENSE_KEY || '';
18
+ const baseUrl = `http://localhost:${port}`;
19
+ const res = await axios_1.default.post(`${baseUrl}/api/subscription/activate`, { licenseKey }, { timeout: 10000 });
20
+ return res.data.token;
21
+ }
22
+ function getBaseUrl() {
23
+ return `http://localhost:${(0, utils_1.getPort)()}`;
24
+ }
25
+ async function authHeaders() {
26
+ let token;
27
+ try {
28
+ token = await getJwt();
29
+ }
30
+ catch (err) {
31
+ throw new Error(`Authentication failed — make sure the OmniKey backend is running and your license key is configured.\nCause: ${err?.message ?? String(err)}`);
32
+ }
33
+ return { Authorization: `Bearer ${token}` };
34
+ }
35
+ function parseLines(input) {
36
+ return input
37
+ .split('\n')
38
+ .map((l) => l.trim())
39
+ .filter((l) => l.length > 0);
40
+ }
41
+ function parseKeyValueLines(input) {
42
+ const out = {};
43
+ for (const line of parseLines(input)) {
44
+ const idx = line.indexOf('=');
45
+ if (idx <= 0)
46
+ continue;
47
+ const key = line.slice(0, idx).trim();
48
+ const value = line.slice(idx + 1).trim();
49
+ if (key)
50
+ out[key] = value;
51
+ }
52
+ return out;
53
+ }
54
+ async function promptTransportFields(transport, defaults) {
55
+ if (transport === 'stdio') {
56
+ const ans = await inquirer_1.default.prompt([
57
+ {
58
+ type: 'input',
59
+ name: 'command',
60
+ message: 'Command (executable path or name):',
61
+ default: defaults?.command ?? '',
62
+ validate: (v) => v.trim().length > 0 || 'Command is required for stdio transport',
63
+ },
64
+ {
65
+ type: 'editor',
66
+ name: 'args',
67
+ message: 'Args (one per line):',
68
+ default: (defaults?.args ?? []).join('\n'),
69
+ },
70
+ {
71
+ type: 'editor',
72
+ name: 'env',
73
+ message: 'Environment variables (one KEY=VALUE per line):',
74
+ default: formatKVForEditor(defaults?.env),
75
+ },
76
+ ]);
77
+ return {
78
+ command: ans.command.trim(),
79
+ args: parseLines(ans.args),
80
+ env: parseKeyValueLines(ans.env),
81
+ url: null,
82
+ headers: {},
83
+ };
84
+ }
85
+ const ans = await inquirer_1.default.prompt([
86
+ {
87
+ type: 'input',
88
+ name: 'url',
89
+ message: `URL for ${transport} transport:`,
90
+ default: defaults?.url ?? '',
91
+ validate: (v) => v.trim().length > 0 || 'URL is required',
92
+ },
93
+ {
94
+ type: 'editor',
95
+ name: 'headers',
96
+ message: 'Headers (one KEY=VALUE per line):',
97
+ default: formatKVForEditor(defaults?.headers),
98
+ },
99
+ ]);
100
+ return {
101
+ url: ans.url.trim(),
102
+ headers: parseKeyValueLines(ans.headers),
103
+ command: null,
104
+ args: [],
105
+ env: {},
106
+ };
107
+ }
108
+ function formatKVForEditor(dict) {
109
+ if (!dict)
110
+ return '';
111
+ return Object.entries(dict)
112
+ .map(([k, v]) => `${k}=${v}`)
113
+ .join('\n');
114
+ }
115
+ async function mcpAdd() {
116
+ const baseAnswers = await inquirer_1.default.prompt([
117
+ {
118
+ type: 'input',
119
+ name: 'name',
120
+ message: 'Name (unique, e.g. "github"):',
121
+ validate: (v) => v.trim().length > 0 || 'Name is required',
122
+ },
123
+ {
124
+ type: 'input',
125
+ name: 'description',
126
+ message: 'Description (optional):',
127
+ },
128
+ {
129
+ type: 'list',
130
+ name: 'transport',
131
+ message: 'Transport:',
132
+ choices: [
133
+ { name: 'stdio (local process)', value: 'stdio' },
134
+ { name: 'http', value: 'http' },
135
+ { name: 'sse', value: 'sse' },
136
+ ],
137
+ default: 'stdio',
138
+ },
139
+ {
140
+ type: 'confirm',
141
+ name: 'isEnabled',
142
+ message: 'Enabled?',
143
+ default: true,
144
+ },
145
+ ]);
146
+ const transportFields = await promptTransportFields(baseAnswers.transport);
147
+ try {
148
+ const headers = await authHeaders();
149
+ const res = await axios_1.default.post(`${getBaseUrl()}/api/mcp-servers`, {
150
+ name: baseAnswers.name.trim(),
151
+ description: baseAnswers.description.trim() || null,
152
+ transport: baseAnswers.transport,
153
+ isEnabled: baseAnswers.isEnabled,
154
+ ...transportFields,
155
+ }, { headers, timeout: 15000 });
156
+ console.log('\nMCP server created:');
157
+ printServer(res.data);
158
+ }
159
+ catch (err) {
160
+ const msg = err.response?.data?.error ?? err.message;
161
+ console.error(`Error creating MCP server: ${msg}`);
162
+ }
163
+ }
164
+ async function mcpList() {
165
+ try {
166
+ const headers = await authHeaders();
167
+ const res = await axios_1.default.get(`${getBaseUrl()}/api/mcp-servers`, {
168
+ headers,
169
+ timeout: 10000,
170
+ });
171
+ const { servers } = res.data;
172
+ if (servers.length === 0) {
173
+ console.log('No MCP servers installed.');
174
+ return;
175
+ }
176
+ console.log('\nMCP Servers:');
177
+ console.log('─'.repeat(90));
178
+ console.log(padRight('ID', 28) +
179
+ padRight('Name', 22) +
180
+ padRight('Transport', 12) +
181
+ padRight('Enabled', 10) +
182
+ 'Endpoint');
183
+ console.log('─'.repeat(90));
184
+ for (const s of servers) {
185
+ const endpoint = s.transport === 'stdio' ? (s.command ?? '—') : (s.url ?? '—');
186
+ console.log(padRight(s.id.slice(0, 26), 28) +
187
+ padRight(s.name.slice(0, 20), 22) +
188
+ padRight(s.transport, 12) +
189
+ padRight(s.isEnabled ? 'yes' : 'no', 10) +
190
+ endpoint.slice(0, 40));
191
+ }
192
+ console.log('─'.repeat(90));
193
+ }
194
+ catch (err) {
195
+ const msg = err.response?.data?.error ?? err.message;
196
+ console.error(`Error fetching MCP servers: ${msg}`);
197
+ }
198
+ }
199
+ async function pickServer(action) {
200
+ const headers = await authHeaders();
201
+ const res = await axios_1.default.get(`${getBaseUrl()}/api/mcp-servers`, {
202
+ headers,
203
+ timeout: 10000,
204
+ });
205
+ const { servers } = res.data;
206
+ if (servers.length === 0) {
207
+ console.log(`No MCP servers to ${action}.`);
208
+ return null;
209
+ }
210
+ const { id } = await inquirer_1.default.prompt([
211
+ {
212
+ type: 'list',
213
+ name: 'id',
214
+ message: `Select an MCP server to ${action}:`,
215
+ choices: servers.map((s) => ({
216
+ name: `${s.name} [${s.transport}] ${s.isEnabled ? '✓' : '✗'}`,
217
+ value: s.id,
218
+ })),
219
+ },
220
+ ]);
221
+ return servers.find((s) => s.id === id) ?? null;
222
+ }
223
+ async function mcpRemove() {
224
+ try {
225
+ const server = await pickServer('remove');
226
+ if (!server)
227
+ return;
228
+ const { confirm } = await inquirer_1.default.prompt([
229
+ {
230
+ type: 'confirm',
231
+ name: 'confirm',
232
+ message: `Delete MCP server "${server.name}"?`,
233
+ default: false,
234
+ },
235
+ ]);
236
+ if (!confirm) {
237
+ console.log('Aborted.');
238
+ return;
239
+ }
240
+ const headers = await authHeaders();
241
+ await axios_1.default.delete(`${getBaseUrl()}/api/mcp-servers/${server.id}`, {
242
+ headers,
243
+ timeout: 10000,
244
+ });
245
+ console.log('MCP server removed.');
246
+ }
247
+ catch (err) {
248
+ const msg = err.response?.data?.error ?? err.message;
249
+ console.error(`Error removing MCP server: ${msg}`);
250
+ }
251
+ }
252
+ async function mcpToggle(id) {
253
+ try {
254
+ const headers = await authHeaders();
255
+ const current = await axios_1.default.get(`${getBaseUrl()}/api/mcp-servers/${id}`, {
256
+ headers,
257
+ timeout: 10000,
258
+ });
259
+ const newState = !current.data.isEnabled;
260
+ const res = await axios_1.default.patch(`${getBaseUrl()}/api/mcp-servers/${id}`, { isEnabled: newState }, { headers, timeout: 10000 });
261
+ console.log(`MCP server ${res.data.name} is now ${res.data.isEnabled ? 'enabled' : 'disabled'}.`);
262
+ }
263
+ catch (err) {
264
+ const msg = err.response?.data?.error ?? err.message;
265
+ console.error(`Error toggling MCP server: ${msg}`);
266
+ }
267
+ }
268
+ async function mcpUpdate(id) {
269
+ try {
270
+ const headers = await authHeaders();
271
+ const current = (await axios_1.default.get(`${getBaseUrl()}/api/mcp-servers/${id}`, {
272
+ headers,
273
+ timeout: 10000,
274
+ })).data;
275
+ const baseAnswers = await inquirer_1.default.prompt([
276
+ {
277
+ type: 'input',
278
+ name: 'name',
279
+ message: 'Name:',
280
+ default: current.name,
281
+ },
282
+ {
283
+ type: 'input',
284
+ name: 'description',
285
+ message: 'Description:',
286
+ default: current.description ?? '',
287
+ },
288
+ {
289
+ type: 'list',
290
+ name: 'transport',
291
+ message: 'Transport:',
292
+ choices: ['stdio', 'http', 'sse'],
293
+ default: current.transport,
294
+ },
295
+ {
296
+ type: 'confirm',
297
+ name: 'isEnabled',
298
+ message: 'Enabled?',
299
+ default: current.isEnabled,
300
+ },
301
+ ]);
302
+ const transportFields = await promptTransportFields(baseAnswers.transport, current);
303
+ const res = await axios_1.default.patch(`${getBaseUrl()}/api/mcp-servers/${id}`, {
304
+ name: baseAnswers.name.trim(),
305
+ description: baseAnswers.description.trim() || null,
306
+ transport: baseAnswers.transport,
307
+ isEnabled: baseAnswers.isEnabled,
308
+ ...transportFields,
309
+ }, { headers, timeout: 15000 });
310
+ console.log('\nMCP server updated:');
311
+ printServer(res.data);
312
+ }
313
+ catch (err) {
314
+ const msg = err.response?.data?.error ?? err.message;
315
+ console.error(`Error updating MCP server: ${msg}`);
316
+ }
317
+ }
318
+ function printServer(s) {
319
+ console.log(` ID: ${s.id}`);
320
+ console.log(` Name: ${s.name}`);
321
+ console.log(` Transport: ${s.transport}`);
322
+ console.log(` Enabled: ${s.isEnabled}`);
323
+ if (s.transport === 'stdio') {
324
+ console.log(` Command: ${s.command ?? '—'}`);
325
+ if (s.args.length > 0)
326
+ console.log(` Args: ${s.args.join(' ')}`);
327
+ }
328
+ else {
329
+ console.log(` URL: ${s.url ?? '—'}`);
330
+ }
331
+ }
332
+ function padRight(str, width) {
333
+ return str.length >= width ? str.slice(0, width) : str + ' '.repeat(width - str.length);
334
+ }
package/dist/onboard.js CHANGED
@@ -9,8 +9,8 @@ const fs_1 = __importDefault(require("fs"));
9
9
  const path_1 = __importDefault(require("path"));
10
10
  const utils_1 = require("./utils");
11
11
  const AI_PROVIDERS = [
12
- { name: 'OpenAI (gpt-4o-mini / gpt-5.1)', value: 'openai' },
13
- { name: 'Anthropic — Claude (claude-haiku / claude-sonnet)', value: 'anthropic' },
12
+ { name: 'OpenAI (gpt-4o-mini / gpt-5.5)', value: 'openai' },
13
+ { name: 'Anthropic — Claude (claude-haiku / claude-opus)', value: 'anthropic' },
14
14
  { name: 'Google Gemini (gemini-2.5-flash / gemini-2.5-pro)', value: 'gemini' },
15
15
  ];
16
16
  const SEARCH_PROVIDERS = [
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "access": "public",
5
5
  "registry": "https://registry.npmjs.org/"
6
6
  },
7
- "version": "1.0.38",
7
+ "version": "1.0.40",
8
8
  "description": "CLI for onboarding users to Omnikey AI and configuring OPENAI_API_KEY. Use Yarn for install/build.",
9
9
  "engines": {
10
10
  "node": ">=14.0.0",
@@ -27,9 +27,10 @@
27
27
  "author": "Gurinder Rawala",
28
28
  "license": "MIT",
29
29
  "dependencies": {
30
- "@anthropic-ai/sdk": "^0.80.0",
30
+ "@anthropic-ai/sdk": "^0.96.0",
31
31
  "@google-cloud/storage": "^7.19.0",
32
32
  "@google/genai": "^1.46.0",
33
+ "@modelcontextprotocol/sdk": "^1.29.0",
33
34
  "axios": "^1.13.5",
34
35
  "commander": "^11.0.0",
35
36
  "cors": "^2.8.5",
@@ -38,7 +39,7 @@
38
39
  "express": "^4.21.2",
39
40
  "inquirer": "^9.0.0",
40
41
  "jsonwebtoken": "^9.0.3",
41
- "openai": "^6.16.0",
42
+ "openai": "^6.37.0",
42
43
  "pg": "^8.18.0",
43
44
  "pg-hstore": "^2.3.4",
44
45
  "playwright-core": "^1.50.0",
package/src/index.ts CHANGED
@@ -11,6 +11,7 @@ import { showConfig } from './showConfig';
11
11
  import { setConfig } from './setConfig';
12
12
  import { grantBrowserAccess, reopenBrowserDebugProfile } from './grantBrowserAccess';
13
13
  import { scheduleAdd, scheduleList, scheduleRemove, scheduleRunNow } from './scheduleJob';
14
+ import { mcpAdd, mcpList, mcpRemove, mcpToggle, mcpUpdate } from './mcpServer';
14
15
 
15
16
  const program = new Command();
16
17
 
@@ -110,28 +111,73 @@ program
110
111
  await reopenBrowserDebugProfile();
111
112
  });
112
113
 
113
- const scheduleCmd = program
114
- .command('schedule')
115
- .description('Manage scheduled prompt jobs');
114
+ const scheduleCmd = program.command('schedule').description('Manage scheduled prompt jobs');
116
115
 
117
116
  scheduleCmd
118
117
  .command('add')
119
118
  .description('Add a new scheduled job')
120
- .action(async () => { await scheduleAdd(); });
119
+ .action(async () => {
120
+ await scheduleAdd();
121
+ });
121
122
 
122
123
  scheduleCmd
123
124
  .command('list')
124
125
  .description('List all scheduled jobs')
125
- .action(async () => { await scheduleList(); });
126
+ .action(async () => {
127
+ await scheduleList();
128
+ });
126
129
 
127
130
  scheduleCmd
128
131
  .command('remove')
129
132
  .description('Remove a scheduled job')
130
- .action(async () => { await scheduleRemove(); });
133
+ .action(async () => {
134
+ await scheduleRemove();
135
+ });
131
136
 
132
137
  scheduleCmd
133
138
  .command('run-now <id>')
134
139
  .description('Immediately run a scheduled job by ID')
135
- .action(async (id: string) => { await scheduleRunNow(id); });
140
+ .action(async (id: string) => {
141
+ await scheduleRunNow(id);
142
+ });
143
+
144
+ const mcpCmd = program
145
+ .command('mcp')
146
+ .description('Manage MCP (Model Context Protocol) servers available to the agent');
147
+
148
+ mcpCmd
149
+ .command('add')
150
+ .description('Install a new MCP server')
151
+ .action(async () => {
152
+ await mcpAdd();
153
+ });
154
+
155
+ mcpCmd
156
+ .command('list')
157
+ .description('List installed MCP servers')
158
+ .action(async () => {
159
+ await mcpList();
160
+ });
161
+
162
+ mcpCmd
163
+ .command('remove')
164
+ .description('Remove an installed MCP server')
165
+ .action(async () => {
166
+ await mcpRemove();
167
+ });
168
+
169
+ mcpCmd
170
+ .command('toggle <id>')
171
+ .description('Toggle an MCP server enabled/disabled by ID')
172
+ .action(async (id: string) => {
173
+ await mcpToggle(id);
174
+ });
175
+
176
+ mcpCmd
177
+ .command('update <id>')
178
+ .description('Update an existing MCP server by ID')
179
+ .action(async (id: string) => {
180
+ await mcpUpdate(id);
181
+ });
136
182
 
137
183
  program.parseAsync(process.argv);