用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/tomevault-io/skills-registry --skill xp-app-creator命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
| Use when this capability is needed.
> Use when this capability is needed.
Review architecture and API design for the vfs-s3 project. Use when the user mentions @architect, asks to review an issue's design, discuss module boundaries, API shape, or architectural decisions for vfs-s3. Also trigger when the user wants to create an ADR (Architecture Decision Record) or evaluate a technical approach for the project. Intended for dispatch from Codex automation or Claude routines; GitHub trigger phrase: @vfs-s3-bot please prepare design doc Use when this capability is needed.
基于 SOC 职业分类
正在显示 SKILL.md
| name | xp-app-creator |
| description | > Use when this capability is needed. |
<tool>, <widget>, <api>, and <task> use xmlns="urn:enonic:xp:model:1.0". Component descriptors (<page>, <part>, <layout>), <service> descriptors, and schema files (<content-type>, <mixin>, <x-data>, <site>, <application>) do NOT use a namespace. XP 8 uses .yml descriptors for admin tools, APIs, and webapps instead of XML — see references/controllers.md.parts/my-part/my-part.xml. Content types: content-types/article/article.xml.<name>.js next to <name>.xml. In TS apps, tsup/webpack compiles <name>.ts to <name>.js in build/resources/main/.name attribute on <input>, not id.minimum="0" maximum="1" if omitted. Use maximum="0" for unlimited.${app}:type-name where ${app} resolves to the application key (e.g. com.example.myapp).site/ directory (pages, parts, content-types). Webapps use webapp/webapp.js as entry point. Admin tools use admin/tools/ only (no site/, no webapp/)..ts, .tsx, .json (tsconfig files). Only compiled .js should be in the JAR.scriptEngine = "GraalJS" in the build.gradle app block. This enables ES2023 features (optional chaining, for...of, Array.includes(), Number.isNaN(), etc.) and strict mode. Server-side esbuild/tsup target must be es2023 (not es5/es2015). See references/build-system.md for full configuration.With CLI (preferred): Use the enonic-cli skill. Run enonic project create -r starter-vanilla or enonic project create -r starter-ts.
Without CLI: See references/build-system.md for manual setup of build.gradle, gradle.properties, and settings.gradle.
Key files to verify after init:
gradle.properties -- appName, xpVersion, group set correctlysrc/main/resources/application.xml -- exists with descriptionsrc/main/resources/site/site.xml -- exists if building a site app (delete for webapp-only).enonic -- links project to sandbox (created by CLI)gradlew -- Gradle wrapper must be present. If missing, run gradle wrapper --gradle-version latest| Task | Files to create | Reference |
|---|---|---|
| Page | site/pages/<name>/<name>.xml + .js/.ts + .html | references/components.md |
| Part | site/parts/<name>/<name>.xml + .js/.ts + .html | references/components.md |
| Layout | site/layouts/<name>/<name>.xml + .js/.ts + .html | references/components.md |
| Content type | site/content-types/<name>/<name>.xml | references/content-types.md |
| Mixin | site/mixins/<name>/<name>.xml | references/content-types.md |
| X-Data | site/x-data/<name>/<name>.xml | references/content-types.md |
| Service | services/<name>/<name>.xml + .js/.ts | references/controllers.md |
| API | apis/<name>/<name>.yml (.xml for XP 7) + .js/.ts | references/controllers.md |
| Task | tasks/<name>/<name>.xml + .js/.ts | references/controllers.md |
| Admin tool | admin/tools/<name>/<name>.xml (.yml for XP 8) + .js/.ts + .html | references/controllers.md |
| Widget | admin/widgets/<name>/<name>.xml + .js/.ts + .html |
XML (site/parts/hello/hello.xml):
<part>
<display-name>Hello</display-name>
<description>A simple greeting part</description>
<form>
<input name="greeting" type="TextLine">
<label>Greeting</label>
<occurrences minimum="1" maximum="1"/>
</input>
</form>
</part>
JS controller (site/parts/hello/hello.js):
var portal = require('/lib/xp/portal');
var thymeleaf = require('/lib/thymeleaf');
exports.get = function(req) {
var component = portal.getComponent();
var model = {
greeting: component.config.greeting || 'Hello, World!'
};
return {
body: thymeleaf.render(resolve('hello.html'), model)
};
};
TS controller (site/parts/hello/hello.ts):
import { getComponent } from '/lib/xp/portal';
import { render } from '/lib/thymeleaf';
export function get(req: XP.Request): XP.Response {
const component = getComponent<{ greeting?: string }>();
const model = {
greeting: component.config.greeting || 'Hello, World!'
};
return {
body: render(resolve('hello.html'), model)
};
}
View (site/parts/hello/hello.html):
<div data-th-text="${greeting}">Placeholder</div>
XML (site/content-types/article/article.xml):
<content-type>
<display-name>Article</display-name>
<description>News article</description>
<super-type>base:structured</super-type>
<form>
<input name="title" type="TextLine">
<label>Title</label>
<occurrences minimum="1" maximum="1"/>
</input>
<input name="body" type="HtmlArea">
<label>Body</label>
<occurrences minimum="0" maximum="1"/>
</input>
<input name="image" type="ImageSelector">
<label>Featured Image</label>
| Type | Description | Key config |
|---|---|---|
TextLine | Single-line text | regexp, max-length |
TextArea | Multi-line text | max-length |
HtmlArea | Rich text editor | allowedContentTypes (image/media filter) |
Checkbox | Boolean toggle | default ("checked") |
ComboBox | Dropdown select | <option> children, max |
RadioButton | Single choice | <option> children |
Tag | Tag input | -- |
Date | Date picker | default, timezone |
DateTime | Date + time | default, timezone |
Time | Time picker | default |
Long | Integer | default |
Double | Decimal | default |
GeoPoint | Lat/lon | -- |
ContentSelector | Content reference | allowContentType, allowPath |
ImageSelector | Image reference | allowPath |
MediaSelector | Media reference | allowContentType, allowPath |
AttachmentUploader |
All types support: name, label, help-text, occurrences, default.
See references/input-types.md for full XML examples and config options.
ItemSet -- repeatable group of fields:
<item-set name="links">
<label>Links</label>
<occurrences minimum="0" maximum="0"/>
<items>
<input name="url" type="TextLine"><label>URL</label></input>
<input name="text" type="TextLine"><label>Text</label></input>
</items>
</item-set>
OptionSet -- choose between alternative field groups:
<option-set name="media">
<label>Media</label>
<options minimum="1" maximum="1">
<option name="image">
<label>Image</label>
<items>
<input name="image" type="ImageSelector"><label>Image</label></input>
</items>
</option>
<option name="video">
<label>Video</label>
<items>
<input name="url" type="TextLine"><label>Video URL</label></input>
</items>
FieldSet -- visual grouping (no data structure):
<field-set name="metadata">
<label>Metadata</label>
<items>
<input name="tags" type="Tag"><label>Tags</label></input>
</items>
</field-set>
Inline mixin:
<inline mixin="my-mixin"/>
Portal lib (/lib/xp/portal):
getComponent() -- current page/part/layout configgetContent() -- current content in contextgetSiteConfig() -- site.xml config valuesassetUrl({ path }) -- URL to static assetserviceUrl({ service }) -- URL to service controllerapiUrl({ api, path? }) -- URL to API endpoint (XP 8+)pageUrl({ path }) -- URL to content pathimageUrl({ id, scale }) -- URL to imageAsset lib (/lib/enonic/asset) -- for admin tools without portal context:
assetUrl({ path }) -- URL to static asset (use instead of portal.assetUrl in admin tools)Content lib (/lib/xp/content):
get({ key }) -- get content by ID or pathquery({ query, contentTypes, count, start }) -- query contentcreate({ name, parentPath, contentType, data }) -- create contentmodify({ key, editor }) -- modify contentThymeleaf (/lib/thymeleaf):
render(view, model) -- render template with modelresolve('template.html') to get view referenceGlobal objects (available in all controllers):
app.name -- application key (e.g. com.example.myapp)app.version -- application versionapp.config -- values from <appName>.cfg in XP home config directory (e.g. com.example.myapp.cfg)log.info(), log.error(), log.debug(), log.warning()__ (double underscore) -- Java interop (__.newBean(), __.toNativeObject(), __.toScriptValue())Java.type(className) -- direct Java class access (e.g. Java.type('com.enonic.xp.name.NamePrettyfier'))resolve(path) -- resolve relative resource pathController response format:
return {
status: 200, // HTTP status (default 200)
contentType: 'text/html', // MIME type
body: content, // string, object (auto-JSON), or stream
headers: { 'Cache-Control': '...' }, // optional
cookies: {}, // optional
pageContributions: { // optional (pages/parts/layouts only)
headBegin: [],
headEnd: [],
bodyBegin: [],
bodyEnd: []
}
};
| File | Load when... |
|---|---|
references/project-structure.md | Setting up a new project or understanding directory layout |
references/components.md | Creating pages, parts, or layouts with controllers and views |
references/content-types.md | Creating content types, mixins, or x-data schemas |
references/input-types.md | Need full XML syntax for specific input types or form structures |
references/controllers.md | Writing controllers for services, tasks, admin tools, widgets, error handlers |
references/site-config.md | Configuring site.xml, content mappings, or x-data activation |
references/build-system.md | Setting up or modifying Gradle, tsup, or webpack build pipeline |
Converted and distributed by TomeVault — claim your Tome and manage your conversions.
references/controllers.md| Error handler | error/error.js/.ts | references/controllers.md |
| Response processor | site/processors/<name>.js/.ts | references/controllers.md |
| Webapp | webapp/webapp.js/.ts | references/controllers.md |
| File upload |
| -- |
CustomSelector | Custom endpoint | service |
ContentTypeFilter | Content type filter | -- |