@angeloashmore/prismic-cli-poc 0.0.0-pr.8.b80fefa → 0.0.0-pr.9.5366ece

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.
Files changed (58) hide show
  1. package/dist/index.mjs +302 -168
  2. package/package.json +1 -1
  3. package/src/custom-type-add-field-boolean.ts +49 -12
  4. package/src/custom-type-add-field-color.ts +46 -12
  5. package/src/custom-type-add-field-date.ts +46 -12
  6. package/src/custom-type-add-field-embed.ts +46 -12
  7. package/src/custom-type-add-field-geo-point.ts +46 -12
  8. package/src/custom-type-add-field-group.ts +179 -0
  9. package/src/custom-type-add-field-image.ts +46 -12
  10. package/src/custom-type-add-field-key-text.ts +46 -12
  11. package/src/custom-type-add-field-link.ts +46 -12
  12. package/src/custom-type-add-field-number.ts +46 -12
  13. package/src/custom-type-add-field-rich-text.ts +46 -12
  14. package/src/custom-type-add-field-select.ts +47 -21
  15. package/src/custom-type-add-field-timestamp.ts +46 -12
  16. package/src/custom-type-add-field-uid.ts +17 -0
  17. package/src/custom-type-add-field.ts +5 -0
  18. package/src/index.ts +5 -0
  19. package/src/lib/field-path.ts +81 -0
  20. package/src/page-type-add-field-boolean.ts +66 -13
  21. package/src/page-type-add-field-color.ts +66 -13
  22. package/src/page-type-add-field-date.ts +66 -13
  23. package/src/page-type-add-field-embed.ts +66 -13
  24. package/src/page-type-add-field-geo-point.ts +66 -13
  25. package/src/page-type-add-field-group.ts +198 -0
  26. package/src/page-type-add-field-image.ts +66 -13
  27. package/src/page-type-add-field-key-text.ts +66 -13
  28. package/src/page-type-add-field-link.ts +66 -13
  29. package/src/page-type-add-field-number.ts +66 -13
  30. package/src/page-type-add-field-rich-text.ts +66 -13
  31. package/src/page-type-add-field-select.ts +67 -22
  32. package/src/page-type-add-field-timestamp.ts +66 -13
  33. package/src/page-type-add-field-uid.ts +37 -1
  34. package/src/page-type-add-field.ts +5 -0
  35. package/src/page-type-create.ts +25 -0
  36. package/src/repo-create.ts +59 -0
  37. package/src/skill-install.ts +177 -0
  38. package/src/skill-uninstall.ts +85 -0
  39. package/src/skill.ts +50 -0
  40. package/src/slice-add-field-boolean.ts +90 -16
  41. package/src/slice-add-field-color.ts +90 -16
  42. package/src/slice-add-field-date.ts +90 -16
  43. package/src/slice-add-field-embed.ts +90 -16
  44. package/src/slice-add-field-geo-point.ts +90 -16
  45. package/src/slice-add-field-group.ts +191 -0
  46. package/src/slice-add-field-image.ts +90 -16
  47. package/src/slice-add-field-key-text.ts +90 -16
  48. package/src/slice-add-field-link.ts +90 -16
  49. package/src/slice-add-field-number.ts +90 -16
  50. package/src/slice-add-field-rich-text.ts +90 -16
  51. package/src/slice-add-field-select.ts +91 -25
  52. package/src/slice-add-field-timestamp.ts +90 -16
  53. package/src/slice-add-field.ts +5 -0
  54. package/src/slice-create.ts +66 -5
  55. package/src/slice-set-screenshot.ts +235 -0
  56. package/src/slice-view.ts +3 -0
  57. package/src/slice.ts +5 -0
  58. package/src/status.ts +164 -124
