@reefclaw/openclaw-plugin 0.1.0 → 0.1.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.
@@ -1,4 +1,17 @@
1
1
  import type { TradingMode, ExchangeConfig } from '../types.js';
2
+ /** The connection the AGENT saves during onboarding lives in OpenClaw's own
3
+ * config (`skills.entries.reefclaw.config` in ~/.openclaw/openclaw.json) —
4
+ * the connector reads it there, and since the chat-install flow never writes
5
+ * ~/.reefclaw/plugin-config.json, the PLUGIN must fall back to it too or
6
+ * every fresh install has working dashboards but token-starved intel tools,
7
+ * journaling ingest, and config polling (hit live on the first real user,
8
+ * 2026-07-06). Nested `.config.*` is the schema-valid shape; legacy flat
9
+ * fields are read as a fallback. Fail-soft: {} on any problem. */
10
+ export declare function readOpenClawConnection(): {
11
+ token?: string;
12
+ userId?: string;
13
+ relayUrl?: string;
14
+ };
2
15
  /** Full on-disk schema. Unknown keys are preserved on round-trip. */
3
16
  export interface PluginConfigFile {
4
17
  connectionToken?: string;
@@ -8,6 +8,33 @@
8
8
  import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync, } from 'node:fs';
9
9
  import { homedir } from 'node:os';
10
10
  import { dirname, join } from 'node:path';
11
+ /** The connection the AGENT saves during onboarding lives in OpenClaw's own
12
+ * config (`skills.entries.reefclaw.config` in ~/.openclaw/openclaw.json) —
13
+ * the connector reads it there, and since the chat-install flow never writes
14
+ * ~/.reefclaw/plugin-config.json, the PLUGIN must fall back to it too or
15
+ * every fresh install has working dashboards but token-starved intel tools,
16
+ * journaling ingest, and config polling (hit live on the first real user,
17
+ * 2026-07-06). Nested `.config.*` is the schema-valid shape; legacy flat
18
+ * fields are read as a fallback. Fail-soft: {} on any problem. */
19
+ export function readOpenClawConnection() {
20
+ try {
21
+ const path = process.env.OPENCLAW_CONFIG_PATH ?? join(homedir(), '.openclaw', 'openclaw.json');
22
+ if (!existsSync(path))
23
+ return {};
24
+ const parsed = JSON.parse(readFileSync(path, 'utf-8'));
25
+ const entry = parsed?.skills?.entries?.reefclaw;
26
+ if (!entry)
27
+ return {};
28
+ return {
29
+ token: entry.config?.token ?? entry.token,
30
+ userId: entry.config?.userId ?? entry.userId,
31
+ relayUrl: entry.config?.relayUrl ?? entry.relayUrl,
32
+ };
33
+ }
34
+ catch {
35
+ return {};
36
+ }
37
+ }
11
38
  export function defaultConfigPath() {
12
39
  return join(homedir(), '.reefclaw', 'plugin-config.json');
13
40
  }
