@gobi-ai/cli 2.0.24 → 2.0.26
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 +3 -3
- package/.claude-plugin/plugin.json +2 -2
- package/README.md +30 -35
- package/dist/commands/artifact.js +472 -0
- package/dist/commands/global.js +21 -104
- package/dist/commands/personal.js +21 -102
- package/dist/commands/space.js +20 -103
- package/dist/commands/utils.js +0 -15
- package/dist/commands/vault.js +1 -1
- package/dist/main.js +2 -2
- package/package.json +1 -1
- package/skills/gobi-artifact/SKILL.md +133 -0
- package/skills/gobi-artifact/references/artifact.md +142 -0
- package/skills/gobi-core/SKILL.md +6 -7
- package/skills/gobi-homepage/SKILL.md +1 -1
- package/skills/gobi-media/SKILL.md +2 -2
- package/skills/gobi-sense/SKILL.md +2 -2
- package/skills/gobi-space/SKILL.md +12 -18
- package/skills/gobi-space/references/global.md +17 -28
- package/skills/gobi-space/references/personal.md +17 -26
- package/skills/gobi-space/references/space.md +1 -10
- package/skills/gobi-vault/SKILL.md +3 -3
- package/skills/gobi-vault/references/vault.md +2 -2
- package/dist/commands/draft.js +0 -230
- package/skills/gobi-draft/SKILL.md +0 -113
- package/skills/gobi-draft/references/draft.md +0 -114
package/dist/commands/space.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { WEB_BASE_URL } from "../constants.js";
|
|
2
2
|
import { apiGet, apiPost, apiPatch, apiDelete } from "../client.js";
|
|
3
3
|
import { requireSpace, selectSpace, setSpaceRequirement, writeSpaceSetting, } from "./init.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { getValidToken } from "../auth/manager.js";
|
|
4
|
+
import { isJsonMode, jsonOut, readStdin, resolveSpaceSlug, unwrapResp, } from "./utils.js";
|
|
5
|
+
import { uploadPostAttachments, assertPostAttachmentMix, } from "../attachments.js";
|
|
7
6
|
function readContent(value) {
|
|
8
7
|
if (value === "-")
|
|
9
8
|
return readStdin();
|
|
@@ -316,45 +315,22 @@ export function registerSpaceCommand(program) {
|
|
|
316
315
|
.option("--title <title>", "Title of the post")
|
|
317
316
|
.option("--content <content>", "Post content (markdown supported, use \"-\" for stdin)")
|
|
318
317
|
.option("--rich-text <richText>", "Rich-text JSON array (mutually exclusive with --content)")
|
|
319
|
-
.option("--
|
|
320
|
-
.option("--vault-slug <vaultSlug>", "Attribute the post to this vault (sets authorVaultSlug). Also used as upload destination for --auto-attachments.")
|
|
318
|
+
.option("--artifact <artifactId>", "Attach an existing artifact to the post (repeatable). Create artifacts with `gobi artifact create`.", (value, prev = []) => [...prev, value], [])
|
|
321
319
|
.option("--space-slug <spaceSlug>", "Space slug (overrides .gobi/settings.yaml)")
|
|
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.")
|
|
323
320
|
.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
321
|
.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.")
|
|
325
322
|
.action(async (opts) => {
|
|
326
|
-
if (opts.
|
|
327
|
-
|
|
328
|
-
throw new Error("--draft-id sources title and content from the draft; --title, --content, and --rich-text are not allowed alongside it.");
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
else {
|
|
332
|
-
if (!opts.content && !opts.richText) {
|
|
333
|
-
throw new Error("Provide either --content or --rich-text (or --draft-id).");
|
|
334
|
-
}
|
|
335
|
-
if (opts.content && opts.richText) {
|
|
336
|
-
throw new Error("--content and --rich-text are mutually exclusive.");
|
|
337
|
-
}
|
|
323
|
+
if (!opts.content && !opts.richText) {
|
|
324
|
+
throw new Error("Provide either --content or --rich-text.");
|
|
338
325
|
}
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
const effectiveContent = draft ? draft.content : opts.content;
|
|
342
|
-
const effectiveVaultSlugOpt = opts.vaultSlug ?? draft?.vaultSlug ?? undefined;
|
|
343
|
-
let authorVaultSlug;
|
|
344
|
-
if (effectiveVaultSlugOpt || opts.autoAttachments) {
|
|
345
|
-
authorVaultSlug = resolveVaultSlug({ vaultSlug: effectiveVaultSlugOpt });
|
|
326
|
+
if (opts.content && opts.richText) {
|
|
327
|
+
throw new Error("--content and --rich-text are mutually exclusive.");
|
|
346
328
|
}
|
|
347
329
|
const body = {};
|
|
348
|
-
if (
|
|
349
|
-
body.title =
|
|
350
|
-
if (
|
|
351
|
-
|
|
352
|
-
if (opts.autoAttachments) {
|
|
353
|
-
const token = await getValidToken();
|
|
354
|
-
const links = extractWikiLinks(content);
|
|
355
|
-
await uploadAttachments(authorVaultSlug, links, token, { addToSyncfiles: true });
|
|
356
|
-
}
|
|
357
|
-
body.content = content;
|
|
330
|
+
if (opts.title != null)
|
|
331
|
+
body.title = opts.title;
|
|
332
|
+
if (opts.content != null) {
|
|
333
|
+
body.content = readContent(opts.content);
|
|
358
334
|
}
|
|
359
335
|
if (opts.richText != null) {
|
|
360
336
|
let parsed;
|
|
@@ -366,8 +342,8 @@ export function registerSpaceCommand(program) {
|
|
|
366
342
|
}
|
|
367
343
|
body.richText = parsed;
|
|
368
344
|
}
|
|
369
|
-
if (
|
|
370
|
-
body.
|
|
345
|
+
if (opts.artifact && opts.artifact.length > 0)
|
|
346
|
+
body.artifactIds = opts.artifact;
|
|
371
347
|
if (opts.attach && opts.attach.length > 0) {
|
|
372
348
|
assertPostAttachmentMix(opts.attach);
|
|
373
349
|
body.attachments = await uploadPostAttachments(opts.attach);
|
|
@@ -382,19 +358,6 @@ export function registerSpaceCommand(program) {
|
|
|
382
358
|
const spaceSlug = resolveSpaceSlug(space, opts);
|
|
383
359
|
const resp = (await apiPost(`/spaces/${spaceSlug}/posts`, body));
|
|
384
360
|
const post = unwrapResp(resp);
|
|
385
|
-
if (opts.draftId && post.id != null) {
|
|
386
|
-
try {
|
|
387
|
-
await apiPatch(`/app/drafts/${opts.draftId}/metadata`, {
|
|
388
|
-
postId: typeof post.id === "number" ? post.id : Number(post.id),
|
|
389
|
-
spaceSlug,
|
|
390
|
-
});
|
|
391
|
-
}
|
|
392
|
-
catch (e) {
|
|
393
|
-
// Don't fail the create if linking fails — the post is live; just
|
|
394
|
-
// surface a warning so the agent can mention it.
|
|
395
|
-
console.error(`Warning: failed to link post to draft ${opts.draftId}: ${e.message}`);
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
361
|
const shareUrl = `${WEB_BASE_URL}/spaces/${spaceSlug}/posts/${post.id}`;
|
|
399
362
|
if (isJsonMode(space)) {
|
|
400
363
|
jsonOut({ ...post, shareUrl });
|
|
@@ -404,8 +367,7 @@ export function registerSpaceCommand(program) {
|
|
|
404
367
|
` ID: ${post.id}\n` +
|
|
405
368
|
(post.title ? ` Title: ${post.title}\n` : "") +
|
|
406
369
|
` Created: ${post.createdAt}\n` +
|
|
407
|
-
` URL: ${shareUrl}`
|
|
408
|
-
(opts.draftId ? `\n Linked to draft: ${opts.draftId}` : ""));
|
|
370
|
+
` URL: ${shareUrl}`);
|
|
409
371
|
});
|
|
410
372
|
space
|
|
411
373
|
.command("edit-post <postId>")
|
|
@@ -413,39 +375,25 @@ export function registerSpaceCommand(program) {
|
|
|
413
375
|
.option("--title <title>", "New title for the post")
|
|
414
376
|
.option("--content <content>", "New content for the post (markdown supported, use \"-\" for stdin)")
|
|
415
377
|
.option("--rich-text <richText>", "Rich-text JSON array (mutually exclusive with --content)")
|
|
416
|
-
.option("--auto-attachments", "Upload wiki-linked [[files]] to webdrive before editing (also attributes the post to that vault)")
|
|
417
|
-
.option("--vault-slug <vaultSlug>", "Attribute the post to this vault (sets authorVaultSlug). Also used as upload destination for --auto-attachments.")
|
|
418
378
|
.option("--space-slug <spaceSlug>", "Space slug (overrides .gobi/settings.yaml)")
|
|
419
379
|
.option("--attach <file>", "Replace the post's media attachments with the given files (existing attachments are removed). Repeatable. X-style mix rule: up to 4 photos OR 1 GIF OR 1 video. Size ceilings: 5MB photos / 15MB GIFs / 512MB video. Omit to leave attachments unchanged.", (value, prev = []) => [...prev, value], [])
|
|
420
380
|
.action(async (postId, opts) => {
|
|
421
|
-
const wantsVaultChange = !!(opts.vaultSlug || opts.autoAttachments);
|
|
422
381
|
const wantsAttachChange = !!(opts.attach && opts.attach.length > 0);
|
|
423
382
|
if (opts.title == null &&
|
|
424
383
|
opts.content == null &&
|
|
425
384
|
opts.richText == null &&
|
|
426
|
-
!wantsVaultChange &&
|
|
427
385
|
!wantsAttachChange) {
|
|
428
|
-
throw new Error("Provide at least --title, --content, --rich-text,
|
|
386
|
+
throw new Error("Provide at least --title, --content, --rich-text, or --attach to update.");
|
|
429
387
|
}
|
|
430
388
|
if (opts.content && opts.richText) {
|
|
431
389
|
throw new Error("--content and --rich-text are mutually exclusive.");
|
|
432
390
|
}
|
|
433
391
|
const spaceSlug = resolveSpaceSlug(space, opts);
|
|
434
|
-
let authorVaultSlug;
|
|
435
|
-
if (opts.vaultSlug || opts.autoAttachments) {
|
|
436
|
-
authorVaultSlug = resolveVaultSlug(opts);
|
|
437
|
-
}
|
|
438
392
|
const body = {};
|
|
439
393
|
if (opts.title != null)
|
|
440
394
|
body.title = opts.title;
|
|
441
395
|
if (opts.content != null) {
|
|
442
|
-
|
|
443
|
-
if (opts.autoAttachments) {
|
|
444
|
-
const token = await getValidToken();
|
|
445
|
-
const links = extractWikiLinks(content);
|
|
446
|
-
await uploadAttachments(authorVaultSlug, links, token, { addToSyncfiles: true });
|
|
447
|
-
}
|
|
448
|
-
body.content = content;
|
|
396
|
+
body.content = readContent(opts.content);
|
|
449
397
|
}
|
|
450
398
|
if (opts.richText != null) {
|
|
451
399
|
let parsed;
|
|
@@ -457,8 +405,6 @@ export function registerSpaceCommand(program) {
|
|
|
457
405
|
}
|
|
458
406
|
body.richText = parsed;
|
|
459
407
|
}
|
|
460
|
-
if (authorVaultSlug !== undefined)
|
|
461
|
-
body.authorVaultSlug = authorVaultSlug;
|
|
462
408
|
if (opts.attach && opts.attach.length > 0) {
|
|
463
409
|
assertPostAttachmentMix(opts.attach);
|
|
464
410
|
body.attachments = await uploadPostAttachments(opts.attach);
|
|
@@ -493,8 +439,6 @@ export function registerSpaceCommand(program) {
|
|
|
493
439
|
.description("Create a reply to a post in a space.")
|
|
494
440
|
.option("--content <content>", "Reply content (markdown supported, use \"-\" for stdin)")
|
|
495
441
|
.option("--rich-text <richText>", "Rich-text JSON array (mutually exclusive with --content)")
|
|
496
|
-
.option("--auto-attachments", "Upload wiki-linked [[files]] to webdrive before posting (also attributes the reply to that vault)")
|
|
497
|
-
.option("--vault-slug <vaultSlug>", "Attribute the reply to this vault (sets authorVaultSlug). Also used as upload destination for --auto-attachments.")
|
|
498
442
|
.option("--space-slug <spaceSlug>", "Space slug (overrides .gobi/settings.yaml)")
|
|
499
443
|
.option("--attach <file>", "Local media file to attach to this reply. 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], [])
|
|
500
444
|
.action(async (postId, opts) => {
|
|
@@ -504,19 +448,9 @@ export function registerSpaceCommand(program) {
|
|
|
504
448
|
if (opts.content && opts.richText) {
|
|
505
449
|
throw new Error("--content and --rich-text are mutually exclusive.");
|
|
506
450
|
}
|
|
507
|
-
let authorVaultSlug;
|
|
508
|
-
if (opts.vaultSlug || opts.autoAttachments) {
|
|
509
|
-
authorVaultSlug = resolveVaultSlug(opts);
|
|
510
|
-
}
|
|
511
451
|
const body = {};
|
|
512
452
|
if (opts.content != null) {
|
|
513
|
-
|
|
514
|
-
if (opts.autoAttachments) {
|
|
515
|
-
const token = await getValidToken();
|
|
516
|
-
const links = extractWikiLinks(content);
|
|
517
|
-
await uploadAttachments(authorVaultSlug, links, token, { addToSyncfiles: true });
|
|
518
|
-
}
|
|
519
|
-
body.content = content;
|
|
453
|
+
body.content = readContent(opts.content);
|
|
520
454
|
}
|
|
521
455
|
if (opts.richText != null) {
|
|
522
456
|
let parsed;
|
|
@@ -528,8 +462,6 @@ export function registerSpaceCommand(program) {
|
|
|
528
462
|
}
|
|
529
463
|
body.richText = parsed;
|
|
530
464
|
}
|
|
531
|
-
if (authorVaultSlug)
|
|
532
|
-
body.authorVaultSlug = authorVaultSlug;
|
|
533
465
|
if (opts.attach && opts.attach.length > 0) {
|
|
534
466
|
assertPostAttachmentMix(opts.attach);
|
|
535
467
|
body.attachments = await uploadPostAttachments(opts.attach);
|
|
@@ -549,31 +481,18 @@ export function registerSpaceCommand(program) {
|
|
|
549
481
|
.description("Edit a reply you authored in a space.")
|
|
550
482
|
.option("--content <content>", "New content for the reply (markdown supported, use \"-\" for stdin)")
|
|
551
483
|
.option("--rich-text <richText>", "Rich-text JSON array (mutually exclusive with --content)")
|
|
552
|
-
.option("--auto-attachments", "Upload wiki-linked [[files]] to webdrive before editing (also attributes the reply to that vault)")
|
|
553
|
-
.option("--vault-slug <vaultSlug>", "Attribute the reply to this vault (sets authorVaultSlug). Also used as upload destination for --auto-attachments.")
|
|
554
484
|
.option("--space-slug <spaceSlug>", "Space slug (overrides .gobi/settings.yaml)")
|
|
555
485
|
.action(async (replyId, opts) => {
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
throw new Error("Provide at least --content, --rich-text, or --vault-slug to update.");
|
|
486
|
+
if (opts.content == null && opts.richText == null) {
|
|
487
|
+
throw new Error("Provide at least --content or --rich-text to update.");
|
|
559
488
|
}
|
|
560
489
|
if (opts.content && opts.richText) {
|
|
561
490
|
throw new Error("--content and --rich-text are mutually exclusive.");
|
|
562
491
|
}
|
|
563
492
|
const spaceSlug = resolveSpaceSlug(space, opts);
|
|
564
|
-
let authorVaultSlug;
|
|
565
|
-
if (opts.vaultSlug || opts.autoAttachments) {
|
|
566
|
-
authorVaultSlug = resolveVaultSlug(opts);
|
|
567
|
-
}
|
|
568
493
|
const body = {};
|
|
569
494
|
if (opts.content != null) {
|
|
570
|
-
|
|
571
|
-
if (opts.autoAttachments) {
|
|
572
|
-
const token = await getValidToken();
|
|
573
|
-
const links = extractWikiLinks(content);
|
|
574
|
-
await uploadAttachments(authorVaultSlug, links, token, { addToSyncfiles: true });
|
|
575
|
-
}
|
|
576
|
-
body.content = content;
|
|
495
|
+
body.content = readContent(opts.content);
|
|
577
496
|
}
|
|
578
497
|
if (opts.richText != null) {
|
|
579
498
|
let parsed;
|
|
@@ -585,8 +504,6 @@ export function registerSpaceCommand(program) {
|
|
|
585
504
|
}
|
|
586
505
|
body.richText = parsed;
|
|
587
506
|
}
|
|
588
|
-
if (authorVaultSlug !== undefined)
|
|
589
|
-
body.authorVaultSlug = authorVaultSlug;
|
|
590
507
|
const resp = (await apiPatch(`/spaces/${spaceSlug}/replies/${replyId}`, body));
|
|
591
508
|
const msg = unwrapResp(resp);
|
|
592
509
|
if (isJsonMode(space)) {
|
package/dist/commands/utils.js
CHANGED
|
@@ -1,20 +1,5 @@
|
|
|
1
1
|
import { readFileSync } from "fs";
|
|
2
|
-
import { apiGet } from "../client.js";
|
|
3
2
|
import { getSpaceSlug, getVaultSlug } from "./init.js";
|
|
4
|
-
// Fetch a draft and return just the fields a post-creation flow needs. Used
|
|
5
|
-
// by `space create-post` and `global create-post` when --draft-id is passed:
|
|
6
|
-
// title/content come from the draft, vaultSlug seeds the post's authorship
|
|
7
|
-
// when the caller did not pass --vault-slug.
|
|
8
|
-
export async function fetchDraftSummary(draftId) {
|
|
9
|
-
const resp = (await apiGet(`/app/drafts/${draftId}`));
|
|
10
|
-
const data = unwrapResp(resp);
|
|
11
|
-
return {
|
|
12
|
-
draftId: String(data.draftId ?? draftId),
|
|
13
|
-
title: String(data.title ?? ""),
|
|
14
|
-
content: String(data.content ?? ""),
|
|
15
|
-
vaultSlug: data.vaultSlug ?? null,
|
|
16
|
-
};
|
|
17
|
-
}
|
|
18
3
|
// Reads all of stdin synchronously. Uses fd 0 (cross-platform) instead of
|
|
19
4
|
// "/dev/stdin", which doesn't exist on Windows.
|
|
20
5
|
export function readStdin() {
|
package/dist/commands/vault.js
CHANGED
|
@@ -103,7 +103,7 @@ export function registerVaultCommand(program) {
|
|
|
103
103
|
});
|
|
104
104
|
const statusCmd = vault
|
|
105
105
|
.command("status")
|
|
106
|
-
.description("Show the configured vault's publish state and metadata (use before
|
|
106
|
+
.description("Show the configured vault's publish state and metadata (use before authoring a markdown artifact with --auto-attachments to confirm the vault is public).")
|
|
107
107
|
.option("--vault-slug <vaultSlug>", "Vault slug to inspect (defaults to .gobi/settings.yaml)")
|
|
108
108
|
.action(async (opts) => {
|
|
109
109
|
const slug = opts.vaultSlug ?? getVaultSlug();
|
package/dist/main.js
CHANGED
|
@@ -11,7 +11,7 @@ import { registerVaultCommand } from "./commands/vault.js";
|
|
|
11
11
|
import { registerSenseCommand } from "./commands/sense.js";
|
|
12
12
|
import { registerUpdateCommand } from "./commands/update.js";
|
|
13
13
|
import { registerMediaCommand } from "./commands/media.js";
|
|
14
|
-
import {
|
|
14
|
+
import { registerArtifactCommand } from "./commands/artifact.js";
|
|
15
15
|
const require = createRequire(import.meta.url);
|
|
16
16
|
const { version } = require("../package.json");
|
|
17
17
|
function hasParentOption(cmd, key) {
|
|
@@ -64,7 +64,7 @@ export async function cli() {
|
|
|
64
64
|
registerSenseCommand(program);
|
|
65
65
|
registerUpdateCommand(program);
|
|
66
66
|
registerMediaCommand(program);
|
|
67
|
-
|
|
67
|
+
registerArtifactCommand(program);
|
|
68
68
|
// Propagate helpWidth to all subcommands
|
|
69
69
|
const helpWidth = process.stdout.columns || 200;
|
|
70
70
|
for (const cmd of program.commands) {
|
package/package.json
CHANGED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: gobi-artifact
|
|
3
|
+
description: >-
|
|
4
|
+
Gobi artifact commands for versioned creations attached to posts: create,
|
|
5
|
+
revise, publish, revert, history, download, delete, get, list. An artifact
|
|
6
|
+
is a human-owned creation (image, video, gif, markdown, or meeting_summary)
|
|
7
|
+
whose revisions form a draft/published tree. Use when the user wants to
|
|
8
|
+
author, version, publish, or attach an artifact to a post.
|
|
9
|
+
allowed-tools: Bash(gobi:*)
|
|
10
|
+
metadata:
|
|
11
|
+
author: gobi-ai
|
|
12
|
+
version: "2.0.26"
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# gobi-artifact
|
|
16
|
+
|
|
17
|
+
Gobi artifact commands for versioned, post-attachable creations (v2.0.26).
|
|
18
|
+
|
|
19
|
+
Requires gobi-cli installed and authenticated. See gobi-core skill for setup.
|
|
20
|
+
|
|
21
|
+
## What is an artifact?
|
|
22
|
+
|
|
23
|
+
An artifact is a versioned creation that can be attached to one or more posts. Each artifact has:
|
|
24
|
+
|
|
25
|
+
- **kind** — one of `image | video | gif | markdown | meeting_summary`. `markdown` and `meeting_summary` carry a markdown **body**; `image`, `gif`, and `video` carry an uploaded **media file**.
|
|
26
|
+
- **title** — optional display title.
|
|
27
|
+
- **owner** — always a human (the calling user). Even when an agent runs the CLI, the artifact is owned by the agent's owner.
|
|
28
|
+
- **revisions** — a draft/published tree. New revisions start as `draft`; publishing one makes it the artifact's single `published` revision (at most one published per artifact). `revise --from <revisionId>` branches off an earlier revision instead of the latest, so the history can fork.
|
|
29
|
+
- **metadata** — per-kind extras. For markdown kinds, `metadata.vaultSlug` is the anchor vault used to resolve `[[wikilinks]]` in the body.
|
|
30
|
+
|
|
31
|
+
Markdown bodies can reference vault notes with `[[wikilinks]]`. Resolution against the anchor vault (`--vault-slug` on create) only works for viewers who can read that vault.
|
|
32
|
+
|
|
33
|
+
## Important: JSON Mode
|
|
34
|
+
|
|
35
|
+
For programmatic/agent usage, always pass `--json` as a **global** option (before the subcommand):
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
gobi --json artifact list --limit 20
|
|
39
|
+
gobi --json artifact create --kind markdown --content "# Notes" --title "My note"
|
|
40
|
+
gobi --json artifact get <artifactId>
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
JSON mode wraps the response as `{"success": true, "data": <artifact|revision|...>}` (or `{"success": false, "error": "..."}`).
|
|
44
|
+
|
|
45
|
+
## Typical Workflow (markdown artifact)
|
|
46
|
+
|
|
47
|
+
Create a markdown artifact, attaching it to a post in the same call:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
gobi --json artifact create --kind markdown --file notes.md --title "Design notes" \
|
|
51
|
+
--vault-slug my-vault --post-id 12345
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The body can come from `--file <path>`, `--content <md>` inline, or stdin (`--content -`). `--vault-slug` anchors `[[wikilink]]` resolution and is stored as `metadata.vaultSlug`.
|
|
55
|
+
|
|
56
|
+
Add `--auto-attachments` (markdown kinds only) to upload any `[[wiki-linked files]]` in the body to the `--vault-slug` vault on webdrive before creating:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
gobi --json artifact create --kind markdown --file notes.md --vault-slug my-vault --auto-attachments
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Revise it (adds a new draft revision), then publish that revision:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
gobi --json artifact revise <artifactId> --file notes-v2.md --change-note "Tighten intro"
|
|
66
|
+
gobi --json artifact publish <artifactId> --revision <revisionId>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`revise --auto-attachments` reuses the artifact's stored `metadata.vaultSlug` (it GETs the artifact first), so you don't repeat `--vault-slug`.
|
|
70
|
+
|
|
71
|
+
Inspect and roll back:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
gobi --json artifact history <artifactId> # full revision tree (owner only)
|
|
75
|
+
gobi --json artifact revert <artifactId> --to <revisionId>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Typical Workflow (media artifact)
|
|
79
|
+
|
|
80
|
+
Image / gif / video kinds upload a local file (init → PUT → create) instead of a body:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
gobi --json artifact create --kind image --file diagram.png --title "Architecture" --post-id 12345
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Media-file size ceilings mirror post media: 5MB photos / 15MB GIFs / 512MB video, derived from the file's content type. Revise a media artifact by uploading a replacement file:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
gobi --json artifact revise <artifactId> --file diagram-v2.png --change-note "Add cache layer"
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Download
|
|
93
|
+
|
|
94
|
+
`download` defaults to the artifact's current (published, else latest) revision; pass `--revision` to pick one.
|
|
95
|
+
|
|
96
|
+
- markdown → writes the body to `--out <path>`, or prints to stdout when `--out` is omitted.
|
|
97
|
+
- media → fetches the `mediaUrl` bytes to `--out <path>` (defaults to `<artifactId>.<ext>`).
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
gobi artifact download <artifactId> --out notes.md
|
|
101
|
+
gobi artifact download <artifactId> --revision <revisionId> --out image.png
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Attaching to a post
|
|
105
|
+
|
|
106
|
+
`create --post-id <id>` attaches the new artifact to a post **without clobbering** the post's existing artifacts: the CLI reads the post's current artifact attachments, appends the new id, and writes the merged set via the post edit endpoint (`PATCH /posts/:id` with `artifactIds`). The post API's `artifactIds` is otherwise a full replacement.
|
|
107
|
+
|
|
108
|
+
Attaching is done at artifact-create time via `--post-id`. The post commands (`create-post` / `edit-post`) do **not** expose an artifact-attach flag — to attach to an existing post, create the artifact with `--post-id <that post's id>`.
|
|
109
|
+
|
|
110
|
+
## Available Commands
|
|
111
|
+
|
|
112
|
+
- `gobi artifact create` — Create an artifact (markdown body or uploaded media). `--post-id` attaches it to a post; `--auto-attachments` (markdown) uploads `[[wikilinks]]`.
|
|
113
|
+
- `gobi artifact revise` — Add a draft revision (new body or media file). `--from` branches off a specific revision.
|
|
114
|
+
- `gobi artifact publish` — Publish a revision (becomes the single published revision).
|
|
115
|
+
- `gobi artifact revert` — Move the published pointer to an earlier revision.
|
|
116
|
+
- `gobi artifact history` — List the full revision tree (owner only).
|
|
117
|
+
- `gobi artifact download` — Download a revision's content (markdown body or media bytes).
|
|
118
|
+
- `gobi artifact delete` — Delete an artifact and its revision tree.
|
|
119
|
+
- `gobi artifact get` — Get one artifact with its current revision.
|
|
120
|
+
- `gobi artifact list` — List your artifacts (`--kind`, `--limit`).
|
|
121
|
+
|
|
122
|
+
## Confirm before mutating
|
|
123
|
+
|
|
124
|
+
Artifacts are user-owned creations. The authoring commands (`create`, `revise`) are the normal flow and run without extra confirmation. Two commands change what's live or destroy data — confirm first:
|
|
125
|
+
|
|
126
|
+
- `publish <id> --revision <id>` / `revert <id> --to <id>` — change which revision is published (visible on attached posts). Confirm the target revision with the user.
|
|
127
|
+
- `delete <id>` — irreversible (removes the artifact and its whole revision tree). Confirm the target id before running.
|
|
128
|
+
|
|
129
|
+
Read-only commands (`get`, `list`, `history`) and `download` run without confirmation.
|
|
130
|
+
|
|
131
|
+
## Reference Documentation
|
|
132
|
+
|
|
133
|
+
- [gobi artifact](references/artifact.md)
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# gobi artifact
|
|
2
|
+
|
|
3
|
+
```
|
|
4
|
+
Usage: gobi artifact [options] [command]
|
|
5
|
+
|
|
6
|
+
Versioned creations attached to posts. Kinds: image | video | gif | markdown | meeting_summary. Always human-owned; revisions form a draft/published tree (at most one published per artifact).
|
|
7
|
+
|
|
8
|
+
Options:
|
|
9
|
+
-h, --help display help for command
|
|
10
|
+
|
|
11
|
+
Commands:
|
|
12
|
+
create [options] Create an artifact. markdown/meeting_summary kinds take a body via --file, --content, or stdin ("-"). image/gif/video kinds upload --file. Pass --post-id to attach
|
|
13
|
+
the new artifact to a post.
|
|
14
|
+
revise [options] <artifactId> Add a draft revision to an artifact. New body via --file, --content, or stdin (markdown), or --file (media). Use --from to branch off a specific revision.
|
|
15
|
+
publish [options] <artifactId> Publish a revision (becomes the artifact's single published revision).
|
|
16
|
+
revert [options] <artifactId> Revert the artifact's published pointer to an earlier revision.
|
|
17
|
+
history <artifactId> List the artifact's full revision tree (owner only).
|
|
18
|
+
download [options] <artifactId> Download an artifact's content. markdown → write the body; media → fetch the bytes. Defaults to the published/latest revision; pass --revision to pick one. Writes
|
|
19
|
+
to --out or stdout (markdown).
|
|
20
|
+
delete <artifactId> Delete an artifact (and its revision tree).
|
|
21
|
+
get <artifactId> Get one artifact with its current revision.
|
|
22
|
+
list [options] List your artifacts (newest first).
|
|
23
|
+
help [command] display help for command
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## create
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
Usage: gobi artifact create [options]
|
|
30
|
+
|
|
31
|
+
Create an artifact. markdown/meeting_summary kinds take a body via --file, --content, or stdin ("-"). image/gif/video kinds upload --file. Pass --post-id to attach the new artifact to a post.
|
|
32
|
+
|
|
33
|
+
Options:
|
|
34
|
+
--kind <kind> Artifact kind: image | video | gif | markdown | meeting_summary
|
|
35
|
+
--file <path> Local file: markdown body (markdown kinds) or media file (media kinds)
|
|
36
|
+
--content <md> Markdown body inline (markdown kinds; pass "-" for stdin)
|
|
37
|
+
--title <t> Display title
|
|
38
|
+
--vault-slug <slug> Anchor vault for [[wikilink]] resolution (markdown kinds). Stored in metadata.vaultSlug.
|
|
39
|
+
--post-id <id> Attach the created artifact to this post afterward
|
|
40
|
+
--auto-attachments Upload wiki-linked [[files]] to webdrive before creating (markdown kinds; uses --vault-slug)
|
|
41
|
+
--change-note <note> Note describing this revision
|
|
42
|
+
-h, --help display help for command
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## revise
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
Usage: gobi artifact revise [options] <artifactId>
|
|
49
|
+
|
|
50
|
+
Add a draft revision to an artifact. New body via --file, --content, or stdin (markdown), or --file (media). Use --from to branch off a specific revision.
|
|
51
|
+
|
|
52
|
+
Options:
|
|
53
|
+
--file <path> Local file: markdown body (markdown kinds) or media file (media kinds)
|
|
54
|
+
--content <md> Markdown body inline (markdown kinds; pass "-" for stdin)
|
|
55
|
+
--change-note <note> Note describing this revision
|
|
56
|
+
--from <revisionId> Branch the new draft off this revision (defaults to the latest)
|
|
57
|
+
--auto-attachments Upload wiki-linked [[files]] to webdrive before revising (markdown kinds; uses the artifact's stored metadata.vaultSlug)
|
|
58
|
+
-h, --help display help for command
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## publish
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
Usage: gobi artifact publish [options] <artifactId>
|
|
65
|
+
|
|
66
|
+
Publish a revision (becomes the artifact's single published revision).
|
|
67
|
+
|
|
68
|
+
Options:
|
|
69
|
+
--revision <revisionId> Revision to publish
|
|
70
|
+
-h, --help display help for command
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## revert
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
Usage: gobi artifact revert [options] <artifactId>
|
|
77
|
+
|
|
78
|
+
Revert the artifact's published pointer to an earlier revision.
|
|
79
|
+
|
|
80
|
+
Options:
|
|
81
|
+
--to <revisionId> Revision to revert to
|
|
82
|
+
-h, --help display help for command
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## history
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
Usage: gobi artifact history [options] <artifactId>
|
|
89
|
+
|
|
90
|
+
List the artifact's full revision tree (owner only).
|
|
91
|
+
|
|
92
|
+
Options:
|
|
93
|
+
-h, --help display help for command
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## download
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
Usage: gobi artifact download [options] <artifactId>
|
|
100
|
+
|
|
101
|
+
Download an artifact's content. markdown → write the body; media → fetch the bytes. Defaults to the published/latest revision; pass --revision to pick one. Writes to --out or stdout (markdown).
|
|
102
|
+
|
|
103
|
+
Options:
|
|
104
|
+
--revision <revisionId> Specific revision (defaults to the artifact's current revision)
|
|
105
|
+
--out <path> Write to this file (markdown defaults to stdout)
|
|
106
|
+
-h, --help display help for command
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## delete
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
Usage: gobi artifact delete [options] <artifactId>
|
|
113
|
+
|
|
114
|
+
Delete an artifact (and its revision tree).
|
|
115
|
+
|
|
116
|
+
Options:
|
|
117
|
+
-h, --help display help for command
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## get
|
|
121
|
+
|
|
122
|
+
```
|
|
123
|
+
Usage: gobi artifact get [options] <artifactId>
|
|
124
|
+
|
|
125
|
+
Get one artifact with its current revision.
|
|
126
|
+
|
|
127
|
+
Options:
|
|
128
|
+
-h, --help display help for command
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## list
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
Usage: gobi artifact list [options]
|
|
135
|
+
|
|
136
|
+
List your artifacts (newest first).
|
|
137
|
+
|
|
138
|
+
Options:
|
|
139
|
+
--kind <kind> Filter by kind: image | video | gif | markdown | meeting_summary
|
|
140
|
+
--limit <n> Max items to return
|
|
141
|
+
-h, --help display help for command
|
|
142
|
+
```
|
|
@@ -8,12 +8,12 @@ description: >-
|
|
|
8
8
|
allowed-tools: Bash(gobi:*)
|
|
9
9
|
metadata:
|
|
10
10
|
author: gobi-ai
|
|
11
|
-
version: "2.0.
|
|
11
|
+
version: "2.0.26"
|
|
12
12
|
---
|
|
13
13
|
|
|
14
14
|
# gobi-core
|
|
15
15
|
|
|
16
|
-
Core CLI commands for the Gobi collaborative knowledge platform (v2.0.
|
|
16
|
+
Core CLI commands for the Gobi collaborative knowledge platform (v2.0.26).
|
|
17
17
|
|
|
18
18
|
## Prerequisites
|
|
19
19
|
|
|
@@ -41,7 +41,7 @@ brew tap gobi-ai/tap && brew install gobi
|
|
|
41
41
|
- **Personal Post**: A post on the author's profile that surfaces in the public global feed. Same `Post` data model as a Space Post — only the scope differs.
|
|
42
42
|
- **Space Post**: A post inside a community space.
|
|
43
43
|
- **Space**: A shared community knowledge area. A user can be a member of one or more spaces; each space contains posts, replies, and connected vaults.
|
|
44
|
-
- **
|
|
44
|
+
- **Artifact**: A versioned, human-owned creation (image, video, gif, markdown, or meeting_summary) attached to posts. Its revisions form a draft/published tree (at most one published). See the **gobi-artifact** skill.
|
|
45
45
|
|
|
46
46
|
## Setup steps (run only what you need)
|
|
47
47
|
|
|
@@ -50,7 +50,7 @@ There is **no `gobi init`** command — each setup step is its own command, and
|
|
|
50
50
|
| Step | Command | Unlocks |
|
|
51
51
|
|------|---------|---------|
|
|
52
52
|
| 1. Log in | `gobi auth login` | All authenticated commands |
|
|
53
|
-
| 2. Configure a vault for this directory | `gobi vault init` | Every `gobi vault …` command; also lets `
|
|
53
|
+
| 2. Configure a vault for this directory | `gobi vault init` | Every `gobi vault …` command; also lets `artifact create --auto-attachments` resolve that vault automatically |
|
|
54
54
|
| 3. Pick an active space for this directory | `gobi space warp` | Every `gobi space …` post/reply/feed command without needing `--space-slug` |
|
|
55
55
|
|
|
56
56
|
After step 2 + step 3, `.gobi/settings.yaml` looks like:
|
|
@@ -72,7 +72,7 @@ gobi auth status
|
|
|
72
72
|
|
|
73
73
|
| Command family | Needs vault in `.gobi`? | Needs space in `.gobi`? | Per-call override |
|
|
74
74
|
|----------------|------------------------|------------------------|-------------------|
|
|
75
|
-
| `auth …`, `update`, `
|
|
75
|
+
| `auth …`, `update`, `artifact …`, `media …`, `sense …` | no | no | – |
|
|
76
76
|
| `vault publish` / `unpublish` / `sync` | **yes** | no | none — must run `gobi vault init` first |
|
|
77
77
|
| `vault init` | no (it sets it up) | no | – |
|
|
78
78
|
| `space list` / `warp [slug]` / `get [slug]` | no | no | – |
|
|
@@ -84,7 +84,7 @@ gobi auth status
|
|
|
84
84
|
| `personal create-post` | optional¹ | no | command-level `--vault-slug <slug>` |
|
|
85
85
|
| `personal edit-post` | optional² | no | command-level `--vault-slug <slug>` |
|
|
86
86
|
|
|
87
|
-
¹ `global create-post` accepts `--vault-slug
|
|
87
|
+
¹ `global create-post` accepts `--vault-slug`, optional. With no flag and no `vaultSlug` in `.gobi`, the post is created with no `authorVaultSlug` (vault-less personal post) — same as a Space post that isn't attributed to any vault. Set `--vault-slug` to attribute it.
|
|
88
88
|
|
|
89
89
|
² `global edit-post` only consults `--vault-slug` when you pass it explicitly. Use `--vault-slug ""` to detach an existing attribution; non-empty re-attaches.
|
|
90
90
|
|
|
@@ -139,4 +139,3 @@ Read-only commands (`auth status`, `space list`) run without confirmation.
|
|
|
139
139
|
| `GOBI_BASE_URL` | `https://api.joingobi.com` | API server URL |
|
|
140
140
|
| `GOBI_WEBDRIVE_BASE_URL` | `https://webdrive.joingobi.com` | File storage URL |
|
|
141
141
|
| `GOBI_WEB_BASE_URL` | `https://gobispace.com` | Public web URL (used when assembling shareable links) |
|
|
142
|
-
| `GOBI_SESSION_ID` | — | Default `--session` for `gobi draft add` (set automatically inside agent runs) |
|
|
@@ -10,12 +10,12 @@ description: >-
|
|
|
10
10
|
allowed-tools: Bash(gobi:*)
|
|
11
11
|
metadata:
|
|
12
12
|
author: gobi-ai
|
|
13
|
-
version: "2.0.
|
|
13
|
+
version: "2.0.26"
|
|
14
14
|
---
|
|
15
15
|
|
|
16
16
|
# gobi-media
|
|
17
17
|
|
|
18
|
-
Gobi media generation commands (v2.0.
|
|
18
|
+
Gobi media generation commands (v2.0.26).
|
|
19
19
|
|
|
20
20
|
Requires gobi-cli installed and authenticated. See gobi-core skill for setup.
|
|
21
21
|
|