opc-agent 0.1.0 → 0.3.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 (79) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/CONTRIBUTING.md +75 -0
  3. package/README.md +105 -116
  4. package/README.zh-CN.md +58 -96
  5. package/dist/analytics/index.d.ts +31 -0
  6. package/dist/analytics/index.js +52 -0
  7. package/dist/channels/telegram.d.ts +21 -0
  8. package/dist/channels/telegram.js +120 -0
  9. package/dist/channels/websocket.d.ts +15 -0
  10. package/dist/channels/websocket.js +81 -0
  11. package/dist/cli.js +261 -27
  12. package/dist/core/agent.d.ts +2 -0
  13. package/dist/core/agent.js +3 -1
  14. package/dist/core/logger.d.ts +19 -0
  15. package/dist/core/logger.js +50 -0
  16. package/dist/core/room.d.ts +24 -0
  17. package/dist/core/room.js +97 -0
  18. package/dist/core/runtime.d.ts +11 -0
  19. package/dist/core/runtime.js +76 -0
  20. package/dist/core/sandbox.d.ts +28 -0
  21. package/dist/core/sandbox.js +118 -0
  22. package/dist/i18n/index.d.ts +13 -0
  23. package/dist/i18n/index.js +73 -0
  24. package/dist/index.d.ts +17 -1
  25. package/dist/index.js +28 -1
  26. package/dist/memory/deepbrain.d.ts +40 -0
  27. package/dist/memory/deepbrain.js +135 -0
  28. package/dist/plugins/index.d.ts +47 -0
  29. package/dist/plugins/index.js +59 -0
  30. package/dist/schema/oad.d.ts +294 -36
  31. package/dist/schema/oad.js +22 -3
  32. package/dist/templates/code-reviewer.d.ts +41 -0
  33. package/dist/templates/code-reviewer.js +38 -0
  34. package/dist/templates/content-writer.d.ts +36 -0
  35. package/dist/templates/content-writer.js +52 -0
  36. package/dist/templates/hr-recruiter.d.ts +36 -0
  37. package/dist/templates/hr-recruiter.js +52 -0
  38. package/dist/templates/knowledge-base.d.ts +44 -0
  39. package/dist/templates/knowledge-base.js +35 -0
  40. package/dist/templates/project-manager.d.ts +36 -0
  41. package/dist/templates/project-manager.js +52 -0
  42. package/dist/templates/sales-assistant.d.ts +56 -0
  43. package/dist/templates/sales-assistant.js +79 -0
  44. package/dist/tools/mcp.d.ts +32 -0
  45. package/dist/tools/mcp.js +49 -0
  46. package/package.json +11 -2
  47. package/src/analytics/index.ts +66 -0
  48. package/src/channels/telegram.ts +90 -0
  49. package/src/channels/websocket.ts +87 -0
  50. package/src/cli.ts +286 -33
  51. package/src/core/agent.ts +4 -1
  52. package/src/core/logger.ts +57 -0
  53. package/src/core/room.ts +109 -0
  54. package/src/core/runtime.ts +79 -1
  55. package/src/core/sandbox.ts +101 -0
  56. package/src/i18n/index.ts +79 -0
  57. package/src/index.ts +19 -1
  58. package/src/memory/deepbrain.ts +108 -0
  59. package/src/plugins/index.ts +87 -0
  60. package/src/schema/oad.ts +24 -2
  61. package/src/templates/code-reviewer.ts +34 -0
  62. package/src/templates/content-writer.ts +58 -0
  63. package/src/templates/hr-recruiter.ts +58 -0
  64. package/src/templates/knowledge-base.ts +31 -0
  65. package/src/templates/project-manager.ts +58 -0
  66. package/src/templates/sales-assistant.ts +79 -0
  67. package/src/tools/mcp.ts +76 -0
  68. package/templates/code-reviewer/README.md +27 -0
  69. package/templates/code-reviewer/oad.yaml +41 -0
  70. package/templates/knowledge-base/README.md +28 -0
  71. package/templates/knowledge-base/oad.yaml +38 -0
  72. package/templates/sales-assistant/README.md +26 -0
  73. package/templates/sales-assistant/oad.yaml +43 -0
  74. package/tests/analytics.test.ts +50 -0
  75. package/tests/i18n.test.ts +41 -0
  76. package/tests/mcp.test.ts +54 -0
  77. package/tests/plugin.test.ts +74 -0
  78. package/tests/room.test.ts +106 -0
  79. package/tests/sandbox.test.ts +46 -0
