@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 +9 -4
- package/lib/cli.mjs +8 -3
- package/lib/commands/admin.mjs +44 -6
- package/lib/commands/deploy.mjs +3 -1
- package/lib/commands/onboard.mjs +4 -2
- package/package.json +1 -1
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:
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
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.
|
|
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
|
|
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
|
package/lib/commands/admin.mjs
CHANGED
|
@@ -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
|
|
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
|
-
|
|
139
|
-
|
|
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) {
|
package/lib/commands/deploy.mjs
CHANGED
|
@@ -275,7 +275,9 @@ async function deployList(ctx) {
|
|
|
275
275
|
return 0;
|
|
276
276
|
}
|
|
277
277
|
for (const d of items) {
|
|
278
|
-
io.log(
|
|
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
|
}
|
package/lib/commands/onboard.mjs
CHANGED
|
@@ -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
|
-
|
|
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;
|