@perkos/perkos-a2a 0.12.35 → 0.12.37
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/README.md +6 -3
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +120 -29
- package/dist/index.js.map +3 -3
- package/dist/openclaw-supervisor-client.d.ts +7 -0
- package/dist/openclaw-supervisor-client.d.ts.map +1 -1
- package/dist/openclaw-supervisor-client.js +29 -6
- package/dist/openclaw-supervisor-client.js.map +1 -1
- package/dist/openclaw-supervisor.d.ts.map +1 -1
- package/dist/openclaw-supervisor.js +8 -1
- package/dist/openclaw-supervisor.js.map +1 -1
- package/dist/repair.d.ts +4 -1
- package/dist/repair.d.ts.map +1 -1
- package/dist/repair.js +90 -14
- package/dist/repair.js.map +1 -1
- package/dist/runtime-evidence.d.ts +26 -2
- package/dist/runtime-evidence.d.ts.map +1 -1
- package/dist/runtime-evidence.js +130 -6
- package/dist/runtime-evidence.js.map +1 -1
- package/dist/supervisor-protocol.d.ts +8 -1
- package/dist/supervisor-protocol.d.ts.map +1 -1
- package/dist/supervisor-protocol.js.map +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -241,14 +241,17 @@ generation. Before accepting a newer generation, the supervisor waits for
|
|
|
241
241
|
confirmed transport shutdown; a timeout fails closed with
|
|
242
242
|
`OWNER_STOP_TIMEOUT`. A private TTL rollover lock serializes concurrent upgrades,
|
|
243
243
|
and health certifies the supervisor package version and real install root. Lease
|
|
244
|
-
and health evidence are owner-only files and never
|
|
245
|
-
|
|
244
|
+
and health evidence are owner-only files and never contain relay or chat
|
|
245
|
+
credentials. From 0.12.37, supervisor health is HMAC-bound to the active repair
|
|
246
|
+
attempt and is authoritative after a real restart; runtime load status is
|
|
247
|
+
written only by the claimed owner service. Incidental validation/doctor plugin
|
|
248
|
+
loads are diagnostic and cannot invalidate signed owner health. This ownership boundary applies to OpenClaw;
|
|
246
249
|
Hermes/custom runtimes keep their existing runtime-owned model and transport
|
|
247
250
|
routing.
|
|
248
251
|
|
|
249
252
|
```bash
|
|
250
253
|
A2A_RELAY_API_KEY='<credential-from-invitation>' \
|
|
251
|
-
npx --yes @perkos/perkos-a2a@0.12.
|
|
254
|
+
npx --yes @perkos/perkos-a2a@0.12.37 connect \
|
|
252
255
|
--artifact ./perkos-a2a.tgz \
|
|
253
256
|
--sha256 '<sha256-from-the-official-invitation>' \
|
|
254
257
|
--agent-name '<agent-name>' \
|
package/dist/index.d.ts
CHANGED
|
@@ -53,5 +53,12 @@ export declare function runOpenClawChatTurn(api: any, config: A2APluginConfig, s
|
|
|
53
53
|
export declare function formatRecentChatContext(messages: ChatMessage[], currentMessageId: string): string;
|
|
54
54
|
/** The identity the relay treats as exclusive; names are display metadata. */
|
|
55
55
|
export declare function a2aLifecycleKey(config: A2APluginConfig): string;
|
|
56
|
+
/**
|
|
57
|
+
* OpenClaw may briefly call register while a plugin entry is being rewritten.
|
|
58
|
+
* Treat partial/empty config as an inert, valid shape instead of crashing the
|
|
59
|
+
* whole service on string operations. The repair CLI restores the complete
|
|
60
|
+
* identity atomically before the service is enabled.
|
|
61
|
+
*/
|
|
62
|
+
export declare function normalizeOpenClawPluginConfig(value: unknown): A2APluginConfig;
|
|
56
63
|
export default function register(api: any): void;
|
|
57
64
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAaH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,KAAK,EAGV,WAAW,EAEZ,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,cAAc,YAAY,CAAC;AA0C3B,kEAAkE;AAClE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAItF;AAED,KAAK,oBAAoB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AASpD;;;;;GAKG;AACH,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,OAAO,EACd,oBAAoB,EAAE,MAAM,GAC3B,OAAO,CA2BT;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,oBAAoB,EAC3B,eAAe,CAAC,EAAE,MAAM,GACvB,oBAAoB,CA+BtB;AAiED,KAAK,qBAAqB,GAAG;IAC3B,QAAQ,CAAC,EAAE,KAAK,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,WAAW,CAAC,EAAE,OAAO,CAAC;QACtB,YAAY,CAAC,EAAE,OAAO,CAAC;KACxB,CAAC,CAAC;IACH,IAAI,CAAC,EAAE;QACL,yBAAyB,CAAC,EAAE,MAAM,CAAC;QACnC,qBAAqB,CAAC,EAAE,MAAM,CAAC;KAChC,CAAC;CACH,CAAC;AAEF,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,qBAAqB,GAAG,MAAM,GAAG,IAAI,CAYrF;AAQD,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,GAAG,EACR,MAAM,EAAE,eAAe,EACvB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,gBAAgB,EAAE,MAAM,EACxB,MAAM,EAAE;IAAE,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;IAAC,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;CAAE,GAClF,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAuFxB;AAYD,oFAAoF;AACpF,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,WAAW,EAAE,EACvB,gBAAgB,EAAE,MAAM,GACvB,MAAM,CAWR;AA4CD,8EAA8E;AAC9E,wBAAgB,eAAe,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CAe/D;AAED,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,GAAG,EAAE,GAAG,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAaH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,KAAK,EAGV,WAAW,EAEZ,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,cAAc,YAAY,CAAC;AA0C3B,kEAAkE;AAClE,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAItF;AAED,KAAK,oBAAoB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AASpD;;;;;GAKG;AACH,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,OAAO,EACd,oBAAoB,EAAE,MAAM,GAC3B,OAAO,CA2BT;AAED;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,oBAAoB,EAC3B,eAAe,CAAC,EAAE,MAAM,GACvB,oBAAoB,CA+BtB;AAiED,KAAK,qBAAqB,GAAG;IAC3B,QAAQ,CAAC,EAAE,KAAK,CAAC;QACf,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,WAAW,CAAC,EAAE,OAAO,CAAC;QACtB,YAAY,CAAC,EAAE,OAAO,CAAC;KACxB,CAAC,CAAC;IACH,IAAI,CAAC,EAAE;QACL,yBAAyB,CAAC,EAAE,MAAM,CAAC;QACnC,qBAAqB,CAAC,EAAE,MAAM,CAAC;KAChC,CAAC;CACH,CAAC;AAEF,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,qBAAqB,GAAG,MAAM,GAAG,IAAI,CAYrF;AAQD,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,GAAG,EACR,MAAM,EAAE,eAAe,EACvB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,gBAAgB,EAAE,MAAM,EACxB,MAAM,EAAE;IAAE,IAAI,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;IAAC,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;CAAE,GAClF,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAuFxB;AAYD,oFAAoF;AACpF,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,WAAW,EAAE,EACvB,gBAAgB,EAAE,MAAM,GACvB,MAAM,CAWR;AA4CD,8EAA8E;AAC9E,wBAAgB,eAAe,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CAe/D;AAMD;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,OAAO,GAAG,eAAe,CAc7E;AAED,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,GAAG,EAAE,GAAG,QAszBxC"}
|
package/dist/index.js
CHANGED
|
@@ -24817,7 +24817,7 @@ var require_websocket = __commonJS({
|
|
|
24817
24817
|
var http = __require("http");
|
|
24818
24818
|
var net2 = __require("net");
|
|
24819
24819
|
var tls = __require("tls");
|
|
24820
|
-
var { randomBytes, createHash:
|
|
24820
|
+
var { randomBytes, createHash: createHash4 } = __require("crypto");
|
|
24821
24821
|
var { Duplex, Readable } = __require("stream");
|
|
24822
24822
|
var { URL: URL2 } = __require("url");
|
|
24823
24823
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
@@ -25477,7 +25477,7 @@ var require_websocket = __commonJS({
|
|
|
25477
25477
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
25478
25478
|
return;
|
|
25479
25479
|
}
|
|
25480
|
-
const digest =
|
|
25480
|
+
const digest = createHash4("sha1").update(key + GUID).digest("base64");
|
|
25481
25481
|
if (res.headers["sec-websocket-accept"] !== digest) {
|
|
25482
25482
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
25483
25483
|
return;
|
|
@@ -25844,7 +25844,7 @@ var require_websocket_server = __commonJS({
|
|
|
25844
25844
|
var EventEmitter = __require("events");
|
|
25845
25845
|
var http = __require("http");
|
|
25846
25846
|
var { Duplex } = __require("stream");
|
|
25847
|
-
var { createHash:
|
|
25847
|
+
var { createHash: createHash4 } = __require("crypto");
|
|
25848
25848
|
var extension2 = require_extension();
|
|
25849
25849
|
var PerMessageDeflate2 = require_permessage_deflate();
|
|
25850
25850
|
var subprotocol2 = require_subprotocol();
|
|
@@ -26145,7 +26145,7 @@ var require_websocket_server = __commonJS({
|
|
|
26145
26145
|
);
|
|
26146
26146
|
}
|
|
26147
26147
|
if (this._state > RUNNING) return abortHandshake(socket, 503);
|
|
26148
|
-
const digest =
|
|
26148
|
+
const digest = createHash4("sha1").update(key + GUID).digest("base64");
|
|
26149
26149
|
const headers = [
|
|
26150
26150
|
"HTTP/1.1 101 Switching Protocols",
|
|
26151
26151
|
"Upgrade: websocket",
|
|
@@ -28469,7 +28469,7 @@ var OpenClawSupervisorClient = class {
|
|
|
28469
28469
|
claim = await this.rolloverSupervisor("legacy-health-missing-target");
|
|
28470
28470
|
}
|
|
28471
28471
|
const health = claim?.health;
|
|
28472
|
-
if (claim?.state !== "READY" || health?.schemaVersion !== 2 || health.authority !== "process-external-supervisor" || health.state !== "running" || health.ownerKey !== this.ownerHash || health.instanceId !== this.lease.instanceId || health.generation !== this.lease.generation || !this.healthMatchesTarget(health) || health.relayClientCount !== (this.config.relay?.enabled && this.config.relay.url ? 1 : 0) || !health.claimedAt) {
|
|
28472
|
+
if (claim?.state !== "READY" || health?.schemaVersion !== 2 && health?.schemaVersion !== 3 || health.authority !== "process-external-supervisor" || health.state !== "running" || health.ownerKey !== this.ownerHash || health.instanceId !== this.lease.instanceId || health.generation !== this.lease.generation || !this.healthMatchesTarget(health) || health.relayClientCount !== (this.config.relay?.enabled && this.config.relay.url ? 1 : 0) || !health.claimedAt) {
|
|
28473
28473
|
throw new Error("OWNERSHIP_PRIMITIVE_UNAVAILABLE:supervisor claim did not return certified READY/CLAIMED health");
|
|
28474
28474
|
}
|
|
28475
28475
|
this.health = health;
|
|
@@ -28530,17 +28530,42 @@ var OpenClawSupervisorClient = class {
|
|
|
28530
28530
|
const oldHealth = this.health;
|
|
28531
28531
|
this.closeSocket(new Error("SUPERVISOR_ROLLOVER"));
|
|
28532
28532
|
await this.waitForSupervisorStop(oldHealth, 1e4);
|
|
28533
|
-
await this.
|
|
28534
|
-
const target = await this.claimCurrentSupervisor();
|
|
28535
|
-
if (!this.healthMatchesTarget(target.health)) {
|
|
28536
|
-
throw new Error(`SUPERVISOR_ROLLOVER_TARGET_MISMATCH:${reason}`);
|
|
28537
|
-
}
|
|
28533
|
+
const target = await this.claimTargetAfterRollover(reason);
|
|
28538
28534
|
this.logger.info(`[perkos-a2a] Supervisor rollover complete targetVersion=${this.config.version}`);
|
|
28539
28535
|
return target;
|
|
28540
28536
|
} finally {
|
|
28541
28537
|
releaseLock();
|
|
28542
28538
|
}
|
|
28543
28539
|
}
|
|
28540
|
+
/**
|
|
28541
|
+
* OpenClaw can register two adjacent hot-reload generations while its config
|
|
28542
|
+
* file is settling. The first generation may successfully bootstrap the
|
|
28543
|
+
* target supervisor just as its client socket is replaced. Reconnect to that
|
|
28544
|
+
* single fenced supervisor instead of abandoning the agent offline.
|
|
28545
|
+
*/
|
|
28546
|
+
async claimTargetAfterRollover(reason) {
|
|
28547
|
+
let lastError;
|
|
28548
|
+
for (let attempt = 1; attempt <= 3; attempt += 1) {
|
|
28549
|
+
try {
|
|
28550
|
+
await this.connectOrSpawn();
|
|
28551
|
+
const target = await this.claimCurrentSupervisor();
|
|
28552
|
+
if (!this.healthMatchesTarget(target.health)) {
|
|
28553
|
+
throw new Error(`SUPERVISOR_ROLLOVER_TARGET_MISMATCH:${reason}`);
|
|
28554
|
+
}
|
|
28555
|
+
return target;
|
|
28556
|
+
} catch (error) {
|
|
28557
|
+
lastError = error;
|
|
28558
|
+
this.closeSocket(new Error("SUPERVISOR_ROLLOVER_TARGET_RETRY"));
|
|
28559
|
+
this.logger.error(
|
|
28560
|
+
`[perkos-a2a] Supervisor target claim retry ${attempt}/3: ${error instanceof Error ? error.message : String(error)}`
|
|
28561
|
+
);
|
|
28562
|
+
if (attempt < 3) await new Promise((resolveWait) => setTimeout(resolveWait, 250));
|
|
28563
|
+
}
|
|
28564
|
+
}
|
|
28565
|
+
throw new Error(
|
|
28566
|
+
`SUPERVISOR_ROLLOVER_TARGET_START_FAILED:${lastError instanceof Error ? lastError.message : String(lastError)}`
|
|
28567
|
+
);
|
|
28568
|
+
}
|
|
28544
28569
|
async acquireRolloverLock(timeoutMs = 15e3) {
|
|
28545
28570
|
const path = supervisorRolloverLockPath(this.stateDir, this.ownerHash);
|
|
28546
28571
|
mkdirSync2(dirname2(path), { recursive: true, mode: 448 });
|
|
@@ -28830,7 +28855,7 @@ var OpenClawSupervisorClient = class {
|
|
|
28830
28855
|
};
|
|
28831
28856
|
|
|
28832
28857
|
// src/runtime-evidence.ts
|
|
28833
|
-
import { createHmac } from "node:crypto";
|
|
28858
|
+
import { createHash as createHash3, createHmac, timingSafeEqual } from "node:crypto";
|
|
28834
28859
|
import {
|
|
28835
28860
|
chmodSync as chmodSync2,
|
|
28836
28861
|
mkdirSync as mkdirSync3,
|
|
@@ -28840,7 +28865,8 @@ import {
|
|
|
28840
28865
|
} from "node:fs";
|
|
28841
28866
|
import { homedir as homedir4 } from "node:os";
|
|
28842
28867
|
import { join as join3, resolve as resolve2 } from "node:path";
|
|
28843
|
-
var
|
|
28868
|
+
var RUNTIME_ATTEMPT_SCHEMA_VERSION = 2;
|
|
28869
|
+
var RUNTIME_STATUS_SCHEMA_VERSION = 3;
|
|
28844
28870
|
function canonicalize(value) {
|
|
28845
28871
|
if (Array.isArray(value)) return value.map(canonicalize);
|
|
28846
28872
|
if (!value || typeof value !== "object") return value;
|
|
@@ -28848,8 +28874,52 @@ function canonicalize(value) {
|
|
|
28848
28874
|
Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, child]) => [key, canonicalize(child)])
|
|
28849
28875
|
);
|
|
28850
28876
|
}
|
|
28877
|
+
function objectValue(value) {
|
|
28878
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
28879
|
+
}
|
|
28880
|
+
function normalizedServiceUrl(value) {
|
|
28881
|
+
if (typeof value !== "string" || !value.trim()) return void 0;
|
|
28882
|
+
try {
|
|
28883
|
+
const url = new URL(value);
|
|
28884
|
+
url.username = "";
|
|
28885
|
+
url.password = "";
|
|
28886
|
+
url.search = "";
|
|
28887
|
+
url.hash = "";
|
|
28888
|
+
return url.toString().replace(/\/+$/u, "");
|
|
28889
|
+
} catch {
|
|
28890
|
+
return value.trim().replace(/\/+$/u, "");
|
|
28891
|
+
}
|
|
28892
|
+
}
|
|
28893
|
+
function configEvidenceProjection(config) {
|
|
28894
|
+
const root = objectValue(config);
|
|
28895
|
+
const relay = objectValue(root.relay);
|
|
28896
|
+
const chat = objectValue(root.chat);
|
|
28897
|
+
const platform = objectValue(root.platform);
|
|
28898
|
+
const heartbeatUrl = typeof platform.heartbeatUrl === "string" ? platform.heartbeatUrl : "";
|
|
28899
|
+
const heartbeatAgentId = heartbeatUrl.match(/\/agents\/([^/]+)\/heartbeat(?:\?|$)/u)?.[1];
|
|
28900
|
+
const agentId = typeof root.agentId === "string" ? root.agentId : typeof platform.agentId === "string" ? platform.agentId : heartbeatAgentId;
|
|
28901
|
+
return {
|
|
28902
|
+
agentName: typeof root.agentName === "string" ? root.agentName.trim() : "",
|
|
28903
|
+
agentId: agentId ?? "unknown",
|
|
28904
|
+
relay: {
|
|
28905
|
+
enabled: relay.enabled === true,
|
|
28906
|
+
url: normalizedServiceUrl(relay.url) ?? ""
|
|
28907
|
+
},
|
|
28908
|
+
chat: {
|
|
28909
|
+
enabled: chat.enabled === true,
|
|
28910
|
+
url: normalizedServiceUrl(chat.url) ?? (chat.enabled === true ? "wss://chat.perkos.xyz/chat" : "")
|
|
28911
|
+
},
|
|
28912
|
+
platform: {
|
|
28913
|
+
heartbeatAgentId: heartbeatAgentId ?? agentId ?? "unknown",
|
|
28914
|
+
heartbeatIntervalMs: typeof platform.heartbeatIntervalMs === "number" ? platform.heartbeatIntervalMs : null
|
|
28915
|
+
}
|
|
28916
|
+
};
|
|
28917
|
+
}
|
|
28851
28918
|
function canonicalConfigJson(config) {
|
|
28852
|
-
return JSON.stringify({ schemaVersion:
|
|
28919
|
+
return JSON.stringify({ schemaVersion: RUNTIME_STATUS_SCHEMA_VERSION, config: canonicalize(configEvidenceProjection(config)) });
|
|
28920
|
+
}
|
|
28921
|
+
function configDigest(config) {
|
|
28922
|
+
return createHash3("sha256").update(canonicalConfigJson(config)).digest("hex");
|
|
28853
28923
|
}
|
|
28854
28924
|
function configFingerprint(config, hmacKeyHex) {
|
|
28855
28925
|
if (!/^[a-f0-9]{64}$/u.test(hmacKeyHex)) throw new Error("runtime evidence HMAC key is invalid");
|
|
@@ -28879,17 +28949,22 @@ function recordRuntimeLoadEvidence(input) {
|
|
|
28879
28949
|
return null;
|
|
28880
28950
|
}
|
|
28881
28951
|
const agentId = configAgentId(input.config);
|
|
28882
|
-
if (attempt.schemaVersion !==
|
|
28952
|
+
if (attempt.schemaVersion !== RUNTIME_ATTEMPT_SCHEMA_VERSION || attempt.targetVersion !== input.version || attempt.expectedAgentId !== agentId) {
|
|
28883
28953
|
input.logger.warn?.("[perkos-a2a] runtime evidence attempt does not match the loaded plugin identity");
|
|
28884
28954
|
return null;
|
|
28885
28955
|
}
|
|
28956
|
+
const digest = configDigest(input.config);
|
|
28886
28957
|
const status = {
|
|
28887
|
-
schemaVersion:
|
|
28958
|
+
schemaVersion: RUNTIME_STATUS_SCHEMA_VERSION,
|
|
28888
28959
|
loadedAt: (input.now?.() ?? /* @__PURE__ */ new Date()).toISOString(),
|
|
28889
28960
|
version: input.version,
|
|
28890
28961
|
agentId,
|
|
28891
28962
|
fingerprint: configFingerprint(input.config, attempt.hmacKeyHex),
|
|
28963
|
+
configDigest: digest,
|
|
28964
|
+
configRevision: `${input.generation}:${digest}`,
|
|
28892
28965
|
attemptId: attempt.attemptId,
|
|
28966
|
+
writerKind: "owner-plugin",
|
|
28967
|
+
generation: input.generation,
|
|
28893
28968
|
pid: process.pid,
|
|
28894
28969
|
processStartTime: processStartIdentity(),
|
|
28895
28970
|
bootId: currentBootId(),
|
|
@@ -29607,25 +29682,32 @@ function a2aLifecycleKey(config) {
|
|
|
29607
29682
|
}
|
|
29608
29683
|
const heartbeatUrl = config.platform?.heartbeatUrl || "";
|
|
29609
29684
|
const idFromHeartbeat = heartbeatUrl.match(/\/agents\/([^/]+)\/heartbeat(?:\?|$)/u)?.[1];
|
|
29610
|
-
const agentId = config.platform?.agentId || idFromHeartbeat || config.agentName
|
|
29685
|
+
const agentId = config.platform?.agentId || idFromHeartbeat || safeAgentName(config.agentName).toLowerCase();
|
|
29611
29686
|
return `${relayUrl}|${agentId}`;
|
|
29612
29687
|
}
|
|
29613
|
-
function
|
|
29614
|
-
|
|
29615
|
-
|
|
29616
|
-
|
|
29617
|
-
|
|
29618
|
-
|
|
29688
|
+
function safeAgentName(value) {
|
|
29689
|
+
return typeof value === "string" && value.trim() ? value.trim() : "agent";
|
|
29690
|
+
}
|
|
29691
|
+
function normalizeOpenClawPluginConfig(value) {
|
|
29692
|
+
const raw = value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
29693
|
+
const platform = raw.platform && typeof raw.platform === "object" ? raw.platform : void 0;
|
|
29694
|
+
const heartbeatAgentId = platform?.heartbeatUrl?.match(/\/agents\/([^/]+)\/heartbeat/u)?.[1];
|
|
29695
|
+
const agentName = safeAgentName(raw.agentName || platform?.agentId || heartbeatAgentId);
|
|
29696
|
+
return {
|
|
29697
|
+
...raw,
|
|
29698
|
+
agentName,
|
|
29699
|
+
port: typeof raw.port === "number" ? raw.port : 5050,
|
|
29700
|
+
skills: Array.isArray(raw.skills) ? raw.skills : [],
|
|
29701
|
+
peers: raw.peers && typeof raw.peers === "object" ? raw.peers : {}
|
|
29619
29702
|
};
|
|
29703
|
+
}
|
|
29704
|
+
function register(api) {
|
|
29705
|
+
const pluginConfig = normalizeOpenClawPluginConfig(
|
|
29706
|
+
api.config?.plugins?.entries?.["perkos-a2a"]?.config
|
|
29707
|
+
);
|
|
29620
29708
|
const logger = api.logger || console;
|
|
29621
29709
|
const pluginVersion = loadedPluginVersion();
|
|
29622
29710
|
const pluginRoot = resolve3(dirname3(fileURLToPath2(import.meta.url)), "..");
|
|
29623
|
-
recordRuntimeLoadEvidence({
|
|
29624
|
-
config: pluginConfig,
|
|
29625
|
-
version: pluginVersion,
|
|
29626
|
-
pluginRoot,
|
|
29627
|
-
logger
|
|
29628
|
-
});
|
|
29629
29711
|
const server = new A2AServer(pluginConfig, logger, { relayOwnership: "external-required" });
|
|
29630
29712
|
const lifecycleKey = a2aLifecycleKey(pluginConfig);
|
|
29631
29713
|
const lifecycleInstanceId = randomUUID7();
|
|
@@ -29880,7 +29962,7 @@ function register(api) {
|
|
|
29880
29962
|
if (pluginConfig.chat?.enabled && !chatApiKey) {
|
|
29881
29963
|
logger.error("[perkos-chat] chat.enabled=true but no apiKey (set chat.apiKey or fall back from relay.apiKey)");
|
|
29882
29964
|
}
|
|
29883
|
-
const platformAgentId = pluginConfig.platform?.agentId || pluginConfig.platform?.heartbeatUrl?.match(/\/agents\/([^/]+)\/heartbeat/u)?.[1] || pluginConfig.agentName
|
|
29965
|
+
const platformAgentId = pluginConfig.platform?.agentId || pluginConfig.platform?.heartbeatUrl?.match(/\/agents\/([^/]+)\/heartbeat/u)?.[1] || safeAgentName(pluginConfig.agentName).toLowerCase();
|
|
29884
29966
|
supervisorClient = new OpenClawSupervisorClient({
|
|
29885
29967
|
ownerHash: supervisorOwnerHash(lifecycleKey),
|
|
29886
29968
|
generation: Date.now(),
|
|
@@ -29922,6 +30004,14 @@ function register(api) {
|
|
|
29922
30004
|
start: async () => {
|
|
29923
30005
|
try {
|
|
29924
30006
|
await supervisorClient.start();
|
|
30007
|
+
const ownerHealth = supervisorClient.currentHealth();
|
|
30008
|
+
recordRuntimeLoadEvidence({
|
|
30009
|
+
config: pluginConfig,
|
|
30010
|
+
version: pluginVersion,
|
|
30011
|
+
pluginRoot,
|
|
30012
|
+
generation: ownerHealth?.generation ?? 0,
|
|
30013
|
+
logger
|
|
30014
|
+
});
|
|
29925
30015
|
await server.start();
|
|
29926
30016
|
logger.info(`[perkos-a2a] A2A server started for ${pluginConfig.agentName}`);
|
|
29927
30017
|
} catch (error) {
|
|
@@ -30325,6 +30415,7 @@ export {
|
|
|
30325
30415
|
extractOpenClawChatReply,
|
|
30326
30416
|
formatRecentChatContext,
|
|
30327
30417
|
isWebhookEvent,
|
|
30418
|
+
normalizeOpenClawPluginConfig,
|
|
30328
30419
|
omitUnavailableAgentHarness,
|
|
30329
30420
|
openclawChatSessionKey,
|
|
30330
30421
|
runOpenClawChatTurn
|