@rrwebcloud/openclaw-session-recording 2026.3.28-1 → 2026.3.28
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 +0 -2
- package/index.ts +15 -83
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -21,8 +21,6 @@ plugins:
|
|
|
21
21
|
|
|
22
22
|
## Notes
|
|
23
23
|
|
|
24
|
-
- OpenClaw `2026.3.24+` uses the full automatic browser-runtime integration path
|
|
25
|
-
- OpenClaw `2026.3.13` loads in legacy compatibility mode and reports clear next steps instead of failing on install
|
|
26
24
|
- `serverUrl` defaults to `https://api.rrwebcloud.com`
|
|
27
25
|
- `secretKey` is not required for the bundled browser flow
|
|
28
26
|
- the plugin targets managed Chromium browser profiles such as `openclaw`
|
package/index.ts
CHANGED
|
@@ -2,6 +2,12 @@ import crypto from "node:crypto";
|
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { Type } from "@sinclair/typebox";
|
|
5
|
+
import {
|
|
6
|
+
clearManagedBrowserReplayContextsForSession,
|
|
7
|
+
registerManagedBrowserExtensions,
|
|
8
|
+
setManagedBrowserReplayContext,
|
|
9
|
+
unregisterManagedBrowserExtensions,
|
|
10
|
+
} from "openclaw/plugin-sdk/browser-runtime";
|
|
5
11
|
import { readJsonFileWithFallback, writeJsonFileAtomically } from "openclaw/plugin-sdk/json-store";
|
|
6
12
|
import { definePluginEntry, type OpenClawPluginApi } from "openclaw/plugin-sdk/plugin-entry";
|
|
7
13
|
import { type AnyAgentTool, type OpenClawConfig } from "openclaw/plugin-sdk/plugin-entry";
|
|
@@ -39,28 +45,6 @@ type ReplayStateStore = {
|
|
|
39
45
|
|
|
40
46
|
const RRWEB_PLUGIN_ID = "rrweb-replay";
|
|
41
47
|
const DEFAULT_RRWEB_API_BASE_URL = "https://api.rrwebcloud.com";
|
|
42
|
-
const LEGACY_BROWSER_RUNTIME_REASON =
|
|
43
|
-
"This OpenClaw host does not export plugin-sdk/browser-runtime. Automatic rrweb extension wiring requires OpenClaw >=2026.3.24. On legacy hosts, install/configure the rrweb browser addon separately or upgrade OpenClaw.";
|
|
44
|
-
|
|
45
|
-
type BrowserRuntimeCompat = {
|
|
46
|
-
clearManagedBrowserReplayContextsForSession: (sessionKey: string) => void;
|
|
47
|
-
registerManagedBrowserExtensions: (params: {
|
|
48
|
-
sourceId: string;
|
|
49
|
-
profiles: string[];
|
|
50
|
-
extensionPaths: string[];
|
|
51
|
-
}) => void;
|
|
52
|
-
setManagedBrowserReplayContext: (params: {
|
|
53
|
-
cdpUrl: string;
|
|
54
|
-
profile: string;
|
|
55
|
-
sessionKey?: string;
|
|
56
|
-
sessionId?: string;
|
|
57
|
-
replaySessionId: string;
|
|
58
|
-
replayServerUrl?: string;
|
|
59
|
-
replayUrl?: string;
|
|
60
|
-
updatedAt: string;
|
|
61
|
-
}) => void;
|
|
62
|
-
unregisterManagedBrowserExtensions: (sourceId: string) => void;
|
|
63
|
-
};
|
|
64
48
|
|
|
65
49
|
const rrwebReplayConfigSchema = {
|
|
66
50
|
parse(value: unknown): RrwebReplayConfig {
|
|
@@ -226,17 +210,10 @@ function buildReplaySessionState(params: {
|
|
|
226
210
|
function describeReplayAvailability(params: {
|
|
227
211
|
config: RrwebReplayConfig;
|
|
228
212
|
extensionDir: string | null;
|
|
229
|
-
browserRuntimeAvailable: boolean;
|
|
230
213
|
}): { enabled: boolean; reason?: string } {
|
|
231
214
|
if (!params.config.enabled) {
|
|
232
215
|
return { enabled: false, reason: "Plugin disabled in rrweb-replay config." };
|
|
233
216
|
}
|
|
234
|
-
if (!params.browserRuntimeAvailable) {
|
|
235
|
-
return {
|
|
236
|
-
enabled: false,
|
|
237
|
-
reason: LEGACY_BROWSER_RUNTIME_REASON,
|
|
238
|
-
};
|
|
239
|
-
}
|
|
240
217
|
if (!params.extensionDir) {
|
|
241
218
|
return {
|
|
242
219
|
enabled: false,
|
|
@@ -257,23 +234,6 @@ function describeReplayAvailability(params: {
|
|
|
257
234
|
return { enabled: true };
|
|
258
235
|
}
|
|
259
236
|
|
|
260
|
-
async function loadBrowserRuntimeCompat(): Promise<BrowserRuntimeCompat | null> {
|
|
261
|
-
try {
|
|
262
|
-
const mod = (await import("openclaw/plugin-sdk/browser-runtime")) as BrowserRuntimeCompat;
|
|
263
|
-
if (
|
|
264
|
-
typeof mod.registerManagedBrowserExtensions === "function" &&
|
|
265
|
-
typeof mod.unregisterManagedBrowserExtensions === "function" &&
|
|
266
|
-
typeof mod.setManagedBrowserReplayContext === "function" &&
|
|
267
|
-
typeof mod.clearManagedBrowserReplayContextsForSession === "function"
|
|
268
|
-
) {
|
|
269
|
-
return mod;
|
|
270
|
-
}
|
|
271
|
-
} catch {
|
|
272
|
-
// Legacy OpenClaw hosts do not expose plugin-sdk/browser-runtime.
|
|
273
|
-
}
|
|
274
|
-
return null;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
237
|
function resolveBrowserProfileForReplay(params: {
|
|
278
238
|
config: OpenClawConfig;
|
|
279
239
|
preferredProfile?: string;
|
|
@@ -393,7 +353,6 @@ async function markReplaySessionEnded(params: {
|
|
|
393
353
|
async function armReplayContext(params: {
|
|
394
354
|
api: OpenClawPluginApi;
|
|
395
355
|
pluginConfig: RrwebReplayConfig;
|
|
396
|
-
browserRuntime: BrowserRuntimeCompat | null;
|
|
397
356
|
sessionKey?: string;
|
|
398
357
|
sessionId?: string;
|
|
399
358
|
preferredProfile?: string;
|
|
@@ -414,10 +373,10 @@ async function armReplayContext(params: {
|
|
|
414
373
|
config: params.api.config,
|
|
415
374
|
preferredProfile: params.preferredProfile ?? replayEntry.currentProfile,
|
|
416
375
|
});
|
|
417
|
-
if (!
|
|
376
|
+
if (!profile || !profile.cdpUrl) {
|
|
418
377
|
return replayEntry;
|
|
419
378
|
}
|
|
420
|
-
|
|
379
|
+
setManagedBrowserReplayContext({
|
|
421
380
|
cdpUrl: profile.cdpUrl,
|
|
422
381
|
profile: profile.name,
|
|
423
382
|
sessionKey: params.sessionKey,
|
|
@@ -446,7 +405,6 @@ function createReplaySessionInfoTool(params: {
|
|
|
446
405
|
api: OpenClawPluginApi;
|
|
447
406
|
pluginConfig: RrwebReplayConfig;
|
|
448
407
|
extensionDir: string | null;
|
|
449
|
-
browserRuntimePromise: Promise<BrowserRuntimeCompat | null>;
|
|
450
408
|
context: {
|
|
451
409
|
sessionKey?: string;
|
|
452
410
|
sessionId?: string;
|
|
@@ -471,13 +429,11 @@ function createReplaySessionInfoTool(params: {
|
|
|
471
429
|
),
|
|
472
430
|
}),
|
|
473
431
|
execute: async (_id, rawParams) => {
|
|
474
|
-
const browserRuntime = await params.browserRuntimePromise;
|
|
475
432
|
const toolParams =
|
|
476
433
|
rawParams && typeof rawParams === "object" ? (rawParams as Record<string, unknown>) : null;
|
|
477
434
|
const availability = describeReplayAvailability({
|
|
478
435
|
config: params.pluginConfig,
|
|
479
436
|
extensionDir: params.extensionDir,
|
|
480
|
-
browserRuntimeAvailable: Boolean(browserRuntime),
|
|
481
437
|
});
|
|
482
438
|
const activate = toolParams?.activate === true;
|
|
483
439
|
const preferredProfile = toolParams
|
|
@@ -506,7 +462,6 @@ function createReplaySessionInfoTool(params: {
|
|
|
506
462
|
entry = await armReplayContext({
|
|
507
463
|
api: params.api,
|
|
508
464
|
pluginConfig: params.pluginConfig,
|
|
509
|
-
browserRuntime,
|
|
510
465
|
sessionKey: params.context.sessionKey,
|
|
511
466
|
sessionId: params.context.sessionId,
|
|
512
467
|
preferredProfile,
|
|
@@ -524,7 +479,6 @@ function createReplaySessionInfoTool(params: {
|
|
|
524
479
|
enabled: availability.enabled,
|
|
525
480
|
reason: availability.reason ?? entry.reason ?? null,
|
|
526
481
|
activated: activate && availability.enabled,
|
|
527
|
-
compatibilityMode: browserRuntime ? "modern" : "legacy",
|
|
528
482
|
});
|
|
529
483
|
},
|
|
530
484
|
};
|
|
@@ -539,27 +493,22 @@ export default definePluginEntry({
|
|
|
539
493
|
const pluginConfig = rrwebReplayConfigSchema.parse(api.pluginConfig);
|
|
540
494
|
const extensionDir = resolveExtensionDirectory({ config: pluginConfig, api });
|
|
541
495
|
const serviceSourceId = `${RRWEB_PLUGIN_ID}:${api.source}`;
|
|
542
|
-
const
|
|
496
|
+
const availability = describeReplayAvailability({ config: pluginConfig, extensionDir });
|
|
543
497
|
|
|
544
498
|
api.registerService({
|
|
545
499
|
id: "rrweb-replay-browser-extension",
|
|
546
500
|
async start(ctx) {
|
|
547
|
-
const browserRuntime = await browserRuntimePromise;
|
|
548
501
|
if (!pluginConfig.enabled) {
|
|
549
502
|
ctx.logger.info("[rrweb-replay] disabled; not registering browser extension");
|
|
550
503
|
return;
|
|
551
504
|
}
|
|
552
|
-
if (!browserRuntime) {
|
|
553
|
-
ctx.logger.warn(`[rrweb-replay] ${LEGACY_BROWSER_RUNTIME_REASON}`);
|
|
554
|
-
return;
|
|
555
|
-
}
|
|
556
505
|
if (!extensionDir) {
|
|
557
506
|
ctx.logger.warn(
|
|
558
507
|
"[rrweb-replay] extension directory missing; replay browser extension was not registered",
|
|
559
508
|
);
|
|
560
509
|
return;
|
|
561
510
|
}
|
|
562
|
-
|
|
511
|
+
registerManagedBrowserExtensions({
|
|
563
512
|
sourceId: serviceSourceId,
|
|
564
513
|
profiles: pluginConfig.browserProfiles,
|
|
565
514
|
extensionPaths: [extensionDir],
|
|
@@ -569,18 +518,11 @@ export default definePluginEntry({
|
|
|
569
518
|
);
|
|
570
519
|
},
|
|
571
520
|
async stop() {
|
|
572
|
-
|
|
573
|
-
browserRuntime?.unregisterManagedBrowserExtensions(serviceSourceId);
|
|
521
|
+
unregisterManagedBrowserExtensions(serviceSourceId);
|
|
574
522
|
},
|
|
575
523
|
});
|
|
576
524
|
|
|
577
525
|
api.on("session_start", async (event, ctx) => {
|
|
578
|
-
const browserRuntime = await browserRuntimePromise;
|
|
579
|
-
const availability = describeReplayAvailability({
|
|
580
|
-
config: pluginConfig,
|
|
581
|
-
extensionDir,
|
|
582
|
-
browserRuntimeAvailable: Boolean(browserRuntime),
|
|
583
|
-
});
|
|
584
526
|
await upsertReplaySession({
|
|
585
527
|
api,
|
|
586
528
|
config: pluginConfig,
|
|
@@ -594,9 +536,8 @@ export default definePluginEntry({
|
|
|
594
536
|
});
|
|
595
537
|
|
|
596
538
|
api.on("before_reset", async (_event, ctx) => {
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
browserRuntime.clearManagedBrowserReplayContextsForSession(ctx.sessionKey);
|
|
539
|
+
if (ctx.sessionKey) {
|
|
540
|
+
clearManagedBrowserReplayContextsForSession(ctx.sessionKey);
|
|
600
541
|
}
|
|
601
542
|
await markReplaySessionEnded({
|
|
602
543
|
api,
|
|
@@ -606,9 +547,8 @@ export default definePluginEntry({
|
|
|
606
547
|
});
|
|
607
548
|
|
|
608
549
|
api.on("session_end", async (_event, ctx) => {
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
browserRuntime.clearManagedBrowserReplayContextsForSession(ctx.sessionKey);
|
|
550
|
+
if (ctx.sessionKey) {
|
|
551
|
+
clearManagedBrowserReplayContextsForSession(ctx.sessionKey);
|
|
612
552
|
}
|
|
613
553
|
await markReplaySessionEnded({
|
|
614
554
|
api,
|
|
@@ -618,12 +558,6 @@ export default definePluginEntry({
|
|
|
618
558
|
});
|
|
619
559
|
|
|
620
560
|
api.on("before_tool_call", async (event, ctx) => {
|
|
621
|
-
const browserRuntime = await browserRuntimePromise;
|
|
622
|
-
const availability = describeReplayAvailability({
|
|
623
|
-
config: pluginConfig,
|
|
624
|
-
extensionDir,
|
|
625
|
-
browserRuntimeAvailable: Boolean(browserRuntime),
|
|
626
|
-
});
|
|
627
561
|
if (event.toolName !== "browser" || pluginConfig.recordingPolicy !== "browser-only") {
|
|
628
562
|
return;
|
|
629
563
|
}
|
|
@@ -637,7 +571,6 @@ export default definePluginEntry({
|
|
|
637
571
|
await armReplayContext({
|
|
638
572
|
api,
|
|
639
573
|
pluginConfig,
|
|
640
|
-
browserRuntime,
|
|
641
574
|
sessionKey: ctx.sessionKey,
|
|
642
575
|
sessionId: ctx.sessionId,
|
|
643
576
|
preferredProfile: rawProfile,
|
|
@@ -650,7 +583,6 @@ export default definePluginEntry({
|
|
|
650
583
|
api,
|
|
651
584
|
pluginConfig,
|
|
652
585
|
extensionDir,
|
|
653
|
-
browserRuntimePromise,
|
|
654
586
|
context: {
|
|
655
587
|
sessionKey: context.sessionKey,
|
|
656
588
|
sessionId: context.sessionId,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rrwebcloud/openclaw-session-recording",
|
|
3
|
-
"version": "2026.3.28
|
|
3
|
+
"version": "2026.3.28",
|
|
4
4
|
"description": "OpenClaw rrweb replay plugin",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"openclaw": "workspace:*"
|
|
20
20
|
},
|
|
21
21
|
"peerDependencies": {
|
|
22
|
-
"openclaw": ">=2026.3.
|
|
22
|
+
"openclaw": ">=2026.3.24"
|
|
23
23
|
},
|
|
24
24
|
"peerDependenciesMeta": {
|
|
25
25
|
"openclaw": {
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"npmSpec": "@rrwebcloud/openclaw-session-recording",
|
|
36
36
|
"localPath": "extensions/rrweb-replay",
|
|
37
37
|
"defaultChoice": "npm",
|
|
38
|
-
"minHostVersion": ">=2026.3.
|
|
38
|
+
"minHostVersion": ">=2026.3.24"
|
|
39
39
|
},
|
|
40
40
|
"release": {
|
|
41
41
|
"publishToNpm": true
|