@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
@@ -4,6 +4,8 @@ import { writeFile } from "node:fs/promises";
4
4
  import { parseArgs } from "node:util";
5
5
 
6
6
  import { buildTypes } from "./codegen-types";
7
+ import { findGroupInVariation, isGroupField, parseFieldPath, validateNestedFieldPath } from "./lib/field-path";
8
+ import { type Framework, detectFrameworkInfo } from "./lib/framework";
7
9
  import { stringify } from "./lib/json";
8
10
  import { findSliceModel } from "./lib/slice";
9
11
  import { humanReadable } from "./lib/string";
@@ -40,6 +42,28 @@ EXAMPLES
40
42
  prismic slice add-field rich-text blog post --multi "paragraph,strong,em,hyperlink" --allow-target-blank
41
43
  `.trim();
42
44
 
45
+ function getDocsPath(framework: Framework): string {
46
+ switch (framework) {
47
+ case "next":
48
+ return "nextjs/with-cli";
49
+ case "nuxt":
50
+ return "nuxt/with-cli";
51
+ case "sveltekit":
52
+ return "sveltekit/with-cli";
53
+ }
54
+ }
55
+
56
+ function getWriteComponentsAnchor(framework: Framework): string {
57
+ switch (framework) {
58
+ case "nuxt":
59
+ return "#write-vue-components";
60
+ case "sveltekit":
61
+ return "#write-svelte-components";
62
+ default:
63
+ return "#write-react-components";
64
+ }
65
+ }
66
+
43
67
  export async function sliceAddFieldRichText(): Promise<void> {
44
68
  const {
45
69
  values: {
@@ -87,6 +111,15 @@ export async function sliceAddFieldRichText(): Promise<void> {
87
111
  return;
88
112
  }
89
113
 
114
+ // Parse and validate field path
115
+ const fieldPath = parseFieldPath(fieldId);
116
+ const pathValidation = validateNestedFieldPath(fieldPath);
117
+ if (!pathValidation.ok) {
118
+ console.error(pathValidation.error);
119
+ process.exitCode = 1;
120
+ return;
121
+ }
122
+
90
123
  // Find the slice model
91
124
  const result = await findSliceModel(sliceId);
92
125
  if (!result.ok) {
@@ -122,20 +155,11 @@ export async function sliceAddFieldRichText(): Promise<void> {
122
155
  targetVariation.primary = {};
123
156
  }
124
157
 
125
- // Check if field already exists in any variation
126
- for (const v of model.variations) {
127
- if (v.primary?.[fieldId]) {
128
- console.error(`Field "${fieldId}" already exists in variation "${v.id}"`);
129
- process.exitCode = 1;
130
- return;
131
- }
132
- }
133
-
134
158
  // Build field definition
135
159
  const fieldDefinition: RichText = {
136
160
  type: "StructuredText",
137
161
  config: {
138
- label: label ?? humanReadable(fieldId),
162
+ label: label ?? humanReadable(fieldPath.type === "nested" ? fieldPath.nestedFieldId : fieldId),
139
163
  ...(placeholder && { placeholder }),
140
164
  ...(single && { single }),
141
165
  ...(multi && { multi }),
@@ -143,8 +167,44 @@ export async function sliceAddFieldRichText(): Promise<void> {
143
167
  },
144
168
  };
145
169
 
146
- // Add field to variation
147
- targetVariation.primary[fieldId] = fieldDefinition;
170
+ // Add field to variation (with nested field support)
171
+ if (fieldPath.type === "nested") {
172
+ const groupResult = findGroupInVariation(targetVariation.primary, fieldPath.groupId, targetVariation.id);
173
+ if (!groupResult.ok) {
174
+ console.error(groupResult.error);
175
+ process.exitCode = 1;
176
+ return;
177
+ }
178
+ // Check if nested field already exists
179
+ if (groupResult.group.config.fields[fieldPath.nestedFieldId]) {
180
+ console.error(
181
+ `Field "${fieldPath.nestedFieldId}" already exists in group "${fieldPath.groupId}"`,
182
+ );
183
+ process.exitCode = 1;
184
+ return;
185
+ }
186
+ groupResult.group.config.fields[fieldPath.nestedFieldId] = fieldDefinition;
187
+ } else {
188
+ // Check if field already exists in any variation (at top level or in groups)
189
+ for (const v of model.variations) {
190
+ if (v.primary?.[fieldId]) {
191
+ console.error(`Field "${fieldId}" already exists in variation "${v.id}"`);
192
+ process.exitCode = 1;
193
+ return;
194
+ }
195
+ // Also check inside groups
196
+ for (const [groupFieldId, groupField] of Object.entries(v.primary ?? {})) {
197
+ if (isGroupField(groupField) && groupField.config.fields[fieldId]) {
198
+ console.error(
199
+ `Field "${fieldId}" already exists in group "${groupFieldId}" in variation "${v.id}"`,
200
+ );
201
+ process.exitCode = 1;
202
+ return;
203
+ }
204
+ }
205
+ }
206
+ targetVariation.primary[fieldId] = fieldDefinition;
207
+ }
148
208
 
149
209
  // Write updated model
150
210
  try {
@@ -159,9 +219,15 @@ export async function sliceAddFieldRichText(): Promise<void> {
159
219
  return;
160
220
  }
161
221
 
162
- console.info(
163
- `Added field "${fieldId}" (StructuredText) to "${targetVariation.id}" variation in ${sliceId}`,
164
- );
222
+ if (fieldPath.type === "nested") {
223
+ console.info(
224
+ `Added field "${fieldPath.nestedFieldId}" (StructuredText) to group "${fieldPath.groupId}" in ${sliceId}`,
225
+ );
226
+ } else {
227
+ console.info(
228
+ `Added field "${fieldId}" (StructuredText) to "${targetVariation.id}" variation in ${sliceId}`,
229
+ );
230
+ }
165
231
 
166
232
  try {
167
233
  await buildTypes({ output: types });
@@ -172,5 +238,13 @@ export async function sliceAddFieldRichText(): Promise<void> {
172
238
 
173
239
  console.info();
174
240
  console.info("Next: Add more fields with `prismic slice add-field`");
175
- console.info(" Run `prismic status` when done to find next steps");
241
+
242
+ const frameworkInfo = await detectFrameworkInfo();
243
+ if (frameworkInfo?.framework) {
244
+ const docsPath = getDocsPath(frameworkInfo.framework);
245
+ const anchor = getWriteComponentsAnchor(frameworkInfo.framework);
246
+ console.info(
247
+ ` Run \`prismic docs ${docsPath}${anchor}\` to learn how to implement the slice's component`,
248
+ );
249
+ }
176
250
  }
