@gobi-ai/cli 0.9.4 → 0.9.6

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.
@@ -4,12 +4,12 @@
4
4
  "name": "gobi-ai"
5
5
  },
6
6
  "description": "Claude Code plugin for the Gobi collaborative knowledge platform CLI",
7
- "version": "0.9.3",
7
+ "version": "0.9.5",
8
8
  "plugins": [
9
9
  {
10
10
  "name": "gobi",
11
11
  "description": "Manage the Gobi collaborative knowledge platform from the command line. Search and ask brains, publish brain documents, create threads, manage sessions, generate images and videos.",
12
- "version": "0.9.3",
12
+ "version": "0.9.5",
13
13
  "author": {
14
14
  "name": "gobi-ai"
15
15
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "gobi",
3
3
  "description": "Manage the Gobi collaborative knowledge platform from the command line",
4
- "version": "0.9.3",
4
+ "version": "0.9.5",
5
5
  "author": {
6
6
  "name": "gobi-ai"
7
7
  },
@@ -122,7 +122,9 @@ export function registerMediaCommand(program) {
122
122
  .requiredOption("--script <script>", "Script for the avatar to read")
123
123
  .option("--background-media-id <backgroundMediaId>", "Background media ID (from upload)")
124
124
  .option("--wait", "Poll until generation completes")
125
+ .option("-o, --output <path>", "Download video to this path when done (implies --wait)")
125
126
  .action(async (opts) => {
127
+ const shouldWait = opts.wait || !!opts.output;
126
128
  const body = {
127
129
  name: opts.name,
128
130
  avatarId: opts.avatarId,
@@ -134,10 +136,56 @@ export function registerMediaCommand(program) {
134
136
  const resp = (await apiPost("/media-gen/videos", body));
135
137
  let data = unwrapResp(resp);
136
138
  const videoId = data.id || data.videoId;
137
- if (opts.wait && videoId) {
139
+ if (shouldWait && videoId) {
138
140
  console.log(`Video ${videoId} queued — polling for completion…`);
139
141
  data = await pollStatus(`/media-gen/videos/${videoId}/status`, ["inference_complete", "inference_failed"]);
140
142
  }
143
+ // Download video to file if -o specified
144
+ if (opts.output && videoId && data.status === "inference_complete") {
145
+ const token = await getValidToken();
146
+ const dlUrl = `${BASE_URL}/media-gen/videos/${videoId}/download`;
147
+ const dlRes = await fetch(dlUrl, {
148
+ headers: { Authorization: `Bearer ${token}` },
149
+ redirect: "follow",
150
+ });
151
+ if (dlRes.ok) {
152
+ const { writeFile, mkdir } = await import("fs/promises");
153
+ const { dirname } = await import("path");
154
+ const buffer = Buffer.from(await dlRes.arrayBuffer());
155
+ await mkdir(dirname(opts.output), { recursive: true });
156
+ await writeFile(opts.output, buffer);
157
+ const contentType = dlRes.headers.get("content-type") || "video/mp4";
158
+ if (isJsonMode(media)) {
159
+ jsonOut({ ...data, filename: opts.output, contentType, size: buffer.length });
160
+ return;
161
+ }
162
+ console.log(`Video saved to ${opts.output} (${buffer.length} bytes)`);
163
+ return;
164
+ }
165
+ // If direct download fails, try getting the URL and fetching that
166
+ const dlRes2 = await fetch(dlUrl, {
167
+ headers: { Authorization: `Bearer ${token}` },
168
+ redirect: "manual",
169
+ });
170
+ const location = dlRes2.headers.get("location");
171
+ if (location) {
172
+ const videoRes = await fetch(location);
173
+ if (videoRes.ok) {
174
+ const { writeFile, mkdir } = await import("fs/promises");
175
+ const { dirname } = await import("path");
176
+ const buffer = Buffer.from(await videoRes.arrayBuffer());
177
+ await mkdir(dirname(opts.output), { recursive: true });
178
+ await writeFile(opts.output, buffer);
179
+ const contentType = videoRes.headers.get("content-type") || "video/mp4";
180
+ if (isJsonMode(media)) {
181
+ jsonOut({ ...data, filename: opts.output, contentType, size: buffer.length });
182
+ return;
183
+ }
184
+ console.log(`Video saved to ${opts.output} (${buffer.length} bytes)`);
185
+ return;
186
+ }
187
+ }
188
+ }
141
189
  if (isJsonMode(media)) {
142
190
  jsonOut(data);
143
191
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gobi-ai/cli",
3
- "version": "0.9.4",
3
+ "version": "0.9.6",
4
4
  "description": "CLI client for the Gobi collaborative knowledge platform",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -30,20 +30,48 @@ gobi --json media image-generate --prompt "a sunset over mountains"
30
30
  Single command — generate and download in one step:
31
31
 
32
32
  ```bash
33
- gobi --json media image-generate --prompt "a sunset over mountains" -o media/sunset.png
33
+ gobi --json media image-generate --prompt "<PROMPT>" -o media/<NAME>.png
34
34
  ```
35
35
 
36
+ Replace `<NAME>` with a short descriptive slug derived from the prompt (e.g., `happy-family`, `sunset-mountains`).
37
+
36
38
  The `-o` flag implies `--wait` and downloads the image when done.
37
39
 
38
- Then show the result as an embedded vault link: `![[media/sunset.png]]`
40
+ **IMPORTANT: After downloading, show the image using Obsidian wiki-link syntax EXACTLY like this:**
41
+
42
+ ```
43
+ ![[media/<NAME>.png]]
44
+ ```
45
+
46
+ Do NOT use markdown image syntax `![](...)` or `gobi://` URLs. Always use `![[media/<NAME>.png]]`.
39
47
 
40
48
  ### Key rules
41
- - Use `-o media/<name>.png` to generate AND download in one command. Pick a short descriptive name.
49
+ - Replace `<NAME>` with a descriptive slug NEVER use example names like `sunset.png` literally.
42
50
  - `--name` is **optional** — auto-derived from prompt if omitted.
43
51
  - Do NOT use the `downloadUrl` from the response — it is a frontend path, not a direct download link.
44
52
  - `image-download` takes a **positional** jobId (NOT `--job-id`): `gobi media image-download <jobId>`
45
53
  - The `jobId` (or `id`) field is what you pass to `image-download` / `image-status` — NOT `mediaId`.
46
54
 
55
+ ## Typical Workflow (Video Generation)
56
+
57
+ Single command — create and download in one step:
58
+
59
+ ```bash
60
+ gobi --json media video-create --name "<NAME>" --avatar-id "<AVATAR_ID>" --voice-id "<VOICE_ID>" --script "<SCRIPT>" -o media/<NAME>.mp4
61
+ ```
62
+
63
+ Replace `<NAME>` with a short descriptive slug. Use `gobi media avatars` and `gobi media voices` to list available IDs.
64
+
65
+ The `-o` flag implies `--wait` and downloads the video when done.
66
+
67
+ **IMPORTANT: After downloading, show the video using Obsidian wiki-link syntax EXACTLY like this:**
68
+
69
+ ```
70
+ ![[media/<NAME>.mp4]]
71
+ ```
72
+
73
+ Do NOT use markdown image/link syntax `![](...)` or `gobi://` URLs. Always use `![[media/<NAME>.mp4]]`.
74
+
47
75
  ## Available Commands
48
76
 
49
77
  ### Upload