@stamn/agent 0.8.0 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,14 +1,11 @@
1
1
  import { createRequire } from "module"; const require = createRequire(import.meta.url);
2
- import {
3
- SERVER_URL
4
- } from "./chunk-JVIBUEVN.js";
5
2
 
6
3
  // src/logging/logger.ts
7
4
  import pino from "pino";
8
- function createLogger(config2) {
5
+ function createLogger(config) {
9
6
  const isDev = process.env.NODE_ENV !== "production";
10
7
  return pino({
11
- level: config2.logLevel,
8
+ level: config.logLevel,
12
9
  transport: isDev ? {
13
10
  target: "pino-pretty",
14
11
  options: { colorize: true, translateTime: "SYS:HH:MM:ss" }
@@ -145,7 +142,8 @@ var WSClient = class {
145
142
  }
146
143
  connect() {
147
144
  if (this.isShuttingDown) return;
148
- const wsUrl = SERVER_URL.replace(/^http:/, "ws:").replace(/^https:/, "wss:");
145
+ const config = this.options.config;
146
+ const wsUrl = config.serverUrl.replace(/^http:/, "ws:").replace(/^https:/, "wss:");
149
147
  const url = `${wsUrl}/ws/agent`;
150
148
  this.options.logger.info({ url }, "Connecting to server...");
151
149
  this.ws = new WebSocket(url);
@@ -266,7 +264,7 @@ var WSClient = class {
266
264
  const payload = {
267
265
  agentId: this.options.config.agentId,
268
266
  status,
269
- version: "0.8.0",
267
+ version: "0.8.1",
270
268
  platform: `${process.platform}-${process.arch}`,
271
269
  nodeVersion: process.versions.node
272
270
  };
@@ -373,4 +371,4 @@ export {
373
371
  WSClient,
374
372
  SpendClient
375
373
  };
376
- //# sourceMappingURL=chunk-6EKA3TV7.js.map
374
+ //# sourceMappingURL=chunk-5RSB2UIE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/logging/logger.ts","../src/ws/ws-client.ts","../src/ws/heartbeat.ts","../src/ws/message-handler.ts","../src/spend/spend-client.ts"],"sourcesContent":["import pino from 'pino';\nimport type { AgentConfig } from '../config/config-schema.js';\n\nexport function createLogger(\n config: Pick<AgentConfig, 'logLevel'>,\n): pino.Logger {\n const isDev = process.env.NODE_ENV !== 'production';\n\n return pino({\n level: config.logLevel,\n transport: isDev\n ? {\n target: 'pino-pretty',\n options: { colorize: true, translateTime: 'SYS:HH:MM:ss' },\n }\n : undefined,\n });\n}\n","import WebSocket from 'ws';\nimport type {\n AuthenticatePayload,\n AuthenticatedPayload,\n AuthErrorPayload,\n StatusReportPayload,\n SpendApprovedPayload,\n SpendDeniedPayload,\n} from '@stamn/types';\n\ndeclare const AGENT_VERSION: string;\nimport type { Logger } from 'pino';\nimport type { AgentConfig } from '../config/config-schema.js';\nimport { Heartbeat, type HeartbeatSender } from './heartbeat.js';\nimport { MessageHandler } from './message-handler.js';\n\nexport type SpendResultCallback = (\n type: 'approved' | 'denied',\n payload: SpendApprovedPayload | SpendDeniedPayload,\n) => void;\n\nexport interface WSClientOptions {\n config: AgentConfig;\n logger: Logger;\n onCommand: (command: string, params?: Record<string, unknown>) => void;\n onDisconnect: () => void;\n onConnected: () => void;\n}\n\nexport class WSClient implements HeartbeatSender {\n private ws: WebSocket | null = null;\n private heartbeat: Heartbeat | null = null;\n private handler: MessageHandler;\n private reconnectAttempt = 0;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private isShuttingDown = false;\n private authenticated = false;\n private readonly startTime = Date.now();\n private spendListeners = new Map<string, SpendResultCallback>();\n\n constructor(private options: WSClientOptions) {\n this.handler = new MessageHandler(options.logger, options.onCommand);\n }\n\n onSpendResult(requestId: string, callback: SpendResultCallback): void {\n this.spendListeners.set(requestId, callback);\n }\n\n removeSpendListener(requestId: string): void {\n this.spendListeners.delete(requestId);\n }\n\n connect(): void {\n if (this.isShuttingDown) return;\n\n const config = this.options.config;\n const wsUrl = config.serverUrl\n .replace(/^http:/, 'ws:')\n .replace(/^https:/, 'wss:');\n const url = `${wsUrl}/ws/agent`;\n\n this.options.logger.info({ url }, 'Connecting to server...');\n\n this.ws = new WebSocket(url);\n\n this.ws.on('open', () => {\n this.options.logger.info('WebSocket connected, authenticating...');\n this.reconnectAttempt = 0;\n\n const payload: AuthenticatePayload = {\n agentId: config.agentId!,\n apiKey: config.apiKey ?? '',\n };\n\n this.send('agent:authenticate', payload);\n });\n\n this.ws.on('message', (data: WebSocket.RawData) => {\n const raw = data.toString();\n const result = this.handler.handle(raw);\n if (!result) return;\n\n switch (result.type) {\n case 'server:authenticated': {\n const payload = result.payload as AuthenticatedPayload;\n this.authenticated = true;\n this.options.logger.info(\n { serverVersion: payload.serverVersion },\n `Agent ${payload.agentId} authenticated`,\n );\n\n this.heartbeat = new Heartbeat(\n this,\n config.agentId!,\n config.heartbeatIntervalMs,\n this.startTime,\n );\n this.heartbeat.start();\n\n this.sendStatusReport('online');\n this.options.onConnected();\n break;\n }\n\n case 'server:auth_error': {\n const payload = result.payload as AuthErrorPayload;\n this.options.logger.error(\n { reason: payload.reason },\n 'Authentication failed',\n );\n this.isShuttingDown = true;\n this.ws?.close(4003, 'Auth failed');\n break;\n }\n\n case 'server:heartbeat_ack':\n this.heartbeat?.onAck();\n break;\n\n case 'server:spend_approved': {\n const sp = result.payload as SpendApprovedPayload;\n const cb = this.spendListeners.get(sp.requestId);\n if (cb) {\n cb('approved', sp);\n this.spendListeners.delete(sp.requestId);\n }\n break;\n }\n\n case 'server:spend_denied': {\n const sd = result.payload as SpendDeniedPayload;\n const dcb = this.spendListeners.get(sd.requestId);\n if (dcb) {\n dcb('denied', sd);\n this.spendListeners.delete(sd.requestId);\n }\n break;\n }\n\n case 'server:event':\n this.options.logger.debug({ event: result.payload }, 'Server event');\n break;\n\n case 'server:command':\n // Already handled by MessageHandler → onCommand callback\n break;\n }\n });\n\n this.ws.on('close', (code: number, reason: Buffer) => {\n this.authenticated = false;\n this.heartbeat?.stop();\n this.heartbeat = null;\n\n if (this.isShuttingDown) {\n this.options.logger.info('Connection closed');\n return;\n }\n\n this.options.logger.warn(\n { code, reason: reason.toString() },\n 'Connection lost',\n );\n this.options.onDisconnect();\n this.scheduleReconnect();\n });\n\n this.ws.on('error', (err: Error) => {\n this.options.logger.error({ err: err.message }, 'WebSocket error');\n });\n }\n\n reconnect(): void {\n this.heartbeat?.stop();\n this.heartbeat = null;\n this.ws?.close();\n }\n\n send<T>(type: string, payload: T): void {\n if (this.ws?.readyState !== WebSocket.OPEN) return;\n\n // NestJS @SubscribeMessage expects {event, data} format\n this.ws.send(JSON.stringify({ event: type, data: payload }));\n }\n\n disconnect(): void {\n this.isShuttingDown = true;\n\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n\n if (this.authenticated) {\n this.sendStatusReport('shutting_down');\n }\n\n this.heartbeat?.stop();\n this.ws?.close(1000, 'Client shutdown');\n }\n\n get isAuthenticated(): boolean {\n return this.authenticated;\n }\n\n private sendStatusReport(status: StatusReportPayload['status']): void {\n const payload: StatusReportPayload = {\n agentId: this.options.config.agentId!,\n status,\n version: AGENT_VERSION,\n platform: `${process.platform}-${process.arch}`,\n nodeVersion: process.versions.node,\n };\n this.send('agent:status_report', payload);\n }\n\n private scheduleReconnect(): void {\n const { wsReconnectBaseMs, wsReconnectMaxMs } = this.options.config;\n const delay = Math.min(\n wsReconnectBaseMs * 2 ** this.reconnectAttempt,\n wsReconnectMaxMs,\n );\n const jitter = Math.random() * delay * 0.1;\n const totalDelay = Math.round(delay + jitter);\n\n this.reconnectAttempt++;\n this.options.logger.info(\n { attempt: this.reconnectAttempt, delayMs: totalDelay },\n 'Reconnecting...',\n );\n\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.connect();\n }, totalDelay);\n }\n}\n","import type { HeartbeatPayload } from '@stamn/types';\n\nexport interface HeartbeatSender {\n send<T>(type: string, payload: T): void;\n reconnect(): void;\n}\n\nexport class Heartbeat {\n private timer: ReturnType<typeof setInterval> | null = null;\n private missedPongs = 0;\n private readonly maxMissedPongs = 3;\n\n constructor(\n private sender: HeartbeatSender,\n private agentId: string,\n private intervalMs: number,\n private startTime: number,\n ) {}\n\n start(): void {\n this.missedPongs = 0;\n this.timer = setInterval(() => {\n if (this.missedPongs >= this.maxMissedPongs) {\n this.sender.reconnect();\n return;\n }\n\n const payload: HeartbeatPayload = {\n agentId: this.agentId,\n uptimeSeconds: Math.floor((Date.now() - this.startTime) / 1000),\n memoryUsageMb: Math.round(process.memoryUsage().rss / 1024 / 1024),\n };\n\n this.sender.send('agent:heartbeat', payload);\n this.missedPongs++;\n }, this.intervalMs);\n }\n\n onAck(): void {\n this.missedPongs = 0;\n }\n\n stop(): void {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n }\n}\n","import type { Logger } from 'pino';\nimport { z } from 'zod';\nimport type { ServerToAgentMessageType, CommandPayload } from '@stamn/types';\n\n// NestJS WS sends {event, data} format\nconst wsMessageSchema = z.object({\n event: z.string(),\n data: z.unknown(),\n});\n\nconst commandPayloadSchema = z.object({\n commandId: z.string(),\n command: z.enum(['pause', 'resume', 'update_config', 'shutdown']),\n params: z.record(z.unknown()).optional(),\n});\n\nexport class MessageHandler {\n constructor(\n private logger: Logger,\n private onCommand: (\n command: string,\n params?: Record<string, unknown>,\n ) => void,\n ) {}\n\n handle(\n raw: string,\n ): { type: ServerToAgentMessageType; payload: unknown } | null {\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n this.logger.warn({ raw }, 'Invalid JSON received');\n return null;\n }\n\n const result = wsMessageSchema.safeParse(parsed);\n if (!result.success) {\n this.logger.warn({ error: result.error.message }, 'Invalid WS message');\n return null;\n }\n\n const { event, data } = result.data;\n\n switch (event) {\n case 'server:authenticated':\n case 'server:auth_error':\n case 'server:heartbeat_ack':\n case 'server:event':\n case 'server:spend_approved':\n case 'server:spend_denied':\n return {\n type: event as ServerToAgentMessageType,\n payload: data,\n };\n\n case 'server:command': {\n const cmdResult = commandPayloadSchema.safeParse(data);\n if (!cmdResult.success) {\n this.logger.warn(\n { error: cmdResult.error.message },\n 'Invalid command payload',\n );\n return null;\n }\n\n const cmd = cmdResult.data as CommandPayload;\n this.logger.info(\n { command: cmd.command, commandId: cmd.commandId },\n 'Received command',\n );\n this.onCommand(cmd.command, cmd.params);\n return { type: 'server:command', payload: cmd };\n }\n\n default:\n this.logger.debug({ type: event }, 'Unknown message type');\n return null;\n }\n }\n}\n","import { randomUUID } from 'crypto';\nimport type { Logger } from 'pino';\nimport type {\n SpendRequestPayload,\n SpendApprovedPayload,\n SpendDeniedPayload,\n LedgerCategory,\n LedgerRail,\n} from '@stamn/types';\nimport type { WSClient } from '../ws/ws-client.js';\n\nexport type SpendResult =\n | {\n approved: true;\n ledgerEntryId: string;\n transactionHash?: string;\n remainingBalanceCents: number;\n }\n | { approved: false; reason: string; code: string };\n\nexport interface SpendParams {\n amountCents: number;\n category: LedgerCategory;\n rail: LedgerRail;\n vendor?: string;\n description: string;\n recipientAgentId?: string;\n recipientAddress?: string;\n}\n\nconst SPEND_TIMEOUT_MS = 30_000;\n\nexport class SpendClient {\n constructor(\n private wsClient: WSClient,\n private logger: Logger,\n ) {}\n\n async request(params: SpendParams): Promise<SpendResult> {\n const requestId = randomUUID();\n\n const payload: SpendRequestPayload = {\n requestId,\n amountCents: params.amountCents,\n currency: 'USDC',\n category: params.category,\n rail: params.rail,\n vendor: params.vendor,\n description: params.description,\n recipientAgentId: params.recipientAgentId,\n recipientAddress: params.recipientAddress,\n };\n\n this.logger.info(\n {\n requestId,\n amountCents: params.amountCents,\n vendor: params.vendor,\n category: params.category,\n },\n `Requesting spend: ${params.description}`,\n );\n\n return new Promise<SpendResult>((resolve) => {\n const timeout = setTimeout(() => {\n this.wsClient.removeSpendListener(requestId);\n this.logger.error({ requestId }, 'Spend request timed out');\n resolve({\n approved: false,\n reason: 'Request timed out',\n code: 'timeout',\n });\n }, SPEND_TIMEOUT_MS);\n\n this.wsClient.onSpendResult(requestId, (type, result) => {\n clearTimeout(timeout);\n\n if (type === 'approved') {\n const approved = result as SpendApprovedPayload;\n this.logger.info(\n {\n requestId,\n ledgerEntryId: approved.ledgerEntryId,\n remainingBalanceCents: approved.remainingBalanceCents,\n },\n 'Spend approved',\n );\n resolve({\n approved: true,\n ledgerEntryId: approved.ledgerEntryId,\n transactionHash: approved.transactionHash,\n remainingBalanceCents: approved.remainingBalanceCents,\n });\n } else {\n const denied = result as SpendDeniedPayload;\n this.logger.warn(\n { requestId, code: denied.code, reason: denied.reason },\n 'Spend denied',\n );\n resolve({\n approved: false,\n reason: denied.reason,\n code: denied.code,\n });\n }\n });\n\n this.wsClient.send('agent:spend_request', payload);\n });\n }\n}\n"],"mappings":"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","names":[]}
@@ -3,7 +3,7 @@ import {
3
3
  SpendClient,
4
4
  WSClient,
5
5
  createLogger
6
- } from "../chunk-6EKA3TV7.js";
6
+ } from "../chunk-5RSB2UIE.js";
7
7
  import {
8
8
  ConfigStore
9
9
  } from "../chunk-KQC5O25P.js";
@@ -6,7 +6,7 @@ import {
6
6
  SpendClient,
7
7
  WSClient,
8
8
  createLogger
9
- } from "../chunk-6EKA3TV7.js";
9
+ } from "../chunk-5RSB2UIE.js";
10
10
  import {
11
11
  ConfigStore
12
12
  } from "../chunk-KQC5O25P.js";
@@ -6,13 +6,13 @@ import { execSync } from "child_process";
6
6
  var Update = class extends Command {
7
7
  static description = "Update the Stamn agent to the latest version";
8
8
  async run() {
9
- this.log(`Current version: ${"0.8.0"}`);
9
+ this.log(`Current version: ${"0.8.1"}`);
10
10
  this.log("Checking for updates...");
11
11
  try {
12
12
  const latest = execSync("npm view @stamn/agent version", {
13
13
  encoding: "utf-8"
14
14
  }).trim();
15
- if (latest === "0.8.0") {
15
+ if (latest === "0.8.1") {
16
16
  this.log("Already on the latest version.");
17
17
  return;
18
18
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stamn/agent",
3
- "version": "0.8.0",
3
+ "version": "0.8.1",
4
4
  "description": "Stamn Agent Daemon CLI",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/logging/logger.ts","../src/ws/ws-client.ts","../src/ws/heartbeat.ts","../src/ws/message-handler.ts","../src/spend/spend-client.ts"],"sourcesContent":["import pino from 'pino';\nimport type { AgentConfig } from '../config/config-schema.js';\n\nexport function createLogger(\n config: Pick<AgentConfig, 'logLevel'>,\n): pino.Logger {\n const isDev = process.env.NODE_ENV !== 'production';\n\n return pino({\n level: config.logLevel,\n transport: isDev\n ? {\n target: 'pino-pretty',\n options: { colorize: true, translateTime: 'SYS:HH:MM:ss' },\n }\n : undefined,\n });\n}\n","import WebSocket from 'ws';\nimport type {\n AuthenticatePayload,\n AuthenticatedPayload,\n AuthErrorPayload,\n StatusReportPayload,\n SpendApprovedPayload,\n SpendDeniedPayload,\n} from '@stamn/types';\n\ndeclare const AGENT_VERSION: string;\nimport type { Logger } from 'pino';\nimport type { AgentConfig } from '../config/config-schema.js';\nimport { SERVER_URL } from '../config/config-schema.js';\nimport { Heartbeat, type HeartbeatSender } from './heartbeat.js';\nimport { MessageHandler } from './message-handler.js';\n\nexport type SpendResultCallback = (\n type: 'approved' | 'denied',\n payload: SpendApprovedPayload | SpendDeniedPayload,\n) => void;\n\nexport interface WSClientOptions {\n config: AgentConfig;\n logger: Logger;\n onCommand: (command: string, params?: Record<string, unknown>) => void;\n onDisconnect: () => void;\n onConnected: () => void;\n}\n\nexport class WSClient implements HeartbeatSender {\n private ws: WebSocket | null = null;\n private heartbeat: Heartbeat | null = null;\n private handler: MessageHandler;\n private reconnectAttempt = 0;\n private reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n private isShuttingDown = false;\n private authenticated = false;\n private readonly startTime = Date.now();\n private spendListeners = new Map<string, SpendResultCallback>();\n\n constructor(private options: WSClientOptions) {\n this.handler = new MessageHandler(options.logger, options.onCommand);\n }\n\n onSpendResult(requestId: string, callback: SpendResultCallback): void {\n this.spendListeners.set(requestId, callback);\n }\n\n removeSpendListener(requestId: string): void {\n this.spendListeners.delete(requestId);\n }\n\n connect(): void {\n if (this.isShuttingDown) return;\n\n const wsUrl = SERVER_URL.replace(/^http:/, 'ws:').replace(/^https:/, 'wss:');\n const url = `${wsUrl}/ws/agent`;\n\n this.options.logger.info({ url }, 'Connecting to server...');\n\n this.ws = new WebSocket(url);\n\n this.ws.on('open', () => {\n this.options.logger.info('WebSocket connected, authenticating...');\n this.reconnectAttempt = 0;\n\n const payload: AuthenticatePayload = {\n agentId: config.agentId!,\n apiKey: config.apiKey ?? '',\n };\n\n this.send('agent:authenticate', payload);\n });\n\n this.ws.on('message', (data: WebSocket.RawData) => {\n const raw = data.toString();\n const result = this.handler.handle(raw);\n if (!result) return;\n\n switch (result.type) {\n case 'server:authenticated': {\n const payload = result.payload as AuthenticatedPayload;\n this.authenticated = true;\n this.options.logger.info(\n { serverVersion: payload.serverVersion },\n `Agent ${payload.agentId} authenticated`,\n );\n\n this.heartbeat = new Heartbeat(\n this,\n config.agentId!,\n config.heartbeatIntervalMs,\n this.startTime,\n );\n this.heartbeat.start();\n\n this.sendStatusReport('online');\n this.options.onConnected();\n break;\n }\n\n case 'server:auth_error': {\n const payload = result.payload as AuthErrorPayload;\n this.options.logger.error(\n { reason: payload.reason },\n 'Authentication failed',\n );\n this.isShuttingDown = true;\n this.ws?.close(4003, 'Auth failed');\n break;\n }\n\n case 'server:heartbeat_ack':\n this.heartbeat?.onAck();\n break;\n\n case 'server:spend_approved': {\n const sp = result.payload as SpendApprovedPayload;\n const cb = this.spendListeners.get(sp.requestId);\n if (cb) {\n cb('approved', sp);\n this.spendListeners.delete(sp.requestId);\n }\n break;\n }\n\n case 'server:spend_denied': {\n const sd = result.payload as SpendDeniedPayload;\n const dcb = this.spendListeners.get(sd.requestId);\n if (dcb) {\n dcb('denied', sd);\n this.spendListeners.delete(sd.requestId);\n }\n break;\n }\n\n case 'server:event':\n this.options.logger.debug({ event: result.payload }, 'Server event');\n break;\n\n case 'server:command':\n // Already handled by MessageHandler → onCommand callback\n break;\n }\n });\n\n this.ws.on('close', (code: number, reason: Buffer) => {\n this.authenticated = false;\n this.heartbeat?.stop();\n this.heartbeat = null;\n\n if (this.isShuttingDown) {\n this.options.logger.info('Connection closed');\n return;\n }\n\n this.options.logger.warn(\n { code, reason: reason.toString() },\n 'Connection lost',\n );\n this.options.onDisconnect();\n this.scheduleReconnect();\n });\n\n this.ws.on('error', (err: Error) => {\n this.options.logger.error({ err: err.message }, 'WebSocket error');\n });\n }\n\n reconnect(): void {\n this.heartbeat?.stop();\n this.heartbeat = null;\n this.ws?.close();\n }\n\n send<T>(type: string, payload: T): void {\n if (this.ws?.readyState !== WebSocket.OPEN) return;\n\n // NestJS @SubscribeMessage expects {event, data} format\n this.ws.send(JSON.stringify({ event: type, data: payload }));\n }\n\n disconnect(): void {\n this.isShuttingDown = true;\n\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n\n if (this.authenticated) {\n this.sendStatusReport('shutting_down');\n }\n\n this.heartbeat?.stop();\n this.ws?.close(1000, 'Client shutdown');\n }\n\n get isAuthenticated(): boolean {\n return this.authenticated;\n }\n\n private sendStatusReport(status: StatusReportPayload['status']): void {\n const payload: StatusReportPayload = {\n agentId: this.options.config.agentId!,\n status,\n version: AGENT_VERSION,\n platform: `${process.platform}-${process.arch}`,\n nodeVersion: process.versions.node,\n };\n this.send('agent:status_report', payload);\n }\n\n private scheduleReconnect(): void {\n const { wsReconnectBaseMs, wsReconnectMaxMs } = this.options.config;\n const delay = Math.min(\n wsReconnectBaseMs * 2 ** this.reconnectAttempt,\n wsReconnectMaxMs,\n );\n const jitter = Math.random() * delay * 0.1;\n const totalDelay = Math.round(delay + jitter);\n\n this.reconnectAttempt++;\n this.options.logger.info(\n { attempt: this.reconnectAttempt, delayMs: totalDelay },\n 'Reconnecting...',\n );\n\n this.reconnectTimer = setTimeout(() => {\n this.reconnectTimer = null;\n this.connect();\n }, totalDelay);\n }\n}\n","import type { HeartbeatPayload } from '@stamn/types';\n\nexport interface HeartbeatSender {\n send<T>(type: string, payload: T): void;\n reconnect(): void;\n}\n\nexport class Heartbeat {\n private timer: ReturnType<typeof setInterval> | null = null;\n private missedPongs = 0;\n private readonly maxMissedPongs = 3;\n\n constructor(\n private sender: HeartbeatSender,\n private agentId: string,\n private intervalMs: number,\n private startTime: number,\n ) {}\n\n start(): void {\n this.missedPongs = 0;\n this.timer = setInterval(() => {\n if (this.missedPongs >= this.maxMissedPongs) {\n this.sender.reconnect();\n return;\n }\n\n const payload: HeartbeatPayload = {\n agentId: this.agentId,\n uptimeSeconds: Math.floor((Date.now() - this.startTime) / 1000),\n memoryUsageMb: Math.round(process.memoryUsage().rss / 1024 / 1024),\n };\n\n this.sender.send('agent:heartbeat', payload);\n this.missedPongs++;\n }, this.intervalMs);\n }\n\n onAck(): void {\n this.missedPongs = 0;\n }\n\n stop(): void {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n }\n}\n","import type { Logger } from 'pino';\nimport { z } from 'zod';\nimport type { ServerToAgentMessageType, CommandPayload } from '@stamn/types';\n\n// NestJS WS sends {event, data} format\nconst wsMessageSchema = z.object({\n event: z.string(),\n data: z.unknown(),\n});\n\nconst commandPayloadSchema = z.object({\n commandId: z.string(),\n command: z.enum(['pause', 'resume', 'update_config', 'shutdown']),\n params: z.record(z.unknown()).optional(),\n});\n\nexport class MessageHandler {\n constructor(\n private logger: Logger,\n private onCommand: (\n command: string,\n params?: Record<string, unknown>,\n ) => void,\n ) {}\n\n handle(\n raw: string,\n ): { type: ServerToAgentMessageType; payload: unknown } | null {\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n this.logger.warn({ raw }, 'Invalid JSON received');\n return null;\n }\n\n const result = wsMessageSchema.safeParse(parsed);\n if (!result.success) {\n this.logger.warn({ error: result.error.message }, 'Invalid WS message');\n return null;\n }\n\n const { event, data } = result.data;\n\n switch (event) {\n case 'server:authenticated':\n case 'server:auth_error':\n case 'server:heartbeat_ack':\n case 'server:event':\n case 'server:spend_approved':\n case 'server:spend_denied':\n return {\n type: event as ServerToAgentMessageType,\n payload: data,\n };\n\n case 'server:command': {\n const cmdResult = commandPayloadSchema.safeParse(data);\n if (!cmdResult.success) {\n this.logger.warn(\n { error: cmdResult.error.message },\n 'Invalid command payload',\n );\n return null;\n }\n\n const cmd = cmdResult.data as CommandPayload;\n this.logger.info(\n { command: cmd.command, commandId: cmd.commandId },\n 'Received command',\n );\n this.onCommand(cmd.command, cmd.params);\n return { type: 'server:command', payload: cmd };\n }\n\n default:\n this.logger.debug({ type: event }, 'Unknown message type');\n return null;\n }\n }\n}\n","import { randomUUID } from 'crypto';\nimport type { Logger } from 'pino';\nimport type {\n SpendRequestPayload,\n SpendApprovedPayload,\n SpendDeniedPayload,\n LedgerCategory,\n LedgerRail,\n} from '@stamn/types';\nimport type { WSClient } from '../ws/ws-client.js';\n\nexport type SpendResult =\n | {\n approved: true;\n ledgerEntryId: string;\n transactionHash?: string;\n remainingBalanceCents: number;\n }\n | { approved: false; reason: string; code: string };\n\nexport interface SpendParams {\n amountCents: number;\n category: LedgerCategory;\n rail: LedgerRail;\n vendor?: string;\n description: string;\n recipientAgentId?: string;\n recipientAddress?: string;\n}\n\nconst SPEND_TIMEOUT_MS = 30_000;\n\nexport class SpendClient {\n constructor(\n private wsClient: WSClient,\n private logger: Logger,\n ) {}\n\n async request(params: SpendParams): Promise<SpendResult> {\n const requestId = randomUUID();\n\n const payload: SpendRequestPayload = {\n requestId,\n amountCents: params.amountCents,\n currency: 'USDC',\n category: params.category,\n rail: params.rail,\n vendor: params.vendor,\n description: params.description,\n recipientAgentId: params.recipientAgentId,\n recipientAddress: params.recipientAddress,\n };\n\n this.logger.info(\n {\n requestId,\n amountCents: params.amountCents,\n vendor: params.vendor,\n category: params.category,\n },\n `Requesting spend: ${params.description}`,\n );\n\n return new Promise<SpendResult>((resolve) => {\n const timeout = setTimeout(() => {\n this.wsClient.removeSpendListener(requestId);\n this.logger.error({ requestId }, 'Spend request timed out');\n resolve({\n approved: false,\n reason: 'Request timed out',\n code: 'timeout',\n });\n }, SPEND_TIMEOUT_MS);\n\n this.wsClient.onSpendResult(requestId, (type, result) => {\n clearTimeout(timeout);\n\n if (type === 'approved') {\n const approved = result as SpendApprovedPayload;\n this.logger.info(\n {\n requestId,\n ledgerEntryId: approved.ledgerEntryId,\n remainingBalanceCents: approved.remainingBalanceCents,\n },\n 'Spend approved',\n );\n resolve({\n approved: true,\n ledgerEntryId: approved.ledgerEntryId,\n transactionHash: approved.transactionHash,\n remainingBalanceCents: approved.remainingBalanceCents,\n });\n } else {\n const denied = result as SpendDeniedPayload;\n this.logger.warn(\n { requestId, code: denied.code, reason: denied.reason },\n 'Spend denied',\n );\n resolve({\n approved: false,\n reason: denied.reason,\n code: denied.code,\n });\n }\n });\n\n this.wsClient.send('agent:spend_request', payload);\n });\n }\n}\n"],"mappings":"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","names":["config"]}