@epilot/cli 0.1.10 → 0.1.12

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 (89) hide show
  1. package/README.md +18 -21
  2. package/definitions/app.json +56 -6
  3. package/definitions/automation.json +214 -1
  4. package/definitions/blueprint-manifest.json +1303 -60
  5. package/definitions/customer-portal.json +757 -81
  6. package/definitions/data-governance.json +1126 -0
  7. package/definitions/deduplication.json +135 -4
  8. package/definitions/design.json +103 -57
  9. package/definitions/email-settings.json +150 -0
  10. package/definitions/email-template.json +25 -3
  11. package/definitions/entity.json +405 -5
  12. package/definitions/erp-integration.json +3140 -1049
  13. package/definitions/integration-toolkit.json +7998 -0
  14. package/definitions/journey.json +18 -1
  15. package/definitions/kanban.json +25 -1
  16. package/definitions/message.json +202 -0
  17. package/definitions/organization.json +35 -1
  18. package/definitions/partner-directory.json +795 -229
  19. package/definitions/permissions.json +41 -6
  20. package/definitions/sharing.json +956 -0
  21. package/definitions/template-variables.json +12 -4
  22. package/definitions/webhooks.json +111 -2
  23. package/definitions/workflow-definition.json +87 -202
  24. package/definitions/workflow.json +142 -0
  25. package/dist/{access-token-PTTCRMGK.js → access-token-CIM4RLBP.js} +1 -1
  26. package/dist/add-component-AAVQVPKK.js +296 -0
  27. package/dist/{address-2FDPEPR6.js → address-EDRTUWTP.js} +1 -1
  28. package/dist/{address-suggestions-XBEK5DDQ.js → address-suggestions-S5WEST2N.js} +1 -1
  29. package/dist/{ai-agents-ZY5BNVTN.js → ai-agents-RXDDJDAR.js} +1 -1
  30. package/dist/{app-IT5FWGUK.js → api-36XROHLK.js} +5 -5
  31. package/dist/app-I3XXHZLD.js +24 -0
  32. package/dist/{audit-logs-FB4TE4TI.js → audit-logs-PXGDGJGV.js} +1 -1
  33. package/dist/{automation-JE5LDKJM.js → automation-LS6MVLP2.js} +1 -1
  34. package/dist/{billing-GOFCP5T3.js → billing-KVYFUKZK.js} +1 -1
  35. package/dist/bin/epilot.js +53 -52
  36. package/dist/{blueprint-manifest-WJIQKFYK.js → blueprint-manifest-W4ZGJD2Z.js} +1 -1
  37. package/dist/{chunk-P5IZZW4Y.js → chunk-BYAEI4Z2.js} +1 -1
  38. package/dist/chunk-CEP7S7X3.js +366 -0
  39. package/dist/{chunk-MNSG22DM.js → chunk-F6KWKTQJ.js} +124 -63
  40. package/dist/{completion-HZNPHJI4.js → completion-QP4IYMVI.js} +1 -1
  41. package/dist/{consent-DSMWWHUL.js → consent-M4QB2HPM.js} +1 -1
  42. package/dist/{customer-portal-IJYTJYUZ.js → customer-portal-SVO2YCXA.js} +1 -1
  43. package/dist/{dashboard-DOAX6XDG.js → dashboard-CYCXIX74.js} +1 -1
  44. package/dist/{data-management-C4JPPUPD.js → data-governance-DJAAIE6F.js} +6 -6
  45. package/dist/{deduplication-7OGLZLAC.js → deduplication-M3KEVJRG.js} +1 -1
  46. package/dist/deploy-4XDFWOEV.js +214 -0
  47. package/dist/{design-3CAYTWFY.js → design-UVJJ2KO2.js} +1 -1
  48. package/dist/{document-NT5JOJQV.js → document-5HB632XE.js} +1 -1
  49. package/dist/{email-settings-2M3WJTQS.js → email-settings-H7HQTDYE.js} +1 -1
  50. package/dist/{email-template-F4PLBPPC.js → email-template-2DHZ3VKF.js} +1 -1
  51. package/dist/{entity-32LKMZAU.js → entity-HED6QHG7.js} +1 -1
  52. package/dist/{entity-mapping-OBCZDYQJ.js → entity-mapping-QP22B65Z.js} +1 -1
  53. package/dist/{environments-H3TBCDQE.js → environments-6LLEIGWV.js} +1 -1
  54. package/dist/{event-catalog-NVAPTZ4M.js → event-catalog-2ZCZTATY.js} +1 -1
  55. package/dist/export-JA5N4JCJ.js +44 -0
  56. package/dist/{file-US2HR4SV.js → file-R6IIXOIZ.js} +1 -1
  57. package/dist/{iban-7QUCOULB.js → iban-EQD2VROZ.js} +1 -1
  58. package/dist/init-5KGNJEWF.js +524 -0
  59. package/dist/integration-toolkit-4CLQDSK7.js +54 -0
  60. package/dist/{journey-E5T4BZZX.js → journey-V7X2KUKH.js} +1 -1
  61. package/dist/{kanban-7UHU5VE6.js → kanban-EPI6C3FR.js} +1 -1
  62. package/dist/{message-7KY33RJE.js → message-477EJ5JO.js} +1 -1
  63. package/dist/{metering-P7BZGMY7.js → metering-5EAEKRSL.js} +1 -1
  64. package/dist/{notes-TNJ7FPA3.js → notes-CVXNRULU.js} +1 -1
  65. package/dist/{notification-6KXEFVO5.js → notification-6HXS76XP.js} +1 -1
  66. package/dist/{organization-FF4Y3PBO.js → organization-O33CZQKD.js} +1 -1
  67. package/dist/{partner-directory-VH2SBAS2.js → partner-directory-NZWGCKSB.js} +2 -2
  68. package/dist/{permissions-KENZ4HNY.js → permissions-6QEOBJ6M.js} +1 -1
  69. package/dist/{pricing-P6QZ77VJ.js → pricing-KNYSULCW.js} +1 -1
  70. package/dist/{pricing-tier-2IRJMTM6.js → pricing-tier-OCHP6SHT.js} +1 -1
  71. package/dist/{purpose-IHROR6LQ.js → purpose-NGM42XWB.js} +1 -1
  72. package/dist/remove-component-LXSRR23E.js +89 -0
  73. package/dist/review-HFOO3NXE.js +69 -0
  74. package/dist/{sandbox-62XQPOU6.js → sandbox-YX3VVAQG.js} +1 -1
  75. package/dist/sharing-X5U53KSU.js +54 -0
  76. package/dist/{submission-PUWGOYQB.js → submission-YOWVSZNA.js} +1 -1
  77. package/dist/{targeting-QB3DFYNI.js → targeting-BMZCOG72.js} +1 -1
  78. package/dist/{template-variables-IPKRUJ4E.js → template-variables-YTABZL3E.js} +1 -1
  79. package/dist/{upgrade-TNDH4WGQ.js → upgrade-SYSSIAQC.js} +1 -1
  80. package/dist/{user-2CP75TFC.js → user-3N5ZOUYS.js} +1 -1
  81. package/dist/validate-TUMXW56Y.js +53 -0
  82. package/dist/{validation-rules-GNI4EEG5.js → validation-rules-QVS7LKEP.js} +1 -1
  83. package/dist/versions-ZTWQAGXY.js +109 -0
  84. package/dist/{webhooks-2OWUX7UL.js → webhooks-6WMWACOW.js} +1 -1
  85. package/dist/{workflow-WSLERVJI.js → workflow-ZO2MKDBS.js} +1 -1
  86. package/dist/{workflow-definition-FP3WKHGG.js → workflow-definition-RCWKIPYI.js} +1 -1
  87. package/package.json +2 -1
  88. package/definitions/data-management.json +0 -962
  89. package/dist/erp-integration-UW6H55EK.js +0 -54
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  callApi
4
- } from "./chunk-P5IZZW4Y.js";
4
+ } from "./chunk-BYAEI4Z2.js";
5
5
  import "./chunk-RSA7K5HB.js";