@@ -4,6 +4,8 @@ import { writeFile } from "node:fs/promises";
4
4
  import { parseArgs } from "node:util";
5
5
 
6
6
  import { buildTypes } from "./codegen-types";
7
+ import { findGroupInVariation, isGroupField, parseFieldPath, validateNestedFieldPath } from "./lib/field-path";
8
+ import { type Framework, detectFrameworkInfo } from "./lib/framework";
7
9
  import { stringify } from "./lib/json";
8
10
  import { findSliceModel } from "./lib/slice";
9
11
  import { humanReadable } from "./lib/string";
@@ -33,17 +35,31 @@ EXAMPLES
33
35
  prismic slice add-field select product size --option "small" --option "medium" --option "large" --label "Size"
34
36
  `.trim();
35
37
 
38
+ function getDocsPath(framework: Framework): string {
39
+ switch (framework) {
40
+ case "next":
41
+ return "nextjs/with-cli";
42
+ case "nuxt":
43
+ return "nuxt/with-cli";
44
+ case "sveltekit":
45
+ return "sveltekit/with-cli";
46
+ }
47
+ }
48
+
49
+ function getWriteComponentsAnchor(framework: Framework): string {
50
+ switch (framework) {
51
+ case "nuxt":
52
+ return "#write-vue-components";
53
+ case "sveltekit":
54
+ return "#write-svelte-components";
55
+ default:
56
+ return "#write-react-components";
57
+ }
58
+ }
59
+
36
60
  export async function sliceAddFieldSelect(): Promise<void> {
37
61
  const {
38
- values: {
39
- help,
40
- variation,
41
- label,
42
- placeholder,
43
- option,
44
- default: defaultValue,
45
- types,
46
- },
62
+ values: { help, variation, label, placeholder, option, default: defaultValue, types },
47
63
  positionals: [sliceId, fieldId],
48
64
  } = parseArgs({
49
65
  args: process.argv.slice(5), // skip: node, script, "slice", "add-field", "select"
@@ -78,6 +94,15 @@ export async function sliceAddFieldSelect(): Promise<void> {
78
94
  return;
79
95
  }
80
96
 
97
+ // Parse and validate field path
98
+ const fieldPath = parseFieldPath(fieldId);
99
+ const pathValidation = validateNestedFieldPath(fieldPath);
100
+ if (!pathValidation.ok) {
101
+ console.error(pathValidation.error);
102
+ process.exitCode = 1;
103
+ return;
104
+ }
105
+
81
106
  // Find the slice model
82
107
  const result = await findSliceModel(sliceId);
83
108
  if (!result.ok) {
@@ -113,28 +138,55 @@ export async function sliceAddFieldSelect(): Promise<void> {
113
138
  targetVariation.primary = {};
114
139
  }
115
140
 
116
- // Check if field already exists in any variation
117
- for (const v of model.variations) {
118
- if (v.primary?.[fieldId]) {
119
- console.error(`Field "${fieldId}" already exists in variation "${v.id}"`);
120
- process.exitCode = 1;
121
- return;
122
- }
123
- }
124
-
125
141
  // Build field definition
126
142
  const fieldDefinition: Select = {
127
143
  type: "Select",
128
144
  config: {
129
- label: label ?? humanReadable(fieldId),
145
+ label: label ?? humanReadable(fieldPath.type === "nested" ? fieldPath.nestedFieldId : fieldId),
130
146
  ...(placeholder && { placeholder }),
131
147
  ...(option && option.length > 0 && { options: option }),
132
148
  ...(defaultValue && { default_value: defaultValue }),
133
149
  },
134
150
  };
135
151
 
136
- // Add field to variation
137
- targetVariation.primary[fieldId] = fieldDefinition;
152
+ // Add field to variation (with nested field support)
153
+ if (fieldPath.type === "nested") {
154
+ const groupResult = findGroupInVariation(targetVariation.primary, fieldPath.groupId, targetVariation.id);
155
+ if (!groupResult.ok) {
156
+ console.error(groupResult.error);
157
+ process.exitCode = 1;
158
+ return;
159
+ }
160
+ // Check if nested field already exists
161
+ if (groupResult.group.config.fields[fieldPath.nestedFieldId]) {
162
+ console.error(
163
+ `Field "${fieldPath.nestedFieldId}" already exists in group "${fieldPath.groupId}"`,
164
+ );
165
+ process.exitCode = 1;
166
+ return;
167
+ }
168
+ groupResult.group.config.fields[fieldPath.nestedFieldId] = fieldDefinition;
169
+ } else {
170
+ // Check if field already exists in any variation (at top level or in groups)
171
+ for (const v of model.variations) {
172
+ if (v.primary?.[fieldId]) {
173
+ console.error(`Field "${fieldId}" already exists in variation "${v.id}"`);
174
+ process.exitCode = 1;
175
+ return;
176
+ }
177
+ // Also check inside groups
178
+ for (const [groupFieldId, groupField] of Object.entries(v.primary ?? {})) {
179
+ if (isGroupField(groupField) && groupField.config.fields[fieldId]) {
180
+ console.error(
181
+ `Field "${fieldId}" already exists in group "${groupFieldId}" in variation "${v.id}"`,
182
+ );
183
+ process.exitCode = 1;
184
+ return;
185
+ }
186
+ }
187
+ }
188
+ targetVariation.primary[fieldId] = fieldDefinition;
189
+ }
138
190
 
139
191
  // Write updated model
140
192
  try {
@@ -149,9 +201,15 @@ export async function sliceAddFieldSelect(): Promise<void> {
149
201
  return;
150
202
  }
151
203
 
152
- console.info(
153
- `Added field "${fieldId}" (Select) to "${targetVariation.id}" variation in ${sliceId}`,
154
- );
204
+ if (fieldPath.type === "nested") {
205
+ console.info(
206
+ `Added field "${fieldPath.nestedFieldId}" (Select) to group "${fieldPath.groupId}" in ${sliceId}`,
207
+ );
208
+ } else {
209
+ console.info(
210
+ `Added field "${fieldId}" (Select) to "${targetVariation.id}" variation in ${sliceId}`,
211
+ );
212
+ }
155
213
 
156
214
  try {
157
215
  await buildTypes({ output: types });
@@ -162,5 +220,13 @@ export async function sliceAddFieldSelect(): Promise<void> {
162
220
 
163
221
  console.info();
164
222
  console.info("Next: Add more fields with `prismic slice add-field`");
165
- console.info(" Run `prismic status` when done to find next steps");
223
+
224
+ const frameworkInfo = await detectFrameworkInfo();
225
+ if (frameworkInfo?.framework) {
226
+ const docsPath = getDocsPath(frameworkInfo.framework);
227
+ const anchor = getWriteComponentsAnchor(frameworkInfo.framework);
228
+ console.info(
229
+ ` Run \`prismic docs ${docsPath}${anchor}\` to learn how to implement the slice's component`,
230
+ );
231
+ }
166
232
  }
