luang-cli 0.2.0 → 0.3.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.
package/README.md CHANGED
@@ -145,7 +145,12 @@ CLI API Browser (kamu)
145
145
  | `provider add` | Tambah / override provider config | `luang-cli provider add codex --exec_template 'codex exec "{task}"'` |
146
146
  | `provider remove` | Hapus provider dari config | `luang-cli provider remove codex` |
147
147
  | `provider default` | Set provider default (dipakai `agent --exec`) | `luang-cli provider default opencode` |
148
- | `agent` | Daemon: heartbeat + poll tugas live | `luang-cli agent --interval 5 --exec` |
148
+ | `telemetry` | Konsent kirim data usage/model (`on\|off\|status`) | `luang-cli telemetry status` |
149
+ | `agent` | Daemon **realtime WS** + background/auto + polling (fallback) | `luang-cli agent start` |
150
+ | `models` | Daftar model AI per provider (deteksi dinamis + saran) | `luang-cli models opencode` |
151
+ | `workspace` | Folder kerja provider (sinkron dashboard), dipakai cwd `--exec` | `luang-cli workspace ~/project` |
152
+ | `agent start` | Jalankan daemon di **background** (mode auto, log + pid file) | `luang-cli agent start` |
153
+ | `agent stop\|status\|logs` | Hentikan (SIGTERM) · status (pid/uptime/log) · tail log | `luang-cli agent logs --tail 50` |
149
154
  | `task list` | Daftar tugas agent (filter status) | `luang-cli task list --status todo` |
150
155
  | `task create` | Buat tugas (butuh izin admin) | `luang-cli task create --title "Refactor auth" --priority high` |
151
156
  | `task status` | Perbarui status + catatan progress | `luang-cli task status TGS-12 in_progress --note "mulai"` |
@@ -186,42 +191,144 @@ Daftar manual (path khusus, alias brand, multi-provider):
186
191
 
187
192
  ```bash
188
193
  luang-cli provider add claude_code --path /opt/homebrew/bin/claude \
189
- --exec_template 'claude -p "{task}"'
190
- luang-cli provider add opencode --exec_template 'opencode run "{task}"'
191
- luang-cli provider default claude_code
194
+ --exec_template 'claude -p --model {model} "{task}"'
195
+ luang-cli provider add opencode --exec_template 'opencode run "{task}"' --model sonnet-4
196
+ luang-cli provider default opencode
192
197
  ```
193
198
 
194
- - `{task}` pada template otomatis diganti **judul + deskripsi** tugas; template tanpa `{task}` tidak dipakai mode `--exec`.
195
- - Daftar provider tersimpan di `~/.luang-cli/config.json` dan disinkron ke server lewat heartbeat (`provider_count` tampil di dashboard Agents).
199
+ - `{task}` pada template otomatis diganti **judul + deskripsi** tugas; template tanpa `{task}` tidak dipakai mode `--exec` (notifikasi saja).
200
+ - `{model}` diganti model aktif provider — urutan: `agent.command set_model` (dashboard) → `--model` / field `model` di config → env `LUANG_MODEL`. Bila template memuat `{model}` tapi tak ada model, tugas ditunda dengan notifikasi (bukan error diam-diam).
201
+ - Provider tipe yang dikenal tapi tidak punya `exec_template` di config memakai template default pada tabel di atas.
202
+ - Daftar provider tersimpan di `~/.luang-cli/config.json` dan disinkron ke server lewat heartbeat / frame WS `provider.update` (`provider_count` + model tampil di dashboard Agents).
203
+
204
+ ---
205
+
206
+ ## 🧩 Daftar model (`luang-cli models`)
207
+
208
+ ```bash
209
+ luang-cli models # semua provider (tabel)
210
+ luang-cli models opencode # satu provider saja
211
+ luang-cli models --json # untuk mesin: {<provider>: {provider, source, models}}
212
+ ```
213
+
214
+ - **Sumber (berurutan)**: dinamis **hanya** untuk `opencode` — coba perintah `opencode models`, gagal → parse `~/.config/opencode/` atau `~/.opencode`, gagal juga → registry statis. Provider lain selalu registry statis per harness (saran/datalist; versi lama tidak masalah — model tetap bisa diketik manual).
215
+ - **Kebijakan ketat**: binary `claude`, `gemini`, dan `codex` **tidak pernah dieksekusi**.
216
+ - Tabel: `Provider | Jumlah model | daftar` (wrap maks 6 baris + `…+n lagi`); `--json` untuk konsumsi mesin.
217
+ - Field `models` (maks 50 item, tiap ≤120 karakter) ikut dikirim ke server pada heartbeat dan hello frame WS.
196
218
 
