enonic-controller-generator
Generates Enonic XP controller files (TypeScript/JavaScript) and paired XML descriptors for pages, parts, and layouts. Covers lib-portal imports, HTTP handler exports, region definitions, Thymeleaf/Mustache rendering, and response processors. Use when scaffolding page controllers with regions, part controllers with config access, layout controllers with multi-region support, or response processors for Enonic XP sites. Do not use for content type schemas, headless Next.js/React frontends, GraphQL Guillotine queries, or non-Enonic web frameworks.
Works with
---
name: enonic-controller-generator
description: Generates Enonic XP controller files (TypeScript/JavaScript) and paired XML descriptors for pages, parts, and layouts. Covers lib-portal imports, HTTP handler exports, region definitions, Thymeleaf/Mustache rendering, and response processors. Use when scaffolding page controllers with regions, part controllers with config access, layout controllers with multi-region support, or response processors for Enonic XP sites. Do not use for content type schemas, headless Next.js/React frontends, GraphQL Guillotine queries, or non-Enonic web frameworks.
license: MIT
---
# Enonic XP Controller Generator
## Procedures
**Step 1: Detect Enonic XP Project**
1. Execute `node scripts/find-enonic-targets.mjs <workspace-root>` to locate the project root and existing components.
2. If the script exits with code 1 (no markers found), inform the user that no Enonic XP project was detected and stop.
3. Record the `sitePath` from stdout — all generated files target directories relative to this path.
**Step 2: Determine Component Type**
1. Identify which component type the user requires:
- **Page** — renders a full page, may declare one or more regions.
- **Part** — a leaf component with a config form, no regions.
- **Layout** — organizes other components via named regions.
- **Response processor** — a site-level filter that modifies the HTTP response (e.g., inject scripts).
2. If the request is ambiguous, ask the user to clarify the component type before proceeding.
**Step 3: Gather Component Details**
1. Ask for or infer the following:
- **Component name** (kebab-case, e.g., `hero-banner`).
- **Display name** (human-readable, e.g., `Hero Banner`).
- **Language** — TypeScript (`.ts`, default) or JavaScript (`.js`). Read `references/compatibility.md` for guidance on TS vs JS differences.
- **Template engine** — Thymeleaf (default) or Mustache.
- For pages/layouts: **region names** (default: `main` for pages).
- For parts: **form fields** (name, type, occurrences).
- For response processors: **page contribution target** (`bodyEnd`, `headEnd`, etc.) and the content to inject.
**Step 4: Generate the XML Descriptor**
1. Read `references/controller-reference.md` for the XML descriptor schema.
2. Create the descriptor file:
- Page: `<sitePath>/pages/<name>/<name>.xml`
- Part: `<sitePath>/parts/<name>/<name>.xml`
- Layout: `<sitePath>/layouts/<name>/<name>.xml`
3. Include `<display-name>`, `<description>`, `<form>` (with inputs for parts), and `<regions>` (for pages and layouts).
**Step 5: Generate the Controller**
1. Read the appropriate template from `assets/`:
- `assets/page-controller.template.ts` for pages.
- `assets/part-controller.template.ts` for parts.
- `assets/layout-controller.template.ts` for layouts.
2. Replace placeholders with the actual component name, config field mappings, region names, and library imports.
3. If JavaScript was requested, convert the ES module syntax to CommonJS (`require`/`exports`).
4. Read `references/controller-reference.md` for the Portal API surface (functions, import paths).
5. Place the controller at:
- Page: `<sitePath>/pages/<name>/<name>.ts` (or `.js`)
- Part: `<sitePath>/parts/<name>/<name>.ts` (or `.js`)
- Layout: `<sitePath>/layouts/<name>/<name>.ts` (or `.js`)
- Processor: `<sitePath>/processors/<name>.js`
**Step 6: Generate the View (if applicable)**
1. For pages, parts, and layouts using Thymeleaf or Mustache, generate a paired `.html` view file in the same directory as the controller.
2. For pages and layouts, include `data-portal-region="<region-name>"` attributes on container elements.
3. For region iteration, use `data-th-each="component : ${region.components}"` with `data-portal-component="${component.path}"`.
**Step 7: Wire Response Processors (if applicable)**
1. If generating a response processor, check whether `<sitePath>/site.xml` exists.
2. If it exists, add a `<response-processor>` entry inside the `<processors>` block.
3. If it does not exist, create `<sitePath>/site.xml` with the processor declaration.
**Step 8: Update build.gradle Dependencies**
1. Check the project's `build.gradle` for existing library includes.
2. Add any missing dependencies:
- `com.enonic.xp:lib-portal:${xpVersion}` — required for all controllers.
- `com.enonic.xp:lib-content:${xpVersion}` — if the controller uses content queries.
- `com.enonic.lib:lib-thymeleaf:2.0.0` — if using Thymeleaf rendering.
- `com.enonic.lib:lib-mustache:2.1.0` — if using Mustache rendering.
- `com.enonic.lib:lib-asset:${libVersion}` — if the controller generates asset URLs (replaces the deprecated `portalLib.assetUrl` in XP 7.15+).
**Step 9: Validate Output**
1. Verify the descriptor file name matches the parent directory name exactly.
2. Verify the controller file name matches the descriptor directory name.
3. Verify all region names in the controller/view match those declared in the XML descriptor.
4. Read `references/examples.md` to cross-check the generated code against known-good patterns.
## Error Handling
* If `scripts/find-enonic-targets.mjs` exits with code 1 (`NO_PROJECT`), inform the user that no Enonic XP project was found and suggest creating the standard directory structure under `src/main/resources/site/`.
* If a component with the same name already exists at the target path, warn the user and ask whether to overwrite or rename.
* If the user reports a 404 on a part or missing regions, read `references/troubleshooting.md` to diagnose common causes.
* If the generated controller fails at runtime with view resolution errors, verify the view file is co-located with the controller and the `resolve()` call uses the correct filename.More API Design skills
lark-event
larksuite/cli
Lark/Feishu real-time event listening / subscribing / consuming: stream events as NDJSON via `lark-cli event consume <EventKey>` (covers IM messages/reactions/chat changes, Approval status changes, Task updates, VC meeting started/joined/ended, Minutes generated, Whiteboard updated, etc.). Use for Lark bots, real-time message processing, long-running subscribers, streaming webhook/push handlers. Supports `--max-events` / `--timeout` bounded runs and a stderr ready-marker contract — designed for AI agents running as subprocesses.
lark-contact
larksuite/cli
飞书 / Lark 通讯录:按姓名 / 邮箱解析成 open_id,或按 open_id 反查姓名 / 部门 / 邮箱 / 联系方式 / 个人状态 / 签名,以及按关键词搜索当前用户可见的机器人 / 智能体(agent)。当用户提到一个名字要下一步发消息 / 排日程,或拿到 open_id 想查具体信息时使用。不负责部门树遍历、按部门列员工、组织架构图,这类需求走原生 OpenAPI。
lark-openapi-explorer
larksuite/cli
飞书/Lark 原生 OpenAPI 探索:从官方文档库中挖掘未经 CLI 封装的原生 OpenAPI 接口。当用户的需求无法被现有 lark-* skill 或 lark-cli 已注册命令满足,需要查找并调用原生飞书 OpenAPI 时使用。