@@ -4,6 +4,8 @@ import { writeFile } from "node:fs/promises";
4
4
  import { parseArgs } from "node:util";
5
5
 
6
6
  import { buildTypes } from "./codegen-types";
7
+ import { findGroupInVariation, isGroupField, parseFieldPath, validateNestedFieldPath } from "./lib/field-path";
8
+ import { type Framework, detectFrameworkInfo } from "./lib/framework";
7
9
  import { stringify } from "./lib/json";
8
10
  import { findSliceModel } from "./lib/slice";
9
11
  import { humanReadable } from "./lib/string";
@@ -31,6 +33,28 @@ EXAMPLES
31
33
  prismic slice add-field timestamp schedule meeting_time --variation "detailed"
32
34
  `.trim();
33
35
 
36
+ function getDocsPath(framework: Framework): string {
37
+ switch (framework) {
38
+ case "next":
39
+ return "nextjs/with-cli";
40
+ case "nuxt":
41
+ return "nuxt/with-cli";
42
+ case "sveltekit":
43
+ return "sveltekit/with-cli";
44
+ }
45
+ }
46
+
47
+ function getWriteComponentsAnchor(framework: Framework): string {
48
+ switch (framework) {
49
+ case "nuxt":
50
+ return "#write-vue-components";
51
+ case "sveltekit":
52
+ return "#write-svelte-components";
53
+ default:
54
+ return "#write-react-components";
55
+ }
56
+ }
57
+
34
58
  export async function sliceAddFieldTimestamp(): Promise<void> {
35
59
  const {
36
60
  values: { help, variation, label, placeholder, types },
@@ -66,6 +90,15 @@ export async function sliceAddFieldTimestamp(): Promise<void> {
66
90
  return;
67
91
  }
68
92
 
93
+ // Parse and validate field path
94
+ const fieldPath = parseFieldPath(fieldId);
95
+ const pathValidation = validateNestedFieldPath(fieldPath);
96
+ if (!pathValidation.ok) {
97
+ console.error(pathValidation.error);
98
+ process.exitCode = 1;
99
+ return;
100
+ }
101
+
69
102
  // Find the slice model
70
103
  const result = await findSliceModel(sliceId);
71
104
  if (!result.ok) {
@@ -101,26 +134,53 @@ export async function sliceAddFieldTimestamp(): Promise<void> {
101
134
  targetVariation.primary = {};
102
135
  }
103
136
 
104
- // Check if field already exists in any variation
105
- for (const v of model.variations) {
106
- if (v.primary?.[fieldId]) {
107
- console.error(`Field "${fieldId}" already exists in variation "${v.id}"`);
108
- process.exitCode = 1;
109
- return;
110
- }
111
- }
112
-
113
137
  // Build field definition
114
138
  const fieldDefinition: Timestamp = {
115
139
  type: "Timestamp",
116
140
  config: {
117
- label: label ?? humanReadable(fieldId),
141
+ label: label ?? humanReadable(fieldPath.type === "nested" ? fieldPath.nestedFieldId : fieldId),
118
142
  ...(placeholder && { placeholder }),
119
143
  },
120
144
  };
121
145
 
122
- // Add field to variation
123
- targetVariation.primary[fieldId] = fieldDefinition;
146
+ // Add field to variation (with nested field support)
147
+ if (fieldPath.type === "nested") {
148
+ const groupResult = findGroupInVariation(targetVariation.primary, fieldPath.groupId, targetVariation.id);
149
+ if (!groupResult.ok) {
150
+ console.error(groupResult.error);
151
+ process.exitCode = 1;
152
+ return;
153
+ }
154
+ // Check if nested field already exists
155
+ if (groupResult.group.config.fields[fieldPath.nestedFieldId]) {
156
+ console.error(
157
+ `Field "${fieldPath.nestedFieldId}" already exists in group "${fieldPath.groupId}"`,
158
+ );
159
+ process.exitCode = 1;
160
+ return;
161
+ }
162
+ groupResult.group.config.fields[fieldPath.nestedFieldId] = fieldDefinition;
163
+ } else {
164
+ // Check if field already exists in any variation (at top level or in groups)
165
+ for (const v of model.variations) {
166
+ if (v.primary?.[fieldId]) {
167
+ console.error(`Field "${fieldId}" already exists in variation "${v.id}"`);
168
+ process.exitCode = 1;
169
+ return;
170
+ }
171
+ // Also check inside groups
172
+ for (const [groupFieldId, groupField] of Object.entries(v.primary ?? {})) {
173
+ if (isGroupField(groupField) && groupField.config.fields[fieldId]) {
174
+ console.error(
175
+ `Field "${fieldId}" already exists in group "${groupFieldId}" in variation "${v.id}"`,
176
+ );
177
+ process.exitCode = 1;
178
+ return;
179
+ }
180
+ }
181
+ }
182
+ targetVariation.primary[fieldId] = fieldDefinition;
183
+ }
124
184
 
125
185
  // Write updated model
126
186
  try {
@@ -135,9 +195,15 @@ export async function sliceAddFieldTimestamp(): Promise<void> {
135
195
  return;
136
196
  }
137
197
 
138
- console.info(
139
- `Added field "${fieldId}" (Timestamp) to "${targetVariation.id}" variation in ${sliceId}`,
140
- );
198
+ if (fieldPath.type === "nested") {
199
+ console.info(
200
+ `Added field "${fieldPath.nestedFieldId}" (Timestamp) to group "${fieldPath.groupId}" in ${sliceId}`,
201
+ );
202
+ } else {
203
+ console.info(
204
+ `Added field "${fieldId}" (Timestamp) to "${targetVariation.id}" variation in ${sliceId}`,
205
+ );
206
+ }
141
207
 
142
208
  try {
143
209
  await buildTypes({ output: types });
@@ -148,5 +214,13 @@ export async function sliceAddFieldTimestamp(): Promise<void> {
148
214
 
149
215
  console.info();
150
216
  console.info("Next: Add more fields with `prismic slice add-field`");
151
- console.info(" Run `prismic status` when done to find next steps");
217
+
218
+ const frameworkInfo = await detectFrameworkInfo();
219
+ if (frameworkInfo?.framework) {
220
+ const docsPath = getDocsPath(frameworkInfo.framework);
221
+ const anchor = getWriteComponentsAnchor(frameworkInfo.framework);
222
+ console.info(
223
+ ` Run \`prismic docs ${docsPath}${anchor}\` to learn how to implement the slice's component`,
224
+ );
225
+ }
152
226
  }
