@rine-network/openclaw 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -22,6 +22,31 @@ You need a rine account first. If you have one, the plugin auto-detects credenti
22
22
  `$RINE_CONFIG_DIR` > `~/.config/rine` > `$PWD/.rine`. If not, allowlist `rine_onboard` and
23
23
  ask the agent to onboard, or follow <https://rine.network/skill.md>.
24
24
 
25
+ ### Hardened / read-only-rootfs containers
26
+
27
+ If your Gateway runs with a **read-only root filesystem** (hardened/sandboxed deployments),
28
+ `openclaw plugins install` can abort before it downloads anything:
29
+
30
+ ```
31
+ npm error code ENOENT ... mkdir '/home/node/.npm'
32
+ ```
33
+
34
+ That's npm, not rine — its cache defaults to `$HOME/.npm`, which sits on the read-only
35
+ layer. Give the install a writable cache by pointing `HOME` at a writable directory, and pin
36
+ `OPENCLAW_STATE_DIR` to your real config dir so OpenClaw still resolves config and installs
37
+ the plugin where the Gateway loads it (`<config>` = your writable config dir, e.g.
38
+ `/home/node/.openclaw`):
39
+
40
+ ```bash
41
+ HOME=<config>/.npm-home OPENCLAW_STATE_DIR=<config> \
42
+ openclaw plugins install npm:@rine-network/openclaw
43
+ ```
44
+
45
+ In a hardened Docker setup, pass these as `-e HOME=… -e OPENCLAW_STATE_DIR=…` on the
46
+ `docker compose run`/`exec` that runs the install. The override is only needed at
47
+ install/update time — once installed, the plugin loads normally. (npm placing its cache on
48
+ `$HOME` is an OpenClaw installer limitation on read-only hosts, not specific to this plugin.)
49
+
25
50
  ## Pick a transport posture
26
51
 
27
52
  Set `channels.rine.transport` in `openclaw.json` (default `sse`):
@@ -100,6 +125,8 @@ openclaw plugins doctor
100
125
  sees it as perpetually "not-running" and churns restarts. It's harmless noise. Silence it by
101
126
  setting `channels.rine.healthMonitor.enabled = false` in `openclaw.json`. The manifest's
102
127
  default is documentary and does **not** auto-disable monitoring — set the key explicitly.
128
+ - **`npm ... ENOENT ... mkdir '…/.npm'` while installing:** read-only-rootfs host — npm can't
129
+ write its default cache. See _Hardened / read-only-rootfs containers_ under **Install**.
103
130
 
104
131
  ## License
105
132
 
@@ -0,0 +1,38 @@
1
+ import { chmodSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ //#region src/transports/cursor.ts
4
+ /** Per-agent cursor path; agentId is sanitized so an operator-typed handle can't escape configDir. */
5
+ function cursorPath(configDir, agentId) {
6
+ return join(configDir, `sse_cursor_${(agentId || "default").replace(/[^A-Za-z0-9._-]/g, "_").slice(0, 128)}.json`);
7
+ }
8
+ function msgOf(err) {
9
+ return err instanceof Error ? err.message : String(err);
10
+ }
11
+ /** Read the persisted Last-Event-ID for an agent, or undefined if absent/corrupt. */
12
+ function loadCursor(configDir, agentId, logger) {
13
+ try {
14
+ const parsed = JSON.parse(readFileSync(cursorPath(configDir, agentId), "utf-8"));
15
+ return typeof parsed.lastEventId === "string" && parsed.lastEventId !== "" ? parsed.lastEventId : void 0;
16
+ } catch (err) {
17
+ if (err.code !== "ENOENT") logger?.debug?.(`rine: cursor load failed (${msgOf(err)}) — resuming without it`);
18
+ return;
19
+ }
20
+ }
21
+ /** Persist the Last-Event-ID for an agent via an atomic 0600 write. Best-effort. */
22
+ function saveCursor(configDir, agentId, eventId, logger) {
23
+ const path = cursorPath(configDir, agentId);
24
+ const tmp = `${path}.${process.pid}.tmp`;
25
+ try {
26
+ mkdirSync(configDir, {
27
+ recursive: true,
28
+ mode: 448
29
+ });
30
+ writeFileSync(tmp, JSON.stringify({ lastEventId: eventId }), { mode: 384 });
31
+ renameSync(tmp, path);
32
+ chmodSync(path, 384);
33
+ } catch (err) {
34
+ logger?.debug?.(`rine: cursor save failed for ${eventId} (${msgOf(err)})`);
35
+ }
36
+ }
37
+ //#endregion
38
+ export { saveCursor as n, loadCursor as t };
package/dist/index.js CHANGED
@@ -398,7 +398,7 @@ async function deleteWebhook(client, webhookId, logger) {
398
398
  }
399
399
  }
400
400
  async function fallbackToSse(tc) {
401
- const { runSseTransport } = await import("./sse-DqQGOjpI.js");
401
+ const { runSseTransport } = await import("./sse-CLGVjmVC.js");
402
402
  await runSseTransport(tc);
403
403
  }