197
219
  ---
198
220
 
199
221
  ## 🖥 Daemon agent (`luang-cli agent`)
200
222
 
201
223
  ```bash
202
- luang-cli agent # heartbeat tiap 30 detik, poll tugas tiap 5 detik
203
- luang-cli agent --interval 10 # poll tiap 10 detik
204
- luang-cli agent --exec # tertarik juga mengeksekusi tugas To-Do
224
+ luang-cli agent # realtime WS (heartbeat + push tugas); fallback polling bila WS gagal
225
+ luang-cli agent --interval 10 # (mode fallback) poll tiap 10 detik
226
+ luang-cli agent --exec # eksekusi tugas To-Do (konfirmasi y/N)
227
+
228
+ # Background — terminal boleh ditutup
229
+ luang-cli agent start # spawn detached → ~/.luang-cli/agent.log + agent.pid (mode AUTO)
230
+ luang-cli agent start --no-auto # background tanpa eksekusi (monitor saja)
231
+ luang-cli agent status # pid · uptime · mode auto/manual · 3 baris log terakhir
232
+ luang-cli agent logs --tail 50 # tail log (default 30 baris)
233
+ luang-cli agent stop # SIGTERM graceful + hapus agent.pid
234
+ ```
235
+
236
+ **Mode auto** (`agent start`, default): tugas `To-Do` yang di-assign ke key ini **langsung dieksekusi tanpa konfirmasi y/N** (karena tidak ada terminal) — termasuk event realtime `task.assigned`. Pilihan ini disimpan ke `config.json → auto_exec` dan ditampilkan oleh `agent status`. Foreground `agent` / `agent --exec` tetap memakai konfirmasi y/N seperti biasa.
237
+
238
+ ### Workspace folder (`luang-cli workspace`)
239
+
240
+ Folder kerja tempat provider dijalankan (mis. repo yang dikerjakan `opencode`). Diatur dari **dashboard** (Detail Agent → Workspace Folder) **atau** CLI — server adalah sumber kebenaran, CLI menyalin ke config lokal:
241
+
242
+ ```bash
243
+ luang-cli workspace # tampilkan server/lokal/efektif
244
+ luang-cli workspace ~/project # simpan (validasi folder harus ada)
245
+ luang-cli workspace --reset # kosongkan → exec pakai folder saat ini
205
246
  ```
206
247
 
207
- Perilaku:
248
+ Dipakai sebagai **cwd** saat `--exec`/`agent start` menjalankan provider (baris `Folder : …` di log eksekusi). Folder tidak ada → warning + fallback ke folder saat ini.
208
249
 
209
- 1. **Heartbeat** `POST /api/v1/agent/heartbeat` setiap 30 detik (nama + provider list tersinkron; dashboard tampil "Terakhir aktif …").
210
- 2. **Polling** `GET /api/v1/agent/tasks` tiap `--interval` detik — perubahan terdeteksi via fingerprint (status, agent_status, catatan, judul, timestamp) per id tugas.
250
+ **Mode utama: realtime WebSocket** (`/api/v1/agent/ws`, auth `X-CLI-Key`) — tugas di-assign dari dashboard langsung ter-push ke terminal tanpa polling. **Fallback**: bila WS gagal (jaringan/proxy/Node lama), otomatis turun ke polling HTTP seperti versi lama — daemon tetap hidup, tidak crash.
251
+
252
+ Perilaku (kedua mode):
253
+
254
+ 1. **Heartbeat** — `hello` sekali saat connect + heartbeat berkala (nama + provider tersinkron; dashboard tampil "Terakhir aktif …" + badge **Live**).
255
+ 2. **Perubahan tugas terdeteksi** (push WS / fingerprint polling): status, agent_status, catatan, judul.
211
256
  3. Baris perubahan dicetak: `[HH:MM:SS] TGS-1 Judul In Progress agent=… note="…"`.
