@epilot/cli 0.1.9 → 0.1.11

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 (78) hide show
  1. package/README.md +3 -3
  2. package/definitions/app.json +56 -6
  3. package/definitions/blueprint-manifest.json +115 -1
  4. package/definitions/customer-portal.json +757 -81
  5. package/definitions/data-management.json +10 -0
  6. package/definitions/email-settings.json +121 -0
  7. package/definitions/email-template.json +25 -3
  8. package/definitions/entity.json +328 -10
  9. package/definitions/erp-integration.json +472 -13
  10. package/definitions/journey.json +274 -12
  11. package/definitions/kanban.json +654 -78
  12. package/definitions/organization.json +614 -51
  13. package/definitions/partner-directory.json +795 -229
  14. package/definitions/permissions.json +41 -6
  15. package/definitions/webhooks.json +111 -2
  16. package/definitions/workflow.json +40 -0
  17. package/dist/{access-token-PTTCRMGK.js → access-token-CIM4RLBP.js} +1 -1
  18. package/dist/add-component-IW4644NE.js +241 -0
  19. package/dist/{address-2FDPEPR6.js → address-EDRTUWTP.js} +1 -1
  20. package/dist/{address-suggestions-XBEK5DDQ.js → address-suggestions-S5WEST2N.js} +1 -1
  21. package/dist/{ai-agents-ZY5BNVTN.js → ai-agents-RXDDJDAR.js} +1 -1
  22. package/dist/{app-IT5FWGUK.js → api-36XROHLK.js} +5 -5
  23. package/dist/app-BKS7M4UQ.js +24 -0
  24. package/dist/{audit-logs-FB4TE4TI.js → audit-logs-PXGDGJGV.js} +1 -1
  25. package/dist/{automation-JE5LDKJM.js → automation-LS6MVLP2.js} +1 -1
  26. package/dist/{billing-GOFCP5T3.js → billing-KVYFUKZK.js} +1 -1
  27. package/dist/bin/epilot.js +52 -52
  28. package/dist/{blueprint-manifest-WJIQKFYK.js → blueprint-manifest-W4ZGJD2Z.js} +1 -1
  29. package/dist/{chunk-P5IZZW4Y.js → chunk-BYAEI4Z2.js} +1 -1
  30. package/dist/{chunk-PHXL66VA.js → chunk-K2UQOP3Q.js} +28 -11
  31. package/dist/chunk-POCU2J27.js +365 -0
  32. package/dist/{completion-EKFXGPNK.js → completion-HTO64G2S.js} +1 -1
  33. package/dist/{consent-DSMWWHUL.js → consent-M4QB2HPM.js} +1 -1
  34. package/dist/{customer-portal-IJYTJYUZ.js → customer-portal-SVO2YCXA.js} +1 -1
  35. package/dist/{dashboard-DOAX6XDG.js → dashboard-CYCXIX74.js} +1 -1
  36. package/dist/{data-management-C4JPPUPD.js → data-management-KXAPA7ZU.js} +1 -1
  37. package/dist/{deduplication-7OGLZLAC.js → deduplication-M3KEVJRG.js} +1 -1
  38. package/dist/deploy-UQZAUHAB.js +214 -0
  39. package/dist/{design-3CAYTWFY.js → design-UVJJ2KO2.js} +1 -1
  40. package/dist/{document-NT5JOJQV.js → document-5HB632XE.js} +1 -1
  41. package/dist/{email-settings-2M3WJTQS.js → email-settings-H7HQTDYE.js} +1 -1
  42. package/dist/{email-template-F4PLBPPC.js → email-template-2DHZ3VKF.js} +1 -1
  43. package/dist/{entity-32LKMZAU.js → entity-HED6QHG7.js} +1 -1
  44. package/dist/{entity-mapping-OBCZDYQJ.js → entity-mapping-QP22B65Z.js} +1 -1
  45. package/dist/{environments-H3TBCDQE.js → environments-6LLEIGWV.js} +1 -1
  46. package/dist/{erp-integration-UW6H55EK.js → erp-integration-DXFYJ2F3.js} +1 -1
  47. package/dist/{event-catalog-NVAPTZ4M.js → event-catalog-2ZCZTATY.js} +1 -1
  48. package/dist/export-US5GMHTS.js +44 -0
  49. package/dist/{file-US2HR4SV.js → file-R6IIXOIZ.js} +1 -1
  50. package/dist/{iban-7QUCOULB.js → iban-EQD2VROZ.js} +1 -1
  51. package/dist/init-DGPWBRRB.js +524 -0
  52. package/dist/{journey-E5T4BZZX.js → journey-V7X2KUKH.js} +1 -1
  53. package/dist/{kanban-7UHU5VE6.js → kanban-EPI6C3FR.js} +1 -1
  54. package/dist/{message-7KY33RJE.js → message-477EJ5JO.js} +1 -1
  55. package/dist/{metering-P7BZGMY7.js → metering-5EAEKRSL.js} +1 -1
  56. package/dist/{notes-TNJ7FPA3.js → notes-CVXNRULU.js} +1 -1
  57. package/dist/{notification-6KXEFVO5.js → notification-6HXS76XP.js} +1 -1
  58. package/dist/{organization-FF4Y3PBO.js → organization-O33CZQKD.js} +1 -1
  59. package/dist/{partner-directory-VH2SBAS2.js → partner-directory-NZWGCKSB.js} +2 -2
  60. package/dist/{permissions-KENZ4HNY.js → permissions-6QEOBJ6M.js} +1 -1
  61. package/dist/{pricing-P6QZ77VJ.js → pricing-KNYSULCW.js} +1 -1
  62. package/dist/{pricing-tier-2IRJMTM6.js → pricing-tier-OCHP6SHT.js} +1 -1
  63. package/dist/{purpose-IHROR6LQ.js → purpose-NGM42XWB.js} +1 -1
  64. package/dist/remove-component-B2GMICMD.js +89 -0
  65. package/dist/review-QFPON37R.js +69 -0
  66. package/dist/{sandbox-62XQPOU6.js → sandbox-YX3VVAQG.js} +1 -1
  67. package/dist/{submission-PUWGOYQB.js → submission-YOWVSZNA.js} +1 -1
  68. package/dist/{targeting-QB3DFYNI.js → targeting-BMZCOG72.js} +1 -1
  69. package/dist/{template-variables-IPKRUJ4E.js → template-variables-YTABZL3E.js} +1 -1
  70. package/dist/{upgrade-KDDTJRUC.js → upgrade-KZSOPDCR.js} +1 -1
  71. package/dist/{user-2CP75TFC.js → user-3N5ZOUYS.js} +1 -1
  72. package/dist/validate-G7K6AVBI.js +53 -0
  73. package/dist/{validation-rules-GNI4EEG5.js → validation-rules-QVS7LKEP.js} +1 -1
  74. package/dist/versions-UTPAWTIU.js +109 -0
  75. package/dist/{webhooks-2OWUX7UL.js → webhooks-6WMWACOW.js} +1 -1
  76. package/dist/{workflow-WSLERVJI.js → workflow-ZO2MKDBS.js} +1 -1
  77. package/dist/{workflow-definition-FP3WKHGG.js → workflow-definition-RCWKIPYI.js} +1 -1
  78. package/package.json +2 -1