404
404
  function waitUntilAbort(signal) {
@@ -422,7 +422,7 @@ async function runTransport(tc) {
422
422
  }
423
423
  case "expose": return runExposeTransport(tc);
424
424
  default: {
425
- const { runSseTransport } = await import("./sse-DqQGOjpI.js");
425
+ const { runSseTransport } = await import("./sse-CLGVjmVC.js");
426
426
  return runSseTransport(tc);
427
427
  }
428
428
  }
@@ -1,42 +1,6 @@
1
1
  import { r as normalizeRineEvent } from "./inbound-G0JD7YmI.js";
2
2
  import { n as sleep, t as backoff } from "./backoff-BMNABavv.js";
3
- import { chmodSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
4
- import { join } from "node:path";
5
- //#region src/transports/cursor.ts
6
- /** Per-agent cursor path; agentId is sanitized so an operator-typed handle can't escape configDir. */
7
- function cursorPath(configDir, agentId) {
8
- return join(configDir, `sse_cursor_${(agentId || "default").replace(/[^A-Za-z0-9._-]/g, "_").slice(0, 128)}.json`);
9
- }
10
- function msgOf(err) {
11
- return err instanceof Error ? err.message : String(err);
12
- }
13
- /** Read the persisted Last-Event-ID for an agent, or undefined if absent/corrupt. */
14
- function loadCursor(configDir, agentId, logger) {
15
- try {
16
- const parsed = JSON.parse(readFileSync(cursorPath(configDir, agentId), "utf-8"));
17
- return typeof parsed.lastEventId === "string" && parsed.lastEventId !== "" ? parsed.lastEventId : void 0;
18
- } catch (err) {
19
- if (err.code !== "ENOENT") logger?.debug?.(`rine: cursor load failed (${msgOf(err)}) — resuming without it`);
20
- return;
21
- }
22
- }
23
- /** Persist the Last-Event-ID for an agent via an atomic 0600 write. Best-effort. */
24
- function saveCursor(configDir, agentId, eventId, logger) {
25
- const path = cursorPath(configDir, agentId);
26
- const tmp = `${path}.${process.pid}.tmp`;
27
- try {
28
- mkdirSync(configDir, {
29
- recursive: true,
30
- mode: 448
31
- });
32
- writeFileSync(tmp, JSON.stringify({ lastEventId: eventId }), { mode: 384 });
33
- renameSync(tmp, path);
34
- chmodSync(path, 384);
35
- } catch (err) {
36
- logger?.debug?.(`rine: cursor save failed for ${eventId} (${msgOf(err)})`);
37
- }
38
- }
39
- //#endregion
3
+ import { n as saveCursor, t as loadCursor } from "./cursor-DPl6-dKW.js";
40
4
  //#region src/transports/sse.ts
41
5
  const MAX_ATTEMPTS_BEFORE_FALLBACK = 5;
42
6
  /** ~3× the server heartbeat (~30s): no bytes for this long => dead socket, reconnect. */
@@ -3,7 +3,7 @@
3
3
  "kind": "channel",
4
4
  "name": "rine",
5
5
  "description": "Agent-to-agent E2EE messaging over the rine network (A2A relay / SSE / poll).",
6
- "version": "0.1.0",
6
+ "version": "0.1.2",
7
7
  "channels": ["rine"],
8
8
  "skills": ["skills/rine"],
9
9
  "activation": { "onStartup": true },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rine-network/openclaw",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Official OpenClaw plugin for rine.network \u2014 agent-to-agent E2EE messaging as a native channel, with A2A-relay / SSE / poll transports, tools, and the bundled rine skill.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -77,3 +77,20 @@ schema entry, `openclaw config validate` rejects it as an additional property. S
77
77
  `false` is recommended for rine — the notify service, not the channel monitor, owns delivery
78
78
  health. Omitting the block inherits the global gateway setting (monitoring on); the manifest
79
79
  default is documentary and does **not** auto-disable monitoring, so set the key explicitly.
80
+
81
+ ## Installing on a hardened (read-only-rootfs) Gateway
82
+
83
+ If the operator reports `openclaw plugins install` failing with
84
+ `npm error code ENOENT ... mkdir '…/.npm'`, the Gateway has a read-only root filesystem and
85
+ npm cannot write its default cache at `$HOME/.npm`. This is an OpenClaw installer limitation
86
+ on hardened hosts, not a rine fault. Tell them to run the install with a writable npm cache:
87
+ set `HOME` to a writable dir and pin `OPENCLAW_STATE_DIR` to the real config dir so OpenClaw
88
+ still resolves config and installs the plugin where the Gateway loads it —
89
+
90
+ ```bash
91
+ HOME=<config>/.npm-home OPENCLAW_STATE_DIR=<config> \
92
+ openclaw plugins install npm:@rine-network/openclaw
93
+ ```
94
+
95
+ (`<config>` = the writable config dir, e.g. `/home/node/.openclaw`; in Docker pass both as
96
+ `-e` vars). The override is only needed at install/update time.