@@ -64,6 +64,10 @@ export declare function getUserDataStreamIngestBaseUrl(config?: PluginConfigFile
64
64
  *
65
65
  * Both ingest paths (position-decisions journal + WS audit-trail) use this. */
66
66
  export declare function resolveIngestToken(config?: PluginConfigFile): string;
67
+ /** Resolve the trader's ReefClaw userId: env (legacy prod deployments) →
68
+ * the connection the agent saved in OpenClaw's config. Ingest paths need it
69
+ * alongside the token; fresh installs only ever have the latter source. */
70
+ export declare function resolveReefclawUserId(): string;
67
71
  /** Is the WS authoritative for reads (observe or enforce)? In shadow it's
68
72
  * only observed — REST remains the source of truth for getPositions etc. */
69
73
  export declare function userDataStreamAuthoritative(mode: UserDataStreamMode): boolean;
@@ -20,7 +20,7 @@
20
20
  // Transitions must progress forward only (no skipping). Deploy script enforces.
21
21
  // Reverse transitions to any earlier stage (including 'shadow' and 'off') are
22
22
  // always permitted as a safety-net rollback.
23
- import { readPluginConfig } from './plugin-config-io.js';
23
+ import { readPluginConfig, readOpenClawConnection } from './plugin-config-io.js';
24
24
  const VALID = new Set(['off', 'shadow', 'observe', 'enforce']);
25
25
  /** Allowed forward transitions. Reverse transitions are always permitted so
26
26
  * the operator can fall back to REST if WS misbehaves.
@@ -138,7 +138,22 @@ export function resolveIngestToken(config) {
138
138
  const fromConfig = config?.connectionToken;
139
139
  if (typeof fromConfig === 'string' && fromConfig.trim())
140
140
  return fromConfig.trim();
141
- return process.env.WEBAPP_INGEST_TOKEN ?? '';
141
+ const fromEnv = process.env.WEBAPP_INGEST_TOKEN ?? '';
142
+ if (fromEnv.trim())
143
+ return fromEnv.trim();
144
+ // Chat/npx onboarding stores the token only where the AGENT saves it —
145
+ // OpenClaw's own config. Without this fallback every fresh install has a
146
+ // token-starved plugin (intel tools, ingest, config poller all dead).
147
+ return readOpenClawConnection().token?.trim() ?? '';
148
+ }
149
+ /** Resolve the trader's ReefClaw userId: env (legacy prod deployments) →
150
+ * the connection the agent saved in OpenClaw's config. Ingest paths need it
151
+ * alongside the token; fresh installs only ever have the latter source. */
152
+ export function resolveReefclawUserId() {
153
+ const fromEnv = process.env.REEFCLAW_USER_ID ?? '';
154
+ if (fromEnv.trim())
155
+ return fromEnv.trim();
156
+ return readOpenClawConnection().userId?.trim() ?? '';
142
157
  }
143
158
  /** Is the WS authoritative for reads (observe or enforce)? In shadow it's
144
159
  * only observed — REST remains the source of truth for getPositions etc. */
package/index.js CHANGED
@@ -20,7 +20,7 @@ import { DEFAULT_CONFIG } from './types.js';
20
20
  import { PaperAdapter } from './paper-adapter.js';
21
21
  import { LiveAdapter } from './live/live-adapter.js';
22
22
  import { loadBracketMode } from './config/brackets-config.js';
23
- import { loadUserDataStreamMode, loadUserDataStreamTunables, loadUserDataStreamDbWrite, getUserDataStreamIngestBaseUrl, resolveIngestToken, } from './config/user-data-stream-config.js';
23
+ import { loadUserDataStreamMode, loadUserDataStreamTunables, loadUserDataStreamDbWrite, getUserDataStreamIngestBaseUrl, resolveIngestToken, resolveReefclawUserId, } from './config/user-data-stream-config.js';
24
24
  import { TradeStoreClient } from './ingest/trade-store-client.js';
25
25
  import { ProposalManager } from './live/proposal-manager.js';
26
26
  import { ProposalDecisionListener } from './live/proposal-decision-listener.js';
@@ -39,7 +39,7 @@ import { proposeLearningTool } from './tools/propose-learning.js';
39
39
  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
- import { readPluginConfig } from './config/plugin-config-io.js';
42
+ import { readPluginConfig, readOpenClawConnection } from './config/plugin-config-io.js';
43
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';
@@ -945,6 +945,17 @@ const paperTradingPlugin = {
945
945
  catch (err) {
946
946
  logger.warn(TAG, `Could not read ReefClaw config: ${formatError(err)}`);
947
947
  }
948
+ if (!connectionToken) {
949
+ // Chat/npx onboarding saves the connection ONLY in OpenClaw's config
950
+ // (skills.entries.reefclaw.config) — the agent writes it there and the
951
+ // connector reads it there. Fall back so a fresh install's intel tools,
952
+ // ingest, and config poller aren't token-starved (first-user bug).
953
+ const conn = readOpenClawConnection();
954
+ if (conn.token) {
955
+ connectionToken = conn.token;
956
+ logger.info(TAG, 'Connection token loaded from OpenClaw config (skills.entries.reefclaw)');
957
+ }
958
+ }
948
959
  if (connectionToken) {
949
960
  logger.info(TAG, `Connection token loaded (prefix: ${connectionToken.slice(0, 7)}...)`);
950
961
  }
@@ -1020,7 +1031,7 @@ const paperTradingPlugin = {
1020
1031
  // Ingest token: plugin-config.json `connectionToken` preferred, legacy
1021
1032
  // WEBAPP_INGEST_TOKEN env as fallback — see resolveIngestToken.
1022
1033
  const ingestToken = resolveIngestToken(cfgForIngest);
1023
- const reefclawUserId = process.env.REEFCLAW_USER_ID ?? '';
1034
+ const reefclawUserId = resolveReefclawUserId();
1024
1035
  if (ingestToken && reefclawUserId) {
1025
1036
  const ingestBaseUrl = getUserDataStreamIngestBaseUrl(cfgForIngest);
1026
1037
  positionDecisionsClient = new PositionDecisionsClient({
@@ -1124,7 +1135,7 @@ const paperTradingPlugin = {
1124
1135
  cfgForIngest = undefined;
1125
1136
  }
1126
1137
  const ingestToken = resolveIngestToken(cfgForIngest);
1127
- const reefclawUserId = process.env.REEFCLAW_USER_ID ?? '';
1138
+ const reefclawUserId = resolveReefclawUserId();
1128
1139
  if (userDataStreamMode !== 'off' &&
1129
1140
  dbWriteMode === 'on' &&
1130
1141
  ingestToken &&
package/package.json CHANGED
@@ -1,11 +1,19 @@
1
1
  {
2
2
  "name": "@reefclaw/openclaw-plugin",
3
- "version": "0.1.0",
4
- "description": "ReefClaw trading plugin for OpenClaw paper trading with real Binance market data, plus the ReefClaw dashboard connector (supervised by OpenClaw, no service manager needed). Install: /plugins install npm:@reefclaw/openclaw-plugin",
3
+ "version": "0.1.1",
4
+ "description": "ReefClaw trading plugin for OpenClaw \u2014 paper trading with real Binance market data, plus the ReefClaw dashboard connector (supervised by OpenClaw, no service manager needed). Install: /plugins install clawhub:@reefclaw/openclaw-plugin",
5
5
  "type": "module",
6
6
  "main": "index.js",
7
7
  "openclaw": {
8
- "extensions": ["./index.js"]
8
+ "extensions": [
9
+ "./index.js"
10
+ ],
11
+ "compat": {
12
+ "pluginApi": ">=2026.6.0"
13
+ },
14
+ "build": {
15
+ "openclawVersion": "2026.6.11"
16
+ }
9
17
  },
10
18
  "files": [
11
19
  "**/*"
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: reefclaw
3
- version: 0.0.3
3
+ version: 0.0.5
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
@@ -72,7 +72,7 @@ OpenClaw can install the ReefClaw plugin through its own owner chat command —
72
72
 
73
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
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.
75
+ 3. Then the user types: `/plugins install clawhub:@reefclaw/openclaw-plugin` — the install restarts OpenClaw automatically; the bundled connector starts by itself and the dashboard flips to Connected.
76
76
 
77
77
  Only fall back to `npx @reefclaw/connect` (below) when the chat install is unavailable.
78
78
 
@@ -1,6 +1,10 @@
1
- // 6 built-in strategy definitions for the Strategy Box.
2
- // Seeded into the strategies table on first run with is_builtin: true.
3
- // Users can toggle them on/off but cannot delete or modify them.
1
+ // LEGACY strategy configs used ONLY as fixtures by the local-evaluator
2
+ // tests (strategy/__tests__/evaluator.test.ts). NOT seeded anywhere and NOT
3
+ // part of the product catalog: the shipped catalog lives in
4
+ // intelligence/src/signals/strategy-store.ts (exactly two template
5
+ // strategies since the 2026-07-06 trim — see CLAUDE.md), and the plugin's
6
+ // local evaluator (signals.evaluator, default 'central') receives its
7
+ // strategy set from the intel service, not from this file.
4
8
  export const BUILTIN_STRATEGIES = [
5
9
  {
6
10
  name: 'trend_continuation',