@@ -2,7 +2,7 @@
2
2
  "openapi": "3.0.3",
3
3
  "info": {
4
4
  "title": "Permissions API",
5
- "version": "1.2.0",
5
+ "version": "1.2.1",
6
6
  "description": "Flexible Role-based Access Control for epilot"
7
7
  },
8
8
  "tags": [
@@ -927,11 +927,34 @@
927
927
  "anyOf": [
928
928
  {
929
929
  "$ref": "#/components/schemas/EqualsCondition"
930
+ },
931
+ {
932
+ "$ref": "#/components/schemas/EqualsCurrentUserCondition"
930
933
  }
931
934
  ]
932
935
  }
933
936
  ]
934
937
  },
938
+ "EqualsCurrentUserCondition": {
939
+ "description": "Check if any relation_user attribute on the entity contains the current user. When attribute is provided, only that specific attribute path is checked.",
940
+ "type": "object",
941
+ "properties": {
942
+ "attribute": {
943
+ "type": "string",
944
+ "description": "Optional JSON path to a specific user attribute. When omitted, all relation_user attributes on the entity are scanned.",
945
+ "example": "assignee.*.user_id"
946
+ },
947
+ "operation": {
948
+ "type": "string",
949
+ "enum": [
950
+ "equals_current_user"
951
+ ]
952
+ }
953
+ },
954
+ "required": [
955
+ "operation"
956
+ ]
957
+ },
935
958
  "EqualsCondition": {
936
959
  "description": "Check if attribute equals to any of the values",
937
960
  "type": "object",
@@ -1076,6 +1099,10 @@
1076
1099
  "description": "Optional parent role that this role inherits from. Must be an `org_role` or `share_role`."
1077
1100
  }
