agentspd 1.0.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/LICENSE +21 -0
- package/README.md +333 -0
- package/dist/api.d.ts +198 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +171 -0
- package/dist/commands/agents.d.ts +3 -0
- package/dist/commands/agents.d.ts.map +1 -0
- package/dist/commands/agents.js +277 -0
- package/dist/commands/audit.d.ts +3 -0
- package/dist/commands/audit.d.ts.map +1 -0
- package/dist/commands/audit.js +181 -0
- package/dist/commands/auth.d.ts +3 -0
- package/dist/commands/auth.d.ts.map +1 -0
- package/dist/commands/auth.js +226 -0
- package/dist/commands/config-cmd.d.ts +3 -0
- package/dist/commands/config-cmd.d.ts.map +1 -0
- package/dist/commands/config-cmd.js +111 -0
- package/dist/commands/index.d.ts +9 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +8 -0
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +275 -0
- package/dist/commands/policies.d.ts +3 -0
- package/dist/commands/policies.d.ts.map +1 -0
- package/dist/commands/policies.js +362 -0
- package/dist/commands/threats.d.ts +3 -0
- package/dist/commands/threats.d.ts.map +1 -0
- package/dist/commands/threats.js +161 -0
- package/dist/commands/webhooks.d.ts +3 -0
- package/dist/commands/webhooks.d.ts.map +1 -0
- package/dist/commands/webhooks.js +222 -0
- package/dist/config.d.ts +24 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +58 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +328 -0
- package/dist/output.d.ts +60 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/output.js +212 -0
- package/package.json +58 -0
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import inquirer from 'inquirer';
|
|
3
|
+
import ora from 'ora';
|
|
4
|
+
import { api } from '../api.js';
|
|
5
|
+
import * as output from '../output.js';
|
|
6
|
+
const AVAILABLE_EVENTS = [
|
|
7
|
+
'agent.created',
|
|
8
|
+
'agent.revoked',
|
|
9
|
+
'agent.suspended',
|
|
10
|
+
'agent.reputation_changed',
|
|
11
|
+
'threat.detected',
|
|
12
|
+
'threat.blocked',
|
|
13
|
+
'threat.escalated',
|
|
14
|
+
'threat.resolved',
|
|
15
|
+
'policy.updated',
|
|
16
|
+
'policy.activated',
|
|
17
|
+
'audit.high_volume',
|
|
18
|
+
];
|
|
19
|
+
export function createWebhooksCommand() {
|
|
20
|
+
const webhooks = new Command('webhooks')
|
|
21
|
+
.alias('webhook')
|
|
22
|
+
.description('Manage webhook integrations');
|
|
23
|
+
webhooks
|
|
24
|
+
.command('create')
|
|
25
|
+
.alias('add')
|
|
26
|
+
.description('Create a new webhook')
|
|
27
|
+
.option('-u, --url <url>', 'Webhook URL')
|
|
28
|
+
.option('-e, --events <events>', 'Comma-separated list of events')
|
|
29
|
+
.option('-s, --secret <secret>', 'Webhook secret for signature verification')
|
|
30
|
+
.option('--json', 'Output as JSON')
|
|
31
|
+
.action(async (options) => {
|
|
32
|
+
let url = options.url;
|
|
33
|
+
let events = options.events ? options.events.split(',') : [];
|
|
34
|
+
let secret = options.secret;
|
|
35
|
+
// Interactive prompts
|
|
36
|
+
if (!url) {
|
|
37
|
+
const answers = await inquirer.prompt([
|
|
38
|
+
{
|
|
39
|
+
type: 'input',
|
|
40
|
+
name: 'url',
|
|
41
|
+
message: 'Webhook URL:',
|
|
42
|
+
validate: (input) => {
|
|
43
|
+
try {
|
|
44
|
+
new URL(input);
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return 'Please enter a valid URL';
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
]);
|
|
53
|
+
url = answers.url;
|
|
54
|
+
}
|
|
55
|
+
if (events.length === 0) {
|
|
56
|
+
const answers = await inquirer.prompt([
|
|
57
|
+
{
|
|
58
|
+
type: 'checkbox',
|
|
59
|
+
name: 'events',
|
|
60
|
+
message: 'Select events to subscribe to:',
|
|
61
|
+
choices: AVAILABLE_EVENTS.map(e => ({
|
|
62
|
+
name: e,
|
|
63
|
+
checked: e.startsWith('threat.'),
|
|
64
|
+
})),
|
|
65
|
+
validate: (input) => input.length > 0 || 'Select at least one event',
|
|
66
|
+
},
|
|
67
|
+
]);
|
|
68
|
+
events = answers.events;
|
|
69
|
+
}
|
|
70
|
+
if (!secret) {
|
|
71
|
+
const answers = await inquirer.prompt([
|
|
72
|
+
{
|
|
73
|
+
type: 'password',
|
|
74
|
+
name: 'secret',
|
|
75
|
+
message: 'Webhook secret (optional, for signature verification):',
|
|
76
|
+
mask: '*',
|
|
77
|
+
},
|
|
78
|
+
]);
|
|
79
|
+
secret = answers.secret || undefined;
|
|
80
|
+
}
|
|
81
|
+
const spinner = ora('Creating webhook...').start();
|
|
82
|
+
const result = await api.createWebhook({ url, events, secret });
|
|
83
|
+
if (result.error) {
|
|
84
|
+
spinner.fail('Failed to create webhook');
|
|
85
|
+
output.error(result.error.message);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
spinner.succeed('Webhook created successfully!');
|
|
89
|
+
if (options.json) {
|
|
90
|
+
output.printJson(result.data);
|
|
91
|
+
}
|
|
92
|
+
else if (result.data) {
|
|
93
|
+
console.log();
|
|
94
|
+
output.printKeyValue([
|
|
95
|
+
['Webhook ID', result.data.id],
|
|
96
|
+
['URL', result.data.url],
|
|
97
|
+
['Events', result.data.events.join(', ')],
|
|
98
|
+
['Created', output.formatDate(result.data.createdAt)],
|
|
99
|
+
]);
|
|
100
|
+
console.log();
|
|
101
|
+
output.info('Webhook payload example:');
|
|
102
|
+
output.printJson({
|
|
103
|
+
id: 'evt_123',
|
|
104
|
+
type: 'threat.blocked',
|
|
105
|
+
timestamp: new Date().toISOString(),
|
|
106
|
+
data: {
|
|
107
|
+
agentId: 'agent_abc',
|
|
108
|
+
threatType: 'prompt_injection',
|
|
109
|
+
severity: 'high',
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
webhooks
|
|
115
|
+
.command('list')
|
|
116
|
+
.alias('ls')
|
|
117
|
+
.description('List all webhooks')
|
|
118
|
+
.option('--json', 'Output as JSON')
|
|
119
|
+
.action(async (options) => {
|
|
120
|
+
const spinner = ora('Fetching webhooks...').start();
|
|
121
|
+
const result = await api.listWebhooks();
|
|
122
|
+
if (result.error) {
|
|
123
|
+
spinner.fail('Failed to fetch webhooks');
|
|
124
|
+
output.error(result.error.message);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
spinner.stop();
|
|
128
|
+
if (options.json) {
|
|
129
|
+
output.printJson(result.data);
|
|
130
|
+
}
|
|
131
|
+
else if (result.data) {
|
|
132
|
+
if (result.data.webhooks.length === 0) {
|
|
133
|
+
output.info('No webhooks configured');
|
|
134
|
+
output.info('Create one with: emotos webhooks create');
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
output.heading('Webhooks');
|
|
138
|
+
output.printWebhookTable(result.data.webhooks);
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
webhooks
|
|
142
|
+
.command('delete <webhookId>')
|
|
143
|
+
.alias('rm')
|
|
144
|
+
.description('Delete a webhook')
|
|
145
|
+
.option('-f, --force', 'Skip confirmation')
|
|
146
|
+
.action(async (webhookId, options) => {
|
|
147
|
+
if (!options.force) {
|
|
148
|
+
const answers = await inquirer.prompt([
|
|
149
|
+
{
|
|
150
|
+
type: 'confirm',
|
|
151
|
+
name: 'confirm',
|
|
152
|
+
message: `Delete webhook ${webhookId}?`,
|
|
153
|
+
default: false,
|
|
154
|
+
},
|
|
155
|
+
]);
|
|
156
|
+
if (!answers.confirm) {
|
|
157
|
+
output.info('Operation cancelled');
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
const spinner = ora('Deleting webhook...').start();
|
|
162
|
+
const result = await api.deleteWebhook(webhookId);
|
|
163
|
+
if (result.error) {
|
|
164
|
+
spinner.fail('Failed to delete webhook');
|
|
165
|
+
output.error(result.error.message);
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
spinner.succeed('Webhook deleted');
|
|
169
|
+
});
|
|
170
|
+
webhooks
|
|
171
|
+
.command('test <webhookId>')
|
|
172
|
+
.description('Send a test webhook')
|
|
173
|
+
.action(async (webhookId) => {
|
|
174
|
+
const spinner = ora('Sending test webhook...').start();
|
|
175
|
+
const result = await api.testWebhook(webhookId);
|
|
176
|
+
if (result.error) {
|
|
177
|
+
spinner.fail('Failed to send test webhook');
|
|
178
|
+
output.error(result.error.message);
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
if (result.data?.success) {
|
|
182
|
+
spinner.succeed('Test webhook sent successfully!');
|
|
183
|
+
output.info(`Response status: ${result.data.statusCode}`);
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
spinner.fail('Test webhook failed');
|
|
187
|
+
if (result.data?.error) {
|
|
188
|
+
output.error(result.data.error);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
webhooks
|
|
193
|
+
.command('events')
|
|
194
|
+
.description('List available webhook events')
|
|
195
|
+
.action(() => {
|
|
196
|
+
output.heading('Available Webhook Events');
|
|
197
|
+
const agentEvents = AVAILABLE_EVENTS.filter(e => e.startsWith('agent.'));
|
|
198
|
+
const threatEvents = AVAILABLE_EVENTS.filter(e => e.startsWith('threat.'));
|
|
199
|
+
const policyEvents = AVAILABLE_EVENTS.filter(e => e.startsWith('policy.'));
|
|
200
|
+
const auditEvents = AVAILABLE_EVENTS.filter(e => e.startsWith('audit.'));
|
|
201
|
+
console.log(output.bold('Agent Events'));
|
|
202
|
+
for (const event of agentEvents) {
|
|
203
|
+
console.log(` - ${event}`);
|
|
204
|
+
}
|
|
205
|
+
console.log();
|
|
206
|
+
console.log(output.bold('Threat Events'));
|
|
207
|
+
for (const event of threatEvents) {
|
|
208
|
+
console.log(` - ${event}`);
|
|
209
|
+
}
|
|
210
|
+
console.log();
|
|
211
|
+
console.log(output.bold('Policy Events'));
|
|
212
|
+
for (const event of policyEvents) {
|
|
213
|
+
console.log(` - ${event}`);
|
|
214
|
+
}
|
|
215
|
+
console.log();
|
|
216
|
+
console.log(output.bold('Audit Events'));
|
|
217
|
+
for (const event of auditEvents) {
|
|
218
|
+
console.log(` - ${event}`);
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
return webhooks;
|
|
222
|
+
}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import Conf from 'conf';
|
|
2
|
+
export interface EmotosConfig {
|
|
3
|
+
apiUrl: string;
|
|
4
|
+
apiKey?: string;
|
|
5
|
+
sessionToken?: string;
|
|
6
|
+
orgId?: string;
|
|
7
|
+
orgName?: string;
|
|
8
|
+
userId?: string;
|
|
9
|
+
userName?: string;
|
|
10
|
+
defaultEnvironment: 'development' | 'staging' | 'production';
|
|
11
|
+
outputFormat: 'table' | 'json' | 'yaml';
|
|
12
|
+
}
|
|
13
|
+
declare const config: Conf<EmotosConfig>;
|
|
14
|
+
export declare function getConfig(): EmotosConfig;
|
|
15
|
+
export declare function setConfig<K extends keyof EmotosConfig>(key: K, value: EmotosConfig[K]): void;
|
|
16
|
+
export declare function clearConfig(): void;
|
|
17
|
+
export declare function getApiUrl(): string;
|
|
18
|
+
export declare function getApiKey(): string | undefined;
|
|
19
|
+
export declare function getSessionToken(): string | undefined;
|
|
20
|
+
export declare function getOrgId(): string | undefined;
|
|
21
|
+
export declare function isAuthenticated(): boolean;
|
|
22
|
+
export declare function getAuthHeader(): Record<string, string>;
|
|
23
|
+
export { config };
|
|
24
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kBAAkB,EAAE,aAAa,GAAG,SAAS,GAAG,YAAY,CAAC;IAC7D,YAAY,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;CACzC;AAoBD,QAAA,MAAM,MAAM,oBAIV,CAAC;AAEH,wBAAgB,SAAS,IAAI,YAAY,CAExC;AAED,wBAAgB,SAAS,CAAC,CAAC,SAAS,MAAM,YAAY,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI,CAE5F;AAED,wBAAgB,WAAW,IAAI,IAAI,CAElC;AAED,wBAAgB,SAAS,IAAI,MAAM,CAElC;AAED,wBAAgB,SAAS,IAAI,MAAM,GAAG,SAAS,CAE9C;AAED,wBAAgB,eAAe,IAAI,MAAM,GAAG,SAAS,CAEpD;AAED,wBAAgB,QAAQ,IAAI,MAAM,GAAG,SAAS,CAE7C;AAED,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AAED,wBAAgB,aAAa,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAWtD;AAED,OAAO,EAAE,MAAM,EAAE,CAAC"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import Conf from 'conf';
|
|
2
|
+
const defaults = {
|
|
3
|
+
apiUrl: 'https://api.emotos.ai',
|
|
4
|
+
defaultEnvironment: 'development',
|
|
5
|
+
outputFormat: 'table',
|
|
6
|
+
};
|
|
7
|
+
const schema = {
|
|
8
|
+
apiUrl: { type: 'string' },
|
|
9
|
+
apiKey: { type: 'string' },
|
|
10
|
+
sessionToken: { type: 'string' },
|
|
11
|
+
orgId: { type: 'string' },
|
|
12
|
+
orgName: { type: 'string' },
|
|
13
|
+
userId: { type: 'string' },
|
|
14
|
+
userName: { type: 'string' },
|
|
15
|
+
defaultEnvironment: { type: 'string', enum: ['development', 'staging', 'production'] },
|
|
16
|
+
outputFormat: { type: 'string', enum: ['table', 'json', 'yaml'] },
|
|
17
|
+
};
|
|
18
|
+
const config = new Conf({
|
|
19
|
+
projectName: 'emotos',
|
|
20
|
+
defaults,
|
|
21
|
+
schema,
|
|
22
|
+
});
|
|
23
|
+
export function getConfig() {
|
|
24
|
+
return config.store;
|
|
25
|
+
}
|
|
26
|
+
export function setConfig(key, value) {
|
|
27
|
+
config.set(key, value);
|
|
28
|
+
}
|
|
29
|
+
export function clearConfig() {
|
|
30
|
+
config.clear();
|
|
31
|
+
}
|
|
32
|
+
export function getApiUrl() {
|
|
33
|
+
return config.get('apiUrl');
|
|
34
|
+
}
|
|
35
|
+
export function getApiKey() {
|
|
36
|
+
return config.get('apiKey');
|
|
37
|
+
}
|
|
38
|
+
export function getSessionToken() {
|
|
39
|
+
return config.get('sessionToken');
|
|
40
|
+
}
|
|
41
|
+
export function getOrgId() {
|
|
42
|
+
return config.get('orgId');
|
|
43
|
+
}
|
|
44
|
+
export function isAuthenticated() {
|
|
45
|
+
return !!(config.get('apiKey') || config.get('sessionToken'));
|
|
46
|
+
}
|
|
47
|
+
export function getAuthHeader() {
|
|
48
|
+
const apiKey = config.get('apiKey');
|
|
49
|
+
const sessionToken = config.get('sessionToken');
|
|
50
|
+
if (apiKey) {
|
|
51
|
+
return { 'Authorization': `Bearer ${apiKey}` };
|
|
52
|
+
}
|
|
53
|
+
if (sessionToken) {
|
|
54
|
+
return { 'Authorization': `Bearer ${sessionToken}` };
|
|
55
|
+
}
|
|
56
|
+
return {};
|
|
57
|
+
}
|
|
58
|
+
export { config };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { createAuthCommand, createAgentsCommand, createPoliciesCommand, createAuditCommand, createThreatsCommand, createWebhooksCommand, createConfigCommand, createInitCommand, } from './commands/index.js';
|
|
5
|
+
import { setConfig, getConfig } from './config.js';
|
|
6
|
+
import * as output from './output.js';
|
|
7
|
+
const VERSION = '1.0.0';
|
|
8
|
+
const BANNER = `
|
|
9
|
+
${chalk.cyan('╔═══════════════════════════════════════════════════════════╗')}
|
|
10
|
+
${chalk.cyan('║')} ${chalk.bold.white('EMOTOS CLI')} - Security Infrastructure for AI Agents ${chalk.cyan('║')}
|
|
11
|
+
${chalk.cyan('╚═══════════════════════════════════════════════════════════╝')}
|
|
12
|
+
`;
|
|
13
|
+
const program = new Command();
|
|
14
|
+
program
|
|
15
|
+
.name('agentspd')
|
|
16
|
+
.description('Emotos CLI - Security Infrastructure for AI Agents')
|
|
17
|
+
.version(VERSION)
|
|
18
|
+
.option('--api-url <url>', 'Override API URL')
|
|
19
|
+
.option('--json', 'Output in JSON format')
|
|
20
|
+
.option('--yaml', 'Output in YAML format')
|
|
21
|
+
.hook('preAction', (thisCommand) => {
|
|
22
|
+
const opts = thisCommand.opts();
|
|
23
|
+
if (opts.apiUrl) {
|
|
24
|
+
setConfig('apiUrl', opts.apiUrl);
|
|
25
|
+
}
|
|
26
|
+
if (opts.json) {
|
|
27
|
+
setConfig('outputFormat', 'json');
|
|
28
|
+
}
|
|
29
|
+
else if (opts.yaml) {
|
|
30
|
+
setConfig('outputFormat', 'yaml');
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
// Add subcommands
|
|
34
|
+
program.addCommand(createInitCommand());
|
|
35
|
+
program.addCommand(createAuthCommand());
|
|
36
|
+
program.addCommand(createAgentsCommand());
|
|
37
|
+
program.addCommand(createPoliciesCommand());
|
|
38
|
+
program.addCommand(createAuditCommand());
|
|
39
|
+
program.addCommand(createThreatsCommand());
|
|
40
|
+
program.addCommand(createWebhooksCommand());
|
|
41
|
+
program.addCommand(createConfigCommand());
|
|
42
|
+
// Quick commands (shortcuts)
|
|
43
|
+
program
|
|
44
|
+
.command('login')
|
|
45
|
+
.description('Quick login (alias for auth login)')
|
|
46
|
+
.option('-k, --api-key <key>', 'Use API key')
|
|
47
|
+
.action(async (options) => {
|
|
48
|
+
const authCmd = createAuthCommand();
|
|
49
|
+
const loginCmd = authCmd.commands.find((c) => c.name() === 'login');
|
|
50
|
+
if (loginCmd) {
|
|
51
|
+
await loginCmd.parseAsync(['', '', ...(options.apiKey ? ['-k', options.apiKey] : [])]);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
program
|
|
55
|
+
.command('status')
|
|
56
|
+
.description('Show authentication and system status')
|
|
57
|
+
.action(async () => {
|
|
58
|
+
const config = getConfig();
|
|
59
|
+
output.heading('Emotos Status');
|
|
60
|
+
// Auth status
|
|
61
|
+
const authStatus = config.apiKey || config.sessionToken ? 'Authenticated' : 'Not authenticated';
|
|
62
|
+
const authColor = config.apiKey || config.sessionToken ? chalk.green : chalk.red;
|
|
63
|
+
output.printKeyValue([
|
|
64
|
+
['Auth Status', authColor(authStatus)],
|
|
65
|
+
['API URL', config.apiUrl],
|
|
66
|
+
['Organization', config.orgName || 'N/A'],
|
|
67
|
+
['User', config.userName || 'N/A'],
|
|
68
|
+
['Environment', config.defaultEnvironment],
|
|
69
|
+
]);
|
|
70
|
+
if (!config.apiKey && !config.sessionToken) {
|
|
71
|
+
console.log();
|
|
72
|
+
output.info('Run `agentspd auth login` to authenticate');
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
// Help command enhancements
|
|
76
|
+
program
|
|
77
|
+
.command('docs')
|
|
78
|
+
.description('Open documentation')
|
|
79
|
+
.action(() => {
|
|
80
|
+
console.log(BANNER);
|
|
81
|
+
output.heading('Documentation');
|
|
82
|
+
console.log(' Full documentation: ' + output.link('https://docs.emotos.ai'));
|
|
83
|
+
console.log(' API Reference: ' + output.link('https://api.emotos.ai/docs'));
|
|
84
|
+
console.log();
|
|
85
|
+
output.heading('Quick Start');
|
|
86
|
+
console.log(' 1. Sign up: ' + output.highlight('agentspd auth signup'));
|
|
87
|
+
console.log(' 2. Create policy: ' + output.highlight('agentspd policies create'));
|
|
88
|
+
console.log(' 3. Register agent: ' + output.highlight('agentspd agents create'));
|
|
89
|
+
console.log(' 4. Issue token: ' + output.highlight('agentspd agents token <agent-id>'));
|
|
90
|
+
console.log(' 5. Connect to MCP: ' + output.highlight('wss://proxy.emotos.ai/v1/mcp'));
|
|
91
|
+
console.log();
|
|
92
|
+
output.heading('For Agent Providers');
|
|
93
|
+
console.log(' - Register and manage AI agents');
|
|
94
|
+
console.log(' - Define security policies');
|
|
95
|
+
console.log(' - Monitor agent reputation and behavior');
|
|
96
|
+
console.log();
|
|
97
|
+
output.heading('For Agent Consumers');
|
|
98
|
+
console.log(' - Vet and approve third-party agents');
|
|
99
|
+
console.log(' - Monitor threats in real-time');
|
|
100
|
+
console.log(' - Review audit logs for compliance');
|
|
101
|
+
});
|
|
102
|
+
program
|
|
103
|
+
.command('quickstart')
|
|
104
|
+
.alias('tutorial')
|
|
105
|
+
.description('Interactive quickstart tutorial')
|
|
106
|
+
.option('--provider', 'Agent provider tutorial')
|
|
107
|
+
.option('--consumer', 'Agent consumer tutorial')
|
|
108
|
+
.action(async (options) => {
|
|
109
|
+
console.log(BANNER);
|
|
110
|
+
if (options.provider) {
|
|
111
|
+
await providerTutorial();
|
|
112
|
+
}
|
|
113
|
+
else if (options.consumer) {
|
|
114
|
+
await consumerTutorial();
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
const inquirer = await import('inquirer');
|
|
118
|
+
const answers = await inquirer.default.prompt([
|
|
119
|
+
{
|
|
120
|
+
type: 'list',
|
|
121
|
+
name: 'role',
|
|
122
|
+
message: 'Which tutorial would you like to follow?',
|
|
123
|
+
choices: [
|
|
124
|
+
{ name: 'Agent Provider - Build and deploy secure AI agents', value: 'provider' },
|
|
125
|
+
{ name: 'Agent Consumer - Protect your systems from AI agents', value: 'consumer' },
|
|
126
|
+
],
|
|
127
|
+
},
|
|
128
|
+
]);
|
|
129
|
+
if (answers.role === 'provider') {
|
|
130
|
+
await providerTutorial();
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
await consumerTutorial();
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
async function providerTutorial() {
|
|
138
|
+
output.heading('Agent Provider Tutorial');
|
|
139
|
+
console.log('This tutorial will guide you through:');
|
|
140
|
+
console.log(' 1. Creating a security policy');
|
|
141
|
+
console.log(' 2. Registering an AI agent');
|
|
142
|
+
console.log(' 3. Issuing identity tokens');
|
|
143
|
+
console.log(' 4. Connecting to the MCP proxy');
|
|
144
|
+
console.log();
|
|
145
|
+
const inquirer = await import('inquirer');
|
|
146
|
+
// Step 1: Check authentication
|
|
147
|
+
output.heading('Step 1: Authentication');
|
|
148
|
+
const config = getConfig();
|
|
149
|
+
if (!config.apiKey && !config.sessionToken) {
|
|
150
|
+
console.log('You need to authenticate first.');
|
|
151
|
+
const answers = await inquirer.default.prompt([
|
|
152
|
+
{
|
|
153
|
+
type: 'confirm',
|
|
154
|
+
name: 'signup',
|
|
155
|
+
message: 'Would you like to create an account now?',
|
|
156
|
+
default: true,
|
|
157
|
+
},
|
|
158
|
+
]);
|
|
159
|
+
if (answers.signup) {
|
|
160
|
+
console.log();
|
|
161
|
+
console.log('Run: ' + output.highlight('agentspd auth signup'));
|
|
162
|
+
console.log('Then run this tutorial again.');
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
output.success('Already authenticated');
|
|
168
|
+
}
|
|
169
|
+
// Step 2: Create a policy
|
|
170
|
+
output.heading('Step 2: Create a Security Policy');
|
|
171
|
+
console.log('Security policies define what your agents can and cannot do.');
|
|
172
|
+
console.log();
|
|
173
|
+
console.log('Example policy (save as my-policy.yaml):');
|
|
174
|
+
console.log();
|
|
175
|
+
console.log(chalk.gray(`version: "1.0"
|
|
176
|
+
name: "my-agent-policy"
|
|
177
|
+
|
|
178
|
+
settings:
|
|
179
|
+
default_action: deny
|
|
180
|
+
require_identity: true
|
|
181
|
+
|
|
182
|
+
tools:
|
|
183
|
+
- pattern: "read_*"
|
|
184
|
+
action: allow
|
|
185
|
+
- pattern: "write_*"
|
|
186
|
+
action: allow
|
|
187
|
+
constraints:
|
|
188
|
+
paths:
|
|
189
|
+
allow: ["/data/**"]
|
|
190
|
+
deny: ["**/.env", "**/secrets/**"]
|
|
191
|
+
|
|
192
|
+
prompt_injection:
|
|
193
|
+
enabled: true
|
|
194
|
+
action: block`));
|
|
195
|
+
console.log();
|
|
196
|
+
console.log('Create with: ' + output.highlight('agentspd policies create --file my-policy.yaml'));
|
|
197
|
+
// Step 3: Register an agent
|
|
198
|
+
output.heading('Step 3: Register Your Agent');
|
|
199
|
+
console.log('Each AI agent needs a unique identity.');
|
|
200
|
+
console.log();
|
|
201
|
+
console.log('Create with: ' + output.highlight('agentspd agents create --name my-agent --environment development'));
|
|
202
|
+
console.log();
|
|
203
|
+
console.log('This returns:');
|
|
204
|
+
console.log(' - Agent ID: unique identifier for your agent');
|
|
205
|
+
console.log(' - API Key: for authenticating API calls');
|
|
206
|
+
console.log();
|
|
207
|
+
output.warn('Save the API key securely - it will not be shown again!');
|
|
208
|
+
// Step 4: Issue tokens
|
|
209
|
+
output.heading('Step 4: Issue JWT Tokens');
|
|
210
|
+
console.log('Before connecting to the MCP proxy, issue a short-lived JWT:');
|
|
211
|
+
console.log();
|
|
212
|
+
console.log('Command: ' + output.highlight('agentspd agents token <agent-id> --ttl 3600'));
|
|
213
|
+
console.log();
|
|
214
|
+
console.log('The token contains:');
|
|
215
|
+
console.log(' - Agent identity claims');
|
|
216
|
+
console.log(' - Permissions and policy version');
|
|
217
|
+
console.log(' - Reputation score');
|
|
218
|
+
// Step 5: Connect to proxy
|
|
219
|
+
output.heading('Step 5: Connect to MCP Proxy');
|
|
220
|
+
console.log('Use the JWT token to connect your agent:');
|
|
221
|
+
console.log();
|
|
222
|
+
console.log(chalk.gray(`const WebSocket = require('ws');
|
|
223
|
+
|
|
224
|
+
const ws = new WebSocket('wss://proxy.emotos.ai/v1/mcp', {
|
|
225
|
+
headers: {
|
|
226
|
+
'Authorization': 'Bearer ' + agentToken
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
ws.on('open', () => {
|
|
231
|
+
console.log('Connected to Emotos MCP Proxy');
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
ws.on('message', (data) => {
|
|
235
|
+
// Handle MCP messages
|
|
236
|
+
});`));
|
|
237
|
+
console.log();
|
|
238
|
+
output.success('Tutorial complete!');
|
|
239
|
+
console.log();
|
|
240
|
+
console.log('Next steps:');
|
|
241
|
+
console.log(' - Monitor your agent: ' + output.highlight('agentspd agents monitor <agent-id>'));
|
|
242
|
+
console.log(' - Check threats: ' + output.highlight('agentspd threats list'));
|
|
243
|
+
console.log(' - View audit logs: ' + output.highlight('agentspd audit events'));
|
|
244
|
+
}
|
|
245
|
+
async function consumerTutorial() {
|
|
246
|
+
output.heading('Agent Consumer Tutorial');
|
|
247
|
+
console.log('This tutorial will guide you through:');
|
|
248
|
+
console.log(' 1. Setting up threat monitoring');
|
|
249
|
+
console.log(' 2. Configuring webhooks for alerts');
|
|
250
|
+
console.log(' 3. Reviewing audit logs');
|
|
251
|
+
console.log(' 4. Responding to security incidents');
|
|
252
|
+
console.log();
|
|
253
|
+
const inquirer = await import('inquirer');
|
|
254
|
+
// Step 1: Check authentication
|
|
255
|
+
output.heading('Step 1: Authentication');
|
|
256
|
+
const config = getConfig();
|
|
257
|
+
if (!config.apiKey && !config.sessionToken) {
|
|
258
|
+
console.log('You need to authenticate first.');
|
|
259
|
+
console.log('Run: ' + output.highlight('agentspd auth signup --role consumer'));
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
output.success('Already authenticated');
|
|
263
|
+
// Step 2: Configure webhooks
|
|
264
|
+
output.heading('Step 2: Configure Webhook Alerts');
|
|
265
|
+
console.log('Get real-time alerts when threats are detected:');
|
|
266
|
+
console.log();
|
|
267
|
+
console.log('Command: ' + output.highlight('agentspd webhooks create'));
|
|
268
|
+
console.log();
|
|
269
|
+
console.log('Recommended events to subscribe:');
|
|
270
|
+
console.log(' - threat.detected');
|
|
271
|
+
console.log(' - threat.blocked');
|
|
272
|
+
console.log(' - agent.suspended');
|
|
273
|
+
console.log(' - agent.reputation_changed');
|
|
274
|
+
// Step 3: Monitor threats
|
|
275
|
+
output.heading('Step 3: Monitor Threats');
|
|
276
|
+
console.log('View current threats:');
|
|
277
|
+
console.log(' ' + output.highlight('agentspd threats list'));
|
|
278
|
+
console.log();
|
|
279
|
+
console.log('Watch threats in real-time:');
|
|
280
|
+
console.log(' ' + output.highlight('agentspd threats watch'));
|
|
281
|
+
console.log();
|
|
282
|
+
console.log('Filter by severity:');
|
|
283
|
+
console.log(' ' + output.highlight('agentspd threats list --severity high'));
|
|
284
|
+
// Step 4: Review audit logs
|
|
285
|
+
output.heading('Step 4: Review Audit Logs');
|
|
286
|
+
console.log('Query audit events for compliance:');
|
|
287
|
+
console.log(' ' + output.highlight('agentspd audit events --start 2026-01-01'));
|
|
288
|
+
console.log();
|
|
289
|
+
console.log('Export for reports:');
|
|
290
|
+
console.log(' ' + output.highlight('agentspd audit export --output audit-report.json'));
|
|
291
|
+
// Step 5: Respond to incidents
|
|
292
|
+
output.heading('Step 5: Respond to Incidents');
|
|
293
|
+
console.log('When a threat is detected:');
|
|
294
|
+
console.log();
|
|
295
|
+
console.log('1. Review the threat details:');
|
|
296
|
+
console.log(' ' + output.highlight('agentspd threats list --status detected'));
|
|
297
|
+
console.log();
|
|
298
|
+
console.log('2. Revoke compromised agent if needed:');
|
|
299
|
+
console.log(' ' + output.highlight('agentspd agents revoke <agent-id>'));
|
|
300
|
+
console.log();
|
|
301
|
+
console.log('3. Resolve the threat after investigation:');
|
|
302
|
+
console.log(' ' + output.highlight('agentspd threats resolve <threat-id>'));
|
|
303
|
+
console.log();
|
|
304
|
+
output.success('Tutorial complete!');
|
|
305
|
+
console.log();
|
|
306
|
+
console.log('Useful commands:');
|
|
307
|
+
console.log(' - View all agents: ' + output.highlight('agentspd agents list'));
|
|
308
|
+
console.log(' - Get threat stats: ' + output.highlight('agentspd threats stats'));
|
|
309
|
+
console.log(' - Audit statistics: ' + output.highlight('agentspd audit stats'));
|
|
310
|
+
}
|
|
311
|
+
// Error handling
|
|
312
|
+
program.exitOverride();
|
|
313
|
+
try {
|
|
314
|
+
await program.parseAsync(process.argv);
|
|
315
|
+
}
|
|
316
|
+
catch (err) {
|
|
317
|
+
// Handle Commander.js special exits (help, version, etc.)
|
|
318
|
+
if (err instanceof Error && 'code' in err) {
|
|
319
|
+
const code = err.code;
|
|
320
|
+
if (code === 'commander.help' || code === 'commander.helpDisplayed' || code === 'commander.version') {
|
|
321
|
+
// Help or version was displayed, exit cleanly
|
|
322
|
+
process.exit(0);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
// Real error
|
|
326
|
+
console.error(chalk.red('Error:'), err instanceof Error ? err.message : err);
|
|
327
|
+
process.exit(1);
|
|
328
|
+
}
|