@sav7ng/cloudphone 0.0.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.
- package/README.md +237 -0
- package/dist/index.d.ts +46 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +69 -0
- package/dist/index.js.map +1 -0
- package/dist/tools.d.ts +40 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +118 -0
- package/dist/tools.js.map +1 -0
- package/openclaw.plugin.json +40 -0
- package/package.json +28 -0
package/README.md
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
## CloudPhone Plugin
|
|
2
|
+
|
|
3
|
+
OpenClaw CloudPhone 插件,用于为 Agent 提供 **CloudPhone 设备连接链路查询** 等自定义工具能力。
|
|
4
|
+
|
|
5
|
+
当前实现的主要功能:
|
|
6
|
+
|
|
7
|
+
- **调试工具 `echo`**:回显输入内容,验证插件和工具调用链路是否正常
|
|
8
|
+
- **设备连接链路查询 `get_device_connection_link`**:根据设备 ID 查询 SSH 连接命令、密码以及过期时间
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
### 目录结构
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
cloudphone/
|
|
16
|
+
├── openclaw.plugin.json # 插件清单(id、configSchema、uiHints)
|
|
17
|
+
├── package.json # npm 依赖 & 构建脚本
|
|
18
|
+
├── tsconfig.json # TypeScript 编译配置
|
|
19
|
+
├── src/
|
|
20
|
+
│ ├── index.ts # 插件入口,注册所有工具
|
|
21
|
+
│ └── tools.ts # Agent 工具定义与实现
|
|
22
|
+
└── README.md
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
### 开发与构建
|
|
28
|
+
|
|
29
|
+
- **安装依赖**
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npm install
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
- **开发模式(监听编译)**
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npm run dev
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
- **生产构建**
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npm run build
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
构建产物默认为 `dist/index.js`,并通过 `package.json` 中的 `openclaw.extensions` 暴露给 OpenClaw。
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
### 在 OpenClaw 中加载插件
|
|
52
|
+
|
|
53
|
+
- **方式一:链接模式(开发推荐)**
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
openclaw plugins install -l ./
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
- **方式二:扩展目录**
|
|
60
|
+
|
|
61
|
+
将整个目录复制(或软链接)到工作区:
|
|
62
|
+
|
|
63
|
+
```text
|
|
64
|
+
<workspace>/.openclaw/extensions/cloudphone/
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
或全局目录:
|
|
68
|
+
|
|
69
|
+
```text
|
|
70
|
+
~/.openclaw/extensions/cloudphone/
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
- **方式三:配置路径**
|
|
74
|
+
|
|
75
|
+
在 OpenClaw 配置中添加(指向构建后的入口文件):
|
|
76
|
+
|
|
77
|
+
```json
|
|
78
|
+
{
|
|
79
|
+
"plugins": {
|
|
80
|
+
"load": {
|
|
81
|
+
"paths": ["E:/cloudphone/dist/index.js"]
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
### 插件配置(`openclaw.plugin.json`)
|
|
90
|
+
|
|
91
|
+
插件配置位于 OpenClaw 配置的 `plugins.entries.cloudphone.config` 下,对应的 `configSchema` 为:
|
|
92
|
+
|
|
93
|
+
- `baseUrl`:CloudPhone API 基础地址,默认 `https://cptest.yaltc.cn`
|
|
94
|
+
- `token`:Bearer Token 鉴权凭证
|
|
95
|
+
- `timeout`:请求超时时间(毫秒),默认 `5000`
|
|
96
|
+
|
|
97
|
+
示例配置:
|
|
98
|
+
|
|
99
|
+
```json
|
|
100
|
+
{
|
|
101
|
+
"plugins": {
|
|
102
|
+
"entries": {
|
|
103
|
+
"cloudphone": {
|
|
104
|
+
"enabled": true,
|
|
105
|
+
"config": {
|
|
106
|
+
"baseUrl": "https://cptest.yaltc.cn",
|
|
107
|
+
"token": "your-bearer-token",
|
|
108
|
+
"timeout": 5000
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
| 字段 | 类型 | 必填 | 说明 |
|
|
117
|
+
|------------|--------|------|----------------------------------------|
|
|
118
|
+
| `baseUrl` | string | 否 | CloudPhone API 基础地址,未配置时使用默认值 |
|
|
119
|
+
| `token` | string | 否 | Bearer Token,用于访问受保护接口 |
|
|
120
|
+
| `timeout` | number | 否 | 请求超时(ms),默认 `5000` |
|
|
121
|
+
|
|
122
|
+
> 修改配置后通常需要重启 Gateway 才能生效。
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
### 已注册工具
|
|
127
|
+
|
|
128
|
+
所有工具都在 `src/tools.ts` 中定义,并在 `src/index.ts` 中通过 `api.registerTool` 注册。
|
|
129
|
+
|
|
130
|
+
| 工具名 | 说明 |
|
|
131
|
+
|-----------------------------------|--------------------------------------------------|
|
|
132
|
+
| `echo` | 回显输入文本,用于验证工具调用是否正常 |
|
|
133
|
+
| `get_device_connection_link` | 查询指定设备的 SSH 连接链路及过期时间 |
|
|
134
|
+
|
|
135
|
+
#### `echo`
|
|
136
|
+
|
|
137
|
+
- **用途**:调试用工具,确保 OpenClaw 已正确加载插件并能成功调用工具。
|
|
138
|
+
- **请求参数**:
|
|
139
|
+
|
|
140
|
+
```json
|
|
141
|
+
{
|
|
142
|
+
"text": "hello"
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
- **返回示例**:
|
|
147
|
+
|
|
148
|
+
```json
|
|
149
|
+
{
|
|
150
|
+
"echo": "hello"
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
#### `get_device_connection_link`
|
|
155
|
+
|
|
156
|
+
- **用途**:根据设备 ID 查询 SSH 连接链路信息。
|
|
157
|
+
- **后端 API**:
|
|
158
|
+
- `GET {baseUrl}/webide/api/autojs-stream/device-connection-link/{deviceId}`
|
|
159
|
+
- 鉴权:可选 `Authorization: Bearer <token>`
|
|
160
|
+
- **请求参数**:
|
|
161
|
+
|
|
162
|
+
```json
|
|
163
|
+
{
|
|
164
|
+
"deviceId": "7593283098889067310"
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
- **成功返回示例(简化)**:
|
|
169
|
+
|
|
170
|
+
```json
|
|
171
|
+
{
|
|
172
|
+
"ok": true,
|
|
173
|
+
"deviceId": "7593283098889067310",
|
|
174
|
+
"sshCommand": "ssh root@host -p 12345",
|
|
175
|
+
"macSshCommand": "ssh root@host -p 12345",
|
|
176
|
+
"sshPwd": "password",
|
|
177
|
+
"expireTime": 1730000000,
|
|
178
|
+
"expireAt": "2024-10-27T10:00:00.000Z",
|
|
179
|
+
"traceId": "xxxx"
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
- **失败返回示例(简化)**:
|
|
184
|
+
|
|
185
|
+
```json
|
|
186
|
+
{
|
|
187
|
+
"ok": false,
|
|
188
|
+
"code": "xxx",
|
|
189
|
+
"message": "错误信息",
|
|
190
|
+
"traceId": "xxxx"
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
工具内部会根据配置自动:
|
|
195
|
+
|
|
196
|
+
- 选择 `baseUrl`(默认 `https://cptest.yaltc.cn`)
|
|
197
|
+
- 在配置了 `token` 时附带 `Authorization` 头
|
|
198
|
+
- 根据 `timeout` 做超时控制,并返回明确的错误信息
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
### 扩展:添加新工具
|
|
203
|
+
|
|
204
|
+
1. 在 `src/tools.ts` 中新增一个符合 `ToolDefinition` 接口的对象:
|
|
205
|
+
|
|
206
|
+
```typescript
|
|
207
|
+
const myTool: ToolDefinition = {
|
|
208
|
+
name: "my_tool", // 建议使用 snake_case
|
|
209
|
+
description: "工具功能描述",
|
|
210
|
+
parameters: {
|
|
211
|
+
type: "object",
|
|
212
|
+
properties: {
|
|
213
|
+
input: { type: "string", description: "输入参数" }
|
|
214
|
+
},
|
|
215
|
+
required: ["input"]
|
|
216
|
+
},
|
|
217
|
+
handler: async ({ input }, config) => {
|
|
218
|
+
// 使用 config.baseUrl / config.token / config.timeout 实现业务逻辑
|
|
219
|
+
return { result: input };
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
2. 将新工具加入导出的 `tools` 数组:
|
|
225
|
+
|
|
226
|
+
```typescript
|
|
227
|
+
export const tools: ToolDefinition[] = [echoTool, getDeviceConnectionLinkTool, myTool];
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
3. 运行构建并重启 Gateway:
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
npm run build
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
> 重启后,OpenClaw 会自动根据插件导出的工具列表更新 Agent 可用工具。
|
|
237
|
+
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { CloudphonePluginConfig, McpToolResult } from "./tools";
|
|
2
|
+
/**
|
|
3
|
+
* OpenClaw 插件 API 简化类型声明。
|
|
4
|
+
* 完整类型由 OpenClaw 运行时在加载时注入,此处仅声明插件用到的部分。
|
|
5
|
+
*/
|
|
6
|
+
interface PluginApi {
|
|
7
|
+
logger: {
|
|
8
|
+
info: (msg: string, ...args: unknown[]) => void;
|
|
9
|
+
warn: (msg: string, ...args: unknown[]) => void;
|
|
10
|
+
error: (msg: string, ...args: unknown[]) => void;
|
|
11
|
+
};
|
|
12
|
+
config: {
|
|
13
|
+
plugins?: {
|
|
14
|
+
entries?: Record<string, {
|
|
15
|
+
config?: CloudphonePluginConfig;
|
|
16
|
+
}>;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
registerTool: (tool: {
|
|
20
|
+
name: string;
|
|
21
|
+
description: string;
|
|
22
|
+
parameters: unknown;
|
|
23
|
+
execute: (id: string, params: Record<string, unknown>) => Promise<McpToolResult>;
|
|
24
|
+
}) => void;
|
|
25
|
+
}
|
|
26
|
+
declare const plugin: {
|
|
27
|
+
id: string;
|
|
28
|
+
configSchema: {
|
|
29
|
+
type: string;
|
|
30
|
+
additionalProperties: boolean;
|
|
31
|
+
properties: {
|
|
32
|
+
baseUrl: {
|
|
33
|
+
type: string;
|
|
34
|
+
};
|
|
35
|
+
token: {
|
|
36
|
+
type: string;
|
|
37
|
+
};
|
|
38
|
+
timeout: {
|
|
39
|
+
type: string;
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
register(api: PluginApi): void;
|
|
44
|
+
};
|
|
45
|
+
export default plugin;
|
|
46
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,sBAAsB,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAEvE;;;GAGG;AACH,UAAU,SAAS;IACjB,MAAM,EAAE;QACN,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;QAChD,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;QAChD,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;KAClD,CAAC;IACF,MAAM,EAAE;QACN,OAAO,CAAC,EAAE;YACR,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;gBAAE,MAAM,CAAC,EAAE,sBAAsB,CAAA;aAAE,CAAC,CAAC;SAC/D,CAAC;KACH,CAAC;IACF,YAAY,EAAE,CAAC,IAAI,EAAE;QACnB,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,UAAU,EAAE,OAAO,CAAC;QACpB,OAAO,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC;KAClF,KAAK,IAAI,CAAC;CACZ;AASD,QAAA,MAAM,MAAM;;;;;;;;;;;;;;;;;kBAaI,SAAS;CAuDxB,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tools_1 = require("./tools");
|
|
4
|
+
/**
|
|
5
|
+
* 从 OpenClaw 运行时配置中读取当前插件的配置项。
|
|
6
|
+
*/
|
|
7
|
+
function resolveConfig(api) {
|
|
8
|
+
return api.config?.plugins?.entries?.["cloudphone"]?.config ?? {};
|
|
9
|
+
}
|
|
10
|
+
const plugin = {
|
|
11
|
+
id: "cloudphone",
|
|
12
|
+
configSchema: {
|
|
13
|
+
type: "object",
|
|
14
|
+
additionalProperties: false,
|
|
15
|
+
properties: {
|
|
16
|
+
baseUrl: { type: "string" },
|
|
17
|
+
token: { type: "string" },
|
|
18
|
+
timeout: { type: "number" },
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
register(api) {
|
|
22
|
+
const config = resolveConfig(api);
|
|
23
|
+
api.logger.info(`[cloudphone] 加载完成,baseUrl=${config.baseUrl ?? "(未配置,使用默认值)"}`);
|
|
24
|
+
for (const tool of tools_1.tools) {
|
|
25
|
+
api.registerTool({
|
|
26
|
+
name: tool.name,
|
|
27
|
+
description: tool.description,
|
|
28
|
+
parameters: tool.parameters,
|
|
29
|
+
execute: async (id, params) => {
|
|
30
|
+
api.logger.info(`[cloudphone] 工具 ${tool.name} 开始执行,id=${id},params=${JSON.stringify(params)}`);
|
|
31
|
+
try {
|
|
32
|
+
const result = await tool.execute(id, params, config);
|
|
33
|
+
api.logger.info(`[cloudphone] 工具 ${tool.name} 返回值: ${JSON.stringify(result)}`);
|
|
34
|
+
if (result &&
|
|
35
|
+
Array.isArray(result.content) &&
|
|
36
|
+
result.content.length > 0) {
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
content: [
|
|
41
|
+
{
|
|
42
|
+
type: "text",
|
|
43
|
+
text: result
|
|
44
|
+
? JSON.stringify(result)
|
|
45
|
+
: `[cloudphone] 工具 ${tool.name} 未返回有效内容`,
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
52
|
+
api.logger.error(`[cloudphone] 工具 ${tool.name} 执行异常: ${message}`);
|
|
53
|
+
return {
|
|
54
|
+
content: [
|
|
55
|
+
{
|
|
56
|
+
type: "text",
|
|
57
|
+
text: JSON.stringify({ ok: false, error: message }),
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
api.logger.info(`[cloudphone] 已注册工具: ${tool.name}`);
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
exports.default = plugin;
|
|
69
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;AAAA,mCAAuE;AAyBvE;;GAEG;AACH,SAAS,aAAa,CAAC,GAAc;IACnC,OAAO,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,YAAY,CAAC,EAAE,MAAM,IAAI,EAAE,CAAC;AACpE,CAAC;AAED,MAAM,MAAM,GAAG;IACb,EAAE,EAAE,YAAY;IAEhB,YAAY,EAAE;QACZ,IAAI,EAAE,QAAQ;QACd,oBAAoB,EAAE,KAAK;QAC3B,UAAU,EAAE;YACV,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YAC3B,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YACzB,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;SAC5B;KACF;IAED,QAAQ,CAAC,GAAc;QACrB,MAAM,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;QAClC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,6BAA6B,MAAM,CAAC,OAAO,IAAI,aAAa,EAAE,CAAC,CAAC;QAEhF,KAAK,MAAM,IAAI,IAAI,aAAK,EAAE,CAAC;YACzB,GAAG,CAAC,YAAY,CAAC;gBACf,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,WAAW,EAAE,IAAI,CAAC,WAAW;gBAC7B,UAAU,EAAE,IAAI,CAAC,UAAU;gBAC3B,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE;oBAC5B,GAAG,CAAC,MAAM,CAAC,IAAI,CACb,mBAAmB,IAAI,CAAC,IAAI,YAAY,EAAE,WAAW,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAC9E,CAAC;oBACF,IAAI,CAAC;wBACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;wBACtD,GAAG,CAAC,MAAM,CAAC,IAAI,CACb,mBAAmB,IAAI,CAAC,IAAI,SAAS,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAC9D,CAAC;wBACF,IACE,MAAM;4BACN,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC;4BAC7B,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EACzB,CAAC;4BACD,OAAO,MAAM,CAAC;wBAChB,CAAC;wBACD,OAAO;4BACL,OAAO,EAAE;gCACP;oCACE,IAAI,EAAE,MAAe;oCACrB,IAAI,EAAE,MAAM;wCACV,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;wCACxB,CAAC,CAAC,mBAAmB,IAAI,CAAC,IAAI,UAAU;iCAC3C;6BACF;yBACF,CAAC;oBACJ,CAAC;oBAAC,OAAO,GAAG,EAAE,CAAC;wBACb,MAAM,OAAO,GACX,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;wBACnD,GAAG,CAAC,MAAM,CAAC,KAAK,CACd,mBAAmB,IAAI,CAAC,IAAI,UAAU,OAAO,EAAE,CAChD,CAAC;wBACF,OAAO;4BACL,OAAO,EAAE;gCACP;oCACE,IAAI,EAAE,MAAe;oCACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;iCACpD;6BACF;yBACF,CAAC;oBACJ,CAAC;gBACH,CAAC;aACF,CAAC,CAAC;YACH,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,uBAAuB,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QACtD,CAAC;IACH,CAAC;CACF,CAAC;AAEF,kBAAe,MAAM,CAAC"}
|
package/dist/tools.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent 工具定义模块
|
|
3
|
+
*
|
|
4
|
+
* 每个工具需包含:
|
|
5
|
+
* - name: snake_case 格式的工具名
|
|
6
|
+
* - description: 向 AI Agent 说明工具用途
|
|
7
|
+
* - parameters: JSON Schema 描述入参结构
|
|
8
|
+
* - execute: 执行函数,接收 (id, params),返回 MCP Content 格式结果
|
|
9
|
+
*
|
|
10
|
+
* 官方文档:https://docs.openclaw.ai/plugins/agent-tools
|
|
11
|
+
*/
|
|
12
|
+
/** 插件配置类型(与 openclaw.plugin.json configSchema 保持一致) */
|
|
13
|
+
export interface CloudphonePluginConfig {
|
|
14
|
+
baseUrl?: string;
|
|
15
|
+
token?: string;
|
|
16
|
+
timeout?: number;
|
|
17
|
+
}
|
|
18
|
+
/** MCP Content 项 */
|
|
19
|
+
export interface McpContentItem {
|
|
20
|
+
type: "text";
|
|
21
|
+
text: string;
|
|
22
|
+
}
|
|
23
|
+
/** MCP 风格的工具返回值 */
|
|
24
|
+
export interface McpToolResult {
|
|
25
|
+
content: McpContentItem[];
|
|
26
|
+
}
|
|
27
|
+
/** 工具定义类型(与 OpenClaw api.registerTool 参数对齐) */
|
|
28
|
+
export interface ToolDefinition {
|
|
29
|
+
name: string;
|
|
30
|
+
description: string;
|
|
31
|
+
parameters: {
|
|
32
|
+
type: "object";
|
|
33
|
+
properties: Record<string, unknown>;
|
|
34
|
+
required?: string[];
|
|
35
|
+
};
|
|
36
|
+
execute: (id: string, params: Record<string, unknown>, config: CloudphonePluginConfig) => Promise<McpToolResult>;
|
|
37
|
+
}
|
|
38
|
+
/** 导出所有工具定义列表 */
|
|
39
|
+
export declare const tools: ToolDefinition[];
|
|
40
|
+
//# sourceMappingURL=tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,uDAAuD;AACvD,MAAM,WAAW,sBAAsB;IACrC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,oBAAoB;AACpB,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,mBAAmB;AACnB,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,cAAc,EAAE,CAAC;CAC3B;AAED,+CAA+C;AAC/C,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE;QACV,IAAI,EAAE,QAAQ,CAAC;QACf,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACpC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;KACrB,CAAC;IACF,OAAO,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,sBAAsB,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC;CAClH;AAiID,iBAAiB;AACjB,eAAO,MAAM,KAAK,EAAE,cAAc,EAA4C,CAAC"}
|
package/dist/tools.js
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Agent 工具定义模块
|
|
4
|
+
*
|
|
5
|
+
* 每个工具需包含:
|
|
6
|
+
* - name: snake_case 格式的工具名
|
|
7
|
+
* - description: 向 AI Agent 说明工具用途
|
|
8
|
+
* - parameters: JSON Schema 描述入参结构
|
|
9
|
+
* - execute: 执行函数,接收 (id, params),返回 MCP Content 格式结果
|
|
10
|
+
*
|
|
11
|
+
* 官方文档:https://docs.openclaw.ai/plugins/agent-tools
|
|
12
|
+
*/
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.tools = void 0;
|
|
15
|
+
/**
|
|
16
|
+
* 调试工具:echo
|
|
17
|
+
* 原样返回输入内容,用于验证工具调用链路是否正常。
|
|
18
|
+
*/
|
|
19
|
+
const echoTool = {
|
|
20
|
+
name: "echo",
|
|
21
|
+
description: "将输入的文本原样返回,用于验证工具调用是否正常。",
|
|
22
|
+
parameters: {
|
|
23
|
+
type: "object",
|
|
24
|
+
properties: {
|
|
25
|
+
text: {
|
|
26
|
+
type: "string",
|
|
27
|
+
description: "需要回显的文本内容",
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
required: ["text"],
|
|
31
|
+
},
|
|
32
|
+
execute: async (_id, { text }) => {
|
|
33
|
+
return { content: [{ type: "text", text: String(text) }] };
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* 工具:get_device_connection_link
|
|
38
|
+
* 查询指定设备的 SSH 连接链路信息。
|
|
39
|
+
*
|
|
40
|
+
* API: GET {baseUrl}/webide/api/autojs-stream/device-connection-link/{deviceId}
|
|
41
|
+
* Auth: Bearer Token
|
|
42
|
+
*/
|
|
43
|
+
const getDeviceConnectionLinkTool = {
|
|
44
|
+
name: "get_device_connection_link",
|
|
45
|
+
description: "查询指定设备的 SSH 连接链路信息,返回 SSH 连接地址(host:port)和链路过期时间。需要提供设备 ID。",
|
|
46
|
+
parameters: {
|
|
47
|
+
type: "object",
|
|
48
|
+
properties: {
|
|
49
|
+
deviceId: {
|
|
50
|
+
type: "string",
|
|
51
|
+
description: "设备 ID,如 7593283098889067310",
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
required: ["deviceId"],
|
|
55
|
+
},
|
|
56
|
+
execute: async (_id, { deviceId }, config) => {
|
|
57
|
+
const base = config.baseUrl ?? "https://cptest.yaltc.cn";
|
|
58
|
+
const timeout = config.timeout ?? 5000;
|
|
59
|
+
const url = `${base}/webide/api/autojs-stream/device-connection-link/${String(deviceId)}`;
|
|
60
|
+
const headers = {
|
|
61
|
+
"Content-Type": "application/json",
|
|
62
|
+
};
|
|
63
|
+
if (config.token) {
|
|
64
|
+
headers["Authorization"] = `Bearer ${config.token}`;
|
|
65
|
+
}
|
|
66
|
+
let timer;
|
|
67
|
+
let body;
|
|
68
|
+
try {
|
|
69
|
+
const controller = typeof AbortController !== "undefined" ? new AbortController() : undefined;
|
|
70
|
+
if (controller) {
|
|
71
|
+
timer = setTimeout(() => controller.abort(), timeout);
|
|
72
|
+
}
|
|
73
|
+
const res = await fetch(url, {
|
|
74
|
+
method: "GET",
|
|
75
|
+
headers,
|
|
76
|
+
signal: controller?.signal,
|
|
77
|
+
});
|
|
78
|
+
if (!res.ok) {
|
|
79
|
+
const result = { ok: false, httpStatus: res.status, message: `HTTP 错误:${res.status} ${res.statusText}` };
|
|
80
|
+
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
|
81
|
+
}
|
|
82
|
+
body = (await res.json());
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
86
|
+
const result = { ok: false, message: `请求失败:${message}` };
|
|
87
|
+
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
|
88
|
+
}
|
|
89
|
+
finally {
|
|
90
|
+
if (timer) {
|
|
91
|
+
clearTimeout(timer);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (!body.success || body.code !== "1") {
|
|
95
|
+
const result = { ok: false, code: body.code, message: body.message, traceId: body.traceId };
|
|
96
|
+
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
|
97
|
+
}
|
|
98
|
+
const data = body.data;
|
|
99
|
+
if (!data) {
|
|
100
|
+
const result = { ok: false, message: "API 返回数据为空", traceId: body.traceId };
|
|
101
|
+
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
|
102
|
+
}
|
|
103
|
+
const result = {
|
|
104
|
+
ok: true,
|
|
105
|
+
deviceId: data.deviceId,
|
|
106
|
+
sshCommand: data.sshCommand,
|
|
107
|
+
macSshCommand: data.macSshCommand,
|
|
108
|
+
sshPwd: data.sshPwd,
|
|
109
|
+
expireTime: data.expireTime,
|
|
110
|
+
expireAt: new Date(data.expireTime * 1000).toISOString(),
|
|
111
|
+
traceId: body.traceId,
|
|
112
|
+
};
|
|
113
|
+
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
/** 导出所有工具定义列表 */
|
|
117
|
+
exports.tools = [echoTool, getDeviceConnectionLinkTool];
|
|
118
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "cloudphone",
|
|
3
|
+
"name": "CloudPhone Plugin",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"description": "OpenClaw CloudPhone 插件 —— 提供设备连接链路查询等 Agent 工具能力",
|
|
6
|
+
"configSchema": {
|
|
7
|
+
"type": "object",
|
|
8
|
+
"additionalProperties": false,
|
|
9
|
+
"properties": {
|
|
10
|
+
"baseUrl": {
|
|
11
|
+
"type": "string",
|
|
12
|
+
"description": "CloudPhone API 基础地址",
|
|
13
|
+
"default": "https://cptest.yaltc.cn"
|
|
14
|
+
},
|
|
15
|
+
"token": {
|
|
16
|
+
"type": "string",
|
|
17
|
+
"description": "Bearer Token 鉴权凭证"
|
|
18
|
+
},
|
|
19
|
+
"timeout": {
|
|
20
|
+
"type": "number",
|
|
21
|
+
"description": "请求超时时间(毫秒)",
|
|
22
|
+
"default": 5000
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"uiHints": {
|
|
27
|
+
"baseUrl": {
|
|
28
|
+
"label": "API 基础地址",
|
|
29
|
+
"placeholder": "https://cptest.yaltc.cn"
|
|
30
|
+
},
|
|
31
|
+
"token": {
|
|
32
|
+
"label": "Bearer Token",
|
|
33
|
+
"placeholder": "输入鉴权 Token",
|
|
34
|
+
"sensitive": true
|
|
35
|
+
},
|
|
36
|
+
"timeout": {
|
|
37
|
+
"label": "请求超时(ms)"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sav7ng/cloudphone",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "OpenClaw CloudPhone 插件 —— 提供自定义 Agent 工具能力",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"openclaw.plugin.json"
|
|
10
|
+
],
|
|
11
|
+
"keywords": [
|
|
12
|
+
"openclaw",
|
|
13
|
+
"plugin",
|
|
14
|
+
"cloudphone"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc",
|
|
18
|
+
"dev": "tsc --watch",
|
|
19
|
+
"clean": "rimraf dist"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"typescript": "^5.4.0",
|
|
23
|
+
"rimraf": "^5.0.0"
|
|
24
|
+
},
|
|
25
|
+
"openclaw": {
|
|
26
|
+
"extensions": ["./dist/index.js"]
|
|
27
|
+
}
|
|
28
|
+
}
|