@se-studio/contentful-cms 1.0.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.
Files changed (173) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +519 -0
  3. package/dist/bin/cms-edit.d.ts +4 -0
  4. package/dist/bin/cms-edit.d.ts.map +1 -0
  5. package/dist/bin/cms-edit.js +101 -0
  6. package/dist/bin/cms-edit.js.map +1 -0
  7. package/dist/commands/add.d.ts +4 -0
  8. package/dist/commands/add.d.ts.map +1 -0
  9. package/dist/commands/add.js +166 -0
  10. package/dist/commands/add.js.map +1 -0
  11. package/dist/commands/asset.d.ts +4 -0
  12. package/dist/commands/asset.d.ts.map +1 -0
  13. package/dist/commands/asset.js +110 -0
  14. package/dist/commands/asset.js.map +1 -0
  15. package/dist/commands/colours.d.ts +4 -0
  16. package/dist/commands/colours.d.ts.map +1 -0
  17. package/dist/commands/colours.js +91 -0
  18. package/dist/commands/colours.js.map +1 -0
  19. package/dist/commands/create.d.ts +4 -0
  20. package/dist/commands/create.d.ts.map +1 -0
  21. package/dist/commands/create.js +223 -0
  22. package/dist/commands/create.js.map +1 -0
  23. package/dist/commands/diff.d.ts +4 -0
  24. package/dist/commands/diff.d.ts.map +1 -0
  25. package/dist/commands/diff.js +141 -0
  26. package/dist/commands/diff.js.map +1 -0
  27. package/dist/commands/discard.d.ts +4 -0
  28. package/dist/commands/discard.d.ts.map +1 -0
  29. package/dist/commands/discard.js +36 -0
  30. package/dist/commands/discard.js.map +1 -0
  31. package/dist/commands/entry-search.d.ts +4 -0
  32. package/dist/commands/entry-search.d.ts.map +1 -0
  33. package/dist/commands/entry-search.js +81 -0
  34. package/dist/commands/entry-search.js.map +1 -0
  35. package/dist/commands/export-converted.d.ts +8 -0
  36. package/dist/commands/export-converted.d.ts.map +1 -0
  37. package/dist/commands/export-converted.js +62 -0
  38. package/dist/commands/export-converted.js.map +1 -0
  39. package/dist/commands/links.d.ts +4 -0
  40. package/dist/commands/links.d.ts.map +1 -0
  41. package/dist/commands/links.js +255 -0
  42. package/dist/commands/links.js.map +1 -0
  43. package/dist/commands/list.d.ts +4 -0
  44. package/dist/commands/list.d.ts.map +1 -0
  45. package/dist/commands/list.js +91 -0
  46. package/dist/commands/list.js.map +1 -0
  47. package/dist/commands/move.d.ts +3 -0
  48. package/dist/commands/move.d.ts.map +1 -0
  49. package/dist/commands/move.js +84 -0
  50. package/dist/commands/move.js.map +1 -0
  51. package/dist/commands/nav.d.ts +4 -0
  52. package/dist/commands/nav.d.ts.map +1 -0
  53. package/dist/commands/nav.js +196 -0
  54. package/dist/commands/nav.js.map +1 -0
  55. package/dist/commands/open.d.ts +4 -0
  56. package/dist/commands/open.d.ts.map +1 -0
  57. package/dist/commands/open.js +74 -0
  58. package/dist/commands/open.js.map +1 -0
  59. package/dist/commands/read.d.ts +4 -0
  60. package/dist/commands/read.d.ts.map +1 -0
  61. package/dist/commands/read.js +102 -0
  62. package/dist/commands/read.js.map +1 -0
  63. package/dist/commands/remove.d.ts +4 -0
  64. package/dist/commands/remove.d.ts.map +1 -0
  65. package/dist/commands/remove.js +98 -0
  66. package/dist/commands/remove.js.map +1 -0
  67. package/dist/commands/rtf.d.ts +3 -0
  68. package/dist/commands/rtf.d.ts.map +1 -0
  69. package/dist/commands/rtf.js +131 -0
  70. package/dist/commands/rtf.js.map +1 -0
  71. package/dist/commands/save.d.ts +4 -0
  72. package/dist/commands/save.d.ts.map +1 -0
  73. package/dist/commands/save.js +59 -0
  74. package/dist/commands/save.js.map +1 -0
  75. package/dist/commands/screenshot.d.ts +4 -0
  76. package/dist/commands/screenshot.d.ts.map +1 -0
  77. package/dist/commands/screenshot.js +246 -0
  78. package/dist/commands/screenshot.js.map +1 -0
  79. package/dist/commands/set.d.ts +3 -0
  80. package/dist/commands/set.d.ts.map +1 -0
  81. package/dist/commands/set.js +152 -0
  82. package/dist/commands/set.js.map +1 -0
  83. package/dist/commands/skill.d.ts +4 -0
  84. package/dist/commands/skill.d.ts.map +1 -0
  85. package/dist/commands/skill.js +73 -0
  86. package/dist/commands/skill.js.map +1 -0
  87. package/dist/commands/snapshot.d.ts +3 -0
  88. package/dist/commands/snapshot.d.ts.map +1 -0
  89. package/dist/commands/snapshot.js +21 -0
  90. package/dist/commands/snapshot.js.map +1 -0
  91. package/dist/commands/types.d.ts +4 -0
  92. package/dist/commands/types.d.ts.map +1 -0
  93. package/dist/commands/types.js +78 -0
  94. package/dist/commands/types.js.map +1 -0
  95. package/dist/config/load.d.ts +14 -0
  96. package/dist/config/load.d.ts.map +1 -0
  97. package/dist/config/load.js +79 -0
  98. package/dist/config/load.js.map +1 -0
  99. package/dist/config/types.d.ts +13 -0
  100. package/dist/config/types.d.ts.map +1 -0
  101. package/dist/config/types.js +2 -0
  102. package/dist/config/types.js.map +1 -0
  103. package/dist/contentful/assets.d.ts +20 -0
  104. package/dist/contentful/assets.d.ts.map +1 -0
  105. package/dist/contentful/assets.js +36 -0
  106. package/dist/contentful/assets.js.map +1 -0
  107. package/dist/contentful/client.d.ts +28 -0
  108. package/dist/contentful/client.d.ts.map +1 -0
  109. package/dist/contentful/client.js +30 -0
  110. package/dist/contentful/client.js.map +1 -0
  111. package/dist/contentful/fetch.d.ts +20 -0
  112. package/dist/contentful/fetch.d.ts.map +1 -0
  113. package/dist/contentful/fetch.js +154 -0
  114. package/dist/contentful/fetch.js.map +1 -0
  115. package/dist/contentful/references.d.ts +7 -0
  116. package/dist/contentful/references.d.ts.map +1 -0
  117. package/dist/contentful/references.js +12 -0
  118. package/dist/contentful/references.js.map +1 -0
  119. package/dist/contentful/write.d.ts +16 -0
  120. package/dist/contentful/write.d.ts.map +1 -0
  121. package/dist/contentful/write.js +75 -0
  122. package/dist/contentful/write.js.map +1 -0
  123. package/dist/index.d.ts +3 -0
  124. package/dist/index.d.ts.map +1 -0
  125. package/dist/index.js +2 -0
  126. package/dist/index.js.map +1 -0
  127. package/dist/output/json.d.ts +47 -0
  128. package/dist/output/json.d.ts.map +1 -0
  129. package/dist/output/json.js +87 -0
  130. package/dist/output/json.js.map +1 -0
  131. package/dist/output/mode.d.ts +3 -0
  132. package/dist/output/mode.d.ts.map +1 -0
  133. package/dist/output/mode.js +16 -0
  134. package/dist/output/mode.js.map +1 -0
  135. package/dist/output/print.d.ts +14 -0
  136. package/dist/output/print.d.ts.map +1 -0
  137. package/dist/output/print.js +61 -0
  138. package/dist/output/print.js.map +1 -0
  139. package/dist/rtf/fromMarkdown.d.ts +19 -0
  140. package/dist/rtf/fromMarkdown.d.ts.map +1 -0
  141. package/dist/rtf/fromMarkdown.js +230 -0
  142. package/dist/rtf/fromMarkdown.js.map +1 -0
  143. package/dist/rtf/toMarkdown.d.ts +6 -0
  144. package/dist/rtf/toMarkdown.d.ts.map +1 -0
  145. package/dist/rtf/toMarkdown.js +105 -0
  146. package/dist/rtf/toMarkdown.js.map +1 -0
  147. package/dist/session/refs.d.ts +35 -0
  148. package/dist/session/refs.d.ts.map +1 -0
  149. package/dist/session/refs.js +128 -0
  150. package/dist/session/refs.js.map +1 -0
  151. package/dist/session/state.d.ts +91 -0
  152. package/dist/session/state.d.ts.map +1 -0
  153. package/dist/session/state.js +61 -0
  154. package/dist/session/state.js.map +1 -0
  155. package/dist/session/store.d.ts +10 -0
  156. package/dist/session/store.d.ts.map +1 -0
  157. package/dist/session/store.js +62 -0
  158. package/dist/session/store.js.map +1 -0
  159. package/dist/snapshot/render.d.ts +15 -0
  160. package/dist/snapshot/render.d.ts.map +1 -0
  161. package/dist/snapshot/render.js +166 -0
  162. package/dist/snapshot/render.js.map +1 -0
  163. package/dist/validation/allowed-types.d.ts +7 -0
  164. package/dist/validation/allowed-types.d.ts.map +1 -0
  165. package/dist/validation/allowed-types.js +16 -0
  166. package/dist/validation/allowed-types.js.map +1 -0
  167. package/package.json +61 -0
  168. package/skills/core/SKILL.md +483 -0
  169. package/skills/manifest.json +7 -0
  170. package/skills/navigation/SKILL.md +18 -0
  171. package/skills/rich-text/SKILL.md +23 -0
  172. package/skills/screenshots/SKILL.md +32 -0
  173. package/skills/templates/SKILL.md +16 -0