212
- 4. Tugas yang dipindah status di dashboard → tampil live; tugas yang ditugaskan ke agent-mu → masuk daftar.
257
+ 4. Tugas yang dipindah status di dashboard → tampil live; tugas yang di-assign ke agent-mu → event `task.assigned`.
258
+
259
+ ### Perintah dari dashboard (realtime)
260
+
261
+ Server bisa mengirim `agent.command` — CLI menanganinya langsung lalu membalas `command.ack`:
262
+
263
+ | Perintah | Efek di CLI |
264
+ |---|---|
265
+ | `set_model` | Simpan model ke provider config (tampil `🎛 set_model → opencode = …`), dipakai placeholder `{model}` |
266
+ | `pause` | Eksekusi `--exec` ditunda (heartbeat tetap jalan) |
267
+ | `resume` | Eksekusi dilanjutkan |
213
268
 
214
269
  ### Mode `--exec` (semi-otomatis, konfirmasi y/N)
215
270
 
216
- Bila ada tugas `To-Do` yang belum pernah dieksekusi dan default provider punya `exec_template` berisi `{task}`:
271
+ Bila ada tugas `To-Do` yang belum pernah dieksekusi dan default provider punya `exec_template` berisi `{task}` (dan tidak sedang PAUSE):
217
272
 
218
273
  1. Konfirmasi `y/N` di terminal — **tidak ada eksekusi diam-diam**.
219
- 2. CLI kirim `{status:"in_progress", agent_status:"menjalankan"}` ke server sebelum menjalankan.
220
- 3. Template dipanggil via `child_process.exec` (shell-safe escaping, timeout **15 menit**, `windowsHide` on).
274
+ 2. CLI kirim `{status:"in_progress", agent_status:"menjalankan"}` (via WS bila realtime, HTTP bila fallback).
275
+ 3. Template dipanggil via `child_process.spawn` (shell mode, `stdio:inherit` → output provider tampil live, timeout **15 menit**, `windowsHide` on).
221
276
  4. Hasil:
222
277
  - exit 0 → `{status:"done", agent_status:"selesai", progress_note:"exec exit 0"}`;
223
278
  - exit ≠ 0 → `{status:"review", agent_status:"gagal", progress_note:"exit code <n>"}`.
