openclaw-multi-auto 1.4.5 → 1.4.7
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/dist/build-info.json +3 -3
- package/dist/canvas-host/a2ui/.bundle.hash +1 -1
- package/dist/plugin-sdk/mattermost.js +3 -3
- package/dist/plugin-sdk/signal.js +2 -2
- package/docs/browser-architecture.md +602 -0
- package/extensions/googlechat/node_modules/.bin/openclaw +2 -2
- package/extensions/memory-core/node_modules/.bin/openclaw +2 -2
- package/extensions/memory-lancedb/node_modules/.bin/openai +2 -2
- package/extensions/page-action-cache/dist/actions-executor.d.ts +62 -0
- package/extensions/page-action-cache/dist/actions-executor.d.ts.map +1 -0
- package/extensions/page-action-cache/dist/actions-executor.js +339 -0
- package/extensions/page-action-cache/dist/actions-executor.js.map +1 -0
- package/extensions/page-action-cache/dist/cache-invalidator.d.ts +70 -0
- package/extensions/page-action-cache/dist/cache-invalidator.d.ts.map +1 -0
- package/extensions/page-action-cache/dist/cache-invalidator.js +212 -0
- package/extensions/page-action-cache/dist/cache-invalidator.js.map +1 -0
- package/extensions/page-action-cache/dist/cache-store.d.ts +80 -0
- package/extensions/page-action-cache/dist/cache-store.d.ts.map +1 -0
- package/extensions/page-action-cache/dist/cache-store.js +361 -0
- package/extensions/page-action-cache/dist/cache-store.js.map +1 -0
- package/extensions/page-action-cache/dist/cache-strategy.d.ts +65 -0
- package/extensions/page-action-cache/dist/cache-strategy.d.ts.map +1 -0
- package/extensions/page-action-cache/dist/cache-strategy.js +237 -0
- package/extensions/page-action-cache/dist/cache-strategy.js.map +1 -0
- package/extensions/page-action-cache/dist/hooks-entry.d.ts +18 -0
- package/extensions/page-action-cache/dist/hooks-entry.d.ts.map +1 -0
- package/extensions/page-action-cache/dist/hooks-entry.js +27 -0
- package/extensions/page-action-cache/dist/hooks-entry.js.map +1 -0
- package/extensions/page-action-cache/dist/hooks.d.ts +10 -0
- package/extensions/page-action-cache/dist/hooks.d.ts.map +1 -0
- package/extensions/page-action-cache/dist/hooks.js +277 -0
- package/extensions/page-action-cache/dist/hooks.js.map +1 -0
- package/extensions/page-action-cache/dist/index.d.ts +24 -0
- package/extensions/page-action-cache/dist/index.d.ts.map +1 -0
- package/extensions/page-action-cache/dist/index.js +34 -0
- package/extensions/page-action-cache/dist/index.js.map +1 -0
- package/extensions/page-action-cache/dist/scenario-recognizer.d.ts +45 -0
- package/extensions/page-action-cache/dist/scenario-recognizer.d.ts.map +1 -0
- package/extensions/page-action-cache/dist/scenario-recognizer.js +213 -0
- package/extensions/page-action-cache/dist/scenario-recognizer.js.map +1 -0
- package/extensions/page-action-cache/dist/security-policy.d.ts +62 -0
- package/extensions/page-action-cache/dist/security-policy.d.ts.map +1 -0
- package/extensions/page-action-cache/dist/security-policy.js +219 -0
- package/extensions/page-action-cache/dist/security-policy.js.map +1 -0
- package/extensions/page-action-cache/dist/tools.d.ts +209 -0
- package/extensions/page-action-cache/dist/tools.d.ts.map +1 -0
- package/extensions/page-action-cache/dist/tools.js +383 -0
- package/extensions/page-action-cache/dist/tools.js.map +1 -0
- package/extensions/page-action-cache/dist/types.d.ts +336 -0
- package/extensions/page-action-cache/dist/types.d.ts.map +1 -0
- package/extensions/page-action-cache/dist/types.js +8 -0
- package/extensions/page-action-cache/dist/types.js.map +1 -0
- package/extensions/page-action-cache/dist/ux-enhancer.d.ts +60 -0
- package/extensions/page-action-cache/dist/ux-enhancer.d.ts.map +1 -0
- package/extensions/page-action-cache/dist/ux-enhancer.js +218 -0
- package/extensions/page-action-cache/dist/ux-enhancer.js.map +1 -0
- package/extensions/page-action-cache/dist/variable-resolver.d.ts +28 -0
- package/extensions/page-action-cache/dist/variable-resolver.d.ts.map +1 -0
- package/extensions/page-action-cache/dist/variable-resolver.js +201 -0
- package/extensions/page-action-cache/dist/variable-resolver.js.map +1 -0
- package/extensions/page-action-cache/docs/API.md +555 -0
- package/extensions/page-action-cache/docs/IMPLEMENTATION.md +1792 -0
- package/extensions/page-action-cache/docs/INTEGRATION.md +387 -0
- package/extensions/page-action-cache/docs/README.md +183 -0
- package/extensions/page-action-cache/index.ts +118 -0
- package/extensions/page-action-cache/node_modules/.bin/nlc +21 -0
- package/extensions/page-action-cache/node_modules/.bin/node-llama-cpp +21 -0
- package/extensions/page-action-cache/node_modules/.bin/openclaw +21 -0
- package/extensions/page-action-cache/node_modules/.bin/tsc +21 -0
- package/extensions/page-action-cache/node_modules/.bin/tsserver +21 -0
- package/extensions/page-action-cache/node_modules/.bin/vitest +21 -0
- package/extensions/page-action-cache/openclaw.plugin.json +208 -0
- package/extensions/page-action-cache/package.json +76 -0
- package/extensions/page-action-cache/scripts/npm_publish.sh +80 -0
- package/extensions/page-action-cache/skills/page-action-cache/SKILL.md +216 -0
- package/extensions/page-action-cache/src/actions-executor.ts +441 -0
- package/extensions/page-action-cache/src/cache-invalidator.ts +271 -0
- package/extensions/page-action-cache/src/cache-store.ts +457 -0
- package/extensions/page-action-cache/src/cache-strategy.ts +327 -0
- package/extensions/page-action-cache/src/hooks-entry.ts +114 -0
- package/extensions/page-action-cache/src/hooks.ts +332 -0
- package/extensions/page-action-cache/src/index.ts +104 -0
- package/extensions/page-action-cache/src/scenario-recognizer.ts +259 -0
- package/extensions/page-action-cache/src/security-policy.ts +268 -0
- package/extensions/page-action-cache/src/tools.ts +437 -0
- package/extensions/page-action-cache/src/types.ts +482 -0
- package/extensions/page-action-cache/src/ux-enhancer.ts +266 -0
- package/extensions/page-action-cache/src/variable-resolver.ts +258 -0
- package/extensions/page-action-cache/tests/actions-executor.test.ts +424 -0
- package/extensions/page-action-cache/tests/cache-store.test.ts +267 -0
- package/extensions/page-action-cache/tests/integration-test.ts +62 -0
- package/extensions/page-action-cache/tests/scenario-recognizer.test.ts +140 -0
- package/extensions/page-action-cache/tests/variable-resolver.test.ts +187 -0
- package/extensions/page-action-cache/tsconfig.json +39 -0
- package/package.json +1 -1
- package/scripts/create-instance.sh +26 -8
- package/scripts/npm_publish.sh +59 -1
- package/scripts/publish-extension.sh +343 -0
- package/ui/node_modules/.bin/vite +2 -2
- package/ui/node_modules/.bin/vitest +2 -2
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration Test
|
|
3
|
+
* 集成测试 - 验证扩展的基本功能
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, it, expect, beforeAll } from "vitest";
|
|
7
|
+
import { getCacheStore } from "../src/cache-store.js";
|
|
8
|
+
|
|
9
|
+
describe("Page Action Cache Integration", () => {
|
|
10
|
+
let cacheStore = getCacheStore();
|
|
11
|
+
|
|
12
|
+
beforeAll(() => {
|
|
13
|
+
// 清空缓存
|
|
14
|
+
cacheStore.clear();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
describe("Basic Cache Operations", () => {
|
|
18
|
+
it("should save and retrieve cache entry", () => {
|
|
19
|
+
const url = "https://example.com/login";
|
|
20
|
+
const viewport = { width: 1920, height: 1080 };
|
|
21
|
+
const actions = [
|
|
22
|
+
{ type: "type" as const, ref: "#username", text: "test", order: 1 },
|
|
23
|
+
{ type: "type" as const, ref: "#password", text: "secret", order: 2 },
|
|
24
|
+
{ type: "click" as const, ref: "#submit", order: 3 },
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
const key = cacheStore.set(url, viewport, actions, {
|
|
28
|
+
scenario: "login",
|
|
29
|
+
cacheLevel: "L3",
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
expect(key).toBeDefined();
|
|
33
|
+
expect(typeof key).toBe("string");
|
|
34
|
+
|
|
35
|
+
const entry = cacheStore.get(url, viewport);
|
|
36
|
+
expect(entry).not.toBeNull();
|
|
37
|
+
expect(entry?.scenario).toBe("login");
|
|
38
|
+
expect(entry?.cacheLevel).toBe("L3");
|
|
39
|
+
expect(entry?.actions).toEqual(actions);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("should return null for non-existent cache", () => {
|
|
43
|
+
const entry = cacheStore.get("https://example.com/nonexistent", viewport);
|
|
44
|
+
expect(entry).toBeNull();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("should delete cache entry", () => {
|
|
48
|
+
const url = "https://example.com/login";
|
|
49
|
+
const viewport = { width: 1920, height: 1080 };
|
|
50
|
+
const actions = [];
|
|
51
|
+
const key = cacheStore.set(url, viewport, actions, {
|
|
52
|
+
scenario: "login",
|
|
53
|
+
cacheLevel: "L3",
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const deleted = cacheStore.delete(url, viewport);
|
|
57
|
+
expect(deleted).toBe(true);
|
|
58
|
+
|
|
59
|
+
const entry = cacheStore.get(url, viewport);
|
|
60
|
+
expect(entry).toBeNull();
|
|
61
|
+
});
|
|
62
|
+
});
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scenario Recognizer Tests
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it, expect, beforeEach } from "vitest";
|
|
6
|
+
import { ScenarioRecognizer } from "../src/scenario-recognizer.js";
|
|
7
|
+
|
|
8
|
+
describe("ScenarioRecognizer", () => {
|
|
9
|
+
let recognizer: ScenarioRecognizer;
|
|
10
|
+
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
recognizer = new ScenarioRecognizer();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
describe("matchExactRules", () => {
|
|
16
|
+
it("should match login keywords", async () => {
|
|
17
|
+
const match = await recognizer.recognize("登录 example.com", "https://example.com");
|
|
18
|
+
expect(match).not.toBeNull();
|
|
19
|
+
expect(match?.scenario).toBe("login");
|
|
20
|
+
expect(match?.confidence).toBeGreaterThanOrEqual(90);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("should match login URL patterns", async () => {
|
|
24
|
+
const match = await recognizer.recognize(
|
|
25
|
+
"open page",
|
|
26
|
+
"https://example.com/login"
|
|
27
|
+
);
|
|
28
|
+
expect(match).not.toBeNull();
|
|
29
|
+
expect(match?.scenario).toBe("login");
|
|
30
|
+
expect(match?.method).toBe("url");
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("should match search keywords", async () => {
|
|
34
|
+
const match = await recognizer.recognize("搜索产品", "https://example.com");
|
|
35
|
+
expect(match).not.toBeNull();
|
|
36
|
+
expect(match?.scenario).toBe("search");
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("should match checkout keywords", async () => {
|
|
40
|
+
const match = await recognizer.recognize("结账购物车", "https://example.com/checkout");
|
|
41
|
+
expect(match).not.toBeNull();
|
|
42
|
+
expect(match?.scenario).toBe("checkout");
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("should match settings keywords", async () => {
|
|
46
|
+
const match = await recognizer.recognize("修改设置", "https://example.com/settings");
|
|
47
|
+
expect(match).not.toBeNull();
|
|
48
|
+
expect(match?.scenario).toBe("settings");
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("should not match unrelated input", async () => {
|
|
52
|
+
const match = await recognizer.recognize("do something random", "https://example.com/random");
|
|
53
|
+
expect(match).toBeNull();
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
describe("confidence levels", () => {
|
|
58
|
+
it("should give high confidence for exact keyword match", async () => {
|
|
59
|
+
const match = await recognizer.recognize("登录 account", "https://example.com");
|
|
60
|
+
expect(match?.confidence).toBeGreaterThanOrEqual(90);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("should give lower confidence for URL match", async () => {
|
|
64
|
+
const match = await recognizer.recognize("open", "https://example.com/login");
|
|
65
|
+
if (match) {
|
|
66
|
+
expect(match.confidence).toBeLessThan(90);
|
|
67
|
+
expect(match.confidence).toBeGreaterThanOrEqual(80);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
describe("method detection", () => {
|
|
73
|
+
it("should use keyword method for keyword matches", async () => {
|
|
74
|
+
const match = await recognizer.recognize("登录", "https://example.com");
|
|
75
|
+
expect(match?.method).toBe("keyword");
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("should use url method for URL pattern matches", async () => {
|
|
79
|
+
const match = await recognizer.recognize("open", "https://example.com/login");
|
|
80
|
+
if (match) {
|
|
81
|
+
expect(match.method).toBe("url");
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
describe("case insensitivity", () => {
|
|
87
|
+
it("should match keywords case-insensitively", async () => {
|
|
88
|
+
const match1 = await recognizer.recognize("登录", "https://example.com");
|
|
89
|
+
const match2 = await recognizer.recognize("LOGIN", "https://example.com");
|
|
90
|
+
const match3 = await recognizer.recognize("Login", "https://example.com");
|
|
91
|
+
|
|
92
|
+
expect(match1?.scenario).toBe("login");
|
|
93
|
+
expect(match2?.scenario).toBe("login");
|
|
94
|
+
expect(match3?.scenario).toBe("login");
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("should match URLs case-insensitively", async () => {
|
|
98
|
+
const match1 = await recognizer.recognize("open", "https://example.com/Login");
|
|
99
|
+
const match2 = await recognizer.recognize("open", "https://example.com/LOGIN");
|
|
100
|
+
|
|
101
|
+
expect(match1?.scenario).toBe("login");
|
|
102
|
+
expect(match2?.scenario).toBe("login");
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
describe("getRules", () => {
|
|
107
|
+
it("should return all rules", () => {
|
|
108
|
+
const rules = recognizer.getRules();
|
|
109
|
+
expect(rules.length).toBeGreaterThan(0);
|
|
110
|
+
expect(rules[0]).toHaveProperty("scenario");
|
|
111
|
+
expect(rules[0]).toHaveProperty("keywords");
|
|
112
|
+
expect(rules[0]).toHaveProperty("urlPatterns");
|
|
113
|
+
expect(rules[0]).toHaveProperty("priority");
|
|
114
|
+
expect(rules[0]).toHaveProperty("cacheLevel");
|
|
115
|
+
expect(rules[0]).toHaveProperty("confidence");
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
describe("getRecommendedCacheLevel", () => {
|
|
120
|
+
it("should return L3 for login", () => {
|
|
121
|
+
const level = recognizer.getRecommendedCacheLevel("login");
|
|
122
|
+
expect(level).toBe("L3");
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it("should return L3 for checkout", () => {
|
|
126
|
+
const level = recognizer.getRecommendedCacheLevel("checkout");
|
|
127
|
+
expect(level).toBe("L3");
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it("should return L1 for screenshot", () => {
|
|
131
|
+
const level = recognizer.getRecommendedCacheLevel("screenshot");
|
|
132
|
+
expect(level).toBe("L1");
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it("should return L1 for unknown scenario", () => {
|
|
136
|
+
const level = recognizer.getRecommendedCacheLevel("unknown");
|
|
137
|
+
expect(level).toBe("L1");
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
});
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Variable Resolver Tests
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it, expect, beforeEach } from "vitest";
|
|
6
|
+
import { VariableResolver } from "../src/variable-resolver.js";
|
|
7
|
+
|
|
8
|
+
describe("VariableResolver", () => {
|
|
9
|
+
let resolver: VariableResolver;
|
|
10
|
+
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
resolver = new VariableResolver();
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
describe("login scenario", () => {
|
|
16
|
+
it("should extract username and password", () => {
|
|
17
|
+
const variables = resolver.resolveVariables(
|
|
18
|
+
"登录 example.com,用户名 alice,密码 secret123",
|
|
19
|
+
"login"
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
expect(variables.username).toBe("alice");
|
|
23
|
+
expect(variables.password).toBe("secret123");
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("should extract username from different patterns", () => {
|
|
27
|
+
const testCases = [
|
|
28
|
+
"登录 账号 bob",
|
|
29
|
+
"username: charlie",
|
|
30
|
+
"user david",
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
for (const input of testCases) {
|
|
34
|
+
const variables = resolver.resolveVariables(input, "login");
|
|
35
|
+
expect(variables.username).toBeDefined();
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("should extract email as username", () => {
|
|
40
|
+
const variables = resolver.resolveVariables(
|
|
41
|
+
"使用 test@example.com 登录",
|
|
42
|
+
"login"
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
expect(variables.username).toBe("test@example.com");
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("should extract password from different patterns", () => {
|
|
49
|
+
const testCases = [
|
|
50
|
+
"密码 mypassword",
|
|
51
|
+
"password: secret",
|
|
52
|
+
"pwd: 123456",
|
|
53
|
+
];
|
|
54
|
+
|
|
55
|
+
for (const input of testCases) {
|
|
56
|
+
const variables = resolver.resolveVariables(input, "login");
|
|
57
|
+
expect(variables.password).toBeDefined();
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
describe("checkout scenario", () => {
|
|
63
|
+
it("should extract payment method", () => {
|
|
64
|
+
const variables = resolver.resolveVariables(
|
|
65
|
+
"结账,支付方式信用卡",
|
|
66
|
+
"checkout"
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
expect(variables.custom?.paymentMethod).toBe("信用卡");
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("should extract amount", () => {
|
|
73
|
+
const variables = resolver.resolveVariables(
|
|
74
|
+
"支付 金额100",
|
|
75
|
+
"checkout"
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
expect(variables.custom?.amount).toBe("100");
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
describe("search scenario", () => {
|
|
83
|
+
it("should extract search query", () => {
|
|
84
|
+
const variables = resolver.resolveVariables("搜索 产品A", "search");
|
|
85
|
+
|
|
86
|
+
expect(variables.custom?.query).toBe("产品A");
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("should extract find query", () => {
|
|
90
|
+
const variables = resolver.resolveVariables("查找 测试项目", "search");
|
|
91
|
+
|
|
92
|
+
expect(variables.custom?.query).toBe("测试项目");
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
describe("settings scenario", () => {
|
|
97
|
+
it("should extract key-value pairs", () => {
|
|
98
|
+
const variables = resolver.resolveVariables(
|
|
99
|
+
"设置 language:zh-CN, theme:dark",
|
|
100
|
+
"settings"
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
expect(variables.custom?.language).toBe("zh-CN");
|
|
104
|
+
expect(variables.custom?.theme).toBe("dark");
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
describe("generic resolver", () => {
|
|
109
|
+
it("should extract common fields", () => {
|
|
110
|
+
const variables = resolver.resolveVariables(
|
|
111
|
+
"user:john, email:john@example.com, phone:1234567890",
|
|
112
|
+
"unknown"
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
expect(variables.username).toBe("john");
|
|
116
|
+
expect(variables.email).toBe("john@example.com");
|
|
117
|
+
expect(variables.phone).toBe("1234567890");
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it("should extract verification code", () => {
|
|
121
|
+
const variables = resolver.resolveVariables(
|
|
122
|
+
"验证码 123456",
|
|
123
|
+
"unknown"
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
expect(variables.code).toBe("123456");
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
describe("validateVariables", () => {
|
|
131
|
+
it("should validate login variables", () => {
|
|
132
|
+
const validVars = { username: "alice", password: "secret" };
|
|
133
|
+
const invalidVars = { password: "secret" }; // Missing username
|
|
134
|
+
|
|
135
|
+
expect(resolver.validateVariables(validVars, "login")).toBe(true);
|
|
136
|
+
expect(resolver.validateVariables(invalidVars, "login")).toBe(false);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it("should validate login with email", () => {
|
|
140
|
+
const validVars = { email: "alice@example.com" };
|
|
141
|
+
|
|
142
|
+
expect(resolver.validateVariables(validVars, "login")).toBe(true);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it("should always validate checkout variables", () => {
|
|
146
|
+
const vars = { custom: { paymentMethod: "credit" } };
|
|
147
|
+
|
|
148
|
+
expect(resolver.validateVariables(vars, "checkout")).toBe(true);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it("should always validate unknown scenarios", () => {
|
|
152
|
+
const emptyVars = {};
|
|
153
|
+
|
|
154
|
+
expect(resolver.validateVariables(emptyVars, "unknown")).toBe(true);
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
describe("mergeVariables", () => {
|
|
159
|
+
it("should merge variables correctly", () => {
|
|
160
|
+
const base = {
|
|
161
|
+
username: "alice",
|
|
162
|
+
custom: { theme: "dark" },
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
const override = {
|
|
166
|
+
password: "secret",
|
|
167
|
+
custom: { language: "en" },
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
const merged = resolver.mergeVariables(base, override);
|
|
171
|
+
|
|
172
|
+
expect(merged.username).toBe("alice");
|
|
173
|
+
expect(merged.password).toBe("secret");
|
|
174
|
+
expect(merged.custom?.theme).toBe("dark");
|
|
175
|
+
expect(merged.custom?.language).toBe("en");
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it("should override with second object", () => {
|
|
179
|
+
const base = { username: "alice" };
|
|
180
|
+
const override = { username: "bob" };
|
|
181
|
+
|
|
182
|
+
const merged = resolver.mergeVariables(base, override);
|
|
183
|
+
|
|
184
|
+
expect(merged.username).toBe("bob");
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "node",
|
|
6
|
+
"lib": ["ES2022"],
|
|
7
|
+
"outDir": "./dist",
|
|
8
|
+
"rootDir": "./src",
|
|
9
|
+
"declaration": true,
|
|
10
|
+
"declarationMap": true,
|
|
11
|
+
"sourceMap": true,
|
|
12
|
+
"removeComments": false,
|
|
13
|
+
"noUnusedLocals": true,
|
|
14
|
+
"noUnusedParameters": true,
|
|
15
|
+
"noImplicitReturns": true,
|
|
16
|
+
"noFallthroughCasesInSwitch": true,
|
|
17
|
+
"esModuleInterop": true,
|
|
18
|
+
"skipLibCheck": true,
|
|
19
|
+
"forceConsistentCasingInFileNames": true,
|
|
20
|
+
"strict": true,
|
|
21
|
+
"resolveJsonModule": true,
|
|
22
|
+
"allowSyntheticDefaultImports": true
|
|
23
|
+
},
|
|
24
|
+
"include": [
|
|
25
|
+
"src/**/*"
|
|
26
|
+
],
|
|
27
|
+
"exclude": [
|
|
28
|
+
"node_modules",
|
|
29
|
+
"dist",
|
|
30
|
+
"**/*.test.ts",
|
|
31
|
+
"**/*.spec.ts"
|
|
32
|
+
],
|
|
33
|
+
"ts-node": {
|
|
34
|
+
"compilerOptions": {
|
|
35
|
+
"module": "ESNext",
|
|
36
|
+
"esModuleInterop": true
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
package/package.json
CHANGED
|
@@ -136,6 +136,16 @@ fi
|
|
|
136
136
|
|
|
137
137
|
pnpm install --shamefully-hoist --ignore-workspace --registry=https://registry.npmmirror.com --no-frozen-lockfile
|
|
138
138
|
|
|
139
|
+
# 安装 page-action-cache 扩展
|
|
140
|
+
echo -e "${BLUE}📦 安装 page-action-cache 扩展...${NC}"
|
|
141
|
+
cd "${INSTANCE_DIR}"
|
|
142
|
+
if pnpm install --registry=https://registry.npmmirror.com @openclaw/page-action-cache@latest; then
|
|
143
|
+
echo -e "${GREEN}✅ page-action-cache 扩展安装成功${NC}"
|
|
144
|
+
else
|
|
145
|
+
echo -e "${YELLOW}⚠️ page-action-cache 扩展安装失败,但将继续实例创建${NC}"
|
|
146
|
+
echo -e "${YELLOW}💡 提示: 可以稍后手动安装: cd ${INSTANCE_DIR} && pnpm install @openclaw/page-action-cache@latest${NC}"
|
|
147
|
+
fi
|
|
148
|
+
|
|
139
149
|
if [ ! -d "node_modules" ]; then
|
|
140
150
|
echo -e "${RED}❌ 严重错误: pnpm install 完成但 node_modules 目录未创建!${NC}"
|
|
141
151
|
exit 1
|
|
@@ -264,7 +274,21 @@ cat > "${INSTANCE_DIR}/config/openclaw.json" << EOF
|
|
|
264
274
|
}
|
|
265
275
|
},
|
|
266
276
|
"commands": { "native": "auto", "restart": false },
|
|
267
|
-
"gateway": { "port": ${PORT}, "mode": "local" }
|
|
277
|
+
"gateway": { "port": ${PORT}, "mode": "local" },
|
|
278
|
+
"plugins": {
|
|
279
|
+
"enabled": true,
|
|
280
|
+
"allow": ["page-action-cache"],
|
|
281
|
+
"entries": {
|
|
282
|
+
"page-action-cache": {
|
|
283
|
+
"enabled": true,
|
|
284
|
+
"config": {
|
|
285
|
+
"enabled": true,
|
|
286
|
+
"autoUseCache": true,
|
|
287
|
+
"scenarioRecognitionEnabled": true
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
268
292
|
}
|
|
269
293
|
EOF
|
|
270
294
|
|
|
@@ -306,7 +330,7 @@ if [ "$INSTANCE_NAME" = "yunwei" ]; then
|
|
|
306
330
|
if [ -d "$item" ]; then
|
|
307
331
|
# 目录(如 memory、skills)复制到 workspace
|
|
308
332
|
cp -r "$item" "$INSTANCE_DIR/workspace/"
|
|
309
|
-
elif [ -f "$item" ]
|
|
333
|
+
elif [ -f "$item" ]; then
|
|
310
334
|
# 非 .md 文件(如 package.json)也复制到 workspace
|
|
311
335
|
cp "$item" "$INSTANCE_DIR/workspace/" 2>/dev/null || true
|
|
312
336
|
fi
|
|
@@ -446,12 +470,6 @@ check_port() {
|
|
|
446
470
|
fi
|
|
447
471
|
}
|
|
448
472
|
|
|
449
|
-
sleep 3
|
|
450
|
-
(
|
|
451
|
-
cd "$INSTANCE_DIR"
|
|
452
|
-
./start.sh heartbeat
|
|
453
|
-
) >> "$INSTANCE_DIR/workspace/server.log" 2>&1 &
|
|
454
|
-
|
|
455
473
|
if kill -0 $PID 2>/dev/null; then
|
|
456
474
|
if check_port; then
|
|
457
475
|
echo -e "${GREEN}================================================${NC}"
|
package/scripts/npm_publish.sh
CHANGED
|
@@ -117,4 +117,62 @@ echo -ne "${YELLOW}🔄 通知镜像同步... ${NC}"
|
|
|
117
117
|
PKG_NAME=$(node -e "console.log(require('./package.json').name)")
|
|
118
118
|
curl -s -X PUT "https://registry-direct.npmmirror.com/${PKG_NAME}/sync?publish=true" > /dev/null && echo -e "${GREEN}[完成]${NC}"
|
|
119
119
|
|
|
120
|
-
echo -e "${GREEN}🎉 OpenClaw
|
|
120
|
+
echo -e "${GREEN}🎉 OpenClaw 发布成功!${NC}"
|
|
121
|
+
|
|
122
|
+
# 8. 发布 page-action-cache 扩展
|
|
123
|
+
echo -ne "${BLUE}📦 正在发布 @openclaw/page-action-cache 扩展...${NC}"
|
|
124
|
+
|
|
125
|
+
# 进入扩展目录处理 workspace:* 依赖问题
|
|
126
|
+
cd "$ROOT_DIR/extensions/page-action-cache"
|
|
127
|
+
|
|
128
|
+
# 处理 package.json 中的 workspace:* 依赖(npm 不支持)
|
|
129
|
+
TMP_PACKAGE_JSON="/tmp/page-action-cache-publish-$(date +%s).json"
|
|
130
|
+
cp package.json "$TMP_PACKAGE_JSON"
|
|
131
|
+
|
|
132
|
+
node -e "
|
|
133
|
+
const pkg = JSON.parse(require('fs').readFileSync('$TMP_PACKAGE_JSON', 'utf8'));
|
|
134
|
+
// 移除 workspace:* 依赖
|
|
135
|
+
delete pkg.dependencies;
|
|
136
|
+
// 保留 peerDependencies
|
|
137
|
+
pkg.peerDependencies = pkg.peerDependencies || {};
|
|
138
|
+
require('fs').writeFileSync('$TMP_PACKAGE_JSON', JSON.stringify(pkg, null, 2));
|
|
139
|
+
"
|
|
140
|
+
|
|
141
|
+
# 处理后的 package.json
|
|
142
|
+
cp "$TMP_PACKAGE_JSON" package.json
|
|
143
|
+
|
|
144
|
+
echo -ne "${GREEN}✅ 已处理 package.json(移除 workspace 依赖)${NC}"
|
|
145
|
+
|
|
146
|
+
# 检查是否需要登录
|
|
147
|
+
if ! npm whoami > /dev/null 2>&1; then
|
|
148
|
+
echo -ne "${YELLOW}🔐 page-action-cache 扩展发布需要 npm 登录${NC}"
|
|
149
|
+
echo -ne "${YELLOW}💡 提示: 请执行 npm login 后重新运行此脚本${NC}"
|
|
150
|
+
rm -f "$TMP_PACKAGE_JSON"
|
|
151
|
+
git checkout package.json 2>/dev/null || true
|
|
152
|
+
exit 1
|
|
153
|
+
fi
|
|
154
|
+
|
|
155
|
+
# 发布扩展
|
|
156
|
+
echo -ne "${YELLOW}🚀 正在发布到 npm...${NC}"
|
|
157
|
+
npm publish --access public
|
|
158
|
+
|
|
159
|
+
if [ $? -eq 0 ]; then
|
|
160
|
+
echo -e "${GREEN}✅ @openclaw/page-action-cache 发布成功!${NC}"
|
|
161
|
+
# 通知镜像同步
|
|
162
|
+
curl -s -X PUT "https://registry-direct.npmmirror.com/@openclaw/page-action-cache/sync?publish=true" > /dev/null && echo -e "${GREEN}[完成]${NC}"
|
|
163
|
+
else
|
|
164
|
+
echo -e "${RED}❌ @openclaw/page-action-cache 发布失败${NC}"
|
|
165
|
+
fi
|
|
166
|
+
|
|
167
|
+
# 恢复原始 package.json
|
|
168
|
+
git checkout package.json 2>/dev/null || true
|
|
169
|
+
rm -f "$TMP_PACKAGE_JSON"
|
|
170
|
+
|
|
171
|
+
echo -e "${GREEN}🎉 完整发布流程完成!${NC}"
|
|
172
|
+
echo -e "${GREEN}📋 已发布:${NC}"
|
|
173
|
+
echo -e "${GREEN} - openclaw-multi-auto (v${CUR_VERSION})${NC}"
|
|
174
|
+
echo -e "${GREEN} - @openclaw/page-action-cache (latest)${NC}"
|
|
175
|
+
echo ""
|
|
176
|
+
echo -e "${BLUE}💡 提示:${NC}"
|
|
177
|
+
echo -e "${BLUE} 扩展发布后,需要重启实例才能生效 page-action-cache${NC}"
|
|
178
|
+
echo -e "${BLUE} 运行: cd ~/openclaws/<instance> && ./start.sh${NC}"
|