page-action-cache 1.0.4 → 2.0.0

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.
Files changed (89) hide show
  1. package/README.md +399 -0
  2. package/dist/browser-action-executor.d.ts +87 -0
  3. package/dist/browser-action-executor.d.ts.map +1 -0
  4. package/dist/browser-action-executor.js +283 -0
  5. package/dist/browser-action-executor.js.map +1 -0
  6. package/dist/cache-invalidation.d.ts +128 -0
  7. package/dist/cache-invalidation.d.ts.map +1 -0
  8. package/dist/cache-invalidation.js +262 -0
  9. package/dist/cache-invalidation.js.map +1 -0
  10. package/dist/cache-manager.d.ts +83 -0
  11. package/dist/cache-manager.d.ts.map +1 -0
  12. package/dist/cache-manager.js +184 -0
  13. package/dist/cache-manager.js.map +1 -0
  14. package/dist/index.d.ts +7 -21
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +249 -31
  17. package/dist/index.js.map +1 -1
  18. package/dist/multi-level-cache.d.ts +127 -0
  19. package/dist/multi-level-cache.d.ts.map +1 -0
  20. package/dist/multi-level-cache.js +362 -0
  21. package/dist/multi-level-cache.js.map +1 -0
  22. package/dist/scenario-recognizer.d.ts +17 -27
  23. package/dist/scenario-recognizer.d.ts.map +1 -1
  24. package/dist/scenario-recognizer.js +63 -183
  25. package/dist/scenario-recognizer.js.map +1 -1
  26. package/dist/types.d.ts +38 -312
  27. package/dist/types.d.ts.map +1 -1
  28. package/dist/types.js +2 -4
  29. package/dist/types.js.map +1 -1
  30. package/dist/variable-extractor.d.ts +56 -0
  31. package/dist/variable-extractor.d.ts.map +1 -0
  32. package/dist/variable-extractor.js +159 -0
  33. package/dist/variable-extractor.js.map +1 -0
  34. package/openclaw.plugin.json +12 -190
  35. package/package.json +29 -45
  36. package/src/browser-action-executor.ts +337 -0
  37. package/src/cache-invalidation.ts +338 -0
  38. package/src/cache-manager.ts +211 -0
  39. package/src/index.ts +306 -0
  40. package/src/multi-level-cache.ts +478 -0
  41. package/src/scenario-recognizer.ts +121 -0
  42. package/src/types-mock.d.ts +18 -0
  43. package/src/types.ts +66 -0
  44. package/src/variable-extractor.ts +204 -0
  45. package/dist/actions-executor.d.ts +0 -62
  46. package/dist/actions-executor.d.ts.map +0 -1
  47. package/dist/actions-executor.js +0 -339
  48. package/dist/actions-executor.js.map +0 -1
  49. package/dist/cache-invalidator.d.ts +0 -70
  50. package/dist/cache-invalidator.d.ts.map +0 -1
  51. package/dist/cache-invalidator.js +0 -212
  52. package/dist/cache-invalidator.js.map +0 -1
  53. package/dist/cache-store.d.ts +0 -80
  54. package/dist/cache-store.d.ts.map +0 -1
  55. package/dist/cache-store.js +0 -361
  56. package/dist/cache-store.js.map +0 -1
  57. package/dist/cache-strategy.d.ts +0 -65
  58. package/dist/cache-strategy.d.ts.map +0 -1
  59. package/dist/cache-strategy.js +0 -237
  60. package/dist/cache-strategy.js.map +0 -1
  61. package/dist/hooks-entry.d.ts +0 -29
  62. package/dist/hooks-entry.d.ts.map +0 -1
  63. package/dist/hooks-entry.js +0 -83
  64. package/dist/hooks-entry.js.map +0 -1
  65. package/dist/hooks.d.ts +0 -10
  66. package/dist/hooks.d.ts.map +0 -1
  67. package/dist/hooks.js +0 -277
  68. package/dist/hooks.js.map +0 -1
  69. package/dist/security-policy.d.ts +0 -62
  70. package/dist/security-policy.d.ts.map +0 -1
  71. package/dist/security-policy.js +0 -219
  72. package/dist/security-policy.js.map +0 -1
  73. package/dist/tools.d.ts +0 -209
  74. package/dist/tools.d.ts.map +0 -1
  75. package/dist/tools.js +0 -383
  76. package/dist/tools.js.map +0 -1
  77. package/dist/ux-enhancer.d.ts +0 -60
  78. package/dist/ux-enhancer.d.ts.map +0 -1
  79. package/dist/ux-enhancer.js +0 -218
  80. package/dist/ux-enhancer.js.map +0 -1
  81. package/dist/variable-resolver.d.ts +0 -28
  82. package/dist/variable-resolver.d.ts.map +0 -1
  83. package/dist/variable-resolver.js +0 -201
  84. package/dist/variable-resolver.js.map +0 -1
  85. package/docs/API.md +0 -555
  86. package/docs/IMPLEMENTATION.md +0 -1792
  87. package/docs/INTEGRATION.md +0 -387
  88. package/docs/README.md +0 -183
  89. package/skills/page-action-cache/SKILL.md +0 -216
