@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";
@@ -30,6 +32,28 @@ EXAMPLES
30
32
  prismic slice add-field image gallery thumbnail --variation "grid"
31
33
  `.trim();
32
34
 
35
+ function getDocsPath(framework: Framework): string {
36
+ switch (framework) {
37
+ case "next":
38
+ return "nextjs/with-cli";
39
+ case "nuxt":
40
+ return "nuxt/with-cli";
41
+ case "sveltekit":
42
+ return "sveltekit/with-cli";
43
+ }
44
+ }
45
+
46
+ function getWriteComponentsAnchor(framework: Framework): string {
47
+ switch (framework) {
48
+ case "nuxt":
49
+ return "#write-vue-components";
50
+ case "sveltekit":
51
+ return "#write-svelte-components";
52
+ default:
53
+ return "#write-react-components";
54
+ }
55
+ }
56
+
33
57
  export async function sliceAddFieldImage(): Promise<void> {
34
58
  const {
35
59
  values: { help, variation, label, types },
@@ -64,6 +88,15 @@ export async function sliceAddFieldImage(): Promise<void> {
64
88
  return;
65
89
  }
66
90
 
91
+ // Parse and validate field path
92
+ const fieldPath = parseFieldPath(fieldId);
93
+ const pathValidation = validateNestedFieldPath(fieldPath);
94
+ if (!pathValidation.ok) {
95
+ console.error(pathValidation.error);
96
+ process.exitCode = 1;
97
+ return;
98
+ }
99
+
67
100
  // Find the slice model
68
101
  const result = await findSliceModel(sliceId);
69
102
  if (!result.ok) {
@@ -99,25 +132,52 @@ export async function sliceAddFieldImage(): Promise<void> {
99
132
  targetVariation.primary = {};
100
133
  }
101
134
 
102
- // Check if field already exists in any variation
103
- for (const v of model.variations) {
104
- if (v.primary?.[fieldId]) {
105
- console.error(`Field "${fieldId}" already exists in variation "${v.id}"`);
106
- process.exitCode = 1;
107
- return;
108
- }
109
- }
110
-
111
135
  // Build field definition
112
136
  const fieldDefinition: Image = {
113
137
  type: "Image",
114
138
  config: {
115
- label: label ?? humanReadable(fieldId),
139
+ label: label ?? humanReadable(fieldPath.type === "nested" ? fieldPath.nestedFieldId : fieldId),
116
140
  },
117
141
  };
118
142
 
119
- // Add field to variation
120
- targetVariation.primary[fieldId] = fieldDefinition;
143
+ // Add field to variation (with nested field support)
144
+ if (fieldPath.type === "nested") {
145
+ const groupResult = findGroupInVariation(targetVariation.primary, fieldPath.groupId, targetVariation.id);
146
+ if (!groupResult.ok) {
147
+ console.error(groupResult.error);
148
+ process.exitCode = 1;
149
+ return;
150
+ }
151
+ // Check if nested field already exists
152
+ if (groupResult.group.config.fields[fieldPath.nestedFieldId]) {
153
+ console.error(
154
+ `Field "${fieldPath.nestedFieldId}" already exists in group "${fieldPath.groupId}"`,
155
+ );
156
+ process.exitCode = 1;
157
+ return;
158
+ }
159
+ groupResult.group.config.fields[fieldPath.nestedFieldId] = fieldDefinition;
160
+ } else {
161
+ // Check if field already exists in any variation (at top level or in groups)
162
+ for (const v of model.variations) {
163
+ if (v.primary?.[fieldId]) {
164
+ console.error(`Field "${fieldId}" already exists in variation "${v.id}"`);
165
+ process.exitCode = 1;
166
+ return;
167
+ }
168
+ // Also check inside groups
169
+ for (const [groupFieldId, groupField] of Object.entries(v.primary ?? {})) {
170
+ if (isGroupField(groupField) && groupField.config.fields[fieldId]) {
171
+ console.error(
172
+ `Field "${fieldId}" already exists in group "${groupFieldId}" in variation "${v.id}"`,
173
+ );
174
+ process.exitCode = 1;
175
+ return;
176
+ }
177
+ }
178
+ }
179
+ targetVariation.primary[fieldId] = fieldDefinition;
180
+ }
121
181
 
122
182
  // Write updated model
123
183
  try {
@@ -132,9 +192,15 @@ export async function sliceAddFieldImage(): Promise<void> {
132
192
  return;
133
193
  }
134
194
 
135
- console.info(
136
- `Added field "${fieldId}" (Image) to "${targetVariation.id}" variation in ${sliceId}`,
137
- );
195
+ if (fieldPath.type === "nested") {
196
+ console.info(
197
+ `Added field "${fieldPath.nestedFieldId}" (Image) to group "${fieldPath.groupId}" in ${sliceId}`,
198
+ );
199
+ } else {
200
+ console.info(
201
+ `Added field "${fieldId}" (Image) to "${targetVariation.id}" variation in ${sliceId}`,
202
+ );
203
+ }
138
204
 
139
205
  try {
140
206
  await buildTypes({ output: types });
@@ -145,5 +211,13 @@ export async function sliceAddFieldImage(): Promise<void> {
145
211
 
146
212
  console.info();
147
213
  console.info("Next: Add more fields with `prismic slice add-field`");
148
- console.info(" Run `prismic status` when done to find next steps");
214
+
215
+ const frameworkInfo = await detectFrameworkInfo();
216
+ if (frameworkInfo?.framework) {
217
+ const docsPath = getDocsPath(frameworkInfo.framework);
218
+ const anchor = getWriteComponentsAnchor(frameworkInfo.framework);
219
+ console.info(
220
+ ` Run \`prismic docs ${docsPath}${anchor}\` to learn how to implement the slice's component`,
221
+ );
222
+ }
149
223
  }
