hanoman 0.1.11 → 0.1.13

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hanoman",
3
- "version": "0.1.11",
3
+ "version": "0.1.13",
4
4
  "description": "Orchestrator + dashboard workflow docs-driven untuk sesi Claude Code / Codex",
5
5
  "type": "module",
6
6
  "repository": {
@@ -0,0 +1,13 @@
1
+ -- SPEC-480 · ADR-0098 · putusan lead yang bisa dipakai mesin: pilihan tersimpan sebagai data.
2
+ --
3
+ -- Ditulis tangan (bukan `migrate dev`): worktree tetangga membuat `migrate dev` me-reset DB saat
4
+ -- ada drift. ADITIF murni — empat kolom NULLABLE tanpa default, tak ada tabel diredefinisi, tak
5
+ -- ada baris disentuh. Larangan SQLite atas `ADD COLUMN … DEFAULT <non-konstan>` (lihat migration
6
+ -- SPEC-408) tak berlaku di sini karena tak ada default sama sekali.
7
+ --
8
+ -- `options` menyimpan menu yang DIKIRIM PEMINTA. Tanpa itu jejaknya tak bisa dibaca ulang:
9
+ -- `question` tersimpan, opsinya tidak, jadi "lead memilih opsi 2" tak bisa diverifikasi kemudian.
10
+ ALTER TABLE "LeadDecision" ADD COLUMN "choice" TEXT;
11
+ ALTER TABLE "LeadDecision" ADD COLUMN "choiceIndex" INTEGER;
12
+ ALTER TABLE "LeadDecision" ADD COLUMN "options" JSONB;
13
+ ALTER TABLE "LeadDecision" ADD COLUMN "missing" JSONB;
@@ -0,0 +1,48 @@
1
+ -- SPEC-481 · ADR-0100 · webhook keluar: endpoint + antrean/riwayat pengiriman.
2
+ --
3
+ -- Dua tabel BARU → `CREATE TABLE` polos; tak ada redefinisi tabel seperti migration SPEC-408.
4
+ -- Keduanya LOCAL-only (tanpa kolom `version`): barisnya memegang secret dan menunjuk pengiriman
5
+ -- dari mesin ini.
6
+ CREATE TABLE "WebhookEndpoint" (
7
+ "id" TEXT NOT NULL PRIMARY KEY,
8
+ "name" TEXT NOT NULL,
9
+ "url" TEXT NOT NULL,
10
+ "secret" TEXT NOT NULL,
11
+ "events" JSONB NOT NULL,
12
+ "projectIds" JSONB,
13
+ "enabled" BOOLEAN NOT NULL DEFAULT true,
14
+ "allowPrivate" BOOLEAN NOT NULL DEFAULT false,
15
+ "apiVersion" INTEGER NOT NULL DEFAULT 1,
16
+ "maxPerMinute" INTEGER NOT NULL DEFAULT 60,
17
+ "disabledAt" DATETIME,
18
+ "disabledReason" TEXT,
19
+ "lastSuccessAt" DATETIME,
20
+ "lastFailureAt" DATETIME,
21
+ "failureStreak" INTEGER NOT NULL DEFAULT 0,
22
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
23
+ "updatedAt" DATETIME NOT NULL
24
+ );
25
+
26
+ CREATE TABLE "WebhookDelivery" (
27
+ "id" TEXT NOT NULL PRIMARY KEY,
28
+ "endpointId" TEXT NOT NULL,
29
+ "eventId" TEXT NOT NULL,
30
+ "eventType" TEXT NOT NULL,
31
+ "projectId" TEXT,
32
+ "payload" JSONB NOT NULL,
33
+ "status" TEXT NOT NULL DEFAULT 'pending',
34
+ "attempt" INTEGER NOT NULL DEFAULT 0,
35
+ "maxAttempts" INTEGER NOT NULL DEFAULT 6,
36
+ "nextAttemptAt" DATETIME,
37
+ "httpStatus" INTEGER,
38
+ "durationMs" INTEGER,
39
+ "error" TEXT,
40
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
41
+ "sentAt" DATETIME,
42
+ CONSTRAINT "WebhookDelivery_endpointId_fkey" FOREIGN KEY ("endpointId")
43
+ REFERENCES "WebhookEndpoint" ("id") ON DELETE CASCADE ON UPDATE CASCADE
44
+ );
45
+
46
+ CREATE INDEX "WebhookDelivery_status_nextAttemptAt_idx" ON "WebhookDelivery" ("status", "nextAttemptAt");
47
+ CREATE INDEX "WebhookDelivery_endpointId_createdAt_idx" ON "WebhookDelivery" ("endpointId", "createdAt");
48
+ CREATE INDEX "WebhookDelivery_eventId_idx" ON "WebhookDelivery" ("eventId");
@@ -0,0 +1,8 @@
1
+ -- SPEC-486 · ADR-0103 · kebijakan auto-merge saat sesi selesai.
2
+ --
3
+ -- ADITIF & nullable tanpa default → `ADD COLUMN` polos (pola migration SPEC-447). Yang dilarang
4
+ -- SQLite adalah `ADD COLUMN … DEFAULT <non-konstan>`, bukan `ADD COLUMN` itu sendiri. Baris lama
5
+ -- tetap NULL, dan NULL berarti "tanpa auto-merge" di Project / "warisi project" di Spec —
6
+ -- jadi tak ada backfill, dan project lama tak berubah perilaku satu langkah git pun.
7
+ ALTER TABLE "Project" ADD COLUMN "autoMerge" JSONB;
8
+ ALTER TABLE "Spec" ADD COLUMN "autoMerge" JSONB;
@@ -0,0 +1,8 @@
1
+ -- SPEC-484 · ADR-0101 · penyaring mesin sesi per definisi agen.
2
+ --
3
+ -- NULLABLE TANPA DEFAULT, dan itu yang membuat migration ini satu baris: setiap baris lama tetap
4
+ -- NULL = "ikut sesi induk" = perilaku ADR-0094 apa adanya, jadi tak ada backfill dan tak ada satu
5
+ -- pun roster yang berubah saat rilis ini mendarat. Larangan SQLite atas
6
+ -- `ADD COLUMN … DEFAULT CURRENT_TIMESTAMP` (migration SPEC-408) tak berlaku di sini justru karena
7
+ -- kolomnya tanpa default — tabel tak perlu diredefinisi.
8
+ ALTER TABLE "CustomAgent" ADD COLUMN "runtime" TEXT;
@@ -0,0 +1,36 @@
1
+ -- SPEC-485 · ADR-0102 · rantai keputusan lead + pilihan jamak.
2
+ --
3
+ -- Ditulis tangan (bukan `migrate dev`): worktree tetangga membuat `migrate dev` me-reset DB saat
4
+ -- ada drift. ADITIF murni — satu tabel baru + empat kolom NULLABLE tanpa default, tak ada tabel
5
+ -- diredefinisi, tak ada baris disentuh. Larangan SQLite atas `ADD COLUMN … DEFAULT <non-konstan>`
6
+ -- (lihat migration SPEC-408) tak berlaku di sini karena tak ada default sama sekali pada ALTER.
7
+ --
8
+ -- `LeadFlow` LOCAL-only: tanpa kolom `version`, tak pernah masuk changefeed sync — barisnya
9
+ -- menunjuk sesi tmux & worktree di MESIN INI, persis alasan `LeadDecision` juga tak disync.
10
+ CREATE TABLE "LeadFlow" (
11
+ "id" TEXT NOT NULL PRIMARY KEY,
12
+ "projectId" TEXT NOT NULL,
13
+ "specId" TEXT,
14
+ "sessionId" TEXT,
15
+ "gate" TEXT NOT NULL,
16
+ "status" TEXT NOT NULL DEFAULT 'menunggu',
17
+ "title" TEXT NOT NULL,
18
+ "steps" INTEGER NOT NULL DEFAULT 0,
19
+ "closeReason" TEXT,
20
+ "openedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
21
+ "closedAt" DATETIME,
22
+ "expiresAt" DATETIME NOT NULL,
23
+ "createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
24
+ "updatedAt" DATETIME NOT NULL
25
+ );
26
+ CREATE INDEX "LeadFlow_projectId_createdAt_idx" ON "LeadFlow"("projectId", "createdAt");
27
+ CREATE INDEX "LeadFlow_status_idx" ON "LeadFlow"("status");
28
+
29
+ -- `choices` menggantikan pasangan skalar `choice`/`choiceIndex` sebagai bentuk yang berlaku; yang
30
+ -- lama DIPERTAHANKAN dan diisi dari `choices[0]` supaya pembaca lama (dan baris pra-migrasi) tetap
31
+ -- terbaca tanpa backfill apa pun.
32
+ ALTER TABLE "LeadDecision" ADD COLUMN "flowId" TEXT;
33
+ ALTER TABLE "LeadDecision" ADD COLUMN "step" INTEGER;
34
+ ALTER TABLE "LeadDecision" ADD COLUMN "choices" JSONB;
35
+ ALTER TABLE "LeadDecision" ADD COLUMN "select" JSONB;
36
+ CREATE INDEX "LeadDecision_flowId_idx" ON "LeadDecision"("flowId");
@@ -21,6 +21,9 @@ model Project {
21
21
  helpEnabled Boolean @default(false) // SPEC-253 · opt-in Help Center publik
22
22
  schedulerOptIn Boolean @default(false) // SPEC-294 · ADR-0072 · opt-in scheduler otonom (LOCAL — tak masuk FIELDS sync)
23
23
  leadOptIn Boolean @default(false) // SPEC-409 · ADR-0091 · opt-in hanoman-lead (LOCAL — cermin schedulerOptIn)
24
+ // SPEC-486 · ADR-0103 · kebijakan auto-merge saat backlog item selesai (LOCAL — tak masuk
25
+ // FIELDS sync, cermin repoDir/schedulerOptIn). null = tanpa auto-merge (default, nol backfill).
26
+ autoMerge Json?
24
27
  specs Spec[]
25
28
  tickets Ticket[]
26
29
  customAgents CustomAgent[] // SPEC-450 · ADR-0094 · custom agent milik project ini
@@ -54,6 +57,9 @@ model Spec {
54
57
  // dan kolom ikut FIELDS.spec sync apa adanya. Integritas ditegakkan di boundary route +
55
58
  // pembersihan saat spec dihapus, bukan FK.
56
59
  dependsOn Json?
60
+ // SPEC-486 · ADR-0103 · override kebijakan auto-merge untuk item ini. null = warisi project.
61
+ // `Json?` dengan alasan yang sama seperti dependsOn: blok dibaca utuh, tak pernah difilter.
62
+ autoMerge Json?
57
63
  updatedAt DateTime @updatedAt
58
64
  project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
59
65
  }
@@ -82,6 +88,7 @@ model CustomAgent {
82
88
  tools Json?
83
89
  model String?
84
90
  mentions Json?
91
+ runtime String? // SPEC-484 · ADR-0101 · penyaring mesin sesi; null = ikut sesi induk
85
92
  enabled Boolean @default(true)
86
93
  version Int @default(0) // SPEC-213 · version-stamp sync (ADR-0045)
87
94
  createdAt DateTime @default(now())
@@ -371,6 +378,33 @@ model SchedulerQueueItem {
371
378
  @@index([status])
372
379
  }
373
380
 
381
+ // SPEC-485 · ADR-0102 · satu RANTAI keputusan lead: beberapa pertanyaan berurutan yang satu urusan,
382
+ // dari pertanyaan pertama sampai submit akhir. Sebelum model ini "alur" hanya ada sebagai kebetulan
383
+ // (baris jejak yang berdekatan waktunya), jadi tak ada tempat untuk menegakkan "pertanyaan lanjutan
384
+ // hanya boleh masuk ke alur yang masih aktif" dan tak ada yang bisa ditanya "sudah di-submit belum".
385
+ //
386
+ // LOCAL-ONLY (tanpa `version`, tak pernah disync) dan TANPA FK — cermin LeadDecision di bawah:
387
+ // id project/spec/sesi boleh lenyap tanpa menyeret jejaknya.
388
+ model LeadFlow {
389
+ id String @id @default(cuid())
390
+ projectId String
391
+ specId String?
392
+ sessionId String?
393
+ gate String // pintu yang membuka rantai (contract|detected|pulse)
394
+ status String @default("menunggu") // menunggu | sebagian | selesai | dibatalkan
395
+ title String // pertanyaan pertama, terpangkas — ini yang dibaca operator
396
+ steps Int @default(0)
397
+ closeReason String? // tunggal | submit | operator | kedaluwarsa
398
+ openedAt DateTime @default(now())
399
+ closedAt DateTime?
400
+ expiresAt DateTime // pagar anti-menggantung; penyapunya menumpang tick lead
401
+ createdAt DateTime @default(now())
402
+ updatedAt DateTime @updatedAt
403
+
404
+ @@index([projectId, createdAt])
405
+ @@index([status])
406
+ }
407
+
374
408
  // SPEC-409 · ADR-0091 · jejak keputusan hanoman-lead. Data BARU yang harus bertahan (bukan nilai
375
409
  // turunan seperti coverage/PRD, ADR-0011/0018): pertanyaan yang ditanyakan sesi yang sudah mati,
376
410
  // dan alasan yang dipakai lead, tak bisa dihitung ulang dari sumber mana pun.
@@ -396,12 +430,26 @@ model LeadDecision {
396
430
  weighty Boolean @default(false) // memicu notifikasi (AC-25)
397
431
  supersededById String? // baris yang menimpanya (jawaban operator, AC-28)
398
432
  actor String @default("lead") // lead | operator — siapa yang mengeluarkan baris ini
433
+ // SPEC-480 · ADR-0098 · pilihan sebagai DATA. Keempatnya nullable tanpa default: baris yang lahir
434
+ // sebelum spec ini sah apa adanya, dan "tak ada opsi" beda dari "opsi kosong".
435
+ choice String? // label opsi terpilih, verbatim; null = tak ada opsi / pilihan ditolak
436
+ choiceIndex Int? // 1-basis, sepasang dengan `choice`
437
+ options Json? // string[] — daftar opsi yang DIKIRIM peminta, supaya jejak bisa diaudit
438
+ missing Json? // string[] — apa yang kurang bila lead menyatakan konteksnya tak cukup
439
+ // SPEC-485 · ADR-0102 · aditif & nullable: baris lama sah apa adanya. `choices` adalah bentuk
440
+ // penyimpanan yang BERLAKU; `choice`/`choiceIndex` di atas tinggal turunan `choices[0]`, dan
441
+ // baris pra-migrasi diturunkan balik jadi `choices` saat dibaca (kompatibilitas mundur).
442
+ flowId String? // rantai tempat langkah ini duduk
443
+ step Int? // urutan langkah dalam rantai, 1-basis
444
+ choices Json? // {index,option}[] — SELALU daftar
445
+ select Json? // {mode,min,max} sebagaimana dikirim peminta
399
446
  createdAt DateTime @default(now())
400
447
  updatedAt DateTime @updatedAt
401
448
 
402
449
  @@index([projectId, createdAt])
403
450
  @@index([specId])
404
451
  @@index([sessionId])
452
+ @@index([flowId])
405
453
  }
406
454
 
407
455
  // SPEC-215 · ADR-0049 · LOCAL-ONLY: override config runtime (env → DB). Tak pernah disync.
@@ -564,3 +612,58 @@ model TicketAttachment {
564
612
 
565
613
  @@index([ticketId])
566
614
  }
615
+
616
+ // SPEC-481 · ADR-0100 · endpoint webhook keluar. LOCAL-only (cermin AgentToken/RuntimeConfig):
617
+ // barisnya memegang secret dan menunjuk pengiriman dari MESIN INI, jadi menyiarkannya ke hub
618
+ // akan mengirim kredensial dan riwayat yang tak berlaku di sana. Tanpa `version`/notifySynced.
619
+ //
620
+ // `secret` disimpan sebagai ciphertext `enc:v1:` (services/secret-box.ts, ADR-0097) dan TAK PERNAH
621
+ // dikembalikan utuh oleh API — hanya empat karakter terakhir sebagai `secretHint`.
622
+ model WebhookEndpoint {
623
+ id String @id @default(cuid())
624
+ name String
625
+ url String
626
+ secret String
627
+ events Json // string[]; ["*"] = semua, "spec.*" = satu keluarga
628
+ projectIds Json? // string[] | null = semua project
629
+ enabled Boolean @default(true)
630
+ allowPrivate Boolean @default(false) // izin EKSPLISIT alamat internal/loopback (anti-SSRF)
631
+ apiVersion Int @default(1) // versi amplop yang diminta penerima
632
+ maxPerMinute Int @default(60)
633
+ disabledAt DateTime?
634
+ disabledReason String?
635
+ lastSuccessAt DateTime?
636
+ lastFailureAt DateTime?
637
+ failureStreak Int @default(0)
638
+ createdAt DateTime @default(now())
639
+ updatedAt DateTime @updatedAt
640
+ deliveries WebhookDelivery[]
641
+ }
642
+
643
+ // SPEC-481 · ADR-0100 · satu tabel merangkap ANTREAN dan RIWAYAT.
644
+ //
645
+ // `payload` disimpan per pengiriman, bukan dirender ulang: retry wajib mengirim byte yang SAMA
646
+ // supaya `id` peristiwa stabil dan idempotensi penerima berlaku, dan riwayat harus memperlihatkan
647
+ // apa yang benar-benar dikirim, bukan keadaan hari ini.
648
+ model WebhookDelivery {
649
+ id String @id @default(cuid())
650
+ endpointId String
651
+ eventId String // SAMA untuk semua endpoint dari satu peristiwa
652
+ eventType String
653
+ projectId String?
654
+ payload Json
655
+ status String @default("pending") // pending | sending | sent | failed | dropped
656
+ attempt Int @default(0)
657
+ maxAttempts Int @default(6)
658
+ nextAttemptAt DateTime?
659
+ httpStatus Int?
660
+ durationMs Int?
661
+ error String?
662
+ createdAt DateTime @default(now())
663
+ sentAt DateTime?
664
+ endpoint WebhookEndpoint @relation(fields: [endpointId], references: [id], onDelete: Cascade)
665
+
666
+ @@index([status, nextAttemptAt])
667
+ @@index([endpointId, createdAt])
668
+ @@index([eventId])
669
+ }