@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/global.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { WEB_BASE_URL } from "../constants.js";
|
|
2
2
|
import { apiGet, apiPost, apiPatch, apiDelete } from "../client.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { getValidToken } from "../auth/manager.js";
|
|
3
|
+
import { isJsonMode, jsonOut, readStdin, resolveVaultSlug, unwrapResp, } from "./utils.js";
|
|
4
|
+
import { uploadPostAttachments, assertPostAttachmentMix, } from "../attachments.js";
|
|
6
5
|
function readContent(value) {
|
|
7
6
|
if (value === "-")
|
|
8
7
|
return readStdin();
|
|
@@ -188,48 +187,29 @@ export function registerGlobalCommand(program) {
|
|
|
188
187
|
// ── Create post ──
|
|
189
188
|
global
|
|
190
189
|
.command("create-post")
|
|
191
|
-
.description("Create a post in the global feed. --vault-slug attributes it to a vault you own. With no --vault-slug
|
|
190
|
+
.description("Create a post in the global feed. --vault-slug attributes it to a vault you own. With no --vault-slug, the post is created without an authorVaultSlug (vault-less personal post).")
|
|
192
191
|
.option("--title <title>", "Title of the post")
|
|
193
192
|
.option("--content <content>", "Post content (markdown supported, use \"-\" for stdin)")
|
|
194
193
|
.option("--rich-text <richText>", "Rich-text JSON array (mutually exclusive with --content)")
|
|
195
194
|
.option("--vault-slug <vaultSlug>", "Attribute the post to this vault (sets authorVaultSlug). Caller must own the vault.")
|
|
196
|
-
.option("--auto-attachments", "Upload wiki-linked [[files]] to webdrive before posting (also sets authorVaultSlug to that vault)")
|
|
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.")
|
|
198
195
|
.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
196
|
.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.")
|
|
200
197
|
.action(async (opts) => {
|
|
201
|
-
if (opts.
|
|
202
|
-
|
|
203
|
-
throw new Error("--draft-id sources title and content from the draft; --title, --content, and --rich-text are not allowed alongside it.");
|
|
204
|
-
}
|
|
198
|
+
if (!opts.content && !opts.richText) {
|
|
199
|
+
throw new Error("Provide either --content or --rich-text.");
|
|
205
200
|
}
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
throw new Error("Provide either --content or --rich-text (or --draft-id).");
|
|
209
|
-
}
|
|
210
|
-
if (opts.content && opts.richText) {
|
|
211
|
-
throw new Error("--content and --rich-text are mutually exclusive.");
|
|
212
|
-
}
|
|
201
|
+
if (opts.content && opts.richText) {
|
|
202
|
+
throw new Error("--content and --rich-text are mutually exclusive.");
|
|
213
203
|
}
|
|
214
|
-
const draft = opts.draftId ? await fetchDraftSummary(opts.draftId) : null;
|
|
215
|
-
const effectiveTitle = draft ? draft.title : opts.title;
|
|
216
|
-
const effectiveContent = draft ? draft.content : opts.content;
|
|
217
|
-
const effectiveVaultSlugOpt = opts.vaultSlug ?? draft?.vaultSlug ?? undefined;
|
|
218
204
|
let authorVaultSlug;
|
|
219
|
-
if (
|
|
220
|
-
authorVaultSlug = resolveVaultSlug({ vaultSlug:
|
|
205
|
+
if (opts.vaultSlug) {
|
|
206
|
+
authorVaultSlug = resolveVaultSlug({ vaultSlug: opts.vaultSlug });
|
|
221
207
|
}
|
|
222
208
|
const body = {};
|
|
223
|
-
if (
|
|
224
|
-
body.title =
|
|
225
|
-
if (
|
|
226
|
-
|
|
227
|
-
if (opts.autoAttachments && authorVaultSlug) {
|
|
228
|
-
const token = await getValidToken();
|
|
229
|
-
const links = extractWikiLinks(content);
|
|
230
|
-
await uploadAttachments(authorVaultSlug, links, token, { addToSyncfiles: true });
|
|
231
|
-
}
|
|
232
|
-
body.content = content;
|
|
209
|
+
if (opts.title != null)
|
|
210
|
+
body.title = opts.title;
|
|
211
|
+
if (opts.content != null) {
|
|
212
|
+
body.content = readContent(opts.content);
|
|
233
213
|
}
|
|
234
214
|
if (opts.richText != null) {
|
|
235
215
|
let parsed;
|
|
@@ -256,19 +236,6 @@ export function registerGlobalCommand(program) {
|
|
|
256
236
|
}
|
|
257
237
|
const resp = (await apiPost(`/posts`, body));
|
|
258
238
|
const post = unwrapResp(resp);
|
|
259
|
-
if (opts.draftId && post.id != null) {
|
|
260
|
-
try {
|
|
261
|
-
await apiPatch(`/app/drafts/${opts.draftId}/metadata`, {
|
|
262
|
-
postId: typeof post.id === "number" ? post.id : Number(post.id),
|
|
263
|
-
spaceSlug: null,
|
|
264
|
-
});
|
|
265
|
-
}
|
|
266
|
-
catch (e) {
|
|
267
|
-
// Don't fail the create if linking fails — the post is live; just
|
|
268
|
-
// surface a warning so the agent can mention it.
|
|
269
|
-
console.error(`Warning: failed to link post to draft ${opts.draftId}: ${e.message}`);
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
239
|
const shareUrl = buildPersonalPostUrl(post);
|
|
273
240
|
if (isJsonMode(global)) {
|
|
274
241
|
jsonOut({ ...post, shareUrl });
|
|
@@ -278,8 +245,7 @@ export function registerGlobalCommand(program) {
|
|
|
278
245
|
` ID: ${post.id}\n` +
|
|
279
246
|
(post.title ? ` Title: ${post.title}\n` : "") +
|
|
280
247
|
` Created: ${post.createdAt}\n` +
|
|
281
|
-
` URL: ${shareUrl}`
|
|
282
|
-
(opts.draftId ? `\n Linked to draft: ${opts.draftId}` : ""));
|
|
248
|
+
` URL: ${shareUrl}`);
|
|
283
249
|
});
|
|
284
250
|
// ── Edit post ──
|
|
285
251
|
global
|
|
@@ -289,33 +255,29 @@ export function registerGlobalCommand(program) {
|
|
|
289
255
|
.option("--content <content>", "New content (markdown supported, use \"-\" for stdin)")
|
|
290
256
|
.option("--rich-text <richText>", "Rich-text JSON array (mutually exclusive with --content)")
|
|
291
257
|
.option("--vault-slug <vaultSlug>", "Attribute the post to this vault (sets authorVaultSlug).")
|
|
292
|
-
.option("--
|
|
258
|
+
.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], [])
|
|
293
259
|
.action(async (postId, opts) => {
|
|
294
|
-
const wantsVaultChange = !!
|
|
260
|
+
const wantsVaultChange = !!opts.vaultSlug;
|
|
261
|
+
const wantsAttachChange = !!(opts.attach && opts.attach.length > 0);
|
|
295
262
|
if (opts.title == null &&
|
|
296
263
|
opts.content == null &&
|
|
297
264
|
opts.richText == null &&
|
|
298
|
-
!wantsVaultChange
|
|
299
|
-
|
|
265
|
+
!wantsVaultChange &&
|
|
266
|
+
!wantsAttachChange) {
|
|
267
|
+
throw new Error("Provide at least --title, --content, --rich-text, --vault-slug, or --attach to update.");
|
|
300
268
|
}
|
|
301
269
|
if (opts.content && opts.richText) {
|
|
302
270
|
throw new Error("--content and --rich-text are mutually exclusive.");
|
|
303
271
|
}
|
|
304
272
|
let authorVaultSlug;
|
|
305
|
-
if (opts.vaultSlug
|
|
273
|
+
if (opts.vaultSlug) {
|
|
306
274
|
authorVaultSlug = resolveVaultSlug(opts);
|
|
307
275
|
}
|
|
308
276
|
const body = {};
|
|
309
277
|
if (opts.title != null)
|
|
310
278
|
body.title = opts.title;
|
|
311
279
|
if (opts.content != null) {
|
|
312
|
-
|
|
313
|
-
if (opts.autoAttachments && authorVaultSlug) {
|
|
314
|
-
const token = await getValidToken();
|
|
315
|
-
const links = extractWikiLinks(content);
|
|
316
|
-
await uploadAttachments(authorVaultSlug, links, token, { addToSyncfiles: true });
|
|
317
|
-
}
|
|
318
|
-
body.content = content;
|
|
280
|
+
body.content = readContent(opts.content);
|
|
319
281
|
}
|
|
320
282
|
if (opts.richText != null) {
|
|
321
283
|
let parsed;
|
|
@@ -329,6 +291,10 @@ export function registerGlobalCommand(program) {
|
|
|
329
291
|
}
|
|
330
292
|
if (authorVaultSlug !== undefined)
|
|
331
293
|
body.authorVaultSlug = authorVaultSlug;
|
|
294
|
+
if (opts.attach && opts.attach.length > 0) {
|
|
295
|
+
assertPostAttachmentMix(opts.attach);
|
|
296
|
+
body.attachments = await uploadPostAttachments(opts.attach);
|
|
297
|
+
}
|
|
332
298
|
const resp = (await apiPatch(`/posts/${postId}`, body));
|
|
333
299
|
const post = unwrapResp(resp);
|
|
334
300
|
if (isJsonMode(global)) {
|
|
@@ -355,8 +321,7 @@ export function registerGlobalCommand(program) {
|
|
|
355
321
|
.description("Create a reply to a post in the global feed.")
|
|
356
322
|
.option("--content <content>", "Reply content (markdown supported, use \"-\" for stdin)")
|
|
357
323
|
.option("--rich-text <richText>", "Rich-text JSON array (mutually exclusive with --content)")
|
|
358
|
-
.option("--vault-slug <vaultSlug>", "Attribute the reply to this vault (sets authorVaultSlug).
|
|
359
|
-
.option("--auto-attachments", "Upload wiki-linked [[files]] to webdrive before posting (also attributes the reply to that vault)")
|
|
324
|
+
.option("--vault-slug <vaultSlug>", "Attribute the reply to this vault (sets authorVaultSlug).")
|
|
360
325
|
.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], [])
|
|
361
326
|
.action(async (postId, opts) => {
|
|
362
327
|
if (!opts.content && !opts.richText) {
|
|
@@ -366,18 +331,12 @@ export function registerGlobalCommand(program) {
|
|
|
366
331
|
throw new Error("--content and --rich-text are mutually exclusive.");
|
|
367
332
|
}
|
|
368
333
|
let authorVaultSlug;
|
|
369
|
-
if (opts.vaultSlug
|
|
334
|
+
if (opts.vaultSlug) {
|
|
370
335
|
authorVaultSlug = resolveVaultSlug(opts);
|
|
371
336
|
}
|
|
372
337
|
const body = {};
|
|
373
338
|
if (opts.content != null) {
|
|
374
|
-
|
|
375
|
-
if (opts.autoAttachments && authorVaultSlug) {
|
|
376
|
-
const token = await getValidToken();
|
|
377
|
-
const links = extractWikiLinks(content);
|
|
378
|
-
await uploadAttachments(authorVaultSlug, links, token, { addToSyncfiles: true });
|
|
379
|
-
}
|
|
380
|
-
body.content = content;
|
|
339
|
+
body.content = readContent(opts.content);
|
|
381
340
|
}
|
|
382
341
|
if (opts.richText != null) {
|
|
383
342
|
let parsed;
|
|
@@ -408,10 +367,9 @@ export function registerGlobalCommand(program) {
|
|
|
408
367
|
.description("Edit a reply you authored in the global feed.")
|
|
409
368
|
.option("--content <content>", "New reply content (markdown supported, use \"-\" for stdin)")
|
|
410
369
|
.option("--rich-text <richText>", "Rich-text JSON array (mutually exclusive with --content)")
|
|
411
|
-
.option("--vault-slug <vaultSlug>", "Attribute the reply to this vault (sets authorVaultSlug).
|
|
412
|
-
.option("--auto-attachments", "Upload wiki-linked [[files]] to webdrive before editing (also attributes the reply to that vault)")
|
|
370
|
+
.option("--vault-slug <vaultSlug>", "Attribute the reply to this vault (sets authorVaultSlug).")
|
|
413
371
|
.action(async (replyId, opts) => {
|
|
414
|
-
const wantsVaultChange = !!
|
|
372
|
+
const wantsVaultChange = !!opts.vaultSlug;
|
|
415
373
|
if (opts.content == null && opts.richText == null && !wantsVaultChange) {
|
|
416
374
|
throw new Error("Provide at least --content, --rich-text, or --vault-slug to update.");
|
|
417
375
|
}
|
|
@@ -419,18 +377,12 @@ export function registerGlobalCommand(program) {
|
|
|
419
377
|
throw new Error("--content and --rich-text are mutually exclusive.");
|
|
420
378
|
}
|
|
421
379
|
let authorVaultSlug;
|
|
422
|
-
if (opts.vaultSlug
|
|
380
|
+
if (opts.vaultSlug) {
|
|
423
381
|
authorVaultSlug = resolveVaultSlug(opts);
|
|
424
382
|
}
|
|
425
383
|
const body = {};
|
|
426
384
|
if (opts.content != null) {
|
|
427
|
-
|
|
428
|
-
if (opts.autoAttachments && authorVaultSlug) {
|
|
429
|
-
const token = await getValidToken();
|
|
430
|
-
const links = extractWikiLinks(content);
|
|
431
|
-
await uploadAttachments(authorVaultSlug, links, token, { addToSyncfiles: true });
|
|
432
|
-
}
|
|
433
|
-
body.content = content;
|
|
385
|
+
body.content = readContent(opts.content);
|
|
434
386
|
}
|
|
435
387
|
if (opts.richText != null) {
|
|
436
388
|
let parsed;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { apiGet, apiPost, apiPatch, apiDelete } from "../client.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { getValidToken } from "../auth/manager.js";
|
|
2
|
+
import { isJsonMode, jsonOut, readStdin, resolveVaultSlug, unwrapResp, } from "./utils.js";
|
|
3
|
+
import { uploadPostAttachments, assertPostAttachmentMix, } from "../attachments.js";
|
|
5
4
|
function readContent(value) {
|
|
6
5
|
if (value === "-")
|
|
7
6
|
return readStdin();
|
|
@@ -191,43 +190,24 @@ export function registerPersonalCommand(program) {
|
|
|
191
190
|
.option("--content <content>", "Post content (markdown supported, use \"-\" for stdin)")
|
|
192
191
|
.option("--rich-text <richText>", "Rich-text JSON array (mutually exclusive with --content)")
|
|
193
192
|
.option("--vault-slug <vaultSlug>", "Attribute the post to this vault (sets authorVaultSlug). Caller must own the vault.")
|
|
194
|
-
.option("--auto-attachments", "Upload wiki-linked [[files]] to webdrive before posting (also sets authorVaultSlug to that vault)")
|
|
195
|
-
.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 via draft.metadata. The draft's vaultSlug seeds --vault-slug when not given explicitly.")
|
|
196
193
|
.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], [])
|
|
197
194
|
.option("--repost-post-id <postId>", "Wrap an existing top-level post as the embedded card on this new private post. The referenced post must be visible to you (your own personal-space post, a global-feed post, or a post in a space you're a member of). Reposting someone else's personal-space post returns 404.")
|
|
198
195
|
.action(async (opts) => {
|
|
199
|
-
if (opts.
|
|
200
|
-
|
|
201
|
-
throw new Error("--draft-id sources title and content from the draft; --title, --content, and --rich-text are not allowed alongside it.");
|
|
202
|
-
}
|
|
196
|
+
if (!opts.content && !opts.richText) {
|
|
197
|
+
throw new Error("Provide either --content or --rich-text.");
|
|
203
198
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
throw new Error("Provide either --content or --rich-text (or --draft-id).");
|
|
207
|
-
}
|
|
208
|
-
if (opts.content && opts.richText) {
|
|
209
|
-
throw new Error("--content and --rich-text are mutually exclusive.");
|
|
210
|
-
}
|
|
199
|
+
if (opts.content && opts.richText) {
|
|
200
|
+
throw new Error("--content and --rich-text are mutually exclusive.");
|
|
211
201
|
}
|
|
212
|
-
const draft = opts.draftId ? await fetchDraftSummary(opts.draftId) : null;
|
|
213
|
-
const effectiveTitle = draft ? draft.title : opts.title;
|
|
214
|
-
const effectiveContent = draft ? draft.content : opts.content;
|
|
215
|
-
const effectiveVaultSlugOpt = opts.vaultSlug ?? draft?.vaultSlug ?? undefined;
|
|
216
202
|
let authorVaultSlug;
|
|
217
|
-
if (
|
|
218
|
-
authorVaultSlug = resolveVaultSlug({ vaultSlug:
|
|
203
|
+
if (opts.vaultSlug) {
|
|
204
|
+
authorVaultSlug = resolveVaultSlug({ vaultSlug: opts.vaultSlug });
|
|
219
205
|
}
|
|
220
206
|
const body = {};
|
|
221
|
-
if (
|
|
222
|
-
body.title =
|
|
223
|
-
if (
|
|
224
|
-
|
|
225
|
-
if (opts.autoAttachments && authorVaultSlug) {
|
|
226
|
-
const token = await getValidToken();
|
|
227
|
-
const links = extractWikiLinks(content);
|
|
228
|
-
await uploadAttachments(authorVaultSlug, links, token, { addToSyncfiles: true });
|
|
229
|
-
}
|
|
230
|
-
body.content = content;
|
|
207
|
+
if (opts.title != null)
|
|
208
|
+
body.title = opts.title;
|
|
209
|
+
if (opts.content != null) {
|
|
210
|
+
body.content = readContent(opts.content);
|
|
231
211
|
}
|
|
232
212
|
if (opts.richText != null) {
|
|
233
213
|
let parsed;
|
|
@@ -254,17 +234,6 @@ export function registerPersonalCommand(program) {
|
|
|
254
234
|
}
|
|
255
235
|
const resp = (await apiPost(`/posts/personal-space`, body));
|
|
256
236
|
const post = unwrapResp(resp);
|
|
257
|
-
if (opts.draftId && post.id != null) {
|
|
258
|
-
try {
|
|
259
|
-
await apiPatch(`/app/drafts/${opts.draftId}/metadata`, {
|
|
260
|
-
postId: typeof post.id === "number" ? post.id : Number(post.id),
|
|
261
|
-
spaceSlug: null,
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
catch (e) {
|
|
265
|
-
console.error(`Warning: failed to link post to draft ${opts.draftId}: ${e.message}`);
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
237
|
if (isJsonMode(personal)) {
|
|
269
238
|
jsonOut(post);
|
|
270
239
|
return;
|
|
@@ -273,8 +242,7 @@ export function registerPersonalCommand(program) {
|
|
|
273
242
|
` ID: ${post.id}\n` +
|
|
274
243
|
(post.title ? ` Title: ${post.title}\n` : "") +
|
|
275
244
|
` Created: ${post.createdAt}\n` +
|
|
276
|
-
` Visibility: private (only you can see this)`
|
|
277
|
-
(opts.draftId ? `\n Linked to draft: ${opts.draftId}` : ""));
|
|
245
|
+
` Visibility: private (only you can see this)`);
|
|
278
246
|
});
|
|
279
247
|
// ── Edit post ──
|
|
280
248
|
//
|
|
@@ -288,33 +256,29 @@ export function registerPersonalCommand(program) {
|
|
|
288
256
|
.option("--content <content>", "New content (markdown supported, use \"-\" for stdin)")
|
|
289
257
|
.option("--rich-text <richText>", "Rich-text JSON array (mutually exclusive with --content)")
|
|
290
258
|
.option("--vault-slug <vaultSlug>", "Attribute the post to this vault (sets authorVaultSlug).")
|
|
291
|
-
.option("--
|
|
259
|
+
.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], [])
|
|
292
260
|
.action(async (postId, opts) => {
|
|
293
|
-
const wantsVaultChange = !!
|
|
261
|
+
const wantsVaultChange = !!opts.vaultSlug;
|
|
262
|
+
const wantsAttachChange = !!(opts.attach && opts.attach.length > 0);
|
|
294
263
|
if (opts.title == null &&
|
|
295
264
|
opts.content == null &&
|
|
296
265
|
opts.richText == null &&
|
|
297
|
-
!wantsVaultChange
|
|
298
|
-
|
|
266
|
+
!wantsVaultChange &&
|
|
267
|
+
!wantsAttachChange) {
|
|
268
|
+
throw new Error("Provide at least --title, --content, --rich-text, --vault-slug, or --attach to update.");
|
|
299
269
|
}
|
|
300
270
|
if (opts.content && opts.richText) {
|
|
301
271
|
throw new Error("--content and --rich-text are mutually exclusive.");
|
|
302
272
|
}
|
|
303
273
|
let authorVaultSlug;
|
|
304
|
-
if (opts.vaultSlug
|
|
274
|
+
if (opts.vaultSlug) {
|
|
305
275
|
authorVaultSlug = resolveVaultSlug(opts);
|
|
306
276
|
}
|
|
307
277
|
const body = {};
|
|
308
278
|
if (opts.title != null)
|
|
309
279
|
body.title = opts.title;
|
|
310
280
|
if (opts.content != null) {
|
|
311
|
-
|
|
312
|
-
if (opts.autoAttachments && authorVaultSlug) {
|
|
313
|
-
const token = await getValidToken();
|
|
314
|
-
const links = extractWikiLinks(content);
|
|
315
|
-
await uploadAttachments(authorVaultSlug, links, token, { addToSyncfiles: true });
|
|
316
|
-
}
|
|
317
|
-
body.content = content;
|
|
281
|
+
body.content = readContent(opts.content);
|
|
318
282
|
}
|
|
319
283
|
if (opts.richText != null) {
|
|
320
284
|
let parsed;
|
|
@@ -328,6 +292,10 @@ export function registerPersonalCommand(program) {
|
|
|
328
292
|
}
|
|
329
293
|
if (authorVaultSlug !== undefined)
|
|
330
294
|
body.authorVaultSlug = authorVaultSlug;
|
|
295
|
+
if (opts.attach && opts.attach.length > 0) {
|
|
296
|
+
assertPostAttachmentMix(opts.attach);
|
|
297
|
+
body.attachments = await uploadPostAttachments(opts.attach);
|
|
298
|
+
}
|
|
331
299
|
const resp = (await apiPatch(`/posts/${postId}`, body));
|
|
332
300
|
const post = unwrapResp(resp);
|
|
333
301
|
if (isJsonMode(personal)) {
|
|
@@ -359,8 +327,7 @@ export function registerPersonalCommand(program) {
|
|
|
359
327
|
.description("Reply to a personal-space post. The reply inherits the parent's private scope automatically.")
|
|
360
328
|
.option("--content <content>", "Reply content (markdown supported, use \"-\" for stdin)")
|
|
361
329
|
.option("--rich-text <richText>", "Rich-text JSON array (mutually exclusive with --content)")
|
|
362
|
-
.option("--vault-slug <vaultSlug>", "Attribute the reply to this vault (sets authorVaultSlug).
|
|
363
|
-
.option("--auto-attachments", "Upload wiki-linked [[files]] to webdrive before posting (also attributes the reply to that vault)")
|
|
330
|
+
.option("--vault-slug <vaultSlug>", "Attribute the reply to this vault (sets authorVaultSlug).")
|
|
364
331
|
.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], [])
|
|
365
332
|
.action(async (postId, opts) => {
|
|
366
333
|
if (!opts.content && !opts.richText) {
|
|
@@ -370,18 +337,12 @@ export function registerPersonalCommand(program) {
|
|
|
370
337
|
throw new Error("--content and --rich-text are mutually exclusive.");
|
|
371
338
|
}
|
|
372
339
|
let authorVaultSlug;
|
|
373
|
-
if (opts.vaultSlug
|
|
340
|
+
if (opts.vaultSlug) {
|
|
374
341
|
authorVaultSlug = resolveVaultSlug(opts);
|
|
375
342
|
}
|
|
376
343
|
const body = {};
|
|
377
344
|
if (opts.content != null) {
|
|
378
|
-
|
|
379
|
-
if (opts.autoAttachments && authorVaultSlug) {
|
|
380
|
-
const token = await getValidToken();
|
|
381
|
-
const links = extractWikiLinks(content);
|
|
382
|
-
await uploadAttachments(authorVaultSlug, links, token, { addToSyncfiles: true });
|
|
383
|
-
}
|
|
384
|
-
body.content = content;
|
|
345
|
+
body.content = readContent(opts.content);
|
|
385
346
|
}
|
|
386
347
|
if (opts.richText != null) {
|
|
387
348
|
let parsed;
|
|
@@ -412,10 +373,9 @@ export function registerPersonalCommand(program) {
|
|
|
412
373
|
.description("Edit a reply you authored in your personal space.")
|
|
413
374
|
.option("--content <content>", "New reply content (markdown supported, use \"-\" for stdin)")
|
|
414
375
|
.option("--rich-text <richText>", "Rich-text JSON array (mutually exclusive with --content)")
|
|
415
|
-
.option("--vault-slug <vaultSlug>", "Attribute the reply to this vault (sets authorVaultSlug).
|
|
416
|
-
.option("--auto-attachments", "Upload wiki-linked [[files]] to webdrive before editing (also attributes the reply to that vault)")
|
|
376
|
+
.option("--vault-slug <vaultSlug>", "Attribute the reply to this vault (sets authorVaultSlug).")
|
|
417
377
|
.action(async (replyId, opts) => {
|
|
418
|
-
const wantsVaultChange = !!
|
|
378
|
+
const wantsVaultChange = !!opts.vaultSlug;
|
|
419
379
|
if (opts.content == null && opts.richText == null && !wantsVaultChange) {
|
|
420
380
|
throw new Error("Provide at least --content, --rich-text, or --vault-slug to update.");
|
|
421
381
|
}
|
|
@@ -423,18 +383,12 @@ export function registerPersonalCommand(program) {
|
|
|
423
383
|
throw new Error("--content and --rich-text are mutually exclusive.");
|
|
424
384
|
}
|
|
425
385
|
let authorVaultSlug;
|
|
426
|
-
if (opts.vaultSlug
|
|
386
|
+
if (opts.vaultSlug) {
|
|
427
387
|
authorVaultSlug = resolveVaultSlug(opts);
|
|
428
388
|
}
|
|
429
389
|
const body = {};
|
|
430
390
|
if (opts.content != null) {
|
|
431
|
-
|
|
432
|
-
if (opts.autoAttachments && authorVaultSlug) {
|
|
433
|
-
const token = await getValidToken();
|
|
434
|
-
const links = extractWikiLinks(content);
|
|
435
|
-
await uploadAttachments(authorVaultSlug, links, token, { addToSyncfiles: true });
|
|
436
|
-
}
|
|
437
|
-
body.content = content;
|
|
391
|
+
body.content = readContent(opts.content);
|
|
438
392
|
}
|
|
439
393
|
if (opts.richText != null) {
|
|
440
394
|
let parsed;
|