6
6
  import "./chunk-PDMWUCWD.js";
7
7
  import "./chunk-IOLKUHUB.js";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  callApi
4
- } from "./chunk-P5IZZW4Y.js";
4
+ } from "./chunk-BYAEI4Z2.js";
5
5
  import "./chunk-RSA7K5HB.js";
6
6
  import "./chunk-PDMWUCWD.js";
7
7
  import "./chunk-IOLKUHUB.js";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  callApi
4
- } from "./chunk-P5IZZW4Y.js";
4
+ } from "./chunk-BYAEI4Z2.js";
5
5
  import "./chunk-RSA7K5HB.js";
6
6
  import "./chunk-PDMWUCWD.js";
7
7
  import "./chunk-IOLKUHUB.js";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  callApi
4
- } from "./chunk-P5IZZW4Y.js";
4
+ } from "./chunk-BYAEI4Z2.js";
5
5
  import "./chunk-RSA7K5HB.js";
6
6
  import "./chunk-PDMWUCWD.js";
7
7
  import "./chunk-IOLKUHUB.js";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  callApi
4
- } from "./chunk-P5IZZW4Y.js";
4
+ } from "./chunk-BYAEI4Z2.js";
5
5
  import "./chunk-RSA7K5HB.js";
6
6
  import "./chunk-PDMWUCWD.js";
