@letterstory/cli 0.91.0 → 0.92.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/lib/cli.mjs CHANGED
@@ -57,7 +57,7 @@ import {
57
57
  } from "./commands.mjs";
58
58
 
59
59
  // Keep in sync with cli/package.json.
60
- export const VERSION = "0.91.0";
60
+ export const VERSION = "0.92.0";
61
61
 
62
62
  // Flags that never take a value. Listing them explicitly means `deploy get --json <id>`
63
63
  // can't accidentally swallow the id as --json's value. Every `type: "bool"` flag (and its
@@ -121,6 +121,8 @@ export const BOOLEAN_FLAGS = new Set([
121
121
  // `phantom-onboard collection --enable-planner`, `strategy sitemap --posts-only`, and the
122
122
  // `strategy positioning set --clear-*` switches: value-less, and each sits next to a value.
123
123
  "enable-planner",
124
+ // `phantom-onboard primitives --retry [<domain>]` re-reads a domain whose read failed.
125
+ "retry",
124
126
  "posts-only",
125
127
  "clear-topics",
126
128
  "clear-stances",
@@ -581,6 +583,9 @@ Propose lane (the Fleet wizard's Plan and Name screens; persists nothing, spends
581
583
  (--plan '<json>' inline, or - for stdin).
582
584
 
583
585
  What does this org still need? (the router — reads only, decides nothing):
586
+ ${bin === "phantom" ? "onboard" : "phantom-onboard"} primitives [<domain>] [--retry] The primitives that fit a domain (default:
587
+ yours), each with the exact call that sets
588
+ it up — the plan Instances shows
584
589
  ${bin === "phantom" ? "onboard" : "phantom-onboard"} plan Every onboarding step (context, main blog,
585
590
  Planner, CMS, phantom) with its status:
586
591
  done / running / ready / blocked, and what
@@ -174,6 +174,12 @@ export const ARGS = {
174
174
  get_phantom_launch_status: {
175
175
  job_id: { internal: "the job id plan_phantom just returned" },
176
176
  },
177
+ // The primitive plan: a domain (default: the org's own) read into the calls that would
178
+ // stand each primitive up. Printed, never run — approving an item is running its call.
179
+ propose_primitive_plan: {
180
+ domain: { positional: 0, label: "domain" },
181
+ retry: { flag: "retry", type: "bool" },
182
+ },
177
183
  propose_phantom_plan: {
178
184
  client_domain: { positional: 0, label: "client-domain" },
179
185
  direction: ["about", "direction"],
@@ -752,8 +758,62 @@ async function cmdOnboardNext(ctx) {
752
758
  return 0;
753
759
  }
754
760
 
761
+ // `onboard primitives [<domain>]` — what Letterstory would stand up for this company: one
762
+ // read of propose_primitive_plan, printed as a table whose last column is the exact
763
+ // `call` that sets each item up. Nothing runs; approving an item is running its line.
764
+ // A first read crawls the site; `pending` means one is already in flight, so wait and ask.
765
+ function shellQuote(json) {
766
+ return `'${json.replace(/'/g, "'\\''")}'`;
767
+ }
768
+
769
+ function formatPrimitivePlan(ctx) {
770
+ return (res) => {
771
+ if (res.status !== "complete") {
772
+ return res.status === "pending"
773
+ ? `Still reading ${res.domain} — run this again in a few seconds.`
774
+ : `Couldn't read ${res.domain}: ${res.error ?? "unknown error"} (retry with --retry)`;
775
+ }
776
+ const { plan } = res;
777
+ const lines = [`${plan.company_name} (${plan.domain})`, ` ${plan.priority_topics.join(" · ")}`, ""];
778
+ for (const item of plan.items) {
779
+ // A part of its parent's setup prints indented under it.
780
+ const pad = item.parent ? " " : "";
781
+ const mark = item.status === "exists" ? "running " : "proposed";
782
+ lines.push(`${pad}${mark} ${item.title}`);
783
+ lines.push(
784
+ item.status === "exists"
785
+ ? `${pad} already: ${item.existing.map((e) => e.name).join(", ")}`
786
+ : `${pad} ${item.detail}`
787
+ );
788
+ if (item.call) {
789
+ lines.push(
790
+ `${pad} ${ctx.bin} call ${item.call.tool} --args ${shellQuote(JSON.stringify(item.call.args))}`
791
+ );
792
+ for (const [arg, ref] of Object.entries(item.refs ?? {})) {
793
+ lines.push(`${pad} with ${arg} = ${ref.field} from ${ref.item}`);
794
+ }
795
+ if (item.after?.length) lines.push(`${pad} after: ${item.after.join(", ")}`);
796
+ if (item.poll) lines.push(`${pad} then poll: ${item.poll.tool}`);
797
+ }
798
+ }
799
+ return lines.join("\n");
800
+ };
801
+ }
802
+
803
+ async function cmdOnboardPrimitives(ctx) {
804
+ const args = argsFromFlags(ARGS.propose_primitive_plan, ctx.flags, ctx.positionals);
805
+ ok(ctx, "Reading the domain…");
806
+ const res = await ctx.client.callTool("propose_primitive_plan", args);
807
+ printResult(ctx.io, ctx.flags, res, formatPrimitivePlan(ctx));
808
+ return 0;
809
+ }
810
+
755
811
  export async function cmdOnboard(ctx) {
756
812
  const { client, flags, io } = ctx;
813
+ // `onboard primitives [<domain>]` — the primitive plan and the call behind each item.
814
+ if (ctx.positionals[0] === "primitives") {
815
+ return cmdOnboardPrimitives({ ...ctx, positionals: ctx.positionals.slice(1) });
816
+ }
757
817
  // `onboard plan` / `onboard next` — the router: what does this org still need?
758
818
  if (ctx.positionals[0] === "plan") return cmdOnboardPlan(ctx);
759
819
  if (ctx.positionals[0] === "next") return cmdOnboardNext(ctx);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@letterstory/cli",
3
- "version": "0.91.0",
3
+ "version": "0.92.0",
4
4
  "description": "Spin up and manage Letterstory phantom blogs from your terminal.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",