@optima-chat/optima-agent 0.8.91 → 0.8.92

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 (44) hide show
  1. package/.claude/skills/browser/SKILL.md +8 -0
  2. package/.claude/skills/homepage/SKILL.md +4 -3
  3. package/.claude/skills/kol-outreach/SKILL.md +360 -0
  4. package/.claude/skills/kol-outreach/template/campaign/CONFIG.md +60 -0
  5. package/.claude/skills/kol-outreach/template/campaign/CONVERSATIONS/.gitkeep +0 -0
  6. package/.claude/skills/kol-outreach/template/campaign/KOLS.md +6 -0
  7. package/.claude/skills/kol-outreach/template/campaign/PROGRESS.md +3 -0
  8. package/.claude/skills/kol-outreach/template/campaign/TEMPLATES.md +88 -0
  9. package/.claude/skills/kol-outreach/template/campaign/assets/.gitkeep +0 -0
  10. package/.claude/skills/kol-outreach/template/merchant/BRAND.md +36 -0
  11. package/.claude/skills/kol-outreach/template/merchant/CAMPAIGNS.md +6 -0
  12. package/.claude/skills/kol-outreach/template/merchant/MERCHANT_LIMITS.md +16 -0
  13. package/.claude/skills/kol-outreach/template/merchant/PROGRESS.md +4 -0
  14. package/.claude/skills/kol-outreach/template/merchant/README.md +20 -0
  15. package/.claude/skills/video-clone/SKILL.md +125 -217
  16. package/.claude/skills/video-clone/assets/phase-state-template.json +11 -0
  17. package/.claude/skills/video-clone/references/ffmpeg-commands.md +31 -34
  18. package/.claude/skills/video-clone/references/gate-enforcement.md +144 -0
  19. package/.claude/skills/video-clone/references/kling-api.md +39 -72
  20. package/.claude/skills/video-clone/references/url-parsing.md +32 -13
  21. package/.claude/skills/video-clone/scripts/_confirm.py +96 -0
  22. package/.claude/skills/video-clone/scripts/_confirm_test.py +125 -0
  23. package/.claude/skills/video-clone/scripts/_gate.py +162 -0
  24. package/.claude/skills/video-clone/scripts/_gate_e2e_test.py +226 -0
  25. package/.claude/skills/video-clone/scripts/_gate_test.py +148 -0
  26. package/.claude/skills/video-clone/scripts/_project.py +56 -0
  27. package/.claude/skills/video-clone/scripts/analyze_source.py +113 -0
  28. package/.claude/skills/video-clone/scripts/analyze_source_test.py +52 -0
  29. package/.claude/skills/video-clone/scripts/assemble.py +106 -0
  30. package/.claude/skills/video-clone/scripts/confirm.py +12 -0
  31. package/.claude/skills/video-clone/scripts/edit_first_frame.py +66 -0
  32. package/.claude/skills/video-clone/scripts/extract_frames.py +108 -0
  33. package/.claude/skills/video-clone/scripts/gen_video.py +59 -0
  34. package/.claude/skills/video-clone/scripts/init_project.py +103 -0
  35. package/.claude/skills/video-clone/scripts/init_project_test.py +106 -0
  36. package/.claude/skills/video-clone/scripts/kling_generate.py +182 -0
  37. package/.claude/skills/video-clone/scripts/preflight.py +95 -0
  38. package/.claude/skills/video-clone/scripts/preview.py +208 -0
  39. package/.claude/skills/video-clone/scripts/preview_test.py +169 -0
  40. package/.claude/skills/video-clone/scripts/save_workflow.py +129 -0
  41. package/.claude/skills/video-clone/scripts/save_workflow_test.py +106 -0
  42. package/.claude/skills/video-clone/scripts/status.py +202 -0
  43. package/.claude/skills/video-clone/scripts/status_test.py +174 -0
  44. package/package.json +2 -1
