hanoman 0.9.18 → 0.9.20
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/dist/build-info.json +3 -3
- package/dist/cli.js +63 -167
- package/dist/server.js +418 -639
- package/docs/agent-integration.md +9 -53
- package/package.json +1 -1
- package/prisma/migrations/20261007120000_project_memory/migration.sql +54 -0
- package/prisma/migrations/20261007130000_memory_sync/migration.sql +32 -0
- package/prisma/migrations/20261010070000_remove_memory_changelog/migration.sql +40 -0
- package/prisma/schema.prisma +3 -25
- package/web/assets/{DalangHanomanScreen-C1Ivdj4r.js → DalangHanomanScreen-DqzYitwv.js} +1 -1
- package/web/assets/{DocPreviewModal-Cw69hQk1.js → DocPreviewModal-Chk-jQ51.js} +1 -1
- package/web/assets/{DocsWorkspace--9rvckps.js → DocsWorkspace-DuNVIjTg.js} +1 -1
- package/web/assets/{IdeScreen-DxNG9eLb.js → IdeScreen-BZGVyFT5.js} +1 -1
- package/web/assets/{LeadScreen-CV3Lgbyd.js → LeadScreen-35VgddUo.js} +1 -1
- package/web/assets/{ReviewScreen-JLPOS52f.js → ReviewScreen-EkG8ywTU.js} +1 -1
- package/web/assets/{SchedulerScreen-UhxWcCtY.js → SchedulerScreen-ClaLLB8Y.js} +1 -1
- package/web/assets/SettingsScreen-liOlVCeT.js +62 -0
- package/web/assets/{TeamScreen-D24DsEwn.js → TeamScreen-Dzl6Ruju.js} +1 -1
- package/web/assets/{TerminalScreen-3nSnkwTy.js → TerminalScreen-CK3SzzgP.js} +1 -1
- package/web/assets/{TriageScreen-Dw6EqWar.js → TriageScreen-EtBRNg-t.js} +1 -1
- package/web/assets/{VpsScreen-C_rNhMi5.js → VpsScreen-9qeTHo1w.js} +1 -1
- package/web/assets/index-D5w059cP.js +1063 -0
- package/web/assets/{live-DHIFZVo0.js → live-Bz-jmiWI.js} +1 -1
- package/web/index.html +1 -1
- package/web/assets/ChangelogScreen-Bj1KreGh.js +0 -1
- package/web/assets/SettingsScreen-D3nVVnsZ.js +0 -62
- package/web/assets/index-DHVdBKua.js +0 -1053
|
@@ -114,19 +114,6 @@ perlu mengambilnya, cukup rujuk tabel di bawah:
|
|
|
114
114
|
| `telegram` | `/api/telegram*` kecuali sub-path kredensial | context/memory/reply/audit kanal operator Telegram (ADR-0096) |
|
|
115
115
|
| `team` | `/api/tasks*`, `/api/members*` | papan **Tim**: kartu kerja MANUSIA & direktori anggota (ADR-0157). `status` kartu milik manusia — ia **bukan** `stage` backlog. `POST /api/tasks/:id/escalate` melahirkan backlog item dan tetap `team:write` (cermin `POST /api/tickets/:id/accept`) |
|
|
116
116
|
|
|
117
|
-
Aturan pemetaan **deterministik** (`server/src/services/agent-capabilities.ts`): `GET`/`HEAD` →
|
|
118
|
-
`:read`, metode lain → `:write`. Itu berlaku untuk domain `lead` juga — **`POST /api/lead/decisions`
|
|
119
|
-
menuntut `lead:write`**, dan `lead:read` tak pernah cukup: meminta putusan melahirkan baris jejak
|
|
120
|
-
permanen dan keputusannya bisa menggerakkan sesi. Sub-path `/api/projects/:id/{docs,prds}` dihitung
|
|
121
|
-
domain **`docs`**; sub-path IDE/git di atas dihitung domain **`ide`**; WebSocket terminal butuh
|
|
122
|
-
**`sessions:write`**.
|
|
123
|
-
|
|
124
|
-
Empat endpoint STATUS tak menuntut capability sama sekali — token sah mana pun boleh membacanya
|
|
125
|
-
(`GLOBAL_READ`, ADR-0157): `GET /api/limits`, `GET /api/limits/codex`, `GET /api/update`, dan
|
|
126
|
-
`GET /api/fs/browse` (menelusuri folder mesin untuk mengisi `repoDir`). Hanya method BACA:
|
|
127
|
-
`POST /api/update/apply` me-restart instance dan tetap **403** untuk agent token, apa pun
|
|
128
|
-
capability-nya (SPEC-405/ADR-0088) — prefix yang sama tak menurunkan gerbangnya.
|
|
129
|
-
|
|
130
117
|
## 4. Aturan gate & kode status
|
|
131
118
|
|
|
132
119
|
Gate `onRequest` yang sama menegakkan semuanya:
|
|
@@ -205,8 +192,6 @@ dan tak memakai agent token.
|
|
|
205
192
|
| `GET /api/specs/:id/review` | `backlog:read` | diff hasil kerja sesi. |
|
|
206
193
|
| `GET /api/projects/:id/docs` | `docs:read` | index Source of Truth project. |
|
|
207
194
|
| `GET /api/projects/:id/docs/<path>` | `docs:read` | isi satu dokumen. |
|
|
208
|
-
| `GET /api/projects/:id/changelog` | `docs:read` | changelog yang sudah dibangkitkan (paginated). |
|
|
209
|
-
| `POST /api/projects/:id/changelog` | `docs:write` | bangkitkan changelog baru — bentuknya di **§6a**. |
|
|
210
195
|
| `GET /api/terminal/sessions` | `sessions:read` | sesi yang sedang hidup. |
|
|
211
196
|
| `GET /api/notifications` | `notifications:read` | notifikasi. **Tanpa `limit` → 50 teratas**, bukan seluruhnya (lihat jebakan di §10). |
|
|
212
197
|
| `GET /api/tickets` | `support:read` | tiket Help Center. |
|
|
@@ -214,44 +199,6 @@ dan tak memakai agent token.
|
|
|
214
199
|
| `GET /api/scheduler/queue` | `settings:read` | antrean scheduler (`?status=queued\|launched\|done\|failed`). `GET /api/scheduler/state` **tak lagi** memuat `queue` — ia memuat `queueCounts`. |
|
|
215
200
|
| `POST /api/lead/decisions` | `lead:write` | minta putusan — baca **§8** dan **§11** dulu. |
|
|
216
201
|
|
|
217
|
-
## 6a. Changelog per project
|
|
218
|
-
|
|
219
|
-
Ringkasan perubahan **berorientasi pemakai** — bukan daftar commit. Tiga mode, satu endpoint;
|
|
220
|
-
`mode` menentukan field lainnya:
|
|
221
|
-
|
|
222
|
-
```bash
|
|
223
|
-
# 1) backlog yang selesai di rentang tanggal (dua field opsional → 30 hari terakhir)
|
|
224
|
-
curl -sS -X POST "$HANOMAN_HOST/api/projects/<id>/changelog" \
|
|
225
|
-
-H "Authorization: Bearer $HANOMAN_AGENT_TOKEN" -H 'Content-Type: application/json' \
|
|
226
|
-
-d '{"mode":"backlog","from":"2026-07-01","to":"2026-07-31"}'
|
|
227
|
-
|
|
228
|
-
# 2) rentang commit di repo project
|
|
229
|
-
-d '{"mode":"commit","fromSha":"4f2a1c9","toSha":"HEAD"}'
|
|
230
|
-
|
|
231
|
-
# 3) versi/tag rilis (fromTag opsional → sejak versi sebelumnya)
|
|
232
|
-
-d '{"mode":"version","toTag":"v1.2.0"}'
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
Jawaban **201** berisi `body` (markdown siap pakai), `title`, `itemCount`, `generator`, dan
|
|
236
|
-
`warning`. Ambil ulang atau unduh kapan saja:
|
|
237
|
-
|
|
238
|
-
```bash
|
|
239
|
-
curl -sS "$HANOMAN_HOST/api/projects/<id>/changelog/<cid>?download=md" \
|
|
240
|
-
-H "Authorization: Bearer $HANOMAN_AGENT_TOKEN"
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
Tiga hal yang perlu kamu tahu sebelum memanggilnya:
|
|
244
|
-
|
|
245
|
-
- **Panggil `GET /api/projects/:id/changelog/sources` dulu.** Ia memberi tag yang tersedia, HEAD
|
|
246
|
-
singkat, rentang default, dan — bila repo belum ditautkan di mesin itu atau belum punya tag — satu
|
|
247
|
-
`reason` yang menjelaskan sebabnya. Ia menjawab **200**, bukan galat, jadi jangan perlakukan
|
|
248
|
-
`reason` sebagai kegagalan.
|
|
249
|
-
- **422 berarti permintaanmu sah tapi tak ada isinya** (rentang kosong, repo tanpa tag, revisi tak
|
|
250
|
-
dikenal) — pesannya bisa langsung diteruskan ke manusia. **400** berarti bentuknya salah
|
|
251
|
-
(mis. `from` lebih baru dari `to`).
|
|
252
|
-
- **`generator:"fallback"` bukan kegagalan.** Artinya narasi otomatis tak tersedia dan yang kamu
|
|
253
|
-
terima adalah draf ringkas deterministik; alasannya ada di `warning`.
|
|
254
|
-
|
|
255
202
|
## 7. `POST /api/specs` — bentuk payload per `source`
|
|
256
203
|
|
|
257
204
|
`source` dan bentuk `payload` **saling mengikat**. Salah pasang → **400**
|
|
@@ -526,3 +473,12 @@ menambah tool tak mematahkan klien lama.
|
|
|
526
473
|
untuk permukaan MCP, [ADR-0099](../internal/docs/adr/0099-mcp-server-hanoman.md). Kontrak API penuh:
|
|
527
474
|
[`internal/docs/architecture/api-contract.md`](../internal/docs/architecture/api-contract.md) —
|
|
528
475
|
permukaan REST-nya identik dengan yang dipakai dashboard.*
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
## Fitur yang dihapus — skema tool MCP versi 2
|
|
479
|
+
|
|
480
|
+
Memori project dan changelog dihapus (ADR-0182). Tool `hanoman_memory_*` dan
|
|
481
|
+
`hanoman_changelog_*` tidak tersedia; endpoint `/api/memories*` dan
|
|
482
|
+
`/api/projects/:id/changelog*` tidak terdaftar. Token tidak lagi memiliki
|
|
483
|
+
capability `memory:*` atau allowlist project khusus memori. Fungsi context/memory
|
|
484
|
+
kanal Telegram tetap tersedia melalui domain `telegram`.
|
package/package.json
CHANGED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
-- ADR-0178 · memori project bersama lintas runtime
|
|
2
|
+
-- AlterTable
|
|
3
|
+
ALTER TABLE "AgentToken" ADD COLUMN "projectIds" JSONB;
|
|
4
|
+
|
|
5
|
+
-- CreateTable
|
|
6
|
+
CREATE TABLE "ProjectMemory" (
|
|
7
|
+
"id" TEXT NOT NULL PRIMARY KEY,
|
|
8
|
+
"projectId" TEXT NOT NULL,
|
|
9
|
+
"kind" TEXT NOT NULL,
|
|
10
|
+
"content" TEXT NOT NULL,
|
|
11
|
+
"scopePaths" JSONB NOT NULL,
|
|
12
|
+
"anchors" JSONB NOT NULL,
|
|
13
|
+
"status" TEXT NOT NULL,
|
|
14
|
+
"supersedesId" TEXT,
|
|
15
|
+
"reviewReason" TEXT,
|
|
16
|
+
"sourceRuntime" TEXT NOT NULL,
|
|
17
|
+
"sourceSessionId" TEXT,
|
|
18
|
+
"sourceTokenId" TEXT,
|
|
19
|
+
"sourceDeviceId" TEXT,
|
|
20
|
+
"commitSha" TEXT,
|
|
21
|
+
"trusted" BOOLEAN NOT NULL DEFAULT true,
|
|
22
|
+
"version" INTEGER NOT NULL DEFAULT 0,
|
|
23
|
+
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
24
|
+
"updatedAt" DATETIME NOT NULL,
|
|
25
|
+
CONSTRAINT "ProjectMemory_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "Project" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
-- CreateTable
|
|
29
|
+
CREATE TABLE "MemoryEvent" (
|
|
30
|
+
"id" TEXT NOT NULL PRIMARY KEY,
|
|
31
|
+
"memoryId" TEXT NOT NULL,
|
|
32
|
+
"op" TEXT NOT NULL,
|
|
33
|
+
"actorKind" TEXT NOT NULL,
|
|
34
|
+
"actorId" TEXT,
|
|
35
|
+
"reason" TEXT,
|
|
36
|
+
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
37
|
+
CONSTRAINT "MemoryEvent_memoryId_fkey" FOREIGN KEY ("memoryId") REFERENCES "ProjectMemory" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
-- CreateTable
|
|
41
|
+
CREATE TABLE "MemoryLocalState" (
|
|
42
|
+
"memoryId" TEXT NOT NULL PRIMARY KEY,
|
|
43
|
+
"verdict" TEXT NOT NULL,
|
|
44
|
+
"verifiedHead" TEXT,
|
|
45
|
+
"lastVerifiedAt" DATETIME,
|
|
46
|
+
"lastUsedAt" DATETIME
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
-- CreateIndex
|
|
50
|
+
CREATE INDEX "ProjectMemory_projectId_status_idx" ON "ProjectMemory"("projectId", "status");
|
|
51
|
+
|
|
52
|
+
-- CreateIndex
|
|
53
|
+
CREATE INDEX "MemoryEvent_memoryId_createdAt_idx" ON "MemoryEvent"("memoryId", "createdAt");
|
|
54
|
+
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
-- ADR-0180 · sync memori: MemoryEvent.version/updatedAt, SyncState.entities (LOCAL-only)
|
|
2
|
+
-- RedefineTables
|
|
3
|
+
PRAGMA defer_foreign_keys=ON;
|
|
4
|
+
PRAGMA foreign_keys=OFF;
|
|
5
|
+
CREATE TABLE "new_MemoryEvent" (
|
|
6
|
+
"id" TEXT NOT NULL PRIMARY KEY,
|
|
7
|
+
"memoryId" TEXT NOT NULL,
|
|
8
|
+
"op" TEXT NOT NULL,
|
|
9
|
+
"actorKind" TEXT NOT NULL,
|
|
10
|
+
"actorId" TEXT,
|
|
11
|
+
"reason" TEXT,
|
|
12
|
+
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
13
|
+
"version" INTEGER NOT NULL DEFAULT 0,
|
|
14
|
+
"updatedAt" DATETIME NOT NULL,
|
|
15
|
+
CONSTRAINT "MemoryEvent_memoryId_fkey" FOREIGN KEY ("memoryId") REFERENCES "ProjectMemory" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
|
16
|
+
);
|
|
17
|
+
-- ADR-0180 · baris lama tak punya updatedAt: isi dengan createdAt (event append-only, tak pernah berubah).
|
|
18
|
+
INSERT INTO "new_MemoryEvent" ("actorId", "actorKind", "createdAt", "id", "memoryId", "op", "reason", "updatedAt") SELECT "actorId", "actorKind", "createdAt", "id", "memoryId", "op", "reason", "createdAt" FROM "MemoryEvent";
|
|
19
|
+
DROP TABLE "MemoryEvent";
|
|
20
|
+
ALTER TABLE "new_MemoryEvent" RENAME TO "MemoryEvent";
|
|
21
|
+
CREATE INDEX "MemoryEvent_memoryId_createdAt_idx" ON "MemoryEvent"("memoryId", "createdAt");
|
|
22
|
+
CREATE TABLE "new_SyncState" (
|
|
23
|
+
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT DEFAULT 1,
|
|
24
|
+
"cursor" TEXT NOT NULL DEFAULT '0',
|
|
25
|
+
"entities" TEXT NOT NULL DEFAULT ''
|
|
26
|
+
);
|
|
27
|
+
INSERT INTO "new_SyncState" ("cursor", "id") SELECT "cursor", "id" FROM "SyncState";
|
|
28
|
+
DROP TABLE "SyncState";
|
|
29
|
+
ALTER TABLE "new_SyncState" RENAME TO "SyncState";
|
|
30
|
+
PRAGMA foreign_keys=ON;
|
|
31
|
+
PRAGMA defer_foreign_keys=OFF;
|
|
32
|
+
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
-- ADR-0182: user requested removal of these features AND their stored data.
|
|
2
|
+
-- Purge sync payloads/outboxes first so retired records cannot be replayed.
|
|
3
|
+
DELETE FROM "SyncLog" WHERE "entity" IN ('projectMemory', 'memoryEvent');
|
|
4
|
+
DELETE FROM "SyncOutbox" WHERE "entity" IN ('projectMemory', 'memoryEvent');
|
|
5
|
+
DELETE FROM "SyncConflict" WHERE "entity" IN ('projectMemory', 'memoryEvent');
|
|
6
|
+
DELETE FROM "SyncTombstone" WHERE "entity" IN ('projectMemory', 'memoryEvent');
|
|
7
|
+
UPDATE "SyncState" SET "entities" = trim(replace(replace(',' || "entities" || ',', ',projectMemory,', ','), ',memoryEvent,', ','), ',');
|
|
8
|
+
DELETE FROM "Notification" WHERE "type" = 'memory';
|
|
9
|
+
UPDATE "Setting" SET "data" = json_remove("data", '$.changelog') WHERE json_type("data", '$.changelog') IS NOT NULL;
|
|
10
|
+
UPDATE "AgentToken" SET "capabilities" = (
|
|
11
|
+
SELECT json_group_array(value) FROM json_each("AgentToken"."capabilities")
|
|
12
|
+
WHERE value NOT IN ('memory:read', 'memory:write')
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
DROP TABLE "MemoryEvent";
|
|
16
|
+
DROP TABLE "MemoryLocalState";
|
|
17
|
+
DROP TABLE "ProjectMemory";
|
|
18
|
+
DROP TABLE "Changelog";
|
|
19
|
+
|
|
20
|
+
PRAGMA defer_foreign_keys=ON;
|
|
21
|
+
PRAGMA foreign_keys=OFF;
|
|
22
|
+
CREATE TABLE "new_AgentToken" (
|
|
23
|
+
"id" TEXT NOT NULL PRIMARY KEY,
|
|
24
|
+
"name" TEXT NOT NULL,
|
|
25
|
+
"tokenHash" TEXT NOT NULL,
|
|
26
|
+
"tokenPrefix" TEXT NOT NULL,
|
|
27
|
+
"capabilities" JSONB NOT NULL,
|
|
28
|
+
"enabled" BOOLEAN NOT NULL DEFAULT true,
|
|
29
|
+
"createdBy" TEXT,
|
|
30
|
+
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
31
|
+
"lastUsedAt" DATETIME,
|
|
32
|
+
"revokedAt" DATETIME
|
|
33
|
+
);
|
|
34
|
+
INSERT INTO "new_AgentToken" ("capabilities", "createdAt", "createdBy", "enabled", "id", "lastUsedAt", "name", "revokedAt", "tokenHash", "tokenPrefix") SELECT "capabilities", "createdAt", "createdBy", "enabled", "id", "lastUsedAt", "name", "revokedAt", "tokenHash", "tokenPrefix" FROM "AgentToken";
|
|
35
|
+
DROP TABLE "AgentToken";
|
|
36
|
+
ALTER TABLE "new_AgentToken" RENAME TO "AgentToken";
|
|
37
|
+
CREATE UNIQUE INDEX "AgentToken_tokenHash_key" ON "AgentToken"("tokenHash");
|
|
38
|
+
PRAGMA foreign_keys=ON;
|
|
39
|
+
PRAGMA defer_foreign_keys=OFF;
|
|
40
|
+
|
package/prisma/schema.prisma
CHANGED
|
@@ -32,7 +32,6 @@ model Project {
|
|
|
32
32
|
tickets Ticket[]
|
|
33
33
|
customAgents CustomAgent[] // SPEC-450 · ADR-0094 · custom agent milik project ini
|
|
34
34
|
githubIssues GithubIssue[] // SPEC-471 · ADR-0095 · cermin issue repo GitHub project ini
|
|
35
|
-
changelogs Changelog[] // SPEC-516 · ADR-0105 · changelog tersimpan project ini
|
|
36
35
|
clientAccess ClientProjectAccess[] // SPEC-617 · ADR-0110 · akun klien yang boleh melihat project ini
|
|
37
36
|
portalChats PortalChatSession[] // SPEC-854 · ADR-0129 · percakapan portal klien project ini
|
|
38
37
|
tasks Task[] // SPEC-945 · ADR-0150 · kartu kerja manusia di project ini
|
|
@@ -105,7 +104,7 @@ model Spec {
|
|
|
105
104
|
// `storageKey` opaque, `filename` nama asli tersanitasi untuk tampilan saja.
|
|
106
105
|
//
|
|
107
106
|
// LOCAL-only: TANPA `version`, jadi ia tak pernah masuk changefeed sync (cermin LeadFlow,
|
|
108
|
-
// WebhookEndpoint
|
|
107
|
+
// WebhookEndpoint). Byte memang tak menyeberang (ADR-0062), dan metadata yang menyeberang
|
|
109
108
|
// TANPA byte-nya hanya menghasilkan lampiran yang tak bisa dibuka di mesin lain — keadaan terburuk
|
|
110
109
|
// dari ketiga pilihan. Sengaja BUKAN TicketAttachment: tiket dan backlog dua domain dengan aturan
|
|
111
110
|
// sync dan tingkat kepercayaan yang berbeda (ADR-0124 §1/§4).
|
|
@@ -123,29 +122,6 @@ model SpecAttachment {
|
|
|
123
122
|
@@index([specId])
|
|
124
123
|
}
|
|
125
124
|
|
|
126
|
-
// SPEC-516 · ADR-0105 · changelog naratif per project yang sudah dibangkitkan.
|
|
127
|
-
//
|
|
128
|
-
// LOCAL-only: TANPA kolom `version`, jadi ia tak pernah masuk changefeed sync (cermin LeadFlow,
|
|
129
|
-
// WebhookEndpoint, dan Project.autoMerge). Dua dari tiga modenya diturunkan dari checkout git di
|
|
130
|
-
// MESIN INI, jadi barisnya fakta lokal; yang portabel adalah keluarannya, dan jalannya sudah ada
|
|
131
|
-
// — unduh .md.
|
|
132
|
-
model Changelog {
|
|
133
|
-
id String @id @default(cuid())
|
|
134
|
-
projectId String
|
|
135
|
-
mode String // "backlog" | "commit" | "version" (zChangelogMode di @hanoman/shared)
|
|
136
|
-
title String // judul di daftar: rentang tanggal / nama tag / rentang tag
|
|
137
|
-
params Json // parameter pembangkitan apa adanya (zChangelogRequest)
|
|
138
|
-
body String // markdown hasil akhir, sudah lewat scrubOutput
|
|
139
|
-
generator String // "agent" | "fallback"
|
|
140
|
-
warning String? // alasan fallback + catatan cakupan; null = mulus
|
|
141
|
-
itemCount Int @default(0)
|
|
142
|
-
createdAt DateTime @default(now())
|
|
143
|
-
updatedAt DateTime @updatedAt
|
|
144
|
-
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
|
145
|
-
|
|
146
|
-
@@index([projectId, createdAt])
|
|
147
|
-
}
|
|
148
|
-
|
|
149
125
|
// SPEC-450 · ADR-0094 · custom agent: persona yang bisa dipilih ulang & dibagi.
|
|
150
126
|
// `projectId` null = GLOBAL (semua project); terisi = milik satu project, dan agen project
|
|
151
127
|
// MENIMPA agen global bernama sama.
|
|
@@ -584,6 +560,8 @@ model SyncOutbox {
|
|
|
584
560
|
model SyncState {
|
|
585
561
|
id Int @id @default(1)
|
|
586
562
|
cursor String @default("0")
|
|
563
|
+
// ADR-0180 · LOCAL-only: entitas sync OPSIONAL yang sudah di-catch-up mesin ini (dipisah koma).
|
|
564
|
+
entities String @default("")
|
|
587
565
|
}
|
|
588
566
|
|
|
589
567
|
// SPEC-270 · ADR-0067 · LOCAL-ONLY: antrean konflik dua-sisi menunggu keputusan manusia (modal).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{i as ie,j as e,b as re,I as E}from"./index-DHVdBKua.js";import{R as g}from"./react-DfGhg7ZW.js";import"./markdown-CWEY34jk.js";import"./xterm-3VOAfa_q.js";const de="/assets/hnm-hero-rig-body-v01-DmbKJJHB.webp",ce="/assets/hnm-hero-rig-arm-ul-v01-CIAWAxFe.webp",he="/assets/hnm-hero-rig-arm-ur-v01-C0R0CZnp.webp",oe="/assets/hnm-hero-rig-arm-ml-v01-Kts3pjTf.webp",ge="/assets/hnm-hero-rig-arm-mr-v01-DQgnE6bD.webp",me="/assets/hnm-wayang-satria-alus-v01-CpfoXKTy.webp",ue="/assets/hnm-wayang-satria-gagah-v01-bLfIYAsv.webp",pe="/assets/hnm-wayang-putri-v01-F6p69kHq.webp",xe="/assets/hnm-wayang-panakawan-v01-1LGv-V8N.webp",q=[me,ue,pe,xe],z=a=>q[[...a].reduce((t,o)=>t+o.charCodeAt(0),0)%q.length],V=["Jan","Feb","Mar","Apr","Mei","Jun","Jul","Agu","Sep","Okt","Nov","Des"],C=a=>String(a).padStart(2,"0");function je(){return g.useMemo(()=>typeof window<"u"&&!!window.matchMedia&&window.matchMedia("(prefers-reduced-motion: reduce)").matches,[])}function Ne(){const[a,t]=g.useState(()=>new Date);return g.useEffect(()=>{const o=setInterval(()=>t(new Date),1e3);return()=>clearInterval(o)},[]),a}function ye(a,t){const[o,m]=g.useState(""),p=a.join("|");return g.useEffect(()=>{if(t||a.length===0){m(a[0]??"");return}let x=0,h=0,r=null,d=null;const l=()=>{const y=a[x%a.length]??"";h=0,r=setInterval(()=>{h++,m(y.slice(0,h)),h>=y.length&&r&&(clearInterval(r),r=null,d=setTimeout(()=>{x++,l()},3200))},26)};return l(),()=>{r&&clearInterval(r),d&&clearTimeout(d)}},[p,t]),o}function S(a,t){const[o,m]=g.useState(t?a:0);return g.useEffect(()=>{if(t){m(a);return}const p=performance.now(),x=900;let h=0;const r=d=>{const l=Math.min(1,(d-p)/x);m(Math.round(a*(1-Math.pow(1-l,3)))),l<1&&(h=requestAnimationFrame(r))};return h=requestAnimationFrame(r),()=>cancelAnimationFrame(h)},[a,t]),o}function M({icon:a,tone:t,label:o,value:m,sub:p}){return e.jsxs("div",{className:"hn-dlg-kpi",children:[e.jsx("span",{className:`hn-dlg-kpi-ic hn-dlg-tone-${t}`,children:e.jsx(E,{name:a,size:17})}),e.jsxs("span",{style:{minWidth:0},children:[e.jsx("span",{className:"hn-dlg-kpi-l",children:o}),e.jsx("span",{className:"hn-dlg-kpi-v",children:m}),e.jsx("span",{className:"hn-dlg-kpi-s",children:p})]})]})}function ke({projects:a,backlog:t,sessions:o,onOpenSession:m,onOpenProject:p,onGoto:x,onExit:h}){const r=je(),d=Ne();g.useEffect(()=>{const n=s=>{s.key==="Escape"&&h()};return window.addEventListener("keydown",n),()=>window.removeEventListener("keydown",n)},[h]);const l=o.filter(n=>!n.exited).sort((n,s)=>n.id.localeCompare(s.id)),y=new Set(l.map(n=>n.projectId)),f=a.filter(n=>!y.has(n.id)),R=l.filter(n=>!!n.decision&&!n.deciding).length,F=t.filter(n=>ie(n.startedAt)).length,Q=S(a.length,r),X=S(F,r),Z=S(l.length,r),_=S(R,r),ee=ye([l.length>0?`HANOMAN ONLINE · ${l.length} SESI HIDUP`:"HANOMAN ONLINE · KELIR SUNYI",`${F} TASK DIKERJAKAN HARI INI`,R>0?`${R} SESI MENUNGGU JAWABANMU`:"SEMUA SISTEM NORMAL",`${a.length} PROYEK DALAM PANTAUAN`],r),j={done:0,executing:0,planned:0,spec:0};for(const n of t)n.stage==="done"?j.done++:n.stage==="executing"?j.executing++:n.stage==="planned"?j.planned++:j.spec++;const D=t.length,ne=[{key:"executing",cls:"wind",label:"Execute"},{key:"done",cls:"leaf",label:"Done"},{key:"planned",cls:"amber",label:"Plan"},{key:"spec",cls:"brass",label:"Spec"}];let L=0;const O=ne.map(n=>{const s=D?j[n.key]/D*100:0,u={...n,n:j[n.key],frac:s,offset:25-L};return L+=s,u}),v=[];for(let n=6;n>=0;n--){const s=new Date(d.getFullYear(),d.getMonth(),d.getDate()-n),u=t.filter(i=>{if(!i.startedAt)return!1;const c=new Date(i.startedAt);return c.getFullYear()===s.getFullYear()&&c.getMonth()===s.getMonth()&&c.getDate()===s.getDate()}).length;v.push({label:`${s.getDate()} ${V[s.getMonth()]}`,n:u})}const $=Math.max(1,...v.map(n=>n.n)),se=v.map((n,s)=>`${32+s*35},${78-n.n/$*60}`).join(" "),ae=`${l.map(n=>n.id).join("|")}#${f.map(n=>n.id).join("|")}`,H=g.useRef(null),[P,W]=g.useState([]);g.useLayoutEffect(()=>{const n=H.current;if(!n||l.length===0&&f.length===0){W([]);return}const s=()=>{var J;const i=n.getBoundingClientRect();if(i.width<60)return;const c=(J=n.querySelector(".hn-dlg-hero-art"))==null?void 0:J.getBoundingClientRect(),b=c?c.left+c.width/2-i.left:i.width/2,w={};n.querySelectorAll("[data-hand]").forEach(N=>{const A=N.getBoundingClientRect();w[N.dataset.hand??""]={x:A.left+A.width/2-i.left,y:A.top+A.height/2-i.top}});const k={x:b,y:c?c.top-i.top+c.height*.36:i.height*.35},G=[];n.querySelectorAll(".hn-dlg-prj").forEach(N=>{const U=(N.querySelector(".hn-dlg-puppet img")??N).getBoundingClientRect(),T=U.left+U.width/2-i.left,K=U.top-i.top+1,B=!N.hasAttribute("data-puppet"),te=T<b?"l":"r",I=w[(B?"m":"u")+te]??k,le=B?Math.max(I.y,K)+26:Math.min(I.y,K)-16;G.push({d:`M ${I.x.toFixed(1)} ${I.y.toFixed(1)} Q ${((I.x+T)/2).toFixed(1)} ${le.toFixed(1)}, ${T.toFixed(1)} ${K.toFixed(1)}`,slack:B})}),W(G)};if(s(),typeof ResizeObserver>"u")return;const u=new ResizeObserver(s);return u.observe(n),()=>u.disconnect()},[ae,l.length,f.length]);const Y=a.slice(0,6).map(n=>({id:n.id,name:n.name,text:n.activity,commit:n.commit,live:y.has(n.id)}));return e.jsxs("div",{className:"hn-dlg",children:[e.jsxs("div",{className:"hn-dlg-top hn-wrap-mobile",children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:12,minWidth:0},children:[e.jsx("img",{className:"hn-dlg-blencong",src:re,alt:"","aria-hidden":"true","data-lit":l.length>0||void 0}),e.jsxs("div",{style:{minWidth:0},children:[e.jsx("h2",{className:"hn-dlg-title",children:"Dalang Hanoman"}),e.jsx("p",{className:"hn-dlg-boot","aria-live":"off",children:ee})]})]}),e.jsxs("div",{className:"hn-dlg-chips",children:[e.jsxs("span",{className:"hn-dlg-chip",children:[e.jsx(E,{name:"calendar",size:13}),d.getDate()," ",V[d.getMonth()]," ",d.getFullYear()]}),e.jsxs("span",{className:"hn-dlg-chip",children:[e.jsx(E,{name:"clock",size:13}),C(d.getHours()),":",C(d.getMinutes()),":",C(d.getSeconds())]}),e.jsx("button",{type:"button",className:"hn-dlg-exit",onClick:h,"aria-label":"Keluar dari panggung (Esc)",children:e.jsx(E,{name:"x",size:14})})]})]}),e.jsxs("div",{className:"hn-dlg-kpis",children:[e.jsx(M,{icon:"layout-grid",tone:"wind",label:"TOTAL PROYEK",value:Q,sub:"dalam pantauan"}),e.jsx(M,{icon:"check-circle-2",tone:"leaf",label:"TASK HARI INI",value:X,sub:"mulai dikerjakan"}),e.jsx(M,{icon:"activity",tone:"brass",label:"SESI BERJALAN",value:Z,sub:"wayang dimainkan"}),e.jsx(M,{icon:"hand",tone:"amber",label:"MENUNGGU KAMU",value:_,sub:"butuh keputusan"})]}),e.jsxs("div",{className:"hn-dlg-grid hn-grid-mobile",children:[e.jsxs("div",{style:{minWidth:0},children:[e.jsxs("div",{className:"hn-dlg-hero",ref:H,children:[e.jsxs("svg",{className:"hn-dlg-hud",viewBox:"0 0 330 330","aria-hidden":"true",children:[e.jsx("g",{className:"hn-dlg-hud-a",children:e.jsx("circle",{cx:"165",cy:"165",r:"150",strokeDasharray:"3 14"})}),e.jsx("g",{className:"hn-dlg-hud-b",children:e.jsx("circle",{cx:"165",cy:"165",r:"126",strokeDasharray:"40 22"})})]}),P.length>0&&e.jsx("svg",{className:"hn-dlg-threads","aria-hidden":"true",focusable:"false",children:P.map((n,s)=>e.jsx("path",{d:n.d,className:n.slack?"hn-dlg-thread--slack":void 0,style:n.slack?void 0:{animationDelay:`${s%6*.3}s`}},s))}),e.jsx("div",{className:"hn-dlg-scan","aria-hidden":"true"}),e.jsxs("div",{className:"hn-dlg-hero-art","aria-hidden":"true",children:[e.jsx("img",{className:"hn-dlg-rig-arm hn-dlg-rig-arm--ul",src:ce,alt:""}),e.jsx("img",{className:"hn-dlg-rig-arm hn-dlg-rig-arm--ur",src:he,alt:""}),e.jsx("img",{className:"hn-dlg-rig-arm hn-dlg-rig-arm--ml",src:oe,alt:""}),e.jsx("img",{className:"hn-dlg-rig-arm hn-dlg-rig-arm--mr",src:ge,alt:""}),e.jsx("img",{className:"hn-dlg-rig-body",src:de,alt:""}),e.jsx("span",{className:"hn-dlg-hand","data-hand":"ul"}),e.jsx("span",{className:"hn-dlg-hand","data-hand":"ur"}),e.jsx("span",{className:"hn-dlg-hand","data-hand":"ml"}),e.jsx("span",{className:"hn-dlg-hand","data-hand":"mr"})]}),l.length>0||f.length>0?e.jsxs("div",{className:"hn-dlg-cards",role:"list","aria-label":"Wayang project",children:[l.map((n,s)=>{var w;const u=((w=a.find(k=>k.id===n.projectId))==null?void 0:w.name)??n.projectId,i=n.specId?t.find(k=>k.id===n.specId):void 0,c=!!n.decision&&!n.deciding,b=c?"menunggu jawabanmu":i?`${i.id} · ${i.stage}`:n.flow??"sesi terminal";return e.jsxs("button",{type:"button",className:"hn-dlg-prj","data-puppet":!0,"data-waiting":c||void 0,onClick:()=>m(n.id),"aria-label":`Buka terminal — ${u}, ${b}`,children:[e.jsx("span",{className:c?"hn-dlg-puppet hn-dlg-puppet--still":"hn-dlg-puppet",style:{animationDelay:`${s%6*.6}s`},children:e.jsx("img",{src:z(n.projectId),alt:"","aria-hidden":"true"})}),e.jsx("span",{className:"hn-dlg-prj-name",children:u}),e.jsx("span",{className:c?"hn-dlg-prj-sub hn-dlg-prj-sub--amber":"hn-dlg-prj-sub",children:b})]},n.id)}),f.map(n=>e.jsxs("button",{type:"button",className:"hn-dlg-prj hn-dlg-prj--off",onClick:()=>p(n),"aria-label":`Buka project ${n.name}`,children:[e.jsx("span",{className:"hn-dlg-puppet hn-dlg-puppet--still",children:e.jsx("img",{src:z(n.id),alt:"","aria-hidden":"true"})}),e.jsx("span",{className:"hn-dlg-prj-name",children:n.name}),e.jsx("span",{className:"hn-dlg-prj-sub hn-dlg-prj-sub--off",children:"tersandar di debog"})]},n.id))]}):e.jsxs("div",{className:"hn-dlg-empty",children:[e.jsx("div",{children:"Panggung sunyi — belum ada project di workspace."}),e.jsx("div",{children:"Tambahkan project dan sang dalang mengangkat wayangnya."})]})]}),e.jsxs("button",{type:"button",className:"hn-dlg-cmd",onClick:()=>x("terminal"),"aria-label":"Buka terminal — pusat kendali sesi",children:[e.jsx("span",{className:"hn-dlg-mic","aria-hidden":"true"}),e.jsxs("span",{className:"hn-dlg-cmd-t",children:[e.jsx("b",{children:"Perintah dalang"})," — buka Terminal untuk mengarahkan sesi yang berjalan…"]}),e.jsx("span",{className:"hn-dlg-cmd-k",children:"Terminal"})]})]}),e.jsxs("aside",{className:"hn-dlg-rail",children:[e.jsxs("div",{className:"hn-dlg-card",children:[e.jsx("div",{className:"hn-dlg-rt",children:"AKTIVITAS TERAKHIR"}),Y.length===0?e.jsx("div",{className:"hn-dlg-mut",children:"Belum ada project."}):Y.map(n=>e.jsxs("div",{className:"hn-dlg-act",children:[e.jsx("span",{className:n.live?"hn-dlg-dot hn-dlg-dot--on":"hn-dlg-dot"}),e.jsxs("span",{className:"hn-dlg-act-x",children:[e.jsx("b",{children:n.name})," ",n.text]})]},n.id))]}),e.jsxs("div",{className:"hn-dlg-card",children:[e.jsx("div",{className:"hn-dlg-rt",children:"DISTRIBUSI BACKLOG"}),e.jsxs("div",{className:"hn-dlg-donut-wrap",children:[e.jsxs("div",{className:"hn-dlg-donut",children:[e.jsxs("svg",{viewBox:"0 0 42 42",width:"112",height:"112","aria-hidden":"true",children:[e.jsx("circle",{className:"hn-dlg-ring",cx:"21",cy:"21",r:"15.9",strokeWidth:"5"}),O.map(n=>n.frac>0&&e.jsx("circle",{className:`hn-dlg-seg hn-dlg-seg--${n.cls}`,cx:"21",cy:"21",r:"15.9",strokeWidth:"5",strokeDasharray:`${n.frac} ${100-n.frac}`,strokeDashoffset:n.offset},n.key))]}),e.jsxs("div",{className:"hn-dlg-donut-c",children:[e.jsx("b",{children:D}),e.jsx("span",{children:"backlog"})]})]}),e.jsx("div",{className:"hn-dlg-leg",children:O.map(n=>e.jsxs("span",{children:[e.jsx("i",{className:`hn-dlg-seg--${n.cls}`}),n.label," ",e.jsx("b",{children:n.n})]},n.key))})]})]}),e.jsxs("div",{className:"hn-dlg-card",children:[e.jsx("div",{className:"hn-dlg-rt",children:"DIMULAI · 7 HARI"}),e.jsxs("svg",{viewBox:"0 0 260 100",className:"hn-dlg-chart","aria-hidden":"true",children:[e.jsx("line",{x1:"24",y1:"18",x2:"252",y2:"18"}),e.jsx("line",{x1:"24",y1:"48",x2:"252",y2:"48"}),e.jsx("line",{x1:"24",y1:"78",x2:"252",y2:"78"}),e.jsx("text",{x:"8",y:"21",children:$}),e.jsx("text",{x:"10",y:"81",children:"0"}),e.jsx("polyline",{className:"hn-dlg-trend",points:se}),v.map((n,s)=>e.jsx("circle",{cx:32+s*35,cy:78-n.n/$*60,r:"2.4"},s)),v.map((n,s)=>s%2===0?e.jsx("text",{x:22+s*35,y:"94",children:n.label},`l${s}`):null)]})]})]})]}),e.jsx("div",{className:"hn-dlg-foot",children:"◈ HANOMAN · ORKESTRASI CERDAS · EKSEKUSI SEMPURNA ◈"})]})}export{ke as DalangHanomanScreen};
|
|
1
|
+
import{i as ie,j as e,b as re,I as E}from"./index-D5w059cP.js";import{R as g}from"./react-DfGhg7ZW.js";import"./markdown-CWEY34jk.js";import"./xterm-3VOAfa_q.js";const de="/assets/hnm-hero-rig-body-v01-DmbKJJHB.webp",ce="/assets/hnm-hero-rig-arm-ul-v01-CIAWAxFe.webp",he="/assets/hnm-hero-rig-arm-ur-v01-C0R0CZnp.webp",oe="/assets/hnm-hero-rig-arm-ml-v01-Kts3pjTf.webp",ge="/assets/hnm-hero-rig-arm-mr-v01-DQgnE6bD.webp",me="/assets/hnm-wayang-satria-alus-v01-CpfoXKTy.webp",ue="/assets/hnm-wayang-satria-gagah-v01-bLfIYAsv.webp",pe="/assets/hnm-wayang-putri-v01-F6p69kHq.webp",xe="/assets/hnm-wayang-panakawan-v01-1LGv-V8N.webp",q=[me,ue,pe,xe],z=a=>q[[...a].reduce((t,o)=>t+o.charCodeAt(0),0)%q.length],V=["Jan","Feb","Mar","Apr","Mei","Jun","Jul","Agu","Sep","Okt","Nov","Des"],C=a=>String(a).padStart(2,"0");function je(){return g.useMemo(()=>typeof window<"u"&&!!window.matchMedia&&window.matchMedia("(prefers-reduced-motion: reduce)").matches,[])}function Ne(){const[a,t]=g.useState(()=>new Date);return g.useEffect(()=>{const o=setInterval(()=>t(new Date),1e3);return()=>clearInterval(o)},[]),a}function ye(a,t){const[o,m]=g.useState(""),p=a.join("|");return g.useEffect(()=>{if(t||a.length===0){m(a[0]??"");return}let x=0,h=0,r=null,d=null;const l=()=>{const y=a[x%a.length]??"";h=0,r=setInterval(()=>{h++,m(y.slice(0,h)),h>=y.length&&r&&(clearInterval(r),r=null,d=setTimeout(()=>{x++,l()},3200))},26)};return l(),()=>{r&&clearInterval(r),d&&clearTimeout(d)}},[p,t]),o}function S(a,t){const[o,m]=g.useState(t?a:0);return g.useEffect(()=>{if(t){m(a);return}const p=performance.now(),x=900;let h=0;const r=d=>{const l=Math.min(1,(d-p)/x);m(Math.round(a*(1-Math.pow(1-l,3)))),l<1&&(h=requestAnimationFrame(r))};return h=requestAnimationFrame(r),()=>cancelAnimationFrame(h)},[a,t]),o}function M({icon:a,tone:t,label:o,value:m,sub:p}){return e.jsxs("div",{className:"hn-dlg-kpi",children:[e.jsx("span",{className:`hn-dlg-kpi-ic hn-dlg-tone-${t}`,children:e.jsx(E,{name:a,size:17})}),e.jsxs("span",{style:{minWidth:0},children:[e.jsx("span",{className:"hn-dlg-kpi-l",children:o}),e.jsx("span",{className:"hn-dlg-kpi-v",children:m}),e.jsx("span",{className:"hn-dlg-kpi-s",children:p})]})]})}function ke({projects:a,backlog:t,sessions:o,onOpenSession:m,onOpenProject:p,onGoto:x,onExit:h}){const r=je(),d=Ne();g.useEffect(()=>{const n=s=>{s.key==="Escape"&&h()};return window.addEventListener("keydown",n),()=>window.removeEventListener("keydown",n)},[h]);const l=o.filter(n=>!n.exited).sort((n,s)=>n.id.localeCompare(s.id)),y=new Set(l.map(n=>n.projectId)),f=a.filter(n=>!y.has(n.id)),R=l.filter(n=>!!n.decision&&!n.deciding).length,F=t.filter(n=>ie(n.startedAt)).length,Q=S(a.length,r),X=S(F,r),Z=S(l.length,r),_=S(R,r),ee=ye([l.length>0?`HANOMAN ONLINE · ${l.length} SESI HIDUP`:"HANOMAN ONLINE · KELIR SUNYI",`${F} TASK DIKERJAKAN HARI INI`,R>0?`${R} SESI MENUNGGU JAWABANMU`:"SEMUA SISTEM NORMAL",`${a.length} PROYEK DALAM PANTAUAN`],r),j={done:0,executing:0,planned:0,spec:0};for(const n of t)n.stage==="done"?j.done++:n.stage==="executing"?j.executing++:n.stage==="planned"?j.planned++:j.spec++;const D=t.length,ne=[{key:"executing",cls:"wind",label:"Execute"},{key:"done",cls:"leaf",label:"Done"},{key:"planned",cls:"amber",label:"Plan"},{key:"spec",cls:"brass",label:"Spec"}];let L=0;const O=ne.map(n=>{const s=D?j[n.key]/D*100:0,u={...n,n:j[n.key],frac:s,offset:25-L};return L+=s,u}),v=[];for(let n=6;n>=0;n--){const s=new Date(d.getFullYear(),d.getMonth(),d.getDate()-n),u=t.filter(i=>{if(!i.startedAt)return!1;const c=new Date(i.startedAt);return c.getFullYear()===s.getFullYear()&&c.getMonth()===s.getMonth()&&c.getDate()===s.getDate()}).length;v.push({label:`${s.getDate()} ${V[s.getMonth()]}`,n:u})}const $=Math.max(1,...v.map(n=>n.n)),se=v.map((n,s)=>`${32+s*35},${78-n.n/$*60}`).join(" "),ae=`${l.map(n=>n.id).join("|")}#${f.map(n=>n.id).join("|")}`,H=g.useRef(null),[P,W]=g.useState([]);g.useLayoutEffect(()=>{const n=H.current;if(!n||l.length===0&&f.length===0){W([]);return}const s=()=>{var J;const i=n.getBoundingClientRect();if(i.width<60)return;const c=(J=n.querySelector(".hn-dlg-hero-art"))==null?void 0:J.getBoundingClientRect(),b=c?c.left+c.width/2-i.left:i.width/2,w={};n.querySelectorAll("[data-hand]").forEach(N=>{const A=N.getBoundingClientRect();w[N.dataset.hand??""]={x:A.left+A.width/2-i.left,y:A.top+A.height/2-i.top}});const k={x:b,y:c?c.top-i.top+c.height*.36:i.height*.35},G=[];n.querySelectorAll(".hn-dlg-prj").forEach(N=>{const U=(N.querySelector(".hn-dlg-puppet img")??N).getBoundingClientRect(),T=U.left+U.width/2-i.left,K=U.top-i.top+1,B=!N.hasAttribute("data-puppet"),te=T<b?"l":"r",I=w[(B?"m":"u")+te]??k,le=B?Math.max(I.y,K)+26:Math.min(I.y,K)-16;G.push({d:`M ${I.x.toFixed(1)} ${I.y.toFixed(1)} Q ${((I.x+T)/2).toFixed(1)} ${le.toFixed(1)}, ${T.toFixed(1)} ${K.toFixed(1)}`,slack:B})}),W(G)};if(s(),typeof ResizeObserver>"u")return;const u=new ResizeObserver(s);return u.observe(n),()=>u.disconnect()},[ae,l.length,f.length]);const Y=a.slice(0,6).map(n=>({id:n.id,name:n.name,text:n.activity,commit:n.commit,live:y.has(n.id)}));return e.jsxs("div",{className:"hn-dlg",children:[e.jsxs("div",{className:"hn-dlg-top hn-wrap-mobile",children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:12,minWidth:0},children:[e.jsx("img",{className:"hn-dlg-blencong",src:re,alt:"","aria-hidden":"true","data-lit":l.length>0||void 0}),e.jsxs("div",{style:{minWidth:0},children:[e.jsx("h2",{className:"hn-dlg-title",children:"Dalang Hanoman"}),e.jsx("p",{className:"hn-dlg-boot","aria-live":"off",children:ee})]})]}),e.jsxs("div",{className:"hn-dlg-chips",children:[e.jsxs("span",{className:"hn-dlg-chip",children:[e.jsx(E,{name:"calendar",size:13}),d.getDate()," ",V[d.getMonth()]," ",d.getFullYear()]}),e.jsxs("span",{className:"hn-dlg-chip",children:[e.jsx(E,{name:"clock",size:13}),C(d.getHours()),":",C(d.getMinutes()),":",C(d.getSeconds())]}),e.jsx("button",{type:"button",className:"hn-dlg-exit",onClick:h,"aria-label":"Keluar dari panggung (Esc)",children:e.jsx(E,{name:"x",size:14})})]})]}),e.jsxs("div",{className:"hn-dlg-kpis",children:[e.jsx(M,{icon:"layout-grid",tone:"wind",label:"TOTAL PROYEK",value:Q,sub:"dalam pantauan"}),e.jsx(M,{icon:"check-circle-2",tone:"leaf",label:"TASK HARI INI",value:X,sub:"mulai dikerjakan"}),e.jsx(M,{icon:"activity",tone:"brass",label:"SESI BERJALAN",value:Z,sub:"wayang dimainkan"}),e.jsx(M,{icon:"hand",tone:"amber",label:"MENUNGGU KAMU",value:_,sub:"butuh keputusan"})]}),e.jsxs("div",{className:"hn-dlg-grid hn-grid-mobile",children:[e.jsxs("div",{style:{minWidth:0},children:[e.jsxs("div",{className:"hn-dlg-hero",ref:H,children:[e.jsxs("svg",{className:"hn-dlg-hud",viewBox:"0 0 330 330","aria-hidden":"true",children:[e.jsx("g",{className:"hn-dlg-hud-a",children:e.jsx("circle",{cx:"165",cy:"165",r:"150",strokeDasharray:"3 14"})}),e.jsx("g",{className:"hn-dlg-hud-b",children:e.jsx("circle",{cx:"165",cy:"165",r:"126",strokeDasharray:"40 22"})})]}),P.length>0&&e.jsx("svg",{className:"hn-dlg-threads","aria-hidden":"true",focusable:"false",children:P.map((n,s)=>e.jsx("path",{d:n.d,className:n.slack?"hn-dlg-thread--slack":void 0,style:n.slack?void 0:{animationDelay:`${s%6*.3}s`}},s))}),e.jsx("div",{className:"hn-dlg-scan","aria-hidden":"true"}),e.jsxs("div",{className:"hn-dlg-hero-art","aria-hidden":"true",children:[e.jsx("img",{className:"hn-dlg-rig-arm hn-dlg-rig-arm--ul",src:ce,alt:""}),e.jsx("img",{className:"hn-dlg-rig-arm hn-dlg-rig-arm--ur",src:he,alt:""}),e.jsx("img",{className:"hn-dlg-rig-arm hn-dlg-rig-arm--ml",src:oe,alt:""}),e.jsx("img",{className:"hn-dlg-rig-arm hn-dlg-rig-arm--mr",src:ge,alt:""}),e.jsx("img",{className:"hn-dlg-rig-body",src:de,alt:""}),e.jsx("span",{className:"hn-dlg-hand","data-hand":"ul"}),e.jsx("span",{className:"hn-dlg-hand","data-hand":"ur"}),e.jsx("span",{className:"hn-dlg-hand","data-hand":"ml"}),e.jsx("span",{className:"hn-dlg-hand","data-hand":"mr"})]}),l.length>0||f.length>0?e.jsxs("div",{className:"hn-dlg-cards",role:"list","aria-label":"Wayang project",children:[l.map((n,s)=>{var w;const u=((w=a.find(k=>k.id===n.projectId))==null?void 0:w.name)??n.projectId,i=n.specId?t.find(k=>k.id===n.specId):void 0,c=!!n.decision&&!n.deciding,b=c?"menunggu jawabanmu":i?`${i.id} · ${i.stage}`:n.flow??"sesi terminal";return e.jsxs("button",{type:"button",className:"hn-dlg-prj","data-puppet":!0,"data-waiting":c||void 0,onClick:()=>m(n.id),"aria-label":`Buka terminal — ${u}, ${b}`,children:[e.jsx("span",{className:c?"hn-dlg-puppet hn-dlg-puppet--still":"hn-dlg-puppet",style:{animationDelay:`${s%6*.6}s`},children:e.jsx("img",{src:z(n.projectId),alt:"","aria-hidden":"true"})}),e.jsx("span",{className:"hn-dlg-prj-name",children:u}),e.jsx("span",{className:c?"hn-dlg-prj-sub hn-dlg-prj-sub--amber":"hn-dlg-prj-sub",children:b})]},n.id)}),f.map(n=>e.jsxs("button",{type:"button",className:"hn-dlg-prj hn-dlg-prj--off",onClick:()=>p(n),"aria-label":`Buka project ${n.name}`,children:[e.jsx("span",{className:"hn-dlg-puppet hn-dlg-puppet--still",children:e.jsx("img",{src:z(n.id),alt:"","aria-hidden":"true"})}),e.jsx("span",{className:"hn-dlg-prj-name",children:n.name}),e.jsx("span",{className:"hn-dlg-prj-sub hn-dlg-prj-sub--off",children:"tersandar di debog"})]},n.id))]}):e.jsxs("div",{className:"hn-dlg-empty",children:[e.jsx("div",{children:"Panggung sunyi — belum ada project di workspace."}),e.jsx("div",{children:"Tambahkan project dan sang dalang mengangkat wayangnya."})]})]}),e.jsxs("button",{type:"button",className:"hn-dlg-cmd",onClick:()=>x("terminal"),"aria-label":"Buka terminal — pusat kendali sesi",children:[e.jsx("span",{className:"hn-dlg-mic","aria-hidden":"true"}),e.jsxs("span",{className:"hn-dlg-cmd-t",children:[e.jsx("b",{children:"Perintah dalang"})," — buka Terminal untuk mengarahkan sesi yang berjalan…"]}),e.jsx("span",{className:"hn-dlg-cmd-k",children:"Terminal"})]})]}),e.jsxs("aside",{className:"hn-dlg-rail",children:[e.jsxs("div",{className:"hn-dlg-card",children:[e.jsx("div",{className:"hn-dlg-rt",children:"AKTIVITAS TERAKHIR"}),Y.length===0?e.jsx("div",{className:"hn-dlg-mut",children:"Belum ada project."}):Y.map(n=>e.jsxs("div",{className:"hn-dlg-act",children:[e.jsx("span",{className:n.live?"hn-dlg-dot hn-dlg-dot--on":"hn-dlg-dot"}),e.jsxs("span",{className:"hn-dlg-act-x",children:[e.jsx("b",{children:n.name})," ",n.text]})]},n.id))]}),e.jsxs("div",{className:"hn-dlg-card",children:[e.jsx("div",{className:"hn-dlg-rt",children:"DISTRIBUSI BACKLOG"}),e.jsxs("div",{className:"hn-dlg-donut-wrap",children:[e.jsxs("div",{className:"hn-dlg-donut",children:[e.jsxs("svg",{viewBox:"0 0 42 42",width:"112",height:"112","aria-hidden":"true",children:[e.jsx("circle",{className:"hn-dlg-ring",cx:"21",cy:"21",r:"15.9",strokeWidth:"5"}),O.map(n=>n.frac>0&&e.jsx("circle",{className:`hn-dlg-seg hn-dlg-seg--${n.cls}`,cx:"21",cy:"21",r:"15.9",strokeWidth:"5",strokeDasharray:`${n.frac} ${100-n.frac}`,strokeDashoffset:n.offset},n.key))]}),e.jsxs("div",{className:"hn-dlg-donut-c",children:[e.jsx("b",{children:D}),e.jsx("span",{children:"backlog"})]})]}),e.jsx("div",{className:"hn-dlg-leg",children:O.map(n=>e.jsxs("span",{children:[e.jsx("i",{className:`hn-dlg-seg--${n.cls}`}),n.label," ",e.jsx("b",{children:n.n})]},n.key))})]})]}),e.jsxs("div",{className:"hn-dlg-card",children:[e.jsx("div",{className:"hn-dlg-rt",children:"DIMULAI · 7 HARI"}),e.jsxs("svg",{viewBox:"0 0 260 100",className:"hn-dlg-chart","aria-hidden":"true",children:[e.jsx("line",{x1:"24",y1:"18",x2:"252",y2:"18"}),e.jsx("line",{x1:"24",y1:"48",x2:"252",y2:"48"}),e.jsx("line",{x1:"24",y1:"78",x2:"252",y2:"78"}),e.jsx("text",{x:"8",y:"21",children:$}),e.jsx("text",{x:"10",y:"81",children:"0"}),e.jsx("polyline",{className:"hn-dlg-trend",points:se}),v.map((n,s)=>e.jsx("circle",{cx:32+s*35,cy:78-n.n/$*60,r:"2.4"},s)),v.map((n,s)=>s%2===0?e.jsx("text",{x:22+s*35,y:"94",children:n.label},`l${s}`):null)]})]})]})]}),e.jsx("div",{className:"hn-dlg-foot",children:"◈ HANOMAN · ORKESTRASI CERDAS · EKSEKUSI SEMPURNA ◈"})]})}export{ke as DalangHanomanScreen};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{j as e,M as r,ay as d,aA as a,f as x}from"./index-
|
|
1
|
+
import{j as e,M as r,ay as d,aA as a,f as x}from"./index-D5w059cP.js";import"./react-DfGhg7ZW.js";function m({path:i,text:o,eyebrow:n,download:t,onClose:s}){const l=i.slice(i.lastIndexOf("/")+1)||i;return e.jsx(r,{open:!0,title:l,eyebrow:n??i,icon:"book-open",onClose:s,width:980,fillHeight:!0,children:e.jsxs("div",{style:{display:"flex",flexDirection:"column",height:"100%",minHeight:0},children:[t&&e.jsx("div",{style:{display:"flex",justifyContent:"flex-end",paddingBottom:6,borderBottom:"1px solid var(--border-hair)",marginBottom:8},children:e.jsx(d,{href:t})}),e.jsx("div",{"data-testid":"doc-preview-scroll",style:{flex:"1 1 0",minHeight:0,overflow:"auto",padding:"0 4px 8px"},children:o?e.jsx(a,{text:o,name:i}):e.jsx(x,{kind:"empty",icon:"file-text",title:"Berkas kosong",hint:i})})]})})}export{m as D};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{h as re,u as oe,e as y,j as e,v as le,as as T,ao as de,a as j,f as b,aP as ce,I as k,B as $,ay as xe,aA as A,p as pe,aC as ue}from"./index-
|
|
1
|
+
import{h as re,u as oe,e as y,j as e,v as le,as as T,ao as de,a as j,f as b,aP as ce,I as k,B as $,ay as xe,aA as A,p as pe,aC as ue}from"./index-D5w059cP.js";import{R as l}from"./react-DfGhg7ZW.js";import"./markdown-CWEY34jk.js";import"./xterm-3VOAfa_q.js";function J(s){let a={...s,kids:s.kids.map(J)};for(;!a.cat&&a.kids.length===1;){const i=a.kids[0];a={...i,label:a.label+"/"+i.label}}return a}function G(s){const a={path:"",kids:[]};for(const i of s){if(i.cat==="."){a.kids.push({path:".",label:".",cat:i,kids:[]});continue}let r=a;for(const x of i.cat.split("/")){const g=r.path?r.path+"/"+x:x;let d=r.kids.find(t=>t.path===g);d||(d={path:g,label:x,kids:[]},r.kids.push(d)),r=d}r.cat=i}return a.kids.map(J)}function O(s){const a=s.find(i=>i.scored&&i.linked)??s.find(i=>i.scored)??s[0];return a&&a.files[0]?`${a.cat}/${a.files[0]}`:""}function I({node:s,selected:a,onSelect:i,depth:r=0}){var h,u,p;const[x,g]=l.useState(!1),d=((h=s.cat)==null?void 0:h.scored)??!0,t=((u=s.cat)==null?void 0:u.linked)??!0;return e.jsxs("div",{style:r===0?{borderBottom:"1px solid var(--border-hair)"}:void 0,children:[e.jsxs("button",{onClick:()=>g(c=>!c),style:{display:"flex",alignItems:"center",gap:8,width:"100%",padding:"9px 6px",paddingLeft:6+r*12,border:"none",background:"transparent",cursor:"pointer",textAlign:"left"},children:[e.jsx(k,{name:x?"chevron-down":"chevron-right",size:14,color:"var(--text-subtle)"}),e.jsx(k,{name:"folder",size:15,color:d?t?"var(--brass-500)":"var(--clay-500)":"var(--text-subtle)"}),e.jsxs("span",{style:{fontFamily:"var(--font-mono)",fontSize:12.5,color:"var(--text-strong)",fontWeight:500},children:[s.label,"/"]}),e.jsx("span",{style:{flex:1}}),s.cat&&d&&(s.cat.linked?e.jsx(k,{name:"link",size:13,color:"var(--leaf-600)"}):e.jsx(k,{name:"unlink",size:13,color:"var(--clay-500)"}))]}),x&&e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:1,paddingBottom:4},children:[s.kids.map(c=>e.jsx(I,{node:c,selected:a,onSelect:i,depth:r+1},c.path)),(p=s.cat)==null?void 0:p.files.map(c=>{const f=s.path+"/"+c,v=f===a;return e.jsxs("button",{onClick:()=>i(f),style:{display:"flex",alignItems:"center",gap:8,width:"100%",padding:"6px 8px",paddingLeft:18+r*12,borderRadius:"var(--radius-sm)",border:"none",cursor:"pointer",textAlign:"left",background:v?"var(--brass-100)":"transparent"},children:[e.jsx(k,{name:"file-text",size:13,color:v?"var(--brass-700)":"var(--text-subtle)"}),e.jsx("span",{style:{fontFamily:"var(--font-mono)",fontSize:12,color:v?"var(--brass-700)":!d||t?"var(--text-body)":"var(--text-muted)",fontWeight:v?600:400},children:c})]},c)})]})]})}function ve({projectId:s,projectName:a,docStatus:i}){const[r,x]=l.useState([]),[g,d]=l.useState(0),[t,h]=re(ue("docs",s),"selected","",pe),[u,p]=l.useState({}),[c,f]=l.useState("preview"),[v,P]=l.useState("tree"),[w,F]=l.useState(""),[S,M]=l.useState(!1),{confirm:K,dialog:U}=oe(),[H,z]=l.useState("loading"),[V,q]=l.useState(0);l.useEffect(()=>{let n=!0;return z("loading"),y.getDocs(s).then(o=>{if(!n)return;const m=o.tree;x(m),d(o.coverage),p({}),f("preview"),z("ready"),h(O(m))}).catch(()=>{n&&(x([]),h(""),z("error"))}),()=>{n=!1}},[s,V]),l.useEffect(()=>{if(!t||t in u)return;let n=!0;return y.getDoc(s,t).then(o=>{n&&p(m=>({...m,[t]:o.content}))}).catch(()=>{n&&p(o=>({...o,[t]:null}))}),()=>{n=!1}},[t,s,u]);const D=!!t&&!(t in u),C=t?u[t]===null:!1,Q=()=>p(n=>{const o={...n};return delete o[t],o}),X=l.useMemo(()=>G(r.filter(n=>n.scored)),[r]),L=l.useMemo(()=>G(r.filter(n=>!n.scored)),[r]),N=u[t]??"",Y=t.includes("/")?t.slice(0,t.lastIndexOf("/")):".",B=r.find(n=>n.cat===Y),Z=t,_=i==="broken"?"err":i==="drift"?"warn":"ok",ee=i==="broken"?"broken":i==="drift"?"drift":"ok";function te(){F(N),f("edit")}function ne(){f("preview")}async function se(){await y.putDoc(s,t,w),p(n=>({...n,[t]:w})),f("preview")}function E(n){h(n),f("preview"),P("viewer")}async function R(){const n=await y.getDocs(s),o=n.tree;x(o),d(n.coverage),o.some(m=>m.files.some(ie=>`${m.cat}/${ie}`===t))||h(O(o))}async function W(){if(!S){M(!0);try{await R()}finally{M(!1)}}}async function ae(){t&&await K({title:`Hapus ${t}?`,message:"Berkas aslinya di disk ikut dihapus — dokumen ini adalah Source of Truth project.",confirmLabel:"Hapus dokumen",run:()=>y.deleteDoc(s,t)})&&(p(n=>{const o={...n};return delete o[t],o}),await R())}return e.jsxs(e.Fragment,{children:[e.jsx(le,{ariaLabel:"Panel Docs",active:v,onActiveChange:n=>P(n),masterWidth:288,className:"hn-workspace-panels",panels:[{id:"tree",label:"Files",className:"hn-panel-flex",content:e.jsxs("div",{style:{display:"flex",flexDirection:"column",gap:16,minHeight:0,overflow:"auto"},children:[e.jsxs(T,{padding:0,children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",gap:8,padding:"12px 14px",borderBottom:"1px solid var(--border-hair)"},children:[e.jsxs("span",{className:"hn-eyebrow",children:["docs · ",a]}),e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8},children:[e.jsx(de,{status:ee,size:"sm"}),e.jsx(j,{size:"sm",variant:"ghost",leftIcon:S?"loader":"radar",onClick:W,disabled:S,children:S?"…":"Muat ulang"})]})]}),e.jsx("div",{style:{padding:"4px 8px"},children:H==="loading"?e.jsx(b,{kind:"loading",compact:!0,title:"Memuat index…"}):H==="error"?e.jsx(b,{kind:"error",compact:!0,title:"Gagal memuat index docs",hint:a,action:()=>q(n=>n+1)}):r.length===0?e.jsx(b,{kind:"empty",compact:!0,icon:"folder-open",title:"Belum ada docs",hint:"Belum ada Markdown di repo ini.",action:W,actionLabel:"Muat ulang",actionIcon:"radar"}):e.jsxs(e.Fragment,{children:[X.map(n=>e.jsx(I,{node:n,selected:t,onSelect:E},n.path)),L.length>0&&e.jsxs("div",{style:{marginTop:8,paddingTop:8,borderTop:"1px solid var(--border-hair)"},children:[e.jsx("div",{className:"hn-eyebrow",style:{padding:"4px 6px",color:"var(--text-subtle)"},children:"Lainnya (tidak dinilai)"}),L.map(n=>e.jsx(I,{node:n,selected:t,onSelect:E},n.path))]})]})})]}),e.jsxs(T,{padding:16,children:[e.jsxs("div",{style:{display:"flex",alignItems:"center",justifyContent:"space-between",marginBottom:12},children:[e.jsx("span",{className:"hn-eyebrow",children:"SoT coverage"}),e.jsx("span",{style:{fontFamily:"var(--font-mono)",fontSize:12,color:"var(--text-muted)"},children:a})]}),e.jsx(ce,{value:g,showLabel:!0,label:"Kategori ter-index",tone:_})]})]})},{id:"viewer",label:"Dokumen",className:"hn-panel-flex",content:e.jsxs(T,{padding:0,fill:!0,children:[e.jsxs("div",{style:{flex:"0 0 auto",display:"flex",alignItems:"center",gap:12,padding:"12px 16px",borderBottom:"1px solid var(--border-hair)",flexWrap:"wrap"},children:[e.jsx(k,{name:"file-text",size:15,color:"var(--text-muted)"}),e.jsx("span",{style:{fontFamily:"var(--font-mono)",fontSize:13,color:"var(--text-strong)",fontWeight:500},children:Z}),B&&B.scored&&(B.linked?e.jsx($,{tone:"ok",size:"sm",icon:"link",children:"indexed"}):e.jsx($,{tone:"err",size:"sm",icon:"unlink",children:"unlinked"})),e.jsx("span",{style:{flex:1}}),c==="preview"?e.jsxs("div",{style:{display:"flex",gap:8,alignItems:"center"},children:[e.jsx(xe,{href:n=>y.docDownloadUrl(s,t,n),disabled:!t||D||C}),e.jsx(j,{size:"sm",variant:"ghost",leftIcon:"trash-2",onClick:ae,disabled:!t,children:"Hapus"}),e.jsx(j,{size:"sm",variant:"secondary",leftIcon:"pencil",onClick:te,disabled:!t||D||C,children:"Edit"})]}):e.jsxs("div",{style:{display:"flex",alignItems:"center",gap:8},children:[e.jsx(j,{size:"sm",variant:"ghost",onClick:ne,children:"Batal"}),e.jsx(j,{size:"sm",leftIcon:"check",onClick:se,children:"Simpan"})]})]}),c==="preview"?e.jsx("div",{"data-testid":"doc-preview-scroll",style:{padding:"8px 30px 34px",flex:"1 1 auto",minHeight:0,overflow:"auto"},children:t?D?e.jsx(b,{kind:"loading",title:"Memuat dokumen…",hint:t}):C?e.jsx(b,{kind:"error",title:"Gagal memuat dokumen",hint:t,action:Q}):e.jsx(A,{text:N,name:t}):e.jsx(b,{kind:"empty",icon:"file-text",title:"Tidak ada dokumen dipilih",hint:"Pilih file dari pohon docs di kiri."})}):e.jsxs("div",{className:"hn-grid-mobile",style:{display:"grid",gridTemplateColumns:"1fr 1fr",flex:"1 1 auto",minHeight:0},children:[e.jsxs("div",{style:{display:"flex",flexDirection:"column",borderRight:"1px solid var(--border-hair)",minHeight:0},children:[e.jsx("div",{style:{padding:"8px 14px",borderBottom:"1px solid var(--border-hair)",background:"var(--bone-100)"},children:e.jsx("span",{className:"hn-eyebrow",children:"Markdown"})}),e.jsx("textarea",{value:w,onChange:n=>F(n.target.value),spellCheck:!1,placeholder:`# Judul dokumen
|
|
2
2
|
|
|
3
3
|
Paragraf pembuka…`,style:{flex:1,width:"100%",boxSizing:"border-box",resize:"none",border:"none",outline:"none",padding:"16px 18px",fontFamily:"var(--font-mono)",fontSize:12.5,lineHeight:1.7,color:"var(--text-body)",background:"var(--surface-card)"}})]}),e.jsxs("div",{style:{display:"flex",flexDirection:"column",minHeight:0},children:[e.jsx("div",{style:{padding:"8px 14px",borderBottom:"1px solid var(--border-hair)",background:"var(--bone-100)"},children:e.jsx("span",{className:"hn-eyebrow",children:"Preview langsung"})}),e.jsx("div",{style:{flex:1,overflow:"auto",padding:"4px 24px 24px"},children:e.jsx(A,{text:w,name:t})})]})]})]})}]}),U]})}export{ve as DocsWorkspace,G as buildTree,O as firstDoc};
|