@camunda8/cli 2.6.1 → 2.7.0-alpha.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.
Files changed (135) hide show
  1. package/dist/command-dispatch.d.ts +16 -0
  2. package/dist/command-dispatch.d.ts.map +1 -0
  3. package/dist/command-dispatch.js +129 -0
  4. package/dist/command-dispatch.js.map +1 -0
  5. package/dist/command-framework.d.ts +248 -0
  6. package/dist/command-framework.d.ts.map +1 -0
  7. package/dist/command-framework.js +229 -0
  8. package/dist/command-framework.js.map +1 -0
  9. package/dist/command-registry.d.ts +2081 -0
  10. package/dist/command-registry.d.ts.map +1 -0
  11. package/dist/command-registry.js +1460 -0
  12. package/dist/command-registry.js.map +1 -0
  13. package/dist/command-validation.d.ts +30 -4
  14. package/dist/command-validation.d.ts.map +1 -1
  15. package/dist/command-validation.js +90 -4
  16. package/dist/command-validation.js.map +1 -1
  17. package/dist/commands/completion.d.ts +1 -1
  18. package/dist/commands/completion.d.ts.map +1 -1
  19. package/dist/commands/completion.js +331 -1221
  20. package/dist/commands/completion.js.map +1 -1
  21. package/dist/commands/deployments.d.ts +2 -0
  22. package/dist/commands/deployments.d.ts.map +1 -1
  23. package/dist/commands/deployments.js +13 -2
  24. package/dist/commands/deployments.js.map +1 -1
  25. package/dist/commands/forms.d.ts +2 -20
  26. package/dist/commands/forms.d.ts.map +1 -1
  27. package/dist/commands/forms.js +76 -79
  28. package/dist/commands/forms.js.map +1 -1
  29. package/dist/commands/help.d.ts +3 -87
  30. package/dist/commands/help.d.ts.map +1 -1
  31. package/dist/commands/help.js +565 -1939
  32. package/dist/commands/help.js.map +1 -1
  33. package/dist/commands/identity-authorizations.d.ts +5 -24
  34. package/dist/commands/identity-authorizations.d.ts.map +1 -1
  35. package/dist/commands/identity-authorizations.js +113 -137
  36. package/dist/commands/identity-authorizations.js.map +1 -1
  37. package/dist/commands/identity-groups.d.ts +5 -26
  38. package/dist/commands/identity-groups.d.ts.map +1 -1
  39. package/dist/commands/identity-groups.js +91 -124
  40. package/dist/commands/identity-groups.js.map +1 -1
  41. package/dist/commands/identity-mapping-rules.d.ts +5 -30
  42. package/dist/commands/identity-mapping-rules.d.ts.map +1 -1
  43. package/dist/commands/identity-mapping-rules.js +106 -136
  44. package/dist/commands/identity-mapping-rules.js.map +1 -1
  45. package/dist/commands/identity-roles.d.ts +5 -26
  46. package/dist/commands/identity-roles.d.ts.map +1 -1
  47. package/dist/commands/identity-roles.js +91 -124
  48. package/dist/commands/identity-roles.js.map +1 -1
  49. package/dist/commands/identity-tenants.d.ts +5 -26
  50. package/dist/commands/identity-tenants.d.ts.map +1 -1
  51. package/dist/commands/identity-tenants.js +92 -126
  52. package/dist/commands/identity-tenants.js.map +1 -1
  53. package/dist/commands/identity-users.d.ts +5 -29
  54. package/dist/commands/identity-users.d.ts.map +1 -1
  55. package/dist/commands/identity-users.js +95 -129
  56. package/dist/commands/identity-users.js.map +1 -1
  57. package/dist/commands/identity.d.ts +6 -6
  58. package/dist/commands/identity.d.ts.map +1 -1
  59. package/dist/commands/identity.js +6 -7
  60. package/dist/commands/identity.js.map +1 -1
  61. package/dist/commands/incidents.d.ts +3 -16
  62. package/dist/commands/incidents.d.ts.map +1 -1
  63. package/dist/commands/incidents.js +71 -98
  64. package/dist/commands/incidents.js.map +1 -1
  65. package/dist/commands/jobs.d.ts +4 -26
  66. package/dist/commands/jobs.d.ts.map +1 -1
  67. package/dist/commands/jobs.js +143 -159
  68. package/dist/commands/jobs.js.map +1 -1
  69. package/dist/commands/mcp-proxy.d.ts +1 -0
  70. package/dist/commands/mcp-proxy.d.ts.map +1 -1
  71. package/dist/commands/mcp-proxy.js +10 -2
  72. package/dist/commands/mcp-proxy.js.map +1 -1
  73. package/dist/commands/messages.d.ts +2 -12
  74. package/dist/commands/messages.d.ts.map +1 -1
  75. package/dist/commands/messages.js +87 -81
  76. package/dist/commands/messages.js.map +1 -1
  77. package/dist/commands/open.d.ts +4 -0
  78. package/dist/commands/open.d.ts.map +1 -1
  79. package/dist/commands/open.js +18 -0
  80. package/dist/commands/open.js.map +1 -1
  81. package/dist/commands/plugins.d.ts +7 -9
  82. package/dist/commands/plugins.d.ts.map +1 -1
  83. package/dist/commands/plugins.js +32 -25
  84. package/dist/commands/plugins.js.map +1 -1
  85. package/dist/commands/process-definitions.d.ts +2 -14
  86. package/dist/commands/process-definitions.d.ts.map +1 -1
  87. package/dist/commands/process-definitions.js +57 -80
  88. package/dist/commands/process-definitions.js.map +1 -1
  89. package/dist/commands/process-instances.d.ts +8 -37
  90. package/dist/commands/process-instances.d.ts.map +1 -1
  91. package/dist/commands/process-instances.js +242 -193
  92. package/dist/commands/process-instances.js.map +1 -1
  93. package/dist/commands/profiles.d.ts +4 -0
  94. package/dist/commands/profiles.d.ts.map +1 -1
  95. package/dist/commands/profiles.js +29 -0
  96. package/dist/commands/profiles.js.map +1 -1
  97. package/dist/commands/run.d.ts +2 -0
  98. package/dist/commands/run.d.ts.map +1 -1
  99. package/dist/commands/run.js +10 -0
  100. package/dist/commands/run.js.map +1 -1
  101. package/dist/commands/search.d.ts +7 -100
  102. package/dist/commands/search.d.ts.map +1 -1
  103. package/dist/commands/search.js +530 -694
  104. package/dist/commands/search.js.map +1 -1
  105. package/dist/commands/session.d.ts +3 -0
  106. package/dist/commands/session.d.ts.map +1 -1
  107. package/dist/commands/session.js +30 -0
  108. package/dist/commands/session.js.map +1 -1
  109. package/dist/commands/topology.d.ts +1 -3
  110. package/dist/commands/topology.d.ts.map +1 -1
  111. package/dist/commands/topology.js +11 -18
  112. package/dist/commands/topology.js.map +1 -1
  113. package/dist/commands/user-tasks.d.ts +2 -16
  114. package/dist/commands/user-tasks.d.ts.map +1 -1
  115. package/dist/commands/user-tasks.js +73 -101
  116. package/dist/commands/user-tasks.js.map +1 -1
  117. package/dist/commands/watch.d.ts +1 -0
  118. package/dist/commands/watch.d.ts.map +1 -1
  119. package/dist/commands/watch.js +15 -0
  120. package/dist/commands/watch.js.map +1 -1
  121. package/dist/default-plugins/cluster/c8ctl-plugin.js +11 -0
  122. package/dist/index.d.ts +0 -4
  123. package/dist/index.d.ts.map +1 -1
  124. package/dist/index.js +77 -1020
  125. package/dist/index.js.map +1 -1
  126. package/dist/logger.d.ts +5 -0
  127. package/dist/logger.d.ts.map +1 -1
  128. package/dist/logger.js +7 -1
  129. package/dist/logger.js.map +1 -1
  130. package/dist/plugin-loader.d.ts +5 -0
  131. package/dist/plugin-loader.d.ts.map +1 -1
  132. package/dist/plugin-loader.js +1 -0
  133. package/dist/plugin-loader.js.map +1 -1
  134. package/package.json +1 -1
  135. /package/dist/templates/{tsconfig.json → tsconfig.json.template} +0 -0
@@ -4,543 +4,131 @@
4
4
  import { readFileSync } from "node:fs";
5
5
  import { dirname, join } from "node:path";
6
6
  import { fileURLToPath } from "node:url";
7
+ import { COMMAND_REGISTRY, GLOBAL_FLAGS, RESOURCE_ALIASES, SEARCH_FLAGS, } from "../command-registry.js";
7
8
  import { getLogger } from "../logger.js";
8
9
  import { getPluginCommandsInfo, } from "../plugin-loader.js";
9
10
  const __filename = fileURLToPath(import.meta.url);
10
11
  const __dirname = dirname(__filename);
