@letterstory/cli 0.11.0 → 0.13.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
@@ -40,7 +40,7 @@ import {
40
40
  } from "./commands.mjs";
41
41
 
42
42
  // Keep in sync with cli/package.json.
43
- export const VERSION = "0.11.0";
43
+ export const VERSION = "0.13.0";
44
44
 
45
45
  // Flags that never take a value. Listing them explicitly means `deploy get --json <id>`
46
46
  // can't accidentally swallow the id as --json's value.
@@ -64,6 +64,10 @@ const BOOLEAN_FLAGS = new Set([
64
64
  // both put a value-less flag next to a value: without these entries the parser
65
65
  // hands the following token to the flag and the real argument disappears.
66
66
  "regenerate",
67
+ // `connectors connect --provider framer --token … --auto-deploy` / `--no-auto-deploy`
68
+ // are value-less; without these the parser eats the following token.
69
+ "auto-deploy",
70
+ "no-auto-deploy",
67
71
  "stock-only",
68
72
  "gate",
69
73
  "skip",
@@ -203,6 +207,21 @@ Connectors:
203
207
  [--confirm-missing-target] re-publish even though
204
208
  the item was deleted/unpublished on the provider
205
209
  connectors status --connector <connector> --publish-id <id>
210
+ connectors pull [--collection <uuid>] [--provider <webflow|framer|sanity|contentful>]
211
+ Pull existing posts FROM a connected CMS into a
212
+ collection, reconciling (adopt/update/create/orphan).
213
+ --collection for a bound collection, --provider to
214
+ auto-resolve, or both to wire an unbound collection.
215
+ connectors connect --provider <p> --token <api-token>
216
+ Save + validate CMS credentials. framer also needs
217
+ --project-url (+ [--no-auto-deploy]); sanity needs
218
+ --project-id [--dataset]; contentful needs --space-id
219
+ [--environment].
220
+ connectors disconnect --provider <p> Forget a CMS connection (keeps imported posts)
221
+ connectors connections Show connection status for every provider
222
+ connectors mappings --provider <p> List the org's field mappings for a provider
223
+ connectors bind --collection <uuid> --provider <p> [--mapping <uuid>]
224
+ Wire a collection to a CMS + field mapping
206
225
 
207
226
  Strategy & onboarding:
208
227
  strategy company get | set [--name] [--domain] [--manifesto <text>|--manifesto-file <path>]
@@ -270,14 +289,15 @@ Phantom onboarding recipe (domain -> live phantom blog with first posts):
270
289
 
271
290
  Collection onboarding (your OWN blog, on your org's domain — no provisioning):
272
291
  ${bin === "phantom" ? "onboard" : "phantom-onboard"} collection [--collection <uuid>] [--name "<collection name>"]
273
- [--about "the direction"] [--sitemap <url>] [--watch]
292
+ [--about "the direction"] [--sitemap <url>] [--cms <provider>] [--watch]
274
293
  Import the existing blog from its sitemap
275
294
  (auto-discovered from the org's domain unless
276
- --sitemap pins one), derive content areas +
277
- series, build the topic map, bind SEO demand,
278
- and stock Headlines & Queue. Omit --collection
279
- to create a fresh one (--name, default Blog).
280
- The Planner stays OFF (manual approval).
295
+ --sitemap pins one) OR from a connected CMS with
296
+ --cms <webflow|framer|sanity|contentful>, then
297
+ derive content areas + series, build the topic
298
+ map, bind SEO demand, and stock Headlines & Queue.
299
+ Omit --collection to create a fresh one (--name,
300
+ default Blog). The Planner stays OFF (manual approval).
281
301
  ${bin === "phantom" ? "onboard" : "phantom-onboard"} sync-sitemap --collection <uuid>
282
302
  Re-check an already-onboarded blog's sitemap
283
303
  right now instead of waiting for its cadence
@@ -17,8 +17,23 @@ export async function cmdConnectors(ctx) {
17
17
  return connectorsPublish(rest);
18
18
  case "status":
19
19
  return connectorsStatus(rest);
20
+ case "pull":
21
+ case "import":
22
+ return connectorsPull(rest);
23
+ case "connect":
24
+ return connectorsConnect(rest);
25
+ case "disconnect":
26
+ return connectorsDisconnect(rest);
27
+ case "connections":
28
+ return connectorsConnections(rest);
29
+ case "mappings":
30
+ return connectorsMappings(rest);
31
+ case "bind":
32
+ return connectorsBind(rest);
20
33
  default:
21
- throw new CliError(`Unknown connectors subcommand: ${sub ?? "(none)"}. Try: list, publish, status`);
34
+ throw new CliError(
35
+ `Unknown connectors subcommand: ${sub ?? "(none)"}. Try: list, publish, status, pull, connect, disconnect, connections, mappings, bind`
36
+ );
22
37
  }
23
38
  }
24
39
 
@@ -59,3 +74,86 @@ async function connectorsStatus(ctx) {
59
74
  printResult(io, flags, result);
60
75
  return 0;
61
76
  }
77
+
78
+ async function connectorsPull(ctx) {
79
+ const { client, flags, io } = ctx;
80
+ // Dual key: --collection (a CMS-bound collection), or --provider (resolve/wire),
81
+ // or both (--provider wires an unbound --collection first). At least one required.
82
+ const collectionId = flagStr(flags.collection);
83
+ const provider = flagStr(flags.provider);
84
+ if (!collectionId && !provider) {
85
+ throw new CliError("Pass --collection <id> and/or --provider <webflow|framer|sanity|contentful>");
86
+ }
87
+ const args = compact({ collection_id: collectionId, provider });
88
+ const result = await client.callTool("import_from_cms", args);
89
+ ok(
90
+ ctx,
91
+ `Pulled from ${result?.provider ?? provider ?? "CMS"} into collection ${result?.collection_id ?? collectionId ?? ""}.`
92
+ );
93
+ printResult(io, flags, result);
94
+ return 0;
95
+ }
96
+
97
+ async function connectorsConnect(ctx) {
98
+ const { client, flags, io } = ctx;
99
+ const provider = requireFlag(flags, "provider");
100
+ // api_token is required for every provider; the rest are provider-specific.
101
+ const args = compact({
102
+ provider,
103
+ api_token: requireFlag(flags, "token"),
104
+ project_url: flagStr(flags["project-url"]),
105
+ auto_deploy: flags["no-auto-deploy"] ? false : flagBool(flags["auto-deploy"]) || undefined,
106
+ project_id: flagStr(flags["project-id"]),
107
+ dataset: flagStr(flags.dataset),
108
+ project_name: flagStr(flags["project-name"]),
109
+ workspace_name: flagStr(flags.workspace),
110
+ space_id: flagStr(flags["space-id"]),
111
+ environment_id: flagStr(flags.environment),
112
+ space_name: flagStr(flags["space-name"]),
113
+ default_locale: flagStr(flags.locale),
114
+ });
115
+ const result = await client.callTool("connect_cms", args);
116
+ ok(ctx, `Connected ${provider}${result?.label ? ` (${result.label})` : ""}.`);
117
+ printResult(io, flags, result);
118
+ return 0;
119
+ }
120
+
121
+ async function connectorsDisconnect(ctx) {
122
+ const { client, flags, io } = ctx;
123
+ const provider = requireFlag(flags, "provider");
124
+ const result = await client.callTool("disconnect_cms", { provider });
125
+ ok(ctx, `Disconnected ${provider}.`);
126
+ printResult(io, flags, result);
127
+ return 0;
128
+ }
129
+
130
+ async function connectorsConnections(ctx) {
131
+ const { client, flags, io } = ctx;
132
+ const result = await client.callTool("list_cms_connections", {});
133
+ printResult(io, flags, result);
134
+ return 0;
135
+ }
136
+
137
+ async function connectorsMappings(ctx) {
138
+ const { client, flags, io } = ctx;
139
+ const provider = requireFlag(flags, "provider");
140
+ const result = await client.callTool("list_cms_mappings", { provider });
141
+ printResult(io, flags, result);
142
+ return 0;
143
+ }
144
+
145
+ async function connectorsBind(ctx) {
146
+ const { client, flags, io } = ctx;
147
+ const args = compact({
148
+ collection_id: requireFlag(flags, "collection"),
149
+ provider: requireFlag(flags, "provider"),
150
+ mapping_id: flagStr(flags.mapping),
151
+ });
152
+ const result = await client.callTool("bind_collection_cms", args);
153
+ ok(
154
+ ctx,
155
+ `Bound collection ${result?.collection_id ?? ""} to ${result?.provider ?? ""} (mapping ${result?.mapping_id ?? ""}).`
156
+ );
157
+ printResult(io, flags, result);
158
+ return 0;
159
+ }
@@ -140,6 +140,8 @@ async function cmdOnboardCollection(ctx) {
140
140
  collection_name: flagStr(flags.name),
141
141
  direction: flagStr(flags.about) ?? flagStr(flags.direction),
142
142
  sitemap_url: flagStr(flags.sitemap),
143
+ // Source the existing blog from a connected CMS instead of a sitemap.
144
+ cms_provider: flagStr(flags.cms),
143
145
  });
144
146
 
145
147
  ok(ctx, "Starting collection onboarding…");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@letterstory/cli",
3
- "version": "0.11.0",
3
+ "version": "0.13.0",
4
4
  "description": "Spin up and manage Letterstory phantom blogs from your terminal.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",