@filiptrivan/openclaw-helmio-chat-probe 0.0.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.
package/README.md ADDED
@@ -0,0 +1,38 @@
1
+ # @filiptrivan/openclaw-helmio-chat-probe
2
+
3
+ ADR-0008 probe plugin. **Throwaway.** Validates two narrow things:
4
+
5
+ - **C1** — `@microsoft/signalr` Node client survives inside the OpenClaw plugin runtime (long-lived connection, auto-reconnect after `pkill -9 node`, access-token callback works).
6
+ - **C4** — plugin installs cleanly into OpenClaw via `openclaw plugins install npm:@filiptrivan/openclaw-helmio-chat-probe@<ver>` at cloud-init against the pinned image.
7
+
8
+ Not the real `@helmio/openclaw-helmio-chat` plugin. No channel registration, no message routing, no group primitives. Those land in the real plugin once ADR-0008 ratifies. The personal `@filiptrivan` scope is a temporary stand-in for `@helmio` org until the org is set up on npm; the install path is identical, only the package name differs.
9
+
10
+ ## Build
11
+
12
+ ```bash
13
+ npm install
14
+ npm run build
15
+ ```
16
+
17
+ ## Publish (one-time setup before C4 can run)
18
+
19
+ ```bash
20
+ npm login # as filiptrivan
21
+ npm publish --access public # public — no NPM_TOKEN needed on probe VMs
22
+ ```
23
+
24
+ ## Install (from cloud-init, see infrastructure/cloud-init/probe-c4-install.sh)
25
+
26
+ ```bash
27
+ docker exec openclaw openclaw plugins install npm:@filiptrivan/openclaw-helmio-chat-probe@0.0.1
28
+ docker exec openclaw openclaw gateway restart
29
+ docker exec openclaw openclaw plugins inspect helmio-chat-probe --runtime --json
30
+ ```
31
+
32
+ ## Runtime env vars (set on the container, read at registerFull)
33
+
34
+ - `HELMIO_PROBE_HUB_URL` — SignalR hub URL, e.g. `https://api.helmio.ai/chat` (or whatever `probe-c1` branch deploys to).
35
+ - `HELMIO_CHAT_BRIDGE_TOKEN_PROBE` — static bearer token shared with the hub for the probe run.
36
+ - `HELMIO_PROBE_LOG_PATH` — optional, defaults to `/tmp/helmio-chat-probe.log`. ProbeC1.cs reads this file via `docker exec ... cat`.
37
+
38
+ If hub URL or token are missing, the plugin loads (C4 still passes) but skips the SignalR connection (C1 will skip).
@@ -0,0 +1,11 @@
1
+ export declare const ProbeEvent: {
2
+ readonly Connected: "connected";
3
+ readonly Reconnecting: "reconnecting";
4
+ readonly Reconnected: "reconnected";
5
+ readonly Closed: "closed";
6
+ readonly RestartInitiated: "restart_initiated";
7
+ readonly ConnectFailed: "connect_failed";
8
+ readonly EchoReturned: "echo_returned";
9
+ readonly Heartbeat: "heartbeat";
10
+ };
11
+ export type ProbeEventName = (typeof ProbeEvent)[keyof typeof ProbeEvent];
package/dist/events.js ADDED
@@ -0,0 +1,14 @@
1
+ // Shared event-name vocabulary between the TS plugin and the C# probe.
2
+ // Mirror file: integration-probe/helmio-native-chat/probe-c1/ProbeEvents.cs.
3
+ // Renaming an entry without updating both sides fails the probe silently.
4
+ export const ProbeEvent = {
5
+ Connected: "connected",
6
+ Reconnecting: "reconnecting",
7
+ Reconnected: "reconnected",
8
+ Closed: "closed",
9
+ RestartInitiated: "restart_initiated",
10
+ ConnectFailed: "connect_failed",
11
+ EchoReturned: "echo_returned",
12
+ Heartbeat: "heartbeat",
13
+ };
14
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,6EAA6E;AAC7E,0EAA0E;AAE1E,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,SAAS,EAAE,WAAW;IACtB,YAAY,EAAE,cAAc;IAC5B,WAAW,EAAE,aAAa;IAC1B,MAAM,EAAE,QAAQ;IAChB,gBAAgB,EAAE,mBAAmB;IACrC,aAAa,EAAE,gBAAgB;IAC/B,YAAY,EAAE,eAAe;IAC7B,SAAS,EAAE,WAAW;CACd,CAAC"}
@@ -0,0 +1,2 @@
1
+ declare const _default: import("openclaw/plugin-sdk/plugin-entry").PluginEntryDefinition;
2
+ export default _default;
package/dist/index.js ADDED
@@ -0,0 +1,37 @@
1
+ // ADR-0008 probe plugin (throwaway). Validates SignalR Node client in OpenClaw
2
+ // plugin runtime (C1) and the npm install path (C4). Not the real
3
+ // @helmio/openclaw-helmio-chat — no channel registration, no message routing.
4
+ import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
5
+ import { startProbeRunner } from "./probe-runner.js";
6
+ let runner;
7
+ export default definePluginEntry({
8
+ id: "helmio-chat-probe",
9
+ displayName: "Helmio Chat Probe (ADR-0008 C1/C4)",
10
+ version: "0.0.1",
11
+ registerFull(api) {
12
+ const hubUrl = process.env.HELMIO_PROBE_HUB_URL;
13
+ const token = process.env.HELMIO_CHAT_BRIDGE_TOKEN_PROBE;
14
+ const logPath = process.env.HELMIO_PROBE_LOG_PATH ?? "/tmp/helmio-chat-probe.log";
15
+ if (!hubUrl || !token) {
16
+ api.logger.warn("helmio-chat-probe: HELMIO_PROBE_HUB_URL or HELMIO_CHAT_BRIDGE_TOKEN_PROBE not set; " +
17
+ "plugin loaded but SignalR connection skipped (C4 still validates; C1 will skip).");
18
+ return;
19
+ }
20
+ api.logger.info(`helmio-chat-probe: dialing ${hubUrl} (logging to ${logPath})`);
21
+ runner = startProbeRunner({
22
+ hubUrl,
23
+ accessToken: token,
24
+ logPath,
25
+ logger: {
26
+ info: (m) => api.logger.info(m),
27
+ warn: (m) => api.logger.warn(m),
28
+ error: (m) => api.logger.error(m),
29
+ },
30
+ });
31
+ },
32
+ async dispose() {
33
+ await runner?.stop();
34
+ runner = undefined;
35
+ },
36
+ });
37
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,kEAAkE;AAClE,8EAA8E;AAE9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAoB,MAAM,mBAAmB,CAAC;AAEvE,IAAI,MAA+B,CAAC;AAEpC,eAAe,iBAAiB,CAAC;IAC/B,EAAE,EAAE,mBAAmB;IACvB,WAAW,EAAE,oCAAoC;IACjD,OAAO,EAAE,OAAO;IAChB,YAAY,CAAC,GAAG;QACd,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;QAChD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC;QACzD,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,4BAA4B,CAAC;QAElF,IAAI,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;YACtB,GAAG,CAAC,MAAM,CAAC,IAAI,CACb,qFAAqF;gBACnF,kFAAkF,CACrF,CAAC;YACF,OAAO;QACT,CAAC;QAED,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,8BAA8B,MAAM,gBAAgB,OAAO,GAAG,CAAC,CAAC;QAChF,MAAM,GAAG,gBAAgB,CAAC;YACxB,MAAM;YACN,WAAW,EAAE,KAAK;YAClB,OAAO;YACP,MAAM,EAAE;gBACN,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;gBAC/B,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;gBAC/B,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;aAClC;SACF,CAAC,CAAC;IACL,CAAC;IACD,KAAK,CAAC,OAAO;QACX,MAAM,MAAM,EAAE,IAAI,EAAE,CAAC;QACrB,MAAM,GAAG,SAAS,CAAC;IACrB,CAAC;CACF,CAAC,CAAC"}
@@ -0,0 +1,14 @@
1
+ export interface ProbeRunnerOptions {
2
+ hubUrl: string;
3
+ accessToken: string;
4
+ logPath: string;
5
+ logger: {
6
+ info: (m: string) => void;
7
+ warn: (m: string) => void;
8
+ error: (m: string) => void;
9
+ };
10
+ }
11
+ export interface ProbeRunner {
12
+ stop(): Promise<void>;
13
+ }
14
+ export declare function startProbeRunner(opts: ProbeRunnerOptions): ProbeRunner;
@@ -0,0 +1,95 @@
1
+ // SignalR client lifecycle inside the OpenClaw plugin runtime. Event names
2
+ // come from ./events.ts; the C# probe matches the same vocabulary.
3
+ import { promises as fs } from "node:fs";
4
+ import { HubConnectionBuilder, HubConnectionState, LogLevel, } from "@microsoft/signalr";
5
+ import { ProbeEvent } from "./events.js";
6
+ export function startProbeRunner(opts) {
7
+ let conn;
8
+ let stopped = false;
9
+ let tokenCallbackCount = 0;
10
+ const log = async (event, extra) => {
11
+ const line = JSON.stringify({
12
+ ts: new Date().toISOString(),
13
+ event,
14
+ pid: process.pid,
15
+ ...extra,
16
+ });
17
+ opts.logger.info(`helmio-chat-probe: ${line}`);
18
+ try {
19
+ await fs.appendFile(opts.logPath, line + "\n", { encoding: "utf8" });
20
+ }
21
+ catch (err) {
22
+ opts.logger.warn(`helmio-chat-probe: log write failed: ${err.message}`);
23
+ }
24
+ };
25
+ const buildConnection = () => new HubConnectionBuilder()
26
+ .withUrl(opts.hubUrl, {
27
+ accessTokenFactory: () => {
28
+ tokenCallbackCount += 1;
29
+ return opts.accessToken;
30
+ },
31
+ })
32
+ .withAutomaticReconnect({
33
+ nextRetryDelayInMilliseconds: (retryContext) => {
34
+ const delays = [1000, 2000, 5000, 10000];
35
+ return delays[retryContext.previousRetryCount] ?? 15000;
36
+ },
37
+ })
38
+ .configureLogging(LogLevel.Information)
39
+ .build();
40
+ const wire = (c) => {
41
+ c.onreconnecting((err) => {
42
+ void log(ProbeEvent.Reconnecting, { error: err?.message });
43
+ });
44
+ c.onreconnected((connectionId) => {
45
+ void log(ProbeEvent.Reconnected, { connectionId, tokenCallbackCount });
46
+ });
47
+ c.onclose((err) => {
48
+ void log(ProbeEvent.Closed, { error: err?.message });
49
+ // withAutomaticReconnect returns 15000 forever (no give-up), so onclose
50
+ // means an unrecoverable error (e.g., 401). Restart manually to observe
51
+ // recovery across a full socket recreate.
52
+ if (!stopped) {
53
+ setTimeout(() => void restart(), 5000);
54
+ }
55
+ });
56
+ };
57
+ const restart = async () => {
58
+ if (stopped)
59
+ return;
60
+ await log(ProbeEvent.RestartInitiated);
61
+ conn = buildConnection();
62
+ wire(conn);
63
+ try {
64
+ await conn.start();
65
+ await log(ProbeEvent.Connected, { tokenCallbackCount });
66
+ const echo = await conn.invoke("Echo", "probe-c1");
67
+ await log(ProbeEvent.EchoReturned, { echo });
68
+ }
69
+ catch (err) {
70
+ await log(ProbeEvent.ConnectFailed, { error: err.message });
71
+ if (!stopped)
72
+ setTimeout(() => void restart(), 5000);
73
+ }
74
+ };
75
+ void restart();
76
+ const heartbeat = setInterval(() => {
77
+ void log(ProbeEvent.Heartbeat, {
78
+ state: conn?.state ?? HubConnectionState.Disconnected,
79
+ connectionId: conn?.connectionId,
80
+ });
81
+ }, 60_000);
82
+ return {
83
+ async stop() {
84
+ stopped = true;
85
+ clearInterval(heartbeat);
86
+ try {
87
+ await conn?.stop();
88
+ }
89
+ catch (err) {
90
+ opts.logger.warn(`helmio-chat-probe: stop failed: ${err.message}`);
91
+ }
92
+ },
93
+ };
94
+ }
95
+ //# sourceMappingURL=probe-runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"probe-runner.js","sourceRoot":"","sources":["../src/probe-runner.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@filiptrivan/openclaw-helmio-chat-probe",
3
+ "version": "0.0.1",
4
+ "private": false,
5
+ "description": "ADR-0008 probe plugin (published under @filiptrivan personal scope as a temporary stand-in for @helmio org): validates SignalR Node client (C1) and OpenClaw plugin install path (C4). Throwaway; not the real @helmio/openclaw-helmio-chat plugin.",
6
+ "type": "module",
7
+ "license": "MIT",
8
+ "files": [
9
+ "dist",
10
+ "README.md"
11
+ ],
12
+ "main": "./dist/index.js",
13
+ "exports": {
14
+ ".": "./dist/index.js"
15
+ },
16
+ "openclaw": {
17
+ "extensions": [
18
+ "./dist/index.js"
19
+ ],
20
+ "compat": {
21
+ "minGatewayVersion": "2026.2.26"
22
+ }
23
+ },
24
+ "scripts": {
25
+ "build": "tsc -p tsconfig.json",
26
+ "prepublishOnly": "npm run build"
27
+ },
28
+ "dependencies": {
29
+ "@microsoft/signalr": "^8.0.7"
30
+ },
31
+ "devDependencies": {
32
+ "typescript": "^5.6.3",
33
+ "@types/node": "^20.12.7"
34
+ },
35
+ "engines": {
36
+ "node": ">=20.0.0"
37
+ },
38
+ "publishConfig": {
39
+ "access": "public"
40
+ }
41
+ }