1078
1101
  ]
1102
+ },
1103
+ "vendor_created": {
1104
+ "type": "boolean",
1105
+ "description": "Indicates whether this role was created by a vendor organization on behalf of the partner organization."
1079
1106
  }
1080
1107
  }
1081
1108
  }
@@ -1147,6 +1174,10 @@
1147
1174
  "type": "integer",
1148
1175
  "readOnly": true,
1149
1176
  "description": "Maximum number of users that can be assigned this role (vendor-enforced limit, can only be set via internal auth)"
1177
+ },
1178
+ "vendor_created": {
1179
+ "type": "boolean",
1180
+ "description": "Indicates whether this role was created by a vendor organization on behalf of the partner organization."
1150
1181
  }
1151
1182
  }
1152
1183
  }
@@ -1394,6 +1425,10 @@
1394
1425
  "description": "Optional parent role that this role inherits from. Must be an `org_role` or a sharing role of type `share_role` or `partner_role`."
1395
1426
  }
1396
1427
  ]
1428
+ },
1429
+ "vendor_created": {
1430
+ "type": "boolean",
1431
+ "description": "Indicates whether this role was created by a vendor organization on behalf of the partner organization."
1397
1432
  }
1398
1433
  }
1399
1434
  },
@@ -1439,6 +1474,10 @@
1439
1474
  "$ref": "#/components/schemas/OrganizationId"
1440
1475
  }
1441
1476
  ]
1477
+ },
1478
+ "vendor_created": {
1479
+ "type": "boolean",
1480
+ "description": "Indicates whether this role was created by a vendor organization on behalf of the partner organization."
1442
1481
  }
1443
1482
  }
1444
1483
  },
@@ -1472,9 +1511,5 @@
1472
1511
  }
1473
1512
  }
1474
1513
  },
1475
- "servers": [
1476
- {
1477
- "url": "https://permissions.sls.epilot.io"
1478
- }
1479
- ]
1514
+ "servers": []
1480
1515
  }
@@ -928,7 +928,8 @@
928
928
  "description": "Filter by event outcome",
929
929
  "enum": [
930
930
  "succeeded",
931
- "failed"
931
+ "failed",
932
+ "skipped"
932
933
  ],
933
934
  "example": "succeeded"
934
935
  }
@@ -1006,6 +1007,89 @@
1006
1007
  "supportedValues"
1007
1008
  ]
1008
1009
  },
