camunda-cli 0.4.0 → 0.4.3

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.
package/PANDUAN.md ADDED
@@ -0,0 +1,341 @@
1
+ # Panduan camunda-cli
2
+
3
+ Alat baris perintah untuk Camunda 7 self-hosted. Dibuat untuk dua pekerjaan yang paling
4
+ memakan waktu saat mengembangkan BPMN: **memahami model yang sudah ter-deploy**, dan
5
+ **mencari tahu kenapa sebuah instance macet**.
6
+
7
+ Dokumen ini disusun per kasus nyata, bukan per perintah. Untuk daftar opsi lengkap tiap
8
+ perintah, jalankan `camunda <perintah> --help`.
9
+
10
+ ---
11
+
12
+ ## Pasang dan masuk
13
+
14
+ ```bash
15
+ npm install -g camunda-cli
16
+ camunda login https://camunda.contoh.com
17
+ ```
18
+
19
+ URL boleh tanpa `/engine-rest`, akan ditambahkan otomatis. Username dan password ditanyakan
20
+ lewat prompt (jangan ditulis di baris perintah supaya tidak masuk riwayat shell).
21
+
22
+ Kredensial disimpan di `~/.config/camunda-cli/config.json` dengan permission `0600`. Camunda 7
23
+ memakai HTTP Basic Auth di setiap request dan tidak punya token sesi, jadi yang disimpan
24
+ memang password, dan hanya dikirim ke engine yang kamu konfigurasi.
25
+
26
+ Cek sambungan kapan saja:
27
+
28
+ ```bash
29
+ camunda whoami
30
+ ```
31
+
32
+ **Publish tidak memperbarui yang sudah terpasang.** Setelah versi baru rilis, jalankan lagi
33
+ `npm install -g camunda-cli`, lalu pastikan dengan `camunda --version`.
34
+
35
+ ---
36
+
37
+ ## Kasus 1: memeriksa model sebelum di-deploy
38
+
39
+ Ini kebiasaan yang paling menghemat waktu. Kondisi gateway, form field, dan wiring addon
40
+ hanya ada di dalam XML BPMN, tidak ada endpoint REST-nya, jadi tanpa alat ini satu-satunya
41
+ cara mengetahuinya adalah membaca XML mentah.
42
+
43
+ ```bash
44
+ camunda lint ./proses-saya.bpmn # file lokal, tanpa engine, tanpa login
45
+ camunda lint Process_PengajuanCuti # versi yang sudah ter-deploy
46
+ ```
47
+
48
+ Severity dipisah dengan sengaja:
49
+
50
+ - **ERROR** hanya untuk yang **terbukti rusak dari modelnya sendiri**. `camunda deploy`
51
+ menolak model yang punya error.
52
+ - **WARNING** untuk risiko yang butuh penilaianmu, karena modelnya sendiri tidak cukup untuk
53
+ membuktikan salah atau benar.
54
+ - **INFO** untuk catatan, disembunyikan kecuali pakai `--all`.
55
+
56
+ Kalibrasi ini diuji ke 190 model produksi nyata: nol error, nol deploy terblokir, sementara
57
+ model yang memang dibuat rusak tetap menghasilkan dua error.
58
+
59
+ ### Yang ditangkap sebagai ERROR
60
+
61
+ | Aturan | Artinya |
62
+ |---|---|
63
+ | `uncovered-value` | Gateway bercabang `> N` dan `< N`, jadi nilai tepat `N` tidak ke mana-mana. Engine melempar `ENGINE-02004` dan instance berhenti. |
64
+ | `default-flow-with-condition` | Flow yang ditandai default tapi masih punya kondisi. Engine menolak model ini saat deploy dengan `ENGINE-09005`. |
65
+ | `variable-name-mismatch` | Form menulis satu variabel yang tidak dibaca siapa pun, sementara kondisi di hilirnya membaca variabel yang tidak ditulis siapa pun. Menyelesaikan elemen itu tidak akan pernah memenuhi kondisinya. |
66
+ | `dangling-flow`, `dangling-boundary`, `no-start-event` | Menunjuk elemen yang tidak ada. |
67
+
68
+ ### Yang ditangkap sebagai WARNING
69
+
70
+ `no-default-flow` (semua cabang berkondisi tanpa fallback), `unwritten-variable` (membaca
71
+ `${x}` yang tidak ditulis siapa pun di model ini), `initiator-expression`, `no-op-service-task`
72
+ (service task tanpa implementasi), `addon-without-config`, `unreachable`, `dead-end`,
73
+ `ambiguous-branch`.
74
+
75
+ ### Melihat isi model
76
+
77
+ ```bash
78
+ camunda inspect Process_PengajuanCuti
79
+ camunda inspect ./proses-saya.bpmn
80
+ ```
81
+
82
+ Menampilkan semua elemen beserta penanda async, assignee, addon yang dipanggil, jumlah form
83
+ field, dan **berapa instance yang sedang berada di elemen itu**; lalu seluruh sequence flow
84
+ dengan kondisinya; lalu form field per elemen; lalu daftar integrasi.
85
+
86
+ ---
87
+
88
+ ## Kasus 2: menguji proses dari awal sampai selesai
89
+
90
+ ```bash
91
+ camunda start Process_PengajuanCuti --var initiator=budi@contoh.com -b UJI-1
92
+ ```
93
+
94
+ Yang muncul:
95
+
96
+ ```
97
+ Started Process_PengajuanCuti v3 as instance 3441986
98
+ business key UJI-1
99
+
100
+ Now waiting at:
101
+ 3442065 Review Leave Request budi@contoh.com
102
+ camunda complete 3442065 --var catatan=<value>
103
+ ```
104
+
105
+ `start` **tidak berhenti di "berhasil dikirim"**. HTTP 200 dari engine cuma berarti perintahnya
106
+ diterima; apa pun yang ditandai async baru berjalan setelah respons. Jadi `start` menunggu
107
+ sebentar lalu melaporkan salah satu dari tiga: gagal, selesai, atau sedang menunggu di task
108
+ mana beserta perintah persis untuk menyelesaikannya.
109
+
110
+ Lanjutkan dengan menyalin perintah yang disarankan:
111
+
112
+ ```bash
113
+ camunda complete 3442065 --var catatan=ok
114
+ ```
115
+
116
+ ```
117
+ Task 3442065 completed.
118
+ Instance 3441986 finished in 3.6s.
119
+ ```
120
+
121
+ Kalau proses masih berjalan, `complete` menampilkan task berikutnya. Jadi menggiring proses
122
+ tiga langkah cukup tiga perintah, tanpa perlu mencari-cari sendiri.
123
+
124
+ ### Menemukan task lewat business key
125
+
126
+ ```bash
127
+ camunda tasks -b UJI-1
128
+ ```
129
+
130
+ Business key itu pegangan yang kamu tentukan sendiri saat `start`, jadi bisa dipakai langsung
131
+ tanpa perlu tahu instance id.
132
+
133
+ ### Tipe variabel itu penting
134
+
135
+ ```bash
136
+ --var jumlah=300 # String, dan "300" > 200 dibandingkan sebagai teks
137
+ --var jumlah=300:Integer # angka sungguhan
138
+ --var aktif=true:Boolean
139
+ --var data:='{"a":1}' # JSON
140
+ ```
141
+
142
+ Kalau gateway membandingkan secara numerik, salah tipe membuat kondisinya berperilaku aneh
143
+ tanpa error.
144
+
145
+ ### Membersihkan setelah menguji
146
+
147
+ ```bash
148
+ camunda cancel --key Process_PengajuanCuti # semua instance proses itu
149
+ camunda cancel 3441986 # satu instance
150
+ camunda cancel --key Process_X -y -r "bersih-bersih" # tanpa konfirmasi
151
+ ```
152
+
153
+ Menguji meninggalkan banyak instance menggantung. Tanpa `-y` akan diminta konfirmasi.
154
+
155
+ ---
156
+
157
+ ## Kasus 3: instance macet atau gagal
158
+
159
+ Satu perintah untuk semuanya:
160
+
161
+ ```bash
162
+ camunda diagnose 3441986
163
+ ```
164
+
165
+ Ini membaca lebih banyak daripada sekadar `/incident`, karena beberapa bentuk kegagalan tidak
166
+ terlihat di sana:
167
+
168
+ - Langkah yang gagal **di dalam transaksi pemanggilnya** tidak meninggalkan incident maupun
169
+ job sama sekali; satu-satunya jejak ada di historic job log, atau tidak ada sama sekali.
170
+ - Incident menunjuk activity tempat job menempel, yang **sering bukan** activity yang error.
171
+ `diagnose` membedakan keduanya secara eksplisit.
172
+ - Incident yang sudah teratasi hilang dari `/incident`.
173
+
174
+ Contoh keluaran:
175
+
176
+ ```
177
+ Stopped at
178
+ Activity_CekSisaKuota transition Check Remaining Quota
179
+
180
+ 1 problem(s)
181
+
182
+ open incident at 2026-08-13 08:19:33
183
+ failing element: Activity_TinjauPengajuan
184
+ job attached to: Activity_CekSisaKuota (the async marker sits here, the error came from
185
+ the element above)
186
+ Unknown property used in expression: ${initiator}. Cause: Cannot resolve identifier 'initiator'
187
+
188
+ The variable "initiator" is injected by AlurKerja when a process is started through its own
189
+ API. Starting the same process straight through the Camunda REST API skips that...
190
+ ```
191
+
192
+ Exit code-nya **1 kalau ada yang sedang rusak, 0 kalau sehat**, jadi bisa dipakai di skrip.
193
+
194
+ Instance yang pernah gagal lalu pulih dilaporkan **sehat**, dengan riwayat kegagalannya
195
+ ditampilkan terpisah sebagai konteks, bukan sebagai vonis.
196
+
197
+ ### Error addon yang bersarang
198
+
199
+ Kegagalan addon datang sebagai pesan REST yang membungkus exception Java yang membungkus
200
+ `body: {json}` yang field `output`-nya berisi JSON lagi. Kalimat yang benar-benar berguna ada
201
+ di lapisan paling dalam, jadi itulah yang ditampilkan paling atas:
202
+
203
+ ```
204
+ sales_name kosong. Pastikan form Submit-Weekly-Report benar-benar mengisi variabel ini
205
+ sebelum service task ini berjalan.
206
+
207
+ integration response:
208
+ { "details": "script exited with code 1", ... }
209
+
210
+ script output:
211
+ { "status": "error", "message": "sales_name kosong...", ... }
212
+ ```
213
+
214
+ Ini berlaku baik di `diagnose` maupun saat `complete` gagal.
215
+
216
+ ### Perintah pendukung
217
+
218
+ ```bash
219
+ camunda trace 3441986 # setiap langkah yang dilalui, urut sesuai eksekusi engine
220
+ camunda vars 3441986 # variabel saat ini
221
+ camunda vars 3441986 -H # setiap perubahan variabel beserta waktunya
222
+ camunda jobs -i 3441986 -f # job yang gagal
223
+ camunda stacktrace <jobId> # stack trace, frame internal engine disaring
224
+ camunda incidents -k Process_X # incident yang terbuka
225
+ camunda incidents -k Process_X -H # termasuk yang sudah teratasi
226
+ camunda stats Process_X # instance menumpuk di elemen mana
227
+ ```
228
+
229
+ `trace` diurutkan memakai urutan eksekusi milik engine, bukan timestamp. Gateway dan event di
230
+ sekitarnya sering berbagi milidetik yang sama, dan mengurutkan pakai waktu membuat urutannya
231
+ acak.
232
+
233
+ ---
234
+
235
+ ## Kasus 4: memperbaiki instance yang gagal tanpa mengulang dari awal
236
+
237
+ Ini alur sehari-hari saat mengembangkan addon: script-nya salah, instance gagal, script
238
+ diperbaiki, lalu ingin melanjutkan instance yang sudah jalan.
239
+
240
+ ```bash
241
+ camunda jobs -i 3441986 --failed # cari job yang gagal
242
+ camunda set-var 3441986 initiator=budi@contoh.com # perbaiki datanya
243
+ camunda retry 3441988 --now # jalankan ulang job itu sekarang
244
+ camunda diagnose 3441986 # pastikan benar-benar pulih
245
+ ```
246
+
247
+ `retry` mengembalikan jatah percobaan job supaya dijalankan lagi. Tanpa `--now`, job runner
248
+ yang akan mengambilnya beberapa saat kemudian.
249
+
250
+ Kalau yang salah adalah **kodenya** (script addon, konfigurasi listener), jangan retry job di
251
+ instance yang sama untuk menguji perbaikannya: data yang terlanjur dihasilkan run sebelumnya
252
+ sudah tersimpan di variabel instance itu dan tidak akan dibuat ulang. Mulai instance baru.
253
+ Retry di tempat hanya masuk akal untuk yang sifatnya sementara (jaringan, service luar yang
254
+ sedang mati) atau kalau yang diperbaiki memang datanya.
255
+
256
+ ---
257
+
258
+ ## Kasus 5: mesin dengan banyak tenant
259
+
260
+ Di engine bersama, satu process key yang sama ada di banyak tenant. Endpoint bawaan Camunda
261
+ menjawab *"no matching process definition ... and no tenant-id"*, yang terbaca seolah prosesnya
262
+ tidak ada padahal ada.
263
+
264
+ ```bash
265
+ camunda tenants -s Telco # cari id tenant dari namanya
266
+ camunda definitions -k Contract -t <tenantId> -l
267
+ camunda inspect Process_X -t <tenantId>
268
+ ```
269
+
270
+ Kalau sebuah key ambigu, perintahnya tidak menebak, melainkan menampilkan kandidatnya:
271
+
272
+ ```
273
+ "V2-Contract-Lifecycle-Management" exists in 3 tenants. Narrow it with --tenant <id>, or
274
+ pass the full definition id:
275
+ V2-Contract-...:103:2794600 tenant=ef93ab58-... version=103
276
+ ...
277
+ ```
278
+
279
+ ---
280
+
281
+ ## Kasus 6: deploy
282
+
283
+ ```bash
284
+ camunda deploy ./proses.bpmn -t <tenantId> -n "nama deployment"
285
+ ```
286
+
287
+ `deploy` menjalankan pemeriksaan yang sama dengan `lint` dan **menolak model yang punya error**.
288
+ Pakai `--skip-lint` untuk memaksa.
289
+
290
+ Kalau isinya identik dengan yang sudah ter-deploy, Camunda tidak membuat versi baru dan
291
+ perintahnya memberi tahu hal itu, bukan diam-diam sukses.
292
+
293
+ ```bash
294
+ camunda deployments # deployment terbaru
295
+ camunda undeploy <deploymentId> # hapus (pakai --cascade untuk ikut instance & history)
296
+ ```
297
+
298
+ ---
299
+
300
+ ## Dipakai dari skrip atau agent AI
301
+
302
+ Setiap perintah menerima `--json` untuk mengeluarkan payload API mentah:
303
+
304
+ ```bash
305
+ camunda tasks -b UJI-1 --json
306
+ camunda lint Process_X --json
307
+ camunda diagnose 3441986 --json
308
+ ```
309
+
310
+ Keluaran biasa juga sudah aman dibaca mesin: tidak ada karakter garis kotak, dan warna hanya
311
+ muncul kalau stdout benar-benar terminal. Kolomnya dirapikan dengan spasi biasa.
312
+
313
+ Exit code: `0` berhasil, `1` gagal atau ada temuan error.
314
+
315
+ ---
316
+
317
+ ## Hal-hal yang menghemat waktu
318
+
319
+ **401 yang muncul acak.** Engine di belakang load balancer kadang menolak kredensial yang
320
+ benar saat satu replika sedang tidak sehat: pernah teramati 5 kali gagal lalu 5 kali berhasil
321
+ berturut-turut, kredensial sama, jeda setengah detik. Request diulang otomatis supaya ini
322
+ tidak terbaca sebagai password salah. Error 4xx yang membawa pesan Camunda asli tidak pernah
323
+ diulang, karena itu jawaban sungguhan.
324
+
325
+ **`${initiator}` kosong kalau start dari CLI.** AlurKerja mengisi variabel itu saat proses
326
+ dimulai lewat API-nya sendiri. Start langsung ke Camunda melewatkannya, jadi elemen yang
327
+ memakai `${initiator}` (biasanya assignee) gagal begitu tercapai. Tambahkan
328
+ `--var initiator=<userId>` saat menguji dari CLI.
329
+
330
+ **Form micro-frontend menulis variabel yang tidak terlihat di model.** Field bertipe
331
+ `EXTERNAL_MICRO_FRONTEND_FORM` namanya cuma titik pasang; MFE-nya bisa menulis variabel apa
332
+ pun tanpa dideklarasikan di BPMN. Jadi `unwritten-variable` di proses seperti itu wajar dan
333
+ belum tentu bug.
334
+
335
+ ---
336
+
337
+ ## Yang sengaja tidak dicakup
338
+
339
+ Evaluasi DMN, operasi batch, migrasi dan modifikasi instance, serta manajemen authorization.
340
+ Ini keputusan sadar, bukan kelalaian: cakupan perintah di sini mengikuti apa yang benar-benar
341
+ berulang saat mengembangkan dan men-debug proses, bukan seluruh 300-an endpoint REST Camunda.
package/README.md CHANGED
@@ -19,6 +19,8 @@ ERROR variable-name-mismatch flow Flow_0jpsuir (retry)
19
19
  expression throws "Cannot resolve identifier 'input_huruf'" the moment it is evaluated.
