hanoman 0.9.31 → 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 +290 -154
- package/dist/server.js +21875 -20313
- 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/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({
|
|
@@ -6783,7 +6801,11 @@ var init_session_admission = __esm({
|
|
|
6783
6801
|
});
|
|
6784
6802
|
|
|
6785
6803
|
// ../shared/src/dto.ts
|
|
6786
|
-
|
|
6804
|
+
function parseExitIntent(text) {
|
|
6805
|
+
const m = /^(\d+) (\d+)\s*$/.exec(text ?? "");
|
|
6806
|
+
return m ? { pid: Number(m[1]), code: Number(m[2]) } : null;
|
|
6807
|
+
}
|
|
6808
|
+
var zIssueDeviceToken, zSessionResult, zSessionHistory, zCreateProject, zProjectId, zRenameProject, zUpdateProject, zCreateSpec, zPatchSpec, zChangeSpecSource, zMarkSpecDone, zMarkSpecReviewed, zIntegrate, zSessionSummary, zProjectView, zSchedulerQueueItem, zSchedulerSourceView, zSchedulerSessionView, zSchedulerQueueCounts, zSchedulerState, zLeadDecisionView, zLeadFlowView, zLeadAnswer, zLeadProjectStatus, zLeadStatusView, zFlow, zPrdBrief, zPrdDoc, zBreakdownItem, zBreakdownDoc, zBatchCreateSpec, zEscalationTarget, zEscalationPrefill, zAuditEscalation, zAuditEscalationView, zTerminalSession, zDocFileContent, zDocIndexCat, zDocIndex, HOST_RE, USER_RE, zCreateVps, zPatchVps, USER_ROLES, zUserRole, zLogin, zSignup, zSetup, zSetupApply, zChangePassword, zAdminPasswordReset, zCreateClientAccount, zUpdateClientAccount, zVpsCheck, zMarkNa, zMarkNaBulk, zAttest, zRemediate, PROVISION_PROFILES, COMPONENT_IDS, zProvision, UPDATE_RESTART_EXIT, CONFIG_RESTART_EXIT, MANUAL_RESTART_EXIT, EXIT_INTENT_FILE, zUpdateApplyBody, MAX_SUBS, zSubPage, zSubLimit, zTopicParams, zEventsClientMsg, zTicketView, zTicketAttachmentView, zSpecAttachmentView, zTicketDetail, zTicketEditInput, zHelpInfo, zPublicTicketStatus, zCronExpr, zCreateCron, zPatchCron, zSchedulerCron, zSchedulerCronRun;
|
|
6787
6809
|
var init_dto = __esm({
|
|
6788
6810
|
"../shared/src/dto.ts"() {
|
|
6789
6811
|
"use strict";
|
|
@@ -7082,7 +7104,12 @@ var init_dto = __esm({
|
|
|
7082
7104
|
inFlight: external_exports.number(),
|
|
7083
7105
|
queued: external_exports.number(),
|
|
7084
7106
|
capacity: external_exports.number()
|
|
7085
|
-
}).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([])
|
|
7086
7113
|
});
|
|
7087
7114
|
zFlow = external_exports.enum(["feature", "qa", "scaffold", "reverse", "prd", "audit", "breakdown", "goal", "no_effort"]);
|
|
7088
7115
|
zPrdBrief = external_exports.object({
|
|
@@ -7317,6 +7344,7 @@ var init_dto = __esm({
|
|
|
7317
7344
|
UPDATE_RESTART_EXIT = 75;
|
|
7318
7345
|
CONFIG_RESTART_EXIT = 76;
|
|
7319
7346
|
MANUAL_RESTART_EXIT = 77;
|
|
7347
|
+
EXIT_INTENT_FILE = "exit-intent";
|
|
7320
7348
|
zUpdateApplyBody = external_exports.object({ confirm: external_exports.boolean().optional() });
|
|
7321
7349
|
MAX_SUBS = 16;
|
|
7322
7350
|
zSubPage = external_exports.number().int().min(1).max(1e4);
|
|
@@ -7735,6 +7763,10 @@ var init_api = __esm({
|
|
|
7735
7763
|
leadFlows: `${API}/lead/flows`,
|
|
7736
7764
|
leadFlowSubmit: (id) => `${API}/lead/flows/${encodeURIComponent(id)}/submit`,
|
|
7737
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}`,
|
|
7738
7770
|
// SPEC-450 · ADR-0094 · katalog custom agent. `?projectId=` → himpunan EFEKTIF (global+project).
|
|
7739
7771
|
customAgents: `${API}/custom-agents`,
|
|
7740
7772
|
customAgentMetrics: `${API}/custom-agents/metrics`,
|
|
@@ -7929,7 +7961,10 @@ var init_session_kind = __esm({
|
|
|
7929
7961
|
"shell",
|
|
7930
7962
|
"worktree",
|
|
7931
7963
|
"terminal",
|
|
7932
|
-
"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"
|
|
7933
7968
|
];
|
|
7934
7969
|
zSessionKind = external_exports.enum(SESSION_KINDS);
|
|
7935
7970
|
}
|
|
@@ -12005,7 +12040,7 @@ var init_support = __esm({
|
|
|
12005
12040
|
});
|
|
12006
12041
|
|
|
12007
12042
|
// ../shared/src/mcp-catalog/lead.ts
|
|
12008
|
-
var CORE6, MORE5, LEAD_TOOLS;
|
|
12043
|
+
var CORE6, MORE5, listParams, listQuery, SESSION, LEAD_TOOLS;
|
|
12009
12044
|
var init_lead2 = __esm({
|
|
12010
12045
|
"../shared/src/mcp-catalog/lead.ts"() {
|
|
12011
12046
|
"use strict";
|
|
@@ -12043,7 +12078,7 @@ var init_lead2 = __esm({
|
|
|
12043
12078
|
{
|
|
12044
12079
|
name: "hanoman_lead_ask",
|
|
12045
12080
|
title: "Minta putusan hanoman-lead",
|
|
12046
|
-
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.",
|
|
12047
12082
|
inputSchema: obj({
|
|
12048
12083
|
properties: {
|
|
12049
12084
|
project: str("Id proyek."),
|
|
@@ -12208,7 +12243,87 @@ var init_lead2 = __esm({
|
|
|
12208
12243
|
shape: (raw) => raw
|
|
12209
12244
|
}
|
|
12210
12245
|
];
|
|
12211
|
-
|
|
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];
|
|
12212
12327
|
}
|
|
12213
12328
|
});
|
|
12214
12329
|
|
|
@@ -13465,13 +13580,13 @@ var init_transfer = __esm({
|
|
|
13465
13580
|
});
|
|
13466
13581
|
|
|
13467
13582
|
// ../shared/src/mcp-catalog/gates.ts
|
|
13468
|
-
var
|
|
13583
|
+
var SESSION2, CRON, intArray, DECIDE_NOTE, DIALOG, SPAWN_NOTE, CRON_FIELDS, CRONS, GATES_TOOLS;
|
|
13469
13584
|
var init_gates = __esm({
|
|
13470
13585
|
"../shared/src/mcp-catalog/gates.ts"() {
|
|
13471
13586
|
"use strict";
|
|
13472
13587
|
init_mcp_schema();
|
|
13473
13588
|
init_helpers();
|
|
13474
|
-
|
|
13589
|
+
SESSION2 = str("Id sesi hidup, dari hanoman_sessions_list.");
|
|
13475
13590
|
CRON = str("Id cron, dari hanoman_scheduler_crons_list.");
|
|
13476
13591
|
intArray = (description) => ({ type: "array", description, items: { type: "integer", minimum: 1 }, maxItems: 32 });
|
|
13477
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.";
|
|
@@ -13480,7 +13595,7 @@ var init_gates = __esm({
|
|
|
13480
13595
|
name: "hanoman_session_dialog_get",
|
|
13481
13596
|
title: "Baca dialog pertanyaan sesi (BERBAHAYA)",
|
|
13482
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.`,
|
|
13483
|
-
inputSchema: obj({ properties: { session:
|
|
13598
|
+
inputSchema: obj({ properties: { session: SESSION2 }, required: ["session"] }),
|
|
13484
13599
|
mode: "danger",
|
|
13485
13600
|
capability: "sessions:decide",
|
|
13486
13601
|
samplePath: "/terminal/sessions/s1/dialog",
|
|
@@ -13494,7 +13609,7 @@ var init_gates = __esm({
|
|
|
13494
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.`,
|
|
13495
13610
|
inputSchema: obj({
|
|
13496
13611
|
properties: {
|
|
13497
|
-
session:
|
|
13612
|
+
session: SESSION2,
|
|
13498
13613
|
screenHash: str("Nilai `screenHash` dari hanoman_session_dialog_get untuk layar yang sedang dijawab."),
|
|
13499
13614
|
choice: int("Nomor baris opsi (`options[].n`) untuk dialog single-select.", { minimum: 1 }),
|
|
13500
13615
|
choices: intArray("Nomor baris yang dicentang untuk dialog multi-select; [] mengosongkan semuanya. Tak boleh bersama `choice`."),
|
|
@@ -13519,7 +13634,7 @@ var init_gates = __esm({
|
|
|
13519
13634
|
name: "hanoman_session_dialog_takeover",
|
|
13520
13635
|
title: "Rebut sesi dari hanoman-lead (BERBAHAYA)",
|
|
13521
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.`,
|
|
13522
|
-
inputSchema: obj({ properties: { session:
|
|
13637
|
+
inputSchema: obj({ properties: { session: SESSION2 }, required: ["session"] }),
|
|
13523
13638
|
mode: "danger",
|
|
13524
13639
|
capability: "sessions:decide",
|
|
13525
13640
|
samplePath: "/terminal/sessions/s1/dialog/takeover",
|
|
@@ -16187,13 +16302,14 @@ __export(start_exports, {
|
|
|
16187
16302
|
parseStartArgs: () => parseStartArgs,
|
|
16188
16303
|
planSupervisorStep: () => planSupervisorStep,
|
|
16189
16304
|
prismaClientUsable: () => prismaClientUsable,
|
|
16305
|
+
resolveChildExit: () => resolveChildExit,
|
|
16190
16306
|
serverEnv: () => serverEnv,
|
|
16191
16307
|
spawnEnv: () => spawnEnv
|
|
16192
16308
|
});
|
|
16193
16309
|
import { spawn, execFileSync as execFileSync3 } from "node:child_process";
|
|
16194
16310
|
import { createRequire as createRequire2 } from "node:module";
|
|
16195
|
-
import { existsSync as existsSync3, mkdirSync as mkdirSync2, chmodSync as chmodSync3 } from "node:fs";
|
|
16196
|
-
import { dirname as dirname4, resolve as resolvePath } from "node:path";
|
|
16311
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2, chmodSync as chmodSync3, readFileSync as readFileSync3, rmSync } from "node:fs";
|
|
16312
|
+
import { dirname as dirname4, join as join6, resolve as resolvePath } from "node:path";
|
|
16197
16313
|
import { fileURLToPath } from "node:url";
|
|
16198
16314
|
function parseStartArgs(argv) {
|
|
16199
16315
|
const out = { port: null, host: null, db: null, migrate: true };
|
|
@@ -16318,6 +16434,23 @@ function installLatest() {
|
|
|
16318
16434
|
function spawnEnv(fileEnv, processEnv, server) {
|
|
16319
16435
|
return { ...fileEnv, ...processEnv, ...server };
|
|
16320
16436
|
}
|
|
16437
|
+
function resolveChildExit(exit, intentText) {
|
|
16438
|
+
const intent = parseExitIntent(intentText);
|
|
16439
|
+
if (exit.signal === "SIGKILL" && intent && exit.pid !== void 0 && intent.pid === exit.pid) {
|
|
16440
|
+
return { code: intent.code, forced: true };
|
|
16441
|
+
}
|
|
16442
|
+
return { code: exit.code ?? 0, forced: false };
|
|
16443
|
+
}
|
|
16444
|
+
function takeExitIntent(home) {
|
|
16445
|
+
const path = join6(home, EXIT_INTENT_FILE);
|
|
16446
|
+
try {
|
|
16447
|
+
const text = readFileSync3(path, "utf8");
|
|
16448
|
+
rmSync(path, { force: true });
|
|
16449
|
+
return text;
|
|
16450
|
+
} catch {
|
|
16451
|
+
return null;
|
|
16452
|
+
}
|
|
16453
|
+
}
|
|
16321
16454
|
function runServer(serverJs, env, fileEnv) {
|
|
16322
16455
|
const child = spawn(process.execPath, [serverJs], {
|
|
16323
16456
|
stdio: "inherit",
|
|
@@ -16325,9 +16458,9 @@ function runServer(serverJs, env, fileEnv) {
|
|
|
16325
16458
|
});
|
|
16326
16459
|
const handlers = ["SIGINT", "SIGTERM"].map((sig) => [sig, () => child.kill(sig)]);
|
|
16327
16460
|
for (const [sig, h] of handlers) process.on(sig, h);
|
|
16328
|
-
return new Promise((res) => child.on("exit", (code) => {
|
|
16461
|
+
return new Promise((res) => child.on("exit", (code, signal) => {
|
|
16329
16462
|
for (const [sig, h] of handlers) process.off(sig, h);
|
|
16330
|
-
res(code
|
|
16463
|
+
res({ code, signal, pid: child.pid });
|
|
16331
16464
|
}));
|
|
16332
16465
|
}
|
|
16333
16466
|
async function start(argv, ctx) {
|
|
@@ -16386,7 +16519,10 @@ ${hint}
|
|
|
16386
16519
|
let restartsUsed = 0;
|
|
16387
16520
|
let configRestartsUsed = 0;
|
|
16388
16521
|
for (; ; ) {
|
|
16389
|
-
const
|
|
16522
|
+
const exit = await runServer(layout.server, env, readConfigEnv(home));
|
|
16523
|
+
const { code, forced } = resolveChildExit(exit, takeExitIntent(home));
|
|
16524
|
+
if (forced) ctx.stderr(`hanoman: server macet saat keluar \u2014 dihentikan watchdog; dilanjutkan sebagai exit ${code} (ADR-0227)
|
|
16525
|
+
`);
|
|
16390
16526
|
const step = planSupervisorStep(code, restartsUsed, configRestartsUsed);
|
|
16391
16527
|
if (step.action === "exit") {
|
|
16392
16528
|
if (code === UPDATE_RESTART_EXIT) {
|
|
@@ -37833,7 +37969,7 @@ __export(mcp_exports, {
|
|
|
37833
37969
|
agentTokenPath: () => agentTokenPath,
|
|
37834
37970
|
default: () => mcp
|
|
37835
37971
|
});
|
|
37836
|
-
import { readFileSync as
|
|
37972
|
+
import { readFileSync as readFileSync4 } from "node:fs";
|
|
37837
37973
|
import { join as join8 } from "node:path";
|
|
37838
37974
|
async function mcp(argv, ctx) {
|
|
37839
37975
|
const cfg = resolveMcpConfig(argv, ctx.env, () => tokenFile(ctx.env));
|
|
@@ -37868,7 +38004,7 @@ var init_mcp2 = __esm({
|
|
|
37868
38004
|
agentTokenPath = (env) => join8(resolveHome(env), "agent-token");
|
|
37869
38005
|
tokenFile = (env) => {
|
|
37870
38006
|
try {
|
|
37871
|
-
return
|
|
38007
|
+
return readFileSync4(agentTokenPath(env), "utf8");
|
|
37872
38008
|
} catch {
|
|
37873
38009
|
return null;
|
|
37874
38010
|
}
|
|
@@ -38209,11 +38345,11 @@ var init_migrate_pg = __esm({
|
|
|
38209
38345
|
});
|
|
38210
38346
|
|
|
38211
38347
|
// src/config.ts
|
|
38212
|
-
import { readFileSync as
|
|
38348
|
+
import { readFileSync as readFileSync5, existsSync as existsSync7 } from "node:fs";
|
|
38213
38349
|
import { join as join10 } from "node:path";
|
|
38214
38350
|
function loadConfig(repoRoot) {
|
|
38215
38351
|
const p3 = join10(repoRoot, "hanoman.config.json");
|
|
38216
|
-
const raw = existsSync7(p3) ? JSON.parse(
|
|
38352
|
+
const raw = existsSync7(p3) ? JSON.parse(readFileSync5(p3, "utf8")) : {};
|
|
38217
38353
|
return zHanomanConfig.parse(raw);
|
|
38218
38354
|
}
|
|
38219
38355
|
var init_config3 = __esm({
|
|
@@ -38240,10 +38376,10 @@ var init_repo = __esm({
|
|
|
38240
38376
|
});
|
|
38241
38377
|
|
|
38242
38378
|
// src/docs-model.ts
|
|
38243
|
-
import { readFileSync as
|
|
38379
|
+
import { readFileSync as readFileSync6, readdirSync as readdirSync3, statSync as statSync2 } from "node:fs";
|
|
38244
38380
|
import { join as join12, relative as relative2 } from "node:path";
|
|
38245
38381
|
function parseIndex(indexPath) {
|
|
38246
|
-
const md =
|
|
38382
|
+
const md = readFileSync6(indexPath, "utf8");
|
|
38247
38383
|
const out = /* @__PURE__ */ new Set();
|
|
38248
38384
|
for (const m of md.matchAll(LINK_RE2)) {
|
|
38249
38385
|
let t = m[1].trim();
|
|
@@ -38291,7 +38427,7 @@ var init_docs_model = __esm({
|
|
|
38291
38427
|
|
|
38292
38428
|
// src/verify.ts
|
|
38293
38429
|
import { join as join13 } from "node:path";
|
|
38294
|
-
import { existsSync as existsSync8, readFileSync as
|
|
38430
|
+
import { existsSync as existsSync8, readFileSync as readFileSync7 } from "node:fs";
|
|
38295
38431
|
function scanCoverage(cwd) {
|
|
38296
38432
|
const { root, docsDir, indexPath } = resolveRepo(cwd);
|
|
38297
38433
|
const docsRoot = join13(root, docsDir);
|
|
@@ -38300,7 +38436,7 @@ function scanCoverage(cwd) {
|
|
|
38300
38436
|
const corpus = walkDocs(docsRoot);
|
|
38301
38437
|
const read = (rel) => {
|
|
38302
38438
|
try {
|
|
38303
|
-
return
|
|
38439
|
+
return readFileSync7(join13(docsRoot, rel), "utf8");
|
|
38304
38440
|
} catch {
|
|
38305
38441
|
return null;
|
|
38306
38442
|
}
|
|
@@ -38343,9 +38479,9 @@ var init_docs_scan = __esm({
|
|
|
38343
38479
|
});
|
|
38344
38480
|
|
|
38345
38481
|
// src/index-edit.ts
|
|
38346
|
-
import { readFileSync as
|
|
38482
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync2 } from "node:fs";
|
|
38347
38483
|
function addLink(indexPath, relPath, category) {
|
|
38348
|
-
let md =
|
|
38484
|
+
let md = readFileSync8(indexPath, "utf8");
|
|
38349
38485
|
if (md.includes(`(${relPath})`)) return;
|
|
38350
38486
|
const base2 = relPath.split("/").pop().replace(/\.md$/, "");
|
|
38351
38487
|
const line = `- [${base2}](${relPath})`;
|
|
@@ -38375,7 +38511,7 @@ __export(docs_index_exports, {
|
|
|
38375
38511
|
});
|
|
38376
38512
|
import { parseArgs as parseArgs2 } from "node:util";
|
|
38377
38513
|
import { join as join14 } from "node:path";
|
|
38378
|
-
import { existsSync as existsSync9, readFileSync as
|
|
38514
|
+
import { existsSync as existsSync9, readFileSync as readFileSync9 } from "node:fs";
|
|
38379
38515
|
async function docs_index_default(args, ctx) {
|
|
38380
38516
|
const { values } = parseArgs2({ args, options: { check: { type: "boolean" }, fix: { type: "boolean" } }, allowPositionals: true });
|
|
38381
38517
|
const { root, docsDir, indexPath } = resolveRepo(ctx.cwd);
|
|
@@ -38383,7 +38519,7 @@ async function docs_index_default(args, ctx) {
|
|
|
38383
38519
|
const corpus = walkDocs(docsRoot);
|
|
38384
38520
|
const read = (rel) => {
|
|
38385
38521
|
try {
|
|
38386
|
-
return
|
|
38522
|
+
return readFileSync9(join14(docsRoot, rel), "utf8");
|
|
38387
38523
|
} catch {
|
|
38388
38524
|
return null;
|
|
38389
38525
|
}
|
|
@@ -38548,10 +38684,10 @@ var pack_exports = {};
|
|
|
38548
38684
|
__export(pack_exports, {
|
|
38549
38685
|
default: () => pack
|
|
38550
38686
|
});
|
|
38551
|
-
import { cpSync, existsSync as existsSync10, mkdirSync as mkdirSync3, readFileSync as
|
|
38687
|
+
import { cpSync, existsSync as existsSync10, mkdirSync as mkdirSync3, readFileSync as readFileSync10, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "node:fs";
|
|
38552
38688
|
import { dirname as dirname8, join as join16 } from "node:path";
|
|
38553
38689
|
function depVersions(repo) {
|
|
38554
|
-
const read = (p3) => JSON.parse(
|
|
38690
|
+
const read = (p3) => JSON.parse(readFileSync10(join16(repo, p3), "utf8"));
|
|
38555
38691
|
const server = read("server/package.json"), cli = read("cli/package.json");
|
|
38556
38692
|
const pools = [server.dependencies, server.devDependencies, cli.dependencies, cli.devDependencies];
|
|
38557
38693
|
const out = {};
|
|
@@ -38577,7 +38713,7 @@ async function pack(argv, ctx) {
|
|
|
38577
38713
|
}
|
|
38578
38714
|
const outIdx = argv.indexOf("--out");
|
|
38579
38715
|
const out = outIdx === -1 ? join16(repo, "dist-npm") : join16(repo, argv[outIdx + 1] ?? "dist-npm");
|
|
38580
|
-
const version2 = JSON.parse(
|
|
38716
|
+
const version2 = JSON.parse(readFileSync10(join16(repo, "package.json"), "utf8")).version;
|
|
38581
38717
|
if (!version2) {
|
|
38582
38718
|
ctx.stderr("pack: root package.json tanpa field version\n");
|
|
38583
38719
|
return 1;
|
|
@@ -38590,7 +38726,7 @@ async function pack(argv, ctx) {
|
|
|
38590
38726
|
`);
|
|
38591
38727
|
return 1;
|
|
38592
38728
|
}
|
|
38593
|
-
|
|
38729
|
+
rmSync2(out, { recursive: true, force: true });
|
|
38594
38730
|
mkdirSync3(join16(out, "bin"), { recursive: true });
|
|
38595
38731
|
for (const item of copyPlan(repo)) {
|
|
38596
38732
|
if (!existsSync10(item.from)) {
|
|
@@ -38629,13 +38765,13 @@ var verify_packed_exports = {};
|
|
|
38629
38765
|
__export(verify_packed_exports, {
|
|
38630
38766
|
default: () => verifyPacked
|
|
38631
38767
|
});
|
|
38632
|
-
import { readFileSync as
|
|
38768
|
+
import { readFileSync as readFileSync11 } from "node:fs";
|
|
38633
38769
|
import { join as join17 } from "node:path";
|
|
38634
38770
|
function verifyPacked(_argv, ctx) {
|
|
38635
38771
|
const path = join17(process.cwd(), "package.json");
|
|
38636
38772
|
let pkg;
|
|
38637
38773
|
try {
|
|
38638
|
-
pkg = JSON.parse(
|
|
38774
|
+
pkg = JSON.parse(readFileSync11(path, "utf8"));
|
|
38639
38775
|
} catch {
|
|
38640
38776
|
ctx.stderr(`verify: tak bisa membaca ${path}
|
|
38641
38777
|
`);
|