luang-cli 0.1.0 → 0.2.0
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 +278 -110
- package/bin/luang-cli.js +4 -3
- package/lib/agent.js +10 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,171 +1,239 @@
|
|
|
1
|
-
# luang-cli
|
|
1
|
+
# ⚡ luang-cli
|
|
2
2
|
|
|
3
|
-
CLI Agent Orchestration
|
|
3
|
+
> **CLI Agent Orchestration Luang** — hubungkan harness agent coding favoritmu (Claude Code, OpenCode, Codex, Gemini CLI, apapun) ke dashboard **Luang**, kelola tugas dari terminal, jalankan daemon yang memantau progress di kanban, dan eksekusi tugas dengan izin yang dikontrol admin.
|
|
4
4
|
|
|
5
|
-
-
|
|
5
|
+
   
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm i -g luang-cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## ✨ Kenapa luang-cli?
|
|
14
|
+
|
|
15
|
+
| Kebutuhan | Solusi luang-cli |
|
|
16
|
+
|---|---|
|
|
17
|
+
| Admin menugaskan coding task dari kanban dashboard | CLI menerima tugas ber-status live (`To-Do → In Progress → Review → Done`) + catatan progress + analytics |
|
|
18
|
+
| Banyak harness berbeda (Claude Code / OpenCode / Codex / Gemini) | Layer **provider** — auto-detect dari config dir / binary di PATH, atau daftar manual |
|
|
19
|
+
| Login tanpa copy-paste token manual | **Device flow**: CLI membuka browser `luang.id` → kamu approve → key diterima CLI otomatis |
|
|
20
|
+
| Integrasi AI assistant lain (bukan lewat terminal) | Server **MCP** (`luang mcp-config`) — 5 tools siap dipakai Claude Code, OpenCode, Cursor, dll |
|
|
21
|
+
| Aman lintas-tenant | Key per-laptop, hash SHA-256 di server, bisa dicabut kapan pun dari dashboard |
|
|
22
|
+
|
|
23
|
+
- **Zero-dependency**: hanya bawaan Node.js (`fetch`, `node:fs`, `node:readline`, `child_process`) — install cepat, tanpa postinstall.
|
|
6
24
|
- **Node.js ≥ 18** (butuh global `fetch`).
|
|
7
25
|
- API default: `https://api.luang.id` · Dashboard: `https://app.luang.id`
|
|
8
26
|
|
|
9
27
|
---
|
|
10
28
|
|
|
11
|
-
##
|
|
29
|
+
## 🗺 Arsitektur
|
|
12
30
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
31
|
+
```
|
|
32
|
+
┌─────────────────────┐ device flow (user_code 6 digit) ┌──────────────────────┐
|
|
33
|
+
│ luang-cli (laptop) │ ──────────────────────────────────▶ │ app.luang.id │
|
|
34
|
+
│ bin/luang-cli.js │ ◀──── api_key (via poll, sekali) ── │ halaman /cli/verify │
|
|
35
|
+
└─────────┬───────────┘ └──────────────────────┘
|
|
36
|
+
│ X-CLI-Key ▲ JWT browser
|
|
37
|
+
│ heartbeat 30s · poll tugas 5s │
|
|
38
|
+
▼ ▼
|
|
39
|
+
┌────────────────────────────────────────────────────────────────────────────┐
|
|
40
|
+
│ api.luang.id → modul agent │
|
|
41
|
+
│ device_approvals · agent_keys · agent_providers │
|
|
42
|
+
│ tasks(agent_key_id/agent_status/agent_progress_note) · insights │
|
|
43
|
+
│ POST /api/v1/agent/mcp ← JSON-RPC 2.0 (MCP tools) │
|
|
44
|
+
└────────────────────────────────────────────────────────────────────────────┘
|
|
17
45
|
```
|
|
18
46
|
|
|
19
|
-
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## 📦 Instalasi
|
|
20
50
|
|
|
21
51
|
```bash
|
|
52
|
+
# Dari registry npm (recommended, setelah publish)
|
|
22
53
|
npm i -g luang-cli
|
|
54
|
+
|
|
55
|
+
# Atau dari source repo ini
|
|
56
|
+
git clone https://github.com/yudono/Luang && cd Luang/luang-cli
|
|
57
|
+
npm i -g . # tanpa dependensi, instan
|
|
58
|
+
|
|
59
|
+
# Atau run tanpa install
|
|
60
|
+
npx luang-cli help
|
|
23
61
|
```
|
|
24
62
|
|
|
25
63
|
Cek instalasi:
|
|
26
64
|
|
|
27
65
|
```bash
|
|
28
66
|
luang-cli help
|
|
67
|
+
luang-cli --version
|
|
29
68
|
```
|
|
30
69
|
|
|
70
|
+
Upgrade: `npm i -g luang-cli@latest`
|
|
71
|
+
|
|
31
72
|
---
|
|
32
73
|
|
|
33
|
-
##
|
|
74
|
+
## 🚀 Quick start (±60 detik)
|
|
34
75
|
|
|
35
|
-
|
|
76
|
+
```bash
|
|
77
|
+
# 1. Login via browser (device flow)
|
|
78
|
+
luang-cli login --name "Laptop Kantor"
|
|
79
|
+
# → CLI membuka https://app.luang.id/cli/verify?code=123456
|
|
80
|
+
# → Login dashboard bila perlu → klik "Setujui"
|
|
81
|
+
# → CLI otomatis menerima key & menyimpannya
|
|
36
82
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
"api_url": "https://api.luang.id",
|
|
40
|
-
"app_url": "https://app.luang.id",
|
|
41
|
-
"key": null,
|
|
42
|
-
"default_provider": null,
|
|
43
|
-
"providers": {}
|
|
44
|
-
}
|
|
45
|
-
```
|
|
83
|
+
# 2. Verifikasi sesi
|
|
84
|
+
luang-cli whoami
|
|
46
85
|
|
|
47
|
-
|
|
86
|
+
# 3. (opsional) daftarkan harness agent di laptop-mu
|
|
87
|
+
luang-cli provider list # auto-detect
|
|
88
|
+
luang-cli provider default opencode
|
|
48
89
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
90
|
+
# 4. Jalanin daemon — lihat tugas update live di terminal
|
|
91
|
+
luang-cli agent
|
|
92
|
+
|
|
93
|
+
# 5. Dari dashboard: assign tugas ke agent-mu (halaman Agents)
|
|
94
|
+
# …terminal-mu langsung berisik: TGS-1 versi baru terdeteksi 👀
|
|
95
|
+
luang-cli task list
|
|
96
|
+
luang-cli task status TGS-1 in_progress --note "mulai refactor"
|
|
97
|
+
```
|
|
55
98
|
|
|
56
99
|
---
|
|
57
100
|
|
|
58
|
-
## Alur login → verify (device flow)
|
|
101
|
+
## 🔐 Alur login → verify (device flow)
|
|
59
102
|
|
|
60
|
-
|
|
103
|
+
```
|
|
104
|
+
CLI API Browser (kamu)
|
|
105
|
+
│ POST /agent/device/start │ │
|
|
106
|
+
│ ──────────────────────────▶ │ │
|
|
107
|
+
│ ◀─ device_code + user_code │ │
|
|
108
|
+
│ │ │
|
|
109
|
+
│ buka verify_url (6 digit) │ │
|
|
110
|
+
│ ──────────────────────────────────────────────────────────────────▶ │
|
|
111
|
+
│ │ GET /agent/device/lookup (JWT) │
|
|
112
|
+
│ │ ◀─────────────────────────────────── │
|
|
113
|
+
│ │ klik "Setujui" → agent_keys dibuat │
|
|
114
|
+
│ │ ◀─────────────────────────────────── │
|
|
115
|
+
│ GET /agent/device/poll (2s)│ │
|
|
116
|
+
│ ──────────────────────────▶ │ │
|
|
117
|
+
│ ◀─ {status:"approved", │ │
|
|
118
|
+
│ api_key:"lk_…"} │ ← plaintext key dikirim SEKALI, │
|
|
119
|
+
│ │ lalu dihapus dari server │
|
|
120
|
+
```
|
|
61
121
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
122
|
+
- `user_code` 6 digit, sesi kedaluwarsa **10 menit**. Sesi `denied`/`expired` → CLI keluar dengan pesan jelas.
|
|
123
|
+
- Nama sesi default `hostname-OS` — ganti dengan `--name "Laptop Kantor"`.
|
|
124
|
+
- Key dikirim sekali saja (`approved` tanpa `api_key` berarti sudah pernah diambil).
|
|
125
|
+
- Buka browser bisa dimatikan dengan env `LUANG_NO_OPEN=1` (URL tetap dicetak) — pas untuk CI/remote SSH.
|
|
65
126
|
|
|
66
|
-
|
|
67
|
-
Kode besar ditampilkan gaya banner ASCII dan browser dibuka ke `verify_url`
|
|
68
|
-
(bila browser gagal, URL tetap dicetak — cukup buka manual).
|
|
69
|
-
3. Masukkan `user_code` di dashboard, lalu **approve**.
|
|
70
|
-
4. CLI mem-poll `GET /api/v1/agent/device/poll` tiap 2 detik (batas 10 menit):
|
|
71
|
-
- `approved` + `api_key` → key tersimpan, CLI mencetak nama sesi, tenant, dan prefix key (`lk_xxxxxx…`).
|
|
72
|
-
- `approved` **tanpa** `api_key` → key sudah pernah diambil sebelumnya; pakai key lama atau buat sesi agent baru di dashboard.
|
|
73
|
-
- `denied` / `expired` → pesan jelas + exit 1.
|
|
74
|
-
5. Verifikasi:
|
|
127
|
+
### Keamanan
|
|
75
128
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
129
|
+
- Server hanya menyimpan **SHA-256** dari key; plaintext tak pernah persist selain window pickup.
|
|
130
|
+
- Key ber-lingkup **tenant + owner** (upload/assign lintas tenant mustahil — repo layer tenant-scoped).
|
|
131
|
+
- Revocation instan dari dashboard (**Agents → Revoke**) — request berikutnya langsung 401.
|
|
79
132
|
|
|
80
133
|
---
|
|
81
134
|
|
|
82
|
-
## Daftar command
|
|
135
|
+
## 🧭 Daftar command
|
|
83
136
|
|
|
84
137
|
| Command | Fungsi | Contoh |
|
|
85
138
|
|---|---|---|
|
|
139
|
+
| `help` / `--version` | Daftar command / versi | `luang-cli help agent` |
|
|
86
140
|
| `login` | Login device flow via browser | `luang-cli login --name "Laptop Kantor"` |
|
|
87
141
|
| `logout` | Hapus API key tersimpan (`-y` tanpa konfirmasi) | `luang-cli logout -y` |
|
|
88
|
-
| `whoami` | Info sesi, tenant, izin | `luang-cli whoami` |
|
|
89
|
-
| `
|
|
90
|
-
| `provider
|
|
142
|
+
| `whoami` | Info sesi: nama, tenant, izin, provider | `luang-cli whoami` |
|
|
143
|
+
| `status` | Ringkasan singkat CLI | `luang-cli status` |
|
|
144
|
+
| `provider list` | Deteksi otomatis + tabel (`--json`) | `luang-cli provider list` |
|
|
145
|
+
| `provider add` | Tambah / override provider config | `luang-cli provider add codex --exec_template 'codex exec "{task}"'` |
|
|
91
146
|
| `provider remove` | Hapus provider dari config | `luang-cli provider remove codex` |
|
|
92
|
-
| `provider default` | Set default
|
|
93
|
-
| `agent` | Daemon heartbeat +
|
|
94
|
-
| `task list` | Daftar tugas (filter) | `luang-cli task list --status todo` |
|
|
95
|
-
| `task create` | Buat tugas (butuh izin admin) | `luang-cli task create --title "Refactor auth" --priority high
|
|
96
|
-
| `task status` |
|
|
97
|
-
| `
|
|
98
|
-
| `mcp-config` | Snippet konfigurasi MCP | `luang-cli mcp-config` |
|
|
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` |
|
|
149
|
+
| `task list` | Daftar tugas agent (filter status) | `luang-cli task list --status todo` |
|
|
150
|
+
| `task create` | Buat tugas (butuh izin admin) | `luang-cli task create --title "Refactor auth" --priority high` |
|
|
151
|
+
| `task status` | Perbarui status + catatan progress | `luang-cli task status TGS-12 in_progress --note "mulai"` |
|
|
152
|
+
| `mcp-config` | Cetak blok konfigurasi MCP siap-tempel | `luang-cli mcp-config` |
|
|
99
153
|
|
|
100
|
-
|
|
154
|
+
Dokumen bantuan per-com: `luang-cli <command> --help` (mis. `luang-cli agent --help`).
|
|
101
155
|
|
|
102
|
-
|
|
156
|
+
### Pemetaan nilai
|
|
103
157
|
|
|
104
|
-
|
|
158
|
+
**Status tugas** (CLI → server kanban):
|
|
105
159
|
|
|
106
|
-
|
|
107
|
-
|
|
160
|
+
| CLI token | Kanban dashboard |
|
|
161
|
+
|---|---|
|
|
162
|
+
| `todo` / `to_do` | `To-Do` |
|
|
163
|
+
| `in_progress` / `progress` | `In Progress` |
|
|
164
|
+
| `review` | `Review` |
|
|
165
|
+
| `done` / `completed` | `Done` |
|
|
108
166
|
|
|
109
|
-
|
|
110
|
-
|---|---|---|
|
|
111
|
-
| `task create` | Bisa-buat-tugas | `can_create_tasks` (HTTP 403 bila belum aktif) |
|
|
112
|
-
| `agent --exec` / `task status` | Bisa-update-tugas | `can_update_tasks` |
|
|
167
|
+
Selain status kanban, bisa kirim **`--agent-status`** (status mesin singkat, mis. `membaca repo`) dan **`--note`** (catatan progress yang tampil di dashboard).
|
|
113
168
|
|
|
114
|
-
|
|
169
|
+
**Prioritas** untuk `task create`: `high` → `Tinggi` · `medium` → `Sedang` · `low` → `Rendah`.
|
|
170
|
+
**Referensi tugas**: pakai kode `TGS-<n>` (mis. `TGS-7`) atau UUID id tugas.
|
|
115
171
|
|
|
116
172
|
---
|
|
117
173
|
|
|
118
|
-
## Integrasi provider (
|
|
174
|
+
## 🛠 Integrasi provider (multi-harness)
|
|
119
175
|
|
|
120
|
-
|
|
176
|
+
Auto-detect (`provider list`):
|
|
121
177
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
178
|
+
| Provider | Dari | exec_template default |
|
|
179
|
+
|---|---|---|
|
|
180
|
+
| `claude_code` | `~/.claude` / binary `claude` | `claude -p "{task}"` |
|
|
181
|
+
| `codex` | `~/.codex` / binary `codex` | `codex exec "{task}"` |
|
|
182
|
+
| `opencode` | `~/.config/opencode` / `~/.opencode` / binary `opencode` | `opencode run "{task}"` |
|
|
183
|
+
| `gemini_cli` | `~/.gemini` / binary `gemini` | `gemini -p "{task}"` |
|
|
127
184
|
|
|
128
|
-
|
|
185
|
+
Daftar manual (path khusus, alias brand, multi-provider):
|
|
129
186
|
|
|
130
187
|
```bash
|
|
131
|
-
luang-cli provider add claude_code --path /
|
|
188
|
+
luang-cli provider add claude_code --path /opt/homebrew/bin/claude \
|
|
132
189
|
--exec_template 'claude -p "{task}"'
|
|
133
|
-
luang-cli provider add
|
|
134
|
-
luang-cli provider
|
|
135
|
-
luang-cli provider default opencode
|
|
190
|
+
luang-cli provider add opencode --exec_template 'opencode run "{task}"'
|
|
191
|
+
luang-cli provider default claude_code
|
|
136
192
|
```
|
|
137
193
|
|
|
138
|
-
`{task}` pada
|
|
139
|
-
|
|
140
|
-
Bila key sudah ada, daftar provider otomatis disinkron ke server lewat
|
|
141
|
-
`POST /api/v1/agent/heartbeat`.
|
|
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).
|
|
142
196
|
|
|
143
197
|
---
|
|
144
198
|
|
|
145
|
-
## Daemon agent
|
|
199
|
+
## 🖥 Daemon agent (`luang-cli agent`)
|
|
146
200
|
|
|
147
201
|
```bash
|
|
148
|
-
luang-cli agent
|
|
149
|
-
luang-cli agent --interval 10
|
|
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
|
|
150
205
|
```
|
|
151
206
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
207
|
+
Perilaku:
|
|
208
|
+
|
|
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.
|
|
211
|
+
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.
|
|
213
|
+
|
|
214
|
+
### Mode `--exec` (semi-otomatis, konfirmasi y/N)
|
|
215
|
+
|
|
216
|
+
Bila ada tugas `To-Do` yang belum pernah dieksekusi dan default provider punya `exec_template` berisi `{task}`:
|
|
217
|
+
|
|
218
|
+
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).
|
|
221
|
+
4. Hasil:
|
|
222
|
+
- exit 0 → `{status:"done", agent_status:"selesai", progress_note:"exec exit 0"}`;
|
|
223
|
+
- 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.
|
|
162
225
|
|
|
163
226
|
---
|
|
164
227
|
|
|
165
|
-
##
|
|
228
|
+
## 🎛 Integrasi MCP (tanpa terminal)
|
|
229
|
+
|
|
230
|
+
Luang juga menyediakan server MCP (JSON-RPC 2.0) di `POST /api/v1/agent/mcp` dengan auth header `X-CLI-Key` — pas untuk Claude Code, OpenCode, Cursor, dll.
|
|
231
|
+
|
|
232
|
+
Cetak blok konfigurasi siap-tempel:
|
|
166
233
|
|
|
167
|
-
|
|
168
|
-
|
|
234
|
+
```bash
|
|
235
|
+
luang-cli mcp-config
|
|
236
|
+
```
|
|
169
237
|
|
|
170
238
|
```json
|
|
171
239
|
{
|
|
@@ -173,27 +241,127 @@ luang-cli agent --interval 10 --exec
|
|
|
173
241
|
"luang": {
|
|
174
242
|
"type": "http",
|
|
175
243
|
"url": "https://api.luang.id/api/v1/agent/mcp",
|
|
176
|
-
"headers": {
|
|
177
|
-
"X-CLI-Key": "lk_xxxxxxxx"
|
|
178
|
-
}
|
|
244
|
+
"headers": { "X-CLI-Key": "lk_xxxxxxxx…" }
|
|
179
245
|
}
|
|
180
246
|
}
|
|
181
247
|
}
|
|
182
248
|
```
|
|
183
249
|
|
|
184
|
-
|
|
185
|
-
otomatis).
|
|
250
|
+
Tools yang tersedia: `luang_list_tasks`, `luang_update_task_status`, `luang_create_task`, `luang_heartbeat`, `luang_me` — reuse service yang sama dengan CLI, jadi izin per key tetap berlaku.
|
|
186
251
|
|
|
187
252
|
---
|
|
188
253
|
|
|
189
|
-
##
|
|
254
|
+
## 🔑 Izin agent (dikontrol dari dashboard)
|
|
255
|
+
|
|
256
|
+
| Aksi CLI | Izin di dashboard | Field backend |
|
|
257
|
+
|---|---|---|
|
|
258
|
+
| `task status`, daemon update | **Bisa-update-tugas** (default ✅) | `can_update_tasks` |
|
|
259
|
+
| `task create` | **Bisa-buat-tugas** (default ❌) | `can_create_tasks` |
|
|
260
|
+
|
|
261
|
+
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
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## ⚙️ Konfigurasi
|
|
266
|
+
|
|
267
|
+
File config auto-dibuat: `~/.luang-cli/config.json`
|
|
268
|
+
|
|
269
|
+
```json
|
|
270
|
+
{
|
|
271
|
+
"api_url": "https://api.luang.id",
|
|
272
|
+
"app_url": "https://app.luang.id",
|
|
273
|
+
"key": "lk_…", // hasil login
|
|
274
|
+
"name": null, // nama sesi terakhir
|
|
275
|
+
"default_provider": null,
|
|
276
|
+
"providers": { "opencode": { "path": "…", "exec_template": "…" } }
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
State runtime (riwayat terlihat / eksekusi): `~/.luang-cli/state.json`.
|
|
281
|
+
|
|
282
|
+
| Env | Mempengaruhi |
|
|
283
|
+
|---|---|
|
|
284
|
+
| `LUANG_KEY` | Timpa key tanpa menyentuh config (pas untuk CI) |
|
|
285
|
+
| `LUANG_API_URL` | Timpa `api_url` |
|
|
286
|
+
| `LUANG_APP_URL` | Timpa `app_url` |
|
|
287
|
+
| `LUANG_NO_OPEN` | `login` tidak membuka browser otomatis (cetak URL saja) |
|
|
288
|
+
|
|
289
|
+
Precedence: **flag `--api <url>` → env → config file**.
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
## 🧯 Troubleshooting
|
|
190
294
|
|
|
191
295
|
| Gejala | Solusi |
|
|
192
296
|
|---|---|
|
|
193
|
-
| `❌ Belum login` |
|
|
194
|
-
| HTTP 401 di semua command | Key ditolak → `luang-cli logout` lalu `login` ulang |
|
|
195
|
-
| HTTP 403 saat `task create` |
|
|
196
|
-
|
|
|
197
|
-
|
|
|
198
|
-
|
|
|
199
|
-
|
|
|
297
|
+
| `❌ Belum login` | `luang-cli login`, atau set env `LUANG_KEY` |
|
|
298
|
+
| HTTP 401 di semua command | Key ditolak/dicabut → `luang-cli logout` lalu `login` ulang |
|
|
299
|
+
| HTTP 403 saat `task create` | Admin belum aktifkan izin **Bisa-buat-tugas** (lihat seksi Izin) |
|
|
300
|
+
| `Sesi login kedaluwarsa` | Sesi device flow lewat 10 menit → jalankan `login` lagi |
|
|
301
|
+
| `key sudah pernah diambil` | Browser approve dua kali / poll dijalankan 2× → buat sesi agent baru |
|
|
302
|
+
| Timeout 15 detik | Cek jaringan + `--api https://api.luang.id` |
|
|
303
|
+
| Tabel provider kosong | `provider add <type> --exec_template '…'` manual |
|
|
304
|
+
| `--exec` tak berjalan | Set `provider default <type>` + template harus berisi `{task}` |
|
|
305
|
+
| Daemon boring (tak ada event) | Wajar — ia hanya print KETIKA ada perubahan; coba assign tugas dari dashboard |
|
|
306
|
+
| Mulai bersih total | Hapus `~/.luang-cli/` (config + state) |
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
## 💡 Mengapa dashboard perlu agent ini?
|
|
311
|
+
|
|
312
|
+
Dengan pasangan **Luang dashboard + luang-cli**, satu workspace bisa:
|
|
313
|
+
|
|
314
|
+
1. **Orchestrate** banyak user × banyak mesin × banyak harness, dengan kontrol izin per key.
|
|
315
|
+
2. **Kanban + analytics live**: `To-Do / In Progress / Review / Done` per agent + provider count + 5 tugas terakhir (modul **Agents**).
|
|
316
|
+
3. **Fleksibilitas dua jalur**: operasionalisasi lewat CLI, atau tools MCP bagi AI assistantmu.
|
|
317
|
+
|
|
318
|
+
Baca arsitektur & kontrak API lengkapnya di [`docs/agent-orchestration.md`](../docs/agent-orchestration.md).
|
|
319
|
+
|
|
320
|
+
---
|
|
321
|
+
|
|
322
|
+
## 🧪 Development
|
|
323
|
+
|
|
324
|
+
Struktur repo (folder `luang-cli/` di monorepo [yudono/Luang](https://github.com/yudono/Luang)):
|
|
325
|
+
|
|
326
|
+
```
|
|
327
|
+
luang-cli/
|
|
328
|
+
├── bin/luang-cli.js # entrypoint + dispatcher
|
|
329
|
+
├── lib/
|
|
330
|
+
│ ├── 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
|
|
333
|
+
└── package.json # bin: luang-cli → bin/luang-cli.js
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
Jalankan dari source:
|
|
337
|
+
|
|
338
|
+
```bash
|
|
339
|
+
node bin/luang-cli.js help
|
|
340
|
+
node --check bin/luang-cli.js # sanity sintaks
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
Publish (owner):
|
|
344
|
+
|
|
345
|
+
```bash
|
|
346
|
+
cd luang-cli
|
|
347
|
+
npm publish --access public --auth-type=legacy --otp=<kode2FA>
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
> Versi di `package.json` adalah sumber kebenaran — bump sebelum publish (`npm version patch`).
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
354
|
+
## 🗺 Roadmap
|
|
355
|
+
|
|
356
|
+
- [ ] MCP tools lanjutan: komentar tugas, subtasks, timesheet
|
|
357
|
+
- [ ] `agent --exec` multi-provider (eksekusi paralel beberapa harness)
|
|
358
|
+
- [ ] Skill installer (Claude Code skill / OpenCode skill yang membungkus luang-cli)
|
|
359
|
+
- [ ] `luang-cli setup` wizard pertama kali (login + provider + tes)
|
|
360
|
+
- [ ] Webhook/SSE realtime (pengganti polling)
|
|
361
|
+
|
|
362
|
+
---
|
|
363
|
+
|
|
364
|
+
## 📄 Lisensi
|
|
365
|
+
|
|
366
|
+
**MIT** — © 2026 Yudono / Luang.
|
|
367
|
+
Link utama: [app.luang.id](https://app.luang.id) · [api.luang.id](https://api.luang.id/health) · [Luang repo](https://github.com/yudono/Luang)
|
package/bin/luang-cli.js
CHANGED
|
@@ -98,12 +98,13 @@ Opsi:
|
|
|
98
98
|
Perilaku:
|
|
99
99
|
• POST /api/v1/agent/heartbeat tiap 30 detik
|
|
100
100
|
• Polling GET /api/v1/agent/tasks tiap N detik; baris berubah dicetak:
|
|
101
|
-
TGS-1 Judul In Progress
|
|
101
|
+
[HH:MM:SS] TGS-1 Judul In Progress agent=… note="…"
|
|
102
102
|
• State: ~/.luang-cli/state.json
|
|
103
103
|
• --exec: tugas To-Do + default provider punya exec_template berisi {task}
|
|
104
104
|
perlu konfirmasi y/N lalu dijalankan; sebelum eksekusi status di-set
|
|
105
|
-
in_progress
|
|
106
|
-
review ("gagal") bila gagal.
|
|
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.
|
|
107
108
|
• Ctrl+C menghentikan daemon dengan bersih.`,
|
|
108
109
|
|
|
109
110
|
task: `luang-cli task — kelola tugas
|
package/lib/agent.js
CHANGED
|
@@ -41,9 +41,10 @@ function taskIdFingerprint(t) {
|
|
|
41
41
|
function printTaskLine(t, tag) {
|
|
42
42
|
const code = c.taskIdOf(t) || '?';
|
|
43
43
|
let tail = '';
|
|
44
|
-
if (t.agent_status) tail += `
|
|
45
|
-
if (t.agent_progress_note) tail += (tail ? ' ' : '') +
|
|
46
|
-
|
|
44
|
+
if (t.agent_status) tail += `[${t.agent_status}]`;
|
|
45
|
+
if (t.agent_progress_note) tail += (tail ? ' ' : '') + t.agent_progress_note;
|
|
46
|
+
const stamp = tag ? ` (${stampNow()} ${trunc(tag, 16)})` : '';
|
|
47
|
+
console.log(`${code} ${trunc(t.title, 36)} ${t.status || '-'} ${tail}${stamp}`.replace(/\s+$/, ''));
|
|
47
48
|
}
|
|
48
49
|
|
|
49
50
|
function buildExecCommand(tpl, taskText) {
|
|
@@ -107,10 +108,10 @@ async function tryExecTask(rt, tasks, state, execCfg, current) {
|
|
|
107
108
|
saveState(state);
|
|
108
109
|
return true;
|
|
109
110
|
}
|
|
110
|
-
// Spesifikasi:
|
|
111
|
+
// Spesifikasi: sebelum eksekusi, tandai in_progress dengan agent_status "menjalankan".
|
|
111
112
|
try {
|
|
112
113
|
await apiRequest(rt, 'POST', `/api/v1/agent/tasks/${encodeURIComponent(code)}/status`, {
|
|
113
|
-
body: { status: 'in_progress' },
|
|
114
|
+
body: { status: 'in_progress', agent_status: 'menjalankan' },
|
|
114
115
|
});
|
|
115
116
|
} catch (e) {
|
|
116
117
|
console.error(`⚠️ Gagal set in_progress: ${e.message}`);
|
|
@@ -119,13 +120,13 @@ async function tryExecTask(rt, tasks, state, execCfg, current) {
|
|
|
119
120
|
current.child = child;
|
|
120
121
|
});
|
|
121
122
|
const ok = exitCode === 0;
|
|
122
|
-
// Spesifikasi: exit 0 → {status:"done", agent_status:"selesai", progress_note:"exec
|
|
123
|
-
// selain itu → {status:"review", agent_status:"gagal"}.
|
|
123
|
+
// Spesifikasi: exit 0 → {status:"done", agent_status:"selesai", progress_note:"exec exit 0"};
|
|
124
|
+
// selain itu → {status:"review", agent_status:"gagal", progress_note:"exit code N"}.
|
|
124
125
|
try {
|
|
125
126
|
await apiRequest(rt, 'POST', `/api/v1/agent/tasks/${encodeURIComponent(code)}/status`, {
|
|
126
127
|
body: ok
|
|
127
|
-
? { status: 'done', agent_status: 'selesai', progress_note: 'exec
|
|
128
|
-
: { status: 'review', agent_status: 'gagal' },
|
|
128
|
+
? { status: 'done', agent_status: 'selesai', progress_note: 'exec exit 0' }
|
|
129
|
+
: { status: 'review', agent_status: 'gagal', progress_note: `exit code ${exitCode}` },
|
|
129
130
|
});
|
|
130
131
|
} catch (e) {
|
|
131
132
|
console.error(`⚠️ Gagal update status tugas: ${e.message}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "luang-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "CLI Agent Orchestration Luang — login device flow, sinkronisasi provider AI, daemon tugas, dan manajemen task dari terminal. Zero-dependency, Node >= 18.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|