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.
- package/CHANGELOG.md +25 -0
- package/README.md +91 -32
- package/dist/channels/email.d.ts +32 -26
- package/dist/channels/email.js +239 -62
- package/dist/channels/feishu.d.ts +21 -6
- package/dist/channels/feishu.js +225 -126
- package/dist/channels/telegram.d.ts +30 -9
- package/dist/channels/telegram.js +125 -33
- package/dist/channels/websocket.d.ts +46 -3
- package/dist/channels/websocket.js +306 -37
- package/dist/channels/wechat.d.ts +33 -13
- package/dist/channels/wechat.js +229 -42
- package/dist/cli.js +1127 -19
- package/dist/core/a2a.d.ts +17 -0
- package/dist/core/a2a.js +43 -1
- package/dist/core/agent.d.ts +39 -0
- package/dist/core/agent.js +228 -3
- package/dist/core/runtime.d.ts +7 -0
- package/dist/core/runtime.js +205 -2
- package/dist/core/sandbox.d.ts +26 -0
- package/dist/core/sandbox.js +117 -0
- package/dist/core/scheduler.d.ts +52 -0
- package/dist/core/scheduler.js +168 -0
- package/dist/core/subagent.d.ts +28 -0
- package/dist/core/subagent.js +65 -0
- package/dist/core/workflow-graph.d.ts +93 -0
- package/dist/core/workflow-graph.js +247 -0
- package/dist/daemon.d.ts +3 -0
- package/dist/daemon.js +134 -0
- package/dist/doctor.d.ts +15 -0
- package/dist/doctor.js +183 -0
- package/dist/eval/index.d.ts +65 -0
- package/dist/eval/index.js +191 -0
- package/dist/index.d.ts +37 -6
- package/dist/index.js +75 -3
- package/dist/plugins/content-filter.d.ts +7 -0
- package/dist/plugins/content-filter.js +25 -0
- package/dist/plugins/index.d.ts +42 -0
- package/dist/plugins/index.js +108 -2
- package/dist/plugins/logger.d.ts +6 -0
- package/dist/plugins/logger.js +20 -0
- package/dist/plugins/rate-limiter.d.ts +7 -0
- package/dist/plugins/rate-limiter.js +35 -0
- package/dist/protocols/a2a/client.d.ts +25 -0
- package/dist/protocols/a2a/client.js +115 -0
- package/dist/protocols/a2a/index.d.ts +6 -0
- package/dist/protocols/a2a/index.js +12 -0
- package/dist/protocols/a2a/server.d.ts +41 -0
- package/dist/protocols/a2a/server.js +295 -0
- package/dist/protocols/a2a/types.d.ts +91 -0
- package/dist/protocols/a2a/types.js +15 -0
- package/dist/protocols/a2a/utils.d.ts +6 -0
- package/dist/protocols/a2a/utils.js +47 -0
- package/dist/protocols/agui/client.d.ts +10 -0
- package/dist/protocols/agui/client.js +75 -0
- package/dist/protocols/agui/index.d.ts +4 -0
- package/dist/protocols/agui/index.js +25 -0
- package/dist/protocols/agui/server.d.ts +37 -0
- package/dist/protocols/agui/server.js +191 -0
- package/dist/protocols/agui/types.d.ts +107 -0
- package/dist/protocols/agui/types.js +17 -0
- package/dist/protocols/index.d.ts +2 -0
- package/dist/protocols/index.js +19 -0
- package/dist/protocols/mcp/agent-tools.d.ts +11 -0
- package/dist/protocols/mcp/agent-tools.js +129 -0
- package/dist/protocols/mcp/index.d.ts +5 -0
- package/dist/protocols/mcp/index.js +11 -0
- package/dist/protocols/mcp/server.d.ts +31 -0
- package/dist/protocols/mcp/server.js +248 -0
- package/dist/protocols/mcp/types.d.ts +92 -0
- package/dist/protocols/mcp/types.js +17 -0
- package/dist/providers/index.d.ts +5 -1
- package/dist/providers/index.js +16 -9
- package/dist/publish/index.d.ts +45 -0
- package/dist/publish/index.js +350 -0
- package/dist/schema/oad.d.ts +859 -67
- package/dist/schema/oad.js +47 -3
- package/dist/security/approval.d.ts +36 -0
- package/dist/security/approval.js +113 -0
- package/dist/security/index.d.ts +4 -0
- package/dist/security/index.js +8 -0
- package/dist/security/keys.d.ts +16 -0
- package/dist/security/keys.js +117 -0
- package/dist/skills/auto-learn.d.ts +28 -0
- package/dist/skills/auto-learn.js +257 -0
- package/dist/studio/server.d.ts +63 -0
- package/dist/studio/server.js +625 -0
- package/dist/studio-ui/index.html +662 -0
- package/dist/telemetry/index.d.ts +93 -0
- package/dist/telemetry/index.js +285 -0
- package/dist/tools/builtin/datetime.d.ts +3 -0
- package/dist/tools/builtin/datetime.js +44 -0
- package/dist/tools/builtin/file.d.ts +3 -0
- package/dist/tools/builtin/file.js +151 -0
- package/dist/tools/builtin/index.d.ts +15 -0
- package/dist/tools/builtin/index.js +30 -0
- package/dist/tools/builtin/shell.d.ts +3 -0
- package/dist/tools/builtin/shell.js +43 -0
- package/dist/tools/builtin/web.d.ts +3 -0
- package/dist/tools/builtin/web.js +37 -0
- package/dist/tools/mcp-client.d.ts +24 -0
- package/dist/tools/mcp-client.js +119 -0
- package/package.json +5 -3
- package/scripts/install.ps1 +31 -0
- package/scripts/install.sh +40 -0
- package/src/channels/email.ts +351 -177
- package/src/channels/feishu.ts +349 -236
- package/src/channels/telegram.ts +212 -90
- package/src/channels/websocket.ts +399 -87
- package/src/channels/wechat.ts +329 -149
- package/src/cli.ts +1201 -20
- package/src/core/a2a.ts +60 -0
- package/src/core/agent.ts +420 -152
- package/src/core/runtime.ts +174 -0
- package/src/core/sandbox.ts +143 -0
- package/src/core/scheduler.ts +187 -0
- package/src/core/subagent.ts +98 -0
- package/src/core/workflow-graph.ts +365 -0
- package/src/daemon.ts +96 -0
- package/src/doctor.ts +156 -0
- package/src/eval/index.ts +211 -0
- package/src/eval/suites/basic.json +16 -0
- package/src/eval/suites/memory.json +12 -0
- package/src/eval/suites/safety.json +14 -0
- package/src/index.ts +65 -6
- package/src/plugins/content-filter.ts +23 -0
- package/src/plugins/index.ts +133 -2
- package/src/plugins/logger.ts +18 -0
- package/src/plugins/rate-limiter.ts +38 -0
- package/src/protocols/a2a/client.ts +132 -0
- package/src/protocols/a2a/index.ts +8 -0
- package/src/protocols/a2a/server.ts +333 -0
- package/src/protocols/a2a/types.ts +88 -0
- package/src/protocols/a2a/utils.ts +50 -0
- package/src/protocols/agui/client.ts +83 -0
- package/src/protocols/agui/index.ts +4 -0
- package/src/protocols/agui/server.ts +218 -0
- package/src/protocols/agui/types.ts +153 -0
- package/src/protocols/index.ts +2 -0
- package/src/protocols/mcp/agent-tools.ts +134 -0
- package/src/protocols/mcp/index.ts +8 -0
- package/src/protocols/mcp/server.ts +262 -0
- package/src/protocols/mcp/types.ts +69 -0
- package/src/providers/index.ts +354 -339
- package/src/publish/index.ts +376 -0
- package/src/schema/oad.ts +204 -154
- package/src/security/approval.ts +131 -0
- package/src/security/index.ts +3 -0
- package/src/security/keys.ts +87 -0
- package/src/skills/auto-learn.ts +262 -0
- package/src/studio/server.ts +629 -0
- package/src/studio-ui/index.html +662 -0
- package/src/telemetry/index.ts +324 -0
- package/src/tools/builtin/datetime.ts +41 -0
- package/src/tools/builtin/file.ts +107 -0
- package/src/tools/builtin/index.ts +28 -0
- package/src/tools/builtin/shell.ts +43 -0
- package/src/tools/builtin/web.ts +35 -0
- package/src/tools/mcp-client.ts +131 -0
- package/src/types/agent-workstation.d.ts +2 -0
- package/tests/a2a-protocol.test.ts +285 -0
- package/tests/agui-protocol.test.ts +246 -0
- package/tests/auto-learn.test.ts +105 -0
- package/tests/builtin-tools.test.ts +83 -0
- package/tests/channels/discord.test.ts +79 -0
- package/tests/channels/email.test.ts +148 -0
- package/tests/channels/feishu.test.ts +123 -0
- package/tests/channels/telegram.test.ts +129 -0
- package/tests/channels/websocket.test.ts +53 -0
- package/tests/channels/wechat.test.ts +170 -0
- package/tests/chat-cli.test.ts +160 -0
- package/tests/cli.test.ts +46 -0
- package/tests/daemon.test.ts +135 -0
- package/tests/deepbrain-wire.test.ts +234 -0
- package/tests/doctor.test.ts +38 -0
- package/tests/eval.test.ts +173 -0
- package/tests/init-role.test.ts +124 -0
- package/tests/mcp-client.test.ts +92 -0
- package/tests/mcp-server.test.ts +178 -0
- package/tests/plugin-a2a-enhanced.test.ts +230 -0
- package/tests/publish.test.ts +231 -0
- package/tests/scheduler.test.ts +200 -0
- package/tests/security-enhanced.test.ts +233 -0
- package/tests/skill-learner.test.ts +161 -0
- package/tests/studio.test.ts +229 -0
- package/tests/subagent.test.ts +193 -0
- package/tests/telegram-discord.test.ts +60 -0
- package/tests/telemetry.test.ts +186 -0
- package/tests/tools/builtin-extended.test.ts +138 -0
- package/tests/workflow-graph.test.ts +279 -0
- package/tutorial/customer-service-agent/README.md +612 -0
- package/tutorial/customer-service-agent/SOUL.md +26 -0
- package/tutorial/customer-service-agent/agent.yaml +63 -0
- package/tutorial/customer-service-agent/package.json +19 -0
- package/tutorial/customer-service-agent/src/index.ts +69 -0
- package/tutorial/customer-service-agent/src/skills/faq.ts +27 -0
- package/tutorial/customer-service-agent/src/skills/ticket.ts +22 -0
- package/tutorial/customer-service-agent/tsconfig.json +14 -0
package/dist/schema/oad.js
CHANGED
|
@@ -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.
|
|
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,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
|