luang-cli 0.0.0-stage → 0.1.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 +198 -2
- package/bin/luang-cli.js +247 -0
- package/lib/agent.js +424 -0
- package/lib/commands.js +337 -0
- package/lib/core.js +442 -0
- package/package.json +17 -4
package/README.md
CHANGED
|
@@ -1,3 +1,199 @@
|
|
|
1
|
-
#
|
|
1
|
+
# luang-cli
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
CLI Agent Orchestration **Luang** — login device flow, sinkronisasi provider AI local, daemon agent (heartbeat + polling tugas), dan manajemen task dari terminal.
|
|
4
|
+
|
|
5
|
+
- **Zero-dependency**: tidak ada `npm install` — hanya bawaan Node.js (`fetch`, `node:fs`, `node:readline`, `child_process`).
|
|
6
|
+
- **Node.js ≥ 18** (butuh global `fetch`).
|
|
7
|
+
- API default: `https://api.luang.id` · Dashboard: `https://app.luang.id`
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Instalasi
|
|
12
|
+
|
|
13
|
+
Dari folder repo ini (lokal):
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm i -g .
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Setelah package dipublish, cukup:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm i -g luang-cli
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Cek instalasi:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
luang-cli help
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Konfigurasi lokal
|
|
34
|
+
|
|
35
|
+
File config: `~/.luang-cli/config.json` (dibuat otomatis saat login simpan key):
|
|
36
|
+
|
|
37
|
+
```json
|
|
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
|
+
```
|
|
46
|
+
|
|
47
|
+
Override (urutan: flag → env → config):
|
|
48
|
+
|
|
49
|
+
| Sumber | Tutorial |
|
|
50
|
+
|---|---|
|
|
51
|
+
| `LUANG_API_URL` | Timpa `api_url` |
|
|
52
|
+
| `LUANG_APP_URL` | Timpa `app_url` |
|
|
53
|
+
| `LUANG_KEY` | Timpa key (tanpa menyentuh config) |
|
|
54
|
+
| `--api <url>` | Timpa URL API di command mana pun |
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Alur login → verify (device flow)
|
|
59
|
+
|
|
60
|
+
1. Jalankan:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
luang-cli login --name "Laptop Kantor"
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
2. CLI meminta `device_code` + `user_code` dari `POST /api/v1/agent/device/start`.
|
|
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:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
luang-cli whoami
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## Daftar command
|
|
83
|
+
|
|
84
|
+
| Command | Fungsi | Contoh |
|
|
85
|
+
|---|---|---|
|
|
86
|
+
| `login` | Login device flow via browser | `luang-cli login --name "Laptop Kantor"` |
|
|
87
|
+
| `logout` | Hapus API key tersimpan (`-y` tanpa konfirmasi) | `luang-cli logout -y` |
|
|
88
|
+
| `whoami` | Info sesi, tenant, izin | `luang-cli whoami` |
|
|
89
|
+
| `provider list` | Deteksi + tabel provider (`--json`) | `luang-cli provider list` |
|
|
90
|
+
| `provider add` | Tambah/override provider di config | `luang-cli provider add opencode --exec_template 'opencode run "{task}"'` |
|
|
91
|
+
| `provider remove` | Hapus provider dari config | `luang-cli provider remove codex` |
|
|
92
|
+
| `provider default` | Set default provider (dipakai `agent --exec`) | `luang-cli provider default opencode` |
|
|
93
|
+
| `agent` | Daemon heartbeat + polling tugas | `luang-cli agent --interval 5 --exec` |
|
|
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 --due 2026-11-01` |
|
|
96
|
+
| `task status` | Ubah status tugas | `luang-cli task status TGS-12 in_progress --note "mulai analisis"` |
|
|
97
|
+
| `status` | Ringkasan CLI (key/tenant/izin/provider) | `luang-cli status` |
|
|
98
|
+
| `mcp-config` | Snippet konfigurasi MCP | `luang-cli mcp-config` |
|
|
99
|
+
|
|
100
|
+
Bantuan per command: `luang-cli <command> --help` (contoh `luang-cli agent --help`).
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Izin agent di dashboard
|
|
105
|
+
|
|
106
|
+
Beberapa aksi butuh izin yang diberikan admin/owner lewat dashboard
|
|
107
|
+
(**Agents → izin**):
|
|
108
|
+
|
|
109
|
+
| Aksi CLI | Izin | Field |
|
|
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` |
|
|
113
|
+
|
|
114
|
+
Cek izin kapan pun dengan `luang-cli whoami` atau `luang-cli status`.
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Integrasi provider (manual)
|
|
119
|
+
|
|
120
|
+
`luang-cli provider list` mendeteksi otomatis:
|
|
121
|
+
|
|
122
|
+
- `~/.claude` → `claude_code`
|
|
123
|
+
- `~/.codex` → `codex`
|
|
124
|
+
- `~/.config/opencode` atau `~/.opencode` → `opencode`
|
|
125
|
+
- `~/.gemini` → `gemini_cli`
|
|
126
|
+
- plus `which(1)` untuk binary `claude`, `codex`, `opencode`, `gemini`
|
|
127
|
+
|
|
128
|
+
Bila tidak terdeteksi (atau butuh aturan khusus), daftarkan manual:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
luang-cli provider add claude_code --path /usr/local/bin/claude \
|
|
132
|
+
--exec_template 'claude -p "{task}"'
|
|
133
|
+
luang-cli provider add codex --exec_template 'codex exec "{task}"'
|
|
134
|
+
luang-cli provider add opencode --exec_template 'opencode run "{task}"'
|
|
135
|
+
luang-cli provider default opencode
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
`{task}` pada `exec_template` otomatis diganti **judul + deskripsi** tugas.
|
|
139
|
+
Template tanpa `{task}` tidak bisa dipakai mode `--exec`.
|
|
140
|
+
Bila key sudah ada, daftar provider otomatis disinkron ke server lewat
|
|
141
|
+
`POST /api/v1/agent/heartbeat`.
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## Daemon agent
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
luang-cli agent # heartbeat 30 detik, poll tugas 5 detik
|
|
149
|
+
luang-cli agent --interval 10 --exec
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
- Heartbeat (`POST /api/v1/agent/heartbeat`) tiap 30 detik.
|
|
153
|
+
- Polling `GET /api/v1/agent/tasks` tiap `--interval` detik (default 5).
|
|
154
|
+
- Perubahan tugas dicetak satu baris: `TGS-1 Judul In Progress [agent_status] note`.
|
|
155
|
+
- State daftar run disimpan di `~/.luang-cli/state.json` (terakhir `agent_updated_at`/`updated_at` per tugas + riwayat tugas yang sudah dieksekusi).
|
|
156
|
+
- `--exec`: tugas berstatus `To-Do` yang belum dijalankan, saat default provider punya `exec_template` berisi `{task}`:
|
|
157
|
+
1. konfirmasi `y/N` di terminal,
|
|
158
|
+
2. status dikirim `in_progress` (`agent_status: menjalankan`),
|
|
159
|
+
3. template dijalankan via `child_process.exec` setelah `{task}` diganti,
|
|
160
|
+
4. exit 0 → `done` ("selesai", note `exec exit 0`); gagal → `review` ("gagal", note `exit code N`).
|
|
161
|
+
- `Ctrl+C` menghentikan daemon dengan bersih (exit 0).
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Konfigurasi MCP
|
|
166
|
+
|
|
167
|
+
`luang-cli mcp-config` mencetak blok JSON siap-tempel untuk klien MCP
|
|
168
|
+
(endpoint `POST /api/v1/agent/mcp`, autentikasi header `X-CLI-Key`):
|
|
169
|
+
|
|
170
|
+
```json
|
|
171
|
+
{
|
|
172
|
+
"mcpServers": {
|
|
173
|
+
"luang": {
|
|
174
|
+
"type": "http",
|
|
175
|
+
"url": "https://api.luang.id/api/v1/agent/mcp",
|
|
176
|
+
"headers": {
|
|
177
|
+
"X-CLI-Key": "lk_xxxxxxxx"
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Ganti `lk_xxxxxxxx` dengan key asli (bila sudah `login`, CLI menuliskannya
|
|
185
|
+
otomatis).
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## Troubleshooting
|
|
190
|
+
|
|
191
|
+
| Gejala | Solusi |
|
|
192
|
+
|---|---|
|
|
193
|
+
| `❌ Belum login` | Jalankan `luang-cli login`, atau set env `LUANG_KEY` |
|
|
194
|
+
| HTTP 401 di semua command | Key ditolak → `luang-cli logout` lalu `login` ulang |
|
|
195
|
+
| HTTP 403 saat `task create` | Minta admin aktifkan izin **Bisa-buat-tugas** |
|
|
196
|
+
| Timeout 15 detik | Cek jaringan / coba `--api <url>` menunjuk API yang benar |
|
|
197
|
+
| Tabel provider kosong | Daftar manual `provider add <type> --exec_template '…'` |
|
|
198
|
+
| `--exec` tidak berjalan | Pastikan `provider default <type>` + template berisi `{task}` |
|
|
199
|
+
| Mulai bersih | Hapus `~/.luang-cli/state.json` (riwayat eksekusi & status) |
|
package/bin/luang-cli.js
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
// bin/luang-cli.js — entry point CLI Luang: parsing argumen, dispatch, help.
|
|
5
|
+
|
|
6
|
+
const pkg = require('../package.json');
|
|
7
|
+
const core = require('../lib/core');
|
|
8
|
+
const c = require('../lib/commands');
|
|
9
|
+
const ag = require('../lib/agent');
|
|
10
|
+
|
|
11
|
+
const OVERVIEW = `luang-cli v${pkg.version} — CLI Agent Orchestration Luang
|
|
12
|
+
|
|
13
|
+
Penggunaan: luang-cli <command> [sub] [opsi]
|
|
14
|
+
|
|
15
|
+
Command:
|
|
16
|
+
login Login device flow via browser luang-cli login --name "Laptop"
|
|
17
|
+
logout Hapus API key tersimpan luang-cli logout [-y]
|
|
18
|
+
whoami Info sesi agent, tenant & izin luang-cli whoami
|
|
19
|
+
provider Kelola provider CLI coding luang-cli provider list
|
|
20
|
+
agent Daemon heartbeat + polling tugas luang-cli agent [--interval 5] [--exec]
|
|
21
|
+
task Kelola tugas (list|create|status) luang-cli task list
|
|
22
|
+
status Ringkasan CLI (key, tenant, izin) luang-cli status
|
|
23
|
+
mcp-config Snippet konfigurasi MCP klien luang-cli mcp-config
|
|
24
|
+
|
|
25
|
+
Opsi global:
|
|
26
|
+
--api <url> Override URL API (default https://api.luang.id)
|
|
27
|
+
-h, --help Bantuan (juga: luang-cli help <command>) · --version
|
|
28
|
+
|
|
29
|
+
Detail: luang-cli help <command>`;
|
|
30
|
+
|
|
31
|
+
const TOPICS = {
|
|
32
|
+
login: `luang-cli login — login via device flow
|
|
33
|
+
|
|
34
|
+
Penggunaan:
|
|
35
|
+
luang-cli login [--name <label>]
|
|
36
|
+
|
|
37
|
+
Opsi:
|
|
38
|
+
--name <label> Nama sesi/agent (default: hostname — CLI)
|
|
39
|
+
|
|
40
|
+
Alur:
|
|
41
|
+
1. CLI meminta device_code + user_code dari API
|
|
42
|
+
2. Browser terbuka ke halaman verify (bila gagal, URL cukup dicetak)
|
|
43
|
+
3. Masukkan user_code di dashboard, klik approve
|
|
44
|
+
4. API key tersimpan di ~/.luang-cli/config.json
|
|
45
|
+
"approved" tanpa api_key berarti key sudah pernah diambil sebelumnya.
|
|
46
|
+
|
|
47
|
+
Contoh:
|
|
48
|
+
luang-cli login
|
|
49
|
+
luang-cli login --name "Laptop Kantor"`,
|
|
50
|
+
|
|
51
|
+
logout: `luang-cli logout — hapus API key dari ~/.luang-cli/config.json
|
|
52
|
+
|
|
53
|
+
Penggunaan:
|
|
54
|
+
luang-cli logout [-y]
|
|
55
|
+
|
|
56
|
+
Opsi:
|
|
57
|
+
-y, --yes Langsung hapus tanpa konfirmasi
|
|
58
|
+
|
|
59
|
+
Catatan: env LUANG_KEY (bila ter-set) tetap override.`,
|
|
60
|
+
|
|
61
|
+
whoami: `luang-cli whoami — info sesi agent dari GET /api/v1/agent/me
|
|
62
|
+
|
|
63
|
+
Penggunaan:
|
|
64
|
+
luang-cli whoami
|
|
65
|
+
|
|
66
|
+
Menampilkan: nama sesi, status, key id, tenant, last seen,
|
|
67
|
+
izin can_update_tasks / can_create_tasks, dan provider terdaftar.`,
|
|
68
|
+
|
|
69
|
+
provider: `luang-cli provider — kelola provider CLI coding
|
|
70
|
+
|
|
71
|
+
Penggunaan:
|
|
72
|
+
luang-cli provider list [--json]
|
|
73
|
+
Deteksi otomatis: ~/.claude (claude_code), ~/.codex (codex),
|
|
74
|
+
~/.config/opencode atau ~/.opencode (opencode), ~/.gemini (gemini_cli),
|
|
75
|
+
plus which(1) untuk claude, codex, opencode, gemini.
|
|
76
|
+
Bila key ada, hasil langsung disinkron via POST /api/v1/agent/heartbeat.
|
|
77
|
+
luang-cli provider add <type> [--path P] [--exec_template T]
|
|
78
|
+
luang-cli provider remove <type>
|
|
79
|
+
luang-cli provider default <type>
|
|
80
|
+
|
|
81
|
+
Param exec_template:
|
|
82
|
+
{task} diganti judul + deskripsi tugas saat mode --exec.
|
|
83
|
+
Contoh: 'claude -p "{task}"', 'opencode run "{task}"', 'codex exec "{task}"'
|
|
84
|
+
|
|
85
|
+
Contoh:
|
|
86
|
+
luang-cli provider add opencode --exec_template 'opencode run "{task}"'
|
|
87
|
+
luang-cli provider default opencode`,
|
|
88
|
+
|
|
89
|
+
agent: `luang-cli agent — daemon agent (heartbeat + polling tugas)
|
|
90
|
+
|
|
91
|
+
Penggunaan:
|
|
92
|
+
luang-cli agent [--interval N] [--exec]
|
|
93
|
+
|
|
94
|
+
Opsi:
|
|
95
|
+
--interval N Jeda polling GET /api/v1/agent/tasks (detik, default 5)
|
|
96
|
+
--exec Eksekusi otomatis tugas "To-Do" yang belum dijalankan
|
|
97
|
+
|
|
98
|
+
Perilaku:
|
|
99
|
+
• POST /api/v1/agent/heartbeat tiap 30 detik
|
|
100
|
+
• Polling GET /api/v1/agent/tasks tiap N detik; baris berubah dicetak:
|
|
101
|
+
TGS-1 Judul In Progress [agent_status] 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 ("menjalankan"), lalu done ("selesai") bila exit 0,
|
|
106
|
+
review ("gagal") bila gagal.
|
|
107
|
+
• Ctrl+C menghentikan daemon dengan bersih.`,
|
|
108
|
+
|
|
109
|
+
task: `luang-cli task — kelola tugas
|
|
110
|
+
|
|
111
|
+
Penggunaan:
|
|
112
|
+
luang-cli task list [--status todo|in_progress|review|done]
|
|
113
|
+
luang-cli task create --title "Judul" [--desc "…"] [--priority high|medium|low] [--due 2026-01-02]
|
|
114
|
+
luang-cli task status <TGS-12|uuid> <todo|in_progress|review|done> [--note "…"] [--agent-status "…"]
|
|
115
|
+
|
|
116
|
+
Catatan:
|
|
117
|
+
• task create butuh izin admin "Bisa-buat-tugas" (can_create_tasks)
|
|
118
|
+
• task status butuh izin "Bisa-update-tugas" (can_update_tasks)
|
|
119
|
+
|
|
120
|
+
Contoh:
|
|
121
|
+
luang-cli task list --status todo
|
|
122
|
+
luang-cli task create --title "Refactor auth" --priority high --due 2026-11-01
|
|
123
|
+
luang-cli task status TGS-12 in_progress --note "mulai analisis"`,
|
|
124
|
+
|
|
125
|
+
status: `luang-cli status — ringkasan CLI
|
|
126
|
+
|
|
127
|
+
Penggunaan:
|
|
128
|
+
luang-cli status
|
|
129
|
+
|
|
130
|
+
Menampilkan: API/App URL, key prefix, tenant, izin,
|
|
131
|
+
default provider & provider lokal, lokasi config/state.`,
|
|
132
|
+
|
|
133
|
+
'mcp-config': `luang-cli mcp-config — snippet konfigurasi MCP
|
|
134
|
+
|
|
135
|
+
Penggunaan:
|
|
136
|
+
luang-cli mcp-config
|
|
137
|
+
|
|
138
|
+
Mencetak blok JSON mcpServers untuk klien MCP: endpoint
|
|
139
|
+
POST /api/v1/agent/mcp dengan header X-CLI-Key. Key dipakai dari
|
|
140
|
+
config bila sudah login, selain itu placeholder.`,
|
|
141
|
+
|
|
142
|
+
help: OVERVIEW,
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
// ── Parsing argumen ──────────────────────────────────────────────────────────
|
|
146
|
+
|
|
147
|
+
const VALUE_FLAGS = new Set([
|
|
148
|
+
'name', 'path', 'exec_template', 'interval', 'status', 'title', 'desc',
|
|
149
|
+
'description', 'priority', 'due', 'note', 'agent-status', 'api',
|
|
150
|
+
]);
|
|
151
|
+
|
|
152
|
+
function parseArgs(argv) {
|
|
153
|
+
const pos = [];
|
|
154
|
+
const flags = {};
|
|
155
|
+
for (let i = 0; i < argv.length; i++) {
|
|
156
|
+
const a = argv[i];
|
|
157
|
+
if (a === '--') {
|
|
158
|
+
for (const x of argv.slice(i + 1)) pos.push(x);
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
if (a.startsWith('--')) {
|
|
162
|
+
const eq = a.indexOf('=');
|
|
163
|
+
if (eq > 2) {
|
|
164
|
+
flags[a.slice(2, eq)] = a.slice(eq + 1);
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
const name = a.slice(2);
|
|
168
|
+
const next = argv[i + 1];
|
|
169
|
+
if (VALUE_FLAGS.has(name) && next !== undefined && !next.startsWith('-')) {
|
|
170
|
+
flags[name] = next;
|
|
171
|
+
i++;
|
|
172
|
+
} else {
|
|
173
|
+
flags[name] = true;
|
|
174
|
+
}
|
|
175
|
+
} else if (a.startsWith('-') && a.length >= 2) {
|
|
176
|
+
const name = a.slice(1);
|
|
177
|
+
if (name === 'h') flags.help = true;
|
|
178
|
+
else flags[name] = true;
|
|
179
|
+
} else {
|
|
180
|
+
pos.push(a);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return { pos, flags };
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function printHelp(topic) {
|
|
187
|
+
const t = TOPICS[topic || 'help'];
|
|
188
|
+
if (!t) {
|
|
189
|
+
console.error(`❌ Command tidak dikenal: ${topic}`);
|
|
190
|
+
console.error('');
|
|
191
|
+
console.log(OVERVIEW);
|
|
192
|
+
return 1;
|
|
193
|
+
}
|
|
194
|
+
console.log(t);
|
|
195
|
+
return 0;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// ── Dispatch ─────────────────────────────────────────────────────────────────
|
|
199
|
+
|
|
200
|
+
async function main() {
|
|
201
|
+
const args = parseArgs(process.argv.slice(2));
|
|
202
|
+
const flags = args.flags;
|
|
203
|
+
const cmd = args.pos[0];
|
|
204
|
+
|
|
205
|
+
if (flags.version === true) {
|
|
206
|
+
console.log(`luang-cli v${pkg.version}`);
|
|
207
|
+
return 0;
|
|
208
|
+
}
|
|
209
|
+
if (!cmd || flags.help === true) {
|
|
210
|
+
return printHelp(cmd || 'help');
|
|
211
|
+
}
|
|
212
|
+
if (cmd === 'help') {
|
|
213
|
+
return printHelp(args.pos[1] || 'help');
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const rt = core.resolveRuntime(core.loadConfig(), flags);
|
|
217
|
+
switch (cmd) {
|
|
218
|
+
case 'login':
|
|
219
|
+
return c.cmdLogin(rt, args);
|
|
220
|
+
case 'logout':
|
|
221
|
+
return c.cmdLogout(rt, args);
|
|
222
|
+
case 'whoami':
|
|
223
|
+
return c.cmdWhoami(rt, args);
|
|
224
|
+
case 'provider':
|
|
225
|
+
return c.cmdProvider(rt, args);
|
|
226
|
+
case 'agent':
|
|
227
|
+
return ag.cmdAgent(rt, args);
|
|
228
|
+
case 'task':
|
|
229
|
+
return ag.cmdTask(rt, args);
|
|
230
|
+
case 'status':
|
|
231
|
+
return ag.cmdStatus(rt, args);
|
|
232
|
+
case 'mcp-config':
|
|
233
|
+
return ag.cmdMcpConfig(rt, args);
|
|
234
|
+
default: {
|
|
235
|
+
console.error(`❌ Command tidak dikenal: ${cmd}`);
|
|
236
|
+
console.error(' Jalankan `luang-cli help` untuk daftar command.');
|
|
237
|
+
return 1;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
main()
|
|
243
|
+
.then((code) => process.exit(code === undefined ? 0 : code))
|
|
244
|
+
.catch((e) => {
|
|
245
|
+
console.error(`❌ ${e && e.message ? e.message : e}`);
|
|
246
|
+
process.exit(1);
|
|
247
|
+
});
|