20
20
  ```
21
21
 
22
+ A task-by-task guide in Indonesian is in [PANDUAN.md](PANDUAN.md).
23
+
22
24
  ## Install
23
25
 
24
26
  ```bash
package/bin/camunda.js CHANGED
@@ -24,7 +24,7 @@ program
24
24
  'Start with "camunda inspect <key>" to read a deployed model, and\n' +
25
25
  '"camunda diagnose <instanceId>" when an instance misbehaves.'
26
26
  )
27
- .version('0.4.0')
27
+ .version('0.4.3')
28
28
  .option('--json', 'print the raw API payload instead of a formatted view')
29
29
  .option('--no-color', 'never emit colour, even on a terminal')
30
30
  .showHelpAfterError()
@@ -189,6 +189,7 @@ withTenant(
189
189
  .description('Open human tasks')
190
190
  .option('-a, --assignee <userId>')
191
191
  .option('-i, --instance <processInstanceId>')
192
+ .option('-b, --business-key <key>', 'tasks of the instance started with this business key')
192
193
  .option('-k, --key <definitionKey>')
193
194
  .option('-u, --unassigned')
194
195
  .option('--limit <n>', 'maximum rows', int)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "camunda-cli",
3
- "version": "0.4.0",
3
+ "version": "0.4.3",
4
4
  "description": "Command-line client for self-hosted Camunda 7: inspect and lint deployed BPMN models, and diagnose why an instance is stuck",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -16,7 +16,8 @@
16
16
  },