package/src/status.ts CHANGED
@@ -30,8 +30,8 @@ import { getWebhooks } from "./webhook-view";
30
30
  const HELP = `
31
31
  Show the status of the current Prismic project.
32
32
 
33
- Includes a "Next:" step showing the most important action to take based on
34
- project state.
33
+ Each section with incomplete items includes "Next steps:" with actionable
34
+ instructions.
35
35
 
36
36
  By default, this command reads the repository from prismic.config.json at the
37
37
  project root.
@@ -57,13 +57,14 @@ type StatusItem = {
57
57
  hint?: string;
58
58
  };
59
59
 
60
+ type NextStep = {
61
+ action: string;
62
+ };
63
+
60
64
  type StatusSection = {
61
65
  title: string;
62
66
  items: StatusItem[];
63
- };
64
-
65
- type NextStep = {
66
- message: string;
67
+ nextSteps?: NextStep[];
67
68
  };
68
69
 
69
70
  function getDocsPath(framework: Framework | undefined): string {
@@ -82,7 +83,7 @@ function getDocsPath(framework: Framework | undefined): string {
82
83
  function getDocsRef(docsPath: string, anchor?: string): string {
83
84
  if (!docsPath) return "";
84
85
  const fullPath = anchor ? `${docsPath}${anchor}` : docsPath;
85
- return ` (run \`prismic docs ${fullPath}\`)`;
86
+ return `\`prismic docs ${fullPath}\``;
86
87
  }
87
88
 
88
89
  function getClientSetupAnchor(framework: Framework | undefined): string {
@@ -116,126 +117,161 @@ function getWriteComponentsAnchor(framework: Framework | undefined): string {
116
117
  }
117
118
  }
118
119
 
