hanoman 0.1.13 → 0.1.15

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.
@@ -0,0 +1,429 @@
1
+ # hanoman — dokumentasi AI Agent
2
+
3
+ **Halaman ini ditulis untuk kamu, agen.** Kalau kamu diberi tautan ini dan satu **agent token**,
4
+ tak ada lagi yang perlu dijelaskan manusia: semua yang kamu butuhkan ada di bawah.
5
+
6
+ Naskah ini punya **satu sumber** dan tiga cara membacanya — isinya byte yang sama:
7
+
8
+ | Cara | Alamat |
9
+ |---|---|
10
+ | **markdown mentah** (paling berguna untukmu) | `GET $HANOMAN_HOST/api/agent-integration.md` — **publik, tanpa auth** |
11
+ | repo GitHub | [`docs/agent-integration.md`](https://github.com/denameidina/hanoman/blob/main/docs/agent-integration.md) |
12
+ | dashboard | Settings → **Dokumentasi AI Agent** |
13
+
14
+ > SPEC-257/265/489 · ADR-0065 (agent token & capability) · ADR-0099 (MCP server).
15
+
16
+ ---
17
+
18
+ ## 0. Apa itu hanoman, dan bagaimana ia bekerja
19
+
20
+ hanoman adalah **orchestrator + dashboard** untuk pengembangan yang digerakkan dokumentasi. Ia tidak
21
+ menulis kode sendiri; ia **menjalankan agen** (Claude Code atau Codex CLI) sebagai sesi interaktif,
22
+ lalu memantau semuanya dalam satu tempat.
23
+
24
+ Model kerjanya tiga tingkat, dan penting kamu pegang sebelum memanggil endpoint apa pun:
25
+
26
+ ```
27
+ backlog item (Spec) → sesi agen (tmux) → git worktree terisolasi
28
+ "SPEC-489" satu sesi per item <repo>/.worktrees/spec-489
29
+ ```
30
+
31
+ - **Backlog item** (`Spec`, id `SPEC-nnn`) adalah unit kerja: sebuah brief, temuan QA, laporan
32
+ audit, tiket Help Center, atau satu goal. Ia milik sebuah **project**.
33
+ - **Satu backlog = satu sesi.** Menekan Start dua kali bukan melahirkan sesi kedua — ia menyambung
34
+ ke sesi yang sudah ada.
35
+ - **Sesi hidup di worktree-nya sendiri**, bercabang dari branch basis, dan mendorong hasilnya ke
36
+ `hanoman/<id>`. Isolasi worktree itulah satu-satunya batas keamanan eksekusi di hanoman —
37
+ tak ada guardrail perintah.
38
+ - **Fase bukan proses, melainkan giliran** di dalam satu sesi: `Brainstorm → Objective → Spec →
39
+ Plan → Execute` (bervariasi per jenis kerja). Kemajuannya dibaca dari berkas fase, bukan dari
40
+ status proses.
41
+ - **Dokumentasi project (`internal/docs/**`) adalah Source of Truth.** Sebelum mengusulkan apa pun,
42
+ baca dokumen project-nya — itu sikap yang diharapkan dari agen di sini.
43
+
44
+ Dashboard React hanyalah **satu klien** dari REST API di bawah `/api`. Kamu memakai API yang persis
45
+ sama; yang berbeda hanya jalur auth-nya: **`Authorization: Bearer`**, bukan cookie sesi.
46
+
47
+ ## 1. Nyalakan akses & buat token (manusia, sekali)
48
+
49
+ Langkah ini **bukan** milikmu — mintalah ke manusia bila belum dilakukan. Di dashboard hanoman:
50
+ **Settings → Akses AI Agent**.
51
+
52
+ 1. **Aktifkan "Akses AI Agent"** (master switch). Selagi mati, *semua* agent token dibalas **401**
53
+ apa pun capability-nya.
54
+ 2. **Buat token:** beri nama (mis. `agent-ci`), centang **capability** yang dibutuhkan (baca/tulis
55
+ per domain), klik **Buat token**.
56
+ 3. **Salin token plaintext sekarang** — bentuknya `hnm_agt_<hex>` dan **hanya ditampilkan sekali**
57
+ (di server hanya `sha256` yang tersimpan). Simpan di rahasia agen (mis. env
58
+ `HANOMAN_AGENT_TOKEN`).
59
+
60
+ Cabut/nonaktifkan token atau matikan master switch kapan saja → efek **instan**.
61
+
62
+ ## 2. Base URL & autentikasi
63
+
64
+ ```bash
65
+ export HANOMAN_HOST="https://hanoman.example" # TANPA "/" di ekor
66
+ export HANOMAN_AGENT_TOKEN="hnm_agt_…" # dari langkah §1
67
+ ```
68
+
69
+ - **Seluruh path berawalan `/api`.** `$HANOMAN_HOST/api/specs`, bukan `$HANOMAN_HOST/specs`.
70
+ - **`HANOMAN_HOST` tanpa garis miring di ekor** — path di dokumen ini selalu dimulai dengan `/`,
71
+ jadi ekor ganda menghasilkan `//api/...` yang tak dikenal router.
72
+ - Sertakan token di **tiap** request:
73
+
74
+ ```
75
+ Authorization: Bearer hnm_agt_xxxxxxxxxxxx
76
+ ```
77
+
78
+ - Untuk **WebSocket** (terminal PTY, event stream) yang tak bisa memasang header dari browser,
79
+ kirim sebagai query: `?agent_token=hnm_agt_...`.
80
+ - **Token diterbitkan per-instance.** Token dari instance lain selalu 401 di sini.
81
+
82
+ ```bash
83
+ curl -s "$HANOMAN_HOST/api/specs" -H "Authorization: Bearer $HANOMAN_AGENT_TOKEN"
84
+ ```
85
+
86
+ **Probe host lebih dulu.** `GET /api/health` bersifat **publik** (tanpa auth), begitu pula halaman
87
+ ini (`GET /api/agent-integration.md`). Keduanya memisahkan tiga sebab yang tampak identik sebagai
88
+ "401 telanjang": host salah · master switch mati · token dicabut. Kalau `/api/health` menjawab 200,
89
+ host-mu benar dan masalahnya ada pada token atau master switch.
90
+
91
+ ## 3. Capability
92
+
93
+ Capability berformat `"<domain>:<access>"`, `access ∈ {read, write}`, dan **write meng-implikasikan
94
+ read** pada domain yang sama. Ada **12 domain × 2 = 24 capability**. Katalog resmi (dengan label &
95
+ deskripsi) tampil di panel **Settings → Akses AI Agent** saat manusia membuat token; endpoint
96
+ katalognya (`GET /api/agent-tokens/capabilities`) bersifat **cookie-only** (lihat §5) — kamu tak
97
+ perlu mengambilnya, cukup rujuk tabel di bawah:
98
+
99
+ | Domain | Cakupan endpoint | Catatan |
100
+ |---|---|---|
101
+ | `projects` | `/api/projects*` | project, branch, binding, Help Center |
102
+ | `backlog` | `/api/specs*` | spec/backlog, dokumen, review diff, integrate |
103
+ | `sessions` | `/api/terminal*` (+ WS terminal) | jalankan sesi agen/shell, kirim input — **high-risk (RCE)** |
104
+ | `docs` | `/api/prds*`, `/api/projects/:id/{docs,prds}*` | dokumen SoT project & PRD |
105
+ | `ide` | `/api/projects/:id/{tree,file,file-diff,working-status,graph,commit,git,status,stashes,remotes,compare,archive,pr-url}*` | tree/file working tree, operasi git |
106
+ | `vps` | `/api/vps*` | kelola VPS, audit, harden, konsol — **high-risk (remote exec)** |
107
+ | `settings` | `/api/settings*`, `/api/config*`, `/api/scheduler*` | setelan instance & config runtime |
108
+ | `support` | `/api/tickets*`, `/api/github-issues*`, `/api/projects/:id/github*` | tiket Help Center & issue GitHub (triase) |
109
+ | `notifications` | `/api/notifications*` | notifikasi |
110
+ | `lead` | `/api/lead*` | minta putusan ke hanoman-lead & baca jejaknya — **`lead:write` bisa menggerakkan sesi** (ADR-0091) |
111
+ | `agents` | `/api/custom-agents*` | katalog custom agent global & per project — **`agents:write` mengubah apa yang dilihat SETIAP sesi baru** (ADR-0094) |
112
+ | `telegram` | `/api/telegram*` kecuali sub-path kredensial | context/memory/reply/audit kanal operator Telegram (ADR-0096) |
113
+
114
+ Aturan pemetaan **deterministik** (`server/src/services/agent-capabilities.ts`): `GET`/`HEAD` →
115
+ `:read`, metode lain → `:write`. Itu berlaku untuk domain `lead` juga — **`POST /api/lead/decisions`
116
+ menuntut `lead:write`**, dan `lead:read` tak pernah cukup: meminta putusan melahirkan baris jejak
117
+ permanen dan keputusannya bisa menggerakkan sesi. Sub-path `/api/projects/:id/{docs,prds}` dihitung
118
+ domain **`docs`**; sub-path IDE/git di atas dihitung domain **`ide`**; WebSocket terminal butuh
119
+ **`sessions:write`**.
120
+
121
+ ## 4. Aturan gate & kode status
122
+
123
+ Gate `onRequest` yang sama menegakkan semuanya:
124
+
125
+ | Situasi | Balasan |
126
+ |---|---|
127
+ | Master switch mati, atau token invalid/nonaktif/dicabut | **401** `{ error: "unauthorized" }` |
128
+ | Token valid tapi capability kurang | **403** `{ error: "capability required", need: "<domain>:<access>" }` |
129
+ | Route cookie-only (§5) diakses agen | **403** `{ error: "cookie session required" }` |
130
+ | Capability cukup | request diproses seperti biasa |
131
+
132
+ Field **`need`** pada 403 memberi tahu capability persis yang harus ditambahkan ke token. Baca 403
133
+ seperti itu bukan sebagai "gagal" melainkan sebagai **instruksi**: sampaikan `need` ke manusia dan
134
+ minta capability itu ditambahkan di Settings.
135
+
136
+ ## 5. Yang tak bisa didelegasikan (cookie-only)
137
+
138
+ Untuk mencegah privilege-escalation, endpoint berikut **hanya** untuk sesi cookie manusia — agent
139
+ token selalu **403**, apa pun capability-nya, dan tak ada capability yang bisa membukanya:
140
+
141
+ - `/api/auth/*` — kelola user & password
142
+ - `/api/agent-tokens*` — agen tak boleh mencetak/menaikkan token sendiri
143
+ - `/api/device-tokens*`, `/api/sync*` — identitas mesin & sync hub
144
+ - `/api/webhooks*` — memegang secret penandatanganan **dan** menentukan ke mana data workspace
145
+ mengalir keluar (ADR-0100)
146
+ - `/api/telegram/settings`, `/api/telegram/test`, `/api/telegram/credentials` — permukaan
147
+ **kredensial** (bot token & agent token), beda dari sisa `/api/telegram*` (ADR-0097)
148
+ - `POST /api/update/apply` dan tulis lain di bawah prefix status (`/api/limits`, `/api/update`,
149
+ `/api/events`, `/api/fs`, `/api/health`) — **baca**-nya terbuka untuk token mana pun, **tulis**-nya
150
+ cookie-only
151
+
152
+ Route yang tak dikenal peta juga **default cookie-only** (aman): endpoint baru tak pernah terbuka
153
+ karena kelalaian. Endpoint `/api/help*` (Help Center publik) punya otorisasi sendiri (kunci tiket)
154
+ dan tak memakai agent token.
155
+
156
+ ## 6. Endpoint yang paling sering dipakai
157
+
158
+ | Method & path | Capability | Catatan |
159
+ |---|---|---|
160
+ | `GET /api/health` | — (publik) | probe host. Tanpa auth. |
161
+ | `GET /api/agent-integration.md` | — (publik) | halaman ini, markdown mentah. |
162
+ | `GET /api/projects` | `projects:read` | daftar project. `id` di sini yang dipakai `POST /api/specs`. |
163
+ | `GET /api/projects/:id` | `projects:read` | detail satu project. |
164
+ | `GET /api/specs` | `backlog:read` | backlog. Filter: `project`, `source`, `q`, `stage`, `priority`, `startable=true`, `dateField=created\|started` + `from`/`to` (`YYYY-MM-DD`, inklusif), `page`, `limit`. |
165
+ | `POST /api/specs` | `backlog:write` | buat backlog item — bentuk payload di §7. |
166
+ | `PATCH /api/specs/:id` | `backlog:write` | ubah item; konten hanya selagi belum dimulai. |
167
+ | `GET /api/specs/:id/docs` | `backlog:read` | dokumen yang ditulis sesi item itu. |
168
+ | `GET /api/specs/:id/review` | `backlog:read` | diff hasil kerja sesi. |
169
+ | `GET /api/projects/:id/docs` | `docs:read` | index Source of Truth project. |
170
+ | `GET /api/projects/:id/docs/<path>` | `docs:read` | isi satu dokumen. |
171
+ | `GET /api/terminal/sessions` | `sessions:read` | sesi yang sedang hidup. |
172
+ | `GET /api/notifications` | `notifications:read` | notifikasi. |
173
+ | `GET /api/tickets` | `support:read` | tiket Help Center. |
174
+ | `GET /api/lead/decisions` | `lead:read` | jejak keputusan hanoman-lead. |
175
+ | `POST /api/lead/decisions` | `lead:write` | minta putusan — baca **§8** dan **§11** dulu. |
176
+
177
+ ## 7. `POST /api/specs` — bentuk payload per `source`
178
+
179
+ `source` dan bentuk `payload` **saling mengikat**. Salah pasang → **400**
180
+ `"bentuk payload tak cocok dengan source"`. Union saja tak menjaganya (objek non-strict), jadi
181
+ server menegakkannya di boundary.
182
+
183
+ | `source` | Bentuk `payload` | Field |
184
+ |---|---|---|
185
+ | `brief` | brief | `context`, `outcome`, `constraints`, `priority` |
186
+ | `audit` | brief | idem — audit-only: hasilnya dokumen temuan, tanpa Execute |
187
+ | `help` | brief | idem — item yang lahir dari tiket Help Center |
188
+ | `qa` | qa | `severity` (`critical`\|`major`\|`minor`), `steps`, `expected`, `actual`, `env` |
189
+ | `goal` | goal | `goal` (wajib), `done`, `constraints`, `priority` |
190
+
191
+ Body lengkap: `project` (slug project), `source`, `title`, `priority`
192
+ (`tinggi`\|`sedang`\|`rendah`), `payload`; opsional `branchFrom` (branch basis — harus benar-benar
193
+ ada di repo project) dan `dependsOn` (array id backlog yang harus selesai & ter-merge lebih dulu).
194
+
195
+ Yang **tak** kamu kirim karena diturunkan server: `objective` (dari `outcome`/`context` untuk brief,
196
+ `actual`/`steps` untuk qa, `goal` untuk goal) dan — khusus `qa` — `priority`, yang diturunkan dari
197
+ `severity`.
198
+
199
+ ```json
200
+ {
201
+ "project": "hanoman",
202
+ "source": "qa",
203
+ "title": "Tombol Lanjutkan diam saat pane mati",
204
+ "priority": "tinggi",
205
+ "payload": {
206
+ "severity": "major",
207
+ "steps": "Buka Terminal → tunggu sesi keluar → klik Lanjutkan",
208
+ "expected": "Sesi dilanjutkan dari fase terakhir",
209
+ "actual": "Tak terjadi apa-apa",
210
+ "env": "hanoman 0.1.13, macOS"
211
+ }
212
+ }
213
+ ```
214
+
215
+ Balasannya **201** dengan seluruh baris `Spec`, termasuk `id` (`SPEC-nnn`) yang diterbitkan server.
216
+
217
+ ## 8. Tindakan berbahaya — wajib konfirmasi manusia
218
+
219
+ Tiga permukaan ini **wajib** kamu konfirmasikan ke manusia lebih dulu, walaupun token-mu sudah punya
220
+ capability-nya. Capability menjawab "boleh?", bukan "sebaiknya?".
221
+
222
+ | Tindakan | Kenapa |
223
+ |---|---|
224
+ | `POST /api/terminal/sessions` | melahirkan proses agen `--dangerously-skip-permissions` di sebuah worktree — **RCE efektif**. Batas satu-satunya adalah isolasi git worktree (ADR-0037). |
225
+ | `POST`/`PUT`/`DELETE` di bawah `/api/vps` | **remote exec** di server produksi. |
226
+ | `POST /api/lead/decisions` | putusannya bisa **menggerakkan sesi** (integrate ke main, menghentikan sesi) dan selalu melahirkan baris jejak permanen (ADR-0091/0098). |
227
+
228
+ Perlakukan `POST /api/specs/:id/integrate`, `DELETE /api/specs/:id`, dan perubahan `stage` dengan
229
+ disiplin yang sama: ketiganya mengubah sejarah git atau membuang pekerjaan.
230
+
231
+ **Preseden yang mengikat:** MCP server resmi (`hanoman mcp`, §13) sengaja **tak punya tool** untuk
232
+ satu pun dari yang di atas — batasnya ada di katalog tool, bukan di token. Token yang punya
233
+ `sessions:write` sekalipun tak akan menemukan tool untuk memakainya. Lewat REST kamu *bisa*
234
+ memanggilnya; jangan lakukan tanpa manusia.
235
+
236
+ ## 9. Jebakan yang sudah diketahui
237
+
238
+ | Jebakan | Yang benar |
239
+ |---|---|
240
+ | `startable` hanya bereaksi pada string **`"true"`**; nilai lain (`false`, `1`, `yes`) diabaikan **senyap** dan kamu menerima daftar penuh yang terlihat sah | kirim `?startable=true`, atau jangan kirim sama sekali |
241
+ | `q` mencari di `id`, `title`, dan `objective` saja — ia **tak menyentuh `payload`** | untuk mencari isi brief/QA, ambil itemnya lalu baca `payload` sendiri |
242
+ | `id` dan `stage` yang kamu sertakan di `POST /api/specs` **dibuang diam-diam** — tak ada galat | `id` diterbitkan server (`SPEC-nnn` berikutnya), `stage` selalu mulai `brainstorming`. Untuk mengubah stage pakai `PATCH /api/specs/:id`, dan ia hanya boleh **mundur** (ADR-0027) |
243
+ | **`GET /api/specs/:id` tidak ada** | `GET /api/specs?q=SPEC-489` lalu cocokkan `id` **persis** — `q` itu substring, jadi ia bisa mengembalikan lebih dari satu |
244
+ | daftar mengembalikan amplop `{ items, total, page, pageSize }` | jangan perlakukan responsnya sebagai array |
245
+ | tanpa `limit`, daftar mengembalikan **seluruh** item dalam satu halaman | kirim `limit` untuk backlog besar |
246
+ | `PATCH /api/specs/:id` menolak edit konten begitu item pernah dimulai | ubah `title`/`payload` hanya selagi item belum punya sesi |
247
+ | `branchFrom` yang tak ada di repo project → **400**, bukan diterima lalu gagal di tengah sesi | ambil kandidatnya dari `GET /api/projects/:id/branches` |
248
+ | **401 telanjang** tak memisahkan "host salah" dari "token salah" dari "master switch mati" | probe `GET /api/health` sekali: 200 = host benar → masalahnya token atau master switch |
249
+ | **403** bukan kegagalan permanen | bacalah field `need`, sampaikan ke manusia, minta capability itu ditambahkan |
250
+
251
+ ## 10. Contoh alur end-to-end
252
+
253
+ Bisa disalin apa adanya.
254
+
255
+ ```bash
256
+ export HANOMAN_HOST="https://hanoman.example" # tanpa "/" di ekor
257
+ export HANOMAN_AGENT_TOKEN="hnm_agt_…" # dari Settings → Akses AI Agent
258
+ auth=(-H "Authorization: Bearer $HANOMAN_AGENT_TOKEN")
259
+
260
+ # 0. Host benar? (publik, tanpa auth — memisahkan "host salah" dari "token salah")
261
+ curl -fsS "$HANOMAN_HOST/api/health"
262
+
263
+ # 0b. Baca halaman ini sendiri (publik, markdown mentah)
264
+ curl -fsS "$HANOMAN_HOST/api/agent-integration.md"
265
+
266
+ # 1. Project apa saja yang ada? (projects:read) — `id` di sini yang dipakai langkah berikutnya
267
+ curl -fsS "${auth[@]}" "$HANOMAN_HOST/api/projects"
268
+
269
+ # 2. Backlog yang belum selesai di satu project (backlog:read)
270
+ curl -fsS "${auth[@]}" "$HANOMAN_HOST/api/specs?project=hanoman&startable=true&limit=20"
271
+
272
+ # 3. Sudah ada item tentang "webhook"? (q = substring atas id+title+objective, BUKAN payload)
273
+ curl -fsS "${auth[@]}" "$HANOMAN_HOST/api/specs?project=hanoman&q=webhook"
274
+
275
+ # 4. Filekan temuan sebagai backlog item (backlog:write)
276
+ curl -fsS -X POST "$HANOMAN_HOST/api/specs" "${auth[@]}" \
277
+ -H "Content-Type: application/json" \
278
+ -d '{
279
+ "project": "hanoman",
280
+ "source": "qa",
281
+ "title": "Preview docs menggulir ke samping",
282
+ "priority": "sedang",
283
+ "payload": { "severity": "minor", "steps": "Buka Docs → pilih .md panjang",
284
+ "expected": "Teks membungkus", "actual": "Muncul scrollbar horizontal",
285
+ "env": "hanoman 0.1.13, Chrome" }
286
+ }'
287
+ # → 201 { "id": "SPEC-490", ... } ← id datang dari server; jangan pernah dikirim
288
+
289
+ # 5. Ambil satu item (tak ada GET /api/specs/:id — pakai q lalu cocokkan persis)
290
+ curl -fsS "${auth[@]}" "$HANOMAN_HOST/api/specs?q=SPEC-490" \
291
+ | python3 -c 'import json,sys; print([s for s in json.load(sys.stdin)["items"] if s["id"]=="SPEC-490"])'
292
+
293
+ # 6. Baca Source of Truth project sebelum mengusulkan apa pun (docs:read)
294
+ curl -fsS "${auth[@]}" "$HANOMAN_HOST/api/projects/hanoman/docs"
295
+
296
+ # 7. 403? Bacanya bukan "gagal" — bacanya "tambahkan capability ini ke token":
297
+ # { "error": "capability required", "need": "backlog:write" }
298
+ ```
299
+
300
+ **Yang TIDAK kamu lakukan tanpa manusia:** menjalankan backlog itu
301
+ (`POST /api/terminal/sessions`) — lihat §8.
302
+
303
+ ## 11. Minta putusan ke hanoman-lead
304
+
305
+ Agen yang menemui persimpangan tak selalu harus berhenti menunggu manusia — bila project-nya
306
+ meng-opt-in **hanoman-lead**, ia boleh **meminta putusan**:
307
+
308
+ ```bash
309
+ curl -s -X POST "$HANOMAN_HOST/api/lead/decisions" \
310
+ -H "Authorization: Bearer $HANOMAN_AGENT_TOKEN" \
311
+ -H "Content-Type: application/json" \
312
+ -d '{
313
+ "projectId": "hanoman",
314
+ "specId": "SPEC-409",
315
+ "question": "Tambah kolom baru di Spec, atau turunkan dari updatedAt?",
316
+ "options": ["kolom baru", "turunkan dari updatedAt"],
317
+ "context": "Filter rentang tanggal butuh waktu item dibuat."
318
+ }'
319
+ # 201 { id, decision, reason, refs: ["ADR-0090", "internal/docs/..."], confidence: "tinggi", action: "none" }
320
+ ```
321
+
322
+ Jawabannya **terbaca mesin**, bukan prosa bebas, dan `refs` hanya memuat rujukan yang benar-benar
323
+ ada di repo — jadi kamu bisa memverifikasi sendiri dasar keputusannya. `confidence: "ragu"` berarti
324
+ lead tetap memutuskan tapi memilih opsi yang paling mudah dibatalkan, dan operator sudah
325
+ dinotifikasi.
326
+
327
+ Kode balasan yang perlu ditangani:
328
+
329
+ | Kode | Artinya |
330
+ |---|---|
331
+ | **409** | lead tak aktif / project belum opt-in → **kembali ke perilaku lama**: berhenti & tunggu manusia |
332
+ | **503** + `Retry-After` | lead sedang penuh (batas konkurensi) → **boleh diulang** sesudah jeda; ini bukan kegagalan lead |
333
+ | **504** | lead tak berhasil memutuskan dalam batas waktu; kegagalannya sudah tercatat & dinotifikasi |
334
+ | **403** `{ need: "lead:write" }` | token cuma punya `lead:read` |
335
+
336
+ Ingat §8: permintaan putusan **bisa menggerakkan sesi**. Konfirmasikan ke manusia dulu.
337
+
338
+ ## 12. Keamanan
339
+
340
+ - Token = rahasia. Simpan di env/secret manager, **jangan commit**, dan **jangan pernah** berikan
341
+ lewat argumen baris perintah — ARGV terbaca proses lain di mesin yang sama. Bocor → **Cabut** di
342
+ Settings (efek instan).
343
+ - Beri capability **seminimal** mungkin. `sessions:write` (spawn agen
344
+ `--dangerously-skip-permissions`) dan `vps:write` (remote exec) adalah RCE efektif — batas
345
+ eksekusi sesungguhnya tetap **isolasi git worktree** (ADR-0037), tapi tetap tandai high-risk.
346
+ - `lastUsedAt` per token = jejak audit ringan. Matikan master switch untuk kill-switch seluruh
347
+ workspace.
348
+ - Halaman ini sendiri **tak pernah memuat token nyata** — hanya format/placeholder. Kalau kamu
349
+ melihat sesuatu yang menyerupai token asli di sini, itu bug; laporkan.
350
+
351
+ ## 13. MCP server (ADR-0099)
352
+
353
+ Agen yang berbicara **MCP** tak perlu menulis pembungkus sendiri. `hanoman mcp` adalah MCP server
354
+ **stdio** yang membungkus permukaan REST di atas sebagai **17 tool**. Ia memakai **agent token dan
355
+ capability yang sama** — bukan jalur otorisasi baru — jadi seluruh aturan §3–§5 berlaku apa adanya.
356
+
357
+ Prasyarat: `npm i -g hanoman` di mesin tempat klien AI-nya jalan.
358
+
359
+ **Claude Code / Claude Desktop / Cursor / Copilot** (`~/.claude.json`,
360
+ `claude_desktop_config.json`, `~/.cursor/mcp.json`, `.vscode/mcp.json` — Cursor & Copilot memakai
361
+ kunci `"servers"` alih-alih `"mcpServers"`):
362
+
363
+ ```json
364
+ {
365
+ "mcpServers": {
366
+ "hanoman": {
367
+ "command": "hanoman",
368
+ "args": ["mcp"],
369
+ "env": {
370
+ "HANOMAN_HOST": "https://hanoman.example",
371
+ "HANOMAN_AGENT_TOKEN": "hnm_agt_…"
372
+ }
373
+ }
374
+ }
375
+ }
376
+ ```
377
+
378
+ **Codex** (`~/.codex/config.toml`):
379
+
380
+ ```toml
381
+ [mcp_servers.hanoman]
382
+ command = "hanoman"
383
+ args = ["mcp"]
384
+ env = { HANOMAN_HOST = "https://hanoman.example", HANOMAN_AGENT_TOKEN = "hnm_agt_…" }
385
+ ```
386
+
387
+ Panduan siap salin untuk keempat klien, berikut tabel tool → capability, ada di dashboard:
388
+ **Settings → Akses AI Agent → MCP server**.
389
+
390
+ ### Tool
391
+
392
+ | Tool | Mode | Capability |
393
+ |---|---|---|
394
+ | `hanoman_about` | baca | — (tak memanggil `/api` selain `/health`) |
395
+ | `hanoman_projects_list`, `hanoman_project_get` | baca | `projects:read` |
396
+ | `hanoman_backlog_search`, `hanoman_backlog_get`, `hanoman_backlog_docs_list`, `hanoman_backlog_doc_read` | baca | `backlog:read` |
397
+ | `hanoman_sessions_list` | baca | `sessions:read` |
398
+ | `hanoman_notifications_list` | baca | `notifications:read` |
399
+ | `hanoman_tickets_list`, `hanoman_ticket_get`, `hanoman_github_issues_list` | baca | `support:read` |
400
+ | `hanoman_lead_decisions_list` | baca | `lead:read` |
401
+ | `hanoman_backlog_create`, `hanoman_backlog_update` | tulis | `backlog:write` |
402
+ | `hanoman_notifications_mark_read` | tulis | `notifications:write` |
403
+ | `hanoman_lead_ask` | tulis | `lead:write` |
404
+
405
+ ### Yang sengaja TIDAK tersedia lewat MCP
406
+
407
+ Membuat sesi terminal (`POST /api/terminal/sessions` — menjalankan agen di worktree, RCE efektif)
408
+ dan seluruh `/api/vps*` (remote exec) **tidak ikut**, begitu pula merge/rebase (`integrate`),
409
+ penghapusan backlog, dan perubahan `stage`. Batasan ini ada di katalog toolnya, bukan di token:
410
+ token yang punya `sessions:write` sekalipun tak akan menemukan tool untuk memakainya. Lihat §8.
411
+
412
+ ### Opsi
413
+
414
+ | Variabel / flag | Arti |
415
+ |---|---|
416
+ | `HANOMAN_HOST` / `--host <url>` | **Wajib.** Instance yang dituju. Agent token diterbitkan per-instance — token dari instance lain selalu 401 di sini, dan MCP server menjelaskannya, bukan meneruskan 401 telanjang. |
417
+ | `HANOMAN_AGENT_TOKEN` | **Wajib.** Hanya dari env atau `~/.hanoman/agent-token` — **tak pernah** dari argumen baris perintah (ARGV terbaca proses lain di mesin yang sama). |
418
+ | `HANOMAN_MCP_READ_ONLY=1` / `--read-only` | Menyembunyikan seluruh tool tulis dari `tools/list`. |
419
+ | `HANOMAN_MCP_MAX_BYTES` / `--max-bytes <n>` | Plafon ukuran balasan tool. Default 24576. Balasan yang dipotong ditandai `truncated: true` + `shown`/`total`. |
420
+
421
+ Skema tool berversi (`MCP_TOOL_SCHEMA_VERSION`, saat ini **1**) dan aditif dalam satu versi:
422
+ menambah tool tak mematahkan klien lama.
423
+
424
+ ---
425
+
426
+ *Doc-of-record fitur: [ADR-0065](../internal/docs/adr/0065-ai-agent-capability-agent-token.md) dan,
427
+ untuk permukaan MCP, [ADR-0099](../internal/docs/adr/0099-mcp-server-hanoman.md). Kontrak API penuh:
428
+ [`internal/docs/architecture/api-contract.md`](../internal/docs/architecture/api-contract.md) —
429
+ permukaan REST-nya identik dengan yang dipakai dashboard.*
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hanoman",
3
- "version": "0.1.13",
3
+ "version": "0.1.15",
4
4
  "description": "Orchestrator + dashboard workflow docs-driven untuk sesi Claude Code / Codex",
5
5
  "type": "module",
6
6
  "repository": {
@@ -22,6 +22,7 @@
22
22
  "dist",
23
23
  "web",
24
24
  "prisma",
25
+ "docs",
25
26
  "README.md",
26
27
  "LICENSE"
27
28
  ],