@@ -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 key-text cta button_text --placeholder "Enter button text"
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 sliceAddFieldKeyText(): Promise<void> {
35
59
  const {
36
60
  values: { help, variation, label, placeholder, types },
@@ -66,6 +90,15 @@ export async function sliceAddFieldKeyText(): 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 sliceAddFieldKeyText(): 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: Text = {
115
139
  type: "Text",
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 sliceAddFieldKeyText(): Promise<void> {
135
195
  return;
136
196
  }
137
197
 
138
- console.info(
139
- `Added field "${fieldId}" (Text) to "${targetVariation.id}" variation in ${sliceId}`,
140
- );
198
+ if (fieldPath.type === "nested") {
199
+ console.info(
200
+ `Added field "${fieldPath.nestedFieldId}" (Text) to group "${fieldPath.groupId}" in ${sliceId}`,
201
+ );
202
+ } else {
203
+ console.info(
204
+ `Added field "${fieldId}" (Text) 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 sliceAddFieldKeyText(): 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
  }
@@ -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";
@@ -35,6 +37,28 @@ EXAMPLES
35
37
  prismic slice add-field link hero cta --allow-text --allow-target-blank
36
38
  `.trim();
37
39
 
40
+ function getDocsPath(framework: Framework): string {
41
+ switch (framework) {
42
+ case "next":
43
+ return "nextjs/with-cli";
44
+ case "nuxt":
45
+ return "nuxt/with-cli";
46
+ case "sveltekit":
47
+ return "sveltekit/with-cli";
48
+ }
49
+ }
50
+
51
+ function getWriteComponentsAnchor(framework: Framework): string {
52
+ switch (framework) {
53
+ case "nuxt":
54
+ return "#write-vue-components";
55
+ case "sveltekit":
56
+ return "#write-svelte-components";
57
+ default:
58
+ return "#write-react-components";
59
+ }
60
+ }
61
+
38
62
  export async function sliceAddFieldLink(): Promise<void> {
39
63
  const {
40
64
  values: {
@@ -82,6 +106,15 @@ export async function sliceAddFieldLink(): Promise<void> {
82
106
  return;
83
107
  }
84
108
 
109
+ // Parse and validate field path
110
+ const fieldPath = parseFieldPath(fieldId);
111
+ const pathValidation = validateNestedFieldPath(fieldPath);
112
+ if (!pathValidation.ok) {
113
+ console.error(pathValidation.error);
114
+ process.exitCode = 1;
115
+ return;
116
+ }
117
+
85
118
  // Find the slice model
86
119
  const result = await findSliceModel(sliceId);
87
120
  if (!result.ok) {
@@ -117,20 +150,11 @@ export async function sliceAddFieldLink(): Promise<void> {
117
150
  targetVariation.primary = {};
118
151
  }
119
152
 
120
- // Check if field already exists in any variation
121
- for (const v of model.variations) {
122
- if (v.primary?.[fieldId]) {
123
- console.error(`Field "${fieldId}" already exists in variation "${v.id}"`);
124
- process.exitCode = 1;
125
- return;
126
- }
127
- }
128
-
129
153
  // Build field definition
130
154
  const fieldDefinition: Link = {
131
155
  type: "Link",
132
156
  config: {
133
- label: label ?? humanReadable(fieldId),
157
+ label: label ?? humanReadable(fieldPath.type === "nested" ? fieldPath.nestedFieldId : fieldId),
134
158
  ...(placeholder && { placeholder }),
135
159
  ...(allowText && { allowText: true }),
136
160
  ...(allowTargetBlank && { allowTargetBlank: true }),
@@ -138,8 +162,44 @@ export async function sliceAddFieldLink(): Promise<void> {
138
162
  },
139
163
  };
140
164
 
141
- // Add field to variation
142
- targetVariation.primary[fieldId] = fieldDefinition;
165
+ // Add field to variation (with nested field support)
166
+ if (fieldPath.type === "nested") {
167
+ const groupResult = findGroupInVariation(targetVariation.primary, fieldPath.groupId, targetVariation.id);
168
+ if (!groupResult.ok) {
169
+ console.error(groupResult.error);
170
+ process.exitCode = 1;
171
+ return;
172
+ }
173
+ // Check if nested field already exists
174
+ if (groupResult.group.config.fields[fieldPath.nestedFieldId]) {
175
+ console.error(
176
+ `Field "${fieldPath.nestedFieldId}" already exists in group "${fieldPath.groupId}"`,
177
+ );
178
+ process.exitCode = 1;
179
+ return;
180
+ }
181
+ groupResult.group.config.fields[fieldPath.nestedFieldId] = fieldDefinition;
182
+ } else {
183
+ // Check if field already exists in any variation (at top level or in groups)
184
+ for (const v of model.variations) {
185
+ if (v.primary?.[fieldId]) {
186
+ console.error(`Field "${fieldId}" already exists in variation "${v.id}"`);
187
+ process.exitCode = 1;
188
+ return;
189
+ }
190
+ // Also check inside groups
191
+ for (const [groupFieldId, groupField] of Object.entries(v.primary ?? {})) {
192
+ if (isGroupField(groupField) && groupField.config.fields[fieldId]) {
193
+ console.error(
194
+ `Field "${fieldId}" already exists in group "${groupFieldId}" in variation "${v.id}"`,
195
+ );
196
+ process.exitCode = 1;
197
+ return;
198
+ }
199
+ }
200
+ }
201
+ targetVariation.primary[fieldId] = fieldDefinition;
202
+ }
143
203
 
144
204
  // Write updated model
145
205
  try {
@@ -154,9 +214,15 @@ export async function sliceAddFieldLink(): Promise<void> {
154
214
  return;
155
215
  }
156
216
 
157
- console.info(
158
- `Added field "${fieldId}" (Link) to "${targetVariation.id}" variation in ${sliceId}`,
159
- );
217
+ if (fieldPath.type === "nested") {
218
+ console.info(
219
+ `Added field "${fieldPath.nestedFieldId}" (Link) to group "${fieldPath.groupId}" in ${sliceId}`,
220
+ );
221
+ } else {
222
+ console.info(
223
+ `Added field "${fieldId}" (Link) to "${targetVariation.id}" variation in ${sliceId}`,
224
+ );
225
+ }
160
226
 
161
227
  try {
162
228
  await buildTypes({ output: types });
@@ -167,5 +233,13 @@ export async function sliceAddFieldLink(): Promise<void> {
167
233
 
168
234
  console.info();
169
235
  console.info("Next: Add more fields with `prismic slice add-field`");
170
- console.info(" Run `prismic status` when done to find next steps");
236
+
237
+ const frameworkInfo = await detectFrameworkInfo();
238
+ if (frameworkInfo?.framework) {
239
+ const docsPath = getDocsPath(frameworkInfo.framework);
240
+ const anchor = getWriteComponentsAnchor(frameworkInfo.framework);
241
+ console.info(
242
+ ` Run \`prismic docs ${docsPath}${anchor}\` to learn how to implement the slice's component`,
243
+ );
244
+ }
171
245
  }
@@ -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 number stats count --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 sliceAddFieldNumber(): Promise<void> {
35
59
  const {
36
60
  values: { help, variation, label, placeholder, types },
@@ -66,6 +90,15 @@ export async function sliceAddFieldNumber(): 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 sliceAddFieldNumber(): 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: Number = {
115
139
  type: "Number",
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 sliceAddFieldNumber(): Promise<void> {
135
195
  return;
136
196
  }
137
197
 
138
- console.info(
139
- `Added field "${fieldId}" (Number) to "${targetVariation.id}" variation in ${sliceId}`,
140
- );
198
+ if (fieldPath.type === "nested") {
199
+ console.info(
200
+ `Added field "${fieldPath.nestedFieldId}" (Number) to group "${fieldPath.groupId}" in ${sliceId}`,
201
+ );
202
+ } else {
203
+ console.info(
204
+ `Added field "${fieldId}" (Number) 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 sliceAddFieldNumber(): 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
  }