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
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OPC Agent Telemetry — Lightweight OTel-compatible tracing & metrics.
|
|
3
|
+
* Zero external dependencies. Produces OTLP-compatible JSON.
|
|
4
|
+
*/
|
|
5
|
+
export interface Span {
|
|
6
|
+
traceId: string;
|
|
7
|
+
spanId: string;
|
|
8
|
+
parentSpanId?: string;
|
|
9
|
+
name: string;
|
|
10
|
+
kind: 'internal' | 'client' | 'server';
|
|
11
|
+
startTime: number;
|
|
12
|
+
endTime?: number;
|
|
13
|
+
status: 'ok' | 'error' | 'unset';
|
|
14
|
+
attributes: Record<string, string | number | boolean>;
|
|
15
|
+
events: SpanEvent[];
|
|
16
|
+
}
|
|
17
|
+
export interface SpanEvent {
|
|
18
|
+
name: string;
|
|
19
|
+
timestamp: number;
|
|
20
|
+
attributes?: Record<string, string | number | boolean>;
|
|
21
|
+
}
|
|
22
|
+
export interface Metric {
|
|
23
|
+
name: string;
|
|
24
|
+
type: 'counter' | 'gauge' | 'histogram';
|
|
25
|
+
value: number;
|
|
26
|
+
timestamp: number;
|
|
27
|
+
labels: Record<string, string>;
|
|
28
|
+
}
|
|
29
|
+
export interface TraceExporter {
|
|
30
|
+
export(spans: Span[]): Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
export declare function generateTraceId(): string;
|
|
33
|
+
export declare function generateSpanId(): string;
|
|
34
|
+
export declare class Tracer {
|
|
35
|
+
private spans;
|
|
36
|
+
private metrics;
|
|
37
|
+
private maxSpans;
|
|
38
|
+
private maxMetrics;
|
|
39
|
+
private exporters;
|
|
40
|
+
constructor(options?: {
|
|
41
|
+
maxSpans?: number;
|
|
42
|
+
maxMetrics?: number;
|
|
43
|
+
});
|
|
44
|
+
startSpan(name: string, options?: {
|
|
45
|
+
parent?: Span;
|
|
46
|
+
attributes?: Record<string, string | number | boolean>;
|
|
47
|
+
kind?: Span['kind'];
|
|
48
|
+
}): Span;
|
|
49
|
+
endSpan(span: Span, status?: Span['status']): void;
|
|
50
|
+
addEvent(span: Span, name: string, attributes?: Record<string, string | number | boolean>): void;
|
|
51
|
+
increment(name: string, value?: number, labels?: Record<string, string>): void;
|
|
52
|
+
gauge(name: string, value: number, labels?: Record<string, string>): void;
|
|
53
|
+
histogram(name: string, value: number, labels?: Record<string, string>): void;
|
|
54
|
+
private addMetric;
|
|
55
|
+
getSpans(options?: {
|
|
56
|
+
limit?: number;
|
|
57
|
+
traceId?: string;
|
|
58
|
+
name?: string;
|
|
59
|
+
since?: number;
|
|
60
|
+
}): Span[];
|
|
61
|
+
getMetrics(options?: {
|
|
62
|
+
name?: string;
|
|
63
|
+
since?: number;
|
|
64
|
+
}): Metric[];
|
|
65
|
+
getTrace(traceId: string): Span[];
|
|
66
|
+
addExporter(exporter: TraceExporter): void;
|
|
67
|
+
exportOTLP(): object;
|
|
68
|
+
getStats(): {
|
|
69
|
+
totalSpans: number;
|
|
70
|
+
totalTraces: number;
|
|
71
|
+
avgDuration: number;
|
|
72
|
+
errorRate: number;
|
|
73
|
+
spansByName: Record<string, number>;
|
|
74
|
+
p50Latency: number;
|
|
75
|
+
p95Latency: number;
|
|
76
|
+
p99Latency: number;
|
|
77
|
+
};
|
|
78
|
+
clear(): void;
|
|
79
|
+
}
|
|
80
|
+
export declare class ConsoleExporter implements TraceExporter {
|
|
81
|
+
export(spans: Span[]): Promise<void>;
|
|
82
|
+
}
|
|
83
|
+
export declare class FileExporter implements TraceExporter {
|
|
84
|
+
private filePath;
|
|
85
|
+
constructor(filePath: string);
|
|
86
|
+
export(spans: Span[]): Promise<void>;
|
|
87
|
+
}
|
|
88
|
+
export declare class OTLPHttpExporter implements TraceExporter {
|
|
89
|
+
private endpoint;
|
|
90
|
+
constructor(endpoint: string);
|
|
91
|
+
export(spans: Span[]): Promise<void>;
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* OPC Agent Telemetry — Lightweight OTel-compatible tracing & metrics.
|
|
4
|
+
* Zero external dependencies. Produces OTLP-compatible JSON.
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
+
}) : function(o, v) {
|
|
20
|
+
o["default"] = v;
|
|
21
|
+
});
|
|
22
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
+
var ownKeys = function(o) {
|
|
24
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
+
var ar = [];
|
|
26
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
+
return ar;
|
|
28
|
+
};
|
|
29
|
+
return ownKeys(o);
|
|
30
|
+
};
|
|
31
|
+
return function (mod) {
|
|
32
|
+
if (mod && mod.__esModule) return mod;
|
|
33
|
+
var result = {};
|
|
34
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
+
__setModuleDefault(result, mod);
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
})();
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
exports.OTLPHttpExporter = exports.FileExporter = exports.ConsoleExporter = exports.Tracer = void 0;
|
|
41
|
+
exports.generateTraceId = generateTraceId;
|
|
42
|
+
exports.generateSpanId = generateSpanId;
|
|
43
|
+
const fs = __importStar(require("fs"));
|
|
44
|
+
const crypto = __importStar(require("crypto"));
|
|
45
|
+
// ─── ID Generation ───────────────────────────────────────────
|
|
46
|
+
function generateTraceId() {
|
|
47
|
+
return crypto.randomBytes(16).toString('hex'); // 32 hex chars
|
|
48
|
+
}
|
|
49
|
+
function generateSpanId() {
|
|
50
|
+
return crypto.randomBytes(8).toString('hex'); // 16 hex chars
|
|
51
|
+
}
|
|
52
|
+
// ─── Tracer ──────────────────────────────────────────────────
|
|
53
|
+
class Tracer {
|
|
54
|
+
spans = [];
|
|
55
|
+
metrics = [];
|
|
56
|
+
maxSpans;
|
|
57
|
+
maxMetrics;
|
|
58
|
+
exporters = [];
|
|
59
|
+
constructor(options) {
|
|
60
|
+
this.maxSpans = options?.maxSpans || 10000;
|
|
61
|
+
this.maxMetrics = options?.maxMetrics || 50000;
|
|
62
|
+
}
|
|
63
|
+
startSpan(name, options) {
|
|
64
|
+
const span = {
|
|
65
|
+
traceId: options?.parent?.traceId || generateTraceId(),
|
|
66
|
+
spanId: generateSpanId(),
|
|
67
|
+
parentSpanId: options?.parent?.spanId,
|
|
68
|
+
name,
|
|
69
|
+
kind: options?.kind || 'internal',
|
|
70
|
+
startTime: Date.now(),
|
|
71
|
+
status: 'unset',
|
|
72
|
+
attributes: options?.attributes ? { ...options.attributes } : {},
|
|
73
|
+
events: [],
|
|
74
|
+
};
|
|
75
|
+
this.spans.push(span);
|
|
76
|
+
// Evict oldest spans if over limit
|
|
77
|
+
if (this.spans.length > this.maxSpans) {
|
|
78
|
+
const excess = this.spans.length - this.maxSpans;
|
|
79
|
+
this.spans.splice(0, excess);
|
|
80
|
+
}
|
|
81
|
+
return span;
|
|
82
|
+
}
|
|
83
|
+
endSpan(span, status) {
|
|
84
|
+
span.endTime = Date.now();
|
|
85
|
+
span.status = status || 'ok';
|
|
86
|
+
// Notify exporters
|
|
87
|
+
for (const exporter of this.exporters) {
|
|
88
|
+
exporter.export([span]).catch(() => { });
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
addEvent(span, name, attributes) {
|
|
92
|
+
span.events.push({ name, timestamp: Date.now(), attributes });
|
|
93
|
+
}
|
|
94
|
+
// ─── Metrics ─────────────────────────────────────────────
|
|
95
|
+
increment(name, value = 1, labels = {}) {
|
|
96
|
+
this.addMetric(name, 'counter', value, labels);
|
|
97
|
+
}
|
|
98
|
+
gauge(name, value, labels = {}) {
|
|
99
|
+
this.addMetric(name, 'gauge', value, labels);
|
|
100
|
+
}
|
|
101
|
+
histogram(name, value, labels = {}) {
|
|
102
|
+
this.addMetric(name, 'histogram', value, labels);
|
|
103
|
+
}
|
|
104
|
+
addMetric(name, type, value, labels) {
|
|
105
|
+
this.metrics.push({ name, type, value, timestamp: Date.now(), labels });
|
|
106
|
+
if (this.metrics.length > this.maxMetrics) {
|
|
107
|
+
this.metrics.splice(0, this.metrics.length - this.maxMetrics);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// ─── Query ───────────────────────────────────────────────
|
|
111
|
+
getSpans(options) {
|
|
112
|
+
let result = [...this.spans];
|
|
113
|
+
if (options?.traceId)
|
|
114
|
+
result = result.filter(s => s.traceId === options.traceId);
|
|
115
|
+
if (options?.name)
|
|
116
|
+
result = result.filter(s => s.name === options.name);
|
|
117
|
+
if (options?.since)
|
|
118
|
+
result = result.filter(s => s.startTime >= options.since);
|
|
119
|
+
// Most recent first
|
|
120
|
+
result.sort((a, b) => b.startTime - a.startTime);
|
|
121
|
+
if (options?.limit)
|
|
122
|
+
result = result.slice(0, options.limit);
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
getMetrics(options) {
|
|
126
|
+
let result = [...this.metrics];
|
|
127
|
+
if (options?.name)
|
|
128
|
+
result = result.filter(m => m.name === options.name);
|
|
129
|
+
if (options?.since)
|
|
130
|
+
result = result.filter(m => m.timestamp >= options.since);
|
|
131
|
+
return result;
|
|
132
|
+
}
|
|
133
|
+
getTrace(traceId) {
|
|
134
|
+
return this.spans.filter(s => s.traceId === traceId).sort((a, b) => a.startTime - b.startTime);
|
|
135
|
+
}
|
|
136
|
+
// ─── Export (OTLP-compatible) ────────────────────────────
|
|
137
|
+
addExporter(exporter) {
|
|
138
|
+
this.exporters.push(exporter);
|
|
139
|
+
}
|
|
140
|
+
exportOTLP() {
|
|
141
|
+
// OTLP JSON format: https://opentelemetry.io/docs/specs/otlp/
|
|
142
|
+
const spansByResource = this.spans.filter(s => s.endTime != null);
|
|
143
|
+
return {
|
|
144
|
+
resourceSpans: [{
|
|
145
|
+
resource: {
|
|
146
|
+
attributes: [
|
|
147
|
+
{ key: 'service.name', value: { stringValue: 'opc-agent' } },
|
|
148
|
+
],
|
|
149
|
+
},
|
|
150
|
+
scopeSpans: [{
|
|
151
|
+
scope: { name: 'opc-telemetry', version: '1.0.0' },
|
|
152
|
+
spans: spansByResource.map(s => ({
|
|
153
|
+
traceId: s.traceId,
|
|
154
|
+
spanId: s.spanId,
|
|
155
|
+
parentSpanId: s.parentSpanId || '',
|
|
156
|
+
name: s.name,
|
|
157
|
+
kind: s.kind === 'server' ? 2 : s.kind === 'client' ? 3 : 1,
|
|
158
|
+
startTimeUnixNano: String(s.startTime * 1_000_000),
|
|
159
|
+
endTimeUnixNano: String((s.endTime || s.startTime) * 1_000_000),
|
|
160
|
+
attributes: Object.entries(s.attributes).map(([key, value]) => ({
|
|
161
|
+
key,
|
|
162
|
+
value: typeof value === 'string' ? { stringValue: value }
|
|
163
|
+
: typeof value === 'number' ? (Number.isInteger(value) ? { intValue: String(value) } : { doubleValue: value })
|
|
164
|
+
: { boolValue: value },
|
|
165
|
+
})),
|
|
166
|
+
events: s.events.map(e => ({
|
|
167
|
+
timeUnixNano: String(e.timestamp * 1_000_000),
|
|
168
|
+
name: e.name,
|
|
169
|
+
attributes: e.attributes ? Object.entries(e.attributes).map(([key, value]) => ({
|
|
170
|
+
key,
|
|
171
|
+
value: typeof value === 'string' ? { stringValue: value }
|
|
172
|
+
: typeof value === 'number' ? { intValue: String(value) }
|
|
173
|
+
: { boolValue: value },
|
|
174
|
+
})) : [],
|
|
175
|
+
})),
|
|
176
|
+
status: {
|
|
177
|
+
code: s.status === 'ok' ? 1 : s.status === 'error' ? 2 : 0,
|
|
178
|
+
},
|
|
179
|
+
})),
|
|
180
|
+
}],
|
|
181
|
+
}],
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
// ─── Stats ───────────────────────────────────────────────
|
|
185
|
+
getStats() {
|
|
186
|
+
const completed = this.spans.filter(s => s.endTime != null);
|
|
187
|
+
const durations = completed.map(s => s.endTime - s.startTime).sort((a, b) => a - b);
|
|
188
|
+
const traceIds = new Set(this.spans.map(s => s.traceId));
|
|
189
|
+
const errors = completed.filter(s => s.status === 'error').length;
|
|
190
|
+
const spansByName = {};
|
|
191
|
+
for (const s of this.spans) {
|
|
192
|
+
spansByName[s.name] = (spansByName[s.name] || 0) + 1;
|
|
193
|
+
}
|
|
194
|
+
const percentile = (arr, p) => {
|
|
195
|
+
if (arr.length === 0)
|
|
196
|
+
return 0;
|
|
197
|
+
const idx = Math.ceil(arr.length * p / 100) - 1;
|
|
198
|
+
return arr[Math.max(0, idx)];
|
|
199
|
+
};
|
|
200
|
+
return {
|
|
201
|
+
totalSpans: this.spans.length,
|
|
202
|
+
totalTraces: traceIds.size,
|
|
203
|
+
avgDuration: durations.length > 0 ? durations.reduce((a, b) => a + b, 0) / durations.length : 0,
|
|
204
|
+
errorRate: completed.length > 0 ? errors / completed.length : 0,
|
|
205
|
+
spansByName,
|
|
206
|
+
p50Latency: percentile(durations, 50),
|
|
207
|
+
p95Latency: percentile(durations, 95),
|
|
208
|
+
p99Latency: percentile(durations, 99),
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
clear() {
|
|
212
|
+
this.spans = [];
|
|
213
|
+
this.metrics = [];
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
exports.Tracer = Tracer;
|
|
217
|
+
// ─── Exporters ───────────────────────────────────────────────
|
|
218
|
+
class ConsoleExporter {
|
|
219
|
+
async export(spans) {
|
|
220
|
+
for (const span of spans) {
|
|
221
|
+
const duration = span.endTime ? `${span.endTime - span.startTime}ms` : 'ongoing';
|
|
222
|
+
console.log(`[TRACE] ${span.name} (${duration}) [${span.status}] trace=${span.traceId.slice(0, 8)}`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
exports.ConsoleExporter = ConsoleExporter;
|
|
227
|
+
class FileExporter {
|
|
228
|
+
filePath;
|
|
229
|
+
constructor(filePath) {
|
|
230
|
+
this.filePath = filePath;
|
|
231
|
+
}
|
|
232
|
+
async export(spans) {
|
|
233
|
+
const lines = spans.map(s => JSON.stringify(s)).join('\n') + '\n';
|
|
234
|
+
fs.appendFileSync(this.filePath, lines);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
exports.FileExporter = FileExporter;
|
|
238
|
+
class OTLPHttpExporter {
|
|
239
|
+
endpoint;
|
|
240
|
+
constructor(endpoint) {
|
|
241
|
+
this.endpoint = endpoint.replace(/\/$/, '');
|
|
242
|
+
}
|
|
243
|
+
async export(spans) {
|
|
244
|
+
const body = {
|
|
245
|
+
resourceSpans: [{
|
|
246
|
+
resource: {
|
|
247
|
+
attributes: [
|
|
248
|
+
{ key: 'service.name', value: { stringValue: 'opc-agent' } },
|
|
249
|
+
],
|
|
250
|
+
},
|
|
251
|
+
scopeSpans: [{
|
|
252
|
+
scope: { name: 'opc-telemetry', version: '1.0.0' },
|
|
253
|
+
spans: spans.filter(s => s.endTime).map(s => ({
|
|
254
|
+
traceId: s.traceId,
|
|
255
|
+
spanId: s.spanId,
|
|
256
|
+
parentSpanId: s.parentSpanId || '',
|
|
257
|
+
name: s.name,
|
|
258
|
+
kind: s.kind === 'server' ? 2 : s.kind === 'client' ? 3 : 1,
|
|
259
|
+
startTimeUnixNano: String(s.startTime * 1_000_000),
|
|
260
|
+
endTimeUnixNano: String((s.endTime || s.startTime) * 1_000_000),
|
|
261
|
+
attributes: Object.entries(s.attributes).map(([key, value]) => ({
|
|
262
|
+
key,
|
|
263
|
+
value: typeof value === 'string' ? { stringValue: value }
|
|
264
|
+
: typeof value === 'number' ? { intValue: String(value) }
|
|
265
|
+
: { boolValue: value },
|
|
266
|
+
})),
|
|
267
|
+
status: { code: s.status === 'ok' ? 1 : s.status === 'error' ? 2 : 0 },
|
|
268
|
+
})),
|
|
269
|
+
}],
|
|
270
|
+
}],
|
|
271
|
+
};
|
|
272
|
+
try {
|
|
273
|
+
await fetch(`${this.endpoint}/v1/traces`, {
|
|
274
|
+
method: 'POST',
|
|
275
|
+
headers: { 'Content-Type': 'application/json' },
|
|
276
|
+
body: JSON.stringify(body),
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
catch {
|
|
280
|
+
// Best effort
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
exports.OTLPHttpExporter = OTLPHttpExporter;
|
|
285
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.datetimeTool = void 0;
|
|
4
|
+
exports.datetimeTool = {
|
|
5
|
+
name: 'datetime',
|
|
6
|
+
description: 'Get current date, time, timezone info',
|
|
7
|
+
inputSchema: {
|
|
8
|
+
type: 'object',
|
|
9
|
+
properties: {
|
|
10
|
+
format: { type: 'string', default: 'iso' },
|
|
11
|
+
timezone: { type: 'string' },
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
async execute(input) {
|
|
15
|
+
const now = new Date();
|
|
16
|
+
const timezone = input.timezone;
|
|
17
|
+
const format = input.format || 'iso';
|
|
18
|
+
let content;
|
|
19
|
+
if (format === 'iso') {
|
|
20
|
+
content = now.toISOString();
|
|
21
|
+
}
|
|
22
|
+
else if (format === 'locale') {
|
|
23
|
+
content = timezone
|
|
24
|
+
? now.toLocaleString('en-US', { timeZone: timezone })
|
|
25
|
+
: now.toLocaleString();
|
|
26
|
+
}
|
|
27
|
+
else if (format === 'unix') {
|
|
28
|
+
content = String(Math.floor(now.getTime() / 1000));
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
content = now.toISOString();
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
content: JSON.stringify({
|
|
35
|
+
iso: now.toISOString(),
|
|
36
|
+
unix: Math.floor(now.getTime() / 1000),
|
|
37
|
+
formatted: content,
|
|
38
|
+
timezone: timezone || Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
39
|
+
}),
|
|
40
|
+
isError: false,
|
|
41
|
+
};
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=datetime.js.map
|
|
@@ -0,0 +1,151 @@
|
|
|
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.fileTool = void 0;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
function resolveSafe(basePath, targetPath) {
|
|
40
|
+
const resolved = path.resolve(basePath, targetPath);
|
|
41
|
+
if (!resolved.startsWith(path.resolve(basePath)))
|
|
42
|
+
return null;
|
|
43
|
+
return resolved;
|
|
44
|
+
}
|
|
45
|
+
function searchFiles(dir, query, results = [], maxResults = 20) {
|
|
46
|
+
if (results.length >= maxResults)
|
|
47
|
+
return results;
|
|
48
|
+
try {
|
|
49
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
50
|
+
for (const entry of entries) {
|
|
51
|
+
if (results.length >= maxResults)
|
|
52
|
+
break;
|
|
53
|
+
const full = path.join(dir, entry.name);
|
|
54
|
+
if (entry.isDirectory()) {
|
|
55
|
+
if (entry.name === 'node_modules' || entry.name === '.git')
|
|
56
|
+
continue;
|
|
57
|
+
searchFiles(full, query, results, maxResults);
|
|
58
|
+
}
|
|
59
|
+
else if (entry.isFile()) {
|
|
60
|
+
try {
|
|
61
|
+
const content = fs.readFileSync(full, 'utf-8');
|
|
62
|
+
const lines = content.split('\n');
|
|
63
|
+
for (let i = 0; i < lines.length; i++) {
|
|
64
|
+
if (lines[i].includes(query)) {
|
|
65
|
+
results.push(`${full}:${i + 1}: ${lines[i].trim()}`);
|
|
66
|
+
if (results.length >= maxResults)
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch { /* skip binary/unreadable */ }
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch { /* skip inaccessible dirs */ }
|
|
76
|
+
return results;
|
|
77
|
+
}
|
|
78
|
+
exports.fileTool = {
|
|
79
|
+
name: 'file_operations',
|
|
80
|
+
description: 'Read, write, list, and search files in the workspace',
|
|
81
|
+
inputSchema: {
|
|
82
|
+
type: 'object',
|
|
83
|
+
properties: {
|
|
84
|
+
action: { type: 'string', enum: ['read', 'write', 'list', 'search', 'exists'] },
|
|
85
|
+
path: { type: 'string' },
|
|
86
|
+
content: { type: 'string' },
|
|
87
|
+
query: { type: 'string' },
|
|
88
|
+
},
|
|
89
|
+
required: ['action'],
|
|
90
|
+
},
|
|
91
|
+
async execute(input, context) {
|
|
92
|
+
const action = input.action;
|
|
93
|
+
const workspace = process.cwd();
|
|
94
|
+
const targetPath = input.path;
|
|
95
|
+
if (action === 'search') {
|
|
96
|
+
const query = input.query;
|
|
97
|
+
if (!query)
|
|
98
|
+
return { content: 'query is required for search', isError: true };
|
|
99
|
+
const results = searchFiles(workspace, query);
|
|
100
|
+
return { content: results.length ? results.join('\n') : 'No matches found', isError: false };
|
|
101
|
+
}
|
|
102
|
+
if (action === 'list') {
|
|
103
|
+
const dir = targetPath ? resolveSafe(workspace, targetPath) : workspace;
|
|
104
|
+
if (!dir)
|
|
105
|
+
return { content: 'Path outside workspace', isError: true };
|
|
106
|
+
try {
|
|
107
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
108
|
+
const listing = entries.map(e => `${e.isDirectory() ? '[DIR] ' : ''}${e.name}`).join('\n');
|
|
109
|
+
return { content: listing || '(empty directory)', isError: false };
|
|
110
|
+
}
|
|
111
|
+
catch (err) {
|
|
112
|
+
return { content: `Error listing directory: ${err instanceof Error ? err.message : String(err)}`, isError: true };
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (!targetPath)
|
|
116
|
+
return { content: 'path is required', isError: true };
|
|
117
|
+
const resolved = resolveSafe(workspace, targetPath);
|
|
118
|
+
if (!resolved)
|
|
119
|
+
return { content: 'Path outside workspace', isError: true };
|
|
120
|
+
switch (action) {
|
|
121
|
+
case 'read': {
|
|
122
|
+
try {
|
|
123
|
+
const content = fs.readFileSync(resolved, 'utf-8');
|
|
124
|
+
return { content: content.slice(0, 50000), isError: false };
|
|
125
|
+
}
|
|
126
|
+
catch (err) {
|
|
127
|
+
return { content: `Error reading file: ${err instanceof Error ? err.message : String(err)}`, isError: true };
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
case 'write': {
|
|
131
|
+
const content = input.content;
|
|
132
|
+
if (content === undefined)
|
|
133
|
+
return { content: 'content is required for write', isError: true };
|
|
134
|
+
try {
|
|
135
|
+
fs.mkdirSync(path.dirname(resolved), { recursive: true });
|
|
136
|
+
fs.writeFileSync(resolved, content, 'utf-8');
|
|
137
|
+
return { content: `Written ${content.length} bytes to ${targetPath}`, isError: false };
|
|
138
|
+
}
|
|
139
|
+
catch (err) {
|
|
140
|
+
return { content: `Error writing file: ${err instanceof Error ? err.message : String(err)}`, isError: true };
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
case 'exists': {
|
|
144
|
+
return { content: String(fs.existsSync(resolved)), isError: false };
|
|
145
|
+
}
|
|
146
|
+
default:
|
|
147
|
+
return { content: `Unknown action: ${action}`, isError: true };
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
//# sourceMappingURL=file.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { MCPTool } from '../mcp';
|
|
2
|
+
import { fileTool } from './file';
|
|
3
|
+
import { webTool } from './web';
|
|
4
|
+
import { shellTool } from './shell';
|
|
5
|
+
import { datetimeTool } from './datetime';
|
|
6
|
+
export { fileTool, webTool, shellTool, datetimeTool };
|
|
7
|
+
/**
|
|
8
|
+
* Get all built-in tools.
|
|
9
|
+
*/
|
|
10
|
+
export declare function getBuiltinTools(): MCPTool[];
|
|
11
|
+
/**
|
|
12
|
+
* Get specific built-in tools by name. If no names given, returns all.
|
|
13
|
+
*/
|
|
14
|
+
export declare function getBuiltinToolsByName(names?: string[]): MCPTool[];
|
|
15
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.datetimeTool = exports.shellTool = exports.webTool = exports.fileTool = void 0;
|
|
4
|
+
exports.getBuiltinTools = getBuiltinTools;
|
|
5
|
+
exports.getBuiltinToolsByName = getBuiltinToolsByName;
|
|
6
|
+
const file_1 = require("./file");
|
|
7
|
+
Object.defineProperty(exports, "fileTool", { enumerable: true, get: function () { return file_1.fileTool; } });
|
|
8
|
+
const web_1 = require("./web");
|
|
9
|
+
Object.defineProperty(exports, "webTool", { enumerable: true, get: function () { return web_1.webTool; } });
|
|
10
|
+
const shell_1 = require("./shell");
|
|
11
|
+
Object.defineProperty(exports, "shellTool", { enumerable: true, get: function () { return shell_1.shellTool; } });
|
|
12
|
+
const datetime_1 = require("./datetime");
|
|
13
|
+
Object.defineProperty(exports, "datetimeTool", { enumerable: true, get: function () { return datetime_1.datetimeTool; } });
|
|
14
|
+
const ALL_BUILTIN_TOOLS = [file_1.fileTool, web_1.webTool, shell_1.shellTool, datetime_1.datetimeTool];
|
|
15
|
+
const BUILTIN_MAP = new Map(ALL_BUILTIN_TOOLS.map(t => [t.name, t]));
|
|
16
|
+
/**
|
|
17
|
+
* Get all built-in tools.
|
|
18
|
+
*/
|
|
19
|
+
function getBuiltinTools() {
|
|
20
|
+
return [...ALL_BUILTIN_TOOLS];
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Get specific built-in tools by name. If no names given, returns all.
|
|
24
|
+
*/
|
|
25
|
+
function getBuiltinToolsByName(names) {
|
|
26
|
+
if (!names || names.length === 0)
|
|
27
|
+
return getBuiltinTools();
|
|
28
|
+
return names.map(n => BUILTIN_MAP.get(n)).filter((t) => !!t);
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.shellTool = void 0;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
exports.shellTool = {
|
|
6
|
+
name: 'shell_exec',
|
|
7
|
+
description: 'Execute a shell command (sandboxed to workspace)',
|
|
8
|
+
inputSchema: {
|
|
9
|
+
type: 'object',
|
|
10
|
+
properties: {
|
|
11
|
+
command: { type: 'string' },
|
|
12
|
+
timeout: { type: 'number', default: 30000 },
|
|
13
|
+
},
|
|
14
|
+
required: ['command'],
|
|
15
|
+
},
|
|
16
|
+
async execute(input) {
|
|
17
|
+
const command = input.command;
|
|
18
|
+
const timeout = input.timeout || 30000;
|
|
19
|
+
const workspace = process.cwd();
|
|
20
|
+
// Block path traversal attempts
|
|
21
|
+
if (command.includes('..')) {
|
|
22
|
+
return { content: 'Commands with ".." are not allowed for security', isError: true };
|
|
23
|
+
}
|
|
24
|
+
try {
|
|
25
|
+
const output = (0, child_process_1.execSync)(command, {
|
|
26
|
+
cwd: workspace,
|
|
27
|
+
timeout,
|
|
28
|
+
encoding: 'utf-8',
|
|
29
|
+
maxBuffer: 1024 * 1024,
|
|
30
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
31
|
+
});
|
|
32
|
+
const result = (output || '').slice(0, 5000);
|
|
33
|
+
return { content: result || '(no output)', isError: false };
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
const stderr = err.stderr ? String(err.stderr).slice(0, 2500) : '';
|
|
37
|
+
const stdout = err.stdout ? String(err.stdout).slice(0, 2500) : '';
|
|
38
|
+
const output = [stdout, stderr].filter(Boolean).join('\n') || err.message;
|
|
39
|
+
return { content: `Command failed: ${output.slice(0, 5000)}`, isError: true };
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=shell.js.map
|