hanoman 0.9.32 → 0.9.33
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 +240 -130
- package/dist/server.js +21995 -20480
- package/package.json +1 -1
- package/prisma/migrations/20261020120000_lead_session_inbox/migration.sql +42 -0
- package/prisma/schema.prisma +46 -0
- package/web/assets/{DalangHanomanScreen-DdsEmtBl.js → DalangHanomanScreen-DAXIQxrw.js} +1 -1
- package/web/assets/{DocPreviewModal-BbOqdfaH.js → DocPreviewModal-Cu0UFzPH.js} +1 -1
- package/web/assets/{DocsWorkspace-Cr7AXz9z.js → DocsWorkspace-DElNcoar.js} +1 -1
- package/web/assets/{IdeScreen-hdbQW-ui.js → IdeScreen-BBr567gf.js} +1 -1
- package/web/assets/LeadScreen-CYn8RS3H.js +1 -0
- package/web/assets/{ReviewScreen-BIkpEspG.js → ReviewScreen-zAvwSL50.js} +1 -1
- package/web/assets/{SchedulerScreen-3KVE-d_d.js → SchedulerScreen-BptlSAOx.js} +1 -1
- package/web/assets/{SettingsScreen-B0-W2TeR.js → SettingsScreen-a0Cx4M4j.js} +3 -3
- package/web/assets/{TeamScreen-DNdt2P1g.js → TeamScreen-Cm_phItS.js} +1 -1
- package/web/assets/{TerminalScreen-BjQF48XI.js → TerminalScreen-CFuNRq6d.js} +1 -1
- package/web/assets/{TriageScreen-CzM99CrG.js → TriageScreen-ChTidhCT.js} +1 -1
- package/web/assets/{VpsScreen-SGB_BpbS.js → VpsScreen-8vz0QHO-.js} +1 -1
- package/web/assets/{fields-of8G961J.js → fields-Bhl01LnE.js} +1 -1
- package/web/assets/{index-C5P4ykKO.js → index-R2HBkTbR.js} +207 -207
- package/web/assets/{live-DQen7wLm.js → live-V9nWiHoE.js} +1 -1
- package/web/assets/{sched-lead-shared-C34TvLVv.js → sched-lead-shared-Dr48bY7n.js} +1 -1
- package/web/assets/{settings-rebase-DHIWk4mV.js → settings-rebase-DOqNAynI.js} +1 -1
- package/web/index.html +1 -1
- package/web/assets/LeadScreen-BWE4mfJI.js +0 -1
package/dist/build-info.json
CHANGED
package/dist/cli.js
CHANGED
|
@@ -4491,6 +4491,127 @@ var init_auto_merge = __esm({
|
|
|
4491
4491
|
}
|
|
4492
4492
|
});
|
|
4493
4493
|
|
|
4494
|
+
// ../shared/src/lead.ts
|
|
4495
|
+
var zLeadGate, zLeadKind, zLeadConfidence, zLeadStatus, zLeadFlowStatus, LEAD_ACTIONS, zLeadAction, zLeadChoice, zLeadSelect, zLeadVerdict, zLeadAsk, zLeadOverride, LEAD_AUTHORITY_MODES, zLeadAuthorityMode, zLeadProject, zLeadAct;
|
|
4496
|
+
var init_lead = __esm({
|
|
4497
|
+
"../shared/src/lead.ts"() {
|
|
4498
|
+
"use strict";
|
|
4499
|
+
init_zod();
|
|
4500
|
+
zLeadGate = external_exports.enum(["contract", "detected", "pulse"]);
|
|
4501
|
+
zLeadKind = external_exports.enum(["answer", "order", "collision", "quality", "refusal"]);
|
|
4502
|
+
zLeadConfidence = external_exports.enum(["tinggi", "sedang", "ragu"]);
|
|
4503
|
+
zLeadStatus = external_exports.enum(["berlaku", "ditimpa", "dibatalkan", "gagal"]);
|
|
4504
|
+
zLeadFlowStatus = external_exports.enum(["menunggu", "sebagian", "selesai", "dibatalkan"]);
|
|
4505
|
+
LEAD_ACTIONS = [
|
|
4506
|
+
"none",
|
|
4507
|
+
// keputusan murni jawaban; tak ada tindakan menyusul
|
|
4508
|
+
"answer-session",
|
|
4509
|
+
// ketik jawaban ke pane sesi (pintu deteksi otomatis)
|
|
4510
|
+
"start-session",
|
|
4511
|
+
// mulai sesi untuk sebuah backlog (lewat antrean scheduler)
|
|
4512
|
+
"stop-session",
|
|
4513
|
+
// hentikan sesi — worktree DIBIARKAN utuh (AC-32a)
|
|
4514
|
+
"resume-session",
|
|
4515
|
+
// lanjutkan sesi terputus (jalur ADR-0084)
|
|
4516
|
+
"restart-session",
|
|
4517
|
+
// ulangi pekerjaan dari awal
|
|
4518
|
+
"order-queue",
|
|
4519
|
+
// tata urutan antrean yang sudah ada (ADR-0072) — bukan antrean kedua
|
|
4520
|
+
"hold-work",
|
|
4521
|
+
// tunda satu pekerjaan karena tabrakan area kerja
|
|
4522
|
+
"push-branch",
|
|
4523
|
+
// dorong perubahan ke branch
|
|
4524
|
+
"integrate-main",
|
|
4525
|
+
// integrasikan ke branch utama (risiko yang diterima sadar, PRD §Risiko)
|
|
4526
|
+
"run-migration"
|
|
4527
|
+
// jalankan migration pada basis data LOKAL operator
|
|
4528
|
+
];
|
|
4529
|
+
zLeadAction = external_exports.enum(LEAD_ACTIONS);
|
|
4530
|
+
zLeadChoice = external_exports.object({ index: external_exports.number().int().positive(), option: external_exports.string() });
|
|
4531
|
+
zLeadSelect = external_exports.object({
|
|
4532
|
+
mode: external_exports.enum(["single", "multi"]).default("single"),
|
|
4533
|
+
min: external_exports.number().int().min(0).max(20).default(0),
|
|
4534
|
+
max: external_exports.number().int().min(1).max(20).nullable().default(null)
|
|
4535
|
+
});
|
|
4536
|
+
zLeadVerdict = external_exports.object({
|
|
4537
|
+
decision: external_exports.string().min(1),
|
|
4538
|
+
reason: external_exports.string().min(1),
|
|
4539
|
+
refs: external_exports.array(external_exports.string()).default([]),
|
|
4540
|
+
confidence: zLeadConfidence.default("sedang"),
|
|
4541
|
+
// Sengaja `string`, BUKAN `zLeadAction`: tindakan di luar allowlist harus bisa MASUK supaya
|
|
4542
|
+
// server menolaknya secara sadar — mencatat penolakan & menotifikasi operator (AC-33). Kalau
|
|
4543
|
+
// enum yang menyaring di sini, permintaan "deploy ke produksi" hanya akan tampak sebagai
|
|
4544
|
+
// keluaran rusak, dan justru peristiwa paling layak dilaporkan itulah yang hilang dari jejak.
|
|
4545
|
+
action: external_exports.string().default("none"),
|
|
4546
|
+
/**
|
|
4547
|
+
* SPEC-480 · opsi yang dipilih — nomor ATAU label. Sengaja `string`, bukan enum/number: pilihan
|
|
4548
|
+
* di luar daftar harus BISA MASUK supaya server menolaknya secara sadar & mencatatnya, alasan
|
|
4549
|
+
* yang sama persis dengan `action` di atas.
|
|
4550
|
+
*/
|
|
4551
|
+
choice: external_exports.string().default(""),
|
|
4552
|
+
/**
|
|
4553
|
+
* SPEC-485 · pilihan JAMAK. `string[]` dengan alasan yang sama persis seperti `choice` & `action`
|
|
4554
|
+
* di atas: pilihan di luar daftar harus BISA MASUK supaya server menolaknya secara sadar dan
|
|
4555
|
+
* mencatatnya. Kosong + `choice` terisi dibaca sebagai satu pilihan — keluaran agen berbentuk
|
|
4556
|
+
* ADR-0098 harus tetap terpakai, dan menuntut field baru berarti setiap agen lama mendadak
|
|
4557
|
+
* "tak memilih apa pun".
|
|
4558
|
+
*/
|
|
4559
|
+
choices: external_exports.array(external_exports.string().max(2e3)).max(20).default([]),
|
|
4560
|
+
/**
|
|
4561
|
+
* SPEC-480 · apa yang KURANG bila konteksnya memang tak cukup untuk memutuskan. Bukan pengganti
|
|
4562
|
+
* `confidence: "ragu"` (bukti tipis, jawabannya tetap ada) melainkan untuk fakta konkret yang
|
|
4563
|
+
* tak ada di repo maupun konteks. Terisi ⇒ server memaksa `ragu` ⇒ operator dinotifikasi.
|
|
4564
|
+
*/
|
|
4565
|
+
missing: external_exports.array(external_exports.string().max(200)).max(10).default([]),
|
|
4566
|
+
/** Teks yang benar-benar diketik ke pane sesi (pintu deteksi otomatis). */
|
|
4567
|
+
reply: external_exports.string().default("")
|
|
4568
|
+
});
|
|
4569
|
+
zLeadAsk = external_exports.object({
|
|
4570
|
+
projectId: external_exports.string().min(1),
|
|
4571
|
+
specId: external_exports.string().nullish(),
|
|
4572
|
+
sessionId: external_exports.string().nullish(),
|
|
4573
|
+
question: external_exports.string().min(1).max(8e3),
|
|
4574
|
+
options: external_exports.array(external_exports.string().max(2e3)).max(20).default([]),
|
|
4575
|
+
context: external_exports.string().max(2e4).default(""),
|
|
4576
|
+
/** SPEC-485 · bentuk pilihan yang diminta peminta. Default = perilaku hari ini (single). */
|
|
4577
|
+
select: zLeadSelect.default({ mode: "single", min: 0, max: null }),
|
|
4578
|
+
/** `true` = peminta akan mengajukan pertanyaan lanjutan; alurnya dibiarkan terbuka sampai submit. */
|
|
4579
|
+
chain: external_exports.boolean().default(false),
|
|
4580
|
+
/** Lanjutkan rantai yang sudah ada. Alur tertutup ditolak 409 — bukan dibuatkan diam-diam. */
|
|
4581
|
+
flowId: external_exports.string().min(1).nullish().default(null)
|
|
4582
|
+
});
|
|
4583
|
+
zLeadOverride = external_exports.object({
|
|
4584
|
+
answer: external_exports.string().min(1).max(8e3),
|
|
4585
|
+
reason: external_exports.string().max(8e3).default(""),
|
|
4586
|
+
/**
|
|
4587
|
+
* SPEC-485 · centang operator sebagai DATA, bukan prosa. Dipetakan ke opsi baris yang ditimpa,
|
|
4588
|
+
* lalu ikut diketikkan ke pane — jadi manusia mencentang di dashboard dan kotaknya benar-benar
|
|
4589
|
+
* tercentang di dialog sesi.
|
|
4590
|
+
*/
|
|
4591
|
+
choices: external_exports.array(external_exports.string().max(2e3)).max(20).default([])
|
|
4592
|
+
});
|
|
4593
|
+
LEAD_AUTHORITY_MODES = ["auto", "ask", "off"];
|
|
4594
|
+
zLeadAuthorityMode = external_exports.enum(LEAD_AUTHORITY_MODES);
|
|
4595
|
+
zLeadProject = external_exports.object({
|
|
4596
|
+
// zod 3: record berkunci enum diinfer `Partial<Record<…>>` — tindakan yang tak disebut memakai default.
|
|
4597
|
+
authority: external_exports.record(zLeadAction, zLeadAuthorityMode).default({}),
|
|
4598
|
+
targetBranch: external_exports.string().min(1).default("main"),
|
|
4599
|
+
/** Kosong = integrasi lead SELALU minta izin (server tak bisa membuktikan test hijau). */
|
|
4600
|
+
verifyCommand: external_exports.string().default(""),
|
|
4601
|
+
quotaStopPct: external_exports.number().int().min(1).max(100).default(85),
|
|
4602
|
+
rampStep: external_exports.number().int().min(1).max(16).default(1),
|
|
4603
|
+
rampProbeMin: external_exports.number().int().min(1).max(240).default(10),
|
|
4604
|
+
failStreak: external_exports.number().int().min(1).max(20).default(2),
|
|
4605
|
+
answerSlaSec: external_exports.number().int().min(30).max(3600).default(300)
|
|
4606
|
+
});
|
|
4607
|
+
zLeadAct = external_exports.object({
|
|
4608
|
+
eventId: external_exports.string().min(1),
|
|
4609
|
+
verdict: zLeadVerdict,
|
|
4610
|
+
evidence: external_exports.array(external_exports.string().max(500)).max(50).default([])
|
|
4611
|
+
});
|
|
4612
|
+
}
|
|
4613
|
+
});
|
|
4614
|
+
|
|
4494
4615
|
// ../shared/src/relay.ts
|
|
4495
4616
|
function utf8Bytes(s2) {
|
|
4496
4617
|
let n2 = 0;
|
|
@@ -4887,6 +5008,7 @@ var init_entities = __esm({
|
|
|
4887
5008
|
init_telegram();
|
|
4888
5009
|
init_agent_engine();
|
|
4889
5010
|
init_auto_merge();
|
|
5011
|
+
init_lead();
|
|
4890
5012
|
init_method_catalog();
|
|
4891
5013
|
init_relay();
|
|
4892
5014
|
init_logs();
|
|
@@ -5064,26 +5186,12 @@ var init_entities = __esm({
|
|
|
5064
5186
|
// rem per project (AC-15/US-4)
|
|
5065
5187
|
everyMin: external_exports.number().int().min(1).max(1440).default(5),
|
|
5066
5188
|
// denyut proaktif (OQ-2)
|
|
5067
|
-
//
|
|
5068
|
-
//
|
|
5069
|
-
//
|
|
5070
|
-
//
|
|
5071
|
-
// sendiri adalah paragraf anggaran waktu di `leadPrompt` (306 dtk → 101 dtk).
|
|
5072
|
-
timeoutSec: external_exports.number().int().min(10).max(900).default(600),
|
|
5189
|
+
// ADR-0228 · `timeoutSec` (batas satu proses brain), `maxConcurrent` & `queueWaitSec` (gerbang
|
|
5190
|
+
// konkurensi brain, SPEC-479) DICABUT bersama brain sekali-panggil. Tenggatnya kini milik inbox:
|
|
5191
|
+
// `projects[<id>].answerSlaSec` untuk pertanyaan, `deliverTimeoutSec` untuk pengantaran. Baris
|
|
5192
|
+
// Setting lama yang masih membawa kunci itu tetap ter-parse — zod membuang kunci tak dikenal.
|
|
5073
5193
|
// AC-11 / OQ-10 · berapa jawaban otomatis berturut-turut untuk SATU sesi sebelum lead berhenti.
|
|
5074
5194
|
maxAutoAnswers: external_exports.number().int().min(1).max(20).default(3),
|
|
5075
|
-
// SPEC-479 (QA) · berapa putusan boleh DISUSUN SEKALIGUS, untuk KETIGA pintu bersama. Sebelum
|
|
5076
|
-
// knob ini jawabannya tak pernah dinyatakan, jadi ia jatuh ke bentuk kode tiap pintu: 1 di pintu
|
|
5077
|
-
// deteksi (`for`+`await`, terukur `maxInFlight = 1` dengan tangga tunggu linier) dan tak hingga
|
|
5078
|
-
// di pintu kontrak (Fastify konkuren, terukur 12 permintaan → 12 proses agen). Default 2 diambil
|
|
5079
|
-
// dari mesin tempat keluhan lahir — 8 GB / 8 core yang sudah menanggung sesi pekerja di tmux,
|
|
5080
|
-
// sementara satu `claude -p --effort xhigh` adalah runtime Node penuh, bukan panggilan HTTP tipis.
|
|
5081
|
-
maxConcurrent: external_exports.number().int().min(1).max(16).default(2),
|
|
5082
|
-
// Deadline penerimaan: menunggu slot lebih lama dari ini → penolakan EKSPLISIT yang bisa dicoba
|
|
5083
|
-
// ulang (503 + Retry-After di pintu kontrak), bukan gantung. Wajib ada karena Fastify menyetel
|
|
5084
|
-
// `requestTimeout: 0` (terukur dari `buildApp()`) — tak ada pihak lain yang akan memutus peminta.
|
|
5085
|
-
// 0 = tanpa antrean sama sekali: penuh berarti langsung ditolak.
|
|
5086
|
-
queueWaitSec: external_exports.number().int().min(0).max(900).default(120),
|
|
5087
5195
|
// SPEC-485 · ADR-0102 · umur maksimum satu RANTAI keputusan yang dibiarkan terbuka. Peminta bisa
|
|
5088
5196
|
// mati di tengah rantai (sesi ditutup, agen crash); tanpa batas ini alurnya `sebagian` selamanya
|
|
5089
5197
|
// dan tak ada yang tahu apakah ia masih ditunggu. Penyapunya menumpang tick lead yang sudah ada —
|
|
@@ -5092,6 +5200,14 @@ var init_entities = __esm({
|
|
|
5092
5200
|
// OQ-3 · syarat objektif sebelum lead boleh mengintegrasikan ke branch utama. Default MENYALA:
|
|
5093
5201
|
// risiko "kode masuk main tanpa mata manusia" diterima sadar, tapi syaratnya tetap terukur.
|
|
5094
5202
|
requireGreenBeforeIntegrate: external_exports.boolean().default(true),
|
|
5203
|
+
// ADR-0228 · sesi lead. Knob GLOBAL: tenggat antar-jemput event, umur izin, dan kapan pane
|
|
5204
|
+
// lead dirotasi supaya konteksnya tak menumpuk tanpa batas.
|
|
5205
|
+
deliverTimeoutSec: external_exports.number().int().min(60).max(3600).default(600),
|
|
5206
|
+
approvalTtlMin: external_exports.number().int().min(5).max(10080).default(1440),
|
|
5207
|
+
rotateAfterEvents: external_exports.number().int().min(5).max(500).default(40),
|
|
5208
|
+
// Setelan PER PROYEK (wewenang, branch target, perintah verifikasi, jatah). Proyek yang tak
|
|
5209
|
+
// disebut memakai default `zLeadProject` — penggabungnya `lead/project-config.ts`.
|
|
5210
|
+
projects: external_exports.record(external_exports.string(), zLeadProject.partial()).default({}),
|
|
5095
5211
|
engine: zLeadEngine.default({})
|
|
5096
5212
|
});
|
|
5097
5213
|
LEAD_DEFAULTS = zLead.parse({});
|
|
@@ -5289,6 +5405,10 @@ var init_agent = __esm({
|
|
|
5289
5405
|
// endpoint tulis menumpang prefix status yang dipetakan tanpa melihat method (AC-5).
|
|
5290
5406
|
"lead:read",
|
|
5291
5407
|
"lead:write",
|
|
5408
|
+
// ADR-0228 · menyetujui tindakan lead yang menunggu izin (bisa MERGE ke branch target). Akses
|
|
5409
|
+
// `danger`, tak diimplikasikan `lead:write`: pane lead & agen peminta putusan memegang write,
|
|
5410
|
+
// dan mereka tak boleh menyetujui tindakannya sendiri (ADR-0192).
|
|
5411
|
+
"lead:approve",
|
|
5292
5412
|
// SPEC-450 · ADR-0094 · custom agent. Domain TERSENDIRI, dipetakan MENURUT METHOD: menulis
|
|
5293
5413
|
// definisi agen mengubah apa yang dilihat SETIAP sesi baru di seluruh workspace, jadi izin
|
|
5294
5414
|
// baca tak pernah cukup untuk itu (kelas bug SPEC-405).
|
|
@@ -6556,108 +6676,6 @@ var init_github = __esm({
|
|
|
6556
6676
|
}
|
|
6557
6677
|
});
|
|
6558
6678
|
|
|
6559
|
-
// ../shared/src/lead.ts
|
|
6560
|
-
var zLeadGate, zLeadKind, zLeadConfidence, zLeadStatus, zLeadFlowStatus, LEAD_ACTIONS, zLeadAction, zLeadChoice, zLeadSelect, zLeadVerdict, zLeadAsk, zLeadOverride;
|
|
6561
|
-
var init_lead = __esm({
|
|
6562
|
-
"../shared/src/lead.ts"() {
|
|
6563
|
-
"use strict";
|
|
6564
|
-
init_zod();
|
|
6565
|
-
zLeadGate = external_exports.enum(["contract", "detected", "pulse"]);
|
|
6566
|
-
zLeadKind = external_exports.enum(["answer", "order", "collision", "quality", "refusal"]);
|
|
6567
|
-
zLeadConfidence = external_exports.enum(["tinggi", "sedang", "ragu"]);
|
|
6568
|
-
zLeadStatus = external_exports.enum(["berlaku", "ditimpa", "dibatalkan", "gagal"]);
|
|
6569
|
-
zLeadFlowStatus = external_exports.enum(["menunggu", "sebagian", "selesai", "dibatalkan"]);
|
|
6570
|
-
LEAD_ACTIONS = [
|
|
6571
|
-
"none",
|
|
6572
|
-
// keputusan murni jawaban; tak ada tindakan menyusul
|
|
6573
|
-
"answer-session",
|
|
6574
|
-
// ketik jawaban ke pane sesi (pintu deteksi otomatis)
|
|
6575
|
-
"start-session",
|
|
6576
|
-
// mulai sesi untuk sebuah backlog (lewat antrean scheduler)
|
|
6577
|
-
"stop-session",
|
|
6578
|
-
// hentikan sesi — worktree DIBIARKAN utuh (AC-32a)
|
|
6579
|
-
"resume-session",
|
|
6580
|
-
// lanjutkan sesi terputus (jalur ADR-0084)
|
|
6581
|
-
"restart-session",
|
|
6582
|
-
// ulangi pekerjaan dari awal
|
|
6583
|
-
"order-queue",
|
|
6584
|
-
// tata urutan antrean yang sudah ada (ADR-0072) — bukan antrean kedua
|
|
6585
|
-
"hold-work",
|
|
6586
|
-
// tunda satu pekerjaan karena tabrakan area kerja
|
|
6587
|
-
"push-branch",
|
|
6588
|
-
// dorong perubahan ke branch
|
|
6589
|
-
"integrate-main",
|
|
6590
|
-
// integrasikan ke branch utama (risiko yang diterima sadar, PRD §Risiko)
|
|
6591
|
-
"run-migration"
|
|
6592
|
-
// jalankan migration pada basis data LOKAL operator
|
|
6593
|
-
];
|
|
6594
|
-
zLeadAction = external_exports.enum(LEAD_ACTIONS);
|
|
6595
|
-
zLeadChoice = external_exports.object({ index: external_exports.number().int().positive(), option: external_exports.string() });
|
|
6596
|
-
zLeadSelect = external_exports.object({
|
|
6597
|
-
mode: external_exports.enum(["single", "multi"]).default("single"),
|
|
6598
|
-
min: external_exports.number().int().min(0).max(20).default(0),
|
|
6599
|
-
max: external_exports.number().int().min(1).max(20).nullable().default(null)
|
|
6600
|
-
});
|
|
6601
|
-
zLeadVerdict = external_exports.object({
|
|
6602
|
-
decision: external_exports.string().min(1),
|
|
6603
|
-
reason: external_exports.string().min(1),
|
|
6604
|
-
refs: external_exports.array(external_exports.string()).default([]),
|
|
6605
|
-
confidence: zLeadConfidence.default("sedang"),
|
|
6606
|
-
// Sengaja `string`, BUKAN `zLeadAction`: tindakan di luar allowlist harus bisa MASUK supaya
|
|
6607
|
-
// server menolaknya secara sadar — mencatat penolakan & menotifikasi operator (AC-33). Kalau
|
|
6608
|
-
// enum yang menyaring di sini, permintaan "deploy ke produksi" hanya akan tampak sebagai
|
|
6609
|
-
// keluaran rusak, dan justru peristiwa paling layak dilaporkan itulah yang hilang dari jejak.
|
|
6610
|
-
action: external_exports.string().default("none"),
|
|
6611
|
-
/**
|
|
6612
|
-
* SPEC-480 · opsi yang dipilih — nomor ATAU label. Sengaja `string`, bukan enum/number: pilihan
|
|
6613
|
-
* di luar daftar harus BISA MASUK supaya server menolaknya secara sadar & mencatatnya, alasan
|
|
6614
|
-
* yang sama persis dengan `action` di atas.
|
|
6615
|
-
*/
|
|
6616
|
-
choice: external_exports.string().default(""),
|
|
6617
|
-
/**
|
|
6618
|
-
* SPEC-485 · pilihan JAMAK. `string[]` dengan alasan yang sama persis seperti `choice` & `action`
|
|
6619
|
-
* di atas: pilihan di luar daftar harus BISA MASUK supaya server menolaknya secara sadar dan
|
|
6620
|
-
* mencatatnya. Kosong + `choice` terisi dibaca sebagai satu pilihan — keluaran agen berbentuk
|
|
6621
|
-
* ADR-0098 harus tetap terpakai, dan menuntut field baru berarti setiap agen lama mendadak
|
|
6622
|
-
* "tak memilih apa pun".
|
|
6623
|
-
*/
|
|
6624
|
-
choices: external_exports.array(external_exports.string().max(2e3)).max(20).default([]),
|
|
6625
|
-
/**
|
|
6626
|
-
* SPEC-480 · apa yang KURANG bila konteksnya memang tak cukup untuk memutuskan. Bukan pengganti
|
|
6627
|
-
* `confidence: "ragu"` (bukti tipis, jawabannya tetap ada) melainkan untuk fakta konkret yang
|
|
6628
|
-
* tak ada di repo maupun konteks. Terisi ⇒ server memaksa `ragu` ⇒ operator dinotifikasi.
|
|
6629
|
-
*/
|
|
6630
|
-
missing: external_exports.array(external_exports.string().max(200)).max(10).default([]),
|
|
6631
|
-
/** Teks yang benar-benar diketik ke pane sesi (pintu deteksi otomatis). */
|
|
6632
|
-
reply: external_exports.string().default("")
|
|
6633
|
-
});
|
|
6634
|
-
zLeadAsk = external_exports.object({
|
|
6635
|
-
projectId: external_exports.string().min(1),
|
|
6636
|
-
specId: external_exports.string().nullish(),
|
|
6637
|
-
sessionId: external_exports.string().nullish(),
|
|
6638
|
-
question: external_exports.string().min(1).max(8e3),
|
|
6639
|
-
options: external_exports.array(external_exports.string().max(2e3)).max(20).default([]),
|
|
6640
|
-
context: external_exports.string().max(2e4).default(""),
|
|
6641
|
-
/** SPEC-485 · bentuk pilihan yang diminta peminta. Default = perilaku hari ini (single). */
|
|
6642
|
-
select: zLeadSelect.default({ mode: "single", min: 0, max: null }),
|
|
6643
|
-
/** `true` = peminta akan mengajukan pertanyaan lanjutan; alurnya dibiarkan terbuka sampai submit. */
|
|
6644
|
-
chain: external_exports.boolean().default(false),
|
|
6645
|
-
/** Lanjutkan rantai yang sudah ada. Alur tertutup ditolak 409 — bukan dibuatkan diam-diam. */
|
|
6646
|
-
flowId: external_exports.string().min(1).nullish().default(null)
|
|
6647
|
-
});
|
|
6648
|
-
zLeadOverride = external_exports.object({
|
|
6649
|
-
answer: external_exports.string().min(1).max(8e3),
|
|
6650
|
-
reason: external_exports.string().max(8e3).default(""),
|
|
6651
|
-
/**
|
|
6652
|
-
* SPEC-485 · centang operator sebagai DATA, bukan prosa. Dipetakan ke opsi baris yang ditimpa,
|
|
6653
|
-
* lalu ikut diketikkan ke pane — jadi manusia mencentang di dashboard dan kotaknya benar-benar
|
|
6654
|
-
* tercentang di dialog sesi.
|
|
6655
|
-
*/
|
|
6656
|
-
choices: external_exports.array(external_exports.string().max(2e3)).max(20).default([])
|
|
6657
|
-
});
|
|
6658
|
-
}
|
|
6659
|
-
});
|
|
6660
|
-
|
|
6661
6679
|
// ../shared/src/handled-by.ts
|
|
6662
6680
|
var zHandledByEntry, HANDLED_BY_MAX, zHandledBy, zHandledByView;
|
|
6663
6681
|
var init_handled_by = __esm({
|
|
@@ -7086,7 +7104,12 @@ var init_dto = __esm({
|
|
|
7086
7104
|
inFlight: external_exports.number(),
|
|
7087
7105
|
queued: external_exports.number(),
|
|
7088
7106
|
capacity: external_exports.number()
|
|
7089
|
-
}).default({ inFlight: 0, queued: 0, capacity: 1 })
|
|
7107
|
+
}).default({ inFlight: 0, queued: 0, capacity: 1 }),
|
|
7108
|
+
// ADR-0228 · sesi lead: inbox terbuka/terlambat, izin yang menunggu, dan pane lead per proyek.
|
|
7109
|
+
// `.default([])` supaya klien lama tetap mem-parse respons ini.
|
|
7110
|
+
inbox: external_exports.array(external_exports.custom()).default([]),
|
|
7111
|
+
approvals: external_exports.array(external_exports.custom()).default([]),
|
|
7112
|
+
sessions: external_exports.array(external_exports.custom()).default([])
|
|
7090
7113
|
});
|
|
7091
7114
|
zFlow = external_exports.enum(["feature", "qa", "scaffold", "reverse", "prd", "audit", "breakdown", "goal", "no_effort"]);
|
|
7092
7115
|
zPrdBrief = external_exports.object({
|
|
@@ -7740,6 +7763,10 @@ var init_api = __esm({
|
|
|
7740
7763
|
leadFlows: `${API}/lead/flows`,
|
|
7741
7764
|
leadFlowSubmit: (id) => `${API}/lead/flows/${encodeURIComponent(id)}/submit`,
|
|
7742
7765
|
leadFlowCancel: (id) => `${API}/lead/flows/${encodeURIComponent(id)}/cancel`,
|
|
7766
|
+
// ADR-0228 · sesi lead: inbox, antrean izin, dan pane lead per proyek.
|
|
7767
|
+
leadInboxTake: (id) => `${API}/lead/inbox/${encodeURIComponent(id)}/take`,
|
|
7768
|
+
leadApprovalDecide: (id) => `${API}/lead/approvals/${encodeURIComponent(id)}/decide`,
|
|
7769
|
+
leadSession: (projectId, op) => `${API}/lead/sessions/${encodeURIComponent(projectId)}/${op}`,
|
|
7743
7770
|
// SPEC-450 · ADR-0094 · katalog custom agent. `?projectId=` → himpunan EFEKTIF (global+project).
|
|
7744
7771
|
customAgents: `${API}/custom-agents`,
|
|
7745
7772
|
customAgentMetrics: `${API}/custom-agents/metrics`,
|
|
@@ -7934,7 +7961,10 @@ var init_session_kind = __esm({
|
|
|
7934
7961
|
"shell",
|
|
7935
7962
|
"worktree",
|
|
7936
7963
|
"terminal",
|
|
7937
|
-
"telegram"
|
|
7964
|
+
"telegram",
|
|
7965
|
+
// ADR-0228 · pane hanoman-lead per proyek (`lead-<proyek>`). Tak restartable: ia dilahirkan
|
|
7966
|
+
// ulang oleh server sendiri, bukan oleh tombol "Mulai lagi".
|
|
7967
|
+
"lead"
|
|
7938
7968
|
];
|
|
7939
7969
|
zSessionKind = external_exports.enum(SESSION_KINDS);
|
|
7940
7970
|
}
|
|
@@ -12010,7 +12040,7 @@ var init_support = __esm({
|
|
|
12010
12040
|
});
|
|
12011
12041
|
|
|
12012
12042
|
// ../shared/src/mcp-catalog/lead.ts
|
|
12013
|
-
var CORE6, MORE5, LEAD_TOOLS;
|
|
12043
|
+
var CORE6, MORE5, listParams, listQuery, SESSION, LEAD_TOOLS;
|
|
12014
12044
|
var init_lead2 = __esm({
|
|
12015
12045
|
"../shared/src/mcp-catalog/lead.ts"() {
|
|
12016
12046
|
"use strict";
|
|
@@ -12048,7 +12078,7 @@ var init_lead2 = __esm({
|
|
|
12048
12078
|
{
|
|
12049
12079
|
name: "hanoman_lead_ask",
|
|
12050
12080
|
title: "Minta putusan hanoman-lead",
|
|
12051
|
-
description: "Minta putusan ke hanoman-lead saat menemui persimpangan yang biasanya butuh manusia. Jawabannya terbaca mesin (`decision`, `reason`, `refs`, `confidence`, `action`, `choices`) dan `refs` hanya memuat rujukan yang benar-benar ada di repo. Bila opsinya TIDAK saling eksklusif, set `multi: true` \u2014 balasannya memuat `choices` (daftar), bukan hanya `choice`. Panggilan ini melahirkan jejak permanen dan putusannya bisa menggerakkan sesi \u2014 pakai hanya saat memang buntu. 409 = lead tak aktif atau proyek belum opt-in:
|
|
12081
|
+
description: "Minta putusan ke hanoman-lead saat menemui persimpangan yang biasanya butuh manusia. Pertanyaanmu masuk inbox sesi lead proyek itu dan dijawab pane lead setelah ia memeriksa; panggilan ini MENUNGGU sampai dijawab atau tenggat `answerSlaSec` proyek (default 300 dtk). Jawabannya terbaca mesin (`decision`, `reason`, `refs`, `confidence`, `action`, `choices`) dan `refs` hanya memuat rujukan yang benar-benar ada di repo. Bila opsinya TIDAK saling eksklusif, set `multi: true` \u2014 balasannya memuat `choices` (daftar), bukan hanya `choice`. Panggilan ini melahirkan jejak permanen dan putusannya bisa menggerakkan sesi \u2014 pakai hanya saat memang buntu. 409 = lead tak aktif atau proyek belum opt-in: berhenti dan tunggu manusia; 504 = sesi lead tak menjawab dalam tenggat (diserahkan ke manusia); 400 = bentuk `multi`/`minChoices`/`maxChoices` mustahil dipenuhi oleh daftar opsi yang kamu kirim.",
|
|
12052
12082
|
inputSchema: obj({
|
|
12053
12083
|
properties: {
|
|
12054
12084
|
project: str("Id proyek."),
|
|
@@ -12213,7 +12243,87 @@ var init_lead2 = __esm({
|
|
|
12213
12243
|
shape: (raw) => raw
|
|
12214
12244
|
}
|
|
12215
12245
|
];
|
|
12216
|
-
|
|
12246
|
+
listParams = {
|
|
12247
|
+
project: str("Saring menurut id proyek."),
|
|
12248
|
+
status: str("Saring menurut status."),
|
|
12249
|
+
page: int("Halaman, mulai 1.", { minimum: 1 }),
|
|
12250
|
+
limit: int("Item per halaman.", { minimum: 1, maximum: 100 })
|
|
12251
|
+
};
|
|
12252
|
+
listQuery = (a) => query({ projectId: s(a.project), status: s(a.status), page: n(a.page)?.toString(), limit: n(a.limit)?.toString() });
|
|
12253
|
+
SESSION = [
|
|
12254
|
+
{
|
|
12255
|
+
name: "hanoman_lead_inbox",
|
|
12256
|
+
title: "Inbox sesi lead",
|
|
12257
|
+
description: "Event yang diantarkan ke sesi hanoman-lead, terbaru dulu: pertanyaan sesi pekerja (`ask`), sesi selesai/gagal (`session-ended`), pilihan backlog (`pulse`), penolakan manusia (`rejected`), integrasi gagal (`integrate-failed`). `status`: `open` (menunggu diantar), `delivered` (sudah di pane lead), `done`, `late` (lewat tenggat \u2192 manusia), `human` (diambil manusia).",
|
|
12258
|
+
inputSchema: obj({ properties: listParams }),
|
|
12259
|
+
mode: "read",
|
|
12260
|
+
capability: "lead:read",
|
|
12261
|
+
samplePath: "/lead/inbox",
|
|
12262
|
+
sampleMethod: "GET",
|
|
12263
|
+
build: (a) => ({ method: "GET", path: "/lead/inbox", query: listQuery(a) }),
|
|
12264
|
+
shape: (raw) => raw
|
|
12265
|
+
},
|
|
12266
|
+
{
|
|
12267
|
+
name: "hanoman_lead_inbox_take",
|
|
12268
|
+
title: "Ambil alih event lead",
|
|
12269
|
+
description: "Mengambil satu event inbox dari sesi lead supaya MANUSIA yang memutuskannya. Jawaban lead yang datang sesudahnya ditolak server. Event yang sudah ditutup menjawab 409.",
|
|
12270
|
+
inputSchema: obj({ properties: { event: str("Id event, dari hanoman_lead_inbox.") }, required: ["event"] }),
|
|
12271
|
+
mode: "write",
|
|
12272
|
+
capability: "lead:write",
|
|
12273
|
+
samplePath: "/lead/inbox/e1/take",
|
|
12274
|
+
sampleMethod: "POST",
|
|
12275
|
+
build: (a) => ({ method: "POST", path: `/lead/inbox/${enc(String(a.event))}/take` }),
|
|
12276
|
+
shape: (raw) => raw
|
|
12277
|
+
},
|
|
12278
|
+
{
|
|
12279
|
+
name: "hanoman_lead_approvals_list",
|
|
12280
|
+
title: "Tindakan lead yang menunggu izin",
|
|
12281
|
+
description: "Tindakan hanoman-lead yang ditahan gerbang server menunggu izin manusia (mis. merge ke branch target, jawaban yang menyentuh produksi/kredensial). Tiap kartu membawa `reason` lead, `evidence` yang ia periksa, dan `gateReport` dari server. `status`: `pending`, `approved`, `rejected`, `expired` (kedaluwarsa = ditolak).",
|
|
12282
|
+
inputSchema: obj({ properties: listParams }),
|
|
12283
|
+
mode: "read",
|
|
12284
|
+
capability: "lead:read",
|
|
12285
|
+
samplePath: "/lead/approvals",
|
|
12286
|
+
sampleMethod: "GET",
|
|
12287
|
+
build: (a) => ({ method: "GET", path: "/lead/approvals", query: listQuery(a) }),
|
|
12288
|
+
shape: (raw) => raw
|
|
12289
|
+
},
|
|
12290
|
+
{
|
|
12291
|
+
name: "hanoman_lead_approval_decide",
|
|
12292
|
+
title: "Setujui/tolak tindakan lead (BERBAHAYA)",
|
|
12293
|
+
description: "BERBAHAYA \u2014 menyetujui atau menolak tindakan hanoman-lead yang menunggu izin. Menyetujui MENJALANKAN tindakan itu apa adanya, termasuk merge branch sesi ke branch target (server tetap menjalankan verifikasinya lebih dulu). Baca dulu kartunya lewat hanoman_lead_approvals_list. Penolakan dikirim balik ke lead beserta `note`. Izin yang sudah diputuskan menjawab 409. Butuh capability `lead:approve`. Hanya muncul saat tingkat `--danger` menyala.",
|
|
12294
|
+
inputSchema: obj({
|
|
12295
|
+
properties: {
|
|
12296
|
+
approval: str("Id izin, dari hanoman_lead_approvals_list."),
|
|
12297
|
+
approve: bool("`true` = setujui, `false` = tolak."),
|
|
12298
|
+
note: str("Opsional. Catatan untuk lead, maksimum 2000 karakter.")
|
|
12299
|
+
},
|
|
12300
|
+
required: ["approval", "approve"]
|
|
12301
|
+
}),
|
|
12302
|
+
mode: "danger",
|
|
12303
|
+
capability: "lead:approve",
|
|
12304
|
+
samplePath: "/lead/approvals/a1/decide",
|
|
12305
|
+
sampleMethod: "POST",
|
|
12306
|
+
build: (a) => ({
|
|
12307
|
+
method: "POST",
|
|
12308
|
+
path: `/lead/approvals/${enc(String(a.approval))}/decide`,
|
|
12309
|
+
body: { approve: a.approve === true, ...s(a.note) ? { note: a.note } : {} }
|
|
12310
|
+
}),
|
|
12311
|
+
shape: (raw) => raw
|
|
12312
|
+
},
|
|
12313
|
+
...["start", "stop", "rotate"].map((op) => ({
|
|
12314
|
+
name: `hanoman_lead_session_${op}`,
|
|
12315
|
+
title: op === "start" ? "Mulai sesi lead (BERBAHAYA)" : op === "stop" ? "Hentikan sesi lead (BERBAHAYA)" : "Rotasi sesi lead (BERBAHAYA)",
|
|
12316
|
+
description: op === "start" ? "BERBAHAYA \u2014 melahirkan pane `lead-<proyek>` (agen hidup yang menjawab pertanyaan sesi pekerja, memilih backlog, dan memutuskan nasib sesi yang selesai). 409 = lead tak aktif/proyek belum opt-in atau belum di-bind, atau pane sedang backoff sesudah gagal lahir. Hanya muncul saat tingkat `--danger` menyala." : op === "stop" ? "BERBAHAYA \u2014 menghentikan pane lead proyek. Pertanyaan sesi pekerja jatuh ke manusia sampai pane lahir lagi (tick lead melahirkannya kembali bila inbox berisi dan lead tak dijeda \u2014 jeda proyeknya untuk benar-benar menghentikan). Hanya muncul saat tingkat `--danger` menyala." : "BERBAHAYA \u2014 menghentikan pane lead lalu melahirkannya lagi dengan konteks bersih (state ada di DB). Event yang sedang diproses dikembalikan ke inbox oleh sapuan. Hanya muncul saat tingkat `--danger` menyala.",
|
|
12317
|
+
inputSchema: obj({ properties: { project: str("Id proyek.") }, required: ["project"] }),
|
|
12318
|
+
mode: "danger",
|
|
12319
|
+
capability: "lead:write",
|
|
12320
|
+
samplePath: `/lead/sessions/p1/${op}`,
|
|
12321
|
+
sampleMethod: "POST",
|
|
12322
|
+
build: (a) => ({ method: "POST", path: `/lead/sessions/${enc(String(a.project))}/${op}` }),
|
|
12323
|
+
shape: (raw) => raw
|
|
12324
|
+
}))
|
|
12325
|
+
];
|
|
12326
|
+
LEAD_TOOLS = [...CORE6, ...MORE5, ...SESSION];
|
|
12217
12327
|
}
|
|
12218
12328
|
});
|
|
12219
12329
|
|
|
@@ -13470,13 +13580,13 @@ var init_transfer = __esm({
|
|
|
13470
13580
|
});
|
|
13471
13581
|
|
|
13472
13582
|
// ../shared/src/mcp-catalog/gates.ts
|
|
13473
|
-
var
|
|
13583
|
+
var SESSION2, CRON, intArray, DECIDE_NOTE, DIALOG, SPAWN_NOTE, CRON_FIELDS, CRONS, GATES_TOOLS;
|
|
13474
13584
|
var init_gates = __esm({
|
|
13475
13585
|
"../shared/src/mcp-catalog/gates.ts"() {
|
|
13476
13586
|
"use strict";
|
|
13477
13587
|
init_mcp_schema();
|
|
13478
13588
|
init_helpers();
|
|
13479
|
-
|
|
13589
|
+
SESSION2 = str("Id sesi hidup, dari hanoman_sessions_list.");
|
|
13480
13590
|
CRON = str("Id cron, dari hanoman_scheduler_crons_list.");
|
|
13481
13591
|
intArray = (description) => ({ type: "array", description, items: { type: "integer", minimum: 1 }, maxItems: 32 });
|
|
13482
13592
|
DECIDE_NOTE = "Menuntut capability `sessions:decide` (BUKAN `sessions:write`). Server menolak 403 bila token ini yang meluncurkan sesi tersebut, atau bila panggilan datang dari dalam sebuah sesi hanoman \u2014 agen tak boleh memutuskan pertanyaan sesinya sendiri.";
|
|
@@ -13485,7 +13595,7 @@ var init_gates = __esm({
|
|
|
13485
13595
|
name: "hanoman_session_dialog_get",
|
|
13486
13596
|
title: "Baca dialog pertanyaan sesi (BERBAHAYA)",
|
|
13487
13597
|
description: `BERBAHAYA \u2014 membaca dialog AskUserQuestion yang sedang tampil di pane sebuah sesi: judul, opsi bernomor, dan \`screenHash\` yang wajib dikirim balik saat menjawab. Hasil kosong (\`dialog: null\`) berarti layar bukan dialog yang bisa dijawab (atau sesinya sudah berakhir). Dialog trust & prompt izin sengaja TIDAK pernah muncul di sini. ${DECIDE_NOTE} Hanya muncul saat tingkat \`--danger\` menyala.`,
|
|
13488
|
-
inputSchema: obj({ properties: { session:
|
|
13598
|
+
inputSchema: obj({ properties: { session: SESSION2 }, required: ["session"] }),
|
|
13489
13599
|
mode: "danger",
|
|
13490
13600
|
capability: "sessions:decide",
|
|
13491
13601
|
samplePath: "/terminal/sessions/s1/dialog",
|
|
@@ -13499,7 +13609,7 @@ var init_gates = __esm({
|
|
|
13499
13609
|
description: `BERBAHAYA \u2014 mengetikkan jawaban ke dialog AskUserQuestion sebuah sesi; sesi langsung bergerak dan tak ada undo. Ambil \`screenHash\` dari hanoman_session_dialog_get tepat sebelumnya: 409 \`stale\` berarti layar sudah berganti \u2014 baca ulang, jangan menebak. 409 \`deciding\` berarti hanoman-lead sedang menyusun keputusan untuk sesi itu (jangan dipaksa; rebut dulu lewat hanoman_session_dialog_takeover bila memang perlu). 409 \`answering\` berarti jawaban lain sedang dikirim. Isi TEPAT SATU bentuk: \`choice\` (single-select), \`choices\` (multi-select; [] = kosongkan semua lalu submit), atau \`text\` (prosa untuk kolom bebas/catatan; boleh menyertai \`choices\`). ${DECIDE_NOTE} Ini gerbang "manusia yang memutuskan": jawablah hanya atas instruksi manusia. Hanya muncul saat tingkat \`--danger\` menyala.`,
|
|
13500
13610
|
inputSchema: obj({
|
|
13501
13611
|
properties: {
|
|
13502
|
-
session:
|
|
13612
|
+
session: SESSION2,
|
|
13503
13613
|
screenHash: str("Nilai `screenHash` dari hanoman_session_dialog_get untuk layar yang sedang dijawab."),
|
|
13504
13614
|
choice: int("Nomor baris opsi (`options[].n`) untuk dialog single-select.", { minimum: 1 }),
|
|
13505
13615
|
choices: intArray("Nomor baris yang dicentang untuk dialog multi-select; [] mengosongkan semuanya. Tak boleh bersama `choice`."),
|
|
@@ -13524,7 +13634,7 @@ var init_gates = __esm({
|
|
|
13524
13634
|
name: "hanoman_session_dialog_takeover",
|
|
13525
13635
|
title: "Rebut sesi dari hanoman-lead (BERBAHAYA)",
|
|
13526
13636
|
description: `BERBAHAYA \u2014 merebut sesi yang pertanyaannya sedang ditangani hanoman-lead: lead dibatalkan dan hanya pemegang \`sessions:decide\` yang bisa menjawab sesudahnya. 404 berarti tak ada pertanyaan hidup untuk sesi itu; 409 \`answering\` berarti lead sudah terlanjur mengetik jawabannya ke pane (rebutan kalah). ${DECIDE_NOTE} Hanya muncul saat tingkat \`--danger\` menyala.`,
|
|
13527
|
-
inputSchema: obj({ properties: { session:
|
|
13637
|
+
inputSchema: obj({ properties: { session: SESSION2 }, required: ["session"] }),
|
|
13528
13638
|
mode: "danger",
|
|
13529
13639
|
capability: "sessions:decide",
|
|
13530
13640
|
samplePath: "/terminal/sessions/s1/dialog/takeover",
|