@perkos/perkos-a2a 0.12.19 → 0.12.27
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 +60 -0
- package/dist/agent.js +3 -2
- package/dist/agent.js.map +1 -1
- package/dist/bridge-agent.js +25 -56
- package/dist/bridge-agent.js.map +1 -1
- package/dist/bridge-chat-reply.d.ts +14 -1
- package/dist/bridge-chat-reply.d.ts.map +1 -1
- package/dist/bridge-chat-reply.js +71 -5
- package/dist/bridge-chat-reply.js.map +1 -1
- package/dist/gateway-health.d.ts +5 -11
- package/dist/gateway-health.d.ts.map +1 -1
- package/dist/gateway-health.js +53 -15
- package/dist/gateway-health.js.map +1 -1
- package/dist/hermes-plugin.d.ts +2 -0
- package/dist/hermes-plugin.d.ts.map +1 -1
- package/dist/hermes-plugin.js +4 -2
- package/dist/hermes-plugin.js.map +1 -1
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +407 -19
- package/dist/index.js.map +3 -3
- package/dist/platform-heartbeat.d.ts +26 -0
- package/dist/platform-heartbeat.d.ts.map +1 -0
- package/dist/platform-heartbeat.js +72 -0
- package/dist/platform-heartbeat.js.map +1 -0
- package/dist/project-chat-context.d.ts +3 -0
- package/dist/project-chat-context.d.ts.map +1 -0
- package/dist/project-chat-context.js +16 -0
- package/dist/project-chat-context.js.map +1 -0
- package/dist/relay-client.d.ts +21 -2
- package/dist/relay-client.d.ts.map +1 -1
- package/dist/relay-client.js +82 -17
- package/dist/relay-client.js.map +1 -1
- package/dist/repair-cli.d.ts +3 -0
- package/dist/repair-cli.d.ts.map +1 -0
- package/dist/repair-cli.js +31 -0
- package/dist/repair-cli.js.map +1 -0
- package/dist/repair.d.ts +53 -0
- package/dist/repair.d.ts.map +1 -0
- package/dist/repair.js +357 -0
- package/dist/repair.js.map +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +5 -2
- package/dist/server.js.map +1 -1
- package/dist/task-context.d.ts +18 -0
- package/dist/task-context.d.ts.map +1 -0
- package/dist/task-context.js +35 -0
- package/dist/task-context.js.map +1 -0
- package/dist/types.d.ts +20 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/openclaw.plugin.json +28 -1
- package/package.json +9 -5
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export type PlatformHeartbeatLogger = {
|
|
2
|
+
info(message: string): void;
|
|
3
|
+
warn(message: string): void;
|
|
4
|
+
};
|
|
5
|
+
export type PlatformHeartbeatHandle = {
|
|
6
|
+
stop(): void;
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Keep the PerkOS agent presence record fresh while the bridge is alive.
|
|
10
|
+
*
|
|
11
|
+
* The relay has its own websocket heartbeat, but the app derives its
|
|
12
|
+
* Available/Offline label from the API heartbeat timestamp. A one-shot boot
|
|
13
|
+
* ping therefore makes a healthy, long-running agent look offline after the
|
|
14
|
+
* presence TTL expires.
|
|
15
|
+
*/
|
|
16
|
+
export declare function startPlatformHeartbeat(opts: {
|
|
17
|
+
env?: Record<string, string | undefined>;
|
|
18
|
+
fetcher?: typeof fetch;
|
|
19
|
+
logger: PlatformHeartbeatLogger;
|
|
20
|
+
intervalMs?: number;
|
|
21
|
+
url?: string;
|
|
22
|
+
relayKey?: string;
|
|
23
|
+
runtimeKind?: "openclaw" | "hermes" | "custom";
|
|
24
|
+
version?: string;
|
|
25
|
+
}): PlatformHeartbeatHandle;
|
|
26
|
+
//# sourceMappingURL=platform-heartbeat.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform-heartbeat.d.ts","sourceRoot":"","sources":["../src/platform-heartbeat.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,uBAAuB,GAAG;IACpC,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,IAAI,IAAI,IAAI,CAAC;CACd,CAAC;AAKF;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE;IAC3C,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzC,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;IACvB,MAAM,EAAE,uBAAuB,CAAC;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,UAAU,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAC/C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GAAG,uBAAuB,CAuE1B"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
const DEFAULT_INTERVAL_MS = 60_000;
|
|
2
|
+
const MIN_INTERVAL_MS = 10_000;
|
|
3
|
+
/**
|
|
4
|
+
* Keep the PerkOS agent presence record fresh while the bridge is alive.
|
|
5
|
+
*
|
|
6
|
+
* The relay has its own websocket heartbeat, but the app derives its
|
|
7
|
+
* Available/Offline label from the API heartbeat timestamp. A one-shot boot
|
|
8
|
+
* ping therefore makes a healthy, long-running agent look offline after the
|
|
9
|
+
* presence TTL expires.
|
|
10
|
+
*/
|
|
11
|
+
export function startPlatformHeartbeat(opts) {
|
|
12
|
+
const env = opts.env ?? process.env;
|
|
13
|
+
const fetcher = opts.fetcher ?? fetch;
|
|
14
|
+
const url = opts.url?.trim() || env.PERKOS_HEARTBEAT_URL?.trim();
|
|
15
|
+
const relayKey = opts.relayKey?.trim() || env.A2A_RELAY_API_KEY?.trim();
|
|
16
|
+
if (!url || !relayKey)
|
|
17
|
+
return { stop: () => undefined };
|
|
18
|
+
const configuredInterval = Number(opts.intervalMs ?? env.PERKOS_HEARTBEAT_INTERVAL_MS ?? DEFAULT_INTERVAL_MS);
|
|
19
|
+
const intervalMs = Number.isFinite(configuredInterval)
|
|
20
|
+
? Math.max(MIN_INTERVAL_MS, configuredInterval)
|
|
21
|
+
: DEFAULT_INTERVAL_MS;
|
|
22
|
+
const a2aRuntime = env.A2A_RUNTIME?.trim() || "hermes-api";
|
|
23
|
+
const runtimeKind = opts.runtimeKind ?? (a2aRuntime === "openclaw"
|
|
24
|
+
? "openclaw"
|
|
25
|
+
: a2aRuntime === "custom"
|
|
26
|
+
? "custom"
|
|
27
|
+
: "hermes");
|
|
28
|
+
let stopped = false;
|
|
29
|
+
let firstSuccess = true;
|
|
30
|
+
const report = async () => {
|
|
31
|
+
if (stopped)
|
|
32
|
+
return;
|
|
33
|
+
try {
|
|
34
|
+
const res = await fetcher(url, {
|
|
35
|
+
method: "POST",
|
|
36
|
+
headers: {
|
|
37
|
+
"content-type": "application/json",
|
|
38
|
+
authorization: `Bearer ${relayKey}`,
|
|
39
|
+
"x-relay-key": relayKey,
|
|
40
|
+
},
|
|
41
|
+
body: JSON.stringify({
|
|
42
|
+
runtimeKind,
|
|
43
|
+
version: opts.version?.trim() || env.PERKOS_A2A_VERSION?.trim() || "0.12.26",
|
|
44
|
+
ts: Date.now(),
|
|
45
|
+
}),
|
|
46
|
+
});
|
|
47
|
+
if (res.ok) {
|
|
48
|
+
if (firstSuccess) {
|
|
49
|
+
opts.logger.info(`[perkos-heartbeat] reported online to ${url} (status=${res.status}, every=${intervalMs}ms)`);
|
|
50
|
+
firstSuccess = false;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
opts.logger.warn(`[perkos-heartbeat] ${res.status} from ${url} (continuing)`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
59
|
+
opts.logger.warn(`[perkos-heartbeat] POST failed to ${url}: ${msg} (continuing)`);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
void report();
|
|
63
|
+
const timer = setInterval(() => void report(), intervalMs);
|
|
64
|
+
timer.unref?.();
|
|
65
|
+
return {
|
|
66
|
+
stop: () => {
|
|
67
|
+
stopped = true;
|
|
68
|
+
clearInterval(timer);
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=platform-heartbeat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"platform-heartbeat.js","sourceRoot":"","sources":["../src/platform-heartbeat.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-chat-context.d.ts","sourceRoot":"","sources":["../src/project-chat-context.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,wBAAgB,kBAAkB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAY/D"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** Ground project-chat planning turns in the canonical board identity. */
|
|
2
|
+
export function projectChatContext(projectId) {
|
|
3
|
+
const canonical = projectId?.trim();
|
|
4
|
+
if (!canonical)
|
|
5
|
+
return [];
|
|
6
|
+
return [
|
|
7
|
+
`Canonical projectId: ${canonical}`,
|
|
8
|
+
"You are the project coordinator, not a worker. Discuss scope, constraints, sources, and definition of done with the human before drafting.",
|
|
9
|
+
"If the human asks you to clarify first, or material details are ambiguous, ask one concise clarifying question and do not call planning tools in that reply.",
|
|
10
|
+
"Do not perform or paste the final research/deliverable in project chat. Summarize decisions and coordinate the work.",
|
|
11
|
+
"Use perkos-board planning tools only after the human explicitly requests a written plan, or when a dedicated PerkOS orchestration instruction tells you to draft/update and propose the canonical plan.",
|
|
12
|
+
`For every board tool call, pass projectId exactly "${canonical}"; never add a project- prefix, suffix, or transform it.`,
|
|
13
|
+
"Never materialize live tasks or approve the plan yourself; the user approves the proposed revision in PerkOS.",
|
|
14
|
+
];
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=project-chat-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-chat-context.js","sourceRoot":"","sources":["../src/project-chat-context.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,MAAM,UAAU,kBAAkB,CAAC,SAAkB;IACnD,MAAM,SAAS,GAAG,SAAS,EAAE,IAAI,EAAE,CAAC;IACpC,IAAI,CAAC,SAAS;QAAE,OAAO,EAAE,CAAC;IAC1B,OAAO;QACL,wBAAwB,SAAS,EAAE;QACnC,4IAA4I;QAC5I,8JAA8J;QAC9J,sHAAsH;QACtH,yMAAyM;QACzM,sDAAsD,SAAS,0DAA0D;QACzH,+GAA+G;KAChH,CAAC;AACJ,CAAC"}
|
package/dist/relay-client.d.ts
CHANGED
|
@@ -14,6 +14,13 @@ export interface RelayClientOptions {
|
|
|
14
14
|
onTask: (msg: RelayMessage) => void;
|
|
15
15
|
/** Called when a discover response arrives */
|
|
16
16
|
onDiscoverResponse?: (agents: RelayAgentEntry[]) => void;
|
|
17
|
+
/**
|
|
18
|
+
* Called for a `task_response` that no in-flight `sendTask` is waiting for —
|
|
19
|
+
* the request timed out, or the bridge reconnected and lost the callback.
|
|
20
|
+
* The response is also buffered so a retry with the same id can claim it, but
|
|
21
|
+
* this hook lets a caller act on work that finished after it gave up.
|
|
22
|
+
*/
|
|
23
|
+
onOrphanTaskResponse?: (msg: RelayMessage) => void;
|
|
17
24
|
logger?: {
|
|
18
25
|
info: (...args: unknown[]) => void;
|
|
19
26
|
error: (...args: unknown[]) => void;
|
|
@@ -29,12 +36,21 @@ export declare class RelayClient {
|
|
|
29
36
|
private connected;
|
|
30
37
|
private stopped;
|
|
31
38
|
private pendingCallbacks;
|
|
39
|
+
/** Responses that arrived with nobody waiting, claimable by a retry. */
|
|
40
|
+
private orphanResponses;
|
|
32
41
|
constructor(options: RelayClientOptions);
|
|
33
42
|
isConnected(): boolean;
|
|
34
43
|
start(): void;
|
|
35
44
|
stop(): void;
|
|
36
|
-
/**
|
|
37
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Send a task to another agent via the relay.
|
|
47
|
+
*
|
|
48
|
+
* Pass `taskId` to retry a task that already went out: the relay dedups on
|
|
49
|
+
* the id and will not run the work twice, and if the first attempt's response
|
|
50
|
+
* arrived after we gave up it is claimed from the orphan buffer instead of
|
|
51
|
+
* waiting again. Omit it for genuinely new work.
|
|
52
|
+
*/
|
|
53
|
+
sendTask(targetAgent: string, payload: Record<string, unknown>, taskId?: string): Promise<RelayMessage>;
|
|
38
54
|
/** Discover agents connected to the relay */
|
|
39
55
|
discover(): Promise<RelayAgentEntry[]>;
|
|
40
56
|
/** Send a task response back through the relay */
|
|
@@ -43,6 +59,9 @@ export declare class RelayClient {
|
|
|
43
59
|
private register;
|
|
44
60
|
private handleMessage;
|
|
45
61
|
private send;
|
|
62
|
+
/** Take a buffered response for `id`, if one arrived while nobody waited. */
|
|
63
|
+
private claimOrphan;
|
|
64
|
+
private bufferOrphan;
|
|
46
65
|
private sendAndWait;
|
|
47
66
|
private startHeartbeat;
|
|
48
67
|
private scheduleReconnect;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relay-client.d.ts","sourceRoot":"","sources":["../src/relay-client.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAExF,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,WAAW,CAAC;IACnB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,uDAAuD;IACvD,MAAM,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,IAAI,CAAC;IACpC,8CAA8C;IAC9C,kBAAkB,CAAC,EAAE,CAAC,MAAM,EAAE,eAAe,EAAE,KAAK,IAAI,CAAC;IACzD,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,CAAC;CACtF;
|
|
1
|
+
{"version":3,"file":"relay-client.d.ts","sourceRoot":"","sources":["../src/relay-client.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAExF,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,WAAW,CAAC;IACnB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,uDAAuD;IACvD,MAAM,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,IAAI,CAAC;IACpC,8CAA8C;IAC9C,kBAAkB,CAAC,EAAE,CAAC,MAAM,EAAE,eAAe,EAAE,KAAK,IAAI,CAAC;IACzD;;;;;OAKG;IACH,oBAAoB,CAAC,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,IAAI,CAAC;IACnD,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,CAAC;CACtF;AAoBD,qBAAa,WAAW;IACtB,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,MAAM,CAA8E;IAC5F,OAAO,CAAC,WAAW,CAAoB;IACvC,OAAO,CAAC,cAAc,CAA8C;IACpE,OAAO,CAAC,cAAc,CAA+C;IACrE,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,gBAAgB,CAA0C;IAClE,wEAAwE;IACxE,OAAO,CAAC,eAAe,CAAoE;gBAE/E,OAAO,EAAE,kBAAkB;IAKvC,WAAW,IAAI,OAAO;IAItB,KAAK,IAAI,IAAI;IAKb,IAAI,IAAI,IAAI;IAUZ;;;;;;;OAOG;IACG,QAAQ,CACZ,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,YAAY,CAAC;IAiBxB,6CAA6C;IACvC,QAAQ,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;IAW5C,kDAAkD;IAClD,gBAAgB,CAAC,WAAW,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAYlF,OAAO,CAAC,OAAO;IAgDf,OAAO,CAAC,QAAQ;IAehB,OAAO,CAAC,aAAa;IAkDrB,OAAO,CAAC,IAAI;IAMZ,6EAA6E;IAC7E,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,YAAY;YAWN,WAAW;IA8BzB,OAAO,CAAC,cAAc;IAatB,OAAO,CAAC,iBAAiB;IAQzB,OAAO,CAAC,WAAW;CAUpB"}
|
package/dist/relay-client.js
CHANGED
|
@@ -10,6 +10,14 @@ import { randomUUID } from "crypto";
|
|
|
10
10
|
const MIN_RECONNECT_MS = 1_000;
|
|
11
11
|
const MAX_RECONNECT_MS = 60_000;
|
|
12
12
|
const HEARTBEAT_INTERVAL_MS = 25_000;
|
|
13
|
+
/**
|
|
14
|
+
* How long a response nobody was waiting for stays claimable, and how many are
|
|
15
|
+
* kept. Both bounded: an orphan that expires is a response we log and drop —
|
|
16
|
+
* the same outcome as before, just after a window in which a retry can still
|
|
17
|
+
* recover it, instead of immediately.
|
|
18
|
+
*/
|
|
19
|
+
const ORPHAN_TTL_MS = 10 * 60_000;
|
|
20
|
+
const ORPHAN_MAX = 256;
|
|
13
21
|
export class RelayClient {
|
|
14
22
|
ws = null;
|
|
15
23
|
options;
|
|
@@ -20,6 +28,8 @@ export class RelayClient {
|
|
|
20
28
|
connected = false;
|
|
21
29
|
stopped = false;
|
|
22
30
|
pendingCallbacks = new Map();
|
|
31
|
+
/** Responses that arrived with nobody waiting, claimable by a retry. */
|
|
32
|
+
orphanResponses = new Map();
|
|
23
33
|
constructor(options) {
|
|
24
34
|
this.options = options;
|
|
25
35
|
this.logger = options.logger || { info: console.log, error: console.error };
|
|
@@ -40,12 +50,25 @@ export class RelayClient {
|
|
|
40
50
|
}
|
|
41
51
|
this.connected = false;
|
|
42
52
|
}
|
|
43
|
-
/**
|
|
44
|
-
|
|
53
|
+
/**
|
|
54
|
+
* Send a task to another agent via the relay.
|
|
55
|
+
*
|
|
56
|
+
* Pass `taskId` to retry a task that already went out: the relay dedups on
|
|
57
|
+
* the id and will not run the work twice, and if the first attempt's response
|
|
58
|
+
* arrived after we gave up it is claimed from the orphan buffer instead of
|
|
59
|
+
* waiting again. Omit it for genuinely new work.
|
|
60
|
+
*/
|
|
61
|
+
async sendTask(targetAgent, payload, taskId) {
|
|
62
|
+
const id = taskId ?? randomUUID();
|
|
63
|
+
const alreadyAnswered = this.claimOrphan(id);
|
|
64
|
+
if (alreadyAnswered) {
|
|
65
|
+
this.logger.info(`[perkos-a2a] Reusing buffered response for task ${id}`);
|
|
66
|
+
return alreadyAnswered;
|
|
67
|
+
}
|
|
45
68
|
return this.sendAndWait({
|
|
46
69
|
type: "task",
|
|
47
70
|
to: targetAgent,
|
|
48
|
-
id
|
|
71
|
+
id,
|
|
49
72
|
from: this.options.agentName,
|
|
50
73
|
payload,
|
|
51
74
|
timestamp: new Date().toISOString(),
|
|
@@ -133,11 +156,14 @@ export class RelayClient {
|
|
|
133
156
|
this.send(msg);
|
|
134
157
|
}
|
|
135
158
|
handleMessage(msg) {
|
|
136
|
-
//
|
|
137
|
-
|
|
138
|
-
|
|
159
|
+
// Resolve an in-flight request only when the type is the one it asked for.
|
|
160
|
+
// Matching on id alone made any same-id frame settle the promise — and the
|
|
161
|
+
// relay now sends `task_ack` on a deduplicated task, which would otherwise
|
|
162
|
+
// resolve `sendTask` with an ack instead of the real `task_response`.
|
|
163
|
+
const pending = this.pendingCallbacks.get(msg.id);
|
|
164
|
+
if (pending && (msg.type === pending.expectedType || msg.type === "error")) {
|
|
139
165
|
this.pendingCallbacks.delete(msg.id);
|
|
140
|
-
|
|
166
|
+
pending.settle(msg);
|
|
141
167
|
return;
|
|
142
168
|
}
|
|
143
169
|
switch (msg.type) {
|
|
@@ -147,9 +173,21 @@ export class RelayClient {
|
|
|
147
173
|
case "task":
|
|
148
174
|
this.options.onTask(msg);
|
|
149
175
|
break;
|
|
176
|
+
case "task_ack":
|
|
177
|
+
// The relay recognised this id as already routed. The work is running
|
|
178
|
+
// (or ran) on the target; keep waiting for the real task_response.
|
|
179
|
+
if (msg.payload?.deduplicated) {
|
|
180
|
+
this.logger.info(`[perkos-a2a] Relay deduplicated task ${msg.id}; awaiting the original response`);
|
|
181
|
+
}
|
|
182
|
+
break;
|
|
150
183
|
case "task_response":
|
|
151
|
-
//
|
|
152
|
-
|
|
184
|
+
// A response nobody is waiting for used to be dropped here, which is
|
|
185
|
+
// how completed work went missing whenever a request timed out or the
|
|
186
|
+
// bridge reconnected mid-flight. Buffer it so a retry with the same id
|
|
187
|
+
// can claim it, and surface it to the caller.
|
|
188
|
+
this.bufferOrphan(msg);
|
|
189
|
+
this.logger.info(`[perkos-a2a] Buffered unmatched task response: ${msg.id}`);
|
|
190
|
+
this.options.onOrphanTaskResponse?.(msg);
|
|
153
191
|
break;
|
|
154
192
|
case "discover_response":
|
|
155
193
|
if (this.options.onDiscoverResponse) {
|
|
@@ -170,20 +208,47 @@ export class RelayClient {
|
|
|
170
208
|
this.ws.send(JSON.stringify(msg));
|
|
171
209
|
}
|
|
172
210
|
}
|
|
211
|
+
/** Take a buffered response for `id`, if one arrived while nobody waited. */
|
|
212
|
+
claimOrphan(id) {
|
|
213
|
+
const entry = this.orphanResponses.get(id);
|
|
214
|
+
if (!entry)
|
|
215
|
+
return null;
|
|
216
|
+
this.orphanResponses.delete(id);
|
|
217
|
+
if (entry.expiresAt <= Date.now())
|
|
218
|
+
return null;
|
|
219
|
+
return entry.msg;
|
|
220
|
+
}
|
|
221
|
+
bufferOrphan(msg) {
|
|
222
|
+
const now = Date.now();
|
|
223
|
+
for (const [id, entry] of this.orphanResponses) {
|
|
224
|
+
if (entry.expiresAt <= now)
|
|
225
|
+
this.orphanResponses.delete(id);
|
|
226
|
+
}
|
|
227
|
+
this.orphanResponses.set(msg.id, { msg, expiresAt: now + ORPHAN_TTL_MS });
|
|
228
|
+
while (this.orphanResponses.size > ORPHAN_MAX) {
|
|
229
|
+
this.orphanResponses.delete(this.orphanResponses.keys().next().value);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
173
232
|
async sendAndWait(msg, expectedType, timeoutMs) {
|
|
174
233
|
return new Promise((resolve, reject) => {
|
|
175
234
|
const timer = setTimeout(() => {
|
|
176
235
|
this.pendingCallbacks.delete(msg.id);
|
|
236
|
+
// The work may still be running on the target. Its response will land
|
|
237
|
+
// in the orphan buffer, where a retry with this same id can claim it —
|
|
238
|
+
// so a timeout is no longer the end of the road for that task.
|
|
177
239
|
reject(new Error(`Relay request timed out after ${timeoutMs}ms`));
|
|
178
240
|
}, timeoutMs);
|
|
179
|
-
this.pendingCallbacks.set(msg.id,
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
241
|
+
this.pendingCallbacks.set(msg.id, {
|
|
242
|
+
expectedType,
|
|
243
|
+
settle: (response) => {
|
|
244
|
+
clearTimeout(timer);
|
|
245
|
+
if (response.type === "error") {
|
|
246
|
+
reject(new Error(`Relay error: ${response.payload.message}`));
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
resolve(response);
|
|
250
|
+
}
|
|
251
|
+
},
|
|
187
252
|
});
|
|
188
253
|
this.send(msg);
|
|
189
254
|
});
|
package/dist/relay-client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relay-client.js","sourceRoot":"","sources":["../src/relay-client.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,SAAS,MAAM,IAAI,CAAC;AAC3B,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"relay-client.js","sourceRoot":"","sources":["../src/relay-client.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,SAAS,MAAM,IAAI,CAAC;AAC3B,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAqBpC,MAAM,gBAAgB,GAAG,KAAK,CAAC;AAC/B,MAAM,gBAAgB,GAAG,MAAM,CAAC;AAChC,MAAM,qBAAqB,GAAG,MAAM,CAAC;AAErC;;;;;GAKG;AACH,MAAM,aAAa,GAAG,EAAE,GAAG,MAAM,CAAC;AAClC,MAAM,UAAU,GAAG,GAAG,CAAC;AAOvB,MAAM,OAAO,WAAW;IACd,EAAE,GAAqB,IAAI,CAAC;IAC5B,OAAO,CAAqB;IAC5B,MAAM,CAA8E;IACpF,WAAW,GAAG,gBAAgB,CAAC;IAC/B,cAAc,GAAyC,IAAI,CAAC;IAC5D,cAAc,GAA0C,IAAI,CAAC;IAC7D,SAAS,GAAG,KAAK,CAAC;IAClB,OAAO,GAAG,KAAK,CAAC;IAChB,gBAAgB,GAAgC,IAAI,GAAG,EAAE,CAAC;IAClE,wEAAwE;IAChE,eAAe,GAA0D,IAAI,GAAG,EAAE,CAAC;IAE3F,YAAY,OAA2B;QACrC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,GAAG,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC;IAC9E,CAAC;IAED,WAAW;QACT,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED,KAAK;QACH,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACrB,IAAI,CAAC,OAAO,EAAE,CAAC;IACjB,CAAC;IAED,IAAI;QACF,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;YACZ,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,sBAAsB,CAAC,CAAC;YAC5C,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC;QACjB,CAAC;QACD,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;IACzB,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,QAAQ,CACZ,WAAmB,EACnB,OAAgC,EAChC,MAAe;QAEf,MAAM,EAAE,GAAG,MAAM,IAAI,UAAU,EAAE,CAAC;QAClC,MAAM,eAAe,GAAG,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;QAC7C,IAAI,eAAe,EAAE,CAAC;YACpB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,mDAAmD,EAAE,EAAE,CAAC,CAAC;YAC1E,OAAO,eAAe,CAAC;QACzB,CAAC;QACD,OAAO,IAAI,CAAC,WAAW,CAAC;YACtB,IAAI,EAAE,MAAM;YACZ,EAAE,EAAE,WAAW;YACf,EAAE;YACF,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS;YAC5B,OAAO;YACP,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,EAAE,eAAe,EAAE,MAAM,CAAC,CAAC;IAC9B,CAAC;IAED,6CAA6C;IAC7C,KAAK,CAAC,QAAQ;QACZ,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC;YACtC,IAAI,EAAE,UAAU;YAChB,EAAE,EAAE,UAAU,EAAE;YAChB,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS;YAC5B,OAAO,EAAE,EAAE;YACX,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,EAAE,mBAAmB,EAAE,MAAM,CAAC,CAAC;QAChC,OAAQ,QAAQ,CAAC,OAAO,CAAC,MAA4B,IAAI,EAAE,CAAC;IAC9D,CAAC;IAED,kDAAkD;IAClD,gBAAgB,CAAC,WAAyB,EAAE,MAA+B;QACzE,MAAM,QAAQ,GAAiB;YAC7B,IAAI,EAAE,eAAe;YACrB,EAAE,EAAE,WAAW,CAAC,EAAE;YAClB,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS;YAC5B,EAAE,EAAE,WAAW,CAAC,IAAI;YACpB,OAAO,EAAE,MAAM;YACf,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC;QACF,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACtB,CAAC;IAEO,OAAO;QACb,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO;QAEzB,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC;QACnC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,qCAAqC,GAAG,EAAE,CAAC,CAAC;QAE7D,IAAI,CAAC;YACH,IAAI,CAAC,EAAE,GAAG,IAAI,SAAS,CAAC,GAAG,CAAC,CAAC;QAC/B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC7D,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,4CAA4C,GAAG,EAAE,CAAC,CAAC;YACrE,IAAI,CAAC,iBAAiB,EAAE,CAAC;YACzB,OAAO;QACT,CAAC;QAED,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE;YACtB,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;YACtB,IAAI,CAAC,WAAW,GAAG,gBAAgB,CAAC;YACpC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,qCAAqC,CAAC,CAAC;YACxD,IAAI,CAAC,QAAQ,EAAE,CAAC;YAChB,IAAI,CAAC,cAAc,EAAE,CAAC;QACxB,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,EAAE;YAC7B,IAAI,GAAiB,CAAC;YACtB,IAAI,CAAC;gBACH,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;YACpC,CAAC;YAAC,MAAM,CAAC;gBACP,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;gBAChE,OAAO;YACT,CAAC;YACD,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;QAC1B,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE;YACnC,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;YACvB,IAAI,CAAC,WAAW,EAAE,CAAC;YACnB,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;gBAClB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,yCAAyC,IAAI,KAAK,MAAM,IAAI,WAAW,oBAAoB,CAAC,CAAC;gBAC9G,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAC3B,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YAC1B,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,uCAAuC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QAC1E,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,QAAQ;QACd,MAAM,GAAG,GAAiB;YACxB,IAAI,EAAE,UAAU;YAChB,EAAE,EAAE,UAAU,EAAE;YAChB,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS;YAC5B,OAAO,EAAE;gBACP,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS;gBACjC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM;gBACjC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI;aACxB;YACD,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC;QACF,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACjB,CAAC;IAEO,aAAa,CAAC,GAAiB;QACrC,2EAA2E;QAC3E,2EAA2E;QAC3E,2EAA2E;QAC3E,sEAAsE;QACtE,MAAM,OAAO,GAAG,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAClD,IAAI,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,KAAK,OAAO,CAAC,YAAY,IAAI,GAAG,CAAC,IAAI,KAAK,OAAO,CAAC,EAAE,CAAC;YAC3E,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACrC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACpB,OAAO;QACT,CAAC;QAED,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC;YACjB,KAAK,cAAc;gBACjB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC;gBAC3D,MAAM;YACR,KAAK,MAAM;gBACT,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACzB,MAAM;YACR,KAAK,UAAU;gBACb,sEAAsE;gBACtE,mEAAmE;gBACnE,IAAI,GAAG,CAAC,OAAO,EAAE,YAAY,EAAE,CAAC;oBAC9B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,wCAAwC,GAAG,CAAC,EAAE,kCAAkC,CAAC,CAAC;gBACrG,CAAC;gBACD,MAAM;YACR,KAAK,eAAe;gBAClB,qEAAqE;gBACrE,sEAAsE;gBACtE,uEAAuE;gBACvE,8CAA8C;gBAC9C,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;gBACvB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,kDAAkD,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;gBAC7E,IAAI,CAAC,OAAO,CAAC,oBAAoB,EAAE,CAAC,GAAG,CAAC,CAAC;gBACzC,MAAM;YACR,KAAK,mBAAmB;gBACtB,IAAI,IAAI,CAAC,OAAO,CAAC,kBAAkB,EAAE,CAAC;oBACpC,IAAI,CAAC,OAAO,CAAC,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC,MAA2B,CAAC,CAAC;gBAC3E,CAAC;gBACD,MAAM;YACR,KAAK,eAAe;gBAClB,MAAM;YACR,KAAK,OAAO;gBACV,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,6BAA6B,GAAG,CAAC,OAAO,CAAC,IAAI,MAAM,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;gBAC5F,MAAM;YACR;gBACE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,4CAA4C,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;QAC7E,CAAC;IACH,CAAC;IAEO,IAAI,CAAC,GAAiB;QAC5B,IAAI,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,EAAE,CAAC,UAAU,KAAK,SAAS,CAAC,IAAI,EAAE,CAAC;YACrD,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IAED,6EAA6E;IACrE,WAAW,CAAC,EAAU;QAC5B,MAAM,KAAK,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC3C,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QACxB,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAChC,IAAI,KAAK,CAAC,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE;YAAE,OAAO,IAAI,CAAC;QAC/C,OAAO,KAAK,CAAC,GAAG,CAAC;IACnB,CAAC;IAEO,YAAY,CAAC,GAAiB;QACpC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,KAAK,MAAM,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YAC/C,IAAI,KAAK,CAAC,SAAS,IAAI,GAAG;gBAAE,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC9D,CAAC;QACD,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,GAAG,aAAa,EAAE,CAAC,CAAC;QAC1E,OAAO,IAAI,CAAC,eAAe,CAAC,IAAI,GAAG,UAAU,EAAE,CAAC;YAC9C,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAe,CAAC,CAAC;QAClF,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,WAAW,CACvB,GAAiB,EACjB,YAAoB,EACpB,SAAiB;QAEjB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;gBAC5B,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBACrC,sEAAsE;gBACtE,uEAAuE;gBACvE,+DAA+D;gBAC/D,MAAM,CAAC,IAAI,KAAK,CAAC,iCAAiC,SAAS,IAAI,CAAC,CAAC,CAAC;YACpE,CAAC,EAAE,SAAS,CAAC,CAAC;YAEd,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE;gBAChC,YAAY;gBACZ,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE;oBACnB,YAAY,CAAC,KAAK,CAAC,CAAC;oBACpB,IAAI,QAAQ,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;wBAC9B,MAAM,CAAC,IAAI,KAAK,CAAC,gBAAgB,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;oBAChE,CAAC;yBAAM,CAAC;wBACN,OAAO,CAAC,QAAQ,CAAC,CAAC;oBACpB,CAAC;gBACH,CAAC;aACF,CAAC,CAAC;YAEH,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjB,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,cAAc;QACpB,IAAI,CAAC,cAAc,GAAG,WAAW,CAAC,GAAG,EAAE;YACrC,MAAM,GAAG,GAAiB;gBACxB,IAAI,EAAE,WAAW;gBACjB,EAAE,EAAE,UAAU,EAAE;gBAChB,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS;gBAC5B,OAAO,EAAE,EAAE;gBACX,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;aACpC,CAAC;YACF,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjB,CAAC,EAAE,qBAAqB,CAAC,CAAC;IAC5B,CAAC;IAEO,iBAAiB;QACvB,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO;QACzB,IAAI,CAAC,cAAc,GAAG,UAAU,CAAC,GAAG,EAAE;YACpC,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,CAAC,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QACrB,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,GAAG,CAAC,EAAE,gBAAgB,CAAC,CAAC;IACtE,CAAC;IAEO,WAAW;QACjB,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACxB,aAAa,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;YACnC,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;QAC7B,CAAC;QACD,IAAI,IAAI,CAAC,cAAc,EAAE,CAAC;YACxB,YAAY,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;YAClC,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;QAC7B,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repair-cli.d.ts","sourceRoot":"","sources":["../src/repair-cli.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { repairOpenClaw } from "./repair.js";
|
|
3
|
+
function value(flag) {
|
|
4
|
+
const index = process.argv.indexOf(flag);
|
|
5
|
+
return index >= 0 ? process.argv[index + 1] : undefined;
|
|
6
|
+
}
|
|
7
|
+
function required(flag) {
|
|
8
|
+
const found = value(flag);
|
|
9
|
+
if (!found)
|
|
10
|
+
throw new Error(`missing required argument: ${flag}`);
|
|
11
|
+
return found;
|
|
12
|
+
}
|
|
13
|
+
async function main() {
|
|
14
|
+
const command = process.argv[2];
|
|
15
|
+
if (command !== "repair")
|
|
16
|
+
throw new Error("usage: perkos-a2a repair --artifact <plugin.tgz> --sha256 <digest> --agent-name <name> --agent-id <id> [--json]");
|
|
17
|
+
const result = await repairOpenClaw({
|
|
18
|
+
artifactPath: required("--artifact"),
|
|
19
|
+
artifactSha256: required("--sha256"),
|
|
20
|
+
expectedAgentName: required("--agent-name"),
|
|
21
|
+
expectedAgentId: required("--agent-id"),
|
|
22
|
+
timeoutMs: value("--timeout-ms") ? Number(value("--timeout-ms")) : undefined,
|
|
23
|
+
});
|
|
24
|
+
process.stdout.write(`${JSON.stringify(result)}\n`);
|
|
25
|
+
}
|
|
26
|
+
main().catch((error) => {
|
|
27
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
28
|
+
process.stdout.write(`${JSON.stringify({ ok: false, error: message })}\n`);
|
|
29
|
+
process.exitCode = 1;
|
|
30
|
+
});
|
|
31
|
+
//# sourceMappingURL=repair-cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repair-cli.js","sourceRoot":"","sources":["../src/repair-cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,SAAS,KAAK,CAAC,IAAY;IACzB,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAC1D,CAAC;AAED,SAAS,QAAQ,CAAC,IAAY;IAC5B,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,IAAI,EAAE,CAAC,CAAC;IAClE,OAAO,KAAK,CAAC;AACf,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAChC,IAAI,OAAO,KAAK,QAAQ;QAAE,MAAM,IAAI,KAAK,CAAC,iHAAiH,CAAC,CAAC;IAC7J,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC;QAClC,YAAY,EAAE,QAAQ,CAAC,YAAY,CAAC;QACpC,cAAc,EAAE,QAAQ,CAAC,UAAU,CAAC;QACpC,iBAAiB,EAAE,QAAQ,CAAC,cAAc,CAAC;QAC3C,eAAe,EAAE,QAAQ,CAAC,YAAY,CAAC;QACvC,SAAS,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS;KAC7E,CAAC,CAAC;IACH,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AACtD,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACvE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC;IAC3E,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CAAC,CAAC"}
|
package/dist/repair.d.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export interface RepairOptions {
|
|
2
|
+
artifactPath: string;
|
|
3
|
+
artifactSha256: string;
|
|
4
|
+
expectedAgentName: string;
|
|
5
|
+
expectedAgentId: string;
|
|
6
|
+
openclawBin?: string;
|
|
7
|
+
stateDir?: string;
|
|
8
|
+
configPath?: string;
|
|
9
|
+
timeoutMs?: number;
|
|
10
|
+
pollIntervalMs?: number;
|
|
11
|
+
skipRestart?: boolean;
|
|
12
|
+
}
|
|
13
|
+
export interface CommandResult {
|
|
14
|
+
code: number;
|
|
15
|
+
stdout: string;
|
|
16
|
+
stderr: string;
|
|
17
|
+
}
|
|
18
|
+
export type CommandRunner = (command: string, args: string[]) => Promise<CommandResult>;
|
|
19
|
+
export interface RepairResult {
|
|
20
|
+
ok: boolean;
|
|
21
|
+
version: string;
|
|
22
|
+
artifactVerified: boolean;
|
|
23
|
+
source: "managed-npm";
|
|
24
|
+
normalized: boolean;
|
|
25
|
+
removedUnsupportedPaths: string[];
|
|
26
|
+
quarantinedLegacyExtension: boolean;
|
|
27
|
+
configValid: boolean;
|
|
28
|
+
pluginDoctorClean: boolean;
|
|
29
|
+
restart: {
|
|
30
|
+
requested: boolean;
|
|
31
|
+
verified: boolean;
|
|
32
|
+
beforePid?: number;
|
|
33
|
+
afterPid?: number;
|
|
34
|
+
beforeStartTime?: string;
|
|
35
|
+
afterStartTime?: string;
|
|
36
|
+
};
|
|
37
|
+
postRestart: {
|
|
38
|
+
connected: boolean;
|
|
39
|
+
registered: boolean;
|
|
40
|
+
heartbeat200: boolean;
|
|
41
|
+
chatAuthed: boolean;
|
|
42
|
+
duplicatePlugin: boolean;
|
|
43
|
+
duplicateRegistration: boolean;
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
export declare function normalizeToSchema(value: unknown, schema: unknown, at?: string): {
|
|
47
|
+
value: unknown;
|
|
48
|
+
removed: string[];
|
|
49
|
+
};
|
|
50
|
+
export declare function postRestartStateFromLogs(output: string, agentName: string, startedAt: number): RepairResult["postRestart"];
|
|
51
|
+
export declare const defaultCommandRunner: CommandRunner;
|
|
52
|
+
export declare function repairOpenClaw(options: RepairOptions, run?: CommandRunner): Promise<RepairResult>;
|
|
53
|
+
//# sourceMappingURL=repair.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repair.d.ts","sourceRoot":"","sources":["../src/repair.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC;AAExF,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,MAAM,EAAE,aAAa,CAAC;IACtB,UAAU,EAAE,OAAO,CAAC;IACpB,uBAAuB,EAAE,MAAM,EAAE,CAAC;IAClC,0BAA0B,EAAE,OAAO,CAAC;IACpC,WAAW,EAAE,OAAO,CAAC;IACrB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,OAAO,EAAE;QACP,SAAS,EAAE,OAAO,CAAC;QACnB,QAAQ,EAAE,OAAO,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,cAAc,CAAC,EAAE,MAAM,CAAC;KACzB,CAAC;IACF,WAAW,EAAE;QACX,SAAS,EAAE,OAAO,CAAC;QACnB,UAAU,EAAE,OAAO,CAAC;QACpB,YAAY,EAAE,OAAO,CAAC;QACtB,UAAU,EAAE,OAAO,CAAC;QACpB,eAAe,EAAE,OAAO,CAAC;QACzB,qBAAqB,EAAE,OAAO,CAAC;KAChC,CAAC;CACH;AA0BD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,SAAK,GAAG;IAC3E,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,CAyBA;AA4FD,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,YAAY,CAAC,aAAa,CAAC,CAE1H;AAaD,eAAO,MAAM,oBAAoB,EAAE,aAQjC,CAAC;AA8CH,wBAAsB,cAAc,CAAC,OAAO,EAAE,aAAa,EAAE,GAAG,GAAE,aAAoC,GAAG,OAAO,CAAC,YAAY,CAAC,CAgI7H"}
|