1010
+ "WebhookCondition": {
1011
+ "type": "object",
1012
+ "description": "A condition that must be met for the webhook to fire.",
1013
+ "properties": {
1014
+ "field": {
1015
+ "type": "string",
1016
+ "description": "Dot-notation path to the field in the event payload (e.g. \"entity.status\", \"entity.line_items\")"
1017
+ },
1018
+ "operation": {
1019
+ "type": "string",
1020
+ "enum": [
1021
+ "equals",
1022
+ "not_equals",
1023
+ "any_of",
1024
+ "none_of",
1025
+ "contains",
1026
+ "not_contains",
1027
+ "starts_with",
1028
+ "ends_with",
1029
+ "greater_than",
1030
+ "less_than",
1031
+ "greater_than_or_equals",
1032
+ "less_than_or_equals",
1033
+ "is_empty",
1034
+ "is_not_empty"
1035
+ ]
1036
+ },
1037
+ "values": {
1038
+ "type": "array",
1039
+ "description": "Values to compare against (not required for is_empty/is_not_empty)",
1040
+ "items": {
1041
+ "type": "string"
1042
+ }
1043
+ },
1044
+ "field_type": {
1045
+ "type": "string",
1046
+ "description": "Type hint for the field (affects comparison logic)",
1047
+ "enum": [
1048
+ "string",
1049
+ "number",
1050
+ "boolean",
1051
+ "date",
1052
+ "datetime"
1053
+ ],
1054
+ "default": "string"
1055
+ },
1056
+ "is_array_field": {
1057
+ "type": "boolean",
1058
+ "description": "Whether the target field is an array (repeatable)",
1059
+ "default": false
1060
+ },
1061
+ "repeatable_item_op": {
1062
+ "type": "boolean",
1063
+ "description": "When true, evaluates conditions per-item in repeatable array fields",
1064
+ "default": false
1065
+ }
1066
+ },
1067
+ "required": [
1068
+ "field",
1069
+ "operation"
1070
+ ]
1071
+ },
1072
+ "WebhookConditionGroup": {
1073
+ "type": "object",
1074
+ "description": "A group of conditions with a logical operator. Multiple conditions are AND-ed by default.",
1075
+ "properties": {
1076
+ "conditions": {
1077
+ "type": "array",
1078
+ "items": {
1079
+ "$ref": "#/components/schemas/WebhookCondition"
1080
+ },
1081
+ "maxItems": 10
1082
+ },
1083
+ "logical_operator": {
1084
+ "type": "string",
1085
+ "enum": [
1086
+ "AND",
1087
+ "OR"
1088
+ ],
1089
+ "default": "AND"
1090
+ }
1091
+ }
1092
+ },
1009
1093
  "Auth": {
1010
1094
  "type": "object",
1011
1095
  "properties": {
@@ -1137,6 +1221,27 @@
1137
1221
  "enableStaticIP": {
1138
1222
  "type": "boolean"
1139
1223
  },
1224
+ "protected": {
1225
+ "type": "boolean",
1226
+ "description": "When true, indicates this webhook configuration is protected and should not be modified without explicit intent."
1227
+ },
1228
+ "secureProxy": {
1229
+ "type": "object",
1230
+ "description": "Routes webhook requests through a secure VPC proxy (ERP integration service). When set, takes precedence over enableStaticIP.",
1231
+ "properties": {
1232
+ "integration_id": {
1233
+ "type": "string",
1234
+ "format": "uuid"
1235
+ },
1236
+ "use_case_slug": {
1237
+ "type": "string"
1238
+ }
1239
+ },
1240
+ "required": [
1241
+ "integration_id",
1242
+ "use_case_slug"
1243
+ ]
1244
+ },
1140
1245
  "status": {
1141
1246
  "type": "string",
1142
1247
  "enum": [
@@ -1149,6 +1254,9 @@
1149
1254
  "type": "string",
1150
1255
  "description": "JSONata expression to transform the payload"
1151
1256
  },
1257
+ "filterConditions": {
1258
+ "$ref": "#/components/schemas/WebhookConditionGroup"
1259
+ },
1152
1260
  "_manifest": {
1153
1261
  "type": "array",
1154
1262
  "description": "Manifest ID used to create/update the webhook resource",
@@ -1427,7 +1535,8 @@
1427
1535
  "enum": [
1428
1536
  "succeeded",
1429
1537
  "failed",
1430
- "in_progress"
1538
+ "in_progress",
1539
+ "skipped"
1431
1540
  ]
1432
1541
  },
1433
1542
  "http_method": {
@@ -2030,6 +2030,10 @@
2030
2030
  "description": "The user which moved the step/task to the IN_PROGRESS state. The user should also be present in the assignedTo property of the step/task",
2031
2031
  "type": "string"
2032
2032
  },
2033
+ "assignedToOnHold": {
2034
+ "description": "The user which moved the step/task to the ON_HOLD state. The user should also be present in the assignedTo property of the step/task",
2035
+ "type": "string"
2036
+ },
2033
2037
  "status": {
2034
2038
  "$ref": "#/components/schemas/StepStatus"
2035
2039
  },
@@ -2306,6 +2310,10 @@
2306
2310
  "description": "The user which moved the step/task to the IN_PROGRESS state. The user should also be present in the assignedTo property of the step/task",
2307
2311
  "type": "string"
2308
2312
  },
2313
+ "assignedToOnHold": {
2314
+ "description": "The user which moved the step/task to the ON_HOLD state. The user should also be present in the assignedTo property of the step/task",
2315
+ "type": "string"
2316
+ },
2309
2317
  "status": {
2310
2318
  "$ref": "#/components/schemas/StepStatus"
2311
2319
  },
@@ -2860,6 +2868,7 @@
2860
2868
  },
2861
2869
  "contexts": {
2862
2870
  "type": "array",
2871
+ "minItems": 1,
2863
2872
  "items": {
2864
2873
  "$ref": "#/components/schemas/FlowContext"
2865
2874
  }
@@ -3694,6 +3703,10 @@
3694
3703
  "skipped_by": {
3695
3704
  "$ref": "#/components/schemas/UserId",
3696
3705
  "description": "The user which moved the task/phase to SKIPPED state."
3706
+ },
3707
+ "on_hold_by": {
3708
+ "$ref": "#/components/schemas/UserId",
3709
+ "description": "The user which moved the task/phase to ON_HOLD state."
3697
3710
  }
3698
3711
  }
3699
3712
  },
