@ryuu-reinzz/ryuu-cli 0.5.0 → 0.5.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/CHANGELOG.md CHANGED
@@ -3,6 +3,53 @@
3
3
  Semua perubahan penting pada Ryuu Agent CLI didokumentasikan di sini.
4
4
  Project ini mengikuti [Semantic Versioning](https://semver.org/).
5
5
 
6
+ ## [0.5.2] - 2026-11-03
7
+
8
+ ### Ditambahkan
9
+
10
+ - **`github_delete_repository`** — menghapus repository GitHub secara permanen.
11
+ Berisiko `destructive`, selalu melewati approval Ryuu, dan hanya berjalan bila
12
+ argumen `confirm` berisi `owner/repo` yang sama persis. Bisa dimatikan dengan
13
+ `/github config set confirmDestructive false`.
14
+ - **Panduan `/github` dan `/drive` di `/help`** — `/help` kini menampilkan daftar
15
+ subcommand kedua plugin selama plugin dimuat, dan `/help drive` menampilkan
16
+ tutorial seperti `/help github`.
17
+
18
+ ### Diubah
19
+
20
+ - Safelist proxy backend menerima `DELETE /repos/{owner}/{repo}` khusus untuk
21
+ tool penghapusan repository; endpoint DELETE lain tetap ditolak.
22
+
23
+ ## [0.5.1] - 2026-11-03
24
+
25
+ Rilis ini menambahkan integrasi GitHub App sebagai plugin opsional, dengan
26
+ seluruh kewenangan OAuth dan penyimpanan token berada di backend.
27
+
28
+ ### Ditambahkan
29
+
30
+ - **Integrasi GitHub (`plugins/github/`)** dengan 35 tool AI: akun, repository,
31
+ branch/commit/file, issue, pull request, release, dan GitHub Actions.
32
+ - **Command `/github`**: `login` (browser), `login --device` (headless),
33
+ `logout`, `status`, `account`, `test`, `enable`, `disable`, `config`.
34
+ - **Gateway backend GitHub** (`website/api/lib/github/`) sebagai satu-satunya
35
+ pemegang Client Secret, Private Key, Webhook Secret, dan token pengguna.
36
+ CLI hanya memegang `cliToken` per akun yang disimpan terenkripsi
37
+ (AES-256-GCM) dan tidak pernah menerima access/refresh token GitHub.
38
+ - **OAuth GitHub App** dengan `state` sekali pakai, PKCE S256, sesi pairing
39
+ berumur pendek, polling sekali ambil, serta fallback device flow.
40
+ - **Auto-refresh token** di backend dengan single-flight dan rotasi refresh
41
+ token; `invalid_grant` menandai akun perlu login ulang.
42
+ - **Webhook `/webhooks/github`** dengan verifikasi HMAC SHA-256 constant-time,
43
+ deduplikasi delivery, dan pemrosesan asynchronous.
44
+ - **Approval** untuk seluruh operasi yang mengubah data; penghapusan file dan
45
+ merge pull request berisiko `destructive` dan dapat diblokir lewat
46
+ `confirmDestructive`.
47
+
48
+ ### Catatan
49
+
50
+ - Plugin Google Drive tidak diubah perilakunya.
51
+ - Tidak ada Client Secret, Private Key, atau token GitHub di source code CLI.
52
+
6
53
  ## [0.5.0] - 2026-11-01
7
54
 
8
55
  Rilis ini menambahkan sistem plugin dan integrasi Google Drive, sekaligus
package/docs/github.md ADDED
@@ -0,0 +1,470 @@
1
+ # Integrasi GitHub — Ryuu CLI
2
+
3
+ Dokumen ini menjelaskan cara memasang, mengonfigurasi, memakai, dan menguji
4
+ integrasi GitHub pada Ryuu CLI. Integrasi terdiri dari dua bagian:
5
+
6
+ 1. **Backend** (`/root/website/api`, modul `lib/github/`) — Integration Gateway
7
+ yang memegang seluruh kredensial GitHub App dan token pengguna.
8
+ 2. **Plugin CLI** (`/root/agents/ryuu/plugins/github/`) — command `/github` dan
9
+ 36 tool AI yang memanggil GitHub melalui gateway.
10
+
11
+ Tidak ada Client Secret, Private Key, Webhook Secret, access token, atau refresh
12
+ token di sisi CLI. CLI hanya memegang `cliToken` per akun yang disimpan
13
+ terenkripsi.
14
+
15
+ ---
16
+
17
+ ## 1. Arsitektur
18
+
19
+ ```
20
+ ┌──────────────────────────┐ ┌─────────────────────────────────┐
21
+ │ Ryuu CLI │ │ Backend Ryuu (lib/github) │
22
+ │ plugins/github │ │ │
23
+ │ /github login ──────────┼───────▶│ POST /integrations/github/connect│
24
+ │ browser / device flow │ │ state + PKCE + URL otorisasi │
25
+ │ polling sesi ───────────┼───────▶│ GET /integrations/github/session│
26
+ │ cliToken (terenkripsi) │◀───────┤ cliToken (sekali ambil) │
27
+ │ │ │ │
28
+ │ tools GitHub ───────────┼───────▶│ ALL /integrations/github/api/* │
29
+ │ │ │ token pengguna + safelist │
30
+ └──────────────────────────┘ └───────────────┬─────────────────┘
31
+ │ HTTPS
32
+ ┌──────────────▼──────────────┐
33
+ │ github.com / api.github.com │
34
+ │ GitHub App + instalasi │
35
+ └─────────────────────────────┘
36
+
37
+ GitHub ── webhook ──▶ POST /webhooks/github (signature HMAC SHA-256)
38
+ ```
39
+
40
+ Prinsip:
41
+
42
+ - **Satu akun GitHub = satu record token** di backend. Tidak ada token global.
43
+ - Backend memakai penyimpanan JSON yang sudah menjadi pola proyek
44
+ (`~/.config/ryuu/github/data/tokens.json`) dengan atomic write + lock; bukan
45
+ database baru.
46
+ - Token disimpan dengan AES-256-GCM; kunci enkripsi terpisah dari data.
47
+ - CLI memanggil GitHub hanya lewat proxy backend, sehingga token tidak pernah
48
+ meninggalkan server.
49
+
50
+ ---
51
+
52
+ ## 2. Prasyarat
53
+
54
+ - Node.js ≥ 22 di mesin CLI dan server backend.
55
+ - GitHub App sudah dibuat dan diinstal ke akun/organisasi.
56
+ - Backend dapat diakses publik pada domain yang terdaftar di GitHub App.
57
+ - `express` (sudah menjadi dependensi backend).
58
+
59
+ ---
60
+
61
+ ## 3. Membuat GitHub App
62
+
63
+ Buka **GitHub → Settings → Developer settings → GitHub Apps → New GitHub App**.
64
+
65
+ | Field | Nilai |
66
+ | --- | --- |
67
+ | App name | `Ryuu CLI` |
68
+ | Homepage URL | `https://restapi.ryuu-dev.my.id/site` |
69
+ | Callback URL | `https://restapi.ryuu-dev.my.id/integrations/github/callback` |
70
+ | Webhook URL | `https://restapi.ryuu-dev.my.id/webhooks/github` |
71
+ | Webhook secret | string acak panjang; simpan di konfigurasi backend |
72
+ | Expire user authorization tokens | **aktifkan** agar refresh token diterbitkan |
73
+ | Device flow | aktifkan bila ingin `login --device` |
74
+ | Request user authorization during installation | opsional |
75
+
76
+ Catat **App ID**, **Client ID**, dan buat **Client Secret** + **Private Key**
77
+ (`.pem`). Client ID bukan rahasia; Client Secret dan Private Key hanya boleh ada
78
+ di server.
79
+
80
+ ### Permission minimum
81
+
82
+ | Permission | Level | Dipakai untuk |
83
+ | --- | --- | --- |
84
+ | Metadata | Read | Wajib untuk semua akses repository |
85
+ | Contents | Read | File, branch, commit, release |
86
+ | Contents | Write | Buat/ubah/hapus file, buat release |
87
+ | Issues | Read & Write | Issue dan komentar |
88
+ | Pull requests | Read & Write | PR, review, merge |
89
+ | Actions | Read | Workflow dan workflow run |
90
+ | Actions | Write | Menjalankan ulang workflow |
91
+ | Administration | Write | Membuat/mengubah repository |
92
+
93
+ Tidak meminta permission yang tidak dipakai (Secrets, Checks, Statuses,
94
+ Workflows, Packages, dll). Tidak ada tool penghapusan repository.
95
+
96
+ ### Event webhook
97
+
98
+ Pilih minimal: **Push**, **Issues**, **Issue comment**, **Pull request**,
99
+ **Pull request review**, **Release**, **Installation**,
100
+ **Installation repositories**, **GitHub App authorization**.
101
+
102
+ ### Instalasi
103
+
104
+ Setelah App dibuat, klik **Install App** dan pilih akun/organisasi serta
105
+ repository yang boleh diakses. Login saja tidak memberi akses ke seluruh
106
+ repository: akses adalah irisan antara permission App, persetujuan pengguna,
107
+ dan repository yang tercakup instalasi.
108
+
109
+ ---
110
+
111
+ ## 4. Konfigurasi backend
112
+
113
+ Default file: `~/.config/ryuu/github/server.json` (Linux:
114
+ `$XDG_CONFIG_HOME`/`~/.config`; macOS: `~/Library/Application Support`;
115
+ Windows: `%APPDATA%`). Override: `RYUU_GITHUB_CONFIG=/path/server.json`.
116
+
117
+ ```json
118
+ {
119
+ "appId": "<App ID>",
120
+ "clientId": "<Client ID>",
121
+ "clientSecret": "<Client Secret>",
122
+ "privateKeyPath": "/path/ryuu-cli.private-key.pem",
123
+ "webhookSecret": "<Webhook Secret>",
124
+ "redirectUri": "https://<domain>/integrations/github/callback",
125
+ "webhookUrl": "https://<domain>/webhooks/github",
126
+ "apiVersion": "2022-11-28"
127
+ }
128
+ ```
129
+
130
+ Field wajib: `appId`, `clientId`, `clientSecret`, `privateKeyPath`,
131
+ `webhookSecret`, `redirectUri`, `webhookUrl`. `apiVersion` default
132
+ `2022-11-28` (versi REST GitHub yang didukung implementasi ini).
133
+
134
+ Permission yang disarankan:
135
+
136
+ ```bash
137
+ chmod 700 ~/.config/ryuu/github
138
+ chmod 600 ~/.config/ryuu/github/server.json
139
+ chmod 600 /path/ryuu-cli.private-key.pem
140
+ ```
141
+
142
+ Kunci enkripsi token berada di `~/.config/ryuu/github/.keys/tokens.key` (0600)
143
+ atau dari `RYUU_GITHUB_TOKEN_KEY` (hex 64 karakter / base64 32 byte). Kunci tidak
144
+ boleh disimpan bersama file data token.
145
+
146
+ Backend membaca ulang konfigurasi saat mtime berubah; rotasi credential tidak
147
+ memerlukan restart. Jika field belum lengkap, endpoint menjawab HTTP 503 dengan
148
+ **nama field** yang belum diisi — bukan nilainya.
149
+
150
+ ---
151
+
152
+ ## 5. Konfigurasi CLI
153
+
154
+ CLI hanya menyimpan pengaturan non-rahasia:
155
+
156
+ ```
157
+ <config>/integrations/github/config.json (0600)
158
+ <config>/integrations/github/state.json (0600)
159
+ <config>/integrations/github/credentials.enc (0600, cliToken terenkripsi)
160
+ <config>/.keys/github.key (0600)
161
+ ```
162
+
163
+ Key yang dapat diubah:
164
+
165
+ ```bash
166
+ ryuu /github config set enabled true
167
+ ryuu /github config set confirmDestructive false
168
+ ryuu /github config set defaultRepo ryuu-reinzz/ryuu-cli
169
+ ```
170
+
171
+ `clientId` boleh tampil (publik). `clientSecret`, `privateKeyPath`,
172
+ `webhookSecret`, `accessToken`, `refreshToken`, dan `cliToken` tidak dapat
173
+ diubah dari CLI.
174
+
175
+ ---
176
+
177
+ ## 6. Login
178
+
179
+ ### Browser (utama)
180
+
181
+ ```bash
182
+ ryuu /github login
183
+ ```
184
+
185
+ Alur:
186
+
187
+ 1. CLI meminta backend membuat sesi sementara (`sessionId`, `pairingSecret`,
188
+ `state`, PKCE challenge, URL otorisasi).
189
+ 2. Browser dibuka. Jika tidak ada browser, URL dicetak untuk dibuka manual.
190
+ 3. Pengguna menyetujui akses di GitHub.
191
+ 4. GitHub mengarahkan ke `/integrations/github/callback`.
192
+ 5. Backend memvalidasi `state`, menukar `code` (client secret + PKCE verifier),
193
+ mengambil `GET /user`, dan menyimpan token terenkripsi.
194
+ 6. Backend menerbitkan `cliToken` per akun dan menandai sesi `authorized`.
195
+ 7. CLI polling dengan `pairingSecret`, menerima hasil **sekali**, lalu sesi
196
+ dihapus. Sesi kedaluwarsa setelah 10 menit.
197
+
198
+ Login otomatis mengaktifkan integrasi dan mendaftarkan tool pada sesi berjalan.
199
+
200
+ ### Device flow (headless)
201
+
202
+ ```bash
203
+ ryuu /github login --device
204
+ ```
205
+
206
+ CLI menampilkan `verification_uri` dan `user_code`, lalu benar-benar melakukan
207
+ polling sampai GitHub menyelesaikan otorisasi (bukan hanya menampilkan kode).
208
+ Device flow harus diaktifkan pada pengaturan GitHub App.
209
+
210
+ Catatan PKCE: challenge dan verifier dikirim pada flow browser. GitHub belum
211
+ mendokumentasikan dukungan PKCE untuk OAuth App, sehingga jaminan utama adalah
212
+ `state` acak sekali pakai + Client Secret yang hanya ada di server. Dokumentasi
213
+ ini tidak mengklaim PKCE diverifikasi oleh GitHub.
214
+
215
+ ---
216
+
217
+ ## 7. Status, akun, dan test
218
+
219
+ ```bash
220
+ ryuu /github status
221
+ ryuu /github account
222
+ ryuu /github test
223
+ ```
224
+
225
+ `status` menampilkan status integrasi, login, enable/disable, respons backend,
226
+ masa berlaku access token, ketersediaan refresh token, jumlah instalasi, dan
227
+ lokasi file konfigurasi. Tidak ada token yang dicetak.
228
+
229
+ `account` menampilkan username, nama, tipe akun, URL profil, avatar, scope, dan
230
+ status autentikasi.
231
+
232
+ `test` memeriksa konfigurasi, sesi CLI, respons backend, `GET /user`, instalasi,
233
+ rate limit, App JWT/private key, dan status token. **Tidak** membuat, mengubah,
234
+ atau menghapus repository.
235
+
236
+ ---
237
+
238
+ ## 8. Enable dan disable
239
+
240
+ ```bash
241
+ ryuu /github enable
242
+ ryuu /github disable
243
+ ```
244
+
245
+ - `enable` mendaftarkan tool ke registry agent. Konfigurasi dan sesi harus valid.
246
+ - `disable` hanya melepas tool. Akun, token, dan instalasi GitHub App tetap ada.
247
+ - Tool memeriksa ulang status saat eksekusi, jadi model yang memegang daftar tool
248
+ lama tidak bisa bertindak setelah disable.
249
+
250
+ ---
251
+
252
+ ## 9. Logout dan disconnect
253
+
254
+ ```bash
255
+ ryuu /github logout
256
+ ```
257
+
258
+ Logout:
259
+
260
+ 1. Meminta backend mencabut token (`DELETE /applications/{client_id}/token`).
261
+ 2. Menghapus `cliToken` lokal dan kunci enkripsi CLI.
262
+ 3. Menonaktifkan integrasi.
263
+ 4. Tidak menghapus repository, issue, release, atau instalasi GitHub App.
264
+
265
+ Jika backend tidak dapat dihubungi, kredensial lokal tetap dihapus dan CLI
266
+ memberi tahu bahwa token di server mungkin masih tersimpan. Untuk memutus
267
+ instalasi sepenuhnya, lakukan dari **GitHub → Settings → Applications** atau
268
+ halaman instalasi App.
269
+
270
+ ---
271
+
272
+ ## 10. Tools
273
+
274
+ | Kelompok | Tool |
275
+ | --- | --- |
276
+ | Akun | `github_get_me`, `github_get_user`, `github_get_rate_limit` |
277
+ | Repository | `github_list_repositories`, `github_get_repository`, `github_create_repository`, `github_update_repository`, `github_delete_repository`, `github_list_branches`, `github_get_branch`, `github_list_commits`, `github_get_commit`, `github_get_file_contents`, `github_create_or_update_file`, `github_delete_file`, `github_compare_commits` |
278
+ | Issue | `github_list_issues`, `github_get_issue`, `github_create_issue`, `github_update_issue`, `github_comment_issue`, `github_list_issue_comments` |
279
+ | Pull request | `github_list_pull_requests`, `github_get_pull_request`, `github_create_pull_request`, `github_update_pull_request`, `github_merge_pull_request`, `github_list_pull_request_files`, `github_review_pull_request` |
280
+ | Release | `github_list_releases`, `github_get_release`, `github_create_release` |
281
+ | Actions | `github_list_workflows`, `github_list_workflow_runs`, `github_get_workflow_run`, `github_rerun_workflow` |
282
+
283
+ Setiap tool memiliki schema input yang divalidasi registry, pemeriksaan
284
+ autentikasi, pembatasan output, dan deskripsi permission yang dibutuhkan.
285
+
286
+ Operasi yang mengubah data selalu melewati approval Ryuu:
287
+
288
+ - membuat/mengubah repository;
289
+ - menghapus repository;
290
+ - membuat/mengubah/menghapus file;
291
+ - membuat/mengubah issue dan komentar;
292
+ - membuat/mengubah/merge pull request dan review;
293
+ - membuat release;
294
+ - menjalankan ulang workflow.
295
+
296
+ `github_delete_file`, `github_merge_pull_request`, dan `github_delete_repository`
297
+ berisiko `destructive`. `confirmDestructive: false` memblokirnya sepenuhnya.
298
+
299
+ `github_delete_repository` adalah satu-satunya tool yang menghapus repository.
300
+ Selain approval Ryuu, handler-nya menuntut argumen `confirm` berisi
301
+ `owner/repo` yang sama persis, sehingga model tidak bisa menghapus repository
302
+ tanpa token konfirmasi eksplisit dari pengguna:
303
+
304
+ ---
305
+
306
+ ## 11. Token kedaluwarsa dan refresh
307
+
308
+ GitHub App dapat menerbitkan access token yang kedaluwarsa (default 8 jam) dan
309
+ refresh token (default 6 bulan) bila opsi expire user authorization tokens
310
+ aktif. Jangan mengasumsikan durasi: backend memakai `expires_in` dan
311
+ `refresh_token_expires_in` dari respons aktual.
312
+
313
+ - Backend me-refresh otomatis bila access token tinggal ≤ 5 menit.
314
+ - Refresh memakai single-flight per akun, sehingga request paralel tidak
315
+ melakukan dua rotasi refresh token.
316
+ - Refresh token yang dirotasi disimpan; jika GitHub tidak mengirim yang baru,
317
+ token lama dipertahankan.
318
+ - `invalid_grant`/`bad_refresh_token` menandai akun `needsReconnect`; pengguna
319
+ diminta `/github login` lagi.
320
+ - Bila token tidak punya expiry (opsi expire dimatikan), token dipakai tanpa
321
+ refresh dan status menampilkan “tanpa masa berlaku”.
322
+
323
+ Perintah manual:
324
+
325
+ ```bash
326
+ ryuu /github test
327
+ ryuu /github status
328
+ ```
329
+
330
+ `/github test` melakukan pemeriksaan; refresh paksa tersedia di endpoint backend
331
+ `POST /integrations/github/refresh` (dipakai untuk diagnostik).
332
+
333
+ ---
334
+
335
+ ## 12. Mengganti credential
336
+
337
+ 1. **Client Secret baru**: buat di GitHub App settings, lalu perbarui
338
+ `clientSecret` di `server.json`. File dibaca ulang otomatis (mtime).
339
+ 2. **Private Key baru**: generate, simpan dengan mode 0600, perbarui
340
+ `privateKeyPath`, lalu hapus key lama.
341
+ 3. **Webhook Secret baru**: perbarui di GitHub dan `server.json`; delivery lama
342
+ yang belum diproses akan ditolak jika signature-nya memakai secret lama.
343
+ 4. **Client ID/App ID berubah**: perbarui `clientId`/`appId`, lalu login ulang.
344
+ 5. **Mengganti akun pengguna**: `/github logout`, lalu `/github login`.
345
+
346
+ Tidak ada perubahan source code yang diperlukan. Jangan menaruh nilai rahasia di
347
+ dokumentasi, issue, commit, atau log.
348
+
349
+ ---
350
+
351
+ ## 13. Webhook
352
+
353
+ Endpoint: `POST /webhooks/github` (dipasang sebelum parser JSON global).
354
+
355
+ - Signature `X-Hub-Signature-256` (HMAC SHA-256, constant-time) wajib valid.
356
+ - `X-GitHub-Event` dan `X-GitHub-Delivery` divalidasi.
357
+ - Delivery duplikat diabaikan (`202 { duplicate: true }`).
358
+ - Event diproses asynchronous; respons `202` dikirim lebih dulu.
359
+ - Event yang didukung: `push`, `issues`, `issue_comment`, `pull_request`,
360
+ `pull_request_review`, `release`, `installation`,
361
+ `installation_repositories`, `github_app_authorization`.
362
+ - Handler hanya mencatat dan memperbarui data instalasi. Tidak ada aksi otomatis
363
+ yang mengubah repository.
364
+ - Payload dicatat dalam bentuk ter-redaksi.
365
+
366
+ ---
367
+
368
+ ## 14. Batasan akses
369
+
370
+ - Login GitHub **tidak** berarti akses ke seluruh repository. Akses adalah
371
+ irisan permission App, persetujuan pengguna, dan repository yang tercakup
372
+ instalasi.
373
+ - Repository privat hanya terlihat bila instalasi mencakupnya.
374
+ - Organisasi dapat membatasi atau meninjau instalasi; administrator organisasi
375
+ mungkin perlu menyetujui.
376
+ - Endpoint tertentu memerlukan permission tambahan (mis. Administration write
377
+ untuk membuat repository).
378
+ - GitHub REST rate limit tetap berlaku; gunakan `github_get_rate_limit`.
379
+
380
+ ---
381
+
382
+ ## 15. Catatan keamanan
383
+
384
+ - Client Secret, Private Key, dan Webhook Secret hanya ada di backend.
385
+ - Token pengguna disimpan terenkripsi (AES-256-GCM); kunci terpisah dari data.
386
+ - `cliToken` disimpan sebagai hash SHA-256, maksimal 5 per akun, dan memiliki
387
+ masa berlaku (default 30 hari).
388
+ - `pairingSecret` hanya dikembalikan ke CLI pembuat sesi dan dibandingkan
389
+ constant-time; sesi berumur 10 menit dan hasil login hanya bisa diambil sekali.
390
+ - Proxy API memakai safelist method+path; CLI tidak bisa memanggil endpoint
391
+ sembarang.
392
+ - Log tidak memuat Authorization header, token, atau secret.
393
+ - Approval Ryuu tidak bisa dilewati oleh tool; `confirmDestructive=false`
394
+ menambahkan lapisan blokir di handler.
395
+ - File rahasia dan data runtime tidak masuk Git (`lib/github/data/`, `.pem`,
396
+ `.env`, kunci).
397
+
398
+ ---
399
+
400
+ ## 16. Testing lokal
401
+
402
+ Backend:
403
+
404
+ ```bash
405
+ cd /root/website/api
406
+ npm test
407
+ ```
408
+
409
+ CLI:
410
+
411
+ ```bash
412
+ cd /root/agents/ryuu
413
+ node --test tests/unit/github.test.js tests/integration/github.test.js
414
+ npm run check
415
+ ```
416
+
417
+ Test memakai mock `fetch`/server lokal. **Jangan** menguji konektivitas domain
418
+ `restapi.ryuu-dev.my.id` dari VPS LXC: domain dan jaringan dikelola VPS induk.
419
+ Pengujian callback/webhook dari perangkat eksternal dapat dilakukan dengan:
420
+
421
+ ```bash
422
+ curl -i "https://restapi.ryuu-dev.my.id/integrations/github/callback?state=invalid"
423
+ # harapan: 404 + halaman HTML "sesi tidak ditemukan", bukan error 500
424
+ ```
425
+
426
+ ---
427
+
428
+ ## 17. Troubleshooting
429
+
430
+ | Gejala | Penyebab umum | Tindakan |
431
+ | --- | --- | --- |
432
+ | 503 konfigurasi belum lengkap | `server.json` belum diisi | Isi field yang disebut pada pesan |
433
+ | `invalid_client` saat callback | Client Secret salah/berputar | Perbarui `clientSecret`, login ulang |
434
+ | `redirect_uri` mismatch | Callback URL di GitHub berbeda | Samakan `redirectUri` di App dan `server.json` |
435
+ | 401 signature webhook | Webhook Secret berbeda | Samakan secret di GitHub dan backend |
436
+ | 403 akses repository | Instalasi tidak mencakup repo | Instal/ubah akses App |
437
+ | Tool tidak muncul | Belum login atau disable | `/github login`, `/github enable` |
438
+ | Token perlu login ulang | Refresh token dicabut/kedaluwarsa | `/github login` |
439
+ | Rate limit | Kuota GitHub habis | Tunggu reset, cek `/github test` |
440
+
441
+ ---
442
+
443
+ ## 18. Struktur file
444
+
445
+ ```
446
+ /root/website/api/
447
+ ├── index.js # memasang webhook + router
448
+ ├── lib/github/
449
+ │ ├── index.js # factory integrasi
450
+ │ ├── config.js # konfigurasi server + validasi
451
+ │ ├── data/ # hanya jika diarahkan ke repo (di-ignore)
452
+ │ ├── encryption.js # AES-256-GCM + kunci terpisah
453
+ │ ├── store.js # atomic write + lock
454
+ │ ├── token-storage.js # record per akun + cliToken hash
455
+ │ ├── session.js # sesi login sementara
456
+ │ ├── oauth.js # PKCE, exchange, refresh, device flow
457
+ │ ├── app-token.js # App JWT + installation token
458
+ │ ├── token-manager.js # auto-refresh single-flight
459
+ │ ├── api.js # GitHub REST client
460
+ │ ├── signature.js # verifikasi webhook
461
+ │ ├── webhook.js # handler + dedupe + antrean
462
+ │ ├── router.js # endpoint + proxy
463
+ │ └── README.md
464
+ └── tests/github/ # 48 test lokal
465
+
466
+ /root/agents/ryuu/
467
+ ├── plugins/github/ # plugin CLI
468
+ ├── docs/github.md # dokumen ini
469
+ └── tests/{unit,integration}/github.test.js
470
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ryuu-reinzz/ryuu-cli",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "Ryuu Agent CLI - an autonomous, approval-gated AI coding agent for your terminal",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,158 @@
1
+ # Plugin GitHub — Ryuu CLI
2
+
3
+ Integrasi GitHub untuk agent Ryuu: akun, repository, file, issue, pull request,
4
+ release, dan GitHub Actions. Plugin ini mengikuti pola `plugins/google-drive/`
5
+ dan **tidak memegang kredensial GitHub rahasia apa pun**.
6
+
7
+ ## Arsitektur singkat
8
+
9
+ ```
10
+ ryuu /github login
11
+ │ POST /integrations/github/connect (sesi + URL)
12
+ ▼
13
+ Backend Ryuu (Integration Gateway) ──HTTPS──▶ github.com / api.github.com
14
+ │ Client Secret, Private Key, Webhook Secret, token pengguna
15
+ │
16
+ └─ menerbitkan cliToken per akun
17
+ CLI menyimpan cliToken terenkripsi, lalu semua tools lewat backend.
18
+ ```
19
+
20
+ - **Backend** memiliki Client Secret, Private Key, Webhook Secret, access token,
21
+ dan refresh token.
22
+ - **CLI** hanya memiliki Client ID publik (boleh tampil), `cliToken` per akun
23
+ (AES-256-GCM di disk), dan cache identitas akun.
24
+ - Tools tidak pernah menerima access token GitHub; backend memasangnya saat
25
+ meneruskan request ke `api.github.com`.
26
+
27
+ ## Struktur modul
28
+
29
+ | File | Tanggung jawab |
30
+ | --- | --- |
31
+ | `index.js` | Deskriptor plugin untuk host |
32
+ | `manager.js` | Lifecycle: login, logout, status, enable/disable, test |
33
+ | `config.js` | Konfigurasi non-rahasia + path OS + state cache |
34
+ | `credentials.js` | Penyimpanan `cliToken` terenkripsi |
35
+ | `auth.js` | Membuka browser + pesan kegagalan login |
36
+ | `backend.js` | HTTP client ke backend (connect, session, status, proxy) |
37
+ | `api.js` | Klien GitHub REST melalui gateway + pagination |
38
+ | `tools*.js` | 36 tool AI, dikelompokkan per domain |
39
+ | `tool-helpers.js` | Validasi owner/repo/ref/path + pembatasan output |
40
+ | `errors.js` | Error plugin + kode yang stabil |
41
+ | `command.js` | Handler `/github` |
42
+
43
+ ## Konfigurasi lokal
44
+
45
+ Mengikuti direktori konfigurasi OS lewat `settingsDir()`:
46
+
47
+ ```
48
+ <config>/integrations/github/config.json (0600, non-rahasia)
49
+ <config>/integrations/github/state.json (0600, cache status)
50
+ <config>/integrations/github/credentials.enc (0600, cliToken terenkripsi)
51
+ <config>/.keys/github.key (0600, kunci enkripsi CLI)
52
+ ```
53
+
54
+ Linux memakai `$XDG_CONFIG_HOME` atau `~/.config`, macOS memakai
55
+ `~/Library/Application Support`, Windows memakai `%APPDATA%`.
56
+
57
+ Key yang dapat diubah:
58
+
59
+ ```
60
+ /github config set enabled true|false
61
+ /github config set autoRefresh true|false
62
+ /github config set confirmDestructive true|false
63
+ /github config set defaultRepo owner/repo
64
+ ```
65
+
66
+ Client Secret, Private Key, Webhook Secret, endpoint backend, dan token tidak
67
+ dapat diubah dari CLI dan tidak pernah ditulis ke file konfigurasi.
68
+
69
+ ## Command
70
+
71
+ ```
72
+ /github login login lewat browser (utama)
73
+ /github login --device device flow untuk mesin headless
74
+ /github logout putuskan akun + hapus kredensial lokal
75
+ /github status status integrasi, akun, token, backend
76
+ /github account identitas akun GitHub terhubung
77
+ /github test diagnostik aman (tanpa mengubah repository)
78
+ /github enable daftarkan tool ke agent
79
+ /github disable lepas tool (akun/token tetap)
80
+ /github config tampilkan konfigurasi non-rahasia
81
+ /github config set ... ubah satu key
82
+ ```
83
+
84
+ `/github status`, `/github account`, dan `/github config` tidak pernah
85
+ menampilkan Client Secret, Private Key, Webhook Secret, access token, refresh
86
+ token, atau `cliToken`.
87
+
88
+ ## Tool yang tersedia (36)
89
+
90
+ **Akun (3)** — `github_get_me`, `github_get_user`, `github_get_rate_limit`
91
+
92
+ **Repository (13)** — `github_list_repositories`, `github_get_repository`,
93
+ `github_create_repository`, `github_update_repository`,
94
+ `github_delete_repository`, `github_list_branches`,
95
+ `github_get_branch`, `github_list_commits`, `github_get_commit`,
96
+ `github_get_file_contents`, `github_create_or_update_file`,
97
+ `github_delete_file`, `github_compare_commits`
98
+
99
+ **Issue (6)** — `github_list_issues`, `github_get_issue`,
100
+ `github_create_issue`, `github_update_issue`, `github_comment_issue`,
101
+ `github_list_issue_comments`
102
+
103
+ **Pull request (7)** — `github_list_pull_requests`, `github_get_pull_request`,
104
+ `github_create_pull_request`, `github_update_pull_request`,
105
+ `github_merge_pull_request`, `github_list_pull_request_files`,
106
+ `github_review_pull_request`
107
+
108
+ **Release (3)** — `github_list_releases`, `github_get_release`,
109
+ `github_create_release`
110
+
111
+ **GitHub Actions (4)** — `github_list_workflows`,
112
+ `github_list_workflow_runs`, `github_get_workflow_run`,
113
+ `github_rerun_workflow`
114
+
115
+ `github_delete_repository` menghapus repository secara permanen dan hanya
116
+ berjalan bila argumen `confirm` berisi `owner/repo` yang sama persis; proxy
117
+ backend baru mengizinkannya lewat safelist `DELETE /repos/{owner}/{repo}`.
118
+ Penghapusan repository, penghapusan file, dan merge pull request berisiko
119
+ `destructive` dan selalu melewati approval Ryuu.
120
+
121
+ ## Approval & keamanan
122
+
123
+ - `risk: read` berjalan tanpa prompt.
124
+ - Semua tool `write` memakai `requiresApproval: true`.
125
+ - `github_delete_file`, `github_merge_pull_request`, dan
126
+ `github_delete_repository` memakai
127
+ `risk: destructive` (approval wajib).
128
+ - `github_delete_repository` menuntut `confirm` = `owner/repo`; nilai lain
129
+ ditolak sebagai `VALIDATION_FAILED` sebelum request dibuat.
130
+ - `confirmDestructive: false` memblokir operasi destruktif di handler, bukan
131
+ hanya mengandalkan prompt.
132
+ - Tool memanggil `plugin.requireClient()` setiap kali, sehingga model yang
133
+ memegang daftar tool lama tidak bisa bertindak setelah `/github disable`.
134
+ - Output dibatasi: list dipotong, body panjang diringkas, isi file > 200 KB
135
+ hanya metadata.
136
+
137
+ ## Testing
138
+
139
+ ```bash
140
+ cd /root/agents/ryuu
141
+ node --test tests/unit/github.test.js tests/integration/github.test.js
142
+ ```
143
+
144
+ Test memakai mock backend lokal. Tidak ada koneksi ke domain produksi dan tidak
145
+ ada perubahan data GitHub nyata.
146
+
147
+ ## Troubleshooting
148
+
149
+ | Gejala | Tindakan |
150
+ | --- | --- |
151
+ | `Belum ada akun GitHub yang terhubung` | `/github login` |
152
+ | `Integrasi GitHub sedang nonaktif` | `/github enable` |
153
+ | `Sesi CLI sudah berakhir` | `/github login` lagi |
154
+ | `Akses ditolak` pada repository privat | Pastikan GitHub App diinstal ke akun/organisasi dan repository itu dipilih |
155
+ | `Rate limit` | Tunggu reset; cek `/github test` |
156
+ | `confirmDestructive=false` | `/github config set confirmDestructive true` |
157
+
158
+ Dokumentasi lengkap: [`../../docs/github.md`](../../docs/github.md).