119
- function computeNextStep(
120
- sections: StatusSection[],
121
- frameworkInfo: FrameworkInfo,
122
- typeStatuses: TypeWithStatus[],
123
- sliceStatuses: TypeWithStatus[],
124
- slicesWithMissingComponents: string[],
125
- slicesReadyToConnect: string[],
126
- ): NextStep | undefined {
120
+ // Next-step builder functions
121
+
122
+ function buildSetupNextSteps(items: StatusItem[], frameworkInfo: FrameworkInfo): NextStep[] {
123
+ const nextSteps: NextStep[] = [];
127
124
  const docsPath = getDocsPath(frameworkInfo.framework);
128
125
 
129
- // 1. Setup - missing dependencies
130
- const setupSection = sections.find((s) => s.title === "Setup");
131
- const missingDeps = setupSection?.items.filter((i) => !i.done && i.hint === "not installed");
132
- if (missingDeps && missingDeps.length > 0) {
126
+ // Missing dependencies
127
+ const missingDeps = items.filter((i) => !i.done && i.hint === "not installed");
128
+ if (missingDeps.length > 0) {
133
129
  const depsList = missingDeps.map((d) => d.label).join(" ");
134
- return { message: `Install Prismic packages with 'npm install ${depsList}'` };
130
+ nextSteps.push({
131
+ action: `Install dependencies: Run \`npm install ${depsList}\``,
132
+ });
135
133
  }
136
134
 
137
- // 2. Setup - missing client file
138
- const missingClientFile = setupSection?.items.find((i) => !i.done && i.hint?.includes("client"));
135
+ // Missing client file
136
+ const missingClientFile = items.find((i) => !i.done && i.hint?.includes("client"));
139
137
  if (missingClientFile) {
140
- return { message: `Create a ${missingClientFile.label} file${getDocsRef(docsPath, getClientSetupAnchor(frameworkInfo.framework))}` };
138
+ const docsRef = getDocsRef(docsPath, getClientSetupAnchor(frameworkInfo.framework));
139
+ nextSteps.push({
140
+ action: `Create Prismic client file: Run ${docsRef} and create the file as shown`,
141
+ });
141
142
  }
142
143
 
143
- // 3-7. Preview section (in order: local files, then remote config)
144
- const previewSection = sections.find((s) => s.title === "Preview");
145
- if (previewSection) {
146
- // Local files first
147
- const sliceSimRoute = previewSection.items.find(
148
- (i) => i.label === "/slice-simulator route" && !i.done,
149
- );
150
- if (sliceSimRoute) {
151
- return { message: `Create the /slice-simulator route${getDocsRef(docsPath, "#set-up-live-previewing")}` };
152
- }
144
+ return nextSteps;
145
+ }
153
146
 
154
- const apiPreview = previewSection.items.find(
155
- (i) => i.label === "/api/preview endpoint" && !i.done,
156
- );
157
- if (apiPreview) {
158
- return { message: `Create the /api/preview route${getDocsRef(docsPath, getPreviewSetupAnchor(frameworkInfo.framework))}` };
159
- }
147
+ function buildTypesNextSteps(statuses: TypeWithStatus[]): NextStep[] {
148
+ const nextSteps: NextStep[] = [];
160
149
 
161
- const exitPreview = previewSection.items.find(
162
- (i) => i.label === "/api/exit-preview endpoint" && !i.done,
163
- );
164
- if (exitPreview) {
165
- return { message: `Create the /api/exit-preview route${getDocsRef(docsPath, getPreviewSetupAnchor(frameworkInfo.framework))}` };
166
- }
150
+ const hasToPush = statuses.some((t) => t.status === "to_push");
151
+ const hasToPull = statuses.some((t) => t.status === "to_pull");
167
152
 
168
- // Remote config
169
- const simulatorUrl = previewSection.items.find(
170
- (i) => i.label === "Slice simulator URL" && !i.done,
171
- );
172
- if (simulatorUrl) {
173
- return { message: `Configure the slice simulator URL with 'prismic preview set-simulator'` };
174
- }
153
+ if (hasToPush) {
154
+ nextSteps.push({
155
+ action: "Push local models to Prismic: Run `prismic push`",
156
+ });
157
+ }
175
158
 
176
- const previewEnv = previewSection.items.find(
177
- (i) => i.label === "Preview environment" && !i.done,
178
- );
179
- if (previewEnv) {
180
- return { message: `Add a preview environment with 'prismic preview add'` };
181
- }
159
+ if (hasToPull) {
160
+ nextSteps.push({
161
+ action: "Pull remote models from Prismic: Run `prismic pull`",
162
+ });
163
+ }
164
+
165
+ return nextSteps;
166
+ }
167
+
168
+ function buildSlicesNextSteps(
169
+ statuses: TypeWithStatus[],
170
+ missingComponents: string[],
171
+ slicesReadyToConnect: string[],
172
+ frameworkInfo: FrameworkInfo,
173
+ ): NextStep[] {
174
+ const nextSteps: NextStep[] = [];
175
+ const docsPath = getDocsPath(frameworkInfo.framework);
176
+
177
+ if (missingComponents.length > 0) {
178
+ const docsRef = getDocsRef(docsPath, getWriteComponentsAnchor(frameworkInfo.framework));
179
+ nextSteps.push({
180
+ action: `Implement slice components: Run ${docsRef} and create each component file`,
181
+ });
182
182
  }
183
183
 
184
- // 8. Models to pull
185
- const hasToPull =
186
- typeStatuses.some((t) => t.status === "to_pull") ||
187
- sliceStatuses.some((s) => s.status === "to_pull");
184
+ const hasToPull = statuses.some((t) => t.status === "to_pull");
185
+ const hasToPush = statuses.some((t) => t.status === "to_push");
186
+
188
187
  if (hasToPull) {
189
- return { message: `Pull remote models with 'prismic pull'` };
188
+ nextSteps.push({
189
+ action: "Pull remote models from Prismic: Run `prismic pull`",
190
+ });
190
191
  }
191
192
 
192
- // 8.5 Slices ready to connect to a page type (before pushing)
193
+ // Slices should be connected to page types before pushing
193
194
  if (slicesReadyToConnect.length > 0) {
194
195
  const sorted = [...slicesReadyToConnect].sort();
195
196
  const sliceName = sorted[0];
196
- return {
197
- message: `Connect ${sliceName} to a page type with 'prismic page-type connect-slice <type-id> ${sliceName}'`,
198
- };
197
+ nextSteps.push({
198
+ action: `Connect slice to page type: Run \`prismic page-type connect-slice <type-id> ${sliceName}\``,
199
+ });
199
200
  }
200
201
 
201
- // 9. Models to push
202
- const hasToPush =
203
- typeStatuses.some((t) => t.status === "to_push") ||
204
- sliceStatuses.some((s) => s.status === "to_push");
205
202
  if (hasToPush) {
206
- return { message: `Push local models with 'prismic push'` };
203
+ nextSteps.push({
204
+ action: "Push local models to Prismic: Run `prismic push`",
205
+ });
207
206
  }
208
207
 
209
- // 10. Slice components to implement (first alphabetically)
210
- if (slicesWithMissingComponents.length > 0) {
211
- const sorted = [...slicesWithMissingComponents].sort();
212
- const sliceName = sorted[0];
213
- const slicesDir = getSlicesDirectory(frameworkInfo);
214
- const ext = getSliceComponentExtensions(frameworkInfo.framework)[0];
215
- const path = `${slicesDir}${sliceName}/index${ext}`;
216
- return { message: `Implement the ${sliceName} slice component at ${path}${getDocsRef(docsPath, getWriteComponentsAnchor(frameworkInfo.framework))}` };
208
+ return nextSteps;
209
+ }
210
+
211
+ function buildPreviewNextSteps(items: StatusItem[], frameworkInfo: FrameworkInfo): NextStep[] {
212
+ const nextSteps: NextStep[] = [];
213
+ const docsPath = getDocsPath(frameworkInfo.framework);
214
+
215
+ // Check for missing /slice-simulator route
216
+ const sliceSimRoute = items.find((i) => i.label === "/slice-simulator route" && !i.done);
217
+ if (sliceSimRoute) {
218
+ const docsRef = getDocsRef(docsPath, "#set-up-live-previewing");
219
+ nextSteps.push({
220
+ action: `Create /slice-simulator route: Run ${docsRef} and create the route file as shown`,
221
+ });
217
222
  }
218
223
 
219
- // 11-12. Deployment (Next.js only)
220
- const deploymentSection = sections.find((s) => s.title === "Deployment");
221
- if (deploymentSection) {
222
- const revalidateEndpoint = deploymentSection.items.find(
223
- (i) => i.label === "/api/revalidate endpoint" && !i.done,
224
- );
225
- if (revalidateEndpoint) {
226
- return { message: `Create the /api/revalidate route for ISR${getDocsRef(docsPath, "#handle-content-changes")}` };
227
- }
224
+ // Check for missing simulator URL config
225
+ const simulatorUrl = items.find((i) => i.label === "Slice simulator URL" && !i.done);
226
+ if (simulatorUrl) {
227
+ nextSteps.push({
228
+ action: "Configure slice simulator URL: Run `prismic preview set-simulator`",
229
+ });
230
+ }
228
231
 
229
- const webhook = deploymentSection.items.find(
230
- (i) => i.label === "Revalidation webhook" && !i.done,
231
- );
232
- if (webhook) {
233
- return { message: `Create a revalidation webhook with 'prismic webhook create'` };
234
- }
232
+ // Check for missing preview endpoints (combine /api/preview and /api/exit-preview)
233
+ const apiPreview = items.find((i) => i.label === "/api/preview endpoint" && !i.done);
234
+ const exitPreview = items.find((i) => i.label === "/api/exit-preview endpoint" && !i.done);
235
+ if (apiPreview || exitPreview) {
236
+ const docsRef = getDocsRef(docsPath, getPreviewSetupAnchor(frameworkInfo.framework));
237
+ nextSteps.push({
238
+ action: `Create preview endpoints: Run ${docsRef} and create the endpoint files as shown`,
239
+ });
240
+ }
241
+
242
+ // Check for missing preview environment
243
+ const previewEnv = items.find((i) => i.label === "Preview environment" && !i.done);
244
+ if (previewEnv) {
245
+ nextSteps.push({
246
+ action: "Add preview environment: Run `prismic preview add`",
247
+ });
248
+ }
249
+
250
+ return nextSteps;
251
+ }
252
+
253
+ function buildDeploymentNextSteps(items: StatusItem[], frameworkInfo: FrameworkInfo): NextStep[] {
254
+ const nextSteps: NextStep[] = [];
255
+ const docsPath = getDocsPath(frameworkInfo.framework);
256
+
257
+ // Check for missing /api/revalidate endpoint
258
+ const revalidateEndpoint = items.find((i) => i.label === "/api/revalidate endpoint" && !i.done);
259
+ if (revalidateEndpoint) {
260
+ const docsRef = getDocsRef(docsPath, "#handle-content-changes");
261
+ nextSteps.push({
262
+ action: `Create /api/revalidate endpoint: Run ${docsRef} and create the endpoint as shown`,
263
+ });
264
+ }
265
+
266
+ // Check for missing revalidation webhook
267
+ const webhook = items.find((i) => i.label === "Revalidation webhook" && !i.done);
268
+ if (webhook) {
269
+ nextSteps.push({
270
+ action: "Create revalidation webhook: Run `prismic webhook create`",
271
+ });
235
272
  }
236
273
 
237
- // All complete
238
- return undefined;
274
+ return nextSteps;
239
275
  }
240
276
 
241
277
  export async function status(): Promise<void> {
@@ -304,25 +340,21 @@ export async function status(): Promise<void> {
304
340
 
305
341
  const sections: StatusSection[] = [];
306
342
 
307
- // Track statuses for next step computation
308
- let typeStatuses: TypeWithStatus[] = [];
309
- let sliceStatuses: TypeWithStatus[] = [];
310
- let slicesWithMissingComponents: string[] = [];
311
- let slicesReadyToConnect: string[] = [];
312
-
313
343
  // Setup section
314
344
  const setupSection = await buildSetupSection(frameworkInfo, installedDeps);
345
+ setupSection.nextSteps = buildSetupNextSteps(setupSection.items, frameworkInfo);
315
346
  sections.push(setupSection);
316
347
 
317
348
  // Types sections (Page Types and Custom Types)
318
349
  if (localTypesResult.ok && remoteTypesResult.ok) {
319
- const { pageTypes, customTypes, allTypeStatuses } = buildTypeSections(
350
+ const { pageTypes, customTypes, pageTypeStatuses, customTypeStatuses } = buildTypeSections(
320
351
  localTypesResult.value,
321
352
  remoteTypesResult.value,
322
353
  );
354
+ pageTypes.nextSteps = buildTypesNextSteps(pageTypeStatuses);
355
+ customTypes.nextSteps = buildTypesNextSteps(customTypeStatuses);
323
356
  sections.push(pageTypes);
324
357
  sections.push(customTypes);
325
- typeStatuses = allTypeStatuses;
326
358
  }
327
359
 
328
360
  // Slices section
@@ -331,17 +363,20 @@ export async function status(): Promise<void> {
331
363
  section: slicesSection,
332
364
  statuses,
333
365
  missingComponents,
334
- slicesReadyToConnect: readyToConnect,
366
+ slicesReadyToConnect,
335
367
  } = await buildSlicesSection(
336
368
  localSlicesResult.value,
337
369
  remoteSlicesResult.value,
338
370
  frameworkInfo,
339
371
  localTypesResult.ok ? localTypesResult.value : [],
340
372
  );
373
+ slicesSection.nextSteps = buildSlicesNextSteps(
374
+ statuses,
375
+ missingComponents,
376
+ slicesReadyToConnect,
377
+ frameworkInfo,
378
+ );
341
379
  sections.push(slicesSection);
342
- sliceStatuses = statuses;
343
- slicesWithMissingComponents = missingComponents;
344
- slicesReadyToConnect = readyToConnect;
345
380
  }
346
381
 
347
382
  // Preview section
@@ -350,6 +385,7 @@ export async function status(): Promise<void> {
350
385
  previewsResult.ok ? previewsResult.value : undefined,
351
386
  repoInfoResult.ok ? repoInfoResult.value.simulator_url : undefined,
352
387
  );
388
+ previewSection.nextSteps = buildPreviewNextSteps(previewSection.items, frameworkInfo);
353
389
  sections.push(previewSection);
354
390
 
355
391
  // Deployment section (Next.js only)
@@ -358,6 +394,7 @@ export async function status(): Promise<void> {
358
394
  frameworkInfo,
359
395
  webhooksResult.ok ? webhooksResult.value : [],
360
396
  );
397
+ deploymentSection.nextSteps = buildDeploymentNextSteps(deploymentSection.items, frameworkInfo);
361
398
  sections.push(deploymentSection);
362
399
  }
363
400
 
@@ -365,19 +402,6 @@ export async function status(): Promise<void> {
365
402
  for (const section of sections) {
366
403
  printSection(section);
367
404
  }
368
-
369
- // Print next step
370
- const nextStep = computeNextStep(
371
- sections,
372
- frameworkInfo,
373
- typeStatuses,
374
- sliceStatuses,
375
- slicesWithMissingComponents,
376
- slicesReadyToConnect,
377
- );
378
- if (nextStep) {
379
- console.info(`Next: ${nextStep.message}`);
380
- }
381
405
  }
382
406
 
383
407
  function printSection(section: StatusSection): void {
@@ -409,6 +433,15 @@ function printSection(section: StatusSection): void {
409
433
  console.info(` ${CIRCLE} ${item.label}${hint}`);
410
434
  }
411
435
 
436
+ // Print next steps if there are any
437
+ if (section.nextSteps && section.nextSteps.length > 0) {
438
+ console.info("");
439
+ console.info(" Next steps:");
440
+ for (const step of section.nextSteps) {
441
+ console.info(` - ${step.action}`);
442
+ }
443
+ }
444
+
412
445
  console.info("");
413
446
  }
414
447
 
@@ -561,7 +594,12 @@ function computeTypeStatus<T extends { id: string }>(local: T[], remote: T[]): T
561
594
  function buildTypeSections(
562
595
  localTypes: CustomType[],
563
596
  remoteTypes: CustomType[],
564
- ): { pageTypes: StatusSection; customTypes: StatusSection; allTypeStatuses: TypeWithStatus[] } {
597
+ ): {
598
+ pageTypes: StatusSection;
599
+ customTypes: StatusSection;
600
+ pageTypeStatuses: TypeWithStatus[];
601
+ customTypeStatuses: TypeWithStatus[];
602
+ } {
565
603
  const typeStatuses = computeTypeStatus(localTypes, remoteTypes);
566
604
 
567
605
  // Separate by format
@@ -594,7 +632,8 @@ function buildTypeSections(
594
632
  return {
595
633
  pageTypes: { title: "Page Types", items: pageTypeItems },
596
634
  customTypes: { title: "Custom Types", items: customTypeItems },
597
- allTypeStatuses: typeStatuses,
635
+ pageTypeStatuses,
636
+ customTypeStatuses,
598
637
  };
599
638
  }
600
639
 
@@ -670,6 +709,7 @@ async function buildSlicesSection(
670
709
  slicesReadyToConnect.push(slice.label);
671
710
  }
672
711
  }
712
+
673
713
  // Check if component is implemented
674
714
  const componentExists = await checkSliceComponent(info, slicesDir, slice.id, extensions);
675
715