@letterstory/cli 0.176.25 → 0.176.26

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
@@ -82,7 +82,7 @@ import {
82
82
  import { fetchParkedSections, withoutParked } from "./parked.mjs";
83
83
 
84
84
  // Matches cli/package.json; publish-cli.yml rewrites both to the published version.
85
- export const VERSION = "0.176.25";
85
+ export const VERSION = "0.176.26";
86
86
 
87
87
  /** The exit code for a gate refusal (CARD_REQUIRED, PAYMENT_FAILED, OUT_OF_TOKENS): 1 is a plain error. */
88
88
  export const EXIT_PAYMENT_REQUIRED = 3;
@@ -1088,12 +1088,14 @@ Admin (STAFF key — --staff-key / LETTERSTORY_STAFF_API_KEY; acts before an org
1088
1088
  domain typed into Set-up maps and reads it all afresh.
1089
1089
  admin demo domains The farm domains a new demo org could take (live
1090
1090
  phantoms; the phantom is kept). Needs demo:read.
1091
- admin demo new <domain> [--name <n>] [--brief <t>] [--full] [--no-wait]
1091
+ admin demo new <domain> [--name <n>] [--brief <t>] [--full] [--host vercel|pages] [--no-wait]
1092
1092
  A new demo org on a farm phantom's domain: a made-up
1093
1093
  company, a one-page site in the demo GitHub org served by
1094
1094
  Pages, the domain moved off its phantom (kept), the org
1095
- enrolled and shown as blank. Takes minutes; calls again
1096
- until done (--no-wait: once). Auto-Plan stays off.
1095
+ enrolled and shown as blank. Served from Vercel (a project
1096
+ linked to the repo: a merged PR redeploys it); --host pages
1097
+ for GitHub Pages, and --host vercel on an org that has a Pages
1098
+ site moves it. Calls again until done (--no-wait: once).
1097
1099
  admin demo teardown <org-id> [--keep-repo] Put the site back: the domain to its phantom, the repo gone.
1098
1100
  admin demo check <org-id> Is it ready to show? Competitors, targets, answers, the
1099
1101
  Plan's rows, the issues open, no PR open, GitHub, the
@@ -1803,8 +1805,10 @@ Repo changes (Claude Code edits your repo in a sandbox; the Letter GitHub App op
1803
1805
  repo publish <run-id> Make PR on a preview in review
1804
1806
  repo merge <run-id> Merge its open PR (a squash; the repo's branch rules decide)
1805
1807
  repo revise <run-id> --instructions <text>|--instructions-file <path|-> [--copy-edits-file <path|->]
1808
+ [--attach <path>]… [--attach-ref <path>]… [--attach-url name=url]… [--attach-url-ref name=url]…
1806
1809
  Ask for more on a preview (it takes over the preview's link) or an
1807
- open PR (one more commit); copy edits: JSON [{ path, before, after }]
1810
+ open PR (one more commit); copy edits: JSON [{ path, before, after }];
1811
+ files as repo start takes them (--attach-ref: read, never committed)
1808
1812
  repo cancel <run-id> [--force] Stop it and delete the sandbox; no PR (Discard a preview)
1809
1813
 
1810
1814
  Feedback (tell us what's broken, missing, unclear, or wanted):
@@ -6518,7 +6518,7 @@ const DEMO_ITEM_FLAGS = [
6518
6518
  "setup",
6519
6519
  ];
6520
6520
  const DEMO_USAGE =
6521
- "Usage: admin demo guide | list [--enrollable] | show <org-id> [--moves] | set <org-id> [--enroll] [--unenroll] [--file <state.json>] [--phantom parked|shown] [--main-blog …] [--visitors …] [--probes not_run|shown] [--cms hidden|shown] [--publish-target …] [--search-console …] [--github …] [--domain …] [--setup fresh|finished] [--domain-cap n] [--inject <key>]... [--hide <key>]... [--save-as <name>] [--baseline <owner/repo>[@sha] | --clear-baseline] [--copy-from <org-id> [--copy-scenarios a,b] [--overwrite]] [--auto-reset <scenario>|off] [--every <minutes>] [--release] | domains | new <domain> [--name <n>] [--brief <t>] [--full] [--no-wait] | teardown <org-id> [--keep-repo] | bootstrap <org-id>... --from <org-id> [--scenarios a,b] [--overwrite] | reset <org-id> <scenario> [--clean-slate] [--close-prs since_applied|all_open|none] [--hold <minutes>] [--restore-repo revert|force] [--rebuild] [--reread-company] [--forget-company] [--forget-site] | check <org-id>";
6521
+ "Usage: admin demo guide | list [--enrollable] | show <org-id> [--moves] | set <org-id> [--enroll] [--unenroll] [--file <state.json>] [--phantom parked|shown] [--main-blog …] [--visitors …] [--probes not_run|shown] [--cms hidden|shown] [--publish-target …] [--search-console …] [--github …] [--domain …] [--setup fresh|finished] [--domain-cap n] [--inject <key>]... [--hide <key>]... [--save-as <name>] [--baseline <owner/repo>[@sha] | --clear-baseline] [--copy-from <org-id> [--copy-scenarios a,b] [--overwrite]] [--auto-reset <scenario>|off] [--every <minutes>] [--release] | domains | new <domain> [--name <n>] [--brief <t>] [--full] [--host vercel|pages] [--no-wait] | teardown <org-id> [--keep-repo] | bootstrap <org-id>... --from <org-id> [--scenarios a,b] [--overwrite] | reset <org-id> <scenario> [--clean-slate] [--close-prs since_applied|all_open|none] [--hold <minutes>] [--restore-repo revert|force] [--rebuild] [--reread-company] [--forget-company] [--forget-site] | check <org-id>";
6522
6522
 
6523
6523
  const readinessLines = (r) =>
6524
6524
  r
@@ -6668,6 +6668,7 @@ async function cmdAdminDemo(ctx) {
6668
6668
  name: flagStr(flags.name),
6669
6669
  brief: flagStr(flags.brief),
6670
6670
  full: flagBool(flags.full) || undefined,
6671
+ host: flagStr(flags.host),
6671
6672
  });
6672
6673
  for (let attempt = 0; ; attempt++) {
6673
6674
  const r = await staffPost(ctx, `${DEMO}/orgs`, body);
@@ -32,6 +32,8 @@ const ARGS = {
32
32
  delivery: { flag: "action", enum: ["build", "build_pr", "build_merge", "slack", "linear"] },
33
33
  notify_slack: { flag: "notify-slack", type: "bool" },
34
34
  harness: { flag: "harness", enum: ["letterpress-1", "claude-code", "codex"] },
35
+ // --branch <name>: where its changes start and its pull requests go; omitted, the branch that builds the site.
36
+ base_branch: "branch",
35
37
  // --effort low|medium|high|xhigh: how hard the coding agent works on each change; omitted, its own default.
36
38
  effort: { flag: "effort", enum: ["low", "medium", "high", "xhigh"] },
37
39
  again: { flag: "again", type: "bool" },
@@ -59,6 +61,8 @@ const ARGS = {
59
61
  conversation_id: "conversation",
60
62
  build_id: "build",
61
63
  domain: "site",
64
+ // --branch <name>: where a build this message starts works from.
65
+ base_branch: "branch",
62
66
  subjects: { flag: "subject", type: "list" },
63
67
  // --recipe <id>: the recipe the words carry out (a Plan row's), recorded on the build it starts.
64
68
  recipe: "recipe",
@@ -189,6 +193,7 @@ async function buildStart(ctx) {
189
193
  "again",
190
194
  "plan-only",
191
195
  "plan-file",
196
+ "branch",
192
197
  ...FILE_FLAGS,
193
198
  ]);
194
199
  const files = await attachedFiles(ctx);
@@ -220,6 +225,7 @@ async function buildTalk(ctx) {
220
225
  "subject",
221
226
  "harness",
222
227
  "repo",
228
+ "branch",
223
229
  "action",
224
230
  "intent",
225
231
  ...FILE_FLAGS,
@@ -257,6 +257,7 @@ const ARGS = {
257
257
  run_id: { positional: 0, required: true, label: "run-id" },
258
258
  instructions: { value: (flags) => readTextInput(flags, "instructions", "instructions-file") },
259
259
  copy_edits: { value: (flags) => copyEdits(flags) },
260
+ files: { value: (_flags, _positionals, extra) => (extra.files?.length ? extra.files : undefined) },
260
261
  },
261
262
  list_repo_changes: {
262
263
  status: { flag: "status", enum: ["running", "succeeded", "no_changes", "failed", "cancelled", "sent"] },
@@ -437,6 +438,19 @@ export async function uploadAttachments(ctx, paths) {
437
438
  return uploads.map((slot) => ({ name: slot.name, upload_path: slot.path }));
438
439
  }
439
440
 
441
+ /** --attach / --attach-ref (uploaded) and --attach-url / --attach-url-ref, as a change's `files`. */
442
+ async function attachedFiles(ctx) {
443
+ const { flags } = ctx;
444
+ // One upload for every file (names must be unique across both), then the references marked.
445
+ const place = flagList(flags.attach);
446
+ const uploaded = await uploadAttachments(ctx, [...place, ...flagList(flags["attach-ref"])]);
447
+ return [
448
+ ...uploaded.map((f, i) => (i < place.length ? f : { ...f, reference: true })),
449
+ ...attachmentUrls(flagList(flags["attach-url"])),
450
+ ...attachmentUrls(flagList(flags["attach-url-ref"])).map((f) => ({ ...f, reference: true })),
451
+ ];
452
+ }
453
+
440
454
  async function repoStart(ctx) {
441
455
  const { client, flags, io } = ctx;
442
456
  refuseUnknownFlags(ctx, {}, [
@@ -460,15 +474,7 @@ async function repoStart(ctx) {
460
474
  "page",
461
475
  "wait",
462
476
  ]);
463
- // One upload for every file (names must be unique across both), then the references marked.
464
- const place = flagList(flags.attach);
465
- const uploaded = await uploadAttachments(ctx, [...place, ...flagList(flags["attach-ref"])]);
466
- const files = [
467
- ...uploaded.map((f, i) => (i < place.length ? f : { ...f, reference: true })),
468
- ...attachmentUrls(flagList(flags["attach-url"])),
469
- ...attachmentUrls(flagList(flags["attach-url-ref"])).map((f) => ({ ...f, reference: true })),
470
- ];
471
- const args = argsFromFlags(ARGS.start_repo_change, flags, ctx.positionals, { files });
477
+ const args = argsFromFlags(ARGS.start_repo_change, flags, ctx.positionals, { files: await attachedFiles(ctx) });
472
478
  if (!args.repo_owner || !args.repo_name) throw new CliError("Missing --repo owner/name");
473
479
  if (!args.instructions) throw new CliError("Missing --instructions (or --instructions-file <path|->)");
474
480
 
@@ -795,10 +801,13 @@ function copyEdits(flags) {
795
801
  return list;
796
802
  }
797
803
 
798
- /** `repo revise <run-id> --instructions <text> [--copy-edits-file <path|->]`: a follow-up, built on top of the change. */
804
+ /**
805
+ * `repo revise <run-id> --instructions <text> [--copy-edits-file <path|->] [--attach-ref <path>]…`: a follow-up,
806
+ * built on top of the change, with any files it needs (a screenshot to read, an image to place) as `repo start` takes them.
807
+ */
799
808
  async function repoRevise(ctx) {
800
809
  const { client, flags, io } = ctx;
801
- const args = argsFromFlags(ARGS.revise_repo_change, flags, ctx.positionals);
810
+ const args = argsFromFlags(ARGS.revise_repo_change, flags, ctx.positionals, { files: await attachedFiles(ctx) });
802
811
  if (!args.instructions && !args.copy_edits) {
803
812
  throw new CliError("Missing --instructions (or --instructions-file <path|->), or --copy-edits-file <path|->");
804
813
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@letterstory/cli",
3
- "version": "0.176.25",
3
+ "version": "0.176.26",
4
4
  "description": "Spin up and manage Letter phantom blogs from your terminal.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",