opc-agent 0.4.0 → 0.5.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/README.md +20 -0
- package/dist/cli.js +49 -1
- package/dist/deploy/openclaw.d.ts +14 -0
- package/dist/deploy/openclaw.js +208 -0
- package/examples/customer-service-demo/README.md +90 -0
- package/examples/customer-service-demo/oad.yaml +107 -0
- package/package.json +1 -1
- package/src/cli.ts +524 -472
- package/src/deploy/openclaw.ts +200 -0
package/src/cli.ts
CHANGED
|
@@ -1,472 +1,524 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { Command } from 'commander';
|
|
3
|
-
import * as fs from 'fs';
|
|
4
|
-
import * as path from 'path';
|
|
5
|
-
import * as yaml from 'js-yaml';
|
|
6
|
-
import * as readline from 'readline';
|
|
7
|
-
import { AgentRuntime } from './core/runtime';
|
|
8
|
-
import { createCustomerServiceConfig } from './templates/customer-service';
|
|
9
|
-
import { createSalesAssistantConfig } from './templates/sales-assistant';
|
|
10
|
-
import { createKnowledgeBaseConfig } from './templates/knowledge-base';
|
|
11
|
-
import { createCodeReviewerConfig } from './templates/code-reviewer';
|
|
12
|
-
import { createHRRecruiterConfig } from './templates/hr-recruiter';
|
|
13
|
-
import { createProjectManagerConfig } from './templates/project-manager';
|
|
14
|
-
import { createContentWriterConfig } from './templates/content-writer';
|
|
15
|
-
import { createLegalAssistantConfig } from './templates/legal-assistant';
|
|
16
|
-
import { createFinancialAdvisorConfig } from './templates/financial-advisor';
|
|
17
|
-
import { createExecutiveAssistantConfig } from './templates/executive-assistant';
|
|
18
|
-
import { FAQSkill, HandoffSkill } from './templates/customer-service';
|
|
19
|
-
import { Analytics } from './analytics';
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
'
|
|
50
|
-
'
|
|
51
|
-
'
|
|
52
|
-
'
|
|
53
|
-
'
|
|
54
|
-
'
|
|
55
|
-
'
|
|
56
|
-
'
|
|
57
|
-
'
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
.
|
|
84
|
-
.
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
.
|
|
89
|
-
.
|
|
90
|
-
.
|
|
91
|
-
.option('-
|
|
92
|
-
.
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
const
|
|
109
|
-
config
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
fs.writeFileSync(
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
console.log(
|
|
119
|
-
console.log(` ${icon.file}
|
|
120
|
-
console.log(
|
|
121
|
-
console.log(`\n${color.
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
.
|
|
127
|
-
.
|
|
128
|
-
.
|
|
129
|
-
.
|
|
130
|
-
|
|
131
|
-
const
|
|
132
|
-
config
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
.
|
|
141
|
-
.
|
|
142
|
-
.
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
const
|
|
146
|
-
const
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
console.log(
|
|
151
|
-
console.log(`
|
|
152
|
-
console.log(`
|
|
153
|
-
console.log(`
|
|
154
|
-
console.log(`
|
|
155
|
-
console.log(`
|
|
156
|
-
console.log(`
|
|
157
|
-
console.log(`
|
|
158
|
-
console.log(`
|
|
159
|
-
console.log(`
|
|
160
|
-
console.log(`
|
|
161
|
-
console.log(`
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
console.log(`
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
.
|
|
179
|
-
.
|
|
180
|
-
.
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
const
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
.
|
|
194
|
-
.
|
|
195
|
-
.
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
runtime.
|
|
201
|
-
runtime.registerSkill(new
|
|
202
|
-
|
|
203
|
-
console.log(
|
|
204
|
-
console.log(`
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
console.log(
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
.
|
|
219
|
-
.
|
|
220
|
-
.
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
await runtime.
|
|
224
|
-
runtime.
|
|
225
|
-
runtime.registerSkill(new
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
.
|
|
234
|
-
.
|
|
235
|
-
.
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
runtime
|
|
244
|
-
|
|
245
|
-
await runtime.
|
|
246
|
-
runtime.
|
|
247
|
-
runtime.registerSkill(new
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
.
|
|
279
|
-
.
|
|
280
|
-
.
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
const
|
|
284
|
-
const
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
console.log(
|
|
288
|
-
console.log(`
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
console.log(
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
.
|
|
321
|
-
.
|
|
322
|
-
.
|
|
323
|
-
|
|
324
|
-
console.log(`\n
|
|
325
|
-
console.log(
|
|
326
|
-
console.log(`
|
|
327
|
-
console.log(
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
.
|
|
336
|
-
.
|
|
337
|
-
.
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
.
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
.
|
|
398
|
-
.
|
|
399
|
-
.
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
console.log(
|
|
414
|
-
console.log(
|
|
415
|
-
});
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
.command('
|
|
419
|
-
.description('
|
|
420
|
-
.
|
|
421
|
-
.action(
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
.
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
const
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import * as fs from 'fs';
|
|
4
|
+
import * as path from 'path';
|
|
5
|
+
import * as yaml from 'js-yaml';
|
|
6
|
+
import * as readline from 'readline';
|
|
7
|
+
import { AgentRuntime } from './core/runtime';
|
|
8
|
+
import { createCustomerServiceConfig } from './templates/customer-service';
|
|
9
|
+
import { createSalesAssistantConfig } from './templates/sales-assistant';
|
|
10
|
+
import { createKnowledgeBaseConfig } from './templates/knowledge-base';
|
|
11
|
+
import { createCodeReviewerConfig } from './templates/code-reviewer';
|
|
12
|
+
import { createHRRecruiterConfig } from './templates/hr-recruiter';
|
|
13
|
+
import { createProjectManagerConfig } from './templates/project-manager';
|
|
14
|
+
import { createContentWriterConfig } from './templates/content-writer';
|
|
15
|
+
import { createLegalAssistantConfig } from './templates/legal-assistant';
|
|
16
|
+
import { createFinancialAdvisorConfig } from './templates/financial-advisor';
|
|
17
|
+
import { createExecutiveAssistantConfig } from './templates/executive-assistant';
|
|
18
|
+
import { FAQSkill, HandoffSkill } from './templates/customer-service';
|
|
19
|
+
import { Analytics } from './analytics';
|
|
20
|
+
import { deployToOpenClaw } from './deploy/openclaw';
|
|
21
|
+
import { WorkflowEngine } from './core/workflow';
|
|
22
|
+
import { VersionManager } from './core/versioning';
|
|
23
|
+
|
|
24
|
+
const program = new Command();
|
|
25
|
+
|
|
26
|
+
const color = {
|
|
27
|
+
green: (s: string) => `\x1b[32m${s}\x1b[0m`,
|
|
28
|
+
red: (s: string) => `\x1b[31m${s}\x1b[0m`,
|
|
29
|
+
yellow: (s: string) => `\x1b[33m${s}\x1b[0m`,
|
|
30
|
+
blue: (s: string) => `\x1b[34m${s}\x1b[0m`,
|
|
31
|
+
cyan: (s: string) => `\x1b[36m${s}\x1b[0m`,
|
|
32
|
+
bold: (s: string) => `\x1b[1m${s}\x1b[0m`,
|
|
33
|
+
dim: (s: string) => `\x1b[2m${s}\x1b[0m`,
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const icon = {
|
|
37
|
+
success: color.green('✔'),
|
|
38
|
+
error: color.red('✘'),
|
|
39
|
+
warn: color.yellow('⚠'),
|
|
40
|
+
info: color.blue('ℹ'),
|
|
41
|
+
rocket: '🚀',
|
|
42
|
+
package: '📦',
|
|
43
|
+
search: '🔍',
|
|
44
|
+
gear: '⚙️',
|
|
45
|
+
file: '📄',
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const TEMPLATES: Record<string, { label: string; factory: () => any }> = {
|
|
49
|
+
'customer-service': { label: 'Customer Service - FAQ + human handoff', factory: createCustomerServiceConfig },
|
|
50
|
+
'sales-assistant': { label: 'Sales Assistant - product Q&A + lead capture', factory: createSalesAssistantConfig },
|
|
51
|
+
'knowledge-base': { label: 'Knowledge Base - RAG with DeepBrain', factory: createKnowledgeBaseConfig },
|
|
52
|
+
'code-reviewer': { label: 'Code Reviewer - bug detection + style checks', factory: createCodeReviewerConfig },
|
|
53
|
+
'hr-recruiter': { label: 'HR Recruiter - resume screening + interview scheduling', factory: createHRRecruiterConfig },
|
|
54
|
+
'project-manager': { label: 'Project Manager - task tracking + meeting notes', factory: createProjectManagerConfig },
|
|
55
|
+
'content-writer': { label: 'Content Writer - blog posts + social media + SEO', factory: createContentWriterConfig },
|
|
56
|
+
'legal-assistant': { label: 'Legal Assistant - contract review + compliance + legal research', factory: createLegalAssistantConfig },
|
|
57
|
+
'financial-advisor': { label: 'Financial Advisor - budget analysis + expense tracking + planning', factory: createFinancialAdvisorConfig },
|
|
58
|
+
'executive-assistant': { label: 'Executive Assistant - calendar + email drafting + meeting prep', factory: createExecutiveAssistantConfig },
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
async function prompt(question: string, defaultValue?: string): Promise<string> {
|
|
62
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
63
|
+
const suffix = defaultValue ? ` ${color.dim(`(${defaultValue})`)}` : '';
|
|
64
|
+
return new Promise((resolve) => {
|
|
65
|
+
rl.question(`${question}${suffix}: `, (answer) => {
|
|
66
|
+
rl.close();
|
|
67
|
+
resolve(answer.trim() || defaultValue || '');
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async function select(question: string, options: { value: string; label: string }[]): Promise<string> {
|
|
73
|
+
console.log(`\n${question}`);
|
|
74
|
+
options.forEach((opt, i) => {
|
|
75
|
+
console.log(` ${color.cyan(`${i + 1})`)} ${opt.label}`);
|
|
76
|
+
});
|
|
77
|
+
const answer = await prompt(`\nChoose ${color.dim('(1-' + options.length + ')')}`, '1');
|
|
78
|
+
const idx = parseInt(answer) - 1;
|
|
79
|
+
return options[Math.max(0, Math.min(idx, options.length - 1))].value;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
program
|
|
83
|
+
.name('opc')
|
|
84
|
+
.description('OPC Agent - Open Agent Framework for business workstations')
|
|
85
|
+
.version('0.5.0');
|
|
86
|
+
|
|
87
|
+
program
|
|
88
|
+
.command('init')
|
|
89
|
+
.description('Initialize a new OPC agent project (interactive)')
|
|
90
|
+
.argument('[name]', 'Project name')
|
|
91
|
+
.option('-t, --template <template>', 'Template to use')
|
|
92
|
+
.option('-y, --yes', 'Skip prompts, use defaults')
|
|
93
|
+
.action(async (nameArg: string | undefined, opts: { template?: string; yes?: boolean }) => {
|
|
94
|
+
console.log(`\n${icon.rocket} ${color.bold('OPC Agent - Create New Project')}\n`);
|
|
95
|
+
|
|
96
|
+
const name = opts.yes ? (nameArg ?? 'my-agent') : (nameArg ?? await prompt('Project name', 'my-agent'));
|
|
97
|
+
const template = opts.yes
|
|
98
|
+
? (opts.template ?? 'customer-service')
|
|
99
|
+
: (opts.template ?? await select('Select a template:', Object.entries(TEMPLATES).map(([value, { label }]) => ({ value, label }))));
|
|
100
|
+
|
|
101
|
+
const dir = path.resolve(name);
|
|
102
|
+
if (fs.existsSync(dir)) {
|
|
103
|
+
console.error(`\n${icon.error} Directory ${color.bold(name)} already exists.`);
|
|
104
|
+
process.exit(1);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
108
|
+
const factory = TEMPLATES[template]?.factory ?? createCustomerServiceConfig;
|
|
109
|
+
const config = factory();
|
|
110
|
+
config.metadata.name = name;
|
|
111
|
+
|
|
112
|
+
fs.writeFileSync(path.join(dir, 'oad.yaml'), yaml.dump(config, { lineWidth: 120 }));
|
|
113
|
+
fs.writeFileSync(
|
|
114
|
+
path.join(dir, 'README.md'),
|
|
115
|
+
`# ${name}\n\nCreated with OPC Agent using the \`${template}\` template.\n\n## Run\n\n\`\`\`bash\nopc run\n\`\`\`\n`,
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
console.log(`\n${icon.success} Created agent project: ${color.bold(name + '/')}`);
|
|
119
|
+
console.log(` ${icon.file} oad.yaml - Agent definition`);
|
|
120
|
+
console.log(` ${icon.file} README.md`);
|
|
121
|
+
console.log(`\n Template: ${color.cyan(template)}`);
|
|
122
|
+
console.log(`\n${color.dim('Next:')} cd ${name} && opc run\n`);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
program
|
|
126
|
+
.command('create')
|
|
127
|
+
.description('Create an agent from a template')
|
|
128
|
+
.argument('<name>', 'Agent name')
|
|
129
|
+
.option('-t, --template <template>', 'Template', 'customer-service')
|
|
130
|
+
.action(async (name: string, opts: { template: string }) => {
|
|
131
|
+
const factory = TEMPLATES[opts.template]?.factory ?? createCustomerServiceConfig;
|
|
132
|
+
const config = factory();
|
|
133
|
+
config.metadata.name = name;
|
|
134
|
+
const outFile = `${name}-oad.yaml`;
|
|
135
|
+
fs.writeFileSync(outFile, yaml.dump(config, { lineWidth: 120 }));
|
|
136
|
+
console.log(`${icon.success} Created ${color.bold(outFile)}`);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
program
|
|
140
|
+
.command('info')
|
|
141
|
+
.description('Show agent info from OAD')
|
|
142
|
+
.option('-f, --file <file>', 'OAD file', 'oad.yaml')
|
|
143
|
+
.action(async (opts: { file: string }) => {
|
|
144
|
+
try {
|
|
145
|
+
const runtime = new AgentRuntime();
|
|
146
|
+
const config = await runtime.loadConfig(opts.file);
|
|
147
|
+
const m = config.metadata;
|
|
148
|
+
const s = config.spec;
|
|
149
|
+
|
|
150
|
+
console.log(`\n${icon.gear} ${color.bold('Agent Info')}\n`);
|
|
151
|
+
console.log(` Name: ${color.cyan(m.name)}`);
|
|
152
|
+
console.log(` Version: ${m.version}`);
|
|
153
|
+
console.log(` Description: ${m.description ?? color.dim('(none)')}`);
|
|
154
|
+
console.log(` Author: ${m.author ?? color.dim('(none)')}`);
|
|
155
|
+
console.log(` License: ${m.license}`);
|
|
156
|
+
console.log(` Model: ${s.model}`);
|
|
157
|
+
console.log(` Provider: ${s.provider?.default ?? 'deepseek'}`);
|
|
158
|
+
console.log(` Channels: ${s.channels.map(c => c.type).join(', ') || color.dim('(none)')}`);
|
|
159
|
+
console.log(` Skills: ${s.skills.map(sk => sk.name).join(', ') || color.dim('(none)')}`);
|
|
160
|
+
console.log(` Trust: ${s.dtv?.trust?.level ?? 'sandbox'}`);
|
|
161
|
+
console.log(` Streaming: ${s.streaming ? 'enabled' : 'disabled'}`);
|
|
162
|
+
console.log(` Locale: ${s.locale ?? 'en'}`);
|
|
163
|
+
if (s.room) {
|
|
164
|
+
console.log(` Room: ${s.room.name}`);
|
|
165
|
+
}
|
|
166
|
+
if (m.marketplace) {
|
|
167
|
+
console.log(` Category: ${m.marketplace.category ?? color.dim('(none)')}`);
|
|
168
|
+
console.log(` Pricing: ${m.marketplace.pricing ?? 'free'}`);
|
|
169
|
+
}
|
|
170
|
+
console.log();
|
|
171
|
+
} catch (err) {
|
|
172
|
+
console.error(`${icon.error} Failed to read OAD:`, err instanceof Error ? err.message : err);
|
|
173
|
+
process.exit(1);
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
program
|
|
178
|
+
.command('build')
|
|
179
|
+
.description('Validate OAD and compile')
|
|
180
|
+
.option('-f, --file <file>', 'OAD file', 'oad.yaml')
|
|
181
|
+
.action(async (opts: { file: string }) => {
|
|
182
|
+
try {
|
|
183
|
+
const runtime = new AgentRuntime();
|
|
184
|
+
const config = await runtime.loadConfig(opts.file);
|
|
185
|
+
console.log(`${icon.success} Valid OAD: ${color.bold(config.metadata.name)} v${config.metadata.version}`);
|
|
186
|
+
} catch (err) {
|
|
187
|
+
console.error(`${icon.error} Invalid OAD:`, err instanceof Error ? err.message : err);
|
|
188
|
+
process.exit(1);
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
program
|
|
193
|
+
.command('test')
|
|
194
|
+
.description('Run agent in sandbox mode')
|
|
195
|
+
.option('-f, --file <file>', 'OAD file', 'oad.yaml')
|
|
196
|
+
.action(async (opts: { file: string }) => {
|
|
197
|
+
console.log(`\n${icon.gear} Running agent in sandbox mode...`);
|
|
198
|
+
const runtime = new AgentRuntime();
|
|
199
|
+
await runtime.loadConfig(opts.file);
|
|
200
|
+
const agent = await runtime.initialize();
|
|
201
|
+
runtime.registerSkill(new FAQSkill());
|
|
202
|
+
runtime.registerSkill(new HandoffSkill());
|
|
203
|
+
console.log(`${icon.success} Agent "${color.bold(agent.name)}" initialized in sandbox.`);
|
|
204
|
+
console.log(` State: ${agent.state}`);
|
|
205
|
+
console.log(` Sending test message...`);
|
|
206
|
+
|
|
207
|
+
const response = await agent.handleMessage({
|
|
208
|
+
id: 'test_1',
|
|
209
|
+
role: 'user',
|
|
210
|
+
content: 'What are your business hours?',
|
|
211
|
+
timestamp: Date.now(),
|
|
212
|
+
});
|
|
213
|
+
console.log(` Response: ${response.content}`);
|
|
214
|
+
console.log(`${icon.success} Sandbox test passed.\n`);
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
program
|
|
218
|
+
.command('run')
|
|
219
|
+
.description('Start agent with channels')
|
|
220
|
+
.option('-f, --file <file>', 'OAD file', 'oad.yaml')
|
|
221
|
+
.action(async (opts: { file: string }) => {
|
|
222
|
+
const runtime = new AgentRuntime();
|
|
223
|
+
await runtime.loadConfig(opts.file);
|
|
224
|
+
await runtime.initialize();
|
|
225
|
+
runtime.registerSkill(new FAQSkill());
|
|
226
|
+
runtime.registerSkill(new HandoffSkill());
|
|
227
|
+
await runtime.start();
|
|
228
|
+
const agent = runtime.getAgent();
|
|
229
|
+
console.log(`\n${icon.rocket} Agent "${color.bold(agent?.name ?? 'unknown')}" is running.\n`);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
program
|
|
233
|
+
.command('dev')
|
|
234
|
+
.description('Hot-reload development mode')
|
|
235
|
+
.option('-f, --file <file>', 'OAD file', 'oad.yaml')
|
|
236
|
+
.action(async (opts: { file: string }) => {
|
|
237
|
+
console.log(`\n${icon.gear} ${color.bold('Development mode')} - watching for changes...\n`);
|
|
238
|
+
|
|
239
|
+
let runtime: AgentRuntime | null = null;
|
|
240
|
+
|
|
241
|
+
const startAgent = async () => {
|
|
242
|
+
try {
|
|
243
|
+
if (runtime) await runtime.stop();
|
|
244
|
+
runtime = new AgentRuntime();
|
|
245
|
+
await runtime.loadConfig(opts.file);
|
|
246
|
+
await runtime.initialize();
|
|
247
|
+
runtime.registerSkill(new FAQSkill());
|
|
248
|
+
runtime.registerSkill(new HandoffSkill());
|
|
249
|
+
await runtime.start();
|
|
250
|
+
const agent = runtime.getAgent();
|
|
251
|
+
console.log(`${icon.success} Agent "${color.bold(agent?.name ?? 'unknown')}" restarted.`);
|
|
252
|
+
} catch (err) {
|
|
253
|
+
console.error(`${icon.error} Failed to start:`, err instanceof Error ? err.message : err);
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
await startAgent();
|
|
258
|
+
|
|
259
|
+
const watchPaths = [opts.file, 'src'];
|
|
260
|
+
for (const watchPath of watchPaths) {
|
|
261
|
+
if (fs.existsSync(watchPath)) {
|
|
262
|
+
const isDir = fs.statSync(watchPath).isDirectory();
|
|
263
|
+
fs.watch(watchPath, { recursive: isDir }, async (_event, filename) => {
|
|
264
|
+
console.log(`\n${icon.info} ${color.dim(`Change detected: ${filename}`)} - restarting...`);
|
|
265
|
+
await startAgent();
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
process.on('SIGINT', async () => {
|
|
271
|
+
console.log(`\n${color.dim('Shutting down dev mode...')}`);
|
|
272
|
+
if (runtime) await runtime.stop();
|
|
273
|
+
process.exit(0);
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
program
|
|
278
|
+
.command('publish')
|
|
279
|
+
.description('Validate and package for OPC Registry')
|
|
280
|
+
.option('-f, --file <file>', 'OAD file', 'oad.yaml')
|
|
281
|
+
.action(async (opts: { file: string }) => {
|
|
282
|
+
try {
|
|
283
|
+
const runtime = new AgentRuntime();
|
|
284
|
+
const config = await runtime.loadConfig(opts.file);
|
|
285
|
+
const trust = config.spec.dtv?.trust?.level ?? 'sandbox';
|
|
286
|
+
|
|
287
|
+
console.log(`\n${icon.package} Publishing: ${color.bold(config.metadata.name)} v${config.metadata.version}`);
|
|
288
|
+
console.log(` ${icon.success} OAD validation passed`);
|
|
289
|
+
console.log(` 🔐 Trust level: ${trust}`);
|
|
290
|
+
|
|
291
|
+
if (trust === 'sandbox') {
|
|
292
|
+
console.log(` ${icon.warn} Trust level is 'sandbox'. Upgrade for marketplace listing.`);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const manifest = {
|
|
296
|
+
name: config.metadata.name,
|
|
297
|
+
version: config.metadata.version,
|
|
298
|
+
description: config.metadata.description,
|
|
299
|
+
author: config.metadata.author,
|
|
300
|
+
license: config.metadata.license,
|
|
301
|
+
trust,
|
|
302
|
+
category: config.metadata.marketplace?.category,
|
|
303
|
+
pricing: config.metadata.marketplace?.pricing ?? 'free',
|
|
304
|
+
tags: config.metadata.marketplace?.tags ?? [],
|
|
305
|
+
channels: config.spec.channels.map(c => c.type),
|
|
306
|
+
skills: config.spec.skills.map(s => s.name),
|
|
307
|
+
publishedAt: new Date().toISOString(),
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
fs.writeFileSync('opc-manifest.json', JSON.stringify(manifest, null, 2));
|
|
311
|
+
console.log(` ${icon.file} Generated opc-manifest.json`);
|
|
312
|
+
console.log(`\n🚧 OPC Registry is coming soon. Manifest saved locally.\n`);
|
|
313
|
+
} catch (err) {
|
|
314
|
+
console.error(`${icon.error} Publish failed:`, err instanceof Error ? err.message : err);
|
|
315
|
+
process.exit(1);
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
program
|
|
320
|
+
.command('search')
|
|
321
|
+
.description('Search OPC Registry for agents and skills')
|
|
322
|
+
.argument('<query>', 'Search query')
|
|
323
|
+
.action(async (query: string) => {
|
|
324
|
+
console.log(`\n${icon.search} Searching OPC Registry for "${color.bold(query)}"...`);
|
|
325
|
+
console.log(`\n🚧 OPC Registry coming soon!`);
|
|
326
|
+
console.log(` The marketplace is under development.`);
|
|
327
|
+
console.log(` Browse templates with: ${color.cyan('opc init --template <name>')}`);
|
|
328
|
+
console.log(`\n Available templates: ${Object.keys(TEMPLATES).map(t => color.cyan(t)).join(', ')}\n`);
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
// ── Deploy command ────────────────────────────────────────────
|
|
332
|
+
|
|
333
|
+
program
|
|
334
|
+
.command('deploy')
|
|
335
|
+
.description('Deploy agent to a target runtime')
|
|
336
|
+
.option('-f, --file <file>', 'OAD file', 'oad.yaml')
|
|
337
|
+
.option('-t, --target <target>', 'Deploy target', 'openclaw')
|
|
338
|
+
.option('-o, --output <dir>', 'Output directory')
|
|
339
|
+
.option('--install', 'Also register in OpenClaw config')
|
|
340
|
+
.action(async (opts: { file: string; target: string; output?: string; install?: boolean }) => {
|
|
341
|
+
if (opts.target !== 'openclaw') {
|
|
342
|
+
console.error(`${icon.error} Unknown target: ${color.bold(opts.target)}. Supported: openclaw`);
|
|
343
|
+
process.exit(1);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
try {
|
|
347
|
+
const runtime = new AgentRuntime();
|
|
348
|
+
const config = await runtime.loadConfig(opts.file);
|
|
349
|
+
const agentId = config.metadata.name.toLowerCase().replace(/[^a-z0-9-]/g, '-');
|
|
350
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE || '';
|
|
351
|
+
const defaultOutput = path.join(homeDir, '.openclaw', 'agents', agentId, 'workspace');
|
|
352
|
+
const outputDir = path.resolve(opts.output ?? defaultOutput);
|
|
353
|
+
|
|
354
|
+
console.log(`\n${icon.rocket} ${color.bold('Deploy to OpenClaw')}\n`);
|
|
355
|
+
console.log(` Agent: ${color.cyan(config.metadata.name)} v${config.metadata.version}`);
|
|
356
|
+
console.log(` Target: ${color.cyan('OpenClaw')}`);
|
|
357
|
+
console.log(` Output: ${color.dim(outputDir)}`);
|
|
358
|
+
|
|
359
|
+
const result = deployToOpenClaw({ oad: config, outputDir, install: opts.install });
|
|
360
|
+
|
|
361
|
+
console.log(`\n${icon.success} Generated ${result.files.length} files:`);
|
|
362
|
+
for (const f of result.files) {
|
|
363
|
+
console.log(` ${icon.file} ${f}`);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
if (result.installed) {
|
|
367
|
+
console.log(`\n${icon.success} Registered in OpenClaw config: ${color.dim(result.configPath!)}`);
|
|
368
|
+
console.log(`\n${color.dim('Next:')} Restart OpenClaw gateway to pick up the new agent.`);
|
|
369
|
+
console.log(` ${color.cyan('openclaw gateway restart')}\n`);
|
|
370
|
+
} else if (opts.install) {
|
|
371
|
+
console.log(`\n${icon.warn} Could not auto-register. Add the agent manually to openclaw.json.`);
|
|
372
|
+
} else {
|
|
373
|
+
console.log(`\n${color.dim('Next:')} Copy the output to your OpenClaw agents directory, or re-run with ${color.cyan('--install')}`);
|
|
374
|
+
console.log(` ${color.cyan(`opc deploy --target openclaw --install`)}\n`);
|
|
375
|
+
}
|
|
376
|
+
} catch (err) {
|
|
377
|
+
console.error(`${icon.error} Deploy failed:`, err instanceof Error ? err.message : err);
|
|
378
|
+
process.exit(1);
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
// ── Tool commands ────────────────────────────────────────────
|
|
383
|
+
|
|
384
|
+
const toolCmd = program.command('tool').description('Manage MCP tools');
|
|
385
|
+
|
|
386
|
+
toolCmd
|
|
387
|
+
.command('list')
|
|
388
|
+
.description('List available MCP tools')
|
|
389
|
+
.action(() => {
|
|
390
|
+
console.log(`\n${icon.gear} ${color.bold('MCP Tools')}\n`);
|
|
391
|
+
console.log(` ${color.dim('No tools installed yet.')}`);
|
|
392
|
+
console.log(`\n Add tools with: ${color.cyan('opc tool add <name>')}\n`);
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
toolCmd
|
|
396
|
+
.command('add')
|
|
397
|
+
.description('Add an MCP tool from registry')
|
|
398
|
+
.argument('<name>', 'Tool name')
|
|
399
|
+
.action((name: string) => {
|
|
400
|
+
console.log(`\n🚧 Tool registry coming soon!`);
|
|
401
|
+
console.log(` Would add tool: ${color.cyan(name)}\n`);
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
// ── Plugin commands ──────────────────────────────────────────
|
|
405
|
+
|
|
406
|
+
const pluginCmd = program.command('plugin').description('Manage plugins');
|
|
407
|
+
|
|
408
|
+
pluginCmd
|
|
409
|
+
.command('list')
|
|
410
|
+
.description('List installed plugins')
|
|
411
|
+
.action(() => {
|
|
412
|
+
console.log(`\n${icon.gear} ${color.bold('Installed Plugins')}\n`);
|
|
413
|
+
console.log(` ${color.dim('No plugins installed yet.')}`);
|
|
414
|
+
console.log(`\n Add plugins with: ${color.cyan('opc plugin add <name>')}\n`);
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
pluginCmd
|
|
418
|
+
.command('add')
|
|
419
|
+
.description('Add a plugin')
|
|
420
|
+
.argument('<name>', 'Plugin name')
|
|
421
|
+
.action((name: string) => {
|
|
422
|
+
console.log(`\n🚧 Plugin registry coming soon!`);
|
|
423
|
+
console.log(` Would add plugin: ${color.cyan(name)}\n`);
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
// ── Stats command ────────────────────────────────────────────
|
|
427
|
+
|
|
428
|
+
program
|
|
429
|
+
.command('stats')
|
|
430
|
+
.description('Show agent analytics')
|
|
431
|
+
.action(() => {
|
|
432
|
+
const analytics = new Analytics();
|
|
433
|
+
// Show demo stats
|
|
434
|
+
const snap = analytics.getSnapshot();
|
|
435
|
+
console.log(`\n${icon.gear} ${color.bold('Agent Analytics')}\n`);
|
|
436
|
+
console.log(` Messages Processed: ${snap.messagesProcessed}`);
|
|
437
|
+
console.log(` Avg Response Time: ${snap.avgResponseTimeMs}ms`);
|
|
438
|
+
console.log(` Error Count: ${snap.errorCount}`);
|
|
439
|
+
console.log(` Token Usage: ${snap.tokenUsage.total} (in: ${snap.tokenUsage.input}, out: ${snap.tokenUsage.output})`);
|
|
440
|
+
console.log(` Uptime: ${Math.round(snap.uptime / 1000)}s`);
|
|
441
|
+
console.log(`\n ${color.dim('Run an agent to collect analytics data.')}\n`);
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
// 🔄 Workflow commands ────────────────────────────────────────
|
|
445
|
+
|
|
446
|
+
const workflowCmd = program.command('workflow').description('Manage workflows');
|
|
447
|
+
|
|
448
|
+
workflowCmd
|
|
449
|
+
.command('run')
|
|
450
|
+
.description('Run a workflow defined in OAD')
|
|
451
|
+
.argument('<name>', 'Workflow name')
|
|
452
|
+
.option('-f, --file <file>', 'OAD file', 'oad.yaml')
|
|
453
|
+
.action(async (name: string, opts: { file: string }) => {
|
|
454
|
+
console.log(`\n${icon.gear} Running workflow "${color.bold(name)}"...`);
|
|
455
|
+
const runtime = new AgentRuntime();
|
|
456
|
+
const config = await runtime.loadConfig(opts.file);
|
|
457
|
+
const workflows = config.spec.workflows ?? [];
|
|
458
|
+
const wfDef = workflows.find((w: any) => w.name === name);
|
|
459
|
+
if (!wfDef) {
|
|
460
|
+
console.error(`${icon.error} Workflow "${name}" not found in OAD.`);
|
|
461
|
+
process.exit(1);
|
|
462
|
+
}
|
|
463
|
+
const engine = new WorkflowEngine();
|
|
464
|
+
engine.registerWorkflow(wfDef as any);
|
|
465
|
+
console.log(`${icon.success} Workflow "${name}" loaded with ${(wfDef as any).steps?.length ?? 0} steps.`);
|
|
466
|
+
console.log(`${color.dim(' Workflow execution requires a running agent context.')}\n`);
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
workflowCmd
|
|
470
|
+
.command('list')
|
|
471
|
+
.description('List workflows in OAD')
|
|
472
|
+
.option('-f, --file <file>', 'OAD file', 'oad.yaml')
|
|
473
|
+
.action(async (opts: { file: string }) => {
|
|
474
|
+
const runtime = new AgentRuntime();
|
|
475
|
+
const config = await runtime.loadConfig(opts.file);
|
|
476
|
+
const workflows = config.spec.workflows ?? [];
|
|
477
|
+
console.log(`\n${icon.gear} ${color.bold('Workflows')}\n`);
|
|
478
|
+
if (workflows.length === 0) {
|
|
479
|
+
console.log(` ${color.dim('No workflows defined.')}\n`);
|
|
480
|
+
} else {
|
|
481
|
+
for (const wf of workflows) {
|
|
482
|
+
console.log(` ${color.cyan((wf as any).name)} - ${(wf as any).description ?? color.dim('(no description)')}`);
|
|
483
|
+
}
|
|
484
|
+
console.log();
|
|
485
|
+
}
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
// 📦 Version commands ─────────────────────────────────────────
|
|
489
|
+
|
|
490
|
+
const versionCmd = program.command('version').description('Manage agent versions');
|
|
491
|
+
|
|
492
|
+
versionCmd
|
|
493
|
+
.command('list')
|
|
494
|
+
.description('List saved versions')
|
|
495
|
+
.action(() => {
|
|
496
|
+
const vm = new VersionManager();
|
|
497
|
+
const versions = vm.list();
|
|
498
|
+
console.log(`\n${icon.gear} ${color.bold('Agent Versions')}\n`);
|
|
499
|
+
if (versions.length === 0) {
|
|
500
|
+
console.log(` ${color.dim('No versions saved.')}\n`);
|
|
501
|
+
} else {
|
|
502
|
+
for (const v of versions) {
|
|
503
|
+
console.log(` ${color.cyan(v.version)} - ${new Date(v.timestamp).toISOString()} ${v.description ?? ''}`);
|
|
504
|
+
}
|
|
505
|
+
console.log();
|
|
506
|
+
}
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
versionCmd
|
|
510
|
+
.command('rollback')
|
|
511
|
+
.description('Rollback to a saved version')
|
|
512
|
+
.argument('<version>', 'Version to rollback to')
|
|
513
|
+
.action((version: string) => {
|
|
514
|
+
const vm = new VersionManager();
|
|
515
|
+
const oad = vm.rollback(version);
|
|
516
|
+
if (!oad) {
|
|
517
|
+
console.error(`${icon.error} Version "${version}" not found.`);
|
|
518
|
+
process.exit(1);
|
|
519
|
+
}
|
|
520
|
+
fs.writeFileSync('oad.yaml', oad);
|
|
521
|
+
console.log(`${icon.success} Rolled back to version ${color.bold(version)}.`);
|
|
522
|
+
});
|
|
523
|
+
|
|
524
|
+
program.parse();
|