@perkos/perkos-a2a 0.8.31 → 0.8.33

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.
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-reply.d.ts","sourceRoot":"","sources":["../src/runtime-reply.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAiDxD;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC,CA2EjB;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAczE;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAE3D"}
1
+ {"version":3,"file":"runtime-reply.d.ts","sourceRoot":"","sources":["../src/runtime-reply.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AA8CxD;;;;;;;GAOG;AACH,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC,CA2EjB;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAczE;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAE3D"}
package/dist/server.d.ts CHANGED
@@ -8,6 +8,14 @@ import express from "express";
8
8
  import type { AgentCard, Task, JsonRpcResponse, A2APluginConfig } from "./types.js";
9
9
  export type TaskResultHandler = (task: Task, text: string) => Promise<void> | void;
10
10
  export type TaskFailureHandler = (task: Task, errorText: string) => Promise<void> | void;
11
+ export type RuntimeDeliveryHealth = {
12
+ ok: boolean;
13
+ status: "delivered" | "failed";
14
+ timestamp: string;
15
+ taskId?: string;
16
+ runtimeKind?: string;
17
+ detail?: string;
18
+ };
11
19
  /** Detect if the host is behind NAT by comparing public IP to local interfaces */
12
20
  export declare function detectNetworking(): Promise<{
13
21
  isBehindNat: boolean;
@@ -28,6 +36,7 @@ export declare class A2AServer {
28
36
  private messageInjector;
29
37
  private taskResultHandler;
30
38
  private taskFailureHandler;
39
+ private lastRuntimeDelivery;
31
40
  constructor(config: A2APluginConfig, logger?: {
32
41
  info: (...args: unknown[]) => void;
33
42
  error: (...args: unknown[]) => void;
@@ -37,6 +46,9 @@ export declare class A2AServer {
37
46
  setTaskResultHandler(handler: TaskResultHandler | null): void;
38
47
  setTaskFailureHandler(handler: TaskFailureHandler | null): void;
39
48
  getTasks(): IterableIterator<Task>;
49
+ recordRuntimeDelivery(result: Omit<RuntimeDeliveryHealth, "timestamp"> & {
50
+ timestamp?: string;
51
+ }): void;
40
52
  isClientOnly(): boolean;
41
53
  isRelayConnected(): boolean;
42
54
  private authMiddleware;
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,OAAO,MAAM,SAAS,CAAC;AAO9B,OAAO,KAAK,EACV,SAAS,EACT,IAAI,EAEJ,eAAe,EACf,eAAe,EAGhB,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,iBAAiB,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AACnF,MAAM,MAAM,kBAAkB,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAoBzF,kFAAkF;AAClF,wBAAsB,gBAAgB,IAAI,OAAO,CAAC;IAChD,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,EAAE,OAAO,CAAC;IACtB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B,CAAC,CA8BD;AAED,qBAAa,SAAS;IACpB,OAAO,CAAC,GAAG,CAAkB;IAC7B,OAAO,CAAC,KAAK,CAAgC;IAC7C,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,MAAM,CAA8E;IAC5F,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,QAAQ,CAAyB;IACzC,OAAO,CAAC,eAAe,CAA6E;IACpG,OAAO,CAAC,iBAAiB,CAAkC;IAC3D,OAAO,CAAC,kBAAkB,CAAmC;gBAG3D,MAAM,EAAE,eAAe,EACvB,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;QAAC,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;KAAE;IAsBtF,2EAA2E;IAC3E,kBAAkB,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,GAAG,IAAI;IAI9F,oBAAoB,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI,GAAG,IAAI;IAI7D,qBAAqB,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI,GAAG,IAAI;IAI/D,QAAQ,IAAI,gBAAgB,CAAC,IAAI,CAAC;IAIlC,YAAY,IAAI,OAAO;IAIvB,gBAAgB,IAAI,OAAO;IAI3B,OAAO,CAAC,cAAc;IAqBtB,OAAO,CAAC,WAAW;YA6EL,iBAAiB;YA8BjB,WAAW;IA+EzB,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,eAAe;IASvB,OAAO,CAAC,gBAAgB;IAaxB,0EAA0E;IACpE,QAAQ,CACZ,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,eAAe,CAAC;YA6Bb,cAAc;YAgDd,yBAAyB;YA2BzB,wBAAwB;YAgBxB,gBAAgB;IAuB9B,gDAAgD;IAC1C,aAAa,IAAI,OAAO,CAC5B,MAAM,CAAC,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,SAAS,CAAA;KAAE,CAAC,CACrD;IAsCD,OAAO,CAAC,OAAO;IAIf,OAAO,CAAC,KAAK;IAIb,oDAAoD;IACpD,OAAO,CAAC,eAAe;IA0BvB,OAAO,CAAC,gBAAgB;IAgBxB,OAAO,CAAC,aAAa;IAiBf,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAyD5B,OAAO,CAAC,SAAS;IA8BjB,aAAa,IAAI,OAAO,CAAC,OAAO;CAGjC"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "id": "perkos-a2a",
3
3
  "name": "PerkOS A2A",
4
- "version": "0.8.11",
4
+ "version": "0.8.33",
5
5
  "description": "Agent-to-Agent (A2A) protocol communication for OpenClaw agents",
6
6
  "author": "PerkOS",
7
7
  "configSchema": {
@@ -166,6 +166,10 @@
166
166
  }
167
167
  },
168
168
  "description": "Authentication configuration for A2A endpoints"
169
+ },
170
+ "pairingStorePath": {
171
+ "type": "string",
172
+ "description": "Path to a local pairing credential profile, e.g. ~/.perkos/a2a/agents/Alice.json. The plugin may load relay credentials from this store without printing secrets."
169
173
  }
170
174
  }
171
175
  },
package/package.json CHANGED
@@ -1,21 +1,37 @@
1
1
  {
2
2
  "name": "@perkos/perkos-a2a",
3
- "version": "0.8.31",
3
+ "version": "0.8.33",
4
4
  "description": "A2A Protocol communication plugin for OpenClaw — Agent-to-Agent protocol implementation",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
8
8
  "files": [
9
- "dist",
10
- "bin",
9
+ "dist/index.js",
10
+ "dist/index.js.map",
11
+ "dist/index.d.ts",
12
+ "dist/index.d.ts.map",
13
+ "dist/types.js",
14
+ "dist/types.js.map",
15
+ "dist/types.d.ts",
16
+ "dist/types.d.ts.map",
17
+ "dist/server.d.ts",
18
+ "dist/server.d.ts.map",
19
+ "dist/relay-client.d.ts",
20
+ "dist/relay-client.d.ts.map",
21
+ "dist/relay.d.ts",
22
+ "dist/relay.d.ts.map",
23
+ "dist/pairing.d.ts",
24
+ "dist/pairing.d.ts.map",
25
+ "dist/runtime-reply.d.ts",
26
+ "dist/runtime-reply.d.ts.map",
27
+ "dist/agentic-actions.d.ts",
28
+ "dist/agentic-actions.d.ts.map",
11
29
  "docs",
12
30
  "skills",
13
- "openclaw.plugin.json"
31
+ "openclaw.plugin.json",
32
+ "README.md",
33
+ "LICENSE"
14
34
  ],
15
- "bin": {
16
- "a2a-relay": "bin/relay.ts",
17
- "perkos-a2a-agent": "dist/agent.js"
18
- },
19
35
  "scripts": {
20
36
  "build": "tsc && node scripts/bundle.mjs",
21
37
  "dev": "tsc --watch",
package/bin/agent.ts DELETED
@@ -1,182 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Standalone PerkOS A2A bridge.
4
- *
5
- * This is for runtimes that do not load OpenClaw plugins directly, especially
6
- * Hermes Workspace. It runs the same A2A HTTP/relay server and delivers inbound
7
- * tasks into a local runtime over that runtime's native wake/send API.
8
- *
9
- * Usage:
10
- * perkos-a2a-agent --config ./a2a.config.json
11
- * A2A_AGENT_NAME=hermes A2A_RUNTIME=hermes-api HERMES_API_URL=http://127.0.0.1:8642 perkos-a2a-agent
12
- */
13
-
14
- import { readFileSync } from "fs";
15
- import { randomUUID } from "crypto";
16
- import { A2AServer } from "../src/server.js";
17
- import type { A2APluginConfig, Task } from "../src/types.js";
18
-
19
- function argValue(flag: string): string | undefined {
20
- const idx = process.argv.indexOf(flag);
21
- if (idx === -1) return undefined;
22
- return process.argv[idx + 1];
23
- }
24
-
25
- function parseJsonEnv<T>(name: string, fallback: T): T {
26
- const raw = process.env[name];
27
- if (!raw) return fallback;
28
- try {
29
- return JSON.parse(raw) as T;
30
- } catch (err) {
31
- throw new Error(`${name} must be valid JSON: ${err instanceof Error ? err.message : String(err)}`);
32
- }
33
- }
34
-
35
- function loadConfig(): A2APluginConfig {
36
- const configPath = argValue("--config") || argValue("-c") || process.env.A2A_CONFIG;
37
- if (configPath) {
38
- return JSON.parse(readFileSync(configPath, "utf8")) as A2APluginConfig;
39
- }
40
-
41
- const port = Number(process.env.A2A_PORT || "5050");
42
- const relayEnabled = String(process.env.A2A_RELAY_ENABLED || "").toLowerCase() === "true";
43
- return {
44
- agentName: process.env.A2A_AGENT_NAME || "agent",
45
- port,
46
- bindHost: process.env.A2A_BIND_HOST || "0.0.0.0",
47
- publicUrl: process.env.A2A_PUBLIC_URL,
48
- mode: (process.env.A2A_MODE as A2APluginConfig["mode"]) || "auto",
49
- skills: parseJsonEnv("A2A_SKILLS", []),
50
- peers: parseJsonEnv("A2A_PEERS", {}),
51
- peerAuth: parseJsonEnv("A2A_PEER_AUTH", {}),
52
- auth: process.env.A2A_API_KEYS
53
- ? { requireApiKey: true, apiKeys: process.env.A2A_API_KEYS.split(",").map((v) => v.trim()).filter(Boolean) }
54
- : undefined,
55
- relay: relayEnabled || process.env.A2A_RELAY_URL
56
- ? {
57
- enabled: relayEnabled || Boolean(process.env.A2A_RELAY_URL),
58
- url: process.env.A2A_RELAY_URL || "",
59
- apiKey: process.env.A2A_RELAY_API_KEY || "",
60
- hubPort: process.env.A2A_RELAY_HUB_PORT ? Number(process.env.A2A_RELAY_HUB_PORT) : undefined,
61
- hubApiKeys: process.env.A2A_RELAY_HUB_API_KEYS?.split(",").map((v) => v.trim()).filter(Boolean),
62
- }
63
- : undefined,
64
- runtime: {
65
- kind: (process.env.A2A_RUNTIME as A2APluginConfig["runtime"] extends infer R ? R extends { kind?: infer K } ? K : never : never) || "hermes",
66
- sessionKey: process.env.A2A_SESSION_KEY,
67
- hermesUrl: process.env.HERMES_WORKSPACE_URL,
68
- hermesToken: process.env.HERMES_WORKSPACE_TOKEN || process.env.HERMES_SESSION_TOKEN,
69
- hermesEndpoint: process.env.HERMES_WORKSPACE_ENDPOINT,
70
- },
71
- };
72
- }
73
-
74
- function taskMarker(task: Task): string {
75
- return `[A2A_RESULT:${task.id}]`;
76
- }
77
-
78
- function buildRuntimeMessage(task: Task, text: string): string {
79
- const from = (task.metadata?.fromAgent as string) || "unknown";
80
- const marker = taskMarker(task);
81
- return [
82
- marker,
83
- `From: ${from}`,
84
- `Task ID: ${task.id}`,
85
- `Context ID: ${task.contextId}`,
86
- "",
87
- "Execute the following request and include the final answer in your assistant reply.",
88
- `Your final answer must begin with exactly: ${marker}`,
89
- "Return the useful final answer after that marker.",
90
- "",
91
- text,
92
- ].join("\n");
93
- }
94
-
95
- async function deliverToHermes(config: A2APluginConfig, message: string): Promise<void> {
96
- const runtime = config.runtime || {};
97
- const baseUrl = (runtime.hermesUrl || process.env.HERMES_API_URL || process.env.HERMES_WORKSPACE_URL || "http://127.0.0.1:8642").replace(/\/+$/, "");
98
- const endpoint = runtime.hermesEndpoint || process.env.HERMES_API_ENDPOINT || process.env.HERMES_WORKSPACE_ENDPOINT || "/v1/responses";
99
- const sessionKey = runtime.sessionKey || process.env.HERMES_SESSION_ID || process.env.HERMES_SESSION_KEY || "a2a";
100
- const token = runtime.hermesToken || process.env.API_SERVER_KEY || process.env.HERMES_API_KEY || process.env.HERMES_WORKSPACE_TOKEN || process.env.HERMES_SESSION_TOKEN;
101
- const url = `${baseUrl}${endpoint.startsWith("/") ? endpoint : `/${endpoint}`}`;
102
- const headers: Record<string, string> = {
103
- "content-type": "application/json",
104
- "x-hermes-session-id": sessionKey,
105
- "x-hermes-session-key": sessionKey,
106
- };
107
- if (token) headers.authorization = `Bearer ${token}`;
108
-
109
- const normalizedEndpoint = endpoint.replace(/^\/?/, "/");
110
- const body = normalizedEndpoint.startsWith("/v1/chat/completions")
111
- ? { model: process.env.HERMES_MODEL || "hermes-agent", messages: [{ role: "user", content: message }], stream: false }
112
- : normalizedEndpoint.startsWith("/v1/runs")
113
- ? { input: message, session_id: sessionKey }
114
- : normalizedEndpoint.startsWith("/v1/responses")
115
- ? { model: process.env.HERMES_MODEL || "hermes-agent", input: message, store: true }
116
- : { sessionKey, message };
117
-
118
- const response = await fetch(url, { method: "POST", headers, body: JSON.stringify(body) });
119
- if (!response.ok) {
120
- const text = await response.text().catch(() => "");
121
- throw new Error(`Hermes API delivery failed (${response.status}) at ${url}: ${text || response.statusText}`);
122
- }
123
- }
124
-
125
- async function main(): Promise<void> {
126
- const config = loadConfig();
127
- const logger = console;
128
- const server = new A2AServer(config, logger);
129
-
130
- server.setTaskResultHandler(async (task, text) => {
131
- const runtimeKind = config.runtime?.kind || "hermes";
132
- task.status = {
133
- state: "working",
134
- timestamp: new Date().toISOString(),
135
- message: { role: "agent", parts: [{ kind: "text", text: `Task dispatched to ${runtimeKind} runtime.` }] },
136
- };
137
-
138
- if ((runtimeKind === "hermes" || runtimeKind === "hermes-api")) {
139
- await deliverToHermes(config, buildRuntimeMessage(task, text));
140
- task.artifacts.push({
141
- kind: "artifact",
142
- artifactId: randomUUID(),
143
- parts: [{ kind: "text", text: "Delivered to Hermes API Server." }],
144
- });
145
- return;
146
- }
147
-
148
- if (runtimeKind === "none") {
149
- task.artifacts.push({
150
- kind: "artifact",
151
- artifactId: randomUUID(),
152
- parts: [{ kind: "text", text: "Runtime delivery disabled." }],
153
- });
154
- return;
155
- }
156
-
157
- throw new Error(`Standalone runtime '${runtimeKind}' is not supported yet. Use OpenClaw plugin mode for OpenClaw delivery.`);
158
- });
159
-
160
- server.setTaskFailureHandler((task, errorText) => {
161
- task.status = {
162
- state: "failed",
163
- timestamp: new Date().toISOString(),
164
- message: { role: "agent", parts: [{ kind: "text", text: errorText }] },
165
- };
166
- });
167
-
168
- await server.start();
169
- logger.info(`[perkos-a2a] standalone bridge running for ${config.agentName} (${config.runtime?.kind || "hermes"})`);
170
-
171
- const stop = () => {
172
- logger.info("[perkos-a2a] standalone bridge shutting down");
173
- process.exit(0);
174
- };
175
- process.on("SIGINT", stop);
176
- process.on("SIGTERM", stop);
177
- }
178
-
179
- main().catch((err) => {
180
- console.error(`[perkos-a2a] standalone bridge failed: ${err instanceof Error ? err.stack || err.message : String(err)}`);
181
- process.exit(1);
182
- });
package/bin/relay.ts DELETED
@@ -1,106 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Standalone A2A Relay Hub
4
- *
5
- * Usage:
6
- * npx tsx bin/relay.ts [--port 6060] [--api-keys key1,key2]
7
- *
8
- * Environment variables:
9
- * RELAY_PORT - WebSocket port (default: 6060)
10
- * RELAY_API_KEYS - Comma-separated list of accepted API keys
11
- * RELAY_AGENTS - Comma-separated approved agents as name:key,name2:key2
12
- * RELAY_MAX_QUEUE - Max queued messages per offline agent (default: 200)
13
- * RELAY_RATE_LIMIT - Max messages per agent per minute (default: 60)
14
- */
15
-
16
- import { RelayHub } from "../src/relay.js";
17
- import type { RelayHubConfig } from "../src/relay.js";
18
-
19
- function parseArgs(): Partial<RelayHubConfig> {
20
- const args = process.argv.slice(2);
21
- const config: Partial<RelayHubConfig> = {};
22
-
23
- for (let i = 0; i < args.length; i++) {
24
- switch (args[i]) {
25
- case "--port":
26
- case "-p":
27
- config.port = parseInt(args[++i], 10);
28
- break;
29
- case "--api-keys":
30
- config.apiKeys = args[++i].split(",").map((k) => k.trim()).filter(Boolean);
31
- break;
32
- case "--agents":
33
- config.registeredAgents = Object.fromEntries(
34
- args[++i].split(",").map((entry) => {
35
- const [name, ...keyParts] = entry.split(":");
36
- return [name.trim(), keyParts.join(":").trim()];
37
- }).filter(([name, key]) => name && key)
38
- );
39
- break;
40
- case "--max-queue":
41
- config.maxQueuePerAgent = parseInt(args[++i], 10);
42
- break;
43
- case "--rate-limit":
44
- config.rateLimitPerMinute = parseInt(args[++i], 10);
45
- break;
46
- case "--help":
47
- case "-h":
48
- console.log("A2A Relay Hub");
49
- console.log("");
50
- console.log("Options:");
51
- console.log(" --port, -p <port> WebSocket port (default: 6060)");
52
- console.log(" --api-keys <k1,k2,...> Accepted API keys (legacy shared-key mode)");
53
- console.log(" --agents <name:key,...> Approved agent registry (recommended)");
54
- console.log(" --max-queue <n> Max queued messages per offline agent (default: 200)");
55
- console.log(" --rate-limit <n> Max messages per agent per minute (default: 60)");
56
- console.log("");
57
- console.log("Environment variables:");
58
- console.log(" RELAY_PORT, RELAY_API_KEYS, RELAY_MAX_QUEUE, RELAY_RATE_LIMIT");
59
- process.exit(0);
60
- }
61
- }
62
-
63
- // Environment variable overrides
64
- if (!config.port && process.env.RELAY_PORT) {
65
- config.port = parseInt(process.env.RELAY_PORT, 10);
66
- }
67
- if (!config.apiKeys && process.env.RELAY_API_KEYS) {
68
- config.apiKeys = process.env.RELAY_API_KEYS.split(",").map((k) => k.trim()).filter(Boolean);
69
- }
70
- if (!config.registeredAgents && process.env.RELAY_AGENTS) {
71
- config.registeredAgents = Object.fromEntries(
72
- process.env.RELAY_AGENTS.split(",").map((entry) => {
73
- const [name, ...keyParts] = entry.split(":");
74
- return [name.trim(), keyParts.join(":").trim()];
75
- }).filter(([name, key]) => name && key)
76
- );
77
- }
78
- if (!config.maxQueuePerAgent && process.env.RELAY_MAX_QUEUE) {
79
- config.maxQueuePerAgent = parseInt(process.env.RELAY_MAX_QUEUE, 10);
80
- }
81
- if (!config.rateLimitPerMinute && process.env.RELAY_RATE_LIMIT) {
82
- config.rateLimitPerMinute = parseInt(process.env.RELAY_RATE_LIMIT, 10);
83
- }
84
-
85
- return config;
86
- }
87
-
88
- const config = parseArgs();
89
- const hub = new RelayHub(config);
90
-
91
- hub.start();
92
-
93
- console.log("[perkos-a2a] Relay hub running");
94
- console.log(`[perkos-a2a] Port: ${config.port || 6060}`);
95
- console.log(`[perkos-a2a] Auth: ${config.registeredAgents && Object.keys(config.registeredAgents).length ? "approved-agent registry" : config.apiKeys?.length ? "shared-key" : "disabled (no API keys configured)"}`);
96
-
97
- process.on("SIGINT", () => {
98
- console.log("\n[perkos-a2a] Shutting down relay hub...");
99
- hub.stop();
100
- process.exit(0);
101
- });
102
-
103
- process.on("SIGTERM", () => {
104
- hub.stop();
105
- process.exit(0);
106
- });
package/dist/agent.d.ts DELETED
@@ -1,14 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Standalone PerkOS A2A bridge.
4
- *
5
- * This is for runtimes that do not load OpenClaw plugins directly, especially
6
- * Hermes Workspace. It runs the same A2A HTTP/relay server and delivers inbound
7
- * tasks into a local runtime over that runtime's native wake/send API.
8
- *
9
- * Usage:
10
- * perkos-a2a-agent --config ./a2a.config.json
11
- * A2A_AGENT_NAME=hermes A2A_RUNTIME=hermes-api HERMES_API_URL=http://127.0.0.1:8642 perkos-a2a-agent
12
- */
13
- export {};
14
- //# sourceMappingURL=agent.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../src/agent.ts"],"names":[],"mappings":";AACA;;;;;;;;;;GAUG"}