@letterstory/cli 0.14.0 → 0.15.1

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/README.md CHANGED
@@ -247,10 +247,15 @@ letterstory phantom-onboard domain --sitemap https://acme.com/sitemap.xml --seer
247
247
  letterstory phantom-onboard domain --attach <job-id> --watch # watch a job started elsewhere
248
248
  letterstory phantom-onboard domain --status # the org's latest domain onboarding
249
249
 
250
- # Staff: create the org itself first (the key exchange), with a STAFF key.
251
- LETTERSTORY_STAFF_API_KEY=<staff key with org:create> \
252
- letterstory admin create-org --domain acme.com --onboard --about "payroll for platform teams"
253
- # → prints the org id, a fresh ORG-scoped API key (once), and the job id to watch.
250
+ # Staff: the key exchange (create the org first) needs a STAFF key with org:create —
251
+ # mint your OWN, don't share one. --watch makes the whole recipe ONE command: the
252
+ # freshly-minted org key is used only in this process's memory to poll to completion.
253
+ LETTERSTORY_STAFF_API_KEY=<your staff key with org:create> \
254
+ letterstory admin create-org --domain acme.com --onboard --watch --about "payroll for platform teams"
255
+
256
+ # Without --watch, it prints the org id, a fresh ORG-scoped API key (once), and the job
257
+ # id — watch it yourself with:
258
+ # LETTERSTORY_API_KEY=<the printed key> letterstory phantom-onboard domain --attach <job-id> --watch
254
259
  ```
255
260
 
256
261
  Everything the parent job does is also its own tool for existing orgs:
package/lib/cli.mjs CHANGED
@@ -41,7 +41,7 @@ import {
41
41
  } from "./commands.mjs";
42
42
 
43
43
  // Keep in sync with cli/package.json.
44
- export const VERSION = "0.14.0";
44
+ export const VERSION = "0.15.1";
45
45
 
46
46
  // Flags that never take a value. Listing them explicitly means `deploy get --json <id>`
47
47
  // can't accidentally swallow the id as --json's value.
@@ -341,12 +341,17 @@ Domain onboarding (ONE SHOT: a bare domain in, a fully-configured organization o
341
341
 
342
342
  Admin (STAFF key — --staff-key / LETTERSTORY_STAFF_API_KEY; acts before an org exists):
343
343
  admin create-org --domain <bare-domain> [--name "Acme"] [--test] [--no-key]
344
- [--key-name N] [--capabilities a,b] [--onboard] [+ the onboard domain flags]
344
+ [--key-name N] [--capabilities a,b] [--onboard] [--watch] [+ the onboard domain flags]
345
345
  The key exchange: create the client org from
346
346
  its domain (one org per domain), mint an
347
347
  ORG-scoped API key and print it ONCE. With
348
348
  --onboard the domain onboarding starts in the
349
- same call; watch it with the printed key.
349
+ same call; add --watch to poll it to
350
+ completion in this same command — the org key
351
+ is used only in memory for the poll, never
352
+ written to disk or printed twice — a bare
353
+ domain in, a fully-configured org out, one
354
+ command.
350
355
 
351
356
  Seers (event-driven signals -> drafts):
352
357
  seers list List seers with recent activity
@@ -6,19 +6,23 @@
6
6
  // admin create-org --domain acme.com [--name "Acme"] [--test] [--no-key] [--key-name N]
7
7
  // [--capabilities a,b] [--onboard] [--about "…"] [--sitemap <url>]
8
8
  // [--cms <provider>] [--posts N] [--seers suggest|skip] [--no-visuals]
9
- // [--no-enhance] [--readiness-minutes N]
9
+ // [--no-enhance] [--readiness-minutes N] [--watch]
10
10
  //
11
11
  // The KEY EXCHANGE: create the client org from its domain (one org per domain; an existing
12
12
  // owner is adopted), mint an ORG-scoped API key for it and print the plaintext ONCE. With
13
13
  // --onboard, the one-shot domain onboarding (main blog + org visuals + enhance + phantom +
14
- // seers) starts in the same call; watch it afterwards with
14
+ // seers) starts in the same call. --onboard --watch makes the whole recipe ONE command: the
15
+ // freshly-minted org key is used ONLY in this process's memory (never written to disk, never
16
+ // re-printed) to poll the job to completion, reusing the exact same loop
17
+ // `phantom-onboard domain --watch` uses. Without --watch, watch it afterwards with
15
18
  // LETTERSTORY_API_KEY=<printed key> letterstory phantom-onboard domain --watch --attach <job-id>
16
19
  //
17
20
  // The staff key comes from --staff-key or LETTERSTORY_STAFF_API_KEY; the base URL from the
18
21
  // usual --url / LETTERSTORY_API_URL / config resolution.
19
22
 
20
- import { CliError } from "../client.mjs";
23
+ import { CliError, LetterstoryClient } from "../client.mjs";
21
24
  import { flagStr, flagNum, flagBool, flagList, printResult, compact, ok } from "./shared.mjs";
25
+ import { watchDomainJob } from "./onboard.mjs";
22
26
 
23
27
  const SEER_MODES = ["suggest", "skip"];
24
28
  const CMS_PROVIDERS = ["webflow", "framer", "sanity", "contentful"];
@@ -107,10 +111,18 @@ function formatCreateOrg(r) {
107
111
  }
108
112
 
109
113
  async function cmdAdminCreateOrg(ctx) {
110
- const { flags, io } = ctx;
114
+ const { flags, io, client } = ctx;
111
115
  const domain = flagStr(flags.domain);
112
116
  if (!domain) throw new CliError("admin create-org requires --domain <bare-domain>.");
113
117
 
118
+ const watch = flagBool(flags.watch);
119
+ if (watch && !flagBool(flags.onboard)) {
120
+ throw new CliError("--watch needs --onboard (nothing to watch without a job).");
121
+ }
122
+ if (watch && flagBool(flags["no-key"])) {
123
+ throw new CliError("--watch needs an org key to poll with — drop --no-key.");
124
+ }
125
+
114
126
  // --capabilities a,b or repeated --capabilities a --capabilities b.
115
127
  const capabilities = flagList(flags.capabilities)
116
128
  .flatMap((v) => v.split(","))
@@ -135,8 +147,34 @@ async function cmdAdminCreateOrg(ctx) {
135
147
 
136
148
  ok(ctx, `Provisioning ${domain}…`);
137
149
  const result = await staffPost(ctx, "/api/superadmin/orgs", body);
138
- printResult(io, flags, result, formatCreateOrg);
139
- return 0;
150
+
151
+ if (!watch) {
152
+ printResult(io, flags, result, formatCreateOrg);
153
+ return 0;
154
+ }
155
+
156
+ // --watch: everything spins up from this one command. The org key exists ONLY in this
157
+ // process's memory for the rest of the run — never written to disk, never printed again
158
+ // after the summary above — and is used to build a second, throwaway MCP client that
159
+ // polls the SAME loop `phantom-onboard domain --watch` uses. `ok(...)` here (not
160
+ // printResult) so the key/warning above are still shown before the poll starts.
161
+ ok(ctx, formatCreateOrg(result));
162
+ if (!result.job_id) {
163
+ ok(ctx, "No job to watch (the org call didn't start one — see the error above, if any).");
164
+ return 0;
165
+ }
166
+ if (!result.api_key?.plain_key) {
167
+ throw new CliError("No org key came back to watch with (did --no-key sneak in?).");
168
+ }
169
+ const orgClient = new LetterstoryClient({
170
+ url: client.url,
171
+ key: result.api_key.plain_key,
172
+ fetchImpl: client.fetch,
173
+ verbose: client.verbose,
174
+ verboseLog: client.verboseLog,
175
+ bin: ctx.bin,
176
+ });
177
+ return watchDomainJob({ ...ctx, client: orgClient }, result.job_id);
140
178
  }
141
179
 
142
180
  export async function cmdAdmin(ctx) {
@@ -275,7 +275,9 @@ async function deployList(ctx) {
275
275
  return 0;
276
276
  }
277
277
  for (const d of items) {
278
- io.log(`${d.status.padEnd(13)} ${d.deployment_id} ${d.name}${d.url ? ` ${d.url}` : ""}`);
278
+ io.log(
279
+ `${d.status.padEnd(13)} ${d.deployment_id} collection:${d.collection_id ?? "(none)"} ${d.name}${d.url ? ` ${d.url}` : ""}`
280
+ );
279
281
  }
280
282
  return 0;
281
283
  }
@@ -228,7 +228,7 @@ const SEER_MODES = ["suggest", "skip"];
228
228
  const CMS_PROVIDERS = ["webflow", "framer", "sanity", "contentful"];
229
229
 
230
230
  // Final readback of a domain-onboarding job — the counts the engine PERSISTED.
231
- function formatDomainStatus(s) {
231
+ export function formatDomainStatus(s) {
232
232
  const r = s.result ?? {};
233
233
  const lines = [
234
234
  `Domain onboarding ${s.status} at stage "${s.stage}" (${s.domain})`,
@@ -264,7 +264,9 @@ function formatDomainStatus(s) {
264
264
  return lines.join("\n");
265
265
  }
266
266
 
267
- async function watchDomainJob(ctx, jobId) {
267
+ // Exported so `admin create-org --onboard --watch` can drive the SAME poll loop against a
268
+ // freshly-minted org key, instead of duplicating it — see admin.mjs.
269
+ export async function watchDomainJob(ctx, jobId) {
268
270
  const { client, flags } = ctx;
269
271
  let printed = 0;
270
272
  let lastStage = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@letterstory/cli",
3
- "version": "0.14.0",
3
+ "version": "0.15.1",
4
4
  "description": "Spin up and manage Letterstory phantom blogs from your terminal.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",