@contentful/create-contentful-app 4.1.1 → 4.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -56,6 +56,20 @@ Select between predefined and custom templates:
56
56
 
57
57
  These flags are mutually exclusive. If no flag is provided, the TypeScript template is used.
58
58
 
59
+ ### AI App-Building Skill
60
+
61
+ By default, `create-contentful-app` installs Contentful's official app-building AI skill ([`contentful-custom-app-from-scratch`](https://github.com/contentful/skills)) into your new app. The skill gives AI coding harnesses (Claude Code, OpenAI Codex, Cursor, and others) expert guidance for building Contentful apps. It is pulled live via the [`skills`](https://skills.sh) CLI at scaffold time, so you always get the current version, and the CLI automatically detects your harness.
62
+
63
+ In interactive mode you are asked whether to include it (default yes). Installation is best-effort: if it fails (e.g. you are offline), your app is still created and a message shows the command to add it later.
64
+
65
+ - `--skip-skills` (or `--no-skills`): do not install the app-building skill.
66
+
67
+ To install it manually later, run this inside your app folder:
68
+
69
+ ```bash
70
+ npx -y skills add contentful/skills --skill contentful-custom-app-from-scratch -y
71
+ ```
72
+
59
73
  Some popular templates are:
60
74
 
61
75
  | Template | CLI Command |
@@ -98,6 +112,8 @@ Options:
98
112
  format: URL (HTTPS or SSH) or vendor:user/repo (e.g., github:user/repo)
99
113
  -f, --function <function-template-name> include the specified function template
100
114
  --skip-ui use with --function to clone the template without a user interface (UI).
115
+ --skip-skills skip installing the Contentful app-building AI skill into the new app
116
+ --no-skills alias for --skip-skills
101
117
  -h, --help shows all available CLI options
