opc-agent 1.4.0 → 2.0.1

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 (198) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +91 -32
  3. package/dist/channels/email.d.ts +32 -26
  4. package/dist/channels/email.js +239 -62
  5. package/dist/channels/feishu.d.ts +21 -6
  6. package/dist/channels/feishu.js +225 -126
  7. package/dist/channels/telegram.d.ts +30 -9
  8. package/dist/channels/telegram.js +125 -33
  9. package/dist/channels/websocket.d.ts +46 -3
  10. package/dist/channels/websocket.js +306 -37
  11. package/dist/channels/wechat.d.ts +33 -13
  12. package/dist/channels/wechat.js +229 -42
  13. package/dist/cli.js +1127 -19
  14. package/dist/core/a2a.d.ts +17 -0
  15. package/dist/core/a2a.js +43 -1
  16. package/dist/core/agent.d.ts +39 -0
  17. package/dist/core/agent.js +228 -3
  18. package/dist/core/runtime.d.ts +7 -0
  19. package/dist/core/runtime.js +205 -2
  20. package/dist/core/sandbox.d.ts +26 -0
  21. package/dist/core/sandbox.js +117 -0
  22. package/dist/core/scheduler.d.ts +52 -0
  23. package/dist/core/scheduler.js +168 -0
  24. package/dist/core/subagent.d.ts +28 -0
  25. package/dist/core/subagent.js +65 -0
  26. package/dist/core/workflow-graph.d.ts +93 -0
  27. package/dist/core/workflow-graph.js +247 -0
  28. package/dist/daemon.d.ts +3 -0
  29. package/dist/daemon.js +134 -0
  30. package/dist/doctor.d.ts +15 -0
  31. package/dist/doctor.js +183 -0
  32. package/dist/eval/index.d.ts +65 -0
  33. package/dist/eval/index.js +191 -0
  34. package/dist/index.d.ts +37 -6
  35. package/dist/index.js +75 -3
  36. package/dist/plugins/content-filter.d.ts +7 -0
  37. package/dist/plugins/content-filter.js +25 -0
  38. package/dist/plugins/index.d.ts +42 -0
  39. package/dist/plugins/index.js +108 -2
  40. package/dist/plugins/logger.d.ts +6 -0
  41. package/dist/plugins/logger.js +20 -0
  42. package/dist/plugins/rate-limiter.d.ts +7 -0
  43. package/dist/plugins/rate-limiter.js +35 -0
  44. package/dist/protocols/a2a/client.d.ts +25 -0
  45. package/dist/protocols/a2a/client.js +115 -0
  46. package/dist/protocols/a2a/index.d.ts +6 -0
  47. package/dist/protocols/a2a/index.js +12 -0
  48. package/dist/protocols/a2a/server.d.ts +41 -0
  49. package/dist/protocols/a2a/server.js +295 -0
  50. package/dist/protocols/a2a/types.d.ts +91 -0
  51. package/dist/protocols/a2a/types.js +15 -0
  52. package/dist/protocols/a2a/utils.d.ts +6 -0
  53. package/dist/protocols/a2a/utils.js +47 -0
  54. package/dist/protocols/agui/client.d.ts +10 -0
  55. package/dist/protocols/agui/client.js +75 -0
  56. package/dist/protocols/agui/index.d.ts +4 -0
  57. package/dist/protocols/agui/index.js +25 -0
  58. package/dist/protocols/agui/server.d.ts +37 -0
  59. package/dist/protocols/agui/server.js +191 -0
  60. package/dist/protocols/agui/types.d.ts +107 -0
  61. package/dist/protocols/agui/types.js +17 -0
  62. package/dist/protocols/index.d.ts +2 -0
  63. package/dist/protocols/index.js +19 -0
  64. package/dist/protocols/mcp/agent-tools.d.ts +11 -0
  65. package/dist/protocols/mcp/agent-tools.js +129 -0
  66. package/dist/protocols/mcp/index.d.ts +5 -0
  67. package/dist/protocols/mcp/index.js +11 -0
  68. package/dist/protocols/mcp/server.d.ts +31 -0
  69. package/dist/protocols/mcp/server.js +248 -0
  70. package/dist/protocols/mcp/types.d.ts +92 -0
  71. package/dist/protocols/mcp/types.js +17 -0
  72. package/dist/providers/index.d.ts +5 -1
  73. package/dist/providers/index.js +16 -9
  74. package/dist/publish/index.d.ts +45 -0
  75. package/dist/publish/index.js +350 -0
  76. package/dist/schema/oad.d.ts +859 -67
  77. package/dist/schema/oad.js +47 -3
  78. package/dist/security/approval.d.ts +36 -0
  79. package/dist/security/approval.js +113 -0
  80. package/dist/security/index.d.ts +4 -0
  81. package/dist/security/index.js +8 -0
  82. package/dist/security/keys.d.ts +16 -0
  83. package/dist/security/keys.js +117 -0
  84. package/dist/skills/auto-learn.d.ts +28 -0
  85. package/dist/skills/auto-learn.js +257 -0
  86. package/dist/studio/server.d.ts +63 -0
  87. package/dist/studio/server.js +625 -0
  88. package/dist/studio-ui/index.html +662 -0
  89. package/dist/telemetry/index.d.ts +93 -0
  90. package/dist/telemetry/index.js +285 -0
  91. package/dist/tools/builtin/datetime.d.ts +3 -0
  92. package/dist/tools/builtin/datetime.js +44 -0
  93. package/dist/tools/builtin/file.d.ts +3 -0
  94. package/dist/tools/builtin/file.js +151 -0
  95. package/dist/tools/builtin/index.d.ts +15 -0
  96. package/dist/tools/builtin/index.js +30 -0
  97. package/dist/tools/builtin/shell.d.ts +3 -0
  98. package/dist/tools/builtin/shell.js +43 -0
  99. package/dist/tools/builtin/web.d.ts +3 -0
  100. package/dist/tools/builtin/web.js +37 -0
  101. package/dist/tools/mcp-client.d.ts +24 -0
  102. package/dist/tools/mcp-client.js +119 -0
  103. package/package.json +5 -3
  104. package/scripts/install.ps1 +31 -0
  105. package/scripts/install.sh +40 -0
  106. package/src/channels/email.ts +351 -177
  107. package/src/channels/feishu.ts +349 -236
  108. package/src/channels/telegram.ts +212 -90
  109. package/src/channels/websocket.ts +399 -87
  110. package/src/channels/wechat.ts +329 -149
  111. package/src/cli.ts +1201 -20
  112. package/src/core/a2a.ts +60 -0
  113. package/src/core/agent.ts +420 -152
  114. package/src/core/runtime.ts +174 -0
  115. package/src/core/sandbox.ts +143 -0
  116. package/src/core/scheduler.ts +187 -0
  117. package/src/core/subagent.ts +98 -0
  118. package/src/core/workflow-graph.ts +365 -0
  119. package/src/daemon.ts +96 -0
  120. package/src/doctor.ts +156 -0
  121. package/src/eval/index.ts +211 -0
  122. package/src/eval/suites/basic.json +16 -0
  123. package/src/eval/suites/memory.json +12 -0
  124. package/src/eval/suites/safety.json +14 -0
  125. package/src/index.ts +65 -6
  126. package/src/plugins/content-filter.ts +23 -0
  127. package/src/plugins/index.ts +133 -2
  128. package/src/plugins/logger.ts +18 -0
  129. package/src/plugins/rate-limiter.ts +38 -0
  130. package/src/protocols/a2a/client.ts +132 -0
  131. package/src/protocols/a2a/index.ts +8 -0
  132. package/src/protocols/a2a/server.ts +333 -0
  133. package/src/protocols/a2a/types.ts +88 -0
  134. package/src/protocols/a2a/utils.ts +50 -0
  135. package/src/protocols/agui/client.ts +83 -0
  136. package/src/protocols/agui/index.ts +4 -0
  137. package/src/protocols/agui/server.ts +218 -0
  138. package/src/protocols/agui/types.ts +153 -0
  139. package/src/protocols/index.ts +2 -0
  140. package/src/protocols/mcp/agent-tools.ts +134 -0
  141. package/src/protocols/mcp/index.ts +8 -0
  142. package/src/protocols/mcp/server.ts +262 -0
  143. package/src/protocols/mcp/types.ts +69 -0
  144. package/src/providers/index.ts +354 -339
  145. package/src/publish/index.ts +376 -0
  146. package/src/schema/oad.ts +204 -154
  147. package/src/security/approval.ts +131 -0
  148. package/src/security/index.ts +3 -0
  149. package/src/security/keys.ts +87 -0
  150. package/src/skills/auto-learn.ts +262 -0
  151. package/src/studio/server.ts +629 -0
  152. package/src/studio-ui/index.html +662 -0
  153. package/src/telemetry/index.ts +324 -0
  154. package/src/tools/builtin/datetime.ts +41 -0
  155. package/src/tools/builtin/file.ts +107 -0
  156. package/src/tools/builtin/index.ts +28 -0
  157. package/src/tools/builtin/shell.ts +43 -0
  158. package/src/tools/builtin/web.ts +35 -0
  159. package/src/tools/mcp-client.ts +131 -0
  160. package/src/types/agent-workstation.d.ts +2 -0
  161. package/tests/a2a-protocol.test.ts +285 -0
  162. package/tests/agui-protocol.test.ts +246 -0
  163. package/tests/auto-learn.test.ts +105 -0
  164. package/tests/builtin-tools.test.ts +83 -0
  165. package/tests/channels/discord.test.ts +79 -0
  166. package/tests/channels/email.test.ts +148 -0
  167. package/tests/channels/feishu.test.ts +123 -0
  168. package/tests/channels/telegram.test.ts +129 -0
  169. package/tests/channels/websocket.test.ts +53 -0
  170. package/tests/channels/wechat.test.ts +170 -0
  171. package/tests/chat-cli.test.ts +160 -0
  172. package/tests/cli.test.ts +46 -0
  173. package/tests/daemon.test.ts +135 -0
  174. package/tests/deepbrain-wire.test.ts +234 -0
  175. package/tests/doctor.test.ts +38 -0
  176. package/tests/eval.test.ts +173 -0
  177. package/tests/init-role.test.ts +124 -0
  178. package/tests/mcp-client.test.ts +92 -0
  179. package/tests/mcp-server.test.ts +178 -0
  180. package/tests/plugin-a2a-enhanced.test.ts +230 -0
  181. package/tests/publish.test.ts +231 -0
  182. package/tests/scheduler.test.ts +200 -0
  183. package/tests/security-enhanced.test.ts +233 -0
  184. package/tests/skill-learner.test.ts +161 -0
  185. package/tests/studio.test.ts +229 -0
  186. package/tests/subagent.test.ts +193 -0
  187. package/tests/telegram-discord.test.ts +60 -0
  188. package/tests/telemetry.test.ts +186 -0
  189. package/tests/tools/builtin-extended.test.ts +138 -0
  190. package/tests/workflow-graph.test.ts +279 -0
  191. package/tutorial/customer-service-agent/README.md +612 -0
  192. package/tutorial/customer-service-agent/SOUL.md +26 -0
  193. package/tutorial/customer-service-agent/agent.yaml +63 -0
  194. package/tutorial/customer-service-agent/package.json +19 -0
  195. package/tutorial/customer-service-agent/src/index.ts +69 -0
  196. package/tutorial/customer-service-agent/src/skills/faq.ts +27 -0
  197. package/tutorial/customer-service-agent/src/skills/ticket.ts +22 -0
  198. package/tutorial/customer-service-agent/tsconfig.json +14 -0
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.OADSchema = exports.SpecSchema = exports.StreamingSchema = exports.RoomSchema = exports.MetadataSchema = exports.MarketplaceSchema = exports.ProviderSchema = exports.DTVSchema = exports.TrustLevel = exports.MemorySchema = exports.LongTermMemorySchema = exports.ChannelSchema = exports.AuthSchema = exports.PluginRefSchema = exports.HITLSchema = exports.WebhookSchema = exports.VoiceSchema = exports.WorkflowSchema = exports.WorkflowStepSchema = exports.SkillRefSchema = void 0;
3
+ exports.OADSchema = exports.SpecSchema = exports.ProtocolsSchema = exports.AGUIProtocolSchema = exports.TelemetrySchema = exports.ToolsSchema = exports.MCPServeSchema = exports.MCPServerSchema = exports.StreamingSchema = exports.RoomSchema = exports.MetadataSchema = exports.MarketplaceSchema = exports.ProviderSchema = exports.DTVSchema = exports.TrustLevel = exports.MemorySchema = exports.LongTermMemorySchema = exports.ChannelSchema = exports.AuthSchema = exports.PluginRefSchema = exports.HITLSchema = exports.WebhookSchema = exports.VoiceSchema = exports.WorkflowSchema = exports.WorkflowStepSchema = exports.SkillRefSchema = void 0;
4
4
  const zod_1 = require("zod");
