ai-world-sdk 1.5.15 → 1.5.17
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/cli/commands/help.js +3 -1
- package/dist/cli/commands/plugin.js +10 -4
- package/dist/config.d.ts +3 -3
- package/dist/config.js +3 -2
- package/dist/index.d.ts +1 -1
- package/dist/plugin-management.d.ts +19 -6
- package/dist/plugin-management.js +4 -0
- package/package.json +1 -1
- package/skills/ai-world-sdk/SKILL.md +122 -3
- package/skills/ai-world-sdk/docs/cli-commands.md +2 -1
- package/skills/ai-world-sdk/docs/platform-api.md +12 -2
|
@@ -109,7 +109,7 @@ const COMMAND_DETAILS = {
|
|
|
109
109
|
},
|
|
110
110
|
plugin: {
|
|
111
111
|
desc: '插件管理 —— 部署、启用/禁用、重启、查看日志',
|
|
112
|
-
usage: 'ai-world plugin <list|get|ids|create|enable|disable|reload|restart|logs|status|delete>',
|
|
112
|
+
usage: 'ai-world plugin <list|get|ids|create|update|enable|disable|reload|restart|logs|status|delete>',
|
|
113
113
|
examples: [
|
|
114
114
|
'ai-world plugin list',
|
|
115
115
|
'ai-world plugin ids --enabled-only',
|
|
@@ -117,6 +117,8 @@ const COMMAND_DETAILS = {
|
|
|
117
117
|
'ai-world plugin enable my-plugin',
|
|
118
118
|
'ai-world plugin logs my-plugin --lines 50',
|
|
119
119
|
'ai-world plugin create ./dist.zip --plugin-id my-plugin --name "我的插件"',
|
|
120
|
+
'ai-world plugin create --plugin-id py-plugin --server-zip server.zip --backend-type python',
|
|
121
|
+
'ai-world plugin update --plugin-id my-plugin --server-zip server.zip --backend-type node',
|
|
120
122
|
],
|
|
121
123
|
},
|
|
122
124
|
admin: {
|
|
@@ -191,8 +191,9 @@ function registerPluginCommands(program) {
|
|
|
191
191
|
.option('--description <text>', '插件描述')
|
|
192
192
|
.option('--author <author>', '插件作者')
|
|
193
193
|
.option('--version <ver>', '插件版本')
|
|
194
|
-
.option('--server-zip <path>', '
|
|
195
|
-
.option('--backend-
|
|
194
|
+
.option('--server-zip <path>', '后端代码 zip 包路径')
|
|
195
|
+
.option('--backend-type <type>', '后端类型: node 或 python(默认 node)')
|
|
196
|
+
.option('--backend-entry <entry>', '后端入口文件(Node.js 默认 index.js,Python 默认 start.py)')
|
|
196
197
|
.option('--backend-websocket', '启用 WebSocket 代理')
|
|
197
198
|
.option('--disable-sdk-update-notice', '禁用 SDK 更新提示')
|
|
198
199
|
.action(async (zipFile, options, cmd) => {
|
|
@@ -206,6 +207,7 @@ function registerPluginCommands(program) {
|
|
|
206
207
|
});
|
|
207
208
|
(0, utils_1.initSDK)(auth);
|
|
208
209
|
const client = new plugin_management_1.PluginManagementClient();
|
|
210
|
+
const bt = options.backendType;
|
|
209
211
|
const res = await client.create({
|
|
210
212
|
pluginId: options.pluginId,
|
|
211
213
|
name: options.name,
|
|
@@ -214,6 +216,7 @@ function registerPluginCommands(program) {
|
|
|
214
216
|
version: options.version,
|
|
215
217
|
staticZip: zipFile ? (0, utils_1.readFileAsFile)(zipFile) : undefined,
|
|
216
218
|
serverZip: options.serverZip ? (0, utils_1.readFileAsFile)(options.serverZip) : undefined,
|
|
219
|
+
backendType: bt === 'node' || bt === 'python' ? bt : undefined,
|
|
217
220
|
backendEntry: options.backendEntry,
|
|
218
221
|
backendWebsocket: options.backendWebsocket === true ? true : undefined,
|
|
219
222
|
disableSdkUpdateNotice: options.disableSdkUpdateNotice === true ? true : undefined,
|
|
@@ -232,8 +235,9 @@ function registerPluginCommands(program) {
|
|
|
232
235
|
.option('--description <text>', '插件描述')
|
|
233
236
|
.option('--author <author>', '插件作者')
|
|
234
237
|
.option('--version <ver>', '插件版本')
|
|
235
|
-
.option('--server-zip <path>', '
|
|
236
|
-
.option('--backend-
|
|
238
|
+
.option('--server-zip <path>', '后端代码 zip 包路径')
|
|
239
|
+
.option('--backend-type <type>', '后端类型: node 或 python(默认 node)')
|
|
240
|
+
.option('--backend-entry <entry>', '后端入口文件(Node.js 默认 index.js,Python 默认 start.py)')
|
|
237
241
|
.option('--backend-websocket', '启用 WebSocket 代理')
|
|
238
242
|
.option('--disable-sdk-update-notice', '禁用 SDK 更新提示')
|
|
239
243
|
.action(async (zipFile, options, cmd) => {
|
|
@@ -247,6 +251,7 @@ function registerPluginCommands(program) {
|
|
|
247
251
|
});
|
|
248
252
|
(0, utils_1.initSDK)(auth);
|
|
249
253
|
const client = new plugin_management_1.PluginManagementClient();
|
|
254
|
+
const bt = options.backendType;
|
|
250
255
|
const res = await client.update({
|
|
251
256
|
pluginId: options.pluginId,
|
|
252
257
|
name: options.name,
|
|
@@ -255,6 +260,7 @@ function registerPluginCommands(program) {
|
|
|
255
260
|
version: options.version,
|
|
256
261
|
staticZip: zipFile ? (0, utils_1.readFileAsFile)(zipFile) : undefined,
|
|
257
262
|
serverZip: options.serverZip ? (0, utils_1.readFileAsFile)(options.serverZip) : undefined,
|
|
263
|
+
backendType: bt === 'node' || bt === 'python' ? bt : undefined,
|
|
258
264
|
backendEntry: options.backendEntry,
|
|
259
265
|
backendWebsocket: options.backendWebsocket === true ? true : undefined,
|
|
260
266
|
disableSdkUpdateNotice: options.disableSdkUpdateNotice === true ? true : undefined,
|
package/dist/config.d.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*
|
|
10
10
|
* 注意: {VERSION} 占位符会在构建时被替换为实际版本号
|
|
11
11
|
*/
|
|
12
|
-
export declare const SDK_SIGNATURE = "AI_WORLD_SDK_V:1.5.
|
|
12
|
+
export declare const SDK_SIGNATURE = "AI_WORLD_SDK_V:1.5.17";
|
|
13
13
|
/**
|
|
14
14
|
* 版本兼容性错误
|
|
15
15
|
*/
|
|
@@ -35,8 +35,8 @@ declare class SDKConfig {
|
|
|
35
35
|
private _authCheckPromise;
|
|
36
36
|
private _currentUser;
|
|
37
37
|
private _cliMode;
|
|
38
|
-
readonly sdkSignature = "AI_WORLD_SDK_V:1.5.
|
|
39
|
-
readonly sdkVersion = "1.5.
|
|
38
|
+
readonly sdkSignature = "AI_WORLD_SDK_V:1.5.17";
|
|
39
|
+
readonly sdkVersion = "1.5.17";
|
|
40
40
|
constructor();
|
|
41
41
|
/**
|
|
42
42
|
* Set global base URL
|
package/dist/config.js
CHANGED
|
@@ -7,7 +7,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
7
7
|
exports.sdkConfig = exports.VersionCompatibilityError = exports.SDK_SIGNATURE = void 0;
|
|
8
8
|
// SDK 版本号(构建时自动从 package.json 更新)
|
|
9
9
|
// 此版本号会在运行 npm run build 时自动从 package.json 读取并更新
|
|
10
|
-
const SDK_VERSION = "1.5.
|
|
10
|
+
const SDK_VERSION = "1.5.17";
|
|
11
11
|
/**
|
|
12
12
|
* SDK 特征码 - 用于在构建后的 JS 文件中识别 SDK 版本
|
|
13
13
|
* 格式: AI_WORLD_SDK_V:版本号
|
|
@@ -15,7 +15,7 @@ const SDK_VERSION = "1.5.15";
|
|
|
15
15
|
*
|
|
16
16
|
* 注意: {VERSION} 占位符会在构建时被替换为实际版本号
|
|
17
17
|
*/
|
|
18
|
-
exports.SDK_SIGNATURE = "AI_WORLD_SDK_V:1.5.
|
|
18
|
+
exports.SDK_SIGNATURE = "AI_WORLD_SDK_V:1.5.17";
|
|
19
19
|
/**
|
|
20
20
|
* 版本兼容性错误
|
|
21
21
|
*/
|
|
@@ -291,6 +291,7 @@ class SDKConfig {
|
|
|
291
291
|
const path = require('path');
|
|
292
292
|
const fs = require('fs');
|
|
293
293
|
const cwd = process.cwd();
|
|
294
|
+
console.log('server cwd:', cwd);
|
|
294
295
|
// .env.local 优先级最高(仅次于已有 process.env)
|
|
295
296
|
const envLocalPath = path.resolve(cwd, '.env.local');
|
|
296
297
|
if (fs.existsSync(envLocalPath)) {
|
package/dist/index.d.ts
CHANGED
|
@@ -34,7 +34,7 @@ export { VersionedResourceClient, type VersionedResourceClientConfig, type Versi
|
|
|
34
34
|
export { AgentSkillClient, type AgentSkillClientConfig, type AgentSkillInfo, type AgentSkillListResponse, type ListSkillsOptions, } from "./agent-skills";
|
|
35
35
|
export { AuthClient, getCurrentUserInfo, type AuthConfig, type UserInfo, };
|
|
36
36
|
export { AdminClient, type AdminClientConfig, type AdminUserInfo, type AdminUserListResponse, type ListUsersOptions, type RoleInfo, type CreateRoleData, type UpdateRoleData, type RoleUserCount, type TableColumn, type TableDataResponse, type ListTableDataOptions, } from "./admin";
|
|
37
|
-
export { PluginManagementClient, type PluginManagementClientConfig, type PluginInfo, type PluginListResponse, type ListPluginsOptions, type CreatePluginData, type PluginStatus, type PluginTemplateInfo, type PluginTemplateListResponse, type ListPluginTemplatesOptions, type CreatePluginTemplateData, type UpdatePluginTemplateData, } from "./plugin-management";
|
|
37
|
+
export { PluginManagementClient, type PluginManagementClientConfig, type PluginInfo, type PluginListResponse, type ListPluginsOptions, type CreatePluginData, type UpdatePluginData, type PluginStatus, type RestartServerResult, type PluginTemplateInfo, type PluginTemplateListResponse, type ListPluginTemplatesOptions, type CreatePluginTemplateData, type UpdatePluginTemplateData, } from "./plugin-management";
|
|
38
38
|
export { StatsClient, DashboardClient, type StatsClientConfig, type AiApiCallsOptions, type AiApiCallsTrendOptions, type AiApiCallsTrendByUserOptions, type PluginAccessOptions, } from "./stats";
|
|
39
39
|
export { AIConfigClient, type AIConfigClientConfig, } from "./ai-config";
|
|
40
40
|
export { SharedResourceClient, type SharedResourceClientConfig, type SharedResourceInfo, type SharedResourceListResponse, type ListSharedResourceOptions, type UpdateSharedResourceData, } from "./shared-resource";
|
|
@@ -14,7 +14,13 @@ export interface PluginInfo {
|
|
|
14
14
|
author?: string;
|
|
15
15
|
version?: string;
|
|
16
16
|
enabled: boolean;
|
|
17
|
-
|
|
17
|
+
has_backend?: boolean;
|
|
18
|
+
backend_type?: "node" | "python";
|
|
19
|
+
backend_port?: number;
|
|
20
|
+
backend_running?: boolean;
|
|
21
|
+
backend_entry?: string;
|
|
22
|
+
backend_websocket?: boolean;
|
|
23
|
+
has_static_file?: boolean;
|
|
18
24
|
created_at?: string;
|
|
19
25
|
updated_at?: string;
|
|
20
26
|
[key: string]: any;
|
|
@@ -45,6 +51,7 @@ export interface CreatePluginData {
|
|
|
45
51
|
templateId?: string;
|
|
46
52
|
staticZip?: File | Blob;
|
|
47
53
|
serverZip?: File | Blob;
|
|
54
|
+
backendType?: "node" | "python";
|
|
48
55
|
backendEntry?: string;
|
|
49
56
|
backendWebsocket?: boolean;
|
|
50
57
|
disableSdkUpdateNotice?: boolean;
|
|
@@ -57,6 +64,7 @@ export interface UpdatePluginData {
|
|
|
57
64
|
version?: string;
|
|
58
65
|
staticZip?: File | Blob;
|
|
59
66
|
serverZip?: File | Blob;
|
|
67
|
+
backendType?: "node" | "python";
|
|
60
68
|
backendEntry?: string;
|
|
61
69
|
backendWebsocket?: boolean;
|
|
62
70
|
disableSdkUpdateNotice?: boolean;
|
|
@@ -64,8 +72,7 @@ export interface UpdatePluginData {
|
|
|
64
72
|
export interface PluginStatus {
|
|
65
73
|
plugin_id: string;
|
|
66
74
|
enabled: boolean;
|
|
67
|
-
|
|
68
|
-
server_running?: boolean;
|
|
75
|
+
exists: boolean;
|
|
69
76
|
[key: string]: any;
|
|
70
77
|
}
|
|
71
78
|
export interface PluginTemplateInfo {
|
|
@@ -92,6 +99,14 @@ export interface ListPluginTemplatesOptions {
|
|
|
92
99
|
name?: string;
|
|
93
100
|
category?: string;
|
|
94
101
|
}
|
|
102
|
+
export interface RestartServerResult {
|
|
103
|
+
message: string;
|
|
104
|
+
plugin_id: string;
|
|
105
|
+
port: number;
|
|
106
|
+
backend_type: string;
|
|
107
|
+
install_logs: string;
|
|
108
|
+
startup_logs: string;
|
|
109
|
+
}
|
|
95
110
|
export interface CreatePluginTemplateData {
|
|
96
111
|
pluginId: string;
|
|
97
112
|
name: string;
|
|
@@ -135,9 +150,7 @@ export declare class PluginManagementClient {
|
|
|
135
150
|
reload(pluginId: string): Promise<{
|
|
136
151
|
message: string;
|
|
137
152
|
}>;
|
|
138
|
-
restartServer(pluginId: string): Promise<
|
|
139
|
-
message: string;
|
|
140
|
-
}>;
|
|
153
|
+
restartServer(pluginId: string): Promise<RestartServerResult>;
|
|
141
154
|
getServerLogs(pluginId: string, lines?: number): Promise<string>;
|
|
142
155
|
listTemplates(): Promise<any[]>;
|
|
143
156
|
getTemplate(templateId: string): Promise<any>;
|
|
@@ -118,6 +118,8 @@ class PluginManagementClient {
|
|
|
118
118
|
formData.append("static_zip", data.staticZip);
|
|
119
119
|
if (data.serverZip)
|
|
120
120
|
formData.append("server_zip", data.serverZip);
|
|
121
|
+
if (data.backendType)
|
|
122
|
+
formData.append("backend_type", data.backendType);
|
|
121
123
|
if (data.backendEntry)
|
|
122
124
|
formData.append("backend_entry", data.backendEntry);
|
|
123
125
|
if (data.backendWebsocket !== undefined)
|
|
@@ -153,6 +155,8 @@ class PluginManagementClient {
|
|
|
153
155
|
formData.append("static_zip", data.staticZip);
|
|
154
156
|
if (data.serverZip)
|
|
155
157
|
formData.append("server_zip", data.serverZip);
|
|
158
|
+
if (data.backendType)
|
|
159
|
+
formData.append("backend_type", data.backendType);
|
|
156
160
|
if (data.backendEntry)
|
|
157
161
|
formData.append("backend_entry", data.backendEntry);
|
|
158
162
|
if (data.backendWebsocket !== undefined)
|
package/package.json
CHANGED
|
@@ -119,11 +119,129 @@ sdkConfig.setToken('your-jwt-token');
|
|
|
119
119
|
sdkConfig.setPluginId('my-plugin');
|
|
120
120
|
```
|
|
121
121
|
|
|
122
|
-
|
|
123
|
-
- `AI_WORLD_BASE_URL` —
|
|
122
|
+
也可通过环境变量自动初始化(SDK 自动读取 `.env.local` > `.env` > `AI_WORLD_ENV_FILE` 指定文件):
|
|
123
|
+
- `AI_WORLD_BASE_URL` — 服务端地址,插件后端启动时由平台自动注入
|
|
124
124
|
- `PLUGIN_ID` — 插件 ID
|
|
125
125
|
- `DEBUG_TOKEN` — 调试用 JWT Token
|
|
126
126
|
- `AI_WORLD_TOKEN` — 用户登录后获取的 JWT Token
|
|
127
|
+
- `AI_WORLD_ENV_FILE` — 指定自定义 `.env` 文件路径(绝对或相对路径均可)
|
|
128
|
+
|
|
129
|
+
### 插件后端环境(平台自动注入)
|
|
130
|
+
|
|
131
|
+
当插件配置了后端(`plugin.json` 的 `backend` 字段),平台启动子进程时会自动注入以下环境变量:
|
|
132
|
+
|
|
133
|
+
| 环境变量 | 说明 |
|
|
134
|
+
|----------|------|
|
|
135
|
+
| `PORT` | **插件后端必须监听的端口**(平台自动分配,范围 19000~19999) |
|
|
136
|
+
| `SERVER_PORT` | 同 `PORT`,兼容别名 |
|
|
137
|
+
| `PLUGIN_ID` | 当前插件 ID |
|
|
138
|
+
| `AI_WORLD_BASE_URL` | 平台后端地址(默认 `http://127.0.0.1:8000`) |
|
|
139
|
+
| `AI_WORLD_ENV_FILE` | 平台写入的 `.env` 文件路径(`server/.env`),SDK 自动加载 |
|
|
140
|
+
| `NODE_ENV` | 固定为 `production`(仅 Node.js 后端) |
|
|
141
|
+
|
|
142
|
+
**重要**:插件后端 **必须** 监听 `PORT` 环境变量指定的端口,否则平台无法正确代理请求。
|
|
143
|
+
|
|
144
|
+
#### plugin.json backend 配置
|
|
145
|
+
|
|
146
|
+
```json
|
|
147
|
+
{
|
|
148
|
+
"backend": {
|
|
149
|
+
"type": "node",
|
|
150
|
+
"entry": "index.js",
|
|
151
|
+
"install_cmd": "npm install",
|
|
152
|
+
"health_check": "/health"
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
| 字段 | 说明 |
|
|
158
|
+
|------|------|
|
|
159
|
+
| `type` | 后端类型:`"node"` 或 `"python"`(默认 `"node"`) |
|
|
160
|
+
| `entry` | 入口文件(Node.js 默认 `index.js`,Python 默认 `start.py`) |
|
|
161
|
+
| `install_cmd` | 依赖安装命令(Node.js 默认 `npm install`,Python 默认 `pip install -r requirements.txt`) |
|
|
162
|
+
| `start_cmd` | 启动命令(可选,默认 `node {entry}` 或 `python {entry}`) |
|
|
163
|
+
| `health_check` | 健康检查路径(默认 `/health`) |
|
|
164
|
+
| `enable_websocket` | 是否启用 WebSocket 代理(默认 `false`) |
|
|
165
|
+
|
|
166
|
+
#### Node.js 后端示例
|
|
167
|
+
|
|
168
|
+
```javascript
|
|
169
|
+
// server/index.js
|
|
170
|
+
const express = require('express');
|
|
171
|
+
const app = express();
|
|
172
|
+
const port = process.env.PORT || 3000;
|
|
173
|
+
|
|
174
|
+
app.get('/health', (req, res) => res.json({ status: 'ok' }));
|
|
175
|
+
app.get('/api/hello', (req, res) => res.json({ message: 'Hello from plugin backend!' }));
|
|
176
|
+
|
|
177
|
+
app.listen(port, () => {
|
|
178
|
+
console.log(`Plugin backend listening on port ${port}`);
|
|
179
|
+
});
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
#### Python 后端示例
|
|
183
|
+
|
|
184
|
+
```python
|
|
185
|
+
# server/start.py
|
|
186
|
+
import os
|
|
187
|
+
from fastapi import FastAPI
|
|
188
|
+
import uvicorn
|
|
189
|
+
|
|
190
|
+
app = FastAPI()
|
|
191
|
+
port = int(os.environ.get("PORT", "3000"))
|
|
192
|
+
|
|
193
|
+
@app.get("/health")
|
|
194
|
+
def health():
|
|
195
|
+
return {"status": "ok"}
|
|
196
|
+
|
|
197
|
+
@app.get("/api/hello")
|
|
198
|
+
def hello():
|
|
199
|
+
return {"message": "Hello from Python plugin backend!"}
|
|
200
|
+
|
|
201
|
+
if __name__ == "__main__":
|
|
202
|
+
uvicorn.run(app, host="0.0.0.0", port=port)
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
对应 `plugin.json`:
|
|
206
|
+
```json
|
|
207
|
+
{
|
|
208
|
+
"backend": {
|
|
209
|
+
"type": "python",
|
|
210
|
+
"entry": "start.py",
|
|
211
|
+
"install_cmd": "pip install -r requirements.txt",
|
|
212
|
+
"health_check": "/health"
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### 插件前端请求插件后端(HTTP 代理)
|
|
218
|
+
|
|
219
|
+
平台为每个后端插件注册了 HTTP 反向代理路由,**插件前端不需要知道后端实际端口**,统一通过以下地址访问:
|
|
220
|
+
|
|
221
|
+
```
|
|
222
|
+
{AI_WORLD_BASE_URL}/api/{plugin-id}/server/{path}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
例如插件 ID 为 `my-plugin`,后端有 `/api/hello` 接口,前端请求地址为:
|
|
226
|
+
|
|
227
|
+
```
|
|
228
|
+
https://aiworld.local:8000/api/my-plugin/server/api/hello
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
在插件前端代码中使用 `sdkConfig` 获取 baseUrl:
|
|
232
|
+
|
|
233
|
+
```typescript
|
|
234
|
+
import { sdkConfig } from 'ai-world-sdk';
|
|
235
|
+
|
|
236
|
+
// 插件前端请求插件后端
|
|
237
|
+
const baseUrl = sdkConfig.getServerUrl();
|
|
238
|
+
const pluginId = sdkConfig.getPluginId();
|
|
239
|
+
const response = await fetch(`${baseUrl}/api/${pluginId}/server/api/hello`, {
|
|
240
|
+
headers: { 'Authorization': `Bearer ${sdkConfig.getToken()}` }
|
|
241
|
+
});
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
WebSocket 同理:`ws(s)://{host}/api/{plugin-id}/server/ws`
|
|
127
245
|
|
|
128
246
|
## 功能模块
|
|
129
247
|
|
|
@@ -269,7 +387,8 @@ for await (const chunk of stream.textStream) {
|
|
|
269
387
|
- `PluginManagementClient` — 插件 CRUD(`create` / `update` 分离)、启用/禁用/重载/重启、模板管理
|
|
270
388
|
- `create(data)` — 创建新插件(POST `/api/plugins/create`),插件不存在时使用
|
|
271
389
|
- `update(data)` — 更新已有插件(POST `/api/plugins/update`),插件必须已存在,未传入的字段保留原值
|
|
272
|
-
- 两者均支持: pluginId / name / description / author / version / staticZip / serverZip / backendEntry / backendWebsocket / disableSdkUpdateNotice
|
|
390
|
+
- 两者均支持: pluginId / name / description / author / version / staticZip / serverZip / backendType / backendEntry / backendWebsocket / disableSdkUpdateNotice
|
|
391
|
+
- `backendType` — 后端类型:`"node"` 或 `"python"`(默认 node)
|
|
273
392
|
- `StatsClient` — AI 接口调用统计/趋势、插件访问统计(管理员)
|
|
274
393
|
- `DashboardClient` — 当前用户统计(无需管理员权限)
|
|
275
394
|
- `SharedResourceClient` — 平台级文件共享(与 `ResourceClient` 的插件级 ACL 不同)
|
|
@@ -139,7 +139,8 @@ ai-world plugin disable <plugin-id>
|
|
|
139
139
|
ai-world plugin reload <plugin-id>
|
|
140
140
|
ai-world plugin restart <plugin-id>
|
|
141
141
|
ai-world plugin logs <plugin-id> [--lines 100]
|
|
142
|
-
ai-world plugin create ./plugin.zip --plugin-id my-plugin [--name "My Plugin"] [--description "说明"]
|
|
142
|
+
ai-world plugin create ./plugin.zip --plugin-id my-plugin [--name "My Plugin"] [--description "说明"] [--backend-type node|python] [--server-zip server.zip] [--backend-entry index.js]
|
|
143
|
+
ai-world plugin update [zip-file] --plugin-id <id> [--name "Name"] [--backend-type node|python] [--server-zip server.zip] [--backend-entry entry.js]
|
|
143
144
|
ai-world plugin delete <plugin-id>
|
|
144
145
|
ai-world plugin status <plugin-id>
|
|
145
146
|
```
|
|
@@ -19,13 +19,23 @@ const ids = await plugins.listIds(true); // string[]
|
|
|
19
19
|
const info = await plugins.get('my-plugin');
|
|
20
20
|
const status = await plugins.getStatus('my-plugin');
|
|
21
21
|
|
|
22
|
-
//
|
|
22
|
+
// 创建插件(Node.js 后端)
|
|
23
23
|
await plugins.create({
|
|
24
24
|
pluginId: 'new-plugin',
|
|
25
25
|
name: '新插件',
|
|
26
26
|
description: '描述',
|
|
27
27
|
staticZip: someZipFile, // 可选,含 index.html 的 zip
|
|
28
|
-
serverZip: serverZipFile, //
|
|
28
|
+
serverZip: serverZipFile, // 可选,后端代码 zip
|
|
29
|
+
backendType: 'node', // 可选,'node' | 'python',默认 'node'
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// 创建 Python 后端插件
|
|
33
|
+
await plugins.create({
|
|
34
|
+
pluginId: 'py-plugin',
|
|
35
|
+
name: 'Python 插件',
|
|
36
|
+
serverZip: pyZipFile,
|
|
37
|
+
backendType: 'python',
|
|
38
|
+
backendEntry: 'start.py',
|
|
29
39
|
});
|
|
30
40
|
|
|
31
41
|
// 启用 / 禁用 / 重载 / 重启后端
|