102
118
  ```
103
119
 
package/lib/index.js CHANGED
@@ -17,10 +17,22 @@ const logger_1 = require("./logger");
17
17
  const chalk_1 = __importDefault(require("chalk"));
18
18
  const constants_1 = require("./constants");
19
19
  const getTemplateSource_1 = require("./getTemplateSource");
20
+ const skills_1 = require("./skills");
20
21
  const analytics_1 = require("./analytics");
21
22
  const app_scripts_1 = require("@contentful/app-scripts");
22
23
  const fs_2 = __importDefault(require("fs"));
23
24
  const DEFAULT_APP_NAME = 'contentful-app';
25
+ /**
26
+ * Whether the CLI is running without any template-selecting flags. In that case
27
+ * we prompt the user (e.g. for the app-building skill); otherwise we honor the flags.
28
+ */
29
+ function isInteractiveRun(options) {
30
+ return (!options.example &&
31
+ !options.source &&
32
+ !options.javascript &&
33
+ !options.typescript &&
34
+ !options.function);
35
+ }
24
36
  function successMessage(folder, packageManager) {
25
37
  let command = '';
26
38
  if (packageManager === 'yarn') {
@@ -112,6 +124,10 @@ async function initProject(appName, options) {
112
124
  else {
113
125
  await (0, utils_1.exec)('npm', ['install', '--no-audit', '--no-fund'], { cwd: fullAppFolder });
114
126
  }
127
+ const includeSkill = await (0, skills_1.resolveShouldIncludeSkill)(normalizedOptions, isInteractiveRun(normalizedOptions));
128
+ if (includeSkill) {
129
+ await (0, skills_1.installAppBuildingSkill)(fullAppFolder);
130
+ }
115
131
  successMessage(fullAppFolder, packageManager);
116
132
  }
117
133
  catch (err) {
@@ -119,11 +135,7 @@ async function initProject(appName, options) {
119
135
  process.exit(1);
120
136
  }
121
137
  async function addAppExample(fullAppFolder) {
122
- const isInteractive = !normalizedOptions.example &&
123
- !normalizedOptions.source &&
124
- !normalizedOptions.javascript &&
125
- !normalizedOptions.typescript &&
126
- !normalizedOptions.function;
138
+ const isInteractive = isInteractiveRun(normalizedOptions);
127
139
  const templateSource = await (0, getTemplateSource_1.getTemplateSource)(options);
128
140
  (0, analytics_1.track)({
129
141
  template: templateSource,
@@ -193,6 +205,8 @@ async function initProject(appName, options) {
193
205
  ].join('\n'))
194
206
  .option('-f, --function [function-template-name]', 'include the specified function template')
195
207
  .option('--skip-ui', 'use with --function to clone the template without a user interface (UI).')
208
+ .option('--skip-skills', 'skip installing the Contentful app-building AI skill into the new app')
209
+ .option('--no-skills', 'alias for --skip-skills')
196
210
  .action(initProject);
197
211
  await commander_1.program.parseAsync();
198
212
  })();
package/lib/skills.js ADDED
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.resolveShouldIncludeSkill = exports.promptIncludeSkill = exports.installAppBuildingSkill = exports.MANUAL_INSTALL_COMMAND = exports.APP_BUILDING_SKILL = exports.SKILLS_SOURCE = void 0;
7
+ const inquirer_1 = __importDefault(require("inquirer"));
8
+ const child_process_1 = require("child_process");
9
+ const logger_1 = require("./logger");
10
+ exports.SKILLS_SOURCE = 'contentful/skills';
11
+ exports.APP_BUILDING_SKILL = 'contentful-custom-app-from-scratch';
12
+ /**
13
+ * The command a user can run manually to install the skill later. Kept in sync
14
+ * with the arguments passed to the default runner below.
15
+ */
16
+ exports.MANUAL_INSTALL_COMMAND = `npx -y skills add ${exports.SKILLS_SOURCE} --skill ${exports.APP_BUILDING_SKILL} -y`;
17
+ const defaultRunner = (appFolder) => new Promise((resolve, reject) => {
18
+ const child = (0, child_process_1.spawn)('npx', ['-y', 'skills', 'add', exports.SKILLS_SOURCE, '--skill', exports.APP_BUILDING_SKILL, '-y'], { stdio: 'inherit', shell: true, cwd: appFolder });
19
+ child.on('error', reject);
20
+ child.on('exit', (exitCode) => {
21
+ if (exitCode === 0) {
22
+ resolve();
23
+ }
24
+ else {
25
+ reject(new Error(`skills installer exited with code ${exitCode ?? 'unknown'}`));
26
+ }
27
+ });
28
+ });
29
+ /**
30
+ * Best-effort installation of the Contentful app-building skill into a scaffolded
31
+ * app. The skill is pulled live via the `skills` CLI so it is always current and
32
+ * works across AI harnesses (Claude Code, OpenAI Codex, Cursor, and others — the
33
+ * CLI auto-detects the active harness).
34
+ *
35
+ * This never throws: a failure (offline, npx error, etc.) is logged as a warning
36
+ * with the manual command so app creation always completes.
37
+ *
38
+ * @returns `true` if the skill was installed, `false` if installation was skipped
39
+ * due to an error.
40
+ */
41
+ async function installAppBuildingSkill(appFolder, deps = {}) {
42
+ const run = deps.run ?? defaultRunner;
43
+ console.log(`Installing the Contentful app-building AI skill (${(0, logger_1.highlight)(exports.APP_BUILDING_SKILL)})...`);
44
+ try {
45
+ await run(appFolder);
46
+ console.log(`${(0, logger_1.success)('Done!')} Added the ${(0, logger_1.highlight)(exports.APP_BUILDING_SKILL)} skill to your app.`);
47
+ return true;
48
+ }
49
+ catch (e) {
50
+ const reason = e instanceof Error ? e.message : String(e);
51
+ (0, logger_1.warn)(`Could not install the Contentful app-building AI skill (${reason}). Your app was created successfully. ` +
52
+ `To add it later, run ${(0, logger_1.choice)(exports.MANUAL_INSTALL_COMMAND)} inside your app folder.`);
53
+ return false;
54
+ }
55
+ }
56
+ exports.installAppBuildingSkill = installAppBuildingSkill;
57
+ /**
58
+ * Prompts the user (interactive mode only) whether to include the app-building
59
+ * skill. Defaults to yes.
60
+ */
61
+ async function promptIncludeSkill() {
62
+ const { includeSkill } = await inquirer_1.default.prompt([
63
+ {
64
+ type: 'confirm',
65
+ name: 'includeSkill',
66
+ message: 'Include the Contentful app-building AI skill?',
67
+ default: true,
68
+ },
69
+ ]);
70
+ return includeSkill;
71
+ }
72
+ exports.promptIncludeSkill = promptIncludeSkill;
73
+ /**
74
+ * Resolves whether the app-building skill should be installed.
75
+ *
76
+ * - An explicit opt-out (`--skip-skills`, or commander's `--no-skills` which sets
77
+ * `skills: false`) always wins and never prompts.
78
+ * - In interactive mode, the user is prompted (default yes).
79
+ * - In non-interactive / flagged runs, the skill is installed by default.
80
+ */
81
+ async function resolveShouldIncludeSkill(options, isInteractive, prompt = promptIncludeSkill) {
82
+ if (options.skipSkills === true || options.skills === false) {
83
+ return false;
84
+ }
85
+ if (isInteractive) {
86
+ return prompt();
87
+ }
88
+ return true;
89
+ }
90
+ exports.resolveShouldIncludeSkill = resolveShouldIncludeSkill;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentful/create-contentful-app",
3
- "version": "4.1.1",
3
+ "version": "4.1.2",
4
4
  "description": "A template for building Contentful Apps",
5
5
  "keywords": [
6
6
  "contentful",