@optima-chat/optima-agent 0.9.10 → 0.9.12

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.
Files changed (94) hide show
  1. package/.claude/skills/.kb-skills-managed.json +9 -9
  2. package/.claude/skills/ads/SKILL.md +244 -244
  3. package/.claude/skills/ads/template/campaign/CREATIVES.md +18 -18
  4. package/.claude/skills/ads/template/campaign/NOTES.md +10 -10
  5. package/.claude/skills/ads/template/campaign/STRATEGY.md +29 -29
  6. package/.claude/skills/ads/template/user/ADS.md +29 -29
  7. package/.claude/skills/ads/template/user/LEARNINGS.md +15 -15
  8. package/.claude/skills/ads/template/user/PROGRESS.md +20 -20
  9. package/.claude/skills/ads/template/user/README.md +25 -25
  10. package/.claude/skills/ads/template/user/assets/.gitignore +2 -2
  11. package/.claude/skills/bi/SKILL.md +131 -131
  12. package/.claude/skills/browser/SKILL.md +201 -201
  13. package/.claude/skills/channels/SKILL.md +188 -188
  14. package/.claude/skills/collection/SKILL.md +88 -88
  15. package/.claude/skills/douyin/SKILL.md +408 -408
  16. package/.claude/skills/ffmpeg/SKILL.md +164 -164
  17. package/.claude/skills/gen/SKILL.md +279 -279
  18. package/.claude/skills/growth/SKILL.md +90 -90
  19. package/.claude/skills/growth/template/ACCOUNTS.md +14 -14
  20. package/.claude/skills/growth/template/CALENDAR.md +7 -7
  21. package/.claude/skills/growth/template/COMMENTS.md +7 -7
  22. package/.claude/skills/growth/template/GROWTH.md +37 -37
  23. package/.claude/skills/growth/template/PROGRESS.md +4 -4
  24. package/.claude/skills/growth/template/README.md +20 -20
  25. package/.claude/skills/growth/template/TOPICS.md +7 -7
  26. package/.claude/skills/homepage/SKILL.md +177 -177
  27. package/.claude/skills/i18n/SKILL.md +517 -517
  28. package/.claude/skills/ingesting-sources/SKILL.md +94 -94
  29. package/.claude/skills/initializing-kb/SKILL.md +117 -117
  30. package/.claude/skills/instagram/SKILL.md +321 -321
  31. package/.claude/skills/inventory/SKILL.md +328 -328
  32. package/.claude/skills/kol-outreach/SKILL.md +232 -232
  33. package/.claude/skills/kol-outreach/template/campaign/CONFIG.md +60 -60
  34. package/.claude/skills/kol-outreach/template/campaign/KOLS.md +6 -6
  35. package/.claude/skills/kol-outreach/template/campaign/PROGRESS.md +3 -3
  36. package/.claude/skills/kol-outreach/template/campaign/TEMPLATES.md +88 -88
  37. package/.claude/skills/kol-outreach/template/merchant/BRAND.md +36 -36
  38. package/.claude/skills/kol-outreach/template/merchant/CAMPAIGNS.md +6 -6
  39. package/.claude/skills/kol-outreach/template/merchant/MERCHANT_LIMITS.md +16 -16
  40. package/.claude/skills/kol-outreach/template/merchant/PROGRESS.md +4 -4
  41. package/.claude/skills/kol-outreach/template/merchant/README.md +20 -20
  42. package/.claude/skills/linting-the-wiki/SKILL.md +68 -68
  43. package/.claude/skills/logistics/SKILL.md +180 -180
  44. package/.claude/skills/markdown-pdf/SKILL.md +72 -72
  45. package/.claude/skills/merchant/SKILL.md +110 -110
  46. package/.claude/skills/multigrid-poster/SKILL.md +192 -192
  47. package/.claude/skills/multigrid-poster/layouts/2x2.json +34 -34
  48. package/.claude/skills/multigrid-poster/layouts/3x3.json +43 -43
  49. package/.claude/skills/multigrid-poster/scripts/compose.py +116 -116
  50. package/.claude/skills/order/SKILL.md +452 -452
  51. package/.claude/skills/product/SKILL.md +379 -379
  52. package/.claude/skills/product-page/SKILL.md +106 -106
  53. package/.claude/skills/querying-the-wiki/SKILL.md +59 -59
  54. package/.claude/skills/reddit/SKILL.md +277 -277
  55. package/.claude/skills/review/SKILL.md +321 -321
  56. package/.claude/skills/scout/SKILL.md +575 -575
  57. package/.claude/skills/sentinel/SKILL.md +281 -281
  58. package/.claude/skills/shein/SKILL.md +246 -246
  59. package/.claude/skills/shipping/SKILL.md +200 -200
  60. package/.claude/skills/shop-content/SKILL.md +101 -101
  61. package/.claude/skills/shopify/SKILL.md +282 -282
  62. package/.claude/skills/skillify/SKILL.md +114 -114
  63. package/.claude/skills/taobao/SKILL.md +238 -238
  64. package/.claude/skills/tiktok/SKILL.md +381 -381
  65. package/.claude/skills/twitter/SKILL.md +302 -302
  66. package/.claude/skills/updating-related-pages/SKILL.md +65 -65
  67. package/.claude/skills/video-edit/SKILL.md +138 -138
  68. package/.claude/skills/video-gen/SKILL.md +630 -548
  69. package/.claude/skills/video-gen/templates/INDEX.md +78 -78
  70. package/.claude/skills/video-gen/templates/before-after-beauty.md +183 -183
  71. package/.claude/skills/video-gen/templates/drama-fmcg.md +183 -183
  72. package/.claude/skills/video-gen/templates/kol-reaction-food.md +193 -193
  73. package/.claude/skills/video-gen/templates/multi-point-apparel.md +185 -185
  74. package/.claude/skills/video-gen/templates/pain-solution-home.md +184 -184
  75. package/.claude/skills/video-gen/templates/pdp-360-showcase.md +189 -189
  76. package/.claude/skills/video-gen/templates/pdp-feature-highlight.md +182 -182
  77. package/.claude/skills/video-gen/templates/scene-digital.md +183 -183
  78. package/.claude/skills/wechat/SKILL.md +174 -174
  79. package/.claude/skills/xhs/SKILL.md +170 -170
  80. package/README.md +276 -276
  81. package/dist/bin/optima.js +26 -26
  82. package/dist/bin/serve.js +23 -23
  83. package/dist/bin/video-edit.d.ts +3 -0
  84. package/dist/bin/video-edit.d.ts.map +1 -0
  85. package/dist/bin/video-edit.js +153 -0
  86. package/dist/bin/video-edit.js.map +1 -0
  87. package/dist/src/agent.d.ts +1 -1
  88. package/dist/src/agent.js +4 -4
  89. package/dist/src/system-prompt.d.ts.map +1 -1
  90. package/dist/src/system-prompt.js +175 -173
  91. package/dist/src/system-prompt.js.map +1 -1
  92. package/dist/src/tools/memory.js +10 -10
  93. package/dist/src/ui/headless.js +7 -7
  94. package/package.json +79 -79
