@wings006/agent-link 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,23 @@
1
+ import type { Discovery } from "./discovery.js";
2
+ import type { TaskStore } from "./task-store.js";
3
+ import type { A2AClient } from "./a2a-client.js";
4
+ import type { RelayClient } from "./relay-client.js";
5
+ import type { AgentLinkConfig, TaskEvent } from "./types.js";
6
+ export declare class DaemonApi {
7
+ private server;
8
+ private config;
9
+ private discovery;
10
+ private taskStore;
11
+ private a2aClient;
12
+ private relayClient;
13
+ private startTime;
14
+ private sseClients;
15
+ constructor(config: AgentLinkConfig, discovery: Discovery, taskStore: TaskStore, a2aClient: A2AClient);
16
+ setRelayClient(client: RelayClient): void;
17
+ start(): Promise<number>;
18
+ stop(): Promise<void>;
19
+ broadcastEvent(event: TaskEvent): void;
20
+ private handleRequest;
21
+ private getLocalAddress;
22
+ private readBody;
23
+ }
@@ -0,0 +1,272 @@
1
+ import http from "node:http";
2
+ import os from "node:os";
3
+ export class DaemonApi {
4
+ server;
5
+ config;
6
+ discovery;
7
+ taskStore;
8
+ a2aClient;
9
+ relayClient = null;
10
+ startTime = Date.now();
11
+ sseClients = new Set();
12
+ constructor(config, discovery, taskStore, a2aClient) {
13
+ this.config = config;
14
+ this.discovery = discovery;
15
+ this.taskStore = taskStore;
16
+ this.a2aClient = a2aClient;
17
+ this.server = http.createServer(this.handleRequest.bind(this));
18
+ }
19
+ setRelayClient(client) {
20
+ this.relayClient = client;
21
+ }
22
+ start() {
23
+ return new Promise((resolve, reject) => {
24
+ const tryListen = (port) => {
25
+ const onError = (err) => {
26
+ if (err.code === "EADDRINUSE") {
27
+ this.server.removeListener("error", onError);
28
+ tryListen(0);
29
+ }
30
+ else {
31
+ reject(err);
32
+ }
33
+ };
34
+ this.server.once("error", onError);
35
+ // 仅绑定 127.0.0.1,不暴露到局域网
36
+ this.server.listen(port, "127.0.0.1", () => {
37
+ this.server.removeListener("error", onError);
38
+ const addr = this.server.address();
39
+ this.config.apiPort = addr.port;
40
+ resolve(addr.port);
41
+ });
42
+ };
43
+ tryListen(this.config.apiPort);
44
+ });
45
+ }
46
+ stop() {
47
+ // 关闭所有 SSE 连接
48
+ for (const client of this.sseClients) {
49
+ client.end();
50
+ }
51
+ this.sseClients.clear();
52
+ return new Promise((resolve, reject) => {
53
+ this.server.close((err) => err ? reject(err) : resolve());
54
+ });
55
+ }
56
+ broadcastEvent(event) {
57
+ const data = `data: ${JSON.stringify(event)}\n\n`;
58
+ for (const client of this.sseClients) {
59
+ client.write(data);
60
+ }
61
+ }
62
+ async handleRequest(req, res) {
63
+ try {
64
+ // GET /api/health
65
+ if (req.method === "GET" && req.url === "/api/health") {
66
+ res.setHeader("Content-Type", "application/json");
67
+ const health = {
68
+ name: this.config.name,
69
+ port: this.config.port,
70
+ apiPort: this.config.apiPort,
71
+ uptime: Date.now() - this.startTime,
72
+ agentCount: this.discovery.getAgents().length,
73
+ };
74
+ res.writeHead(200);
75
+ res.end(JSON.stringify(health));
76
+ return;
77
+ }
78
+ // GET /api/events (SSE)
79
+ if (req.method === "GET" && req.url === "/api/events") {
80
+ res.writeHead(200, {
81
+ "Content-Type": "text/event-stream",
82
+ "Cache-Control": "no-cache",
83
+ Connection: "keep-alive",
84
+ });
85
+ res.write(":ok\n\n");
86
+ this.sseClients.add(res);
87
+ req.on("close", () => {
88
+ this.sseClients.delete(res);
89
+ });
90
+ return;
91
+ }
92
+ res.setHeader("Content-Type", "application/json");
93
+ // GET /api/agents
94
+ if (req.method === "GET" && req.url === "/api/agents") {
95
+ res.writeHead(200);
96
+ res.end(JSON.stringify(this.discovery.getAgents()));
97
+ return;
98
+ }
99
+ // GET /api/tasks/inbox?unread_only=true
100
+ if (req.method === "GET" && req.url?.startsWith("/api/tasks/inbox")) {
101
+ const url = new URL(req.url, `http://127.0.0.1`);
102
+ const unreadOnly = url.searchParams.get("unread_only") === "true";
103
+ const tasks = unreadOnly
104
+ ? this.taskStore.getPending(this.config.name)
105
+ : this.taskStore.getInbox(this.config.name);
106
+ res.writeHead(200);
107
+ res.end(JSON.stringify(tasks));
108
+ return;
109
+ }
110
+ // POST /api/tasks/send body: { to, message }
111
+ if (req.method === "POST" && req.url === "/api/tasks/send") {
112
+ const body = await this.readBody(req);
113
+ const { to, message } = JSON.parse(body);
114
+ const target = this.discovery.getAgent(to);
115
+ if (!target) {
116
+ res.writeHead(404);
117
+ res.end(JSON.stringify({ error: `Agent "${to}" 不在线` }));
118
+ return;
119
+ }
120
+ let result;
121
+ if (this.discovery.isRelayAgent(to) && this.relayClient) {
122
+ // 中继 Agent,通过 WebSocket 转发
123
+ const rpcReq = {
124
+ jsonrpc: "2.0",
125
+ id: Date.now(),
126
+ method: "message/send",
127
+ params: { from: this.config.name, message },
128
+ };
129
+ const rpcRes = await this.relayClient.sendRequest(to, rpcReq);
130
+ if (rpcRes.error) {
131
+ throw new Error(rpcRes.error.message);
132
+ }
133
+ result = rpcRes.result;
134
+ }
135
+ else {
136
+ // 局域网 Agent,直接 HTTP
137
+ const callbackUrl = `http://${this.getLocalAddress()}:${this.config.port}/a2a`;
138
+ result = await this.a2aClient.sendTask(target, this.config.name, message, callbackUrl);
139
+ }
140
+ // 记录发出任务对应的目标 agent(持久化)
141
+ this.taskStore.trackOutbound(result.taskId, to);
142
+ res.writeHead(200);
143
+ res.end(JSON.stringify(result));
144
+ return;
145
+ }
146
+ // POST /api/tasks/clear body: { read_only, oldest }
147
+ if (req.method === "POST" && req.url === "/api/tasks/clear") {
148
+ const body = await this.readBody(req);
149
+ const params = JSON.parse(body);
150
+ let count;
151
+ if (params.oldest != null) {
152
+ count = this.taskStore.clearOldest(this.config.name, params.oldest);
153
+ }
154
+ else {
155
+ count = this.taskStore.clearInbox(this.config.name, params.read_only !== false);
156
+ }
157
+ res.writeHead(200);
158
+ res.end(JSON.stringify({ cleared: count }));
159
+ return;
160
+ }
161
+ // POST /api/tasks/read body: { task_id } 或 { all: true }
162
+ if (req.method === "POST" && req.url === "/api/tasks/read") {
163
+ const body = await this.readBody(req);
164
+ const params = JSON.parse(body);
165
+ if (params.all) {
166
+ const count = this.taskStore.markAllRead(this.config.name);
167
+ res.writeHead(200);
168
+ res.end(JSON.stringify({ marked: count }));
169
+ }
170
+ else if (params.task_id) {
171
+ const ok = this.taskStore.markRead(params.task_id);
172
+ res.writeHead(ok ? 200 : 404);
173
+ res.end(JSON.stringify({ ok }));
174
+ }
175
+ else {
176
+ res.writeHead(400);
177
+ res.end(JSON.stringify({ error: "需要 task_id 或 all 参数" }));
178
+ }
179
+ return;
180
+ }
181
+ // POST /api/tasks/:id/reply body: { message, status }
182
+ const replyMatch = req.url?.match(/^\/api\/tasks\/([^/]+)\/reply$/);
183
+ if (req.method === "POST" && replyMatch) {
184
+ const taskId = replyMatch[1];
185
+ const body = await this.readBody(req);
186
+ const { message, status } = JSON.parse(body);
187
+ const task = this.taskStore.updateTask(taskId, {
188
+ status,
189
+ result: message,
190
+ });
191
+ if (task) {
192
+ this.taskStore.markRead(taskId);
193
+ }
194
+ if (!task) {
195
+ res.writeHead(404);
196
+ res.end(JSON.stringify({ error: `任务 ${taskId} 不存在` }));
197
+ return;
198
+ }
199
+ // 回调通知发送方
200
+ if (task.callbackUrl && (status === "completed" || status === "rejected")) {
201
+ this.a2aClient.sendTaskNotification(task.callbackUrl, task).catch(() => { });
202
+ }
203
+ res.writeHead(200);
204
+ res.end(JSON.stringify(task));
205
+ return;
206
+ }
207
+ // GET /api/tasks/:id/poll?target=xxx — 轮询任务状态(本地或远端)
208
+ const pollMatch = req.url?.match(/^\/api\/tasks\/([^/]+)\/poll/);
209
+ if (req.method === "GET" && pollMatch) {
210
+ const taskId = pollMatch[1];
211
+ const url = new URL(req.url, `http://127.0.0.1`);
212
+ const queryTarget = url.searchParams.get("target");
213
+ // 先查本地
214
+ const localTask = this.taskStore.getTask(taskId);
215
+ if (localTask) {
216
+ res.writeHead(200);
217
+ res.end(JSON.stringify(localTask));
218
+ return;
219
+ }
220
+ // 查远端发出的任务(优先用查询参数,其次用持久化记录)
221
+ const targetName = queryTarget || this.taskStore.getOutboundTarget(taskId);
222
+ if (targetName) {
223
+ const target = this.discovery.getAgent(targetName);
224
+ if (target) {
225
+ try {
226
+ const task = await this.a2aClient.getTask(target, taskId);
227
+ res.writeHead(200);
228
+ res.end(JSON.stringify(task));
229
+ return;
230
+ }
231
+ catch (err) {
232
+ res.writeHead(502);
233
+ res.end(JSON.stringify({ error: `查询远端任务失败: ${err instanceof Error ? err.message : String(err)}` }));
234
+ return;
235
+ }
236
+ }
237
+ }
238
+ res.writeHead(404);
239
+ res.end(JSON.stringify({ error: `任务 ${taskId} 不存在` }));
240
+ return;
241
+ }
242
+ res.writeHead(404);
243
+ res.end(JSON.stringify({ error: "Not found" }));
244
+ }
245
+ catch (err) {
246
+ res.writeHead(500);
247
+ res.end(JSON.stringify({
248
+ error: err instanceof Error ? err.message : String(err),
249
+ }));
250
+ }
251
+ }
252
+ getLocalAddress() {
253
+ const interfaces = os.networkInterfaces();
254
+ for (const name of Object.keys(interfaces)) {
255
+ for (const iface of interfaces[name] || []) {
256
+ if (iface.family === "IPv4" && !iface.internal) {
257
+ return iface.address;
258
+ }
259
+ }
260
+ }
261
+ return "127.0.0.1";
262
+ }
263
+ readBody(req) {
264
+ return new Promise((resolve, reject) => {
265
+ const chunks = [];
266
+ req.on("data", (chunk) => chunks.push(chunk));
267
+ req.on("end", () => resolve(Buffer.concat(chunks).toString()));
268
+ req.on("error", reject);
269
+ });
270
+ }
271
+ }
272
+ //# sourceMappingURL=daemon-api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemon-api.js","sourceRoot":"","sources":["../src/daemon-api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/daemon.js ADDED
@@ -0,0 +1,141 @@
1
+ #!/usr/bin/env node
2
+ // 局域网通信不走代理
3
+ const noProxy = process.env.no_proxy || process.env.NO_PROXY || "";
4
+ if (!noProxy.includes(".local")) {
5
+ const updated = noProxy ? `${noProxy},.local` : ".local";
6
+ process.env.no_proxy = updated;
7
+ process.env.NO_PROXY = updated;
8
+ }
9
+ import { parseArgs } from "./config.js";
10
+ import { Discovery } from "./discovery.js";
11
+ import { A2AServer } from "./a2a-server.js";
12
+ import { A2AClient } from "./a2a-client.js";
13
+ import { TaskStore } from "./task-store.js";
14
+ import { DaemonApi } from "./daemon-api.js";
15
+ import { RelayClient } from "./relay-client.js";
16
+ const config = parseArgs(process.argv.slice(2));
17
+ const taskStore = new TaskStore();
18
+ const discovery = new Discovery(config.name);
19
+ const a2aClient = new A2AClient();
20
+ const a2aServer = new A2AServer(config, taskStore);
21
+ const daemonApi = new DaemonApi(config, discovery, taskStore, a2aClient);
22
+ let relayClient = null;
23
+ // 收到远端任务时通知
24
+ a2aServer.setOnTaskReceived((task) => {
25
+ console.error(`[agent-link daemon] 收到来自 ${task.from} 的任务: ${task.message} (ID: ${task.id})`);
26
+ daemonApi.broadcastEvent({ type: "task:created", task });
27
+ });
28
+ // 远端回调通知(对方回复了我们发出的任务)
29
+ a2aServer.setOnTaskNotified((partialTask) => {
30
+ console.error(`[agent-link daemon] 收到任务回复通知: ${partialTask.id} (状态: ${partialTask.status})`);
31
+ daemonApi.broadcastEvent({
32
+ type: "task:updated",
33
+ task: partialTask,
34
+ });
35
+ });
36
+ // 本地任务状态变更时广播 SSE
37
+ taskStore.on("task:updated", (task) => {
38
+ daemonApi.broadcastEvent({ type: "task:updated", task });
39
+ });
40
+ // 处理通过中继收到的 A2A 请求
41
+ function handleRelayRequest(from, req) {
42
+ switch (req.method) {
43
+ case "message/send": {
44
+ const params = req.params;
45
+ const task = taskStore.createTask(params.from, config.name, params.message);
46
+ console.error(`[agent-link daemon] 收到中继消息来自 ${params.from}: ${params.message} (ID: ${task.id})`);
47
+ daemonApi.broadcastEvent({ type: "task:created", task });
48
+ return { jsonrpc: "2.0", id: req.id, result: { taskId: task.id, status: task.status } };
49
+ }
50
+ case "tasks/get": {
51
+ const params = req.params;
52
+ const task = taskStore.getTask(params.taskId);
53
+ if (!task) {
54
+ return { jsonrpc: "2.0", id: req.id, error: { code: -32001, message: "Task not found" } };
55
+ }
56
+ return { jsonrpc: "2.0", id: req.id, result: task };
57
+ }
58
+ case "tasks/notify": {
59
+ const params = req.params;
60
+ console.error(`[agent-link daemon] 收到中继回复通知: ${params.taskId} (状态: ${params.status})`);
61
+ daemonApi.broadcastEvent({
62
+ type: "task:updated",
63
+ task: { id: params.taskId, status: params.status, result: params.result, from: params.from, to: params.to },
64
+ });
65
+ return { jsonrpc: "2.0", id: req.id, result: { ok: true } };
66
+ }
67
+ default:
68
+ return { jsonrpc: "2.0", id: req.id, error: { code: -32601, message: `Method not found: ${req.method}` } };
69
+ }
70
+ }
71
+ async function main() {
72
+ // 启动 A2A HTTP Server
73
+ const a2aPort = await a2aServer.start();
74
+ if (a2aPort !== config.port) {
75
+ console.error(`[agent-link daemon] A2A 端口 ${config.port} 已被占用,自动使用 ${a2aPort}`);
76
+ }
77
+ config.port = a2aPort;
78
+ console.error(`[agent-link daemon] A2A Server 启动在端口 ${a2aPort}`);
79
+ // 启动内部 API
80
+ const apiPort = await daemonApi.start();
81
+ if (apiPort !== config.apiPort) {
82
+ console.error(`[agent-link daemon] API 端口 ${config.apiPort} 已被占用,自动使用 ${apiPort}`);
83
+ }
84
+ config.apiPort = apiPort;
85
+ console.error(`[agent-link daemon] 内部 API 启动在 127.0.0.1:${apiPort}`);
86
+ // 广播自己并发现其他 Agent
87
+ discovery.publish(a2aPort, config.skills.map((s) => s.id));
88
+ discovery.browse((agent) => {
89
+ console.error(`[agent-link daemon] 发现 Agent: ${agent.name} (${agent.host}:${agent.port})`);
90
+ }, (name) => {
91
+ console.error(`[agent-link daemon] Agent 离线: ${name}`);
92
+ });
93
+ // 连接中继服务器
94
+ if (config.relayUrl) {
95
+ relayClient = new RelayClient(config.relayUrl, config.name, config.skills.map((s) => s.id));
96
+ relayClient.setOnAgentFound((agent) => {
97
+ console.error(`[agent-link daemon] 中继发现 Agent: ${agent.name}`);
98
+ discovery.addRelayAgent(agent);
99
+ });
100
+ relayClient.setOnAgentLost((name) => {
101
+ console.error(`[agent-link daemon] 中继 Agent 离线: ${name}`);
102
+ discovery.removeRelayAgent(name);
103
+ });
104
+ relayClient.setOnMessageReceived(async (from, payload) => {
105
+ return handleRelayRequest(from, payload);
106
+ });
107
+ relayClient.connect();
108
+ daemonApi.setRelayClient(relayClient);
109
+ console.error(`[agent-link daemon] 正在连接中继服务器 ${config.relayUrl}`);
110
+ }
111
+ // 等待 mDNS 发现完成
112
+ console.error("[agent-link daemon] 等待 mDNS 发现...");
113
+ await new Promise((r) => setTimeout(r, 3000));
114
+ const agentCount = discovery.getAgents().length;
115
+ console.error(`[agent-link daemon] Agent "${config.name}" 已就绪 (A2A: ${a2aPort}, API: ${apiPort}, 发现 ${agentCount} 个 Agent)`);
116
+ // daemon 保持运行,输出 ready 信号供 MCP Client 检测
117
+ process.stdout.write(JSON.stringify({ ready: true, apiPort, a2aPort, name: config.name }) + "\n");
118
+ }
119
+ // 优雅退出
120
+ process.on("SIGINT", () => {
121
+ console.error("[agent-link daemon] 正在关闭...");
122
+ discovery.destroy();
123
+ taskStore.close();
124
+ relayClient?.destroy();
125
+ Promise.all([a2aServer.stop(), daemonApi.stop()]).then(() => {
126
+ process.exit(0);
127
+ });
128
+ });
129
+ process.on("SIGTERM", () => {
130
+ discovery.destroy();
131
+ taskStore.close();
132
+ relayClient?.destroy();
133
+ Promise.all([a2aServer.stop(), daemonApi.stop()]).then(() => {
134
+ process.exit(0);
135
+ });
136
+ });
137
+ main().catch((err) => {
138
+ console.error("[agent-link daemon] 启动失败:", err);
139
+ process.exit(1);
140
+ });
141
+ //# sourceMappingURL=daemon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemon.js","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { AgentInfo } from "./types.js";
2
+ export declare class Discovery {
3
+ private bonjour;
4
+ private lanAgents;
5
+ private relayAgents;
6
+ private localName;
7
+ private onAgentFound?;
8
+ private onAgentLost?;
9
+ constructor(localName: string);
10
+ publish(port: number, skills: string[]): void;
11
+ browse(onFound?: (agent: AgentInfo) => void, onLost?: (name: string) => void): void;
12
+ addRelayAgent(agent: AgentInfo): void;
13
+ removeRelayAgent(name: string): void;
14
+ getAgents(): AgentInfo[];
15
+ getAgent(name: string): AgentInfo | undefined;
16
+ isRelayAgent(name: string): boolean;
17
+ destroy(): void;
18
+ }
@@ -0,0 +1,104 @@
1
+ import { Bonjour } from "bonjour-service";
2
+ const SERVICE_TYPE = "agent-link";
3
+ export class Discovery {
4
+ bonjour;
5
+ lanAgents = new Map();
6
+ relayAgents = new Map();
7
+ localName;
8
+ onAgentFound;
9
+ onAgentLost;
10
+ constructor(localName) {
11
+ this.bonjour = new Bonjour();
12
+ this.localName = localName;
13
+ }
14
+ // 广播自己
15
+ publish(port, skills) {
16
+ this.bonjour.publish({
17
+ name: this.localName,
18
+ type: SERVICE_TYPE,
19
+ port,
20
+ txt: {
21
+ version: "1.0",
22
+ skills: skills.join(","),
23
+ },
24
+ });
25
+ }
26
+ // 发现其他 Agent
27
+ browse(onFound, onLost) {
28
+ this.onAgentFound = onFound;
29
+ this.onAgentLost = onLost;
30
+ const browser = this.bonjour.find({ type: SERVICE_TYPE });
31
+ browser.on("up", (service) => {
32
+ if (service.name === this.localName)
33
+ return; // 跳过自己
34
+ // 优先使用 IP 地址,避免 mDNS hostname 冲突导致无法解析
35
+ const addresses = (service.addresses || []).filter((a) => !a.includes(":"));
36
+ const host = addresses[0] || service.host;
37
+ const agent = {
38
+ name: service.name,
39
+ host,
40
+ port: service.port,
41
+ skills: (service.txt?.skills || "")
42
+ .split(",")
43
+ .filter(Boolean),
44
+ version: service.txt?.version || "1.0",
45
+ status: "online",
46
+ };
47
+ this.lanAgents.set(agent.name, agent);
48
+ this.onAgentFound?.(agent);
49
+ });
50
+ browser.on("down", (service) => {
51
+ this.lanAgents.delete(service.name);
52
+ // 如果中继也没有这个 Agent,才通知离线
53
+ if (!this.relayAgents.has(service.name)) {
54
+ this.onAgentLost?.(service.name);
55
+ }
56
+ });
57
+ }
58
+ // 添加中继发现的 Agent
59
+ addRelayAgent(agent) {
60
+ // 局域网已有的不覆盖
61
+ if (this.lanAgents.has(agent.name))
62
+ return;
63
+ const isNew = !this.relayAgents.has(agent.name);
64
+ this.relayAgents.set(agent.name, agent);
65
+ if (isNew) {
66
+ this.onAgentFound?.(agent);
67
+ }
68
+ }
69
+ // 移除中继 Agent
70
+ removeRelayAgent(name) {
71
+ if (!this.relayAgents.has(name))
72
+ return;
73
+ this.relayAgents.delete(name);
74
+ // 局域网也没有才通知离线
75
+ if (!this.lanAgents.has(name)) {
76
+ this.onAgentLost?.(name);
77
+ }
78
+ }
79
+ // 获取所有 Agent(局域网优先)
80
+ getAgents() {
81
+ const merged = new Map();
82
+ // 先放中继的
83
+ for (const [name, agent] of this.relayAgents) {
84
+ merged.set(name, agent);
85
+ }
86
+ // 局域网的覆盖中继的(优先直连)
87
+ for (const [name, agent] of this.lanAgents) {
88
+ merged.set(name, agent);
89
+ }
90
+ return [...merged.values()];
91
+ }
92
+ getAgent(name) {
93
+ // 局域网优先
94
+ return this.lanAgents.get(name) || this.relayAgents.get(name);
95
+ }
96
+ // 判断是否是中继 Agent(非局域网直连)
97
+ isRelayAgent(name) {
98
+ return !this.lanAgents.has(name) && this.relayAgents.has(name);
99
+ }
100
+ destroy() {
101
+ this.bonjour.destroy();
102
+ }
103
+ }
104
+ //# sourceMappingURL=discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};