224
- 5. Riwayat eksekusi disimpan `~/.luang-cli/state.json` — tugas yang sama tidak ditawari dua kali. `Ctrl+C` keluar bersih.
279
+ 5. Setelah selesai, event **`telemetry.run`** (started/completed/failed + provider/model/durasi/exit_code) dikirim **hanya bila konsent telemetry aktif** (lihat bawah).
280
+ 6. Riwayat eksekusi disimpan `~/.luang-cli/state.json` — tugas yang sama tidak ditawari dua kali. `Ctrl+C` keluar bersih.
281
+
282
+ ### Background + mode otomatis (`agent start`)
283
+
284
+ Terminal boleh ditutup — daemon jalan di background:
285
+
286
+ ```bash
287
+ luang-cli agent start # background + mode auto (eksekusi To-Do TANPA konfirmasi y/N)
288
+ luang-cli agent start --no-auto # background tapi hanya memantau (tanpa eksekusi)
289
+ luang-cli agent status # pid, uptime, mode, 3 baris log terakhir
290
+ luang-cli agent logs --tail 50 # isi log
291
+ luang-cli agent stop # hentikan (SIGTERM graceful)
292
+ ```
293
+
294
+ - Child ditulis ke `~/.luang-cli/agent.pid` (`{pid, started_at, auto, mode}`), log ke `~/.luang-cli/agent.log`.
295
+ - Mode auto: tugas To-Do yang di-assign ke key ini langsung dieksekusi (termasuk via event realtime `task.assigned`); default provider + template `{task}` tetap dipakai seperti `--exec`.
296
+ - Foreground (`luang-cli agent` / `--exec`) tetap seperti dulu — konfirmasi y/N, cocok untuk percobaan manual.
297
+
298
+ ### Daftar model (`luang-cli models`)
299
+
300
+ ```bash
301
+ luang-cli models # semua provider: jumlah + daftar (wrap 6 baris)
302
+ luang-cli models opencode # satu provider
303
+ luang-cli models --json # mesin
304
+ ```
305
+
306
+ Urutan sumber: **deteksi dinamis** (untuk opencode: perintah/config lokal bila tersedia) → **registry saran statis** per provider → ketik manual selalu bisa. Hasil sync ke server (heartbeat/hello) sehingga dashboard bisa menampilkan saran model di Detail Agent. Kebijakan: binary `claude`/`gemini`/`codex` **tidak pernah dieksekusi** untuk deteksi (hanya opencode yang aman + parse file config).
307
+
308
+ ---
309
+
310
+ ## 📡 Telemetry (ops-in, konsent ganda)
311
+
312
+ Daemon bisa mengirim **data ringan** setiap kali eksekusi berjalan (`telemetry.run`): provider, model, durasi, exit_code, jumlah token (bila tersedia). **Tanpa isi kode / deskripsi tugas** — hanya metadata usage. Ini yang membuat dashboard bisa menampilkan usage & kontrol model secara realtime.
313
+
314
+ **Konsent ganda — keduanya harus ON, kalau tidak CLI tidak mengirim apa pun:**
315
+
316
+ | Level | Cara mengubah | Field |
317
+ |---|---|---|
318
+ | Lokal (mesin ini) | `luang-cli telemetry on` / `off` | `config.json → telemetry` (default `false`) |
319
+ | Server (per key) | Dashboard **Agents → toggle "Kirim telemetri"** | `agent_keys.telemetry_enabled` |
320
+
321
+ Cek status efektif:
322
+
323
+ ```bash
324
+ luang-cli telemetry status
325
+ # 📊 Telemetry — konsent ganda (opt-in, bukan opt-out)
326
+ # Lokal : config.telemetry = false ❌ (…)
327
+ # Server : telemetry_enabled = false ❌ (Agents → toggle Telemetry di dashboard)
328
+ # Efektif: lokal ❌ · server ❌ → efektif ❌ tidak dikirim
329
+ ```
330
+
331
+ Bila hanya satu yang ON → tetap tidak dikirim (dan server pun men-drop bila konsent server mati). Flag server diambil dari `/api/v1/agent/me` (atau `hello.ok` saat realtime).
225
332
 
226
333
  ---
227
334
 
@@ -257,6 +364,7 @@ Tools yang tersedia: `luang_list_tasks`, `luang_update_task_status`, `luang_crea
257
364
  |---|---|---|
258
365
  | `task status`, daemon update | **Bisa-update-tugas** (default ✅) | `can_update_tasks` |
259
366
  | `task create` | **Bisa-buat-tugas** (default ❌) | `can_create_tasks` |
367
+ | kirim `telemetry.run` (usage/model) | **Kirim telemetri** (default ❌) | `telemetry_enabled` |
260
368
 
261
369
  Bila `task create` gagal HTTP **403**, minta owner buka **app.luang.id/agents → pilih key → nyalakan \"Bisa-buat-tugas\"**, lalu cek ulang via `luang-cli whoami`.
262
370
 
@@ -272,12 +380,15 @@ File config auto-dibuat: `~/.luang-cli/config.json`
272
380
  "app_url": "https://app.luang.id",
273
381
  "key": "lk_…", // hasil login
274
382
  "name": null, // nama sesi terakhir
383
+ "telemetry": false, // konsent lokal telemetry (default OFF)
384
+ "auto_exec": false, // mode auto agent (ditulis `agent start [--no-auto]`)
275
385
  "default_provider": null,
276
- "providers": { "opencode": { "path": "…", "exec_template": "…" } }
386
+ "providers": { "opencode": { "path": "…", "exec_template": "…", "model": "sonnet-4" } }
277
387
  }
278
388
  ```
279
389
 
280
390
  State runtime (riwayat terlihat / eksekusi): `~/.luang-cli/state.json`.
391
+ Daemon background: `~/.luang-cli/agent.pid` (JSON `{pid, started_at, auto, mode}`) + `~/.luang-cli/agent.log`.
281
392
 
282
393
  | Env | Mempengaruhi |
283
394
  |---|---|