@@ -0,0 +1,21 @@
1
+ import { BaseChannel } from './index';
2
+ /**
3
+ * Telegram channel — basic webhook handler for Telegram Bot API.
4
+ * Set TELEGRAM_BOT_TOKEN env var or pass in config.
5
+ */
6
+ export declare class TelegramChannel extends BaseChannel {
7
+ readonly type = "telegram";
8
+ private token;
9
+ private webhookUrl?;
10
+ private server;
11
+ private port;
12
+ constructor(options?: {
13
+ token?: string;
14
+ webhookUrl?: string;
15
+ port?: number;
16
+ });
17
+ start(): Promise<void>;
18
+ stop(): Promise<void>;
19
+ private sendMessage;
20
+ }
21
+ //# sourceMappingURL=telegram.d.ts.map
@@ -0,0 +1,120 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.TelegramChannel = void 0;
37
+ const index_1 = require("./index");
38
+ /**
39
+ * Telegram channel — basic webhook handler for Telegram Bot API.
40
+ * Set TELEGRAM_BOT_TOKEN env var or pass in config.
41
+ */
42
+ class TelegramChannel extends index_1.BaseChannel {
43
+ type = 'telegram';
44
+ token;
45
+ webhookUrl;
46
+ server = null;
47
+ port;
48
+ constructor(options = {}) {
49
+ super();
50
+ this.token = options.token ?? process.env.TELEGRAM_BOT_TOKEN ?? '';
51
+ this.webhookUrl = options.webhookUrl;
52
+ this.port = options.port ?? 3001;
53
+ }
54
+ async start() {
55
+ if (!this.token) {
56
+ console.warn('[TelegramChannel] No bot token provided. Set TELEGRAM_BOT_TOKEN or pass token in config.');
57
+ return;
58
+ }
59
+ const express = (await Promise.resolve().then(() => __importStar(require('express')))).default;
60
+ const app = express();
61
+ app.use(express.json());
62
+ app.post(`/webhook/${this.token}`, async (req, res) => {
63
+ try {
64
+ const update = req.body;
65
+ if (update.message?.text && this.handler) {
66
+ const msg = {
67
+ id: `tg_${update.message.message_id}`,
68
+ role: 'user',
69
+ content: update.message.text,
70
+ timestamp: update.message.date * 1000,
71
+ metadata: {
72
+ sessionId: `tg_${update.message.chat.id}`,
73
+ chatId: update.message.chat.id,
74
+ userId: update.message.from?.id,
75
+ platform: 'telegram',
76
+ },
77
+ };
78
+ const response = await this.handler(msg);
79
+ await this.sendMessage(update.message.chat.id, response.content);
80
+ }
81
+ res.json({ ok: true });
82
+ }
83
+ catch (err) {
84
+ console.error('[TelegramChannel] Error handling update:', err);
85
+ res.status(500).json({ error: 'Internal error' });
86
+ }
87
+ });
88
+ app.get('/health', (_req, res) => {
89
+ res.json({ status: 'ok', channel: 'telegram' });
90
+ });
91
+ return new Promise((resolve) => {
92
+ this.server = app.listen(this.port, () => {
93
+ console.log(`[TelegramChannel] Webhook server on port ${this.port}`);
94
+ resolve();
95
+ });
96
+ });
97
+ }
98
+ async stop() {
99
+ return new Promise((resolve, reject) => {
100
+ if (!this.server)
101
+ return resolve();
102
+ this.server.close((err) => (err ? reject(err) : resolve()));
103
+ });
104
+ }
105
+ async sendMessage(chatId, text) {
106
+ const url = `https://api.telegram.org/bot${this.token}/sendMessage`;
107
+ try {
108
+ await fetch(url, {
109
+ method: 'POST',
110
+ headers: { 'Content-Type': 'application/json' },
111
+ body: JSON.stringify({ chat_id: chatId, text, parse_mode: 'Markdown' }),
112
+ });
113
+ }
114
+ catch (err) {
115
+ console.error('[TelegramChannel] Failed to send message:', err);
116
+ }
117
+ }
118
+ }
119
+ exports.TelegramChannel = TelegramChannel;
120
+ //# sourceMappingURL=telegram.js.map
@@ -0,0 +1,15 @@
1
+ import { BaseChannel } from './index';
2
+ /**
3
+ * WebSocket channel — real-time bidirectional communication.
4
+ */
5
+ export declare class WebSocketChannel extends BaseChannel {
6
+ readonly type = "websocket";
7
+ private wss;
8
+ private port;
9
+ private clients;
10
+ constructor(port?: number);
11
+ start(): Promise<void>;
12
+ stop(): Promise<void>;
13
+ broadcast(content: string): void;
14
+ }
15
+ //# sourceMappingURL=websocket.d.ts.map
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WebSocketChannel = void 0;
4
+ const index_1 = require("./index");
5
+ const ws_1 = require("ws");
6
+ /**
7
+ * WebSocket channel — real-time bidirectional communication.
8
+ */
9
+ class WebSocketChannel extends index_1.BaseChannel {
10
+ type = 'websocket';
11
+ wss = null;
12
+ port;
13
+ clients = new Set();
14
+ constructor(port = 3002) {
15
+ super();
16
+ this.port = port;
17
+ }
18
+ async start() {
19
+ return new Promise((resolve) => {
20
+ this.wss = new ws_1.WebSocketServer({ port: this.port });
21
+ this.wss.on('connection', (ws) => {
22
+ this.clients.add(ws);
23
+ ws.on('message', async (data) => {
24
+ if (!this.handler)
25
+ return;
26
+ try {
27
+ const parsed = JSON.parse(data.toString());
28
+ const msg = {
29
+ id: parsed.id ?? `ws_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
30
+ role: 'user',
31
+ content: parsed.content ?? parsed.message ?? data.toString(),
32
+ timestamp: Date.now(),
33
+ metadata: {
34
+ sessionId: parsed.sessionId ?? 'ws-default',
35
+ platform: 'websocket',
36
+ },
37
+ };
38
+ const response = await this.handler(msg);
39
+ ws.send(JSON.stringify({
40
+ id: response.id,
41
+ content: response.content,
42
+ timestamp: response.timestamp,
43
+ }));
44
+ }
45
+ catch (err) {
46
+ ws.send(JSON.stringify({ error: 'Invalid message format' }));
47
+ }
48
+ });
49
+ ws.on('close', () => {
50
+ this.clients.delete(ws);
51
+ });
52
+ ws.send(JSON.stringify({ type: 'connected', timestamp: Date.now() }));
53
+ });
54
+ this.wss.on('listening', () => {
55
+ console.log(`[WebSocketChannel] Listening on port ${this.port}`);
56
+ resolve();
57
+ });
58
+ });
59
+ }
60
+ async stop() {
61
+ for (const client of this.clients) {
62
+ client.close();
63
+ }
64
+ this.clients.clear();
65
+ return new Promise((resolve, reject) => {
66
+ if (!this.wss)
67
+ return resolve();
68
+ this.wss.close((err) => (err ? reject(err) : resolve()));
69
+ });
70
+ }
71
+ broadcast(content) {
72
+ const msg = JSON.stringify({ type: 'broadcast', content, timestamp: Date.now() });
73
+ for (const client of this.clients) {
74
+ if (client.readyState === 1) { // OPEN
75
+ client.send(msg);
76
+ }
77
+ }
78
+ }
79
+ }
80
+ exports.WebSocketChannel = WebSocketChannel;
81
+ //# sourceMappingURL=websocket.js.map
package/dist/cli.js CHANGED
@@ -38,46 +38,148 @@ const commander_1 = require("commander");
38
38
  const fs = __importStar(require("fs"));
39
39
  const path = __importStar(require("path"));
40
40
  const yaml = __importStar(require("js-yaml"));
41
+ const readline = __importStar(require("readline"));
41
42
  const runtime_1 = require("./core/runtime");
42
43
  const customer_service_1 = require("./templates/customer-service");
44
+ const sales_assistant_1 = require("./templates/sales-assistant");
45
+ const knowledge_base_1 = require("./templates/knowledge-base");
46
+ const code_reviewer_1 = require("./templates/code-reviewer");
47
+ const hr_recruiter_1 = require("./templates/hr-recruiter");
48
+ const project_manager_1 = require("./templates/project-manager");
49
+ const content_writer_1 = require("./templates/content-writer");
43
50
  const customer_service_2 = require("./templates/customer-service");
51
+ const analytics_1 = require("./analytics");
44
52
  const program = new commander_1.Command();
53
+ const color = {
54
+ green: (s) => `\x1b[32m${s}\x1b[0m`,
55
+ red: (s) => `\x1b[31m${s}\x1b[0m`,
56
+ yellow: (s) => `\x1b[33m${s}\x1b[0m`,
57
+ blue: (s) => `\x1b[34m${s}\x1b[0m`,
58
+ cyan: (s) => `\x1b[36m${s}\x1b[0m`,
59
+ bold: (s) => `\x1b[1m${s}\x1b[0m`,
60
+ dim: (s) => `\x1b[2m${s}\x1b[0m`,
61
+ };
62
+ const icon = {
63
+ success: color.green('āœ”'),
64
+ error: color.red('✘'),
65
+ warn: color.yellow('⚠'),
66
+ info: color.blue('ℹ'),
67
+ rocket: 'šŸš€',
68
+ package: 'šŸ“¦',
69
+ search: 'šŸ”',
70
+ gear: 'āš™ļø',
71
+ file: 'šŸ“„',
72
+ };
73
+ const TEMPLATES = {
74
+ 'customer-service': { label: 'Customer Service — FAQ + human handoff', factory: customer_service_1.createCustomerServiceConfig },
75
+ 'sales-assistant': { label: 'Sales Assistant — product Q&A + lead capture', factory: sales_assistant_1.createSalesAssistantConfig },
76
+ 'knowledge-base': { label: 'Knowledge Base — RAG with DeepBrain', factory: knowledge_base_1.createKnowledgeBaseConfig },
77
+ 'code-reviewer': { label: 'Code Reviewer — bug detection + style checks', factory: code_reviewer_1.createCodeReviewerConfig },
78
+ 'hr-recruiter': { label: 'HR Recruiter — resume screening + interview scheduling', factory: hr_recruiter_1.createHRRecruiterConfig },
79
+ 'project-manager': { label: 'Project Manager — task tracking + meeting notes', factory: project_manager_1.createProjectManagerConfig },
80
+ 'content-writer': { label: 'Content Writer — blog posts + social media + SEO', factory: content_writer_1.createContentWriterConfig },
81
+ };
82
+ async function prompt(question, defaultValue) {
83
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
84
+ const suffix = defaultValue ? ` ${color.dim(`(${defaultValue})`)}` : '';
85
+ return new Promise((resolve) => {
86
+ rl.question(`${question}${suffix}: `, (answer) => {
87
+ rl.close();
88
+ resolve(answer.trim() || defaultValue || '');
89
+ });
90
+ });
91
+ }
92
+ async function select(question, options) {
93
+ console.log(`\n${question}`);
94
+ options.forEach((opt, i) => {
95
+ console.log(` ${color.cyan(`${i + 1})`)} ${opt.label}`);
96
+ });
97
+ const answer = await prompt(`\nChoose ${color.dim('(1-' + options.length + ')')}`, '1');
98
+ const idx = parseInt(answer) - 1;
99
+ return options[Math.max(0, Math.min(idx, options.length - 1))].value;
100
+ }
45
101
  program
46
102
  .name('opc')
47
103
  .description('OPC Agent — Open Agent Framework for business workstations')
48
- .version('0.1.0');
104
+ .version('0.3.0');
49
105
  program
50
106
  .command('init')
51
- .description('Initialize a new OPC agent project')
52
- .argument('[name]', 'Project name', 'my-agent')
53
- .option('-t, --template <template>', 'Template to use', 'customer-service')
54
- .action(async (name, opts) => {
107
+ .description('Initialize a new OPC agent project (interactive)')
108
+ .argument('[name]', 'Project name')
109
+ .option('-t, --template <template>', 'Template to use')
110
+ .option('-y, --yes', 'Skip prompts, use defaults')
111
+ .action(async (nameArg, opts) => {
112
+ console.log(`\n${icon.rocket} ${color.bold('OPC Agent — Create New Project')}\n`);
113
+ const name = opts.yes ? (nameArg ?? 'my-agent') : (nameArg ?? await prompt('Project name', 'my-agent'));
114
+ const template = opts.yes
115
+ ? (opts.template ?? 'customer-service')
116
+ : (opts.template ?? await select('Select a template:', Object.entries(TEMPLATES).map(([value, { label }]) => ({ value, label }))));
55
117
  const dir = path.resolve(name);
56
118
  if (fs.existsSync(dir)) {
57
- console.error(`Directory ${name} already exists.`);
119
+ console.error(`\n${icon.error} Directory ${color.bold(name)} already exists.`);
58
120
  process.exit(1);
59
121
  }
60
122
  fs.mkdirSync(dir, { recursive: true });
61
- const config = (0, customer_service_1.createCustomerServiceConfig)();
123
+ const factory = TEMPLATES[template]?.factory ?? customer_service_1.createCustomerServiceConfig;
124
+ const config = factory();
62
125
  config.metadata.name = name;
63
126
  fs.writeFileSync(path.join(dir, 'oad.yaml'), yaml.dump(config, { lineWidth: 120 }));
64
- fs.writeFileSync(path.join(dir, 'README.md'), `# ${name}\n\nCreated with OPC Agent.\n\n## Run\n\n\`\`\`bash\nopc run\n\`\`\`\n`);
65
- console.log(`āœ… Created agent project: ${name}/`);
66
- console.log(` šŸ“„ oad.yaml — Agent definition`);
67
- console.log(` šŸ“– README.md`);
68
- console.log(`\nNext: cd ${name} && opc run`);
127
+ fs.writeFileSync(path.join(dir, 'README.md'), `# ${name}\n\nCreated with OPC Agent using the \`${template}\` template.\n\n## Run\n\n\`\`\`bash\nopc run\n\`\`\`\n`);
128
+ console.log(`\n${icon.success} Created agent project: ${color.bold(name + '/')}`);
129
+ console.log(` ${icon.file} oad.yaml — Agent definition`);
130
+ console.log(` ${icon.file} README.md`);
131
+ console.log(`\n Template: ${color.cyan(template)}`);
132
+ console.log(`\n${color.dim('Next:')} cd ${name} && opc run\n`);
69
133
  });
70
134
  program
71
135
  .command('create')
72
136
  .description('Create an agent from a template')
73
137
  .argument('<name>', 'Agent name')
74
138
  .option('-t, --template <template>', 'Template', 'customer-service')
75
- .action(async (name) => {
76
- const config = (0, customer_service_1.createCustomerServiceConfig)();
139
+ .action(async (name, opts) => {
140
+ const factory = TEMPLATES[opts.template]?.factory ?? customer_service_1.createCustomerServiceConfig;
141
+ const config = factory();
77
142
  config.metadata.name = name;
78
143
  const outFile = `${name}-oad.yaml`;
79
144
  fs.writeFileSync(outFile, yaml.dump(config, { lineWidth: 120 }));
80
- console.log(`āœ… Created ${outFile}`);
145
+ console.log(`${icon.success} Created ${color.bold(outFile)}`);
146
+ });
147
+ program
148
+ .command('info')
149
+ .description('Show agent info from OAD')
150
+ .option('-f, --file <file>', 'OAD file', 'oad.yaml')
151
+ .action(async (opts) => {
152
+ try {
153
+ const runtime = new runtime_1.AgentRuntime();
154
+ const config = await runtime.loadConfig(opts.file);
155
+ const m = config.metadata;
156
+ const s = config.spec;
157
+ console.log(`\n${icon.gear} ${color.bold('Agent Info')}\n`);
158
+ console.log(` Name: ${color.cyan(m.name)}`);
159
+ console.log(` Version: ${m.version}`);
160
+ console.log(` Description: ${m.description ?? color.dim('(none)')}`);
161
+ console.log(` Author: ${m.author ?? color.dim('(none)')}`);
162
+ console.log(` License: ${m.license}`);
163
+ console.log(` Model: ${s.model}`);
164
+ console.log(` Provider: ${s.provider?.default ?? 'deepseek'}`);
165
+ console.log(` Channels: ${s.channels.map(c => c.type).join(', ') || color.dim('(none)')}`);
166
+ console.log(` Skills: ${s.skills.map(sk => sk.name).join(', ') || color.dim('(none)')}`);
167
+ console.log(` Trust: ${s.dtv?.trust?.level ?? 'sandbox'}`);
168
+ console.log(` Streaming: ${s.streaming ? 'enabled' : 'disabled'}`);
169
+ console.log(` Locale: ${s.locale ?? 'en'}`);
170
+ if (s.room) {
171
+ console.log(` Room: ${s.room.name}`);
172
+ }
173
+ if (m.marketplace) {
174
+ console.log(` Category: ${m.marketplace.category ?? color.dim('(none)')}`);
175
+ console.log(` Pricing: ${m.marketplace.pricing ?? 'free'}`);
176
+ }
177
+ console.log();
178
+ }
179
+ catch (err) {
180
+ console.error(`${icon.error} Failed to read OAD:`, err instanceof Error ? err.message : err);
181
+ process.exit(1);
182
+ }
81
183
  });
82
184
  program
83
185
  .command('build')
@@ -87,10 +189,10 @@ program
87
189
  try {
88
190
  const runtime = new runtime_1.AgentRuntime();
89
191
  const config = await runtime.loadConfig(opts.file);
90
- console.log(`āœ… Valid OAD: ${config.metadata.name} v${config.metadata.version}`);
192
+ console.log(`${icon.success} Valid OAD: ${color.bold(config.metadata.name)} v${config.metadata.version}`);
91
193
  }
92
194
  catch (err) {
93
- console.error('āŒ Invalid OAD:', err instanceof Error ? err.message : err);
195
+ console.error(`${icon.error} Invalid OAD:`, err instanceof Error ? err.message : err);
94
196
  process.exit(1);
95
197
  }
96
198
  });
@@ -99,15 +201,15 @@ program
99
201
  .description('Run agent in sandbox mode')
100
202
  .option('-f, --file <file>', 'OAD file', 'oad.yaml')
101
203
  .action(async (opts) => {
102
- console.log('🧪 Running agent in sandbox mode...');
204
+ console.log(`\n${icon.gear} Running agent in sandbox mode...`);
103
205
  const runtime = new runtime_1.AgentRuntime();
104
206
  await runtime.loadConfig(opts.file);
105
207
  const agent = await runtime.initialize();
106
208
  runtime.registerSkill(new customer_service_2.FAQSkill());
107
209
  runtime.registerSkill(new customer_service_2.HandoffSkill());
108
- console.log(`āœ… Agent "${agent.name}" initialized in sandbox.`);
210
+ console.log(`${icon.success} Agent "${color.bold(agent.name)}" initialized in sandbox.`);
109
211
  console.log(` State: ${agent.state}`);
110
- console.log(` Send test message...`);
212
+ console.log(` Sending test message...`);
111
213
  const response = await agent.handleMessage({
112
214
  id: 'test_1',
113
215
  role: 'user',
@@ -115,7 +217,7 @@ program
115
217
  timestamp: Date.now(),
116
218
  });
117
219
  console.log(` Response: ${response.content}`);
118
- console.log('āœ… Sandbox test passed.');
220
+ console.log(`${icon.success} Sandbox test passed.\n`);
119
221
  });
120
222
  program
121
223
  .command('run')
@@ -129,18 +231,150 @@ program
129
231
  runtime.registerSkill(new customer_service_2.HandoffSkill());
130
232
  await runtime.start();
131
233
  const agent = runtime.getAgent();
132
- console.log(`šŸš€ Agent "${agent?.name}" is running.`);
234
+ console.log(`\n${icon.rocket} Agent "${color.bold(agent?.name ?? 'unknown')}" is running.\n`);
235
+ });
236
+ program
237
+ .command('dev')
238
+ .description('Hot-reload development mode')
239
+ .option('-f, --file <file>', 'OAD file', 'oad.yaml')
240
+ .action(async (opts) => {
241
+ console.log(`\n${icon.gear} ${color.bold('Development mode')} — watching for changes...\n`);
242
+ let runtime = null;
243
+ const startAgent = async () => {
244
+ try {
245
+ if (runtime)
246
+ await runtime.stop();
247
+ runtime = new runtime_1.AgentRuntime();
248
+ await runtime.loadConfig(opts.file);
249
+ await runtime.initialize();
250
+ runtime.registerSkill(new customer_service_2.FAQSkill());
251
+ runtime.registerSkill(new customer_service_2.HandoffSkill());
252
+ await runtime.start();
253
+ const agent = runtime.getAgent();
254
+ console.log(`${icon.success} Agent "${color.bold(agent?.name ?? 'unknown')}" restarted.`);
255
+ }
256
+ catch (err) {
257
+ console.error(`${icon.error} Failed to start:`, err instanceof Error ? err.message : err);
258
+ }
259
+ };
260
+ await startAgent();
261
+ const watchPaths = [opts.file, 'src'];
262
+ for (const watchPath of watchPaths) {
263
+ if (fs.existsSync(watchPath)) {
264
+ const isDir = fs.statSync(watchPath).isDirectory();
265
+ fs.watch(watchPath, { recursive: isDir }, async (_event, filename) => {
266
+ console.log(`\n${icon.info} ${color.dim(`Change detected: ${filename}`)} — restarting...`);
267
+ await startAgent();
268
+ });
269
+ }
270
+ }
133
271
  process.on('SIGINT', async () => {
134
- console.log('\nShutting down...');
135
- await runtime.stop();
272
+ console.log(`\n${color.dim('Shutting down dev mode...')}`);
273
+ if (runtime)
274
+ await runtime.stop();
136
275
  process.exit(0);
137
276
  });
138
277
  });
139
278
  program
140
279
  .command('publish')
141
- .description('Validate and package for OPC Registry (stub)')
142
- .action(async () => {
143
- console.log('šŸ“¦ Publishing is not yet available. Coming soon in OPC Registry v1.');
280
+ .description('Validate and package for OPC Registry')
281
+ .option('-f, --file <file>', 'OAD file', 'oad.yaml')
282
+ .action(async (opts) => {
283
+ try {
284
+ const runtime = new runtime_1.AgentRuntime();
285
+ const config = await runtime.loadConfig(opts.file);
286
+ const trust = config.spec.dtv?.trust?.level ?? 'sandbox';
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
+ if (trust === 'sandbox') {
291
+ console.log(` ${icon.warn} Trust level is 'sandbox'. Upgrade for marketplace listing.`);
292
+ }
293
+ const manifest = {
294
+ name: config.metadata.name,
295
+ version: config.metadata.version,
296
+ description: config.metadata.description,
297
+ author: config.metadata.author,
298
+ license: config.metadata.license,
299
+ trust,
300
+ category: config.metadata.marketplace?.category,
301
+ pricing: config.metadata.marketplace?.pricing ?? 'free',
302
+ tags: config.metadata.marketplace?.tags ?? [],
303
+ channels: config.spec.channels.map(c => c.type),
304
+ skills: config.spec.skills.map(s => s.name),
305
+ publishedAt: new Date().toISOString(),
306
+ };
307
+ fs.writeFileSync('opc-manifest.json', JSON.stringify(manifest, null, 2));
308
+ console.log(` ${icon.file} Generated opc-manifest.json`);
309
+ console.log(`\n🚧 OPC Registry is coming soon. Manifest saved locally.\n`);
310
+ }
311
+ catch (err) {
312
+ console.error(`${icon.error} Publish failed:`, err instanceof Error ? err.message : err);
313
+ process.exit(1);
314
+ }
315
+ });
316
+ program
317
+ .command('search')
318
+ .description('Search OPC Registry for agents and skills')
319
+ .argument('<query>', 'Search query')
320
+ .action(async (query) => {
321
+ console.log(`\n${icon.search} Searching OPC Registry for "${color.bold(query)}"...`);
322
+ console.log(`\n🚧 OPC Registry coming soon!`);
323
+ console.log(` The marketplace is under development.`);
324
+ console.log(` Browse templates with: ${color.cyan('opc init --template <name>')}`);
325
+ console.log(`\n Available templates: ${Object.keys(TEMPLATES).map(t => color.cyan(t)).join(', ')}\n`);
326
+ });
327
+ // ── Tool commands ────────────────────────────────────────────
328
+ const toolCmd = program.command('tool').description('Manage MCP tools');
329
+ toolCmd
330
+ .command('list')
331
+ .description('List available MCP tools')
332
+ .action(() => {
333
+ console.log(`\n${icon.gear} ${color.bold('MCP Tools')}\n`);
334
+ console.log(` ${color.dim('No tools installed yet.')}`);
335
+ console.log(`\n Add tools with: ${color.cyan('opc tool add <name>')}\n`);
336
+ });
337
+ toolCmd
338
+ .command('add')
339
+ .description('Add an MCP tool from registry')
340
+ .argument('<name>', 'Tool name')
341
+ .action((name) => {
342
+ console.log(`\n🚧 Tool registry coming soon!`);
343
+ console.log(` Would add tool: ${color.cyan(name)}\n`);
344
+ });
345
+ // ── Plugin commands ──────────────────────────────────────────
346
+ const pluginCmd = program.command('plugin').description('Manage plugins');
347
+ pluginCmd
348
+ .command('list')
349
+ .description('List installed plugins')
350
+ .action(() => {
351
+ console.log(`\n${icon.gear} ${color.bold('Installed Plugins')}\n`);
352
+ console.log(` ${color.dim('No plugins installed yet.')}`);
353
+ console.log(`\n Add plugins with: ${color.cyan('opc plugin add <name>')}\n`);
354
+ });
355
+ pluginCmd
356
+ .command('add')
357
+ .description('Add a plugin')
358
+ .argument('<name>', 'Plugin name')
359
+ .action((name) => {
360
+ console.log(`\n🚧 Plugin registry coming soon!`);
361
+ console.log(` Would add plugin: ${color.cyan(name)}\n`);
362
+ });
363
+ // ── Stats command ────────────────────────────────────────────
364
+ program
365
+ .command('stats')
366
+ .description('Show agent analytics')
367
+ .action(() => {
368
+ const analytics = new analytics_1.Analytics();
369
+ // Show demo stats
370
+ const snap = analytics.getSnapshot();
371
+ console.log(`\n${icon.gear} ${color.bold('Agent Analytics')}\n`);
372
+ console.log(` Messages Processed: ${snap.messagesProcessed}`);
373
+ console.log(` Avg Response Time: ${snap.avgResponseTimeMs}ms`);
374
+ console.log(` Error Count: ${snap.errorCount}`);
375
+ console.log(` Token Usage: ${snap.tokenUsage.total} (in: ${snap.tokenUsage.input}, out: ${snap.tokenUsage.output})`);
376
+ console.log(` Uptime: ${Math.round(snap.uptime / 1000)}s`);
377
+ console.log(`\n ${color.dim('Run an agent to collect analytics data.')}\n`);
144
378
  });
145
379
  program.parse();
146
380
  //# sourceMappingURL=cli.js.map
@@ -8,12 +8,14 @@ export declare class BaseAgent extends EventEmitter implements IAgent {
8
8
  private memory;
9
9
  private provider;
10
10
  private systemPrompt;
11
+ private historyLimit;
11
12
  constructor(options: {
12
13
  name: string;
13
14
  systemPrompt?: string;
14
15
  provider?: string;
15
16
  model?: string;
16
17
  memory?: MemoryStore;
18
+ historyLimit?: number;
17
19
  });
18
20
  get state(): AgentState;
19
21
  private transition;
@@ -12,12 +12,14 @@ class BaseAgent extends events_1.EventEmitter {
12
12
  memory;
13
13
  provider;
14
14
  systemPrompt;
15
+ historyLimit;
15
16
  constructor(options) {
16
17
  super();
17
18
  this.name = options.name;
18
19
  this.systemPrompt = options.systemPrompt ?? 'You are a helpful AI agent.';
19
20
  this.memory = options.memory ?? new memory_1.InMemoryStore();
20
21
  this.provider = (0, providers_1.createProvider)(options.provider ?? 'deepseek', options.model ?? 'deepseek-chat');
22
+ this.historyLimit = options.historyLimit ?? 50;
21
23
  }
22
24
  get state() {
23
25
  return this._state;
@@ -59,7 +61,7 @@ class BaseAgent extends events_1.EventEmitter {
59
61
  const context = {
60
62
  agentName: this.name,
61
63
  sessionId,
62
- messages: await this.memory.getConversation(sessionId),
64
+ messages: (await this.memory.getConversation(sessionId)).slice(-this.historyLimit),
63
65
  memory: this.memory,
64
66
  metadata: {},
65
67
  };
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Structured logger with log levels.
3
+ */
4
+ export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
5
+ export declare class Logger {
6
+ private context;
7
+ private level;
8
+ constructor(context: string, level?: LogLevel);
9
+ private shouldLog;
10
+ private format;
11
+ debug(message: string, data?: Record<string, unknown>): void;
12
+ info(message: string, data?: Record<string, unknown>): void;
13
+ warn(message: string, data?: Record<string, unknown>): void;
14
+ error(message: string, data?: Record<string, unknown>): void;
15
+ setLevel(level: LogLevel): void;
16
+ child(context: string): Logger;
17
+ }
18
+ export declare const defaultLogger: Logger;
19
+ //# sourceMappingURL=logger.d.ts.map