@camunda8/cli 1.1.0 → 2.0.0-alpha.10

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 (47) hide show
  1. package/README.md +98 -39
  2. package/dist/client.d.ts.map +1 -1
  3. package/dist/client.js +1 -1
  4. package/dist/client.js.map +1 -1
  5. package/dist/commands/completion.d.ts.map +1 -1
  6. package/dist/commands/completion.js +108 -9
  7. package/dist/commands/completion.js.map +1 -1
  8. package/dist/commands/deployments.d.ts.map +1 -1
  9. package/dist/commands/deployments.js +289 -49
  10. package/dist/commands/deployments.js.map +1 -1
  11. package/dist/commands/forms.d.ts +26 -0
  12. package/dist/commands/forms.d.ts.map +1 -0
  13. package/dist/commands/forms.js +125 -0
  14. package/dist/commands/forms.js.map +1 -0
  15. package/dist/commands/help.d.ts +24 -0
  16. package/dist/commands/help.d.ts.map +1 -1
  17. package/dist/commands/help.js +238 -9
  18. package/dist/commands/help.js.map +1 -1
  19. package/dist/commands/incidents.d.ts +6 -0
  20. package/dist/commands/incidents.d.ts.map +1 -1
  21. package/dist/commands/incidents.js +15 -0
  22. package/dist/commands/incidents.js.map +1 -1
  23. package/dist/commands/plugins.d.ts +5 -0
  24. package/dist/commands/plugins.d.ts.map +1 -1
  25. package/dist/commands/plugins.js +190 -23
  26. package/dist/commands/plugins.js.map +1 -1
  27. package/dist/commands/process-instances.d.ts +12 -2
  28. package/dist/commands/process-instances.d.ts.map +1 -1
  29. package/dist/commands/process-instances.js +55 -4
  30. package/dist/commands/process-instances.js.map +1 -1
  31. package/dist/commands/profiles.d.ts +17 -8
  32. package/dist/commands/profiles.d.ts.map +1 -1
  33. package/dist/commands/profiles.js +74 -35
  34. package/dist/commands/profiles.js.map +1 -1
  35. package/dist/commands/session.js +3 -3
  36. package/dist/commands/session.js.map +1 -1
  37. package/dist/config.d.ts +104 -49
  38. package/dist/config.d.ts.map +1 -1
  39. package/dist/config.js +306 -165
  40. package/dist/config.js.map +1 -1
  41. package/dist/index.js +100 -16
  42. package/dist/index.js.map +1 -1
  43. package/dist/plugin-registry.d.ts +45 -0
  44. package/dist/plugin-registry.d.ts.map +1 -0
  45. package/dist/plugin-registry.js +101 -0
  46. package/dist/plugin-registry.js.map +1 -0
  47. package/package.json +1 -1
package/dist/config.js CHANGED
@@ -1,16 +1,107 @@
1
1
  /**
2
2
  * Configuration and session state management for c8ctl
3
- * Handles profiles, session state, and credential resolution
3
+ *
4
+ * c8ctl stores its own profiles in DATA_DIR/c8ctl/profiles.json
5
+ * Modeler connections are read from settings.json (read-only) with "modeler:" prefix
4
6
  */
5
7
  import { homedir, platform } from 'node:os';
6
8
  import { join } from 'node:path';
7
9
  import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';
8
10
  import { c8ctl } from "./runtime.js";