@@ -5,6 +5,7 @@ import { sliceAddFieldColor } from "./slice-add-field-color";
5
5
  import { sliceAddFieldDate } from "./slice-add-field-date";
6
6
  import { sliceAddFieldEmbed } from "./slice-add-field-embed";
7
7
  import { sliceAddFieldGeoPoint } from "./slice-add-field-geo-point";
8
+ import { sliceAddFieldGroup } from "./slice-add-field-group";
8
9
  import { sliceAddFieldImage } from "./slice-add-field-image";
9
10
  import { sliceAddFieldKeyText } from "./slice-add-field-key-text";
10
11
  import { sliceAddFieldLink } from "./slice-add-field-link";
@@ -25,6 +26,7 @@ FIELD TYPES
25
26
  date Date picker
26
27
  embed Embed (oEmbed)
27
28
  geo-point Geographic coordinates
29
+ group Repeatable group of fields
28
30
  image Image
29
31
  key-text Single-line text
30
32
  link Any link type
@@ -74,6 +76,9 @@ export async function sliceAddField(): Promise<void> {
74
76
  case "geo-point":
75
77
  await sliceAddFieldGeoPoint();
76
78
  break;
79
+ case "group":
80
+ await sliceAddFieldGroup();
81
+ break;
77
82
  case "image":
78
83
  await sliceAddFieldImage();
79
84
  break;
@@ -5,8 +5,11 @@ import { parseArgs } from "node:util";
5
5
  import * as v from "valibot";
6
6
 
7
7
  import { buildTypes } from "./codegen-types";
8
+ import { isAuthenticated } from "./lib/auth";
9
+ import { safeGetRepositoryFromConfig } from "./lib/config";
8
10
  import { exists, findUpward } from "./lib/file";
9
11
  import { stringify } from "./lib/json";
12
+ import { uploadScreenshot } from "./slice-set-screenshot";
10
13
 
11
14
  const HELP = `
12
15
  Create a new slice in a Prismic project.
@@ -18,9 +21,11 @@ ARGUMENTS
18
21
  id Slice identifier (required)
19
22
 
20
23
  FLAGS
21
- -n, --name string Display name for the slice
22
- --types string Output file for generated types (default: "prismicio-types.d.ts")
23
- -h, --help Show help for command
24
+ -n, --name string Display name for the slice
25
+ --screenshot string Path to screenshot image for default variation
26
+ -r, --repo string Repository name (required for screenshot)
27
+ --types string Output file for generated types (default: "prismicio-types.d.ts")
28
+ -h, --help Show help for command
24
29
 
25
30
  LEARN MORE
26
31
  Use \`prismic slice <command> --help\` for more information about a command.
@@ -28,12 +33,14 @@ LEARN MORE
28
33
 
29
34
  export async function sliceCreate(): Promise<void> {
30
35
  const {
31
- values: { help, name, types },
36
+ values: { help, name, types, screenshot, repo: repoFlag },
32
37
  positionals: [id],
33
38
  } = parseArgs({
34
39
  args: process.argv.slice(4), // skip: node, script, "slice", "create"
35
40
  options: {
36
41
  name: { type: "string", short: "n" },
42
+ screenshot: { type: "string" },
43
+ repo: { type: "string", short: "r" },
37
44
  types: { type: "string" },
38
45
  help: { type: "boolean", short: "h" },
39
46
  },
@@ -51,6 +58,60 @@ export async function sliceCreate(): Promise<void> {
51
58
  return;
52
59
  }
53
60
 
61
+ // Handle screenshot upload if provided
62
+ let screenshotUrl: string | undefined;
63
+ if (screenshot) {
64
+ // Check authentication
65
+ const authenticated = await isAuthenticated();
66
+ if (!authenticated) {
67
+ console.error("You must be logged in to upload a screenshot.");
68
+ console.error("Run `prismic login` to authenticate.");
69
+ process.exitCode = 1;
70
+ return;
71
+ }
72
+
73
+ // Resolve repository
74
+ const repo = repoFlag ?? (await safeGetRepositoryFromConfig());
75
+ if (!repo) {
76
+ console.error("Could not determine repository for screenshot upload.");
77
+ console.error("Use --repo flag or run from a directory with prismic.config.json");
78
+ process.exitCode = 1;
79
+ return;
80
+ }
81
+
82
+ // Read and upload the screenshot
83
+ let imageData: Buffer;
84
+ try {
85
+ imageData = await readFile(screenshot);
86
+ } catch (error) {
87
+ if (error instanceof Error) {
88
+ console.error(`Failed to read screenshot file: ${error.message}`);
89
+ } else {
90
+ console.error("Failed to read screenshot file");
91
+ }
92
+ process.exitCode = 1;
93
+ return;
94
+ }
95
+
96
+ try {
97
+ screenshotUrl = await uploadScreenshot({
98
+ data: imageData,
99
+ repo,
100
+ sliceId: id,
101
+ variationId: "default",
102
+ filename: screenshot,
103
+ });
104
+ } catch (error) {
105
+ if (error instanceof Error) {
106
+ console.error(`Failed to upload screenshot: ${error.message}`);
107
+ } else {
108
+ console.error("Failed to upload screenshot");
109
+ }
110
+ process.exitCode = 1;
111
+ return;
112
+ }
113
+ }
114
+
54
115
  const model: SharedSlice = {
55
116
  id,
56
117
  type: "SharedSlice",
@@ -61,7 +122,7 @@ export async function sliceCreate(): Promise<void> {
61
122
  id: "default",
62
123
  name: "Default",
63
124
  description: "Default",
64
- imageUrl: "",
125
+ imageUrl: screenshotUrl ?? "",
65
126
  docURL: "",
66
127
  version: "initial",
67
128
  primary: {},