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.
Files changed (42) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +333 -0
  3. package/dist/api.d.ts +198 -0
  4. package/dist/api.d.ts.map +1 -0
  5. package/dist/api.js +171 -0
  6. package/dist/commands/agents.d.ts +3 -0
  7. package/dist/commands/agents.d.ts.map +1 -0
  8. package/dist/commands/agents.js +277 -0
  9. package/dist/commands/audit.d.ts +3 -0
  10. package/dist/commands/audit.d.ts.map +1 -0
  11. package/dist/commands/audit.js +181 -0
  12. package/dist/commands/auth.d.ts +3 -0
  13. package/dist/commands/auth.d.ts.map +1 -0
  14. package/dist/commands/auth.js +226 -0
  15. package/dist/commands/config-cmd.d.ts +3 -0
  16. package/dist/commands/config-cmd.d.ts.map +1 -0
  17. package/dist/commands/config-cmd.js +111 -0
  18. package/dist/commands/index.d.ts +9 -0
  19. package/dist/commands/index.d.ts.map +1 -0
  20. package/dist/commands/index.js +8 -0
  21. package/dist/commands/init.d.ts +3 -0
  22. package/dist/commands/init.d.ts.map +1 -0
  23. package/dist/commands/init.js +275 -0
  24. package/dist/commands/policies.d.ts +3 -0
  25. package/dist/commands/policies.d.ts.map +1 -0
  26. package/dist/commands/policies.js +362 -0
  27. package/dist/commands/threats.d.ts +3 -0
  28. package/dist/commands/threats.d.ts.map +1 -0
  29. package/dist/commands/threats.js +161 -0
  30. package/dist/commands/webhooks.d.ts +3 -0
  31. package/dist/commands/webhooks.d.ts.map +1 -0
  32. package/dist/commands/webhooks.js +222 -0
  33. package/dist/config.d.ts +24 -0
  34. package/dist/config.d.ts.map +1 -0
  35. package/dist/config.js +58 -0
  36. package/dist/index.d.ts +3 -0
  37. package/dist/index.d.ts.map +1 -0
  38. package/dist/index.js +328 -0
  39. package/dist/output.d.ts +60 -0
  40. package/dist/output.d.ts.map +1 -0
  41. package/dist/output.js +212 -0
  42. 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
+ }
@@ -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 };
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -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
+ }