12
+ /** Typed entries for COMMAND_REGISTRY — avoids `as CommandDef` on every loop. */
13
+ function registryEntries() {
14
+ return Object.entries(COMMAND_REGISTRY);
15
+ }
16
+ /** Typed entries for a flag record — avoids `as FlagDef` on every loop. */
17
+ function flagEntries(flags) {
18
+ return Object.entries(flags);
19
+ }
20
+ /** Look up a verb in COMMAND_REGISTRY, returning undefined for unknown verbs. */
21
+ function lookupVerb(verb) {
22
+ // biome-ignore lint/plugin: single isolation point — COMMAND_REGISTRY uses `satisfies` so Object index needs widening
23
+ return COMMAND_REGISTRY[verb];
24
+ }
25
+ /**
26
+ * Derive the display name for a resource, showing long name with alias.
27
+ * e.g. "pi" → "process-instance (pi)", "jobs" → "jobs"
28
+ */
29
+ function resourceDisplayName(resource) {
30
+ const canonical = RESOURCE_ALIASES[resource];
31
+ // No alias mapping — show as-is
32
+ if (!canonical || canonical === resource)
33
+ return resource;
34
+ // Resource is longer than canonical (e.g. "process-instances" → "process-instance")
35
+ if (resource.length > canonical.length)
36
+ return `${resource} (${canonical})`;
37
+ // Resource is a short alias (e.g. "pi" → "process-instance")
38
+ return `${canonical} (${resource})`;
39
+ }
40
+ /**
41
+ * Format a single flag for display.
42
+ */
43
+ function formatFlag(name, def, col) {
44
+ const flag = def.short ? `--${name}, -${def.short}` : `--${name}`;
45
+ const typeHint = def.type === "string" ? ` <${name}>` : "";
46
+ return ` ${(flag + typeHint).padEnd(col)}${def.description}`;
47
+ }
48
+ /**
49
+ * Build structured JSON help data for machine/agent consumption.
50
+ * Derived entirely from COMMAND_REGISTRY.
51
+ */
11
52
  function buildHelpJson(version, pluginCommandsInfo) {
53
+ const commands = [];
54
+ for (const [verb, def] of registryEntries()) {
55
+ commands.push({
56
+ verb,
57
+ resource: deriveResourcePlaceholder(verb, def),
58
+ resources: [...def.resources],
59
+ description: def.helpDescription ?? def.description,
60
+ mutating: def.mutating,
61
+ });
62
+ }
63
+ for (const cmd of pluginCommandsInfo) {
64
+ commands.push({
65
+ verb: cmd.commandName,
66
+ resource: "",
67
+ resources: [],
68
+ description: cmd.description || "",
69
+ mutating: false,
70
+ examples: cmd.examples || [],
71
+ });
72
+ }
73
+ // Derive resource aliases: short alias → canonical(s)
74
+ const resourceAliases = {};
75
+ for (const [alias, canonical] of Object.entries(RESOURCE_ALIASES)) {
76
+ if (alias.length <= 4 && alias !== canonical) {
77
+ resourceAliases[alias] = `${canonical}(s)`;
78
+ }
79
+ }
80
+ // Derive global flags from GLOBAL_FLAGS + SEARCH_FLAGS
81
+ const globalFlags = [];
82
+ for (const [name, def] of flagEntries(GLOBAL_FLAGS)) {
83
+ globalFlags.push({
84
+ flag: `--${name}`,
85
+ type: def.type,
86
+ description: def.description,
87
+ ...(def.short ? { short: `-${def.short}` } : {}),
88
+ });
89
+ }
90
+ for (const [name, def] of Object.entries(SEARCH_FLAGS)) {
91
+ globalFlags.push({
92
+ flag: `--${name}`,
93
+ type: def.type,
94
+ description: def.description,
95
+ });
96
+ }
97
+ // Derive search flags from list/search resourceFlags
98
+ const searchFlags = [];
99
+ const seenSearchFlags = new Set();
100
+ for (const verb of ["list", "search"]) {
101
+ const cmdDef = lookupVerb(verb);
102
+ if (cmdDef?.resourceFlags) {
103
+ for (const resourceFlags of Object.values(cmdDef.resourceFlags)) {
104
+ for (const [name, fd] of flagEntries(resourceFlags)) {
105
+ if (!seenSearchFlags.has(name)) {
106
+ seenSearchFlags.add(name);
107
+ searchFlags.push({
108
+ flag: `--${name}`,
109
+ type: fd.type,
110
+ description: fd.description,
111
+ });
112
+ }
113
+ }
114
+ }
115
+ }
116
+ }
12
117
  return {
13
118
  version,
14
119
  usage: "c8ctl <command> [resource] [options]",
15
- commands: [
16
- {
17
- verb: "list",
18
- resource: "<resource>",
19
- resources: [
20
- "pi",
21
- "pd",
22
- "ut",
23
- "inc",
24
- "jobs",
25
- "profiles",
26
- "plugins",
27
- "users",
28
- "roles",
29
- "groups",
30
- "tenants",
31
- "auth",
32
- "mapping-rules",
33
- ],
34
- description: "List resources (process, identity)",
35
- mutating: false,
36
- },
37
- {
38
- verb: "search",
39
- resource: "<resource>",
40
- resources: [
41
- "pi",
42
- "pd",
43
- "ut",
44
- "inc",
45
- "jobs",
46
- "vars",
47
- "users",
48
- "roles",
49
- "groups",
50
- "tenants",
51
- "auth",
52
- "mapping-rules",
53
- ],
54
- description: "Search resources with filters",
55
- mutating: false,
56
- },
57
- {
58
- verb: "get",
59
- resource: "<resource> <key>",
60
- resources: [
61
- "pi",
62
- "pd",
63
- "inc",
64
- "topology",
65
- "form",
66
- "user",
67
- "role",
68
- "group",
69
- "tenant",
70
- "auth",
71
- "mapping-rule",
72
- ],
73
- description: "Get resource by key",
74
- mutating: false,
75
- },
76
- {
77
- verb: "create",
78
- resource: "<resource>",
79
- resources: [
80
- "pi",
81
- "user",
82
- "role",
83
- "group",
84
- "tenant",
85
- "auth",
86
- "mapping-rule",
87
- ],
88
- description: "Create resource",
89
- mutating: true,
90
- },
91
- {
92
- verb: "delete",
93
- resource: "<resource> <key>",
94
- resources: ["user", "role", "group", "tenant", "auth", "mapping-rule"],
95
- description: "Delete resource",
96
- mutating: true,
97
- },
98
- {
99
- verb: "assign",
100
- resource: "<resource> <id> --to-<target>=<id>",
101
- resources: ["role", "user", "group", "mapping-rule"],
102
- description: "Assign resource to target",
103
- mutating: true,
104
- },
105
- {
106
- verb: "unassign",
107
- resource: "<resource> <id> --from-<target>=<id>",
108
- resources: ["role", "user", "group", "mapping-rule"],
109
- description: "Unassign resource from target",
110
- mutating: true,
111
- },
112
- {
113
- verb: "cancel",
114
- resource: "<resource> <key>",
115
- resources: ["pi"],
116
- description: "Cancel resource",
117
- mutating: true,
118
- },
119
- {
120
- verb: "await",
121
- resource: "<resource>",
122
- resources: ["pi"],
123
- description: "Create and await completion (alias for create --awaitCompletion)",
124
- mutating: true,
125
- },
126
- {
127
- verb: "complete",
128
- resource: "<resource> <key>",
129
- resources: ["ut", "job"],
130
- description: "Complete resource",
131
- mutating: true,
132
- },
133
- {
134
- verb: "fail",
135
- resource: "job <key>",
136
- resources: ["job"],
137
- description: "Fail a job",
138
- mutating: true,
139
- },
140
- {
141
- verb: "activate",
142
- resource: "jobs <type>",
143
- resources: ["jobs"],
144
- description: "Activate jobs by type",
145
- mutating: true,
146
- },
147
- {
148
- verb: "resolve",
149
- resource: "inc <key>",
150
- resources: ["inc"],
151
- description: "Resolve incident",
152
- mutating: true,
153
- },
154
- {
155
- verb: "publish",
156
- resource: "msg <name>",
157
- resources: ["msg"],
158
- description: "Publish message",
159
- mutating: true,
160
- },
161
- {
162
- verb: "correlate",
163
- resource: "msg <name>",
164
- resources: ["msg"],
165
- description: "Correlate message",
166
- mutating: true,
167
- },
168
- {
169
- verb: "deploy",
170
- resource: "[path...]",
171
- resources: [],
172
- description: "Deploy BPMN/DMN/forms",
173
- mutating: true,
174
- },
175
- {
176
- verb: "run",
177
- resource: "<path>",
178
- resources: [],
179
- description: "Deploy and start process",
180
- mutating: true,
181
- },
182
- {
183
- verb: "watch",
184
- resource: "[path...]",
185
- resources: [],
186
- description: "Watch files for changes and auto-deploy",
187
- mutating: false,
188
- },
189
- {
190
- verb: "open",
191
- resource: "<app>",
192
- resources: ["operate", "tasklist", "modeler", "optimize"],
193
- description: "Open Camunda web application in browser",
194
- mutating: false,
195
- },
196
- {
197
- verb: "add",
198
- resource: "profile <name>",
199
- resources: ["profile"],
200
- description: "Add a profile",
201
- mutating: false,
202
- },
203
- {
204
- verb: "remove",
205
- resource: "profile <name>",
206
- resources: ["profile"],
207
- description: "Remove a profile (alias: rm)",
208
- mutating: false,
209
- },
210
- {
211
- verb: "load",
212
- resource: "plugin <name>",
213
- resources: ["plugin"],
214
- description: "Load a c8ctl plugin",
215
- mutating: false,
216
- },
217
- {
218
- verb: "unload",
219
- resource: "plugin <name>",
220
- resources: ["plugin"],
221
- description: "Unload a c8ctl plugin",
222
- mutating: false,
223
- },
224
- {
225
- verb: "upgrade",
226
- resource: "plugin <name>",
227
- resources: ["plugin"],
228
- description: "Upgrade a plugin",
229
- mutating: false,
230
- },
231
- {
232
- verb: "downgrade",
233
- resource: "plugin <name> <version>",
234
- resources: ["plugin"],
235
- description: "Downgrade a plugin to a specific version",
236
- mutating: false,
237
- },
238
- {
239
- verb: "sync",
240
- resource: "plugin",
241
- resources: ["plugin"],
242
- description: "Synchronize plugins",
243
- mutating: false,
244
- },
245
- {
246
- verb: "init",
247
- resource: "plugin [name]",
248
- resources: ["plugin"],
249
- description: "Create a new plugin from TypeScript template",
250
- mutating: false,
251
- },
252
- {
253
- verb: "use",
254
- resource: "profile|tenant",
255
- resources: ["profile", "tenant"],
256
- description: "Set active profile or tenant",
257
- mutating: false,
258
- },
259
- {
260
- verb: "output",
261
- resource: "[json|text]",
262
- resources: ["json", "text"],
263
- description: "Show or set output format",
264
- mutating: false,
265
- },
266
- {
267
- verb: "completion",
268
- resource: "bash|zsh|fish",
269
- resources: ["bash", "zsh", "fish"],
270
- description: "Generate shell completion script",
271
- mutating: false,
272
- },
273
- {
274
- verb: "mcp-proxy",
275
- resource: "[mcp-path]",
276
- resources: [],
277
- description: "Start a STDIO to remote HTTP MCP proxy server",
278
- mutating: false,
279
- },
280
- {
281
- verb: "feedback",
282
- resource: "",
283
- resources: [],
284
- description: "Open the feedback page to report issues or request features",
285
- mutating: false,
286
- },
287
- {
288
- verb: "help",
289
- resource: "[command]",
290
- resources: [],
291
- description: "Show help",
292
- mutating: false,
293
- },
294
- ...pluginCommandsInfo.map((cmd) => ({
295
- verb: cmd.commandName,
296
- resource: "",
297
- resources: [],
298
- description: cmd.description || "",
299
- mutating: false,
300
- examples: cmd.examples || [],
301
- })),
302
- ],
303
- resourceAliases: {
304
- pi: "process-instance(s)",
305
- pd: "process-definition(s)",
306
- ut: "user-task(s)",
307
- inc: "incident(s)",
308
- msg: "message",
309
- vars: "variable(s)",
310
- auth: "authorization(s)",
311
- mr: "mapping-rule(s)",
312
- },
313
- globalFlags: [
314
- {
315
- flag: "--profile",
316
- type: "string",
317
- description: "Use specific profile for this command",
318
- },
319
- {
320
- flag: "--sortBy",
321
- type: "string",
322
- description: "Sort list/search output by column name",
323
- },
324
- {
325
- flag: "--asc",
326
- type: "boolean",
327
- description: "Sort in ascending order (default)",
328
- },
329
- {
330
- flag: "--desc",
331
- type: "boolean",
332
- description: "Sort in descending order",
333
- },
334
- {
335
- flag: "--limit",
336
- type: "string",
337
- description: "Maximum number of items to fetch (default: 1000000)",
338
- },
339
- {
340
- flag: "--between",
341
- type: "string",
342
- description: "Filter by date range: <from>..<to> (YYYY-MM-DD or ISO 8601; open-ended: ..to or from..)",
343
- },
344
- {
345
- flag: "--dateField",
346
- type: "string",
347
- description: "Date field to filter on with --between (default depends on resource)",
348
- },
349
- {
350
- flag: "--state",
351
- type: "string",
352
- description: "Filter by state (ACTIVE, COMPLETED, etc.)",
353
- },
354
- {
355
- flag: "--id",
356
- type: "string",
357
- description: "Process definition ID (alias for --bpmnProcessId)",
358
- },
359
- {
360
- flag: "--verbose",
361
- type: "boolean",
362
- description: "Enable SDK trace logging and show full error details",
363
- },
364
- {
365
- flag: "--version",
366
- type: "string",
367
- short: "-v",
368
- description: "Show version",
369
- },
370
- {
371
- flag: "--help",
372
- type: "boolean",
373
- short: "-h",
374
- description: "Show help",
375
- },
376
- ],
377
- searchFlags: [
378
- {
379
- flag: "--bpmnProcessId",
380
- type: "string",
381
- description: "Filter by process definition ID",
382
- },
383
- {
384
- flag: "--processDefinitionKey",
385
- type: "string",
386
- description: "Filter by process definition key",
387
- },
388
- {
389
- flag: "--processInstanceKey",
390
- type: "string",
391
- description: "Filter by process instance key",
392
- },
393
- {
394
- flag: "--parentProcessInstanceKey",
395
- type: "string",
396
- description: "Filter by parent process instance key",
397
- },
398
- {
399
- flag: "--name",
400
- type: "string",
401
- description: "Filter by name (variables, process definitions); supports wildcards * and ?",
402
- },
403
- { flag: "--key", type: "string", description: "Filter by key" },
404
- {
405
- flag: "--assignee",
406
- type: "string",
407
- description: "Filter by assignee (user tasks)",
408
- },
409
- {
410
- flag: "--elementId",
411
- type: "string",
412
- description: "Filter by element ID (user tasks)",
413
- },
414
- {
415
- flag: "--errorType",
416
- type: "string",
417
- description: "Filter by error type (incidents)",
418
- },
419
- {
420
- flag: "--errorMessage",
421
- type: "string",
422
- description: "Filter by error message (incidents); supports wildcards",
423
- },
424
- {
425
- flag: "--type",
426
- type: "string",
427
- description: "Filter by type (jobs); supports wildcards",
428
- },
429
- {
430
- flag: "--value",
431
- type: "string",
432
- description: "Filter by variable value",
433
- },
434
- {
435
- flag: "--scopeKey",
436
- type: "string",
437
- description: "Filter by scope key (variables)",
438
- },
439
- {
440
- flag: "--fullValue",
441
- type: "boolean",
442
- description: "Return full variable values (default: truncated)",
443
- },
444
- {
445
- flag: "--iname",
446
- type: "string",
447
- description: "Case-insensitive --name filter (supports wildcards)",
448
- },
449
- {
450
- flag: "--iid",
451
- type: "string",
452
- description: "Case-insensitive --bpmnProcessId filter",
453
- },
454
- {
455
- flag: "--iassignee",
456
- type: "string",
457
- description: "Case-insensitive --assignee filter",
458
- },
459
- {
460
- flag: "--ierrorMessage",
461
- type: "string",
462
- description: "Case-insensitive --errorMessage filter",
463
- },
464
- {
465
- flag: "--itype",
466
- type: "string",
467
- description: "Case-insensitive --type filter",
468
- },
469
- {
470
- flag: "--ivalue",
471
- type: "string",
472
- description: "Case-insensitive --value filter",
473
- },
474
- {
475
- flag: "--username",
476
- type: "string",
477
- description: "Filter by username (users)",
478
- },
479
- {
480
- flag: "--email",
481
- type: "string",
482
- description: "Filter by email (users)",
483
- },
484
- {
485
- flag: "--roleId",
486
- type: "string",
487
- description: "Filter by role ID (roles)",
488
- },
489
- {
490
- flag: "--groupId",
491
- type: "string",
492
- description: "Filter by group ID (groups)",
493
- },
494
- {
495
- flag: "--ownerId",
496
- type: "string",
497
- description: "Filter by owner ID (authorizations)",
498
- },
499
- {
500
- flag: "--ownerType",
501
- type: "string",
502
- description: "Filter by owner type (authorizations)",
503
- },
504
- {
505
- flag: "--resourceType",
506
- type: "string",
507
- description: "Filter by resource type (authorizations)",
508
- },
509
- {
510
- flag: "--resourceId",
511
- type: "string",
512
- description: "Filter by resource ID (authorizations)",
513
- },
514
- {
515
- flag: "--claimName",
516
- type: "string",
517
- description: "Filter by claim name (mapping rules)",
518
- },
519
- {
520
- flag: "--claimValue",
521
- type: "string",
522
- description: "Filter by claim value (mapping rules)",
523
- },
524
- {
525
- flag: "--mappingRuleId",
526
- type: "string",
527
- description: "Filter by mapping rule ID (mapping rules)",
528
- },
529
- ],
530
- agentFlags: [
531
- {
532
- flag: "--fields",
533
- type: "string",
534
- description: "Comma-separated list of output fields to include. Reduces context window size. Case-insensitive. Example: --fields Key,State,processDefinitionId",
535
- appliesTo: "all list/search/get commands",
536
- },
537
- {
538
- flag: "--dry-run",
539
- type: "boolean",
540
- description: "Preview the API request that would be sent without executing it. Emits { dryRun, command, method, url, body } as JSON. Always exits 0.",
541
- appliesTo: "mutating commands: create, cancel, deploy, complete, fail, activate, resolve, publish, correlate, delete, assign, unassign",
542
- },
543
- ],
120
+ commands,
121
+ resourceAliases,
122
+ globalFlags,
123
+ searchFlags,
124
+ agentFlags: flagEntries(GLOBAL_FLAGS)
125
+ .filter(([, f]) => f.agentDescription)
126
+ .map(([name, f]) => ({
127
+ flag: `--${name}`,
128
+ type: f.type,
129
+ description: (f.agentDescription ?? "").replace(/\n/g, " "),
130
+ ...(f.agentAppliesTo ? { appliesTo: f.agentAppliesTo } : {}),
131
+ })),
544
132
  };
545
133
  }
