@ryuu-reinzz/ryuu-cli 0.4.2 → 0.5.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/CHANGELOG.md +102 -0
- package/README.md +53 -6
- package/docs/drive.md +484 -0
- package/package.json +4 -1
- package/plugins/google-drive/auth.js +57 -0
- package/plugins/google-drive/backup.js +282 -0
- package/plugins/google-drive/command.js +266 -0
- package/plugins/google-drive/config.js +252 -0
- package/plugins/google-drive/credentials.js +171 -0
- package/plugins/google-drive/drive-api.js +304 -0
- package/plugins/google-drive/index.js +26 -0
- package/plugins/google-drive/manager.js +507 -0
- package/plugins/google-drive/oauth-backend.js +161 -0
- package/plugins/google-drive/secret.js +50 -0
- package/plugins/google-drive/token-client.js +80 -0
- package/plugins/google-drive/tool-helpers.js +46 -0
- package/plugins/google-drive/tools-backup.js +204 -0
- package/plugins/google-drive/tools-files.js +315 -0
- package/plugins/google-drive/tools.js +13 -0
- package/plugins/google-drive/zip-reader.js +217 -0
- package/plugins/google-drive/zip-writer.js +204 -0
- package/plugins/index.js +56 -0
- package/src/agent/agent.js +128 -48
- package/src/agent/planner.js +1 -0
- package/src/cli/app.js +16 -0
- package/src/cli/commands.js +19 -0
- package/src/cli/markdown.js +10 -5
- package/src/cli/renderer.js +38 -5
- package/src/cli/tui.js +80 -9
- package/src/tools/registry.js +13 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,108 @@
|
|
|
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.0] - 2026-11-01
|
|
7
|
+
|
|
8
|
+
Rilis ini menambahkan sistem plugin dan integrasi Google Drive, sekaligus
|
|
9
|
+
memindahkan seluruh kewenangan OAuth ke proyek API eksternal: CLI tidak lagi
|
|
10
|
+
menyimpan client id maupun client secret Google.
|
|
11
|
+
|
|
12
|
+
### Ditambahkan
|
|
13
|
+
|
|
14
|
+
- **Sistem plugin.** Integrasi opsional kini hidup di `plugins/`, terpisah dari
|
|
15
|
+
`src/services/`, dan didaftarkan lewat `loadPlugins`/`syncPluginTools`.
|
|
16
|
+
Plugin hanya boleh menambah tool, command, dan konfigurasi sendiri; tool-nya
|
|
17
|
+
masuk registry yang sama sehingga approval, undo, dan audit tetap berlaku.
|
|
18
|
+
- **Integrasi Google Drive (`plugins/google-drive/`)** dengan 16 tool:
|
|
19
|
+
`drive_search`, `drive_list`, `drive_get_metadata`, `drive_download`,
|
|
20
|
+
`drive_upload`, `drive_create_folder`, `drive_move`, `drive_rename`,
|
|
21
|
+
`drive_copy`, `drive_delete`, `drive_backup`, `drive_restore`,
|
|
22
|
+
`drive_list_backups`, `drive_delete_backup`, `drive_storage_info`,
|
|
23
|
+
`drive_get_account`.
|
|
24
|
+
- **Command `/drive`**: `login`, `logout`, `account`, `enable`, `disable`,
|
|
25
|
+
`status`, `config [show]`, `config set <key> <value>`, `test`, `tools`.
|
|
26
|
+
- **Backup & restore proyek ke Drive** berbasis ZIP (writer/reader sendiri,
|
|
27
|
+
tanpa dependensi tambahan), dengan aturan exclusion dan hard-exclude untuk
|
|
28
|
+
berkas rahasia (`.env`, kunci privat, `node_modules`).
|
|
29
|
+
- **OAuth Web Application lewat backend API.** CLI meminta URL otorisasi ke
|
|
30
|
+
backend, membuka browser, lalu menerima hasil login tanpa pernah melihat
|
|
31
|
+
client id/secret. PKCE S256 dan penukaran `code` → token seluruhnya di server.
|
|
32
|
+
- **Kunci login khusus Drive** (header `x-ryuu-drive-auth`) yang tertanam,
|
|
33
|
+
terpisah dari root key admin, hanya aktif selama siklus login, dan tidak bisa
|
|
34
|
+
diubah lewat command, config, atau environment variable.
|
|
35
|
+
- **Tool plugin tampil beda di terminal**: nama tool dari plugin diberi warna
|
|
36
|
+
biru langit `#38bdf8` + bold di `--tui` maupun mode baris, sementara tool
|
|
37
|
+
bawaan tetap kuning (TUI) / biru datar (baris). Kegagalan tetap merah bold.
|
|
38
|
+
- **Blok kode dengan tombol copy** (`╭─ label ─… ⧉ copy ╮`) dipakai untuk URL
|
|
39
|
+
login Drive dan jawaban model yang mengandung blok kode. Satu blok = satu
|
|
40
|
+
bingkai utuh; klik barisnya menyalin teks asli (bukan potongan hasil wrap).
|
|
41
|
+
- **Dokumentasi** `docs/drive.md`: arsitektur plugin, alur OAuth, penyimpanan
|
|
42
|
+
credential terenkripsi AES-256-GCM, format backup, dan batasan scope
|
|
43
|
+
`drive.file`.
|
|
44
|
+
|
|
45
|
+
### Diubah
|
|
46
|
+
|
|
47
|
+
- **Nama tool plugin** ikut membawa asal-usulnya (`plugin`) pada event
|
|
48
|
+
`toolStart`/`toolEnd`, sehingga renderer bisa membedakan tool bawaan dan tool
|
|
49
|
+
plugin tanpa lookup tambahan.
|
|
50
|
+
- **Bingkai blok kode dirapikan**: baris isi dipad dan ditutup `│`, pojok
|
|
51
|
+
kanan `╮`/`╯` dilengkapi, dan lebar dibagi rata agar tidak "bergerigi".
|
|
52
|
+
- **Satu perintah = satu blok transcript**: baris berurutan digabung sehingga
|
|
53
|
+
tidak ada garis pemisah di tengah output `/drive login`, dan notifikasi
|
|
54
|
+
sukses tidak lagi tercerai-berai.
|
|
55
|
+
- **`package.json`**: `plugins/` dan `docs/` ikut dipublikasikan; dependensi
|
|
56
|
+
baru `googleapis`.
|
|
57
|
+
|
|
58
|
+
### Keamanan
|
|
59
|
+
|
|
60
|
+
- Client id/secret Google **tidak ada** di CLI: validasi menolak key
|
|
61
|
+
`clientId`, `clientSecret`, `scopes`, `oauthBackend`, `oauthCliPath`,
|
|
62
|
+
`rootKey`, `driveKey`, dan `secret`, dan normalizer membuang key asing
|
|
63
|
+
sehingga config tulisan tangan pun tidak bisa menyelipkan kredensial.
|
|
64
|
+
- Root key admin tidak pernah dikirim atau disimpan oleh plugin Drive;
|
|
65
|
+
refresh/revoke hanya memakai `grantId` sekali-terbit.
|
|
66
|
+
- Credential Drive disimpan terenkripsi (AES-256-GCM) dengan kunci terpisah
|
|
67
|
+
(`RYUU_DRIVE_KEY` dapat menggantikannya untuk secret manager).
|
|
68
|
+
- Jalur ekstraksi ZIP membatasi total ukuran (8 GB) dan menolak path traversal
|
|
69
|
+
serta symlink.
|
|
70
|
+
|
|
71
|
+
### Diperbaiki
|
|
72
|
+
|
|
73
|
+
- Blok kode tanpa pojok kanan dan garis batas berantakan pada mode `--tui`.
|
|
74
|
+
- Notifikasi login Drive yang terpecah oleh rule gradien antarbaris.
|
|
75
|
+
|
|
76
|
+
## [0.4.3] - 2026-10-31
|
|
77
|
+
|
|
78
|
+
### Diperbaiki
|
|
79
|
+
|
|
80
|
+
- **Jawaban yang hanya mengumumkan langkah berikutnya tidak lagi menutup tugas
|
|
81
|
+
sebagai `completed`.** Gejalanya: edit terakhir berhasil, model menulis
|
|
82
|
+
"Edit applied. Let me verify the syntax…" tanpa satu pun tool call, lalu run
|
|
83
|
+
berhenti `◆ completed` padahal verifikasi yang dijanjikan tidak pernah jalan
|
|
84
|
+
dan tugasnya belum selesai. Kini jawaban yang kalimat penutupnya hanya
|
|
85
|
+
merencanakan aksi (`let me…`, `now I'll…`, `saya akan…`,
|
|
86
|
+
`langkah selanjutnya…`) dimasukkan ke riwayat dan model diminta mengirim tool
|
|
87
|
+
call-nya (heartbeat `UNFINISHED_ANSWER`, wording berputar, tidak memakan
|
|
88
|
+
langkah, dan **tanpa batas percobaan** — hanya `/cancel` atau tenggat tugas
|
|
89
|
+
yang menghentikannya, sama seperti giliran kosong). Kalimat yang
|
|
90
|
+
bertanya/menawarkan lanjutan ke pengguna ("let me know", "mau saya") tetap
|
|
91
|
+
dianggap jawaban akhir.
|
|
92
|
+
- **Batas percobaan pada respons terpotong dihapus.** Status `truncated` tidak
|
|
93
|
+
lagi dipakai untuk mengakhiri tugas lebih awal: respons yang kena
|
|
94
|
+
`agent.maxOutputTokens` terus diminta ulang dengan panggilan lebih kecil
|
|
95
|
+
(backoff eksponensial tetap, wording berputar) sampai tugas benar-benar
|
|
96
|
+
selesai, dibatalkan, atau tenggat waktu habis. Tidak ada lagi tugas yang
|
|
97
|
+
berhenti sendiri karena jumlah percobaan recovery.
|
|
98
|
+
- **Tugas yang berakhir tanpa jawaban tidak lagi disimpan sebagai jawaban
|
|
99
|
+
asisten.** Tugas `cancelled`/`failed`/`truncated` sebelumnya masuk memori
|
|
100
|
+
percakapan dengan teks `Task cancelled. No further tool calls were executed.`
|
|
101
|
+
sehingga tugas sesudahnya bisa memantulkannya kembali sebagai jawaban → run
|
|
102
|
+
`completed · 1 step · changed: none`. Kini hanya status `completed` dan
|
|
103
|
+
`step-limit` yang disimpan sebagai jawaban; sisanya menjadi catatan runtime
|
|
104
|
+
internal yang tidak boleh dikutip. Kontrak operasional prompt juga memuat
|
|
105
|
+
aturan baru: respons tanpa tool call mengakhiri tugas, jadi jangan pernah
|
|
106
|
+
menutup turn dengan mengumumkan aksi berikutnya.
|
|
107
|
+
|
|
6
108
|
## [0.4.2] - 2026-10-31
|
|
7
109
|
|
|
8
110
|
### Diperbaiki
|
package/README.md
CHANGED
|
@@ -783,17 +783,64 @@ berpura-pura sebaliknya.
|
|
|
783
783
|
- `finish_reason: \"length\"` ditangani: pemanggilan tool yang terpotong pada
|
|
784
784
|
batas token output dibuang dan dilaporkan, tidak pernah dieksekusi sebagai
|
|
785
785
|
file yang tertulis setengah jalan. Respons yang terpotong **tanpa** tool call
|
|
786
|
-
yang utuh juga tidak pernah dianggap jawaban akhir:
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
786
|
+
yang utuh juga tidak pernah dianggap jawaban akhir: sisa teksnya tetap masuk
|
|
787
|
+
riwayat supaya model melanjutkan (bukan mengulang analisis), lalu model diminta
|
|
788
|
+
mengulang dengan panggilan yang lebih kecil (heartbeat `TRUNCATED_RESPONSE`,
|
|
789
|
+
backoff eksponensial). Pengulangan itu **tanpa batas percobaan** — sama seperti
|
|
790
|
+
giliran kosong, hanya `/cancel` atau tenggat tugas yang menghentikannya.
|
|
791
|
+
- Jawaban yang hanya **mengumumkan** langkah berikutnya ("Edit applied. Let me
|
|
792
|
+
verify the syntax…") juga tidak mengakhiri tugas: pengumuman itu masuk riwayat
|
|
793
|
+
dan model diminta mengirim tool call yang dijanjikannya sendiri (heartbeat
|
|
794
|
+
`UNFINISHED_ANSWER`, wording berputar, tanpa batas percobaan). Jadi run tidak
|
|
795
|
+
bisa berhenti sebagai `completed` dengan pekerjaan yang belum dijalankan.
|
|
796
|
+
Kalimat yang bertanya atau menawarkan lanjutan ke pengguna ("let me know",
|
|
797
|
+
"mau saya") tetap diterima sebagai jawaban akhir.
|
|
798
|
+
- Tugas yang berakhir `cancelled`/`failed` tidak disimpan sebagai jawaban
|
|
799
|
+
asisten, hanya sebagai catatan runtime internal, sehingga tugas berikutnya
|
|
800
|
+
tidak memantulkannya sebagai jawabannya sendiri.
|
|
801
|
+
- Respons tanpa tool call memang mengakhiri tugas, jadi jawaban yang kalimat
|
|
802
|
+
penutupnya hanya merencanakan aksi (`let me…`, `now I'll…`, `saya akan…`,
|
|
803
|
+
`langkah selanjutnya…`) tidak diterima sebagai hasil: model diminta mengirim
|
|
804
|
+
tool call-nya sendiri (heartbeat `UNFINISHED_ANSWER`, maksimum 2 kali, tanpa
|
|
805
|
+
memakan langkah), dan bila tetap mengumumkan tugas berhenti dengan status
|
|
806
|
+
`incomplete` (`✕ ended without finishing`) alih-alih `completed`. Kalimat yang
|
|
807
|
+
bertanya atau menawarkan lanjutan kepada Anda tetap dianggap jawaban akhir.
|
|
808
|
+
- Hanya tugas yang benar-benar menjawab (`completed`/`step-limit`) yang disimpan
|
|
809
|
+
sebagai jawaban di memori percakapan. Tugas `cancelled`, `failed`,
|
|
810
|
+
`truncated`, atau `incomplete` dicatat sebagai catatan runtime internal, jadi
|
|
811
|
+
tugas berikutnya tidak bisa memantulkan kembali "Task cancelled. No further
|
|
812
|
+
tool calls were executed." sebagai jawabannya sendiri.
|
|
792
813
|
- Pada 70% anggaran waktu, model diberi tahu untuk menyatu (konvergen), dan
|
|
793
814
|
aliran respons yang tidak mengirim byte selama
|
|
794
815
|
`agent.streamIdleTimeoutMs` dibatalkan dengan `STREAM_STALLED` alih-alih
|
|
795
816
|
menahan langkah tetap terbuka.
|
|
796
817
|
|
|
818
|
+
## Plugin: Google Drive
|
|
819
|
+
|
|
820
|
+
Integrasi opsional yang tinggal di `agents/ryuu/plugins/` (bukan di `src/services/`) dan
|
|
821
|
+
mendaftarkan toolnya ke registry yang sudah ada hanya ketika aktif **dan** sudah login.
|
|
822
|
+
|
|
823
|
+
```bash
|
|
824
|
+
/drive login # OAuth Web Application via API backend (CLI tanpa client id/secret)
|
|
825
|
+
/drive enable # daftarkan 16 tool Drive untuk AI Agent
|
|
826
|
+
/drive status # status integrasi, akun, scope, kuota
|
|
827
|
+
/drive test # diagnostik konfigurasi + credential + API
|
|
828
|
+
```
|
|
829
|
+
|
|
830
|
+
Tool yang tersedia setelah aktif: `drive_search`, `drive_list`, `drive_get_metadata`,
|
|
831
|
+
`drive_download`, `drive_upload`, `drive_create_folder`, `drive_move`, `drive_rename`,
|
|
832
|
+
`drive_copy`, `drive_delete`, `drive_backup`, `drive_restore`, `drive_list_backups`,
|
|
833
|
+
`drive_delete_backup`, `drive_storage_info`, `drive_get_account`.
|
|
834
|
+
|
|
835
|
+
Client ID dan Client Secret Google **tidak ada di CLI**: keduanya hanya tersimpan di
|
|
836
|
+
proyek API (`website/api/lib/config.js`) yang melayani login lewat
|
|
837
|
+
`/admin/tools/drive-cli`. CLI memakai kunci khusus login Drive yang tertanam di
|
|
838
|
+
`plugins/google-drive/secret.js` (header `x-ryuu-drive-auth`, tidak dapat diubah dan
|
|
839
|
+
tidak pernah ditampilkan); root key admin tidak dipakai dan tidak dikirim ke CLI.
|
|
840
|
+
|
|
841
|
+
Endpoint backend dan redirect URI bersifat hardcode dan tidak bisa diubah lewat
|
|
842
|
+
command apa pun. Dokumentasi lengkap: **[docs/drive.md](docs/drive.md)**.
|
|
843
|
+
|
|
797
844
|
## Model persetujuan dan izin
|
|
798
845
|
|
|
799
846
|
Kebijakannya diatur dengan `agent.approvalPolicy`:
|
package/docs/drive.md
ADDED
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
# Google Drive Integration (plugin)
|
|
2
|
+
|
|
3
|
+
Integrasi Google Drive untuk Ryuu CLI. Plugin ini tinggal di `agents/ryuu/plugins/google-drive/`
|
|
4
|
+
dan terhubung ke arsitektur yang sudah ada: tool registry (`src/tools/registry.js`),
|
|
5
|
+
command parser (`src/cli/commands.js`), dan approval manager (`src/agent/approvals.js`).
|
|
6
|
+
|
|
7
|
+
Tidak ada sistem plugin, command parser, atau registry baru. Tidak ada backend OAuth eksternal.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 1. Pengenalan
|
|
12
|
+
|
|
13
|
+
Setelah `/drive login` dan `/drive enable`, AI Agent dapat mencari file, upload, download,
|
|
14
|
+
mengelola folder, membuat backup ZIP project, dan melakukan restore — semuanya lewat
|
|
15
|
+
function tools yang sudah dikenal provider AI Ryuu.
|
|
16
|
+
|
|
17
|
+
Nama internal: `google-drive` · Command: `/drive` · Dependency: `googleapis`
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 2. Fitur
|
|
22
|
+
|
|
23
|
+
| Kelompok | Fitur |
|
|
24
|
+
| --- | --- |
|
|
25
|
+
| Autentikasi | OAuth 2.0 Web Application lewat backend API, PKCE S256 di server, logout + revocation |
|
|
26
|
+
| File | search, list, metadata, download, upload streaming, create folder, move, rename, copy, delete |
|
|
27
|
+
| Backup | ZIP streaming, exclusion pattern, upload streaming, structured result |
|
|
28
|
+
| Restore | download, validasi ZIP, ekstraksi anti Zip Slip, overwrite opt-in |
|
|
29
|
+
| Info | storage quota, akun terhubung |
|
|
30
|
+
| Lainnya | enable/disable, status, diagnostik, config manager |
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 3. Arsitektur
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
plugins/
|
|
38
|
+
├── index.js host: loadPlugins, syncPluginTools, unregisterPluginTools
|
|
39
|
+
└── google-drive/
|
|
40
|
+
├── index.js deskriptor plugin + factory
|
|
41
|
+
├── manager.js lifecycle (GoogleDrivePlugin), login/logout, status, diagnose
|
|
42
|
+
├── config.js konfigurasi + validasi key (Client ID dikunci)
|
|
43
|
+
├── credentials.js penyimpanan token terenkripsi AES-256-GCM
|
|
44
|
+
├── auth.js PKCE, callback server, authorization URL, revocation
|
|
45
|
+
├── drive-api.js client Drive API v3 (streaming, error mapping)
|
|
46
|
+
├── backup.js engine backup/restore, exclusion, temp cleanup
|
|
47
|
+
├── zip-writer.js penulis ZIP streaming (CRC32, data descriptor)
|
|
48
|
+
├── zip-reader.js pembaca ZIP streaming + proteksi Zip Slip
|
|
49
|
+
├── tools.js gabungan seluruh tool
|
|
50
|
+
├── tools-files.js tool file & folder
|
|
51
|
+
├── tools-backup.js tool backup/restore/info
|
|
52
|
+
├── tool-helpers.js helper path lokal & format ukuran
|
|
53
|
+
└── command.js handler `/drive`
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Alur registrasi tool:
|
|
57
|
+
|
|
58
|
+
1. `src/cli/app.js` memanggil `loadPlugins()` setelah registry dibangun.
|
|
59
|
+
2. `syncPluginTools()` mendaftarkan tool **hanya bila** `enabled === true` **dan** sudah login.
|
|
60
|
+
3. `/drive disable` dan `/drive logout` memanggil `unregisterPluginTools()`.
|
|
61
|
+
4. Setiap handler tool memanggil `plugin.requireClient()`, yang memeriksa ulang status
|
|
62
|
+
dari disk — model yang masih memegang daftar tool lama tidak bisa mengeksekusi apa pun.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 4. Persyaratan
|
|
67
|
+
|
|
68
|
+
- Node.js 18+ (proyek memakai ESM dan `node:test`).
|
|
69
|
+
- `googleapis` (sudah ditambahkan ke `package.json`).
|
|
70
|
+
- Project Google Cloud dengan **Google Drive API** aktif.
|
|
71
|
+
- OAuth Client bertipe **Web application** (redirect URI dikelola proyek API).
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## 5. OAuth lewat backend API (credential bukan milik CLI)
|
|
76
|
+
|
|
77
|
+
Ryuu CLI **tidak memegang Client ID maupun Client Secret Google**. Keduanya hanya
|
|
78
|
+
ada di proyek root `website/api` (`lib/config.js`), dan seluruh langkah OAuth
|
|
79
|
+
dikerjakan di sana:
|
|
80
|
+
|
|
81
|
+
| Langkah | Dikerjakan oleh |
|
|
82
|
+
| --- | --- |
|
|
83
|
+
| `state` + PKCE verifier (S256) | backend API |
|
|
84
|
+
| authorization URL | backend API |
|
|
85
|
+
| penukaran `code` → token (memakai client secret) | backend API |
|
|
86
|
+
| refresh token & revocation | backend API (lewat `grantId`) |
|
|
87
|
+
| menyimpan token terenkripsi + memanggil Drive API | CLI |
|
|
88
|
+
|
|
89
|
+
Kontraknya: `POST /admin/tools/drive-cli` untuk
|
|
90
|
+
start/poll/refresh/revoke, dan `GET /admin/tools/drive-callback` untuk redirect
|
|
91
|
+
Google. Keduanya berada di folder `api/admin/tools/` proyek API.
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
start { action: 'start' } → { state, url, redirectUri } [kunci login]
|
|
95
|
+
poll { action: 'poll', state } → { found, accessToken, grantId, … } [kunci login]
|
|
96
|
+
refresh { action: 'refresh', grantId } → { accessToken baru, grantId } [grant]
|
|
97
|
+
revoke { action: 'revoke', grantId } → { revoked } [grant]
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Refresh dan revoke tidak lagi mengirim refresh token maupun kunci aplikasi:
|
|
101
|
+
CLI memegang `grantId` (terbit sekali saat login, berlaku 90 hari, terikat satu
|
|
102
|
+
akun) dan backend menyimpan refresh token untuk grant tersebut.
|
|
103
|
+
|
|
104
|
+
Alur `/drive login`:
|
|
105
|
+
|
|
106
|
+
1. CLI meminta `start`; backend membuat `state`, verifier PKCE, dan URL Google.
|
|
107
|
+
2. CLI mencetak URL itu (dan membuka browser bila tersedia).
|
|
108
|
+
3. Setelah pengguna setuju, Google mengarahkan ke
|
|
109
|
+
`https://restapi.ryuu-dev.my.id/admin/tools/drive-callback`.
|
|
110
|
+
4. Backend menukar `code` + verifier + client secret menjadi token, lalu
|
|
111
|
+
menyimpannya maksimal 10 menit untuk diambil **sekali**.
|
|
112
|
+
5. CLI mem-poll tiap 2 detik, menerima token, menyimpannya terenkripsi.
|
|
113
|
+
|
|
114
|
+
Endpoint backend dan redirect URI bersifat **hardcode**: tidak ada command,
|
|
115
|
+
config, maupun environment variable yang dapat mengubahnya.
|
|
116
|
+
|
|
117
|
+
### Kunci login Drive (bukan root key)
|
|
118
|
+
|
|
119
|
+
Route CLI dilindungi kunci **khusus login Drive**: header `x-ryuu-drive-auth`,
|
|
120
|
+
nilai turunan HMAC-SHA256 dari 32 byte yang tertanam di
|
|
121
|
+
`website/api/lib/drive-login-key.js` (server) dan
|
|
122
|
+
`plugins/google-drive/secret.js` (CLI). Bahan disimpan sebagai empat potongan
|
|
123
|
+
ter-XOR, dan yang dikirim ke jaringan adalah turunannya — bukan bahan itu.
|
|
124
|
+
|
|
125
|
+
Tidak ada yang perlu diisi pengguna dan tidak ada command untuk mengubahnya.
|
|
126
|
+
Root key admin tidak dipakai di sini dan tidak pernah dikirim ke CLI, jadi
|
|
127
|
+
kebocoran sisi CLI tidak membuka endpoint admin lain. Kunci hanya terpakai pada
|
|
128
|
+
`start` dan `poll`; setelah login selesai CLI memakai `grantId` untuk
|
|
129
|
+
refresh/revoke, sehingga kunci aplikasi tidak tersimpan di mesin pengguna.
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## 6. Yang tidak bisa diubah dari command
|
|
134
|
+
|
|
135
|
+
`validateConfigEntry` menolak key `clientId`, `clientSecret`, `scopes`,
|
|
136
|
+
`oauthBackend`, `oauthCliPath`, `rootKey`, `driveKey`, dan `secret`. Berkas
|
|
137
|
+
config yang ditulis tangan pun dibersihkan: hanya key yang dikenal plugin yang
|
|
138
|
+
dipertahankan, jadi kunci login Drive tidak bisa ditanamkan lewat berkas.
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## 7. Google Cloud setup
|
|
143
|
+
|
|
144
|
+
1. Buka Google Cloud Console → buat project.
|
|
145
|
+
2. **APIs & Services → Library** → aktifkan **Google Drive API**.
|
|
146
|
+
3. **OAuth consent screen** → tipe *External*, tambahkan scope `.../auth/drive.file`,
|
|
147
|
+
tambahkan akun Anda sebagai *test user* selama aplikasi belum dipublikasikan.
|
|
148
|
+
4. **Credentials → Create credentials → OAuth client ID → Web application**.
|
|
149
|
+
5. Tambahkan **Authorized redirect URI**:
|
|
150
|
+
`https://restapi.ryuu-dev.my.id/admin/tools/drive-callback`.
|
|
151
|
+
6. Simpan Client ID + Client Secret di `website/api/lib/config.js`
|
|
152
|
+
(`global.driveOAuthClientId` / `global.driveOAuthClientSecret`). Tidak ada
|
|
153
|
+
tempat lain yang boleh menyimpannya.
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## 8. Aktivasi Google Drive API
|
|
158
|
+
|
|
159
|
+
Tanpa langkah 7.2, login berhasil tetapi setiap panggilan API gagal dengan 403/`accessNotConfigured`.
|
|
160
|
+
Pesan error plugin akan menyebut scope `drive.file` dan menyarankan pemeriksaan ini.
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## 9. Cara login
|
|
165
|
+
|
|
166
|
+
```
|
|
167
|
+
/drive login
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Alur: minta URL otorisasi ke backend API (membawa kunci login Drive) → buka browser →
|
|
171
|
+
tunggu persetujuan → backend menukar code + PKCE verifier dengan client secret →
|
|
172
|
+
CLI mem-poll dan menerima token → simpan token terenkripsi → verifikasi akses dengan
|
|
173
|
+
`about.get` → aktifkan integrasi.
|
|
174
|
+
|
|
175
|
+
Contoh output:
|
|
176
|
+
|
|
177
|
+
```
|
|
178
|
+
Google Drive Authentication
|
|
179
|
+
|
|
180
|
+
Browser tidak tersedia di mesin ini — buka tautan di bawah secara manual.
|
|
181
|
+
Login dengan akun Google lewat tautan berikut; blok di bawah bisa diklik untuk menyalin.
|
|
182
|
+
|
|
183
|
+
╭─ login-url ────────────────────────────────────────────── ⧉ copy ╮
|
|
184
|
+
│ https://accounts.google.com/o/oauth2/v2/auth?access_type=offline&… │
|
|
185
|
+
╰──────────────────────────────────────────────────────────────────╯
|
|
186
|
+
|
|
187
|
+
Callback : https://restapi.ryuu-dev.my.id/admin/tools/drive-callback
|
|
188
|
+
Otorisasi : backend API https://restapi.ryuu-dev.my.id
|
|
189
|
+
Kredensial Google (client id/secret) tidak disimpan di CLI.
|
|
190
|
+
|
|
191
|
+
Menunggu persetujuan pengguna…
|
|
192
|
+
[✓] Autentikasi berhasil!
|
|
193
|
+
|
|
194
|
+
Akun : user@gmail.com
|
|
195
|
+
Permission : https://www.googleapis.com/auth/drive.file
|
|
196
|
+
Status : Connected
|
|
197
|
+
|
|
198
|
+
Google Drive aktif. Tools Drive sekarang tersedia untuk AI Agent.
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
URL selalu dicetak sebagai blok berbingkai dengan tombol `⧉ copy`: di `--tui`
|
|
202
|
+
blok itu bisa diklik (dan menyalin URL utuh, bukan potongan baris hasil wrap),
|
|
203
|
+
sedangkan pada mode baris perintah peramban terminal sudah menyalinnya.
|
|
204
|
+
|
|
205
|
+
> Satu blok per perintah. Semua baris yang dicetak satu perintah tetap satu
|
|
206
|
+
> blok di `--tui`, jadi tidak ada garis pemisah yang menyelip di tengah
|
|
207
|
+
> notifikasi autentikasi.
|
|
208
|
+
|
|
209
|
+
Jika akun sudah terhubung, CLI menanyakan konfirmasi sebelum menimpa kredensial lama.
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## 10. Login dari container, VPS, atau laptop
|
|
214
|
+
|
|
215
|
+
Tidak ada callback server lokal: port dalam container bukan lagi masalah, dan SSH
|
|
216
|
+
port forwarding tidak diperlukan.
|
|
217
|
+
|
|
218
|
+
1. Jalankan `/drive login`. URL Google selalu dicetak lengkap.
|
|
219
|
+
2. Buka URL itu di browser perangkat mana pun (boleh mesin berbeda) dan setujui.
|
|
220
|
+
3. Google mengarahkan ke `https://restapi.ryuu-dev.my.id/admin/tools/drive-callback`.
|
|
221
|
+
4. Backend menyimpan token sebentar; CLI mengambilnya lewat polling (2 detik) dan
|
|
222
|
+
langsung menyimpannya terenkripsi.
|
|
223
|
+
|
|
224
|
+
Batas waktu 5 menit; setelah itu jalankan `/drive login` lagi. Token di backend
|
|
225
|
+
dihapus setelah diambil atau setelah 10 menit.
|
|
226
|
+
|
|
227
|
+
Verifikasi backend tanpa menyentuh Google (fetch Google distub):
|
|
228
|
+
|
|
229
|
+
```
|
|
230
|
+
cd website/api && node tools/test-drive-oauth.mjs
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## 11. Cara logout
|
|
236
|
+
|
|
237
|
+
```
|
|
238
|
+
/drive logout
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Tool dilepas, token di memori dan di disk dihapus, encryption key ikut dihapus
|
|
242
|
+
(kecuali berasal dari `RYUU_DRIVE_KEY`), revocation OAuth dicoba. Konfigurasi
|
|
243
|
+
non-sensitif dan file pengguna di Google Drive **tidak** dihapus.
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## 12. Enable / disable
|
|
248
|
+
|
|
249
|
+
| Perintah | Efek |
|
|
250
|
+
| --- | --- |
|
|
251
|
+
| `/drive enable` | Butuh login. Menulis `enabled=true` dan mendaftarkan seluruh tool. |
|
|
252
|
+
| `/drive disable` | Melepas tool dari registry, memblokir eksekusi, token & config tetap. |
|
|
253
|
+
|
|
254
|
+
Matriks lifecycle:
|
|
255
|
+
|
|
256
|
+
| enabled | authenticated | Tool tersedia |
|
|
257
|
+
| --- | --- | --- |
|
|
258
|
+
| ya | ya | ya |
|
|
259
|
+
| ya | tidak | tidak (arahkan `/drive login`) |
|
|
260
|
+
| tidak | ya | tidak |
|
|
261
|
+
| tidak | tidak | tidak |
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## 13. Status
|
|
266
|
+
|
|
267
|
+
```
|
|
268
|
+
/drive status
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Menampilkan status integrasi, autentikasi, akun, scope, status token, jumlah tool aktif,
|
|
272
|
+
folder backup, dan waktu pemeriksaan koneksi terakhir. Token tidak pernah ditampilkan.
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## 14. Seluruh command
|
|
277
|
+
|
|
278
|
+
```
|
|
279
|
+
/drive bantuan
|
|
280
|
+
/drive login mulai OAuth
|
|
281
|
+
/drive logout putuskan koneksi
|
|
282
|
+
/drive account akun + quota
|
|
283
|
+
/drive enable aktifkan integrasi
|
|
284
|
+
/drive disable nonaktifkan integrasi
|
|
285
|
+
/drive status ringkasan status
|
|
286
|
+
/drive config sama dengan config show
|
|
287
|
+
/drive config show tampilkan konfigurasi
|
|
288
|
+
/drive config set <k> <v> ubah satu konfigurasi
|
|
289
|
+
/drive test diagnostik lengkap
|
|
290
|
+
/drive tools daftar tool yang terdaftar
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
Key konfigurasi: `enabled`, `defaultBackupFolder`, `backupDirectory`, `excludePatterns`,
|
|
294
|
+
`maxUploadSize`, `confirmDestructive`, `autoRefresh`.
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
## 15. Seluruh tool AI
|
|
299
|
+
|
|
300
|
+
| Tool | Risk | Keterangan |
|
|
301
|
+
| --- | --- | --- |
|
|
302
|
+
| `drive_search` | read | Cari by nama, MIME, folder, query mentah, pagination |
|
|
303
|
+
| `drive_list` | read | Isi folder |
|
|
304
|
+
| `drive_get_metadata` | read | Metadata lengkap satu item |
|
|
305
|
+
| `drive_download` | write | Unduh ke path lokal workspace, tidak menimpa tanpa izin |
|
|
306
|
+
| `drive_upload` | write | Upload streaming, dibatasi `maxUploadSize` |
|
|
307
|
+
| `drive_create_folder` | write | Buat folder |
|
|
308
|
+
| `drive_move` | write | Pindahkan item |
|
|
309
|
+
| `drive_rename` | write | Ubah nama |
|
|
310
|
+
| `drive_copy` | write | Salin file |
|
|
311
|
+
| `drive_delete` | destructive | Hapus permanen + approval |
|
|
312
|
+
| `drive_backup` | write | ZIP streaming + upload |
|
|
313
|
+
| `drive_restore` | write | Unduh + validasi + ekstraksi |
|
|
314
|
+
| `drive_list_backups` | read | Daftar arsip ZIP |
|
|
315
|
+
| `drive_delete_backup` | destructive | Hapus arsip backup hanya untuk `.zip` |
|
|
316
|
+
| `drive_storage_info` | read | Kuota penyimpanan |
|
|
317
|
+
| `drive_get_account` | read | Akun terhubung |
|
|
318
|
+
|
|
319
|
+
Operasi `destructive` melewati `ApprovalManager` yang sudah ada, sehingga
|
|
320
|
+
`--auto-approve` dan policy `read-only` tetap berlaku seperti tool bawaan.
|
|
321
|
+
|
|
322
|
+
---
|
|
323
|
+
|
|
324
|
+
## 16. Contoh backup
|
|
325
|
+
|
|
326
|
+
Perintah ke AI:
|
|
327
|
+
|
|
328
|
+
```
|
|
329
|
+
Backup seluruh project ini ke Google Drive, kecuali node_modules, .git, .env dan cache.
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
AI memanggil `drive_backup` dengan `sourcePath: "."` dan `excludePatterns` tambahan.
|
|
333
|
+
Default `excludePatterns` sudah memuat `node_modules`, `.git`, `.env`, `*.pem`, `*.key`,
|
|
334
|
+
`credentials.json`, `cache`, `tmp`, `temp`, `*.log`. Secret (`HARD_EXCLUDES`) tidak pernah
|
|
335
|
+
ikut meskipun pengguna memintanya.
|
|
336
|
+
|
|
337
|
+
Contoh hasil:
|
|
338
|
+
|
|
339
|
+
```
|
|
340
|
+
Backup berhasil!
|
|
341
|
+
Project : Lyoraa
|
|
342
|
+
Arsip : lyoraa-backup-20261101-101500.zip
|
|
343
|
+
Ukuran : 42.8 MB
|
|
344
|
+
Lokasi : Google Drive / Backups
|
|
345
|
+
Dikecualikan: node_modules, .git, .env, cache, …
|
|
346
|
+
Status : berhasil
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
---
|
|
350
|
+
|
|
351
|
+
## 17. Contoh restore
|
|
352
|
+
|
|
353
|
+
```
|
|
354
|
+
Pulihkan backup Lyoraa terakhir ke folder ./restore.
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
AI memanggil `drive_list_backups`, memilih arsip, lalu `drive_restore` dengan
|
|
358
|
+
`fileId` dan `destinationPath: "restore"`. Tanpa `overwrite=true`, restore berhenti
|
|
359
|
+
dan melaporkan file yang sudah ada.
|
|
360
|
+
|
|
361
|
+
---
|
|
362
|
+
|
|
363
|
+
## 18. Personal Drive
|
|
364
|
+
|
|
365
|
+
`folderId` yang dihilangkan berarti My Drive root (`root`). Semua panggilan memakai
|
|
366
|
+
`supportsAllDrives` dan `includeItemsFromAllDrives` agar item Shared Drive yang
|
|
367
|
+
terlihat oleh akun tetap terbaca.
|
|
368
|
+
|
|
369
|
+
---
|
|
370
|
+
|
|
371
|
+
## 19. Shared Folder
|
|
372
|
+
|
|
373
|
+
Gunakan folder ID sebagai identitas:
|
|
374
|
+
|
|
375
|
+
```
|
|
376
|
+
/drive config set defaultBackupFolder <folder-id>
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
Folder divalidasi lewat `assertFolder()` sebelum dipakai (harus ada dan bertipe folder).
|
|
380
|
+
Perlu dicatat: scope `drive.file` hanya memberi akses ke file yang dibuat atau dibuka
|
|
381
|
+
oleh aplikasi ini, jadi folder Shared Drive yang tidak pernah dibuka Ryuu akan ditolak
|
|
382
|
+
Google dengan 403. Pesan error menyebutkan hal ini, bukan menampilkan stack trace.
|
|
383
|
+
|
|
384
|
+
---
|
|
385
|
+
|
|
386
|
+
## 20. Lokasi credential per OS
|
|
387
|
+
|
|
388
|
+
| OS | Direktori |
|
|
389
|
+
| --- | --- |
|
|
390
|
+
| Linux | `$XDG_CONFIG_HOME/ryuu` atau `~/.config/ryuu` |
|
|
391
|
+
| macOS | `~/Library/Application Support/ryuu` |
|
|
392
|
+
| Windows | `%APPDATA%\ryuu` |
|
|
393
|
+
|
|
394
|
+
```
|
|
395
|
+
.config/ryuu/
|
|
396
|
+
├── config.json
|
|
397
|
+
├── .keys/google-drive.key ← 0600, terpisah dari ciphertext
|
|
398
|
+
└── integrations/google-drive/
|
|
399
|
+
├── config.json
|
|
400
|
+
└── credentials.enc ← AES-256-GCM
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
`RYUU_CONFIG_DIR` (override yang sudah dipakai Ryuu) tetap berlaku.
|
|
404
|
+
|
|
405
|
+
---
|
|
406
|
+
|
|
407
|
+
## 21. Keamanan
|
|
408
|
+
|
|
409
|
+
- Token tidak pernah masuk ke context AI, log, atau output tool; `describeCredentials()`
|
|
410
|
+
hanya mengembalikan metadata.
|
|
411
|
+
- Ciphertext dan encryption key berada di direktori berbeda; file 0600, direktori 0700.
|
|
412
|
+
- `RYUU_DRIVE_KEY` (hex 64 karakter atau base64 32 byte) dapat menggantikan file kunci,
|
|
413
|
+
cocok untuk secret manager/VPS.
|
|
414
|
+
- Path lokal dari model divalidasi `Workspace.resolve()`: path absolut ditolak,
|
|
415
|
+
traversal dan symlink escape ditolak, file secret diblokir.
|
|
416
|
+
- ZIP: nama entri absolut dan `..` ditolak, symlink tujuan ditolak, CRC32 diverifikasi,
|
|
417
|
+
total ekstraksi dibatasi 8 GB.
|
|
418
|
+
- Backup tidak pernah menyertakan secret secara diam-diam, dan symlink tidak diikuti.
|
|
419
|
+
|
|
420
|
+
---
|
|
421
|
+
|
|
422
|
+
## 22. Error handling
|
|
423
|
+
|
|
424
|
+
Semua pesan berbahasa Indonesia dan tanpa stack trace secara default:
|
|
425
|
+
|
|
426
|
+
| Kondisi | Pesan |
|
|
427
|
+
| --- | --- |
|
|
428
|
+
| Belum login | `Jalankan /drive login terlebih dahulu` |
|
|
429
|
+
| Integrasi nonaktif | `Integrasi Google Drive sedang nonaktif. Jalankan /drive enable` |
|
|
430
|
+
| Refresh token invalid | `refresh token sudah tidak berlaku. Jalankan /drive login` |
|
|
431
|
+
| 403 permission | Menyebut scope `drive.file` |
|
|
432
|
+
| 403/429 kuota | `Kuota Google Drive habis atau rate limit API tercapai` |
|
|
433
|
+
| 404 | `File atau folder Google Drive tidak ditemukan` |
|
|
434
|
+
| Network | `Tidak dapat menghubungi Google Drive (masalah jaringan)` |
|
|
435
|
+
| Disk penuh | `Disk penuh: tidak ada ruang untuk menulis file` |
|
|
436
|
+
| ZIP rusak | `CRC arsip tidak cocok …` / `Arsip bukan ZIP yang valid` |
|
|
437
|
+
| Zip Slip | `Arsip berisi path traversal dan ditolak` |
|
|
438
|
+
|
|
439
|
+
---
|
|
440
|
+
|
|
441
|
+
## 23. Troubleshooting
|
|
442
|
+
|
|
443
|
+
| Gejala | Penyebab | Tindakan |
|
|
444
|
+
| --- | --- | --- |
|
|
445
|
+
| `redirect_uri_mismatch` | Redirect URI belum terdaftar | Tambahkan `https://restapi.ryuu-dev.my.id/admin/tools/drive-callback` di OAuth client Web application |
|
|
446
|
+
| Login sukses, tool tidak muncul | `enabled=false` | `/drive enable` |
|
|
447
|
+
| Tool hilang setelah restart | Belum pernah `/drive enable` | Jalankan sekali, nilainya tersimpan |
|
|
448
|
+
| `accessNotConfigured` | Drive API belum aktif | Aktifkan di Cloud Console |
|
|
449
|
+
| 403 pada file tertentu | Di luar scope `drive.file` | Buka file lewat Ryuu setelah upload |
|
|
450
|
+
| `Kredensial tidak dapat didekripsi` | Key berbeda/rusak | `/drive login` ulang |
|
|
451
|
+
| Restore berhenti | File tujuan sudah ada | Kirim `overwrite=true` |
|
|
452
|
+
| Backup melebihi batas | `maxUploadSize` | Naikkan atau tambah exclusion |
|
|
453
|
+
|
|
454
|
+
---
|
|
455
|
+
|
|
456
|
+
## 24. Batasan OAuth scope
|
|
457
|
+
|
|
458
|
+
Scope default `https://www.googleapis.com/auth/drive.file` hanya memberi akses ke file
|
|
459
|
+
yang dibuat atau dibuka oleh aplikasi ini. Konsekuensinya:
|
|
460
|
+
|
|
461
|
+
- File pribadi lain di Drive tidak terlihat oleh `drive_search`/`drive_list`.
|
|
462
|
+
- Shared Drive yang belum pernah dibuka Ryuu akan ditolak.
|
|
463
|
+
- `drive.file` **tidak** dapat dinaikkan menjadi `drive` dari command; itu keputusan
|
|
464
|
+
keamanan, bukan bug. Untuk akses penuh, ubah `DEFAULT_GOOGLE_DRIVE_CONFIG.scopes`
|
|
465
|
+
di source setelah meninjau risikonya.
|
|
466
|
+
- Google Picker tidak diimplementasikan, sehingga "membuka" file untuk aplikasi harus
|
|
467
|
+
dilakukan lewat upload Ryuu sendiri.
|
|
468
|
+
|
|
469
|
+
---
|
|
470
|
+
|
|
471
|
+
## Testing
|
|
472
|
+
|
|
473
|
+
`tests/unit/google-drive.test.js` (7 test, seluruhnya lulus):
|
|
474
|
+
|
|
475
|
+
- default config, Client ID terkunci, validasi key
|
|
476
|
+
- penyimpanan kredensial terenkripsi + tidak ada token di metadata
|
|
477
|
+
- PKCE S256, state acak, URL otorisasi tanpa client secret
|
|
478
|
+
- roundtrip ZIP streaming, penolakan overwrite, penolakan Zip Slip
|
|
479
|
+
- exclusion pattern + secret hard-exclude
|
|
480
|
+
- lifecycle: disabled/unauthenticated tidak pernah mendaftarkan tool, risk level benar
|
|
481
|
+
- schema seluruh tool valid dan unik
|
|
482
|
+
|
|
483
|
+
Tidak ada klaim autentikasi sungguhan: belum ada kredensial OAuth nyata yang dipakai
|
|
484
|
+
saat pengujian, jadi alur login hanya diverifikasi secara struktural (URL, PKCE, state).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ryuu-reinzz/ryuu-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Ryuu Agent CLI - an autonomous, approval-gated AI coding agent for your terminal",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
},
|
|
13
13
|
"files": [
|
|
14
14
|
"src",
|
|
15
|
+
"plugins",
|
|
16
|
+
"docs",
|
|
15
17
|
"README.md",
|
|
16
18
|
"CHANGELOG.md"
|
|
17
19
|
],
|
|
@@ -41,6 +43,7 @@
|
|
|
41
43
|
"dependencies": {
|
|
42
44
|
"@modelcontextprotocol/sdk": "^1.32.1",
|
|
43
45
|
"chalk": "^6.0.1",
|
|
46
|
+
"googleapis": "^189.0.0",
|
|
44
47
|
"openai": "^7.39.0",
|
|
45
48
|
"ora": "^9.4.1"
|
|
46
49
|
}
|