hanoman 0.1.45 → 0.1.47

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.
@@ -169,6 +169,10 @@ dan tak memakai agent token.
169
169
  | `POST /api/specs` | `backlog:write` | buat backlog item — bentuk payload di §7. |
170
170
  | `PATCH /api/specs/:id` | `backlog:write` | ubah item; konten hanya selagi belum dimulai. |
171
171
  | `POST /api/specs/:id/done` | `backlog:write` | tandai item **selesai** tanpa menjalankan sesi — untuk pekerjaan yang beres di luar hanoman. Body `{ reason?: string (≤280), confirm?: boolean }`, keduanya opsional; balasannya `Spec` yang sudah `stage:"done"`. Tak menjalankan maupun menghentikan sesi apa pun. |
172
+ | `GET /api/specs/:id/attachments` | `backlog:read` | lampiran backlog item — gambar & dokumen yang dilampirkan manusia sebagai konteks kerja. |
173
+ | `POST /api/specs/:id/attachments` | `backlog:write` | unggah lampiran (`multipart/form-data`, beberapa berkas per request). Berkas yang ditolak **tak** menggagalkan yang lain — periksa `rejected[]`. |
174
+ | `GET /api/specs/:id/attachments/:attId` | `backlog:read` | byte satu lampiran. |
175
+ | `DELETE /api/specs/:id/attachments/:attId` | `backlog:write` | hapus satu lampiran. |
172
176
  | `GET /api/specs/:id/docs` | `backlog:read` | dokumen yang ditulis sesi item itu. |
173
177
  | `GET /api/specs/:id/review` | `backlog:read` | diff hasil kerja sesi. |
174
178
  | `GET /api/projects/:id/docs` | `docs:read` | index Source of Truth project. |
@@ -299,6 +303,7 @@ memanggilnya; jangan lakukan tanpa manusia.
299
303
  | `branchFrom` yang tak ada di repo project → **400**, bukan diterima lalu gagal di tengah sesi | ambil kandidatnya dari `GET /api/projects/:id/branches` |
300
304
  | **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 |
301
305
  | **403** bukan kegagalan permanen | bacalah field `need`, sampaikan ke manusia, minta capability itu ditambahkan |
306
+ | **Lampiran backlog tak menyeberang sync** (`SpecAttachment` LOCAL-only, ADR-0124) | item yang sama di instance lain tampil **tanpa** lampiran. Kalau lampiran yang disebut manusia tak kamu temukan, kemungkinan besar kamu bicara ke instance yang bukan tempat lampiran itu diunggah — tanyakan, jangan simpulkan lampirannya tak ada |
302
307
 
303
308
  ## 10. Contoh alur end-to-end
304
309
 
@@ -461,6 +466,11 @@ dan seluruh `/api/vps*` (remote exec) **tidak ikut**, begitu pula merge/rebase (
461
466
  penghapusan backlog, dan perubahan `stage`. Batasan ini ada di katalog toolnya, bukan di token:
462
467
  token yang punya `sessions:write` sekalipun tak akan menemukan tool untuk memakainya. Lihat §8.
463
468
 
469
+ **Lampiran backlog** (`/api/specs/:id/attachments*`, SPEC-843 · ADR-0124) juga sengaja **tak punya
470
+ tool**: berkasnya lahir dari disk manusia, bukan dari model, dan tool MCP berbentuk JSON sehingga
471
+ byte biner tak punya representasi di sana. REST-nya tetap terjangkau agent token
472
+ ber-`backlog:read`/`backlog:write` — yang tak dipajang adalah **tool**-nya.
473
+
464
474
  ### Opsi
465
475
 
466
476
  | Variabel / flag | Arti |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hanoman",
3
- "version": "0.1.45",
3
+ "version": "0.1.47",
4
4
  "description": "Orchestrator + dashboard workflow docs-driven untuk sesi Claude Code / Codex",
5
5
  "type": "module",
6
6
  "repository": {
@@ -0,0 +1,19 @@
1
+ -- SPEC-843 · ADR-0124 · lampiran per backlog item.
2
+ --
3
+ -- Ditulis tangan (bukan `migrate dev`): worktree tetangga membuat `migrate dev` me-reset DB saat
4
+ -- ada drift. ADITIF murni — satu tabel baru, tak ada tabel yang diredefinisi.
5
+ --
6
+ -- TANPA kolom `version`: entitas ini LOCAL-only dan tak pernah masuk changefeed sync.
7
+ CREATE TABLE "SpecAttachment" (
8
+ "id" TEXT NOT NULL PRIMARY KEY,
9
+ "specId" TEXT NOT NULL,
10
+ "projectId" TEXT NOT NULL,
11
+ "filename" TEXT NOT NULL,
12
+ "mimeType" TEXT NOT NULL,
13
+ "size" INTEGER NOT NULL,
14
+ "storageKey" TEXT NOT NULL,
15
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
16
+ CONSTRAINT "SpecAttachment_specId_fkey" FOREIGN KEY ("specId") REFERENCES "Spec" ("id") ON DELETE CASCADE ON UPDATE CASCADE
17
+ );
18
+
19
+ CREATE INDEX "SpecAttachment_specId_idx" ON "SpecAttachment"("specId");
@@ -87,6 +87,30 @@ model Spec {
87
87
  sourceHistory Json?
88
88
  updatedAt DateTime @updatedAt
89
89
  project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
90
+ attachments SpecAttachment[]
91
+ }
92
+
93
+ // SPEC-843 · ADR-0124 · lampiran per backlog item — konteks yang dipegang manusia saat memfilekan
94
+ // item, dibaca agen di dalam sesi. Byte hidup di HANOMAN_UPLOAD_DIR (server-local, di luar repoDir);
95
+ // `storageKey` opaque, `filename` nama asli tersanitasi untuk tampilan saja.
96
+ //
97
+ // LOCAL-only: TANPA `version`, jadi ia tak pernah masuk changefeed sync (cermin LeadFlow,
98
+ // WebhookEndpoint, Changelog). Byte memang tak menyeberang (ADR-0062), dan metadata yang menyeberang
99
+ // TANPA byte-nya hanya menghasilkan lampiran yang tak bisa dibuka di mesin lain — keadaan terburuk
100
+ // dari ketiga pilihan. Sengaja BUKAN TicketAttachment: tiket dan backlog dua domain dengan aturan
101
+ // sync dan tingkat kepercayaan yang berbeda (ADR-0124 §1/§4).
102
+ model SpecAttachment {
103
+ id String @id @default(cuid())
104
+ specId String
105
+ projectId String // denormal — kuota & isolasi per project, cermin TicketAttachment
106
+ filename String
107
+ mimeType String
108
+ size Int
109
+ storageKey String
110
+ createdAt DateTime @default(now())
111
+ spec Spec @relation(fields: [specId], references: [id], onDelete: Cascade)
112
+
113
+ @@index([specId])
90
114
  }
91
115
 
92
116
  // SPEC-516 · ADR-0105 · changelog naratif per project yang sudah dibangkitkan.