546
134
  /**
@@ -558,6 +146,261 @@ export function showVersion() {
558
146
  const logger = getLogger();
559
147
  logger.info(`c8ctl v${getVersion()}`);
560
148
  }
149
+ // ─── Derived help generation ─────────────────────────────────────────────────
150
+ /**
151
+ * Derive the resource placeholder for a command's help line.
152
+ * Uses helpResource override if set, otherwise auto-derives from
153
+ * resources list, positionals, and requiresResource flag.
154
+ */
155
+ function deriveResourcePlaceholder(_verb, def) {
156
+ if (def.helpResource)
157
+ return def.helpResource;
158
+ const resources = def.resources;
159
+ // Single-resource commands: show "resource <positional>"
160
+ if (resources.length === 1) {
161
+ const canonical = RESOURCE_ALIASES[resources[0]] ?? resources[0];
162
+ const positionals = def.resourcePositionals?.[canonical];
163
+ if (positionals && positionals.length > 0) {
164
+ const posArgs = positionals
165
+ .map((p) => (p.required ? `<${p.name}>` : `[${p.name}]`))
166
+ .join(" ");
167
+ return `${resources[0]} ${posArgs}`;
168
+ }
169
+ return resources[0];
170
+ }
171
+ // Multi-resource commands
172
+ if (resources.length > 1 && def.requiresResource) {
173
+ // Find common positional shape across resources
174
+ const allPositionals = def.resourcePositionals
175
+ ? Object.values(def.resourcePositionals)
176
+ : [];
177
+ if (allPositionals.length > 0) {
178
+ // Use the first resource's positionals as representative
179
+ const first = allPositionals[0];
180
+ if (first.length > 0) {
181
+ const posArgs = first
182
+ .map((p) => (p.required ? `<${p.name}>` : `[${p.name}]`))
183
+ .join(" ");
184
+ return `<resource> ${posArgs}`;
185
+ }
186
+ }
187
+ return "<resource>";
188
+ }
189
+ return "";
190
+ }
191
+ /**
192
+ * Build the resource suffix for description (e.g. "(pi, pd, ut, inc)")
193
+ * Shows the valid resources when the placeholder is generic (<resource>, <app>).
194
+ */
195
+ function deriveResourceSuffix(verb, def) {
196
+ if (def.resources.length === 0)
197
+ return "";
198
+ const placeholder = deriveResourcePlaceholder(verb, def);
199
+ // Show suffix only when placeholder is generic (contains <resource> or <app>)
200
+ if (placeholder.includes("<resource>") || placeholder.includes("<app>")) {
201
+ return ` (${def.resources.join(", ")})`;
202
+ }
203
+ return "";
204
+ }
205
+ /**
206
+ * Generate the Commands section lines from the registry.
207
+ */
208
+ function generateCommandLines() {
209
+ const lines = [];
210
+ const DESC_COL = 36; // description starts at column 36
211
+ for (const [verb, def] of registryEntries()) {
212
+ const resource = deriveResourcePlaceholder(verb, def);
213
+ const desc = def.helpDescription ?? def.description;
214
+ const suffix = deriveResourceSuffix(verb, def);
215
+ // Ensure at least 2 spaces between verb and resource, and between resource and desc
216
+ const verbPadded = verb.length >= 10 ? `${verb} ` : verb.padEnd(10);
217
+ const leftPart = ` ${verbPadded}${resource}`;
218
+ const padding = Math.max(2, DESC_COL - leftPart.length);
219
+ lines.push(`${leftPart}${" ".repeat(padding)}${desc}${suffix}`);
220
+ }
221
+ return lines.join("\n");
222
+ }
223
+ /**
224
+ * Generate the Flags section from GLOBAL_FLAGS and select verb-specific flags.
225
+ * Uses the curated descriptions from the registry.
226
+ */
227
+ function generateFlagsSection() {
228
+ const lines = [];
229
+ const FLAG_COL = 36;
230
+ // Global flags first
231
+ for (const [name, def] of flagEntries(GLOBAL_FLAGS)) {
232
+ const flag = def.short ? `--${name}, -${def.short}` : `--${name}`;
233
+ const typeHint = def.type === "string" ? ` <${name}>` : "";
234
+ lines.push(` ${(flag + typeHint).padEnd(FLAG_COL)}${def.description}`);
235
+ }
236
+ // Collect notable verb-specific flags marked with showInTopLevelHelp
237
+ const seen = new Set(Object.keys(GLOBAL_FLAGS));
238
+ function addFlag(name, flagDef) {
239
+ if (!flagDef.showInTopLevelHelp || seen.has(name))
240
+ return;
241
+ seen.add(name);
242
+ const flag = flagDef.short ? `--${name}, --${flagDef.short}` : `--${name}`;
243
+ const typeHint = flagDef.type === "string" ? ` <${name}>` : "";
244
+ const hint = flagDef.helpHint ? ` (${flagDef.helpHint})` : "";
245
+ lines.push(` ${(flag + typeHint).padEnd(FLAG_COL)}${flagDef.description}${hint}`);
246
+ }
247
+ for (const [, cmd] of registryEntries()) {
248
+ for (const [name, flagDef] of flagEntries(cmd.flags)) {
249
+ addFlag(name, flagDef);
250
+ }
251
+ if (cmd.resourceFlags) {
252
+ for (const resourceFlags of Object.values(cmd.resourceFlags)) {
253
+ for (const [name, flagDef] of flagEntries(resourceFlags)) {
254
+ addFlag(name, flagDef);
255
+ }
256
+ }
257
+ }
258
+ }
259
+ return lines.join("\n");
260
+ }
261
+ /**
262
+ * Generate the Search Flags section from SEARCH_FLAGS and
263
+ * all unique search-specific flags across command resourceFlags.
264
+ */
265
+ function generateSearchFlagsSection() {
266
+ const lines = [];
267
+ const FLAG_COL = 36;
268
+ // Collect unique search flags from list and search commands
269
+ const searchFlagMap = new Map();
270
+ for (const verb of ["list", "search"]) {
271
+ const def = COMMAND_REGISTRY[verb];
272
+ if (def.resourceFlags) {
273
+ for (const resourceFlags of Object.values(def.resourceFlags)) {
274
+ for (const [name, flagDef] of Object.entries(resourceFlags)) {
275
+ if (!searchFlagMap.has(name)) {
276
+ searchFlagMap.set(name, flagDef);
277
+ }
278
+ }
279
+ }
280
+ }
281
+ }
282
+ // Search/list shared flags
283
+ for (const [name, def] of Object.entries(SEARCH_FLAGS)) {
284
+ const typeHint = def.type === "string" ? ` <${name}>` : "";
285
+ lines.push(` ${(`--${name}${typeHint}`).padEnd(FLAG_COL)}${def.description}`);
286
+ }
287
+ // Separate case-sensitive and case-insensitive flags
288
+ const caseSensitive = [];
289
+ const caseInsensitive = [];
290
+ for (const [name, def] of searchFlagMap) {
291
+ // Skip flags already in SEARCH_FLAGS
292
+ if (name in SEARCH_FLAGS)
293
+ continue;
294
+ if (name.startsWith("i") &&
295
+ name.length > 1 &&
296
+ name[1] === name[1].toLowerCase()) {
297
+ // Check if there's a non-i version
298
+ const baseName = name.slice(1);
299
+ const firstLower = baseName[0].toLowerCase() + baseName.slice(1);
300
+ if (searchFlagMap.has(firstLower)) {
301
+ caseInsensitive.push([name, def]);
302
+ continue;
303
+ }
304
+ }
305
+ caseSensitive.push([name, def]);
306
+ }
307
+ for (const [name, def] of caseSensitive) {
308
+ const typeHint = def.type === "string" ? ` <${name}>` : "";
309
+ lines.push(` ${(`--${name}${typeHint}`).padEnd(FLAG_COL)}${def.description}`);
310
+ }
311
+ if (caseInsensitive.length > 0) {
312
+ lines.push("");
313
+ lines.push(" Case-Insensitive Search (--i prefix):");
314
+ for (const [name, def] of caseInsensitive) {
315
+ const typeHint = def.type === "string" ? " <pattern>" : "";
316
+ lines.push(` ${(`--${name}${typeHint}`).padEnd(FLAG_COL)}${def.description}`);
317
+ }
318
+ }
319
+ return lines.join("\n");
320
+ }
321
+ /**
322
+ * Generate resource aliases section from RESOURCE_ALIASES.
323
+ */
324
+ function generateResourceAliases() {
325
+ // Collect unique alias → long-name mappings
326
+ // We want to show short aliases (pi, pd, ut, inc, msg, auth, mr)
327
+ const displayed = new Map();
328
+ for (const [alias, canonical] of Object.entries(RESOURCE_ALIASES)) {
329
+ // Only show short aliases (not the long plural forms)
330
+ if (alias.length <= 4 && alias !== canonical) {
331
+ if (!displayed.has(alias)) {
332
+ // Find the plural/long form for display
333
+ const plural = Object.entries(RESOURCE_ALIASES).find(([k, v]) => v === canonical && k.includes("-") && k !== alias);
334
+ const displayName = plural ? `${canonical}(s)` : canonical;
335
+ displayed.set(alias, displayName);
336
+ }
337
+ }
338
+ }
339
+ const lines = [];
340
+ for (const [alias, longName] of displayed) {
341
+ lines.push(` ${alias.padEnd(5)}= ${longName}`);
342
+ }
343
+ return lines.join("\n");
344
+ }
345
+ /**
346
+ * Generate the "For detailed help" footer from commands with hasDetailedHelp.
347
+ */
348
+ function generateHelpFooter() {
349
+ const lines = [];
350
+ const CMD_COL = 35;
351
+ for (const [verb, def] of registryEntries()) {
352
+ if (def.hasDetailedHelp) {
353
+ const label = def.helpFooterLabel ?? `Show ${verb} command with all flags`;
354
+ lines.push(` ${`c8ctl help ${verb}`.padEnd(CMD_COL)}${label}`);
355
+ }
356
+ }
357
+ // Special entries: profiles and plugin (virtual help topics)
358
+ lines.push(` ${`c8ctl help profiles`.padEnd(CMD_COL)}Show profile management help`);
359
+ lines.push(` ${`c8ctl help plugin`.padEnd(CMD_COL)}Show plugin management help`);
360
+ lines.push(` ${`c8ctl help plugins`.padEnd(CMD_COL)}Show plugin management help (alias)`);
361
+ return lines.join("\n");
362
+ }
363
+ /**
364
+ * Generate the Examples section from registry helpExamples.
365
+ */
366
+ function generateExamplesSection() {
367
+ const lines = [];
368
+ const DESC_COL = 36;
369
+ for (const [, def] of registryEntries()) {
370
+ if (!def.helpExamples)
371
+ continue;
372
+ for (const ex of def.helpExamples) {
373
+ const padding = Math.max(2, DESC_COL - ex.command.length - 2);
374
+ lines.push(` ${ex.command}${" ".repeat(padding)}${ex.description}`);
375
+ }
376
+ }
377
+ return lines.join("\n");
378
+ }
379
+ /**
380
+ * Generate the Agent Flags section from GLOBAL_FLAGS entries
381
+ * that have agentDescription set.
382
+ */
383
+ function generateAgentFlagsSection() {
384
+ const lines = [];
385
+ for (const [name, def] of flagEntries(GLOBAL_FLAGS)) {
386
+ if (!def.agentDescription)
387
+ continue;
388
+ const typeHint = def.type === "string" ? ` <${name}>` : "";
389
+ const flag = `--${name}${typeHint}`;
390
+ const descLines = def.agentDescription.split("\n");
391
+ // First line: flag + first description line
392
+ lines.push(` ${flag.padEnd(22)}${descLines[0]}`);
393
+ // Continuation lines: indented to align
394
+ for (let i = 1; i < descLines.length; i++) {
395
+ lines.push(` ${"".padEnd(22)}${descLines[i]}`);
396
+ }
397
+ if (def.agentAppliesTo) {
398
+ lines.push(` ${"".padEnd(22)}Applies to ${def.agentAppliesTo}.`);
399
+ }
400
+ lines.push("");
401
+ }
402
+ return lines.join("\n").trimEnd();
403
+ }
561
404
  /**
562
405
  * Display full help
563
406
  */
@@ -584,121 +427,33 @@ export function showHelp() {
584
427
  pluginExamples += `\n ${ex.command.padEnd(35)}${ex.description}`;
585
428
  }
586
429
  }