7
7
  import "./chunk-IOLKUHUB.js";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  callApi
4
- } from "./chunk-P5IZZW4Y.js";
4
+ } from "./chunk-BYAEI4Z2.js";
5
5
  import "./chunk-RSA7K5HB.js";
6
6
  import "./chunk-PDMWUCWD.js";
7
7
  import "./chunk-IOLKUHUB.js";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  callApi
4
- } from "./chunk-P5IZZW4Y.js";
4
+ } from "./chunk-BYAEI4Z2.js";
5
5
  import "./chunk-RSA7K5HB.js";
6
6
  import "./chunk-PDMWUCWD.js";
7
7
  import "./chunk-IOLKUHUB.js";
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ createAppApiClient,
4
+ log,
5
+ toManifest,
6
+ writeManifest
7
+ } from "./chunk-CEP7S7X3.js";
8
+ import "./chunk-RSA7K5HB.js";
9
+ import "./chunk-PDMWUCWD.js";
10
+ import "./chunk-7ZQ666ZQ.js";
11
+
12
+ // src/commands/app/export.ts
13
+ import { defineCommand } from "citty";
14
+ import { resolve } from "path";
15
+ var export_default = defineCommand({
16
+ meta: { name: "export", description: "Export an existing app as manifest.json" },
17
+ args: {
18
+ "app-id": { type: "string", description: "App ID to export", required: true },
19
+ version: { type: "string", description: "Version to export (default: latest)" },
20
+ output: { type: "string", alias: "o", description: "Output path (default: manifest.json)" },
21
+ token: { type: "string", alias: "t", description: "Bearer token" },
22
+ server: { type: "string", alias: "s", description: "Override server base URL" },
23
+ profile: { type: "string", description: "Use a named profile" }
24
+ },
25
+ run: async ({ args }) => {
26
+ const client = createAppApiClient({ token: args.token, server: args.server, profile: args.profile });
27
+ const appId = args["app-id"];
28
+ log.header(`Exporting app ${appId}...`);
29
+ const config = await client.getConfiguration(appId);
30
+ const targetVersion = args.version ?? config.latest_version;
31
+ const version = await client.getVersion(appId, targetVersion);
32
+ log.info(`Version: ${targetVersion}`);
33
+ const manifest = toManifest(config, version);
34
+ const outputPath = resolve(args.output ?? "manifest.json");
35
+ writeManifest(outputPath, manifest);
36
+ log.success(`Exported to ${outputPath}`);
37
+ log.info(`App: ${manifest.name}`);
38
+ log.info(`Components: ${manifest.components.length}`);
39
+ log.dim("Asset paths are placeholders. Update them to point to your local files.");
40
+ }
41
+ });
42
+ export {
43
+ export_default as default
44
+ };
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  callApi
4
- } from "./chunk-P5IZZW4Y.js";
4
+ } from "./chunk-BYAEI4Z2.js";
5
5
  import "./chunk-RSA7K5HB.js";
6
6
  import "./chunk-PDMWUCWD.js";
7
7
  import "./chunk-IOLKUHUB.js";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  callApi
4
- } from "./chunk-P5IZZW4Y.js";
4
+ } from "./chunk-BYAEI4Z2.js";
5
5
  import "./chunk-RSA7K5HB.js";
6
6
  import "./chunk-PDMWUCWD.js";
7
7
  import "./chunk-IOLKUHUB.js";