11
+ // ============================================================================
12
+ // Constants - matching Camunda Modeler exactly
13
+ // ============================================================================
14
+ export const TARGET_TYPES = {
15
+ CAMUNDA_CLOUD: 'camundaCloud',
16
+ SELF_HOSTED: 'selfHosted',
17
+ };
18
+ export const AUTH_TYPES = {
19
+ NONE: 'none',
20
+ BASIC: 'basic',
21
+ OAUTH: 'oauth',
22
+ };
23
+ // ============================================================================
24
+ // Validation - matching Camunda Modeler's validation rules
25
+ // ============================================================================
26
+ const VALIDATION_PATTERNS = {
27
+ URL: /^https?:\/\//,
28
+ CAMUNDA_CLOUD_REST_URL: /^https:\/\/[a-z]+-\d+\.zeebe\.camunda\.io(:443|)\/[a-z\d-]+\/?$/,
29
+ };
30
+ // Cloud URLs must be REST URLs (HTTP-based)
31
+ const CAMUNDA_CLOUD_URL_PATTERN = VALIDATION_PATTERNS.CAMUNDA_CLOUD_REST_URL;
32
+ /**
33
+ * Validate a connection configuration
34
+ * Returns array of error messages (empty if valid)
35
+ */
36
+ export function validateConnection(conn) {
37
+ const errors = [];
38
+ if (!conn) {
39
+ errors.push('Connection configuration is required');
40
+ return errors;
41
+ }
42
+ if (!conn.id) {
43
+ errors.push('Connection must have an ID');
44
+ }
45
+ if (!conn.targetType) {
46
+ errors.push('Target type is required (camundaCloud or selfHosted)');
47
+ return errors;
48
+ }
49
+ if (conn.targetType === TARGET_TYPES.CAMUNDA_CLOUD) {
50
+ if (!conn.camundaCloudClusterUrl) {
51
+ errors.push('Cluster URL is required for Camunda Cloud');
52
+ }
53
+ else if (!CAMUNDA_CLOUD_URL_PATTERN.test(conn.camundaCloudClusterUrl)) {
54
+ errors.push('Cluster URL must be a valid Camunda 8 SaaS URL');
55
+ }
56
+ if (!conn.camundaCloudClientId) {
57
+ errors.push('Client ID is required for Camunda Cloud');
58
+ }
59
+ if (!conn.camundaCloudClientSecret) {
60
+ errors.push('Client Secret is required for Camunda Cloud');
61
+ }
62
+ }
63
+ else if (conn.targetType === TARGET_TYPES.SELF_HOSTED) {
64
+ if (!conn.contactPoint) {
65
+ errors.push('Cluster URL (contactPoint) is required for Self-Hosted');
66
+ }
67
+ else if (!VALIDATION_PATTERNS.URL.test(conn.contactPoint)) {
68
+ errors.push('Cluster URL must start with http:// or https://');
69
+ }
70
+ if (conn.authType === AUTH_TYPES.BASIC) {
71
+ if (!conn.basicAuthUsername) {
72
+ errors.push('Username is required for Basic authentication');
73
+ }
74
+ if (!conn.basicAuthPassword) {
75
+ errors.push('Password is required for Basic authentication');
76
+ }
77
+ }
78
+ else if (conn.authType === AUTH_TYPES.OAUTH) {
79
+ if (!conn.clientId) {
80
+ errors.push('Client ID is required for OAuth authentication');
81
+ }
82
+ if (!conn.clientSecret) {
83
+ errors.push('Client Secret is required for OAuth authentication');
84
+ }
85
+ if (!conn.oauthURL) {
86
+ errors.push('OAuth URL is required for OAuth authentication');
87
+ }
88
+ if (!conn.audience) {
89
+ errors.push('Audience is required for OAuth authentication');
90
+ }
91
+ }
92
+ }
93
+ else {
94
+ errors.push(`Unknown target type: ${conn.targetType}`);
95
+ }
96
+ return errors;
97
+ }
98
+ // ============================================================================
99
+ // Directory and Path Utilities
100
+ // ============================================================================
9
101
  /**
10
- * Get platform-specific user data directory
102
+ * Get platform-specific user data directory for c8ctl
11
103
  */
