@kmmao/happy-agent 0.2.2 → 0.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/README.md +2 -2
- package/dist/index.cjs +1060 -97
- package/dist/index.d.cts +327 -0
- package/dist/index.d.mts +327 -0
- package/dist/index.mjs +1042 -98
- package/package.json +3 -2
package/dist/index.d.cts
CHANGED
|
@@ -1 +1,328 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { EventEmitter } from 'node:events';
|
|
4
|
+
import { Socket } from 'socket.io-client';
|
|
5
|
+
|
|
6
|
+
type Config = {
|
|
7
|
+
serverUrl: string;
|
|
8
|
+
webappUrl: string;
|
|
9
|
+
homeDir: string;
|
|
10
|
+
credentialPath: string;
|
|
11
|
+
};
|
|
12
|
+
declare function loadConfig(): Config;
|
|
13
|
+
|
|
14
|
+
type Credentials = {
|
|
15
|
+
token: string;
|
|
16
|
+
secret: Uint8Array;
|
|
17
|
+
contentKeyPair: {
|
|
18
|
+
publicKey: Uint8Array;
|
|
19
|
+
secretKey: Uint8Array;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
declare function readCredentials(config: Config): Credentials | null;
|
|
23
|
+
declare function requireCredentials(config: Config): Credentials;
|
|
24
|
+
|
|
25
|
+
declare function authLogin(config: Config, opts?: {
|
|
26
|
+
web?: boolean;
|
|
27
|
+
}): Promise<void>;
|
|
28
|
+
declare function authLogout(config: Config): Promise<void>;
|
|
29
|
+
declare function authStatus(config: Config): Promise<void>;
|
|
30
|
+
|
|
31
|
+
type EncryptionVariant = "legacy" | "dataKey";
|
|
32
|
+
type SessionEncryption = {
|
|
33
|
+
readonly key: Uint8Array;
|
|
34
|
+
readonly variant: EncryptionVariant;
|
|
35
|
+
};
|
|
36
|
+
type RawSession = {
|
|
37
|
+
readonly id: string;
|
|
38
|
+
readonly seq: number;
|
|
39
|
+
readonly createdAt: number;
|
|
40
|
+
readonly updatedAt: number;
|
|
41
|
+
readonly active: boolean;
|
|
42
|
+
readonly activeAt: number;
|
|
43
|
+
readonly metadata: string;
|
|
44
|
+
readonly metadataVersion: number;
|
|
45
|
+
readonly agentState: string | null;
|
|
46
|
+
readonly agentStateVersion: number;
|
|
47
|
+
readonly dataEncryptionKey: string | null;
|
|
48
|
+
};
|
|
49
|
+
type DecryptedSession = {
|
|
50
|
+
id: string;
|
|
51
|
+
seq: number;
|
|
52
|
+
createdAt: number;
|
|
53
|
+
updatedAt: number;
|
|
54
|
+
active: boolean;
|
|
55
|
+
activeAt: number;
|
|
56
|
+
metadata: unknown;
|
|
57
|
+
agentState: unknown | null;
|
|
58
|
+
dataEncryptionKey: string | null;
|
|
59
|
+
encryption: SessionEncryption;
|
|
60
|
+
};
|
|
61
|
+
declare const MachineMetadataSchema: z.ZodObject<{
|
|
62
|
+
host: z.ZodString;
|
|
63
|
+
platform: z.ZodString;
|
|
64
|
+
happyCliVersion: z.ZodString;
|
|
65
|
+
homeDir: z.ZodString;
|
|
66
|
+
happyHomeDir: z.ZodString;
|
|
67
|
+
happyLibDir: z.ZodString;
|
|
68
|
+
}, z.core.$strip>;
|
|
69
|
+
type MachineMetadata = z.infer<typeof MachineMetadataSchema>;
|
|
70
|
+
declare const DaemonStateSchema: z.ZodObject<{
|
|
71
|
+
status: z.ZodUnion<readonly [z.ZodEnum<{
|
|
72
|
+
running: "running";
|
|
73
|
+
"shutting-down": "shutting-down";
|
|
74
|
+
}>, z.ZodString]>;
|
|
75
|
+
pid: z.ZodOptional<z.ZodNumber>;
|
|
76
|
+
httpPort: z.ZodOptional<z.ZodNumber>;
|
|
77
|
+
startedAt: z.ZodOptional<z.ZodNumber>;
|
|
78
|
+
shutdownRequestedAt: z.ZodOptional<z.ZodNumber>;
|
|
79
|
+
shutdownSource: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
|
|
80
|
+
unknown: "unknown";
|
|
81
|
+
"mobile-app": "mobile-app";
|
|
82
|
+
cli: "cli";
|
|
83
|
+
"os-signal": "os-signal";
|
|
84
|
+
}>, z.ZodString]>>;
|
|
85
|
+
}, z.core.$strip>;
|
|
86
|
+
type DaemonState = z.infer<typeof DaemonStateSchema>;
|
|
87
|
+
type Machine = {
|
|
88
|
+
readonly id: string;
|
|
89
|
+
readonly encryptionKey: Uint8Array;
|
|
90
|
+
readonly encryptionVariant: EncryptionVariant;
|
|
91
|
+
readonly metadata: MachineMetadata;
|
|
92
|
+
readonly metadataVersion: number;
|
|
93
|
+
readonly daemonState: DaemonState | null;
|
|
94
|
+
readonly daemonStateVersion: number;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* HTTP API client for happy-agent.
|
|
99
|
+
*
|
|
100
|
+
* Provides all HTTP-based operations: session CRUD, message fetching,
|
|
101
|
+
* and v3 batch message API. Migrated from src/api.ts with v3 additions.
|
|
102
|
+
*/
|
|
103
|
+
|
|
104
|
+
type DecryptedMessage = {
|
|
105
|
+
id: string;
|
|
106
|
+
seq: number;
|
|
107
|
+
content: unknown;
|
|
108
|
+
localId: string | null;
|
|
109
|
+
createdAt: number;
|
|
110
|
+
updatedAt: number;
|
|
111
|
+
};
|
|
112
|
+
type V3PostMessagesResponse = {
|
|
113
|
+
messages: Array<{
|
|
114
|
+
id: string;
|
|
115
|
+
seq: number;
|
|
116
|
+
localId: string | null;
|
|
117
|
+
createdAt: number;
|
|
118
|
+
updatedAt: number;
|
|
119
|
+
}>;
|
|
120
|
+
};
|
|
121
|
+
declare function resolveSessionEncryption(session: RawSession, creds: Credentials): SessionEncryption;
|
|
122
|
+
declare function listSessions(config: Config, creds: Credentials): Promise<DecryptedSession[]>;
|
|
123
|
+
declare function listActiveSessions(config: Config, creds: Credentials): Promise<DecryptedSession[]>;
|
|
124
|
+
declare function createSession(config: Config, creds: Credentials, opts: {
|
|
125
|
+
tag: string;
|
|
126
|
+
metadata: unknown;
|
|
127
|
+
}): Promise<DecryptedSession & {
|
|
128
|
+
sessionKey: Uint8Array;
|
|
129
|
+
}>;
|
|
130
|
+
declare function deleteSession(config: Config, creds: Credentials, sessionId: string): Promise<void>;
|
|
131
|
+
declare function getSessionMessages(config: Config, creds: Credentials, sessionId: string, encryption: SessionEncryption): Promise<DecryptedMessage[]>;
|
|
132
|
+
/**
|
|
133
|
+
* Fetch messages after a given seq using v3 API.
|
|
134
|
+
* Returns decrypted messages and whether more pages are available.
|
|
135
|
+
*/
|
|
136
|
+
declare function fetchMessagesAfterSeq(config: Config, creds: Credentials, sessionId: string, encryption: SessionEncryption, afterSeq: number, limit?: number): Promise<{
|
|
137
|
+
messages: DecryptedMessage[];
|
|
138
|
+
hasMore: boolean;
|
|
139
|
+
}>;
|
|
140
|
+
/**
|
|
141
|
+
* Send a batch of encrypted messages using v3 API.
|
|
142
|
+
*/
|
|
143
|
+
declare function sendMessagesBatch(config: Config, creds: Credentials, sessionId: string, encryption: SessionEncryption, contents: unknown[]): Promise<V3PostMessagesResponse>;
|
|
144
|
+
type RawMachine = {
|
|
145
|
+
id: string;
|
|
146
|
+
metadata: string;
|
|
147
|
+
metadataVersion: number;
|
|
148
|
+
daemonState: string | null;
|
|
149
|
+
daemonStateVersion: number;
|
|
150
|
+
dataEncryptionKey: string | null;
|
|
151
|
+
};
|
|
152
|
+
/**
|
|
153
|
+
* Get or create a machine identity on the server.
|
|
154
|
+
* Returns the machine with decrypted metadata.
|
|
155
|
+
*/
|
|
156
|
+
declare function getOrCreateMachine(config: Config, creds: Credentials, metadata: MachineMetadata): Promise<Machine>;
|
|
157
|
+
/**
|
|
158
|
+
* List all machines for the current account.
|
|
159
|
+
*/
|
|
160
|
+
declare function listMachines(config: Config, creds: Credentials): Promise<RawMachine[]>;
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Common RPC types and interfaces for both session and machine clients.
|
|
164
|
+
* Mirrors happy-cli/src/api/rpc/types.ts
|
|
165
|
+
*/
|
|
166
|
+
/**
|
|
167
|
+
* Generic RPC handler function type
|
|
168
|
+
*/
|
|
169
|
+
type RpcHandler<TRequest = any, TResponse = any> = (data: TRequest) => TResponse | Promise<TResponse>;
|
|
170
|
+
/**
|
|
171
|
+
* RPC request data from server
|
|
172
|
+
*/
|
|
173
|
+
interface RpcRequest {
|
|
174
|
+
method: string;
|
|
175
|
+
params: string;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Configuration for RPC handler manager
|
|
179
|
+
*/
|
|
180
|
+
interface RpcHandlerConfig {
|
|
181
|
+
scopePrefix: string;
|
|
182
|
+
encryptionKey: Uint8Array;
|
|
183
|
+
encryptionVariant: "legacy" | "dataKey";
|
|
184
|
+
logger?: (message: string, data?: unknown) => void;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Generic RPC handler manager for session and machine clients.
|
|
189
|
+
* Manages RPC method registration, encryption/decryption, and handler execution.
|
|
190
|
+
*
|
|
191
|
+
* Adapted from happy-cli/src/api/rpc/RpcHandlerManager.ts with
|
|
192
|
+
* Agent-local imports (no @/ path alias).
|
|
193
|
+
*/
|
|
194
|
+
|
|
195
|
+
declare class RpcHandlerManager {
|
|
196
|
+
private handlers;
|
|
197
|
+
private readonly scopePrefix;
|
|
198
|
+
private readonly encryptionKey;
|
|
199
|
+
private readonly encryptionVariant;
|
|
200
|
+
private readonly logger;
|
|
201
|
+
private socket;
|
|
202
|
+
private reregisterInterval;
|
|
203
|
+
constructor(config: RpcHandlerConfig);
|
|
204
|
+
/**
|
|
205
|
+
* Register an RPC handler for a specific method
|
|
206
|
+
*/
|
|
207
|
+
registerHandler<TRequest = any, TResponse = any>(method: string, handler: RpcHandler<TRequest, TResponse>): void;
|
|
208
|
+
/**
|
|
209
|
+
* Handle an incoming RPC request
|
|
210
|
+
*/
|
|
211
|
+
handleRequest(request: RpcRequest): Promise<string>;
|
|
212
|
+
onSocketConnect(socket: Socket): void;
|
|
213
|
+
onSocketDisconnect(): void;
|
|
214
|
+
getHandlerCount(): number;
|
|
215
|
+
hasHandler(method: string): boolean;
|
|
216
|
+
clearHandlers(): void;
|
|
217
|
+
/**
|
|
218
|
+
* Register a single method with ack + retry.
|
|
219
|
+
* Falls back to fire-and-forget emit after all retries exhausted.
|
|
220
|
+
*/
|
|
221
|
+
private emitRegisterWithRetry;
|
|
222
|
+
private registerAllHandlers;
|
|
223
|
+
/**
|
|
224
|
+
* Periodic re-registration every 60s as a safety net.
|
|
225
|
+
*/
|
|
226
|
+
private startReregisterInterval;
|
|
227
|
+
private stopReregisterInterval;
|
|
228
|
+
private getPrefixedMethod;
|
|
229
|
+
}
|
|
230
|
+
declare function createRpcHandlerManager(config: RpcHandlerConfig): RpcHandlerManager;
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Enhanced session WebSocket client with RPC support.
|
|
234
|
+
*
|
|
235
|
+
* Improvements over the original session.ts:
|
|
236
|
+
* - RPC handler integration (bash, readFile, writeFile via RpcHandlerManager)
|
|
237
|
+
* - keepAlive with thinking state
|
|
238
|
+
* - updateMetadata / updateAgentState with OCC backoff
|
|
239
|
+
* - Typed socket events
|
|
240
|
+
*
|
|
241
|
+
* All existing public API is preserved for backward compatibility.
|
|
242
|
+
*/
|
|
243
|
+
|
|
244
|
+
type SessionClientOptions = {
|
|
245
|
+
readonly sessionId: string;
|
|
246
|
+
readonly encryptionKey: Uint8Array;
|
|
247
|
+
readonly encryptionVariant: EncryptionVariant;
|
|
248
|
+
readonly token: string;
|
|
249
|
+
readonly serverUrl: string;
|
|
250
|
+
readonly initialAgentState?: unknown | null;
|
|
251
|
+
/** Working directory for RPC handlers (bash cwd, file operations). Defaults to process.cwd(). */
|
|
252
|
+
readonly workingDirectory?: string;
|
|
253
|
+
/** Set to false to disable automatic RPC handler registration. Default: true */
|
|
254
|
+
readonly enableRpc?: boolean;
|
|
255
|
+
};
|
|
256
|
+
declare class SessionClient extends EventEmitter {
|
|
257
|
+
readonly sessionId: string;
|
|
258
|
+
readonly rpcHandlerManager: RpcHandlerManager;
|
|
259
|
+
private readonly encryptionKey;
|
|
260
|
+
private readonly encryptionVariant;
|
|
261
|
+
private socket;
|
|
262
|
+
private metadata;
|
|
263
|
+
private metadataVersion;
|
|
264
|
+
private agentState;
|
|
265
|
+
private agentStateVersion;
|
|
266
|
+
private aliveInterval;
|
|
267
|
+
private thinking;
|
|
268
|
+
constructor(opts: SessionClientOptions);
|
|
269
|
+
sendMessage(text: string, meta?: Record<string, unknown>): void;
|
|
270
|
+
getMetadata(): unknown | null;
|
|
271
|
+
getAgentState(): unknown | null;
|
|
272
|
+
setThinking(thinking: boolean): void;
|
|
273
|
+
waitForConnect(timeoutMs?: number): Promise<void>;
|
|
274
|
+
waitForIdle(timeoutMs?: number): Promise<void>;
|
|
275
|
+
sendStop(): void;
|
|
276
|
+
close(): void;
|
|
277
|
+
updateMetadata(newMetadata: unknown): Promise<void>;
|
|
278
|
+
updateAgentState(newState: unknown | null): Promise<void>;
|
|
279
|
+
private setupSocketListeners;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Machine WebSocket client — trimmed from CLI's ApiMachineClient.
|
|
284
|
+
*
|
|
285
|
+
* Core capabilities retained:
|
|
286
|
+
* - Machine-scoped Socket.IO connection
|
|
287
|
+
* - RPC handler registration (via RpcHandlerManager)
|
|
288
|
+
* - keepAlive heartbeat
|
|
289
|
+
* - updateMetadata / updateDaemonState with OCC backoff
|
|
290
|
+
* - Ephemeral event handling (webhook/supervisor triggers)
|
|
291
|
+
*
|
|
292
|
+
* Removed (CLI-only):
|
|
293
|
+
* - Webhook/supervisor status emit + pending queues
|
|
294
|
+
* - Fix kill handler
|
|
295
|
+
* - CLI-specific logging (debugLargeJson)
|
|
296
|
+
*/
|
|
297
|
+
|
|
298
|
+
type MachineClientOptions = {
|
|
299
|
+
readonly token: string;
|
|
300
|
+
readonly machine: Machine;
|
|
301
|
+
readonly serverUrl: string;
|
|
302
|
+
/** Working directory for RPC handlers. Defaults to process.cwd(). */
|
|
303
|
+
readonly workingDirectory?: string;
|
|
304
|
+
/** Handler for ephemeral events from server. */
|
|
305
|
+
readonly onEphemeral?: (data: {
|
|
306
|
+
type: string;
|
|
307
|
+
[key: string]: unknown;
|
|
308
|
+
}) => void;
|
|
309
|
+
};
|
|
310
|
+
declare class MachineClient {
|
|
311
|
+
readonly machine: Machine;
|
|
312
|
+
readonly rpcHandlerManager: RpcHandlerManager;
|
|
313
|
+
private socket;
|
|
314
|
+
private keepAliveInterval;
|
|
315
|
+
private readonly token;
|
|
316
|
+
private readonly serverUrl;
|
|
317
|
+
private readonly onEphemeral?;
|
|
318
|
+
constructor(opts: MachineClientOptions);
|
|
319
|
+
connect(): void;
|
|
320
|
+
updateMachineMetadata(handler: (metadata: MachineMetadata | null) => MachineMetadata): Promise<void>;
|
|
321
|
+
updateDaemonState(handler: (state: DaemonState | null) => DaemonState): Promise<void>;
|
|
322
|
+
shutdown(): void;
|
|
323
|
+
private startKeepAlive;
|
|
324
|
+
private stopKeepAlive;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
export { MachineClient, RpcHandlerManager, SessionClient, authLogin, authLogout, authStatus, createRpcHandlerManager, createSession, deleteSession, fetchMessagesAfterSeq, getOrCreateMachine, getSessionMessages, listActiveSessions, listMachines, listSessions, loadConfig, readCredentials, requireCredentials, resolveSessionEncryption, sendMessagesBatch };
|
|
328
|
+
export type { Config, Credentials, DecryptedMessage, DecryptedSession, EncryptionVariant, MachineClientOptions, RpcHandler, RpcHandlerConfig, SessionClientOptions, SessionEncryption };
|
package/dist/index.d.mts
CHANGED
|
@@ -1 +1,328 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { EventEmitter } from 'node:events';
|
|
4
|
+
import { Socket } from 'socket.io-client';
|
|
5
|
+
|
|
6
|
+
type Config = {
|
|
7
|
+
serverUrl: string;
|
|
8
|
+
webappUrl: string;
|
|
9
|
+
homeDir: string;
|
|
10
|
+
credentialPath: string;
|
|
11
|
+
};
|
|
12
|
+
declare function loadConfig(): Config;
|
|
13
|
+
|
|
14
|
+
type Credentials = {
|
|
15
|
+
token: string;
|
|
16
|
+
secret: Uint8Array;
|
|
17
|
+
contentKeyPair: {
|
|
18
|
+
publicKey: Uint8Array;
|
|
19
|
+
secretKey: Uint8Array;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
declare function readCredentials(config: Config): Credentials | null;
|
|
23
|
+
declare function requireCredentials(config: Config): Credentials;
|
|
24
|
+
|
|
25
|
+
declare function authLogin(config: Config, opts?: {
|
|
26
|
+
web?: boolean;
|
|
27
|
+
}): Promise<void>;
|
|
28
|
+
declare function authLogout(config: Config): Promise<void>;
|
|
29
|
+
declare function authStatus(config: Config): Promise<void>;
|
|
30
|
+
|
|
31
|
+
type EncryptionVariant = "legacy" | "dataKey";
|
|
32
|
+
type SessionEncryption = {
|
|
33
|
+
readonly key: Uint8Array;
|
|
34
|
+
readonly variant: EncryptionVariant;
|
|
35
|
+
};
|
|
36
|
+
type RawSession = {
|
|
37
|
+
readonly id: string;
|
|
38
|
+
readonly seq: number;
|
|
39
|
+
readonly createdAt: number;
|
|
40
|
+
readonly updatedAt: number;
|
|
41
|
+
readonly active: boolean;
|
|
42
|
+
readonly activeAt: number;
|
|
43
|
+
readonly metadata: string;
|
|
44
|
+
readonly metadataVersion: number;
|
|
45
|
+
readonly agentState: string | null;
|
|
46
|
+
readonly agentStateVersion: number;
|
|
47
|
+
readonly dataEncryptionKey: string | null;
|
|
48
|
+
};
|
|
49
|
+
type DecryptedSession = {
|
|
50
|
+
id: string;
|
|
51
|
+
seq: number;
|
|
52
|
+
createdAt: number;
|
|
53
|
+
updatedAt: number;
|
|
54
|
+
active: boolean;
|
|
55
|
+
activeAt: number;
|
|
56
|
+
metadata: unknown;
|
|
57
|
+
agentState: unknown | null;
|
|
58
|
+
dataEncryptionKey: string | null;
|
|
59
|
+
encryption: SessionEncryption;
|
|
60
|
+
};
|
|
61
|
+
declare const MachineMetadataSchema: z.ZodObject<{
|
|
62
|
+
host: z.ZodString;
|
|
63
|
+
platform: z.ZodString;
|
|
64
|
+
happyCliVersion: z.ZodString;
|
|
65
|
+
homeDir: z.ZodString;
|
|
66
|
+
happyHomeDir: z.ZodString;
|
|
67
|
+
happyLibDir: z.ZodString;
|
|
68
|
+
}, z.core.$strip>;
|
|
69
|
+
type MachineMetadata = z.infer<typeof MachineMetadataSchema>;
|
|
70
|
+
declare const DaemonStateSchema: z.ZodObject<{
|
|
71
|
+
status: z.ZodUnion<readonly [z.ZodEnum<{
|
|
72
|
+
running: "running";
|
|
73
|
+
"shutting-down": "shutting-down";
|
|
74
|
+
}>, z.ZodString]>;
|
|
75
|
+
pid: z.ZodOptional<z.ZodNumber>;
|
|
76
|
+
httpPort: z.ZodOptional<z.ZodNumber>;
|
|
77
|
+
startedAt: z.ZodOptional<z.ZodNumber>;
|
|
78
|
+
shutdownRequestedAt: z.ZodOptional<z.ZodNumber>;
|
|
79
|
+
shutdownSource: z.ZodOptional<z.ZodUnion<readonly [z.ZodEnum<{
|
|
80
|
+
unknown: "unknown";
|
|
81
|
+
"mobile-app": "mobile-app";
|
|
82
|
+
cli: "cli";
|
|
83
|
+
"os-signal": "os-signal";
|
|
84
|
+
}>, z.ZodString]>>;
|
|
85
|
+
}, z.core.$strip>;
|
|
86
|
+
type DaemonState = z.infer<typeof DaemonStateSchema>;
|
|
87
|
+
type Machine = {
|
|
88
|
+
readonly id: string;
|
|
89
|
+
readonly encryptionKey: Uint8Array;
|
|
90
|
+
readonly encryptionVariant: EncryptionVariant;
|
|
91
|
+
readonly metadata: MachineMetadata;
|
|
92
|
+
readonly metadataVersion: number;
|
|
93
|
+
readonly daemonState: DaemonState | null;
|
|
94
|
+
readonly daemonStateVersion: number;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* HTTP API client for happy-agent.
|
|
99
|
+
*
|
|
100
|
+
* Provides all HTTP-based operations: session CRUD, message fetching,
|
|
101
|
+
* and v3 batch message API. Migrated from src/api.ts with v3 additions.
|
|
102
|
+
*/
|
|
103
|
+
|
|
104
|
+
type DecryptedMessage = {
|
|
105
|
+
id: string;
|
|
106
|
+
seq: number;
|
|
107
|
+
content: unknown;
|
|
108
|
+
localId: string | null;
|
|
109
|
+
createdAt: number;
|
|
110
|
+
updatedAt: number;
|
|
111
|
+
};
|
|
112
|
+
type V3PostMessagesResponse = {
|
|
113
|
+
messages: Array<{
|
|
114
|
+
id: string;
|
|
115
|
+
seq: number;
|
|
116
|
+
localId: string | null;
|
|
117
|
+
createdAt: number;
|
|
118
|
+
updatedAt: number;
|
|
119
|
+
}>;
|
|
120
|
+
};
|
|
121
|
+
declare function resolveSessionEncryption(session: RawSession, creds: Credentials): SessionEncryption;
|
|
122
|
+
declare function listSessions(config: Config, creds: Credentials): Promise<DecryptedSession[]>;
|
|
123
|
+
declare function listActiveSessions(config: Config, creds: Credentials): Promise<DecryptedSession[]>;
|
|
124
|
+
declare function createSession(config: Config, creds: Credentials, opts: {
|
|
125
|
+
tag: string;
|
|
126
|
+
metadata: unknown;
|
|
127
|
+
}): Promise<DecryptedSession & {
|
|
128
|
+
sessionKey: Uint8Array;
|
|
129
|
+
}>;
|
|
130
|
+
declare function deleteSession(config: Config, creds: Credentials, sessionId: string): Promise<void>;
|
|
131
|
+
declare function getSessionMessages(config: Config, creds: Credentials, sessionId: string, encryption: SessionEncryption): Promise<DecryptedMessage[]>;
|
|
132
|
+
/**
|
|
133
|
+
* Fetch messages after a given seq using v3 API.
|
|
134
|
+
* Returns decrypted messages and whether more pages are available.
|
|
135
|
+
*/
|
|
136
|
+
declare function fetchMessagesAfterSeq(config: Config, creds: Credentials, sessionId: string, encryption: SessionEncryption, afterSeq: number, limit?: number): Promise<{
|
|
137
|
+
messages: DecryptedMessage[];
|
|
138
|
+
hasMore: boolean;
|
|
139
|
+
}>;
|
|
140
|
+
/**
|
|
141
|
+
* Send a batch of encrypted messages using v3 API.
|
|
142
|
+
*/
|
|
143
|
+
declare function sendMessagesBatch(config: Config, creds: Credentials, sessionId: string, encryption: SessionEncryption, contents: unknown[]): Promise<V3PostMessagesResponse>;
|
|
144
|
+
type RawMachine = {
|
|
145
|
+
id: string;
|
|
146
|
+
metadata: string;
|
|
147
|
+
metadataVersion: number;
|
|
148
|
+
daemonState: string | null;
|
|
149
|
+
daemonStateVersion: number;
|
|
150
|
+
dataEncryptionKey: string | null;
|
|
151
|
+
};
|
|
152
|
+
/**
|
|
153
|
+
* Get or create a machine identity on the server.
|
|
154
|
+
* Returns the machine with decrypted metadata.
|
|
155
|
+
*/
|
|
156
|
+
declare function getOrCreateMachine(config: Config, creds: Credentials, metadata: MachineMetadata): Promise<Machine>;
|
|
157
|
+
/**
|
|
158
|
+
* List all machines for the current account.
|
|
159
|
+
*/
|
|
160
|
+
declare function listMachines(config: Config, creds: Credentials): Promise<RawMachine[]>;
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Common RPC types and interfaces for both session and machine clients.
|
|
164
|
+
* Mirrors happy-cli/src/api/rpc/types.ts
|
|
165
|
+
*/
|
|
166
|
+
/**
|
|
167
|
+
* Generic RPC handler function type
|
|
168
|
+
*/
|
|
169
|
+
type RpcHandler<TRequest = any, TResponse = any> = (data: TRequest) => TResponse | Promise<TResponse>;
|
|
170
|
+
/**
|
|
171
|
+
* RPC request data from server
|
|
172
|
+
*/
|
|
173
|
+
interface RpcRequest {
|
|
174
|
+
method: string;
|
|
175
|
+
params: string;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Configuration for RPC handler manager
|
|
179
|
+
*/
|
|
180
|
+
interface RpcHandlerConfig {
|
|
181
|
+
scopePrefix: string;
|
|
182
|
+
encryptionKey: Uint8Array;
|
|
183
|
+
encryptionVariant: "legacy" | "dataKey";
|
|
184
|
+
logger?: (message: string, data?: unknown) => void;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Generic RPC handler manager for session and machine clients.
|
|
189
|
+
* Manages RPC method registration, encryption/decryption, and handler execution.
|
|
190
|
+
*
|
|
191
|
+
* Adapted from happy-cli/src/api/rpc/RpcHandlerManager.ts with
|
|
192
|
+
* Agent-local imports (no @/ path alias).
|
|
193
|
+
*/
|
|
194
|
+
|
|
195
|
+
declare class RpcHandlerManager {
|
|
196
|
+
private handlers;
|
|
197
|
+
private readonly scopePrefix;
|
|
198
|
+
private readonly encryptionKey;
|
|
199
|
+
private readonly encryptionVariant;
|
|
200
|
+
private readonly logger;
|
|
201
|
+
private socket;
|
|
202
|
+
private reregisterInterval;
|
|
203
|
+
constructor(config: RpcHandlerConfig);
|
|
204
|
+
/**
|
|
205
|
+
* Register an RPC handler for a specific method
|
|
206
|
+
*/
|
|
207
|
+
registerHandler<TRequest = any, TResponse = any>(method: string, handler: RpcHandler<TRequest, TResponse>): void;
|
|
208
|
+
/**
|
|
209
|
+
* Handle an incoming RPC request
|
|
210
|
+
*/
|
|
211
|
+
handleRequest(request: RpcRequest): Promise<string>;
|
|
212
|
+
onSocketConnect(socket: Socket): void;
|
|
213
|
+
onSocketDisconnect(): void;
|
|
214
|
+
getHandlerCount(): number;
|
|
215
|
+
hasHandler(method: string): boolean;
|
|
216
|
+
clearHandlers(): void;
|
|
217
|
+
/**
|
|
218
|
+
* Register a single method with ack + retry.
|
|
219
|
+
* Falls back to fire-and-forget emit after all retries exhausted.
|
|
220
|
+
*/
|
|
221
|
+
private emitRegisterWithRetry;
|
|
222
|
+
private registerAllHandlers;
|
|
223
|
+
/**
|
|
224
|
+
* Periodic re-registration every 60s as a safety net.
|
|
225
|
+
*/
|
|
226
|
+
private startReregisterInterval;
|
|
227
|
+
private stopReregisterInterval;
|
|
228
|
+
private getPrefixedMethod;
|
|
229
|
+
}
|
|
230
|
+
declare function createRpcHandlerManager(config: RpcHandlerConfig): RpcHandlerManager;
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Enhanced session WebSocket client with RPC support.
|
|
234
|
+
*
|
|
235
|
+
* Improvements over the original session.ts:
|
|
236
|
+
* - RPC handler integration (bash, readFile, writeFile via RpcHandlerManager)
|
|
237
|
+
* - keepAlive with thinking state
|
|
238
|
+
* - updateMetadata / updateAgentState with OCC backoff
|
|
239
|
+
* - Typed socket events
|
|
240
|
+
*
|
|
241
|
+
* All existing public API is preserved for backward compatibility.
|
|
242
|
+
*/
|
|
243
|
+
|
|
244
|
+
type SessionClientOptions = {
|
|
245
|
+
readonly sessionId: string;
|
|
246
|
+
readonly encryptionKey: Uint8Array;
|
|
247
|
+
readonly encryptionVariant: EncryptionVariant;
|
|
248
|
+
readonly token: string;
|
|
249
|
+
readonly serverUrl: string;
|
|
250
|
+
readonly initialAgentState?: unknown | null;
|
|
251
|
+
/** Working directory for RPC handlers (bash cwd, file operations). Defaults to process.cwd(). */
|
|
252
|
+
readonly workingDirectory?: string;
|
|
253
|
+
/** Set to false to disable automatic RPC handler registration. Default: true */
|
|
254
|
+
readonly enableRpc?: boolean;
|
|
255
|
+
};
|
|
256
|
+
declare class SessionClient extends EventEmitter {
|
|
257
|
+
readonly sessionId: string;
|
|
258
|
+
readonly rpcHandlerManager: RpcHandlerManager;
|
|
259
|
+
private readonly encryptionKey;
|
|
260
|
+
private readonly encryptionVariant;
|
|
261
|
+
private socket;
|
|
262
|
+
private metadata;
|
|
263
|
+
private metadataVersion;
|
|
264
|
+
private agentState;
|
|
265
|
+
private agentStateVersion;
|
|
266
|
+
private aliveInterval;
|
|
267
|
+
private thinking;
|
|
268
|
+
constructor(opts: SessionClientOptions);
|
|
269
|
+
sendMessage(text: string, meta?: Record<string, unknown>): void;
|
|
270
|
+
getMetadata(): unknown | null;
|
|
271
|
+
getAgentState(): unknown | null;
|
|
272
|
+
setThinking(thinking: boolean): void;
|
|
273
|
+
waitForConnect(timeoutMs?: number): Promise<void>;
|
|
274
|
+
waitForIdle(timeoutMs?: number): Promise<void>;
|
|
275
|
+
sendStop(): void;
|
|
276
|
+
close(): void;
|
|
277
|
+
updateMetadata(newMetadata: unknown): Promise<void>;
|
|
278
|
+
updateAgentState(newState: unknown | null): Promise<void>;
|
|
279
|
+
private setupSocketListeners;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Machine WebSocket client — trimmed from CLI's ApiMachineClient.
|
|
284
|
+
*
|
|
285
|
+
* Core capabilities retained:
|
|
286
|
+
* - Machine-scoped Socket.IO connection
|
|
287
|
+
* - RPC handler registration (via RpcHandlerManager)
|
|
288
|
+
* - keepAlive heartbeat
|
|
289
|
+
* - updateMetadata / updateDaemonState with OCC backoff
|
|
290
|
+
* - Ephemeral event handling (webhook/supervisor triggers)
|
|
291
|
+
*
|
|
292
|
+
* Removed (CLI-only):
|
|
293
|
+
* - Webhook/supervisor status emit + pending queues
|
|
294
|
+
* - Fix kill handler
|
|
295
|
+
* - CLI-specific logging (debugLargeJson)
|
|
296
|
+
*/
|
|
297
|
+
|
|
298
|
+
type MachineClientOptions = {
|
|
299
|
+
readonly token: string;
|
|
300
|
+
readonly machine: Machine;
|
|
301
|
+
readonly serverUrl: string;
|
|
302
|
+
/** Working directory for RPC handlers. Defaults to process.cwd(). */
|
|
303
|
+
readonly workingDirectory?: string;
|
|
304
|
+
/** Handler for ephemeral events from server. */
|
|
305
|
+
readonly onEphemeral?: (data: {
|
|
306
|
+
type: string;
|
|
307
|
+
[key: string]: unknown;
|
|
308
|
+
}) => void;
|
|
309
|
+
};
|
|
310
|
+
declare class MachineClient {
|
|
311
|
+
readonly machine: Machine;
|
|
312
|
+
readonly rpcHandlerManager: RpcHandlerManager;
|
|
313
|
+
private socket;
|
|
314
|
+
private keepAliveInterval;
|
|
315
|
+
private readonly token;
|
|
316
|
+
private readonly serverUrl;
|
|
317
|
+
private readonly onEphemeral?;
|
|
318
|
+
constructor(opts: MachineClientOptions);
|
|
319
|
+
connect(): void;
|
|
320
|
+
updateMachineMetadata(handler: (metadata: MachineMetadata | null) => MachineMetadata): Promise<void>;
|
|
321
|
+
updateDaemonState(handler: (state: DaemonState | null) => DaemonState): Promise<void>;
|
|
322
|
+
shutdown(): void;
|
|
323
|
+
private startKeepAlive;
|
|
324
|
+
private stopKeepAlive;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
export { MachineClient, RpcHandlerManager, SessionClient, authLogin, authLogout, authStatus, createRpcHandlerManager, createSession, deleteSession, fetchMessagesAfterSeq, getOrCreateMachine, getSessionMessages, listActiveSessions, listMachines, listSessions, loadConfig, readCredentials, requireCredentials, resolveSessionEncryption, sendMessagesBatch };
|
|
328
|
+
export type { Config, Credentials, DecryptedMessage, DecryptedSession, EncryptionVariant, MachineClientOptions, RpcHandler, RpcHandlerConfig, SessionClientOptions, SessionEncryption };
|