@@ -3761,6 +3774,14 @@
3761
3774
  "items": {
3762
3775
  "type": "string"
3763
3776
  }
3777
+ },
3778
+ "value_type": {
3779
+ "type": "string",
3780
+ "enum": [
3781
+ "static",
3782
+ "relative_date"
3783
+ ],
3784
+ "description": "How to interpret values. \"static\" (default) means literal values. \"relative_date\" means values[0] is a dynamic date token like \"today\"."
3764
3785
  }
3765
3786
  },
3766
3787
  "required": [
@@ -3838,6 +3859,25 @@
3838
3859
  "attribute_sub_field": {
3839
3860
  "type": "string",
3840
3861
  "description": "For complex attribute types, specifies which sub-field to extract (e.g., 'address', 'name', 'email_type')"
3862
+ },
3863
+ "date_offset": {
3864
+ "type": "object",
3865
+ "description": "Offset to apply to the source date value before comparison (e.g., +18 years for age check, +30 days for expiry)",
3866
+ "properties": {
3867
+ "amount": {
3868
+ "type": "integer",
3869
+ "description": "Number of units to offset"
3870
+ },
3871
+ "unit": {
3872
+ "type": "string",
3873
+ "enum": [
3874
+ "days",
3875
+ "months",
3876
+ "years"
3877
+ ],
3878
+ "description": "Unit of the offset"
3879
+ }
3880
+ }
3841
3881
  }
3842
3882
  }
3843
3883
  },