@@ -0,0 +1,524 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ log,
4
+ writeManifest
5
+ } from "./chunk-CEP7S7X3.js";
6
+ import "./chunk-RSA7K5HB.js";
7
+ import "./chunk-PDMWUCWD.js";
8
+ import "./chunk-7ZQ666ZQ.js";
9
+
10
+ // src/commands/app/init.ts
11
+ import { defineCommand } from "citty";
12
+ import { existsSync, mkdirSync, writeFileSync } from "fs";
13
+ import { resolve, join } from "path";
14
+ var init_default = defineCommand({
15
+ meta: { name: "init", description: "Scaffold a new epilot app project" },
16
+ args: {
17
+ name: { type: "positional", description: "App name (also used as directory name)", required: false }
18
+ },
19
+ run: ({ args }) => {
20
+ const name = args.name ?? "my-epilot-app";
21
+ const rootDir = resolve(name);
22
+ if (existsSync(rootDir)) {
23
+ log.error(`Directory "${name}" already exists.`);
24
+ process.exit(1);
25
+ }
26
+ mkdirSync(rootDir, { recursive: true });
27
+ mkdirSync(join(rootDir, "components"));
28
+ const manifest = {
29
+ $schema: "https://cdn.app.dev.sls.epilot.io/v1/schema.json",
30
+ manifest_version: 1,
31
+ name,
32
+ description: { de: "App description", en: "App description" },
33
+ category: "integration",
34
+ author: { company: "Your Company", name: "Your Name", email: "dev@example.com" },
35
+ components: []
36
+ };
37
+ writeManifest(join(rootDir, "manifest.json"), manifest);
38
+ writeFileSync(
39
+ join(rootDir, "package.json"),
40
+ `${JSON.stringify(
41
+ {
42
+ name,
43
+ version: "0.0.1",
44
+ private: true,
45
+ packageManager: "npm@10.9.2",
46
+ workspaces: ["components/*"],
47
+ scripts: {
48
+ build: "turbo build",
49
+ dev: "turbo dev",
50
+ lint: "turbo lint",
51
+ deploy: "epilot app deploy"
52
+ },
53
+ devDependencies: {
54
+ turbo: "^2"
55
+ }
56
+ },
57
+ null,
58
+ 2
59
+ )}
60
+ `
61
+ );
62
+ writeFileSync(
63
+ join(rootDir, "turbo.json"),
64
+ `${JSON.stringify(
65
+ {
66
+ $schema: "https://turbo.build/schema.json",
67
+ tasks: {
68
+ build: {
69
+ dependsOn: ["^build"],
70
+ outputs: ["dist/**"]
71
+ },
72
+ dev: {
73
+ cache: false,
74
+ persistent: true
75
+ },
76
+ lint: {}
77
+ }
78
+ },
79
+ null,
80
+ 2
81
+ )}
82
+ `
83
+ );
84
+ writeFileSync(join(rootDir, ".gitignore"), ["node_modules", "dist", ".turbo", ""].join("\n"));
85
+ writeFileSync(
86
+ join(rootDir, "components", "README.md"),
87
+ [
88
+ "# Components",
89
+ "",
90
+ "Each subdirectory is a component package in the monorepo.",
91
+ "",
92
+ "Add a new component with:",
93
+ "",
94
+ "```bash",
95
+ "epilot app add-component <name> --type CUSTOM_CAPABILITY",
96
+ "```",
97
+ "",
98
+ "Available component types:",
99
+ "",
100
+ "Code-based (have src/ and build step):",
101
+ "- `CUSTOM_FLOW_ACTION_SANDBOX` \u2014 Sandboxed flow action (JS runs in epilot)",
102
+ "- `CUSTOM_CAPABILITY` \u2014 Custom entity tab or group",
103
+ "- `CUSTOM_JOURNEY_BLOCK` \u2014 Custom journey builder block",
104
+ "- `CUSTOM_PAGE` \u2014 Custom navigation page",
105
+ "- `CUSTOM_PORTAL_BLOCK` \u2014 Custom portal widget",
106
+ "",
107
+ "Config-only (configuration.json):",
108
+ "- `CUSTOM_FLOW_ACTION_EXTERNAL` \u2014 External integration webhook",
109
+ "- `PORTAL_EXTENSION` \u2014 Portal extension hooks",
110
+ "- `EXTERNAL_PRODUCT_CATALOG` \u2014 External product catalog hooks",
111
+ ""
112
+ ].join("\n")
113
+ );
114
+ writeFileSync(
115
+ join(rootDir, "README.md"),
116
+ [
117
+ `# ${name}`,
118
+ "",
119
+ "An [epilot](https://epilot.cloud) app.",
120
+ "",
121
+ "## Getting started",
122
+ "",
123
+ "```bash",
124
+ "# Install dependencies",
125
+ "npm install",
126
+ "",
127
+ "# Add a component",
128
+ "epilot app add-component my-action --type CUSTOM_FLOW_ACTION",
129
+ "",
130
+ "# Build all components",
131
+ "npm run build",
132
+ "",
133
+ "# Validate the manifest",
134
+ "epilot app validate",
135
+ "",
136
+ "# Deploy (dry run)",
137
+ "epilot app deploy --dry-run",
138
+ "",
139
+ "# Deploy for real",
140
+ "epilot app deploy",
141
+ "```",
142
+ "",
143
+ "## Project structure",
144
+ "",
145
+ "```",
146
+ `${name}/`,
147
+ "\u251C\u2500\u2500 manifest.json # App manifest (source of truth)",
148
+ "\u251C\u2500\u2500 package.json # Monorepo root",
149
+ "\u251C\u2500\u2500 turbo.json # Turborepo config",
150
+ "\u2514\u2500\u2500 components/",
151
+ " \u2514\u2500\u2500 <component-name>/ # Each component is a package",
152
+ " \u251C\u2500\u2500 package.json",
153
+ " \u251C\u2500\u2500 src/",
154
+ " \u2514\u2500\u2500 dist/",
155
+ "```",
156
+ ""
157
+ ].join("\n")
158
+ );
159
+ writeFileSync(
160
+ join(rootDir, "SKILL.md"),
161
+ `---
162
+ name: epilot App Builder
163
+ description: Build, deploy, and manage epilot Apps using the declarative manifest system and CLI. Covers all component types, project structure, and deployment workflow.
164
+ ---
165
+
166
+ # epilot App Builder
167
+
168
+ You are working inside an epilot App project. This is a monorepo managed by Turborepo with a declarative \`manifest.json\` at the root. Your job is to help build, configure, and deploy this app.
169
+
170
+ ## Project Structure
171
+
172
+ \`\`\`
173
+ <app-name>/
174
+ \u251C\u2500\u2500 manifest.json # Declarative app manifest (source of truth)
175
+ \u251C\u2500\u2500 package.json # npm workspaces monorepo root
176
+ \u251C\u2500\u2500 turbo.json # Turborepo task config
177
+ \u251C\u2500\u2500 SKILL.md # This file (AI agent instructions)
178
+ \u2514\u2500\u2500 components/ # Each component is a workspace package
179
+ \u251C\u2500\u2500 <component-name>/ # Code-based component
180
+ \u2502 \u251C\u2500\u2500 package.json
181
+ \u2502 \u251C\u2500\u2500 tsconfig.json
182
+ \u2502 \u251C\u2500\u2500 vite.config.ts
183
+ \u2502 \u251C\u2500\u2500 src/
184
+ \u2502 \u2514\u2500\u2500 dist/ # Build output (uploaded on deploy)
185
+ \u2514\u2500\u2500 <component-name>/ # Config-only component
186
+ \u2514\u2500\u2500 configuration.json
187
+ \`\`\`
188
+
189
+ ## manifest.json Schema
190
+
191
+ The manifest is the source of truth. The CLI reads it to create, update, and deploy the app.
192
+
193
+ \`\`\`json
194
+ {
195
+ "$schema": "https://cdn.app.sls.epilot.io/v1/schema.json",
196
+ "manifest_version": 1,
197
+ "app_id": "uuid (set automatically after first deploy)",
198
+ "name": "App Name",
199
+ "description": { "de": "German description (required)", "en": "English description" },
200
+ "category": "integration",
201
+ "author": { "company": "Company", "name": "Name", "email": "dev@example.com" },
202
+ "documentation_url": "https://docs.example.com",
203
+ "support_email": "support@example.com",
204
+ "pricing": { "pricing_type": "FREE" },
205
+ "notifications": { "email": "dev@example.com", "events": ["app.installed", "app.uninstalled"] },
206
+ "permissions": [
207
+ { "action": "entity:read", "resource": "contact" },
208
+ { "action": "entity:write", "resource": "order" }
209
+ ],
210
+ "blueprint": { "manifest_id": "uuid" },
211
+ "assets": { "logo": "./assets/logo.png" },
212
+ "components": []
213
+ }
214
+ \`\`\`
215
+
216
+ **Important rules:**
217
+ - \`description.de\` is always required (German)
218
+ - \`app_id\` is set automatically after first \`epilot app deploy\` \u2014 never set it manually
219
+ - \`_dir\` on components is a CLI-internal field mapping to the directory in \`components/\`
220
+ - Component \`id\` must be a UUID
221
+ - Option values of type \`secret\` are never stored in the manifest \u2014 they are set per-installation
222
+
223
+ ## CLI Commands
224
+
225
+ All commands use \`epilot app <command>\`. Authentication uses stored credentials (\`epilot auth login\`) or \`--token\` / \`EPILOT_TOKEN\` env var.
226
+
227
+ ### \`epilot app init <name>\`
228
+ Scaffold a new app project (monorepo with turbo, manifest.json, components/ dir).
229
+
230
+ ### \`epilot app add-component <name> --type <TYPE>\`
231
+ Add a component. Downloads template from GitHub, adds entry to manifest.json.
232
+ Run interactively (no args) to get a type selector and name prompt.
233
+
234
+ ### \`epilot app remove-component <name>\`
235
+ Remove a component from manifest and delete its directory.
236
+ Run interactively (no args) to get a component selector.
237
+
238
+ ### \`epilot app validate\`
239
+ Validate manifest.json locally against the schema.
240
+
241
+ ### \`epilot app deploy [--dry-run] [--new-version] [--server <url>]\`
242
+ Deploy the app:
243
+ 1. Creates app on first deploy (writes \`app_id\` back to manifest)
244
+ 2. Updates metadata (name, description, etc.)
245
+ 3. Uploads assets (bundles, zips) and resolves CDN URLs
246
+ 4. Upserts components with resolved URLs
247
+ 5. Deletes remote components not in the manifest (sync)
248
+
249
+ **Important:** Components with missing build artifacts (bundle/zip) are skipped. Run \`npm run build\` first.
250
+
251
+ The deploy command reads \`components/<dir>/configuration.json\` at deploy time and uses it as the component's configuration. This means you edit config in the component directory, not in manifest.json.
252
+
253
+ ### \`epilot app export --app-id <id> [-o manifest.json]\`
254
+ Export an existing app from the API as a manifest.json.
255
+
256
+ ### \`epilot app versions [--app-id <id>]\`
257
+ List all versions with visibility, review status, and component count.
258
+
259
+ ### \`epilot app review --technical-contact <email> --marketing-contact <email> [--demo-url <url>]\`
260
+ Submit the latest version for public marketplace review.
261
+
262
+ ### \`epilot app api <operationId> [params]\`
263
+ Raw access to App API operations (OpenAPI-based).
264
+
265
+ ## Component Types
266
+
267
+ ### Code-based components (have src/, build step, produce dist/)
268
+
269
+ #### CUSTOM_JOURNEY_BLOCK
270
+ A Web Component embedded in the epilot Journey Builder. Built as a single UMD bundle.
271
+
272
+ **Stack:** React + Vite + \`@r2wc/react-to-web-component\` + \`@epilot/concorde-elements\`
273
+ **Build output:** \`dist/bundle.js\` (single file, CSS injected by JS)
274
+ **Manifest configuration:**
275
+ \`\`\`json
276
+ {
277
+ "component_type": "CUSTOM_JOURNEY_BLOCK",
278
+ "configuration": {
279
+ "component_url": "./components/<name>/dist/bundle.js",
280
+ "component_tag": "<name>",
281
+ "component_args": []
282
+ },
283
+ "assets": { "bundle": "./components/<name>/dist/bundle.js" }
284
+ }
285
+ \`\`\`
286
+
287
+ The \`component_url\` is a local path in the manifest. On deploy, the CLI uploads the bundle and replaces it with the CDN URL automatically.
288
+
289
+ **Key files:**
290
+ - \`src/main.tsx\` \u2014 Wraps React app as Web Component using \`r2wc\`, defines the custom element tag
291
+ - \`src/App.tsx\` \u2014 React component using \`@epilot/concorde-elements\` (Button, Card, Input)
292
+ - \`vite.config.ts\` \u2014 UMD build with \`fileName: () => 'bundle.js'\`, CSS injected by JS, single file output
293
+
294
+ **Component props (passed by the Journey runtime):**
295
+ \`\`\`typescript
296
+ type AppProps<T> = {
297
+ container: {
298
+ setValue: React.Dispatch<T> // Set the block's value
299
+ value?: T // Current value
300
+ theme?: string // Stringified theme JSON
301
+ errors?: string // Validation errors
302
+ required?: boolean // Whether the block is required
303
+ args?: string // Extra args from Journey Builder config
304
+ subscribe: (blockId: string, fn: (state: unknown) => void) => () => void
305
+ }
306
+ }
307
+ \`\`\`
308
+
309
+ #### CUSTOM_CAPABILITY
310
+ A tab or group on entity detail pages. Uses App Bridge for communication with epilot.
311
+
312
+ **Stack:** React + Vite + Tailwind + \`@epilot/volt-ui\` + \`@epilot/app-bridge\`
313
+ **Build output:** \`dist/\` directory (zipped and uploaded on deploy)
314
+ **Manifest configuration:**
315
+ \`\`\`json
316
+ {
317
+ "component_type": "CUSTOM_CAPABILITY",
318
+ "configuration": { "type": "tab", "allowed_schemas": ["contact", "order"] },
319
+ "surfaces": { "capability_config": { "app_url": "./components/<name>/dist/index.html" } },
320
+ "assets": { "zip": "./components/<name>/dist/" }
321
+ }
322
+ \`\`\`
323
+
324
+ \`allowed_schemas\` controls which entity types show the tab. Empty array = all schemas.
325
+ \`type\` can be \`"tab"\` or \`"group"\`.
326
+
327
+ **Key files:**
328
+ - \`src/main.tsx\` \u2014 Renders React app inside \`AppBridgeProvider\`
329
+ - \`src/AppBridgeProvider.tsx\` \u2014 Initializes App Bridge, receives auth token from parent
330
+ - \`src/AppBridgeContext.ts\` \u2014 React context for the bridge token
331
+ - \`vite.config.ts\` \u2014 Standard Vite build with \`base: './'\` for relative paths
332
+
333
+ #### CUSTOM_PAGE
334
+ A full custom page in the epilot navigation sidebar. Same stack as CUSTOM_CAPABILITY.
335
+
336
+ **Manifest configuration:**
337
+ \`\`\`json
338
+ {
339
+ "component_type": "CUSTOM_PAGE",
340
+ "configuration": { "slug": "<name>", "nav_label": "Page Title", "nav_icon": "layout" },
341
+ "surfaces": { "page": { "app_url": "./components/<name>/dist/index.html" } },
342
+ "assets": { "zip": "./components/<name>/dist/" }
343
+ }
344
+ \`\`\`
345
+
346
+ Reserved slugs (cannot use): entity, settings, dashboard, apps.
347
+
348
+ #### CUSTOM_PORTAL_BLOCK
349
+ A widget in the epilot Customer Portal. Same stack as CUSTOM_CAPABILITY.
350
+
351
+ **Manifest configuration:**
352
+ \`\`\`json
353
+ {
354
+ "component_type": "CUSTOM_PORTAL_BLOCK",
355
+ "configuration": {},
356
+ "surfaces": { "portal_block": { "app_url": "./components/<name>/dist/index.html" } },
357
+ "assets": { "zip": "./components/<name>/dist/" }
358
+ }
359
+ \`\`\`
360
+
361
+ #### CUSTOM_FLOW_ACTION_SANDBOX
362
+ JavaScript code that runs in epilot's sandboxed runtime when a flow action is triggered.
363
+
364
+ **Stack:** TypeScript (compiled to JS)
365
+ **Build output:** \`dist/handler.js\`
366
+ **Manifest configuration:**
367
+ \`\`\`json
368
+ {
369
+ "component_type": "CUSTOM_FLOW_ACTION",
370
+ "configuration": {
371
+ "type": "sandbox",
372
+ "sandbox_settings": { "code": "// read from dist/ during deploy" }
373
+ }
374
+ }
375
+ \`\`\`
376
+
377
+ **Restrictions:** Max 300KB. \`eval()\` and \`Function()\` constructor are not allowed.
378
+
379
+ ### Config-only components (no build step, just configuration.json)
380
+
381
+ #### CUSTOM_FLOW_ACTION_EXTERNAL
382
+ An external webhook called by epilot when a flow action triggers. No code to build.
383
+
384
+ **configuration.json:**
385
+ \`\`\`json
386
+ {
387
+ "type": "external_integration",
388
+ "external_integration_settings": {
389
+ "url": "https://api.example.com/webhook",
390
+ "headers": { "Content-Type": "application/json" }
391
+ }
392
+ }
393
+ \`\`\`
394
+
395
+ Set \`"wait_for_callback": true\` if epilot should wait for your endpoint to respond before continuing the flow.
396
+
397
+ #### PORTAL_EXTENSION
398
+ Hooks that customize Customer Portal behavior. No UI, just configuration.
399
+
400
+ **configuration.json:**
401
+ \`\`\`json
402
+ {
403
+ "hooks": [
404
+ {
405
+ "type": "registration_identifiers_check",
406
+ "call": {
407
+ "method": "POST",
408
+ "url": "https://api.example.com/portal/register",
409
+ "headers": { "x-api-key": "{{api_key}}" }
410
+ }
411
+ }
412
+ ]
413
+ }
414
+ \`\`\`
415
+
416
+ **Available hook types:** \`registration_identifiers_check\`, \`contract_identification\`, \`meter_reading_plausibility_check\`, \`consumption_data_retrieval\`, \`cost_data_retrieval\`, \`price_data_retrieval\`.
417
+
418
+ Use \`{{option_key}}\` syntax in URLs/headers to interpolate secret option values set per-installation.
419
+
420
+ #### EXTERNAL_PRODUCT_CATALOG
421
+ Hooks that provide products from an external catalog to epilot Journeys.
422
+
423
+ **configuration.json:**
424
+ \`\`\`json
425
+ {
426
+ "hooks": [
427
+ {
428
+ "id": "get-products",
429
+ "name": { "de": "Produkte abrufen", "en": "Get Products" },
430
+ "type": "products",
431
+ "call": {
432
+ "method": "POST",
433
+ "url": "https://api.example.com/products",
434
+ "headers": { "Content-Type": "application/json", "x-api-key": "{{api_key}}" }
435
+ }
436
+ }
437
+ ]
438
+ }
439
+ \`\`\`
440
+
441
+ **Hook types:** \`products\`, \`product-recommendations\`.
442
+
443
+ ## Workflow: Building an App from Scratch
444
+
445
+ \`\`\`bash
446
+ # 1. Scaffold the project
447
+ epilot app init my-app
448
+ cd my-app
449
+
450
+ # 2. Add components (interactive or with flags)
451
+ epilot app add-component my-block --type CUSTOM_JOURNEY_BLOCK
452
+ epilot app add-component my-tab --type CUSTOM_CAPABILITY
453
+ epilot app add-component my-webhook --type CUSTOM_FLOW_ACTION_EXTERNAL
454
+
455
+ # 3. Install dependencies
456
+ npm install
457
+
458
+ # 4. Develop components
459
+ cd components/my-block && npm run dev # local dev server
460
+ cd components/my-tab && npm run dev # local dev server
461
+
462
+ # 5. Edit config-only components
463
+ # Edit components/my-webhook/configuration.json directly
464
+
465
+ # 6. Build all components
466
+ npm run build
467
+
468
+ # 7. Validate the manifest
469
+ epilot app validate
470
+
471
+ # 8. Deploy (dry run first)
472
+ epilot app deploy --dry-run
473
+ epilot app deploy
474
+
475
+ # 9. Check versions
476
+ epilot app versions
477
+
478
+ # 10. Submit for marketplace review
479
+ epilot app review --technical-contact dev@example.com --marketing-contact marketing@example.com
480
+ \`\`\`
481
+
482
+ ## Key Concepts
483
+
484
+ ### Configuration override
485
+ For every component with a \`_dir\` field, the CLI reads \`components/<dir>/configuration.json\` at deploy time and uses it as the component's configuration, overriding whatever is in manifest.json. This means: **edit configuration in the component directory, not in manifest.json.**
486
+
487
+ ### Asset upload flow
488
+ 1. CLI reads local paths from manifest (\`./components/x/dist/bundle.js\`)
489
+ 2. Requests a presigned S3 upload URL from the App API
490
+ 3. Uploads the file to S3
491
+ 4. Gets back the CDN URL
492
+ 5. Injects the CDN URL into the component configuration/surfaces before upserting
493
+
494
+ ### Permissions
495
+ Apps can request permissions via the \`permissions\` array in the manifest. These are created as a role when the app is installed. Common actions: \`entity:read\`, \`entity:write\`, \`entity:delete\`, \`workflow:read\`, \`workflow:write\`.
496
+
497
+ ### Options
498
+ Components can declare \`options\` \u2014 configuration values set by the installing organization. Types: \`text\`, \`number\`, \`boolean\`, \`secret\`. Secret values are encrypted and never included in the manifest. Use \`{{option_key}}\` in configuration URLs/headers for interpolation.
499
+
500
+ ### Descriptions
501
+ All user-facing text (app name, component names, descriptions) must include a \`de\` (German) translation. \`en\` is optional but recommended.
502
+
503
+ ### App Bridge
504
+ Components that render inside epilot (capabilities, pages, portal blocks) use \`@epilot/app-bridge\` to communicate with the parent window. The bridge provides an auth token and language setting. Always wrap your React app in an \`AppBridgeProvider\`.
505
+
506
+ ### Volt UI
507
+ Use \`@epilot/volt-ui\` for UI components in App Bridge surfaces (capabilities, pages, portal blocks). It provides cards, buttons, forms, selectors, and more \u2014 consistent with epilot's design system.
508
+
509
+ ### Concorde Elements
510
+ Use \`@epilot/concorde-elements\` for UI components in Journey Blocks. It provides buttons, cards, inputs \u2014 consistent with epilot's journey design system.
511
+ `
512
+ );
513
+ log.success(`Created ${name}/`);
514
+ log.info("");
515
+ log.info(` cd ${name}`);
516
+ log.info(" npm install");
517
+ log.info(" epilot app add-component my-action --type CUSTOM_FLOW_ACTION");
518
+ log.info("");
519
+ log.dim("See README.md for more details.");
520
+ }
521
+ });
522
+ export {
523
+ init_default as default
524
+ };