@reefclaw/connect 0.1.3 → 0.1.4

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,4 +1,20 @@
1
1
  import { spawn } from 'node:child_process';
2
+ /** Bridge bundled INSIDE the plugin package (the npm-channel distribution
3
+ * `@reefclaw/openclaw-plugin` ships the connector at <pluginRoot>/bridge).
4
+ * Compiled connector-supervisor.js sits at the plugin dist root, so the
5
+ * bundled bridge is a sibling directory. */
6
+ export declare function bundledBridgeDir(): string;
7
+ /** Where the connector lives, in preference order: bundled-in-package first
8
+ * (npm-channel install — self-contained), then the npx installer's
9
+ * placement. Returns null when neither exists. */
10
+ export declare function resolveBridgeDir(): string | null;
11
+ /** True when the plugin should supervise the connector even WITHOUT an
12
+ * explicit connectorSupervisor='on' in plugin-config: the connector is
13
+ * bundled inside this plugin package, which only the npm-channel
14
+ * distribution does. Prod's linked plugin dir and the npx installer's
15
+ * ~/.reefclaw/plugin have no bridge/ subdir, so they stay opt-in — prod
16
+ * keeps running the bridge under systemd and must never double-connect. */
17
+ export declare function hasBundledBridge(): boolean;
2
18
  export interface ConnectorSupervisorOptions {
3
19
  /** Directory holding the placed bridge (default ~/.reefclaw/bridge). */
4
20
  bridgeDir?: string;
@@ -16,9 +16,36 @@
16
16
  import { spawn } from 'node:child_process';
17
17
  import { existsSync } from 'node:fs';
18
18
  import { homedir } from 'node:os';
19
- import { join } from 'node:path';
19
+ import { join, dirname } from 'node:path';
20
+ import { fileURLToPath } from 'node:url';
20
21
  import { logger } from './logger.js';
21
22
  const TAG = 'connector-supervisor';
23
+ /** Bridge bundled INSIDE the plugin package (the npm-channel distribution
24
+ * `@reefclaw/openclaw-plugin` ships the connector at <pluginRoot>/bridge).
25
+ * Compiled connector-supervisor.js sits at the plugin dist root, so the
26
+ * bundled bridge is a sibling directory. */
27
+ export function bundledBridgeDir() {
28
+ return join(dirname(fileURLToPath(import.meta.url)), 'bridge');
29
+ }
30
+ /** Where the connector lives, in preference order: bundled-in-package first
31
+ * (npm-channel install — self-contained), then the npx installer's
32
+ * placement. Returns null when neither exists. */
33
+ export function resolveBridgeDir() {
34
+ for (const dir of [bundledBridgeDir(), join(homedir(), '.reefclaw', 'bridge')]) {
35
+ if (existsSync(join(dir, 'index.js')))
36
+ return dir;
37
+ }
38
+ return null;
39
+ }
40
+ /** True when the plugin should supervise the connector even WITHOUT an
41
+ * explicit connectorSupervisor='on' in plugin-config: the connector is
42
+ * bundled inside this plugin package, which only the npm-channel
43
+ * distribution does. Prod's linked plugin dir and the npx installer's
44
+ * ~/.reefclaw/plugin have no bridge/ subdir, so they stay opt-in — prod
45
+ * keeps running the bridge under systemd and must never double-connect. */
46
+ export function hasBundledBridge() {
47
+ return existsSync(join(bundledBridgeDir(), 'index.js'));
48
+ }
22
49
  const MIN_BACKOFF_MS = 5_000;
23
50
  const MAX_BACKOFF_MS = 60_000;
24
51
  /** A child that survives this long resets the backoff (it was healthy). */
@@ -32,10 +59,14 @@ let singleton = null;
32
59
  export function startConnectorSupervisor(opts = {}) {
33
60
  if (singleton)
34
61
  return singleton;
35
- const bridgeDir = opts.bridgeDir ?? join(homedir(), '.reefclaw', 'bridge');
62
+ const bridgeDir = opts.bridgeDir ?? resolveBridgeDir();
63
+ if (!bridgeDir) {
64
+ logger.warn(TAG, 'connector not found (no bundled bridge/ and no ~/.reefclaw/bridge) — supervisor idle');
65
+ return null;
66
+ }
36
67
  const indexJs = join(bridgeDir, 'index.js');
37
68
  if (!existsSync(indexJs)) {
38
- logger.warn(TAG, `connector not found at ${indexJs} — supervisor idle (run the installer first)`);
69
+ logger.warn(TAG, `connector not found at ${indexJs} — supervisor idle`);
39
70
  return null;
40
71
  }
41
72
  const spawnFn = opts.spawnFn ?? spawn;
@@ -40,7 +40,7 @@ import { queryReviewOutcomesTool } from './tools/query-review-outcomes.js';
40
40
  import { loadPositionReviewMode } from './config/position-review-config.js';
41
41
  import { installSignalHandlers } from './lifecycle/install-signal-handlers.js';
42
42
  import { readPluginConfig } from './config/plugin-config-io.js';
43
- import { startConnectorSupervisor } from './connector-supervisor.js';
43
+ import { startConnectorSupervisor, hasBundledBridge } from './connector-supervisor.js';
44
44
  import { ToolGate } from './config/tool-gate.js';
45
45
  import { gateStore } from './config/gate-store.js';
46
46
  import { startAgentConfigPoller } from './config/agent-config-poller.js';
@@ -2010,8 +2010,16 @@ function maybeStartConnectorSupervisor() {
2010
2010
  if (process.env.RC_CONNECTOR_SUPERVISOR === 'off') {
2011
2011
  if (supervisorMode === 'on')
2012
2012
  logger.warn(TAG, 'connector supervisor disabled by RC_CONNECTOR_SUPERVISOR=off');
2013
+ return;
2013
2014
  }
2014
- else if (supervisorMode === 'on') {
2015
+ if (supervisorMode === 'off')
2016
+ return;
2017
+ // 'on' → explicit opt-in (the npx installer writes this).
2018
+ // undefined → auto-start ONLY when the connector is bundled inside this
2019
+ // plugin package (the npm-channel @reefclaw/openclaw-plugin distribution
2020
+ // is self-contained by design). Prod's linked plugin dir has no bundled
2021
+ // bridge and no flag → stays off; systemd keeps owning prod's bridge.
2022
+ if (supervisorMode === 'on' || hasBundledBridge()) {
2015
2023
  startConnectorSupervisor();
2016
2024
  }
2017
2025
  }
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: reefclaw
3
- version: 0.0.2
3
+ version: 0.0.3
4
4
  description: ReefClaw trading control room — bootstrap (connects your agent; full trading instructions arrive automatically after first connect)
5
5
  author: ReefClaw
6
6
  homepage: https://reefclaw.com
@@ -66,6 +66,16 @@ When a user gives you this message (or just a bare `Here's my ReefClaw token: rc
66
66
  - After saving, the connector picks the config up within seconds (it restarts until a token appears). The user does not need to run any command.
67
67
  - If you cannot write the config yourself (e.g. exec or file access is restricted in this session), show the user this exact JSON snippet and where it goes, and offer to verify it after they save it.
68
68
 
69
+ ## Installing without any terminal (preferred)
70
+
71
+ OpenClaw can install the ReefClaw plugin through its own owner chat command — no exec, no terminal:
72
+
73
+ 1. In `~/.openclaw/openclaw.json` set `commands.plugins: true` and add the user's **sender id** (visible in this session) to `commands.ownerAllowFrom`.
74
+ 2. Tell the user to type `/restart` in this chat.
75
+ 3. Then the user types: `/plugins install npm:@reefclaw/openclaw-plugin` — the install restarts OpenClaw automatically; the bundled connector starts by itself and the dashboard flips to Connected.
76
+
77
+ Only fall back to `npx @reefclaw/connect` (below) when the chat install is unavailable.
78
+
69
79
  ## If you cannot run the installer (elevated exec disabled)
70
80
 
71
81
  Fresh OpenClaw installs deny elevated (host) exec from chat sessions. If `npx @reefclaw/connect` is blocked, do NOT dead-end — offer the user this choice:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reefclaw/connect",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "One-command installer that connects your OpenClaw agent to ReefClaw (paper trading, no exchange keys).",
5
5
  "type": "module",
6
6
  "bin": {