@agentxjs/node-platform 2.0.1 → 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.
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  createNodeWebSocket
3
- } from "./chunk-V664KD3R.js";
3
+ } from "./chunk-SUJ5DIDM.js";
4
4
  import "./chunk-DGUM43GV.js";
5
5
  export {
6
6
  createNodeWebSocket
7
7
  };
8
- //# sourceMappingURL=WebSocketFactory-SDWPRZVB.js.map
8
+ //# sourceMappingURL=WebSocketFactory-W4Z4TO7K.js.map
@@ -11,4 +11,4 @@ var createNodeWebSocket = (url) => {
11
11
  export {
12
12
  createNodeWebSocket
13
13
  };
14
- //# sourceMappingURL=chunk-V664KD3R.js.map
14
+ //# sourceMappingURL=chunk-SUJ5DIDM.js.map
@@ -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":[]}
package/dist/index.js CHANGED
@@ -14,7 +14,7 @@ import {
14
14
  WebSocketConnection,
15
15
  WebSocketServer
16
16
  } from "./chunk-VVNULOYS.js";
17
- import "./chunk-V664KD3R.js";
17
+ import "./chunk-SUJ5DIDM.js";
18
18
  import "./chunk-DGUM43GV.js";
19
19
 
20
20
  // src/index.ts
@@ -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-SDWPRZVB.js");
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
- webSocketFactory: createNodeWebSocket
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 { 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 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 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"]}
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"]}
@@ -1,17 +1,17 @@
1
1
  export { W as WebSocketConnection, a as WebSocketServer } from '../WebSocketServer-CbjDC1lS.js';
2
- import { WebSocketFactory } from '@agentxjs/core/network';
2
+ import { ChannelClientFactory } from '@agentxjs/core/network';
3
3
  import 'ws';
4
4
 
5
5
  /**
6
- * Node.js WebSocket factory using the ws library
6
+ * Node.js channel client factory using the ws library
7
7
  *
8
- * Provides WebSocketFactory implementation for @agentxjs/core RpcClient.
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: WebSocketFactory;
15
+ declare const createNodeWebSocket: ChannelClientFactory;
16
16
 
17
17
  export { createNodeWebSocket };
@@ -4,7 +4,7 @@ import {
4
4
  } from "../chunk-VVNULOYS.js";
5
5
  import {
6
6
  createNodeWebSocket
7
- } from "../chunk-V664KD3R.js";
7
+ } from "../chunk-SUJ5DIDM.js";
8
8
  import "../chunk-DGUM43GV.js";
9
9
  export {
10
10
  WebSocketConnection,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentxjs/node-platform",
3
- "version": "2.0.1",
3
+ "version": "3.0.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -36,7 +36,7 @@
36
36
  "test": "echo 'No tests yet'"
37
37
  },
38
38
  "dependencies": {
39
- "@agentxjs/core": "^2.0.1",
39
+ "@agentxjs/core": "^3.0.0",
40
40
  "commonxjs": "^0.1.1",
41
41
  "execa": "9.6.1",
42
42
  "rxjs": "^7.8.2",
package/src/index.ts CHANGED
@@ -110,16 +110,24 @@ export async function createNodePlatform(
110
110
  // Create event bus
111
111
  const eventBus = new EventBusImpl();
112
112
 
113
- // Create WebSocket factory (uses ws library for Node.js)
113
+ // Create channel client factory (uses ws library for Node.js)
114
114
  const { createNodeWebSocket } = await import("./network/WebSocketFactory");
115
115
 
116
+ // Create channel server (uses ws library for Node.js)
117
+ const { WebSocketServer } = await import("./network");
118
+ const channelServer = new WebSocketServer({
119
+ heartbeat: true,
120
+ heartbeatInterval: 30000,
121
+ });
122
+
116
123
  return {
117
124
  containerRepository: persistence.containers,
118
125
  imageRepository: persistence.images,
119
126
  sessionRepository: persistence.sessions,
120
127
  eventBus,
121
128
  bashProvider,
122
- webSocketFactory: createNodeWebSocket,
129
+ channelServer,
130
+ channelClient: createNodeWebSocket,
123
131
  };
124
132
  }
125
133
 
@@ -1,16 +1,16 @@
1
1
  /**
2
- * Node.js WebSocket factory using the ws library
2
+ * Node.js channel client factory using the ws library
3
3
  *
4
- * Provides WebSocketFactory implementation for @agentxjs/core RpcClient.
4
+ * Provides ChannelClientFactory implementation for @agentxjs/core RpcClient.
5
5
  * Browser environments use native WebSocket (the default in RpcClient).
6
6
  */
7
7
 
8
- import type { WebSocketFactory } from "@agentxjs/core/network";
8
+ import type { ChannelClientFactory } from "@agentxjs/core/network";
9
9
 
10
10
  /**
11
11
  * Create a WebSocket instance using the ws library (Node.js)
12
12
  */
13
- export const createNodeWebSocket: WebSocketFactory = (url: string): WebSocket => {
13
+ export const createNodeWebSocket: ChannelClientFactory = (url: string): WebSocket => {
14
14
  // eslint-disable-next-line @typescript-eslint/no-require-imports
15
15
  const { default: WS } = require("ws");
16
16
  return new WS(url) as unknown as WebSocket;
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/network/WebSocketFactory.ts"],"sourcesContent":["/**\n * Node.js WebSocket factory using the ws library\n *\n * Provides WebSocketFactory implementation for @agentxjs/core RpcClient.\n * Browser environments use native WebSocket (the default in RpcClient).\n */\n\nimport type { WebSocketFactory } from \"@agentxjs/core/network\";\n\n/**\n * Create a WebSocket instance using the ws library (Node.js)\n */\nexport const createNodeWebSocket: WebSocketFactory = (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,sBAAwC,CAAC,QAA2B;AAE/E,QAAM,EAAE,SAAS,GAAG,IAAI,UAAQ,IAAI;AACpC,SAAO,IAAI,GAAG,GAAG;AACnB;","names":[]}