hanoman 0.1.12 → 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.
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.1.12",
3
- "sha": "f88186c",
4
- "builtAt": "2026-08-01T11:46:59.162Z"
2
+ "version": "0.1.13",
3
+ "sha": "d971e65",
4
+ "builtAt": "2026-08-01T13:47:43.258Z"
5
5
  }
package/dist/cli.js CHANGED
@@ -4380,6 +4380,25 @@ var init_telegram = __esm({
4380
4380
  }
4381
4381
  });
4382
4382
 
4383
+ // ../shared/src/auto-merge.ts
4384
+ var AUTO_MERGE_MODES, zAutoMerge;
4385
+ var init_auto_merge = __esm({
4386
+ "../shared/src/auto-merge.ts"() {
4387
+ "use strict";
4388
+ init_zod();
4389
+ AUTO_MERGE_MODES = ["off", "default-branch", "branch"];
4390
+ zAutoMerge = external_exports.object({
4391
+ mode: external_exports.enum(AUTO_MERGE_MODES).default("off"),
4392
+ // Tujuan: `local` = perbarui ref/fast-forward di checkout ini; `origin` = push.
4393
+ dest: external_exports.enum(["local", "origin"]).default("local"),
4394
+ // Hanya bermakna saat mode = "branch". Untuk "default-branch" ia diresolve SAAT EKSEKUSI.
4395
+ branch: external_exports.string().min(1).nullable().default(null),
4396
+ // Hapus `hanoman/<spec>` (lokal + origin) — HANYA sesudah merge terbukti bersih.
4397
+ deleteBranch: external_exports.boolean().default(false)
4398
+ });
4399
+ }
4400
+ });
4401
+
4383
4402
  // ../shared/src/entities.ts
4384
4403
  var zProject, zBriefPayload, zQaPayload, zGoalPayload, zSpecBlocker, zSpec, NOTIFY_SOUNDS, zCodex, CODEX_DEFAULTS, zSourceCommon, zScheduler, SCHEDULER_DEFAULTS, zGoal, GOAL_DEFAULTS, zConflict, CONFLICT_DEFAULTS, zLeadEngine, zLead, LEAD_DEFAULTS, zSetting, zNotification, zDocFile, zDeviceTokenView;