17
17
  "files": [
18
18
  "bin",
19
- "src"
19
+ "src",
20
+ "PANDUAN.md"
20
21
  ],
21
22
  "keywords": [
22
23
  "camunda",
Binary file
@@ -65,7 +65,23 @@ export async function messageCommand(name, options) {
65
65
  if (options.businessKey) body.businessKey = options.businessKey;
66
66
  if (options.all) body.all = true;
67
67
 
68
- const result = await client.correlateMessage(body);
68
+ // Camunda answers a message that matches nothing with an exception rather than an empty
69
+ // result, so the ordinary case of getting the name or business key wrong arrives as a
70
+ // Java class name unless it is caught here.
71
+ let result;
72
+ try {
73
+ result = await client.correlateMessage(body);
74
+ } catch (err) {
75
+ const raw = err.body?.message || err.message || '';
76
+ if (/MismatchingMessageCorrelation|No process definition or execution matches/.test(raw)) {
77
+ out.warn(`Nothing is waiting for a message called "${name}"${options.instance ? ` on instance ${options.instance}` : ''}${options.businessKey ? ` with business key ${options.businessKey}` : ''}.`);
78
+ out.note('camunda subscriptions shows what is currently waiting, and under which name.');
79
+ process.exitCode = 1;
80
+ return;
81
+ }
82
+ throw err;
83
+ }
84
+
69
85
  if (out.isJsonMode()) return out.json(result);
70
86
 
71
87
  if (!result || result.length === 0) {
@@ -10,6 +10,9 @@ export async function tasksCommand(options) {
10
10
  const query = { maxResults: options.limit ?? 50 };
11
11
  if (options.assignee) query.assignee = options.assignee;
12
12
  if (options.instance) query.processInstanceId = options.instance;
13
+ // The business key is the handle you chose when starting, so it is the natural way back
14
+ // to a task without first looking the instance id up.
15
+ if (options.businessKey) query.processInstanceBusinessKey = options.businessKey;
13
16
  if (options.key) query.processDefinitionKey = options.key;
14
17
  if (options.tenant) query.tenantIdIn = options.tenant;
15
18
  if (options.unassigned) query.unassigned = true;