@gobi-ai/cli 2.0.23 → 2.0.25
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 +33 -81
- package/dist/commands/personal.js +32 -78
- package/dist/commands/space.js +34 -82
- 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 +7 -12
- package/skills/gobi-space/references/personal.md +4 -8
- package/skills/gobi-space/references/space.md +6 -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, resolveVaultSlug, 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,26 @@ 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("--vault-slug <vaultSlug>", "Attribute the post to this vault (sets authorVaultSlug). Caller must own the vault.")
|
|
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
|
-
}
|
|
323
|
+
if (!opts.content && !opts.richText) {
|
|
324
|
+
throw new Error("Provide either --content or --rich-text.");
|
|
330
325
|
}
|
|
331
|
-
|
|
332
|
-
|
|
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
|
-
}
|
|
326
|
+
if (opts.content && opts.richText) {
|
|
327
|
+
throw new Error("--content and --rich-text are mutually exclusive.");
|
|
338
328
|
}
|
|
339
|
-
const draft = opts.draftId ? await fetchDraftSummary(opts.draftId) : null;
|
|
340
|
-
const effectiveTitle = draft ? draft.title : opts.title;
|
|
341
|
-
const effectiveContent = draft ? draft.content : opts.content;
|
|
342
|
-
const effectiveVaultSlugOpt = opts.vaultSlug ?? draft?.vaultSlug ?? undefined;
|
|
343
329
|
let authorVaultSlug;
|
|
344
|
-
if (
|
|
345
|
-
authorVaultSlug = resolveVaultSlug({ vaultSlug:
|
|
330
|
+
if (opts.vaultSlug) {
|
|
331
|
+
authorVaultSlug = resolveVaultSlug({ vaultSlug: opts.vaultSlug });
|
|
346
332
|
}
|
|
347
333
|
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;
|
|
334
|
+
if (opts.title != null)
|
|
335
|
+
body.title = opts.title;
|
|
336
|
+
if (opts.content != null) {
|
|
337
|
+
body.content = readContent(opts.content);
|
|
358
338
|
}
|
|
359
339
|
if (opts.richText != null) {
|
|
360
340
|
let parsed;
|
|
@@ -382,19 +362,6 @@ export function registerSpaceCommand(program) {
|
|
|
382
362
|
const spaceSlug = resolveSpaceSlug(space, opts);
|
|
383
363
|
const resp = (await apiPost(`/spaces/${spaceSlug}/posts`, body));
|
|
384
364
|
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
365
|
const shareUrl = `${WEB_BASE_URL}/spaces/${spaceSlug}/posts/${post.id}`;
|
|
399
366
|
if (isJsonMode(space)) {
|
|
400
367
|
jsonOut({ ...post, shareUrl });
|
|
@@ -404,8 +371,7 @@ export function registerSpaceCommand(program) {
|
|
|
404
371
|
` ID: ${post.id}\n` +
|
|
405
372
|
(post.title ? ` Title: ${post.title}\n` : "") +
|
|
406
373
|
` Created: ${post.createdAt}\n` +
|
|
407
|
-
` URL: ${shareUrl}`
|
|
408
|
-
(opts.draftId ? `\n Linked to draft: ${opts.draftId}` : ""));
|
|
374
|
+
` URL: ${shareUrl}`);
|
|
409
375
|
});
|
|
410
376
|
space
|
|
411
377
|
.command("edit-post <postId>")
|
|
@@ -413,36 +379,32 @@ export function registerSpaceCommand(program) {
|
|
|
413
379
|
.option("--title <title>", "New title for the post")
|
|
414
380
|
.option("--content <content>", "New content for the post (markdown supported, use \"-\" for stdin)")
|
|
415
381
|
.option("--rich-text <richText>", "Rich-text JSON array (mutually exclusive with --content)")
|
|
416
|
-
.option("--
|
|
417
|
-
.option("--vault-slug <vaultSlug>", "Attribute the post to this vault (sets authorVaultSlug). Also used as upload destination for --auto-attachments.")
|
|
382
|
+
.option("--vault-slug <vaultSlug>", "Attribute the post to this vault (sets authorVaultSlug). Caller must own the vault.")
|
|
418
383
|
.option("--space-slug <spaceSlug>", "Space slug (overrides .gobi/settings.yaml)")
|
|
384
|
+
.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], [])
|
|
419
385
|
.action(async (postId, opts) => {
|
|
420
|
-
const wantsVaultChange = !!
|
|
386
|
+
const wantsVaultChange = !!opts.vaultSlug;
|
|
387
|
+
const wantsAttachChange = !!(opts.attach && opts.attach.length > 0);
|
|
421
388
|
if (opts.title == null &&
|
|
422
389
|
opts.content == null &&
|
|
423
390
|
opts.richText == null &&
|
|
424
|
-
!wantsVaultChange
|
|
425
|
-
|
|
391
|
+
!wantsVaultChange &&
|
|
392
|
+
!wantsAttachChange) {
|
|
393
|
+
throw new Error("Provide at least --title, --content, --rich-text, --vault-slug, or --attach to update.");
|
|
426
394
|
}
|
|
427
395
|
if (opts.content && opts.richText) {
|
|
428
396
|
throw new Error("--content and --rich-text are mutually exclusive.");
|
|
429
397
|
}
|
|
430
398
|
const spaceSlug = resolveSpaceSlug(space, opts);
|
|
431
399
|
let authorVaultSlug;
|
|
432
|
-
if (opts.vaultSlug
|
|
400
|
+
if (opts.vaultSlug) {
|
|
433
401
|
authorVaultSlug = resolveVaultSlug(opts);
|
|
434
402
|
}
|
|
435
403
|
const body = {};
|
|
436
404
|
if (opts.title != null)
|
|
437
405
|
body.title = opts.title;
|
|
438
406
|
if (opts.content != null) {
|
|
439
|
-
|
|
440
|
-
if (opts.autoAttachments) {
|
|
441
|
-
const token = await getValidToken();
|
|
442
|
-
const links = extractWikiLinks(content);
|
|
443
|
-
await uploadAttachments(authorVaultSlug, links, token, { addToSyncfiles: true });
|
|
444
|
-
}
|
|
445
|
-
body.content = content;
|
|
407
|
+
body.content = readContent(opts.content);
|
|
446
408
|
}
|
|
447
409
|
if (opts.richText != null) {
|
|
448
410
|
let parsed;
|
|
@@ -456,6 +418,10 @@ export function registerSpaceCommand(program) {
|
|
|
456
418
|
}
|
|
457
419
|
if (authorVaultSlug !== undefined)
|
|
458
420
|
body.authorVaultSlug = authorVaultSlug;
|
|
421
|
+
if (opts.attach && opts.attach.length > 0) {
|
|
422
|
+
assertPostAttachmentMix(opts.attach);
|
|
423
|
+
body.attachments = await uploadPostAttachments(opts.attach);
|
|
424
|
+
}
|
|
459
425
|
const resp = (await apiPatch(`/spaces/${spaceSlug}/posts/${postId}`, body));
|
|
460
426
|
const post = unwrapResp(resp);
|
|
461
427
|
if (isJsonMode(space)) {
|
|
@@ -486,8 +452,7 @@ export function registerSpaceCommand(program) {
|
|
|
486
452
|
.description("Create a reply to a post in a space.")
|
|
487
453
|
.option("--content <content>", "Reply content (markdown supported, use \"-\" for stdin)")
|
|
488
454
|
.option("--rich-text <richText>", "Rich-text JSON array (mutually exclusive with --content)")
|
|
489
|
-
.option("--
|
|
490
|
-
.option("--vault-slug <vaultSlug>", "Attribute the reply to this vault (sets authorVaultSlug). Also used as upload destination for --auto-attachments.")
|
|
455
|
+
.option("--vault-slug <vaultSlug>", "Attribute the reply to this vault (sets authorVaultSlug). Caller must own the vault.")
|
|
491
456
|
.option("--space-slug <spaceSlug>", "Space slug (overrides .gobi/settings.yaml)")
|
|
492
457
|
.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], [])
|
|
493
458
|
.action(async (postId, opts) => {
|
|
@@ -498,18 +463,12 @@ export function registerSpaceCommand(program) {
|
|
|
498
463
|
throw new Error("--content and --rich-text are mutually exclusive.");
|
|
499
464
|
}
|
|
500
465
|
let authorVaultSlug;
|
|
501
|
-
if (opts.vaultSlug
|
|
466
|
+
if (opts.vaultSlug) {
|
|
502
467
|
authorVaultSlug = resolveVaultSlug(opts);
|
|
503
468
|
}
|
|
504
469
|
const body = {};
|
|
505
470
|
if (opts.content != null) {
|
|
506
|
-
|
|
507
|
-
if (opts.autoAttachments) {
|
|
508
|
-
const token = await getValidToken();
|
|
509
|
-
const links = extractWikiLinks(content);
|
|
510
|
-
await uploadAttachments(authorVaultSlug, links, token, { addToSyncfiles: true });
|
|
511
|
-
}
|
|
512
|
-
body.content = content;
|
|
471
|
+
body.content = readContent(opts.content);
|
|
513
472
|
}
|
|
514
473
|
if (opts.richText != null) {
|
|
515
474
|
let parsed;
|
|
@@ -542,11 +501,10 @@ export function registerSpaceCommand(program) {
|
|
|
542
501
|
.description("Edit a reply you authored in a space.")
|
|
543
502
|
.option("--content <content>", "New content for the reply (markdown supported, use \"-\" for stdin)")
|
|
544
503
|
.option("--rich-text <richText>", "Rich-text JSON array (mutually exclusive with --content)")
|
|
545
|
-
.option("--
|
|
546
|
-
.option("--vault-slug <vaultSlug>", "Attribute the reply to this vault (sets authorVaultSlug). Also used as upload destination for --auto-attachments.")
|
|
504
|
+
.option("--vault-slug <vaultSlug>", "Attribute the reply to this vault (sets authorVaultSlug). Caller must own the vault.")
|
|
547
505
|
.option("--space-slug <spaceSlug>", "Space slug (overrides .gobi/settings.yaml)")
|
|
548
506
|
.action(async (replyId, opts) => {
|
|
549
|
-
const wantsVaultChange = !!
|
|
507
|
+
const wantsVaultChange = !!opts.vaultSlug;
|
|
550
508
|
if (opts.content == null && opts.richText == null && !wantsVaultChange) {
|
|
551
509
|
throw new Error("Provide at least --content, --rich-text, or --vault-slug to update.");
|
|
552
510
|
}
|
|
@@ -555,18 +513,12 @@ export function registerSpaceCommand(program) {
|
|
|
555
513
|
}
|
|
556
514
|
const spaceSlug = resolveSpaceSlug(space, opts);
|
|
557
515
|
let authorVaultSlug;
|
|
558
|
-
if (opts.vaultSlug
|
|
516
|
+
if (opts.vaultSlug) {
|
|
559
517
|
authorVaultSlug = resolveVaultSlug(opts);
|
|
560
518
|
}
|
|
561
519
|
const body = {};
|
|
562
520
|
if (opts.content != null) {
|
|
563
|
-
|
|
564
|
-
if (opts.autoAttachments) {
|
|
565
|
-
const token = await getValidToken();
|
|
566
|
-
const links = extractWikiLinks(content);
|
|
567
|
-
await uploadAttachments(authorVaultSlug, links, token, { addToSyncfiles: true });
|
|
568
|
-
}
|
|
569
|
-
body.content = content;
|
|
521
|
+
body.content = readContent(opts.content);
|
|
570
522
|
}
|
|
571
523
|
if (opts.richText != null) {
|
|
572
524
|
let parsed;
|
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.25"
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# gobi-artifact
|
|
16
|
+
|
|
17
|
+
Gobi artifact commands for versioned, post-attachable creations (v2.0.25).
|
|
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.25"
|
|
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.25).
|
|
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.25"
|
|
14
14
|
---
|
|
15
15
|
|
|
16
16
|
# gobi-media
|
|
17
17
|
|
|
18
|
-
Gobi media generation commands (v2.0.
|
|
18
|
+
Gobi media generation commands (v2.0.25).
|
|
19
19
|
|
|
20
20
|
Requires gobi-cli installed and authenticated. See gobi-core skill for setup.
|
|
21
21
|
|
|
@@ -7,12 +7,12 @@ description: >-
|
|
|
7
7
|
allowed-tools: Bash(gobi:*)
|
|
8
8
|
metadata:
|
|
9
9
|
author: gobi-ai
|
|
10
|
-
version: "2.0.
|
|
10
|
+
version: "2.0.25"
|
|
11
11
|
---
|
|
12
12
|
|
|
13
13
|
# gobi-sense
|
|
14
14
|
|
|
15
|
-
Gobi sense commands for activity and transcription data (v2.0.
|
|
15
|
+
Gobi sense commands for activity and transcription data (v2.0.25).
|
|
16
16
|
|
|
17
17
|
Requires gobi-cli installed and authenticated. See the **gobi-core** skill for setup.
|
|
18
18
|
|