@@ -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,241 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ log,
4
+ readManifest,
5
+ writeManifest
6
+ } from "./chunk-POCU2J27.js";
7
+ import "./chunk-RSA7K5HB.js";
8
+ import "./chunk-PDMWUCWD.js";
9
+ import "./chunk-7ZQ666ZQ.js";
10
+
11
+ // src/commands/app/add-component.ts
12
+ import { defineCommand } from "citty";
13
+ import { randomUUID } from "crypto";
14
+ import { existsSync, readFileSync, writeFileSync, readdirSync } from "fs";
15
+ import { resolve, join } from "path";
16
+ var TEMPLATES_REPO = "epilot-dev/app-templates";
17
+ var TEMPLATE_REGISTRY = {
18
+ CUSTOM_FLOW_ACTION_SANDBOX: {
19
+ configOnly: false,
20
+ manifestType: "CUSTOM_FLOW_ACTION",
21
+ templateDir: "custom-flow-action-sandbox",
22
+ description: "Sandboxed flow action (JS runs in epilot)",
23
+ configuration: () => ({
24
+ type: "sandbox",
25
+ sandbox_settings: { code: "// code is read from dist/ during deploy" }
26
+ })
27
+ },
28
+ CUSTOM_FLOW_ACTION_EXTERNAL: {
29
+ configOnly: true,
30
+ manifestType: "CUSTOM_FLOW_ACTION",
31
+ templateDir: "custom-flow-action-external",
32
+ description: "External integration webhook (config-only)",
33
+ configuration: () => ({
34
+ type: "external_integration",
35
+ external_integration_settings: { url: "https://api.example.com/webhook" }
36
+ }),
37
+ options: [
38
+ { key: "api_key", label: "API Key", type: "secret", required: true, description: "API key for authentication" }
39
+ ]
40
+ },
41
+ CUSTOM_CAPABILITY: {
42
+ configOnly: false,
43
+ manifestType: "CUSTOM_CAPABILITY",
44
+ templateDir: "custom-capability",
45
+ description: "Custom entity tab or group",
46
+ configuration: () => ({ type: "tab", allowed_schemas: [] }),
47
+ surfaces: (id) => ({ capability_config: { app_url: `./components/${id}/dist/index.html` } }),
48
+ assets: (id) => ({ zip: `./components/${id}/dist/` })
49
+ },
50
+ CUSTOM_JOURNEY_BLOCK: {
51
+ configOnly: false,
52
+ manifestType: "CUSTOM_JOURNEY_BLOCK",
53
+ templateDir: "custom-journey-block",
54
+ description: "Custom journey builder block",
55
+ configuration: (id) => ({
56
+ component_url: `./components/${id}/dist/bundle.js`,
57
+ component_tag: id,
58
+ component_args: []
59
+ }),
60
+ assets: (id) => ({ bundle: `./components/${id}/dist/bundle.js` })
61
+ },
62
+ CUSTOM_PAGE: {
63
+ configOnly: false,
64
+ manifestType: "CUSTOM_PAGE",
65
+ templateDir: "custom-page",
66
+ description: "Custom navigation page",
67
+ configuration: (id) => ({ slug: id, nav_label: toPascalCase(id), nav_icon: "layout" }),
68
+ surfaces: (id) => ({ page: { app_url: `./components/${id}/dist/index.html` } }),
69
+ assets: (id) => ({ zip: `./components/${id}/dist/` })
70
+ },
71
+ CUSTOM_PORTAL_BLOCK: {
72
+ configOnly: false,
73
+ manifestType: "CUSTOM_PORTAL_BLOCK",
74
+ templateDir: "custom-portal-block",
75
+ description: "Custom portal widget",
76
+ configuration: () => ({}),
77
+ surfaces: (id) => ({ portal_block: { app_url: `./components/${id}/dist/index.html` } }),
78
+ assets: (id) => ({ zip: `./components/${id}/dist/` })
79
+ },
80
+ PORTAL_EXTENSION: {
81
+ configOnly: true,
82
+ manifestType: "PORTAL_EXTENSION",
83
+ templateDir: "portal-extension",
84
+ description: "Portal extension hooks (config-only)",
85
+ configuration: () => ({
86
+ hooks: [
87
+ {
88
+ type: "registration_identifiers_check",
89
+ call: {
90
+ method: "POST",
91
+ url: "https://api.example.com/portal/register",
92
+ headers: { "x-api-key": "{{api_key}}" }
93
+ }
94
+ }
95
+ ]
96
+ }),
97
+ options: [
98
+ { key: "api_key", label: "API Key", type: "secret", required: true, description: "API key for your backend" }
99
+ ]
100
+ },
101
+ EXTERNAL_PRODUCT_CATALOG: {
102
+ configOnly: true,
103
+ manifestType: "EXTERNAL_PRODUCT_CATALOG",
104
+ templateDir: "external-product-catalog",
105
+ description: "External product catalog hooks (config-only)",
106
+ configuration: () => ({
107
+ hooks: [
108
+ {
109
+ id: "get-products",
110
+ name: { de: "Produkte abrufen", en: "Get Products" },
111
+ type: "products",
112
+ call: {
113
+ method: "POST",
114
+ url: "https://api.example.com/products",
115
+ headers: { "Content-Type": "application/json", "x-api-key": "{{api_key}}" }
116
+ }
117
+ }
118
+ ]
119
+ }),
120
+ options: [
121
+ { key: "api_key", label: "API Key", type: "secret", required: true, description: "API key for product catalog" }
122
+ ]
123
+ }
124
+ };
125
+ var AVAILABLE_TYPES = Object.keys(TEMPLATE_REGISTRY);
126
+ function toPascalCase(str) {
127
+ return str.replace(/(^|[-_])([a-z])/g, (_, __, c) => c.toUpperCase());
128
+ }
129
+ async function downloadTemplate(templateDir, targetDir, componentName) {
130
+ const { downloadTemplate: giget } = await import("giget");
131
+ await giget(`github:${TEMPLATES_REPO}/${templateDir}`, {
132
+ dir: targetDir,
133
+ force: true
134
+ });
135
+ replaceInDir(targetDir, "{{name}}", componentName);
136
+ }
137
+ function replaceInDir(dir, search, replace) {
138
+ const entries = readdirSync(dir, { withFileTypes: true });
139
+ for (const entry of entries) {
140
+ const fullPath = join(dir, entry.name);
141
+ if (entry.isDirectory()) {
142
+ if (entry.name === "node_modules" || entry.name === ".git") continue;
143
+ replaceInDir(fullPath, search, replace);
144
+ } else {
145
+ try {
146
+ const content = readFileSync(fullPath, "utf-8");
147
+ if (content.includes(search)) {
148
+ writeFileSync(fullPath, content.replaceAll(search, replace));
149
+ }
150
+ } catch {
151
+ }
152
+ }
153
+ }
154
+ }
155
+ var add_component_default = defineCommand({
156
+ meta: { name: "add-component", description: "Add a new component to the app" },
157
+ args: {
158
+ name: { type: "positional", description: "Component name", required: false },
159
+ type: { type: "string", alias: "t", description: "Component type" },
160
+ path: { type: "string", description: "Path to manifest.json (default: manifest.json)" }
161
+ },
162
+ run: async ({ args }) => {
163
+ let componentType = args.type;
164
+ if (!componentType) {
165
+ const { select } = await import("@inquirer/prompts");
166
+ componentType = await select({
167
+ message: "Select component type",
168
+ choices: AVAILABLE_TYPES.map((type) => ({
169
+ value: type,
170
+ name: `${type} \u2014 ${TEMPLATE_REGISTRY[type].description}`
171
+ }))
172
+ });
173
+ }
174
+ if (!AVAILABLE_TYPES.includes(componentType)) {
175
+ log.error(`Invalid component type: ${componentType}`);
176
+ log.info("");
177
+ log.info("Available types:");
178
+ for (const type of AVAILABLE_TYPES) {
179
+ log.info(` ${type} \u2014 ${TEMPLATE_REGISTRY[type].description}`);
180
+ }
181
+ process.exit(1);
182
+ }
183
+ let componentName = args.name;
184
+ if (!componentName) {
185
+ const { input } = await import("@inquirer/prompts");
186
+ componentName = await input({
187
+ message: "Component name",
188
+ validate: (v) => {
189
+ if (!v.trim()) return "Name is required";
190
+ if (!/^[a-z0-9][a-z0-9-]*$/.test(v)) return "Use lowercase letters, numbers, and hyphens";
191
+ return true;
192
+ }
193
+ });
194
+ }
195
+ const manifestPath = resolve(args.path ?? "manifest.json");
196
+ if (!existsSync(manifestPath)) {
197
+ log.error('manifest.json not found. Run "epilot app init" first.');
198
+ process.exit(1);
199
+ }
200
+ const manifest = readManifest(manifestPath);
201
+ if (manifest.components.some((c) => c._dir === componentName)) {
202
+ log.error(`Component "${componentName}" already exists in manifest.`);
203
+ process.exit(1);
204
+ }
205
+ const componentDir = resolve("components", componentName);
206
+ if (existsSync(componentDir)) {
207
+ log.error(`Directory "components/${componentName}" already exists.`);
208
+ process.exit(1);
209
+ }
210
+ const tmpl = TEMPLATE_REGISTRY[componentType];
211
+ log.dim(`Downloading template from ${TEMPLATES_REPO}/${tmpl.templateDir}...`);
212
+ await downloadTemplate(tmpl.templateDir, componentDir, componentName);
213
+ const componentId = randomUUID();
214
+ const component = {
215
+ id: componentId,
216
+ component_type: tmpl.manifestType,
217
+ _dir: componentName,
218
+ name: { de: toPascalCase(componentName), en: toPascalCase(componentName) },
219
+ description: { de: "Description", en: "Description" },
220
+ configuration: tmpl.configuration(componentName)
221
+ };
222
+ if (tmpl.surfaces) component.surfaces = tmpl.surfaces(componentName);
223
+ if (tmpl.assets) component.assets = tmpl.assets(componentName);
224
+ if (tmpl.options) component.options = tmpl.options;
225
+ manifest.components.push(component);
226
+ writeManifest(manifestPath, manifest);
227
+ log.success(`Added component "${componentName}" (${componentType})`);
228
+ log.info("");
229
+ log.info(` components/${componentName}/`);
230
+ if (tmpl.configOnly) {
231
+ log.dim("This is a config-only component. Edit configuration.json to configure it.");
232
+ } else {
233
+ log.dim('Run "npm install" to link the new workspace.');
234
+ }
235
+ log.info("");
236
+ log.info(`manifest.json updated (${manifest.components.length} component(s))`);
237
+ }
238
+ });
239
+ export {
240
+ add_component_default as default
241
+ };
@@ -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,16 +1,16 @@
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";
8
8
  import "./chunk-7ZQ666ZQ.js";