@@ -0,0 +1,166 @@
1
+ import { loadConfig, resolveSpaceConfig } from '../config/load.js';
2
+ import { createSafeEnvironment } from '../contentful/client.js';
3
+ import { serializeEntry } from '../contentful/fetch.js';
4
+ import { isJsonMode } from '../output/mode.js';
5
+ import { errorMsg, successMsg, warnMsg } from '../output/print.js';
6
+ import { buildTree, findTreeNode, makeEntryLink, resolveRef } from '../session/refs.js';
7
+ import { requireSession, saveSession } from '../session/store.js';
8
+ import { renderSnapshot } from '../snapshot/render.js';
9
+ import { ALLOWED_CONTENT_TYPES_FOR_PAGE_ARTICLE, isAllowedContentTypeForAdd, } from '../validation/allowed-types.js';
10
+ export function registerAddCommand(program) {
11
+ program
12
+ .command('add <type>')
13
+ .description('Create a new entry and link it to the page/article.\n' +
14
+ '--content-type is required: pass the Contentful content type ID (e.g. component, collection, externalComponent, person).\n' +
15
+ 'For typed content types (component, collection, externalComponent, …) the <type> argument is stored in the\n' +
16
+ ' {contentTypeId}Type field (e.g. componentType, externalComponentType). For content types without that field\n' +
17
+ ' <type> is used only as the initial cmsLabel.\n' +
18
+ 'Use --after <ref> to insert after a specific entry, or --parent <ref> to add inside a collection.\n' +
19
+ 'Use --target <field> to add to topContent, content, or bottomContent (page/article only).')
20
+ .option('--after <ref>', 'Insert the new entry after this ref')
21
+ .option('--parent <ref>', 'Add inside this collection (uses its contents field)')
22
+ .option('--target <field>', 'Target content array: topContent, content, or bottomContent (page/article only)')
23
+ .requiredOption('--content-type <ct>', 'Contentful content type ID (e.g. component, collection, externalComponent, person)')
24
+ .action(async (type, opts, cmd) => {
25
+ const parentOpts = cmd.parent?.opts() ?? {};
26
+ try {
27
+ const session = requireSession();
28
+ const locale = session.defaultLocale;
29
+ const config = loadConfig(parentOpts.config);
30
+ const { space } = resolveSpaceConfig(config, session.spaceKey);
31
+ const env = await createSafeEnvironment(space);
32
+ const ctId = opts.contentType;
33
+ if (!isAllowedContentTypeForAdd(ctId)) {
34
+ errorMsg(`Content type '${ctId}' is not supported for add in this project. Allowed: ${ALLOWED_CONTENT_TYPES_FOR_PAGE_ARTICLE.join(', ')}.`);
35
+ process.exit(1);
36
+ }
37
+ // Resolve whether this content type has a ${ctId}Type discriminator field.
38
+ // Fetching the CT definition avoids passing unknown fields to createEntry.
39
+ const typeFieldId = `${ctId}Type`;
40
+ const ctDefinition = await env.getContentType(ctId);
41
+ const hasTypeField = ctDefinition.fields.some((f) => f.id === typeFieldId);
42
+ // Create the new entry in Contentful
43
+ const newEntry = await env.createEntry(ctId, {
44
+ cmsLabel: { [locale]: `New ${type}` },
45
+ ...(hasTypeField ? { [typeFieldId]: { [locale]: type } } : {}),
46
+ });
47
+ const newEntryId = newEntry.sys.id;
48
+ session.entries[newEntryId] = serializeEntry(newEntry);
49
+ session.originalEntries[newEntryId] = serializeEntry(newEntry);
50
+ // Determine the parent entry and field to insert into
51
+ let parentEntryId;
52
+ let targetField;
53
+ if (opts.parent) {
54
+ resolveRef(session, opts.parent);
55
+ const parentNode = findTreeNode(session, opts.parent);
56
+ if (!parentNode) {
57
+ errorMsg(`Ref "${opts.parent}" not found in the content tree.`);
58
+ process.exit(1);
59
+ }
60
+ parentEntryId = parentNode.entryId;
61
+ targetField = 'contents';
62
+ }
63
+ else if (opts.after) {
64
+ resolveRef(session, opts.after);
65
+ const afterNode = findTreeNode(session, opts.after);
66
+ if (!afterNode || !afterNode.parentId) {
67
+ errorMsg(`Cannot find parent for "${opts.after}". Use --parent to specify.`);
68
+ process.exit(1);
69
+ }
70
+ parentEntryId = afterNode.parentId;
71
+ targetField = afterNode.parentField ?? 'content';
72
+ }
73
+ else {
74
+ parentEntryId = session.rootEntryId;
75
+ if (opts.target) {
76
+ if (session.rootEntryType === 'template') {
77
+ const templateAllowed = ['preContent', 'postContent'];
78
+ if (!templateAllowed.includes(opts.target)) {
79
+ errorMsg('For template use preContent or postContent.');
80
+ process.exit(1);
81
+ }
82
+ targetField = opts.target;
83
+ }
84
+ else if (session.rootEntryType === 'page' || session.rootEntryType === 'article') {
85
+ const pageArticleAllowed = ['topContent', 'content', 'bottomContent'];
86
+ if (!pageArticleAllowed.includes(opts.target)) {
87
+ errorMsg(`--target must be one of: ${pageArticleAllowed.join(', ')}. Got: ${opts.target}`);
88
+ process.exit(1);
89
+ }
90
+ targetField = opts.target;
91
+ }
92
+ else {
93
+ errorMsg(`--target is only supported when the open entry is a page or article. Current root is ${session.rootEntryType}.`);
94
+ process.exit(1);
95
+ }
96
+ }
97
+ else {
98
+ if (session.rootEntryType === 'template') {
99
+ errorMsg('For template, --target is required. Use preContent or postContent.');
100
+ process.exit(1);
101
+ }
102
+ targetField = 'content';
103
+ }
104
+ }
105
+ const parentEntry = session.entries[parentEntryId];
106
+ if (!parentEntry) {
107
+ errorMsg(`Parent entry not found in session.`);
108
+ process.exit(1);
109
+ return;
110
+ }
111
+ // Get or initialise the content array
112
+ if (!parentEntry.fields[targetField]) {
113
+ parentEntry.fields[targetField] = {};
114
+ }
115
+ const fieldLocaleMap = parentEntry.fields[targetField];
116
+ if (!fieldLocaleMap[locale]) {
117
+ fieldLocaleMap[locale] = [];
118
+ }
119
+ const contentArray = fieldLocaleMap[locale];
120
+ const newLink = makeEntryLink(newEntryId);
121
+ if (opts.after) {
122
+ const afterNode = findTreeNode(session, opts.after);
123
+ if (afterNode) {
124
+ const afterIdx = contentArray.findIndex((item) => typeof item === 'object' &&
125
+ item !== null &&
126
+ 'sys' in item &&
127
+ item.sys.id === afterNode.entryId);
128
+ if (afterIdx >= 0) {
129
+ contentArray.splice(afterIdx + 1, 0, newLink);
130
+ }
131
+ else {
132
+ contentArray.push(newLink);
133
+ }
134
+ }
135
+ else {
136
+ contentArray.push(newLink);
137
+ }
138
+ }
139
+ else {
140
+ contentArray.push(newLink);
141
+ }
142
+ if (!session.modifiedEntryIds.includes(parentEntryId)) {
143
+ session.modifiedEntryIds.push(parentEntryId);
144
+ }
145
+ // Rebuild the tree with the new entry
146
+ const { refs, refsByEntry, treeNodes } = buildTree(session.rootEntryId, session.entries, locale);
147
+ session.refs = refs;
148
+ session.refsByEntry = refsByEntry;
149
+ session.treeNodes = treeNodes;
150
+ const newRef = refsByEntry[newEntryId] ?? '?';
151
+ saveSession(session);
152
+ successMsg(hasTypeField
153
+ ? `Created ${ctId} "${type}" as ${newRef} (ID: ${newEntryId})`
154
+ : `Created ${ctId} as ${newRef} (ID: ${newEntryId}) — set fields with "cms-edit set ${newRef} <field> <value>"`);
155
+ warnMsg('Entry is saved to Contentful but changes to the parent page are unsaved. Run "cms-edit save".');
156
+ if (!isJsonMode()) {
157
+ renderSnapshot(session);
158
+ }
159
+ }
160
+ catch (err) {
161
+ errorMsg(err instanceof Error ? err.message : String(err));
162
+ process.exit(1);
163
+ }
164
+ });
165
+ }
166
+ //# sourceMappingURL=add.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add.js","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ /** biome-ignore-all lint/suspicious/noConsole: Console output is intentional in CLI */
2
+ import type { Command } from 'commander';
3
+ export declare function registerAssetCommand(program: Command): void;
4
+ //# sourceMappingURL=asset.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asset.d.ts","sourceRoot":"","sources":["../../src/commands/asset.ts"],"names":[],"mappings":"AAAA,uFAAuF;AAEvF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWzC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA2G3D"}
@@ -0,0 +1,110 @@
1
+ /** biome-ignore-all lint/suspicious/noConsole: Console output is intentional in CLI */
2
+ import pc from 'picocolors';
3
+ import { loadConfig, resolveSpaceConfig } from '../config/load.js';
4
+ import { getAssetSummary, searchAssets } from '../contentful/assets.js';
5
+ import { createSafeEnvironment } from '../contentful/client.js';
6
+ import { assetSummaryToJson } from '../output/json.js';
7
+ import { isJsonMode } from '../output/mode.js';
8
+ import { errorMsg, successMsg } from '../output/print.js';
9
+ import { resolveRef } from '../session/refs.js';
10
+ import { requireSession, saveSession } from '../session/store.js';
11
+ export function registerAssetCommand(program) {
12
+ const asset = program.command('asset').description('Search and inspect Contentful assets');
13
+ asset
14
+ .command('search <query>')
15
+ .description('Search assets by title')
16
+ .option('-n, --limit <n>', 'Max results', '10')
17
+ .action(async (query, opts, cmd) => {
18
+ const parentOpts = cmd.parent?.parent?.opts() ?? {};
19
+ try {
20
+ const session = requireSession();
21
+ const config = loadConfig(parentOpts.config);
22
+ const { space } = resolveSpaceConfig(config, session.spaceKey);
23
+ const env = await createSafeEnvironment(space);
24
+ const limit = Number.parseInt(opts.limit ?? '10', 10);
25
+ const results = await searchAssets(env, query, limit);
26
+ if (isJsonMode()) {
27
+ console.log(JSON.stringify(results.map(assetSummaryToJson), null, 2));
28
+ return;
29
+ }
30
+ if (results.length === 0) {
31
+ console.log(pc.dim(`No assets found for "${query}"`));
32
+ return;
33
+ }
34
+ console.log(`\n${pc.bold('Assets matching: ')}${pc.cyan(query)}\n`);
35
+ for (const a of results) {
36
+ const dims = a.width && a.height ? pc.dim(` (${a.width}×${a.height})`) : '';
37
+ console.log(` ${pc.bold(a.id)} ${a.title}${dims}`);
38
+ console.log(` ${pc.dim(a.fileName)} ${pc.dim(a.url)}`);
39
+ }
40
+ console.log('');
41
+ console.log(pc.dim('Use the asset ID with: cms-edit asset set <ref> <field> <asset-id>'));
42
+ }
43
+ catch (err) {
44
+ errorMsg(err instanceof Error ? err.message : String(err));
45
+ process.exit(1);
46
+ }
47
+ });
48
+ asset
49
+ .command('info <asset-id>')
50
+ .description('Show details for a specific asset')
51
+ .option('--json', 'Output as a JSON object')
52
+ .action(async (assetId, opts, cmd) => {
53
+ const parentOpts = cmd.parent?.parent?.opts() ?? {};
54
+ try {
55
+ const session = requireSession();
56
+ const config = loadConfig(parentOpts.config);
57
+ const { space } = resolveSpaceConfig(config, session.spaceKey);
58
+ const env = await createSafeEnvironment(space);
59
+ const summary = await getAssetSummary(env, assetId);
60
+ if (!summary) {
61
+ errorMsg(`Asset "${assetId}" not found.`);
62
+ process.exit(1);
63
+ return;
64
+ }
65
+ if (opts.json || isJsonMode()) {
66
+ console.log(JSON.stringify(assetSummaryToJson(summary), null, 2));
67
+ return;
68
+ }
69
+ console.log(`\n${pc.bold('Asset: ')}${summary.title}`);
70
+ console.log(` ID: ${summary.id}`);
71
+ console.log(` File: ${summary.fileName}`);
72
+ console.log(` Content type: ${summary.contentType}`);
73
+ if (summary.width)
74
+ console.log(` Dimensions: ${summary.width}×${summary.height}`);
75
+ if (summary.size)
76
+ console.log(` Size: ${Math.round(summary.size / 1024)}KB`);
77
+ console.log(` URL: ${summary.url}\n`);
78
+ }
79
+ catch (err) {
80
+ errorMsg(err instanceof Error ? err.message : String(err));
81
+ process.exit(1);
82
+ }
83
+ });
84
+ asset
85
+ .command('set <ref> <field> <asset-id>')
86
+ .description('Set a visual/asset field on an entry to a specific asset ID')
87
+ .option('--mobile', 'Set the mobile visual field (mobileVisual) instead of visual')
88
+ .action((ref, field, assetId, _opts) => {
89
+ try {
90
+ const session = requireSession();
91
+ const entry = resolveRef(session, ref);
92
+ const locale = session.defaultLocale;
93
+ const assetLink = { sys: { type: 'Link', linkType: 'Asset', id: assetId } };
94
+ if (!entry.fields[field]) {
95
+ entry.fields[field] = {};
96
+ }
97
+ entry.fields[field][locale] = assetLink;
98
+ if (!session.modifiedEntryIds.includes(entry.sys.id)) {
99
+ session.modifiedEntryIds.push(entry.sys.id);
100
+ }
101
+ saveSession(session);
102
+ successMsg(`Set ${field} on ${ref} to asset ${assetId}.`);
103
+ }
104
+ catch (err) {
105
+ errorMsg(err instanceof Error ? err.message : String(err));
106
+ process.exit(1);
107
+ }
108
+ });
109
+ }
110
+ //# sourceMappingURL=asset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asset.js","sourceRoot":"","sources":["../../src/commands/asset.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ /** biome-ignore-all lint/suspicious/noConsole: Console output is intentional in CLI */
2
+ import type { Command } from 'commander';
3
+ export declare function registerColoursCommand(program: Command): void;
4
+ //# sourceMappingURL=colours.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"colours.d.ts","sourceRoot":"","sources":["../../src/commands/colours.ts"],"names":[],"mappings":"AAAA,uFAAuF;AAEvF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiBzC,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAuF7D"}
@@ -0,0 +1,91 @@
1
+ /** biome-ignore-all lint/suspicious/noConsole: Console output is intentional in CLI */
2
+ import pc from 'picocolors';
3
+ import { loadConfig, resolveSpaceConfig } from '../config/load.js';
4
+ import { createSafeEnvironment } from '../contentful/client.js';
5
+ import { isJsonMode } from '../output/mode.js';
6
+ import { errorMsg } from '../output/print.js';
7
+ function extractInValues(field) {
8
+ const values = [];
9
+ for (const v of field.validations ?? []) {
10
+ if (Array.isArray(v.in)) {
11
+ values.push(...v.in);
12
+ }
13
+ }
14
+ return values;
15
+ }
16
+ export function registerColoursCommand(program) {
17
+ program
18
+ .command('colours')
19
+ .description('List the valid backgroundColour and textColour values from the content model.\n' +
20
+ 'Returns one list for background colours and one for text colours.\n' +
21
+ 'No session required — works without opening a page first.\n' +
22
+ 'Example: cms-edit colours | cms-edit colours --json')
23
+ .action(async (_opts, cmd) => {
24
+ const parentOpts = cmd.parent?.opts() ?? {};
25
+ try {
26
+ const config = loadConfig(parentOpts.config);
27
+ const { space } = resolveSpaceConfig(config, parentOpts.space);
28
+ const env = await createSafeEnvironment(space);
29
+ const collection = await env.getContentTypes();
30
+ let backgroundColours = [];
31
+ let textColours = [];
32
+ for (const ct of collection.items) {
33
+ if (backgroundColours.length === 0) {
34
+ const field = ct.fields.find((f) => f.id === 'backgroundColour');
35
+ if (field) {
36
+ const values = extractInValues(field);
37
+ if (values.length > 0)
38
+ backgroundColours = values.sort();
39
+ }
40
+ }
41
+ if (textColours.length === 0) {
42
+ const field = ct.fields.find((f) => f.id === 'textColour');
43
+ if (field) {
44
+ const values = extractInValues(field);
45
+ if (values.length > 0)
46
+ textColours = values.sort();
47
+ }
48
+ }
49
+ if (backgroundColours.length > 0 && textColours.length > 0)
50
+ break;
51
+ }
52
+ if (isJsonMode()) {
53
+ console.log(JSON.stringify({ backgroundColour: backgroundColours, textColour: textColours }, null, 2));
54
+ return;
55
+ }
56
+ if (backgroundColours.length === 0 && textColours.length === 0) {
57
+ console.log(pc.dim('No backgroundColour or textColour fields with valid values found in this space.'));
58
+ return;
59
+ }
60
+ if (backgroundColours.length > 0) {
61
+ console.log(`\n${pc.bold('Background colours')} (${backgroundColours.length}):\n`);
62
+ for (const v of backgroundColours) {
63
+ console.log(` ${pc.cyan(v)}`);
64
+ }
65
+ console.log('');
66
+ console.log(pc.dim('Use with: cms-edit set @ref backgroundColour "<Value>"'));
67
+ console.log('');
68
+ }
69
+ else {
70
+ console.log(pc.dim('\nNo backgroundColour values found in this space.\n'));
71
+ }
72
+ if (textColours.length > 0) {
73
+ console.log(`${pc.bold('Text colours')} (${textColours.length}):\n`);
74
+ for (const v of textColours) {
75
+ console.log(` ${pc.cyan(v)}`);
76
+ }
77
+ console.log('');
78
+ console.log(pc.dim('Use with: cms-edit set @ref textColour "<Value>"'));
79
+ console.log('');
80
+ }
81
+ else {
82
+ console.log(pc.dim('No textColour values found in this space.\n'));
83
+ }
84
+ }
85
+ catch (err) {
86
+ errorMsg(err instanceof Error ? err.message : String(err));
87
+ process.exit(1);
88
+ }
89
+ });
90
+ }
91
+ //# sourceMappingURL=colours.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"colours.js","sourceRoot":"","sources":["../../src/commands/colours.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ /** biome-ignore-all lint/suspicious/noConsole: Console output is intentional in CLI */
2
+ import type { Command } from 'commander';
3
+ export declare function registerCreateCommand(program: Command): void;
4
+ //# sourceMappingURL=create.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/commands/create.ts"],"names":[],"mappings":"AAAA,uFAAuF;AAEvF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWzC,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAsQ5D"}
@@ -0,0 +1,223 @@
1
+ /** biome-ignore-all lint/suspicious/noConsole: Console output is intentional in CLI */
2
+ import { loadConfig, resolveSpaceConfig } from '../config/load.js';
3
+ import { createSafeEnvironment } from '../contentful/client.js';
4
+ import { fetchEntryTree, serializeEntry } from '../contentful/fetch.js';
5
+ import { isJsonMode } from '../output/mode.js';
6
+ import { errorMsg, infoMsg, successMsg } from '../output/print.js';
7
+ import { buildTree } from '../session/refs.js';
8
+ import { saveSession } from '../session/store.js';
9
+ import { renderSnapshot } from '../snapshot/render.js';
10
+ export function registerCreateCommand(program) {
11
+ const create = program
12
+ .command('create')
13
+ .description('Create a new page, article, or other entry. After create, edit with set/rtf/add; then save.');
14
+ create
15
+ .command('page')
16
+ .description('Create a new page entry')
17
+ .requiredOption('--slug <slug>', 'URL slug (e.g. /about-us)')
18
+ .requiredOption('--title <title>', 'Page title')
19
+ .option('--description <desc>', 'Meta description')
20
+ .action(async (opts, _cmd, cmd2) => {
21
+ const parentOpts = cmd2.parent?.parent?.opts() ?? {};
22
+ try {
23
+ const config = loadConfig(parentOpts.config);
24
+ const { key, space } = resolveSpaceConfig(config, parentOpts.space);
25
+ const env = await createSafeEnvironment(space);
26
+ const locale = space.defaultLocale;
27
+ const slug = opts.slug.startsWith('/') ? opts.slug.slice(1) : opts.slug;
28
+ const newEntry = await env.createEntry('page', {
29
+ cmsLabel: { [locale]: opts.title },
30
+ title: { [locale]: opts.title },
31
+ slug: { [locale]: slug || 'index' },
32
+ description: { [locale]: opts.description ?? '' },
33
+ });
34
+ const rootEntryId = newEntry.sys.id;
35
+ const entries = await fetchEntryTree(env, rootEntryId);
36
+ entries[rootEntryId] = serializeEntry(newEntry);
37
+ const { refs, refsByEntry, treeNodes } = buildTree(rootEntryId, entries, locale);
38
+ const session = {
39
+ version: 1,
40
+ spaceKey: key,
41
+ spaceId: space.spaceId,
42
+ environment: space.environment,
43
+ defaultLocale: locale,
44
+ rootEntryId,
45
+ rootEntryType: 'page',
46
+ fetchedAt: new Date().toISOString(),
47
+ entries,
48
+ originalEntries: JSON.parse(JSON.stringify(entries)),
49
+ refs,
50
+ refsByEntry,
51
+ treeNodes,
52
+ modifiedEntryIds: [],
53
+ pendingDeletions: [],
54
+ };
55
+ saveSession(session);
56
+ successMsg(`Created page "${opts.title}" (ID: ${rootEntryId})`);
57
+ infoMsg(`View in Contentful: https://app.contentful.com/spaces/${space.spaceId}/entries/${rootEntryId}`);
58
+ infoMsg(`Slug: /${slug}`);
59
+ if (!isJsonMode()) {
60
+ renderSnapshot(session);
61
+ }
62
+ }
63
+ catch (err) {
64
+ errorMsg(err instanceof Error ? err.message : String(err));
65
+ process.exit(1);
66
+ }
67
+ });
68
+ create
69
+ .command('article')
70
+ .description('Create a new article entry')
71
+ .requiredOption('--slug <slug>', 'URL slug (e.g. /blog/my-article)')
72
+ .requiredOption('--title <title>', 'Article title')
73
+ .requiredOption('--article-type-id <id>', 'Contentful entry ID of the articleType')
74
+ .option('--description <desc>', 'Meta description')
75
+ .action(async (opts, _cmd, cmd2) => {
76
+ const parentOpts = cmd2.parent?.parent?.opts() ?? {};
77
+ try {
78
+ const config = loadConfig(parentOpts.config);
79
+ const { key, space } = resolveSpaceConfig(config, parentOpts.space);
80
+ const env = await createSafeEnvironment(space);
81
+ const locale = space.defaultLocale;
82
+ const slug = opts.slug.startsWith('/') ? opts.slug.slice(1) : opts.slug;
83
+ const newEntry = await env.createEntry('article', {
84
+ cmsLabel: { [locale]: opts.title },
85
+ title: { [locale]: opts.title },
86
+ slug: { [locale]: slug },
87
+ description: { [locale]: opts.description ?? '' },
88
+ date: { [locale]: new Date().toISOString().split('T')[0] },
89
+ articleType: {
90
+ [locale]: { sys: { type: 'Link', linkType: 'Entry', id: opts.articleTypeId } },
91
+ },
92
+ });
93
+ const rootEntryId = newEntry.sys.id;
94
+ const entries = await fetchEntryTree(env, rootEntryId);
95
+ entries[rootEntryId] = serializeEntry(newEntry);
96
+ const { refs, refsByEntry, treeNodes } = buildTree(rootEntryId, entries, locale);
97
+ const session = {
98
+ version: 1,
99
+ spaceKey: key,
100
+ spaceId: space.spaceId,
101
+ environment: space.environment,
102
+ defaultLocale: locale,
103
+ rootEntryId,
104
+ rootEntryType: 'article',
105
+ fetchedAt: new Date().toISOString(),
106
+ entries,
107
+ originalEntries: JSON.parse(JSON.stringify(entries)),
108
+ refs,
109
+ refsByEntry,
110
+ treeNodes,
111
+ modifiedEntryIds: [],
112
+ pendingDeletions: [],
113
+ };
114
+ saveSession(session);
115
+ successMsg(`Created article "${opts.title}" (ID: ${rootEntryId})`);
116
+ infoMsg(`View in Contentful: https://app.contentful.com/spaces/${space.spaceId}/entries/${rootEntryId}`);
117
+ if (!isJsonMode()) {
118
+ renderSnapshot(session);
119
+ }
120
+ }
121
+ catch (err) {
122
+ errorMsg(err instanceof Error ? err.message : String(err));
123
+ process.exit(1);
124
+ }
125
+ });
126
+ create
127
+ .command('template')
128
+ .description('Create a new template entry')
129
+ .requiredOption('--label <label>', 'Template label (cmsLabel)')
130
+ .action(async (opts, _cmd, cmd2) => {
131
+ const parentOpts = cmd2.parent?.parent?.opts() ?? {};
132
+ try {
133
+ const config = loadConfig(parentOpts.config);
134
+ const { key, space } = resolveSpaceConfig(config, parentOpts.space);
135
+ const env = await createSafeEnvironment(space);
136
+ const locale = space.defaultLocale;
137
+ const newEntry = await env.createEntry('template', {
138
+ cmsLabel: { [locale]: opts.label },
139
+ });
140
+ const rootEntryId = newEntry.sys.id;
141
+ const entries = await fetchEntryTree(env, rootEntryId);
142
+ entries[rootEntryId] = serializeEntry(newEntry);
143
+ const { refs, refsByEntry, treeNodes } = buildTree(rootEntryId, entries, locale);
144
+ const session = {
145
+ version: 1,
146
+ spaceKey: key,
147
+ spaceId: space.spaceId,
148
+ environment: space.environment,
149
+ defaultLocale: locale,
150
+ rootEntryId,
151
+ rootEntryType: 'template',
152
+ fetchedAt: new Date().toISOString(),
153
+ entries,
154
+ originalEntries: JSON.parse(JSON.stringify(entries)),
155
+ refs,
156
+ refsByEntry,
157
+ treeNodes,
158
+ modifiedEntryIds: [],
159
+ pendingDeletions: [],
160
+ };
161
+ saveSession(session);
162
+ successMsg(`Created template "${opts.label}" (ID: ${rootEntryId})`);
163
+ infoMsg(`View in Contentful: https://app.contentful.com/spaces/${space.spaceId}/entries/${rootEntryId}`);
164
+ infoMsg(`Open with: cms-edit open ${rootEntryId} --id`);
165
+ if (!isJsonMode()) {
166
+ renderSnapshot(session);
167
+ }
168
+ }
169
+ catch (err) {
170
+ errorMsg(err instanceof Error ? err.message : String(err));
171
+ process.exit(1);
172
+ }
173
+ });
174
+ create
175
+ .command('navigation')
176
+ .description('Create a new navigation entry')
177
+ .requiredOption('--label <label>', 'Navigation label (cmsLabel or adminLabel)')
178
+ .action(async (opts, _cmd, cmd2) => {
179
+ const parentOpts = cmd2.parent?.parent?.opts() ?? {};
180
+ try {
181
+ const config = loadConfig(parentOpts.config);
182
+ const { key, space } = resolveSpaceConfig(config, parentOpts.space);
183
+ const env = await createSafeEnvironment(space);
184
+ const locale = space.defaultLocale;
185
+ const newEntry = await env.createEntry('navigation', {
186
+ cmsLabel: { [locale]: opts.label },
187
+ });
188
+ const rootEntryId = newEntry.sys.id;
189
+ const entries = await fetchEntryTree(env, rootEntryId);
190
+ entries[rootEntryId] = serializeEntry(newEntry);
191
+ const { refs, refsByEntry, treeNodes } = buildTree(rootEntryId, entries, locale);
192
+ const session = {
193
+ version: 1,
194
+ spaceKey: key,
195
+ spaceId: space.spaceId,
196
+ environment: space.environment,
197
+ defaultLocale: locale,
198
+ rootEntryId,
199
+ rootEntryType: 'navigation',
200
+ fetchedAt: new Date().toISOString(),
201
+ entries,
202
+ originalEntries: JSON.parse(JSON.stringify(entries)),
203
+ refs,
204
+ refsByEntry,
205
+ treeNodes,
206
+ modifiedEntryIds: [],
207
+ pendingDeletions: [],
208
+ };
209
+ saveSession(session);
210
+ successMsg(`Created navigation "${opts.label}" (ID: ${rootEntryId})`);
211
+ infoMsg(`View in Contentful: https://app.contentful.com/spaces/${space.spaceId}/entries/${rootEntryId}`);
212
+ infoMsg(`Open with: cms-edit open ${rootEntryId} --id or cms-edit nav open ${rootEntryId} --id`);
213
+ if (!isJsonMode()) {
214
+ renderSnapshot(session);
215
+ }
216
+ }
217
+ catch (err) {
218
+ errorMsg(err instanceof Error ? err.message : String(err));
219
+ process.exit(1);
220
+ }
221
+ });
222
+ }
223
+ //# sourceMappingURL=create.js.map