@aiyiran/myclaw 1.0.213 → 1.0.215
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/assets/myclaw-artifacts.js +5 -1
- package/package.json +1 -1
- package/patches/patch.js +38 -12
- package/skills/yiran-skill-media/SKILL.md +10 -9
- package/skills/yiran-skill-media/scripts/generate.py +8 -13
- package/skills/yiran-skill-media/scripts/image.sh +7 -6
- package/skills/yiran-skill-media/scripts/music.sh +7 -6
|
@@ -285,7 +285,11 @@
|
|
|
285
285
|
row.onclick = function () {
|
|
286
286
|
if (isLatest && !isLatestSeen) localStorage.setItem(latestSeenKey, '1');
|
|
287
287
|
if (isUpdated && !isUpdateSeen) localStorage.setItem(updateSeenKey, '1');
|
|
288
|
-
|
|
288
|
+
if (asset.type === 'html') {
|
|
289
|
+
window.open(buildPreviewUrl(data, asset.path), '_blank');
|
|
290
|
+
} else {
|
|
291
|
+
openPreviewModal(data, asset);
|
|
292
|
+
}
|
|
289
293
|
};
|
|
290
294
|
|
|
291
295
|
// 更新时间
|
package/package.json
CHANGED
package/patches/patch.js
CHANGED
|
@@ -212,8 +212,9 @@ function patch() {
|
|
|
212
212
|
return { success: false, reason: 'inject-failed' };
|
|
213
213
|
}
|
|
214
214
|
|
|
215
|
-
// 7. Patch Permissions-Policy
|
|
215
|
+
// 7. Patch Permissions-Policy 头(允许麦克风)+ CSP frame-src(允许 iframe 加载外部资源)
|
|
216
216
|
// OpenClaw 在 gateway-cli-*.js 或 server-*.js 中硬编码了 microphone=(),需要改为 microphone=(self)
|
|
217
|
+
// 同时 CSP 中 default-src 'self' 导致 iframe 只能加载同源内容,需要添加 frame-src 允许外部资源
|
|
217
218
|
try {
|
|
218
219
|
const distParent = path.resolve(uiDir, '..'); // dist/
|
|
219
220
|
const distFiles = fs.readdirSync(distParent);
|
|
@@ -229,33 +230,58 @@ function patch() {
|
|
|
229
230
|
const filePath = path.join(distParent, f);
|
|
230
231
|
let content = fs.readFileSync(filePath, 'utf8');
|
|
231
232
|
|
|
232
|
-
|
|
233
|
+
// 检查是否需要 patch
|
|
234
|
+
const needsMicrophonePatch = content.includes('microphone=()');
|
|
235
|
+
const needsCspFramePatch = !content.includes('frame-src');
|
|
236
|
+
|
|
237
|
+
if (needsMicrophonePatch || needsCspFramePatch) {
|
|
233
238
|
// 备份
|
|
234
239
|
const backupFile = filePath + BACKUP_SUFFIX;
|
|
235
240
|
if (!fs.existsSync(backupFile)) {
|
|
236
241
|
fs.copyFileSync(filePath, backupFile);
|
|
237
242
|
}
|
|
238
243
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
244
|
+
// Patch 1: microphone
|
|
245
|
+
if (needsMicrophonePatch) {
|
|
246
|
+
content = content.replace(
|
|
247
|
+
'microphone=()',
|
|
248
|
+
'microphone=(self)'
|
|
249
|
+
);
|
|
250
|
+
console.log('[myclaw-patch] ✅ 已修复 Permissions-Policy (microphone): ' + f);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Patch 2: CSP frame-src - 在 buildControlUiCspHeader 的 CSP 数组中添加 frame-src
|
|
254
|
+
// 原始: "default-src 'self'", ... "frame-ancestors 'none'"
|
|
255
|
+
// 目标: 在 "default-src 'self'" 后插入 "frame-src 'self' https:", 并修改 frame-ancestors
|
|
256
|
+
if (needsCspFramePatch) {
|
|
257
|
+
// 在 "default-src 'self'" 后面插入 frame-src 指令
|
|
258
|
+
content = content.replace(
|
|
259
|
+
'"default-src \'self\'"',
|
|
260
|
+
'"default-src \'self\'",\n\t\t"frame-src \'self\' https:"'
|
|
261
|
+
);
|
|
262
|
+
// 同时放开 frame-ancestors,允许被外部 iframe 嵌入
|
|
263
|
+
content = content.replace(
|
|
264
|
+
'"frame-ancestors \'none\'"',
|
|
265
|
+
'"frame-ancestors \'self\' https:"'
|
|
266
|
+
);
|
|
267
|
+
console.log('[myclaw-patch] ✅ 已添加 CSP frame-src 允许 iframe 加载: ' + f);
|
|
268
|
+
}
|
|
269
|
+
|
|
243
270
|
fs.writeFileSync(filePath, content, 'utf8');
|
|
244
|
-
console.log('[myclaw-patch] ✅ 已修复 Permissions-Policy (microphone): ' + f);
|
|
245
271
|
patched = true;
|
|
246
|
-
} else
|
|
247
|
-
console.log('[myclaw-patch] ✅ Permissions-Policy (microphone) 已是允许状态');
|
|
272
|
+
} else {
|
|
273
|
+
console.log('[myclaw-patch] ✅ Permissions-Policy (microphone) 和 CSP (frame-src) 已是允许状态');
|
|
248
274
|
patched = true;
|
|
249
275
|
}
|
|
250
276
|
}
|
|
251
277
|
|
|
252
278
|
if (!patched && foundTarget) {
|
|
253
|
-
console.log('[myclaw-patch] ⚠ 找到目标文件但未检测到 microphone 配置');
|
|
279
|
+
console.log('[myclaw-patch] ⚠ 找到目标文件但未检测到 microphone/CSP 配置');
|
|
254
280
|
} else if (!patched) {
|
|
255
|
-
console.log('[myclaw-patch] ⚠
|
|
281
|
+
console.log('[myclaw-patch] ⚠ 未找到配置文件,麦克风和 iframe 可能受限');
|
|
256
282
|
}
|
|
257
283
|
} catch (err) {
|
|
258
|
-
console.error('[myclaw-patch] ⚠ Permissions-Policy 修复失败 (非致命): ' + err.message);
|
|
284
|
+
console.error('[myclaw-patch] ⚠ Permissions-Policy/CSP 修复失败 (非致命): ' + err.message);
|
|
259
285
|
}
|
|
260
286
|
|
|
261
287
|
console.log('[myclaw-patch] ✅ 注入完成,重启 Gateway 后生效');
|
|
@@ -1,30 +1,29 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: yiran-skill-media
|
|
3
|
-
description: 统一多媒体生成技能。支持图片和音乐生成,按资源类型自动路由到最优 provider,支持主备切换。资源生成规范:所有生成的资源必须存放在当前工作目录下,调用时通过 --output-dir
|
|
3
|
+
description: 统一多媒体生成技能。支持图片和音乐生成,按资源类型自动路由到最优 provider,支持主备切换。资源生成规范:所有生成的资源必须存放在当前工作目录下,调用时通过 --output-dir 传入当前工作目录的绝对路径,通过 --name 传入资源的中文名称。
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# 统一多媒体生成
|
|
7
7
|
|
|
8
8
|
## 资源生成规范(必须遵守)
|
|
9
9
|
|
|
10
|
-
**`--output-dir`
|
|
10
|
+
1. **`--output-dir` 必填** — 传入当前工作目录的绝对路径。你在哪个目录工作,就传哪个路径。
|
|
11
|
+
2. **`--name` 必填** — 传入资源的中文名称,用于生成文件名。名称应简洁准确,能体现资源内容。
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
**所有生成的资源文件必须存放在当前工作目录下。** 不允许省略,不允许猜测路径。
|
|
13
14
|
|
|
14
15
|
例如:
|
|
15
16
|
- 你当前在 `/root/.openclaw/workspace` → 传入 `--output-dir /root/.openclaw/workspace`
|
|
16
|
-
-
|
|
17
|
-
|
|
18
|
-
这是硬性规范,不允许省略,不允许猜测路径。
|
|
17
|
+
- 生成一张日落图片 → 传入 `--name 日落风景`
|
|
19
18
|
|
|
20
19
|
## 一键脚本
|
|
21
20
|
|
|
22
21
|
```bash
|
|
23
|
-
# 图片生成
|
|
24
|
-
./image.sh --output-dir "$(pwd)" "
|
|
22
|
+
# 图片生成
|
|
23
|
+
./image.sh --output-dir "$(pwd)" --name 日落风景 "a sunset landscape" [--aspect-ratio 16:9]
|
|
25
24
|
|
|
26
25
|
# 音乐生成
|
|
27
|
-
./music.sh --output-dir "$(pwd)"
|
|
26
|
+
./music.sh --output-dir "$(pwd)" --name 开场音乐 "epic opening" [--instrumental]
|
|
28
27
|
```
|
|
29
28
|
|
|
30
29
|
## 参数说明
|
|
@@ -34,6 +33,7 @@ description: 统一多媒体生成技能。支持图片和音乐生成,按资
|
|
|
34
33
|
| 参数 | 必填 | 说明 |
|
|
35
34
|
|------|------|------|
|
|
36
35
|
| `--output-dir` | 是 | 输出目录的绝对路径,传入当前工作目录 |
|
|
36
|
+
| `--name` | 是 | 资源中文名称(如:日落风景、产品封面) |
|
|
37
37
|
| `prompt` | 是 | 图片描述 |
|
|
38
38
|
| `--aspect-ratio` | 否 | 比例,默认 1:1。可选:16:9, 9:16, 4:3 等 |
|
|
39
39
|
|
|
@@ -42,6 +42,7 @@ description: 统一多媒体生成技能。支持图片和音乐生成,按资
|
|
|
42
42
|
| 参数 | 必填 | 说明 |
|
|
43
43
|
|------|------|------|
|
|
44
44
|
| `--output-dir` | 是 | 输出目录的绝对路径,传入当前工作目录 |
|
|
45
|
+
| `--name` | 是 | 资源中文名称(如:开场音乐、背景配乐) |
|
|
45
46
|
| `prompt` | 是 | 音乐风格/情绪描述 |
|
|
46
47
|
| `--lyrics` | 否 | 歌词文本 |
|
|
47
48
|
| `--instrumental` | 否 | 纯音乐模式 |
|
|
@@ -55,11 +55,11 @@ def ratio_to_size(ratio_str, max_dim=2048):
|
|
|
55
55
|
return w, h
|
|
56
56
|
|
|
57
57
|
|
|
58
|
-
def make_output_path(out_dir,
|
|
59
|
-
"""Generate filename with
|
|
58
|
+
def make_output_path(out_dir, name, resource_type, params, ext):
|
|
59
|
+
"""Generate filename with Chinese name and key parameters.
|
|
60
60
|
|
|
61
|
-
Format: {
|
|
62
|
-
Example:
|
|
61
|
+
Format: {name}_{params}_{timestamp}.{ext}
|
|
62
|
+
Example: 日落风景_2048x1152_20260414_123456.png
|
|
63
63
|
"""
|
|
64
64
|
ts = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
65
65
|
|
|
@@ -67,18 +67,13 @@ def make_output_path(out_dir, resource_type, model, params, ext):
|
|
|
67
67
|
param_parts = []
|
|
68
68
|
if resource_type == "image":
|
|
69
69
|
aspect_ratio = params.get("aspect_ratio", "1:1")
|
|
70
|
-
# Convert ratio to actual dimensions
|
|
71
70
|
w, h = ratio_to_size(aspect_ratio)
|
|
72
71
|
param_parts.append(f"{w}x{h}")
|
|
73
72
|
elif resource_type == "music":
|
|
74
73
|
if params.get("instrumental"):
|
|
75
74
|
param_parts.append("instrumental")
|
|
76
75
|
|
|
77
|
-
|
|
78
|
-
# Clean model name: replace special chars with dash
|
|
79
|
-
clean_model = model.replace("/", "-").replace("_", "-")
|
|
80
|
-
|
|
81
|
-
parts = [resource_type, clean_model]
|
|
76
|
+
parts = [name]
|
|
82
77
|
if param_parts:
|
|
83
78
|
parts.extend(param_parts)
|
|
84
79
|
parts.append(ts)
|
|
@@ -148,6 +143,7 @@ def main():
|
|
|
148
143
|
parser.add_argument("--instrumental", action="store_true", help="Instrumental mode (music only)")
|
|
149
144
|
parser.add_argument("--output", default=None, help="Output file path")
|
|
150
145
|
parser.add_argument("--output-dir", required=True, help="Absolute path to output directory (required)")
|
|
146
|
+
parser.add_argument("--name", required=True, help="Resource name in Chinese (required, e.g. 日落风景)")
|
|
151
147
|
args = parser.parse_args()
|
|
152
148
|
|
|
153
149
|
out_dir = ensure_output_dir(args.output_dir)
|
|
@@ -184,10 +180,9 @@ def main():
|
|
|
184
180
|
|
|
185
181
|
files, used_provider = dispatch(args.type, args.prompt, **kwargs)
|
|
186
182
|
|
|
187
|
-
# Rename with proper filename containing
|
|
183
|
+
# Rename with proper filename containing name and params (only for auto-naming)
|
|
188
184
|
if not args.output:
|
|
189
|
-
|
|
190
|
-
proper_path = make_output_path(out_dir, args.type, model, kwargs, ext)
|
|
185
|
+
proper_path = make_output_path(out_dir, args.name, args.type, kwargs, ext)
|
|
191
186
|
import shutil
|
|
192
187
|
shutil.move(files[0], proper_path)
|
|
193
188
|
files = [proper_path]
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
# 图片生成入口
|
|
3
|
-
# 用法: ./image.sh --output-dir /abs/path "描述" [--aspect-ratio 16:9]
|
|
3
|
+
# 用法: ./image.sh --output-dir /abs/path --name 中文名 "描述" [--aspect-ratio 16:9]
|
|
4
4
|
set -euo pipefail
|
|
5
5
|
|
|
6
6
|
OUTPUT_DIR=""
|
|
7
|
+
NAME=""
|
|
7
8
|
PROMPT=""
|
|
8
9
|
ASPECT_RATIO=""
|
|
9
10
|
|
|
10
11
|
while [ $# -gt 0 ]; do
|
|
11
12
|
case "$1" in
|
|
12
13
|
--output-dir) OUTPUT_DIR="$2"; shift 2 ;;
|
|
14
|
+
--name) NAME="$2"; shift 2 ;;
|
|
13
15
|
--aspect-ratio) ASPECT_RATIO="$2"; shift 2 ;;
|
|
14
16
|
*)
|
|
15
17
|
if [ -z "$PROMPT" ]; then
|
|
@@ -20,20 +22,19 @@ while [ $# -gt 0 ]; do
|
|
|
20
22
|
esac
|
|
21
23
|
done
|
|
22
24
|
|
|
23
|
-
if [ -z "$OUTPUT_DIR" ] || [ -z "$PROMPT" ]; then
|
|
24
|
-
echo "用法: ./image.sh --output-dir <绝对路径> \"描述\" [--aspect-ratio 16:9]"
|
|
25
|
-
echo "示例: ./image.sh --output-dir /root/.openclaw/workspace
|
|
26
|
-
echo "注意: --output-dir 必须是绝对路径,传入当前工作目录即可"
|
|
25
|
+
if [ -z "$OUTPUT_DIR" ] || [ -z "$NAME" ] || [ -z "$PROMPT" ]; then
|
|
26
|
+
echo "用法: ./image.sh --output-dir <绝对路径> --name <中文名> \"描述\" [--aspect-ratio 16:9]"
|
|
27
|
+
echo "示例: ./image.sh --output-dir /root/.openclaw/workspace --name 日落风景 \"a sunset landscape\""
|
|
27
28
|
exit 1
|
|
28
29
|
fi
|
|
29
30
|
|
|
30
31
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
31
32
|
|
|
32
|
-
# Build args for generate.py
|
|
33
33
|
ARGS=()
|
|
34
34
|
ARGS+=("image")
|
|
35
35
|
ARGS+=("$PROMPT")
|
|
36
36
|
ARGS+=(--output-dir "$OUTPUT_DIR")
|
|
37
|
+
ARGS+=(--name "$NAME")
|
|
37
38
|
[ -n "$ASPECT_RATIO" ] && ARGS+=(--aspect-ratio "$ASPECT_RATIO")
|
|
38
39
|
|
|
39
40
|
python3 "$SCRIPT_DIR/generate.py" "${ARGS[@]}"
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
# 音乐生成入口
|
|
3
|
-
# 用法: ./music.sh --output-dir /abs/path "描述" [--lyrics "歌词"] [--instrumental]
|
|
3
|
+
# 用法: ./music.sh --output-dir /abs/path --name 中文名 "描述" [--lyrics "歌词"] [--instrumental]
|
|
4
4
|
set -euo pipefail
|
|
5
5
|
|
|
6
6
|
OUTPUT_DIR=""
|
|
7
|
+
NAME=""
|
|
7
8
|
PROMPT=""
|
|
8
9
|
LYRICS=""
|
|
9
10
|
INSTRUMENTAL=false
|
|
@@ -11,6 +12,7 @@ INSTRUMENTAL=false
|
|
|
11
12
|
while [ $# -gt 0 ]; do
|
|
12
13
|
case "$1" in
|
|
13
14
|
--output-dir) OUTPUT_DIR="$2"; shift 2 ;;
|
|
15
|
+
--name) NAME="$2"; shift 2 ;;
|
|
14
16
|
--lyrics) LYRICS="$2"; shift 2 ;;
|
|
15
17
|
--instrumental) INSTRUMENTAL=true; shift ;;
|
|
16
18
|
*)
|
|
@@ -22,20 +24,19 @@ while [ $# -gt 0 ]; do
|
|
|
22
24
|
esac
|
|
23
25
|
done
|
|
24
26
|
|
|
25
|
-
if [ -z "$OUTPUT_DIR" ] || [ -z "$PROMPT" ]; then
|
|
26
|
-
echo "用法: ./music.sh --output-dir <绝对路径> \"描述\" [--lyrics \"歌词\"] [--instrumental]"
|
|
27
|
-
echo "示例: ./music.sh --output-dir /root/.openclaw/workspace
|
|
28
|
-
echo "注意: --output-dir 必须是绝对路径,传入当前工作目录即可"
|
|
27
|
+
if [ -z "$OUTPUT_DIR" ] || [ -z "$NAME" ] || [ -z "$PROMPT" ]; then
|
|
28
|
+
echo "用法: ./music.sh --output-dir <绝对路径> --name <中文名> \"描述\" [--lyrics \"歌词\"] [--instrumental]"
|
|
29
|
+
echo "示例: ./music.sh --output-dir /root/.openclaw/workspace --name 开场音乐 \"epic opening\" --instrumental"
|
|
29
30
|
exit 1
|
|
30
31
|
fi
|
|
31
32
|
|
|
32
33
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
33
34
|
|
|
34
|
-
# Build args for generate.py
|
|
35
35
|
ARGS=()
|
|
36
36
|
ARGS+=("music")
|
|
37
37
|
ARGS+=("$PROMPT")
|
|
38
38
|
ARGS+=(--output-dir "$OUTPUT_DIR")
|
|
39
|
+
ARGS+=(--name "$NAME")
|
|
39
40
|
[ -n "$LYRICS" ] && ARGS+=(--lyrics "$LYRICS")
|
|
40
41
|
[ "$INSTRUMENTAL" = true ] && ARGS+=(--instrumental)
|
|
41
42
|
|