9
9
 
10
- // src/commands/apis/app.ts
10
+ // src/commands/app/api.ts
11
11
  import { defineCommand } from "citty";
12
- var app_default = defineCommand({
13
- meta: { name: "app", description: "App API" },
12
+ var api_default = defineCommand({
13
+ meta: { name: "api", description: "Call raw App API operations (OpenAPI)" },
14
14
  args: {
15
15
  operation: { type: "positional", description: "operationId to call", required: false },
16
16
  param: { type: "string", alias: "p", description: "Parameter key=value" },
@@ -50,5 +50,5 @@ var app_default = defineCommand({
50
50
  }
51
51
  });
52
52
  export {
53
- app_default as default
53
+ api_default as default
54
54
  };
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/commands/app/index.ts
4
+ import { defineCommand } from "citty";
5
+ var app_default = defineCommand({
6
+ meta: {
7
+ name: "app",
8
+ description: "Manage epilot Apps \u2014 create, deploy, and manage app manifests"
9
+ },
10
+ subCommands: {
11
+ init: () => import("./init-DGPWBRRB.js").then((m) => m.default),
12
+ "add-component": () => import("./add-component-IW4644NE.js").then((m) => m.default),
13
+ "remove-component": () => import("./remove-component-B2GMICMD.js").then((m) => m.default),
14
+ validate: () => import("./validate-G7K6AVBI.js").then((m) => m.default),
15
+ deploy: () => import("./deploy-UQZAUHAB.js").then((m) => m.default),
16
+ export: () => import("./export-US5GMHTS.js").then((m) => m.default),
17
+ versions: () => import("./versions-UTPAWTIU.js").then((m) => m.default),
18
+ review: () => import("./review-QFPON37R.js").then((m) => m.default),
19
+ api: () => import("./api-36XROHLK.js").then((m) => m.default)
20
+ }
21
+ });
22
+ export {
23
+ app_default as default
24
+ };
@@ -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";