@ryuu-reinzz/ryuu-cli 0.0.0-stage → 0.4.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.
Files changed (63) hide show
  1. package/CHANGELOG.md +592 -0
  2. package/LICENSE +21 -0
  3. package/README.md +1269 -2
  4. package/package.json +45 -4
  5. package/src/agent/agent.js +1194 -0
  6. package/src/agent/approvals.js +76 -0
  7. package/src/agent/context.js +106 -0
  8. package/src/agent/planner.js +237 -0
  9. package/src/agent/worklog.js +318 -0
  10. package/src/cli/app.js +471 -0
  11. package/src/cli/commands.js +1155 -0
  12. package/src/cli/input.js +287 -0
  13. package/src/cli/markdown.js +527 -0
  14. package/src/cli/prompts.js +255 -0
  15. package/src/cli/renderer.js +2155 -0
  16. package/src/cli/settings-editor.js +280 -0
  17. package/src/cli/settings-tui.js +669 -0
  18. package/src/cli/tui.js +1737 -0
  19. package/src/cli/width.js +48 -0
  20. package/src/config/load.js +137 -0
  21. package/src/config/scaffold.js +50 -0
  22. package/src/config/settings-registry.js +495 -0
  23. package/src/config/settings.js +304 -0
  24. package/src/config/validate.js +461 -0
  25. package/src/index.js +449 -0
  26. package/src/providers/catalog.js +407 -0
  27. package/src/providers/ids.js +24 -0
  28. package/src/providers/index.js +103 -0
  29. package/src/providers/nvidia.js +671 -0
  30. package/src/providers/registry.js +104 -0
  31. package/src/providers/river.js +198 -0
  32. package/src/providers/tokenharbor.js +38 -0
  33. package/src/providers/vendor-extras.js +82 -0
  34. package/src/services/clipboard.js +38 -0
  35. package/src/services/diff.js +153 -0
  36. package/src/services/doctor.js +126 -0
  37. package/src/services/logger.js +190 -0
  38. package/src/services/preferences.js +249 -0
  39. package/src/services/processes.js +345 -0
  40. package/src/services/provider-settings.js +226 -0
  41. package/src/services/sessions.js +279 -0
  42. package/src/services/undo.js +133 -0
  43. package/src/services/ushell.js +146 -0
  44. package/src/services/websearch/manager.js +616 -0
  45. package/src/services/websearch/mcp.js +233 -0
  46. package/src/services/websearch/normalize.js +284 -0
  47. package/src/services/websearch/providers.js +178 -0
  48. package/src/services/websearch/serper.js +263 -0
  49. package/src/services/workspace.js +589 -0
  50. package/src/tools/filesystem.js +304 -0
  51. package/src/tools/git.js +114 -0
  52. package/src/tools/index.js +48 -0
  53. package/src/tools/project.js +160 -0
  54. package/src/tools/registry.js +118 -0
  55. package/src/tools/search.js +210 -0
  56. package/src/tools/shell.js +279 -0
  57. package/src/tools/url.js +542 -0
  58. package/src/tools/web.js +67 -0
  59. package/src/utils/errors.js +160 -0
  60. package/src/utils/network.js +129 -0
  61. package/src/utils/redaction.js +73 -0
  62. package/src/utils/validation.js +370 -0
  63. package/src/utils/version.js +24 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,592 @@
