@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 +27 -0
- package/dist/cursor-DPl6-dKW.js +38 -0
- package/dist/index.js +2 -2
- package/dist/{sse-DqQGOjpI.js → sse-CLGVjmVC.js} +1 -37
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/skills/rine/references/openclaw.md +17 -0
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-
|
|
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-
|
|
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 {
|
|
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. */
|
package/openclaw.plugin.json
CHANGED
|
@@ -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.
|
|
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.
|
|
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.
|