@heysummon/consumer-sdk 0.1.1
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/dist/cli.d.ts +14 -0
- package/dist/cli.js +589 -0
- package/dist/cli.js.map +1 -0
- package/dist/client.d.ts +37 -0
- package/dist/client.js +80 -0
- package/dist/client.js.map +1 -0
- package/dist/crypto.d.ts +41 -0
- package/dist/crypto.js +122 -0
- package/dist/crypto.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/poller.d.ts +28 -0
- package/dist/poller.js +57 -0
- package/dist/poller.js.map +1 -0
- package/dist/provider-store.d.ts +25 -0
- package/dist/provider-store.js +73 -0
- package/dist/provider-store.js.map +1 -0
- package/dist/request-tracker.d.ts +22 -0
- package/dist/request-tracker.js +66 -0
- package/dist/request-tracker.js.map +1 -0
- package/dist/types.d.ts +85 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +39 -0
- package/src/cli.ts +683 -0
- package/src/client.ts +117 -0
- package/src/crypto.ts +205 -0
- package/src/index.ts +23 -0
- package/src/poller.ts +72 -0
- package/src/provider-store.ts +88 -0
- package/src/request-tracker.ts +72 -0
- package/src/types.ts +92 -0
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { SubmitRequestOptions, SubmitRequestResult, PendingEvent, Message, WhoamiResult, HeySummonClientOptions, RequestStatusResponse } from "./types.js";
|
|
2
|
+
/** HTTP error with status code for callers to inspect */
|
|
3
|
+
export declare class HeySummonHttpError extends Error {
|
|
4
|
+
readonly status: number;
|
|
5
|
+
readonly statusText: string;
|
|
6
|
+
readonly body: string;
|
|
7
|
+
constructor(status: number, statusText: string, body: string);
|
|
8
|
+
get isAuthError(): boolean;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Typed HTTP client for the HeySummon consumer API.
|
|
12
|
+
* Each method is a thin wrapper around fetch that includes the x-api-key header.
|
|
13
|
+
*/
|
|
14
|
+
export declare class HeySummonClient {
|
|
15
|
+
private readonly baseUrl;
|
|
16
|
+
private readonly apiKey;
|
|
17
|
+
constructor(opts: HeySummonClientOptions);
|
|
18
|
+
private request;
|
|
19
|
+
/** Identify which provider this API key is linked to */
|
|
20
|
+
whoami(): Promise<WhoamiResult>;
|
|
21
|
+
/** Submit a help request */
|
|
22
|
+
submitRequest(opts: SubmitRequestOptions): Promise<SubmitRequestResult>;
|
|
23
|
+
/** Poll for pending events (writes lastPollAt heartbeat on the server) */
|
|
24
|
+
getPendingEvents(): Promise<{
|
|
25
|
+
events: PendingEvent[];
|
|
26
|
+
}>;
|
|
27
|
+
/** Acknowledge a specific event */
|
|
28
|
+
ackEvent(requestId: string): Promise<void>;
|
|
29
|
+
/** Fetch the full message history for a request */
|
|
30
|
+
getMessages(requestId: string): Promise<{
|
|
31
|
+
messages: Message[];
|
|
32
|
+
}>;
|
|
33
|
+
/** Get the current status of a help request */
|
|
34
|
+
getRequestStatus(requestId: string): Promise<RequestStatusResponse>;
|
|
35
|
+
/** Look up a request by its ref code */
|
|
36
|
+
getRequestByRef(refCode: string): Promise<RequestStatusResponse>;
|
|
37
|
+
}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/** HTTP error with status code for callers to inspect */
|
|
2
|
+
export class HeySummonHttpError extends Error {
|
|
3
|
+
status;
|
|
4
|
+
statusText;
|
|
5
|
+
body;
|
|
6
|
+
constructor(status, statusText, body) {
|
|
7
|
+
super(`HTTP ${status}: ${statusText} — ${body}`);
|
|
8
|
+
this.status = status;
|
|
9
|
+
this.statusText = statusText;
|
|
10
|
+
this.body = body;
|
|
11
|
+
this.name = "HeySummonHttpError";
|
|
12
|
+
}
|
|
13
|
+
get isAuthError() {
|
|
14
|
+
return this.status === 401 || this.status === 403 || this.status === 404;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Typed HTTP client for the HeySummon consumer API.
|
|
19
|
+
* Each method is a thin wrapper around fetch that includes the x-api-key header.
|
|
20
|
+
*/
|
|
21
|
+
export class HeySummonClient {
|
|
22
|
+
baseUrl;
|
|
23
|
+
apiKey;
|
|
24
|
+
constructor(opts) {
|
|
25
|
+
this.baseUrl = opts.baseUrl.replace(/\/$/, ""); // trim trailing slash
|
|
26
|
+
this.apiKey = opts.apiKey;
|
|
27
|
+
}
|
|
28
|
+
async request(method, path, body) {
|
|
29
|
+
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
30
|
+
method,
|
|
31
|
+
headers: {
|
|
32
|
+
"Content-Type": "application/json",
|
|
33
|
+
"x-api-key": this.apiKey,
|
|
34
|
+
},
|
|
35
|
+
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
36
|
+
});
|
|
37
|
+
if (!res.ok) {
|
|
38
|
+
const text = await res.text().catch(() => "(no body)");
|
|
39
|
+
throw new HeySummonHttpError(res.status, res.statusText, text);
|
|
40
|
+
}
|
|
41
|
+
return res.json();
|
|
42
|
+
}
|
|
43
|
+
/** Identify which provider this API key is linked to */
|
|
44
|
+
async whoami() {
|
|
45
|
+
return this.request("GET", "/api/v1/whoami");
|
|
46
|
+
}
|
|
47
|
+
/** Submit a help request */
|
|
48
|
+
async submitRequest(opts) {
|
|
49
|
+
return this.request("POST", "/api/v1/help", {
|
|
50
|
+
apiKey: this.apiKey,
|
|
51
|
+
question: opts.question,
|
|
52
|
+
messages: opts.messages,
|
|
53
|
+
signPublicKey: opts.signPublicKey,
|
|
54
|
+
encryptPublicKey: opts.encryptPublicKey,
|
|
55
|
+
providerName: opts.providerName,
|
|
56
|
+
requiresApproval: opts.requiresApproval,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
/** Poll for pending events (writes lastPollAt heartbeat on the server) */
|
|
60
|
+
async getPendingEvents() {
|
|
61
|
+
return this.request("GET", "/api/v1/events/pending");
|
|
62
|
+
}
|
|
63
|
+
/** Acknowledge a specific event */
|
|
64
|
+
async ackEvent(requestId) {
|
|
65
|
+
await this.request("POST", `/api/v1/events/ack/${requestId}`, {});
|
|
66
|
+
}
|
|
67
|
+
/** Fetch the full message history for a request */
|
|
68
|
+
async getMessages(requestId) {
|
|
69
|
+
return this.request("GET", `/api/v1/messages/${requestId}`);
|
|
70
|
+
}
|
|
71
|
+
/** Get the current status of a help request */
|
|
72
|
+
async getRequestStatus(requestId) {
|
|
73
|
+
return this.request("GET", `/api/v1/help/${requestId}`);
|
|
74
|
+
}
|
|
75
|
+
/** Look up a request by its ref code */
|
|
76
|
+
async getRequestByRef(refCode) {
|
|
77
|
+
return this.request("GET", `/api/v1/requests/by-ref/${refCode}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/crypto.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
export interface KeyPair {
|
|
2
|
+
signPublicKey: string;
|
|
3
|
+
encryptPublicKey: string;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Generate ephemeral Ed25519 + X25519 key pairs in memory.
|
|
7
|
+
* Returns hex-encoded DER public keys for the HeySummon API.
|
|
8
|
+
* Used by Claude Code (no file I/O needed).
|
|
9
|
+
*/
|
|
10
|
+
export declare function generateEphemeralKeys(): KeyPair;
|
|
11
|
+
/**
|
|
12
|
+
* Generate persistent Ed25519 + X25519 key pairs, writing PEM files to dir.
|
|
13
|
+
* Returns hex-encoded DER public keys for the HeySummon API.
|
|
14
|
+
* Used by OpenClaw (keys survive restarts).
|
|
15
|
+
*/
|
|
16
|
+
export declare function generatePersistentKeys(dir: string): KeyPair;
|
|
17
|
+
/**
|
|
18
|
+
* Load existing public keys from PEM files without regenerating.
|
|
19
|
+
* Returns hex-encoded DER public keys for the HeySummon API.
|
|
20
|
+
*/
|
|
21
|
+
export declare function loadPublicKeys(dir: string): KeyPair;
|
|
22
|
+
/**
|
|
23
|
+
* Encrypt a plaintext message using X25519 DH + AES-256-GCM + Ed25519 signing.
|
|
24
|
+
*/
|
|
25
|
+
export declare function encrypt(plaintext: string, recipientX25519PubPath: string, ownSignPrivPath: string, ownEncPrivPath: string, messageId?: string): {
|
|
26
|
+
ciphertext: string;
|
|
27
|
+
iv: string;
|
|
28
|
+
authTag: string;
|
|
29
|
+
signature: string;
|
|
30
|
+
messageId: string;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Decrypt an encrypted message, verifying the Ed25519 signature first.
|
|
34
|
+
*/
|
|
35
|
+
export declare function decrypt(payload: {
|
|
36
|
+
ciphertext: string;
|
|
37
|
+
iv: string;
|
|
38
|
+
authTag: string;
|
|
39
|
+
signature: string;
|
|
40
|
+
messageId: string;
|
|
41
|
+
}, senderX25519PubPath: string, senderSignPubPath: string, ownEncPrivPath: string): string;
|
package/dist/crypto.js
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
/**
|
|
5
|
+
* Generate ephemeral Ed25519 + X25519 key pairs in memory.
|
|
6
|
+
* Returns hex-encoded DER public keys for the HeySummon API.
|
|
7
|
+
* Used by Claude Code (no file I/O needed).
|
|
8
|
+
*/
|
|
9
|
+
export function generateEphemeralKeys() {
|
|
10
|
+
const signKeys = crypto.generateKeyPairSync("ed25519");
|
|
11
|
+
const encKeys = crypto.generateKeyPairSync("x25519");
|
|
12
|
+
return {
|
|
13
|
+
signPublicKey: signKeys.publicKey
|
|
14
|
+
.export({ type: "spki", format: "der" })
|
|
15
|
+
.toString("hex"),
|
|
16
|
+
encryptPublicKey: encKeys.publicKey
|
|
17
|
+
.export({ type: "spki", format: "der" })
|
|
18
|
+
.toString("hex"),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Generate persistent Ed25519 + X25519 key pairs, writing PEM files to dir.
|
|
23
|
+
* Returns hex-encoded DER public keys for the HeySummon API.
|
|
24
|
+
* Used by OpenClaw (keys survive restarts).
|
|
25
|
+
*/
|
|
26
|
+
export function generatePersistentKeys(dir) {
|
|
27
|
+
if (!fs.existsSync(dir)) {
|
|
28
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
29
|
+
}
|
|
30
|
+
const ed = crypto.generateKeyPairSync("ed25519", {
|
|
31
|
+
publicKeyEncoding: { type: "spki", format: "pem" },
|
|
32
|
+
privateKeyEncoding: { type: "pkcs8", format: "pem" },
|
|
33
|
+
});
|
|
34
|
+
fs.writeFileSync(path.join(dir, "sign_public.pem"), ed.publicKey);
|
|
35
|
+
fs.writeFileSync(path.join(dir, "sign_private.pem"), ed.privateKey);
|
|
36
|
+
const x = crypto.generateKeyPairSync("x25519", {
|
|
37
|
+
publicKeyEncoding: { type: "spki", format: "pem" },
|
|
38
|
+
privateKeyEncoding: { type: "pkcs8", format: "pem" },
|
|
39
|
+
});
|
|
40
|
+
fs.writeFileSync(path.join(dir, "encrypt_public.pem"), x.publicKey);
|
|
41
|
+
fs.writeFileSync(path.join(dir, "encrypt_private.pem"), x.privateKey);
|
|
42
|
+
// Convert PEM to hex DER for the API
|
|
43
|
+
return {
|
|
44
|
+
signPublicKey: crypto
|
|
45
|
+
.createPublicKey(ed.publicKey)
|
|
46
|
+
.export({ type: "spki", format: "der" })
|
|
47
|
+
.toString("hex"),
|
|
48
|
+
encryptPublicKey: crypto
|
|
49
|
+
.createPublicKey(x.publicKey)
|
|
50
|
+
.export({ type: "spki", format: "der" })
|
|
51
|
+
.toString("hex"),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Load existing public keys from PEM files without regenerating.
|
|
56
|
+
* Returns hex-encoded DER public keys for the HeySummon API.
|
|
57
|
+
*/
|
|
58
|
+
export function loadPublicKeys(dir) {
|
|
59
|
+
const signPem = fs.readFileSync(path.join(dir, "sign_public.pem"), "utf8");
|
|
60
|
+
const encPem = fs.readFileSync(path.join(dir, "encrypt_public.pem"), "utf8");
|
|
61
|
+
return {
|
|
62
|
+
signPublicKey: crypto
|
|
63
|
+
.createPublicKey(signPem)
|
|
64
|
+
.export({ type: "spki", format: "der" })
|
|
65
|
+
.toString("hex"),
|
|
66
|
+
encryptPublicKey: crypto
|
|
67
|
+
.createPublicKey(encPem)
|
|
68
|
+
.export({ type: "spki", format: "der" })
|
|
69
|
+
.toString("hex"),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Encrypt a plaintext message using X25519 DH + AES-256-GCM + Ed25519 signing.
|
|
74
|
+
*/
|
|
75
|
+
export function encrypt(plaintext, recipientX25519PubPath, ownSignPrivPath, ownEncPrivPath, messageId) {
|
|
76
|
+
const recipientPub = crypto.createPublicKey(fs.readFileSync(recipientX25519PubPath));
|
|
77
|
+
const ownEncPriv = crypto.createPrivateKey(fs.readFileSync(ownEncPrivPath));
|
|
78
|
+
const signPriv = crypto.createPrivateKey(fs.readFileSync(ownSignPrivPath));
|
|
79
|
+
const sharedSecret = crypto.diffieHellman({
|
|
80
|
+
privateKey: ownEncPriv,
|
|
81
|
+
publicKey: recipientPub,
|
|
82
|
+
});
|
|
83
|
+
const msgId = messageId || crypto.randomUUID();
|
|
84
|
+
const messageKey = crypto.hkdfSync("sha256", sharedSecret, msgId, "heysummon-msg", 32);
|
|
85
|
+
const iv = crypto.randomBytes(12);
|
|
86
|
+
const cipher = crypto.createCipheriv("aes-256-gcm", Buffer.from(messageKey), iv);
|
|
87
|
+
const encrypted = Buffer.concat([
|
|
88
|
+
cipher.update(plaintext, "utf8"),
|
|
89
|
+
cipher.final(),
|
|
90
|
+
]);
|
|
91
|
+
const authTag = cipher.getAuthTag();
|
|
92
|
+
const signature = crypto.sign(null, encrypted, signPriv);
|
|
93
|
+
return {
|
|
94
|
+
ciphertext: encrypted.toString("base64"),
|
|
95
|
+
iv: iv.toString("base64"),
|
|
96
|
+
authTag: authTag.toString("base64"),
|
|
97
|
+
signature: signature.toString("base64"),
|
|
98
|
+
messageId: msgId,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Decrypt an encrypted message, verifying the Ed25519 signature first.
|
|
103
|
+
*/
|
|
104
|
+
export function decrypt(payload, senderX25519PubPath, senderSignPubPath, ownEncPrivPath) {
|
|
105
|
+
const senderPub = crypto.createPublicKey(fs.readFileSync(senderX25519PubPath));
|
|
106
|
+
const senderSignPub = crypto.createPublicKey(fs.readFileSync(senderSignPubPath));
|
|
107
|
+
const ownPriv = crypto.createPrivateKey(fs.readFileSync(ownEncPrivPath));
|
|
108
|
+
const ciphertextBuf = Buffer.from(payload.ciphertext, "base64");
|
|
109
|
+
const valid = crypto.verify(null, ciphertextBuf, senderSignPub, Buffer.from(payload.signature, "base64"));
|
|
110
|
+
if (!valid) {
|
|
111
|
+
throw new Error("Signature verification failed");
|
|
112
|
+
}
|
|
113
|
+
const sharedSecret = crypto.diffieHellman({
|
|
114
|
+
privateKey: ownPriv,
|
|
115
|
+
publicKey: senderPub,
|
|
116
|
+
});
|
|
117
|
+
const messageKey = crypto.hkdfSync("sha256", sharedSecret, payload.messageId, "heysummon-msg", 32);
|
|
118
|
+
const decipher = crypto.createDecipheriv("aes-256-gcm", Buffer.from(messageKey), Buffer.from(payload.iv, "base64"));
|
|
119
|
+
decipher.setAuthTag(Buffer.from(payload.authTag, "base64"));
|
|
120
|
+
return Buffer.concat([decipher.update(ciphertextBuf), decipher.final()]).toString("utf8");
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=crypto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.js","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { HeySummonClient, HeySummonHttpError } from "./client.js";
|
|
2
|
+
export { PollingWatcher } from "./poller.js";
|
|
3
|
+
export { ProviderStore } from "./provider-store.js";
|
|
4
|
+
export { RequestTracker } from "./request-tracker.js";
|
|
5
|
+
export { generateEphemeralKeys, generatePersistentKeys, loadPublicKeys, encrypt, decrypt, } from "./crypto.js";
|
|
6
|
+
export type { Provider, SubmitRequestOptions, SubmitRequestResult, PendingEvent, Message, RequestStatusResponse, WhoamiResult, HeySummonClientOptions, } from "./types.js";
|
|
7
|
+
export type { PollingWatcherOptions } from "./poller.js";
|
|
8
|
+
export type { KeyPair } from "./crypto.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { HeySummonClient, HeySummonHttpError } from "./client.js";
|
|
2
|
+
export { PollingWatcher } from "./poller.js";
|
|
3
|
+
export { ProviderStore } from "./provider-store.js";
|
|
4
|
+
export { RequestTracker } from "./request-tracker.js";
|
|
5
|
+
export { generateEphemeralKeys, generatePersistentKeys, loadPublicKeys, encrypt, decrypt, } from "./crypto.js";
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,cAAc,EACd,OAAO,EACP,OAAO,GACR,MAAM,aAAa,CAAC"}
|
package/dist/poller.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { HeySummonClient } from "./client.js";
|
|
2
|
+
import type { PendingEvent } from "./types.js";
|
|
3
|
+
export interface PollingWatcherOptions {
|
|
4
|
+
client: HeySummonClient;
|
|
5
|
+
/** Interval between polls in ms (default: 5000) */
|
|
6
|
+
pollIntervalMs?: number;
|
|
7
|
+
/** Called for each new event received */
|
|
8
|
+
onEvent: (event: PendingEvent) => Promise<void>;
|
|
9
|
+
/** Called on network/poll errors — must not throw */
|
|
10
|
+
onError?: (err: Error) => void;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Polls /api/v1/events/pending on an interval and fires onEvent for each result.
|
|
14
|
+
* Replaces the 286-line platform-watcher.sh with a testable TypeScript class.
|
|
15
|
+
*
|
|
16
|
+
* Deduplication: tracks seen requestIds in memory to avoid double-processing.
|
|
17
|
+
*/
|
|
18
|
+
export declare class PollingWatcher {
|
|
19
|
+
private readonly opts;
|
|
20
|
+
private timer;
|
|
21
|
+
private seen;
|
|
22
|
+
constructor(opts: PollingWatcherOptions);
|
|
23
|
+
start(): void;
|
|
24
|
+
stop(): void;
|
|
25
|
+
isRunning(): boolean;
|
|
26
|
+
/** Reset the deduplication set (useful in tests) */
|
|
27
|
+
resetSeen(): void;
|
|
28
|
+
}
|
package/dist/poller.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Polls /api/v1/events/pending on an interval and fires onEvent for each result.
|
|
3
|
+
* Replaces the 286-line platform-watcher.sh with a testable TypeScript class.
|
|
4
|
+
*
|
|
5
|
+
* Deduplication: tracks seen requestIds in memory to avoid double-processing.
|
|
6
|
+
*/
|
|
7
|
+
export class PollingWatcher {
|
|
8
|
+
opts;
|
|
9
|
+
timer = null;
|
|
10
|
+
seen = new Set();
|
|
11
|
+
constructor(opts) {
|
|
12
|
+
this.opts = opts;
|
|
13
|
+
}
|
|
14
|
+
start() {
|
|
15
|
+
if (this.timer !== null)
|
|
16
|
+
return; // already running
|
|
17
|
+
const interval = this.opts.pollIntervalMs ?? 5_000;
|
|
18
|
+
this.timer = setInterval(async () => {
|
|
19
|
+
try {
|
|
20
|
+
const { events } = await this.opts.client.getPendingEvents();
|
|
21
|
+
for (const event of events) {
|
|
22
|
+
const eventKey = `${event.requestId}:${event.type}:${event.latestMessageAt ?? ""}`;
|
|
23
|
+
if (this.seen.has(eventKey))
|
|
24
|
+
continue;
|
|
25
|
+
this.seen.add(eventKey);
|
|
26
|
+
try {
|
|
27
|
+
await this.opts.onEvent(event);
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
this.opts.onError?.(err instanceof Error ? err : new Error(String(err)));
|
|
31
|
+
}
|
|
32
|
+
// Ack the event (best-effort, non-blocking)
|
|
33
|
+
if (event.requestId) {
|
|
34
|
+
this.opts.client.ackEvent(event.requestId).catch(() => { });
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
this.opts.onError?.(err instanceof Error ? err : new Error(String(err)));
|
|
40
|
+
}
|
|
41
|
+
}, interval);
|
|
42
|
+
}
|
|
43
|
+
stop() {
|
|
44
|
+
if (this.timer !== null) {
|
|
45
|
+
clearInterval(this.timer);
|
|
46
|
+
this.timer = null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
isRunning() {
|
|
50
|
+
return this.timer !== null;
|
|
51
|
+
}
|
|
52
|
+
/** Reset the deduplication set (useful in tests) */
|
|
53
|
+
resetSeen() {
|
|
54
|
+
this.seen.clear();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=poller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"poller.js","sourceRoot":"","sources":["../src/poller.ts"],"names":[],"mappings":"AAaA;;;;;GAKG;AACH,MAAM,OAAO,cAAc;IAII;IAHrB,KAAK,GAA0C,IAAI,CAAC;IACpD,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAEjC,YAA6B,IAA2B;QAA3B,SAAI,GAAJ,IAAI,CAAuB;IAAG,CAAC;IAE5D,KAAK;QACH,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI;YAAE,OAAO,CAAC,kBAAkB;QAEnD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,cAAc,IAAI,KAAK,CAAC;QAEnD,IAAI,CAAC,KAAK,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;YAClC,IAAI,CAAC;gBACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,gBAAgB,EAAE,CAAC;gBAE7D,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;oBAC3B,MAAM,QAAQ,GAAG,GAAG,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,eAAe,IAAI,EAAE,EAAE,CAAC;oBACnF,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC;wBAAE,SAAS;oBACtC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;oBAExB,IAAI,CAAC;wBACH,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;oBACjC,CAAC;oBAAC,OAAO,GAAG,EAAE,CAAC;wBACb,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;oBAC3E,CAAC;oBAED,4CAA4C;oBAC5C,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;wBACpB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;oBAC7D,CAAC;gBACH,CAAC;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAC3E,CAAC;QACH,CAAC,EAAE,QAAQ,CAAC,CAAC;IACf,CAAC;IAED,IAAI;QACF,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;YACxB,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC1B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QACpB,CAAC;IACH,CAAC;IAED,SAAS;QACP,OAAO,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC;IAC7B,CAAC;IAED,oDAAoD;IACpD,SAAS;QACP,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IACpB,CAAC;CACF"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Provider } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Typed replacement for the inline `node -e` JSON manipulation in the bash scripts.
|
|
4
|
+
* Reads/writes providers.json with deduplication by API key and case-insensitive name.
|
|
5
|
+
*/
|
|
6
|
+
export declare class ProviderStore {
|
|
7
|
+
private readonly filePath;
|
|
8
|
+
constructor(filePath: string);
|
|
9
|
+
load(): Provider[];
|
|
10
|
+
save(providers: Provider[]): void;
|
|
11
|
+
/**
|
|
12
|
+
* Add or update a provider entry.
|
|
13
|
+
* Deduplicates by API key and case-insensitive name (same logic as the bash script).
|
|
14
|
+
*/
|
|
15
|
+
add(entry: Omit<Provider, "addedAt" | "nameLower"> & {
|
|
16
|
+
addedAt?: string;
|
|
17
|
+
}): Provider;
|
|
18
|
+
/** Case-insensitive lookup by name or alias */
|
|
19
|
+
findByName(name: string): Provider | undefined;
|
|
20
|
+
/** Look up by exact API key */
|
|
21
|
+
findByKey(apiKey: string): Provider | undefined;
|
|
22
|
+
/** Returns the first provider (default when only one is registered) */
|
|
23
|
+
getDefault(): Provider | undefined;
|
|
24
|
+
remove(apiKey: string): boolean;
|
|
25
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
2
|
+
import { dirname } from "path";
|
|
3
|
+
/**
|
|
4
|
+
* Typed replacement for the inline `node -e` JSON manipulation in the bash scripts.
|
|
5
|
+
* Reads/writes providers.json with deduplication by API key and case-insensitive name.
|
|
6
|
+
*/
|
|
7
|
+
export class ProviderStore {
|
|
8
|
+
filePath;
|
|
9
|
+
constructor(filePath) {
|
|
10
|
+
this.filePath = filePath;
|
|
11
|
+
}
|
|
12
|
+
load() {
|
|
13
|
+
if (!existsSync(this.filePath))
|
|
14
|
+
return [];
|
|
15
|
+
try {
|
|
16
|
+
const data = JSON.parse(readFileSync(this.filePath, "utf8"));
|
|
17
|
+
return Array.isArray(data.providers) ? data.providers : [];
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
save(providers) {
|
|
24
|
+
const dir = dirname(this.filePath);
|
|
25
|
+
if (!existsSync(dir)) {
|
|
26
|
+
mkdirSync(dir, { recursive: true });
|
|
27
|
+
}
|
|
28
|
+
writeFileSync(this.filePath, JSON.stringify({ providers }, null, 2));
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Add or update a provider entry.
|
|
32
|
+
* Deduplicates by API key and case-insensitive name (same logic as the bash script).
|
|
33
|
+
*/
|
|
34
|
+
add(entry) {
|
|
35
|
+
const providers = this.load();
|
|
36
|
+
const nameLower = entry.name.toLowerCase();
|
|
37
|
+
// Remove existing entries with same key or name (case-insensitive)
|
|
38
|
+
const filtered = providers.filter((p) => p.apiKey !== entry.apiKey && p.nameLower !== nameLower);
|
|
39
|
+
const newEntry = {
|
|
40
|
+
name: entry.name,
|
|
41
|
+
nameLower,
|
|
42
|
+
apiKey: entry.apiKey,
|
|
43
|
+
providerId: entry.providerId,
|
|
44
|
+
providerName: entry.providerName,
|
|
45
|
+
addedAt: entry.addedAt ?? new Date().toISOString(),
|
|
46
|
+
};
|
|
47
|
+
filtered.push(newEntry);
|
|
48
|
+
this.save(filtered);
|
|
49
|
+
return newEntry;
|
|
50
|
+
}
|
|
51
|
+
/** Case-insensitive lookup by name or alias */
|
|
52
|
+
findByName(name) {
|
|
53
|
+
const lower = name.toLowerCase();
|
|
54
|
+
return this.load().find((p) => p.nameLower === lower || p.name.toLowerCase() === lower);
|
|
55
|
+
}
|
|
56
|
+
/** Look up by exact API key */
|
|
57
|
+
findByKey(apiKey) {
|
|
58
|
+
return this.load().find((p) => p.apiKey === apiKey);
|
|
59
|
+
}
|
|
60
|
+
/** Returns the first provider (default when only one is registered) */
|
|
61
|
+
getDefault() {
|
|
62
|
+
return this.load()[0];
|
|
63
|
+
}
|
|
64
|
+
remove(apiKey) {
|
|
65
|
+
const providers = this.load();
|
|
66
|
+
const filtered = providers.filter((p) => p.apiKey !== apiKey);
|
|
67
|
+
if (filtered.length === providers.length)
|
|
68
|
+
return false;
|
|
69
|
+
this.save(filtered);
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=provider-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-store.js","sourceRoot":"","sources":["../src/provider-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
interface TrackedRequest {
|
|
2
|
+
requestId: string;
|
|
3
|
+
refCode: string;
|
|
4
|
+
provider?: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* File-based request tracker. Each request is stored as a file:
|
|
8
|
+
* {dir}/{requestId} — contains the refCode
|
|
9
|
+
* {dir}/{requestId}.provider — contains the provider name (optional)
|
|
10
|
+
*
|
|
11
|
+
* Compatible with the existing OpenClaw .requests/ directory format.
|
|
12
|
+
*/
|
|
13
|
+
export declare class RequestTracker {
|
|
14
|
+
private readonly dir;
|
|
15
|
+
constructor(dir: string);
|
|
16
|
+
track(requestId: string, refCode: string, providerName?: string): void;
|
|
17
|
+
getRefCode(requestId: string): string | null;
|
|
18
|
+
getProvider(requestId: string): string | null;
|
|
19
|
+
remove(requestId: string): void;
|
|
20
|
+
listActive(): TrackedRequest[];
|
|
21
|
+
}
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync, unlinkSync, readdirSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
/**
|
|
4
|
+
* File-based request tracker. Each request is stored as a file:
|
|
5
|
+
* {dir}/{requestId} — contains the refCode
|
|
6
|
+
* {dir}/{requestId}.provider — contains the provider name (optional)
|
|
7
|
+
*
|
|
8
|
+
* Compatible with the existing OpenClaw .requests/ directory format.
|
|
9
|
+
*/
|
|
10
|
+
export class RequestTracker {
|
|
11
|
+
dir;
|
|
12
|
+
constructor(dir) {
|
|
13
|
+
this.dir = dir;
|
|
14
|
+
if (!existsSync(dir)) {
|
|
15
|
+
mkdirSync(dir, { recursive: true });
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
track(requestId, refCode, providerName) {
|
|
19
|
+
writeFileSync(join(this.dir, requestId), refCode);
|
|
20
|
+
if (providerName) {
|
|
21
|
+
writeFileSync(join(this.dir, `${requestId}.provider`), providerName);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
getRefCode(requestId) {
|
|
25
|
+
const file = join(this.dir, requestId);
|
|
26
|
+
if (!existsSync(file))
|
|
27
|
+
return null;
|
|
28
|
+
return readFileSync(file, "utf8").trim();
|
|
29
|
+
}
|
|
30
|
+
getProvider(requestId) {
|
|
31
|
+
const file = join(this.dir, `${requestId}.provider`);
|
|
32
|
+
if (!existsSync(file))
|
|
33
|
+
return null;
|
|
34
|
+
return readFileSync(file, "utf8").trim();
|
|
35
|
+
}
|
|
36
|
+
remove(requestId) {
|
|
37
|
+
const refFile = join(this.dir, requestId);
|
|
38
|
+
const provFile = join(this.dir, `${requestId}.provider`);
|
|
39
|
+
if (existsSync(refFile))
|
|
40
|
+
unlinkSync(refFile);
|
|
41
|
+
if (existsSync(provFile))
|
|
42
|
+
unlinkSync(provFile);
|
|
43
|
+
}
|
|
44
|
+
listActive() {
|
|
45
|
+
if (!existsSync(this.dir))
|
|
46
|
+
return [];
|
|
47
|
+
const files = readdirSync(this.dir);
|
|
48
|
+
const result = [];
|
|
49
|
+
for (const file of files) {
|
|
50
|
+
// Skip .provider files, .watcher.pid, hidden files
|
|
51
|
+
if (file.includes("."))
|
|
52
|
+
continue;
|
|
53
|
+
const requestId = file;
|
|
54
|
+
const refCode = this.getRefCode(requestId);
|
|
55
|
+
if (!refCode)
|
|
56
|
+
continue;
|
|
57
|
+
result.push({
|
|
58
|
+
requestId,
|
|
59
|
+
refCode,
|
|
60
|
+
provider: this.getProvider(requestId) ?? undefined,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=request-tracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-tracker.js","sourceRoot":"","sources":["../src/request-tracker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACtG,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAQjC;;;;;;GAMG;AACH,MAAM,OAAO,cAAc;IACI;IAA7B,YAA6B,GAAW;QAAX,QAAG,GAAH,GAAG,CAAQ;QACtC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACrB,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IAED,KAAK,CAAC,SAAiB,EAAE,OAAe,EAAE,YAAqB;QAC7D,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,EAAE,OAAO,CAAC,CAAC;QAClD,IAAI,YAAY,EAAE,CAAC;YACjB,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,WAAW,CAAC,EAAE,YAAY,CAAC,CAAC;QACvE,CAAC;IACH,CAAC;IAED,UAAU,CAAC,SAAiB;QAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QACvC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QACnC,OAAO,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;IAC3C,CAAC;IAED,WAAW,CAAC,SAAiB;QAC3B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,WAAW,CAAC,CAAC;QACrD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QACnC,OAAO,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;IAC3C,CAAC;IAED,MAAM,CAAC,SAAiB;QACtB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QAC1C,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,WAAW,CAAC,CAAC;QACzD,IAAI,UAAU,CAAC,OAAO,CAAC;YAAE,UAAU,CAAC,OAAO,CAAC,CAAC;QAC7C,IAAI,UAAU,CAAC,QAAQ,CAAC;YAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;IACjD,CAAC;IAED,UAAU;QACR,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,OAAO,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACpC,MAAM,MAAM,GAAqB,EAAE,CAAC;QAEpC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,mDAAmD;YACnD,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;gBAAE,SAAS;YAEjC,MAAM,SAAS,GAAG,IAAI,CAAC;YACvB,MAAM,OAAO,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;YAC3C,IAAI,CAAC,OAAO;gBAAE,SAAS;YAEvB,MAAM,CAAC,IAAI,CAAC;gBACV,SAAS;gBACT,OAAO;gBACP,QAAQ,EAAE,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,IAAI,SAAS;aACnD,CAAC,CAAC;QACL,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC;CACF"}
|