@@ -285,6 +396,9 @@ State runtime (riwayat terlihat / eksekusi): `~/.luang-cli/state.json`.
285
396
  | `LUANG_API_URL` | Timpa `api_url` |
286
397
  | `LUANG_APP_URL` | Timpa `app_url` |
287
398
  | `LUANG_NO_OPEN` | `login` tidak membuka browser otomatis (cetak URL saja) |
399
+ | `LUANG_MODEL` | Model cadangan untuk placeholder `{model}` |
400
+ | `LUANG_NO_WS` | `1`/`true` → matikan mode realtime, paksa polling HTTP |
401
+ | `LUANG_HEARTBEAT_SEC` | Interval heartbeat (detik; default internal) |
288
402
 
289
403
  Precedence: **flag `--api <url>` → env → config file**.
290
404
 
@@ -302,6 +416,12 @@ Precedence: **flag `--api <url>` → env → config file**.
302
416
  | Timeout 15 detik | Cek jaringan + `--api https://api.luang.id` |
303
417
  | Tabel provider kosong | `provider add <type> --exec_template '…'` manual |
304
418
  | `--exec` tak berjalan | Set `provider default <type>` + template harus berisi `{task}` |
419
+ | Pesan "eksekusi nonaktif" | Normal tanpa `--exec` — nyalakan dengan `luang-cli agent --exec` atau `luang-cli agent start` (mode auto) |
420
+ | `agent start` langsung mati | Cek `luang-cli agent logs` (biasanya belum `login`) |
421
+ | `agent status` bilang "pid file basi" | Proses sudah mati → `luang-cli agent stop` untuk membersihkan |
422
+ | Menunggu `{model}` (tugas ditunda) | `provider add <type> --model <m>` · env `LUANG_MODEL` · atau set_model dari dashboard |
423
+ | Daemon tak realtime (polling) | Wajar bila WS gagal — cek `LUANG_NO_WS`, proxy/firewall port WS; polling tetap jalan |
424
+ | Telemetry tak terkirim | Butuh konsent **ganda**: `luang-cli telemetry on` + toggle server di dashboard Agents |
305
425
  | Daemon boring (tak ada event) | Wajar — ia hanya print KETIKA ada perubahan; coba assign tugas dari dashboard |
306
426
  | Mulai bersih total | Hapus `~/.luang-cli/` (config + state) |
307
427
 
@@ -328,8 +448,15 @@ luang-cli/
328
448
  ├── bin/luang-cli.js # entrypoint + dispatcher
329
449
  ├── lib/
330
450
  │ ├── core.js # config, env, HTTP, provider detect, key util
331
- │ ├── commands.js # login/logout/whoami/provider
332
- │ └── agent.js # daemon, task CRUD, status, mcp-config
451
+ │ ├── ws.js # klien WebSocket RFC 6455 (zero-dep) utk mode realtime
452
+ │ ├── models.js # registry model statis + deteksi aman (hanya opencode)
453
+ │ ├── commands.js # login/logout/whoami/telemetry/provider/models
454
+ │ └── agent.js # daemon realtime+fallback (foreground & background), task CRUD, status, mcp-config
455
+ ├── test/
456
+ │ ├── run-e2e.js # E2E offline (151 assertion): realtime, fallback, konsent, model, lifecycle
457
+ │ ├── ws-stub.js # stub server WS (RFC 6455) utk uji offline
458
+ │ ├── http-stub.js # stub HTTP /agent/me + /agent/heartbeat (di-fork, IPC)
459
+ │ └── bin/opencode # stub binary provider (tidak pernah panggil claude/gemini asli)
333
460
  └── package.json # bin: luang-cli → bin/luang-cli.js
334
461
  ```
335
462
 
@@ -338,6 +465,7 @@ Jalankan dari source:
338
465
  ```bash
339
466
  node bin/luang-cli.js help
340
467
  node --check bin/luang-cli.js # sanity sintaks