@@ -0,0 +1,478 @@
1
+ /**
2
+ * Multi-Level Cache - Page Action Cache
3
+ * 多级缓存管理器 - L3/L2/L1 缓存层次
4
+ */
5
+
6
+ import type { CacheEntry, ScenarioType, CacheActionType } from './types.js';
7
+
8
+ /**
9
+ * 缓存级别
10
+ */
11
+ export type CacheLevel = 'L3' | 'L2' | 'L1';
12
+
13
+ /**
14
+ * 缓存级别配置
15
+ */
16
+ interface CacheLevelConfig {
17
+ level: CacheLevel;
18
+ maxSize: number;
19
+ ttl: number; // milliseconds
20
+ hitPriority: number;
21
+ description: string;
22
+ }
23
+
24
+ /**
25
+ * 缓存条目扩展
26
+ */
27
+ interface ExtendedCacheEntry extends CacheEntry {
28
+ level: CacheLevel;
29
+ createdAt: number;
30
+ lastAccessed: number;
31
+ accessCount: number;
32
+ expiresAt: number;
33
+ llmClassificationScore?: number;
34
+ }
35
+
36
+ /**
37
+ * 缓存策略
38
+ */
39
+ type CacheStrategy = 'auto' | 'l3-only' | 'l2-only' | 'l1-only';
40
+
41
+ /**
42
+ * 多级缓存管理器
43
+ */
44
+ export class MultiLevelCache {
45
+ private levels: Map<CacheLevel, Map<string, ExtendedCacheEntry>> = new Map();
46
+ private levelConfigs: Map<CacheLevel, CacheLevelConfig> = new Map();
47
+ private strategy: CacheStrategy = 'auto';
48
+ private llmThreshold: number = 0.8;
49
+
50
+ constructor() {
51
+ this.initializeLevels();
52
+ }
53
+
54
+ /**
55
+ * 初始化缓存级别
56
+ */
57
+ private initializeLevels(): void {
58
+ // L3: 持久化缓存,最大容量,最长 TTL
59
+ this.levelConfigs.set('L3', {
60
+ level: 'L3',
61
+ maxSize: 1000,
62
+ ttl: 30 * 24 * 60 * 60 * 1000, // 30 天
63
+ hitPriority: 1,
64
+ description: '持久化缓存,适合稳定的重复操作'
65
+ });
66
+
67
+ // L2: 内存缓存,中等容量,中等 TTL
68
+ this.levelConfigs.set('L2', {
69
+ level: 'L2',
70
+ maxSize: 200,
71
+ ttl: 7 * 24 * 60 * 60 * 1000, // 7 天
72
+ hitPriority: 2,
73
+ description: '内存缓存,适合频繁访问的操作'
74
+ });
75
+
76
+ // L1: 热点缓存,小容量,短 TTL
77
+ this.levelConfigs.set('L1', {
78
+ level: 'L1',
79
+ maxSize: 50,
80
+ ttl: 1 * 24 * 60 * 60 * 1000, // 1 天
81
+ hitPriority: 3,
82
+ description: '热点缓存,适合当前会话的操作'
83
+ });
84
+
85
+ // 初始化各级缓存
86
+ this.levels.set('L3', new Map());
87
+ this.levels.set('L2', new Map());
88
+ this.levels.set('L1', new Map());
89
+ }
90
+
91
+ /**
92
+ * 设置缓存策略
93
+ */
94
+ setStrategy(strategy: CacheStrategy): void {
95
+ this.strategy = strategy;
96
+ }
97
+
98
+ /**
99
+ * 设置 LLM 分类阈值
100
+ */
101
+ setLLMThreshold(threshold: number): void {
102
+ this.llmThreshold = Math.max(0, Math.min(1, threshold));
103
+ }
104
+
105
+ /**
106
+ * 添加缓存条目
107
+ */
108
+ addCache(
109
+ url: string,
110
+ viewport: string,
111
+ actions: Array<{
112
+ type: CacheActionType;
113
+ params?: any;
114
+ successCount: number;
115
+ failCount: number;
116
+ }>,
117
+ scenario?: ScenarioType,
118
+ llmScore?: number
119
+ ): string {
120
+ const key = this.getCacheKey(url, viewport);
121
+ const level = this.determineCacheLevel(scenario, llmScore);
122
+
123
+ const entry: ExtendedCacheEntry = {
124
+ id: Date.now().toString(),
125
+ url,
126
+ viewport,
127
+ actions,
128
+ scenario: scenario || 'unknown',
129
+ timestamp: Date.now(),
130
+ hitRate: 0,
131
+ savedActions: 0,
132
+ savedTime: 0,
133
+ level,
134
+ createdAt: Date.now(),
135
+ lastAccessed: Date.now(),
136
+ accessCount: 0,
137
+ expiresAt: Date.now() + this.levelConfigs.get(level)!.ttl,
138
+ llmClassificationScore: llmScore
139
+ };
140
+
141
+ // 确保不超过容量限制
142
+ this.ensureCapacity(level);
143
+
144
+ const cache = this.levels.get(level)!;
145
+ cache.set(key, entry);
146
+
147
+ console.log(`[MultiLevelCache] Added entry to ${level}: ${key}`);
148
+ return entry.id;
149
+ }
150
+
151
+ /**
152
+ * 确定缓存级别
153
+ */
154
+ private determineCacheLevel(scenario?: ScenarioType, llmScore?: number): CacheLevel {
155
+ // 如果指定了特定策略
156
+ if (this.strategy === 'l3-only') return 'L3';
157
+ if (this.strategy === 'l2-only') return 'L2';
158
+ if (this.strategy === 'l1-only') return 'L1';
159
+
160
+ // 自动策略:根据场景和 LLM 分类分数确定级别
161
+ if (llmScore !== undefined) {
162
+ if (llmScore >= this.llmThreshold) {
163
+ return 'L3'; // 高置信度使用 L3
164
+ } else if (llmScore >= 0.5) {
165
+ return 'L2'; // 中等置信度使用 L2
166
+ }
167
+ }
168
+
169
+ // 根据场景确定级别
170
+ switch (scenario) {
171
+ case 'login':
172
+ case 'payment':
173
+ return 'L3'; // 敏感操作使用 L3
174
+
175
+ case 'search':
176
+ case 'checkout':
177
+ return 'L2'; // 重要操作使用 L2
178
+
179
+ default:
180
+ return 'L1'; // 一般操作使用 L1
181
+ }
182
+ }
183
+
184
+ /**
185
+ * 查询缓存
186
+ */
187
+ queryCache(url: string, viewport: string): ExtendedCacheEntry | null {
188
+ const key = this.getCacheKey(url, viewport);
189
+
190
+ // 按优先级从高到低查询
191
+ const levelsToCheck: CacheLevel[] = ['L1', 'L2', 'L3'];
192
+
193
+ for (const level of levelsToCheck) {
194
+ if (this.strategy !== 'auto' && !this.strategy.includes(level)) {
195
+ continue;
196
+ }
197
+
198
+ const cache = this.levels.get(level);
199
+ if (!cache) continue;
200
+
201
+ const entry = cache.get(key);
202
+ if (entry) {
203
+ // 检查是否过期
204
+ if (Date.now() > entry.expiresAt) {
205
+ cache.delete(key);
206
+ continue;
207
+ }
208
+
209
+ // 更新访问统计
210
+ entry.lastAccessed = Date.now();
211
+ entry.accessCount++;
212
+
213
+ // 如果不是当前最高级别,考虑提升
214
+ if (this.shouldPromote(entry, level)) {
215
+ this.promoteEntry(entry, level);
216
+ }
217
+
218
+ return entry;
219
+ }
220
+ }
221
+
222
+ return null;
223
+ }
224
+
225
+ /**
226
+ * 判断是否应该提升缓存级别
227
+ */
228
+ private shouldPromote(entry: ExtendedCacheEntry, currentLevel: CacheLevel): boolean {
229
+ if (currentLevel === 'L3') return false;
230
+
231
+ // 访问次数超过阈值则提升
232
+ const accessThreshold = currentLevel === 'L1' ? 5 : 10;
233
+ if (entry.accessCount >= accessThreshold) {
234
+ return true;
235
+ }
236
+
237
+ // 成功率高且场景重要则提升
238
+ const totalAttempts = entry.actions.reduce((sum, a) => sum + a.successCount + a.failCount, 0);
239
+ if (totalAttempts > 0) {
240
+ const successRate = entry.actions.reduce((sum, a) => sum + a.successCount, 0) / totalAttempts;
241
+ if (successRate > 0.9 && (entry.scenario === 'login' || entry.scenario === 'payment')) {
242
+ return true;
243
+ }
244
+ }
245
+
246
+ return false;
247
+ }
248
+
249
+ /**
250
+ * 提升缓存条目到更高级别
251
+ */
252
+ private promoteEntry(entry: ExtendedCacheEntry, fromLevel: CacheLevel): void {
253
+ const targetLevel = fromLevel === 'L1' ? 'L2' : 'L3';
254
+
255
+ const sourceCache = this.levels.get(fromLevel);
256
+ const targetCache = this.levels.get(targetLevel);
257
+
258
+ if (!sourceCache || !targetCache) {
259
+ return;
260
+ }
261
+
262
+ const key = this.getCacheKey(entry.url, entry.viewport || '');
263
+ sourceCache.delete(key);
264
+
265
+ entry.level = targetLevel;
266
+ entry.expiresAt = Date.now() + this.levelConfigs.get(targetLevel)!.ttl;
267
+ this.ensureCapacity(targetLevel);
268
+ targetCache.set(key, entry);
269
+
270
+ console.log(`[MultiLevelCache] Promoted entry from ${fromLevel} to ${targetLevel}: ${key}`);
271
+ }
272
+
273
+ /**
274
+ * 确保缓存容量
275
+ */
276
+ private ensureCapacity(level: CacheLevel): void {
277
+ const config = this.levelConfigs.get(level);
278
+ if (!config) return;
279
+
280
+ const cache = this.levels.get(level);
281
+ if (!cache) return;
282
+
283
+ while (cache.size >= config.maxSize) {
284
+ this.evictEntry(level);
285
+ }
286
+ }
287
+
288
+ /**
289
+ * 驱逐缓存条目(LRU 策略)
290
+ */
291
+ private evictEntry(level: CacheLevel): void {
292
+ const cache = this.levels.get(level);
293
+ if (!cache || cache.size === 0) return;
294
+
295
+ let oldestKey: string | null = null;
296
+ let oldestTime = Infinity;
297
+
298
+ for (const [key, entry] of cache.entries()) {
299
+ if (entry.lastAccessed < oldestTime) {
300
+ oldestTime = entry.lastAccessed;
301
+ oldestKey = key;
302
+ }
303
+ }
304
+
305
+ if (oldestKey) {
306
+ cache.delete(oldestKey);
307
+ console.log(`[MultiLevelCache] Evicted entry from ${level}: ${oldestKey}`);
308
+ }
309
+ }
310
+
311
+ /**
312
+ * 删除缓存条目
313
+ */
314
+ deleteCache(url: string, viewport: string): boolean {
315
+ const key = this.getCacheKey(url, viewport);
316
+ let deleted = false;
317
+
318
+ for (const [level, cache] of this.levels.entries()) {
319
+ if (cache.delete(key)) {
320
+ deleted = true;
321
+ console.log(`[MultiLevelCache] Deleted entry from ${level}: ${key}`);
322
+ }
323
+ }
324
+
325
+ return deleted;
326
+ }
327
+
328
+ /**
329
+ * 删除 URL 相关的所有缓存
330
+ */
331
+ deleteCacheByUrl(url: string): void {
332
+ const urlPrefix = `${url}:`;
333
+
334
+ for (const [_level, cache] of this.levels.entries()) {
335
+ const keysToDelete: string[] = [];
336
+
337
+ for (const key of cache.keys()) {
338
+ if (key.startsWith(urlPrefix)) {
339
+ keysToDelete.push(key);
340
+ }
341
+ }
342
+
343
+ for (const key of keysToDelete) {
344
+ cache.delete(key);
345
+ }
346
+ }
347
+
348
+ console.log(`[MultiLevelCache] Deleted cache entries for URL: ${url}`);
349
+ }
350
+
351
+ /**
352
+ * 清空指定级别的缓存
353
+ */
354
+ clearLevel(level: CacheLevel): void {
355
+ const cache = this.levels.get(level);
356
+ if (cache) {
357
+ const count = cache.size;
358
+ cache.clear();
359
+ console.log(`[MultiLevelCache] Cleared ${count} entries from ${level}`);
360
+ }
361
+ }
362
+
363
+ /**
364
+ * 清空所有缓存
365
+ */
366
+ clearAll(): void {
367
+ for (const [level, cache] of this.levels.entries()) {
368
+ const count = cache.size;
369
+ cache.clear();
370
+ console.log(`[MultiLevelCache] Cleared ${count} entries from ${level}`);
371
+ }
372
+ }
373
+
374
+ /**
375
+ * 获取缓存统计
376
+ */
377
+ getStats(): {
378
+ totalEntries: number;
379
+ totalHits: number;
380
+ hitRate: number;
381
+ levelStats: Record<CacheLevel, {
382
+ size: number;
383
+ maxCapacity: number;
384
+ usageRate: number;
385
+ avgAccessCount: number;
386
+ }>;
387
+ } {
388
+ let totalEntries = 0;
389
+ let totalHits = 0;
390
+ const levelStats: Record<CacheLevel, any> = {} as any;
391
+
392
+ for (const [level, cache] of this.levels.entries()) {
393
+ const config = this.levelConfigs.get(level)!;
394
+ totalEntries += cache.size;
395
+
396
+ let levelHits = 0;
397
+ let totalAccess = 0;
398
+
399
+ for (const entry of cache.values()) {
400
+ totalHits += entry.accessCount;
401
+ levelHits += entry.accessCount;
402
+ totalAccess += entry.accessCount;
403
+ }
404
+
405
+ levelStats[level] = {
406
+ size: cache.size,
407
+ maxCapacity: config.maxSize,
408
+ usageRate: cache.size / config.maxSize,
409
+ avgAccessCount: cache.size > 0 ? levelHits / cache.size : 0
410
+ };
411
+ }
412
+
413
+ // 计算命中率
414
+ const totalQueries = this.getQueryCount();
415
+ const hitRate = totalQueries > 0 ? (totalHits / totalQueries) * 100 : 0;
416
+
417
+ return {
418
+ totalEntries,
419
+ totalHits,
420
+ hitRate: Math.round(hitRate * 100) / 100,
421
+ levelStats
422
+ };
423
+ }
424
+
425
+ /**
426
+ * 获取查询计数(用于统计)
427
+ */
428
+ private getQueryCount(): number {
429
+ let count = 0;
430
+ for (const cache of this.levels.values()) {
431
+ for (const entry of cache.values()) {
432
+ count += entry.accessCount;
433
+ }
434
+ }
435
+ return count || 1; // 避免除以零
436
+ }
437
+
438
+ /**
439
+ * 生成缓存键
440
+ */
441
+ private getCacheKey(url: string, viewport: string): string {
442
+ return `${url}:${viewport}`;
443
+ }
444
+
445
+ /**
446
+ * 清理过期条目
447
+ */
448
+ cleanupExpired(): number {
449
+ let cleaned = 0;
450
+ const now = Date.now();
451
+
452
+ for (const [_level, cache] of this.levels.entries()) {
453
+ const expiredKeys: string[] = [];
454
+
455
+ for (const [key, entry] of cache.entries()) {
456
+ if (now > entry.expiresAt) {
457
+ expiredKeys.push(key);
458
+ }
459
+ }
460
+
461
+ for (const key of expiredKeys) {
462
+ cache.delete(key);
463
+ cleaned++;
464
+ }
465
+ }
466
+
467
+ if (cleaned > 0) {
468
+ console.log(`[MultiLevelCache] Cleaned up ${cleaned} expired entries`);
469
+ }
470
+
471
+ return cleaned;
472
+ }
473
+ }
474
+
475
+ /**
476
+ * 单例导出
477
+ */
478
+ export const multiLevelCache = new MultiLevelCache();
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Scenario Recognizer - Page Action Cache
3
+ * 场景识别器 - 识别用户操作场景
4
+ */
5
+
6
+ import type { ScenarioType } from './types.js';
7
+
8
+ /**
9
+ * URL 模式匹配规则
10
+ */
11
+ interface URLPattern {
12
+ pattern: RegExp;
13
+ scenario: ScenarioType;
14
+ }
15
+
16
+ /**
17
+ * 场景识别规则
18
+ */
19
+ const SCENARIO_PATTERNS: URLPattern[] = [
20
+ // 登录场景
21
+ { pattern: /(login|signin|auth|oauth|sso|account|register|signup)/i, scenario: 'login' },
22
+
23
+ // 搜索场景
24
+ { pattern: /(search|query|find|explore|discover)/i, scenario: 'search' },
25
+
26
+ // 支付场景
27
+ { pattern: /(payment|pay|checkout|billing|invoice|transaction)/i, scenario: 'payment' },
28
+
29
+ // 结账场景
30
+ { pattern: /(cart|basket|order|purchase|buy)/i, scenario: 'checkout' },
31
+
32
+ // 电商场景
33
+ { pattern: /(shop|store|product|item|goods|marketplace)/i, scenario: 'checkout' }
34
+ ];
35
+
36
+ /**
37
+ * 页面内容关键词
38
+ */
39
+ const CONTENT_KEYWORDS: Record<ScenarioType, string[]> = {
40
+ login: ['username', 'password', 'email', 'phone', '登录', '密码', '用户名', '邮箱', '手机号', 'sign in', 'log in'],
41
+ search: ['search', 'query', '查找', '搜索', '输入', 'input'],
42
+ payment: ['credit card', 'debit card', 'payment method', '银行卡', '信用卡', '支付方式', 'cvv', 'expiry'],
43
+ checkout: ['cart', 'total', 'subtotal', 'shipping', '购物车', '总计', '运费', '收货地址'],
44
+ general: [],
45
+ unknown: []
46
+ };
47
+
48
+ /**
49
+ * 场景识别器
50
+ */
51
+ export class ScenarioRecognizer {
52
+ /**
53
+ * 通过 URL 识别场景
54
+ */
55
+ recognizeByUrl(url: string): ScenarioType {
56
+ for (const { pattern, scenario } of SCENARIO_PATTERNS) {
57
+ if (pattern.test(url)) {
58
+ return scenario;
59
+ }
60
+ }
61
+ return 'general';
62
+ }
63
+
64
+ /**
65
+ * 通过页面内容识别场景
66
+ */
67
+ recognizeByContent(content: string): ScenarioType {
68
+ const lowerContent = content.toLowerCase();
69
+
70
+ for (const [scenario, keywords] of Object.entries(CONTENT_KEYWORDS)) {
71
+ if (keywords.length > 0) {
72
+ const matchedKeywords = keywords.filter(keyword =>
73
+ lowerContent.includes(keyword.toLowerCase())
74
+ );
75
+ if (matchedKeywords.length >= 2) {
76
+ return scenario as ScenarioType;
77
+ }
78
+ }
79
+ }
80
+
81
+ return 'general';
82
+ }
83
+
84
+ /**
85
+ * 综合识别(URL + 内容)
86
+ */
87
+ recognize(url: string, content?: string): ScenarioType {
88
+ const urlScenario = this.recognizeByUrl(url);
89
+
90
+ if (urlScenario !== 'general' && urlScenario !== 'unknown') {
91
+ return urlScenario;
92
+ }
93
+
94
+ if (content) {
95
+ return this.recognizeByContent(content);
96
+ }
97
+
98
+ return urlScenario;
99
+ }
100
+
101
+ /**
102
+ * 添加自定义场景规则
103
+ */
104
+ addCustomRule(pattern: RegExp, scenario: ScenarioType): void {
105
+ SCENARIO_PATTERNS.unshift({ pattern, scenario });
106
+ }
107
+
108
+ /**
109
+ * 添加内容关键词
110
+ */
111
+ addContentKeyword(scenario: ScenarioType, keywords: string[]): void {
112
+ if (CONTENT_KEYWORDS[scenario]) {
113
+ CONTENT_KEYWORDS[scenario].push(...keywords);
114
+ }
115
+ }
116
+ }
117
+
118
+ /**
119
+ * 单例导出
120
+ */
121
+ export const scenarioRecognizer = new ScenarioRecognizer();
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Mock OpenClaw Plugin SDK Types
3
+ * 模拟 OpenClaw 插件 SDK 类型定义
4
+ */
5
+
6
+ export interface OpenClawPluginApi {
7
+ registerTool(tool: {
8
+ name: string;
9
+ description: string;
10
+ execute: (ctx: any) => Promise<any>;
11
+ }): void;
12
+ getConfig?: () => any;
13
+ }
14
+
15
+ export interface PluginContext {
16
+ params: any;
17
+ config?: any;
18
+ }
package/src/types.ts ADDED
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Page Action Cache Types
3
+ * 页面操作缓存类型定义
4
+ */
5
+
6
+ /**
7
+ * 缓存操作类型
8
+ */
9
+ export type CacheActionType = 'navigate' | 'click' | 'screenshot' | 'type' | 'script';
10
+
11
+ /**
12
+ * 场景类型
13
+ */
14
+ export type ScenarioType = 'login' | 'search' | 'payment' | 'checkout' | 'general' | 'unknown';
15
+
16
+ /**
17
+ * 缓存条目
18
+ */
19
+ export interface CacheEntry {
20
+ id: string;
21
+ url: string;
22
+ viewport?: string;
23
+ actions: Array<{
24
+ type: CacheActionType;
25
+ params?: any;
26
+ successCount: number;
27
+ failCount: number;
28
+ }>;
29
+ scenario?: ScenarioType;
30
+ timestamp: number;
31
+ hitRate: number;
32
+ savedActions: number;
33
+ savedTime: number; // ms
34
+ }
35
+
36
+ /**
37
+ * 缓存统计
38
+ */
39
+ export interface CacheStats {
40
+ totalEntries: number;
41
+ totalActions: number;
42
+ hitRate: number;
43
+ savedActions: number;
44
+ savedTime: number;
45
+ }
46
+
47
+ /**
48
+ * 缓存配置
49
+ */
50
+ export interface PageActionCacheConfig {
51
+ enabled: boolean;
52
+ autoUseCache?: boolean;
53
+ scenarioRecognitionEnabled?: boolean;
54
+ llmClassificationThreshold?: number;
55
+ cacheLevelStrategy?: 'auto' | 'l3-only' | 'l2-only' | 'l1-only';
56
+ defaultCacheLevel?: 'L3' | 'L2' | 'L1';
57
+ pageChangeDetectionEnabled?: boolean;
58
+ changeInvalidationThreshold?: number;
59
+ invalidationStrategy?: 'soft' | 'hard';
60
+ variableExtractionEnabled?: boolean;
61
+ allowUserConfirmVariables?: boolean;
62
+ allowUserForcedRefresh?: boolean;
63
+ enableUserCacheErrorReport?: boolean;
64
+ trackExecutionStats?: boolean;
65
+ statsUpdateInterval?: number;
66
+ }