@rolino/cli 0.3.0 → 0.5.0-beta.0

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/bin.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runCli
4
- } from "./chunk-7BCIIFUB.js";
4
+ } from "./chunk-TFNGSKT3.js";
5
5
 
6
6
  // src/bin.ts
7
7
  void runCli().then(
@@ -277,7 +277,7 @@ async function setupMcp(options) {
277
277
  // src/cli.ts
278
278
  import { randomUUID } from "crypto";
279
279
  import { openAsBlob } from "fs";
280
- import { stat } from "fs/promises";
280
+ import { readFile as readFile2, stat } from "fs/promises";
281
281
  import { basename, extname, resolve as resolve2 } from "path";
282
282
  import { createInterface } from "readline/promises";
283
283
  import { Command, CommanderError, InvalidArgumentError } from "commander";
@@ -285,7 +285,7 @@ import { Command, CommanderError, InvalidArgumentError } from "commander";
285
285
  // package.json
286
286
  var package_default = {
287
287
  name: "@rolino/cli",
288
- version: "0.3.0",
288
+ version: "0.5.0-beta.0",
289
289
  description: "Agent-friendly command-line interface for Rolino",
290
290
  type: "module",
291
291
  license: "MIT",
@@ -342,9 +342,9 @@ var package_default = {
342
342
  dev: "tsx src/bin.ts"
343
343
  },
344
344
  dependencies: {
345
- "@rolino/contracts": "0.3.0",
346
- "@rolino/local-auth": "0.3.0",
347
- "@rolino/sdk": "0.3.0",
345
+ "@rolino/contracts": "0.5.0-beta.0",
346
+ "@rolino/local-auth": "0.5.0-beta.0",
347
+ "@rolino/sdk": "0.5.0-beta.0",
348
348
  commander: "^15.0.0",
349
349
  open: "^11.0.0"
350
350
  },
@@ -359,10 +359,14 @@ var package_default = {
359
359
  // src/cli.ts
360
360
  import {
361
361
  PostStatusSchema,
362
+ AgentBlogDraftUpdateSchema,
362
363
  ProjectCreateInputSchema,
363
364
  ProjectTypeSchema,
364
365
  ProviderDeliveryOptionsProviderSchema,
365
366
  PublishingProviderSchema,
367
+ SeoOpportunityKindSchema,
368
+ SeoExpectedImpactSchema,
369
+ SeoReportCompletenessSchema,
366
370
  TikTokDraftSettingsSchema,
367
371
  YouTubePostSettingsSchema
368
372
  } from "@rolino/contracts";
@@ -718,7 +722,6 @@ function formatPosts(data) {
718
722
  return ["ID STATUS SCHEDULED CAPTION", ...rows].join("\n");
719
723
  }
720
724
  function formatPost(post) {
721
- const queued = post.status === "PUBLISHING";
722
725
  return [
723
726
  `Post ${post.id}`,
724
727
  `Project: ${post.projectId}`,
@@ -727,11 +730,11 @@ function formatPost(post) {
727
730
  `Caption: ${post.caption || "-"}`,
728
731
  ...post.campaign ? [`Campaign: ${post.campaign.title} (${post.campaign.id})`] : [],
729
732
  ...post.scheduledAt ? [
730
- `${queued ? "Queued for publishing" : "Scheduled"}: ${post.scheduledAt}${post.timezone ? ` (${post.timezone})` : ""}`
733
+ `Scheduled: ${post.scheduledAt}${post.timezone ? ` (${post.timezone})` : ""}`
731
734
  ] : [],
732
735
  ...post.publishedAt ? [`Published: ${post.publishedAt}`] : [],
733
736
  `Media: ${post.media.length}`,
734
- `Destinations: ${post.destinations.map((destination) => `${destination.provider}:${queued && destination.status === "SCHEDULED" ? "QUEUED" : destination.status}`).join(", ") || "none"}`,
737
+ `Destinations: ${post.destinations.map((destination) => `${destination.provider}:${destination.deliveryMode}:${destination.stage}`).join(", ") || "none"}`,
735
738
  ...post.providerSettings?.TIKTOK ? [
736
739
  `TikTok: ${post.providerSettings.TIKTOK.postMode}, ${post.providerSettings.TIKTOK.privacyLevel ?? "visibility not set"}, settings ${post.providerSettings.TIKTOK.consentedAt ? "reviewed" : "not reviewed"}`
737
740
  ] : [],
@@ -742,7 +745,8 @@ function formatPost(post) {
742
745
  }
743
746
  function formatPostSchedulePending(pending) {
744
747
  return [
745
- `YouTube schedule change pending for post ${pending.postId}.`,
748
+ `YouTube publish-time confirmation pending for post ${pending.postId}.`,
749
+ "Video upload: complete (the video remains private).",
746
750
  pending.message,
747
751
  `Mutation: ${pending.mutationId}`
748
752
  ].join("\n");
@@ -769,7 +773,8 @@ function formatProviderDeliveryOptions(options) {
769
773
  `Checked: ${options.checkedAt}`,
770
774
  `Health: ${options.health.status} (${options.health.code}) ${options.health.message}`,
771
775
  `Post types: ${options.supportedPostTypes.join(", ")}`,
772
- `Images: up to ${options.image.maxItems}; ${options.image.mimeTypes.join(", ")}; under ${options.image.maxPixelsExclusive.toLocaleString()} pixels`
776
+ `Images: up to ${options.image.maxItems}; ${options.image.mimeTypes.join(", ")}; under ${options.image.maxPixelsExclusive.toLocaleString()} pixels`,
777
+ `Video: one ${options.video.mimeTypes.join(", ")}; ${options.video.minDurationMs / 1e3}s to ${options.video.maxDurationMs / 6e4}m; ${options.video.minBytes.toLocaleString()} to ${options.video.maxBytes.toLocaleString()} bytes`
773
778
  ].join("\n");
774
779
  }
775
780
  }
@@ -787,8 +792,14 @@ function formatPostSchedulePreview(preview) {
787
792
  return [
788
793
  `Schedule preview for post ${preview.post.id}`,
789
794
  `Current version: ${preview.post.version}`,
795
+ `Delivery mode: ${preview.deliveryMode}`,
790
796
  `Publish at: ${preview.schedule.scheduledAt} (${preview.schedule.timezone})`,
791
797
  `Destinations: ${preview.destinations.join(", ")}`,
798
+ ...preview.youtube ? [
799
+ "YouTube preparation: starts immediately as PRIVATE.",
800
+ `YouTube scheduled visibility: ${preview.youtube.publishVisibility}.`,
801
+ `YouTube confirmation: ${preview.youtube.confirmationMeaning}`
802
+ ] : [],
792
803
  ...preview.providerReconciliation ? [`Provider reconciliation: ${preview.providerReconciliation.message}`] : [],
793
804
  `Confirmation expires: ${preview.confirmation.expiresAt}`,
794
805
  `Confirmation token: ${preview.confirmation.token}`,
@@ -800,9 +811,10 @@ function formatPostPublishPreview(preview) {
800
811
  return [
801
812
  `Immediate publish preview for post ${preview.post.id}`,
802
813
  `Current version: ${preview.post.version}`,
814
+ `Delivery mode: ${preview.deliveryMode}`,
803
815
  `Destinations: ${preview.destinations.join(", ")}`,
804
816
  "Effect: confirmed execution queues these destinations for immediate publishing.",
805
- ...preview.destinations.includes("YOUTUBE") ? ["YouTube effect: execution starts a resumable upload; PREPARING remains visible until upload, processing, and configured visibility are provider-confirmed."] : [],
817
+ ...preview.youtube ? [`YouTube effect: execution starts a resumable upload using ${preview.youtube.visibility}; it does not create a schedule. PREPARING remains visible until upload, processing, and visibility are provider-confirmed.`] : [],
806
818
  `Confirmation expires: ${preview.confirmation.expiresAt}`,
807
819
  `Confirmation token: ${preview.confirmation.token}`,
808
820
  ...attention.length ? ["Readiness notes:", ...attention.map((check) => `${check.status.toUpperCase()} ${check.provider ?? "POST"} ${check.code} ${check.message}`)] : ["All required readiness checks passed."]
@@ -815,6 +827,65 @@ function formatCalendarEvents(data) {
815
827
  const rows = data.items.map((event) => `${event.postId} ${event.scheduledAt} ${event.status} ${event.destinations.map((item) => item.provider).join(",") || "-"} ${event.title}`);
816
828
  return ["POST ID SCHEDULED STATUS DESTINATIONS TITLE", ...rows].join("\n");
817
829
  }
830
+ function formatSeoOpportunities(data) {
831
+ if (!data.items.length) return "No active SEO tasks found.";
832
+ return [
833
+ "ID DECISION FORMAT SCORE TOPIC RELEVANCE ACTION READINESS TITLE",
834
+ ...data.items.map((item) => `${item.id} ${item.task.decision} ${item.task.primaryFormat} ${item.score} ${item.confidence.topicRelevance.label} ${item.confidence.actionReadiness.label} ${item.title}`)
835
+ ].join("\n");
836
+ }
837
+ function formatSeoOpportunity(opportunity) {
838
+ return [
839
+ `${opportunity.title} (${opportunity.id})`,
840
+ `Project: ${opportunity.projectId}`,
841
+ `Decision: ${opportunity.task.decision}`,
842
+ `Primary format: ${opportunity.task.primaryFormat}`,
843
+ `Objective: ${opportunity.task.objective}`,
844
+ `Next step: ${opportunity.task.nextStep}`,
845
+ `Priority: ${opportunity.score}/100`,
846
+ `Topic relevance: ${opportunity.confidence.topicRelevance.label}${opportunity.confidence.topicRelevance.score === null ? "" : ` (${opportunity.confidence.topicRelevance.score}/100)`}`,
847
+ `Topic relevance explanation: ${opportunity.confidence.topicRelevance.explanation}`,
848
+ `Action readiness: ${opportunity.confidence.actionReadiness.label}${opportunity.confidence.actionReadiness.score === null ? "" : ` (${opportunity.confidence.actionReadiness.score}/100)`}`,
849
+ `Action readiness explanation: ${opportunity.confidence.actionReadiness.explanation}`,
850
+ "",
851
+ opportunity.brief
852
+ ].join("\n");
853
+ }
854
+ function formatSeoReports(data) {
855
+ if (!data.items.length) return "No weekly SEO reports found.";
856
+ return [
857
+ "ID PERIOD START PERIOD END STATUS READY RESEARCH REJECTED LEGACY",
858
+ ...data.items.map((item) => `${item.id} ${item.periodStart} ${item.periodEnd} ${item.completeness} ${item.readyTaskCount} ${item.researchTaskCount} ${item.rejectedFindingCount} ${item.legacy}`)
859
+ ].join("\n");
860
+ }
861
+ function formatSeoReport(report) {
862
+ return [
863
+ `Weekly SEO report ${report.id}`,
864
+ `Project: ${report.projectId}`,
865
+ `Period: ${report.periodStart} to ${report.periodEnd}`,
866
+ `Schedule: day ${report.deliveryDay} in ${report.timeZone}`,
867
+ `Status: ${report.completeness}`,
868
+ ...report.partialLabel ? [`Note: ${report.partialLabel}`] : [],
869
+ `Ready tasks: ${report.readyTaskCount}`,
870
+ `Research tasks: ${report.researchTaskCount}`,
871
+ `Rejected or filtered findings: ${report.rejectedFindingCount}`,
872
+ `Legacy report: ${report.legacy}`,
873
+ "",
874
+ ...report.opportunities.flatMap((item, index) => [
875
+ `${index + 1}. ${item.title}`,
876
+ ` Decision: ${item.task.decision}`,
877
+ ` Format: ${item.task.primaryFormat}`,
878
+ ` Objective: ${item.task.objective}`,
879
+ ` Next step: ${item.task.nextStep}`,
880
+ ` Topic relevance: ${item.confidence.topicRelevance.label}${item.confidence.topicRelevance.score === null ? "" : ` (${item.confidence.topicRelevance.score}/100)`}`,
881
+ ` Action readiness: ${item.confidence.actionReadiness.label}${item.confidence.actionReadiness.score === null ? "" : ` (${item.confidence.actionReadiness.score}/100)`}`
882
+ ]),
883
+ ...report.rejectedFindings.flatMap((item, index) => [
884
+ `Rejected ${index + 1}: ${item.query}`,
885
+ ` Reason: ${item.reason}`
886
+ ])
887
+ ].join("\n");
888
+ }
818
889
 
819
890
  // src/cli.ts
820
891
  var ROLINO_CLI_VERSION = package_default.version;
@@ -847,6 +918,21 @@ function postStatus(value) {
847
918
  `Status must be one of ${PostStatusSchema.options.join(", ")}.`
848
919
  );
849
920
  }
921
+ function seoOpportunityKind(value) {
922
+ const parsed = SeoOpportunityKindSchema.safeParse(value.toUpperCase());
923
+ if (parsed.success) return parsed.data;
924
+ throw new InvalidArgumentError(`SEO kind must be one of ${SeoOpportunityKindSchema.options.join(", ")}.`);
925
+ }
926
+ function seoExpectedImpact(value) {
927
+ const parsed = SeoExpectedImpactSchema.safeParse(value.toUpperCase());
928
+ if (parsed.success) return parsed.data;
929
+ throw new InvalidArgumentError("SEO impact must be HIGH, MEDIUM, or LOW.");
930
+ }
931
+ function seoReportCompleteness(value) {
932
+ const parsed = SeoReportCompletenessSchema.safeParse(value.toUpperCase());
933
+ if (parsed.success) return parsed.data;
934
+ throw new InvalidArgumentError("Report status must be COMPLETE or PARTIAL.");
935
+ }
850
936
  function projectType(value) {
851
937
  const parsed = ProjectTypeSchema.safeParse(value.toUpperCase());
852
938
  if (parsed.success) return parsed.data;
@@ -1864,6 +1950,274 @@ async function runCli(argv = process.argv, overrides = {}) {
1864
1950
  }
1865
1951
  });
1866
1952
  });
1953
+ const blog = program.command("blog").description("Read and manage Blog Studio");
1954
+ const blogPublishing = blog.command("destinations").description("Inspect Blog publishing providers, destinations, and delivery attempts");
1955
+ blogPublishing.command("providers").requiredOption("--project <project-id>", "exact Rolino project ID").action(async (local) => {
1956
+ const global = program.opts();
1957
+ commandExitCode = await execute({ command: "blog destinations providers", global, runtime, async action(context, client) {
1958
+ const data = await client.blog.publishing.providers(local.project, { requestId: context.requestId });
1959
+ writeSuccess(context, data, JSON.stringify(data, null, 2));
1960
+ } });
1961
+ });
1962
+ blogPublishing.command("list").requiredOption("--project <project-id>", "exact Rolino project ID").action(async (local) => {
1963
+ const global = program.opts();
1964
+ commandExitCode = await execute({ command: "blog destinations list", global, runtime, async action(context, client) {
1965
+ const data = await client.blog.publishing.destinations(local.project, { requestId: context.requestId });
1966
+ writeSuccess(context, data, JSON.stringify(data, null, 2));
1967
+ } });
1968
+ });
1969
+ blogPublishing.command("deliveries").requiredOption("--project <project-id>", "exact Rolino project ID").option("--article <article-id>", "filter by exact Blog article ID").action(async (local) => {
1970
+ const global = program.opts();
1971
+ commandExitCode = await execute({ command: "blog destinations deliveries", global, runtime, async action(context, client) {
1972
+ const data = await client.blog.publishing.deliveries(local.project, local.article, { requestId: context.requestId });
1973
+ writeSuccess(context, data, JSON.stringify(data, null, 2));
1974
+ } });
1975
+ });
1976
+ const blogSetup = blog.command("setup").description("Inspect agent-first Blog setup readiness");
1977
+ blogSetup.command("status").requiredOption("--project <project-id>", "exact Rolino project ID").action(async (local) => {
1978
+ const global = program.opts();
1979
+ commandExitCode = await execute({ command: "blog setup status", global, runtime, async action(context, client) {
1980
+ const data = await client.blog.setup.status(local.project, { requestId: context.requestId });
1981
+ writeSuccess(context, data, JSON.stringify(data, null, 2));
1982
+ } });
1983
+ });
1984
+ const blogSite = blog.command("site").description("Initialize or retry the Blog website import");
1985
+ blogSite.command("import").requiredOption("--project <project-id>", "exact Rolino project ID").requiredOption("--idempotency-key <key>", "stable retry key").action(async (local) => {
1986
+ const global = program.opts();
1987
+ commandExitCode = await execute({ command: "blog site import", global, runtime, async action(context, client) {
1988
+ const data = await client.blog.site.import(local.project, local.idempotencyKey, { requestId: context.requestId });
1989
+ writeSuccess(context, data, JSON.stringify(data, null, 2), [`rolino blog job ${data.id} --project ${local.project} --agent`]);
1990
+ } });
1991
+ });
1992
+ blogSite.command("retry").requiredOption("--project <project-id>", "exact Rolino project ID").requiredOption("--idempotency-key <key>", "stable retry key").action(async (local) => {
1993
+ const global = program.opts();
1994
+ commandExitCode = await execute({ command: "blog site retry", global, runtime, async action(context, client) {
1995
+ const data = await client.blog.site.retry(local.project, local.idempotencyKey, { requestId: context.requestId });
1996
+ writeSuccess(context, data, JSON.stringify(data, null, 2), [`rolino blog job ${data.id} --project ${local.project} --agent`]);
1997
+ } });
1998
+ });
1999
+ blog.command("plans").description("List Blog Studio plans").requiredOption("--project <project-id>", "exact Rolino project ID").action(async (local) => {
2000
+ const global = program.opts();
2001
+ commandExitCode = await execute({ command: "blog plans", global, runtime, async action(context, client) {
2002
+ const data = await client.blog.plans.list(local.project, { requestId: context.requestId });
2003
+ writeSuccess(context, data, JSON.stringify(data, null, 2));
2004
+ } });
2005
+ });
2006
+ const blogPlan = blog.command("plan").description("Create, retry, and review a Blog cadence plan");
2007
+ blogPlan.command("create").requiredOption("--project <project-id>", "exact Rolino project ID").requiredOption("--start <date>", "local start date as YYYY-MM-DD").requiredOption("--weekdays <days>", "comma-separated weekday names such as mon,wed,fri").option("--time-zone <zone>", "IANA time zone", "UTC").requiredOption("--idempotency-key <key>", "stable retry key").action(async (local) => {
2008
+ const weekdayMap = { sun: 0, mon: 1, tue: 2, wed: 3, thu: 4, fri: 5, sat: 6 };
2009
+ const weekdays = local.weekdays.split(",").map((day) => weekdayMap[day.trim().toLowerCase()]).filter((day) => day !== void 0);
2010
+ if (!weekdays.length || weekdays.length !== local.weekdays.split(",").length) throw new TypeError("--weekdays must contain comma-separated sun,mon,tue,wed,thu,fri,sat values.");
2011
+ const global = program.opts();
2012
+ commandExitCode = await execute({ command: "blog plan create", global, runtime, async action(context, client) {
2013
+ const data = await client.blog.plans.create(local.project, { startsOn: local.start, weekdays, timeZone: local.timeZone }, local.idempotencyKey, { requestId: context.requestId });
2014
+ writeSuccess(context, data, JSON.stringify(data, null, 2), [`rolino blog job ${data.job.id} --project ${local.project} --agent`]);
2015
+ } });
2016
+ });
2017
+ blogPlan.command("retry").requiredOption("--project <project-id>", "exact Rolino project ID").requiredOption("--plan <plan-id>", "exact Blog plan ID").requiredOption("--idempotency-key <key>", "stable retry key").action(async (local) => {
2018
+ const global = program.opts();
2019
+ commandExitCode = await execute({ command: "blog plan retry", global, runtime, async action(context, client) {
2020
+ const data = await client.blog.plans.retry(local.project, local.plan, local.idempotencyKey, { requestId: context.requestId });
2021
+ writeSuccess(context, data, JSON.stringify(data, null, 2));
2022
+ } });
2023
+ });
2024
+ blogPlan.command("items").requiredOption("--project <project-id>", "exact Rolino project ID").requiredOption("--plan <plan-id>", "exact Blog plan ID").action(async (local) => {
2025
+ const global = program.opts();
2026
+ commandExitCode = await execute({ command: "blog plan items", global, runtime, async action(context, client) {
2027
+ const data = await client.blog.plans.items.list(local.project, local.plan, { requestId: context.requestId });
2028
+ writeSuccess(context, data, JSON.stringify(data, null, 2));
2029
+ } });
2030
+ });
2031
+ const blogPlanItem = blogPlan.command("item").description("Accept or dismiss a reviewed Blog plan item");
2032
+ for (const state of ["accept", "dismiss"]) {
2033
+ blogPlanItem.command(state).requiredOption("--project <project-id>", "exact Rolino project ID").requiredOption("--plan <plan-id>", "exact Blog plan ID").requiredOption("--item <item-id>", "exact plan item ID").requiredOption("--expected-state <state>", "state returned by the latest item read").requiredOption("--expected-version <version>", "version returned by the latest item read", Number).requiredOption("--idempotency-key <key>", "stable retry key").action(async (local) => {
2034
+ const global = program.opts();
2035
+ commandExitCode = await execute({ command: `blog plan item ${state}`, global, runtime, async action(context, client) {
2036
+ const data = await client.blog.plans.items.setState(local.project, local.plan, local.item, { state: state === "accept" ? "ACCEPTED" : "DISMISSED", expectedState: local.expectedState, expectedVersion: local.expectedVersion, idempotencyKey: local.idempotencyKey }, { requestId: context.requestId });
2037
+ writeSuccess(context, data, JSON.stringify(data, null, 2));
2038
+ } });
2039
+ });
2040
+ }
2041
+ const blogArticle = blog.command("article").description("Create an editable Blog article from an accepted item");
2042
+ blogArticle.command("create").requiredOption("--project <project-id>", "exact Rolino project ID").requiredOption("--plan <plan-id>", "exact Blog plan ID").requiredOption("--item <item-id>", "exact accepted item ID").requiredOption("--expected-version <version>", "version returned by the latest item read", Number).requiredOption("--idempotency-key <key>", "stable retry key").action(async (local) => {
2043
+ const global = program.opts();
2044
+ commandExitCode = await execute({ command: "blog article create", global, runtime, async action(context, client) {
2045
+ const data = await client.blog.plans.items.createArticle(local.project, local.plan, local.item, { expectedState: "ACCEPTED", expectedVersion: local.expectedVersion, idempotencyKey: local.idempotencyKey }, { requestId: context.requestId });
2046
+ writeSuccess(context, data, JSON.stringify(data, null, 2));
2047
+ } });
2048
+ });
2049
+ const blogConnection = blog.command("connection").description("Configure and verify the server-only Next.js Blog connection");
2050
+ blogConnection.command("status").requiredOption("--project <project-id>", "exact Rolino project ID").action(async (local) => {
2051
+ const global = program.opts();
2052
+ commandExitCode = await execute({ command: "blog connection status", global, runtime, async action(context, client) {
2053
+ const data = await client.blog.connection.status(local.project, { requestId: context.requestId });
2054
+ writeSuccess(context, data, JSON.stringify(data, null, 2));
2055
+ } });
2056
+ });
2057
+ const addConnectionOptions = (command, execute2) => {
2058
+ command.requiredOption("--project <project-id>", "exact Rolino project ID").option("--endpoint <url>", "same-host signed revalidation endpoint").option("--credential-action <action>", "KEEP, CREATE, ROTATE, or REVOKE", "KEEP").option("--credential-id <id>", "credential to rotate or revoke").option("--secret-action <action>", "KEEP, CREATE, or ROTATE", "KEEP");
2059
+ if (execute2) command.requiredOption("--confirmation-token <token>", "short-lived token returned by preview").requiredOption("--idempotency-key <key>", "stable retry key").option("--yes", "confirm the exact connection change");
2060
+ return command;
2061
+ };
2062
+ addConnectionOptions(blogConnection.command("preview"), false).action(async (local) => {
2063
+ const input = { endpoint: local.endpoint ?? null, credentialAction: local.credentialAction.toUpperCase(), credentialId: local.credentialId ?? null, secretAction: local.secretAction.toUpperCase() };
2064
+ const global = program.opts();
2065
+ commandExitCode = await execute({ command: "blog connection preview", global, runtime, async action(context, client) {
2066
+ const data = await client.blog.connection.preview(local.project, input, { requestId: context.requestId });
2067
+ writeSuccess(context, data, JSON.stringify(data, null, 2));
2068
+ } });
2069
+ });
2070
+ addConnectionOptions(blogConnection.command("execute"), true).action(async (local) => {
2071
+ const input = { endpoint: local.endpoint ?? null, credentialAction: local.credentialAction.toUpperCase(), credentialId: local.credentialId ?? null, secretAction: local.secretAction.toUpperCase() };
2072
+ const global = program.opts();
2073
+ commandExitCode = await execute({ command: "blog connection execute", global, runtime, async action(context, client) {
2074
+ await requireWriteConsent({ yes: local.yes, global, runtime, preview: `Apply the previewed Blog connection change for project ${local.project}? One-time secrets may be returned and must stay server-only.` });
2075
+ const data = await client.blog.connection.execute(local.project, { ...input, confirmationToken: local.confirmationToken, idempotencyKey: local.idempotencyKey }, { requestId: context.requestId });
2076
+ writeSuccess(context, data, JSON.stringify(data, null, 2));
2077
+ } });
2078
+ });
2079
+ blogConnection.command("test").requiredOption("--project <project-id>", "exact Rolino project ID").requiredOption("--idempotency-key <key>", "stable retry key").action(async (local) => {
2080
+ const global = program.opts();
2081
+ commandExitCode = await execute({ command: "blog connection test", global, runtime, async action(context, client) {
2082
+ const data = await client.blog.connection.test(local.project, local.idempotencyKey, { requestId: context.requestId });
2083
+ writeSuccess(context, data, JSON.stringify(data, null, 2));
2084
+ } });
2085
+ });
2086
+ const blogArticles = blog.command("articles").description("Read and edit Blog Studio articles");
2087
+ blogArticles.command("list").requiredOption("--project <project-id>", "exact Rolino project ID").action(async (local) => {
2088
+ const global = program.opts();
2089
+ commandExitCode = await execute({ command: "blog articles list", global, runtime, async action(context, client) {
2090
+ const data = await client.blog.articles.list(local.project, { requestId: context.requestId });
2091
+ writeSuccess(context, data, JSON.stringify(data, null, 2));
2092
+ } });
2093
+ });
2094
+ blogArticles.command("show").argument("<article-id>").requiredOption("--project <project-id>", "exact Rolino project ID").action(async (articleId, local) => {
2095
+ const global = program.opts();
2096
+ commandExitCode = await execute({ command: "blog articles show", global, runtime, async action(context, client) {
2097
+ const data = await client.blog.articles.get(local.project, articleId, { requestId: context.requestId });
2098
+ writeSuccess(context, data, JSON.stringify(data, null, 2));
2099
+ } });
2100
+ });
2101
+ blogArticles.command("update").argument("<article-id>").requiredOption("--project <project-id>", "exact Rolino project ID").requiredOption("--input <json-file>", "complete Blog draft JSON file").option("--yes", "confirm the draft save").action(async (articleId, local) => {
2102
+ const global = program.opts();
2103
+ commandExitCode = await execute({ command: "blog articles update", global, runtime, async action(context, client) {
2104
+ const draft = AgentBlogDraftUpdateSchema.parse(JSON.parse(await readFile2(resolve2(runtime.cwd, local.input), "utf8")));
2105
+ await requireWriteConsent({ yes: local.yes, global, runtime, preview: `Save a new immutable Blog draft revision?
2106
+ Project: ${local.project}
2107
+ Article: ${articleId}
2108
+ This will not publish.` });
2109
+ const data = await client.blog.articles.updateDraft(local.project, articleId, draft, { requestId: context.requestId });
2110
+ writeSuccess(context, data, JSON.stringify(data, null, 2));
2111
+ } });
2112
+ });
2113
+ blogArticles.command("generate").argument("<article-id>").requiredOption("--project <project-id>", "exact Rolino project ID").option("--idempotency-key <key>", "stable retry key; defaults to request ID").option("--yes", "confirm the generation request").action(async (articleId, local) => {
2114
+ const global = program.opts();
2115
+ commandExitCode = await execute({ command: "blog articles generate", global, runtime, async action(context, client) {
2116
+ await requireWriteConsent({ yes: local.yes, global, runtime, preview: `Queue durable Blog article generation?
2117
+ Project: ${local.project}
2118
+ Article: ${articleId}` });
2119
+ const data = await client.blog.articles.generate(local.project, articleId, local.idempotencyKey ?? context.requestId, { requestId: context.requestId });
2120
+ writeSuccess(context, data, JSON.stringify(data, null, 2));
2121
+ } });
2122
+ });
2123
+ blog.command("job").argument("<job-id>").requiredOption("--project <project-id>", "exact Rolino project ID").action(async (jobId, local) => {
2124
+ const global = program.opts();
2125
+ commandExitCode = await execute({ command: "blog job", global, runtime, async action(context, client) {
2126
+ const data = await client.blog.jobs.get(local.project, jobId, { requestId: context.requestId });
2127
+ writeSuccess(context, data, JSON.stringify(data, null, 2));
2128
+ } });
2129
+ });
2130
+ const blogPublish = blog.command("publish").description("Preview or execute exact approved Blog publication");
2131
+ blogPublish.command("preview").argument("<article-id>").requiredOption("--project <project-id>", "exact Rolino project ID").requiredOption("--revision <revision-id>", "exact user-approved revision ID").option("--destination <destination-id...>", "exact destination IDs; defaults to the current primary").action(async (articleId, local) => {
2132
+ const global = program.opts();
2133
+ commandExitCode = await execute({ command: "blog publish preview", global, runtime, async action(context, client) {
2134
+ const data = await client.blog.articles.previewPublish(local.project, articleId, local.revision, { requestId: context.requestId }, local.destination);
2135
+ writeSuccess(context, data, JSON.stringify(data, null, 2));
2136
+ } });
2137
+ });
2138
+ blogPublish.command("execute").argument("<article-id>").requiredOption("--project <project-id>", "exact Rolino project ID").requiredOption("--revision <revision-id>", "same exact revision used for preview").requiredOption("--confirmation-token <token>", "short-lived token returned by preview").option("--destination <destination-id...>", "same exact destination IDs used for preview").option("--idempotency-key <key>", "stable retry key; defaults to request ID").option("--yes", "confirm publication").action(async (articleId, local) => {
2139
+ const global = program.opts();
2140
+ commandExitCode = await execute({ command: "blog publish execute", global, runtime, async action(context, client) {
2141
+ await requireWriteConsent({ yes: local.yes, global, runtime, preview: `Publish the exact approved Blog revision?
2142
+ Project: ${local.project}
2143
+ Article: ${articleId}
2144
+ Revision: ${local.revision}` });
2145
+ const data = await client.blog.articles.executePublish(local.project, articleId, { revisionId: local.revision, destinationIds: local.destination, confirmationToken: local.confirmationToken, idempotencyKey: local.idempotencyKey ?? context.requestId }, { requestId: context.requestId });
2146
+ writeSuccess(context, data, JSON.stringify(data, null, 2));
2147
+ } });
2148
+ });
2149
+ const seo = program.command("seo").description("Read authorized SEO opportunities and weekly reports");
2150
+ const seoOpportunities = seo.command("opportunities").description("Read accepted SEO opportunities");
2151
+ seoOpportunities.command("list").description("List bounded SEO opportunities").requiredOption("--project <project-id>", "exact Rolino project ID").option("--limit <number>", "maximum opportunities to return", (value) => {
2152
+ const parsed = Number(value);
2153
+ if (!Number.isInteger(parsed) || parsed < 1 || parsed > 50) {
2154
+ throw new InvalidArgumentError("Limit must be an integer from 1 to 50.");
2155
+ }
2156
+ return parsed;
2157
+ }).option("--cursor <cursor>", "continue from an SEO opportunity cursor").option("--kind <kind>", "filter by exact SEO opportunity kind", seoOpportunityKind).option("--impact <impact>", "filter by HIGH, MEDIUM, or LOW impact", seoExpectedImpact).action(async (local) => {
2158
+ const global = program.opts();
2159
+ commandExitCode = await execute({
2160
+ command: "seo opportunities list",
2161
+ global,
2162
+ runtime,
2163
+ async action(context, client) {
2164
+ const data = await client.seo.opportunities.list(local.project, {
2165
+ limit: local.limit,
2166
+ cursor: local.cursor,
2167
+ kind: local.kind,
2168
+ expectedImpact: local.impact
2169
+ }, { requestId: context.requestId });
2170
+ writeSuccess(context, data, formatSeoOpportunities(data), data.items.slice(0, 3).map((item) => `rolino seo opportunities show ${item.id} --project ${local.project} --agent`));
2171
+ }
2172
+ });
2173
+ });
2174
+ seoOpportunities.command("show").description("Show one canonical SEO opportunity task").argument("<opportunity-id>").requiredOption("--project <project-id>", "exact Rolino project ID").action(async (opportunityId, local) => {
2175
+ const global = program.opts();
2176
+ commandExitCode = await execute({
2177
+ command: "seo opportunities show",
2178
+ global,
2179
+ runtime,
2180
+ async action(context, client) {
2181
+ const opportunity = await client.seo.opportunities.get(local.project, opportunityId, { requestId: context.requestId });
2182
+ writeSuccess(context, opportunity, formatSeoOpportunity(opportunity));
2183
+ }
2184
+ });
2185
+ });
2186
+ const seoReports = seo.command("reports").description("Read immutable weekly SEO report snapshots");
2187
+ seoReports.command("list").description("List bounded weekly SEO reports").requiredOption("--project <project-id>", "exact Rolino project ID").option("--limit <number>", "maximum reports to return", (value) => {
2188
+ const parsed = Number(value);
2189
+ if (!Number.isInteger(parsed) || parsed < 1 || parsed > 26) {
2190
+ throw new InvalidArgumentError("Limit must be an integer from 1 to 26.");
2191
+ }
2192
+ return parsed;
2193
+ }).option("--cursor <cursor>", "continue from an SEO report cursor").option("--status <status>", "filter by COMPLETE or PARTIAL", seoReportCompleteness).action(async (local) => {
2194
+ const global = program.opts();
2195
+ commandExitCode = await execute({
2196
+ command: "seo reports list",
2197
+ global,
2198
+ runtime,
2199
+ async action(context, client) {
2200
+ const data = await client.seo.reports.list(local.project, {
2201
+ limit: local.limit,
2202
+ cursor: local.cursor,
2203
+ completeness: local.status
2204
+ }, { requestId: context.requestId });
2205
+ writeSuccess(context, data, formatSeoReports(data), data.items.slice(0, 3).map((item) => `rolino seo reports show ${item.id} --project ${local.project} --agent`));
2206
+ }
2207
+ });
2208
+ });
2209
+ seoReports.command("show").description("Show one weekly SEO report snapshot").argument("<report-id>").requiredOption("--project <project-id>", "exact Rolino project ID").action(async (reportId, local) => {
2210
+ const global = program.opts();
2211
+ commandExitCode = await execute({
2212
+ command: "seo reports show",
2213
+ global,
2214
+ runtime,
2215
+ async action(context, client) {
2216
+ const report = await client.seo.reports.get(local.project, reportId, { requestId: context.requestId });
2217
+ writeSuccess(context, report, formatSeoReport(report));
2218
+ }
2219
+ });
2220
+ });
1867
2221
  program.command("doctor").description("Check configuration, compatibility, and authentication").action(async () => {
1868
2222
  const global = program.opts();
1869
2223
  commandExitCode = await execute({
@@ -1957,4 +2311,4 @@ export {
1957
2311
  ROLINO_CLI_VERSION,
1958
2312
  runCli
1959
2313
  };
1960
- //# sourceMappingURL=chunk-7BCIIFUB.js.map
2314
+ //# sourceMappingURL=chunk-TFNGSKT3.js.map