468
+ node test/run-e2e.js # E2E offline penuh (tanpa jaringan/provider asli)
341
469
  ```
342
470
 
343
471
  Publish (owner):
@@ -353,11 +481,12 @@ npm publish --access public --auth-type=legacy --otp=<kode2FA>
353
481
 
354
482
  ## 🗺 Roadmap
355
483
 
484
+ - [x] Realtime WebSocket (daemon + push tugas + perintah `set_model`/`pause`/`resume`) ✅ v0.3.0
485
+ - [x] Telemetry ops-in konsent ganda + `provider --model` / placeholder `{model}` ✅ v0.3.0
356
486
  - [ ] MCP tools lanjutan: komentar tugas, subtasks, timesheet
357
487
  - [ ] `agent --exec` multi-provider (eksekusi paralel beberapa harness)
358
488
  - [ ] Skill installer (Claude Code skill / OpenCode skill yang membungkus luang-cli)
359
489
  - [ ] `luang-cli setup` wizard pertama kali (login + provider + tes)
360
- - [ ] Webhook/SSE realtime (pengganti polling)
361
490
 
362
491
  ---
363
492
 
package/bin/luang-cli.js CHANGED
@@ -17,7 +17,10 @@ Command:
17
17
  logout Hapus API key tersimpan luang-cli logout [-y]
18
18
  whoami Info sesi agent, tenant & izin luang-cli whoami
19
19
  provider Kelola provider CLI coding luang-cli provider list
20
- agent Daemon heartbeat + polling tugas luang-cli agent [--interval 5] [--exec]
20
+ telemetry Konsent telemetry on|off|status luang-cli telemetry status
21
+ workspace Folder kerja provider (sinkron dash) luang-cli workspace [path|--reset]
22
+ agent Daemon realtime WS + polling tugas luang-cli agent [--exec] · start|stop|status|logs
23
+ models Daftar model AI per provider luang-cli models [provider] [--json]
21
24
  task Kelola tugas (list|create|status) luang-cli task list
22
25
  status Ringkasan CLI (key, tenant, izin) luang-cli status
23
26
  mcp-config Snippet konfigurasi MCP klien luang-cli mcp-config
@@ -74,38 +77,127 @@ Penggunaan:
74
77
  ~/.config/opencode atau ~/.opencode (opencode), ~/.gemini (gemini_cli),
75
78
  plus which(1) untuk claude, codex, opencode, gemini.
76
79
  Bila key ada, hasil langsung disinkron via POST /api/v1/agent/heartbeat.
77
- luang-cli provider add <type> [--path P] [--exec_template T]
80
+ luang-cli provider add <type> [--path P] [--exec_template T] [--model M]
78
81
  luang-cli provider remove <type>
79
82
  luang-cli provider default <type>
80
83
 
81
84
  Param exec_template:
82
- {task} diganti judul + deskripsi tugas saat mode --exec.
83
- Contoh: 'claude -p "{task}"', 'opencode run "{task}"', 'codex exec "{task}"'
85
+ {task} diganti judul + deskripsi tugas saat mode --exec.
86
+ {model} diganti nama model (provider add --model, agent.command set_model dari
87
+ server, atau env LUANG_MODEL). Bila {model} ada tapi tidak ada model
88
+ yang bisa dipakai → eksekusi dilewati dengan notifikasi (bukan crash).
89
+ Contoh: 'opencode run --model "{model}" "{task}"'
84
90
 
85
91
  Contoh:
86
- luang-cli provider add opencode --exec_template 'opencode run "{task}"'
92
+ luang-cli provider add opencode --exec_template 'opencode run --model "{model}" "{task}"' --model opencode/gpt-5.1-codex
87
93
  luang-cli provider default opencode`,
88
94
 
89
- agent: `luang-cli agent — daemon agent (heartbeat + polling tugas)
95
+ telemetry: `luang-cli telemetry — konsent telemetry (opt-in, default OFF)
90
96
 
91
97
  Penggunaan:
