@gobi-ai/cli 2.0.17 → 2.0.19
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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/dist/commands/global.js +23 -2
- package/dist/commands/space.js +13 -2
- package/dist/commands/vault.js +2 -2
- package/dist/constants.js +1 -0
- package/package.json +1 -1
- package/skills/gobi-space/references/global.md +11 -9
- package/skills/gobi-space/references/space.md +12 -10
|
@@ -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": "2.0.
|
|
7
|
+
"version": "2.0.19",
|
|
8
8
|
"plugins": [
|
|
9
9
|
{
|
|
10
10
|
"name": "gobi",
|
|
11
11
|
"description": "Manage the Gobi collaborative knowledge platform from the command line. Publish vault profiles, create posts and replies, manage saved notes and posts, manage sessions, generate images and videos.",
|
|
12
|
-
"version": "2.0.
|
|
12
|
+
"version": "2.0.19",
|
|
13
13
|
"author": {
|
|
14
14
|
"name": "gobi-ai"
|
|
15
15
|
},
|
package/dist/commands/global.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { WEB_BASE_URL } from "../constants.js";
|
|
1
2
|
import { apiGet, apiPost, apiPatch, apiDelete } from "../client.js";
|
|
2
3
|
import { fetchDraftSummary, isJsonMode, jsonOut, readStdin, resolveVaultSlug, unwrapResp, } from "./utils.js";
|
|
3
4
|
import { extractWikiLinks, uploadAttachments, uploadPostAttachments, assertPostAttachmentMix, } from "../attachments.js";
|
|
@@ -7,6 +8,16 @@ function readContent(value) {
|
|
|
7
8
|
return readStdin();
|
|
8
9
|
return value;
|
|
9
10
|
}
|
|
11
|
+
function buildPersonalPostUrl(post) {
|
|
12
|
+
const id = post.id;
|
|
13
|
+
const vaultSlug = post.vault?.vaultSlug ||
|
|
14
|
+
post.authorVault?.vaultSlug ||
|
|
15
|
+
post.authorVaultSlug ||
|
|
16
|
+
undefined;
|
|
17
|
+
return vaultSlug
|
|
18
|
+
? `${WEB_BASE_URL}/@${vaultSlug}?postId=${id}`
|
|
19
|
+
: `${WEB_BASE_URL}/posts/${id}`;
|
|
20
|
+
}
|
|
10
21
|
function formatFeedLine(m) {
|
|
11
22
|
const isReply = m.parentPostId != null ||
|
|
12
23
|
m.type === "post-reply";
|
|
@@ -185,6 +196,7 @@ export function registerGlobalCommand(program) {
|
|
|
185
196
|
.option("--auto-attachments", "Upload wiki-linked [[files]] to webdrive before posting (also sets authorVaultSlug to that vault)")
|
|
186
197
|
.option("--draft-id <draftId>", "Use this draft as the source of title and content (mutually exclusive with --title/--content/--rich-text). On success, links the post back by recording postId on draft.metadata so the client can render an 'Open post' button. The draft's vaultSlug seeds --vault-slug when not given explicitly.")
|
|
187
198
|
.option("--attach <file>", "Local media file to attach. Repeatable. X-style mix rule: up to 4 photos OR 1 GIF OR 1 video. Size ceilings: 5MB photos / 15MB GIFs / 512MB video.", (value, prev = []) => [...prev, value], [])
|
|
199
|
+
.option("--repost-post-id <postId>", "Wrap an existing top-level post as the embedded card on this new post. Composes with --content / --rich-text / --attach (the wrapping author's text + media render above the embedded card). Reposts-of-reposts are collapsed to the transitive root server-side. The referenced post must exist, not be deleted, and not itself be a reply.")
|
|
188
200
|
.action(async (opts) => {
|
|
189
201
|
if (opts.draftId) {
|
|
190
202
|
if (opts.title || opts.content || opts.richText) {
|
|
@@ -235,6 +247,13 @@ export function registerGlobalCommand(program) {
|
|
|
235
247
|
assertPostAttachmentMix(opts.attach);
|
|
236
248
|
body.attachments = await uploadPostAttachments(opts.attach);
|
|
237
249
|
}
|
|
250
|
+
if (opts.repostPostId != null) {
|
|
251
|
+
const n = Number(opts.repostPostId);
|
|
252
|
+
if (!Number.isFinite(n) || n <= 0 || !Number.isInteger(n)) {
|
|
253
|
+
throw new Error("--repost-post-id must be a positive integer.");
|
|
254
|
+
}
|
|
255
|
+
body.repostPostId = n;
|
|
256
|
+
}
|
|
238
257
|
const resp = (await apiPost(`/posts`, body));
|
|
239
258
|
const post = unwrapResp(resp);
|
|
240
259
|
if (opts.draftId && post.id != null) {
|
|
@@ -250,14 +269,16 @@ export function registerGlobalCommand(program) {
|
|
|
250
269
|
console.error(`Warning: failed to link post to draft ${opts.draftId}: ${e.message}`);
|
|
251
270
|
}
|
|
252
271
|
}
|
|
272
|
+
const shareUrl = buildPersonalPostUrl(post);
|
|
253
273
|
if (isJsonMode(global)) {
|
|
254
|
-
jsonOut(post);
|
|
274
|
+
jsonOut({ ...post, shareUrl });
|
|
255
275
|
return;
|
|
256
276
|
}
|
|
257
277
|
console.log(`Post created!\n` +
|
|
258
278
|
` ID: ${post.id}\n` +
|
|
259
279
|
(post.title ? ` Title: ${post.title}\n` : "") +
|
|
260
|
-
` Created: ${post.createdAt}` +
|
|
280
|
+
` Created: ${post.createdAt}\n` +
|
|
281
|
+
` URL: ${shareUrl}` +
|
|
261
282
|
(opts.draftId ? `\n Linked to draft: ${opts.draftId}` : ""));
|
|
262
283
|
});
|
|
263
284
|
// ── Edit post ──
|
package/dist/commands/space.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { WEB_BASE_URL } from "../constants.js";
|
|
1
2
|
import { apiGet, apiPost, apiPatch, apiDelete } from "../client.js";
|
|
2
3
|
import { requireSpace, selectSpace, setSpaceRequirement, writeSpaceSetting, } from "./init.js";
|
|
3
4
|
import { fetchDraftSummary, isJsonMode, jsonOut, readStdin, resolveSpaceSlug, resolveVaultSlug, unwrapResp, } from "./utils.js";
|
|
@@ -320,6 +321,7 @@ export function registerSpaceCommand(program) {
|
|
|
320
321
|
.option("--space-slug <spaceSlug>", "Space slug (overrides .gobi/settings.yaml)")
|
|
321
322
|
.option("--draft-id <draftId>", "Use this draft as the source of title and content (mutually exclusive with --title/--content/--rich-text). On success, links the post back by recording postId/spaceSlug on draft.metadata so the client can render an 'Open post' button. The draft's vaultSlug seeds --vault-slug when not given explicitly.")
|
|
322
323
|
.option("--attach <file>", "Local media file to attach. Repeatable. X-style mix rule: up to 4 photos OR 1 GIF OR 1 video. Size ceilings: 5MB photos / 15MB GIFs / 512MB video.", (value, prev = []) => [...prev, value], [])
|
|
324
|
+
.option("--repost-post-id <postId>", "Wrap an existing top-level post as the embedded card on this new post. Composes with --content / --rich-text / --attach (the wrapping author's text + media render above the embedded card). Reposts-of-reposts are collapsed to the transitive root server-side. The referenced post must exist, not be deleted, and not itself be a reply.")
|
|
323
325
|
.action(async (opts) => {
|
|
324
326
|
if (opts.draftId) {
|
|
325
327
|
if (opts.title || opts.content || opts.richText) {
|
|
@@ -370,6 +372,13 @@ export function registerSpaceCommand(program) {
|
|
|
370
372
|
assertPostAttachmentMix(opts.attach);
|
|
371
373
|
body.attachments = await uploadPostAttachments(opts.attach);
|
|
372
374
|
}
|
|
375
|
+
if (opts.repostPostId != null) {
|
|
376
|
+
const n = Number(opts.repostPostId);
|
|
377
|
+
if (!Number.isFinite(n) || n <= 0 || !Number.isInteger(n)) {
|
|
378
|
+
throw new Error("--repost-post-id must be a positive integer.");
|
|
379
|
+
}
|
|
380
|
+
body.repostPostId = n;
|
|
381
|
+
}
|
|
373
382
|
const spaceSlug = resolveSpaceSlug(space, opts);
|
|
374
383
|
const resp = (await apiPost(`/spaces/${spaceSlug}/posts`, body));
|
|
375
384
|
const post = unwrapResp(resp);
|
|
@@ -386,14 +395,16 @@ export function registerSpaceCommand(program) {
|
|
|
386
395
|
console.error(`Warning: failed to link post to draft ${opts.draftId}: ${e.message}`);
|
|
387
396
|
}
|
|
388
397
|
}
|
|
398
|
+
const shareUrl = `${WEB_BASE_URL}/spaces/${spaceSlug}/posts/${post.id}`;
|
|
389
399
|
if (isJsonMode(space)) {
|
|
390
|
-
jsonOut(post);
|
|
400
|
+
jsonOut({ ...post, shareUrl });
|
|
391
401
|
return;
|
|
392
402
|
}
|
|
393
403
|
console.log(`Post created!\n` +
|
|
394
404
|
` ID: ${post.id}\n` +
|
|
395
405
|
(post.title ? ` Title: ${post.title}\n` : "") +
|
|
396
|
-
` Created: ${post.createdAt}` +
|
|
406
|
+
` Created: ${post.createdAt}\n` +
|
|
407
|
+
` URL: ${shareUrl}` +
|
|
397
408
|
(opts.draftId ? `\n Linked to draft: ${opts.draftId}` : ""));
|
|
398
409
|
});
|
|
399
410
|
space
|
package/dist/commands/vault.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from "fs";
|
|
2
2
|
import { join, resolve as pathResolve } from "path";
|
|
3
|
-
import { WEBDRIVE_BASE_URL } from "../constants.js";
|
|
3
|
+
import { WEB_BASE_URL, WEBDRIVE_BASE_URL } from "../constants.js";
|
|
4
4
|
import { getValidToken } from "../auth/manager.js";
|
|
5
5
|
import { GobiError } from "../errors.js";
|
|
6
6
|
import { apiDelete, apiGet, apiPatch, apiPost } from "../client.js";
|
|
@@ -118,7 +118,7 @@ export function registerVaultCommand(program) {
|
|
|
118
118
|
throw new GobiError(`Vault "${slug}" not found among vaults you own.`, "VAULT_NOT_FOUND");
|
|
119
119
|
}
|
|
120
120
|
const isPublished = v.public === true;
|
|
121
|
-
const profileUrl =
|
|
121
|
+
const profileUrl = `${WEB_BASE_URL}/@${slug}`;
|
|
122
122
|
const status = {
|
|
123
123
|
vaultSlug: slug,
|
|
124
124
|
name: v.name,
|
package/dist/constants.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export const BASE_URL = process.env.GOBI_BASE_URL || "https://api.joingobi.com";
|
|
2
2
|
export const WEBDRIVE_BASE_URL = process.env.GOBI_WEBDRIVE_BASE_URL || "https://webdrive.joingobi.com";
|
|
3
|
+
export const WEB_BASE_URL = process.env.GOBI_WEB_BASE_URL || "https://gobispace.com";
|
|
3
4
|
// Refresh access token when less than 5 minutes remain
|
|
4
5
|
export const TOKEN_REFRESH_BUFFER_MS = 5 * 60 * 1000;
|
|
5
6
|
// Max polling duration before giving up (ms) - 10 minutes
|
package/package.json
CHANGED
|
@@ -72,15 +72,17 @@ Usage: gobi global create-post [options]
|
|
|
72
72
|
Create a post in the global feed. --vault-slug attributes it to a vault you own; defaults to your primary vault.
|
|
73
73
|
|
|
74
74
|
Options:
|
|
75
|
-
--title <title>
|
|
76
|
-
--content <content>
|
|
77
|
-
--rich-text <richText>
|
|
78
|
-
--vault-slug <vaultSlug>
|
|
79
|
-
--auto-attachments
|
|
80
|
-
--draft-id <draftId>
|
|
81
|
-
|
|
82
|
-
--attach <file>
|
|
83
|
-
-
|
|
75
|
+
--title <title> Title of the post
|
|
76
|
+
--content <content> Post content (markdown supported, use "-" for stdin)
|
|
77
|
+
--rich-text <richText> Rich-text JSON array (mutually exclusive with --content)
|
|
78
|
+
--vault-slug <vaultSlug> Attribute the post to this vault (sets authorVaultSlug). Defaults to your primary vault.
|
|
79
|
+
--auto-attachments Upload wiki-linked [[files]] to webdrive before posting (also sets authorVaultSlug to that vault)
|
|
80
|
+
--draft-id <draftId> Use this draft as the source of title and content (mutually exclusive with --title/--content/--rich-text). On success, links the post back by recording postId on
|
|
81
|
+
draft.metadata so the client can render an 'Open post' button. The draft's vaultSlug seeds --vault-slug when not given explicitly.
|
|
82
|
+
--attach <file> Local media file to attach. Repeatable. X-style mix rule: up to 4 photos OR 1 GIF OR 1 video. Size ceilings: 5MB photos / 15MB GIFs / 512MB video. (default: [])
|
|
83
|
+
--repost-post-id <postId> Wrap an existing top-level post as the embedded card on this new post. Composes with --content / --rich-text / --attach (the wrapping author's text + media render above
|
|
84
|
+
the embedded card). Reposts-of-reposts are collapsed to the transitive root server-side. The referenced post must exist, not be deleted, and not itself be a reply.
|
|
85
|
+
-h, --help display help for command
|
|
84
86
|
```
|
|
85
87
|
|
|
86
88
|
## edit-post
|
|
@@ -117,16 +117,18 @@ Usage: gobi space create-post [options]
|
|
|
117
117
|
Create a post in a space.
|
|
118
118
|
|
|
119
119
|
Options:
|
|
120
|
-
--title <title>
|
|
121
|
-
--content <content>
|
|
122
|
-
--rich-text <richText>
|
|
123
|
-
--auto-attachments
|
|
124
|
-
--vault-slug <vaultSlug>
|
|
125
|
-
--space-slug <spaceSlug>
|
|
126
|
-
--draft-id <draftId>
|
|
127
|
-
|
|
128
|
-
--attach <file>
|
|
129
|
-
-
|
|
120
|
+
--title <title> Title of the post
|
|
121
|
+
--content <content> Post content (markdown supported, use "-" for stdin)
|
|
122
|
+
--rich-text <richText> Rich-text JSON array (mutually exclusive with --content)
|
|
123
|
+
--auto-attachments Upload wiki-linked [[files]] to webdrive before posting (also attributes the post to that vault)
|
|
124
|
+
--vault-slug <vaultSlug> Attribute the post to this vault (sets authorVaultId). Also used as upload destination for --auto-attachments.
|
|
125
|
+
--space-slug <spaceSlug> Space slug (overrides .gobi/settings.yaml)
|
|
126
|
+
--draft-id <draftId> Use this draft as the source of title and content (mutually exclusive with --title/--content/--rich-text). On success, links the post back by recording postId/spaceSlug
|
|
127
|
+
on draft.metadata so the client can render an 'Open post' button. The draft's vaultSlug seeds --vault-slug when not given explicitly.
|
|
128
|
+
--attach <file> Local media file to attach. Repeatable. X-style mix rule: up to 4 photos OR 1 GIF OR 1 video. Size ceilings: 5MB photos / 15MB GIFs / 512MB video. (default: [])
|
|
129
|
+
--repost-post-id <postId> Wrap an existing top-level post as the embedded card on this new post. Composes with --content / --rich-text / --attach (the wrapping author's text + media render above
|
|
130
|
+
the embedded card). Reposts-of-reposts are collapsed to the transitive root server-side. The referenced post must exist, not be deleted, and not itself be a reply.
|
|
131
|
+
-h, --help display help for command
|
|
130
132
|
```
|
|
131
133
|
|
|
132
134
|
## edit-post
|