@stamn/stamn-plugin 0.1.0-alpha.17 → 0.1.0-alpha.19

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/index.js CHANGED
@@ -5435,6 +5435,78 @@ var import_websocket = __toESM(require_websocket(), 1);
5435
5435
  var import_websocket_server = __toESM(require_websocket_server(), 1);
5436
5436
  var wrapper_default = import_websocket.default;
5437
5437
 
5438
+ // src/ws-service.ts
5439
+ import { hostname } from "os";
5440
+ import { execFile } from "child_process";
5441
+
5442
+ // src/log-reader.ts
5443
+ import { openSync, readSync, closeSync, statSync } from "fs";
5444
+ import { join as join5 } from "path";
5445
+ import { tmpdir as tmpdir3 } from "os";
5446
+ var LOG_DIR = join5(tmpdir3(), "openclaw");
5447
+ var DEFAULT_MAX_BYTES = 64 * 1024;
5448
+ var DEFAULT_LIMIT = 200;
5449
+ function getLogFilePath() {
5450
+ const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
5451
+ return join5(LOG_DIR, `openclaw-${date}.log`);
5452
+ }
5453
+ function readLogs(opts) {
5454
+ const file = getLogFilePath();
5455
+ const limit = opts.limit ?? DEFAULT_LIMIT;
5456
+ const maxBytes = opts.maxBytes ?? DEFAULT_MAX_BYTES;
5457
+ let cursor = opts.cursor;
5458
+ let stat;
5459
+ try {
5460
+ stat = statSync(file);
5461
+ } catch {
5462
+ return { lines: [], cursor: 0, size: 0, file, truncated: false, reset: false };
5463
+ }
5464
+ const size = stat.size;
5465
+ const reset = cursor > size;
5466
+ if (reset) cursor = 0;
5467
+ if (cursor >= size) {
5468
+ return { lines: [], cursor, size, file, truncated: false, reset };
5469
+ }
5470
+ const bytesToRead = Math.min(maxBytes, size - cursor);
5471
+ const buffer = Buffer.alloc(bytesToRead);
5472
+ const fd = openSync(file, "r");
5473
+ try {
5474
+ readSync(fd, buffer, 0, bytesToRead, cursor);
5475
+ } finally {
5476
+ closeSync(fd);
5477
+ }
5478
+ const raw = buffer.toString("utf-8");
5479
+ const rawLines = raw.split("\n");
5480
+ const atEof = cursor + bytesToRead >= size;
5481
+ let actualBytesConsumed = bytesToRead;
5482
+ if (!atEof && rawLines.length > 0 && !raw.endsWith("\n")) {
5483
+ const incomplete = rawLines.pop();
5484
+ actualBytesConsumed -= Buffer.byteLength(incomplete, "utf-8");
5485
+ }
5486
+ const lines = [];
5487
+ let truncated = false;
5488
+ for (const line of rawLines) {
5489
+ const trimmed = line.trim();
5490
+ if (!trimmed) continue;
5491
+ try {
5492
+ lines.push(JSON.parse(trimmed));
5493
+ } catch {
5494
+ }
5495
+ if (lines.length >= limit) {
5496
+ truncated = true;
5497
+ break;
5498
+ }
5499
+ }
5500
+ return {
5501
+ lines,
5502
+ cursor: cursor + actualBytesConsumed,
5503
+ size,
5504
+ file,
5505
+ truncated: truncated || !atEof,
5506
+ reset
5507
+ };
5508
+ }
5509
+
5438
5510
  // src/ws-service.ts
5439
5511
  var MAX_EVENT_BUFFER_SIZE = 200;
5440
5512
  var BASE_RECONNECT_DELAY_MS = 1e3;