430
+ const commandLines = generateCommandLines();
431
+ const flagsSection = generateFlagsSection();
432
+ const searchFlagsSection = generateSearchFlagsSection();
433
+ const resourceAliases = generateResourceAliases();
434
+ const helpFooter = generateHelpFooter();
435
+ const examplesSection = generateExamplesSection();
436
+ const agentFlagsSection = generateAgentFlagsSection();
587
437
  console.log(`
588
438
  c8ctl - Camunda 8 CLI v${version}
589
439
 
590
440
  Usage: c8ctl <command> [resource] [options]
591
441
 
592
442
  Commands:
593
- list <resource> List resources (pi, pd, ut, inc, jobs, profiles, users, roles, groups, tenants, auth, mapping-rules)
594
- search <resource> Search resources with filters (pi, pd, ut, inc, jobs, variables/vars, users, roles, groups, tenants, auth, mapping-rules)
595
- get <resource> <key> Get resource by key (pi, pd, inc, topology, form, user, role, group, tenant, auth, mapping-rule)
596
- create <resource> Create resource (pi, user, role, group, tenant, auth, mapping-rule)
597
- delete <resource> <key> Delete resource (user, role, group, tenant, auth, mapping-rule)
598
- assign <resource> <id> Assign resource to target (role, user, group, mapping-rule)
599
- unassign <resource> <id> Unassign resource from target (role, user, group, mapping-rule)
600
- cancel <resource> <key> Cancel resource (pi)
601
- await <resource> Create and await completion (pi, alias for create --awaitCompletion)
602
- complete <resource> <key> Complete resource (ut, job)
603
- fail job <key> Fail a job
604
- activate jobs <type> Activate jobs by type
605
- resolve inc <key> Resolve incident
606
- publish msg <name> Publish message
607
- correlate msg <name> Correlate message
608
- deploy [path...] Deploy BPMN/DMN/forms
609
- run <path> Deploy and start process
610
- watch [path...] Watch files for changes and auto-deploy
611
- open <app> Open Camunda web app in browser (operate, tasklist, modeler, optimize)
612
- add profile <name> Add a profile
613
- remove profile <name> Remove a profile (alias: rm)
614
- load plugin <name> Load a c8ctl plugin from npm registry
615
- load plugin --from <url> Load a c8ctl plugin from URL (https://, git://, file://)
616
- unload plugin <name> Unload a c8ctl plugin (npm uninstall wrapper)
617
- upgrade plugin <name> [version] Upgrade a plugin (respects source type)
618
- downgrade plugin <name> <version> Downgrade a plugin to a specific version
619
- sync plugin Synchronize plugins from registry (rebuild/reinstall)
620
- init plugin [name] Create a new plugin from TypeScript template
621
- use profile|tenant Set active profile or tenant
622
- output [json|text] Show or set output format
623
- completion bash|zsh|fish Generate shell completion script
624
- mcp-proxy [mcp-path] Start a STDIO to remote HTTP MCP proxy server
625
- feedback Open the feedback page to report issues or request features
626
- help [command] Show help (detailed help for list, get, create, complete, await, delete, assign, unassign)${pluginSection}
443
+ ${commandLines}${pluginSection}
627
444
 
628
445
  Flags:
629
- --profile <name> Use specific profile for this command
630
- --from <url> Load plugin from URL (use with 'load plugin')
631
- --xml Get process definition as XML (use with 'get pd')
632
- --variables Get process instance with variables (use with 'get pi')
633
- --userTask, --ut Get form for a user task (optional, use with 'get form')
634
- --processDefinition, --pd Get start form for a process definition (optional, use with 'get form')
635
- --id <process-id> Process definition ID (alias for --bpmnProcessId)
636
- --awaitCompletion Wait for process instance to complete (use with 'create pi')
637
- --fetchVariables <v> Reserved for future use (all variables returned by default)
638
- --requestTimeout <ms> Timeout in milliseconds for process completion (use with --awaitCompletion)
639
- --sortBy <column> Sort list/search output by column name (use with 'list' or 'search')
640
- --asc Sort in ascending order (default)
641
- --desc Sort in descending order
642
- --limit <n> Maximum number of items to fetch (default: 1000000)
643
- --between <from>..<to> Filter by date range (use with 'list' or 'search'; short dates YYYY-MM-DD or ISO 8601; omit either end for open-ended range)
644
- --dateField <field> Date field to filter on with --between (default depends on resource)
645
- --verbose Enable SDK trace logging and show full error details
646
- --version, -v Show version
647
- --help, -h Show help
446
+ ${flagsSection}
648
447
 
649
448
  Search Flags:
650
- --bpmnProcessId <id> Filter by process definition ID
651
- --processDefinitionKey <key> Filter by process definition key
652
- --processInstanceKey <key> Filter by process instance key
653
- --parentProcessInstanceKey <key> Filter by parent process instance key
654
- --state <state> Filter by state (ACTIVE, COMPLETED, etc.)
655
- --name <name> Filter by name (variables, process definitions)
656
- --key <key> Filter by key
657
- --assignee <user> Filter by assignee (user tasks)
658
- --elementId <id> Filter by element ID (user tasks)
659
- --errorType <type> Filter by error type (incidents)
660
- --errorMessage <msg> Filter by error message (incidents)
661
- --type <type> Filter by type (jobs)
662
- --value <value> Filter by variable value
663
- --scopeKey <key> Filter by scope key (variables)
664
- --fullValue Return full variable values (default: truncated)
665
-
666
- Wildcard Search:
667
- String filters support wildcards: * (any chars) and ? (single char).
668
- Example: --name='*main*' matches all names containing "main".
669
-
670
- Case-Insensitive Search (--i prefix):
671
- --iname <pattern> Case-insensitive --name filter
672
- --iid <pattern> Case-insensitive --bpmnProcessId filter
673
- --iassignee <pattern> Case-insensitive --assignee filter
674
- --ierrorMessage <pattern> Case-insensitive --errorMessage filter
675
- --itype <pattern> Case-insensitive --type filter
676
- --ivalue <pattern> Case-insensitive --value filter
677
- Prefix any string filter with 'i' for case-insensitive matching.
678
- Wildcards (* and ?) are supported. Filtering is applied client-side.
679
- Example: --iname='*ORDER*' matches "order", "Order", "ORDER", etc.
449
+ ${searchFlagsSection}
680
450
 
681
451
  Resource Aliases:
682
- pi = process-instance(s)
683
- pd = process-definition(s)
684
- ut = user-task(s)
685
- inc = incident(s)
686
- msg = message
687
- auth = authorization(s)
688
- mr = mapping-rule(s)
452
+ ${resourceAliases}
689
453
 
690
454
  ━━━ Agent Flags (for programmatic / AI-agent consumption) ━━━
691
455
 
692
- --fields <columns> Comma-separated list of output fields to include.
693
- Reduces context window size when parsing output.
694
- Example: c8ctl list pi --fields Key,State,processDefinitionId
695
- Applies to all list/search/get commands. Case-insensitive.
696
-
697
- --dry-run Preview the API request that would be sent, without executing it.
698
- Emits JSON: { dryRun, command, method, url, body }
699
- Applies to all mutating commands: create, cancel, deploy, complete,
700
- fail, activate, resolve, publish, correlate, delete, assign, unassign.
701
- Always exits 0. Use before confirming a mutating operation.
456
+ ${agentFlagsSection}
702
457
 
703
458
  Note: In JSON output mode (c8ctl output json), help is returned as structured JSON.
704
459
  Use 'c8ctl output json && c8ctl help' to get machine-readable command reference.
@@ -706,1267 +461,192 @@ Resource Aliases:
706
461
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
707
462
 
708
463
  Examples:
709
- c8ctl list pi List process instances
710
- c8ctl list pd List process definitions
711
- c8ctl search pi --state=ACTIVE Search for active process instances
712
- c8ctl search pd --bpmnProcessId=myProcess Search process definitions by ID
713
- c8ctl search pd --name='*main*' Search process definitions with wildcard
714
- c8ctl search ut --assignee=john Search user tasks assigned to john
715
- c8ctl search inc --state=ACTIVE Search for active incidents
716
- c8ctl search jobs --type=myJobType Search jobs by type
717
- c8ctl search jobs --type='*service*' Search jobs with type containing "service"
718
- c8ctl search variables --name=myVar Search for variables by name
719
- c8ctl search variables --value=foo Search for variables by value
720
- c8ctl search variables --processInstanceKey=123 --fullValue Search variables with full values
721
- c8ctl search pd --iname='*order*' Case-insensitive search by name
722
- c8ctl search ut --iassignee=John Case-insensitive search by assignee
723
- c8ctl get pi 123456 Get process instance by key
724
- c8ctl get pi 123456 --variables Get process instance with variables
725
- c8ctl get pd 123456 Get process definition by key
726
- c8ctl get pd 123456 --xml Get process definition XML
727
- c8ctl get form 123456 Get form (searches both user task and process definition)
728
- c8ctl get form 123456 --ut Get form for user task only
729
- c8ctl get form 123456 --pd Get start form for process definition only
730
- c8ctl create pi --id=myProcess
731
- c8ctl create pi --id=myProcess --awaitCompletion
732
- c8ctl await pi --id=myProcess Create and wait for completion
733
- c8ctl deploy ./my-process.bpmn Deploy a BPMN file
734
- c8ctl run ./my-process.bpmn Deploy and start process
735
- c8ctl watch ./src Watch directory for changes
736
- c8ctl open operate Open Camunda Operate in browser
737
- c8ctl open tasklist Open Camunda Tasklist in browser
738
- c8ctl open operate --profile=prod Open Operate using a specific profile
739
- c8ctl use profile prod Set active profile
740
- c8ctl which profile Show currently active profile
741
- c8ctl output json Switch to JSON output
742
- c8ctl init plugin my-plugin Create new plugin from template (c8ctl-plugin-my-plugin)
743
- c8ctl load plugin my-plugin Load plugin from npm registry
744
- c8ctl load plugin --from https://github.com/org/plugin Load plugin from URL
745
- c8ctl upgrade plugin my-plugin Upgrade plugin to latest version
746
- c8ctl upgrade plugin my-plugin 1.2.3 Upgrade plugin to a specific version (source-aware)
747
- c8ctl sync plugin Synchronize plugins
748
- c8ctl completion bash Generate bash completion script
749
- c8ctl list users List users
750
- c8ctl get user john Get user by username
751
- c8ctl create user --username=john --name='John Doe' --email=john@example.com --password=secret
752
- c8ctl delete user john Delete user
753
- c8ctl assign role admin --to-user=john Assign role to user
754
- c8ctl unassign role admin --from-user=john Unassign role from user${pluginExamples}
464
+ ${examplesSection}${pluginExamples}
755
465
 
756
466
  For detailed help on specific commands with all available flags:
757
- c8ctl help list Show all list resources and their flags
758
- c8ctl help get Show all get resources and their flags
759
- c8ctl help create Show all create resources and their flags
760
- c8ctl help complete Show all complete resources and their flags
761
- c8ctl help await Show await command with all flags
762
- c8ctl help mcp-proxy Show mcp-proxy setup and usage
763
- c8ctl help search Show all search resources and their flags
764
- c8ctl help deploy Show deploy command with all flags
765
- c8ctl help run Show run command with all flags
766
- c8ctl help watch Show watch command with all flags
767
- c8ctl help open Show open command with all apps
768
- c8ctl help cancel Show cancel command with all flags
769
- c8ctl help resolve Show resolve command with all flags
770
- c8ctl help fail Show fail command with all flags
771
- c8ctl help activate Show activate command with all flags
772
- c8ctl help publish Show publish command with all flags
773
- c8ctl help correlate Show correlate command with all flags
774
- c8ctl help delete Show delete command with all flags
775
- c8ctl help assign Show assign command with all flags
776
- c8ctl help unassign Show unassign command with all flags
777
- c8ctl help profiles Show profile management help
778
- c8ctl help plugin Show plugin management help
779
- c8ctl help plugins Alias for plugin management help
467
+ ${helpFooter}
780
468
 
781
469
  Feedback & Issues:
782
470
  https://github.com/camunda/c8ctl/issues
783
471
  Or run: c8ctl feedback
784
472
  `.trim());
785
473
  }
474
+ // ─── Derived verb help ───────────────────────────────────────────────────────
786
475
  /**
787
- * Show available resources for a verb
476
+ * Show available resources for a verb. Derived from COMMAND_REGISTRY.
788
477
  */