12
104
  export function getUserDataDir() {
13
- // Allow override for testing
14
105
  if (process.env.C8CTL_DATA_DIR) {
15
106
  return process.env.C8CTL_DATA_DIR;
16
107
  }
@@ -21,14 +112,19 @@ export function getUserDataDir() {
21
112
  return join(process.env.APPDATA || join(home, 'AppData', 'Roaming'), 'c8ctl');
22
113
  case 'darwin':
23
114
  return join(home, 'Library', 'Application Support', 'c8ctl');
24
- default: // linux and others
25
- return join(process.env.XDG_DATA_HOME || join(home, '.local', 'share'), 'c8ctl');
115
+ default:
116
+ return join(process.env.XDG_CONFIG_HOME || join(home, '.config'), 'c8ctl');
26
117
  }
27
118
  }
28
119
  /**
29
120
  * Get platform-specific Camunda Modeler data directory
121
+ * Modeler stores connections in settings.json
30
122
  */
31
123
  export function getModelerDataDir() {
124
+ // Allow override for testing
125
+ if (process.env.C8CTL_MODELER_DIR) {
126
+ return process.env.C8CTL_MODELER_DIR;
127
+ }
32
128
  const plat = platform();
33
129
  const home = homedir();
34
130
  switch (plat) {
@@ -36,13 +132,10 @@ export function getModelerDataDir() {
36
132
  return join(process.env.APPDATA || join(home, 'AppData', 'Roaming'), 'camunda-modeler');
37
133
  case 'darwin':
38
134
  return join(home, 'Library', 'Application Support', 'camunda-modeler');
39
- default: // linux and others
135
+ default:
40
136
  return join(process.env.XDG_CONFIG_HOME || join(home, '.config'), 'camunda-modeler');
41
137
  }
42
138
  }
43
- /**
44
- * Ensure user data directory exists
45
- */
46
139
  function ensureUserDataDir() {
47
140
  const dir = getUserDataDir();
48
141
  if (!existsSync(dir)) {
@@ -50,63 +143,53 @@ function ensureUserDataDir() {
50
143
  }
51
144
  return dir;
52
145
  }
53
- /**
54
- * Get profiles file path
55
- */
146
+ function getSessionStatePath() {
147
+ return join(ensureUserDataDir(), 'session.json');
148
+ }
56
149
  function getProfilesPath() {
57
150
  return join(ensureUserDataDir(), 'profiles.json');
58
151
  }
59
- /**
60
- * Get session state file path
61
- */
62
- function getSessionStatePath() {
63
- return join(ensureUserDataDir(), 'session.json');
152
+ function getModelerSettingsPath() {
153
+ return join(getModelerDataDir(), 'settings.json');
64
154
  }
65
155
  /**
66
- * Load all profiles
156
+ * Load c8ctl profiles from profiles.json
67
157
  */
68
158
  export function loadProfiles() {
69
- const path = getProfilesPath();
70
- if (!existsSync(path)) {
159
+ const profilesPath = getProfilesPath();
160
+ if (!existsSync(profilesPath)) {
71
161
  return [];
72
162
  }
73
163
  try {
74
- const data = readFileSync(path, 'utf-8');
75
- return JSON.parse(data);
164
+ const data = readFileSync(profilesPath, 'utf-8');
165
+ const profilesFile = JSON.parse(data);
166
+ return profilesFile.profiles || [];
76
167
  }
77
- catch (error) {
168
+ catch {
78
169
  return [];
79
170
  }
80
171
  }
81
172
  /**
82
- * Save profiles to disk
173
+ * Save c8ctl profiles to profiles.json
83
174
  */
84
175
  export function saveProfiles(profiles) {
85
- const path = getProfilesPath();
86
- writeFileSync(path, JSON.stringify(profiles, null, 2), 'utf-8');
176
+ const profilesPath = getProfilesPath();
177
+ const profilesFile = { profiles };
178
+ writeFileSync(profilesPath, JSON.stringify(profilesFile, null, 2), 'utf-8');
87
179
  }
88
180
  /**
89
- * Get a profile by name
90
- * Supports both c8ctl profiles and modeler profiles (with 'modeler:' prefix)
181
+ * Get a c8ctl profile by name
91
182
  */
92
183
  export function getProfile(name) {
93
- // Check if this is a modeler profile request
94
- if (name.startsWith('modeler:')) {
95
- const modelerProfile = getModelerProfile(name);
96
- if (modelerProfile) {
97
- return convertModelerProfile(modelerProfile);
98
- }
99
- return undefined;
100
- }
101
- // Check c8ctl profiles
102
184
  const profiles = loadProfiles();
103
185
  return profiles.find(p => p.name === name);
104
186
  }
105
187
  /**
106
- * Add or update a profile
188
+ * Add a c8ctl profile
107
189
  */
108
190
  export function addProfile(profile) {
109
191
  const profiles = loadProfiles();
192
+ // Check if profile already exists
110
193
  const existingIndex = profiles.findIndex(p => p.name === profile.name);
111
194
  if (existingIndex >= 0) {
112
195
  profiles[existingIndex] = profile;
@@ -117,25 +200,192 @@ export function addProfile(profile) {
117
200
  saveProfiles(profiles);
118
201
  }
119
202
  /**
120
- * Remove a profile
203
+ * Remove a c8ctl profile by name
121
204
  */
122
205
  export function removeProfile(name) {
123
206
  const profiles = loadProfiles();
124
207
  const filtered = profiles.filter(p => p.name !== name);
125
208
  if (filtered.length === profiles.length) {
126
- return false; // Profile not found
209
+ return false;
127
210
  }
128
211
  saveProfiles(filtered);
129
212
  return true;
130
213
  }
214
+ // ============================================================================
215
+ // Modeler Connection Management - READ-ONLY from settings.json
216
+ // ============================================================================
217
+ export const MODELER_PREFIX = 'modeler:';
218
+ /**
219
+ * Load connections from Modeler's settings.json (read-only)
220
+ * These are NOT modified by c8ctl
221
+ */
222
+ export function loadModelerConnections() {
223
+ const settingsPath = getModelerSettingsPath();
224
+ if (!existsSync(settingsPath)) {
225
+ return [];
226
+ }
227
+ try {
228
+ const data = readFileSync(settingsPath, 'utf-8');
229
+ const settings = JSON.parse(data);
230
+ const connections = settings['connectionManagerPlugin.c8connections'];
231
+ if (!connections || !Array.isArray(connections)) {
232
+ return [];
233
+ }
234
+ // Filter out invalid connections (must have id)
235
+ return connections.filter(c => c && c.id);
236
+ }
237
+ catch {
238
+ return [];
239
+ }
240
+ }
241
+ /**
242
+ * Get all profiles including c8ctl profiles and Modeler connections
243
+ * Modeler connections are prefixed with "modeler:"
244
+ */
245
+ export function getAllProfiles() {
246
+ const c8ctlProfiles = loadProfiles();
247
+ const modelerConnections = loadModelerConnections();
248
+ // Convert Modeler connections to Profile format with "modeler:" prefix
249
+ const modelerProfiles = modelerConnections.map(connectionToProfile).map(p => ({
250
+ ...p,
251
+ name: `${MODELER_PREFIX}${p.name}`,
252
+ }));
253
+ return [...c8ctlProfiles, ...modelerProfiles];
254
+ }
255
+ /**
256
+ * Get a profile by name, checking both c8ctl and Modeler sources
257
+ * For Modeler profiles, accepts name with or without "modeler:" prefix
258
+ */
259
+ export function getProfileOrModeler(name) {
260
+ // Try c8ctl profiles first
261
+ const c8ctlProfile = getProfile(name);
262
+ if (c8ctlProfile) {
263
+ return c8ctlProfile;
264
+ }
265
+ // Try Modeler connections (with or without prefix)
266
+ const modelerName = name.startsWith(MODELER_PREFIX) ? name.slice(MODELER_PREFIX.length) : name;
267
+ const modelerConnections = loadModelerConnections();
268
+ const modelerConnection = modelerConnections.find(c => c.name === modelerName || c.id === modelerName);
269
+ if (modelerConnection) {
270
+ const profile = connectionToProfile(modelerConnection);
271
+ return {
272
+ ...profile,
273
+ name: `${MODELER_PREFIX}${profile.name}`,
274
+ };
275
+ }
276
+ return undefined;
277
+ }
278
+ // ============================================================================
279
+ // Conversion Utilities
280
+ // ============================================================================
281
+ /**
282
+ * Convert a Connection to ClusterConfig for API client use
283
+ */
284
+ export function connectionToClusterConfig(conn) {
285
+ if (conn.targetType === TARGET_TYPES.CAMUNDA_CLOUD) {
286
+ return {
287
+ baseUrl: conn.camundaCloudClusterUrl || '',
288
+ clientId: conn.camundaCloudClientId,
289
+ clientSecret: conn.camundaCloudClientSecret,
290
+ audience: conn.camundaCloudClusterUrl, // Cloud uses URL as audience
291
+ oAuthUrl: 'https://login.cloud.camunda.io/oauth/token',
292
+ };
293
+ }
294
+ // Self-hosted
295
+ const config = {
296
+ baseUrl: conn.contactPoint || 'http://localhost:8080/v2',
297
+ };
298
+ if (conn.authType === AUTH_TYPES.BASIC) {
299
+ config.username = conn.basicAuthUsername;
300
+ config.password = conn.basicAuthPassword;
301
+ }
302
+ else if (conn.authType === AUTH_TYPES.OAUTH) {
303
+ config.clientId = conn.clientId;
304
+ config.clientSecret = conn.clientSecret;
305
+ config.oAuthUrl = conn.oauthURL;
306
+ config.audience = conn.audience;
307
+ }
308
+ return config;
309
+ }
310
+ /**
311
+ * Convert Connection to Profile format
312
+ * Used to convert read-only Modeler connections to c8ctl Profile format
313
+ */
314
+ export function connectionToProfile(conn) {
315
+ const config = connectionToClusterConfig(conn);
316
+ return {
317
+ name: conn.name || conn.id,
318
+ baseUrl: config.baseUrl,
319
+ clientId: config.clientId,
320
+ clientSecret: config.clientSecret,
321
+ audience: config.audience,
322
+ oAuthUrl: config.oAuthUrl,
323
+ username: config.username,
324
+ password: config.password,
325
+ defaultTenantId: conn.tenantId,
326
+ };
327
+ }
328
+ /**
329
+ * Convert Profile to ClusterConfig for API client use
330
+ */
331
+ export function profileToClusterConfig(profile) {
332
+ return {
333
+ baseUrl: profile.baseUrl,
334
+ clientId: profile.clientId,
335
+ clientSecret: profile.clientSecret,
336
+ audience: profile.audience,
337
+ oAuthUrl: profile.oAuthUrl,
338
+ username: profile.username,
339
+ password: profile.password,
340
+ };
341
+ }
342
+ /**
343
+ * Get display label for a connection
344
+ */
345
+ export function getConnectionLabel(conn) {
346
+ if (conn.name) {
347
+ return conn.name;
348
+ }
349
+ // Fallback to URL-based label like Modeler does
350
+ const url = conn.targetType === TARGET_TYPES.CAMUNDA_CLOUD
351
+ ? conn.camundaCloudClusterUrl
352
+ : conn.contactPoint;
353
+ return url ? `Unnamed (${url})` : 'Unnamed connection';
354
+ }
355
+ /**
356
+ * Get auth type label for display
357
+ */
358
+ export function getAuthTypeLabel(conn) {
359
+ if (conn.targetType === TARGET_TYPES.CAMUNDA_CLOUD) {
360
+ return 'OAuth (Cloud)';
361
+ }
362
+ switch (conn.authType) {
363
+ case AUTH_TYPES.BASIC:
364
+ return 'Basic';
365
+ case AUTH_TYPES.OAUTH:
366
+ return 'OAuth';
367
+ case AUTH_TYPES.NONE:
368
+ default:
369
+ return 'None';
370
+ }
371
+ }
372
+ /**
373
+ * Get target type label for display
374
+ */
375
+ export function getTargetTypeLabel(conn) {
376
+ return conn.targetType === TARGET_TYPES.CAMUNDA_CLOUD
377
+ ? 'Camunda Cloud'
378
+ : 'Self-Hosted';
379
+ }
380
+ // ============================================================================
381
+ // Session State Management
382
+ // ============================================================================
131
383
  /**
132
384
  * Load session state from disk and populate c8ctl runtime object
133
- * Loads all session properties (activeProfile, activeTenant, outputMode)
134
385
  */
135
386
  export function loadSessionState() {
136
387
  const path = getSessionStatePath();
137
388
  if (!existsSync(path)) {
138
- // Return default state if no session file exists
139
389
  return {
140
390
  activeProfile: c8ctl.activeProfile,
141
391
  activeTenant: c8ctl.activeTenant,
@@ -145,7 +395,6 @@ export function loadSessionState() {
145
395
  try {
146
396
  const data = readFileSync(path, 'utf-8');
147
397
  const state = JSON.parse(data);
148
- // Populate c8ctl runtime with loaded state (convert null to undefined)
149
398
  c8ctl.activeProfile = state.activeProfile === null ? undefined : state.activeProfile;
150
399
  c8ctl.activeTenant = state.activeTenant === null ? undefined : state.activeTenant;
151
400
  c8ctl.outputMode = state.outputMode || 'text';
@@ -155,8 +404,7 @@ export function loadSessionState() {
155
404
  outputMode: c8ctl.outputMode,
156
405
  };
157
406
  }
158
- catch (error) {
159
- // Return current state if file is corrupted
407
+ catch {
160
408
  return {
161
409
  activeProfile: c8ctl.activeProfile,
162
410
  activeTenant: c8ctl.activeTenant,
@@ -166,7 +414,6 @@ export function loadSessionState() {
166
414
  }
167
415
  /**
168
416
  * Save session state from c8ctl runtime object to disk
169
- * Always persists all session properties (activeProfile, activeTenant, outputMode)
170
417
  */
171
418
  export function saveSessionState(state) {
172
419
  const stateToSave = {
@@ -174,18 +421,16 @@ export function saveSessionState(state) {
174
421
  activeTenant: state?.activeTenant ?? c8ctl.activeTenant,
175
422
  outputMode: state?.outputMode ?? c8ctl.outputMode,
176
423
  };
177
- // Update c8ctl runtime if state is provided
178
424
  if (state) {
179
425
  c8ctl.activeProfile = state.activeProfile;
180
426
  c8ctl.activeTenant = state.activeTenant;
181
427
  c8ctl.outputMode = state.outputMode;
182
428
  }
183
429
  const path = getSessionStatePath();
184
- // Use custom replacer to preserve undefined as null in JSON
185
- writeFileSync(path, JSON.stringify(stateToSave, (key, value) => value === undefined ? null : value, 2), 'utf-8');
430
+ writeFileSync(path, JSON.stringify(stateToSave, (_, value) => (value === undefined ? null : value), 2), 'utf-8');
186
431
  }
187
432
  /**
188
- * Set active profile in session and persist to disk
433
+ * Set active profile/connection in session and persist to disk
189
434
  */
190
435
  export function setActiveProfile(name) {
191
436
  c8ctl.activeProfile = name;
@@ -205,46 +450,33 @@ export function setOutputMode(mode) {
205
450
  c8ctl.outputMode = mode;
206
451
  saveSessionState();
207
452
  }
453
+ // ============================================================================
454
+ // Cluster Configuration Resolution
455
+ // ============================================================================
208
456
  /**
209
457
  * Resolve cluster configuration from session, flags, env vars, or defaults
210
458
  * Priority: profileFlag → session profile → env vars → localhost fallback
211
459
  */
212
460
  export function resolveClusterConfig(profileFlag) {
213
- // 1. Try profile flag
461
+ // 1. Try profile flag (profile name, including modeler: prefix)
214
462
  if (profileFlag) {
215
- const profile = getProfile(profileFlag);
463
+ const profile = getProfileOrModeler(profileFlag);
216
464
  if (profile) {
217
- return {
218
- baseUrl: profile.baseUrl,
219
- clientId: profile.clientId,
220
- clientSecret: profile.clientSecret,
221
- audience: profile.audience,
222
- oAuthUrl: profile.oAuthUrl,
223
- username: profile.username,
224
- password: profile.password,
225
- };
465
+ return profileToClusterConfig(profile);
226
466
  }
227
467
  }
228
468
  // 2. Try session profile
229
469
  if (c8ctl.activeProfile) {
230
- const profile = getProfile(c8ctl.activeProfile);
470
+ const profile = getProfileOrModeler(c8ctl.activeProfile);
231
471
  if (profile) {
232
- return {
233
- baseUrl: profile.baseUrl,
234
- clientId: profile.clientId,
235
- clientSecret: profile.clientSecret,
236
- audience: profile.audience,
237
- oAuthUrl: profile.oAuthUrl,
238
- username: profile.username,
239
- password: profile.password,
240
- };
472
+ return profileToClusterConfig(profile);
241
473
  }
242
474
  }
243
475
  // 3. Try environment variables
244
476
  const baseUrl = process.env.CAMUNDA_BASE_URL;
245
477
  const clientId = process.env.CAMUNDA_CLIENT_ID;
246
478
  const clientSecret = process.env.CAMUNDA_CLIENT_SECRET;
247
- const audience = process.env.CAMUNDA_AUDIENCE;
479
+ const audience = process.env.CAMUNDA_TOKEN_AUDIENCE;
248
480
  const oAuthUrl = process.env.CAMUNDA_OAUTH_URL;
249
481
  const username = process.env.CAMUNDA_USERNAME;
250
482
  const password = process.env.CAMUNDA_PASSWORD;
@@ -260,8 +492,6 @@ export function resolveClusterConfig(profileFlag) {
260
492
  };
261
493
  }
262
494
  // 4. Localhost fallback with basic auth (demo/demo)
263
- // These default credentials match the docker-compose configuration
264
- // and are intended for local development only
265
495
  return {
266
496
  baseUrl: 'http://localhost:8080/v2',
267
497
  username: 'demo',
@@ -270,7 +500,7 @@ export function resolveClusterConfig(profileFlag) {
270
500
  }
271
501
  /**
272
502
  * Resolve tenant ID from session, profile, env vars, or default
273
- * Priority: session tenant → profile default tenant → env var → '<default>'
503
+ * Priority: session tenant → profile tenant → env var → '<default>'
274
504
  */
275
505
  export function resolveTenantId(profileFlag) {
276
506
  // 1. Try session tenant
@@ -280,7 +510,7 @@ export function resolveTenantId(profileFlag) {
280
510
  // 2. Try profile default tenant (from flag or session)
281
511
  const profileName = profileFlag || c8ctl.activeProfile;
282
512
  if (profileName) {
283
- const profile = getProfile(profileName);
513
+ const profile = getProfileOrModeler(profileName);
284
514
  if (profile?.defaultTenantId) {
285
515
  return profile.defaultTenantId;
286
516
  }
@@ -293,93 +523,4 @@ export function resolveTenantId(profileFlag) {
293
523
  // 4. Default tenant
294
524
  return '<default>';
295
525
  }
296
- /**
297
- * Load Camunda Modeler profiles from profiles.json
298
- * Always reads fresh from disk (no caching)
299
- *
300
- * TODO: Consider introducing caching mechanism for better performance.
301
- * Current implementation reads from disk on every call. For commands that
302
- * list profiles or look up multiple profiles, this could be optimized by
303
- * implementing per-execution memoization or a time-based cache.
304
- */
305
- export function loadModelerProfiles() {
306
- try {
307
- const modelerDir = getModelerDataDir();
308
- const profilesPath = join(modelerDir, 'profiles.json');
309
- if (!existsSync(profilesPath)) {
310
- return [];
311
- }
312
- const data = readFileSync(profilesPath, 'utf-8');
313
- const parsed = JSON.parse(data);
314
- return parsed.profiles || [];
315
- }
316
- catch (error) {
317
- // Silently return empty array if file can't be read or parsed
318
- return [];
319
- }
320
- }
321
- /**
322
- * Get a modeler profile by name or cluster ID
323
- * Accepts 'modeler:name' or 'modeler:id' format, or just 'name'/'id'
324
- */
325
- export function getModelerProfile(identifier) {
326
- const profiles = loadModelerProfiles();
327
- // Remove 'modeler:' prefix if present
328
- const searchId = identifier.startsWith('modeler:')
329
- ? identifier.substring(8)
330
- : identifier;
331
- // Search by name first, then by clusterId
332
- return profiles.find(p => p.name === searchId || p.clusterId === searchId);
333
- }
334
- /**
335
- * Construct REST API URL from modeler profile
336
- * For cloud: uses clusterUrl as-is (Camunda cloud URLs don't need /v2)
337
- * For self-managed: localhost URLs get /v2 appended
338
- * Does not derive values - uses what's provided
339
- *
340
- * Note: Self-managed clusters should include /v2 in their clusterUrl if needed
341
- */
342
- export function constructApiUrl(profile) {
343
- // If clusterUrl is provided, use it as the base
344
- if (profile.clusterUrl) {
345
- const url = profile.clusterUrl;
346
- // If it already has /v2 endpoint, use as-is
347
- if (url.includes('/v2')) {
348
- return url;
349
- }
350
- // Only append /v2 for localhost URLs
351
- // Self-managed clusters should include /v2 in their clusterUrl if needed
352
- if (url.includes('localhost') || url.includes('127.0.0.1')) {
353
- return `${url.replace(/\/$/, '')}/v2`;
354
- }
355
- // For all other URLs (including cloud), use as-is
356
- return url;
357
- }
358
- // If no clusterUrl but have clusterId, construct cloud URL
359
- if (profile.clusterId) {
360
- // Cloud cluster URLs follow pattern: https://{clusterId}.{region}.zeebe.camunda.io
361
- // We can't derive the region, so just use the clusterId as a fallback base
362
- return `https://${profile.clusterId}.zeebe.camunda.io`;
363
- }
364
- // Fallback to localhost
365
- return 'http://localhost:8080/v2';
366
- }
367
- /**
368
- * Convert a modeler profile to a c8ctl Profile
369
- */
370
- export function convertModelerProfile(modelerProfile) {
371
- const name = modelerProfile.name || modelerProfile.clusterId || 'unknown';
372
- const baseUrl = constructApiUrl(modelerProfile);
373
- return {
374
- name: `modeler:${name}`,
375
- baseUrl,
376
- clientId: modelerProfile.clientId,
377
- clientSecret: modelerProfile.clientSecret,
378
- audience: modelerProfile.audience,
379
- // Cloud clusters typically use the standard OAuth URL
380
- oAuthUrl: modelerProfile.audience ?
381
- 'https://login.cloud.camunda.io/oauth/token' :
382
- undefined,
383
- };
384
- }
385
526
  //# sourceMappingURL=config.js.map