@@ -5444,6 +5516,7 @@ var PLUGIN_VERSION = "0.1.0";
5444
5516
  var ServerEvent = {
5445
5517
  AUTHENTICATED: "server:authenticated",
5446
5518
  AUTH_ERROR: "server:auth_error",
5519
+ COMMAND: "server:command",
5447
5520
  HEARTBEAT_ACK: "server:heartbeat_ack",
5448
5521
  WORLD_UPDATE: "server:world_update",
5449
5522
  BALANCE: "server:balance",
@@ -5482,6 +5555,7 @@ var StamnWsService = class {
5482
5555
  this.messageHandlers = {
5483
5556
  [ServerEvent.AUTHENTICATED]: (d) => this.onAuthenticated(d),
5484
5557
  [ServerEvent.AUTH_ERROR]: (d) => this.onAuthError(d),
5558
+ [ServerEvent.COMMAND]: (d) => this.onCommand(d),
5485
5559
  [ServerEvent.HEARTBEAT_ACK]: () => this.logger.debug("Heartbeat acknowledged"),
5486
5560
  [ServerEvent.WORLD_UPDATE]: (d) => this.onWorldUpdate(d),
5487
5561
  [ServerEvent.BALANCE]: (d) => this.onBalanceUpdate(d),
@@ -5499,11 +5573,7 @@ var StamnWsService = class {
5499
5573
  async stop() {
5500
5574
  this.clearTimers();
5501
5575
  if (this.isSocketOpen()) {
5502
- this.sendMessage(ClientEvent.STATUS_REPORT, {
5503
- participantId: this.config.agentId,
5504
- status: "shutting_down",
5505
- version: PLUGIN_VERSION
5506
- });
5576
+ this.sendStatusReport("shutting_down");
5507
5577
  this.ws.close(1e3, "Plugin shutting down");
5508
5578
  }
5509
5579
  this.writeStatus(false);
@@ -5588,9 +5658,70 @@ var StamnWsService = class {
5588
5658
  this.logger.info(
5589
5659
  `Authenticated as ${payload.participantId} (server v${payload.serverVersion})`
5590
5660
  );
5661
+ this.sendStatusReport("online");
5591
5662
  this.startHeartbeat();
5592
5663
  this.writeStatus(true);
5593
5664
  }
5665
+ sendStatusReport(status) {
5666
+ this.sendMessage(ClientEvent.STATUS_REPORT, {
5667
+ participantId: this.config.agentId,
5668
+ status,
5669
+ version: PLUGIN_VERSION,
5670
+ platform: process.platform,
5671
+ hostname: hostname(),
5672
+ nodeVersion: process.version,
5673
+ arch: process.arch
5674
+ });
5675
+ }
5676
+ onCommand(payload) {
5677
+ this.logger.info(`Command received: ${payload.command} (${payload.commandId})`);
5678
+ if (payload.command === "update_plugin") {
5679
+ this.handleUpdatePlugin();
5680
+ return;
5681
+ }
5682
+ if (payload.command === "request_logs") {
5683
+ this.handleRequestLogs(payload.params);
5684
+ return;
5685
+ }
5686
+ this.bufferEvent(ServerEvent.COMMAND, payload);
5687
+ }
5688
+ handleUpdatePlugin() {
5689
+ this.logger.info("Updating plugin via openclaw...");
5690
+ execFile("openclaw", ["plugins", "update", "stamn-plugin"], (err, stdout, stderr) => {
5691
+ if (err) {
5692
+ this.logger.error(`Plugin update failed: ${err.message}`);
5693
+ if (stderr) this.logger.error(stderr);
5694
+ return;
5695
+ }
5696
+ this.logger.info(`Plugin updated: ${stdout.trim()}`);
5697
+ this.sendStatusReport("online");
5698
+ });
5699
+ }
5700
+ handleRequestLogs(params) {
5701
+ try {
5702
+ const result = readLogs({
5703
+ cursor: params.cursor,
5704
+ limit: params.limit,
5705
+ maxBytes: params.maxBytes
5706
+ });
5707
+ this.sendMessage("participant:log_response", {
5708
+ requestId: params.requestId,
5709
+ ...result
5710
+ });
5711
+ } catch (err) {
5712
+ this.logger.error(`Failed to read logs: ${err}`);
5713
+ this.sendMessage("participant:log_response", {
5714
+ requestId: params.requestId,
5715
+ lines: [],
5716
+ cursor: params.cursor,
5717
+ size: 0,
5718
+ file: "",
5719
+ truncated: false,
5720
+ reset: false,
5721
+ error: err.message
5722
+ });
5723
+ }
5724
+ }
5594
5725
  onAuthError(payload) {
5595
5726
  this.authFailed = true;
5596
5727
  this.logger.error(`Authentication failed: ${payload.reason}`);