5
5
  // ─── OAD Schema v1 ───────────────────────────────────────────
6
6
  exports.SkillRefSchema = zod_1.z.object({
@@ -53,14 +53,20 @@ exports.AuthSchema = zod_1.z.object({
53
53
  sessionIsolation: zod_1.z.boolean().default(true),
54
54
  });
55
55
  exports.ChannelSchema = zod_1.z.object({
56
- type: zod_1.z.enum(['web', 'websocket', 'telegram', 'cli', 'voice', 'webhook']),
56
+ type: zod_1.z.enum(['web', 'websocket', 'telegram', 'cli', 'voice', 'webhook', 'wechat', 'feishu', 'email', 'slack', 'discord']),
57
57
  port: zod_1.z.number().optional(),
58
58
  config: zod_1.z.record(zod_1.z.unknown()).optional(),
59
59
  });
60
60
  exports.LongTermMemorySchema = zod_1.z.object({
61
61
  provider: zod_1.z.enum(['in-memory', 'deepbrain']).default('in-memory'),
62
62
  collection: zod_1.z.string().optional(),
63
- config: zod_1.z.record(zod_1.z.unknown()).optional(),
63
+ config: zod_1.z.object({
64
+ database: zod_1.z.string().optional(),
65
+ embeddingProvider: zod_1.z.string().optional(),
66
+ autoLearn: zod_1.z.boolean().optional(),
67
+ autoRecall: zod_1.z.boolean().optional(),
68
+ evolveInterval: zod_1.z.number().optional(),
69
+ }).passthrough().optional(),
64
70
  });
65
71
  exports.MemorySchema = zod_1.z.object({
66
72
  shortTerm: zod_1.z.boolean().default(true),
@@ -103,6 +109,41 @@ exports.StreamingSchema = zod_1.z.object({
103
109
  enabled: zod_1.z.boolean().default(false),
104
110
  chunkSize: zod_1.z.number().optional(),
105
111
  });
112
+ exports.MCPServerSchema = zod_1.z.object({
113
+ name: zod_1.z.string(),
114
+ command: zod_1.z.string(),
115
+ args: zod_1.z.array(zod_1.z.string()).optional(),
116
+ env: zod_1.z.record(zod_1.z.string()).optional(),
117
+ });
118
+ exports.MCPServeSchema = zod_1.z.object({
119
+ enabled: zod_1.z.boolean().default(false),
120
+ mode: zod_1.z.enum(['stdio', 'http']).default('stdio'),
121
+ port: zod_1.z.number().default(3002),
122
+ exposedTools: zod_1.z.array(zod_1.z.string()).optional(),
123
+ });
124
+ exports.ToolsSchema = zod_1.z.object({
125
+ builtin: zod_1.z.array(zod_1.z.string()).optional(),
126
+ mcp: zod_1.z.array(exports.MCPServerSchema).optional(),
127
+ });
128
+ exports.TelemetrySchema = zod_1.z.object({
129
+ enabled: zod_1.z.boolean().default(false),
130
+ exporter: zod_1.z.enum(['console', 'file', 'otlp']).default('console'),
131
+ endpoint: zod_1.z.string().optional(),
132
+ filePath: zod_1.z.string().optional(),
133
+ maxSpans: zod_1.z.number().optional(),
134
+ });
135
+ exports.AGUIProtocolSchema = zod_1.z.object({
136
+ enabled: zod_1.z.boolean().default(false),
137
+ path: zod_1.z.string().default('/agui'),
138
+ });
139
+ exports.ProtocolsSchema = zod_1.z.object({
140
+ a2a: zod_1.z.object({
141
+ enabled: zod_1.z.boolean().default(false),
142
+ port: zod_1.z.number().optional(),
143
+ }).optional(),
144
+ agui: exports.AGUIProtocolSchema.optional(),
145
+ mcp: exports.MCPServeSchema.optional(),
146
+ });
106
147
  exports.SpecSchema = zod_1.z.object({
107
148
  provider: exports.ProviderSchema.optional(),
108
149
  model: zod_1.z.string().default('deepseek-chat'),
@@ -110,6 +151,7 @@ exports.SpecSchema = zod_1.z.object({
110
151
  skills: zod_1.z.array(exports.SkillRefSchema).default([]),
111
152
  channels: zod_1.z.array(exports.ChannelSchema).default([]),
112
153
  memory: exports.MemorySchema.optional(),
154
+ tools: exports.ToolsSchema.optional(),
113
155
  dtv: exports.DTVSchema.optional(),
114
156
  room: exports.RoomSchema.optional(),
115
157
  streaming: zod_1.z.union([zod_1.z.boolean(), exports.StreamingSchema]).default(false),
@@ -119,6 +161,8 @@ exports.SpecSchema = zod_1.z.object({
119
161
  webhook: exports.WebhookSchema.optional(),
120
162
  hitl: exports.HITLSchema.optional(),
121
163
  auth: exports.AuthSchema.optional(),
164
+ telemetry: exports.TelemetrySchema.optional(),
165
+ protocols: exports.ProtocolsSchema.optional(),
122
166
  plugins: zod_1.z.array(exports.PluginRefSchema).optional(),
123
167
  });
124
168
  exports.OADSchema = zod_1.z.object({
@@ -0,0 +1,36 @@
1
+ export type ApprovalPolicy = 'always' | 'dangerous' | 'never';
2
+ export interface ApprovalRequest {
3
+ id: string;
4
+ type: 'shell' | 'file_write' | 'file_delete' | 'network' | 'plugin';
5
+ command: string;
6
+ description: string;
7
+ requestedAt: Date;
8
+ status: 'pending' | 'approved' | 'denied';
9
+ approvedBy?: string;
10
+ }
11
+ export declare class ApprovalManager {
12
+ private policy;
13
+ private pendingApprovals;
14
+ private allowlist;
15
+ private blocklist;
16
+ private static readonly DANGEROUS_PATTERNS;
17
+ constructor(policy?: ApprovalPolicy);
18
+ getPolicy(): ApprovalPolicy;
19
+ setPolicy(policy: ApprovalPolicy): void;
20
+ needsApproval(type: string, command: string): boolean;
21
+ private isDangerous;
22
+ private isAllowed;
23
+ private isBlocked;
24
+ requestApproval(type: ApprovalRequest['type'], command: string, description: string): ApprovalRequest;
25
+ approve(id: string, approver: string): void;
26
+ deny(id: string, approver: string): void;
27
+ getRequest(id: string): ApprovalRequest | undefined;
28
+ addToAllowlist(pattern: string): void;
29
+ removeFromAllowlist(pattern: string): void;
30
+ addToBlocklist(pattern: string): void;
31
+ removeFromBlocklist(pattern: string): void;
32
+ getPending(): ApprovalRequest[];
33
+ getAllowlist(): string[];
34
+ getBlocklist(): string[];
35
+ }
36
+ //# sourceMappingURL=approval.d.ts.map
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ApprovalManager = void 0;
4
+ const crypto_1 = require("crypto");
5
+ class ApprovalManager {
6
+ policy;
7
+ pendingApprovals = new Map();
8
+ allowlist = new Set();
9
+ blocklist = new Set();
10
+ static DANGEROUS_PATTERNS = [
11
+ /rm\s+-rf/i, /del\s+\/s/i, /format\s+/i,
12
+ /DROP\s+TABLE/i, /DELETE\s+FROM/i,
13
+ /curl.*\|.*sh/i, /wget.*\|.*sh/i,
14
+ /chmod\s+777/i, /sudo\s+/i,
15
+ /npm\s+publish/i,
16
+ ];
17
+ constructor(policy = 'dangerous') {
18
+ this.policy = policy;
19
+ }
20
+ getPolicy() {
21
+ return this.policy;
22
+ }
23
+ setPolicy(policy) {
24
+ this.policy = policy;
25
+ }
26
+ needsApproval(type, command) {
27
+ // Blocklist always needs approval (effectively blocked)
28
+ if (this.isBlocked(command))
29
+ return true;
30
+ // Allowlist never needs approval
31
+ if (this.isAllowed(command))
32
+ return false;
33
+ if (this.policy === 'never')
34
+ return false;
35
+ if (this.policy === 'always')
36
+ return true;
37
+ // 'dangerous'
38
+ return this.isDangerous(type, command);
39
+ }
40
+ isDangerous(_type, command) {
41
+ return ApprovalManager.DANGEROUS_PATTERNS.some(p => p.test(command));
42
+ }
43
+ isAllowed(command) {
44
+ for (const pattern of this.allowlist) {
45
+ if (command.includes(pattern))
46
+ return true;
47
+ }
48
+ return false;
49
+ }
50
+ isBlocked(command) {
51
+ for (const pattern of this.blocklist) {
52
+ if (command.includes(pattern))
53
+ return true;
54
+ }
55
+ return false;
56
+ }
57
+ requestApproval(type, command, description) {
58
+ const request = {
59
+ id: (0, crypto_1.randomUUID)(),
60
+ type,
61
+ command,
62
+ description,
63
+ requestedAt: new Date(),
64
+ status: 'pending',
65
+ };
66
+ this.pendingApprovals.set(request.id, request);
67
+ return request;
68
+ }
69
+ approve(id, approver) {
70
+ const req = this.pendingApprovals.get(id);
71
+ if (!req)
72
+ throw new Error(`Approval request ${id} not found`);
73
+ if (req.status !== 'pending')
74
+ throw new Error(`Request ${id} is already ${req.status}`);
75
+ req.status = 'approved';
76
+ req.approvedBy = approver;
77
+ }
78
+ deny(id, approver) {
79
+ const req = this.pendingApprovals.get(id);
80
+ if (!req)
81
+ throw new Error(`Approval request ${id} not found`);
82
+ if (req.status !== 'pending')
83
+ throw new Error(`Request ${id} is already ${req.status}`);
84
+ req.status = 'denied';
85
+ req.approvedBy = approver;
86
+ }
87
+ getRequest(id) {
88
+ return this.pendingApprovals.get(id);
89
+ }
90
+ addToAllowlist(pattern) {
91
+ this.allowlist.add(pattern);
92
+ }
93
+ removeFromAllowlist(pattern) {
94
+ this.allowlist.delete(pattern);
95
+ }
96
+ addToBlocklist(pattern) {
97
+ this.blocklist.add(pattern);
98
+ }
99
+ removeFromBlocklist(pattern) {
100
+ this.blocklist.delete(pattern);
101
+ }
102
+ getPending() {
103
+ return Array.from(this.pendingApprovals.values()).filter(r => r.status === 'pending');
104
+ }
105
+ getAllowlist() {
106
+ return Array.from(this.allowlist);
107
+ }
108
+ getBlocklist() {
109
+ return Array.from(this.blocklist);
110
+ }
111
+ }
112
+ exports.ApprovalManager = ApprovalManager;
113
+ //# sourceMappingURL=approval.js.map
@@ -0,0 +1,4 @@
1
+ export { ApprovalManager } from './approval';
2
+ export type { ApprovalPolicy, ApprovalRequest } from './approval';
3
+ export { KeyManager } from './keys';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.KeyManager = exports.ApprovalManager = void 0;
4
+ var approval_1 = require("./approval");
5
+ Object.defineProperty(exports, "ApprovalManager", { enumerable: true, get: function () { return approval_1.ApprovalManager; } });
6
+ var keys_1 = require("./keys");
7
+ Object.defineProperty(exports, "KeyManager", { enumerable: true, get: function () { return keys_1.KeyManager; } });
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,16 @@
1
+ export declare class KeyManager {
2
+ private keys;
3
+ private keyFile;
4
+ private secret;
5
+ constructor(keyFile?: string);
6
+ private deriveSecret;
7
+ set(name: string, value: string): void;
8
+ get(name: string): string | undefined;
9
+ delete(name: string): boolean;
10
+ list(): string[];
11
+ private load;
12
+ private save;
13
+ private encode;
14
+ private decode;
15
+ }
16
+ //# sourceMappingURL=keys.d.ts.map
@@ -0,0 +1,117 @@
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.KeyManager = void 0;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const crypto = __importStar(require("crypto"));
40
+ const os = __importStar(require("os"));
41
+ class KeyManager {
42
+ keys = new Map();
43
+ keyFile;
44
+ secret;
45
+ constructor(keyFile = '.opc/keys.json') {
46
+ this.keyFile = path.resolve(keyFile);
47
+ this.secret = this.deriveSecret();
48
+ this.load();
49
+ }
50
+ deriveSecret() {
51
+ // Derive a key from machine-specific info (hostname + homedir)
52
+ const machineId = `${os.hostname()}:${os.homedir()}:opc-agent-keys`;
53
+ return crypto.createHash('sha256').update(machineId).digest();
54
+ }
55
+ set(name, value) {
56
+ this.keys.set(name, value);
57
+ this.save();
58
+ }
59
+ get(name) {
60
+ return this.keys.get(name);
61
+ }
62
+ delete(name) {
63
+ const result = this.keys.delete(name);
64
+ if (result)
65
+ this.save();
66
+ return result;
67
+ }
68
+ list() {
69
+ return Array.from(this.keys.keys());
70
+ }
71
+ load() {
72
+ try {
73
+ if (fs.existsSync(this.keyFile)) {
74
+ const data = JSON.parse(fs.readFileSync(this.keyFile, 'utf-8'));
75
+ for (const [name, encoded] of Object.entries(data)) {
76
+ try {
77
+ this.keys.set(name, this.decode(encoded));
78
+ }
79
+ catch {
80
+ // Skip corrupted entries
81
+ }
82
+ }
83
+ }
84
+ }
85
+ catch {
86
+ // File doesn't exist or is corrupted — start fresh
87
+ }
88
+ }
89
+ save() {
90
+ const dir = path.dirname(this.keyFile);
91
+ if (!fs.existsSync(dir)) {
92
+ fs.mkdirSync(dir, { recursive: true });
93
+ }
94
+ const data = {};
95
+ for (const [name, value] of this.keys) {
96
+ data[name] = this.encode(value);
97
+ }
98
+ fs.writeFileSync(this.keyFile, JSON.stringify(data, null, 2), 'utf-8');
99
+ }
100
+ encode(value) {
101
+ const iv = crypto.randomBytes(16);
102
+ const cipher = crypto.createCipheriv('aes-256-cbc', this.secret, iv);
103
+ let encrypted = cipher.update(value, 'utf-8', 'hex');
104
+ encrypted += cipher.final('hex');
105
+ return iv.toString('hex') + ':' + encrypted;
106
+ }
107
+ decode(encoded) {
108
+ const [ivHex, encrypted] = encoded.split(':');
109
+ const iv = Buffer.from(ivHex, 'hex');
110
+ const decipher = crypto.createDecipheriv('aes-256-cbc', this.secret, iv);
111
+ let decrypted = decipher.update(encrypted, 'hex', 'utf-8');
112
+ decrypted += decipher.final('utf-8');
113
+ return decrypted;
114
+ }
115
+ }
116
+ exports.KeyManager = KeyManager;
117
+ //# sourceMappingURL=keys.js.map
@@ -0,0 +1,28 @@
1
+ import type { Message } from '../core/types';
2
+ import type { LLMProvider } from '../providers';
3
+ export interface LearnedSkill {
4
+ name: string;
5
+ description: string;
6
+ trigger: string;
7
+ instructions: string;
8
+ examples: string[];
9
+ createdAt: Date;
10
+ usageCount: number;
11
+ lastUsed?: Date;
12
+ version: number;
13
+ }
14
+ export declare class SkillLearner {
15
+ private skillsDir;
16
+ private skills;
17
+ private loaded;
18
+ constructor(skillsDir: string);
19
+ analyzeForSkillCreation(conversation: Message[], provider: LLMProvider): Promise<LearnedSkill | null>;
20
+ saveSkill(skill: LearnedSkill): Promise<void>;
21
+ loadLearnedSkills(): Promise<LearnedSkill[]>;
22
+ matchSkill(message: string): LearnedSkill | null;
23
+ improveSkill(skill: LearnedSkill, conversation: Message[], provider: LLMProvider): Promise<void>;
24
+ getSkills(): LearnedSkill[];
25
+ }
26
+ export declare function skillToMarkdown(skill: LearnedSkill): string;
27
+ export declare function parseSkillMarkdown(content: string): LearnedSkill | null;
28
+ //# sourceMappingURL=auto-learn.d.ts.map
@@ -0,0 +1,257 @@
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.SkillLearner = void 0;
37
+ exports.skillToMarkdown = skillToMarkdown;
38
+ exports.parseSkillMarkdown = parseSkillMarkdown;
39
+ const fs = __importStar(require("fs"));
40
+ const path = __importStar(require("path"));
41
+ const SKILL_EXTRACTION_PROMPT = `Analyze this conversation and determine if it represents a repeatable task that should be saved as a reusable skill.
42
+
43
+ Criteria for creating a skill:
44
+ 1. The task is specific and well-defined
45
+ 2. It could reasonably happen again
46
+ 3. The solution has clear steps
47
+
48
+ If yes, extract:
49
+ - name: short kebab-case name
50
+ - description: one-line description
51
+ - trigger: regex pattern or keywords that would identify this task
52
+ - instructions: step-by-step instructions to complete the task
53
+ - examples: 2-3 example user inputs that would trigger this skill
54
+
55
+ If this is just casual chat or a one-off question, return null.
56
+
57
+ Respond in JSON format only: { "shouldCreate": boolean, "skill": { "name": string, "description": string, "trigger": string, "instructions": string, "examples": string[] } | null }
58
+
59
+ Conversation:
60
+ `;
61
+ const SKILL_IMPROVEMENT_PROMPT = `This skill was just used. Based on the outcome, suggest improvements:
62
+
63
+ Current skill:
64
+ `;
65
+ const SKILL_IMPROVEMENT_SUFFIX = `
66
+
67
+ Respond in JSON only: { "shouldImprove": boolean, "improvements": { "instructions"?: string, "trigger"?: string, "examples"?: string[] } | null }`;
68
+ class SkillLearner {
69
+ skillsDir;
70
+ skills = [];
71
+ loaded = false;
72
+ constructor(skillsDir) {
73
+ this.skillsDir = skillsDir;
74
+ }
75
+ async analyzeForSkillCreation(conversation, provider) {
76
+ const conversationText = conversation
77
+ .map((m) => `${m.role}: ${m.content}`)
78
+ .join('\n');
79
+ const prompt = SKILL_EXTRACTION_PROMPT + conversationText;
80
+ try {
81
+ const response = await provider.chat([{ id: 'analysis', role: 'user', content: prompt, timestamp: Date.now() }], 'You are a skill extraction assistant. Respond only with valid JSON.');
82
+ const json = extractJson(response);
83
+ if (!json || !json.shouldCreate || !json.skill)
84
+ return null;
85
+ const skill = {
86
+ name: json.skill.name,
87
+ description: json.skill.description,
88
+ trigger: json.skill.trigger,
89
+ instructions: json.skill.instructions,
90
+ examples: json.skill.examples || [],
91
+ createdAt: new Date(),
92
+ usageCount: 0,
93
+ version: 1,
94
+ };
95
+ return skill;
96
+ }
97
+ catch {
98
+ return null;
99
+ }
100
+ }
101
+ async saveSkill(skill) {
102
+ fs.mkdirSync(this.skillsDir, { recursive: true });
103
+ const filePath = path.join(this.skillsDir, `${skill.name}.md`);
104
+ fs.writeFileSync(filePath, skillToMarkdown(skill), 'utf-8');
105
+ // Update cache
106
+ const idx = this.skills.findIndex((s) => s.name === skill.name);
107
+ if (idx >= 0) {
108
+ this.skills[idx] = skill;
109
+ }
110
+ else {
111
+ this.skills.push(skill);
112
+ }
113
+ }
114
+ async loadLearnedSkills() {
115
+ if (!fs.existsSync(this.skillsDir))
116
+ return [];
117
+ const files = fs.readdirSync(this.skillsDir).filter((f) => f.endsWith('.md'));
118
+ this.skills = files
119
+ .map((f) => {
120
+ try {
121
+ const content = fs.readFileSync(path.join(this.skillsDir, f), 'utf-8');
122
+ return parseSkillMarkdown(content);
123
+ }
124
+ catch {
125
+ return null;
126
+ }
127
+ })
128
+ .filter((s) => s !== null);
129
+ this.loaded = true;
130
+ return this.skills;
131
+ }
132
+ matchSkill(message) {
133
+ if (!this.loaded)
134
+ return null;
135
+ for (const skill of this.skills) {
136
+ try {
137
+ const regex = new RegExp(skill.trigger, 'i');
138
+ if (regex.test(message))
139
+ return skill;
140
+ }
141
+ catch {
142
+ // Fallback: keyword matching — split on common separators, strip non-word chars
143
+ const keywords = skill.trigger.split(/[\s,;|]+/).map(k => k.replace(/[^\w-]/g, '').toLowerCase()).filter(k => k.length > 2);
144
+ const lower = message.toLowerCase();
145
+ if (keywords.some((kw) => lower.includes(kw)))
146
+ return skill;
147
+ }
148
+ }
149
+ return null;
150
+ }
151
+ async improveSkill(skill, conversation, provider) {
152
+ const conversationText = conversation
153
+ .map((m) => `${m.role}: ${m.content}`)
154
+ .join('\n');
155
+ const prompt = SKILL_IMPROVEMENT_PROMPT +
156
+ skillToMarkdown(skill) +
157
+ '\n\nConversation where it was used:\n' +
158
+ conversationText +
159
+ SKILL_IMPROVEMENT_SUFFIX;
160
+ try {
161
+ const response = await provider.chat([{ id: 'improve', role: 'user', content: prompt, timestamp: Date.now() }], 'You are a skill improvement assistant. Respond only with valid JSON.');
162
+ const json = extractJson(response);
163
+ if (!json || !json.shouldImprove || !json.improvements)
164
+ return;
165
+ const { improvements } = json;
166
+ if (improvements.instructions)
167
+ skill.instructions = improvements.instructions;
168
+ if (improvements.trigger)
169
+ skill.trigger = improvements.trigger;
170
+ if (improvements.examples)
171
+ skill.examples = [...skill.examples, ...improvements.examples];
172
+ skill.version++;
173
+ await this.saveSkill(skill);
174
+ }
175
+ catch {
176
+ // Silently fail — improvement is best-effort
177
+ }
178
+ }
179
+ getSkills() {
180
+ return [...this.skills];
181
+ }
182
+ }
183
+ exports.SkillLearner = SkillLearner;
184
+ // ─── Helpers ────────────────────────────────────────────────
185
+ function extractJson(text) {
186
+ // Try to extract JSON from response (may be wrapped in markdown code block)
187
+ const match = text.match(/\{[\s\S]*\}/);
188
+ if (!match)
189
+ return null;
190
+ try {
191
+ return JSON.parse(match[0]);
192
+ }
193
+ catch {
194
+ return null;
195
+ }
196
+ }
197
+ function skillToMarkdown(skill) {
198
+ const lines = [
199
+ `# Skill: ${skill.name}`,
200
+ '',
201
+ '## Description',
202
+ skill.description,
203
+ '',
204
+ '## Trigger',
205
+ `Pattern: ${skill.trigger}`,
206
+ '',
207
+ '## Instructions',
208
+ skill.instructions,
209
+ '',
210
+ '## Examples',
211
+ ...skill.examples.map((e) => `- "${e}"`),
212
+ '',
213
+ '## Metadata',
214
+ `- Created: ${skill.createdAt.toISOString()}`,
215
+ `- Version: ${skill.version}`,
216
+ `- Usage Count: ${skill.usageCount}`,
217
+ `- Last Used: ${skill.lastUsed?.toISOString() ?? 'never'}`,
218
+ '',
219
+ ];
220
+ return lines.join('\n');
221
+ }
222
+ function parseSkillMarkdown(content) {
223
+ const nameMatch = content.match(/^# Skill:\s*(.+)$/m);
224
+ if (!nameMatch)
225
+ return null;
226
+ const section = (heading) => {
227
+ const re = new RegExp(`## ${heading}\\s*\\n([\\s\\S]*?)(?=\\n## |$)`);
228
+ const m = content.match(re);
229
+ return m ? m[1].trim() : '';
230
+ };
231
+ const description = section('Description');
232
+ const triggerLine = section('Trigger');
233
+ const trigger = triggerLine.replace(/^Pattern:\s*/i, '').trim();
234
+ const instructions = section('Instructions');
235
+ const examplesRaw = section('Examples');
236
+ const examples = examplesRaw
237
+ .split('\n')
238
+ .map((l) => l.replace(/^-\s*"?|"?\s*$/g, '').trim())
239
+ .filter(Boolean);
240
+ const metadata = section('Metadata');
241
+ const getMeta = (key) => {
242
+ const m = metadata.match(new RegExp(`- ${key}:\\s*(.+)`, 'i'));
243
+ return m ? m[1].trim() : '';
244
+ };
245
+ return {
246
+ name: nameMatch[1].trim(),
247
+ description,
248
+ trigger,
249
+ instructions,
250
+ examples,
251
+ createdAt: new Date(getMeta('Created') || Date.now()),
252
+ version: parseInt(getMeta('Version') || '1', 10),
253
+ usageCount: parseInt(getMeta('Usage Count') || '0', 10),
254
+ lastUsed: getMeta('Last Used') !== 'never' ? new Date(getMeta('Last Used')) : undefined,
255
+ };
256
+ }
257
+ //# sourceMappingURL=auto-learn.js.map