@@ -1,34 +1,34 @@
1
- {
2
- "_comment": "通用 2×2 网格布局 — 适合 4 张 cell 的所有 intent (创业故事/对比测评/教程/场景)",
3
- "canvas_size": [1242, 1660],
4
- "cells": {
5
- "positions": [[0, 0], [621, 0], [0, 830], [621, 830]],
6
- "sizes": [[621, 830], [621, 830], [621, 830], [621, 830]]
7
- },
8
- "text_zones": {
9
- "title": {
10
- "_comment": "中央偏上 2 行标题 - 8-12 字 / 行最佳",
11
- "font": "shared/fonts/MaShanZheng-Regular.ttf",
12
- "size": 110,
13
- "color": "#FFB940",
14
- "stroke_w": 8,
15
- "stroke_color": "#D63D3D",
16
- "lines": [
17
- {"position": [621, 480], "anchor": "mm"},
18
- {"position": [621, 620], "anchor": "mm"}
19
- ]
20
- },
21
- "caption": {
22
- "_comment": "底部 2 行 caption - 15-20 字 / 行最佳",
23
- "font": "shared/fonts/MaShanZheng-Regular.ttf",
24
- "size": 78,
25
- "color": "#FFB940",
26
- "stroke_w": 6,
27
- "stroke_color": "#D63D3D",
28
- "lines": [
29
- {"position": [621, 1340], "anchor": "mm"},
30
- {"position": [621, 1450], "anchor": "mm"}
31
- ]
32
- }
33
- }
34
- }
1
+ {
2
+ "_comment": "通用 2×2 网格布局 — 适合 4 张 cell 的所有 intent (创业故事/对比测评/教程/场景)",
3
+ "canvas_size": [1242, 1660],
4
+ "cells": {
5
+ "positions": [[0, 0], [621, 0], [0, 830], [621, 830]],
6
+ "sizes": [[621, 830], [621, 830], [621, 830], [621, 830]]
7
+ },
8
+ "text_zones": {
9
+ "title": {
10
+ "_comment": "中央偏上 2 行标题 - 8-12 字 / 行最佳",
11
+ "font": "shared/fonts/MaShanZheng-Regular.ttf",
12
+ "size": 110,
13
+ "color": "#FFB940",
14
+ "stroke_w": 8,
15
+ "stroke_color": "#D63D3D",
16
+ "lines": [
17
+ {"position": [621, 480], "anchor": "mm"},
18
+ {"position": [621, 620], "anchor": "mm"}
19
+ ]
20
+ },
21
+ "caption": {
22
+ "_comment": "底部 2 行 caption - 15-20 字 / 行最佳",
23
+ "font": "shared/fonts/MaShanZheng-Regular.ttf",
24
+ "size": 78,
25
+ "color": "#FFB940",
26
+ "stroke_w": 6,
27
+ "stroke_color": "#D63D3D",
28
+ "lines": [
29
+ {"position": [621, 1340], "anchor": "mm"},
30
+ {"position": [621, 1450], "anchor": "mm"}
31
+ ]
32
+ }
33
+ }
34
+ }
@@ -1,43 +1,43 @@
1
- {
2
- "_comment": "通用 3×3 网格布局 - 适合 9 张 cell (商品清单 / 多角度展示)",
3
- "canvas_size": [1242, 1660],
4
- "cells": {
5
- "_comment": "9 格 414×420。顶部 200px 标题区,cells y=200..1460,底部 200px caption 区。3×420 + 200×2 = 1660 = canvas_h ✓",
6
- "positions": [
7
- [0, 200], [414, 200], [828, 200],
8
- [0, 620], [414, 620], [828, 620],
9
- [0, 1040], [414, 1040], [828, 1040]
10
- ],
11
- "sizes": [
12
- [414, 420], [414, 420], [414, 420],
13
- [414, 420], [414, 420], [414, 420],
14
- [414, 420], [414, 420], [414, 420]
15
- ]
16
- },
17
- "text_zones": {
18
- "title": {
19
- "_comment": "顶部白边 2 行标题(y < 200 区间)",
20
- "font": "shared/fonts/MaShanZheng-Regular.ttf",
21
- "size": 78,
22
- "color": "#FFB940",
23
- "stroke_w": 6,
24
- "stroke_color": "#D63D3D",
25
- "lines": [
26
- {"position": [621, 60], "anchor": "mm"},
27
- {"position": [621, 150], "anchor": "mm"}
28
- ]
29
- },
30
- "caption": {
31
- "_comment": "底部白边 2 行 caption(cells 结束于 y=1460,留 200px)",
32
- "font": "shared/fonts/MaShanZheng-Regular.ttf",
33
- "size": 60,
34
- "color": "#FFB940",
35
- "stroke_w": 5,
36
- "stroke_color": "#D63D3D",
37
- "lines": [
38
- {"position": [621, 1530], "anchor": "mm"},
39
- {"position": [621, 1610], "anchor": "mm"}
40
- ]
41
- }
42
- }
43
- }
1
+ {
2
+ "_comment": "通用 3×3 网格布局 - 适合 9 张 cell (商品清单 / 多角度展示)",
3
+ "canvas_size": [1242, 1660],
4
+ "cells": {
5
+ "_comment": "9 格 414×420。顶部 200px 标题区,cells y=200..1460,底部 200px caption 区。3×420 + 200×2 = 1660 = canvas_h ✓",
6
+ "positions": [
7
+ [0, 200], [414, 200], [828, 200],
8
+ [0, 620], [414, 620], [828, 620],
9
+ [0, 1040], [414, 1040], [828, 1040]
10
+ ],
11
+ "sizes": [
12
+ [414, 420], [414, 420], [414, 420],
13
+ [414, 420], [414, 420], [414, 420],
14
+ [414, 420], [414, 420], [414, 420]
15
+ ]
16
+ },
17
+ "text_zones": {
18
+ "title": {
19
+ "_comment": "顶部白边 2 行标题(y < 200 区间)",
20
+ "font": "shared/fonts/MaShanZheng-Regular.ttf",
21
+ "size": 78,
22
+ "color": "#FFB940",
23
+ "stroke_w": 6,
24
+ "stroke_color": "#D63D3D",
25
+ "lines": [
26
+ {"position": [621, 60], "anchor": "mm"},
27
+ {"position": [621, 150], "anchor": "mm"}
28
+ ]
29
+ },
30
+ "caption": {
31
+ "_comment": "底部白边 2 行 caption(cells 结束于 y=1460,留 200px)",
32
+ "font": "shared/fonts/MaShanZheng-Regular.ttf",
33
+ "size": 60,
34
+ "color": "#FFB940",
35
+ "stroke_w": 5,
36
+ "stroke_color": "#D63D3D",
37
+ "lines": [
38
+ {"position": [621, 1530], "anchor": "mm"},
39
+ {"position": [621, 1610], "anchor": "mm"}
40
+ ]
41
+ }
42
+ }
43
+ }
@@ -1,116 +1,116 @@
1
- #!/usr/bin/env python3
2
- """multigrid-poster compose — Pillow 版渲染器
3
-
4
- 输入:layout.json + N 张 cell 图片 + 标题文字 + caption 文字
5
- 输出:1242×1660 PNG(小红书封面标准)
6
-
7
- 用法:
8
- python compose.py \
9
- --layout <SKILL_DIR>/layouts/2x2.json \
10
- --cells cell_0.png cell_1.png cell_2.png cell_3.png \
11
- --title-line "26岁一个人创业" \
12
- --title-line "跨境电商月入10w+" \
13
- --caption-line "只需要一部手机就可以完成!" \
14
- --caption-line "跨境人的必备app推荐" \
15
- --output cover.png
16
-
17
- 依赖:Pillow (容器自带,无需额外安装)
18
- 字体:从 SKILL_DIR/shared/fonts/ 加载(layout.json 里指定)
19
- """
20
- import argparse
21
- import json
22
- import sys
23
- from pathlib import Path
24
- from PIL import Image, ImageDraw, ImageFont
25
-
26
-
27
- def compose(layout_path: Path, cell_paths: list[Path],
28
- title_lines: list[str], caption_lines: list[str],
29
- output_path: Path) -> Path:
30
- """根据 layout.json 渲染海报。
31
-
32
- layout.json 字段:
33
- canvas_size [w, h]
34
- cells.positions [[x,y], ...] cell 左上角
35
- cells.sizes [[w,h], ...] cell 尺寸
36
- text_zones.title {lines: [...], size, color, stroke_w, stroke_color, font}
37
- text_zones.caption {同上}
38
- """
39
- layout = json.loads(layout_path.read_text(encoding="utf-8"))
40
- # 约定:layout 必须放在 <skill>/layouts/ 下,字体路径相对 <skill>/ 解析
41
- skill_dir = layout_path.parent.parent
42
-
43
- # 文本行数 vs layout 配置行数:行多了 zip 会静默截断,显式 fail-fast
44
- # 错误信息用英文 — sys.exit 走 stderr,Windows GBK locale 下中文会乱码
45
- for zone_key, lines in [("title", title_lines), ("caption", caption_lines)]:
46
- zone = layout.get("text_zones", {}).get(zone_key)
47
- if not zone:
48
- continue
49
- max_lines = len(zone["lines"])
50
- if len(lines) > max_lines:
51
- sys.exit(f"too many {zone_key} lines: got {len(lines)}, layout supports {max_lines}")
52
-
53
- # Canvas
54
- canvas = Image.new("RGB", tuple(layout["canvas_size"]), "white")
55
-
56
- # Cells
57
- cell_count = len(layout["cells"]["positions"])
58
- if len(cell_paths) != cell_count:
59
- sys.exit(f"cell count mismatch: layout expects {cell_count}, got {len(cell_paths)}")
60
- for cp, pos, size in zip(cell_paths,
61
- layout["cells"]["positions"],
62
- layout["cells"]["sizes"]):
63
- img = Image.open(cp).convert("RGB").resize(tuple(size), Image.LANCZOS)
64
- canvas.paste(img, tuple(pos))
65
-
66
- draw = ImageDraw.Draw(canvas)
67
-
68
- # Text zones (title + caption 通用绘制)
69
- for zone_key, lines in [("title", title_lines), ("caption", caption_lines)]:
70
- if zone_key not in layout["text_zones"]:
71
- continue
72
- zone = layout["text_zones"][zone_key]
73
- font_path = skill_dir / zone["font"]
74
- font = ImageFont.truetype(str(font_path), zone["size"])
75
- for text, line_cfg in zip(lines, zone["lines"]):
76
- if not text:
77
- continue
78
- draw.text(
79
- tuple(line_cfg["position"]), text,
80
- fill=zone["color"], font=font,
81
- stroke_width=zone.get("stroke_w", 0),
82
- stroke_fill=zone.get("stroke_color", zone["color"]),
83
- anchor=line_cfg.get("anchor", "la"),
84
- )
85
-
86
- canvas.save(output_path, optimize=True)
87
- return output_path
88
-
89
-
90
- def main():
91
- ap = argparse.ArgumentParser(description=__doc__,
92
- formatter_class=argparse.RawDescriptionHelpFormatter)
93
- ap.add_argument("--layout", required=True, type=Path,
94
- help="layout.json 路径(如 SKILL_DIR/layouts/2x2.json)")
95
- ap.add_argument("--cells", required=True, nargs="+", type=Path,
96
- help="N 张 cell 图片路径,顺序对应 layout.cells.positions")
97
- ap.add_argument("--title-line", action="append", default=[],
98
- help="标题行(可重复)")
99
- ap.add_argument("--caption-line", action="append", default=[],
100
- help="底部 caption 行(可重复)")
101
- ap.add_argument("--output", required=True, type=Path,
102
- help="输出 PNG 路径")
103
- args = ap.parse_args()
104
-
105
- out = compose(
106
- layout_path=args.layout,
107
- cell_paths=args.cells,
108
- title_lines=args.title_line,
109
- caption_lines=args.caption_line,
110
- output_path=args.output,
111
- )
112
- print(f"saved {out} ({out.stat().st_size // 1024} KB)")
113
-
114
-
115
- if __name__ == "__main__":
116
- main()
1
+ #!/usr/bin/env python3
2
+ """multigrid-poster compose — Pillow 版渲染器
3
+
4
+ 输入:layout.json + N 张 cell 图片 + 标题文字 + caption 文字
5
+ 输出:1242×1660 PNG(小红书封面标准)
6
+
7
+ 用法:
8
+ python compose.py \
9
+ --layout <SKILL_DIR>/layouts/2x2.json \
10
+ --cells cell_0.png cell_1.png cell_2.png cell_3.png \
11
+ --title-line "26岁一个人创业" \
12
+ --title-line "跨境电商月入10w+" \
13
+ --caption-line "只需要一部手机就可以完成!" \
14
+ --caption-line "跨境人的必备app推荐" \
15
+ --output cover.png
16
+
17
+ 依赖:Pillow (容器自带,无需额外安装)
18
+ 字体:从 SKILL_DIR/shared/fonts/ 加载(layout.json 里指定)
19
+ """
20
+ import argparse
21
+ import json
22
+ import sys
23
+ from pathlib import Path
24
+ from PIL import Image, ImageDraw, ImageFont
25
+
26
+
27
+ def compose(layout_path: Path, cell_paths: list[Path],
28
+ title_lines: list[str], caption_lines: list[str],
29
+ output_path: Path) -> Path:
30
+ """根据 layout.json 渲染海报。
31
+
32
+ layout.json 字段:
33
+ canvas_size [w, h]
34
+ cells.positions [[x,y], ...] cell 左上角
35
+ cells.sizes [[w,h], ...] cell 尺寸
36
+ text_zones.title {lines: [...], size, color, stroke_w, stroke_color, font}
37
+ text_zones.caption {同上}
38
+ """
39
+ layout = json.loads(layout_path.read_text(encoding="utf-8"))
40
+ # 约定:layout 必须放在 <skill>/layouts/ 下,字体路径相对 <skill>/ 解析
41
+ skill_dir = layout_path.parent.parent
42
+
43
+ # 文本行数 vs layout 配置行数:行多了 zip 会静默截断,显式 fail-fast
44
+ # 错误信息用英文 — sys.exit 走 stderr,Windows GBK locale 下中文会乱码
45
+ for zone_key, lines in [("title", title_lines), ("caption", caption_lines)]:
46
+ zone = layout.get("text_zones", {}).get(zone_key)
47
+ if not zone:
48
+ continue
49
+ max_lines = len(zone["lines"])
50
+ if len(lines) > max_lines:
51
+ sys.exit(f"too many {zone_key} lines: got {len(lines)}, layout supports {max_lines}")
52
+
53
+ # Canvas
54
+ canvas = Image.new("RGB", tuple(layout["canvas_size"]), "white")
55
+
56
+ # Cells
57
+ cell_count = len(layout["cells"]["positions"])
58
+ if len(cell_paths) != cell_count:
59
+ sys.exit(f"cell count mismatch: layout expects {cell_count}, got {len(cell_paths)}")
60
+ for cp, pos, size in zip(cell_paths,
61
+ layout["cells"]["positions"],
62
+ layout["cells"]["sizes"]):
63
+ img = Image.open(cp).convert("RGB").resize(tuple(size), Image.LANCZOS)
64
+ canvas.paste(img, tuple(pos))
65
+
66
+ draw = ImageDraw.Draw(canvas)
67
+
68
+ # Text zones (title + caption 通用绘制)
69
+ for zone_key, lines in [("title", title_lines), ("caption", caption_lines)]:
70
+ if zone_key not in layout["text_zones"]:
71
+ continue
72
+ zone = layout["text_zones"][zone_key]
73
+ font_path = skill_dir / zone["font"]
74
+ font = ImageFont.truetype(str(font_path), zone["size"])
75
+ for text, line_cfg in zip(lines, zone["lines"]):
76
+ if not text:
77
+ continue
78
+ draw.text(
79
+ tuple(line_cfg["position"]), text,
80
+ fill=zone["color"], font=font,
81
+ stroke_width=zone.get("stroke_w", 0),
82
+ stroke_fill=zone.get("stroke_color", zone["color"]),
83
+ anchor=line_cfg.get("anchor", "la"),
84
+ )
85
+
86
+ canvas.save(output_path, optimize=True)
87
+ return output_path
88
+
89
+
90
+ def main():
91
+ ap = argparse.ArgumentParser(description=__doc__,
92
+ formatter_class=argparse.RawDescriptionHelpFormatter)
93
+ ap.add_argument("--layout", required=True, type=Path,
94
+ help="layout.json 路径(如 SKILL_DIR/layouts/2x2.json)")
95
+ ap.add_argument("--cells", required=True, nargs="+", type=Path,
96
+ help="N 张 cell 图片路径,顺序对应 layout.cells.positions")
97
+ ap.add_argument("--title-line", action="append", default=[],
98
+ help="标题行(可重复)")
99
+ ap.add_argument("--caption-line", action="append", default=[],
100
+ help="底部 caption 行(可重复)")
101
+ ap.add_argument("--output", required=True, type=Path,
102
+ help="输出 PNG 路径")
103
+ args = ap.parse_args()
104
+
105
+ out = compose(
106
+ layout_path=args.layout,
107
+ cell_paths=args.cells,
108
+ title_lines=args.title_line,
109
+ caption_lines=args.caption_line,
110
+ output_path=args.output,
111
+ )
112
+ print(f"saved {out} ({out.stat().st_size // 1024} KB)")
113
+
114
+
115
+ if __name__ == "__main__":
116
+ main()