@artflo-ai/artflo-openclaw-plugin 0.0.3 → 0.0.4
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/src/core/api/api-base.js +2 -12
- package/dist/src/core/api/api-paths.js +31 -0
- package/dist/src/core/api/upload-file.js +2 -3
- package/dist/src/core/canvas/canvas-websocket-client.js +2 -2
- package/dist/src/core/canvas/create-canvas.js +3 -13
- package/dist/src/core/config/fetch-client-params.js +2 -1
- package/dist/src/core/config/fetch-vip-info.js +2 -1
- package/package.json +1 -1
- package/skills/artflo-canvas/SKILL.md +1 -0
- package/skills/artflo-canvas/references/planning-guide.md +1 -1
|
@@ -1,12 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
3
|
-
return config.apiBaseUrl.replace(/\/+$/, '');
|
|
4
|
-
}
|
|
5
|
-
/**
|
|
6
|
-
* Derive the WebSocket URL from apiBaseUrl.
|
|
7
|
-
* https://webapi.artflo.ai → wss://webapi.artflo.ai/canvas/ws
|
|
8
|
-
*/
|
|
9
|
-
export function getCanvasWsUrl(config) {
|
|
10
|
-
const hostname = new URL(config.apiBaseUrl).hostname;
|
|
11
|
-
return `wss://${hostname}/canvas/ws`;
|
|
12
|
-
}
|
|
1
|
+
// Re-export from api-paths for backward compatibility
|
|
2
|
+
export { buildApiUrl, buildWsUrl, buildVipUrl, buildWebUrl } from './api-paths.js';
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* All Artflo API paths in one place.
|
|
3
|
+
* Every HTTP/WS request in this plugin MUST use a path from here.
|
|
4
|
+
* Do NOT construct API URLs manually elsewhere.
|
|
5
|
+
*/
|
|
6
|
+
/** WebSocket */
|
|
7
|
+
export const WS_CANVAS = '/canvas/ws';
|
|
8
|
+
/** apiBaseUrl paths */
|
|
9
|
+
export const API_CREATE_CANVAS = '/canvas';
|
|
10
|
+
export const API_UPLOAD_FILE = '/storage/obs/starii';
|
|
11
|
+
/** vipApiBaseUrl paths */
|
|
12
|
+
export const API_VIP_INFO = '/h5/user/vip_info_by_group.json';
|
|
13
|
+
/** webApiBaseUrl paths */
|
|
14
|
+
export const API_CLIENT_PARAMS = '/api/subscribe-client-params';
|
|
15
|
+
// ── Helper builders ─────────────────────────────────────────────────
|
|
16
|
+
function strip(url) {
|
|
17
|
+
return url.replace(/\/+$/, '');
|
|
18
|
+
}
|
|
19
|
+
export function buildApiUrl(config, path) {
|
|
20
|
+
return `${strip(config.apiBaseUrl)}${path}`;
|
|
21
|
+
}
|
|
22
|
+
export function buildVipUrl(config, path) {
|
|
23
|
+
return `${strip(config.vipApiBaseUrl)}${path}`;
|
|
24
|
+
}
|
|
25
|
+
export function buildWebUrl(config, path) {
|
|
26
|
+
return `${strip(config.webApiBaseUrl)}${path}`;
|
|
27
|
+
}
|
|
28
|
+
export function buildWsUrl(config) {
|
|
29
|
+
const hostname = new URL(config.apiBaseUrl).hostname;
|
|
30
|
+
return `wss://${hostname}${WS_CANVAS}`;
|
|
31
|
+
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { readFile } from 'node:fs/promises';
|
|
9
9
|
import { basename } from 'node:path';
|
|
10
|
-
import {
|
|
10
|
+
import { buildApiUrl, API_UPLOAD_FILE } from '../api/api-paths.js';
|
|
11
11
|
/**
|
|
12
12
|
* Upload a local file or a remote URL to Artflo OBS.
|
|
13
13
|
*
|
|
@@ -37,8 +37,7 @@ export async function uploadFile(config, source, filename) {
|
|
|
37
37
|
}
|
|
38
38
|
const formData = new FormData();
|
|
39
39
|
formData.append('file', fileBlob, resolvedFilename);
|
|
40
|
-
const
|
|
41
|
-
const response = await fetch(`${baseUrl}/storage/obs/starii`, {
|
|
40
|
+
const response = await fetch(buildApiUrl(config, API_UPLOAD_FILE), {
|
|
42
41
|
method: 'POST',
|
|
43
42
|
headers: {
|
|
44
43
|
'X-API-Key': config.apiKey,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { EventEmitter } from 'node:events';
|
|
2
2
|
import WebSocket from 'ws';
|
|
3
|
-
import {
|
|
3
|
+
import { buildWsUrl } from '../api/api-paths.js';
|
|
4
4
|
import { writeWsTrace } from './ws-trace.js';
|
|
5
5
|
import { WS_ERROR, isJoinErrorMessage, isJoinSuccessMessage, isPushErrorMessage, isPushSuccessMessage, isSyncPushMessage, } from './types.js';
|
|
6
6
|
export class CanvasWebSocketClient extends EventEmitter {
|
|
@@ -33,7 +33,7 @@ export class CanvasWebSocketClient extends EventEmitter {
|
|
|
33
33
|
queryParams.set('country_code', params.countryCode || this.config.countryCode);
|
|
34
34
|
queryParams.set('api_key', params.apiKey || this.config.apiKey);
|
|
35
35
|
queryParams.set('canvas_id', params.canvasId);
|
|
36
|
-
return `${
|
|
36
|
+
return `${buildWsUrl(this.config)}?${queryParams.toString()}`;
|
|
37
37
|
}
|
|
38
38
|
async connect(params) {
|
|
39
39
|
if (this.connected) {
|
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Create a new Artflo canvas via the REST API.
|
|
3
|
-
*
|
|
4
|
-
* Derives the HTTP API base URL from the configured WebSocket URL:
|
|
5
|
-
* wss://prewebapi.artflo.ai/canvas/ws → https://prewebapi.artflo.ai
|
|
6
|
-
* wss://webapi.artflo.ai/canvas/ws → https://webapi.artflo.ai
|
|
7
3
|
*/
|
|
8
|
-
import {
|
|
4
|
+
import { buildApiUrl, buildWebUrl, API_CREATE_CANVAS } from '../api/api-paths.js';
|
|
9
5
|
export async function createCanvas(config, name = 'Untitled') {
|
|
10
|
-
const
|
|
11
|
-
const response = await fetch(`${baseUrl}/canvas`, {
|
|
6
|
+
const response = await fetch(buildApiUrl(config, API_CREATE_CANVAS), {
|
|
12
7
|
method: 'POST',
|
|
13
8
|
headers: {
|
|
14
9
|
'Content-Type': 'application/json',
|
|
@@ -24,14 +19,9 @@ export async function createCanvas(config, name = 'Untitled') {
|
|
|
24
19
|
throw new Error(`Create canvas failed: code=${body.code}`);
|
|
25
20
|
}
|
|
26
21
|
const canvasId = body.data.id;
|
|
27
|
-
// Derive project URL from API host: prewebapi → pre.artflo.ai, webapi → artflo.ai
|
|
28
|
-
const hostname = new URL(baseUrl).hostname;
|
|
29
|
-
const projectHost = hostname.startsWith('prewebapi')
|
|
30
|
-
? 'pre.artflo.ai'
|
|
31
|
-
: 'artflo.ai';
|
|
32
22
|
return {
|
|
33
23
|
id: canvasId,
|
|
34
24
|
name: body.data.name ?? name,
|
|
35
|
-
url:
|
|
25
|
+
url: `${buildWebUrl(config, '/project/' + canvasId)}`,
|
|
36
26
|
};
|
|
37
27
|
}
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
* Fetch appKey, vipAppId, vipGroup from the subscribe-client-params API.
|
|
3
3
|
* GET {webApiBaseUrl}/api/subscribe-client-params
|
|
4
4
|
*/
|
|
5
|
+
import { API_CLIENT_PARAMS } from '../api/api-paths.js';
|
|
5
6
|
export async function fetchClientParams(webApiBaseUrl) {
|
|
6
|
-
const url = `${webApiBaseUrl.replace(/\/+$/, '')}
|
|
7
|
+
const url = `${webApiBaseUrl.replace(/\/+$/, '')}${API_CLIENT_PARAMS}`;
|
|
7
8
|
const response = await fetch(url);
|
|
8
9
|
if (!response.ok) {
|
|
9
10
|
throw new Error(`fetchClientParams failed: HTTP ${response.status}`);
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Fetch user VIP / subscription status from the Artflo subscription API.
|
|
3
3
|
*/
|
|
4
|
+
import { buildVipUrl, API_VIP_INFO } from '../api/api-paths.js';
|
|
4
5
|
export async function fetchVipInfo(config) {
|
|
5
|
-
const url = new URL(
|
|
6
|
+
const url = new URL(buildVipUrl(config, API_VIP_INFO));
|
|
6
7
|
url.searchParams.set('app_id', config.vipAppId);
|
|
7
8
|
url.searchParams.set('vip_group', config.vipGroup);
|
|
8
9
|
const response = await fetch(url.toString(), {
|
package/package.json
CHANGED
|
@@ -48,6 +48,7 @@ metadata:
|
|
|
48
48
|
- 规划时不要臆造底层画布数字节点类型。应使用 plan 中的节点类型,例如 `input`、`refine`、`process`、`selector`、`batch`、`crop`。
|
|
49
49
|
- 在假设画布运行时已就绪之前,先读取连接状态。
|
|
50
50
|
- 将插件配置视为 WebSocket 凭证和连接默认值的唯一真实来源。
|
|
51
|
+
- **禁止编造 API URL**:不要自行拼接或猜测 Artflo API 路径。所有 API 交互必须通过插件提供的 tool 完成(如 `artflo_canvas_create`、`artflo_upload_file` 等)。不要使用 `fetch` 或 `curl` 直接调用 Artflo API。
|
|
51
52
|
- 当插件布局引擎可用时,不要手工编造节点坐标。
|
|
52
53
|
|
|
53
54
|
## 默认编辑规则
|
|
@@ -8,7 +8,7 @@ Read `references/node-schema.json` first for node type constraints, then use thi
|
|
|
8
8
|
Before executing any workflow, ensure you have a canvas:
|
|
9
9
|
|
|
10
10
|
1. **No canvas id available**: Call `artflo_canvas_create` to create a new canvas. Use the returned `canvasId` for all subsequent operations. Share the `url` with the user so they can view the canvas.
|
|
11
|
-
2. **Canvas id available**: Use the existing canvas. On the first task of each day, ask the user whether to create a new canvas or reuse the existing one.
|
|
11
|
+
2. **Canvas id available**: Use the existing canvas. On the first task of each day, ask the user whether to create a new canvas or reuse the existing one. The canvas URL is returned by `artflo_canvas_create`.
|
|
12
12
|
3. **User requests new canvas**: Call `artflo_canvas_create` immediately.
|
|
13
13
|
|
|
14
14
|
## Core Principle
|