agentspd 1.0.0 → 1.1.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.
@@ -1 +1 @@
1
- {"version":3,"file":"policies.d.ts","sourceRoot":"","sources":["../../src/commands/policies.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAkDpC,wBAAgB,qBAAqB,IAAI,OAAO,CA8V/C"}
1
+ {"version":3,"file":"policies.d.ts","sourceRoot":"","sources":["../../src/commands/policies.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAkDpC,wBAAgB,qBAAqB,IAAI,OAAO,CAqa/C"}
@@ -74,17 +74,65 @@ export function createPoliciesCommand() {
74
74
  content = DEFAULT_POLICY_TEMPLATE;
75
75
  }
76
76
  else {
77
- output.info('Enter policy YAML (end with Ctrl+D on a new line):');
78
- console.log();
79
- const answers = await inquirer.prompt([
80
- {
81
- type: 'editor',
82
- name: 'content',
83
- message: 'Policy content:',
84
- default: DEFAULT_POLICY_TEMPLATE,
85
- },
86
- ]);
87
- content = answers.content;
77
+ // Offer AI generation as the primary option
78
+ const { method } = await inquirer.prompt([{
79
+ type: 'list',
80
+ name: 'method',
81
+ message: 'Create policy from:',
82
+ choices: [
83
+ { name: 'Natural language description (AI generates the policy)', value: 'ai' },
84
+ { name: 'YAML editor (manual)', value: 'editor' },
85
+ { name: 'Default template', value: 'template' },
86
+ ],
87
+ }]);
88
+ if (method === 'ai') {
89
+ const { prompt } = await inquirer.prompt([{
90
+ type: 'input',
91
+ name: 'prompt',
92
+ message: 'Describe what your agent does and what it should be allowed to do:',
93
+ validate: (input) => input.length > 0 || 'Description is required',
94
+ }]);
95
+ const genSpinner = ora('Generating policy with AI...').start();
96
+ const genResult = await api.generatePolicy({ prompt, mode: 'single' });
97
+ if (genResult.error || !genResult.data?.generatedPolicy) {
98
+ genSpinner.fail('AI generation failed');
99
+ output.error(genResult.error?.message ?? 'Empty response');
100
+ return;
101
+ }
102
+ content = genResult.data.generatedPolicy;
103
+ genSpinner.succeed('Policy generated!');
104
+ console.log();
105
+ console.log(content);
106
+ console.log();
107
+ const { confirmed } = await inquirer.prompt([{
108
+ type: 'confirm',
109
+ name: 'confirmed',
110
+ message: 'Use this generated policy?',
111
+ default: true,
112
+ }]);
113
+ if (!confirmed) {
114
+ // Let them edit it
115
+ const editAnswers = await inquirer.prompt([{
116
+ type: 'editor',
117
+ name: 'content',
118
+ message: 'Edit the generated policy:',
119
+ default: content,
120
+ }]);
121
+ content = editAnswers.content;
122
+ }
123
+ }
124
+ else if (method === 'template') {
125
+ content = DEFAULT_POLICY_TEMPLATE;
126
+ }
127
+ else {
128
+ const answers = await inquirer.prompt([{
129
+ type: 'editor',
130
+ name: 'content',
131
+ message: 'Policy content:',
132
+ default: DEFAULT_POLICY_TEMPLATE,
133
+ }]);
134
+ content = answers.content;
135
+ }
88
136
  }
89
137
  // Get name and description if not provided
90
138
  if (!name) {
@@ -123,7 +171,12 @@ export function createPoliciesCommand() {
123
171
  }
124
172
  return;
125
173
  }
126
- validateSpinner.succeed('Policy validated');
174
+ if (options.json) {
175
+ validateSpinner.stop();
176
+ }
177
+ else {
178
+ validateSpinner.succeed('Policy validated');
179
+ }
127
180
  // Create policy
128
181
  const spinner = ora('Creating policy...').start();
129
182
  const result = await api.createPolicy({ name, description, content });
@@ -132,23 +185,26 @@ export function createPoliciesCommand() {
132
185
  output.error(result.error.message);
133
186
  return;
134
187
  }
135
- spinner.succeed('Policy created successfully!');
136
188
  if (options.json) {
189
+ spinner.stop();
137
190
  output.printJson(result.data);
138
191
  }
139
- else if (result.data) {
140
- console.log();
141
- output.printKeyValue([
142
- ['Policy ID', result.data.id],
143
- ['Name', result.data.name],
144
- ['Version', result.data.version],
145
- ['Active', result.data.isActive ? 'Yes' : 'No'],
146
- ['Created', output.formatDate(result.data.createdAt)],
147
- ]);
148
- console.log();
149
- output.info('Next steps:');
150
- console.log(` 1. Activate policy: ${output.highlight(`emotos policies activate ${result.data.id}`)}`);
151
- console.log(` 2. Assign to agent: ${output.highlight(`emotos agents create --policy ${result.data.id}`)}`);
192
+ else {
193
+ spinner.succeed('Policy created successfully!');
194
+ if (result.data) {
195
+ console.log();
196
+ output.printKeyValue([
197
+ ['Policy ID', result.data.id],
198
+ ['Name', result.data.name],
199
+ ['Version', result.data.version],
200
+ ['Active', result.data.isActive ? 'Yes' : 'No'],
201
+ ['Created', output.formatDate(result.data.createdAt)],
202
+ ]);
203
+ console.log();
204
+ output.info('Next steps:');
205
+ console.log(` 1. Activate policy: ${output.highlight(`emotos policies activate ${result.data.id}`)}`);
206
+ console.log(` 2. Assign to agent: ${output.highlight(`emotos agents create --policy ${result.data.id}`)}`);
207
+ }
152
208
  }
153
209
  });
154
210
  policies
@@ -181,10 +237,18 @@ export function createPoliciesCommand() {
181
237
  policies
182
238
  .command('get <policyId>')
183
239
  .alias('show')
184
- .description('Get policy details')
240
+ .description('Get policy details (accepts name or ID)')
185
241
  .option('--json', 'Output as JSON')
186
242
  .option('--content', 'Show policy content only')
187
- .action(async (policyId, options) => {
243
+ .action(async (policyIdOrName, options) => {
244
+ let policyId;
245
+ try {
246
+ policyId = await api.resolvePolicy(policyIdOrName);
247
+ }
248
+ catch (e) {
249
+ output.error(e.message);
250
+ return;
251
+ }
188
252
  const spinner = ora('Fetching policy...').start();
189
253
  const result = await api.getPolicy(policyId);
190
254
  if (result.error) {
@@ -218,10 +282,18 @@ export function createPoliciesCommand() {
218
282
  });
219
283
  policies
220
284
  .command('update <policyId>')
221
- .description('Update a policy')
285
+ .description('Update a policy (accepts name or ID)')
222
286
  .option('-f, --file <path>', 'Read policy content from file')
223
287
  .option('--json', 'Output as JSON')
224
- .action(async (policyId, options) => {
288
+ .action(async (policyIdOrName, options) => {
289
+ let policyId;
290
+ try {
291
+ policyId = await api.resolvePolicy(policyIdOrName);
292
+ }
293
+ catch (e) {
294
+ output.error(e.message);
295
+ return;
296
+ }
225
297
  let content;
226
298
  if (options.file) {
227
299
  if (!fs.existsSync(options.file)) {
@@ -259,7 +331,12 @@ export function createPoliciesCommand() {
259
331
  }
260
332
  return;
261
333
  }
262
- validateSpinner.succeed('Policy validated');
334
+ if (options.json) {
335
+ validateSpinner.stop();
336
+ }
337
+ else {
338
+ validateSpinner.succeed('Policy validated');
339
+ }
263
340
  // Update policy
264
341
  const spinner = ora('Updating policy...').start();
265
342
  const result = await api.updatePolicy(policyId, content);
@@ -268,15 +345,18 @@ export function createPoliciesCommand() {
268
345
  output.error(result.error.message);
269
346
  return;
270
347
  }
271
- spinner.succeed('Policy updated successfully!');
272
348
  if (options.json) {
349
+ spinner.stop();
273
350
  output.printJson(result.data);
274
351
  }
275
- else if (result.data) {
276
- output.printKeyValue([
277
- ['Version', result.data.version],
278
- ['Updated', result.data.updatedAt ? output.formatDate(result.data.updatedAt) : 'Now'],
279
- ]);
352
+ else {
353
+ spinner.succeed('Policy updated successfully!');
354
+ if (result.data) {
355
+ output.printKeyValue([
356
+ ['Version', result.data.version],
357
+ ['Updated', result.data.updatedAt ? output.formatDate(result.data.updatedAt) : 'Now'],
358
+ ]);
359
+ }
280
360
  }
281
361
  });
282
362
  policies
@@ -310,8 +390,16 @@ export function createPoliciesCommand() {
310
390
  });
311
391
  policies
312
392
  .command('activate <policyId>')
313
- .description('Activate a policy')
314
- .action(async (policyId) => {
393
+ .description('Activate a policy (accepts name or ID)')
394
+ .action(async (policyIdOrName) => {
395
+ let policyId;
396
+ try {
397
+ policyId = await api.resolvePolicy(policyIdOrName);
398
+ }
399
+ catch (e) {
400
+ output.error(e.message);
401
+ return;
402
+ }
315
403
  const spinner = ora('Activating policy...').start();
316
404
  const result = await api.activatePolicy(policyId);
317
405
  if (result.error) {
@@ -323,8 +411,16 @@ export function createPoliciesCommand() {
323
411
  });
324
412
  policies
325
413
  .command('deactivate <policyId>')
326
- .description('Deactivate a policy')
327
- .action(async (policyId) => {
414
+ .description('Deactivate a policy (accepts name or ID)')
415
+ .action(async (policyIdOrName) => {
416
+ let policyId;
417
+ try {
418
+ policyId = await api.resolvePolicy(policyIdOrName);
419
+ }
420
+ catch (e) {
421
+ output.error(e.message);
422
+ return;
423
+ }
328
424
  const spinner = ora('Deactivating policy...').start();
329
425
  const result = await api.deactivatePolicy(policyId);
330
426
  if (result.error) {
@@ -1 +1 @@
1
- {"version":3,"file":"threats.d.ts","sourceRoot":"","sources":["../../src/commands/threats.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,wBAAgB,oBAAoB,IAAI,OAAO,CAoL9C"}
1
+ {"version":3,"file":"threats.d.ts","sourceRoot":"","sources":["../../src/commands/threats.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,wBAAgB,oBAAoB,IAAI,OAAO,CAkO9C"}
@@ -82,38 +82,84 @@ export function createThreatsCommand() {
82
82
  output.heading('Threat Monitor');
83
83
  output.info('Press Ctrl+C to stop');
84
84
  console.log();
85
- let lastSeen = null;
86
- const fetchThreats = async () => {
87
- const result = await api.listThreats({
88
- agentId: options.agent,
89
- severity: options.severity,
90
- limit: 10,
85
+ // Try SSE stream first, fall back to polling
86
+ const streamPath = options.agent
87
+ ? `/threats/stream?agentId=${encodeURIComponent(options.agent)}`
88
+ : '/threats/stream';
89
+ const reader = await api.streamEvents(streamPath);
90
+ if (reader) {
91
+ output.info('Connected via real-time stream');
92
+ console.log();
93
+ const decoder = new TextDecoder();
94
+ let buffer = '';
95
+ const read = async () => {
96
+ try {
97
+ while (true) {
98
+ const { done, value } = await reader.read();
99
+ if (done)
100
+ break;
101
+ buffer += decoder.decode(value, { stream: true });
102
+ const lines = buffer.split('\n');
103
+ buffer = lines.pop() ?? '';
104
+ for (const line of lines) {
105
+ if (line.startsWith('data: ')) {
106
+ try {
107
+ const threat = JSON.parse(line.slice(6));
108
+ const severityStr = output.formatSeverity(threat.severity ?? 'medium');
109
+ const statusStr = output.formatStatus(threat.status ?? 'detected');
110
+ console.log(`[${output.formatDate(threat.createdAt ?? new Date().toISOString())}] ${severityStr} ${threat.threatType ?? 'threat'} - Agent: ${threat.agentId ?? 'unknown'} - Status: ${statusStr}`);
111
+ }
112
+ catch { /* ignore parse errors */ }
113
+ }
114
+ }
115
+ }
116
+ }
117
+ catch (err) {
118
+ if (err.name !== 'AbortError') {
119
+ output.warn('Stream disconnected, falling back to polling...');
120
+ }
121
+ }
122
+ };
123
+ read();
124
+ process.on('SIGINT', () => {
125
+ reader.cancel();
126
+ console.log();
127
+ output.info('Monitoring stopped');
128
+ process.exit(0);
91
129
  });
92
- if (result.data && result.data.items.length > 0) {
93
- const newThreats = lastSeen
94
- ? result.data.items.filter(t => t.id !== lastSeen && new Date(t.createdAt) > new Date(lastSeen))
95
- : result.data.items;
96
- if (newThreats.length > 0) {
97
- for (const threat of newThreats) {
98
- const severityStr = output.formatSeverity(threat.severity);
99
- const statusStr = output.formatStatus(threat.status);
100
- console.log(`[${output.formatDate(threat.createdAt)}] ${severityStr} ${threat.threatType} - Agent: ${threat.agentId} - Status: ${statusStr}`);
130
+ }
131
+ else {
132
+ // Fallback: polling every 3 seconds
133
+ let lastSeen = null;
134
+ const fetchThreats = async () => {
135
+ const result = await api.listThreats({
136
+ agentId: options.agent,
137
+ severity: options.severity,
138
+ limit: 10,
139
+ });
140
+ if (result.data && result.data.items.length > 0) {
141
+ const newThreats = lastSeen
142
+ ? result.data.items.filter(t => t.id !== lastSeen && new Date(t.createdAt) > new Date(lastSeen))
143
+ : result.data.items;
144
+ if (newThreats.length > 0) {
145
+ for (const threat of newThreats) {
146
+ const severityStr = output.formatSeverity(threat.severity);
147
+ const statusStr = output.formatStatus(threat.status);
148
+ console.log(`[${output.formatDate(threat.createdAt)}] ${severityStr} ${threat.threatType} - Agent: ${threat.agentId} - Status: ${statusStr}`);
149
+ }
150
+ lastSeen = result.data.items[0].id;
101
151
  }
102
- lastSeen = result.data.items[0].id;
103
152
  }
104
- }
105
- };
106
- // Initial fetch
107
- await fetchThreats();
108
- // Poll every 3 seconds
109
- const interval = setInterval(fetchThreats, 3000);
110
- // Handle Ctrl+C
111
- process.on('SIGINT', () => {
112
- clearInterval(interval);
113
- console.log();
114
- output.info('Monitoring stopped');
115
- process.exit(0);
116
- });
153
+ };
154
+ await fetchThreats();
155
+ const interval = setInterval(fetchThreats, 3000);
156
+ process.on('SIGINT', () => {
157
+ clearInterval(interval);
158
+ console.log();
159
+ output.info('Monitoring stopped');
160
+ process.exit(0);
161
+ });
162
+ }
117
163
  });
118
164
  threats
119
165
  .command('stats')
@@ -1 +1 @@
1
- {"version":3,"file":"webhooks.d.ts","sourceRoot":"","sources":["../../src/commands/webhooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAoBpC,wBAAgB,qBAAqB,IAAI,OAAO,CAkO/C"}
1
+ {"version":3,"file":"webhooks.d.ts","sourceRoot":"","sources":["../../src/commands/webhooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAoBpC,wBAAgB,qBAAqB,IAAI,OAAO,CAoO/C"}
@@ -85,30 +85,33 @@ export function createWebhooksCommand() {
85
85
  output.error(result.error.message);
86
86
  return;
87
87
  }
88
- spinner.succeed('Webhook created successfully!');
89
88
  if (options.json) {
89
+ spinner.stop();
90
90
  output.printJson(result.data);
91
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
- });
92
+ else {
93
+ spinner.succeed('Webhook created successfully!');
94
+ if (result.data) {
95
+ console.log();
96
+ output.printKeyValue([
97
+ ['Webhook ID', result.data.id],
98
+ ['URL', result.data.url],
99
+ ['Events', result.data.events.join(', ')],
100
+ ['Created', output.formatDate(result.data.createdAt)],
101
+ ]);
102
+ console.log();
103
+ output.info('Webhook payload example:');
104
+ output.printJson({
105
+ id: 'evt_123',
106
+ type: 'threat.blocked',
107
+ timestamp: new Date().toISOString(),
108
+ data: {
109
+ agentId: 'agent_abc',
110
+ threatType: 'prompt_injection',
111
+ severity: 'high',
112
+ },
113
+ });
114
+ }
112
115
  }
113
116
  });
114
117
  webhooks
@@ -0,0 +1,5 @@
1
+ import { Command } from 'commander';
2
+ export declare function createWorkspacesCommand(): Command;
3
+ export declare function createPolicyGenerateCommand(): Command;
4
+ export declare function createPolicyRefineCommand(): Command;
5
+ //# sourceMappingURL=workspaces.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspaces.d.ts","sourceRoot":"","sources":["../../src/commands/workspaces.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,wBAAgB,uBAAuB,IAAI,OAAO,CAuYjD;AAID,wBAAgB,2BAA2B,IAAI,OAAO,CAwCrD;AAED,wBAAgB,yBAAyB,IAAI,OAAO,CAkCnD"}