4385
4404
  var init_entities = __esm({
@@ -4388,6 +4407,7 @@ var init_entities = __esm({
4388
4407
  init_zod();
4389
4408
  init_enums();
4390
4409
  init_telegram();
4410
+ init_auto_merge();
4391
4411
  zProject = external_exports.object({
4392
4412
  id: external_exports.string(),
4393
4413
  name: external_exports.string(),
@@ -4453,7 +4473,10 @@ var init_entities = __esm({
4453
4473
  dependsOn: external_exports.array(external_exports.string()).default([]),
4454
4474
  // Turunan (bukan kolom): dihitung `liveSpecs` dari stage dependency + git. Klien tak pernah
4455
4475
  // mengirimkannya — `.default([])` supaya bentuk lama tetap parse.
4456
- blockedBy: external_exports.array(zSpecBlocker).default([])
4476
+ blockedBy: external_exports.array(zSpecBlocker).default([]),
4477
+ // SPEC-486 · ADR-0103 · override kebijakan auto-merge item ini; null = warisi project.
4478
+ // `.nullable().default(null)` menjaga respons/klien versi lama tetap parse.
4479
+ autoMerge: zAutoMerge.nullable().default(null)
4457
4480
  });
4458
4481
  NOTIFY_SOUNDS = [
4459
4482
  "off",
@@ -4540,6 +4563,11 @@ var init_entities = __esm({
4540
4563
  // `requestTimeout: 0` (terukur dari `buildApp()`) — tak ada pihak lain yang akan memutus peminta.
4541
4564
  // 0 = tanpa antrean sama sekali: penuh berarti langsung ditolak.
4542
4565
  queueWaitSec: external_exports.number().int().min(0).max(900).default(120),
4566
+ // SPEC-485 · ADR-0102 · umur maksimum satu RANTAI keputusan yang dibiarkan terbuka. Peminta bisa
4567
+ // mati di tengah rantai (sesi ditutup, agen crash); tanpa batas ini alurnya `sebagian` selamanya
4568
+ // dan tak ada yang tahu apakah ia masih ditunggu. Penyapunya menumpang tick lead yang sudah ada —
4569
+ // ADR-0024 melarang timer/scheduler baru.
4570
+ flowTtlMin: external_exports.number().int().min(1).max(1440).default(60),
4543
4571
  // OQ-3 · syarat objektif sebelum lead boleh mengintegrasikan ke branch utama. Default MENYALA:
4544
4572
  // risiko "kode masuk main tanpa mata manusia" diterima sadar, tapi syaratnya tetap terukur.
4545
4573
  requireGreenBeforeIntegrate: external_exports.boolean().default(true),
@@ -4685,12 +4713,24 @@ var init_agent = __esm({
4685
4713
  });
4686
4714
 
4687
4715
  // ../shared/src/custom-agent.ts
4688
- var AGENT_NAME_RE, zCustomAgent, zCreateCustomAgent, zUpdateCustomAgent;
4716
+ var AGENT_RUNTIMES, zAgentRuntime, AGENT_NAME_RE, DEFAULT_AGENT_TOOLS, zCustomAgent, zCreateCustomAgent, zUpdateCustomAgent;
4689
4717
  var init_custom_agent = __esm({
4690
4718
  "../shared/src/custom-agent.ts"() {
4691
4719
  "use strict";
4692
4720
  init_zod();
4721
+ AGENT_RUNTIMES = ["claude", "codex"];
4722
+ zAgentRuntime = external_exports.enum(AGENT_RUNTIMES);
4693
4723
  AGENT_NAME_RE = /^[a-z][a-z0-9-]{1,39}$/;
4724
+ DEFAULT_AGENT_TOOLS = [
4725
+ "Read",
4726
+ "Write",
4727
+ "Edit",
4728
+ "Bash",
4729
+ "Glob",
4730
+ "Grep",
4731
+ "WebFetch",
4732
+ "WebSearch"
4733
+ ];
4694
4734
  zCustomAgent = external_exports.object({
4695
4735
  id: external_exports.string(),
4696
4736
  projectId: external_exports.string().nullable(),
@@ -4700,6 +4740,7 @@ var init_custom_agent = __esm({
4700
4740
  tools: external_exports.array(external_exports.string()).nullable(),
4701
4741
  model: external_exports.string().nullable(),
4702
4742
  mentions: external_exports.array(external_exports.string()).nullable(),
4743
+ runtime: external_exports.enum(AGENT_RUNTIMES).nullable(),
4703
4744
  enabled: external_exports.boolean(),
4704
4745
  createdAt: external_exports.string(),
4705
4746
  updatedAt: external_exports.string()
@@ -4712,12 +4753,29 @@ var init_custom_agent = __esm({
4712
4753
  tools: external_exports.array(external_exports.string()).nullable().optional(),
4713
4754
  model: external_exports.string().nullable().optional(),
4714
4755
  mentions: external_exports.array(external_exports.string()).nullable().optional(),
4756
+ // SPEC-484 · ADR-0101 · PENYARING mesin sesi, bukan pemilih proses. null/absen = ikut sesi induk.
4757
+ runtime: external_exports.enum(AGENT_RUNTIMES).nullable().optional(),
4715
4758
  enabled: external_exports.boolean().optional()
4716
4759
  });
4717
4760
  zUpdateCustomAgent = zCreateCustomAgent.omit({ name: true, projectId: true }).partial();
4718
4761
  }
4719
4762
  });
4720
4763
 
4764
+ // ../shared/src/agent-catalog.ts
4765
+ var BUILTIN_AGENT_TOOLS;
4766
+ var init_agent_catalog = __esm({
4767
+ "../shared/src/agent-catalog.ts"() {
4768
+ "use strict";
4769
+ init_custom_agent();
4770
+ init_entities();
4771
+ BUILTIN_AGENT_TOOLS = DEFAULT_AGENT_TOOLS.map((id) => ({
4772
+ id,
4773
+ label: id,
4774
+ group: "builtin"
4775
+ }));
4776
+ }
4777
+ });
4778
+
4721
4779
  // ../shared/src/github.ts
4722
4780
  var zGithubIssueStatus, zNormalIssue, zGithubIssueView;
4723
4781
  var init_github = __esm({
@@ -4749,7 +4807,7 @@ var init_github = __esm({
4749
4807
  });
4750
4808
 
4751
4809
  // ../shared/src/lead.ts
4752
- var zLeadGate, zLeadKind, zLeadConfidence, zLeadStatus, LEAD_ACTIONS, zLeadAction, zLeadChoice, zLeadVerdict, zLeadAsk, zLeadOverride;
4810
+ var zLeadGate, zLeadKind, zLeadConfidence, zLeadStatus, zLeadFlowStatus, LEAD_ACTIONS, zLeadAction, zLeadChoice, zLeadSelect, zLeadVerdict, zLeadAsk, zLeadOverride;
4753
4811
  var init_lead = __esm({
4754
4812
  "../shared/src/lead.ts"() {
4755
4813
  "use strict";
@@ -4758,6 +4816,7 @@ var init_lead = __esm({
4758
4816
  zLeadKind = external_exports.enum(["answer", "order", "collision", "quality", "refusal"]);
4759
4817
  zLeadConfidence = external_exports.enum(["tinggi", "sedang", "ragu"]);
4760
4818
  zLeadStatus = external_exports.enum(["berlaku", "ditimpa", "dibatalkan", "gagal"]);
4819
+ zLeadFlowStatus = external_exports.enum(["menunggu", "sebagian", "selesai", "dibatalkan"]);
4761
4820
  LEAD_ACTIONS = [
4762
4821
  "none",
4763
4822
  // keputusan murni jawaban; tak ada tindakan menyusul
@@ -4784,6 +4843,11 @@ var init_lead = __esm({
4784
4843
  ];
4785
4844
  zLeadAction = external_exports.enum(LEAD_ACTIONS);
4786
4845
  zLeadChoice = external_exports.object({ index: external_exports.number().int().positive(), option: external_exports.string() });
4846
+ zLeadSelect = external_exports.object({
4847
+ mode: external_exports.enum(["single", "multi"]).default("single"),
4848
+ min: external_exports.number().int().min(0).max(20).default(0),
4849
+ max: external_exports.number().int().min(1).max(20).nullable().default(null)
4850
+ });
4787
4851
  zLeadVerdict = external_exports.object({
4788
4852
  decision: external_exports.string().min(1),
4789
4853
  reason: external_exports.string().min(1),
@@ -4800,6 +4864,14 @@ var init_lead = __esm({
4800
4864
  * yang sama persis dengan `action` di atas.
4801
4865
  */
4802
4866
  choice: external_exports.string().default(""),
4867
+ /**
4868
+ * SPEC-485 · pilihan JAMAK. `string[]` dengan alasan yang sama persis seperti `choice` & `action`
4869
+ * di atas: pilihan di luar daftar harus BISA MASUK supaya server menolaknya secara sadar dan
4870
+ * mencatatnya. Kosong + `choice` terisi dibaca sebagai satu pilihan — keluaran agen berbentuk
4871
+ * ADR-0098 harus tetap terpakai, dan menuntut field baru berarti setiap agen lama mendadak
4872
+ * "tak memilih apa pun".
4873
+ */
4874
+ choices: external_exports.array(external_exports.string().max(2e3)).max(20).default([]),
4803
4875
  /**
4804
4876
  * SPEC-480 · apa yang KURANG bila konteksnya memang tak cukup untuk memutuskan. Bukan pengganti
4805
4877
  * `confidence: "ragu"` (bukti tipis, jawabannya tetap ada) melainkan untuk fakta konkret yang
@@ -4815,23 +4887,36 @@ var init_lead = __esm({
4815
4887
  sessionId: external_exports.string().nullish(),
4816
4888
  question: external_exports.string().min(1).max(8e3),
4817
4889
  options: external_exports.array(external_exports.string().max(2e3)).max(20).default([]),
4818
- context: external_exports.string().max(2e4).default("")
4890
+ context: external_exports.string().max(2e4).default(""),
4891
+ /** SPEC-485 · bentuk pilihan yang diminta peminta. Default = perilaku hari ini (single). */
4892
+ select: zLeadSelect.default({ mode: "single", min: 0, max: null }),
4893
+ /** `true` = peminta akan mengajukan pertanyaan lanjutan; alurnya dibiarkan terbuka sampai submit. */
4894
+ chain: external_exports.boolean().default(false),
4895
+ /** Lanjutkan rantai yang sudah ada. Alur tertutup ditolak 409 — bukan dibuatkan diam-diam. */
4896
+ flowId: external_exports.string().min(1).nullish().default(null)
4819
4897
  });
4820
4898
  zLeadOverride = external_exports.object({
4821
4899
  answer: external_exports.string().min(1).max(8e3),
4822
- reason: external_exports.string().max(8e3).default("")
4900
+ reason: external_exports.string().max(8e3).default(""),
4901
+ /**
4902
+ * SPEC-485 · centang operator sebagai DATA, bukan prosa. Dipetakan ke opsi baris yang ditimpa,
4903
+ * lalu ikut diketikkan ke pane — jadi manusia mencentang di dashboard dan kotaknya benar-benar
4904
+ * tercentang di dialog sesi.
4905
+ */
4906
+ choices: external_exports.array(external_exports.string().max(2e3)).max(20).default([])
4823
4907
  });
4824
4908
  }
4825
4909
  });
4826
4910
 
4827
4911
  // ../shared/src/dto.ts
4828
- var zIssueDeviceToken, zSessionResult, zSessionHistory, zCreateProject, zProjectId, zRenameProject, zUpdateProject, zCreateSpec, zPatchSpec, zIntegrate, zSessionSummary, zProjectView, zSchedulerQueueItem, zSchedulerSourceView, zSchedulerSessionView, zSchedulerState, zLeadDecisionView, zLeadAnswer, zLeadProjectStatus, zLeadStatusView, zFlow, zPrdBrief, zPrdDoc, zBreakdownItem, zBreakdownDoc, zBatchCreateSpec, zEscalationTarget, zEscalationPrefill, zAuditEscalation, zAuditEscalationView, zTerminalSession, zDocFileContent, zDocIndexCat, zDocIndex, HOST_RE, USER_RE, zCreateVps, zPatchVps, zLogin, zSignup, zChangePassword, zVpsCheck, zMarkNa, zMarkNaBulk, zAttest, zRemediate, UPDATE_RESTART_EXIT, zUpdateApplyBody, zTicketView, zTicketAttachmentView, zTicketDetail, zTicketEditInput, zHelpInfo, zPublicTicketStatus;
4912
+ var zIssueDeviceToken, zSessionResult, zSessionHistory, zCreateProject, zProjectId, zRenameProject, zUpdateProject, zCreateSpec, zPatchSpec, zIntegrate, zSessionSummary, zProjectView, zSchedulerQueueItem, zSchedulerSourceView, zSchedulerSessionView, 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, zLogin, zSignup, zChangePassword, zVpsCheck, zMarkNa, zMarkNaBulk, zAttest, zRemediate, UPDATE_RESTART_EXIT, zUpdateApplyBody, zTicketView, zTicketAttachmentView, zTicketDetail, zTicketEditInput, zHelpInfo, zPublicTicketStatus;
4829
4913
  var init_dto = __esm({
4830
4914
  "../shared/src/dto.ts"() {
4831
4915
  "use strict";
4832
4916
  init_zod();
4833
4917
  init_entities();
4834
4918
  init_lead();
4919
+ init_auto_merge();
4835
4920
  init_enums();
4836
4921
  zIssueDeviceToken = external_exports.object({ name: external_exports.string().min(1) });
4837
4922
  zSessionResult = external_exports.object({
@@ -4884,8 +4969,11 @@ var init_dto = __esm({
4884
4969
  // SPEC-217 · path default/server editable (null = kosongkan)
4885
4970
  schedulerOptIn: external_exports.boolean().optional(),
4886
4971
  // SPEC-294 · opt-in scheduler otonom (lokal, tak disync)
4887
- leadOptIn: external_exports.boolean().optional()
4972
+ leadOptIn: external_exports.boolean().optional(),
4888
4973
  // SPEC-409 · ADR-0091 · opt-in hanoman-lead (lokal, tak disync)
4974
+ // SPEC-486 · ADR-0103 · kebijakan auto-merge project (null = kosongkan → tanpa auto-merge).
4975
+ // Divalidasi server terhadap repo (checkAutoMerge): repoDir wajib ada, branch wajib nyata.
4976
+ autoMerge: zAutoMerge.nullable().optional()
4889
4977
  });
4890
4978
  zCreateSpec = external_exports.object({
4891
4979
  project: external_exports.string(),
@@ -4914,7 +5002,11 @@ var init_dto = __esm({
4914
5002
  // SPEC-447 · ADR-0093 · SENGAJA di luar gerbang `editingContent` (SPEC-186): gerbang itu
4915
5003
  // melindungi konten yang sudah jadi dasar kerja sesi berjalan, sedangkan dependsOn hanya
4916
5004
  // menggerbangi peluncuran BERIKUTNYA. `[]` = kosongkan.
4917
- dependsOn: external_exports.array(external_exports.string()).optional()
5005
+ dependsOn: external_exports.array(external_exports.string()).optional(),
5006
+ // SPEC-486 · ADR-0103 · override per item; `null` mengembalikannya ke warisan project.
5007
+ // SENGAJA di luar gerbang `editingContent` (SPEC-186), sama seperti dependsOn: ia menggerbangi
5008
+ // apa yang terjadi SESUDAH kerja, bukan konten yang sedang dikerjakan sesi hidup.
5009
+ autoMerge: zAutoMerge.nullable().optional()
4918
5010
  });
4919
5011
  zIntegrate = external_exports.object({
4920
5012
  op: external_exports.enum(["merge", "rebase"]),
@@ -4937,7 +5029,9 @@ var init_dto = __esm({
4937
5029
  // SPEC-253 · Help Center publik aktif
4938
5030
  schedulerOptIn: external_exports.boolean().default(false),
4939
5031
  // SPEC-294 · opt-in scheduler otonom
4940
- leadOptIn: external_exports.boolean().default(false)
5032
+ leadOptIn: external_exports.boolean().default(false),
5033
+ // SPEC-409 · ADR-0091 · opt-in hanoman-lead
5034
+ autoMerge: zAutoMerge.nullable().default(null)
4941
5035
  });
4942
5036
  zSchedulerQueueItem = external_exports.object({
4943
5037
  id: external_exports.string(),
@@ -4994,11 +5088,32 @@ var init_dto = __esm({
4994
5088
  choiceIndex: external_exports.number().nullable().default(null),
4995
5089
  options: external_exports.array(external_exports.string()).default([]),
4996
5090
  missing: external_exports.array(external_exports.string()).default([]),
5091
+ // SPEC-485 · ADR-0102 · jawaban SELALU daftar di permukaan baca. Baris pra-migrasi tak punya
5092
+ // kolomnya, jadi `toDecisionView` MENURUNKANNYA dari `choice`/`choiceIndex` — itulah yang
5093
+ // membuat riwayat lama tetap terbaca sesudah perubahan skema.
5094
+ choices: external_exports.array(zLeadChoice).default([]),
5095
+ select: zLeadSelect.nullable().default(null),
5096
+ flowId: external_exports.string().nullable().default(null),
5097
+ step: external_exports.number().nullable().default(null),
4997
5098
  status: zLeadStatus,
4998
5099
  weighty: external_exports.boolean(),
4999
5100
  supersededById: external_exports.string().nullable(),
5000
5101
  createdAt: external_exports.string()
5001
5102
  });
5103
+ zLeadFlowView = external_exports.object({
5104
+ id: external_exports.string(),
5105
+ projectId: external_exports.string(),
5106
+ specId: external_exports.string().nullable(),
5107
+ sessionId: external_exports.string().nullable(),
5108
+ gate: zLeadGate,
5109
+ status: zLeadFlowStatus,
5110
+ title: external_exports.string(),
5111
+ steps: external_exports.number(),
5112
+ closeReason: external_exports.string().nullable(),
5113
+ openedAt: external_exports.string(),
5114
+ closedAt: external_exports.string().nullable(),
5115
+ expiresAt: external_exports.string()
5116
+ });
5002
5117
  zLeadAnswer = external_exports.object({
5003
5118
  id: external_exports.string(),
5004
5119
  decision: external_exports.string(),
@@ -5010,7 +5125,12 @@ var init_dto = __esm({
5010
5125
  // dipilih sebagai field, bukan sesuatu yang harus ditebak dari `decision`. `decision`/`reason`
5011
5126
  // di sini TERPANGKAS (jejak penuh ada di `GET /lead/decisions`).
5012
5127
  choice: zLeadChoice.nullable().default(null),
5013
- missing: external_exports.array(external_exports.string()).default([])
5128
+ missing: external_exports.array(external_exports.string()).default([]),
5129
+ // SPEC-485 · ADR-0102 · `choices` adalah bentuk yang berlaku; `choice` di atas tinggal
5130
+ // `choices[0]`. `flowId`/`flowStatus` memberi peminta pegangan untuk melanjutkan rantainya.
5131
+ choices: external_exports.array(zLeadChoice).default([]),
5132
+ flowId: external_exports.string().nullable().default(null),
5133
+ flowStatus: zLeadFlowStatus.nullable().default(null)
5014
5134
  });
5015
5135
  zLeadProjectStatus = external_exports.object({
5016
5136
  projectId: external_exports.string(),
@@ -5370,8 +5490,15 @@ var init_api = __esm({
5370
5490
  leadDecisions: `${API}/lead/decisions`,
5371
5491
  leadDecisionOverride: (id) => `${API}/lead/decisions/${encodeURIComponent(id)}/override`,
5372
5492
  leadDecisionCancel: (id) => `${API}/lead/decisions/${encodeURIComponent(id)}/cancel`,
5493
+ // SPEC-485 · ADR-0102 · rantai keputusan. Di bawah prefix `lead` supaya capability-nya turunan
5494
+ // method (lead:read/lead:write) tanpa peta baru — kelas bug SPEC-405 sudah ditutup di sana.
5495
+ leadFlows: `${API}/lead/flows`,
5496
+ leadFlowSubmit: (id) => `${API}/lead/flows/${encodeURIComponent(id)}/submit`,
5497
+ leadFlowCancel: (id) => `${API}/lead/flows/${encodeURIComponent(id)}/cancel`,
5373
5498
  // SPEC-450 · ADR-0094 · katalog custom agent. `?projectId=` → himpunan EFEKTIF (global+project).
5374
5499
  customAgents: `${API}/custom-agents`,
5500
+ // SPEC-484 · ADR-0101 · sumber daftar tools/model/runtime untuk form (mention dari `customAgents`).
5501
+ customAgentCatalog: `${API}/custom-agents/catalog`,
5375
5502
  // SPEC-481 · ADR-0100 · webhook keluar (cookie-only)
5376
5503
  webhooks: `${API}/webhooks`,
5377
5504
  webhook: (id) => `${API}/webhooks/${encodeURIComponent(id)}`,
@@ -5763,6 +5890,7 @@ var init_webhook = __esm({
5763
5890
  "baseSha",
5764
5891
  "headSha",
5765
5892
  "dependsOn",
5893
+ "autoMerge",
5766
5894
  "createdAt",
5767
5895
  "startedAt",
5768
5896
  "updatedAt"
@@ -5792,6 +5920,7 @@ var init_webhook = __esm({
5792
5920
  baseSha: "5117298c5a3e63af76cbadaa46e2edfa50921d7",
5793
5921
  headSha: null,
5794
5922
  dependsOn: null,
5923
+ autoMerge: null,
5795
5924
  createdAt: "2026-08-01T02:10:00.000Z",
5796
5925
  startedAt: "2026-08-01T02:12:31.000Z",
5797
5926
  updatedAt: "2026-08-01T09:41:22.000Z"
@@ -5811,6 +5940,7 @@ var init_webhook = __esm({
5811
5940
  "helpEnabled",
5812
5941
  "schedulerOptIn",
5813
5942
  "leadOptIn",
5943
+ "autoMerge",
5814
5944
  "createdAt",
5815
5945
  "updatedAt"
5816
5946
  ],
@@ -5831,6 +5961,7 @@ var init_webhook = __esm({
5831
5961
  helpEnabled: false,
5832
5962
  schedulerOptIn: true,
5833
5963
  leadOptIn: false,
5964
+ autoMerge: null,
5834
5965
  createdAt: "2026-05-02T04:00:00.000Z",
5835
5966
  updatedAt: "2026-08-01T09:00:00.000Z"
5836
5967
  }
@@ -6625,7 +6756,7 @@ var init_mcp_catalog = __esm({
6625
6756
  {
6626
6757
  name: "hanoman_lead_ask",
6627
6758
  title: "Minta putusan hanoman-lead",
6628
- description: "Minta putusan ke hanoman-lead saat menemui persimpangan yang biasanya butuh manusia. Jawabannya terbaca mesin (`decision`, `reason`, `refs`, `confidence`, `action`) dan `refs` hanya memuat rujukan yang benar-benar ada di repo. 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: kembali ke perilaku biasa, berhenti dan tunggu manusia.",
6759
+ 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: kembali ke perilaku biasa, berhenti dan tunggu manusia; 400 = bentuk `multi`/`minChoices`/`maxChoices` mustahil dipenuhi oleh daftar opsi yang kamu kirim.",
6629
6760
  inputSchema: obj({
6630
6761
  properties: {
6631
6762
  project: str("Id proyek."),
@@ -6633,7 +6764,10 @@ var init_mcp_catalog = __esm({
6633
6764
  spec: str("Opsional. Id backlog yang bersangkutan."),
6634
6765
  session: str("Opsional. Id sesi yang bersangkutan."),
6635
6766
  options: strArray("Opsional. Pilihan yang tersedia, maksimum 20, masing-masing maksimum 2000 karakter. Lead memilih salah satunya."),
6636
- context: str("Opsional. Konteks pendukung, maksimum 20.000 karakter.")
6767
+ context: str("Opsional. Konteks pendukung, maksimum 20.000 karakter."),
6768
+ multi: bool("Opsional. `true` bila opsinya TIDAK saling eksklusif dan lead boleh memilih beberapa sekaligus. Menuntut `options` terisi."),
6769
+ minChoices: int("Opsional, hanya untuk `multi`. Paling sedikit berapa opsi harus dipilih."),
6770
+ maxChoices: int("Opsional, hanya untuk `multi`. Paling banyak berapa opsi boleh dipilih; tanpa ini sebanyak opsinya.")
6637
6771
  },
6638
6772
  required: ["project", "question"]
6639
6773
  }),
@@ -6650,7 +6784,10 @@ var init_mcp_catalog = __esm({
6650
6784
  ...s(a.spec) ? { specId: a.spec } : {},
6651
6785
  ...s(a.session) ? { sessionId: a.session } : {},
6652
6786
  ...Array.isArray(a.options) ? { options: a.options } : {},
6653
- ...s(a.context) ? { context: a.context } : {}
6787
+ ...s(a.context) ? { context: a.context } : {},
6788
+ // SPEC-485 · ADITIF: tanpa `multi` bentuk permintaannya identik dengan sebelum ADR-0102,
6789
+ // jadi klien MCP lama tak berubah perilakunya satu bit pun.
6790
+ ...a.multi === true ? { select: { mode: "multi", min: n(a.minChoices) ?? 0, max: n(a.maxChoices) ?? null } } : {}
6654
6791
  }
6655
6792
  }),
6656
6793
  shape: (raw) => raw
@@ -6692,6 +6829,7 @@ var init_src = __esm({
6692
6829
  init_entities();
6693
6830
  init_agent();
6694
6831
  init_custom_agent();
6832
+ init_agent_catalog();
6695
6833
  init_github();
6696
6834
  init_lead();
6697
6835
  init_dto();
@@ -6705,6 +6843,7 @@ var init_src = __esm({
6705
6843
  init_telegram();
6706
6844
  init_webhook();
6707
6845
  init_mcp();
6846
+ init_auto_merge();
6708
6847
  }
6709
6848
  });
6710
6849
 
@@ -28273,8 +28412,11 @@ var init_migrate_pg = __esm({
28273
28412
  "SyncOutbox",
28274
28413
  "SyncState",
28275
28414
  "SyncConflict",
28415
+ // SPEC-485 · ADR-0102 · LeadFlow SEBELUM LeadDecision: `flowId` menunjuk ke sana. Tanpa FK, tapi
28416
+ // urutan tabel harus tetap mencerminkan arah tautannya bagi pembaca berikutnya.
28276
28417
  "SchedulerQueueItem",
28277
28418
  "RuntimeConfig",
28419
+ "LeadFlow",
28278
28420
  "LeadDecision",
28279
28421
  // SPEC-476 · ADR-0096 · tabel gateway LOCAL-only; sumber Postgres lama lazimnya tidak punya
28280
28422
  // tabel ini dan jalur 42P01 di bawah memperlakukannya sebagai nol baris.