hanoman 0.2.3 → 0.2.5
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 +232 -34
- package/dist/server.js +1964 -590
- package/package.json +1 -1
- package/prisma/migrations/20260831120000_custom_agent_execution_profiles/migration.sql +5 -0
- package/prisma/migrations/20260831121000_agent_invocations/migration.sql +32 -0
- package/prisma/schema.prisma +36 -0
- package/web/assets/index-B06OYVqX.css +41 -0
- package/web/assets/{index-BllpAcXg.js → index-D6R-u1nz.js} +1555 -1555
- package/web/index.html +2 -2
- package/web/assets/index-DNaw5xBe.css +0 -41
package/dist/build-info.json
CHANGED
package/dist/cli.js
CHANGED
|
@@ -4413,6 +4413,15 @@ var init_auto_merge = __esm({
|
|
|
4413
4413
|
});
|
|
4414
4414
|
|
|
4415
4415
|
// ../shared/src/entities.ts
|
|
4416
|
+
function cmpVersion(a, b) {
|
|
4417
|
+
const pa = a.split(".").map(Number);
|
|
4418
|
+
const pb = b.split(".").map(Number);
|
|
4419
|
+
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
|
|
4420
|
+
const d = (pa[i] ?? 0) - (pb[i] ?? 0);
|
|
4421
|
+
if (d !== 0) return d;
|
|
4422
|
+
}
|
|
4423
|
+
return 0;
|
|
4424
|
+
}
|
|
4416
4425
|
var zProject, zBriefPayload, zQaPayload, zGoalPayload, zSpecBlocker, zSourceChange, zManualDone, zSpec, NOTIFY_SOUNDS, zCodex, CODEX_DEFAULTS, zSourceCommon, zScheduler, SCHEDULER_DEFAULTS, zGoal, GOAL_DEFAULTS, zConflict, CONFLICT_DEFAULTS, CHANGELOG_ENGINE_DEFAULTS, zLeadEngine, zLead, LEAD_DEFAULTS, zPortalChat, PORTAL_CHAT_DEFAULTS, zSetting, zNotification, zDocFile, zDeviceTokenView;
|
|
4417
4426
|
var init_entities = __esm({
|
|
4418
4427
|
"../shared/src/entities.ts"() {
|
|
@@ -4666,7 +4675,10 @@ var init_entities = __esm({
|
|
|
4666
4675
|
//
|
|
4667
4676
|
// LOKAL per mesin: `setting` TIDAK ada di FIELDS sync (server/src/services/sync.ts), jadi dua
|
|
4668
4677
|
// mesin dengan versi hanoman berbeda tak bisa saling menimpa definisi bolak-balik.
|
|
4669
|
-
builtinAgents: external_exports.record(external_exports.string(), external_exports.string()).default({})
|
|
4678
|
+
builtinAgents: external_exports.record(external_exports.string(), external_exports.string()).default({}),
|
|
4679
|
+
// SPEC-950 · marker safety policy lokal. Terpisah dari fingerprint konten agar policy sekali
|
|
4680
|
+
// jalan tidak membuat seed memperlakukan konfigurasi operator sebagai bawaan.
|
|
4681
|
+
builtinAgentPolicies: external_exports.record(external_exports.string(), external_exports.string()).default({})
|
|
4670
4682
|
});
|
|
4671
4683
|
zNotification = external_exports.object({
|
|
4672
4684
|
id: external_exports.string(),
|
|
@@ -4789,13 +4801,28 @@ var init_agent = __esm({
|
|
|
4789
4801
|
});
|
|
4790
4802
|
|
|
4791
4803
|
// ../shared/src/custom-agent.ts
|
|
4792
|
-
|
|
4804
|
+
function validateCreateWorkspacePolicy(value, ctx) {
|
|
4805
|
+
if (value.workspacePolicy === "isolated-worktree" && value.runtime !== "claude") {
|
|
4806
|
+
ctx.addIssue({
|
|
4807
|
+
code: external_exports.ZodIssueCode.custom,
|
|
4808
|
+
path: ["workspacePolicy"],
|
|
4809
|
+
message: "isolated-worktree hanya tersedia untuk Claude Code"
|
|
4810
|
+
});
|
|
4811
|
+
}
|
|
4812
|
+
}
|
|
4813
|
+
var AGENT_RUNTIMES, zAgentRuntime, AGENT_ACTIVATIONS, zAgentActivation, AGENT_EFFORTS, zAgentEffort, AGENT_WORKSPACE_POLICIES, zAgentWorkspacePolicy, AGENT_NAME_RE, DEFAULT_AGENT_TOOLS, zCustomAgent, zCreateCustomAgentFields, zCreateCustomAgent, zUpdateCustomAgent;
|
|
4793
4814
|
var init_custom_agent = __esm({
|
|
4794
4815
|
"../shared/src/custom-agent.ts"() {
|
|
4795
4816
|
"use strict";
|
|
4796
4817
|
init_zod();
|
|
4797
4818
|
AGENT_RUNTIMES = ["claude", "codex"];
|
|
4798
4819
|
zAgentRuntime = external_exports.enum(AGENT_RUNTIMES);
|
|
4820
|
+
AGENT_ACTIVATIONS = ["always", "smart"];
|
|
4821
|
+
zAgentActivation = external_exports.enum(AGENT_ACTIVATIONS);
|
|
4822
|
+
AGENT_EFFORTS = ["ultra", "max", "xhigh", "high", "medium", "low", "ultracode"];
|
|
4823
|
+
zAgentEffort = external_exports.enum(AGENT_EFFORTS);
|
|
4824
|
+
AGENT_WORKSPACE_POLICIES = ["inherit", "read-only", "isolated-worktree"];
|
|
4825
|
+
zAgentWorkspacePolicy = external_exports.enum(AGENT_WORKSPACE_POLICIES);
|
|
4799
4826
|
AGENT_NAME_RE = /^[a-z][a-z0-9-]{1,39}$/;
|
|
4800
4827
|
DEFAULT_AGENT_TOOLS = [
|
|
4801
4828
|
"Read",
|
|
@@ -4817,11 +4844,16 @@ var init_custom_agent = __esm({
|
|
|
4817
4844
|
model: external_exports.string().nullable(),
|
|
4818
4845
|
mentions: external_exports.array(external_exports.string()).nullable(),
|
|
4819
4846
|
runtime: external_exports.enum(AGENT_RUNTIMES).nullable(),
|
|
4847
|
+
activation: zAgentActivation.default("always"),
|
|
4848
|
+
effort: zAgentEffort.nullable().default(null),
|
|
4849
|
+
workspacePolicy: zAgentWorkspacePolicy.default("inherit"),
|
|
4850
|
+
maxTurns: external_exports.number().int().min(1).max(200).nullable().default(null),
|
|
4851
|
+
timeoutSeconds: external_exports.number().int().min(30).max(3600).nullable().default(null),
|
|
4820
4852
|
enabled: external_exports.boolean(),
|
|
4821
4853
|
createdAt: external_exports.string(),
|
|
4822
4854
|
updatedAt: external_exports.string()
|
|
4823
4855
|
});
|
|
4824
|
-
|
|
4856
|
+
zCreateCustomAgentFields = external_exports.object({
|
|
4825
4857
|
projectId: external_exports.string().nullable().optional(),
|
|
4826
4858
|
name: external_exports.string().regex(AGENT_NAME_RE),
|
|
4827
4859
|
description: external_exports.string().trim().min(1).max(500),
|
|
@@ -4831,9 +4863,23 @@ var init_custom_agent = __esm({
|
|
|
4831
4863
|
mentions: external_exports.array(external_exports.string()).nullable().optional(),
|
|
4832
4864
|
// SPEC-484 · ADR-0101 · PENYARING mesin sesi, bukan pemilih proses. null/absen = ikut sesi induk.
|
|
4833
4865
|
runtime: external_exports.enum(AGENT_RUNTIMES).nullable().optional(),
|
|
4866
|
+
activation: zAgentActivation.optional(),
|
|
4867
|
+
effort: zAgentEffort.nullable().optional(),
|
|
4868
|
+
workspacePolicy: zAgentWorkspacePolicy.optional(),
|
|
4869
|
+
maxTurns: external_exports.number().int().min(1).max(200).nullable().optional(),
|
|
4870
|
+
timeoutSeconds: external_exports.number().int().min(30).max(3600).nullable().optional(),
|
|
4834
4871
|
enabled: external_exports.boolean().optional()
|
|
4835
4872
|
});
|
|
4836
|
-
|
|
4873
|
+
zCreateCustomAgent = zCreateCustomAgentFields.superRefine(validateCreateWorkspacePolicy);
|
|
4874
|
+
zUpdateCustomAgent = zCreateCustomAgentFields.omit({ name: true, projectId: true }).partial().superRefine((value, ctx) => {
|
|
4875
|
+
if (value.workspacePolicy === "isolated-worktree" && value.runtime !== void 0 && value.runtime !== "claude") {
|
|
4876
|
+
ctx.addIssue({
|
|
4877
|
+
code: external_exports.ZodIssueCode.custom,
|
|
4878
|
+
path: ["workspacePolicy"],
|
|
4879
|
+
message: "isolated-worktree hanya tersedia untuk Claude Code"
|
|
4880
|
+
});
|
|
4881
|
+
}
|
|
4882
|
+
});
|
|
4837
4883
|
}
|
|
4838
4884
|
});
|
|
4839
4885
|
|
|
@@ -4848,6 +4894,12 @@ var init_builtin_agents = __esm({
|
|
|
4848
4894
|
description: "Gunakan saat perlu tahu DI MANA sesuatu dikerjakan di basis kode, atau bagaimana sebuah alur data mengalir, sebelum menyentuh kode. Ia menyapu banyak berkas dan mengembalikan peta ringkas berisi jangkar path:baris \u2014 bukan isi berkas. Panggil dia alih-alih membaca belasan berkas sendiri.",
|
|
4849
4895
|
tools: ["Read", "Glob", "Grep"],
|
|
4850
4896
|
enabledByDefault: true,
|
|
4897
|
+
activation: "smart",
|
|
4898
|
+
effort: "low",
|
|
4899
|
+
workspacePolicy: "read-only",
|
|
4900
|
+
maxTurns: null,
|
|
4901
|
+
timeoutSeconds: null,
|
|
4902
|
+
models: { claude: "haiku", codex: "gpt-5.6-terra" },
|
|
4851
4903
|
instructions: [
|
|
4852
4904
|
"Kamu navigator basis kode. Tugasmu MENJAWAB, bukan menyalin.",
|
|
4853
4905
|
"",
|
|
@@ -4874,6 +4926,12 @@ var init_builtin_agents = __esm({
|
|
|
4874
4926
|
description: "Gunakan saat ada bug, test merah, atau perilaku tak terduga yang belum jelas sebabnya. Ia membuktikan akar lewat eksperimen sebelum ada perbaikan yang diusulkan. Jangan panggil dia untuk memperbaiki \u2014 dia mendiagnosis.",
|
|
4875
4927
|
tools: ["Read", "Glob", "Grep", "Bash"],
|
|
4876
4928
|
enabledByDefault: false,
|
|
4929
|
+
activation: "smart",
|
|
4930
|
+
effort: "high",
|
|
4931
|
+
workspacePolicy: "read-only",
|
|
4932
|
+
maxTurns: null,
|
|
4933
|
+
timeoutSeconds: null,
|
|
4934
|
+
models: { claude: "sonnet", codex: "gpt-5.6" },
|
|
4877
4935
|
instructions: [
|
|
4878
4936
|
"Kamu diagnostikus. Kamu TIDAK memperbaiki kode \u2014 kamu membuktikan sebabnya.",
|
|
4879
4937
|
"",
|
|
@@ -4903,7 +4961,13 @@ var init_builtin_agents = __esm({
|
|
|
4903
4961
|
name: "qa-verifier",
|
|
4904
4962
|
description: "Gunakan SEBELUM menyatakan pekerjaan selesai atau test hijau. Ia menjalankan test yang tersentuh perubahan, memisahkan gagal palsu dari regresi, dan membuktikan bahwa test yang lulus itu benar-benar menguji perubahannya.",
|
|
4905
4963
|
tools: ["Read", "Glob", "Grep", "Bash"],
|
|
4906
|
-
enabledByDefault:
|
|
4964
|
+
enabledByDefault: false,
|
|
4965
|
+
activation: "smart",
|
|
4966
|
+
effort: "medium",
|
|
4967
|
+
workspacePolicy: "isolated-worktree",
|
|
4968
|
+
maxTurns: 40,
|
|
4969
|
+
timeoutSeconds: 900,
|
|
4970
|
+
models: { claude: "sonnet", codex: "gpt-5.6-terra" },
|
|
4907
4971
|
instructions: [
|
|
4908
4972
|
"Kamu gerbang terakhir sebelum sesuatu diumumkan hijau. Tugasmu MERAGUKAN kehijauan itu.",
|
|
4909
4973
|
"",
|
|
@@ -4915,18 +4979,18 @@ var init_builtin_agents = __esm({
|
|
|
4915
4979
|
" paralelisme antar-berkas test, sisa proses/soket/port dari run sebelumnya, variabel",
|
|
4916
4980
|
" lingkungan yang bocor dari shell, dan test yang memang sudah merah SEBELUM perubahan.",
|
|
4917
4981
|
" Cara memutuskannya: jalankan ulang test itu SENDIRIAN, dengan state yang bersih.",
|
|
4918
|
-
"4. UJI RELEVANSI
|
|
4919
|
-
"
|
|
4920
|
-
"
|
|
4921
|
-
"
|
|
4922
|
-
"
|
|
4923
|
-
"5. Bersihkan pohon kerja sementara (`git worktree remove`).",
|
|
4982
|
+
"4. UJI RELEVANSI hanya di worktree sementara dari `baseSha`, tidak pernah di worktree",
|
|
4983
|
+
" parent: buat worktree terpisah, pasang patch test di sana, jalankan, dan tuntut test",
|
|
4984
|
+
" itu MERAH. Bila `baseSha` atau patch test tidak tersedia, laporkan `belum terbukti`;",
|
|
4985
|
+
" jangan mencoba eksperimen kontrol di source parent.",
|
|
4986
|
+
"5. Bersihkan worktree sementara milikmu. Laporkan secara eksplisit bila cleanup gagal.",
|
|
4924
4987
|
"",
|
|
4925
4988
|
"Larangan keras:",
|
|
4926
4989
|
"- JANGAN `git stash` untuk apa pun. Tumpukan stash milik REPO, bukan pohon kerja \u2014 sesi lain",
|
|
4927
4990
|
" bisa mem-pop stash milikmu, dan kamu bisa mem-pop milik mereka. Isolasi memakai",
|
|
4928
4991
|
" `git worktree add`, titik.",
|
|
4929
4992
|
"- JANGAN mengubah test agar lulus. Bila test-nya yang salah, itu temuan, bukan pekerjaan.",
|
|
4993
|
+
"- JANGAN mengubah satu byte pun di worktree parent, termasuk berkas probe sementara.",
|
|
4930
4994
|
"",
|
|
4931
4995
|
"Gerbang bukti: setiap klaim membawa perintah DAN potongan keluarannya. Tanpa keluaran, tanpa",
|
|
4932
4996
|
"klaim. 'Semua test lulus' tanpa keluaran adalah kegagalanmu, bukan laporan.",
|
|
@@ -4941,6 +5005,12 @@ var init_builtin_agents = __esm({
|
|
|
4941
5005
|
description: "Gunakan saat test yang ada hanya menguji jalur mulus dan kamu ingin batas-batas kontrak benar-benar tertutup. Ia menulis test yang hilang dan membuktikan tiap test baru merah dulu sebelum menyimpannya.",
|
|
4942
5006
|
tools: ["Read", "Glob", "Grep", "Bash", "Write", "Edit"],
|
|
4943
5007
|
enabledByDefault: false,
|
|
5008
|
+
activation: "smart",
|
|
5009
|
+
effort: "high",
|
|
5010
|
+
workspacePolicy: "isolated-worktree",
|
|
5011
|
+
maxTurns: null,
|
|
5012
|
+
timeoutSeconds: null,
|
|
5013
|
+
models: { claude: "sonnet", codex: "gpt-5.6" },
|
|
4944
5014
|
instructions: [
|
|
4945
5015
|
"Kamu penambal jalur bahagia. Cakupan yang terlihat baik bukan urusanmu \u2014 kontrak yang tak",
|
|
4946
5016
|
"pernah diuji itu urusanmu.",
|
|
@@ -4973,6 +5043,12 @@ var init_builtin_agents = __esm({
|
|
|
4973
5043
|
description: "Gunakan sesudah perubahan selesai untuk menemukan tempat LAIN yang seharusnya ikut berubah tapi tidak: daftar kolom, cermin tipe antar-paket, enum kembar, dokumen kontrak, tabel konstanta. Ia mencari kegagalan senyap \u2014 yang tak memunculkan satu pun error.",
|
|
4974
5044
|
tools: ["Read", "Glob", "Grep", "Bash"],
|
|
4975
5045
|
enabledByDefault: true,
|
|
5046
|
+
activation: "smart",
|
|
5047
|
+
effort: "medium",
|
|
5048
|
+
workspacePolicy: "read-only",
|
|
5049
|
+
maxTurns: null,
|
|
5050
|
+
timeoutSeconds: null,
|
|
5051
|
+
models: { claude: "sonnet", codex: "gpt-5.6-terra" },
|
|
4976
5052
|
instructions: [
|
|
4977
5053
|
"Kamu pencari cermin yang hanyut. Kelas bug yang kamu buru punya satu ciri: TIDAK ADA yang",
|
|
4978
5054
|
"error. Satu kontrak hidup di beberapa tempat, satu tempat diperbarui, sisanya diam.",
|
|
@@ -5005,6 +5081,12 @@ var init_builtin_agents = __esm({
|
|
|
5005
5081
|
description: "Gunakan sebelum menutup pekerjaan untuk mengadu apa yang DIMINTA dengan apa yang benar-benar ada di diff. Ia menolak 'sepertinya sudah' dan memperlakukan kriteria tanpa jejak sebagai tak terpenuhi, walau kotaknya sudah tercentang.",
|
|
5006
5082
|
tools: ["Read", "Glob", "Grep", "Bash"],
|
|
5007
5083
|
enabledByDefault: false,
|
|
5084
|
+
activation: "smart",
|
|
5085
|
+
effort: "high",
|
|
5086
|
+
workspacePolicy: "read-only",
|
|
5087
|
+
maxTurns: null,
|
|
5088
|
+
timeoutSeconds: null,
|
|
5089
|
+
models: { claude: "sonnet", codex: "gpt-5.6-terra" },
|
|
5008
5090
|
instructions: [
|
|
5009
5091
|
"Kamu pengadu janji. Kamu tak menilai bagus atau tidaknya kode \u2014 kamu menilai apakah yang",
|
|
5010
5092
|
"diminta benar-benar ada.",
|
|
@@ -5033,6 +5115,12 @@ var init_builtin_agents = __esm({
|
|
|
5033
5115
|
description: "Gunakan sebelum menggabungkan perubahan yang menyentuh route, handler, job, CLI, atau apa pun yang menerima input dari luar. Ia menelusuri jalur konkret dari input tak terpercaya sampai ke tempat ia melukai, dan menolak melaporkan kekhawatiran yang tak bisa ia buktikan jalurnya.",
|
|
5034
5116
|
tools: ["Read", "Glob", "Grep", "Bash"],
|
|
5035
5117
|
enabledByDefault: true,
|
|
5118
|
+
activation: "smart",
|
|
5119
|
+
effort: "high",
|
|
5120
|
+
workspacePolicy: "read-only",
|
|
5121
|
+
maxTurns: null,
|
|
5122
|
+
timeoutSeconds: null,
|
|
5123
|
+
models: { claude: "sonnet", codex: "gpt-5.6" },
|
|
5036
5124
|
instructions: [
|
|
5037
5125
|
"Kamu penelusur sumber-ke-sink. Daftar kekhawatiran umum tak mengubah apa pun; yang mengubah",
|
|
5038
5126
|
"adalah satu jalur konkret dari input yang tak dipercaya sampai ke tempat ia melukai.",
|
|
@@ -5067,6 +5155,12 @@ var init_builtin_agents = __esm({
|
|
|
5067
5155
|
description: "Gunakan saat diff menambah atau menaikkan versi dependensi. Ia memeriksa advisory, lisensi, tanda pemeliharaan, dan \u2014 yang paling sering terlewat \u2014 apakah fungsinya sudah tersedia tanpa dependensi baru itu.",
|
|
5068
5156
|
tools: ["Read", "Glob", "Grep", "Bash", "WebSearch", "WebFetch"],
|
|
5069
5157
|
enabledByDefault: false,
|
|
5158
|
+
activation: "smart",
|
|
5159
|
+
effort: "medium",
|
|
5160
|
+
workspacePolicy: "read-only",
|
|
5161
|
+
maxTurns: null,
|
|
5162
|
+
timeoutSeconds: null,
|
|
5163
|
+
models: { claude: "haiku", codex: "gpt-5.6-terra" },
|
|
5070
5164
|
instructions: [
|
|
5071
5165
|
"Kamu gerbang rantai pasok. Satu dependensi masuk lewat satu baris diff dan tak pernah",
|
|
5072
5166
|
"diperiksa lagi seumur hidup proyek \u2014 pemeriksaan itu terjadi sekarang atau tidak sama sekali.",
|
|
@@ -6217,6 +6311,8 @@ var init_api = __esm({
|
|
|
6217
6311
|
leadFlowCancel: (id) => `${API}/lead/flows/${encodeURIComponent(id)}/cancel`,
|
|
6218
6312
|
// SPEC-450 · ADR-0094 · katalog custom agent. `?projectId=` → himpunan EFEKTIF (global+project).
|
|
6219
6313
|
customAgents: `${API}/custom-agents`,
|
|
6314
|
+
customAgentMetrics: `${API}/custom-agents/metrics`,
|
|
6315
|
+
customAgentInvocation: (id) => `${API}/custom-agents/invocations/${encodeURIComponent(id)}`,
|
|
6220
6316
|
// SPEC-484 · ADR-0101 · sumber daftar tools/model/runtime untuk form (mention dari `customAgents`).
|
|
6221
6317
|
customAgentCatalog: `${API}/custom-agents/catalog`,
|
|
6222
6318
|
// SPEC-481 · ADR-0100 · webhook keluar (cookie-only)
|
|
@@ -10969,6 +11065,13 @@ var init_presence = __esm({
|
|
|
10969
11065
|
}
|
|
10970
11066
|
});
|
|
10971
11067
|
|
|
11068
|
+
// ../shared/src/pending.ts
|
|
11069
|
+
var init_pending = __esm({
|
|
11070
|
+
"../shared/src/pending.ts"() {
|
|
11071
|
+
"use strict";
|
|
11072
|
+
}
|
|
11073
|
+
});
|
|
11074
|
+
|
|
10972
11075
|
// ../shared/src/index.ts
|
|
10973
11076
|
var init_src = __esm({
|
|
10974
11077
|
"../shared/src/index.ts"() {
|
|
@@ -11009,6 +11112,7 @@ var init_src = __esm({
|
|
|
11009
11112
|
init_session_dialog();
|
|
11010
11113
|
init_session_ask();
|
|
11011
11114
|
init_presence();
|
|
11115
|
+
init_pending();
|
|
11012
11116
|
init_team();
|
|
11013
11117
|
}
|
|
11014
11118
|
});
|
|
@@ -11142,17 +11246,27 @@ var init_git = __esm({
|
|
|
11142
11246
|
});
|
|
11143
11247
|
|
|
11144
11248
|
// ../runner/src/settings.ts
|
|
11145
|
-
var EVENT_HOOK_COMMAND;
|
|
11249
|
+
var EVENT_SPOOL_SCRIPT, EVENT_HOOK_COMMAND;
|
|
11146
11250
|
var init_settings2 = __esm({
|
|
11147
11251
|
"../runner/src/settings.ts"() {
|
|
11148
11252
|
"use strict";
|
|
11253
|
+
EVENT_SPOOL_SCRIPT = [
|
|
11254
|
+
'const fs=require("node:fs"),p=require("node:path"),c=require("node:crypto")',
|
|
11255
|
+
'let d=""',
|
|
11256
|
+
'process.stdin.setEncoding("utf8")',
|
|
11257
|
+
'process.stdin.on("data",x=>d+=x)',
|
|
11258
|
+
'process.stdin.on("end",()=>{let t="";try{const n=Date.now()+"-"+process.pid+"-"+c.randomUUID();t=p.join(process.env.HANOMAN_EVENT_DIR,n+".tmp");const f=p.join(process.env.HANOMAN_EVENT_DIR,n+".json");fs.writeFileSync(t,d,{flag:"wx",mode:0o600});fs.renameSync(t,f)}catch{if(t)try{fs.rmSync(t,{force:true})}catch{}}})'
|
|
11259
|
+
].join(";");
|
|
11149
11260
|
EVENT_HOOK_COMMAND = [
|
|
11261
|
+
'if [ -n "${HANOMAN_EVENT_DIR:-}" ]; then',
|
|
11262
|
+
`node -e '${EVENT_SPOOL_SCRIPT}' >/dev/null 2>&1;`,
|
|
11263
|
+
"else",
|
|
11150
11264
|
'curl -sS -m 2 -X POST "$HANOMAN_EVENT_URL"',
|
|
11151
11265
|
"-H 'content-type: application/json'",
|
|
11152
11266
|
'-H "authorization: Bearer $HANOMAN_EVENT_TOKEN"',
|
|
11153
11267
|
'-H "x-hanoman-session: $HANOMAN_SESSION_ID"',
|
|
11154
11268
|
'${HANOMAN_EVENT_HOST:+-H "host: $HANOMAN_EVENT_HOST"}',
|
|
11155
|
-
"--data-binary @- >/dev/null 2>&1; exit 0"
|
|
11269
|
+
"--data-binary @- >/dev/null 2>&1; fi; exit 0"
|
|
11156
11270
|
].join(" ");
|
|
11157
11271
|
}
|
|
11158
11272
|
});
|
|
@@ -11195,6 +11309,75 @@ var init_custom_agents = __esm({
|
|
|
11195
11309
|
}
|
|
11196
11310
|
});
|
|
11197
11311
|
|
|
11312
|
+
// ../runner/src/agent-readonly.ts
|
|
11313
|
+
var init_agent_readonly = __esm({
|
|
11314
|
+
"../runner/src/agent-readonly.ts"() {
|
|
11315
|
+
"use strict";
|
|
11316
|
+
}
|
|
11317
|
+
});
|
|
11318
|
+
|
|
11319
|
+
// ../runner/src/runtime-profile.ts
|
|
11320
|
+
function resolveHardening(env) {
|
|
11321
|
+
if (env.HANOMAN_HARDENING === "1") return true;
|
|
11322
|
+
return env.HANOMAN_SESSION_SANDBOX === "podman" || filled(env.HANOMAN_PUBLIC_ORIGINS) || filled(env.HANOMAN_TRUST_PROXY);
|
|
11323
|
+
}
|
|
11324
|
+
var filled;
|
|
11325
|
+
var init_runtime_profile = __esm({
|
|
11326
|
+
"../runner/src/runtime-profile.ts"() {
|
|
11327
|
+
"use strict";
|
|
11328
|
+
filled = (v) => !!v && v.trim() !== "";
|
|
11329
|
+
}
|
|
11330
|
+
});
|
|
11331
|
+
|
|
11332
|
+
// ../runner/src/codex-agent-config.ts
|
|
11333
|
+
function codexNativeAgentsSupported(version3) {
|
|
11334
|
+
const parsed = version3 ? /(\d+)\.(\d+)\.(\d+)/.exec(version3)?.[0] : null;
|
|
11335
|
+
return parsed ? cmpVersion(parsed, CODEX_NATIVE_AGENTS_MIN_CLIENT) >= 0 : false;
|
|
11336
|
+
}
|
|
11337
|
+
function codexNativeVersionProbe(env, codexBin = env.HANOMAN_CODEX_BIN ?? "codex") {
|
|
11338
|
+
const sandbox = env.HANOMAN_SESSION_SANDBOX ?? (resolveHardening(env) ? "required" : "off");
|
|
11339
|
+
if (sandbox !== "podman") return { bin: codexBin, args: ["--version"] };
|
|
11340
|
+
return {
|
|
11341
|
+
bin: env.HANOMAN_PODMAN_BIN ?? "podman",
|
|
11342
|
+
args: [
|
|
11343
|
+
"run",
|
|
11344
|
+
"--rm",
|
|
11345
|
+
"--read-only",
|
|
11346
|
+
"--cap-drop=ALL",
|
|
11347
|
+
"--userns=keep-id",
|
|
11348
|
+
"--network",
|
|
11349
|
+
"none",
|
|
11350
|
+
env.HANOMAN_SESSION_IMAGE ?? "hanoman-agent:latest",
|
|
11351
|
+
"/bin/sh",
|
|
11352
|
+
"-lc",
|
|
11353
|
+
`${shellQuote(codexBin)} --version`
|
|
11354
|
+
]
|
|
11355
|
+
};
|
|
11356
|
+
}
|
|
11357
|
+
var CODEX_NATIVE_AGENTS_MIN_CLIENT, shellQuote;
|
|
11358
|
+
var init_codex_agent_config = __esm({
|
|
11359
|
+
"../runner/src/codex-agent-config.ts"() {
|
|
11360
|
+
"use strict";
|
|
11361
|
+
init_src();
|
|
11362
|
+
init_custom_agents();
|
|
11363
|
+
init_runtime_profile();
|
|
11364
|
+
CODEX_NATIVE_AGENTS_MIN_CLIENT = "0.151.0";
|
|
11365
|
+
shellQuote = (value) => `'${value.replaceAll("'", "'\\''")}'`;
|
|
11366
|
+
}
|
|
11367
|
+
});
|
|
11368
|
+
|
|
11369
|
+
// ../runner/src/custom-agent-eval.ts
|
|
11370
|
+
var init_custom_agent_eval = __esm({
|
|
11371
|
+
"../runner/src/custom-agent-eval.ts"() {
|
|
11372
|
+
"use strict";
|
|
11373
|
+
init_src();
|
|
11374
|
+
init_codex_agent_config();
|
|
11375
|
+
init_codex_settings();
|
|
11376
|
+
init_custom_agents();
|
|
11377
|
+
init_settings2();
|
|
11378
|
+
}
|
|
11379
|
+
});
|
|
11380
|
+
|
|
11198
11381
|
// ../runner/src/paths.ts
|
|
11199
11382
|
import { homedir } from "node:os";
|
|
11200
11383
|
import { dirname, isAbsolute, join, resolve } from "node:path";
|
|
@@ -11529,19 +11712,6 @@ var init_config_env = __esm({
|
|
|
11529
11712
|
}
|
|
11530
11713
|
});
|
|
11531
11714
|
|
|
11532
|
-
// ../runner/src/runtime-profile.ts
|
|
11533
|
-
function resolveHardening(env) {
|
|
11534
|
-
if (env.HANOMAN_HARDENING === "1") return true;
|
|
11535
|
-
return env.HANOMAN_SESSION_SANDBOX === "podman" || filled(env.HANOMAN_PUBLIC_ORIGINS) || filled(env.HANOMAN_TRUST_PROXY);
|
|
11536
|
-
}
|
|
11537
|
-
var filled;
|
|
11538
|
-
var init_runtime_profile = __esm({
|
|
11539
|
-
"../runner/src/runtime-profile.ts"() {
|
|
11540
|
-
"use strict";
|
|
11541
|
-
filled = (v) => !!v && v.trim() !== "";
|
|
11542
|
-
}
|
|
11543
|
-
});
|
|
11544
|
-
|
|
11545
11715
|
// ../runner/src/sandbox-probe.ts
|
|
11546
11716
|
import { execFileSync } from "node:child_process";
|
|
11547
11717
|
import { accessSync, constants } from "node:fs";
|
|
@@ -11654,6 +11824,9 @@ var init_src2 = __esm({
|
|
|
11654
11824
|
init_codex_settings();
|
|
11655
11825
|
init_agent_cli();
|
|
11656
11826
|
init_custom_agents();
|
|
11827
|
+
init_agent_readonly();
|
|
11828
|
+
init_codex_agent_config();
|
|
11829
|
+
init_custom_agent_eval();
|
|
11657
11830
|
init_verify_scope();
|
|
11658
11831
|
init_code_style();
|
|
11659
11832
|
init_paths();
|
|
@@ -12039,7 +12212,8 @@ var init_start = __esm({
|
|
|
12039
12212
|
var doctor_exports = {};
|
|
12040
12213
|
__export(doctor_exports, {
|
|
12041
12214
|
default: () => doctor,
|
|
12042
|
-
doctorReport: () => doctorReport
|
|
12215
|
+
doctorReport: () => doctorReport,
|
|
12216
|
+
resolveDoctorCodexBin: () => resolveDoctorCodexBin
|
|
12043
12217
|
});
|
|
12044
12218
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
12045
12219
|
import { accessSync as accessSync2, constants as constants2, existsSync as existsSync4 } from "node:fs";
|
|
@@ -12051,19 +12225,22 @@ function doctorReport(p3) {
|
|
|
12051
12225
|
{ mark: p3.git ? "\u2713" : "\u2717", text: p3.git ?? "git \u2014 TAK ADA (wajib: worktree per sesi)", fatal: !p3.git },
|
|
12052
12226
|
{ mark: p3.tmux ? "\u2713" : "\u2717", text: p3.tmux ?? "tmux \u2014 TAK ADA (wajib: sesi agen hidup di tmux)", fatal: !p3.tmux },
|
|
12053
12227
|
{ mark: p3.claude ? "\u2713" : "\xB7", text: p3.claude ? `claude ${p3.claude}` : "claude \u2014 tak ada", fatal: false },
|
|
12054
|
-
{
|
|
12228
|
+
{
|
|
12229
|
+
mark: p3.codex ? codexNativeAgentsSupported(p3.codex) ? "\u2713" : "!" : "\xB7",
|
|
12230
|
+
text: p3.codex ? `codex ${p3.codex} \u2014 custom agent native ${codexNativeAgentsSupported(p3.codex) ? "siap" : `butuh >= ${CODEX_NATIVE_AGENTS_MIN_CLIENT}; sesi parent tetap bisa berjalan`}` : "codex \u2014 tak ada",
|
|
12231
|
+
fatal: false
|
|
12232
|
+
},
|
|
12055
12233
|
// SPEC-471 · ADR-0095 · `gh` opsional: tanpa dia tarik issue jatuh ke HTTPS + GITHUB_TOKEN.
|
|
12056
12234
|
{
|
|
12057
12235
|
mark: p3.gh ? "\u2713" : "\xB7",
|
|
12058
12236
|
text: p3.gh ? `gh ${p3.gh}` : "gh \u2014 tak ada (tarik issue akan lewat HTTP + GITHUB_TOKEN)",
|
|
12059
12237
|
fatal: false
|
|
12060
12238
|
},
|
|
12061
|
-
// SPEC-
|
|
12062
|
-
//
|
|
12063
|
-
// ada error di mana pun yang akan mengatakannya. Kegagalan senyap justru yang layak dilaporkan.
|
|
12239
|
+
// SPEC-950 · jalur normal memakai spool file bahkan di sandbox. curl hanya fallback untuk hook
|
|
12240
|
+
// lama/tanpa HANOMAN_EVENT_DIR, jadi absennya tidak lagi berarti telemetry utama mati.
|
|
12064
12241
|
{
|
|
12065
12242
|
mark: p3.curl ? "\u2713" : "!",
|
|
12066
|
-
text: p3.curl ? `curl ${p3.curl}` : "curl \u2014
|
|
12243
|
+
text: p3.curl ? `curl ${p3.curl}` : "curl \u2014 tak ada (fallback event tanpa spool tidak tersedia)",
|
|
12067
12244
|
fatal: false
|
|
12068
12245
|
},
|
|
12069
12246
|
// Direktori turunan lahir saat dipakai, jadi izin tulis yang belum ada di situ adalah
|
|
@@ -12117,12 +12294,22 @@ function version(bin, args) {
|
|
|
12117
12294
|
return null;
|
|
12118
12295
|
}
|
|
12119
12296
|
}
|
|
12297
|
+
async function resolveDoctorCodexBin(env, dbUrl, read = readRuntimeConfig) {
|
|
12298
|
+
try {
|
|
12299
|
+
const configured = (await read(dbUrl, "HANOMAN_CODEX_BIN"))?.trim();
|
|
12300
|
+
if (configured) return configured;
|
|
12301
|
+
} catch {
|
|
12302
|
+
}
|
|
12303
|
+
return env.HANOMAN_CODEX_BIN?.trim() || "codex";
|
|
12304
|
+
}
|
|
12120
12305
|
async function doctor(_argv, ctx) {
|
|
12121
12306
|
let layout;
|
|
12122
12307
|
let db;
|
|
12308
|
+
let dbUrl;
|
|
12123
12309
|
try {
|
|
12124
12310
|
layout = resolveLayout(distDir(), existsSync4);
|
|
12125
|
-
|
|
12311
|
+
dbUrl = resolveDbUrl(ctx.env, dirname5(layout.schema));
|
|
12312
|
+
db = dbFilePath(dbUrl);
|
|
12126
12313
|
} catch (e) {
|
|
12127
12314
|
ctx.stderr(`${e.message}
|
|
12128
12315
|
`);
|
|
@@ -12136,7 +12323,8 @@ async function doctor(_argv, ctx) {
|
|
|
12136
12323
|
{ label: "key SSH", path: d.sshKeys, writable: writable(d.sshKeys), fatal: false }
|
|
12137
12324
|
];
|
|
12138
12325
|
const claude = version(ctx.env.HANOMAN_CLAUDE_BIN ?? "claude", ["--version"]);
|
|
12139
|
-
const
|
|
12326
|
+
const codexProbe = codexNativeVersionProbe(ctx.env, await resolveDoctorCodexBin(ctx.env, dbUrl));
|
|
12327
|
+
const codex = version(codexProbe.bin, codexProbe.args);
|
|
12140
12328
|
const method = METHODS[DEFAULT_METHOD];
|
|
12141
12329
|
const methods = zAgent.options.filter((a) => (a === "codex" ? codex : claude) !== null).map((a) => {
|
|
12142
12330
|
const s2 = scanAgentSkills(a, ctx.env);
|
|
@@ -12172,6 +12360,7 @@ ${notice}
|
|
|
12172
12360
|
if (!r.ok) ctx.stderr("\nada prasyarat yang belum terpenuhi \u2014 hanoman tak akan bisa menjalankan sesi\n");
|
|
12173
12361
|
return r.ok ? 0 : 1;
|
|
12174
12362
|
}
|
|
12363
|
+
var readRuntimeConfig;
|
|
12175
12364
|
var init_doctor = __esm({
|
|
12176
12365
|
"src/commands/doctor.ts"() {
|
|
12177
12366
|
"use strict";
|
|
@@ -12179,6 +12368,15 @@ var init_doctor = __esm({
|
|
|
12179
12368
|
init_src();
|
|
12180
12369
|
init_layout();
|
|
12181
12370
|
init_start();
|
|
12371
|
+
readRuntimeConfig = async (dbUrl, key) => {
|
|
12372
|
+
const { PrismaClient } = await import("@prisma/client");
|
|
12373
|
+
const client = new PrismaClient({ datasourceUrl: dbUrl });
|
|
12374
|
+
try {
|
|
12375
|
+
return (await client.runtimeConfig.findUnique({ where: { key }, select: { value: true } }))?.value ?? null;
|
|
12376
|
+
} finally {
|
|
12377
|
+
await client.$disconnect();
|
|
12378
|
+
}
|
|
12379
|
+
};
|
|
12182
12380
|
}
|
|
12183
12381
|
});
|
|
12184
12382
|
|