92
- luang-cli agent [--interval N] [--exec]
98
+ luang-cli telemetry on|off|status
99
+
100
+ Perilaku:
101
+ • on/off mengubah config.telemetry (~/.luang-cli/config.json).
102
+ • status menampilkan DUA flag yang harus ON bersamaan:
103
+ lokal : config.telemetry (di sini)
104
+ server : agent_keys.telemetry_enabled — nyalakan di dashboard (Agents → Telemetry)
105
+ • Efektif kirim HANYA bila dua-duanya ON. Archetype frame: telemetry.run via WS
106
+ realtime (started/completed/failed saat exec) — pakai header X-CLI-Key, bukan JWT.
107
+ • Satu flag mati → CLI tidak pernah mengirim data run (server juga men-drop).`,
108
+
109
+ workspace: `luang-cli workspace — folder kerja provider (sinkron dashboard ↔ CLI)
110
+
111
+ Penggunaan:
112
+ luang-cli workspace tampilkan server/lokal/efektif + validasi folder
113
+ luang-cli workspace <path> simpan ke server (POST /agent/workspace) + lokal
114
+ luang-cli workspace --reset kosongkan (exec memakai folder saat ini)
115
+
116
+ Perilaku:
117
+ • Server adalah sumber kebenaran (dashboard Agents → Detail → Workspace Folder);
118
+ CLI menyalin ke config lokal saat hello.ok / status / whoami.
119
+ • Nilai dipakai sebagai cwd saat --exec (spawn provider). Folder tidak ada /
120
+ bukan direktori → warning + fallback ke folder saat ini.
121
+ • Bentuk path: absolut (/x/y), home (~/x), atau relatif (terhadap cwd).`,
122
+
123
+ agent: `luang-cli agent — daemon realtime (WebSocket) + fallback polling
124
+
125
+ Penggunaan (foreground):
126
+ luang-cli agent [--interval N] [--exec] [--auto]
127
+
128
+ Penggunaan (background):
129
+ luang-cli agent start [--no-auto] [--auto] spawn detached → ~/.luang-cli/agent.log
130
+ luang-cli agent stop SIGTERM + hapus ~/.luang-cli/agent.pid
131
+ luang-cli agent status pid · uptime · mode · 3 baris log terakhir
132
+ luang-cli agent logs [--tail N] tail log (default 30 baris)
133
+
134
+ Mode:
135
+ 1) Realtime WebSocket (utama): wss://<api>/api/v1/agent/ws, auth header
136
+ X-CLI-Key. Kirim hello {mode:"cli", version, providers}, lalu:
137
+ • heartbeat frame tiap ≤30s (interval 25s)
138
+ • menerima task.snapshot / task.assigned / task.updated → tampil live
139
+ • exec --exec + konfirmasi y/N seperti biasa; status tugas
140
+ (task.status) & telemetry.run dikirim via WS
141
+ • menerima agent.command: set_model (menyimpan model provider +
142
+ command.ack), pause/resume (menghentikan eksekusi; heartbeat tetap)
143
+ 2) Fallback polling HTTP (lama): bila WS gagal (kunci ditolak, server lama,
144
+ jaringan) atau env LUANG_NO_WS=1 → perilaku polling lama tetap jalan.
145
+ Telemetry tidak dikirim di mode ini (tidak ada kanal realtime).
93
146
 
94
147
  Opsi:
95
- --interval N Jeda polling GET /api/v1/agent/tasks (detik, default 5)
148
+ --interval N Jeda polling fallback HTTP (detik, default 5)
96
149
  --exec Eksekusi otomatis tugas "To-Do" yang belum dijalankan
