@agentxjs/node-platform 2.0.0 → 3.0.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/dist/{WebSocketFactory-SDWPRZVB.js → WebSocketFactory-W4Z4TO7K.js} +2 -2
- package/dist/{WebSocketConnection-BUL85bFC.d.ts → WebSocketServer-CbjDC1lS.d.ts} +29 -29
- package/dist/{chunk-TXESAX3X.js → chunk-247HA6OS.js} +15 -15
- package/dist/chunk-247HA6OS.js.map +1 -0
- package/dist/{chunk-PK2K7CCJ.js → chunk-ABWPBGQW.js} +6 -8
- package/dist/chunk-ABWPBGQW.js.map +1 -0
- package/dist/{chunk-V664KD3R.js → chunk-SUJ5DIDM.js} +1 -1
- package/dist/chunk-SUJ5DIDM.js.map +1 -0
- package/dist/{chunk-BBZV6B5R.js → chunk-VVNULOYS.js} +2 -4
- package/dist/chunk-VVNULOYS.js.map +1 -0
- package/dist/index.d.ts +5 -5
- package/dist/index.js +17 -11
- package/dist/index.js.map +1 -1
- package/dist/mq/index.d.ts +25 -25
- package/dist/mq/index.js +1 -1
- package/dist/network/index.d.ts +5 -5
- package/dist/network/index.js +2 -2
- package/dist/persistence/index.d.ts +44 -44
- package/dist/persistence/index.js +1 -1
- package/package.json +2 -2
- package/src/bash/NodeBashProvider.ts +2 -2
- package/src/index.ts +20 -14
- package/src/logger/FileLoggerFactory.ts +3 -3
- package/src/mq/OffsetGenerator.ts +1 -1
- package/src/mq/SqliteMessageQueue.ts +3 -3
- package/src/mq/index.ts +1 -1
- package/src/network/WebSocketConnection.ts +2 -2
- package/src/network/WebSocketFactory.ts +4 -4
- package/src/network/WebSocketServer.ts +2 -2
- package/src/network/index.ts +1 -1
- package/src/persistence/Persistence.ts +2 -2
- package/src/persistence/StorageContainerRepository.ts +2 -2
- package/src/persistence/StorageImageRepository.ts +2 -2
- package/src/persistence/StorageSessionRepository.ts +2 -2
- package/src/persistence/index.ts +5 -7
- package/src/persistence/sqlite.ts +2 -2
- package/src/persistence/types.ts +1 -1
- package/dist/chunk-BBZV6B5R.js.map +0 -1
- package/dist/chunk-PK2K7CCJ.js.map +0 -1
- package/dist/chunk-TXESAX3X.js.map +0 -1
- package/dist/chunk-V664KD3R.js.map +0 -1
- /package/dist/{WebSocketFactory-SDWPRZVB.js.map → WebSocketFactory-W4Z4TO7K.js.map} +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createNodeWebSocket
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-SUJ5DIDM.js";
|
|
4
4
|
import "./chunk-DGUM43GV.js";
|
|
5
5
|
export {
|
|
6
6
|
createNodeWebSocket
|
|
7
7
|
};
|
|
8
|
-
//# sourceMappingURL=WebSocketFactory-
|
|
8
|
+
//# sourceMappingURL=WebSocketFactory-W4Z4TO7K.js.map
|
|
@@ -1,33 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ChannelConnection, ChannelServerOptions, SendReliableOptions, Unsubscribe, ChannelServer, MinimalHTTPServer } from '@agentxjs/core/network';
|
|
2
2
|
import { WebSocket } from 'ws';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* WebSocket Server - Manages WebSocket connections
|
|
6
|
-
*
|
|
7
|
-
* Supports:
|
|
8
|
-
* - Standalone mode (listen on port)
|
|
9
|
-
* - Attached mode (attach to existing HTTP server)
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* WebSocket Server
|
|
14
|
-
*/
|
|
15
|
-
declare class WebSocketServer implements ChannelServer {
|
|
16
|
-
private wss;
|
|
17
|
-
private connections;
|
|
18
|
-
private connectionHandlers;
|
|
19
|
-
private options;
|
|
20
|
-
private attachedToServer;
|
|
21
|
-
constructor(options?: ChannelServerOptions);
|
|
22
|
-
listen(port: number, host?: string): Promise<void>;
|
|
23
|
-
attach(server: MinimalHTTPServer, path?: string): void;
|
|
24
|
-
private handleConnection;
|
|
25
|
-
onConnection(handler: (connection: ChannelConnection) => void): Unsubscribe;
|
|
26
|
-
broadcast(message: string): void;
|
|
27
|
-
close(): Promise<void>;
|
|
28
|
-
dispose(): Promise<void>;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
4
|
/**
|
|
32
5
|
* WebSocket Connection - Server-side connection wrapper
|
|
33
6
|
*
|
|
@@ -63,4 +36,31 @@ declare class WebSocketConnection implements ChannelConnection {
|
|
|
63
36
|
close(): void;
|
|
64
37
|
}
|
|
65
38
|
|
|
66
|
-
|
|
39
|
+
/**
|
|
40
|
+
* WebSocket Server - Manages WebSocket connections
|
|
41
|
+
*
|
|
42
|
+
* Supports:
|
|
43
|
+
* - Standalone mode (listen on port)
|
|
44
|
+
* - Attached mode (attach to existing HTTP server)
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* WebSocket Server
|
|
49
|
+
*/
|
|
50
|
+
declare class WebSocketServer implements ChannelServer {
|
|
51
|
+
private wss;
|
|
52
|
+
private connections;
|
|
53
|
+
private connectionHandlers;
|
|
54
|
+
private options;
|
|
55
|
+
private attachedToServer;
|
|
56
|
+
constructor(options?: ChannelServerOptions);
|
|
57
|
+
listen(port: number, host?: string): Promise<void>;
|
|
58
|
+
attach(server: MinimalHTTPServer, path?: string): void;
|
|
59
|
+
private handleConnection;
|
|
60
|
+
onConnection(handler: (connection: ChannelConnection) => void): Unsubscribe;
|
|
61
|
+
broadcast(message: string): void;
|
|
62
|
+
close(): Promise<void>;
|
|
63
|
+
dispose(): Promise<void>;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export { WebSocketConnection as W, WebSocketServer as a };
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
// src/persistence/memory.ts
|
|
2
|
+
import { createStorage } from "unstorage";
|
|
3
|
+
function memoryDriver() {
|
|
4
|
+
return {
|
|
5
|
+
async createStorage() {
|
|
6
|
+
return createStorage();
|
|
7
|
+
}
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
|
|
1
11
|
// src/persistence/Persistence.ts
|
|
2
12
|
import { createLogger as createLogger4 } from "commonxjs/logger";
|
|
3
13
|
|
|
@@ -278,8 +288,8 @@ async function createPersistence(driver) {
|
|
|
278
288
|
}
|
|
279
289
|
|
|
280
290
|
// src/persistence/sqlite.ts
|
|
281
|
-
import { createStorage } from "unstorage";
|
|
282
291
|
import { openDatabase } from "commonxjs/sqlite";
|
|
292
|
+
import { createStorage as createStorage2 } from "unstorage";
|
|
283
293
|
function createSqliteUnstorageDriver(db) {
|
|
284
294
|
db.exec(`
|
|
285
295
|
CREATE TABLE IF NOT EXISTS kv_storage (
|
|
@@ -335,27 +345,17 @@ function sqliteDriver(options) {
|
|
|
335
345
|
async createStorage() {
|
|
336
346
|
const db = openDatabase(options.path);
|
|
337
347
|
const driver = createSqliteUnstorageDriver(db);
|
|
338
|
-
return
|
|
339
|
-
}
|
|
340
|
-
};
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
// src/persistence/memory.ts
|
|
344
|
-
import { createStorage as createStorage2 } from "unstorage";
|
|
345
|
-
function memoryDriver() {
|
|
346
|
-
return {
|
|
347
|
-
async createStorage() {
|
|
348
|
-
return createStorage2();
|
|
348
|
+
return createStorage2({ driver });
|
|
349
349
|
}
|
|
350
350
|
};
|
|
351
351
|
}
|
|
352
352
|
|
|
353
353
|
export {
|
|
354
|
+
memoryDriver,
|
|
354
355
|
StorageContainerRepository,
|
|
355
356
|
StorageImageRepository,
|
|
356
357
|
StorageSessionRepository,
|
|
357
358
|
createPersistence,
|
|
358
|
-
sqliteDriver
|
|
359
|
-
memoryDriver
|
|
359
|
+
sqliteDriver
|
|
360
360
|
};
|
|
361
|
-
//# sourceMappingURL=chunk-
|
|
361
|
+
//# sourceMappingURL=chunk-247HA6OS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/persistence/memory.ts","../src/persistence/Persistence.ts","../src/persistence/StorageContainerRepository.ts","../src/persistence/StorageImageRepository.ts","../src/persistence/StorageSessionRepository.ts","../src/persistence/sqlite.ts"],"sourcesContent":["/**\n * Memory Driver - In-memory storage\n *\n * Useful for testing and development.\n * Data is lost when the process exits.\n *\n * @example\n * ```typescript\n * import { createPersistence, memoryDriver } from \"@agentxjs/node-platform/persistence\";\n *\n * const persistence = await createPersistence(memoryDriver());\n * ```\n */\n\nimport { createStorage, type Storage } from \"unstorage\";\nimport type { PersistenceDriver } from \"./types\";\n\n/**\n * Create a memory driver\n */\nexport function memoryDriver(): PersistenceDriver {\n return {\n async createStorage(): Promise<Storage> {\n return createStorage();\n },\n };\n}\n","/**\n * Persistence - Core persistence implementation\n *\n * Creates a Persistence instance from a driver.\n * Each driver provides a createStorage() method that returns an unstorage Storage instance.\n */\n\nimport { createLogger } from \"commonxjs/logger\";\nimport type { Storage } from \"unstorage\";\nimport { StorageContainerRepository } from \"./StorageContainerRepository\";\nimport { StorageImageRepository } from \"./StorageImageRepository\";\nimport { StorageSessionRepository } from \"./StorageSessionRepository\";\nimport type { Persistence, PersistenceDriver } from \"./types\";\n\nconst logger = createLogger(\"node-platform/Persistence\");\n\n/**\n * PersistenceImpl - Internal implementation\n */\nclass PersistenceImpl implements Persistence {\n readonly containers: StorageContainerRepository;\n readonly images: StorageImageRepository;\n readonly sessions: StorageSessionRepository;\n\n constructor(storage: Storage) {\n this.containers = new StorageContainerRepository(storage);\n this.images = new StorageImageRepository(storage);\n this.sessions = new StorageSessionRepository(storage);\n }\n}\n\n/**\n * Create a Persistence instance from a driver\n *\n * @param driver - The persistence driver to use\n * @returns Promise<Persistence> instance\n *\n * @example\n * ```typescript\n * import { createPersistence, memoryDriver } from \"@agentxjs/node-platform/persistence\";\n *\n * const persistence = await createPersistence(memoryDriver());\n * ```\n */\nexport async function createPersistence(driver: PersistenceDriver): Promise<Persistence> {\n logger.debug(\"Creating persistence\");\n\n const storage = await driver.createStorage();\n const persistence = new PersistenceImpl(storage);\n\n logger.info(\"Persistence created successfully\");\n return persistence;\n}\n","/**\n * StorageContainerRepository - unstorage-based ContainerRepository\n *\n * Uses unstorage for backend-agnostic storage (Memory, Redis, SQLite, etc.)\n */\n\nimport type { ContainerRecord, ContainerRepository } from \"@agentxjs/core/persistence\";\nimport { createLogger } from \"commonxjs/logger\";\nimport type { Storage } from \"unstorage\";\n\nconst logger = createLogger(\"node-platform/ContainerRepository\");\n\n/** Key prefix for containers */\nconst PREFIX = \"containers\";\n\n/**\n * StorageContainerRepository - unstorage implementation\n */\nexport class StorageContainerRepository implements ContainerRepository {\n constructor(private readonly storage: Storage) {}\n\n private key(containerId: string): string {\n return `${PREFIX}:${containerId}`;\n }\n\n async saveContainer(record: ContainerRecord): Promise<void> {\n await this.storage.setItem(this.key(record.containerId), record);\n logger.debug(\"Container saved\", { containerId: record.containerId });\n }\n\n async findContainerById(containerId: string): Promise<ContainerRecord | null> {\n const record = await this.storage.getItem<ContainerRecord>(this.key(containerId));\n return record ?? null;\n }\n\n async findAllContainers(): Promise<ContainerRecord[]> {\n const keys = await this.storage.getKeys(PREFIX);\n const records: ContainerRecord[] = [];\n\n for (const key of keys) {\n const record = await this.storage.getItem<ContainerRecord>(key);\n if (record) {\n records.push(record);\n }\n }\n\n return records.sort((a, b) => b.createdAt - a.createdAt);\n }\n\n async deleteContainer(containerId: string): Promise<void> {\n await this.storage.removeItem(this.key(containerId));\n logger.debug(\"Container deleted\", { containerId });\n }\n\n async containerExists(containerId: string): Promise<boolean> {\n return await this.storage.hasItem(this.key(containerId));\n }\n}\n","/**\n * StorageImageRepository - unstorage-based ImageRepository\n *\n * Uses unstorage for backend-agnostic storage (Memory, Redis, SQLite, etc.)\n */\n\nimport type { ImageMetadata, ImageRecord, ImageRepository } from \"@agentxjs/core/persistence\";\nimport { createLogger } from \"commonxjs/logger\";\nimport type { Storage } from \"unstorage\";\n\nconst logger = createLogger(\"node-platform/ImageRepository\");\n\n/** Key prefix for images */\nconst PREFIX = \"images\";\n\n/** Index prefix for name lookup */\nconst INDEX_BY_NAME = \"idx:images:name\";\n\n/** Index prefix for container lookup */\nconst INDEX_BY_CONTAINER = \"idx:images:container\";\n\n/**\n * StorageImageRepository - unstorage implementation\n */\nexport class StorageImageRepository implements ImageRepository {\n constructor(private readonly storage: Storage) {}\n\n private key(imageId: string): string {\n return `${PREFIX}:${imageId}`;\n }\n\n private nameIndexKey(name: string, imageId: string): string {\n return `${INDEX_BY_NAME}:${name}:${imageId}`;\n }\n\n private containerIndexKey(containerId: string, imageId: string): string {\n return `${INDEX_BY_CONTAINER}:${containerId}:${imageId}`;\n }\n\n async saveImage(record: ImageRecord): Promise<void> {\n // Save main record\n await this.storage.setItem(this.key(record.imageId), record);\n\n // Save index for name lookup\n await this.storage.setItem(this.nameIndexKey(record.name, record.imageId), record.imageId);\n\n // Save index for container lookup\n await this.storage.setItem(\n this.containerIndexKey(record.containerId, record.imageId),\n record.imageId\n );\n\n logger.debug(\"Image saved\", { imageId: record.imageId });\n }\n\n async findImageById(imageId: string): Promise<ImageRecord | null> {\n const record = await this.storage.getItem<ImageRecord>(this.key(imageId));\n return record ?? null;\n }\n\n async findAllImages(): Promise<ImageRecord[]> {\n const keys = await this.storage.getKeys(PREFIX);\n const records: ImageRecord[] = [];\n\n for (const key of keys) {\n // Skip index keys\n if (key.startsWith(\"idx:\")) continue;\n\n const record = await this.storage.getItem<ImageRecord>(key);\n if (record) {\n records.push(record);\n }\n }\n\n return records.sort((a, b) => b.createdAt - a.createdAt);\n }\n\n async findImagesByName(name: string): Promise<ImageRecord[]> {\n const indexPrefix = `${INDEX_BY_NAME}:${name}`;\n const keys = await this.storage.getKeys(indexPrefix);\n const records: ImageRecord[] = [];\n\n for (const key of keys) {\n const imageId = await this.storage.getItem<string>(key);\n if (imageId) {\n const record = await this.findImageById(imageId);\n if (record) {\n records.push(record);\n }\n }\n }\n\n return records.sort((a, b) => b.createdAt - a.createdAt);\n }\n\n async findImagesByContainerId(containerId: string): Promise<ImageRecord[]> {\n const indexPrefix = `${INDEX_BY_CONTAINER}:${containerId}`;\n const keys = await this.storage.getKeys(indexPrefix);\n const records: ImageRecord[] = [];\n\n for (const key of keys) {\n const imageId = await this.storage.getItem<string>(key);\n if (imageId) {\n const record = await this.findImageById(imageId);\n if (record) {\n records.push(record);\n }\n }\n }\n\n return records.sort((a, b) => b.createdAt - a.createdAt);\n }\n\n async deleteImage(imageId: string): Promise<void> {\n // Get record to find name and containerId for index cleanup\n const record = await this.findImageById(imageId);\n\n // Delete main record\n await this.storage.removeItem(this.key(imageId));\n\n // Delete indexes\n if (record) {\n await this.storage.removeItem(this.nameIndexKey(record.name, imageId));\n await this.storage.removeItem(this.containerIndexKey(record.containerId, imageId));\n }\n\n logger.debug(\"Image deleted\", { imageId });\n }\n\n async imageExists(imageId: string): Promise<boolean> {\n return await this.storage.hasItem(this.key(imageId));\n }\n\n async updateMetadata(imageId: string, metadata: Partial<ImageMetadata>): Promise<void> {\n const record = await this.findImageById(imageId);\n if (!record) {\n throw new Error(`Image not found: ${imageId}`);\n }\n\n // Merge metadata\n const updatedRecord: ImageRecord = {\n ...record,\n metadata: {\n ...record.metadata,\n ...metadata,\n },\n updatedAt: Date.now(),\n };\n\n await this.storage.setItem(this.key(imageId), updatedRecord);\n logger.debug(\"Image metadata updated\", { imageId, metadata });\n }\n}\n","/**\n * StorageSessionRepository - unstorage-based SessionRepository\n *\n * Uses unstorage for backend-agnostic storage (Memory, Redis, SQLite, etc.)\n */\n\nimport type { Message } from \"@agentxjs/core/agent\";\nimport type { SessionRecord, SessionRepository } from \"@agentxjs/core/persistence\";\nimport { createLogger } from \"commonxjs/logger\";\nimport type { Storage } from \"unstorage\";\n\nconst logger = createLogger(\"node-platform/SessionRepository\");\n\n/** Key prefix for sessions */\nconst PREFIX = \"sessions\";\n\n/** Key prefix for messages */\nconst MESSAGES_PREFIX = \"messages\";\n\n/** Index prefix for image lookup */\nconst INDEX_BY_IMAGE = \"idx:sessions:image\";\n\n/** Index prefix for container lookup */\nconst INDEX_BY_CONTAINER = \"idx:sessions:container\";\n\n/**\n * StorageSessionRepository - unstorage implementation\n */\nexport class StorageSessionRepository implements SessionRepository {\n constructor(private readonly storage: Storage) {}\n\n private key(sessionId: string): string {\n return `${PREFIX}:${sessionId}`;\n }\n\n private messagesKey(sessionId: string): string {\n return `${MESSAGES_PREFIX}:${sessionId}`;\n }\n\n private imageIndexKey(imageId: string, sessionId: string): string {\n return `${INDEX_BY_IMAGE}:${imageId}:${sessionId}`;\n }\n\n private containerIndexKey(containerId: string, sessionId: string): string {\n return `${INDEX_BY_CONTAINER}:${containerId}:${sessionId}`;\n }\n\n async saveSession(record: SessionRecord): Promise<void> {\n // Save main record\n await this.storage.setItem(this.key(record.sessionId), record);\n\n // Save index for image lookup\n await this.storage.setItem(\n this.imageIndexKey(record.imageId, record.sessionId),\n record.sessionId\n );\n\n // Save index for container lookup\n await this.storage.setItem(\n this.containerIndexKey(record.containerId, record.sessionId),\n record.sessionId\n );\n\n logger.debug(\"Session saved\", { sessionId: record.sessionId });\n }\n\n async findSessionById(sessionId: string): Promise<SessionRecord | null> {\n const record = await this.storage.getItem<SessionRecord>(this.key(sessionId));\n return record ?? null;\n }\n\n async findSessionByImageId(imageId: string): Promise<SessionRecord | null> {\n const indexPrefix = `${INDEX_BY_IMAGE}:${imageId}`;\n const keys = await this.storage.getKeys(indexPrefix);\n\n if (keys.length === 0) return null;\n\n // Return the first (most recent) session for this image\n const sessionId = await this.storage.getItem<string>(keys[0]);\n if (!sessionId) return null;\n\n return this.findSessionById(sessionId);\n }\n\n async findSessionsByContainerId(containerId: string): Promise<SessionRecord[]> {\n const indexPrefix = `${INDEX_BY_CONTAINER}:${containerId}`;\n const keys = await this.storage.getKeys(indexPrefix);\n const records: SessionRecord[] = [];\n\n for (const key of keys) {\n const sessionId = await this.storage.getItem<string>(key);\n if (sessionId) {\n const record = await this.findSessionById(sessionId);\n if (record) {\n records.push(record);\n }\n }\n }\n\n return records.sort((a, b) => b.createdAt - a.createdAt);\n }\n\n async findAllSessions(): Promise<SessionRecord[]> {\n const keys = await this.storage.getKeys(PREFIX);\n const records: SessionRecord[] = [];\n\n for (const key of keys) {\n // Skip index keys\n if (key.startsWith(\"idx:\")) continue;\n\n const record = await this.storage.getItem<SessionRecord>(key);\n if (record) {\n records.push(record);\n }\n }\n\n return records.sort((a, b) => b.createdAt - a.createdAt);\n }\n\n async deleteSession(sessionId: string): Promise<void> {\n // Get record for index cleanup\n const record = await this.findSessionById(sessionId);\n\n // Delete main record\n await this.storage.removeItem(this.key(sessionId));\n\n // Delete messages\n await this.storage.removeItem(this.messagesKey(sessionId));\n\n // Delete indexes\n if (record) {\n await this.storage.removeItem(this.imageIndexKey(record.imageId, sessionId));\n await this.storage.removeItem(this.containerIndexKey(record.containerId, sessionId));\n }\n\n logger.debug(\"Session deleted\", { sessionId });\n }\n\n async sessionExists(sessionId: string): Promise<boolean> {\n return await this.storage.hasItem(this.key(sessionId));\n }\n\n // ==================== Message Operations ====================\n\n async addMessage(sessionId: string, message: Message): Promise<void> {\n const messages = await this.getMessages(sessionId);\n messages.push(message);\n await this.storage.setItem(this.messagesKey(sessionId), messages);\n logger.debug(\"Message added to session\", { sessionId, subtype: message.subtype });\n }\n\n async getMessages(sessionId: string): Promise<Message[]> {\n const messages = await this.storage.getItem<Message[]>(this.messagesKey(sessionId));\n // Ensure we always return an array (handle corrupted data)\n if (!messages || !Array.isArray(messages)) {\n if (messages) {\n logger.warn(\"Messages data is not an array, resetting\", {\n sessionId,\n type: typeof messages,\n });\n }\n return [];\n }\n return messages;\n }\n\n async clearMessages(sessionId: string): Promise<void> {\n await this.storage.removeItem(this.messagesKey(sessionId));\n logger.debug(\"Messages cleared for session\", { sessionId });\n }\n}\n","/**\n * SQLite Driver - SQLite database storage\n *\n * Uses commonxjs SQLite abstraction with automatic runtime detection:\n * - Bun: uses bun:sqlite (built-in)\n * - Node.js 22+: uses node:sqlite (built-in)\n *\n * @example\n * ```typescript\n * import { createPersistence, sqliteDriver } from \"@agentxjs/node-platform/persistence\";\n *\n * const persistence = await createPersistence(\n * sqliteDriver({ path: \"./data/agentx.db\" })\n * );\n * ```\n */\n\nimport { type Database, openDatabase } from \"commonxjs/sqlite\";\nimport { createStorage, type Driver, type Storage } from \"unstorage\";\nimport type { PersistenceDriver } from \"./types\";\n\nexport interface SqliteDriverOptions {\n /**\n * Path to SQLite database file\n * @example \"./data/agentx.db\"\n */\n path: string;\n}\n\n/**\n * Create a custom unstorage driver using our SQLite abstraction\n */\nfunction createSqliteUnstorageDriver(db: Database): Driver {\n // Initialize schema\n db.exec(`\n CREATE TABLE IF NOT EXISTS kv_storage (\n key TEXT PRIMARY KEY,\n value TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL\n );\n CREATE INDEX IF NOT EXISTS idx_kv_key ON kv_storage(key);\n `);\n\n return {\n name: \"agentx-sqlite\",\n\n hasItem(key: string): boolean {\n const row = db.prepare(\"SELECT 1 FROM kv_storage WHERE key = ?\").get(key);\n // Note: row can be null (not found) or object (found)\n // Must use != null to handle both null and undefined\n return row != null;\n },\n\n getItem(key: string): string | null {\n const row = db.prepare(\"SELECT value FROM kv_storage WHERE key = ?\").get(key) as\n | { value: string }\n | undefined;\n return row?.value ?? null;\n },\n\n setItem(key: string, value: string): void {\n const now = Date.now();\n const existing = db.prepare(\"SELECT 1 FROM kv_storage WHERE key = ?\").get(key);\n if (existing) {\n db.prepare(\"UPDATE kv_storage SET value = ?, updated_at = ? WHERE key = ?\").run(\n value,\n now,\n key\n );\n } else {\n db.prepare(\n \"INSERT INTO kv_storage (key, value, created_at, updated_at) VALUES (?, ?, ?, ?)\"\n ).run(key, value, now, now);\n }\n },\n\n removeItem(key: string): void {\n db.prepare(\"DELETE FROM kv_storage WHERE key = ?\").run(key);\n },\n\n getKeys(): string[] {\n const rows = db.prepare(\"SELECT key FROM kv_storage\").all() as { key: string }[];\n return rows.map((r) => r.key);\n },\n\n clear(): void {\n db.exec(\"DELETE FROM kv_storage\");\n },\n\n dispose(): void {\n db.close();\n },\n };\n}\n\n/**\n * Create a SQLite driver\n *\n * @param options - Driver options\n */\nexport function sqliteDriver(options: SqliteDriverOptions): PersistenceDriver {\n return {\n async createStorage(): Promise<Storage> {\n const db = openDatabase(options.path);\n const driver = createSqliteUnstorageDriver(db);\n\n return createStorage({ driver });\n },\n };\n}\n"],"mappings":"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","names":["createLogger","createLogger","logger","PREFIX","createLogger","logger","PREFIX","INDEX_BY_CONTAINER","logger","createLogger","createStorage"]}
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
// src/mq/SqliteMessageQueue.ts
|
|
2
|
-
import { Subject } from "rxjs";
|
|
3
|
-
import { filter } from "rxjs/operators";
|
|
4
|
-
import { createLogger } from "commonxjs/logger";
|
|
5
|
-
import { openDatabase } from "commonxjs/sqlite";
|
|
6
|
-
|
|
7
1
|
// src/mq/OffsetGenerator.ts
|
|
8
2
|
var OffsetGenerator = class {
|
|
9
3
|
lastTimestamp = 0;
|
|
@@ -32,11 +26,15 @@ var OffsetGenerator = class {
|
|
|
32
26
|
const [bTime, bSeq] = b.split("-");
|
|
33
27
|
const timeDiff = parseInt(aTime, 36) - parseInt(bTime, 36);
|
|
34
28
|
if (timeDiff !== 0) return timeDiff;
|
|
35
|
-
return parseInt(aSeq) - parseInt(bSeq);
|
|
29
|
+
return parseInt(aSeq, 10) - parseInt(bSeq, 10);
|
|
36
30
|
}
|
|
37
31
|
};
|
|
38
32
|
|
|
39
33
|
// src/mq/SqliteMessageQueue.ts
|
|
34
|
+
import { createLogger } from "commonxjs/logger";
|
|
35
|
+
import { openDatabase } from "commonxjs/sqlite";
|
|
36
|
+
import { Subject } from "rxjs";
|
|
37
|
+
import { filter } from "rxjs/operators";
|
|
40
38
|
var logger = createLogger("node-platform/SqliteMessageQueue");
|
|
41
39
|
var SqliteMessageQueue = class _SqliteMessageQueue {
|
|
42
40
|
subject = new Subject();
|
|
@@ -210,4 +208,4 @@ export {
|
|
|
210
208
|
OffsetGenerator,
|
|
211
209
|
SqliteMessageQueue
|
|
212
210
|
};
|
|
213
|
-
//# sourceMappingURL=chunk-
|
|
211
|
+
//# sourceMappingURL=chunk-ABWPBGQW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/mq/OffsetGenerator.ts","../src/mq/SqliteMessageQueue.ts"],"sourcesContent":["/**\n * OffsetGenerator - Generates monotonically increasing offsets\n *\n * Format: \"{timestamp_base36}-{sequence_padded}\"\n * Example: \"lq5x4g2-0001\"\n *\n * This format ensures:\n * - Lexicographic ordering matches temporal ordering\n * - Multiple events in same millisecond get unique offsets\n * - Human-readable and compact\n */\nexport class OffsetGenerator {\n private lastTimestamp = 0;\n private sequence = 0;\n\n /**\n * Generate a new offset\n */\n generate(): string {\n const now = Date.now();\n\n if (now === this.lastTimestamp) {\n this.sequence++;\n } else {\n this.lastTimestamp = now;\n this.sequence = 0;\n }\n\n const timestampPart = now.toString(36);\n const sequencePart = this.sequence.toString().padStart(4, \"0\");\n\n return `${timestampPart}-${sequencePart}`;\n }\n\n /**\n * Compare two offsets\n * @returns negative if a < b, 0 if a == b, positive if a > b\n */\n static compare(a: string, b: string): number {\n const [aTime, aSeq] = a.split(\"-\");\n const [bTime, bSeq] = b.split(\"-\");\n\n const timeDiff = parseInt(aTime, 36) - parseInt(bTime, 36);\n if (timeDiff !== 0) return timeDiff;\n\n return parseInt(aSeq, 10) - parseInt(bSeq, 10);\n }\n}\n","/**\n * SqliteMessageQueue - RxJS-based message queue with SQLite persistence\n *\n * - In-memory pub/sub using RxJS Subject (real-time)\n * - SQLite persistence for recovery guarantee\n * - Consumer offset tracking for at-least-once delivery\n */\n\nimport type { MessageQueue, QueueConfig, QueueEntry, Unsubscribe } from \"@agentxjs/core/mq\";\nimport { createLogger } from \"commonxjs/logger\";\nimport { type Database, openDatabase } from \"commonxjs/sqlite\";\nimport { Subject } from \"rxjs\";\nimport { filter } from \"rxjs/operators\";\nimport { OffsetGenerator } from \"./OffsetGenerator\";\n\nconst logger = createLogger(\"node-platform/SqliteMessageQueue\");\n\ninterface ResolvedConfig {\n path: string;\n retentionMs: number;\n cleanupIntervalMs: number;\n}\n\n/**\n * SqliteMessageQueue implementation\n */\nexport class SqliteMessageQueue implements MessageQueue {\n private readonly subject = new Subject<QueueEntry>();\n private readonly offsetGen = new OffsetGenerator();\n private readonly config: ResolvedConfig;\n private readonly db: Database;\n private cleanupTimer?: ReturnType<typeof setInterval>;\n private isClosed = false;\n\n private constructor(db: Database, config: ResolvedConfig) {\n this.db = db;\n this.config = config;\n\n if (this.config.cleanupIntervalMs > 0) {\n this.cleanupTimer = setInterval(() => {\n this.cleanup();\n }, this.config.cleanupIntervalMs);\n }\n }\n\n /**\n * Create a new SqliteMessageQueue instance\n */\n static create(path: string, config?: QueueConfig): SqliteMessageQueue {\n const resolvedConfig: ResolvedConfig = {\n path,\n retentionMs: config?.retentionMs ?? 86400000, // 24 hours\n cleanupIntervalMs: 300000, // 5 minutes\n };\n\n const db = openDatabase(resolvedConfig.path);\n initializeSchema(db);\n\n logger.info(\"SqliteMessageQueue created\", { path: resolvedConfig.path });\n return new SqliteMessageQueue(db, resolvedConfig);\n }\n\n async publish(topic: string, event: unknown): Promise<string> {\n if (this.isClosed) {\n logger.warn(\"Attempted to publish to closed queue\", { topic });\n return \"\";\n }\n\n const offset = this.offsetGen.generate();\n const timestamp = Date.now();\n\n const entry: QueueEntry = {\n offset,\n topic,\n event,\n timestamp,\n };\n\n // 1. Persist to SQLite (sync, fast)\n try {\n const eventJson = JSON.stringify(entry.event);\n this.db\n .prepare(\"INSERT INTO queue_entries (offset, topic, event, timestamp) VALUES (?, ?, ?, ?)\")\n .run(entry.offset, entry.topic, eventJson, entry.timestamp);\n } catch (err) {\n logger.error(\"Failed to persist entry\", {\n offset: entry.offset,\n topic: entry.topic,\n error: (err as Error).message,\n });\n }\n\n // 2. Broadcast to subscribers (in-memory)\n this.subject.next(entry);\n\n return offset;\n }\n\n subscribe(topic: string, handler: (entry: QueueEntry) => void): Unsubscribe {\n const subscription = this.subject.pipe(filter((entry) => entry.topic === topic)).subscribe({\n next: (entry) => {\n try {\n handler(entry);\n } catch (err) {\n logger.error(\"Subscriber handler error\", {\n topic,\n offset: entry.offset,\n error: (err as Error).message,\n });\n }\n },\n });\n\n logger.debug(\"Subscribed to topic\", { topic });\n\n return () => {\n subscription.unsubscribe();\n logger.debug(\"Unsubscribed from topic\", { topic });\n };\n }\n\n async ack(consumerId: string, topic: string, offset: string): Promise<void> {\n const now = Date.now();\n\n // Check if consumer exists\n const existing = this.db\n .prepare(\"SELECT 1 FROM queue_consumers WHERE consumer_id = ? AND topic = ?\")\n .get(consumerId, topic);\n\n if (existing) {\n this.db\n .prepare(\n \"UPDATE queue_consumers SET offset = ?, updated_at = ? WHERE consumer_id = ? AND topic = ?\"\n )\n .run(offset, now, consumerId, topic);\n } else {\n this.db\n .prepare(\n \"INSERT INTO queue_consumers (consumer_id, topic, offset, updated_at) VALUES (?, ?, ?, ?)\"\n )\n .run(consumerId, topic, offset, now);\n }\n\n logger.debug(\"Consumer acknowledged\", { consumerId, topic, offset });\n }\n\n async getOffset(consumerId: string, topic: string): Promise<string | null> {\n const row = this.db\n .prepare(\"SELECT offset FROM queue_consumers WHERE consumer_id = ? AND topic = ?\")\n .get(consumerId, topic) as { offset: string } | undefined;\n\n return row?.offset ?? null;\n }\n\n async recover(topic: string, afterOffset?: string, limit: number = 1000): Promise<QueueEntry[]> {\n let rows: { offset: string; topic: string; event: string; timestamp: number }[];\n\n if (afterOffset) {\n rows = this.db\n .prepare(\n \"SELECT offset, topic, event, timestamp FROM queue_entries WHERE topic = ? AND offset > ? ORDER BY offset ASC LIMIT ?\"\n )\n .all(topic, afterOffset, limit) as typeof rows;\n } else {\n rows = this.db\n .prepare(\n \"SELECT offset, topic, event, timestamp FROM queue_entries WHERE topic = ? ORDER BY offset ASC LIMIT ?\"\n )\n .all(topic, limit) as typeof rows;\n }\n\n return rows.map((row) => ({\n offset: row.offset,\n topic: row.topic,\n event: JSON.parse(row.event),\n timestamp: row.timestamp,\n }));\n }\n\n async close(): Promise<void> {\n if (this.isClosed) return;\n this.isClosed = true;\n\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer);\n }\n this.subject.complete();\n this.db.close();\n logger.info(\"SqliteMessageQueue closed\");\n }\n\n /**\n * Cleanup old entries based on retention policy\n */\n private cleanup(): void {\n try {\n const cutoff = Date.now() - this.config.retentionMs;\n const result = this.db.prepare(\"DELETE FROM queue_entries WHERE timestamp < ?\").run(cutoff);\n\n if (result.changes > 0) {\n logger.debug(\"Cleaned up old entries\", {\n count: result.changes,\n retentionMs: this.config.retentionMs,\n });\n }\n } catch (err) {\n logger.error(\"Cleanup failed\", { error: (err as Error).message });\n }\n }\n}\n\n/**\n * Initialize database schema\n */\nfunction initializeSchema(db: Database): void {\n db.exec(`\n PRAGMA journal_mode=WAL;\n\n CREATE TABLE IF NOT EXISTS queue_entries (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n offset TEXT NOT NULL UNIQUE,\n topic TEXT NOT NULL,\n event TEXT NOT NULL,\n timestamp INTEGER NOT NULL\n );\n\n CREATE INDEX IF NOT EXISTS idx_queue_topic_offset ON queue_entries(topic, offset);\n CREATE INDEX IF NOT EXISTS idx_queue_timestamp ON queue_entries(timestamp);\n\n CREATE TABLE IF NOT EXISTS queue_consumers (\n consumer_id TEXT NOT NULL,\n topic TEXT NOT NULL,\n offset TEXT NOT NULL,\n updated_at INTEGER NOT NULL,\n PRIMARY KEY (consumer_id, topic)\n );\n `);\n\n logger.debug(\"Queue database schema initialized\");\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/network/WebSocketFactory.ts"],"sourcesContent":["/**\n * Node.js channel client factory using the ws library\n *\n * Provides ChannelClientFactory implementation for @agentxjs/core RpcClient.\n * Browser environments use native WebSocket (the default in RpcClient).\n */\n\nimport type { ChannelClientFactory } from \"@agentxjs/core/network\";\n\n/**\n * Create a WebSocket instance using the ws library (Node.js)\n */\nexport const createNodeWebSocket: ChannelClientFactory = (url: string): WebSocket => {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { default: WS } = require(\"ws\");\n return new WS(url) as unknown as WebSocket;\n};\n"],"mappings":";;;;;AAYO,IAAM,sBAA4C,CAAC,QAA2B;AAEnF,QAAM,EAAE,SAAS,GAAG,IAAI,UAAQ,IAAI;AACpC,SAAO,IAAI,GAAG,GAAG;AACnB;","names":[]}
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
// src/network/WebSocketServer.ts
|
|
2
|
-
import { createLogger as createLogger2 } from "commonxjs/logger";
|
|
3
|
-
|
|
4
1
|
// src/network/WebSocketConnection.ts
|
|
5
2
|
import { isAckMessage } from "@agentxjs/core/network";
|
|
6
3
|
import { createLogger } from "commonxjs/logger";
|
|
@@ -149,6 +146,7 @@ var WebSocketConnection = class {
|
|
|
149
146
|
};
|
|
150
147
|
|
|
151
148
|
// src/network/WebSocketServer.ts
|
|
149
|
+
import { createLogger as createLogger2 } from "commonxjs/logger";
|
|
152
150
|
var logger2 = createLogger2("node-platform/WebSocketServer");
|
|
153
151
|
var WebSocketServer = class {
|
|
154
152
|
wss = null;
|
|
@@ -261,4 +259,4 @@ export {
|
|
|
261
259
|
WebSocketConnection,
|
|
262
260
|
WebSocketServer
|
|
263
261
|
};
|
|
264
|
-
//# sourceMappingURL=chunk-
|
|
262
|
+
//# sourceMappingURL=chunk-VVNULOYS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/network/WebSocketConnection.ts","../src/network/WebSocketServer.ts"],"sourcesContent":["/**\n * WebSocket Connection - Server-side connection wrapper\n *\n * Handles:\n * - Heartbeat (ping/pong)\n * - Reliable message delivery with ACK\n * - Message routing\n */\n\nimport type {\n ChannelConnection,\n ChannelServerOptions,\n SendReliableOptions,\n Unsubscribe,\n} from \"@agentxjs/core/network\";\nimport { isAckMessage, type ReliableWrapper } from \"@agentxjs/core/network\";\nimport { createLogger } from \"commonxjs/logger\";\nimport type { WebSocket as WS } from \"ws\";\n\nconst logger = createLogger(\"node-platform/WebSocketConnection\");\n\n/**\n * WebSocket connection implementation\n */\nexport class WebSocketConnection implements ChannelConnection {\n public readonly id: string;\n private ws: WS;\n private messageHandlers = new Set<(message: string) => void>();\n private closeHandlers = new Set<() => void>();\n private errorHandlers = new Set<(error: Error) => void>();\n private heartbeatInterval?: ReturnType<typeof setInterval>;\n private isAlive = true;\n private pendingAcks = new Map<\n string,\n { resolve: () => void; timer: ReturnType<typeof setTimeout> }\n >();\n private msgIdCounter = 0;\n\n constructor(ws: WS, options: ChannelServerOptions) {\n this.ws = ws;\n this.id = `conn_${Date.now()}_${Math.random().toString(36).substring(2, 8)}`;\n\n this.setupHeartbeat(options);\n this.setupMessageHandler();\n this.setupCloseHandler();\n this.setupErrorHandler();\n }\n\n private setupHeartbeat(options: ChannelServerOptions): void {\n if (options.heartbeat === false) return;\n\n const interval = options.heartbeatInterval || 30000;\n\n this.ws.on(\"pong\", () => {\n this.isAlive = true;\n logger.debug(\"Heartbeat pong received\", { id: this.id });\n });\n\n this.heartbeatInterval = setInterval(() => {\n if (!this.isAlive) {\n logger.warn(\"Client heartbeat timeout, terminating connection\", { id: this.id });\n clearInterval(this.heartbeatInterval);\n this.ws.terminate();\n return;\n }\n this.isAlive = false;\n this.ws.ping();\n logger.debug(\"Heartbeat ping sent\", { id: this.id });\n }, interval);\n }\n\n private setupMessageHandler(): void {\n this.ws.on(\"message\", (data: Buffer) => {\n const message = data.toString();\n\n // Try to parse as JSON to check for ACK messages\n try {\n const parsed = JSON.parse(message);\n\n // Handle ACK response from client\n if (isAckMessage(parsed)) {\n const pending = this.pendingAcks.get(parsed.__ack);\n if (pending) {\n clearTimeout(pending.timer);\n pending.resolve();\n this.pendingAcks.delete(parsed.__ack);\n logger.debug(\"ACK received\", { msgId: parsed.__ack, connectionId: this.id });\n }\n return; // Don't pass ACK messages to application layer\n }\n } catch {\n // Not JSON, pass through as normal message\n }\n\n // Pass message to handlers\n for (const handler of this.messageHandlers) {\n handler(message);\n }\n });\n }\n\n private setupCloseHandler(): void {\n this.ws.on(\"close\", () => {\n if (this.heartbeatInterval) {\n clearInterval(this.heartbeatInterval);\n }\n for (const handler of this.closeHandlers) {\n handler();\n }\n });\n }\n\n private setupErrorHandler(): void {\n this.ws.on(\"error\", (err: Error) => {\n if (this.heartbeatInterval) {\n clearInterval(this.heartbeatInterval);\n }\n for (const handler of this.errorHandlers) {\n handler(err);\n }\n });\n }\n\n send(message: string): void {\n if (this.ws.readyState === 1) {\n // WebSocket.OPEN\n this.ws.send(message);\n }\n }\n\n sendReliable(message: string, options?: SendReliableOptions): void {\n if (this.ws.readyState !== 1) {\n // WebSocket not open, trigger timeout immediately if callback provided\n options?.onTimeout?.();\n return;\n }\n\n // If no ACK callback needed, just send normally\n if (!options?.onAck) {\n this.send(message);\n return;\n }\n\n // Generate unique message ID\n const msgId = `${this.id}_${++this.msgIdCounter}`;\n\n // Wrap message with msgId\n const wrapped: ReliableWrapper = {\n __msgId: msgId,\n __payload: message,\n };\n\n // Set up timeout\n const timeout = options.timeout ?? 5000;\n const timer = setTimeout(() => {\n if (this.pendingAcks.has(msgId)) {\n this.pendingAcks.delete(msgId);\n logger.warn(\"ACK timeout\", { msgId, connectionId: this.id, timeout });\n options.onTimeout?.();\n }\n }, timeout);\n\n // Store pending ACK\n this.pendingAcks.set(msgId, {\n resolve: options.onAck,\n timer,\n });\n\n // Send wrapped message\n this.ws.send(JSON.stringify(wrapped));\n logger.debug(\"Sent reliable message\", { msgId, connectionId: this.id });\n }\n\n onMessage(handler: (message: string) => void): Unsubscribe {\n this.messageHandlers.add(handler);\n return () => {\n this.messageHandlers.delete(handler);\n };\n }\n\n onClose(handler: () => void): Unsubscribe {\n this.closeHandlers.add(handler);\n return () => {\n this.closeHandlers.delete(handler);\n };\n }\n\n onError(handler: (error: Error) => void): Unsubscribe {\n this.errorHandlers.add(handler);\n return () => {\n this.errorHandlers.delete(handler);\n };\n }\n\n close(): void {\n if (this.heartbeatInterval) {\n clearInterval(this.heartbeatInterval);\n }\n // Clean up pending ACKs\n for (const pending of this.pendingAcks.values()) {\n clearTimeout(pending.timer);\n }\n this.pendingAcks.clear();\n this.ws.close();\n }\n}\n","/**\n * WebSocket Server - Manages WebSocket connections\n *\n * Supports:\n * - Standalone mode (listen on port)\n * - Attached mode (attach to existing HTTP server)\n */\n\nimport type {\n ChannelConnection,\n ChannelServer,\n ChannelServerOptions,\n MinimalHTTPServer,\n Unsubscribe,\n} from \"@agentxjs/core/network\";\nimport { createLogger } from \"commonxjs/logger\";\nimport type { WebSocket as WS, WebSocketServer as WSS } from \"ws\";\nimport { WebSocketConnection } from \"./WebSocketConnection\";\n\nconst logger = createLogger(\"node-platform/WebSocketServer\");\n\n/**\n * WebSocket Server\n */\nexport class WebSocketServer implements ChannelServer {\n private wss: WSS | null = null;\n private connections = new Set<WebSocketConnection>();\n private connectionHandlers = new Set<(connection: ChannelConnection) => void>();\n private options: ChannelServerOptions;\n private attachedToServer = false;\n\n constructor(options: ChannelServerOptions = {}) {\n this.options = options;\n }\n\n async listen(port: number, host: string = \"0.0.0.0\"): Promise<void> {\n if (this.wss) {\n throw new Error(\"Server already listening\");\n }\n if (this.attachedToServer) {\n throw new Error(\n \"Cannot listen when attached to existing server. The server should call listen() instead.\"\n );\n }\n\n const { WebSocketServer: WSS } = await import(\"ws\");\n this.wss = new WSS({ port, host });\n\n this.wss.on(\"connection\", (ws: WS) => {\n this.handleConnection(ws);\n });\n\n logger.info(\"WebSocket server listening\", { port, host });\n }\n\n attach(server: MinimalHTTPServer, path: string = \"/ws\"): void {\n if (this.wss) {\n throw new Error(\"Server already initialized\");\n }\n\n import(\"ws\").then(({ WebSocketServer: WSS }) => {\n this.wss = new WSS({ noServer: true });\n\n // Handle WebSocket upgrade on the HTTP server\n server.on(\"upgrade\", (request, socket, head) => {\n const url = new URL(\n (request as { url?: string }).url || \"\",\n `http://${(request as { headers: { host?: string } }).headers.host}`\n );\n if (url.pathname === path) {\n this.wss!.handleUpgrade(request as never, socket as never, head as never, (ws: WS) => {\n this.wss!.emit(\"connection\", ws, request);\n });\n } else {\n (socket as { destroy: () => void }).destroy();\n }\n });\n\n this.wss.on(\"connection\", (ws: WS) => {\n this.handleConnection(ws);\n });\n\n this.attachedToServer = true;\n logger.info(\"WebSocket attached to existing HTTP server\", { path });\n });\n }\n\n private handleConnection(ws: WS): void {\n const connection = new WebSocketConnection(ws, this.options);\n this.connections.add(connection);\n\n logger.info(\"Client connected\", {\n connectionId: connection.id,\n totalConnections: this.connections.size,\n });\n\n connection.onClose(() => {\n this.connections.delete(connection);\n\n logger.info(\"Client disconnected\", {\n connectionId: connection.id,\n totalConnections: this.connections.size,\n });\n });\n\n // Notify handlers\n for (const handler of this.connectionHandlers) {\n handler(connection);\n }\n }\n\n onConnection(handler: (connection: ChannelConnection) => void): Unsubscribe {\n this.connectionHandlers.add(handler);\n return () => {\n this.connectionHandlers.delete(handler);\n };\n }\n\n broadcast(message: string): void {\n for (const connection of this.connections) {\n connection.send(message);\n }\n }\n\n async close(): Promise<void> {\n if (!this.wss) return;\n\n for (const connection of this.connections) {\n connection.close();\n }\n this.connections.clear();\n\n // Don't close the server if attached to existing HTTP server\n if (!this.attachedToServer) {\n await new Promise<void>((resolve) => {\n // Add timeout to prevent hanging\n const timeout = setTimeout(() => {\n logger.warn(\"WebSocket server close timeout, forcing close\");\n resolve();\n }, 1000);\n\n this.wss!.close(() => {\n clearTimeout(timeout);\n resolve();\n });\n });\n }\n this.wss = null;\n logger.info(\"WebSocket server closed\");\n }\n\n async dispose(): Promise<void> {\n await this.close();\n this.connectionHandlers.clear();\n }\n}\n"],"mappings":"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","names":["createLogger","logger","createLogger"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { AgentXPlatform } from '@agentxjs/core/runtime';
|
|
2
2
|
import { LoggerFactory, LogLevel, Logger } from 'commonxjs/logger';
|
|
3
|
-
export { Persistence, PersistenceDriver, SqliteDriverOptions, StorageContainerRepository, StorageImageRepository, StorageSessionRepository, createPersistence, memoryDriver, sqliteDriver } from './persistence/index.js';
|
|
4
3
|
import { BashProvider, BashOptions, BashResult } from '@agentxjs/core/bash';
|
|
5
4
|
export { OffsetGenerator, SqliteMessageQueue } from './mq/index.js';
|
|
6
|
-
export {
|
|
7
|
-
|
|
8
|
-
import '@agentxjs/core/persistence';
|
|
9
|
-
import '@agentxjs/core/agent';
|
|
5
|
+
export { W as WebSocketConnection, a as WebSocketServer } from './WebSocketServer-CbjDC1lS.js';
|
|
6
|
+
export { Persistence, PersistenceDriver, SqliteDriverOptions, StorageContainerRepository, StorageImageRepository, StorageSessionRepository, createPersistence, memoryDriver, sqliteDriver } from './persistence/index.js';
|
|
10
7
|
import '@agentxjs/core/mq';
|
|
11
8
|
import '@agentxjs/core/network';
|
|
12
9
|
import 'ws';
|
|
10
|
+
import '@agentxjs/core/persistence';
|
|
11
|
+
import 'unstorage';
|
|
12
|
+
import '@agentxjs/core/agent';
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* NodeBashProvider - Node.js implementation of BashProvider
|
package/dist/index.js
CHANGED
|
@@ -5,25 +5,26 @@ import {
|
|
|
5
5
|
createPersistence,
|
|
6
6
|
memoryDriver,
|
|
7
7
|
sqliteDriver
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-247HA6OS.js";
|
|
9
9
|
import {
|
|
10
10
|
OffsetGenerator,
|
|
11
11
|
SqliteMessageQueue
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-ABWPBGQW.js";
|
|
13
13
|
import {
|
|
14
14
|
WebSocketConnection,
|
|
15
15
|
WebSocketServer
|
|
16
|
-
} from "./chunk-
|
|
17
|
-
import "./chunk-
|
|
16
|
+
} from "./chunk-VVNULOYS.js";
|
|
17
|
+
import "./chunk-SUJ5DIDM.js";
|
|
18
18
|
import "./chunk-DGUM43GV.js";
|
|
19
19
|
|
|
20
20
|
// src/index.ts
|
|
21
|
-
import {
|
|
21
|
+
import { join as join2 } from "path";
|
|
22
22
|
import { EventBusImpl } from "@agentxjs/core/event";
|
|
23
|
+
import { ConsoleLogger, setLoggerFactory } from "commonxjs/logger";
|
|
23
24
|
|
|
24
25
|
// src/bash/NodeBashProvider.ts
|
|
25
|
-
import { execa } from "execa";
|
|
26
26
|
import { createLogger } from "commonxjs/logger";
|
|
27
|
+
import { execa } from "execa";
|
|
27
28
|
var logger = createLogger("node-platform/NodeBashProvider");
|
|
28
29
|
var DEFAULT_TIMEOUT = 3e4;
|
|
29
30
|
var NodeBashProvider = class {
|
|
@@ -56,7 +57,7 @@ var NodeBashProvider = class {
|
|
|
56
57
|
};
|
|
57
58
|
|
|
58
59
|
// src/logger/FileLoggerFactory.ts
|
|
59
|
-
import { appendFileSync,
|
|
60
|
+
import { appendFileSync, existsSync, mkdirSync } from "fs";
|
|
60
61
|
import { dirname, join } from "path";
|
|
61
62
|
var FileLogger = class {
|
|
62
63
|
name;
|
|
@@ -135,7 +136,7 @@ var FileLogger = class {
|
|
|
135
136
|
parts.push(message);
|
|
136
137
|
let logLine = parts.join(" ");
|
|
137
138
|
if (context && Object.keys(context).length > 0) {
|
|
138
|
-
logLine +=
|
|
139
|
+
logLine += ` ${JSON.stringify(context)}`;
|
|
139
140
|
}
|
|
140
141
|
logLine += "\n";
|
|
141
142
|
try {
|
|
@@ -166,7 +167,6 @@ var FileLoggerFactory = class {
|
|
|
166
167
|
};
|
|
167
168
|
|
|
168
169
|
// src/index.ts
|
|
169
|
-
import { join as join2 } from "path";
|
|
170
170
|
function nodePlatform(options = {}) {
|
|
171
171
|
return {
|
|
172
172
|
__deferred: true,
|
|
@@ -190,14 +190,20 @@ async function createNodePlatform(options = {}) {
|
|
|
190
190
|
const persistence = await createPersistence(sqliteDriver({ path: join2(dataPath, "agentx.db") }));
|
|
191
191
|
const bashProvider = new NodeBashProvider();
|
|
192
192
|
const eventBus = new EventBusImpl();
|
|
193
|
-
const { createNodeWebSocket } = await import("./WebSocketFactory-
|
|
193
|
+
const { createNodeWebSocket } = await import("./WebSocketFactory-W4Z4TO7K.js");
|
|
194
|
+
const { WebSocketServer: WebSocketServer2 } = await import("./network/index.js");
|
|
195
|
+
const channelServer = new WebSocketServer2({
|
|
196
|
+
heartbeat: true,
|
|
197
|
+
heartbeatInterval: 3e4
|
|
198
|
+
});
|
|
194
199
|
return {
|
|
195
200
|
containerRepository: persistence.containers,
|
|
196
201
|
imageRepository: persistence.images,
|
|
197
202
|
sessionRepository: persistence.sessions,
|
|
198
203
|
eventBus,
|
|
199
204
|
bashProvider,
|
|
200
|
-
|
|
205
|
+
channelServer,
|
|
206
|
+
channelClient: createNodeWebSocket
|
|
201
207
|
};
|
|
202
208
|
}
|
|
203
209
|
function isDeferredPlatform(value) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/bash/NodeBashProvider.ts","../src/logger/FileLoggerFactory.ts"],"sourcesContent":["/**\n * @agentxjs/node-platform\n *\n * Node.js platform for AgentX.\n * Provides implementations for persistence, bash, and network.\n *\n * @example\n * ```typescript\n * import { createNodePlatform } from \"@agentxjs/node-platform\";\n *\n * const platform = await createNodePlatform({ dataPath: \"./data\" });\n * ```\n */\n\nimport type { AgentXPlatform } from \"@agentxjs/core/runtime\";\nimport type { LogLevel } from \"commonxjs/logger\";\nimport { setLoggerFactory, ConsoleLogger } from \"commonxjs/logger\";\nimport { EventBusImpl } from \"@agentxjs/core/event\";\nimport { createPersistence, sqliteDriver } from \"./persistence\";\nimport { NodeBashProvider } from \"./bash/NodeBashProvider\";\nimport { FileLoggerFactory } from \"./logger\";\nimport { join } from \"node:path\";\n\n/**\n * Options for creating a Node platform\n */\nexport interface NodePlatformOptions {\n /**\n * Base path for data storage\n * @default \"./data\"\n */\n dataPath?: string;\n\n /**\n * Directory for log files\n * If provided, enables file logging instead of console\n * @example \".agentx/logs\"\n */\n logDir?: string;\n\n /**\n * Log level\n * @default \"debug\" for file logging, \"info\" for console\n */\n logLevel?: LogLevel;\n}\n\n/**\n * Deferred platform config - resolved lazily\n */\nexport interface DeferredPlatformConfig {\n readonly __deferred: true;\n readonly options: NodePlatformOptions;\n resolve(): Promise<AgentXPlatform>;\n}\n\n/**\n * Create a Node.js platform configuration (deferred initialization)\n *\n * Use this for function-style API. The platform is initialized lazily.\n *\n * @param options - Platform options\n * @returns Deferred platform config\n *\n * @example\n * ```typescript\n * const server = await createServer({\n * platform: nodePlatform({ dataPath: \"./data\" }),\n * });\n * ```\n */\nexport function nodePlatform(options: NodePlatformOptions = {}): DeferredPlatformConfig {\n return {\n __deferred: true,\n options,\n resolve: () => createNodePlatform(options),\n };\n}\n\n/**\n * Create a Node.js platform for AgentX (immediate initialization)\n *\n * @param options - Platform options\n * @returns AgentXPlatform instance\n */\nexport async function createNodePlatform(\n options: NodePlatformOptions = {}\n): Promise<AgentXPlatform> {\n const dataPath = options.dataPath ?? \"./data\";\n\n // Configure logging\n if (options.logDir) {\n const loggerFactory = new FileLoggerFactory({\n logDir: options.logDir,\n level: options.logLevel ?? \"debug\",\n });\n setLoggerFactory(loggerFactory);\n } else if (options.logLevel) {\n setLoggerFactory({\n getLogger: (name: string) => new ConsoleLogger(name, { level: options.logLevel }),\n });\n }\n\n // Create persistence with SQLite\n const persistence = await createPersistence(sqliteDriver({ path: join(dataPath, \"agentx.db\") }));\n\n // Create bash provider\n const bashProvider = new NodeBashProvider();\n\n // Create event bus\n const eventBus = new EventBusImpl();\n\n // Create WebSocket factory (uses ws library for Node.js)\n const { createNodeWebSocket } = await import(\"./network/WebSocketFactory\");\n\n return {\n containerRepository: persistence.containers,\n imageRepository: persistence.images,\n sessionRepository: persistence.sessions,\n eventBus,\n bashProvider,\n webSocketFactory: createNodeWebSocket,\n };\n}\n\n/**\n * Check if value is a deferred platform config\n */\nexport function isDeferredPlatform(value: unknown): value is DeferredPlatformConfig {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"__deferred\" in value &&\n (value as DeferredPlatformConfig).__deferred === true\n );\n}\n\n// Re-export persistence\nexport * from \"./persistence\";\n\n// Re-export bash\nexport { NodeBashProvider } from \"./bash/NodeBashProvider\";\n\n// Re-export mq\nexport { SqliteMessageQueue, OffsetGenerator } from \"./mq\";\n\n// Re-export network\nexport { WebSocketServer, WebSocketConnection } from \"./network\";\n\n// Re-export logger\nexport { FileLoggerFactory, type FileLoggerFactoryOptions } from \"./logger\";\n","/**\n * NodeBashProvider - Node.js implementation of BashProvider\n *\n * Uses execa for subprocess execution with proper timeout,\n * error handling, and cross-platform shell support.\n */\n\nimport { execa } from \"execa\";\nimport type { BashProvider, BashResult, BashOptions } from \"@agentxjs/core/bash\";\nimport { createLogger } from \"commonxjs/logger\";\n\nconst logger = createLogger(\"node-platform/NodeBashProvider\");\n\n/**\n * Default timeout: 30 seconds\n */\nconst DEFAULT_TIMEOUT = 30_000;\n\n/**\n * NodeBashProvider - Executes shell commands via execa\n */\nexport class NodeBashProvider implements BashProvider {\n readonly type = \"child-process\";\n\n async execute(command: string, options?: BashOptions): Promise<BashResult> {\n const timeout = options?.timeout ?? DEFAULT_TIMEOUT;\n\n logger.debug(\"Executing command\", {\n command: command.substring(0, 100),\n cwd: options?.cwd,\n timeout,\n });\n\n const result = await execa({\n shell: true,\n cwd: options?.cwd,\n timeout,\n env: options?.env ? { ...process.env, ...options.env } : undefined,\n reject: false,\n })`${command}`;\n\n logger.debug(\"Command completed\", {\n exitCode: result.exitCode,\n stdoutLength: result.stdout.length,\n stderrLength: result.stderr.length,\n });\n\n return {\n stdout: result.stdout,\n stderr: result.stderr,\n exitCode: result.exitCode ?? 1,\n };\n }\n}\n","/**\n * FileLoggerFactory - File-based logger for Node.js\n *\n * Writes logs to a file instead of console.\n * Useful for TUI applications where console output interferes with the UI.\n *\n * Usage:\n * tail -f .agentx/logs/app.log\n */\n\nimport { appendFileSync, mkdirSync, existsSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport type { Logger, LoggerFactory, LogContext, LogLevel } from \"commonxjs/logger\";\n\nexport interface FileLoggerOptions {\n level?: LogLevel;\n timestamps?: boolean;\n}\n\nclass FileLogger implements Logger {\n readonly name: string;\n readonly level: LogLevel;\n private readonly timestamps: boolean;\n private readonly filePath: string;\n private initialized = false;\n\n constructor(name: string, filePath: string, options: FileLoggerOptions = {}) {\n this.name = name;\n this.filePath = filePath;\n this.level = options.level ?? \"debug\";\n this.timestamps = options.timestamps ?? true;\n }\n\n private ensureDir(): void {\n if (this.initialized) return;\n const dir = dirname(this.filePath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n this.initialized = true;\n }\n\n debug(message: string, context?: LogContext): void {\n if (this.isDebugEnabled()) {\n this.log(\"DEBUG\", message, context);\n }\n }\n\n info(message: string, context?: LogContext): void {\n if (this.isInfoEnabled()) {\n this.log(\"INFO\", message, context);\n }\n }\n\n warn(message: string, context?: LogContext): void {\n if (this.isWarnEnabled()) {\n this.log(\"WARN\", message, context);\n }\n }\n\n error(message: string | Error, context?: LogContext): void {\n if (this.isErrorEnabled()) {\n if (message instanceof Error) {\n this.log(\"ERROR\", message.message, { ...context, stack: message.stack });\n } else {\n this.log(\"ERROR\", message, context);\n }\n }\n }\n\n isDebugEnabled(): boolean {\n return this.getLevelValue(this.level) <= this.getLevelValue(\"debug\");\n }\n\n isInfoEnabled(): boolean {\n return this.getLevelValue(this.level) <= this.getLevelValue(\"info\");\n }\n\n isWarnEnabled(): boolean {\n return this.getLevelValue(this.level) <= this.getLevelValue(\"warn\");\n }\n\n isErrorEnabled(): boolean {\n return this.getLevelValue(this.level) <= this.getLevelValue(\"error\");\n }\n\n private getLevelValue(level: LogLevel): number {\n const levels: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n silent: 4,\n };\n return levels[level];\n }\n\n private log(level: string, message: string, context?: LogContext): void {\n this.ensureDir();\n\n const parts: string[] = [];\n\n if (this.timestamps) {\n parts.push(new Date().toISOString());\n }\n\n parts.push(level.padEnd(5));\n parts.push(`[${this.name}]`);\n parts.push(message);\n\n let logLine = parts.join(\" \");\n\n if (context && Object.keys(context).length > 0) {\n logLine += \" \" + JSON.stringify(context);\n }\n\n logLine += \"\\n\";\n\n try {\n appendFileSync(this.filePath, logLine);\n } catch {\n // Fallback to stderr if file write fails\n process.stderr.write(`[FileLogger] Failed to write: ${logLine}`);\n }\n }\n}\n\n/**\n * FileLoggerFactory options\n */\nexport interface FileLoggerFactoryOptions {\n /**\n * Directory for log files\n */\n logDir: string;\n\n /**\n * Log level\n * @default \"debug\"\n */\n level?: LogLevel;\n\n /**\n * Log file name\n * @default \"app.log\"\n */\n filename?: string;\n}\n\n/**\n * FileLoggerFactory - Creates FileLogger instances\n */\nexport class FileLoggerFactory implements LoggerFactory {\n private readonly filePath: string;\n private readonly level: LogLevel;\n private readonly loggers: Map<string, FileLogger> = new Map();\n\n constructor(options: FileLoggerFactoryOptions) {\n this.filePath = join(options.logDir, options.filename ?? \"app.log\");\n this.level = options.level ?? \"debug\";\n }\n\n getLogger(name: string): Logger {\n if (this.loggers.has(name)) {\n return this.loggers.get(name)!;\n }\n\n const logger = new FileLogger(name, this.filePath, {\n level: this.level,\n });\n\n this.loggers.set(name, logger);\n return logger;\n }\n}\n"],"mappings":"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","names":["logger","join"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/bash/NodeBashProvider.ts","../src/logger/FileLoggerFactory.ts"],"sourcesContent":["/**\n * @agentxjs/node-platform\n *\n * Node.js platform for AgentX.\n * Provides implementations for persistence, bash, and network.\n *\n * @example\n * ```typescript\n * import { createNodePlatform } from \"@agentxjs/node-platform\";\n *\n * const platform = await createNodePlatform({ dataPath: \"./data\" });\n * ```\n */\n\nimport { join } from \"node:path\";\nimport { EventBusImpl } from \"@agentxjs/core/event\";\nimport type { AgentXPlatform } from \"@agentxjs/core/runtime\";\nimport type { LogLevel } from \"commonxjs/logger\";\nimport { ConsoleLogger, setLoggerFactory } from \"commonxjs/logger\";\nimport { NodeBashProvider } from \"./bash/NodeBashProvider\";\nimport { FileLoggerFactory } from \"./logger\";\nimport { createPersistence, sqliteDriver } from \"./persistence\";\n\n/**\n * Options for creating a Node platform\n */\nexport interface NodePlatformOptions {\n /**\n * Base path for data storage\n * @default \"./data\"\n */\n dataPath?: string;\n\n /**\n * Directory for log files\n * If provided, enables file logging instead of console\n * @example \".agentx/logs\"\n */\n logDir?: string;\n\n /**\n * Log level\n * @default \"debug\" for file logging, \"info\" for console\n */\n logLevel?: LogLevel;\n}\n\n/**\n * Deferred platform config - resolved lazily\n */\nexport interface DeferredPlatformConfig {\n readonly __deferred: true;\n readonly options: NodePlatformOptions;\n resolve(): Promise<AgentXPlatform>;\n}\n\n/**\n * Create a Node.js platform configuration (deferred initialization)\n *\n * Use this for function-style API. The platform is initialized lazily.\n *\n * @param options - Platform options\n * @returns Deferred platform config\n *\n * @example\n * ```typescript\n * const server = await createServer({\n * platform: nodePlatform({ dataPath: \"./data\" }),\n * });\n * ```\n */\nexport function nodePlatform(options: NodePlatformOptions = {}): DeferredPlatformConfig {\n return {\n __deferred: true,\n options,\n resolve: () => createNodePlatform(options),\n };\n}\n\n/**\n * Create a Node.js platform for AgentX (immediate initialization)\n *\n * @param options - Platform options\n * @returns AgentXPlatform instance\n */\nexport async function createNodePlatform(\n options: NodePlatformOptions = {}\n): Promise<AgentXPlatform> {\n const dataPath = options.dataPath ?? \"./data\";\n\n // Configure logging\n if (options.logDir) {\n const loggerFactory = new FileLoggerFactory({\n logDir: options.logDir,\n level: options.logLevel ?? \"debug\",\n });\n setLoggerFactory(loggerFactory);\n } else if (options.logLevel) {\n setLoggerFactory({\n getLogger: (name: string) => new ConsoleLogger(name, { level: options.logLevel }),\n });\n }\n\n // Create persistence with SQLite\n const persistence = await createPersistence(sqliteDriver({ path: join(dataPath, \"agentx.db\") }));\n\n // Create bash provider\n const bashProvider = new NodeBashProvider();\n\n // Create event bus\n const eventBus = new EventBusImpl();\n\n // Create channel client factory (uses ws library for Node.js)\n const { createNodeWebSocket } = await import(\"./network/WebSocketFactory\");\n\n // Create channel server (uses ws library for Node.js)\n const { WebSocketServer } = await import(\"./network\");\n const channelServer = new WebSocketServer({\n heartbeat: true,\n heartbeatInterval: 30000,\n });\n\n return {\n containerRepository: persistence.containers,\n imageRepository: persistence.images,\n sessionRepository: persistence.sessions,\n eventBus,\n bashProvider,\n channelServer,\n channelClient: createNodeWebSocket,\n };\n}\n\n/**\n * Check if value is a deferred platform config\n */\nexport function isDeferredPlatform(value: unknown): value is DeferredPlatformConfig {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"__deferred\" in value &&\n (value as DeferredPlatformConfig).__deferred === true\n );\n}\n\n// Re-export bash\nexport { NodeBashProvider } from \"./bash/NodeBashProvider\";\n// Re-export logger\nexport { FileLoggerFactory, type FileLoggerFactoryOptions } from \"./logger\";\n\n// Re-export mq\nexport { OffsetGenerator, SqliteMessageQueue } from \"./mq\";\n\n// Re-export network\nexport { WebSocketConnection, WebSocketServer } from \"./network\";\n// Re-export persistence\nexport * from \"./persistence\";\n","/**\n * NodeBashProvider - Node.js implementation of BashProvider\n *\n * Uses execa for subprocess execution with proper timeout,\n * error handling, and cross-platform shell support.\n */\n\nimport type { BashOptions, BashProvider, BashResult } from \"@agentxjs/core/bash\";\nimport { createLogger } from \"commonxjs/logger\";\nimport { execa } from \"execa\";\n\nconst logger = createLogger(\"node-platform/NodeBashProvider\");\n\n/**\n * Default timeout: 30 seconds\n */\nconst DEFAULT_TIMEOUT = 30_000;\n\n/**\n * NodeBashProvider - Executes shell commands via execa\n */\nexport class NodeBashProvider implements BashProvider {\n readonly type = \"child-process\";\n\n async execute(command: string, options?: BashOptions): Promise<BashResult> {\n const timeout = options?.timeout ?? DEFAULT_TIMEOUT;\n\n logger.debug(\"Executing command\", {\n command: command.substring(0, 100),\n cwd: options?.cwd,\n timeout,\n });\n\n const result = await execa({\n shell: true,\n cwd: options?.cwd,\n timeout,\n env: options?.env ? { ...process.env, ...options.env } : undefined,\n reject: false,\n })`${command}`;\n\n logger.debug(\"Command completed\", {\n exitCode: result.exitCode,\n stdoutLength: result.stdout.length,\n stderrLength: result.stderr.length,\n });\n\n return {\n stdout: result.stdout,\n stderr: result.stderr,\n exitCode: result.exitCode ?? 1,\n };\n }\n}\n","/**\n * FileLoggerFactory - File-based logger for Node.js\n *\n * Writes logs to a file instead of console.\n * Useful for TUI applications where console output interferes with the UI.\n *\n * Usage:\n * tail -f .agentx/logs/app.log\n */\n\nimport { appendFileSync, existsSync, mkdirSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport type { LogContext, Logger, LoggerFactory, LogLevel } from \"commonxjs/logger\";\n\nexport interface FileLoggerOptions {\n level?: LogLevel;\n timestamps?: boolean;\n}\n\nclass FileLogger implements Logger {\n readonly name: string;\n readonly level: LogLevel;\n private readonly timestamps: boolean;\n private readonly filePath: string;\n private initialized = false;\n\n constructor(name: string, filePath: string, options: FileLoggerOptions = {}) {\n this.name = name;\n this.filePath = filePath;\n this.level = options.level ?? \"debug\";\n this.timestamps = options.timestamps ?? true;\n }\n\n private ensureDir(): void {\n if (this.initialized) return;\n const dir = dirname(this.filePath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n this.initialized = true;\n }\n\n debug(message: string, context?: LogContext): void {\n if (this.isDebugEnabled()) {\n this.log(\"DEBUG\", message, context);\n }\n }\n\n info(message: string, context?: LogContext): void {\n if (this.isInfoEnabled()) {\n this.log(\"INFO\", message, context);\n }\n }\n\n warn(message: string, context?: LogContext): void {\n if (this.isWarnEnabled()) {\n this.log(\"WARN\", message, context);\n }\n }\n\n error(message: string | Error, context?: LogContext): void {\n if (this.isErrorEnabled()) {\n if (message instanceof Error) {\n this.log(\"ERROR\", message.message, { ...context, stack: message.stack });\n } else {\n this.log(\"ERROR\", message, context);\n }\n }\n }\n\n isDebugEnabled(): boolean {\n return this.getLevelValue(this.level) <= this.getLevelValue(\"debug\");\n }\n\n isInfoEnabled(): boolean {\n return this.getLevelValue(this.level) <= this.getLevelValue(\"info\");\n }\n\n isWarnEnabled(): boolean {\n return this.getLevelValue(this.level) <= this.getLevelValue(\"warn\");\n }\n\n isErrorEnabled(): boolean {\n return this.getLevelValue(this.level) <= this.getLevelValue(\"error\");\n }\n\n private getLevelValue(level: LogLevel): number {\n const levels: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n silent: 4,\n };\n return levels[level];\n }\n\n private log(level: string, message: string, context?: LogContext): void {\n this.ensureDir();\n\n const parts: string[] = [];\n\n if (this.timestamps) {\n parts.push(new Date().toISOString());\n }\n\n parts.push(level.padEnd(5));\n parts.push(`[${this.name}]`);\n parts.push(message);\n\n let logLine = parts.join(\" \");\n\n if (context && Object.keys(context).length > 0) {\n logLine += ` ${JSON.stringify(context)}`;\n }\n\n logLine += \"\\n\";\n\n try {\n appendFileSync(this.filePath, logLine);\n } catch {\n // Fallback to stderr if file write fails\n process.stderr.write(`[FileLogger] Failed to write: ${logLine}`);\n }\n }\n}\n\n/**\n * FileLoggerFactory options\n */\nexport interface FileLoggerFactoryOptions {\n /**\n * Directory for log files\n */\n logDir: string;\n\n /**\n * Log level\n * @default \"debug\"\n */\n level?: LogLevel;\n\n /**\n * Log file name\n * @default \"app.log\"\n */\n filename?: string;\n}\n\n/**\n * FileLoggerFactory - Creates FileLogger instances\n */\nexport class FileLoggerFactory implements LoggerFactory {\n private readonly filePath: string;\n private readonly level: LogLevel;\n private readonly loggers: Map<string, FileLogger> = new Map();\n\n constructor(options: FileLoggerFactoryOptions) {\n this.filePath = join(options.logDir, options.filename ?? \"app.log\");\n this.level = options.level ?? \"debug\";\n }\n\n getLogger(name: string): Logger {\n if (this.loggers.has(name)) {\n return this.loggers.get(name)!;\n }\n\n const logger = new FileLogger(name, this.filePath, {\n level: this.level,\n });\n\n this.loggers.set(name, logger);\n return logger;\n }\n}\n"],"mappings":"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","names":["join","logger","join","WebSocketServer"]}
|
package/dist/mq/index.d.ts
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
import { MessageQueue, QueueConfig, QueueEntry, Unsubscribe } from '@agentxjs/core/mq';
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* OffsetGenerator - Generates monotonically increasing offsets
|
|
5
|
+
*
|
|
6
|
+
* Format: "{timestamp_base36}-{sequence_padded}"
|
|
7
|
+
* Example: "lq5x4g2-0001"
|
|
8
|
+
*
|
|
9
|
+
* This format ensures:
|
|
10
|
+
* - Lexicographic ordering matches temporal ordering
|
|
11
|
+
* - Multiple events in same millisecond get unique offsets
|
|
12
|
+
* - Human-readable and compact
|
|
13
|
+
*/
|
|
14
|
+
declare class OffsetGenerator {
|
|
15
|
+
private lastTimestamp;
|
|
16
|
+
private sequence;
|
|
17
|
+
/**
|
|
18
|
+
* Generate a new offset
|
|
19
|
+
*/
|
|
20
|
+
generate(): string;
|
|
21
|
+
/**
|
|
22
|
+
* Compare two offsets
|
|
23
|
+
* @returns negative if a < b, 0 if a == b, positive if a > b
|
|
24
|
+
*/
|
|
25
|
+
static compare(a: string, b: string): number;
|
|
26
|
+
}
|
|
27
|
+
|
|
3
28
|
/**
|
|
4
29
|
* SqliteMessageQueue - RxJS-based message queue with SQLite persistence
|
|
5
30
|
*
|
|
@@ -35,29 +60,4 @@ declare class SqliteMessageQueue implements MessageQueue {
|
|
|
35
60
|
private cleanup;
|
|
36
61
|
}
|
|
37
62
|
|
|
38
|
-
/**
|
|
39
|
-
* OffsetGenerator - Generates monotonically increasing offsets
|
|
40
|
-
*
|
|
41
|
-
* Format: "{timestamp_base36}-{sequence_padded}"
|
|
42
|
-
* Example: "lq5x4g2-0001"
|
|
43
|
-
*
|
|
44
|
-
* This format ensures:
|
|
45
|
-
* - Lexicographic ordering matches temporal ordering
|
|
46
|
-
* - Multiple events in same millisecond get unique offsets
|
|
47
|
-
* - Human-readable and compact
|
|
48
|
-
*/
|
|
49
|
-
declare class OffsetGenerator {
|
|
50
|
-
private lastTimestamp;
|
|
51
|
-
private sequence;
|
|
52
|
-
/**
|
|
53
|
-
* Generate a new offset
|
|
54
|
-
*/
|
|
55
|
-
generate(): string;
|
|
56
|
-
/**
|
|
57
|
-
* Compare two offsets
|
|
58
|
-
* @returns negative if a < b, 0 if a == b, positive if a > b
|
|
59
|
-
*/
|
|
60
|
-
static compare(a: string, b: string): number;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
63
|
export { OffsetGenerator, SqliteMessageQueue };
|
package/dist/mq/index.js
CHANGED
package/dist/network/index.d.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
export {
|
|
2
|
-
import {
|
|
1
|
+
export { W as WebSocketConnection, a as WebSocketServer } from '../WebSocketServer-CbjDC1lS.js';
|
|
2
|
+
import { ChannelClientFactory } from '@agentxjs/core/network';
|
|
3
3
|
import 'ws';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* Node.js
|
|
6
|
+
* Node.js channel client factory using the ws library
|
|
7
7
|
*
|
|
8
|
-
* Provides
|
|
8
|
+
* Provides ChannelClientFactory implementation for @agentxjs/core RpcClient.
|
|
9
9
|
* Browser environments use native WebSocket (the default in RpcClient).
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Create a WebSocket instance using the ws library (Node.js)
|
|
14
14
|
*/
|
|
15
|
-
declare const createNodeWebSocket:
|
|
15
|
+
declare const createNodeWebSocket: ChannelClientFactory;
|
|
16
16
|
|
|
17
17
|
export { createNodeWebSocket };
|
package/dist/network/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
WebSocketConnection,
|
|
3
3
|
WebSocketServer
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-VVNULOYS.js";
|
|
5
5
|
import {
|
|
6
6
|
createNodeWebSocket
|
|
7
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-SUJ5DIDM.js";
|
|
8
8
|
import "../chunk-DGUM43GV.js";
|
|
9
9
|
export {
|
|
10
10
|
WebSocketConnection,
|