@contentful/create-contentful-app 4.1.0 → 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 +16 -0
- package/lib/index.js +19 -5
- package/lib/skills.js +90 -0
- package/package.json +2 -2
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 =
|
|
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.
|
|
3
|
+
"version": "4.1.2",
|
|
4
4
|
"description": "A template for building Contentful Apps",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"contentful",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"test": "mocha 'test/**/*.spec.{js,ts}'"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@contentful/app-scripts": "4.1.
|
|
39
|
+
"@contentful/app-scripts": "4.1.1",
|
|
40
40
|
"@segment/analytics-node": "^3.0.0",
|
|
41
41
|
"chalk": "4.1.2",
|
|
42
42
|
"commander": "12.1.0",
|