@clawcrony/claw-crony 1.2.4 → 1.3.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.
- package/CHANGELOG.md +107 -0
- package/CONFIG.md +341 -0
- package/README.md +147 -18
- package/dist/index.js +509 -164
- package/dist/src/ephemeral-token.d.ts +3 -1
- package/dist/src/ephemeral-token.js +7 -2
- package/dist/src/history.d.ts +44 -0
- package/dist/src/history.js +119 -0
- package/dist/src/hub-match.js +1 -1
- package/dist/src/hub-registration.js +1 -1
- package/dist/src/types.d.ts +4 -1
- package/openclaw.plugin.json +46 -18
- package/package.json +43 -27
- package/scripts/a2a-diagnose.ps1 +15 -0
- package/scripts/a2a-diagnose.sh +22 -0
- package/scripts/a2a-history.ps1 +21 -0
- package/scripts/a2a-history.sh +9 -0
- package/scripts/a2a-match.ps1 +16 -0
- package/scripts/a2a-match.sh +13 -0
- package/scripts/a2a-peers.ps1 +1 -0
- package/scripts/a2a-peers.sh +4 -0
- package/scripts/a2a-send.ps1 +23 -0
- package/scripts/a2a-send.sh +14 -0
- package/scripts/a2a-update.ps1 +3 -0
- package/scripts/a2a-update.sh +6 -0
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { GatewayConfig } from "./types.js";
|
|
2
|
-
export declare
|
|
2
|
+
export declare const EPHEMERAL_INBOUND_TOKEN_LENGTH = 48;
|
|
3
|
+
export declare function isValidEphemeralInboundToken(value: unknown): value is string;
|
|
4
|
+
export declare function issueEphemeralInboundToken(config: GatewayConfig, _matchId: number, _peerAgentId: number, ttlMs?: number): {
|
|
3
5
|
token: string;
|
|
4
6
|
expiresAt: string;
|
|
5
7
|
};
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import crypto from "node:crypto";
|
|
2
|
-
export
|
|
3
|
-
|
|
2
|
+
export const EPHEMERAL_INBOUND_TOKEN_LENGTH = 48;
|
|
3
|
+
const EPHEMERAL_INBOUND_TOKEN_PATTERN = /^[0-9a-f]{48}$/;
|
|
4
|
+
export function isValidEphemeralInboundToken(value) {
|
|
5
|
+
return typeof value === "string" && EPHEMERAL_INBOUND_TOKEN_PATTERN.test(value);
|
|
6
|
+
}
|
|
7
|
+
export function issueEphemeralInboundToken(config, _matchId, _peerAgentId, ttlMs = 5 * 60_000) {
|
|
8
|
+
const token = crypto.randomBytes(EPHEMERAL_INBOUND_TOKEN_LENGTH / 2).toString("hex");
|
|
4
9
|
config.security.validTokens.add(token);
|
|
5
10
|
setTimeout(() => {
|
|
6
11
|
config.security.validTokens.delete(token);
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export type RequestHistoryType = "match.created" | "match.failed" | "handshake.offer_sent" | "handshake.offer_received" | "handshake.answer_sent" | "handshake.answer_received" | "handshake.failed" | "peer.upserted" | "send.started" | "send.completed" | "send.failed" | "send_file.started" | "send_file.completed" | "send_file.failed" | "task.inbound_completed" | "task.inbound_failed";
|
|
2
|
+
export type RequestHistoryStatus = "started" | "success" | "failure" | "ignored";
|
|
3
|
+
export type RequestHistoryDirection = "inbound" | "outbound" | "local";
|
|
4
|
+
export interface RequestHistoryEntry {
|
|
5
|
+
ts: string;
|
|
6
|
+
type: RequestHistoryType;
|
|
7
|
+
status: RequestHistoryStatus;
|
|
8
|
+
direction?: RequestHistoryDirection;
|
|
9
|
+
matchId?: number;
|
|
10
|
+
messageId?: number;
|
|
11
|
+
peer?: string;
|
|
12
|
+
durationMs?: number;
|
|
13
|
+
detail?: Record<string, unknown>;
|
|
14
|
+
}
|
|
15
|
+
export interface RequestHistoryFilter {
|
|
16
|
+
count?: number;
|
|
17
|
+
type?: string;
|
|
18
|
+
status?: string;
|
|
19
|
+
direction?: string;
|
|
20
|
+
matchId?: number;
|
|
21
|
+
peer?: string;
|
|
22
|
+
}
|
|
23
|
+
export interface RequestHistoryOptions {
|
|
24
|
+
enabled: boolean;
|
|
25
|
+
includeEncryptedPayloads: boolean;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Append-only request history store for operator-facing troubleshooting.
|
|
29
|
+
* Unlike the audit log, this captures Hub match/handshake milestones and
|
|
30
|
+
* gateway calls. Sensitive fields are redacted before persistence.
|
|
31
|
+
*/
|
|
32
|
+
export declare class RequestHistoryStore {
|
|
33
|
+
private readonly filePath;
|
|
34
|
+
private readonly options;
|
|
35
|
+
private dirEnsured;
|
|
36
|
+
constructor(filePath: string, options?: Partial<RequestHistoryOptions>);
|
|
37
|
+
record(entry: Omit<RequestHistoryEntry, "ts"> & {
|
|
38
|
+
ts?: string;
|
|
39
|
+
}): void;
|
|
40
|
+
tail(filter?: RequestHistoryFilter): Promise<RequestHistoryEntry[]>;
|
|
41
|
+
close(): void;
|
|
42
|
+
private ensureDir;
|
|
43
|
+
private write;
|
|
44
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import readline from "node:readline";
|
|
4
|
+
const SECRET_KEY_NAMES = ["token", "secret", "password", "authorization", "ciphertext"];
|
|
5
|
+
function redactValue(key, value, includeEncryptedPayloads) {
|
|
6
|
+
const normalizedKey = key.toLowerCase();
|
|
7
|
+
if (SECRET_KEY_NAMES.some((name) => normalizedKey.includes(name))) {
|
|
8
|
+
if (normalizedKey.includes("ciphertext") && includeEncryptedPayloads) {
|
|
9
|
+
return value;
|
|
10
|
+
}
|
|
11
|
+
return "[redacted]";
|
|
12
|
+
}
|
|
13
|
+
if (Array.isArray(value)) {
|
|
14
|
+
return value.map((entry) => redactUnknown(entry, includeEncryptedPayloads));
|
|
15
|
+
}
|
|
16
|
+
if (value && typeof value === "object") {
|
|
17
|
+
return redactObject(value, includeEncryptedPayloads);
|
|
18
|
+
}
|
|
19
|
+
return value;
|
|
20
|
+
}
|
|
21
|
+
function redactUnknown(value, includeEncryptedPayloads) {
|
|
22
|
+
if (Array.isArray(value)) {
|
|
23
|
+
return value.map((entry) => redactUnknown(entry, includeEncryptedPayloads));
|
|
24
|
+
}
|
|
25
|
+
if (value && typeof value === "object") {
|
|
26
|
+
return redactObject(value, includeEncryptedPayloads);
|
|
27
|
+
}
|
|
28
|
+
return value;
|
|
29
|
+
}
|
|
30
|
+
function redactObject(value, includeEncryptedPayloads) {
|
|
31
|
+
const next = {};
|
|
32
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
33
|
+
next[key] = redactValue(key, entry, includeEncryptedPayloads);
|
|
34
|
+
}
|
|
35
|
+
return next;
|
|
36
|
+
}
|
|
37
|
+
function matchesFilter(entry, filter) {
|
|
38
|
+
if (filter.type && entry.type !== filter.type)
|
|
39
|
+
return false;
|
|
40
|
+
if (filter.status && entry.status !== filter.status)
|
|
41
|
+
return false;
|
|
42
|
+
if (filter.direction && entry.direction !== filter.direction)
|
|
43
|
+
return false;
|
|
44
|
+
if (filter.matchId != null && entry.matchId !== filter.matchId)
|
|
45
|
+
return false;
|
|
46
|
+
if (filter.peer && entry.peer !== filter.peer)
|
|
47
|
+
return false;
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Append-only request history store for operator-facing troubleshooting.
|
|
52
|
+
* Unlike the audit log, this captures Hub match/handshake milestones and
|
|
53
|
+
* gateway calls. Sensitive fields are redacted before persistence.
|
|
54
|
+
*/
|
|
55
|
+
export class RequestHistoryStore {
|
|
56
|
+
filePath;
|
|
57
|
+
options;
|
|
58
|
+
dirEnsured = false;
|
|
59
|
+
constructor(filePath, options = {}) {
|
|
60
|
+
this.filePath = filePath;
|
|
61
|
+
this.options = {
|
|
62
|
+
enabled: options.enabled ?? true,
|
|
63
|
+
includeEncryptedPayloads: options.includeEncryptedPayloads ?? false,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
record(entry) {
|
|
67
|
+
if (!this.options.enabled) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const detail = entry.detail
|
|
71
|
+
? redactObject(entry.detail, this.options.includeEncryptedPayloads)
|
|
72
|
+
: undefined;
|
|
73
|
+
this.write({
|
|
74
|
+
...entry,
|
|
75
|
+
ts: entry.ts ?? new Date().toISOString(),
|
|
76
|
+
...(detail ? { detail } : {}),
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
async tail(filter = {}) {
|
|
80
|
+
if (!fs.existsSync(this.filePath))
|
|
81
|
+
return [];
|
|
82
|
+
const count = Math.min(Math.max(1, Math.floor(filter.count ?? 50)), 500);
|
|
83
|
+
const entries = [];
|
|
84
|
+
const input = fs.createReadStream(this.filePath, { encoding: "utf-8" });
|
|
85
|
+
const rl = readline.createInterface({ input, crlfDelay: Infinity });
|
|
86
|
+
for await (const line of rl) {
|
|
87
|
+
if (!line.trim())
|
|
88
|
+
continue;
|
|
89
|
+
try {
|
|
90
|
+
const entry = JSON.parse(line);
|
|
91
|
+
if (matchesFilter(entry, filter)) {
|
|
92
|
+
entries.push(entry);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
// Skip malformed lines.
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return entries.slice(-count).reverse();
|
|
100
|
+
}
|
|
101
|
+
close() {
|
|
102
|
+
// No persistent handles.
|
|
103
|
+
}
|
|
104
|
+
ensureDir() {
|
|
105
|
+
if (this.dirEnsured)
|
|
106
|
+
return;
|
|
107
|
+
this.dirEnsured = true;
|
|
108
|
+
fs.mkdirSync(path.dirname(this.filePath), { recursive: true });
|
|
109
|
+
}
|
|
110
|
+
write(entry) {
|
|
111
|
+
try {
|
|
112
|
+
this.ensureDir();
|
|
113
|
+
fs.appendFileSync(this.filePath, JSON.stringify(entry) + "\n");
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
// History is diagnostic only; never crash the gateway.
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
package/dist/src/hub-match.js
CHANGED
|
@@ -51,7 +51,7 @@ export class HubMatchClient {
|
|
|
51
51
|
async getPendingMatches() {
|
|
52
52
|
return this.request(`/api/matches/pending?agentId=${this.registration.agentId}`);
|
|
53
53
|
}
|
|
54
|
-
async updatePresence(presenceStatus, clientVersion = "claw-crony/1.
|
|
54
|
+
async updatePresence(presenceStatus, clientVersion = "claw-crony/1.3.0") {
|
|
55
55
|
return this.request(`/api/agents/${this.registration.agentId}/presence`, {
|
|
56
56
|
method: "PUT",
|
|
57
57
|
body: JSON.stringify({
|
|
@@ -127,7 +127,7 @@ export async function runHubRegistration(api, config, hubConfig, registrationCon
|
|
|
127
127
|
clientId: identity.clientId,
|
|
128
128
|
publicKey: identity.publicKey,
|
|
129
129
|
keyVersion: identity.keyVersion,
|
|
130
|
-
clientVersion: "claw-crony/1.
|
|
130
|
+
clientVersion: "claw-crony/1.3.0",
|
|
131
131
|
username,
|
|
132
132
|
email,
|
|
133
133
|
};
|
package/dist/src/types.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* These types support the A2A v0.3.0 protocol integration via @a2a-js/sdk.
|
|
5
5
|
*/
|
|
6
|
-
export type { OpenClawPluginApi, PluginLogger, OpenClawConfig } from "openclaw/plugin-sdk";
|
|
6
|
+
export type { OpenClawPluginApi, PluginLogger, OpenClawConfig } from "openclaw/plugin-sdk/plugin-entry";
|
|
7
7
|
export type InboundAuth = "none" | "bearer";
|
|
8
8
|
export type PeerAuthType = "bearer" | "apiKey";
|
|
9
9
|
export interface PeerAuthConfig {
|
|
@@ -70,6 +70,9 @@ export interface GatewayConfig {
|
|
|
70
70
|
metricsPath: string;
|
|
71
71
|
metricsAuth: "none" | "bearer";
|
|
72
72
|
auditLogPath: string;
|
|
73
|
+
historyEnabled: boolean;
|
|
74
|
+
historyLogPath: string;
|
|
75
|
+
historyIncludeEncryptedPayloads: boolean;
|
|
73
76
|
};
|
|
74
77
|
timeouts?: {
|
|
75
78
|
/**
|
package/openclaw.plugin.json
CHANGED
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
{
|
|
2
|
-
"id": "claw-crony",
|
|
3
|
-
"name": "Claw Crony",
|
|
4
|
-
"description": "OpenClaw A2A v0.3.0 gateway with Agent Card, JSON-RPC, REST, routing rules, transport fallback, and Hub matchmaking",
|
|
5
|
-
"version": "1.
|
|
6
|
-
"
|
|
2
|
+
"id": "claw-crony",
|
|
3
|
+
"name": "Claw Crony",
|
|
4
|
+
"description": "OpenClaw A2A v0.3.0 gateway with Agent Card, JSON-RPC, REST, routing rules, transport fallback, and Hub matchmaking",
|
|
5
|
+
"version": "1.3.0",
|
|
6
|
+
"activation": {
|
|
7
|
+
"onStartup": true
|
|
8
|
+
},
|
|
9
|
+
"contracts": {
|
|
10
|
+
"tools": [
|
|
11
|
+
"a2a_send_file",
|
|
12
|
+
"a2a_match_request"
|
|
13
|
+
]
|
|
14
|
+
},
|
|
15
|
+
"defaultConfig": {
|
|
7
16
|
"agentCard": {
|
|
8
17
|
"name": "OpenClaw A2A Gateway",
|
|
9
18
|
"description": "A2A bridge for OpenClaw agents",
|
|
@@ -58,12 +67,16 @@
|
|
|
58
67
|
"registration": {
|
|
59
68
|
"type": "object",
|
|
60
69
|
"additionalProperties": false,
|
|
61
|
-
"properties": {
|
|
62
|
-
"username": { "type": "string" },
|
|
63
|
-
"email": { "type": "string" },
|
|
64
|
-
"password": { "type": "string" }
|
|
65
|
-
|
|
66
|
-
|
|
70
|
+
"properties": {
|
|
71
|
+
"username": { "type": "string" },
|
|
72
|
+
"email": { "type": "string" },
|
|
73
|
+
"password": { "type": "string" },
|
|
74
|
+
"clientId": {
|
|
75
|
+
"type": "string",
|
|
76
|
+
"description": "Optional stable client id for Hub registration. If omitted, claw-crony generates and persists one locally."
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
},
|
|
67
80
|
"server": {
|
|
68
81
|
"type": "object",
|
|
69
82
|
"additionalProperties": false,
|
|
@@ -206,13 +219,28 @@
|
|
|
206
219
|
"default": "none",
|
|
207
220
|
"description": "Authentication for the metrics endpoint. When set to 'bearer', reuses security.token/tokens."
|
|
208
221
|
},
|
|
209
|
-
"auditLogPath": {
|
|
210
|
-
"type": "string",
|
|
211
|
-
"default": "~/.openclaw/a2a-audit.jsonl",
|
|
212
|
-
"description": "Path for the JSONL audit log file (separate from structured logs)."
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
|
|
222
|
+
"auditLogPath": {
|
|
223
|
+
"type": "string",
|
|
224
|
+
"default": "~/.openclaw/a2a-audit.jsonl",
|
|
225
|
+
"description": "Path for the JSONL audit log file (separate from structured logs)."
|
|
226
|
+
},
|
|
227
|
+
"historyEnabled": {
|
|
228
|
+
"type": "boolean",
|
|
229
|
+
"default": true,
|
|
230
|
+
"description": "Enable operator-facing JSONL request history for match, handshake, peer, send, and file-send events."
|
|
231
|
+
},
|
|
232
|
+
"historyLogPath": {
|
|
233
|
+
"type": "string",
|
|
234
|
+
"default": "~/.openclaw/a2a-history.jsonl",
|
|
235
|
+
"description": "Path for the JSONL request history file."
|
|
236
|
+
},
|
|
237
|
+
"historyIncludeEncryptedPayloads": {
|
|
238
|
+
"type": "boolean",
|
|
239
|
+
"default": false,
|
|
240
|
+
"description": "Include encrypted handshake payload fields in request history. Tokens and secrets remain redacted."
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
},
|
|
216
244
|
"timeouts": {
|
|
217
245
|
"type": "object",
|
|
218
246
|
"additionalProperties": false,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clawcrony/claw-crony",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "OpenClaw A2A gateway plugin implementing the A2A v0.3.0 protocol surface",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -11,11 +11,16 @@
|
|
|
11
11
|
"types": "./dist/index.d.ts"
|
|
12
12
|
}
|
|
13
13
|
},
|
|
14
|
-
"files": [
|
|
15
|
-
"dist",
|
|
16
|
-
"openclaw.plugin.json",
|
|
17
|
-
"skill"
|
|
18
|
-
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"openclaw.plugin.json",
|
|
17
|
+
"skill",
|
|
18
|
+
"scripts",
|
|
19
|
+
"README.md",
|
|
20
|
+
"CONFIG.md",
|
|
21
|
+
"CHANGELOG.md",
|
|
22
|
+
"LICENSE"
|
|
23
|
+
],
|
|
19
24
|
"scripts": {
|
|
20
25
|
"build": "tsc",
|
|
21
26
|
"test": "node --import tsx --test tests/*.test.ts"
|
|
@@ -29,27 +34,38 @@
|
|
|
29
34
|
],
|
|
30
35
|
"license": "MIT",
|
|
31
36
|
"devDependencies": {
|
|
32
|
-
"@types/express": "
|
|
33
|
-
"@types/node": "
|
|
34
|
-
"@types/supertest": "
|
|
35
|
-
"@types/uuid": "
|
|
36
|
-
"openclaw": "
|
|
37
|
-
"supertest": "
|
|
38
|
-
"tsx": "
|
|
39
|
-
"typescript": "
|
|
40
|
-
},
|
|
41
|
-
"dependencies": {
|
|
42
|
-
"@a2a-js/sdk": "
|
|
43
|
-
"@bufbuild/protobuf": "
|
|
44
|
-
"@grpc/grpc-js": "
|
|
45
|
-
"express": "
|
|
46
|
-
"uuid": "
|
|
47
|
-
},
|
|
48
|
-
"openclaw": {
|
|
49
|
-
"extensions": [
|
|
50
|
-
"./index.
|
|
51
|
-
]
|
|
52
|
-
|
|
37
|
+
"@types/express": "5.0.6",
|
|
38
|
+
"@types/node": "25.5.0",
|
|
39
|
+
"@types/supertest": "2.0.16",
|
|
40
|
+
"@types/uuid": "10.0.0",
|
|
41
|
+
"openclaw": "2026.5.2",
|
|
42
|
+
"supertest": "7.2.2",
|
|
43
|
+
"tsx": "4.21.0",
|
|
44
|
+
"typescript": "5.9.3"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@a2a-js/sdk": "0.3.13",
|
|
48
|
+
"@bufbuild/protobuf": "2.11.0",
|
|
49
|
+
"@grpc/grpc-js": "1.14.3",
|
|
50
|
+
"express": "4.22.1",
|
|
51
|
+
"uuid": "9.0.1"
|
|
52
|
+
},
|
|
53
|
+
"openclaw": {
|
|
54
|
+
"extensions": [
|
|
55
|
+
"./dist/index.js"
|
|
56
|
+
],
|
|
57
|
+
"compat": {
|
|
58
|
+
"pluginApi": ">=2026.5.2",
|
|
59
|
+
"minGatewayVersion": "2026.5.2"
|
|
60
|
+
},
|
|
61
|
+
"build": {
|
|
62
|
+
"openclawVersion": "2026.5.2",
|
|
63
|
+
"pluginSdkVersion": "2026.5.2"
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"overrides": {
|
|
67
|
+
"axios": "1.16.0"
|
|
68
|
+
},
|
|
53
69
|
"engines": {
|
|
54
70
|
"node": ">=22"
|
|
55
71
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Write-Host "== OpenClaw Gateway =="
|
|
2
|
+
openclaw gateway status
|
|
3
|
+
|
|
4
|
+
Write-Host "`n== Plugin =="
|
|
5
|
+
openclaw plugins inspect claw-crony
|
|
6
|
+
openclaw plugins inspect claw-crony --runtime
|
|
7
|
+
|
|
8
|
+
Write-Host "`n== Peers =="
|
|
9
|
+
openclaw gateway call a2a.peers --params "{}"
|
|
10
|
+
|
|
11
|
+
Write-Host "`n== Metrics =="
|
|
12
|
+
openclaw gateway call a2a.metrics --params "{}"
|
|
13
|
+
|
|
14
|
+
Write-Host "`n== Recent History =="
|
|
15
|
+
openclaw gateway call a2a.history --params "{`"count`":20}"
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
echo "== OpenClaw Gateway =="
|
|
5
|
+
openclaw gateway status
|
|
6
|
+
|
|
7
|
+
echo
|
|
8
|
+
echo "== Plugin =="
|
|
9
|
+
openclaw plugins inspect claw-crony
|
|
10
|
+
openclaw plugins inspect claw-crony --runtime
|
|
11
|
+
|
|
12
|
+
echo
|
|
13
|
+
echo "== Peers =="
|
|
14
|
+
openclaw gateway call a2a.peers --params "{}"
|
|
15
|
+
|
|
16
|
+
echo
|
|
17
|
+
echo "== Metrics =="
|
|
18
|
+
openclaw gateway call a2a.metrics --params "{}"
|
|
19
|
+
|
|
20
|
+
echo
|
|
21
|
+
echo "== Recent History =="
|
|
22
|
+
openclaw gateway call a2a.history --params '{"count":20}'
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
param(
|
|
2
|
+
[int] $Count = 50,
|
|
3
|
+
[string] $Type = "",
|
|
4
|
+
[string] $Status = "",
|
|
5
|
+
[string] $Direction = "",
|
|
6
|
+
[int] $MatchId = 0,
|
|
7
|
+
[string] $Peer = ""
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
$payload = @{
|
|
11
|
+
count = $Count
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if ($Type) { $payload.type = $Type }
|
|
15
|
+
if ($Status) { $payload.status = $Status }
|
|
16
|
+
if ($Direction) { $payload.direction = $Direction }
|
|
17
|
+
if ($MatchId -gt 0) { $payload.matchId = $MatchId }
|
|
18
|
+
if ($Peer) { $payload.peer = $Peer }
|
|
19
|
+
|
|
20
|
+
$json = $payload | ConvertTo-Json -Depth 20 -Compress
|
|
21
|
+
openclaw gateway call a2a.history --params $json
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
count="${1:-50}"
|
|
5
|
+
type="${2:-}"
|
|
6
|
+
match_id="${3:-}"
|
|
7
|
+
|
|
8
|
+
params="$(node -e 'const payload={count:Number(process.argv[1] || 50)}; if (process.argv[2]) payload.type=process.argv[2]; if (process.argv[3]) payload.matchId=Number(process.argv[3]); process.stdout.write(JSON.stringify(payload));' "$count" "$type" "$match_id")"
|
|
9
|
+
openclaw gateway call a2a.history --params "$params"
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
param(
|
|
2
|
+
[Parameter(Mandatory = $true)]
|
|
3
|
+
[string[]] $Skills,
|
|
4
|
+
[string] $Description = ""
|
|
5
|
+
)
|
|
6
|
+
|
|
7
|
+
$payload = @{
|
|
8
|
+
skills = $Skills
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
if ($Description) {
|
|
12
|
+
$payload.description = $Description
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
$json = $payload | ConvertTo-Json -Depth 20 -Compress
|
|
16
|
+
openclaw gateway call a2a.match --params $json
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
skills="${1:-}"
|
|
5
|
+
description="${2:-}"
|
|
6
|
+
|
|
7
|
+
if [[ -z "$skills" ]]; then
|
|
8
|
+
echo "usage: $0 chat,code_review [description]" >&2
|
|
9
|
+
exit 2
|
|
10
|
+
fi
|
|
11
|
+
|
|
12
|
+
params="$(node -e 'const skills=process.argv[1].split(",").map((s)=>s.trim()).filter(Boolean); const description=process.argv[2] || ""; const payload={skills}; if (description) payload.description=description; process.stdout.write(JSON.stringify(payload));' "$skills" "$description")"
|
|
13
|
+
openclaw gateway call a2a.match --params "$params"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
openclaw gateway call a2a.peers --params "{}"
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
param(
|
|
2
|
+
[Parameter(Mandatory = $true)]
|
|
3
|
+
[string] $Peer,
|
|
4
|
+
[Parameter(Mandatory = $true)]
|
|
5
|
+
[string] $Text,
|
|
6
|
+
[string] $AgentId = ""
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
$message = @{
|
|
10
|
+
text = $Text
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if ($AgentId) {
|
|
14
|
+
$message.agentId = $AgentId
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
$payload = @{
|
|
18
|
+
peer = $Peer
|
|
19
|
+
message = $message
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
$json = $payload | ConvertTo-Json -Depth 20 -Compress
|
|
23
|
+
openclaw gateway call a2a.send --params $json
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
peer="${1:-}"
|
|
5
|
+
text="${2:-}"
|
|
6
|
+
agent_id="${3:-}"
|
|
7
|
+
|
|
8
|
+
if [[ -z "$peer" || -z "$text" ]]; then
|
|
9
|
+
echo "usage: $0 <peer> <text> [agentId]" >&2
|
|
10
|
+
exit 2
|
|
11
|
+
fi
|
|
12
|
+
|
|
13
|
+
params="$(node -e 'const peer=process.argv[1]; const text=process.argv[2]; const agentId=process.argv[3] || ""; const message={text}; if (agentId) message.agentId=agentId; process.stdout.write(JSON.stringify({peer,message}));' "$peer" "$text" "$agent_id")"
|
|
14
|
+
openclaw gateway call a2a.send --params "$params"
|