1
+ # Changelog
2
+
3
+ Semua perubahan penting pada Ryuu Agent CLI didokumentasikan di sini.
4
+ Project ini mengikuti [Semantic Versioning](https://semver.org/).
5
+
6
+ ## [0.3.2] - 2026-10-30
7
+
8
+ ### Ditambahkan
9
+
10
+ - **River AI jadi provider bawaan, dan reasoning DeepSeek-nya akhirnya tampil.**
11
+ River mematikan thinking secara default untuk `DeepSeek-V4.1-Flash-1017` dan
12
+ `DeepSeek-V4.1-Flash`, sehingga respons hanya berisi `content` dan kotak
13
+ `◈ reasoning` tidak pernah muncul. Modul baru `src/providers/river.js`
14
+ mengirim `reasoning_effort` (default `high`) lewat tabel field request
15
+ `src/providers/vendor-extras.js` yang dibaca klien bersama sebelum setiap
16
+ request. Prioritas nilai: `RYUU_RIVER_REASONING_EFFORT` → `reasoningEffort` di
17
+ `config.json` → `RYUU_REASONING_EFFORT` → `capabilities.reasoningEffort`.
18
+ Level yang tidak didukung model diturunkan ke level aman model itu dan dicatat
19
+ di log, jadi request tidak pernah gagal karena field ini.
20
+ - **Modul klien per vendor.** `tokenharbor.js` menyusul `river.js` sebagai
21
+ pemilik default provider-nya; provider kustom tetap memakai template
22
+ `nvidia.js` tanpa perubahan kode, dan kini bisa membawa field request sendiri
23
+ lewat `extraBody`/`requestParams` di entri `extraProviders`.
24
+
25
+ ### Diubah
26
+
27
+ - Provider bawaan menjadi `nvidia`, `tokenharbor`, dan `river`, masing-masing
28
+ dengan daftar model default-nya sendiri (River: DeepSeek, GLM-5.3,
29
+ Qwen3.8-27B, Nemotron-3.5-Super-VL). `/model` dan `/provider` menampilkannya
30
+ tanpa entri `extraProviders`.
31
+ - Entri `extraProviders` lama yang mendeklarasikan ulang provider bawaan dengan
32
+ base URL yang sama (misalnya `river`) kini diabaikan dengan peringatan, bukan
33
+ menggagalkan startup. Id bawaan dengan URL berbeda tetap ditolak.
34
+ - `extraProviders` menerima `reasoningEffort`, `thinking`, `extraBody`, dan
35
+ `requestParams`; nilai-nilainya dibawa bersama pilihan provider sehingga
36
+ `/provider` tidak menghapusnya.
37
+
38
+ ## [0.3.1] - 2026-10-29
39
+
40
+ ### Ditambahkan
41
+
42
+ - **Kelola provider dan model langsung dari sesi.** `/provider user <name>`
43
+ berpindah provider, `/provider add <name> <url> [apiKey]` mendaftarkan provider
44
+ OpenAI-compatible baru, `/provider del <name>` menghapusnya, dan
45
+ `/addmodel <provider> <model-id>` / `/delmodel <provider> <model-id>` mengatur
46
+ daftar model per provider. Provider baru masuk `extraProviders` di
47
+ `config.json` dan kuncinya ke `providers.<id>.apiKey`; model pertama menjadi
48
+ default. Provider baru boleh dibuat tanpa model. Provider bawaan dan provider
49
+ yang sedang aktif tidak bisa dihapus. Kunci tetap tidak pernah dicetak.
50
+ - **`config.json` dibuat otomatis pada run pertama.** Bila file pengaturan belum
51
+ ada, `ensureSettingsFile` menulis scaffold-nya secara atomik dengan izin
52
+ `0600`: `version`, `provider`, `providers.<id>.apiKey`/`baseURL`,
53
+ `providerModel.<id>`, `extraProviders`, `agent.*`, dan `webSearch.*`, semuanya
54
+ bernilai kosong. Nilai kosong diperlakukan sebagai "pakai bawaan", jadi file
55
+ baru tidak mengubah perilaku; file yang sudah ada atau JSON yang rusak tidak
56
+ pernah ditimpa. `--settings` memakai scaffold yang sama saat membuat file.
57
+
58
+ ### Dihapus
59
+
60
+ - **File `.env` dan seluruh variabel environment tidak lagi dibaca.** Satu-satunya
61
+ sumber konfigurasi kini `config.json` (`ryuu --settings`): kredensial
62
+ (`providers.<id>.apiKey`), base URL (`providers.<id>.baseURL`), model
63
+ (`providerModel.<id>`), batas agent (`agent.*`), pencarian web (`webSearch.*`),
64
+ dan provider tambahan (`extraProviders`). `.env.example` ikut dihapus dari repo
65
+ dan dari daftar file paket. Presedensi: flag CLI > `.ryuu/preferences.json`
66
+ workspace > `config.json` > bawaan katalog; hanya `RYUU_CONFIG_DIR` yang masih
67
+ dibaca untuk menentukan letak `config.json`. Pesan galat, petunjuk pemulihan,
68
+ dan `/web providers` sekarang menyebut path kunci di `config.json`, bukan nama
69
+ variabel yang tidak lagi berpengaruh.
70
+
71
+ ### Diubah
72
+
73
+ - **Model bawaan provider `nvidia` kini `minimaxai/minimax-m3.1-flash`.** Model
74
+ itu masuk katalog sebagai entri ke-6, jadi `/model 6` memilihnya dan startup
75
+ tanpa `--model` memakainya. Lima model sebelumnya
76
+ (`nvidia/nemotron-3.5-super-vl-120b-a12b`, `z-ai/glm-5.3-flash`,
77
+ `google/diffusiongemma-26b-a4b-it`, `poolside/laguna-xs-2.1`,
78
+ `stepfun-ai/step-5-preview`) tetap ada dan nomornya tidak bergeser.
79
+
80
+ ## [0.3.0] - 2026-10-29
81
+
82
+ ### Ditambahkan
83
+
84
+ - **Pengaturan global `ryuu --settings` dan `ryuu --settings --tui`.** Nilai
85
+ pengguna kini tinggal di satu file milik pengguna — Linux/BSD
86
+ `$XDG_CONFIG_HOME/ryuu/config.json` (bawaan `~/.config/ryuu/config.json`),
87
+ macOS `~/Library/Application Support/ryuu/config.json`, Windows
88
+ `%APPDATA%\ryuu\config.json` — dan bisa dialihkan dengan `RYUU_CONFIG_DIR`,
89
+ sehingga terbaca dari direktori kerja mana pun. `--settings` membuka editor
90
+ baris bernomor (`<nomor> <nilai>`, `/list`, `/show`, `/reset`, `/help`,
91
+ `/exit`); `--settings --tui` membuka layar penuh dengan panel deskripsi,
92
+ navigasi panah, pengubahan pilihan provider/model, serta simpan/batal; dan
93
+ `--settings --list` mencetak daftar tanpa masuk mode edit. Setiap perubahan
94
+ tervalidasi lalu langsung disimpan secara atomik (fsync + rename) dengan izin
95
+ `0600`; satu kunci tidak pernah menghapus kunci lain, API key selalu
96
+ disamarkan, dan JSON yang rusak dilaporkan tanpa pernah ditimpa. Presedensi:
97
+ flag CLI > environment/`.env` > `.ryuu/preferences.json` workspace > file
98
+ pengaturan global > bawaan katalog. Kredensial provider, base URL, model,
99
+ batas agent, dan kunci web search semuanya bisa diatur dari sini; provider
100
+ tambahan dari `RYUU_PROVIDERS` otomatis mendapat barisnya sendiri. Mode
101
+ pengaturan tidak pernah membangun agent, tool, atau permintaan model.
102
+ - **Tombol `⧉ copy` pada blok kode.** Code fence di jawaban kini membawa chip
103
+ `⧉ copy` di header-nya, dan seluruh blok menjadi area klik: mengekliknya
104
+ menyalin isi kode (tanpa penanda fence) ke clipboard terminal lewat OSC 52,
105
+ sama seperti blok prompt. Berlaku di kedua antarmuka — `--tui` lewat peta klik
106
+ per-baris, antarmuka baris lewat `Renderer.copies` — dengan teks yang disalin
107
+ dibatasi 100k karakter seperti payload OSC 52.
108
+
109
+ ### Diubah
110
+
111
+ - **Prompt internal dirapikan dan dioptimalkan untuk waktu.** `buildSystemPrompt`
112
+ kini menaruh aturan efisiensi dan pemulihan di bagian tersendiri: jangan
113
+ menganalisis ulang fakta dari worklog/tool result, berpikir sekali lalu
114
+ bertindak, dan — terutama — **heartbeat** (reconnect, giliran kosong,
115
+ argumen yang diperbaiki/dipotong) diperlakukan sebagai transport, bukan reset
116
+ tugas: lanjutkan aksi yang terputus tanpa mengulang read/search/command yang
117
+ sudah berhasil. Nudge giliran kosong dan peringatan anggaran 70% ikut
118
+ menegaskan hal yang sama.
119
+ - **Notifikasi heartbeat kini biru langit tebal.** Pesan heartbeat pada UI baris
120
+ dan `--tui` (reconnect, giliran kosong, argumen diperbaiki, tautan pulih)
121
+ dicetak dengan warna biru langit (`#38bdf8`) dan tebal, menggantikan kuning/
122
+ hijau, agar terbaca sebagai kabar transport, bukan galat.
123
+
124
+ ## [0.2.1] - 2026-10-25
125
+
126
+ ### Ditambahkan
127
+
128
+ - **Dukungan multi-provider AI dengan registry dinamis.** Provider dan model kini
129
+ dideklarasikan di `src/providers/catalog.js` (`nvidia` dan `tokenharbor` bawaan,
130
+ plus entri `RYUU_PROVIDERS` dari `.env`), sehingga agent core tidak menyebut
131
+ provider mana pun. `ProviderRegistry` (`src/providers/registry.js`) membuat
132
+ instance per provider dari satu factory, dan `src/providers/index.js` meresolusi
133
+ pilihan, memvalidasi id/kunci/model, serta menyediakan `updateSelection()` untuk
134
+ berpindah provider tanpa membangun ulang agent.
135
+ - **Provider Token Harbor** (`tokenharbor`) dengan model bawaan
136
+ `deepseek-v4.1-flash:free` (DeepSeek V4.1 Flash Free), base URL
137
+ `https://tokenharbor.ai/v1`, kunci `TOKENHARBOR_API_KEY`, dan override
138
+ `TOKENHARBOR_BASE_URL` / `TOKENHARBOR_MODEL`. Protokolnya Chat Completions yang
139
+ kompatibel OpenAI, jadi klien SDK yang sama dipakai ulang; streaming, tool
140
+ calling, reasoning yang dikirim provider, serta pemetaan galat HTTP tetap sama.
141
+ - **Pemilihan provider dan model.** Flag `--provider <id>`, variabel
142
+ `RYUU_PROVIDER`/`RYUU_MODEL`, dan slash command `/provider [id]` (daftar status
143
+ kunci tanpa membocorkan nilainya). `/model`, `/addmodel`, dan `/delmodel` kini
144
+ bekerja per provider dan disimpan per provider di `.ryuu/preferences.json`;
145
+ berpindah provider mempertahankan riwayat percakapan dan worklog.
146
+ - **Kapabilitas per provider** (`streaming`, `tools`, `reasoning`, `multimodal`)
147
+ menggantikan asumsi bahwa semua endpoint identik. Agent hanya mengirim tools
148
+ atau meminta stream bila provider mengumumkannya, dan menampilkan keterbatasan
149
+ yang diumumkan di banner. Tidak ada fallback otomatis ke provider AI lain.
150
+ - **Validasi sebelum request**: provider harus dikenal, kuncinya harus ada (tidak
151
+ pernah memakai kunci kosong/hardcoded), dan id model harus valid. Model yang
152
+ tidak ada di daftar tetap diizinkan dengan peringatan, karena daftar itu adalah
153
+ id yang ditawarkan CLI, bukan jaminan ketersediaan di server.
154
+ - Uji offline untuk katalog, pemilihan provider/model, request Token Harbor
155
+ (base URL, model, header otorisasi, streaming, tool call), kunci yang hilang,
156
+ galat HTTP/timeout, preferensi per provider, dan redaksi kunci.
157
+
158
+ ### Diubah
159
+
160
+ - Pesan galat provider tidak lagi menyebut NVIDIA secara hard-coded: nama provider
161
+ dan variabel kunci yang benar dipakai, sehingga `401`/`403`/`404`/`429`/`5xx`
162
+ untuk Token Harbor menunjuk `TOKENHARBOR_API_KEY` dan model yang dipilih.
163
+ - `.env.example` dan README mendokumentasikan Token Harbor, `RYUU_PROVIDER`,
164
+ `RYUU_MODEL`, `RYUU_PROVIDERS`, kapabilitas per provider, dan batasan kuota
165
+ (tidak ada klaim gratis tanpa batas).
166
+
167
+ ## [0.2.0] - 2026-10-25
168
+
169
+ ### Ditambahkan
170
+
171
+ - **Pembaruan visual menyeluruh UI layar penuh.** Setiap blok kini dibuka dengan
172
+ header kecil (`▸ TASK`, `◆ response`, `⚙ Using tools`, `◈ reasoning`, `◆ PLAN`)
173
+ dan blok dipisahkan baris kosong plus **garis gradien pink → violet → biru
174
+ langit**. Tool call berurutan berbagi satu blok, satu header
175
+ `⚙ Using tools · N calls` dan tanpa pembatas di antaranya. Setiap jenis baris
176
+ punya warnanya sendiri alih-alih satu abu-abu redup: prosa assistant berwarna
177
+ putih, Markdown (heading, penanda daftar, inline code, link, code fence) dan
178
+ tabel berwarna biru langit, nama tool kuning, teks reasoning hijau dengan baris
179
+ status putih, tool yang gagal berupa nama merah tebal di atas output merah
180
+ redup, header command dan baris `$` berwarna biru langit, serta galat runtime
181
+ berwarna merah. Layar pembuka adalah frame yang sama dengan antarmuka baris —
182
+ wordmark ASCII berbingkai, tagline, dan blok telemetri (model, workspace,
183
+ runtime, access, log) dengan versinya — dan composer adalah `ryuu > ` dengan
184
+ `ryuu` pada gradien pink → blue, teks input kelabu, baris pertanyaan di atasnya,
185
+ serta word wrap lunak, sehingga tugas panjang tidak pernah terpotong. Status bar
186
+ mewarnai setiap segmen secara terpisah (fase, langkah, tool, token, gulir).
187
+ Setiap baris membungkus sesuai lebar terminal, termasuk telemetri banner, output
188
+ command, diff, dan pemberitahuan; palet naik ke truecolor ketika terminal
189
+ melaporkannya.
190
+
191
+ - **Menyalin prompt yang sudah Anda kirim.** Melipat jawaban 200 baris itu mudah,
192
+ tetapi menyalin tugas yang menghasilkannya tidak: memilih output berwarna dan
193
+ berbungkus dengan mouse rawan galat. Setiap blok prompt kini membawa chip
194
+ `⧉ copy` (mengklik bloknya menyalinnya), `Ctrl+Y` menyalin prompt terakhir dan
195
+ `/copy [n]` menyalin yang lebih lama di kedua antarmuka. Teksnya masuk ke
196
+ clipboard terminal dengan **OSC 52** (`src/services/clipboard.js`): tanpa proses
197
+ anak `pbcopy`/`xclip`/`clip.exe`, bekerja lewat SSH, dibatasi 100k karakter, dan
198
+ status bar melaporkan jumlahnya (`⧉ copied prompt #4 · 42 chars`). Terminal yang
199
+ mengabaikan OSC 52 membiarkan clipboard tidak tersentuh; sesi tidak pernah rusak.
200
+ Antarmuka baris menyimpan 25 prompt terakhir agar `/copy` juga bekerja di sana.
201
+
202
+ - **Satu versi, dibaca dari `package.json`.** `src/utils/version.js` kini menjadi
203
+ satu-satunya sumber string versi: banner, `--version`, header TUI, dan handshake
204
+ klien MCP semuanya meresolusinya saat runtime, sehingga sebuah rilis hanya
205
+ menyunting `package.json`. Literal bawaan `0.1.0` di `createApp` dan `Tui` sudah
206
+ dihapus.
207
+
208
+ - **UI layar penuh opsional (`--tui`).** Antarmuka bertipe retained-mode yang
209
+ menyimpan percakapan sebagai data (id stabil, tanda terbuka/tertutup per blok,
210
+ teks lengkap) dan menggambar ulang sebuah frame darinya, alih-alih menambahkan
211
+ baris ke scrollback dan melupakannya. Setiap reasoning, output `run_command`, dan
212
+ jawaban (dan kini blok shell) bisa dibuka secara independen, beberapa sekaligus,
213
+ dan blok lama tetap bisa dibuka sepanjang sesi; transkrip menggul di dalam
214
+ aplikasi (`PgUp`/`PgDn`, roda, klik untuk melipat) dan composer digambar dalam
215
+ frame yang sama. Tanpa `--tui` antarmuka sebelumnya dipakai tanpa perubahan;
216
+ flag diabaikan dengan peringatan ketika tidak ada TTY atau saat `--plain`. File
217
+ baru `src/cli/tui.js`.
218
+
219
+ - **`/bash <command>` dan `!command`.** Menjalankan sendiri command shell, di
220
+ workspace, tanpa melibatkan model: tanpa prompt persetujuan (Anda yang
221
+ mengetiknya), tetapi `--read-only` tetap menolaknya. Output dicetak lengkap
222
+ alih-alih pratinjau 5 baris, tangkapannya dibatasi (ekor disimpan, ditandai
223
+ terpotong), dan command, exit code, durasi, serta output dicatat sebagai giliran
224
+ pengguna dalam percakapan sesi dan worklog, sehingga model tugas berikutnya
225
+ sudah tahu apa yang dijalankan. `Ctrl+C` membatalkannya dengan menyinyalkan
226
+ seluruh grup proses, sehingga anak-anak dari pembungkus `sh -c` tidak selamat.
227
+ Variabel environment yang tampak seperti kredensial dibuang dari proses anak
228
+ (`sanitizedEnv`). `src/services/ushell.js` dan `Agent.recordUserShell()` baru.
229
+ - **Pencarian web multi-provider MCP dengan fallback otomatis.** `web_search` kini
230
+ adalah satu tool yang didukung `WebSearchManager`, yang terhubung secara malas ke
231
+ You.com (profil gratis tanpa kunci), Firecrawl (tingkat tanpa kunci), server stdio
232
+ DuckDuckGo lokal opsional, Tavily (butuh kunci API), dan backend REST Serper yang
233
+ sudah ada. Provider dicoba menurut urutan yang bisa dikonfigurasi; timeout,
234
+ galat DNS/jaringan, HTTP 401/403/429/5xx, kegagalan handshake/penemuan, tool yang
235
+ hilang, ketidaksesuaian skema, dan payload tidak valid semuanya pindah ke provider
236
+ berikutnya. Retry dibatasi (hanya kegagalan pemanggilan sesaat, backoff
237
+ eksponensial dengan jitter), `429` langsung diteruskan, dan dua kegagalan
238
+ berturut-turut membuka circuit breaker 60 detik. Penemuan tool memetakan tool
239
+ ke pencarian/ekstraksi menurut nama, deskripsi, dan skema input, dan semua hasil
240
+ dinormalkan (URL hanya http(s), dedupe menurut URL kanonik, judul/snippet/teks
241
+ terbatas, atribusi provider). Jika semua provider gagal, agent menerima satu galat
242
+ bertipe dan melanjutkan tanpa mengarang hasil. Terminal mencetak satu pohon
243
+ ringkas dengan status dan durasi tiap provider; kunci dan header tidak pernah
244
+ dicatat. `read_url` kini jatuh kembali ke provider MCP berkemampuan ekstraksi
245
+ saat pengambilan lokal gagal atau tidak mengekstrak teks. Konfigurasinya memakai
246
+ `WEB_SEARCH_ENABLED`, `WEB_SEARCH_FALLBACK`, `WEB_SEARCH_PROVIDERS`,
247
+ `WEB_SEARCH_DISABLED`, `WEB_MCP_TIMEOUT_MS`, `WEB_MCP_MAX_RETRIES`, `YDC_API_KEY`,
248
+ `FIRECRAWL_API_KEY`, `TAVILY_API_KEY`, dan `DUCKDUCKGO_MCP_ENABLED`; periksa
249
+ dengan `/web status|providers|test|enable|disable`. Pencarian You.com, pencarian
250
+ Firecrawl, dan ekstraksi Firecrawl sudah diverifikasi terhadap server MCP live;
251
+ Tavily tidak bisa diverifikasi tanpa kunci, dan server stdio DuckDuckGo opsional
252
+ tidak dijalankan karena `uvx` tidak terpasang.
253
+
254
+ - **Tool `read_url`.** Mengambil satu URL http(s) publik dan mengembalikan teks
255
+ hasil ekstraksi, judul, serta meta deskripsinya, sehingga model bisa
256
+ memverifikasi snippet pencarian terhadap halaman sumbernya alih-alih
257
+ memercayainya. Ia selalu terdaftar (tanpa kunci), read-only, dan bebas
258
+ persetujuan, mengikuti maksimal 5 redirect sambil memeriksa ulang setiap hop
259
+ (https→http ditolak), menolak URL dengan kredensial tertanam, hanya membaca jenis
260
+ konten tekstual, membatasi badan hingga 2 MB dan teks hingga 1.000–50.000
261
+ karakter (bawaan 20.000), serta memetakan kegagalan ke `READ_URL_INVALID`,
262
+ `READ_URL_REDIRECT`, `READ_URL_AUTH`, `READ_URL_NOT_FOUND`,
263
+ `READ_URL_RATE_LIMIT`, `READ_URL_UPSTREAM`, `READ_URL_TIMEOUT`,
264
+ `READ_URL_NETWORK`, `READ_URL_UNSUPPORTED`, dan `READ_URL_FAILED`. Alamat lokal,
265
+ privat, link-local, CGNAT, dan metadata cloud ditolak dengan `READ_URL_BLOCKED`
266
+ (nama, literal IP, dan pemeriksaan DNS pra-fetch, diperiksa ulang pada setiap
267
+ redirect); DNS rebinding dikendalikan tetapi tidak dihilangkan sepenuhnya.
268
+ Halaman yang dirender JavaScript mengembalikan tanpa teks alih-alih gagal. System
269
+ prompt memperlakukan teks halaman yang diambil sebagai data tak terpercaya dan
270
+ mencatat setiap pengambilan ke worklog. `web_search` kini menunjuk ke tool ini
271
+ saat sebuah snippet perlu dikonfirmasi.
272
+
273
+ - **Tool `web_search`.** Hasil Google dari SERP API Serper-kompatibel, dimodelkan
274
+ dari pencarian web Freebuff: `title`/`url`/`snippet` plus kotak jawaban, "people
275
+ also ask", dan pencarian terkait, dengan `depth: \"standard\" | \"deep\"`. Ia
276
+ opt-in (`SEARCH_API_KEY`), tidak pernah terdaftar tanpa kunci, men-cache kueri
277
+ identik per sesi, mencatat setiap pencarian ke worklog, dan memetakan kegagalan
278
+ ke `SEARCH_AUTH`, `SEARCH_RATE_LIMIT`, `SEARCH_UPSTREAM`, `SEARCH_TIMEOUT`,
279
+ `SEARCH_NETWORK`, `SEARCH_BAD_RESPONSE` alih-alih mengembalikan hasil kosong.
280
+ System prompt kini mewajibkan mengutip URL sumber dan menandai apa pun yang tidak
281
+ dibuktikan snippet sebagai belum terverifikasi.
282
+
283
+ - **Session worklog.** Fakta terverifikasi — file yang dibaca beserta rentang
284
+ barisnya, file yang diubah, command dengan exit code, temuan, rencana, dan tugas
285
+ lebih awal — disimpan sepanjang sesi dan diteruskan ke tugas berikutnya dalam satu
286
+ pesan `TASK BRIEF`. Tindak lanjut (`lanjutkan`, `continue`, `sudah?`) kini
287
+ melanjutkan pekerjaan alih-alih memulai ulang analisis. Periksa dengan
288
+ `/worklog`; ia disimpan bersama sesi dan dipulihkan oleh `/resume`.
289
+ - **Pembacaan berulang diblokir.** `read_file` pada path yang sudah ada di
290
+ worklog dan punya mtime sama mengembalikan balasan `cached: true` (ditampilkan
291
+ sebagai `↺` di feed aktivitas) alih-alih membaca dan menganalisis ulang file.
292
+ Membaca file yang berubah, rentang berbeda, atau memverifikasi file yang baru
293
+ disunting agent tetap bekerja.
294
+ - **Baris aktivitas kaya telemetri dan detail per-pemanggilan.** Baris live kini
295
+ menampilkan fase, waktu fase, total waktu run, langkah, tool yang sedang berjalan
296
+ beserta posisi antriannya (`writing edit_file src/x.js (2/5)`), token
297
+ prompt/completion live, dan latensi token pertama. Setiap pemanggilan model
298
+ mencetak `◇ model 9.4s · 21.3k↑ 388↓ tok · first token 1.8s`, dan respons yang
299
+ terpotong menyatakannya.
300
+ - **Output command live.** stdout/stderr dari command yang berjalan mengalir ke
301
+ wilayah live (ekor terbatas) alih-alih hanya muncul setelah proses keluar.
302
+ - **Diff perubahan file di UI.** Setiap create/write/edit mencetak baris `-`/`+`
303
+ yang benar-benar berubah (`• Edit src/agent/agent.js (+12 −3)`), dibatasi 24
304
+ baris, sehingga pengguna bisa mengaudit perubahan dan membatalkan + menugaskan
305
+ ulang bila salah.
306
+ - **Watchdog aliran mandek** (`AGENT_STREAM_IDLE_TIMEOUT_MS`, bawaan 45s): aliran
307
+ respons yang berhenti mengirim byte dibatalkan dan dilaporkan sebagai
308
+ `STREAM_STALLED` alih-alih menahan satu langkah terbuka tanpa batas. Permintaan
309
+ juga tidak lagi bisa hidup melampaui tenggat tugas.
310
+ - Command `/worklog`; `/status`, `/history`, dan `/sessions show` kini melaporkan
311
+ durasi, jumlah pemanggilan model, dan bacaan yang dipakai ulang.
312
+
313
+ - Flag CLI `--auto-approve`: melewati prompt persetujuan untuk setiap aksi tool
314
+ (command, penulisan, penghapusan) agar agent bisa bekerja tanpa pengawasan.
315
+ Bisa dikombinasikan dengan `-y` (yang hanya menyetujui penulisan);
316
+ `--auto-approve` mencakup semuanya. Sintaks shell mentah tetap butuh
317
+ `AGENT_ALLOW_SHELL=true`.
318
+ - Binary global `ryuu` (lewat `npm link`); nama `ryuu` sebelumnya tetap menjadi
319
+ alias. Dijalankan dari folder mana pun, folder itu tetap menjadi workspace dan
320
+ jatuh kembali ke `.env` CLI terpasang untuk `NVIDIA_API_KEY` ketika folder saat
321
+ ini tidak punya.
322
+ - HUD terminal futuristik: banner gradien `RYUU // AGENT OS`, panel telemetri,
323
+ feed aktivitas berbasis rail, panel reasoning live, kartu gerbang persetujuan,
324
+ dan dasbor ringkasan run.
325
+ - Pesan assistant sadar-Markdown: heading, bold/italic, inline code, link, daftar,
326
+ kutipan, blok kode bersal dengan penyorotan ringan, dan tabel sadar-lebar yang
327
+ mengecil, membungkus, atau jatuh ke tata letak vertikal ketika terminal terlalu
328
+ sempit. Markdown dirender di HUD maupun mode plain.
329
+ - Memori percakapan lintas tugas: permintaan dan jawaban setiap tugas yang selesai
330
+ disimpan dan dikirim sebagai konteks untuk tugas berikutnya dalam sesi yang sama,
331
+ sehingga agent mengingat apa yang diminta sebelumnya. Periksa dengan `/memory`,
332
+ pulihkan memori sesi tersimpan dengan `/resume <session-id>`, lupakan dengan
333
+ `/clear`. Giliran disunting, disimpan sebagai teks user/assistant saja (tidak
334
+ pernah pesan tool mentah) dan dibatasi `AGENT_MAX_CONTEXT_CHARS`.
335
+ - Jawaban akhir dialirkan langsung sebagai teks biasa sementara provider masih
336
+ menulisnya, alih-alih hanya muncul setelah langkah selesai. Kotak khusus untuk
337
+ aliran reasoning; jawaban yang dialirkan tidak pernah dibungkus kotak maupun
338
+ dicetak dua kali (ringkasan tidak merendernya ulang).
339
+ - CLI membersihkan terminal saat start (`console.clear()` di awal `main`), sehingga
340
+ banner selalu dimulai pada layar bersih. Ini tidak berpengaruh ketika stdout
341
+ bukan TTY (pipe, CI, tes).
342
+ - Katalog model bernomor untuk `/model`: `z-ai/glm-5.3-flash`,
343
+ `nvidia/nemotron-3.5-super-vl-120b-a12b`, `google/diffusiongemma-26b-a4b-it`,
344
+ `poolside/laguna-xs-2.1`, dan `stepfun-ai/step-5-preview` bergabung dengan model
345
+ DeepSeek bawaan, sehingga berpindah tidak perlu mengetik ulang id
346
+ `provider/model` yang panjang.
347
+ ### Diperbaiki
348
+
349
+ - **Jawaban yang dialirkan tidak lagi tumbuh melewati blok-blok yang mengikutinya.**
350
+ TUI menambahkan setiap `contentDelta` sebuah tugas ke blok jawaban terbuka
351
+ pertama, sehingga teks dari langkah berikutnya terus memperpanjang blok awal itu —
352
+ jawaban tampak menggul ke belakang dan terkubur di bawah blok reasoning dan tool.
353
+ Delta kini memulai blok baru setiap kali blok lain ditambahkan setelah blok yang
354
+ terbuka, dan `streamedResponse()` mengingat bahwa teks benar-benar dialirkan,
355
+ sehingga ringkasan akhir tidak digandakan. Dicakup oleh sebuah tes yang
356
+ mengalirkan teks, menjalankan tool, mengalirkan lagi, dan menegaskan urutan blok
357
+ serta barisnya.
358
+
359
+ - **`/exit` kini benar-benar keluar.** Menutup UI melepas listener-nya tetapi
360
+ meninggalkan stdin dalam mode flowing, sehingga event loop tetap hidup setelah
361
+ layar dibersihkan: proses tampak menggantung pada layar kosong sampai `Ctrl+C`
362
+ kedua. `ComposerInput.dispose()`, `PromptSession.close()`, `Tui.close()`, dan
363
+ kembalian interaktif di `main()` kini menjeda stdin, dan pemeriksaan PTY
364
+ end-to-end (stdin dibiarkan terbuka) menunjukkan proses kembali ke shell segera
365
+ setelah `/exit` di kedua antarmuka.
366
+
367
+ - **Payload tool-call yang rusak tidak lagi membunuh run.** Provider memvalidasi
368
+ setiap string `function.arguments` di percakapan pada *setiap* permintaan, jadi
369
+ dulu satu payload terpotong menggagalkan permintaan *berikutnya* dengan
370
+ `messages[n].tool_calls[i].function.arguments must be a valid JSON object string`
371
+ dan membatalkan seluruh tugas. Payload terpotong kini diperbaiki (string/array/
372
+ objek terbuka ditutup), pemanggilan yang diperbaiki dieksekusi, dan payload yang
373
+ tidak bisa diperbaiki diganti dengan `{}` dalam sejarah tersimpan sementara model
374
+ diberi tahu untuk mengirimnya ulang. Provider menyederhanakan permintaan sekali
375
+ lagi, sehingga payload rusak tidak lagi bisa sampai ke API.
376
+ - Tool call dengan argumen yang rusak bukan lagi jalan buntu: agent melaporkan galat
377
+ parse persisnya kembali ke model, tetap bekerja, dan melanjutkan tugas alih-alih
378
+ menggagalkan run.
379
+ - Pemanggilan gagal yang identik diblokir setelah dua kali (command yang keluar
380
+ dengan `1` juga dihitung), sehingga agent berhenti membakar langkah pada galat
381
+ yang sama dan diberi tahu untuk mengganti tool, argumen, atau melaporkan
382
+ temuannya.
383
+ - Penolakan provider yang hanya disebabkan oleh payload tool yang teracuni
384
+ (`INVALID_TOOL_ARGUMENTS`) kini dikenali sebagai bisa dipulihkan alih-alih
385
+ dilaporkan sebagai `BAD_REQUEST` yang tidak bisa dipulihkan.
386
+
387
+ ### Diubah
388
+
389
+ - **Sambung ulang dan giliran model kosong tidak lagi mengakhiri tugas.**
390
+ `AGENT_MAX_RECOVERY_ATTEMPTS` kini berbawaan `0`, yang berarti *tanpa batas*:
391
+ tautan provider yang putus terus menampilkan heartbeat dan mencoba ulang dengan
392
+ backoff eksponensial (maksimal 30s) sampai provider menjawab, tenggat tugas lewat,
393
+ atau pengguna membatalkan. Nilai positif (1–1000) tetap memaksakan batas keras.
394
+ Giliran model kosong juga diperlakukan sebagai percobaan ulang, bukan galat: agent
395
+ mendorong model, melakukan beat `empty response · attempt N (unlimited)`, menunggu
396
+ dengan backoff berbasis `AGENT_RECOVERY_BACKOFF_MS` (maksimal 15s), dan bertanya
397
+ ulang di bawah nomor langkah yang sama, sehingga percobaan ulang tidak
398
+ mengonsumsi anggaran `AGENT_MAX_STEPS` maupun memunculkan galat runtime
399
+ `EMPTY_RESPONSE`. Diverifikasi oleh uji unit yang menjalankan pemulihan melewati
400
+ batas lima-percobaan lama dan empat giliran kosong berturut-turut.
401
+ - **System prompt dirakit sekali per sesi dan dipakai ulang byte-per-byte.** Ia kini
402
+ menjadi kontrak menetap (aturan pengoperasian, katalog tool, fakta project)
403
+ alih-alih instruksi per-tugas, sehingga identik pada setiap langkah, tidak pernah
404
+ tumbuh, dan ramah cache. Setiap tugas hanya menambah badan lewat `TASK BRIEF`.
405
+ - **Prompt mengoptimalkan untuk waktu.** Ia menyatakan aturan lanjutan, meminta
406
+ maksimal enam pemanggilan tool independen dalam satu respons, melarang membaca
407
+ ulang file worklog, mewajibkan satu verifikasi sempit alih-alih loop eksploratif,
408
+ dan memberi tahu model untuk menyatu pada 70% anggaran.
409
+ - `finish_reason: \"length\"` kini ditangani: pemanggilan tool yang terpotong dibuang
410
+ dan dilaporkan ke model (`TRUNCATED_RESPONSE`), tidak pernah dieksekusi. Ini
411
+ menghilangkan mode gagal ketika payload terpotong yang sudah diperbaiki menulis
412
+ setengah file ke disk.
413
+ - Sesi menyimpan `durationMs`, `modelCalls`, `requestMs`, `firstTokenMs`,
414
+ `cachedReads`, dan worklog terbatas, sehingga riwayat run bisa diaudit setelahnya.
415
+ - Satu baris aktivitas yang selalu menyala kini berada di bagian bawah UI percakapan,
416
+ dianimasikan 10 fps dengan spinner dan jam berjalan, berpindah fase bersama run:
417
+ `thinking` saat model bekerja di latar, `reasoning` saat aliran reasoning-nya
418
+ ditampilkan, dan `working` sebagai cadangan (merakit tool call, menjalankan
419
+ command, persetujuan, mengalirkan jawaban). Ia dibersihkan saat run berakhir,
420
+ tidak pernah meninggalkan frame liar, dan hanya barisnya sendiri yang dicetak ulang
421
+ per tick, sehingga model lambat tidak pernah terlihat membeku dan terminal tidak
422
+ dibanjiri.
423
+ - Tugas dikirim dengan satu Enter. Kontrak sebelumnya menunggu Enter kedua yang
424
+ kosong, yang membuat CLI duduk di prompt `>` telanjang tanpa uplink tugas dan
425
+ tanpa baris aktivitas, tampak mati. Tugas multi-baris tetap tersedia dengan
426
+ mengakhiri baris menggunakan `\\`; prompt kelanjutan adalah `↳` dan menampilkan
427
+ petunjuk.
428
+ - Kotak reasoning dan baris aktivitas kini berbagi satu wilayah live yang ditambatkan
429
+ pada baris pertamanya, sehingga output yang diselang-seling (rencana, peringatan,
430
+ hasil tool, jawaban yang dialirkan) selalu membersihkan dan menggambar ulang di
431
+ tempat. Header kotak tidak lagi menampilkan waktu berjalan yang hanya disegarkan
432
+ saat reasoning baru tiba.
433
+ - Banner kini memakai wordmark blok `RYUU` enam baris yang jelas alih-alih glif
434
+ ringkas, dipusatkan di atas tagline dan panel telemetri.
435
+ - Loop agent tidak lagi berhenti pada jumlah langkah tetap. `AGENT_MAX_STEPS` kini
436
+ berbawaan `0` (tanpa batas) dan hanya berperan sebagai batas opsional;
437
+ `--max-steps 0` melakukan hal yang sama. `AGENT_MAX_TASK_DURATION_MS` dan `Ctrl+C`
438
+ tetap menjadi penjaga tugas yang lari sendiri.
439
+ - Renderer menampilkan `step n` dan `unlimited steps` ketika tidak ada batas yang
440
+ dikonfigurasi.
441
+ - Panel reasoning live kini menjadi kotak tertutup yang lebarnya sesuai: header,
442
+ lima baris pratinjau (sebelumnya dua), dan batas bawah. Ia tetap berada di layar
443
+ saat reasoning berakhir — ringkasan `reasoning n chars` ditambahkan di bawahnya
444
+ alih-alih menghapus pratinjaunya, dan path log reasoning tidak lagi dicetak.
445
+ - Tampilan penuh `Tab` kini menjadi viewport berbatas dengan gaya header tertutup
446
+ simetris yang sama dengan pratinjau (`last n/m · Tab: preview`), direbut kembali
447
+ di tempat, sehingga berpindah kembali ke pratinjau tidak lagi meninggalkan teks
448
+ liar.
449
+ - `/model` bekerja menurut nomor: ia mendaftarkan katalog dengan model terpilih
450
+ ditandai, dan `/model <n>` berpindah. Argumen `provider/model` mentah ditolak
451
+ dengan penunjuk ke daftar. Pilihan disimpan ke `.ryuu/preferences.json` dan tetap
452
+ ada setelah CLI restart (`--model` eksplisit tetap menang untuk satu run).
453
+ - Penggambaran ulang kotak reasoning tidak lagi bergeser satu kolom ke kanan:
454
+ penghapusan di tempat kini mereset kursor dengan carriage return sebelum dan
455
+ sesudah melangkah, sehingga header tetap simetris dengan batas bawah pada setiap
456
+ penggambaran ulang.
457
+ - Jawaban yang dialirkan kini merender Markdown inline saat tiba (bold, italic,
458
+ code, link), sehingga penanda `**bold**` tidak lagi bocor ke terminal. Baris
459
+ panjang membungkus pada batas kata sehingga token Markdown tidak pernah terpotong
460
+ setengah, dan baris parsial yang dibuffer selalu dikosongkan sebelum output lain —
461
+ sebuah PLAN atau baris tool tidak lagi bisa membelah jawaban di tengah kalimat.
462
+ - Token kontrol chat-template model yang bocor (`<|channel>`, `<channel|>`,
463
+ `<start_of_turn>`, `</tool_call>`, `<|repo_name|>`, …) dibuang dari jawaban yang
464
+ dialirkan, teks reasoning, rencana, catatan, dan respons akhir.
465
+ - Jawaban yang dialirkan merender lebih banyak Markdown secara langsung: header ATX
466
+ (`### title`) kehilangan tanda pagarnya dan dirender tebal, tabel pipe dan blok
467
+ kode bersal dit buffer dan dirender sebagai blok begitu selesai dialirkan
468
+ (tidak pernah sebagai baris `|` mentah atau pagar ```), dan pembungkusan baris
469
+ panjang kini menjaga rentang `**bold**`/`code` tetap seimbang sehingga penanda
470
+ tidak lagi bisa bocor sebagai asterisk nyasar.
471
+ - Rencana kini memimpin langkah: ia diekstrak hanya dari respons pertengahan tugas
472
+ (yang dilanjutkan dengan tool call) dan dikeluarkan sebelum ringkasan reasoning.
473
+ Jawaban akhir dengan daftar penjelasan bernomor tidak lagi dikira sebagai rencana.
474
+ - Baris tabel yang dialirkan tidak lagi terfragmentasi: deteksi blok kini berjalan
475
+ pada baris logis (dibatasi newline), sehingga baris tabel pipe yang lebih lebar
476
+ dari layar tidak pernah dibungkus di tengah sel — ia dibuffer utuh dan dirender
477
+ oleh perender tabel sadar-lebar ketika tabel berakhir. Garis horizontal (`---`)
478
+ dirender sebagai pembatas redup dan kutipan blok (`>`) kehilangan penandanya dan
479
+ dirender sebagai kutipan, alih-alih bocor mentah.
480
+ - Pengerasan system prompt dari bukti lapangan: periksa `file_info` sebelum membaca
481
+ file yang mungkin besar, jangan pernah mencoba ulang bacaan "too large" (pakai
482
+ `search_files` atau rentang baris sempit), dan jaga sel tabel Markdown tetap
483
+ pendek untuk output terminal.
484
+ - System prompt kini membawa katalog tool langsung (setiap tool terdaftar beserta
485
+ argumen dan gerbang persetujuannya), skrip `package.json` milik project itu
486
+ sendiri dan tata letak modul workspace, sehingga model memilih tool yang benar
487
+ alih-alih keluar ke `grep`/`rg`, dan tahu command apa saja yang benar-benar
488
+ disediakan project tersebut.
489
+ - System prompt mendapat aturan argumen eksplisit (satu objek JSON, tanpa pagar,
490
+ tanpa pemotongan, kutip yang di-escape) dan aturan pemulihan (pemanggilan yang
491
+ gagal adalah bukti, exit code `1` biasanya berarti "tidak ada yang cocok", jangan
492
+ pernah menjalankan ulang command identik).
493
+ - Kegagalan provider yang bisa dipulihkan (jaringan, timeout, `5xx`, `429`) dicoba
494
+ ulang oleh agent dengan backoff eksponensial alih-alih membatalkan tugas, dibatasi
495
+ oleh `AGENT_MAX_RECOVERY_ATTEMPTS` (bawaan 5) dan `AGENT_RECOVERY_BACKOFF_MS`
496
+ (bawaan 1000).
497
+ - **Heartbeat** kini membuktikan agent masih hidup saat memulihkan diri:
498
+ `♥ heartbeat · reconnecting · attempt 2/5 in 1.0s`, diikuti
499
+ `♥ heartbeat · link restored after 2 attempt(s)` ketika provider menjawab lagi.
500
+ Payload rusak menampilkan `♥ heartbeat · INVALID_ARGUMENTS · …` selama pemanggilan
501
+ diperbaiki. Baris aktivitas tetap berputar selama penantian, sehingga terminal
502
+ tidak pernah terlihat membeku.
503
+ - Pemisahan warna: teks respons (jawaban akhir dan catatan yang dialirkan) memakai
504
+ palet putih, sementara baris tugas, nama tool/command, dan baris command di panel
505
+ bukti memakai biru.
506
+ ### Dokumentasi
507
+
508
+ - Mendokumentasikan aliran reasoning langsung (`reasoning_content`, pratinjau lima
509
+ baris dalam kotak tertutup, `Tab` untuk tampilan penuh, log di
510
+ `.ryuu/logs/reasoning/`), memori percakapan (`/memory`, `/resume`), dan aliran
511
+ langsung jawaban akhir.
512
+ - Bagian pemecahan masalah README yang baru: "Tautan terputus di tengah run
513
+ (heartbeat)", "must be a valid JSON object string (HTTP 400)", dan "Sebuah tool
514
+ terus gagal", plus dua variabel environment pemulihan yang baru.
515
+ - Memperbaiki keterbatasan README yang masih mengklaim respons tidak dialirkan, dan
516
+ membuat petunjuk toggle reasoning penuh konsisten berbahasa Inggris.
517
+
518
+ ## [0.1.0] - 2026-10-20
519
+
520
+ Rilis pertama yang bisa dipakai: agen coding otonom yang bergerbang persetujuan
521
+ untuk terminal.
522
+
523
+ ### Ditambahkan
524
+
525
+ - UI terminal interaktif dengan banner bermerek, info model/provider/workspace/
526
+ runtime, pesan status berwarna, rencana tugas, langkah bernomor, aktivitas tool
527
+ live, durasi, permintaan persetujuan, penolakan, ringkasan bukti akhir, serta mode
528
+ plain untuk penggunaan non-TTY.
529
+ - Loop agent eksplisit di atas Chat Completions API NVIDIA yang kompatibel dengan
530
+ OpenAI (`https://integrate.api.nvidia.com/v1`, bawaan
531
+ `deepseek-ai/deepseek-v4.1-flash`): tool call tervalidasi skema, penegakan
532
+ persetujuan, bolak-balik hasil tool, deteksi pemanggilan duplikat, penanganan
533
+ argumen rusak, penolakan tool tak dikenal, pemadatan konteks berbatas, batas
534
+ langkah/durasi/output, dan pembatalan.
535
+ - Tool workspace: `list_files`, `tree`, `read_file`, `search_files`, `file_info`,
536
+ `create_file`, `edit_file`, `write_file`, `move_file`, `delete_file`, `diff_file`,
537
+ `inspect_git`, dan `project_summary`.
538
+ - Tool proses: `run_command`, `start_process`, `list_processes`,
539
+ `get_process_output`, dan `stop_process`, dengan stdout/stderr asli, exit code,
540
+ sinyal, durasi, timeout, buffer terbatas, serta penghentian bersih lalu paksa.
541
+ - Klien provider dengan retry terbatas dan jitter untuk kegagalan sesaat, dukungan
542
+ `Retry-After`, serta pemetaan yang bisa ditindaklanjuti untuk 401/403/404/429/5xx,
543
+ galat koneksi, timeout, galat panjang konteks, dan tool calling yang tidak
544
+ didukung.
545
+ - Slash command: `/help`, `/exit`, `/clear`, `/status`, `/model`, `/workspace`,
546
+ `/files`, `/tree`, `/tools`, `/processes`, `/logs`, `/cancel`, `/history`,
547
+ `/sessions`, `/diff`, `/undo`, `/config`, dan `/doctor`.
548
+ - Riwayat sesi lokal, caching ringkasan project dengan invalidasi, pemadatan
549
+ konteks, log yang disunting (redacted) dengan rotasi, serta undo stack terbatas
550
+ sesi dengan pemeriksaan file basi.
551
+ - Registry tool dengan skema JSON, tingkat risiko, metadata persetujuan, validasi
552
+ plugin, dan deteksi tabrakan.
553
+
554
+ ### Keamanan
555
+
556
+ - Penolakan escape path workspace dan symlink; path absolut di luar workspace
557
+ ditolak.
558
+ - Pemblokiran file rahasia untuk `.env*`, kunci, sertifikat, dan direktori
559
+ kredensial.
560
+ - Direktori hasil-generate (`node_modules`, `.git`, `dist`, output build, ...)
561
+ dikecualikan secara bawaan.
562
+ - Command dijalankan dengan array argumen dan `shell: false`; shell mentah butuh
563
+ `AGENT_ALLOW_SHELL=true` plus persetujuan eksplisit. Didokumentasikan sebagai
564
+ **bukan sandbox**.
565
+ - Variabel environment yang tampak seperti kredensial dibuang dari proses anak.
566
+ - Kunci API dan pola token disunting dari log, sesi, galat, dan output command.
567
+ - Penulisan atomik yang mempertahankan akhir baris, dengan perlindungan mtime basi
568
+ opsional.
569
+ - `.env` dan seluruh state lokal di bawah `.ryuu/` dikecualikan dari Git.
570
+
571
+ ### Pengujian
572
+
573
+ - 109 uji unit dan integrasi offline memakai runner tes bawaan Node, workspace
574
+ sementara, provider terskrip, dan `fetch` yang disuntikkan.
575
+ - Cakupannya meliputi penolakan traversal/symlink, pengecualian rahasia, batas
576
+ ukuran, baca/daftar/cari, diff, sunting aman, penolakan persetujuan, validasi
577
+ argumen, tool tak dikenal, normalisasi/pemetaan galat/retry provider, keluar/
578
+ timeout/truncasi proses, redaksi log dan izin log khusus pemilik, sesi/pemadatan,
579
+ eksekusi command yang disetujui dengan stdout/stderr/exit code/durasi asli, serta
580
+ perilaku start/doctor CLI.
581
+
582
+ ### Keterbatasan yang diketahui
583
+
584
+ - Validasi API NVIDIA langsung pada 2026-10-20 berhasil dengan `z-ai/glm-5.3`
585
+ (tool call plus jawaban akhir). Endpoint `deepseek-ai/deepseek-v4.1-flash` bawaan
586
+ saat itu habis waktu di sisi provider; pakai `--model` atau `NVIDIA_MODEL` sebagai
587
+ solusi dan jalankan ulang `npm run doctor -- --live`.
588
+ - Respons dialirkan dan dikumpulkan sisi-klien; tool call hanya berjalan berurutan.
589
+ - `/undo` terbatas pada tugas saat ini dan menolak saat file berubah di bawahnya.
590
+ - Tidak ada sandbox atau isolasi kontainer tingkat OS.
591
+ - Pembersihan pohon proses di Windows bersifat best-effort.
592
+
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ryuu-agent
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.