150
+ Sebelum menjalankan: konfirmasi y/N; template dipakai dengan
151
+ {task} (judul+deskripsi) dan {model} (model provider).
152
+ exit 0 → done/"selesai"; gagal → review/"gagal exit N".
153
+ Tiap run juga mengirim telemetry.run started/completed/failed
154
+ (consent: telemetry on + flag server ON).
155
+ --auto Mode otomatis: doExec=true TANPA konfirmasi y/N (dipakai
156
+ anak proses \`agent start\`; foreground juga boleh memakai).
157
+
158
+ Background (\`agent start\`):
159
+ • spawn detached (stdio → ~/.luang-cli/agent.log, unref) + tulis
160
+ ~/.luang-cli/agent.pid berisi JSON {pid, started_at, auto, mode}.
161
+ • Default = mode AUTO: eksekusi tugas To-Do begitu terdeteksi (termasuk
162
+ event realtime task.assigned) tanpa y/N — karena tidak ada terminal.
163
+ \`--no-auto\` mematikan (monitor saja, eksekusi nonaktif).
164
+ • Pilihan ini ditulis ke config auto_exec (config.json) dan ditampilkan
165
+ oleh \`agent status\`.
166
+ • \`agent stop\` kirim SIGTERM (jalur shutdown sama dengan Ctrl+C) lalu
167
+ hapus pid file; \`agent status\` cek process.kill(pid,0) + uptime.
168
+ • Tanpa --exec dan tanpa mode auto → tugas hanya diberi tahu sekali:
169
+ "eksekusi nonaktif (jalankan \`luang-cli agent --exec\` atau \`agent start\`
170
+ untuk mode otomatis)" — TIDAK menyalahkan exec_template.
97
171
 
98
172
  Perilaku:
99
- • POST /api/v1/agent/heartbeat tiap 30 detik
100
- • Polling GET /api/v1/agent/tasks tiap N detik; baris berubah dicetak:
101
- [HH:MM:SS] TGS-1 Judul In Progress agent=… note="…"
102
- • State: ~/.luang-cli/state.json
103
- • --exec: tugas To-Do + default provider punya exec_template berisi {task}
104
- perlu konfirmasi y/N lalu dijalankan; sebelum eksekusi status di-set
105
- in_progress, lalu done ("selesai", progress_note "exec selesai") bila
106
- exit 0; review ("gagal") bila gagal. exec_template kosong/tanpa {task}
107
- → cukup notifikasi satu baris.
108
- • Ctrl+C menghentikan daemon dengan bersih.`,
173
+ • State: ~/.luang-cli/state.json · Ctrl+C keluar bersih.
174
+ • Heartbeat HTTP fallback tiap 30 detik (override: LUANG_HEARTBEAT_SEC).`,
175
+
176
+ models: `luang-cli models — daftar model AI per provider
177
+
178
+ Penggunaan:
179
+ luang-cli models [provider] [--json]
180
+
181
+ Provider: claude_code | codex | opencode | gemini_cli | custom
182
+ (tanpa argumen = semua provider)
183
+
184
+ Sumber data (berurutan):
185
+ 1. Dinamis — HANYA opencode: coba perintah \`opencode models\`, bila tidak
186
+ ada/ gagal → parse config ~/.config/opencode/ atau ~/.opencode.
187
+ KEBIJAKAN KETAT: binary claude / gemini / codex TIDAK PERNAH dijalankan.
188
+ 2. Registry statis = saran per harness (versi lama tidak masalah — ini
189
+ datalist; user tetap bisa mengetik model manual).
190
+
191
+ Tampilan: tabel Provider | Jumlah model | daftar (wrap maks 6 baris +
192
+ "…+n lagi"). \`--json\` untuk mesin: {<provider>: {provider, source, models}}.
193
+
194
+ Catatan: field \`models\` (maks 50 item, tiap ≤120 karakter) juga dikirim ke
195
+ server pada heartbeat dan hello frame WS.
196
+
197
+ Contoh:
198
+ luang-cli models
199
+ luang-cli models opencode
200
+ luang-cli models --json`,
109
201
 
110
202
  task: `luang-cli task — kelola tugas
111
203
 
@@ -147,7 +239,8 @@ config bila sudah login, selain itu placeholder.`,
147
239
 
148
240
  const VALUE_FLAGS = new Set([
149
241
  'name', 'path', 'exec_template', 'interval', 'status', 'title', 'desc',
150
- 'description', 'priority', 'due', 'note', 'agent-status', 'api',
242
+ 'description', 'priority', 'due', 'note', 'agent-status', 'api', 'model',
243
+ 'tail',
151
244
  ]);
152
245
 
153
246
  function parseArgs(argv) {
@@ -224,8 +317,14 @@ async function main() {
224
317
  return c.cmdWhoami(rt, args);
225
318
  case 'provider':
226
319
  return c.cmdProvider(rt, args);
320
+ case 'telemetry':
321
+ return c.cmdTelemetry(rt, args);
322
+ case 'workspace':
323
+ return c.cmdWorkspace(rt, args);
227
324
  case 'agent':
228
325
  return ag.cmdAgent(rt, args);
326
+ case 'models':
327
+ return c.cmdModels(rt, args);
229
328
  case 'task':
230
329
  return ag.cmdTask(rt, args);
231
330
  case 'status':