789
478
  export function showVerbResources(verb) {
790
- const resources = {
791
- list: "process-instances (pi), process-definitions (pd), user-tasks (ut), incidents (inc), jobs, profiles, plugins, users, roles, groups, tenants, authorizations (auth), mapping-rules (mr)",
792
- search: "process-instances (pi), process-definitions (pd), user-tasks (ut), incidents (inc), jobs, variables (vars), users, roles, groups, tenants, authorizations (auth), mapping-rules (mr)",
793
- get: "process-instance (pi), process-definition (pd), incident (inc), topology, form, user, role, group, tenant, authorization (auth), mapping-rule (mr)",
794
- create: "process-instance (pi), user, role, group, tenant, authorization (auth), mapping-rule (mr)",
795
- delete: "user, role, group, tenant, authorization (auth), mapping-rule (mr)",
796
- assign: "role, user, group, mapping-rule",
797
- unassign: "role, user, group, mapping-rule",
798
- complete: "user-task (ut), job",
799
- cancel: "process-instance (pi)",
800
- await: "process-instance (pi)",
801
- resolve: "incident (inc)",
802
- activate: "jobs",
803
- fail: "job",
804
- publish: "message (msg)",
805
- correlate: "message (msg)",
806
- add: "profile",
807
- remove: "profile",
808
- rm: "profile",
809
- load: "plugin",
810
- unload: "plugin",
811
- sync: "plugin",
812
- upgrade: "plugin",
813
- downgrade: "plugin",
814
- init: "plugin",
815
- use: "profile, tenant",
816
- which: "profile",
817
- output: "json, text",
818
- open: "operate, tasklist, modeler, optimize",
819
- completion: "bash, zsh, fish",
820
- help: "list, get, create, complete, await, search, deploy, run, watch, open, cancel, resolve, fail, activate, publish, correlate, delete, assign, unassign, upgrade, downgrade, init, profiles, profile, plugin, plugins",
821
- };
822
- const available = resources[verb];
823
- if (available) {
824
- console.log(`\nUsage: c8ctl ${verb} <resource>\n`);
825
- console.log(`Available resources:\n ${available}`);
479
+ // Resolve verb aliases (e.g. "rm" → "remove", "w" → "watch")
480
+ let resolvedVerb = verb;
481
+ if (!lookupVerb(verb)) {
482
+ for (const [v, d] of registryEntries()) {
483
+ if (d.aliases?.includes(verb)) {
484
+ resolvedVerb = v;
485
+ break;
486
+ }
487
+ }
826
488
  }
827
- else {
489
+ const def = lookupVerb(resolvedVerb);
490
+ if (!def) {
828
491
  console.log(`\nUnknown command: ${verb}`);
829
492
  console.log('Run "c8ctl help" for usage information.');
493
+ return;
830
494
  }
831
- }
832
- /**
833
- * Show detailed help for list command with all resources and their flags
834
- */
835
- export function showListHelp() {
836
- console.log(`
837
- c8ctl list - List resources
838
-
839
- Usage: c8ctl list <resource> [flags]
840
-
841
- Resources and their available flags:
842
-
843
- process-instances (pi)
844
- --id <id> Filter by process definition ID (alias: --bpmnProcessId)
845
- --version <num> Filter by process definition version
846
- --state <state> Filter by state (ACTIVE, COMPLETED, etc.)
847
- --all List all instances (pagination)
848
- --between <from>..<to> Filter by date range (default field: startDate)
849
- --dateField <field> Date field for --between (startDate, endDate)
850
- --sortBy <column> Sort by column (Key, Process ID, State, Version, Start Date, Tenant ID)
851
- --asc Sort in ascending order (default)
852
- --desc Sort in descending order
853
- --limit <n> Maximum number of items to fetch (default: 1000000)
854
- --profile <name> Use specific profile
855
- Note: instances with an active incident are marked with ⚠ before the Key
856
-
857
- process-definitions (pd)
858
- --sortBy <column> Sort by column (Key, Process ID, Name, Version, Tenant ID)
859
- --asc Sort in ascending order (default)
860
- --desc Sort in descending order
861
- --limit <n> Maximum number of items to fetch (default: 1000000)
862
- --profile <name> Use specific profile
863
-
864
- user-tasks (ut)
865
- --state <state> Filter by state (CREATED, COMPLETED, etc.)
866
- --assignee <name> Filter by assignee
867
- --all List all tasks (pagination)
868
- --between <from>..<to> Filter by date range (default field: creationDate)
869
- --dateField <field> Date field for --between (creationDate, completionDate, followUpDate, dueDate)
870
- --sortBy <column> Sort by column (Key, Name, State, Assignee, Created, Process Instance, Tenant ID)
871
- --asc Sort in ascending order (default)
872
- --desc Sort in descending order
873
- --limit <n> Maximum number of items to fetch (default: 1000000)
874
- --profile <name> Use specific profile
875
-
876
- incidents (inc)
877
- --state <state> Filter by state (ACTIVE, RESOLVED, etc.)
878
- --processInstanceKey <key> Filter by process instance
879
- --between <from>..<to> Filter by date range (field: creationTime)
880
- --sortBy <column> Sort by column (Key, Type, Message, State, Created, Process Instance, Tenant ID)
881
- --asc Sort in ascending order (default)
882
- --desc Sort in descending order
883
- --limit <n> Maximum number of items to fetch (default: 1000000)
884
- --profile <name> Use specific profile
885
-
886
- jobs
887
- --state <state> Filter by state (ACTIVATABLE, ACTIVATED, etc.)
888
- --type <type> Filter by job type
889
- --between <from>..<to> Filter by date range (default field: creationTime)
890
- --dateField <field> Date field for --between (creationTime, lastUpdateTime)
891
- --sortBy <column> Sort by column (Key, Type, State, Retries, Created, Process Instance, Tenant ID)
892
- --asc Sort in ascending order (default)
893
- --desc Sort in descending order
894
- --limit <n> Maximum number of items to fetch (default: 1000000)
895
- --profile <name> Use specific profile
896
-
897
- profiles
898
- Lists both c8ctl and Camunda Modeler profiles
899
- (Modeler profiles are shown with 'modeler:' prefix)
900
-
901
- plugins
902
- Shows installed plugins with version and sync status
903
-
904
- users
905
- --sortBy <column> Sort by column (Username, Name, Email)
906
- --asc Sort in ascending order (default)
907
- --desc Sort in descending order
908
- --limit <n> Maximum number of items to fetch (default: 1000000)
909
- --profile <name> Use specific profile
910
-
911
- roles
912
- --sortBy <column> Sort by column (Role ID, Name, Description)
913
- --asc Sort in ascending order (default)
914
- --desc Sort in descending order
915
- --limit <n> Maximum number of items to fetch (default: 1000000)
916
- --profile <name> Use specific profile
917
-
918
- groups
919
- --sortBy <column> Sort by column (Group ID, Name, Description)
920
- --asc Sort in ascending order (default)
921
- --desc Sort in descending order
922
- --limit <n> Maximum number of items to fetch (default: 1000000)
923
- --profile <name> Use specific profile
924
-
925
- tenants
926
- --sortBy <column> Sort by column (Tenant ID, Name, Description)
927
- --asc Sort in ascending order (default)
928
- --desc Sort in descending order
929
- --limit <n> Maximum number of items to fetch (default: 1000000)
930
- --profile <name> Use specific profile
931
-
932
- authorizations (auth)
933
- --sortBy <column> Sort by column (Key, Owner ID, Owner Type, Resource Type, Resource ID, Permissions)
934
- --asc Sort in ascending order (default)
935
- --desc Sort in descending order
936
- --limit <n> Maximum number of items to fetch (default: 1000000)
937
- --profile <name> Use specific profile
938
-
939
- mapping-rules (mr)
940
- --sortBy <column> Sort by column (Mapping Rule ID, Name, Claim Name, Claim Value)
941
- --asc Sort in ascending order (default)
942
- --desc Sort in descending order
943
- --limit <n> Maximum number of items to fetch (default: 1000000)
944
- --profile <name> Use specific profile
945
-
946
- Examples:
947
- c8ctl list pi --state=ACTIVE
948
- c8ctl list pi --between=2024-01-01..2024-12-31
949
- c8ctl list pi --between=2024-01-01T00:00:00Z..2024-06-30T23:59:59Z --dateField=endDate
950
- c8ctl list pi --sortBy=State
951
- c8ctl list pi --sortBy=State --desc
952
- c8ctl list ut --assignee=john.doe
953
- c8ctl list ut --between=2024-01-01..2024-03-31 --dateField=dueDate
954
- c8ctl list ut --sortBy=Assignee
955
- c8ctl list inc --processInstanceKey=123456
956
- c8ctl list inc --between=2024-06-01..2024-06-30
957
- c8ctl list inc --sortBy=Type --desc
958
- c8ctl list jobs --type=email-service
959
- c8ctl list jobs --between=2024-01-01..2024-12-31
960
- c8ctl list jobs --sortBy=Retries --asc
961
- c8ctl list profiles
962
- c8ctl list plugins
963
- c8ctl list users
964
- c8ctl list roles
965
- c8ctl list groups
966
- c8ctl list tenants
967
- c8ctl list auth
968
- c8ctl list mapping-rules
969
- `.trim());
970
- }
971
- export function showGetHelp() {
972
- console.log(`
973
- c8ctl get - Get resource by key
974
-
975
- Usage: c8ctl get <resource> <key> [flags]
976
-
977
- Resources and their available flags:
978
-
979
- process-instance (pi) <key>
980
- --variables Include variables for the process instance
981
- --profile <name> Use specific profile
982
-
983
- process-definition (pd) <key>
984
- --xml Return process definition as XML
985
- --profile <name> Use specific profile
986
-
987
- incident (inc) <key>
988
- --profile <name> Use specific profile
989
-
990
- topology
991
- --profile <name> Use specific profile
992
-
993
- form <key>
994
- --userTask, --ut (Optional) Get form for a user task only
995
- --processDefinition, --pd (Optional) Get start form for a process definition only
996
- --profile <name> Use specific profile
997
-
998
- If no flag is specified, searches both user task and process definition.
999
-
1000
- user <username>
1001
- --profile <name> Use specific profile
1002
-
1003
- role <roleId>
1004
- --profile <name> Use specific profile
1005
-
1006
- group <groupId>
1007
- --profile <name> Use specific profile
1008
-
1009
- tenant <tenantId>
1010
- --profile <name> Use specific profile
1011
-
1012
- authorization (auth) <key>
1013
- --profile <name> Use specific profile
1014
-
1015
- mapping-rule (mr) <id>
1016
- --profile <name> Use specific profile
1017
-
1018
- Examples:
1019
- c8ctl get pi 2251799813685249
1020
- c8ctl get pi 2251799813685249 --variables
1021
- c8ctl get pd 2251799813685250
1022
- c8ctl get pd 2251799813685250 --xml
1023
- c8ctl get inc 2251799813685251
1024
- c8ctl get topology
1025
- c8ctl get form 2251799813685251
1026
- c8ctl get form 2251799813685251 --ut
1027
- c8ctl get form 2251799813685252 --pd
1028
- c8ctl get user john
1029
- c8ctl get role my-role
1030
- c8ctl get group developers
1031
- c8ctl get tenant prod
1032
- c8ctl get auth 123456
1033
- c8ctl get mapping-rule abc123
1034
- `.trim());
1035
- }
1036
- /**
1037
- * Show detailed help for create command
1038
- */
1039
- export function showCreateHelp() {
1040
- console.log(`
1041
- c8ctl create - Create a resource
1042
-
1043
- Usage: c8ctl create <resource> [flags]
1044
-
1045
- Resources and their available flags:
1046
-
1047
- process-instance (pi)
1048
- --id <id> Process definition ID (required, alias: --bpmnProcessId)
1049
- --version <num> Process definition version
1050
- --variables <json> Process variables as JSON string
1051
- --awaitCompletion Wait for process instance to complete
1052
- --fetchVariables <vars> Reserved for future use (all variables returned by default)
1053
- --requestTimeout <ms> Timeout in milliseconds for process completion (use with --awaitCompletion)
1054
- --profile <name> Use specific profile
1055
-
1056
- user
1057
- --username <name> Username (required)
1058
- --name <name> Display name
1059
- --email <email> Email address
1060
- --password <pwd> Password (required)
1061
- --profile <name> Use specific profile
1062
-
1063
- role
1064
- --name <name> Role name (required)
1065
- --profile <name> Use specific profile
1066
-
1067
- group
1068
- --name <name> Group name (required)
1069
- --profile <name> Use specific profile
1070
-
1071
- tenant
1072
- --tenantId <id> Tenant ID (required)
1073
- --name <name> Tenant name (required)
1074
- --profile <name> Use specific profile
1075
-
1076
- authorization (auth)
1077
- --ownerId <id> Owner ID (required)
1078
- --ownerType <type> Owner type: USER, GROUP, ROLE, MAPPING_RULE (required)
1079
- --resourceType <type> Resource type (required)
1080
- --resourceId <id> Resource ID (required)
1081
- --permissions <perms> Comma-separated permissions: READ,CREATE,UPDATE,DELETE (required)
1082
- --profile <name> Use specific profile
1083
-
1084
- mapping-rule (mr)
1085
- --mappingRuleId <id> Mapping rule ID (required)
1086
- --name <name> Mapping rule name (required)
1087
- --claimName <name> Claim name (required)
1088
- --claimValue <value> Claim value (required)
1089
- --profile <name> Use specific profile
1090
-
1091
- Examples:
1092
- c8ctl create pi --id=order-process
1093
- c8ctl create pi --id=order-process --version=2
1094
- c8ctl create pi --id=order-process --variables='{"orderId":"12345"}'
1095
- c8ctl create pi --id=order-process --awaitCompletion
1096
- c8ctl create pi --id=order-process --awaitCompletion --requestTimeout=30000
1097
- c8ctl create user --username=john --name='John Doe' --email=john@example.com --password=secret
1098
- c8ctl create role --name=my-role
1099
- c8ctl create group --name=developers
1100
- c8ctl create tenant --tenantId=prod --name='Production'
1101
- c8ctl create auth --ownerId=john --ownerType=USER --resourceType=process-definition --resourceId='*' --permissions=READ,CREATE
1102
- c8ctl create mapping-rule --mappingRuleId=my-rule --name=my-rule --claimName=department --claimValue=engineering
1103
- `.trim());
1104
- }
1105
- /**
1106
- * Show detailed help for complete command
1107
- */
1108
- export function showCompleteHelp() {
1109
- console.log(`
1110
- c8ctl complete - Complete a resource
1111
-
1112
- Usage: c8ctl complete <resource> <key> [flags]
1113
-
1114
- Resources and their available flags:
1115
-
1116
- user-task (ut) <key>
1117
- --variables <json> Completion variables as JSON string
1118
- --profile <name> Use specific profile
1119
-
1120
- job <key>
1121
- --variables <json> Completion variables as JSON string
1122
- --profile <name> Use specific profile
1123
-
1124
- Examples:
1125
- c8ctl complete ut 2251799813685250
1126
- c8ctl complete ut 2251799813685250 --variables='{"approved":true}'
1127
- c8ctl complete job 2251799813685252 --variables='{"result":"success"}'
1128
- `.trim());
1129
- }
1130
- /**
1131
- * Show detailed help for await command
1132
- */
1133
- export function showAwaitHelp() {
1134
- console.log(`
1135
- c8ctl await - Create and await process instance completion
1136
-
1137
- Usage: c8ctl await <resource> [flags]
1138
-
1139
- Note: 'await pi' is an alias for 'create pi --awaitCompletion'
1140
-
1141
- Resources and their available flags:
1142
-
1143
- process-instance (pi)
1144
- --id <id> Process definition ID (required, alias: --bpmnProcessId)
1145
- --version <num> Process definition version
1146
- --variables <json> Process variables as JSON string
1147
- --fetchVariables <vars> Reserved for future use (all variables returned by default)
1148
- --requestTimeout <ms> Timeout in milliseconds for process completion
1149
- --profile <name> Use specific profile
1150
-
1151
- Description:
1152
- Creates a process instance and waits for it to reach a terminal state (COMPLETED, CANCELED).
1153
- Returns the full process instance with all variables when complete.
1154
- Uses the Camunda 8 API's built-in awaitCompletion parameter for reliable server-side waiting.
1155
-
1156
- Examples:
1157
- c8ctl await pi --id=order-process
1158
- c8ctl await pi --id=order-process --variables='{"orderId":"12345"}'
1159
- c8ctl await pi --id=order-process --requestTimeout=30000
1160
-
1161
- # Equivalent to:
1162
- c8ctl create pi --id=order-process --awaitCompletion
1163
- `.trim());
1164
- }
1165
- /**
1166
- * Show detailed help for mcp-proxy command
1167
- */
1168
- export function showMcpProxyHelp() {
1169
- console.log(`
1170
- c8ctl mcp-proxy - Start MCP proxy server
1171
-
1172
- Usage: c8ctl mcp-proxy [mcp-path] [flags]
1173
-
1174
- Description:
1175
- Starts a STDIO-based Model Context Protocol (MCP) proxy server that bridges
1176
- between local MCP clients (like VSCode or other AI assistants) and
1177
- remote Camunda 8 HTTP MCP servers. The proxy handles authentication by
1178
- injecting Camunda credentials from your active profile.
1179
-
1180
- Arguments:
1181
- mcp-path Path to the remote MCP endpoint (default: /mcp/cluster)
1182
-
1183
- Flags:
1184
- --profile <name> Use specific profile for authentication
1185
-
1186
- How it works:
1187
- 1. Accepts MCP requests via STDIO (standard input/output)
1188
- 2. Forwards requests to the remote Camunda 8 cluster's MCP endpoint
1189
- 3. Injects authentication headers from your c8ctl profile
1190
- 4. Returns responses back through STDIO
1191
-
1192
- Configuration:
1193
- VSCode example - add a block like the following to your mcp.json:
1194
-
1195
- {
1196
- "servers": {
1197
- "camunda-cluster": {
1198
- "type": "stdio",
1199
- "command": "npx",
1200
- "args": ["c8ctl", "mcp-proxy"]
1201
- }
495
+ const resources = def.resources;
496
+ // For "help" verb, show all verbs that have detailed help + virtual topics
497
+ if (resolvedVerb === "help") {
498
+ const helpTopics = [];
499
+ for (const [v, d] of registryEntries()) {
500
+ if (d.hasDetailedHelp)
501
+ helpTopics.push(v);
502
+ }
503
+ helpTopics.push("profiles", "profile", "plugin", "plugins");
504
+ const placeholder = deriveResourcePlaceholder(resolvedVerb, def);
505
+ console.log(`\nUsage: c8ctl ${resolvedVerb} ${placeholder}\n`);
506
+ console.log(`Available resources:\n ${helpTopics.join(", ")}`);
507
+ return;
1202
508
  }
1203
- }
1204
-
1205
- Examples:
1206
- # Start proxy with default MCP path and active profile
1207
- c8ctl mcp-proxy
1208
-
1209
- # Use specific MCP endpoint path
1210
- c8ctl mcp-proxy /api/mcp
1211
-
1212
- # Use specific profile for authentication
1213
- c8ctl mcp-proxy --profile=production
1214
-
1215
- # Combine custom path and profile
1216
- c8ctl mcp-proxy /mcp/v2 --profile=staging
1217
-
1218
- Note:
1219
- The mcp-proxy command runs in the foreground and communicates via STDIO.
1220
- It's designed to be launched by MCP clients, not run directly in a terminal.
1221
- `.trim());
1222
- }
1223
- /**
1224
- * Show detailed help for search command
1225
- */
1226
- export function showSearchHelp() {
1227
- console.log(`
1228
- c8ctl search - Search resources with filters
1229
-
1230
- Usage: c8ctl search <resource> [flags]
1231
-
1232
- Resources and their available flags:
1233
-
1234
- process-instances (pi)
1235
- --bpmnProcessId, --id <id> Filter by process definition ID
1236
- --iid <pattern> Case-insensitive --bpmnProcessId filter
1237
- --processDefinitionKey <key> Filter by process definition key
1238
- --version <num> Filter by process definition version
1239
- --state <state> Filter by state (ACTIVE, COMPLETED, etc.)
1240
- --key <key> Filter by key
1241
- --parentProcessInstanceKey <key> Filter by parent process instance key
1242
- --between <from>..<to> Filter by date range (default field: startDate)
1243
- --dateField <field> Date field for --between (startDate, endDate)
1244
- --sortBy <column> Sort by column (Key, Process ID, State, Version, Tenant ID)
1245
- --asc Sort in ascending order (default)
1246
- --desc Sort in descending order
1247
- --profile <name> Use specific profile
1248
-
1249
- process-definitions (pd)
1250
- --bpmnProcessId, --id <id> Filter by process definition ID
1251
- --iid <pattern> Case-insensitive --bpmnProcessId filter
1252
- --name <name> Filter by name
1253
- --iname <pattern> Case-insensitive --name filter
1254
- --version <num> Filter by process definition version
1255
- --key <key> Filter by key
1256
- --sortBy <column> Sort by column (Key, Process ID, Name, Version, Tenant ID)
1257
- --asc Sort in ascending order (default)
1258
- --desc Sort in descending order
1259
- --profile <name> Use specific profile
1260
-
1261
- user-tasks (ut)
1262
- --state <state> Filter by state (CREATED, COMPLETED, etc.)
1263
- --assignee <user> Filter by assignee
1264
- --iassignee <pattern> Case-insensitive --assignee filter
1265
- --processInstanceKey <key> Filter by process instance key
1266
- --processDefinitionKey <key> Filter by process definition key
1267
- --elementId <id> Filter by element ID
1268
- --between <from>..<to> Filter by date range (default field: creationDate)
1269
- --dateField <field> Date field for --between (creationDate, completionDate, followUpDate, dueDate)
1270
- --sortBy <column> Sort by column (Key, Name, State, Assignee, Process Instance, Tenant ID)
1271
- --asc Sort in ascending order (default)
1272
- --desc Sort in descending order
1273
- --profile <name> Use specific profile
1274
-
1275
- incidents (inc)
1276
- --state <state> Filter by state (ACTIVE, RESOLVED, etc.)
1277
- --processInstanceKey <key> Filter by process instance key
1278
- --processDefinitionKey <key> Filter by process definition key
1279
- --bpmnProcessId, --id <id> Filter by process definition ID
1280
- --iid <pattern> Case-insensitive --bpmnProcessId filter
1281
- --errorType <type> Filter by error type
1282
- --errorMessage <msg> Filter by error message
1283
- --ierrorMessage <pattern> Case-insensitive --errorMessage filter
1284
- --between <from>..<to> Filter by date range (field: creationTime)
1285
- --sortBy <column> Sort by column (Key, Type, Message, State, Process Instance, Tenant ID)
1286
- --asc Sort in ascending order (default)
1287
- --desc Sort in descending order
1288
- --profile <name> Use specific profile
1289
-
1290
- jobs
1291
- --state <state> Filter by state (ACTIVATABLE, ACTIVATED, etc.)
1292
- --type <type> Filter by job type
1293
- --itype <pattern> Case-insensitive --type filter
1294
- --processInstanceKey <key> Filter by process instance key
1295
- --processDefinitionKey <key> Filter by process definition key
1296
- --between <from>..<to> Filter by date range (default field: creationTime)
1297
- --dateField <field> Date field for --between (creationTime, lastUpdateTime)
1298
- --sortBy <column> Sort by column (Key, Type, State, Retries, Process Instance, Tenant ID)
1299
- --asc Sort in ascending order (default)
1300
- --desc Sort in descending order
1301
- --profile <name> Use specific profile
1302
-
1303
- variables
1304
- --name <name> Filter by variable name
1305
- --iname <pattern> Case-insensitive --name filter
1306
- --value <value> Filter by variable value
1307
- --ivalue <pattern> Case-insensitive --value filter
1308
- --processInstanceKey <key> Filter by process instance key
1309
- --scopeKey <key> Filter by scope key
1310
- --fullValue Return full variable values (default: truncated)
1311
- --sortBy <column> Sort by column (Name, Value, Process Instance, Scope Key, Tenant ID)
1312
- --asc Sort in ascending order (default)
1313
- --desc Sort in descending order
1314
- --limit <n> Maximum number of items to fetch (default: 1000000)
1315
- --profile <name> Use specific profile
1316
-
1317
- users
1318
- --username <name> Filter by username
1319
- --name <name> Filter by name
1320
- --email <email> Filter by email
1321
- --sortBy <column> Sort by column (Username, Name, Email)
1322
- --asc Sort in ascending order (default)
1323
- --desc Sort in descending order
1324
- --limit <n> Maximum number of items to fetch (default: 1000000)
1325
- --profile <name> Use specific profile
1326
-
1327
- roles
1328
- --roleId <id> Filter by role ID
1329
- --name <name> Filter by name
1330
- --sortBy <column> Sort by column (Role ID, Name, Description)
1331
- --asc Sort in ascending order (default)
1332
- --desc Sort in descending order
1333
- --limit <n> Maximum number of items to fetch (default: 1000000)
1334
- --profile <name> Use specific profile
1335
-
1336
- groups
1337
- --groupId <id> Filter by group ID
1338
- --name <name> Filter by name
1339
- --sortBy <column> Sort by column (Group ID, Name, Description)
1340
- --asc Sort in ascending order (default)
1341
- --desc Sort in descending order
1342
- --limit <n> Maximum number of items to fetch (default: 1000000)
1343
- --profile <name> Use specific profile
1344
-
1345
- tenants
1346
- --name <name> Filter by name
1347
- --tenantId <id> Filter by tenant ID
1348
- --sortBy <column> Sort by column (Tenant ID, Name, Description)
1349
- --asc Sort in ascending order (default)
1350
- --desc Sort in descending order
1351
- --limit <n> Maximum number of items to fetch (default: 1000000)
1352
- --profile <name> Use specific profile
1353
-
1354
- authorizations (auth)
1355
- --ownerId <id> Filter by owner ID
1356
- --ownerType <type> Filter by owner type
1357
- --resourceType <type> Filter by resource type
1358
- --resourceId <id> Filter by resource ID
1359
- --sortBy <column> Sort by column (Key, Owner ID, Owner Type, Resource Type, Resource ID, Permissions)
1360
- --asc Sort in ascending order (default)
1361
- --desc Sort in descending order
1362
- --limit <n> Maximum number of items to fetch (default: 1000000)
1363
- --profile <name> Use specific profile
1364
-
1365
- mapping-rules (mr)
1366
- --mappingRuleId <id> Filter by mapping rule ID
1367
- --name <name> Filter by name
1368
- --claimName <name> Filter by claim name
1369
- --claimValue <value> Filter by claim value
1370
- --sortBy <column> Sort by column (Mapping Rule ID, Name, Claim Name, Claim Value)
1371
- --asc Sort in ascending order (default)
1372
- --desc Sort in descending order
1373
- --limit <n> Maximum number of items to fetch (default: 1000000)
1374
- --profile <name> Use specific profile
1375
-
1376
- Date Range Filter:
1377
- Use --between <from>..<to> to filter results by a date range.
1378
- Dates can be short (YYYY-MM-DD) or full ISO 8601 datetimes.
1379
- Short dates: 'from' is expanded to T00:00:00.000Z, 'to' to T23:59:59.999Z.
1380
- Either end may be omitted for an open-ended range.
1381
- Use --dateField to specify which date field to filter on (default depends on resource).
1382
- Example: --between=2024-01-01..2024-12-31
1383
- Example: --between=2024-01-01T00:00:00Z..2024-06-30T23:59:59Z --dateField=endDate
1384
- Example: --between=..2024-12-31 (everything until end of 2024)
1385
- Example: --between=2024-01-01.. (everything from start of 2024)
1386
-
1387
- Wildcard Search:
1388
- Some string filters support wildcards: * (any chars) and ? (single char).
1389
- Supported: process definitions (name, bpmnProcessId), process instances (bpmnProcessId),
1390
- jobs (type), variables (name, value), users (username, name, email), groups (groupId).
1391
- Not supported (exact match only): roles, tenants, mapping-rules, authorizations.
1392
- Example: --name='*main*' matches all names containing "main".
1393
-
1394
- Case-Insensitive Search:
1395
- Prefix any string filter with 'i' for case-insensitive matching.
1396
- Wildcards (* and ?) are supported. Filtering is applied client-side.
1397
- Example: --iname='*ORDER*' matches "order", "Order", "ORDER", etc.
1398
-
1399
- Examples:
1400
- c8ctl search pi --state=ACTIVE
1401
- c8ctl search pi --bpmnProcessId=order-process
1402
- c8ctl search pi --between=2024-01-01..2024-12-31
1403
- c8ctl search pi --between=2024-01-01..2024-06-30 --dateField=endDate
1404
- c8ctl search pd --name='*main*'
1405
- c8ctl search pd --iname='*order*'
1406
- c8ctl search pd --sortBy=Name --desc
1407
- c8ctl search ut --assignee=john.doe
1408
- c8ctl search ut --iassignee=John
1409
- c8ctl search ut --between=2024-01-01..2024-03-31 --dateField=dueDate
1410
- c8ctl search ut --sortBy=State --asc
1411
- c8ctl search inc --state=ACTIVE --processInstanceKey=123456
1412
- c8ctl search inc --between=2024-06-01..2024-06-30
1413
- c8ctl search jobs --type=email-service
1414
- c8ctl search jobs --itype='*SERVICE*'
1415
- c8ctl search jobs --between=2024-01-01..2024-12-31
1416
- c8ctl search jobs --sortBy=Type --desc
1417
- c8ctl search variables --name=orderId
1418
- c8ctl search variables --value=12345 --fullValue
1419
- c8ctl search variables --sortBy=Name
1420
- c8ctl search users --name=John
1421
- c8ctl search roles --name=admin
1422
- c8ctl search groups --name=developers
1423
- c8ctl search tenants --name=Production
1424
- c8ctl search auth --ownerId=john --resourceType=process-definition
1425
- c8ctl search auth --ownerId=john --resourceId=my-resource
1426
- c8ctl search mapping-rules --claimName=department
1427
- c8ctl search mapping-rules --mappingRuleId=my-rule
1428
- `.trim());
1429
- }
1430
- /**
1431
- * Show detailed help for deploy command
1432
- */
1433
- export function showDeployHelp() {
1434
- console.log(`
1435
- c8ctl deploy - Deploy BPMN, DMN, and form files
1436
-
1437
- Usage: c8ctl deploy [path...] [flags]
1438
-
1439
- Description:
1440
- Deploy BPMN process definitions, DMN decision tables, and forms to Camunda 8.
1441
- Automatically discovers all deployable files in the specified paths.
1442
- If no path is provided, deploys from the current directory.
1443
-
1444
- Flags:
1445
- --profile <name> Use specific profile
1446
-
1447
- Supported File Types:
1448
- - BPMN files (.bpmn)
1449
- - DMN files (.dmn)
1450
- - Form files (.form)
1451
-
1452
- Building Blocks:
1453
- Folders containing '_bb-' in their name are treated as building blocks
1454
- and are deployed before regular processes.
1455
-
1456
- Examples:
1457
- c8ctl deploy Deploy all files in current directory
1458
- c8ctl deploy ./src Deploy all files in ./src directory
1459
- c8ctl deploy ./process.bpmn Deploy a specific BPMN file
1460
- c8ctl deploy ./src ./forms Deploy from multiple directories
1461
- c8ctl deploy --profile=prod Deploy using specific profile
1462
- `.trim());
1463
- }
1464
- /**
1465
- * Show detailed help for run command
1466
- */
1467
- export function showRunHelp() {
1468
- console.log(`
1469
- c8ctl run - Deploy and start a process
1470
-
1471
- Usage: c8ctl run <path> [flags]
1472
-
1473
- Description:
1474
- Deploys a BPMN file and immediately creates a process instance from it.
1475
- This is a convenience command that combines deploy and create operations.
1476
-
1477
- Flags:
1478
- --profile <name> Use specific profile
1479
- --variables <json> Process variables as JSON string
1480
-
1481
- Examples:
1482
- c8ctl run ./my-process.bpmn
1483
- c8ctl run ./my-process.bpmn --variables='{"orderId":"12345"}'
1484
- c8ctl run ./my-process.bpmn --profile=prod
1485
- `.trim());
1486
- }
1487
- /**
1488
- * Show detailed help for watch command
1489
- */
1490
- export function showWatchHelp() {
1491
- console.log(`
1492
- c8ctl watch - Watch files for changes and auto-deploy
1493
-
1494
- Usage: c8ctl watch [path...] [flags]
1495
-
1496
- Alias: w
1497
-
1498
- Description:
1499
- Watches BPMN, DMN, and form files for changes and automatically deploys them.
1500
- Useful during development for rapid iteration.
1501
- If no path is provided, watches the current directory.
1502
-
1503
- Validation errors (INVALID_ARGUMENT) are reported but do not stop the watcher,
1504
- so you can fix the file and save again. Use --force to also continue on other
1505
- errors such as network or authentication failures.
1506
-
1507
- Flags:
1508
- --profile <name> Use specific profile
1509
- --force Continue watching after all deployment errors
1510
-
1511
- Supported File Types:
1512
- - BPMN files (.bpmn)
1513
- - DMN files (.dmn)
1514
- - Form files (.form)
1515
-
1516
- Examples:
1517
- c8ctl watch Watch current directory
1518
- c8ctl watch ./src Watch ./src directory
1519
- c8ctl watch ./src ./forms Watch multiple directories
1520
- c8ctl w ./src Use short alias
1521
- c8ctl watch --profile=dev Watch using specific profile
1522
- c8ctl watch --force Keep watching after all deployment errors
1523
- `.trim());
1524
- }
1525
- /**
1526
- * Show detailed help for open command
1527
- */
1528
- export function showOpenHelp() {
1529
- console.log(`
1530
- c8ctl open - Open a Camunda web application in the browser
1531
-
1532
- Usage: c8ctl open <app> [flags]
1533
-
1534
- Applications:
1535
- operate Camunda Operate – monitor process instances and incidents
1536
- tasklist Camunda Tasklist – manage user tasks
1537
- modeler Camunda Web Modeler – design BPMN/DMN processes
1538
- optimize Camunda Optimize – process analytics
1539
-
1540
- Description:
1541
- Derives the application URL from the active profile's base URL by stripping
1542
- the API path suffix (e.g. /v2) and appending the application path.
1543
-
1544
- Example: baseUrl=http://localhost:8080/v2 → http://localhost:8080/operate
1545
-
1546
- For this command, --dry-run resolves and prints the application URL instead
1547
- of launching the browser.
1548
-
1549
- Flags:
1550
- --profile <name> Use specific profile
1551
- --dry-run Resolve and print the URL without opening the browser
1552
-
1553
- Examples:
1554
- c8ctl open operate
1555
- c8ctl open tasklist
1556
- c8ctl open modeler
1557
- c8ctl open optimize
1558
- c8ctl open operate --profile=prod
1559
- c8ctl open operate --dry-run
1560
- `.trim());
1561
- }
1562
- /**
1563
- * Show detailed help for cancel command
1564
- */
1565
- export function showCancelHelp() {
1566
- console.log(`
1567
- c8ctl cancel - Cancel a resource
1568
-
1569
- Usage: c8ctl cancel <resource> <key> [flags]
1570
-
1571
- Resources and their available flags:
1572
-
1573
- process-instance (pi) <key>
1574
- --profile <name> Use specific profile
1575
-
1576
- Examples:
1577
- c8ctl cancel pi 2251799813685249
1578
- c8ctl cancel pi 2251799813685249 --profile=prod
1579
- `.trim());
1580
- }
1581
- /**
1582
- * Show detailed help for resolve command
1583
- */
1584
- export function showResolveHelp() {
1585
- console.log(`
1586
- c8ctl resolve - Resolve an incident
1587
-
1588
- Usage: c8ctl resolve incident <key> [flags]
1589
-
1590
- Alias: inc for incident
1591
-
1592
- Description:
1593
- Resolves an incident by its key. This marks the incident as resolved
1594
- and allows the process instance to continue.
1595
-
1596
- Flags:
1597
- --profile <name> Use specific profile
1598
-
1599
- Examples:
1600
- c8ctl resolve inc 2251799813685251
1601
- c8ctl resolve incident 2251799813685251
1602
- c8ctl resolve inc 2251799813685251 --profile=prod
1603
- `.trim());
1604
- }
1605
- /**
1606
- * Show detailed help for fail command
1607
- */
1608
- export function showFailHelp() {
1609
- console.log(`
1610
- c8ctl fail - Fail a job
1611
-
1612
- Usage: c8ctl fail job <key> [flags]
1613
-
1614
- Description:
1615
- Marks a job as failed with optional error message and retry count.
1616
-
1617
- Flags:
1618
- --profile <name> Use specific profile
1619
- --retries <num> Number of retries remaining (default: 0)
1620
- --errorMessage <msg> Error message describing the failure
1621
-
1622
- Examples:
1623
- c8ctl fail job 2251799813685252
1624
- c8ctl fail job 2251799813685252 --retries=3
1625
- c8ctl fail job 2251799813685252 --errorMessage="Connection timeout"
1626
- c8ctl fail job 2251799813685252 --retries=2 --errorMessage="Temporary failure"
1627
- `.trim());
1628
- }
1629
- /**
1630
- * Show detailed help for activate command
1631
- */
1632
- export function showActivateHelp() {
1633
- console.log(`
1634
- c8ctl activate - Activate jobs by type
1635
-
1636
- Usage: c8ctl activate jobs <type> [flags]
1637
-
1638
- Description:
1639
- Activates jobs of a specific type for processing by a worker.
1640
-
1641
- Flags:
1642
- --profile <name> Use specific profile
1643
- --maxJobsToActivate <num> Maximum number of jobs to activate (default: 10)
1644
- --timeout <ms> Job lock timeout in milliseconds (default: 60000)
1645
- --worker <name> Worker name (default: "c8ctl")
1646
-
1647
- Examples:
1648
- c8ctl activate jobs email-service
1649
- c8ctl activate jobs payment-processor --maxJobsToActivate=5
1650
- c8ctl activate jobs data-sync --timeout=120000 --worker=my-worker
1651
- c8ctl activate jobs batch-job --maxJobsToActivate=100 --profile=prod
1652
- `.trim());
1653
- }
1654
- /**
1655
- * Show detailed help for publish command
1656
- */
1657
- export function showPublishHelp() {
1658
- console.log(`
1659
- c8ctl publish - Publish a message
1660
-
1661
- Usage: c8ctl publish message <name> [flags]
1662
-
1663
- Alias: msg for message
1664
-
1665
- Description:
1666
- Publishes a message to Camunda 8 for message correlation.
1667
-
1668
- Flags:
1669
- --profile <name> Use specific profile
1670
- --correlationKey <key> Correlation key for the message
1671
- --variables <json> Message variables as JSON string
1672
- --timeToLive <ms> Message time-to-live in milliseconds
1673
-
1674
- Examples:
1675
- c8ctl publish msg payment-received
1676
- c8ctl publish message order-confirmed --correlationKey=order-123
1677
- c8ctl publish msg invoice-paid --variables='{"amount":1000}'
1678
- c8ctl publish msg notification --correlationKey=user-456 --timeToLive=30000
1679
- `.trim());
1680
- }
1681
- /**
1682
- * Show detailed help for correlate command
1683
- */
1684
- export function showCorrelateHelp() {
1685
- console.log(`
1686
- c8ctl correlate - Correlate a message
1687
-
1688
- Usage: c8ctl correlate message <name> [flags]
1689
-
1690
- Alias: msg for message
1691
-
1692
- Description:
1693
- Correlates a message to a specific process instance.
1694
-
1695
- Flags:
1696
- --profile <name> Use specific profile
1697
- --correlationKey <key> Correlation key for the message (required)
1698
- --variables <json> Message variables as JSON string
1699
- --timeToLive <ms> Message time-to-live in milliseconds
1700
-
1701
- Examples:
1702
- c8ctl correlate msg payment-received --correlationKey=order-123
1703
- c8ctl correlate message order-confirmed --correlationKey=order-456 --variables='{"status":"confirmed"}'
1704
- c8ctl correlate msg invoice-paid --correlationKey=inv-789 --timeToLive=60000
1705
- `.trim());
1706
- }
1707
- /**
1708
- * Show detailed help for profile management
1709
- */
1710
- export function showProfilesHelp() {
1711
- console.log(`
1712
- c8ctl profiles - Profile management
1713
-
1714
- Usage: c8ctl <command> profile[s] [args] [flags]
1715
-
1716
- Profile commands:
1717
-
1718
- list profiles
1719
- List all profiles (c8ctl + Camunda Modeler profiles).
1720
- Modeler profiles are shown with "modeler:" prefix.
1721
- The currently active profile is marked with "*".
1722
-
1723
- which profile
1724
- Show the name of the currently active profile.
1725
-
1726
- add profile <name> [flags]
1727
- Add a c8ctl-managed profile.
1728
-
1729
- remove profile <name>
1730
- rm profile <name>
1731
- Remove a c8ctl-managed profile.
1732
-
1733
- use profile <name>
1734
- Set active profile for the current session.
1735
-
1736
- use profile --none
1737
- Clear the active session profile so env vars take effect.
1738
-
1739
- Connection resolution order (highest to lowest priority):
1740
- 1. --profile <name> flag on the current command
1741
- 2. Active session profile (set with: c8ctl use profile <name>)
1742
- ⚠ Warns if CAMUNDA_* env vars are also present
1743
- 3. Environment variables (CAMUNDA_BASE_URL, CAMUNDA_CLIENT_ID, …)
1744
- 4. Default 'local' profile from profiles.json
1745
-
1746
- Default profile: "local"
1747
- c8ctl ships with a built-in 'local' profile (http://localhost:8080/v2, demo/demo).
1748
- It is created automatically in profiles.json on first use.
1749
- Override it: c8ctl add profile local --baseUrl <url>
1750
-
1751
- Flags for add profile:
1752
- Required for all add profile calls:
1753
- (none)
1754
-
1755
- Required for OAuth-secured clusters:
1756
- --clientId <id> OAuth client ID
1757
- --clientSecret <secret> OAuth client secret
1758
-
1759
- Optional (with defaults):
1760
- --baseUrl <url> Cluster base URL (default: http://localhost:8080/v2)
1761
- --defaultTenantId <id> Default tenant ID (default at runtime: <default>)
1762
-
1763
- Optional (no c8ctl default):
1764
- --audience <audience> OAuth audience
1765
- --oAuthUrl <url> OAuth token endpoint
1766
-
1767
- Import from file or environment:
1768
- --from-file <path> Create profile from a .env file containing CAMUNDA_* vars
1769
- --from-env Create profile from current CAMUNDA_* environment variables
1770
-
1771
- Examples:
1772
- c8ctl list profiles
1773
- c8ctl which profile
1774
- c8ctl add profile local --baseUrl=http://localhost:8080/v2
1775
- c8ctl add profile prod --baseUrl=https://camunda.example.com --clientId=xxx --clientSecret=yyy
1776
- c8ctl add profile staging --from-file .env.staging
1777
- c8ctl add profile ci --from-env
1778
- c8ctl use profile prod
1779
- c8ctl use profile "modeler:Local Dev"
1780
- c8ctl use profile --none
1781
- c8ctl remove profile local
1782
- `.trim());
1783
- }
1784
- /**
1785
- * Show detailed help for plugin management
1786
- */
1787
- export function showPluginHelp() {
1788
- console.log(`
1789
- c8ctl plugin - Plugin management
1790
-
1791
- Usage: c8ctl <command> plugin [args] [flags]
1792
-
1793
- Plugin commands:
1794
-
1795
- load plugin <name>
1796
- Load a plugin from npm registry.
1797
-
1798
- load plugin --from <url>
1799
- Load a plugin from URL source (file://, https://, git://, github:).
1800
-
1801
- unload plugin <name>
1802
- Unload and unregister a plugin.
1803
-
1804
- unload plugin <name> --force
1805
- Force-remove a plugin that is installed but not in the registry (limbo state).
1806
-
1807
- list plugins
1808
- List installed plugins with version and sync status.
1809
-
1810
- sync plugins
1811
- Rebuild/reinstall plugins from registry.
1812
-
1813
- upgrade plugin <name> [version]
1814
- Upgrade plugin source.
1815
- - without version: reinstalls registered source as-is
1816
- - npm source with version: installs <name>@<version>
1817
- - URL/git source with version: installs <source>#<version>
1818
- - file:// source with version: not supported, use load plugin --from
1819
-
1820
- downgrade plugin <name> <version>
1821
- Downgrade plugin source.
1822
- - npm source: installs <name>@<version>
1823
- - URL/git source: installs <source>#<version>
1824
- - file:// source: not supported, use load plugin --from
1825
-
1826
- init plugin [name]
1827
- Create a new plugin scaffold from template.
1828
- Default name: c8ctl-plugin-myplugin
1829
-
1830
- Convention over configuration: the directory is always prefixed with
1831
- "c8ctl-plugin-". The plugin is registered by the suffix after the prefix.
1832
- Example: "c8ctl init plugin foo" creates directory "c8ctl-plugin-foo"
1833
- and registers plugin name "foo". Likewise, "c8ctl init plugin
1834
- c8ctl-plugin-foo" produces the same result.
1835
-
1836
- Examples:
1837
- c8ctl load plugin my-plugin
1838
- c8ctl load plugin --from https://github.com/org/plugin
1839
- c8ctl load plugin --from file:///path/to/plugin
1840
- c8ctl list plugins
1841
- c8ctl unload plugin my-plugin
1842
- c8ctl unload plugin my-plugin --force
1843
- c8ctl upgrade plugin my-plugin
1844
- c8ctl upgrade plugin my-plugin 1.2.3
1845
- c8ctl downgrade plugin my-plugin 1.0.0
1846
- c8ctl init plugin my-plugin
1847
- `.trim());
1848
- }
1849
- /**
1850
- * Show detailed help for delete command
1851
- */
1852
- export function showDeleteHelp() {
1853
- console.log(`
1854
- c8ctl delete - Delete a resource
1855
-
1856
- Usage: c8ctl delete <resource> <id> [flags]
1857
-
1858
- Resources and their available flags:
1859
-
1860
- user <username>
1861
- --profile <name> Use specific profile
1862
-
1863
- role <roleId>
1864
- --profile <name> Use specific profile
1865
-
1866
- group <groupId>
1867
- --profile <name> Use specific profile
1868
-
1869
- tenant <tenantId>
1870
- --profile <name> Use specific profile
1871
-
1872
- authorization (auth) <key>
1873
- --profile <name> Use specific profile
1874
-
1875
- mapping-rule (mr) <id>
1876
- --profile <name> Use specific profile
1877
-
1878
- Examples:
1879
- c8ctl delete user john
1880
- c8ctl delete role my-role
1881
- c8ctl delete group developers
1882
- c8ctl delete tenant prod
1883
- c8ctl delete auth 123456
1884
- c8ctl delete mapping-rule abc123
1885
- `.trim());
509
+ if (resources.length === 0 && !def.requiresResource) {
510
+ const placeholder = deriveResourcePlaceholder(resolvedVerb, def);
511
+ console.log(`\nUsage: c8ctl ${resolvedVerb} ${placeholder}\n`);
512
+ console.log(`Argument:\n ${placeholder || "(none)"}`);
513
+ return;
514
+ }
515
+ const displayNames = resources.map((r) => resourceDisplayName(r));
516
+ const placeholder = deriveResourcePlaceholder(resolvedVerb, def);
517
+ console.log(`\nUsage: c8ctl ${resolvedVerb} ${placeholder}\n`);
518
+ console.log(`Available resources:\n ${displayNames.join(", ")}`);
1886
519
  }
1887
520
  /**
1888
- * Show detailed help for assign command
521
+ * Show detailed help for a verb, derived entirely from COMMAND_REGISTRY.
522
+ * Renders: title, usage, aliases, per-resource flags, verb-level flags.
1889
523
  */
1890
- export function showAssignHelp() {
1891
- console.log(`
1892
- c8ctl assign - Assign a resource to a target
1893
-
1894
- Usage: c8ctl assign <resource> <id> --to-<target>=<targetId> [flags]
1895
-
1896
- Resources:
1897
-
1898
- role <roleId>
1899
- --to-user <username> Assign role to user
1900
- --to-group <groupId> Assign role to group
1901
- --to-tenant <tenantId> Assign role to tenant
1902
- --to-mapping-rule <id> Assign role to mapping rule
1903
- --profile <name> Use specific profile
1904
-
1905
- user <username>
1906
- --to-group <groupId> Assign user to group
1907
- --to-tenant <tenantId> Assign user to tenant
1908
- --profile <name> Use specific profile
1909
-
1910
- group <groupId>
1911
- --to-tenant <tenantId> Assign group to tenant
1912
- --profile <name> Use specific profile
1913
-
1914
- mapping-rule <id>
1915
- --to-group <groupId> Assign mapping rule to group
1916
- --to-tenant <tenantId> Assign mapping rule to tenant
1917
- --profile <name> Use specific profile
1918
-
1919
- Examples:
1920
- c8ctl assign role admin --to-user=john
1921
- c8ctl assign role admin --to-group=developers
1922
- c8ctl assign user john --to-group=developers
1923
- c8ctl assign user john --to-tenant=prod
1924
- c8ctl assign group developers --to-tenant=prod
1925
- c8ctl assign mapping-rule my-rule --to-group=developers
1926
- `.trim());
524
+ function showGenericVerbHelp(verb) {
525
+ const def = lookupVerb(verb);
526
+ if (!def) {
527
+ console.log(`\nNo detailed help available for: ${verb}`);
528
+ console.log('Run "c8ctl help" for general usage information.');
529
+ return;
530
+ }
531
+ const lines = [];
532
+ const FLAG_COL = 32;
533
+ // Title
534
+ lines.push(`c8ctl ${verb} - ${def.helpDescription ?? def.description}`);
535
+ lines.push("");
536
+ // Usage
537
+ const resource = deriveResourcePlaceholder(verb, def);
538
+ lines.push(`Usage: c8ctl ${verb} ${resource} [flags]`.trim());
539
+ // Aliases
540
+ if (def.aliases?.length) {
541
+ lines.push("");
542
+ lines.push(`Alias: ${def.aliases.join(", ")}`);
543
+ }
544
+ // Per-resource sections (when resourceFlags exist)
545
+ if (def.resourceFlags && Object.keys(def.resourceFlags).length > 0) {
546
+ lines.push("");
547
+ lines.push("Resources and their available flags:");
548
+ for (const res of def.resources) {
549
+ const canonical = RESOURCE_ALIASES[res] ?? res;
550
+ const displayName = resourceDisplayName(res);
551
+ // Positionals for this resource
552
+ const positionals = def.resourcePositionals?.[canonical];
553
+ const posStr = positionals
554
+ ? ` ${positionals.map((p) => (p.required ? `<${p.name}>` : `[${p.name}]`)).join(" ")}`
555
+ : "";
556
+ lines.push("");
557
+ lines.push(` ${displayName}${posStr}`);
558
+ // Resource-specific flags
559
+ const resFlags = def.resourceFlags[canonical];
560
+ if (resFlags) {
561
+ for (const [name, flagDef] of flagEntries(resFlags)) {
562
+ lines.push(formatFlag(name, flagDef, FLAG_COL));
563
+ }
564
+ }
565
+ // SEARCH_FLAGS for list/search commands
566
+ if (verb === "list" || verb === "search") {
567
+ for (const [name, flagDef] of flagEntries(SEARCH_FLAGS)) {
568
+ lines.push(formatFlag(name, flagDef, FLAG_COL));
569
+ }
570
+ }
571
+ // --profile always applicable
572
+ lines.push(formatFlag("profile", { type: "string", description: "Use specific profile" }, FLAG_COL));
573
+ }
574
+ }
575
+ else if (def.resources.length > 0) {
576
+ // Simple resource list with positionals (no per-resource flags)
577
+ lines.push("");
578
+ lines.push("Resources:");
579
+ for (const res of def.resources) {
580
+ const canonical = RESOURCE_ALIASES[res] ?? res;
581
+ const displayName = resourceDisplayName(res);
582
+ const positionals = def.resourcePositionals?.[canonical];
583
+ const posStr = positionals
584
+ ? ` ${positionals.map((p) => (p.required ? `<${p.name}>` : `[${p.name}]`)).join(" ")}`
585
+ : "";
586
+ lines.push(` ${displayName}${posStr}`);
587
+ }
588
+ }
589
+ // Verb-level flags (excluding search flags already shown per-resource)
590
+ const verbFlags = Object.entries(def.flags).filter(([name]) => !(name in SEARCH_FLAGS));
591
+ if (verbFlags.length > 0) {
592
+ lines.push("");
593
+ lines.push("Flags:");
594
+ for (const [name, flagDef] of verbFlags) {
595
+ lines.push(formatFlag(name, flagDef, FLAG_COL));
596
+ }
597
+ // Add --profile if not already shown via resourceFlags
598
+ if (!def.resourceFlags || Object.keys(def.resourceFlags).length === 0) {
599
+ lines.push(formatFlag("profile", { type: "string", description: "Use specific profile" }, FLAG_COL));
600
+ }
601
+ }
602
+ else if (!def.resourceFlags ||
603
+ Object.keys(def.resourceFlags).length === 0) {
604
+ // No verb flags and no resource flags — still show --profile
605
+ lines.push("");
606
+ lines.push("Flags:");
607
+ lines.push(formatFlag("profile", { type: "string", description: "Use specific profile" }, FLAG_COL));
608
+ }
609
+ console.log(`\n${lines.join("\n")}`);
1927
610
  }
1928
611
  /**
1929
- * Show detailed help for unassign command
612
+ * Show help for a "virtual topic" that spans multiple verbs.
613
+ * Collects all verbs that operate on the given resource.
1930
614
  */
1931
- export function showUnassignHelp() {
1932
- console.log(`
1933
- c8ctl unassign - Unassign a resource from a target
1934
-
1935
- Usage: c8ctl unassign <resource> <id> --from-<target>=<targetId> [flags]
1936
-
1937
- Resources:
1938
-
1939
- role <roleId>
1940
- --from-user <username> Unassign role from user
1941
- --from-group <groupId> Unassign role from group
1942
- --from-tenant <tenantId> Unassign role from tenant
1943
- --from-mapping-rule <id> Unassign role from mapping rule
1944
- --profile <name> Use specific profile
1945
-
1946
- user <username>
1947
- --from-group <groupId> Unassign user from group
1948
- --from-tenant <tenantId> Unassign user from tenant
1949
- --profile <name> Use specific profile
1950
-
1951
- group <groupId>
1952
- --from-tenant <tenantId> Unassign group from tenant
1953
- --profile <name> Use specific profile
1954
-
1955
- mapping-rule <id>
1956
- --from-group <groupId> Unassign mapping rule from group
1957
- --from-tenant <tenantId> Unassign mapping rule from tenant
1958
- --profile <name> Use specific profile
1959
-
1960
- Examples:
1961
- c8ctl unassign role admin --from-user=john
1962
- c8ctl unassign role admin --from-group=developers
1963
- c8ctl unassign user john --from-group=developers
1964
- c8ctl unassign group developers --from-tenant=prod
1965
- c8ctl unassign mapping-rule my-rule --from-group=developers
1966
- `.trim());
615
+ function showVirtualTopicHelp(topic, resource) {
616
+ const lines = [];
617
+ const FLAG_COL = 32;
618
+ lines.push(`c8ctl ${topic} - ${topic.charAt(0).toUpperCase() + topic.slice(1)} management`);
619
+ lines.push("");
620
+ lines.push(`Usage: c8ctl <command> ${resource} [args] [flags]`);
621
+ lines.push("");
622
+ // Find all verbs that operate on this resource
623
+ for (const [verb, def] of registryEntries()) {
624
+ const canonical = RESOURCE_ALIASES[resource] ?? resource;
625
+ if (!def.resources.some((r) => (RESOURCE_ALIASES[r] ?? r) === canonical))
626
+ continue;
627
+ const positionals = def.resourcePositionals?.[canonical];
628
+ const posStr = positionals
629
+ ? ` ${positionals.map((p) => (p.required ? `<${p.name}>` : `[${p.name}]`)).join(" ")}`
630
+ : "";
631
+ lines.push(` ${verb} ${resource}${posStr}`);
632
+ lines.push(` ${def.description}`);
633
+ // Show flags for this verb (filtered to resource-specific or verb-level)
634
+ const resFlags = def.resourceFlags?.[canonical];
635
+ if (resFlags) {
636
+ for (const [name, flagDef] of flagEntries(resFlags)) {
637
+ lines.push(formatFlag(name, flagDef, FLAG_COL));
638
+ }
639
+ }
640
+ for (const [name, flagDef] of flagEntries(def.flags)) {
641
+ lines.push(formatFlag(name, flagDef, FLAG_COL));
642
+ }
643
+ lines.push("");
644
+ }
645
+ console.log(`\n${lines.join("\n").trimEnd()}`);
1967
646
  }
1968
647
  /**
1969
- * Show detailed help for specific commands
648
+ * Show detailed help for a specific command.
649
+ * Dispatches to the generic renderer for all verbs.
1970
650
  */
1971
651
  export function showCommandHelp(command) {
1972
652
  const logger = getLogger();
@@ -1988,79 +668,25 @@ export function showCommandHelp(command) {
1988
668
  });
1989
669
  return;
1990
670
  }
1991
- switch (command) {
1992
- case "list":
1993
- showListHelp();
1994
- break;
1995
- case "get":
1996
- showGetHelp();
1997
- break;
1998
- case "create":
1999
- showCreateHelp();
2000
- break;
2001
- case "complete":
2002
- showCompleteHelp();
2003
- break;
2004
- case "await":
2005
- showAwaitHelp();
2006
- break;
2007
- case "mcp-proxy":
2008
- showMcpProxyHelp();
2009
- break;
2010
- case "search":
2011
- showSearchHelp();
2012
- break;
2013
- case "deploy":
2014
- showDeployHelp();
2015
- break;
2016
- case "run":
2017
- showRunHelp();
2018
- break;
2019
- case "watch":
2020
- case "w":
2021
- showWatchHelp();
2022
- break;
2023
- case "open":
2024
- showOpenHelp();
2025
- break;
2026
- case "cancel":
2027
- showCancelHelp();
2028
- break;
2029
- case "resolve":
2030
- showResolveHelp();
2031
- break;
2032
- case "fail":
2033
- showFailHelp();
2034
- break;
2035
- case "activate":
2036
- showActivateHelp();
2037
- break;
2038
- case "publish":
2039
- showPublishHelp();
2040
- break;
2041
- case "correlate":
2042
- showCorrelateHelp();
2043
- break;
2044
- case "delete":
2045
- showDeleteHelp();
2046
- break;
2047
- case "assign":
2048
- showAssignHelp();
2049
- break;
2050
- case "unassign":
2051
- showUnassignHelp();
2052
- break;
2053
- case "profiles":
2054
- case "profile":
2055
- showProfilesHelp();
2056
- break;
2057
- case "plugin":
2058
- case "plugins":
2059
- showPluginHelp();
2060
- break;
2061
- default:
2062
- console.log(`\nNo detailed help available for: ${command}`);
2063
- console.log('Run "c8ctl help" for general usage information.');
671
+ // Virtual help topics that span multiple verbs
672
+ if (command === "profiles" || command === "profile") {
673
+ showVirtualTopicHelp("profiles", "profile");
674
+ return;
675
+ }
676
+ if (command === "plugin" || command === "plugins") {
677
+ showVirtualTopicHelp("plugin", "plugin");
678
+ return;
679
+ }
680
+ // Resolve verb aliases (e.g. "w" → "watch")
681
+ let resolvedVerb = command;
682
+ if (!lookupVerb(command)) {
683
+ for (const [v, d] of registryEntries()) {
684
+ if (d.aliases?.includes(command)) {
685
+ resolvedVerb = v;
686
+ break;
687
+ }
688
+ }
2064
689
  }
690
+ showGenericVerbHelp(resolvedVerb);
2065
691
  }
2066
692
  //# sourceMappingURL=help.js.map