@@ -0,0 +1,174 @@
1
+ """Tests for status.py — cross-session resume helper."""
2
+ from __future__ import annotations
3
+
4
+ import json
5
+ import os
6
+ import subprocess
7
+ import sys
8
+ import tempfile
9
+ from pathlib import Path
10
+
11
+ SCRIPTS_DIR = Path(__file__).parent
12
+
13
+
14
+ def _make_project(tmp: Path, task_type: str = "video_clone", gate: bool = False) -> Path:
15
+ proj = tmp / "video-clone" / "test-proj"
16
+ for sub in ("source", "frames", "videos", ".state"):
17
+ (proj / sub).mkdir(parents=True)
18
+ state = {
19
+ "schema_version": 1,
20
+ "project": "test-proj",
21
+ "task_type": task_type,
22
+ "created_at": "2025-01-01T00:00:00Z",
23
+ "current_phase": 0,
24
+ "gates": {
25
+ "preview_confirmed": {
26
+ "status": gate,
27
+ "confirmed_at": "2025-01-01T00:01:00Z" if gate else None,
28
+ "user_quote": "go" if gate else None,
29
+ }
30
+ },
31
+ "history": [],
32
+ }
33
+ (proj / ".state" / "phase.json").write_text(
34
+ json.dumps(state, indent=2), encoding="utf-8"
35
+ )
36
+ return proj
37
+
38
+
39
+ def _run(tmp: Path) -> subprocess.CompletedProcess:
40
+ env = os.environ.copy()
41
+ env["GEN_OUTPUT_ROOT"] = str(tmp)
42
+ return subprocess.run(
43
+ [sys.executable, str(SCRIPTS_DIR / "status.py"), "--project", "test-proj"],
44
+ capture_output=True,
45
+ text=True,
46
+ env=env,
47
+ )
48
+
49
+
50
+ # Helpers to add artifacts
51
+ def _add_analysis(proj: Path):
52
+ (proj / "source" / "analysis_v1.json").write_text(
53
+ json.dumps({"duration_s": 10, "width": 720, "height": 1280,
54
+ "fps": 30.0, "has_audio": False, "segments": 1,
55
+ "classification": "single", "scene_cuts": []}),
56
+ encoding="utf-8",
57
+ )
58
+
59
+ def _add_grid(proj: Path):
60
+ extract = proj / "frames" / "extract_v1"
61
+ extract.mkdir(parents=True, exist_ok=True)
62
+ (extract / "grid.jpg").write_bytes(b"dummy")
63
+
64
+ def _add_prompt(proj: Path):
65
+ (proj / "prompt.md").write_text("A person walking.", encoding="utf-8")
66
+
67
+ def _add_frame(proj: Path):
68
+ (proj / "frames" / "frame_v1.png").write_bytes(b"dummy")
69
+
70
+ def _add_preview(proj: Path):
71
+ (proj / "preview_v1.md").write_text("# Preview: test-proj\n", encoding="utf-8")
72
+
73
+ def _add_final_video(proj: Path):
74
+ (proj / "videos" / "final_v1.mp4").write_bytes(b"dummy")
75
+
76
+
77
+ def test_status_exits_zero():
78
+ with tempfile.TemporaryDirectory() as td:
79
+ tmp = Path(td)
80
+ _make_project(tmp)
81
+ result = _run(tmp)
82
+ assert result.returncode == 0, f"Expected 0\nstderr: {result.stderr}"
83
+ print("PASS test_status_exits_zero")
84
+
85
+
86
+ def test_status_no_artifacts_suggests_analyze_source():
87
+ with tempfile.TemporaryDirectory() as td:
88
+ tmp = Path(td)
89
+ _make_project(tmp)
90
+ result = _run(tmp)
91
+ assert "analyze_source" in result.stdout
92
+ print("PASS test_status_no_artifacts_suggests_analyze_source")
93
+
94
+
95
+ def test_status_analysis_done_suggests_extract():
96
+ with tempfile.TemporaryDirectory() as td:
97
+ tmp = Path(td)
98
+ proj = _make_project(tmp)
99
+ _add_analysis(proj)
100
+ result = _run(tmp)
101
+ assert "extract_frames" in result.stdout
102
+ print("PASS test_status_analysis_done_suggests_extract")
103
+
104
+
105
+ def test_status_all_prep_done_suggests_preview():
106
+ with tempfile.TemporaryDirectory() as td:
107
+ tmp = Path(td)
108
+ proj = _make_project(tmp)
109
+ _add_analysis(proj)
110
+ _add_grid(proj)
111
+ _add_prompt(proj)
112
+ _add_frame(proj)
113
+ result = _run(tmp)
114
+ assert "preview.py" in result.stdout
115
+ print("PASS test_status_all_prep_done_suggests_preview")
116
+
117
+
118
+ def test_status_preview_exists_suggests_confirm():
119
+ with tempfile.TemporaryDirectory() as td:
120
+ tmp = Path(td)
121
+ proj = _make_project(tmp)
122
+ _add_analysis(proj)
123
+ _add_grid(proj)
124
+ _add_prompt(proj)
125
+ _add_frame(proj)
126
+ _add_preview(proj)
127
+ result = _run(tmp)
128
+ assert "confirm.py" in result.stdout
129
+ print("PASS test_status_preview_exists_suggests_confirm")
130
+
131
+
132
+ def test_status_gate_confirmed_suggests_generate():
133
+ with tempfile.TemporaryDirectory() as td:
134
+ tmp = Path(td)
135
+ proj = _make_project(tmp, gate=True)
136
+ result = _run(tmp)
137
+ assert "kling_generate" in result.stdout or "gen_video" in result.stdout
138
+ print("PASS test_status_gate_confirmed_suggests_generate")
139
+
140
+
141
+ def test_status_gate_and_final_video_shows_complete():
142
+ with tempfile.TemporaryDirectory() as td:
143
+ tmp = Path(td)
144
+ proj = _make_project(tmp, gate=True)
145
+ _add_final_video(proj)
146
+ result = _run(tmp)
147
+ assert "complete" in result.stdout.lower() or "final_v1.mp4" in result.stdout
148
+ print("PASS test_status_gate_and_final_video_shows_complete")
149
+
150
+
151
+ def test_status_checklist_marks_present_artifacts():
152
+ with tempfile.TemporaryDirectory() as td:
153
+ tmp = Path(td)
154
+ proj = _make_project(tmp)
155
+ _add_analysis(proj)
156
+ # grid, prompt, frame missing
157
+ result = _run(tmp)
158
+ stdout = result.stdout
159
+ # analysis present → [x], others absent → [ ]
160
+ assert "[x]" in stdout
161
+ assert "[ ]" in stdout
162
+ print("PASS test_status_checklist_marks_present_artifacts")
163
+
164
+
165
+ if __name__ == "__main__":
166
+ test_status_exits_zero()
167
+ test_status_no_artifacts_suggests_analyze_source()
168
+ test_status_analysis_done_suggests_extract()
169
+ test_status_all_prep_done_suggests_preview()
170
+ test_status_preview_exists_suggests_confirm()
171
+ test_status_gate_confirmed_suggests_generate()
172
+ test_status_gate_and_final_video_shows_complete()
173
+ test_status_checklist_marks_present_artifacts()
174
+ print("\nAll 8 status tests passed.")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optima-chat/optima-agent",
3
- "version": "0.8.91",
3
+ "version": "0.8.92",
4
4
  "description": "基于 Claude Agent SDK 的电商运营 AI 助手",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",
@@ -63,6 +63,7 @@
63
63
  "devDependencies": {
64
64
  "@types/node": "^22.10.1",
65
65
  "@types/ws": "^8.18.1",
66
+ "execa": "^9.6.1",
66
67
  "tsx": "^4.19.2",
67
68
  "typescript": "^5.7.2",
68
69
  "vitest": "^4.0.14"