@autoposting.ai/cli 0.3.5 → 0.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs CHANGED
@@ -79,7 +79,7 @@ var VERSION, AutopostingError, AuthenticationError, ScopeError, NotFoundError, V
79
79
  var init_dist = __esm({
80
80
  "../sdk/dist/index.mjs"() {
81
81
  "use strict";
82
- VERSION = "0.3.5";
82
+ VERSION = "0.3.6";
83
83
  AutopostingError = class extends Error {
84
84
  status;
85
85
  code;
@@ -298,8 +298,16 @@ var init_dist = __esm({
298
298
  return this.client.request("POST", "/clips/import-url", params);
299
299
  }
300
300
  /** POST /clips/:id/render — backend returns render job ids, not a Clip. */
301
- render(id) {
302
- return this.client.request("POST", `/clips/${id}/render`);
301
+ async render(id, params = {}) {
302
+ const editRevision = params.editRevision ?? (await this.retrieve(id)).editRevision ?? 0;
303
+ return this.client.request("POST", `/clips/${id}/render`, {
304
+ editRevision,
305
+ ...params.candidateId ? { candidateId: params.candidateId } : {}
306
+ });
307
+ }
308
+ /** POST /clips/:id/create-draft — turns a rendered clip into a draft post. */
309
+ createDraft(id, params = {}) {
310
+ return this.client.request("POST", `/clips/${id}/create-draft`, params);
303
311
  }
304
312
  remove(id) {
305
313
  return this.client.request("DELETE", `/clips/${id}`);
@@ -656,10 +664,25 @@ var init_dist = __esm({
656
664
  });
657
665
 
658
666
  // src/mcp/tools.ts
659
- var ALL_TOOLS;
667
+ var MEDIA_ITEMS, ALL_TOOLS;
660
668
  var init_tools = __esm({
661
669
  "src/mcp/tools.ts"() {
662
670
  "use strict";
671
+ MEDIA_ITEMS = {
672
+ type: "array",
673
+ maxItems: 10,
674
+ description: "Images or videos to attach, as public https URLs. To attach a local file, use `ap posts create --media <file>` instead.",
675
+ items: {
676
+ type: "object",
677
+ properties: {
678
+ url: { type: "string", description: "Public https URL of the image or video" },
679
+ type: { type: "string", enum: ["image", "video", "gif"] },
680
+ altText: { type: "string", description: "Optional alt text" }
681
+ },
682
+ required: ["url", "type"],
683
+ additionalProperties: false
684
+ }
685
+ };
663
686
  ALL_TOOLS = [
664
687
  // Posts
665
688
  {
@@ -707,7 +730,8 @@ var init_tools = __esm({
707
730
  scheduledAt: {
708
731
  type: "string",
709
732
  description: "ISO 8601 datetime to schedule the post"
710
- }
733
+ },
734
+ media: MEDIA_ITEMS
711
735
  },
712
736
  required: ["brandSlug", "text", "platforms"],
713
737
  additionalProperties: false
@@ -715,14 +739,15 @@ var init_tools = __esm({
715
739
  },
716
740
  {
717
741
  name: "update-post",
718
- description: "Update the text, platforms, or scheduled time of an existing post.",
742
+ description: "Update the text, platforms, scheduled time, or media of an existing post.",
719
743
  inputSchema: {
720
744
  type: "object",
721
745
  properties: {
722
746
  id: { type: "string", description: "Post ID" },
723
747
  text: { type: "string", description: "New post text" },
724
748
  platforms: { type: "string", description: "Comma-separated new platform list" },
725
- scheduledAt: { type: "string", description: "New ISO 8601 scheduled datetime" }
749
+ scheduledAt: { type: "string", description: "New ISO 8601 scheduled datetime" },
750
+ media: MEDIA_ITEMS
726
751
  },
727
752
  required: ["id"],
728
753
  additionalProperties: false
@@ -1156,24 +1181,41 @@ var init_tools = __esm({
1156
1181
  },
1157
1182
  {
1158
1183
  name: "import-clip",
1159
- description: "Import a video clip from a remote URL.",
1184
+ description: "Start AI clipping: import a long video from a public URL (e.g. a YouTube video). Poll get-clip until status is ready.",
1160
1185
  inputSchema: {
1161
1186
  type: "object",
1162
1187
  properties: {
1163
1188
  url: { type: "string", description: "URL of the video to import" },
1189
+ brandId: { type: "string", description: "Brand ID (the `id` from list-brands)" },
1164
1190
  name: { type: "string", description: "Optional name for the imported clip" }
1165
1191
  },
1166
- required: ["url"],
1192
+ required: ["url", "brandId"],
1167
1193
  additionalProperties: false
1168
1194
  }
1169
1195
  },
1170
1196
  {
1171
1197
  name: "render-clip",
1172
- description: "Trigger rendering for a video clip.",
1198
+ description: "Render a clip (uses credits). Call get-clip first for its editRevision and candidates.",
1199
+ inputSchema: {
1200
+ type: "object",
1201
+ properties: {
1202
+ id: { type: "string", description: "Clip ID to render" },
1203
+ editRevision: { type: "number", description: "Current editRevision from get-clip" },
1204
+ candidateId: { type: "string", description: "Optional: render only this candidate" }
1205
+ },
1206
+ required: ["id", "editRevision"],
1207
+ additionalProperties: false
1208
+ }
1209
+ },
1210
+ {
1211
+ name: "create-clip-draft",
1212
+ description: "Create a draft post from a rendered clip. Publish it with publish-post or schedule it.",
1173
1213
  inputSchema: {
1174
1214
  type: "object",
1175
1215
  properties: {
1176
- id: { type: "string", description: "Clip ID to render" }
1216
+ id: { type: "string", description: "Clip ID" },
1217
+ candidateId: { type: "string", description: "Optional candidate ID (defaults to the first rendered one)" },
1218
+ aspectRatio: { type: "string", enum: ["9:16", "16:9", "1:1", "4:5"], description: "Optional render format" }
1177
1219
  },
1178
1220
  required: ["id"],
1179
1221
  additionalProperties: false
@@ -1424,7 +1466,8 @@ async function dispatchToolCall(name, args, client) {
1424
1466
  brandSlug: args.brandSlug,
1425
1467
  text: args.text,
1426
1468
  platforms: parsePlatforms2(args.platforms),
1427
- ...args.scheduledAt ? { scheduledAt: args.scheduledAt } : {}
1469
+ ...args.scheduledAt ? { scheduledAt: args.scheduledAt } : {},
1470
+ ...args.media ? { media: args.media } : {}
1428
1471
  });
1429
1472
  return ok(result);
1430
1473
  }
@@ -1434,7 +1477,8 @@ async function dispatchToolCall(name, args, client) {
1434
1477
  ...args.platforms ? {
1435
1478
  platforms: parsePlatforms2(args.platforms)
1436
1479
  } : {},
1437
- ...args.scheduledAt ? { scheduledAt: args.scheduledAt } : {}
1480
+ ...args.scheduledAt ? { scheduledAt: args.scheduledAt } : {},
1481
+ ...args.media ? { media: args.media } : {}
1438
1482
  });
1439
1483
  return ok(result);
1440
1484
  }
@@ -1622,12 +1666,23 @@ async function dispatchToolCall(name, args, client) {
1622
1666
  case "import-clip": {
1623
1667
  const result = await client.clips.importUrl({
1624
1668
  url: args.url,
1625
- ...args.name ? { name: args.name } : {}
1669
+ brandId: args.brandId,
1670
+ ...args.name ? { title: args.name } : {}
1626
1671
  });
1627
1672
  return ok(result);
1628
1673
  }
1629
1674
  case "render-clip": {
1630
- const result = await client.clips.render(args.id);
1675
+ const result = await client.clips.render(args.id, {
1676
+ editRevision: args.editRevision,
1677
+ ...args.candidateId ? { candidateId: args.candidateId } : {}
1678
+ });
1679
+ return ok(result);
1680
+ }
1681
+ case "create-clip-draft": {
1682
+ const result = await client.clips.createDraft(args.id, {
1683
+ ...args.candidateId ? { candidateId: args.candidateId } : {},
1684
+ ...args.aspectRatio ? { aspectRatio: args.aspectRatio } : {}
1685
+ });
1631
1686
  return ok(result);
1632
1687
  }
1633
1688
  case "delete-clip": {
@@ -3118,16 +3173,18 @@ function createClipsCommand() {
3118
3173
  process.exit(resolveExitCode4(err));
3119
3174
  }
3120
3175
  });
3121
- clips.command("import").description("Import a clip from a URL").requiredOption("--url <url>", "URL of the video to import").option("--name <name>", "Name for the imported clip").action(async (opts, cmd) => {
3176
+ clips.command("import").description("Start AI clipping from a video URL (e.g. a YouTube video)").requiredOption("--url <url>", "URL of the video to import").option("--brand <id>", "Brand ID (auto-picked when the workspace has exactly one brand)").option("--name <name>", "Name for the imported clip").action(async (opts, cmd) => {
3122
3177
  const globals = cmd.optsWithGlobals();
3123
3178
  const printer = createPrinter(globals);
3124
3179
  const spinner = printer.spinner("Importing clip\u2026");
3125
3180
  try {
3126
3181
  const cred = resolveAuth({ apiKey: globals.apiKey });
3127
3182
  const client = new Autoposting({ apiKey: cred.apiKey });
3183
+ const brandId = await resolveBrandId(client, opts.brand);
3128
3184
  const { clipId } = await client.clips.importUrl({
3129
3185
  url: opts.url,
3130
- ...opts.name ? { name: opts.name } : {}
3186
+ brandId,
3187
+ ...opts.name ? { title: opts.name } : {}
3131
3188
  });
3132
3189
  spinner.stop();
3133
3190
  printer.log({ clipId });
@@ -3137,14 +3194,17 @@ function createClipsCommand() {
3137
3194
  process.exit(resolveExitCode4(err));
3138
3195
  }
3139
3196
  });
3140
- clips.command("render <id>").description("Trigger rendering for a clip").action(async (id, _opts, cmd) => {
3197
+ clips.command("render <id>").description("Render a clip (uses credits)").option("--candidate <id>", "Render only this candidate").option("--revision <n>", "Clip editRevision (read from the clip when omitted)", (v) => Number(v)).action(async (id, opts, cmd) => {
3141
3198
  const globals = cmd.optsWithGlobals();
3142
3199
  const printer = createPrinter(globals);
3143
3200
  const spinner = printer.spinner(`Rendering clip "${id}"\u2026`);
3144
3201
  try {
3145
3202
  const cred = resolveAuth({ apiKey: globals.apiKey });
3146
3203
  const client = new Autoposting({ apiKey: cred.apiKey });
3147
- const { jobIds, activeJobIds, reusedJobIds } = await client.clips.render(id);
3204
+ const { jobIds, activeJobIds, reusedJobIds } = await client.clips.render(id, {
3205
+ ...opts.revision !== void 0 ? { editRevision: opts.revision } : {},
3206
+ ...opts.candidate ? { candidateId: opts.candidate } : {}
3207
+ });
3148
3208
  spinner.stop();
3149
3209
  printer.log({ jobIds, activeJobIds, reusedJobIds });
3150
3210
  } catch (err) {
@@ -3153,6 +3213,25 @@ function createClipsCommand() {
3153
3213
  process.exit(resolveExitCode4(err));
3154
3214
  }
3155
3215
  });
3216
+ clips.command("draft <id>").description("Create a draft post from a rendered clip").option("--candidate <id>", "Candidate to use (defaults to the first rendered one)").option("--aspect-ratio <ratio>", "Render format: 9:16, 16:9, 1:1 or 4:5").action(async (id, opts, cmd) => {
3217
+ const globals = cmd.optsWithGlobals();
3218
+ const printer = createPrinter(globals);
3219
+ const spinner = printer.spinner(`Creating draft from clip "${id}"\u2026`);
3220
+ try {
3221
+ const cred = resolveAuth({ apiKey: globals.apiKey });
3222
+ const client = new Autoposting({ apiKey: cred.apiKey });
3223
+ const { postId } = await client.clips.createDraft(id, {
3224
+ ...opts.candidate ? { candidateId: opts.candidate } : {},
3225
+ ...opts.aspectRatio ? { aspectRatio: opts.aspectRatio } : {}
3226
+ });
3227
+ spinner.stop();
3228
+ printer.log({ postId });
3229
+ } catch (err) {
3230
+ spinner.fail();
3231
+ printer.error(err);
3232
+ process.exit(resolveExitCode4(err));
3233
+ }
3234
+ });
3156
3235
  clips.command("delete <id>").description("Delete a clip (requires --force)").option("--force", "Confirm deletion without interactive prompt").action(async (id, opts, cmd) => {
3157
3236
  const globals = cmd.optsWithGlobals();
3158
3237
  const printer = createPrinter(globals);