hanoman 0.1.26 → 0.1.28
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 +612 -272
- package/dist/server.js +617 -233
- package/package.json +1 -1
- package/web/assets/{index-BfOACraN.js → index-CJNgL7_5.js} +1552 -1552
- package/web/index.html +1 -1
package/dist/cli.js
CHANGED
|
@@ -16,165 +16,6 @@ var init_types = __esm({
|
|
|
16
16
|
}
|
|
17
17
|
});
|
|
18
18
|
|
|
19
|
-
// ../runner/src/reverse-standard.ts
|
|
20
|
-
var init_reverse_standard = __esm({
|
|
21
|
-
"../runner/src/reverse-standard.ts"() {
|
|
22
|
-
"use strict";
|
|
23
|
-
}
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
// ../runner/src/verify-scope.ts
|
|
27
|
-
var CHANGED;
|
|
28
|
-
var init_verify_scope = __esm({
|
|
29
|
-
"../runner/src/verify-scope.ts"() {
|
|
30
|
-
"use strict";
|
|
31
|
-
CHANGED = [
|
|
32
|
-
"Scope verifikasi: HANYA yang berubah. Mesin ini menjalankan beberapa sesi sekaligus \u2014",
|
|
33
|
-
"memverifikasi seluruh project menghabiskan RAM & CPU yang sedang dipakai sesi lain.",
|
|
34
|
-
"",
|
|
35
|
-
"Berkas yang berubah di worktree ini:",
|
|
36
|
-
'`git diff --name-only "$HANOMAN_BASE_SHA"...HEAD` (yang sudah di-commit) dan',
|
|
37
|
-
"`git status --porcelain` (yang belum).",
|
|
38
|
-
"",
|
|
39
|
-
"- Test: jalankan HANYA test yang berkaitan dengan berkas itu. Repo vitest:",
|
|
40
|
-
' `pnpm vitest --run --changed "$HANOMAN_BASE_SHA"` (vitest sendiri menurunkan berkas yang',
|
|
41
|
-
" berubah dari git, termasuk yang belum di-commit), atau `pnpm vitest related --run <berkas\u2026>`,",
|
|
42
|
-
" atau sebut path berkas test-nya langsung. Stack lain: `pytest <path>`, `go test ./paket/...`.",
|
|
43
|
-
" JANGAN `pnpm test` atau `vitest run` polos \u2014 itu seluruh suite.",
|
|
44
|
-
" Jebakan: `--changed` menyalakan `passWithNoTests`, jadi nol test TERLIHAT hijau. Pastikan",
|
|
45
|
-
' test-nya memang berjalan, jangan menerima "no test files" sebagai bukti.',
|
|
46
|
-
"- Typecheck: hanya paket yang tersentuh (mis. `pnpm --filter ./server typecheck`).",
|
|
47
|
-
" JANGAN `pnpm -r typecheck` \u2014 itu menyalakan satu proses tsc per paket sekaligus.",
|
|
48
|
-
"- Lint: hanya berkas yang berubah, bukan seluruh repo.",
|
|
49
|
-
"- Build penuh: hanya bila yang kamu ubah memang soal build/bundling.",
|
|
50
|
-
"- Boot server + curl / smoke end-to-end: hanya bila task ini menyentuh endpoint atau perilaku",
|
|
51
|
-
" runtime-nya, sekali di akhir \u2014 bukan rutin tiap task.",
|
|
52
|
-
"- Membereskan proses nyangkut: JANGAN `pkill -f <pola>` maupun `killall`. Prompt setiap sesi",
|
|
53
|
-
" hidup di ARGV proses agennya, jadi pola seperti `vitest`/`tsc`/`node` ikut mencocoki agen sesi",
|
|
54
|
-
" LAIN di mesin ini dan mematikannya di tengah kerja \u2014 dan `pkill` mengecualikan leluhurnya",
|
|
55
|
-
" sendiri, jadi yang mati selalu sesi tetangga, bukan sesimu. Bunuh per-PID: `ps`/`lsof -ti:<port>`",
|
|
56
|
-
" \u2192 `kill <pid>`; atau sempitkan polanya sampai memuat path worktree-mu sendiri.",
|
|
57
|
-
"",
|
|
58
|
-
"Suite penuh, lint penuh, dan build penuh adalah tugas MANUSIA sebelum merge, bukan tugas sesi.",
|
|
59
|
-
"Pengecualian yang kamu putuskan sendiri: bila perubahanmu memang berdampak luas (mengubah",
|
|
60
|
-
"tipe/kontrak bersama, skema, atau berkas yang diimpor banyak modul), perluas scope seperlunya",
|
|
61
|
-
"dan katakan alasannya. Ini panduan biaya, bukan larangan."
|
|
62
|
-
].join("\n");
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
// ../runner/src/code-style.ts
|
|
67
|
-
var CODE_STYLE_CLAUSE;
|
|
68
|
-
var init_code_style = __esm({
|
|
69
|
-
"../runner/src/code-style.ts"() {
|
|
70
|
-
"use strict";
|
|
71
|
-
CODE_STYLE_CLAUSE = [
|
|
72
|
-
"Gaya kode \u2014 berlaku setiap kali kamu menulis atau mengubah kode:",
|
|
73
|
-
"- Tulis kode yang rapi dan mengikuti idiom, penamaan, serta struktur kode di sekitarnya.",
|
|
74
|
-
" Kodemu harus terbaca seperti kode yang sudah ada di berkas itu, bukan seperti tempelan.",
|
|
75
|
-
"- Jangan menulis komentar yang cuma mengulang apa yang sudah dinyatakan kode.",
|
|
76
|
-
"- Komentar hanya untuk hal yang TIDAK terbaca dari kode: alasan/why sebuah keputusan,",
|
|
77
|
-
" trade-off yang diambil, workaround beserta rujukan SPEC/ADR-nya, atau invariant yang tak",
|
|
78
|
-
" kelihatan. Komentar semacam itu justru berharga \u2014 jangan ikut dibuang.",
|
|
79
|
-
"- Jangan menambahkan komentar pembatas seksi, header berhiasan, atau narasi langkah demi langkah.",
|
|
80
|
-
"- Jangan meninggalkan kode mati atau kode yang dikomentari. Hapus saja; riwayat git yang menyimpannya."
|
|
81
|
-
].join("\n");
|
|
82
|
-
}
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
// ../runner/src/goal-spec.ts
|
|
86
|
-
var init_goal_spec = __esm({
|
|
87
|
-
"../runner/src/goal-spec.ts"() {
|
|
88
|
-
"use strict";
|
|
89
|
-
}
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
// ../runner/src/prompt.ts
|
|
93
|
-
var ESCALATION_CONTRACT, REVERSE_PHASE_GUIDE, SCAFFOLD_PHASE_GUIDE;
|
|
94
|
-
var init_prompt = __esm({
|
|
95
|
-
"../runner/src/prompt.ts"() {
|
|
96
|
-
"use strict";
|
|
97
|
-
init_reverse_standard();
|
|
98
|
-
init_verify_scope();
|
|
99
|
-
init_code_style();
|
|
100
|
-
init_goal_spec();
|
|
101
|
-
ESCALATION_CONTRACT = [
|
|
102
|
-
"REKOMENDASI ESKALASI (wajib, terbaca mesin). Di bagian akhir dokumen audit, tulis bagian",
|
|
103
|
-
"`## Rekomendasi eskalasi` berisi penjelasan singkat untuk manusia, LALU tepat SATU blok ```json",
|
|
104
|
-
"berbentuk persis seperti ini (satu-satunya blok json di dokumen itu):",
|
|
105
|
-
"",
|
|
106
|
-
"```json",
|
|
107
|
-
'{ "escalation": { "target": "none|qa|brief|prd", "reason": "<alasan singkat>",',
|
|
108
|
-
' "alternatives": ["<target lain yang masuk akal>"],',
|
|
109
|
-
' "prefill": { "title": "", "context": "", "outcome": "", "constraints": "", "severity": "", "steps": "" } } }',
|
|
110
|
-
"```",
|
|
111
|
-
"",
|
|
112
|
-
"Pilih `target` dari hasil auditmu, bukan default:",
|
|
113
|
-
'- "qa" \u2014 bug / regresi / perilaku salah yang perlu diperbaiki. Isi `prefill.severity`',
|
|
114
|
-
" (critical|major|minor) dan `prefill.steps` (langkah reproduksi).",
|
|
115
|
-
'- "brief" \u2014 kebutuhan/fitur yang bentuknya sudah jelas dan cakupannya satu backlog.',
|
|
116
|
-
" Isi `prefill.title`, `prefill.context`, `prefill.outcome`.",
|
|
117
|
-
'- "prd" \u2014 kebutuhan produk yang besar, ambigu, atau lintas modul sehingga perlu dokumen PRD',
|
|
118
|
-
" lebih dulu. Isi `prefill.title`, `prefill.context`, `prefill.outcome`.",
|
|
119
|
-
'- "none" \u2014 pertanyaannya sudah terjawab; tak perlu perbaikan maupun fitur baru.',
|
|
120
|
-
"",
|
|
121
|
-
"`alternatives` boleh array kosong. Jangan menulis blok json lain di dokumen itu."
|
|
122
|
-
].join("\n");
|
|
123
|
-
REVERSE_PHASE_GUIDE = [
|
|
124
|
-
"- Scan: baca source code \u2014 stack, arsitektur, data model, API surface, perilaku domain. Belum menulis docs.",
|
|
125
|
-
"- Docs teknis: tulis kategori yang bisa diturunkan dari kode (architecture, requirements + EARS dari perilaku nyata, adr ber-Status accepted (reverse-engineered), operations, security, design-system/frontend bila relevan). Isi lengkap dan spesifik, bukan kerangka.",
|
|
126
|
-
"- Wawancara: untuk product, business, brand, research, entrypoints \u2014 ajukan SATU pertanyaan per giliran ke manusia di terminal ini, tunggu jawabannya, isi docs dari jawaban. Jangan mengarang. Topik tanpa jawaban tandai: Status: draft \u2014 menunggu input.",
|
|
127
|
-
"- Konvensi & index: tulis internal/docs/README.md (index bernomor lengkap), CLAUDE.md, AGENTS.md, .claude/settings.json + .claude/hooks/ensure-docs-updated.py persis seperti STANDAR DOCS.",
|
|
128
|
-
"- Serah terima: pastikan setiap berkas docs terdaftar di index, lalu tulis ringkasan hasil + daftar pertanyaan yang belum terjawab ke terminal."
|
|
129
|
-
].join("\n");
|
|
130
|
-
SCAFFOLD_PHASE_GUIDE = [
|
|
131
|
-
"- Brainstorm: perdalam IDE project (di bawah) jadi masalah, pengguna, scope, dan metrik sukses. Ajukan SATU pertanyaan per giliran ke manusia di terminal ini, tunggu jawabannya. Jangan mengarang; topik yang belum dijawab tandai sebagai open question.",
|
|
132
|
-
"- Objective: kunci SATU MVP objective yang terukur dari hasil brainstorm, tulis ringkas di docs.",
|
|
133
|
-
"- Doc index: tulis SELURUH internal/docs/** dari ide+objective+jawaban, mengikuti STANDAR DOCS di bawah \u2014 entrypoints, product, business, requirements (+EARS dari perilaku yang diinginkan), research, architecture (stack/data-model/api-contract/nfr), adr awal (Status accepted), design-system/frontend bila ada UI, operations, security, plus README index bernomor + CLAUDE.md + AGENTS.md + Stop hook. Lengkap dan spesifik terhadap ide ini, BUKAN kerangka."
|
|
134
|
-
].join("\n");
|
|
135
|
-
}
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
// ../runner/src/git.ts
|
|
139
|
-
var init_git = __esm({
|
|
140
|
-
"../runner/src/git.ts"() {
|
|
141
|
-
"use strict";
|
|
142
|
-
}
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
// ../runner/src/settings.ts
|
|
146
|
-
var init_settings = __esm({
|
|
147
|
-
"../runner/src/settings.ts"() {
|
|
148
|
-
"use strict";
|
|
149
|
-
}
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
// ../runner/src/goal.ts
|
|
153
|
-
var init_goal = __esm({
|
|
154
|
-
"../runner/src/goal.ts"() {
|
|
155
|
-
"use strict";
|
|
156
|
-
init_prompt();
|
|
157
|
-
init_goal_spec();
|
|
158
|
-
}
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
// ../runner/src/codex-settings.ts
|
|
162
|
-
var init_codex_settings = __esm({
|
|
163
|
-
"../runner/src/codex-settings.ts"() {
|
|
164
|
-
"use strict";
|
|
165
|
-
init_prompt();
|
|
166
|
-
}
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
// ../runner/src/agent-cli.ts
|
|
170
|
-
var init_agent_cli = __esm({
|
|
171
|
-
"../runner/src/agent-cli.ts"() {
|
|
172
|
-
"use strict";
|
|
173
|
-
init_settings();
|
|
174
|
-
init_codex_settings();
|
|
175
|
-
}
|
|
176
|
-
});
|
|
177
|
-
|
|
178
19
|
// ../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/util.js
|
|
179
20
|
var util, objectUtil, ZodParsedType, getParsedType;
|
|
180
21
|
var init_util = __esm({
|
|
@@ -4319,6 +4160,120 @@ var init_spec_source = __esm({
|
|
|
4319
4160
|
}
|
|
4320
4161
|
});
|
|
4321
4162
|
|
|
4163
|
+
// ../shared/src/method-catalog.ts
|
|
4164
|
+
function resolveMethod(id) {
|
|
4165
|
+
return (id ? METHODS[id] : void 0) ?? METHODS[DEFAULT_METHOD];
|
|
4166
|
+
}
|
|
4167
|
+
var DEFAULT_METHOD, VERIFICATION_GATE, MATT_CLAUSE, METHODS, METHOD_IDS, uniq, PLAN_DIRS, SPEC_DIRS;
|
|
4168
|
+
var init_method_catalog = __esm({
|
|
4169
|
+
"../shared/src/method-catalog.ts"() {
|
|
4170
|
+
"use strict";
|
|
4171
|
+
DEFAULT_METHOD = "superpowers";
|
|
4172
|
+
VERIFICATION_GATE = "superpowers:verification-before-completion";
|
|
4173
|
+
MATT_CLAUSE = "Sesi ini TAK BERPENUNGGU \u2014 tak ada manusia yang menonton terminal untuk menjawab. Skill mattpocock yang kontraknya mewawancarai manusia (`/grill-me`, `/to-spec`, `/triage`) JANGAN dipakai: pakai primitif model-invoked-nya dan putuskan sendiri. `to-tickets` di fase Plan dipakai HANYA sebagai penghasil berkas plan berkotak `- [ ]` di `docs/matt/plans/`, BUKAN penerbit tiket \u2014 hanoman sendiri adalah issue tracker-nya, jadi jangan menulis ke tracker eksternal mana pun.";
|
|
4174
|
+
METHODS = {
|
|
4175
|
+
// Isi `PHASE_SKILLS` (SPEC-166) dipindah APA ADANYA. Objective & Spec adalah keluaran skill
|
|
4176
|
+
// brainstorming yang di-invoke di fase Brainstorm — sengaja tak punya entri sendiri. Fase reverse
|
|
4177
|
+
// dipandu standar docs di prompt-nya, bukan skill.
|
|
4178
|
+
superpowers: {
|
|
4179
|
+
id: "superpowers",
|
|
4180
|
+
label: "superpowers",
|
|
4181
|
+
planDir: "docs/superpowers/plans",
|
|
4182
|
+
specDir: "docs/superpowers/specs",
|
|
4183
|
+
phaseSkills: {
|
|
4184
|
+
Brainstorm: ["superpowers:brainstorming"],
|
|
4185
|
+
Audit: ["superpowers:systematic-debugging"],
|
|
4186
|
+
Plan: ["superpowers:writing-plans"],
|
|
4187
|
+
Execute: [
|
|
4188
|
+
"superpowers:executing-plans",
|
|
4189
|
+
"superpowers:test-driven-development",
|
|
4190
|
+
VERIFICATION_GATE
|
|
4191
|
+
],
|
|
4192
|
+
// SPEC-407 · fase `Goal` sengaja TANPA skill: seluruh inti flow itu membebaskan sesi dari
|
|
4193
|
+
// proses kaku. Yang tetap dijaga cuma pintu keluarnya.
|
|
4194
|
+
Verifikasi: [VERIFICATION_GATE]
|
|
4195
|
+
},
|
|
4196
|
+
exitSkills: [VERIFICATION_GATE],
|
|
4197
|
+
requires: ["superpowers"],
|
|
4198
|
+
install: {
|
|
4199
|
+
claude: [
|
|
4200
|
+
"claude plugin marketplace add obra/superpowers-marketplace",
|
|
4201
|
+
"claude plugin install superpowers@superpowers-marketplace"
|
|
4202
|
+
],
|
|
4203
|
+
codex: ["codex plugin add superpowers@openai-curated"]
|
|
4204
|
+
}
|
|
4205
|
+
},
|
|
4206
|
+
// Plugin `mattpocock-skills` (`/plugin install mattpocock-skills`); skill plugin di Claude Code
|
|
4207
|
+
// beralamat `plugin:skill`. `superpowers` tetap ikut di `requires` karena gerbang verifikasinya
|
|
4208
|
+
// dipinjam dari sana — mattpocock tak punya padanannya.
|
|
4209
|
+
matt: {
|
|
4210
|
+
id: "matt",
|
|
4211
|
+
label: "mattpocock",
|
|
4212
|
+
planDir: "docs/matt/plans",
|
|
4213
|
+
specDir: "docs/matt/specs",
|
|
4214
|
+
phaseSkills: {
|
|
4215
|
+
Brainstorm: ["mattpocock-skills:grilling"],
|
|
4216
|
+
Audit: ["mattpocock-skills:diagnosing-bugs"],
|
|
4217
|
+
Plan: ["mattpocock-skills:to-tickets"],
|
|
4218
|
+
Execute: [
|
|
4219
|
+
"mattpocock-skills:implement",
|
|
4220
|
+
"mattpocock-skills:tdd",
|
|
4221
|
+
"mattpocock-skills:code-review"
|
|
4222
|
+
],
|
|
4223
|
+
Verifikasi: [VERIFICATION_GATE]
|
|
4224
|
+
},
|
|
4225
|
+
exitSkills: [VERIFICATION_GATE],
|
|
4226
|
+
extraClause: MATT_CLAUSE,
|
|
4227
|
+
requires: ["mattpocock-skills", "superpowers"],
|
|
4228
|
+
// `mattpocock-skills` ada di marketplace resmi Claude Code → tanpa `marketplace add`.
|
|
4229
|
+
// superpowers ikut dipasang karena `requires` menyebutnya: gerbang verifikasinya dipinjam
|
|
4230
|
+
// dari sana (INVARIAN 2). codex belum punya plugin native mattpocock — jalur resminya
|
|
4231
|
+
// `npx skills`, dan ia INTERAKTIF; itu justru alasan pemasangan hidup di pane yang ditonton.
|
|
4232
|
+
install: {
|
|
4233
|
+
claude: [
|
|
4234
|
+
"claude plugin install mattpocock-skills",
|
|
4235
|
+
"claude plugin marketplace add obra/superpowers-marketplace",
|
|
4236
|
+
"claude plugin install superpowers@superpowers-marketplace"
|
|
4237
|
+
],
|
|
4238
|
+
codex: [
|
|
4239
|
+
"npx skills@latest add mattpocock/skills",
|
|
4240
|
+
"codex plugin add superpowers@openai-curated"
|
|
4241
|
+
]
|
|
4242
|
+
}
|
|
4243
|
+
}
|
|
4244
|
+
};
|
|
4245
|
+
METHOD_IDS = Object.keys(METHODS);
|
|
4246
|
+
uniq = (xs) => [...new Set(xs)];
|
|
4247
|
+
PLAN_DIRS = uniq(METHOD_IDS.map((id) => METHODS[id].planDir));
|
|
4248
|
+
SPEC_DIRS = uniq(METHOD_IDS.map((id) => METHODS[id].specDir));
|
|
4249
|
+
}
|
|
4250
|
+
});
|
|
4251
|
+
|
|
4252
|
+
// ../shared/src/method-status.ts
|
|
4253
|
+
function methodSkills(m) {
|
|
4254
|
+
return [.../* @__PURE__ */ new Set([...Object.values(m.phaseSkills).flat(), ...m.exitSkills])];
|
|
4255
|
+
}
|
|
4256
|
+
function methodStatus(m, agent, installed) {
|
|
4257
|
+
const haveSkills = new Set(installed.skills);
|
|
4258
|
+
const havePackages = new Set(installed.packages);
|
|
4259
|
+
const missingPackages = m.requires.filter((p) => !havePackages.has(p));
|
|
4260
|
+
const missingSkills = methodSkills(m).filter((id) => !haveSkills.has(id));
|
|
4261
|
+
return {
|
|
4262
|
+
method: m.id,
|
|
4263
|
+
label: m.label,
|
|
4264
|
+
agent,
|
|
4265
|
+
ready: missingPackages.length === 0 && missingSkills.length === 0,
|
|
4266
|
+
missingPackages,
|
|
4267
|
+
missingSkills,
|
|
4268
|
+
install: [...m.install[agent]]
|
|
4269
|
+
};
|
|
4270
|
+
}
|
|
4271
|
+
var init_method_status = __esm({
|
|
4272
|
+
"../shared/src/method-status.ts"() {
|
|
4273
|
+
"use strict";
|
|
4274
|
+
}
|
|
4275
|
+
});
|
|
4276
|
+
|
|
4322
4277
|
// ../shared/src/agent-engine.ts
|
|
4323
4278
|
var zAgentEngine;
|
|
4324
4279
|
var init_agent_engine = __esm({
|
|
@@ -4465,6 +4420,7 @@ var init_entities = __esm({
|
|
|
4465
4420
|
init_telegram();
|
|
4466
4421
|
init_agent_engine();
|
|
4467
4422
|
init_auto_merge();
|
|
4423
|
+
init_method_catalog();
|
|
4468
4424
|
zProject = external_exports.object({
|
|
4469
4425
|
id: external_exports.string(),
|
|
4470
4426
|
name: external_exports.string(),
|
|
@@ -4664,6 +4620,12 @@ var init_entities = __esm({
|
|
|
4664
4620
|
// SPEC-338 · ADR-0074 · model/effort codex
|
|
4665
4621
|
verifyScope: zVerifyScope.default("changed"),
|
|
4666
4622
|
// SPEC-376 · ADR-0080 · scope verifikasi sesi
|
|
4623
|
+
// SPEC-734 · ADR-0113 · metode workflow default. LENIENT (`z.string()`, bukan `z.enum`):
|
|
4624
|
+
// instance yang di-sync dari hub bisa membawa id metode yang belum ada di build ini, dan itu
|
|
4625
|
+
// harus jadi fallback diam di titik pakai (`resolveMethod`) — bukan baris Setting yang gagal
|
|
4626
|
+
// parse lalu mengosongkan layar Settings. Alasan yang sama dengan model/effort di sini.
|
|
4627
|
+
method: external_exports.string().default(DEFAULT_METHOD),
|
|
4628
|
+
// SPEC-734 · ADR-0113 · metode workflow default
|
|
4667
4629
|
conflict: zConflict.default(CONFLICT_DEFAULTS),
|
|
4668
4630
|
// SPEC-383 · ADR-0081 · default sesi konflik rebase/merge
|
|
4669
4631
|
lead: zLead.default(LEAD_DEFAULTS),
|
|
@@ -5378,7 +5340,15 @@ var init_dto = __esm({
|
|
|
5378
5340
|
// SPEC-236 · terminal biasa NON-claude: shell mentah di repoDir project. Tanpa flow (bukan
|
|
5379
5341
|
// pipeline claude). DIDAHULUKAN: z.object non-strict membuang key asing, jadi bila varian
|
|
5380
5342
|
// longgar {project,flow?} lebih dulu, {project,shell:true} akan lolos sbg plain (shell dibuang).
|
|
5381
|
-
|
|
5343
|
+
// SPEC-739 · ADR-0114 · pemasangan skill metode: klien mengirim METODE + AGEN, bukan teks
|
|
5344
|
+
// perintah — perintahnya diturunkan server dari katalog `METHODS`. Dengan begitu "perintah
|
|
5345
|
+
// instalasi adalah data katalog" berlaku ujung ke ujung, dan endpoint ini tak pernah menjadi
|
|
5346
|
+
// "jalankan shell arbitrer". Tanpa field ini, shell mentah persis seperti SPEC-236.
|
|
5347
|
+
external_exports.object({
|
|
5348
|
+
project: external_exports.string(),
|
|
5349
|
+
shell: external_exports.literal(true),
|
|
5350
|
+
install: external_exports.object({ method: external_exports.string(), agent: zAgent }).optional()
|
|
5351
|
+
}),
|
|
5382
5352
|
// SPEC-166 · "reverse" = sesi project-level di worktree-nya sendiri, menyusun Source of Truth
|
|
5383
5353
|
// dari kode. TANPA override runtime: sesi project-level mengikuti Setting.agent (ADR-0074).
|
|
5384
5354
|
// Terminal biasa (tanpa flow) kini punya variannya SENDIRI di bawah — lihat SPEC-517.
|
|
@@ -5425,6 +5395,10 @@ var init_dto = __esm({
|
|
|
5425
5395
|
goalCondition: external_exports.string().max(4e3).optional(),
|
|
5426
5396
|
agent: zAgent.optional(),
|
|
5427
5397
|
verifyScope: zVerifyScope.optional(),
|
|
5398
|
+
// SPEC-734 · ADR-0113 — metode workflow per SESI: undefined → Spec.payload.method →
|
|
5399
|
+
// Setting.method → "superpowers". LENIENT (`z.string()`, bukan `z.enum`): id yang tak dikenal
|
|
5400
|
+
// jatuh ke default di `resolveMethod`, bukan ditolak 400 — alasan yang sama dengan zSetting.
|
|
5401
|
+
method: external_exports.string().optional(),
|
|
5428
5402
|
// SPEC-447 · ADR-0093 — lewati gerbang dependency. Hanya jalur manusia; UI hanya
|
|
5429
5403
|
// mengirimkannya sesudah operator melihat daftar pemblokirnya.
|
|
5430
5404
|
force: external_exports.boolean().optional()
|
|
@@ -5618,6 +5592,8 @@ var init_api = __esm({
|
|
|
5618
5592
|
limits: `${API}/limits`,
|
|
5619
5593
|
// SPEC-339 · versi codex CLI (peringatan lunak model GPT-5.6).
|
|
5620
5594
|
codexVersion: `${API}/codex/version`,
|
|
5595
|
+
// SPEC-739 · ADR-0114 · kesiapan skill metode per agen. LOCAL-only, diturunkan live dari disk.
|
|
5596
|
+
methodStatus: `${API}/methods/status`,
|
|
5621
5597
|
// SPEC-489 · panduan AI agent — markdown MENTAH & PUBLIC (tanpa auth). Satu definisi URL untuk
|
|
5622
5598
|
// klien web dan untuk tautan yang disalin operator ke agennya.
|
|
5623
5599
|
agentDoc: `${API}/agent-integration.md`,
|
|
@@ -7146,6 +7122,8 @@ var init_src = __esm({
|
|
|
7146
7122
|
"use strict";
|
|
7147
7123
|
init_enums();
|
|
7148
7124
|
init_spec_source();
|
|
7125
|
+
init_method_catalog();
|
|
7126
|
+
init_method_status();
|
|
7149
7127
|
init_agent_engine();
|
|
7150
7128
|
init_entities();
|
|
7151
7129
|
init_agent();
|
|
@@ -7172,6 +7150,169 @@ var init_src = __esm({
|
|
|
7172
7150
|
}
|
|
7173
7151
|
});
|
|
7174
7152
|
|
|
7153
|
+
// ../runner/src/reverse-standard.ts
|
|
7154
|
+
var init_reverse_standard = __esm({
|
|
7155
|
+
"../runner/src/reverse-standard.ts"() {
|
|
7156
|
+
"use strict";
|
|
7157
|
+
}
|
|
7158
|
+
});
|
|
7159
|
+
|
|
7160
|
+
// ../runner/src/verify-scope.ts
|
|
7161
|
+
var CHANGED;
|
|
7162
|
+
var init_verify_scope = __esm({
|
|
7163
|
+
"../runner/src/verify-scope.ts"() {
|
|
7164
|
+
"use strict";
|
|
7165
|
+
CHANGED = [
|
|
7166
|
+
"Scope verifikasi: HANYA yang berubah. Mesin ini menjalankan beberapa sesi sekaligus \u2014",
|
|
7167
|
+
"memverifikasi seluruh project menghabiskan RAM & CPU yang sedang dipakai sesi lain.",
|
|
7168
|
+
"",
|
|
7169
|
+
"Berkas yang berubah di worktree ini:",
|
|
7170
|
+
'`git diff --name-only "$HANOMAN_BASE_SHA"...HEAD` (yang sudah di-commit) dan',
|
|
7171
|
+
"`git status --porcelain` (yang belum).",
|
|
7172
|
+
"",
|
|
7173
|
+
"- Test: jalankan HANYA test yang berkaitan dengan berkas itu. Repo vitest:",
|
|
7174
|
+
' `pnpm vitest --run --changed "$HANOMAN_BASE_SHA"` (vitest sendiri menurunkan berkas yang',
|
|
7175
|
+
" berubah dari git, termasuk yang belum di-commit), atau `pnpm vitest related --run <berkas\u2026>`,",
|
|
7176
|
+
" atau sebut path berkas test-nya langsung. Stack lain: `pytest <path>`, `go test ./paket/...`.",
|
|
7177
|
+
" JANGAN `pnpm test` atau `vitest run` polos \u2014 itu seluruh suite.",
|
|
7178
|
+
" Jebakan: `--changed` menyalakan `passWithNoTests`, jadi nol test TERLIHAT hijau. Pastikan",
|
|
7179
|
+
' test-nya memang berjalan, jangan menerima "no test files" sebagai bukti.',
|
|
7180
|
+
"- Typecheck: hanya paket yang tersentuh (mis. `pnpm --filter ./server typecheck`).",
|
|
7181
|
+
" JANGAN `pnpm -r typecheck` \u2014 itu menyalakan satu proses tsc per paket sekaligus.",
|
|
7182
|
+
"- Lint: hanya berkas yang berubah, bukan seluruh repo.",
|
|
7183
|
+
"- Build penuh: hanya bila yang kamu ubah memang soal build/bundling.",
|
|
7184
|
+
"- Boot server + curl / smoke end-to-end: hanya bila task ini menyentuh endpoint atau perilaku",
|
|
7185
|
+
" runtime-nya, sekali di akhir \u2014 bukan rutin tiap task.",
|
|
7186
|
+
"- Membereskan proses nyangkut: JANGAN `pkill -f <pola>` maupun `killall`. Prompt setiap sesi",
|
|
7187
|
+
" hidup di ARGV proses agennya, jadi pola seperti `vitest`/`tsc`/`node` ikut mencocoki agen sesi",
|
|
7188
|
+
" LAIN di mesin ini dan mematikannya di tengah kerja \u2014 dan `pkill` mengecualikan leluhurnya",
|
|
7189
|
+
" sendiri, jadi yang mati selalu sesi tetangga, bukan sesimu. Bunuh per-PID: `ps`/`lsof -ti:<port>`",
|
|
7190
|
+
" \u2192 `kill <pid>`; atau sempitkan polanya sampai memuat path worktree-mu sendiri.",
|
|
7191
|
+
"",
|
|
7192
|
+
"Suite penuh, lint penuh, dan build penuh adalah tugas MANUSIA sebelum merge, bukan tugas sesi.",
|
|
7193
|
+
"Pengecualian yang kamu putuskan sendiri: bila perubahanmu memang berdampak luas (mengubah",
|
|
7194
|
+
"tipe/kontrak bersama, skema, atau berkas yang diimpor banyak modul), perluas scope seperlunya",
|
|
7195
|
+
"dan katakan alasannya. Ini panduan biaya, bukan larangan."
|
|
7196
|
+
].join("\n");
|
|
7197
|
+
}
|
|
7198
|
+
});
|
|
7199
|
+
|
|
7200
|
+
// ../runner/src/code-style.ts
|
|
7201
|
+
var CODE_STYLE_CLAUSE;
|
|
7202
|
+
var init_code_style = __esm({
|
|
7203
|
+
"../runner/src/code-style.ts"() {
|
|
7204
|
+
"use strict";
|
|
7205
|
+
CODE_STYLE_CLAUSE = [
|
|
7206
|
+
"Gaya kode \u2014 berlaku setiap kali kamu menulis atau mengubah kode:",
|
|
7207
|
+
"- Tulis kode yang rapi dan mengikuti idiom, penamaan, serta struktur kode di sekitarnya.",
|
|
7208
|
+
" Kodemu harus terbaca seperti kode yang sudah ada di berkas itu, bukan seperti tempelan.",
|
|
7209
|
+
"- Jangan menulis komentar yang cuma mengulang apa yang sudah dinyatakan kode.",
|
|
7210
|
+
"- Komentar hanya untuk hal yang TIDAK terbaca dari kode: alasan/why sebuah keputusan,",
|
|
7211
|
+
" trade-off yang diambil, workaround beserta rujukan SPEC/ADR-nya, atau invariant yang tak",
|
|
7212
|
+
" kelihatan. Komentar semacam itu justru berharga \u2014 jangan ikut dibuang.",
|
|
7213
|
+
"- Jangan menambahkan komentar pembatas seksi, header berhiasan, atau narasi langkah demi langkah.",
|
|
7214
|
+
"- Jangan meninggalkan kode mati atau kode yang dikomentari. Hapus saja; riwayat git yang menyimpannya."
|
|
7215
|
+
].join("\n");
|
|
7216
|
+
}
|
|
7217
|
+
});
|
|
7218
|
+
|
|
7219
|
+
// ../runner/src/goal-spec.ts
|
|
7220
|
+
var init_goal_spec = __esm({
|
|
7221
|
+
"../runner/src/goal-spec.ts"() {
|
|
7222
|
+
"use strict";
|
|
7223
|
+
}
|
|
7224
|
+
});
|
|
7225
|
+
|
|
7226
|
+
// ../runner/src/prompt.ts
|
|
7227
|
+
var ESCALATION_CONTRACT, PROJECT_METHOD, REVERSE_PHASE_GUIDE, SCAFFOLD_PHASE_GUIDE;
|
|
7228
|
+
var init_prompt = __esm({
|
|
7229
|
+
"../runner/src/prompt.ts"() {
|
|
7230
|
+
"use strict";
|
|
7231
|
+
init_src();
|
|
7232
|
+
init_reverse_standard();
|
|
7233
|
+
init_verify_scope();
|
|
7234
|
+
init_code_style();
|
|
7235
|
+
init_goal_spec();
|
|
7236
|
+
ESCALATION_CONTRACT = [
|
|
7237
|
+
"REKOMENDASI ESKALASI (wajib, terbaca mesin). Di bagian akhir dokumen audit, tulis bagian",
|
|
7238
|
+
"`## Rekomendasi eskalasi` berisi penjelasan singkat untuk manusia, LALU tepat SATU blok ```json",
|
|
7239
|
+
"berbentuk persis seperti ini (satu-satunya blok json di dokumen itu):",
|
|
7240
|
+
"",
|
|
7241
|
+
"```json",
|
|
7242
|
+
'{ "escalation": { "target": "none|qa|brief|prd", "reason": "<alasan singkat>",',
|
|
7243
|
+
' "alternatives": ["<target lain yang masuk akal>"],',
|
|
7244
|
+
' "prefill": { "title": "", "context": "", "outcome": "", "constraints": "", "severity": "", "steps": "" } } }',
|
|
7245
|
+
"```",
|
|
7246
|
+
"",
|
|
7247
|
+
"Pilih `target` dari hasil auditmu, bukan default:",
|
|
7248
|
+
'- "qa" \u2014 bug / regresi / perilaku salah yang perlu diperbaiki. Isi `prefill.severity`',
|
|
7249
|
+
" (critical|major|minor) dan `prefill.steps` (langkah reproduksi).",
|
|
7250
|
+
'- "brief" \u2014 kebutuhan/fitur yang bentuknya sudah jelas dan cakupannya satu backlog.',
|
|
7251
|
+
" Isi `prefill.title`, `prefill.context`, `prefill.outcome`.",
|
|
7252
|
+
'- "prd" \u2014 kebutuhan produk yang besar, ambigu, atau lintas modul sehingga perlu dokumen PRD',
|
|
7253
|
+
" lebih dulu. Isi `prefill.title`, `prefill.context`, `prefill.outcome`.",
|
|
7254
|
+
'- "none" \u2014 pertanyaannya sudah terjawab; tak perlu perbaikan maupun fitur baru.',
|
|
7255
|
+
"",
|
|
7256
|
+
"`alternatives` boleh array kosong. Jangan menulis blok json lain di dokumen itu."
|
|
7257
|
+
].join("\n");
|
|
7258
|
+
PROJECT_METHOD = resolveMethod();
|
|
7259
|
+
REVERSE_PHASE_GUIDE = [
|
|
7260
|
+
"- Scan: baca source code \u2014 stack, arsitektur, data model, API surface, perilaku domain. Belum menulis docs.",
|
|
7261
|
+
"- Docs teknis: tulis kategori yang bisa diturunkan dari kode (architecture, requirements + EARS dari perilaku nyata, adr ber-Status accepted (reverse-engineered), operations, security, design-system/frontend bila relevan). Isi lengkap dan spesifik, bukan kerangka.",
|
|
7262
|
+
"- Wawancara: untuk product, business, brand, research, entrypoints \u2014 ajukan SATU pertanyaan per giliran ke manusia di terminal ini, tunggu jawabannya, isi docs dari jawaban. Jangan mengarang. Topik tanpa jawaban tandai: Status: draft \u2014 menunggu input.",
|
|
7263
|
+
"- Konvensi & index: tulis internal/docs/README.md (index bernomor lengkap), CLAUDE.md, AGENTS.md, .claude/settings.json + .claude/hooks/ensure-docs-updated.py persis seperti STANDAR DOCS.",
|
|
7264
|
+
"- Serah terima: pastikan setiap berkas docs terdaftar di index, lalu tulis ringkasan hasil + daftar pertanyaan yang belum terjawab ke terminal."
|
|
7265
|
+
].join("\n");
|
|
7266
|
+
SCAFFOLD_PHASE_GUIDE = [
|
|
7267
|
+
"- Brainstorm: perdalam IDE project (di bawah) jadi masalah, pengguna, scope, dan metrik sukses. Ajukan SATU pertanyaan per giliran ke manusia di terminal ini, tunggu jawabannya. Jangan mengarang; topik yang belum dijawab tandai sebagai open question.",
|
|
7268
|
+
"- Objective: kunci SATU MVP objective yang terukur dari hasil brainstorm, tulis ringkas di docs.",
|
|
7269
|
+
"- Doc index: tulis SELURUH internal/docs/** dari ide+objective+jawaban, mengikuti STANDAR DOCS di bawah \u2014 entrypoints, product, business, requirements (+EARS dari perilaku yang diinginkan), research, architecture (stack/data-model/api-contract/nfr), adr awal (Status accepted), design-system/frontend bila ada UI, operations, security, plus README index bernomor + CLAUDE.md + AGENTS.md + Stop hook. Lengkap dan spesifik terhadap ide ini, BUKAN kerangka."
|
|
7270
|
+
].join("\n");
|
|
7271
|
+
}
|
|
7272
|
+
});
|
|
7273
|
+
|
|
7274
|
+
// ../runner/src/git.ts
|
|
7275
|
+
var init_git = __esm({
|
|
7276
|
+
"../runner/src/git.ts"() {
|
|
7277
|
+
"use strict";
|
|
7278
|
+
}
|
|
7279
|
+
});
|
|
7280
|
+
|
|
7281
|
+
// ../runner/src/settings.ts
|
|
7282
|
+
var init_settings = __esm({
|
|
7283
|
+
"../runner/src/settings.ts"() {
|
|
7284
|
+
"use strict";
|
|
7285
|
+
}
|
|
7286
|
+
});
|
|
7287
|
+
|
|
7288
|
+
// ../runner/src/goal.ts
|
|
7289
|
+
var init_goal = __esm({
|
|
7290
|
+
"../runner/src/goal.ts"() {
|
|
7291
|
+
"use strict";
|
|
7292
|
+
init_src();
|
|
7293
|
+
init_prompt();
|
|
7294
|
+
init_goal_spec();
|
|
7295
|
+
}
|
|
7296
|
+
});
|
|
7297
|
+
|
|
7298
|
+
// ../runner/src/codex-settings.ts
|
|
7299
|
+
var init_codex_settings = __esm({
|
|
7300
|
+
"../runner/src/codex-settings.ts"() {
|
|
7301
|
+
"use strict";
|
|
7302
|
+
init_src();
|
|
7303
|
+
init_prompt();
|
|
7304
|
+
}
|
|
7305
|
+
});
|
|
7306
|
+
|
|
7307
|
+
// ../runner/src/agent-cli.ts
|
|
7308
|
+
var init_agent_cli = __esm({
|
|
7309
|
+
"../runner/src/agent-cli.ts"() {
|
|
7310
|
+
"use strict";
|
|
7311
|
+
init_settings();
|
|
7312
|
+
init_codex_settings();
|
|
7313
|
+
}
|
|
7314
|
+
});
|
|
7315
|
+
|
|
7175
7316
|
// ../runner/src/custom-agents.ts
|
|
7176
7317
|
var init_custom_agents = __esm({
|
|
7177
7318
|
"../runner/src/custom-agents.ts"() {
|
|
@@ -7238,6 +7379,186 @@ var init_paths = __esm({
|
|
|
7238
7379
|
}
|
|
7239
7380
|
});
|
|
7240
7381
|
|
|
7382
|
+
// ../runner/src/skills.ts
|
|
7383
|
+
import { homedir as homedir2 } from "node:os";
|
|
7384
|
+
import { basename, dirname as dirname2, join as join2, resolve as resolve2 } from "node:path";
|
|
7385
|
+
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
7386
|
+
function agentSkillHome(agent, env = process.env, osHome = homedir2()) {
|
|
7387
|
+
const own = (agent === "codex" ? env.HANOMAN_CODEX_HOME : env.HANOMAN_CLAUDE_HOME)?.trim();
|
|
7388
|
+
if (own) return own;
|
|
7389
|
+
if (agent === "codex") {
|
|
7390
|
+
const cx = env.CODEX_HOME?.trim();
|
|
7391
|
+
if (cx) return cx;
|
|
7392
|
+
}
|
|
7393
|
+
return join2(osHome, agent === "codex" ? ".codex" : ".claude");
|
|
7394
|
+
}
|
|
7395
|
+
function agentsSkillHome(env = process.env, osHome = homedir2()) {
|
|
7396
|
+
return env.HANOMAN_AGENTS_HOME?.trim() || join2(osHome, ".agents");
|
|
7397
|
+
}
|
|
7398
|
+
function dirsIn(dir) {
|
|
7399
|
+
try {
|
|
7400
|
+
return readdirSync(dir, { withFileTypes: true }).filter((e) => (e.isDirectory() || e.isSymbolicLink()) && !e.name.startsWith(".")).map((e) => e.name);
|
|
7401
|
+
} catch {
|
|
7402
|
+
return [];
|
|
7403
|
+
}
|
|
7404
|
+
}
|
|
7405
|
+
function readJson(file) {
|
|
7406
|
+
try {
|
|
7407
|
+
return JSON.parse(readFileSync(file, "utf8"));
|
|
7408
|
+
} catch {
|
|
7409
|
+
return null;
|
|
7410
|
+
}
|
|
7411
|
+
}
|
|
7412
|
+
function isSkillDir(dir) {
|
|
7413
|
+
return existsSync(join2(dir, "SKILL.md"));
|
|
7414
|
+
}
|
|
7415
|
+
function asSkill(dir, pkg, name = basename(dir)) {
|
|
7416
|
+
return { id: pkg ? `${pkg}:${name}` : name, name, pkg, dir };
|
|
7417
|
+
}
|
|
7418
|
+
function skillsUnder(dir, pkg, depth = 2) {
|
|
7419
|
+
const out = [];
|
|
7420
|
+
for (const name of dirsIn(dir)) {
|
|
7421
|
+
const sub = join2(dir, name);
|
|
7422
|
+
if (isSkillDir(sub)) out.push(asSkill(sub, pkg, name));
|
|
7423
|
+
else if (depth > 1) out.push(...skillsUnder(sub, pkg, depth - 1));
|
|
7424
|
+
}
|
|
7425
|
+
return out;
|
|
7426
|
+
}
|
|
7427
|
+
function manifestSkills(installPath, pkg) {
|
|
7428
|
+
for (const marker of [".claude-plugin", ".codex-plugin"]) {
|
|
7429
|
+
const j = readJson(join2(installPath, marker, "plugin.json"));
|
|
7430
|
+
const declared = j?.skills;
|
|
7431
|
+
if (!Array.isArray(declared)) continue;
|
|
7432
|
+
const out = [];
|
|
7433
|
+
for (const rel of declared) {
|
|
7434
|
+
if (typeof rel !== "string" || !rel) continue;
|
|
7435
|
+
const p = resolve2(installPath, rel);
|
|
7436
|
+
const dir = basename(p) === "SKILL.md" ? dirname2(p) : p;
|
|
7437
|
+
if (isSkillDir(dir)) out.push(asSkill(dir, pkg));
|
|
7438
|
+
}
|
|
7439
|
+
if (out.length) return out;
|
|
7440
|
+
}
|
|
7441
|
+
return [];
|
|
7442
|
+
}
|
|
7443
|
+
function pluginSkills(installPath, pkg) {
|
|
7444
|
+
const declared = manifestSkills(installPath, pkg);
|
|
7445
|
+
return declared.length ? declared : skillsUnder(join2(installPath, "skills"), pkg);
|
|
7446
|
+
}
|
|
7447
|
+
function lockPluginNames(agentsHome) {
|
|
7448
|
+
const out = /* @__PURE__ */ new Map();
|
|
7449
|
+
const j = readJson(join2(agentsHome, ".skill-lock.json"));
|
|
7450
|
+
const skills = j?.skills;
|
|
7451
|
+
if (!skills || typeof skills !== "object") return out;
|
|
7452
|
+
for (const [name, entry] of Object.entries(skills)) {
|
|
7453
|
+
const pkg = entry?.pluginName;
|
|
7454
|
+
if (typeof pkg === "string" && pkg.trim()) out.set(name, pkg.trim());
|
|
7455
|
+
}
|
|
7456
|
+
return out;
|
|
7457
|
+
}
|
|
7458
|
+
function splitPluginKey(key) {
|
|
7459
|
+
const at = key.lastIndexOf("@");
|
|
7460
|
+
return at > 0 ? { pkg: key.slice(0, at), marketplace: key.slice(at + 1) } : { pkg: key, marketplace: "" };
|
|
7461
|
+
}
|
|
7462
|
+
function manifestRoots(home) {
|
|
7463
|
+
const j = readJson(join2(home, "plugins", "installed_plugins.json"));
|
|
7464
|
+
const plugins = j?.plugins;
|
|
7465
|
+
if (!plugins || typeof plugins !== "object") return [];
|
|
7466
|
+
const out = [];
|
|
7467
|
+
for (const [key, entries] of Object.entries(plugins)) {
|
|
7468
|
+
const { pkg, marketplace } = splitPluginKey(key);
|
|
7469
|
+
for (const e of Array.isArray(entries) ? entries : []) {
|
|
7470
|
+
const p = e?.installPath;
|
|
7471
|
+
if (typeof p === "string" && p) out.push({ pkg, marketplace, dir: p });
|
|
7472
|
+
}
|
|
7473
|
+
}
|
|
7474
|
+
return out;
|
|
7475
|
+
}
|
|
7476
|
+
function cacheRoots(home) {
|
|
7477
|
+
const cache = join2(home, "plugins", "cache");
|
|
7478
|
+
const out = [];
|
|
7479
|
+
for (const marketplace of dirsIn(cache))
|
|
7480
|
+
for (const pkg of dirsIn(join2(cache, marketplace)))
|
|
7481
|
+
for (const version3 of dirsIn(join2(cache, marketplace, pkg)))
|
|
7482
|
+
out.push({ pkg, marketplace, dir: join2(cache, marketplace, pkg, version3) });
|
|
7483
|
+
return out;
|
|
7484
|
+
}
|
|
7485
|
+
function disabledPlugins(agent, home) {
|
|
7486
|
+
const out = /* @__PURE__ */ new Set();
|
|
7487
|
+
if (agent === "claude") {
|
|
7488
|
+
const en = readJson(join2(home, "settings.json"))?.enabledPlugins;
|
|
7489
|
+
if (en && typeof en === "object") {
|
|
7490
|
+
for (const [k, v] of Object.entries(en)) if (v === false) out.add(k);
|
|
7491
|
+
}
|
|
7492
|
+
return out;
|
|
7493
|
+
}
|
|
7494
|
+
let toml;
|
|
7495
|
+
try {
|
|
7496
|
+
toml = readFileSync(join2(home, "config.toml"), "utf8");
|
|
7497
|
+
} catch {
|
|
7498
|
+
return out;
|
|
7499
|
+
}
|
|
7500
|
+
let current = null;
|
|
7501
|
+
for (const raw of toml.split("\n")) {
|
|
7502
|
+
const line = raw.trim();
|
|
7503
|
+
const head = /^\[([^\]]*)\]$/.exec(line);
|
|
7504
|
+
if (head) {
|
|
7505
|
+
const m = /^plugins\."(.+)"$/.exec(head[1] ?? "");
|
|
7506
|
+
current = m ? m[1] : null;
|
|
7507
|
+
continue;
|
|
7508
|
+
}
|
|
7509
|
+
if (current && /^enabled\s*=\s*false\b/.test(line)) out.add(current);
|
|
7510
|
+
}
|
|
7511
|
+
return out;
|
|
7512
|
+
}
|
|
7513
|
+
function scanAgentSkills(agent, env = process.env, osHome = homedir2()) {
|
|
7514
|
+
const home = agentSkillHome(agent, env, osHome);
|
|
7515
|
+
const disabled = disabledPlugins(agent, home);
|
|
7516
|
+
const roots = [];
|
|
7517
|
+
const skills = [];
|
|
7518
|
+
const packages = /* @__PURE__ */ new Set();
|
|
7519
|
+
const seenSkill = /* @__PURE__ */ new Set();
|
|
7520
|
+
const seenRoot = /* @__PURE__ */ new Set();
|
|
7521
|
+
const add = (dir, found) => {
|
|
7522
|
+
if (!found.length) return;
|
|
7523
|
+
if (!seenRoot.has(dir)) {
|
|
7524
|
+
seenRoot.add(dir);
|
|
7525
|
+
roots.push(dir);
|
|
7526
|
+
}
|
|
7527
|
+
for (const s2 of found) if (!seenSkill.has(s2.id)) {
|
|
7528
|
+
seenSkill.add(s2.id);
|
|
7529
|
+
skills.push(s2);
|
|
7530
|
+
}
|
|
7531
|
+
};
|
|
7532
|
+
const userDir = join2(home, "skills");
|
|
7533
|
+
add(userDir, skillsUnder(userDir, null));
|
|
7534
|
+
for (const r of [...manifestRoots(home), ...cacheRoots(home)]) {
|
|
7535
|
+
if (disabled.has(`${r.pkg}@${r.marketplace}`)) continue;
|
|
7536
|
+
const found = pluginSkills(r.dir, r.pkg);
|
|
7537
|
+
if (!found.length) continue;
|
|
7538
|
+
packages.add(r.pkg);
|
|
7539
|
+
add(join2(r.dir, "skills"), found);
|
|
7540
|
+
}
|
|
7541
|
+
if (agent === "codex") {
|
|
7542
|
+
const agentsHome = agentsSkillHome(env, osHome);
|
|
7543
|
+
const dir = join2(agentsHome, "skills");
|
|
7544
|
+
const names = lockPluginNames(agentsHome);
|
|
7545
|
+
const flat = skillsUnder(dir, null);
|
|
7546
|
+
const withPkg = flat.flatMap((s2) => {
|
|
7547
|
+
const pkg = names.get(s2.name);
|
|
7548
|
+
if (!pkg) return [s2];
|
|
7549
|
+
packages.add(pkg);
|
|
7550
|
+
return [asSkill(s2.dir, pkg, s2.name), s2];
|
|
7551
|
+
});
|
|
7552
|
+
add(dir, withPkg);
|
|
7553
|
+
}
|
|
7554
|
+
return { agent, home, roots, skills, packages: [...packages] };
|
|
7555
|
+
}
|
|
7556
|
+
var init_skills = __esm({
|
|
7557
|
+
"../runner/src/skills.ts"() {
|
|
7558
|
+
"use strict";
|
|
7559
|
+
}
|
|
7560
|
+
});
|
|
7561
|
+
|
|
7241
7562
|
// ../runner/src/telegram-operator.ts
|
|
7242
7563
|
var init_telegram_operator = __esm({
|
|
7243
7564
|
"../runner/src/telegram-operator.ts"() {
|
|
@@ -7262,29 +7583,30 @@ var init_src2 = __esm({
|
|
|
7262
7583
|
init_verify_scope();
|
|
7263
7584
|
init_code_style();
|
|
7264
7585
|
init_paths();
|
|
7586
|
+
init_skills();
|
|
7265
7587
|
init_telegram_operator();
|
|
7266
7588
|
}
|
|
7267
7589
|
});
|
|
7268
7590
|
|
|
7269
7591
|
// src/layout.ts
|
|
7270
|
-
import { join as
|
|
7592
|
+
import { join as join3, resolve as resolve3 } from "node:path";
|
|
7271
7593
|
function resolveLayout(distDir2, exists) {
|
|
7272
|
-
const pkg =
|
|
7273
|
-
if (exists(
|
|
7594
|
+
const pkg = resolve3(distDir2, "..");
|
|
7595
|
+
if (exists(join3(pkg, "prisma", "schema.prisma"))) {
|
|
7274
7596
|
return {
|
|
7275
7597
|
root: pkg,
|
|
7276
|
-
schema:
|
|
7277
|
-
server:
|
|
7278
|
-
web: exists(
|
|
7598
|
+
schema: join3(pkg, "prisma", "schema.prisma"),
|
|
7599
|
+
server: join3(pkg, "dist", "server.js"),
|
|
7600
|
+
web: exists(join3(pkg, "web")) ? join3(pkg, "web") : null
|
|
7279
7601
|
};
|
|
7280
7602
|
}
|
|
7281
|
-
const repo =
|
|
7282
|
-
if (exists(
|
|
7603
|
+
const repo = resolve3(distDir2, "../..");
|
|
7604
|
+
if (exists(join3(repo, "server", "prisma", "schema.prisma"))) {
|
|
7283
7605
|
return {
|
|
7284
7606
|
root: repo,
|
|
7285
|
-
schema:
|
|
7286
|
-
server:
|
|
7287
|
-
web: exists(
|
|
7607
|
+
schema: join3(repo, "server", "prisma", "schema.prisma"),
|
|
7608
|
+
server: join3(repo, "server", "dist", "server.js"),
|
|
7609
|
+
web: exists(join3(repo, "src", "dist")) ? join3(repo, "src", "dist") : null
|
|
7288
7610
|
};
|
|
7289
7611
|
}
|
|
7290
7612
|
throw new Error(`hanoman: prisma/schema.prisma tak ditemukan dari ${distDir2} \u2014 instalasi rusak?`);
|
|
@@ -7382,8 +7704,8 @@ __export(start_exports, {
|
|
|
7382
7704
|
});
|
|
7383
7705
|
import { spawn, execFileSync as execFileSync2 } from "node:child_process";
|
|
7384
7706
|
import { createRequire } from "node:module";
|
|
7385
|
-
import { existsSync, mkdirSync, readdirSync, statSync, chmodSync } from "node:fs";
|
|
7386
|
-
import { dirname as
|
|
7707
|
+
import { existsSync as existsSync2, mkdirSync, readdirSync as readdirSync2, statSync, chmodSync } from "node:fs";
|
|
7708
|
+
import { dirname as dirname3, join as join4, resolve as resolvePath } from "node:path";
|
|
7387
7709
|
import { fileURLToPath } from "node:url";
|
|
7388
7710
|
function parseStartArgs(argv) {
|
|
7389
7711
|
const out = { port: null, host: null, db: null, migrate: true };
|
|
@@ -7424,7 +7746,7 @@ function parseStartArgs(argv) {
|
|
|
7424
7746
|
return out;
|
|
7425
7747
|
}
|
|
7426
7748
|
function distDir() {
|
|
7427
|
-
return
|
|
7749
|
+
return dirname3(fileURLToPath(import.meta.url));
|
|
7428
7750
|
}
|
|
7429
7751
|
function runPrisma(args, dbUrl) {
|
|
7430
7752
|
const prismaCli = prismaCliPath(createRequire(import.meta.url).resolve);
|
|
@@ -7476,9 +7798,9 @@ async function ensurePrismaClient(schema, dbUrl, ctx) {
|
|
|
7476
7798
|
}
|
|
7477
7799
|
}
|
|
7478
7800
|
function spawnHelperPaths(ptyDir, listDir, exists) {
|
|
7479
|
-
const dirs = [
|
|
7480
|
-
for (const name of listDir(
|
|
7481
|
-
return dirs.map((d) =>
|
|
7801
|
+
const dirs = [join4(ptyDir, "build", "Release")];
|
|
7802
|
+
for (const name of listDir(join4(ptyDir, "prebuilds"))) dirs.push(join4(ptyDir, "prebuilds", name));
|
|
7803
|
+
return dirs.map((d) => join4(d, "spawn-helper")).filter(exists);
|
|
7482
7804
|
}
|
|
7483
7805
|
function ensureSpawnHelpersExecutable(paths2, ops) {
|
|
7484
7806
|
const fixed = [];
|
|
@@ -7496,17 +7818,17 @@ function ensureSpawnHelpersExecutable(paths2, ops) {
|
|
|
7496
7818
|
function repairSpawnHelper(ctx) {
|
|
7497
7819
|
let ptyDir;
|
|
7498
7820
|
try {
|
|
7499
|
-
ptyDir =
|
|
7821
|
+
ptyDir = dirname3(createRequire(import.meta.url).resolve("node-pty/package.json"));
|
|
7500
7822
|
} catch {
|
|
7501
7823
|
return;
|
|
7502
7824
|
}
|
|
7503
7825
|
const paths2 = spawnHelperPaths(ptyDir, (d) => {
|
|
7504
7826
|
try {
|
|
7505
|
-
return
|
|
7827
|
+
return readdirSync2(d);
|
|
7506
7828
|
} catch {
|
|
7507
7829
|
return [];
|
|
7508
7830
|
}
|
|
7509
|
-
},
|
|
7831
|
+
}, existsSync2);
|
|
7510
7832
|
const fixed = ensureSpawnHelpersExecutable(paths2, {
|
|
7511
7833
|
mode: (p) => statSync(p).mode,
|
|
7512
7834
|
chmod: (p, m) => chmodSync(p, m)
|
|
@@ -7558,8 +7880,8 @@ async function start(argv, ctx) {
|
|
|
7558
7880
|
let layout;
|
|
7559
7881
|
let dbUrl;
|
|
7560
7882
|
try {
|
|
7561
|
-
layout = resolveLayout(distDir(),
|
|
7562
|
-
dbUrl = opts.db ? `file:${resolvePath(opts.db)}` : resolveDbUrl(ctx.env,
|
|
7883
|
+
layout = resolveLayout(distDir(), existsSync2);
|
|
7884
|
+
dbUrl = opts.db ? `file:${resolvePath(opts.db)}` : resolveDbUrl(ctx.env, dirname3(layout.schema));
|
|
7563
7885
|
} catch (e) {
|
|
7564
7886
|
ctx.stderr(`${e.message}
|
|
7565
7887
|
`);
|
|
@@ -7570,8 +7892,8 @@ async function start(argv, ctx) {
|
|
|
7570
7892
|
`);
|
|
7571
7893
|
const home = resolveHome(ctx.env);
|
|
7572
7894
|
mkdirSync(home, { recursive: true });
|
|
7573
|
-
mkdirSync(
|
|
7574
|
-
if (!
|
|
7895
|
+
mkdirSync(dirname3(dbFilePath(dbUrl)), { recursive: true });
|
|
7896
|
+
if (!existsSync2(layout.server)) {
|
|
7575
7897
|
ctx.stderr(`hanoman: bundle server tak ada di ${layout.server} \u2014 jalankan \`pnpm build\` dulu
|
|
7576
7898
|
`);
|
|
7577
7899
|
return 1;
|
|
@@ -7655,8 +7977,8 @@ __export(doctor_exports, {
|
|
|
7655
7977
|
doctorReport: () => doctorReport
|
|
7656
7978
|
});
|
|
7657
7979
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
7658
|
-
import { accessSync, constants, existsSync as
|
|
7659
|
-
import { dirname as
|
|
7980
|
+
import { accessSync, constants, existsSync as existsSync3 } from "node:fs";
|
|
7981
|
+
import { dirname as dirname4 } from "node:path";
|
|
7660
7982
|
function doctorReport(p) {
|
|
7661
7983
|
const major = Number(/^v?(\d+)/.exec(p.node)?.[1] ?? 0);
|
|
7662
7984
|
const rows = [
|
|
@@ -7675,6 +7997,15 @@ function doctorReport(p) {
|
|
|
7675
7997
|
{ mark: p.web ? "\u2713" : "!", text: p.web ? "aset dashboard ada" : "aset dashboard tak ada \u2014 API jalan, dashboard tidak", fatal: false },
|
|
7676
7998
|
{ mark: "\xB7", text: `db ${p.db}`, fatal: false }
|
|
7677
7999
|
];
|
|
8000
|
+
for (const m of p.methods) {
|
|
8001
|
+
const agent = m.agent === "codex" ? "Codex CLI" : "Claude Code";
|
|
8002
|
+
rows.push({
|
|
8003
|
+
mark: m.ready ? "\u2713" : "!",
|
|
8004
|
+
text: m.ready ? `metode ${m.method} \xB7 ${agent} \u2014 siap` : `metode ${m.method} \xB7 ${agent} \u2014 belum siap: ` + [...m.missingPackages, ...m.missingSkills].join(", ") + m.install.map((c) => `
|
|
8005
|
+
${c}`).join(""),
|
|
8006
|
+
fatal: false
|
|
8007
|
+
});
|
|
8008
|
+
}
|
|
7678
8009
|
if (!p.claude && !p.codex) {
|
|
7679
8010
|
rows.push({ mark: "\u2717", text: "tak ada CLI agen (claude ATAU codex wajib ada)", fatal: true });
|
|
7680
8011
|
}
|
|
@@ -7691,8 +8022,8 @@ async function doctor(_argv, ctx) {
|
|
|
7691
8022
|
let layout;
|
|
7692
8023
|
let db;
|
|
7693
8024
|
try {
|
|
7694
|
-
layout = resolveLayout(distDir(),
|
|
7695
|
-
db = dbFilePath(resolveDbUrl(ctx.env,
|
|
8025
|
+
layout = resolveLayout(distDir(), existsSync3);
|
|
8026
|
+
db = dbFilePath(resolveDbUrl(ctx.env, dirname4(layout.schema)));
|
|
7696
8027
|
} catch (e) {
|
|
7697
8028
|
ctx.stderr(`${e.message}
|
|
7698
8029
|
`);
|
|
@@ -7701,20 +8032,28 @@ async function doctor(_argv, ctx) {
|
|
|
7701
8032
|
const home = resolveHome(ctx.env);
|
|
7702
8033
|
let homeWritable = false;
|
|
7703
8034
|
try {
|
|
7704
|
-
accessSync(
|
|
8035
|
+
accessSync(existsSync3(home) ? home : dirname4(home), constants.W_OK);
|
|
7705
8036
|
homeWritable = true;
|
|
7706
8037
|
} catch {
|
|
7707
8038
|
}
|
|
8039
|
+
const claude = version(ctx.env.HANOMAN_CLAUDE_BIN ?? "claude", ["--version"]);
|
|
8040
|
+
const codex = version(ctx.env.HANOMAN_CODEX_BIN ?? "codex", ["--version"]);
|
|
8041
|
+
const method = METHODS[DEFAULT_METHOD];
|
|
8042
|
+
const methods = zAgent.options.filter((a) => (a === "codex" ? codex : claude) !== null).map((a) => {
|
|
8043
|
+
const s2 = scanAgentSkills(a, ctx.env);
|
|
8044
|
+
return methodStatus(method, a, { skills: s2.skills.map((k) => k.id), packages: s2.packages });
|
|
8045
|
+
});
|
|
7708
8046
|
const r = doctorReport({
|
|
7709
8047
|
node: process.version,
|
|
7710
8048
|
git: version("git", ["--version"]),
|
|
7711
8049
|
tmux: version("tmux", ["-V"]),
|
|
7712
|
-
claude
|
|
7713
|
-
codex
|
|
8050
|
+
claude,
|
|
8051
|
+
codex,
|
|
7714
8052
|
gh: version(ctx.env.HANOMAN_GH_BIN ?? "gh", ["--version"]),
|
|
7715
8053
|
homeWritable,
|
|
7716
8054
|
web: layout.web !== null,
|
|
7717
|
-
db
|
|
8055
|
+
db,
|
|
8056
|
+
methods
|
|
7718
8057
|
});
|
|
7719
8058
|
ctx.stdout(`hanoman doctor
|
|
7720
8059
|
${r.lines.join("\n")}
|
|
@@ -7730,6 +8069,7 @@ var init_doctor = __esm({
|
|
|
7730
8069
|
"src/commands/doctor.ts"() {
|
|
7731
8070
|
"use strict";
|
|
7732
8071
|
init_src2();
|
|
8072
|
+
init_src();
|
|
7733
8073
|
init_layout();
|
|
7734
8074
|
init_start();
|
|
7735
8075
|
}
|
|
@@ -17097,14 +17437,14 @@ function inputRequiredRoundsExceededMessage(method, maxRounds) {
|
|
|
17097
17437
|
return `Multi-round-trip request '${method}' still required input after ${maxRounds} rounds (inputRequired.maxRounds)`;
|
|
17098
17438
|
}
|
|
17099
17439
|
function sleep(ms, signal) {
|
|
17100
|
-
return new Promise((
|
|
17440
|
+
return new Promise((resolve4, reject) => {
|
|
17101
17441
|
if (signal?.aborted) {
|
|
17102
17442
|
reject(signal.reason instanceof SdkError ? signal.reason : new SdkError(SdkErrorCode.RequestTimeout, String(signal.reason)));
|
|
17103
17443
|
return;
|
|
17104
17444
|
}
|
|
17105
17445
|
const timer = setTimeout(() => {
|
|
17106
17446
|
signal?.removeEventListener("abort", onAbort);
|
|
17107
|
-
|
|
17447
|
+
resolve4();
|
|
17108
17448
|
}, ms);
|
|
17109
17449
|
const onAbort = () => {
|
|
17110
17450
|
clearTimeout(timer);
|
|
@@ -18915,7 +19255,7 @@ var init_src_CX2iR2pK = __esm({
|
|
|
18915
19255
|
const flowStartedAt = Date.now();
|
|
18916
19256
|
let onAbort;
|
|
18917
19257
|
let cleanupMessageId;
|
|
18918
|
-
return new Promise((
|
|
19258
|
+
return new Promise((resolve4, reject) => {
|
|
18919
19259
|
const earlyReject = (error2) => {
|
|
18920
19260
|
reject(error2);
|
|
18921
19261
|
};
|
|
@@ -18983,7 +19323,7 @@ var init_src_CX2iR2pK = __esm({
|
|
|
18983
19323
|
}
|
|
18984
19324
|
if (decoded.kind === "invalid") return reject(decoded.error);
|
|
18985
19325
|
if (decoded.kind === "input_required") {
|
|
18986
|
-
if (options?.allowInputRequired === true) return
|
|
19326
|
+
if (options?.allowInputRequired === true) return resolve4(manualInputRequiredValue(decoded));
|
|
18987
19327
|
const flow = {
|
|
18988
19328
|
codec,
|
|
18989
19329
|
request,
|
|
@@ -18995,11 +19335,11 @@ var init_src_CX2iR2pK = __esm({
|
|
|
18995
19335
|
params
|
|
18996
19336
|
}, resultSchema, legOptions)
|
|
18997
19337
|
};
|
|
18998
|
-
return
|
|
19338
|
+
return resolve4(this._resolveNonCompleteResult(decoded, flow));
|
|
18999
19339
|
}
|
|
19000
19340
|
const result = decoded.result;
|
|
19001
19341
|
validateStandardSchema(resultSchema, result).then((parseResult) => {
|
|
19002
|
-
if (parseResult.success)
|
|
19342
|
+
if (parseResult.success) resolve4(parseResult.data);
|
|
19003
19343
|
else reject(new SdkError(SdkErrorCode.InvalidResult, `Invalid result for ${request.method}: ${parseResult.error}`));
|
|
19004
19344
|
}, reject);
|
|
19005
19345
|
});
|
|
@@ -21815,7 +22155,7 @@ var init_ajvProvider_CEoC_sr = __esm({
|
|
|
21815
22155
|
ref = (0, resolve_1.resolveUrl)(this.opts.uriResolver, baseId, ref);
|
|
21816
22156
|
const schOrFunc = root.refs[ref];
|
|
21817
22157
|
if (schOrFunc) return schOrFunc;
|
|
21818
|
-
let _sch =
|
|
22158
|
+
let _sch = resolve4.call(this, root, ref);
|
|
21819
22159
|
if (_sch === void 0) {
|
|
21820
22160
|
const schema = (_a3 = root.localRefs) === null || _a3 === void 0 ? void 0 : _a3[ref];
|
|
21821
22161
|
const { schemaId } = this.opts;
|
|
@@ -21841,7 +22181,7 @@ var init_ajvProvider_CEoC_sr = __esm({
|
|
|
21841
22181
|
function sameSchemaEnv(s1, s2) {
|
|
21842
22182
|
return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
|
|
21843
22183
|
}
|
|
21844
|
-
function
|
|
22184
|
+
function resolve4(root, ref) {
|
|
21845
22185
|
let sch;
|
|
21846
22186
|
while (typeof (sch = this.refs[ref]) == "string") ref = sch;
|
|
21847
22187
|
return sch || this.schemas[ref] || resolveSchema.call(this, root, ref);
|
|
@@ -22291,7 +22631,7 @@ var init_ajvProvider_CEoC_sr = __esm({
|
|
|
22291
22631
|
else if (typeof uri === "object") uri = parse4(serialize(uri, options), options);
|
|
22292
22632
|
return uri;
|
|
22293
22633
|
}
|
|
22294
|
-
function
|
|
22634
|
+
function resolve4(baseURI, relativeURI, options) {
|
|
22295
22635
|
const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
|
|
22296
22636
|
const resolved = resolveComponent(parse4(baseURI, schemelessOptions), parse4(relativeURI, schemelessOptions), schemelessOptions, true);
|
|
22297
22637
|
schemelessOptions.skipEscape = true;
|
|
@@ -22465,7 +22805,7 @@ var init_ajvProvider_CEoC_sr = __esm({
|
|
|
22465
22805
|
const fastUri = {
|
|
22466
22806
|
SCHEMES,
|
|
22467
22807
|
normalize,
|
|
22468
|
-
resolve:
|
|
22808
|
+
resolve: resolve4,
|
|
22469
22809
|
resolveComponent,
|
|
22470
22810
|
equal,
|
|
22471
22811
|
serialize,
|
|
@@ -28157,7 +28497,7 @@ var init_stdio = __esm({
|
|
|
28157
28497
|
}
|
|
28158
28498
|
send(message) {
|
|
28159
28499
|
if (this._closed) return Promise.reject(/* @__PURE__ */ new Error("StdioServerTransport is closed"));
|
|
28160
|
-
return new Promise((
|
|
28500
|
+
return new Promise((resolve4, reject) => {
|
|
28161
28501
|
const json = serializeMessage(message);
|
|
28162
28502
|
let settled = false;
|
|
28163
28503
|
const onError = (error2) => {
|
|
@@ -28172,14 +28512,14 @@ var init_stdio = __esm({
|
|
|
28172
28512
|
settled = true;
|
|
28173
28513
|
this._stdout.off("error", onError);
|
|
28174
28514
|
this._stdout.off("drain", onDrain);
|
|
28175
|
-
|
|
28515
|
+
resolve4();
|
|
28176
28516
|
};
|
|
28177
28517
|
this._stdout.once("error", onError);
|
|
28178
28518
|
if (this._stdout.write(json)) {
|
|
28179
28519
|
if (settled) return;
|
|
28180
28520
|
settled = true;
|
|
28181
28521
|
this._stdout.off("error", onError);
|
|
28182
|
-
|
|
28522
|
+
resolve4();
|
|
28183
28523
|
} else if (!settled) this._stdout.once("drain", onDrain);
|
|
28184
28524
|
});
|
|
28185
28525
|
}
|
|
@@ -28233,14 +28573,14 @@ var init_stdio = __esm({
|
|
|
28233
28573
|
*/
|
|
28234
28574
|
async whenRequestsAnswered(timeoutMs) {
|
|
28235
28575
|
if (this._closed || this._pendingRequests.size === 0) return true;
|
|
28236
|
-
return await new Promise((
|
|
28576
|
+
return await new Promise((resolve4) => {
|
|
28237
28577
|
const waiter = () => {
|
|
28238
28578
|
clearTimeout(timer);
|
|
28239
|
-
|
|
28579
|
+
resolve4(true);
|
|
28240
28580
|
};
|
|
28241
28581
|
const timer = setTimeout(() => {
|
|
28242
28582
|
this._drainWaiters = this._drainWaiters.filter((pending) => pending !== waiter);
|
|
28243
|
-
|
|
28583
|
+
resolve4(false);
|
|
28244
28584
|
}, timeoutMs);
|
|
28245
28585
|
this._drainWaiters.push(waiter);
|
|
28246
28586
|
});
|
|
@@ -28519,9 +28859,9 @@ var mcp_exports = {};
|
|
|
28519
28859
|
__export(mcp_exports, {
|
|
28520
28860
|
default: () => mcp
|
|
28521
28861
|
});
|
|
28522
|
-
import { readFileSync } from "node:fs";
|
|
28523
|
-
import { homedir as
|
|
28524
|
-
import { join as
|
|
28862
|
+
import { readFileSync as readFileSync2 } from "node:fs";
|
|
28863
|
+
import { homedir as homedir3 } from "node:os";
|
|
28864
|
+
import { join as join5 } from "node:path";
|
|
28525
28865
|
async function mcp(argv, ctx) {
|
|
28526
28866
|
const cfg = resolveMcpConfig(argv, ctx.env, () => tokenFile(ctx.env));
|
|
28527
28867
|
const say = (s2) => ctx.stderr(redactToken(s2, cfg.token) + "\n");
|
|
@@ -28535,9 +28875,9 @@ async function mcp(argv, ctx) {
|
|
|
28535
28875
|
await handle.close();
|
|
28536
28876
|
return 0;
|
|
28537
28877
|
}
|
|
28538
|
-
await new Promise((
|
|
28539
|
-
process.stdin.once("close",
|
|
28540
|
-
process.stdin.once("end",
|
|
28878
|
+
await new Promise((resolve4) => {
|
|
28879
|
+
process.stdin.once("close", resolve4);
|
|
28880
|
+
process.stdin.once("end", resolve4);
|
|
28541
28881
|
});
|
|
28542
28882
|
return 0;
|
|
28543
28883
|
}
|
|
@@ -28552,9 +28892,9 @@ var init_mcp2 = __esm({
|
|
|
28552
28892
|
init_server();
|
|
28553
28893
|
init_redact();
|
|
28554
28894
|
tokenFile = (env) => {
|
|
28555
|
-
const home = env.HANOMAN_HOME ??
|
|
28895
|
+
const home = env.HANOMAN_HOME ?? join5(homedir3(), ".hanoman");
|
|
28556
28896
|
try {
|
|
28557
|
-
return
|
|
28897
|
+
return readFileSync2(join5(home, "agent-token"), "utf8");
|
|
28558
28898
|
} catch {
|
|
28559
28899
|
return null;
|
|
28560
28900
|
}
|
|
@@ -28574,8 +28914,8 @@ __export(migrate_pg_exports, {
|
|
|
28574
28914
|
migrationSteps: () => migrationSteps,
|
|
28575
28915
|
parseMigrateArgs: () => parseMigrateArgs
|
|
28576
28916
|
});
|
|
28577
|
-
import { existsSync as
|
|
28578
|
-
import { dirname as
|
|
28917
|
+
import { existsSync as existsSync4 } from "node:fs";
|
|
28918
|
+
import { dirname as dirname5, resolve as resolvePath2 } from "node:path";
|
|
28579
28919
|
function coerceInt8(rows, fields, model) {
|
|
28580
28920
|
const cols = fields.filter((f) => f.dataTypeID === INT8_OID).map((f) => f.name);
|
|
28581
28921
|
if (!cols.length) return rows;
|
|
@@ -28642,8 +28982,8 @@ async function migratePg(argv, ctx) {
|
|
|
28642
28982
|
let layout;
|
|
28643
28983
|
let dbUrl;
|
|
28644
28984
|
try {
|
|
28645
|
-
layout = resolveLayout(distDir(),
|
|
28646
|
-
dbUrl = opts.to ? `file:${resolvePath2(opts.to)}` : resolveDbUrl(ctx.env,
|
|
28985
|
+
layout = resolveLayout(distDir(), existsSync4);
|
|
28986
|
+
dbUrl = opts.to ? `file:${resolvePath2(opts.to)}` : resolveDbUrl(ctx.env, dirname5(layout.schema));
|
|
28647
28987
|
} catch (e) {
|
|
28648
28988
|
ctx.stderr(`${e.message}
|
|
28649
28989
|
`);
|
|
@@ -28781,11 +29121,11 @@ var init_migrate_pg = __esm({
|
|
|
28781
29121
|
});
|
|
28782
29122
|
|
|
28783
29123
|
// src/config.ts
|
|
28784
|
-
import { readFileSync as
|
|
28785
|
-
import { join as
|
|
29124
|
+
import { readFileSync as readFileSync3, existsSync as existsSync5 } from "node:fs";
|
|
29125
|
+
import { join as join6 } from "node:path";
|
|
28786
29126
|
function loadConfig(repoRoot) {
|
|
28787
|
-
const p =
|
|
28788
|
-
const raw =
|
|
29127
|
+
const p = join6(repoRoot, "hanoman.config.json");
|
|
29128
|
+
const raw = existsSync5(p) ? JSON.parse(readFileSync3(p, "utf8")) : {};
|
|
28789
29129
|
return zHanomanConfig.parse(raw);
|
|
28790
29130
|
}
|
|
28791
29131
|
var init_config3 = __esm({
|
|
@@ -28797,12 +29137,12 @@ var init_config3 = __esm({
|
|
|
28797
29137
|
|
|
28798
29138
|
// src/repo.ts
|
|
28799
29139
|
import { spawnSync } from "node:child_process";
|
|
28800
|
-
import { join as
|
|
29140
|
+
import { join as join7 } from "node:path";
|
|
28801
29141
|
function resolveRepo(cwd) {
|
|
28802
29142
|
const r = spawnSync("git", ["rev-parse", "--show-toplevel"], { cwd, encoding: "utf8" });
|
|
28803
29143
|
const root = r.status === 0 ? r.stdout.trim() : cwd;
|
|
28804
29144
|
const { docsDir } = loadConfig(root);
|
|
28805
|
-
return { root, docsDir, indexPath:
|
|
29145
|
+
return { root, docsDir, indexPath: join7(root, docsDir, "README.md") };
|
|
28806
29146
|
}
|
|
28807
29147
|
var init_repo = __esm({
|
|
28808
29148
|
"src/repo.ts"() {
|
|
@@ -28812,10 +29152,10 @@ var init_repo = __esm({
|
|
|
28812
29152
|
});
|
|
28813
29153
|
|
|
28814
29154
|
// src/docs-model.ts
|
|
28815
|
-
import { readFileSync as
|
|
28816
|
-
import { join as
|
|
29155
|
+
import { readFileSync as readFileSync4, readdirSync as readdirSync3, statSync as statSync2 } from "node:fs";
|
|
29156
|
+
import { join as join8, relative } from "node:path";
|
|
28817
29157
|
function parseIndex(indexPath) {
|
|
28818
|
-
const md =
|
|
29158
|
+
const md = readFileSync4(indexPath, "utf8");
|
|
28819
29159
|
const out = /* @__PURE__ */ new Set();
|
|
28820
29160
|
for (const m of md.matchAll(LINK_RE2)) {
|
|
28821
29161
|
let t = m[1].trim();
|
|
@@ -28828,9 +29168,9 @@ function parseIndex(indexPath) {
|
|
|
28828
29168
|
function walkDocs(docsRoot) {
|
|
28829
29169
|
const out = [];
|
|
28830
29170
|
const walk = (dir) => {
|
|
28831
|
-
for (const name of
|
|
29171
|
+
for (const name of readdirSync3(dir)) {
|
|
28832
29172
|
if (name.startsWith(".")) continue;
|
|
28833
|
-
const abs =
|
|
29173
|
+
const abs = join8(dir, name);
|
|
28834
29174
|
if (statSync2(abs).isDirectory()) walk(abs);
|
|
28835
29175
|
else out.push(relative(docsRoot, abs).split("\\").join("/"));
|
|
28836
29176
|
}
|
|
@@ -28862,17 +29202,17 @@ var init_docs_model = __esm({
|
|
|
28862
29202
|
});
|
|
28863
29203
|
|
|
28864
29204
|
// src/verify.ts
|
|
28865
|
-
import { join as
|
|
28866
|
-
import { existsSync as
|
|
29205
|
+
import { join as join9 } from "node:path";
|
|
29206
|
+
import { existsSync as existsSync6, readFileSync as readFileSync5 } from "node:fs";
|
|
28867
29207
|
function scanCoverage(cwd) {
|
|
28868
29208
|
const { root, docsDir, indexPath } = resolveRepo(cwd);
|
|
28869
|
-
const docsRoot =
|
|
28870
|
-
if (!
|
|
28871
|
-
if (!
|
|
29209
|
+
const docsRoot = join9(root, docsDir);
|
|
29210
|
+
if (!existsSync6(docsRoot)) return { coverage: 100, cats: [] };
|
|
29211
|
+
if (!existsSync6(indexPath)) throw new Error(`index Source of Truth tidak ada: ${indexPath}`);
|
|
28872
29212
|
const corpus = walkDocs(docsRoot);
|
|
28873
29213
|
const read = (rel) => {
|
|
28874
29214
|
try {
|
|
28875
|
-
return
|
|
29215
|
+
return readFileSync5(join9(docsRoot, rel), "utf8");
|
|
28876
29216
|
} catch {
|
|
28877
29217
|
return null;
|
|
28878
29218
|
}
|
|
@@ -28915,9 +29255,9 @@ var init_docs_scan = __esm({
|
|
|
28915
29255
|
});
|
|
28916
29256
|
|
|
28917
29257
|
// src/index-edit.ts
|
|
28918
|
-
import { readFileSync as
|
|
29258
|
+
import { readFileSync as readFileSync6, writeFileSync } from "node:fs";
|
|
28919
29259
|
function addLink(indexPath, relPath, category) {
|
|
28920
|
-
let md =
|
|
29260
|
+
let md = readFileSync6(indexPath, "utf8");
|
|
28921
29261
|
if (md.includes(`(${relPath})`)) return;
|
|
28922
29262
|
const base = relPath.split("/").pop().replace(/\.md$/, "");
|
|
28923
29263
|
const line = `- [${base}](${relPath})`;
|
|
@@ -28946,23 +29286,23 @@ __export(docs_index_exports, {
|
|
|
28946
29286
|
default: () => docs_index_default
|
|
28947
29287
|
});
|
|
28948
29288
|
import { parseArgs as parseArgs2 } from "node:util";
|
|
28949
|
-
import { join as
|
|
28950
|
-
import { existsSync as
|
|
29289
|
+
import { join as join10 } from "node:path";
|
|
29290
|
+
import { existsSync as existsSync7, readFileSync as readFileSync7 } from "node:fs";
|
|
28951
29291
|
async function docs_index_default(args, ctx) {
|
|
28952
29292
|
const { values } = parseArgs2({ args, options: { check: { type: "boolean" }, fix: { type: "boolean" } }, allowPositionals: true });
|
|
28953
29293
|
const { root, docsDir, indexPath } = resolveRepo(ctx.cwd);
|
|
28954
|
-
const docsRoot =
|
|
29294
|
+
const docsRoot = join10(root, docsDir);
|
|
28955
29295
|
const corpus = walkDocs(docsRoot);
|
|
28956
29296
|
const read = (rel) => {
|
|
28957
29297
|
try {
|
|
28958
|
-
return
|
|
29298
|
+
return readFileSync7(join10(docsRoot, rel), "utf8");
|
|
28959
29299
|
} catch {
|
|
28960
29300
|
return null;
|
|
28961
29301
|
}
|
|
28962
29302
|
};
|
|
28963
29303
|
const linked = linkedSetFrom(INDEX_NAME, corpus, read);
|
|
28964
29304
|
const unlinked = corpus.filter((f) => f !== INDEX_NAME && !linked.has(f));
|
|
28965
|
-
const dangling = [...parseIndex(indexPath)].filter((p) => !
|
|
29305
|
+
const dangling = [...parseIndex(indexPath)].filter((p) => !existsSync7(join10(docsRoot, p)));
|
|
28966
29306
|
if (values.fix) {
|
|
28967
29307
|
for (const f of unlinked) addLink(indexPath, f, f.split("/")[0]);
|
|
28968
29308
|
ctx.stdout(`linked ${unlinked.length} doc(s)
|
|
@@ -29015,7 +29355,7 @@ var init_docs_link = __esm({
|
|
|
29015
29355
|
});
|
|
29016
29356
|
|
|
29017
29357
|
// src/release/pack.ts
|
|
29018
|
-
import { join as
|
|
29358
|
+
import { join as join11 } from "node:path";
|
|
29019
29359
|
function packageJsonFor(version3, deps) {
|
|
29020
29360
|
return {
|
|
29021
29361
|
name: PKG_NAME,
|
|
@@ -29053,17 +29393,17 @@ function verifyPackedDeps(pkg) {
|
|
|
29053
29393
|
}
|
|
29054
29394
|
function copyPlan(repo) {
|
|
29055
29395
|
return [
|
|
29056
|
-
{ from:
|
|
29057
|
-
{ from:
|
|
29058
|
-
{ from:
|
|
29059
|
-
{ from:
|
|
29060
|
-
{ from:
|
|
29061
|
-
{ from:
|
|
29062
|
-
{ from:
|
|
29396
|
+
{ from: join11(repo, "server/dist/server.js"), to: "dist/server.js" },
|
|
29397
|
+
{ from: join11(repo, "server/dist/build-info.json"), to: "dist/build-info.json" },
|
|
29398
|
+
{ from: join11(repo, "cli/dist/hanoman.js"), to: "dist/cli.js" },
|
|
29399
|
+
{ from: join11(repo, "src/dist"), to: "web", dir: true },
|
|
29400
|
+
{ from: join11(repo, "server/prisma/schema.prisma"), to: "prisma/schema.prisma" },
|
|
29401
|
+
{ from: join11(repo, "server/prisma/migrations"), to: "prisma/migrations", dir: true },
|
|
29402
|
+
{ from: join11(repo, "internal/docs/operations/npm-readme.md"), to: "README.md" },
|
|
29063
29403
|
// SPEC-489 · dibaca runtime oleh pickGuideFile (kandidat `<pkg>/docs/…`). Bukan README:
|
|
29064
29404
|
// README paket adalah npm-readme.md (berhadapan-MANUSIA), ini naskah berhadapan-AGEN.
|
|
29065
|
-
{ from:
|
|
29066
|
-
{ from:
|
|
29405
|
+
{ from: join11(repo, "docs/agent-integration.md"), to: "docs/agent-integration.md" },
|
|
29406
|
+
{ from: join11(repo, "LICENSE"), to: "LICENSE" }
|
|
29067
29407
|
];
|
|
29068
29408
|
}
|
|
29069
29409
|
var PKG_NAME, REPO_URL, RUNTIME_DEPS, REQUIRED_ARTIFACTS, BIN_SHIM;
|
|
@@ -29109,10 +29449,10 @@ var pack_exports = {};
|
|
|
29109
29449
|
__export(pack_exports, {
|
|
29110
29450
|
default: () => pack
|
|
29111
29451
|
});
|
|
29112
|
-
import { cpSync, existsSync as
|
|
29113
|
-
import { dirname as
|
|
29452
|
+
import { cpSync, existsSync as existsSync8, mkdirSync as mkdirSync2, readFileSync as readFileSync8, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
29453
|
+
import { dirname as dirname6, join as join12 } from "node:path";
|
|
29114
29454
|
function depVersions(repo) {
|
|
29115
|
-
const read = (p) => JSON.parse(
|
|
29455
|
+
const read = (p) => JSON.parse(readFileSync8(join12(repo, p), "utf8"));
|
|
29116
29456
|
const server = read("server/package.json"), cli = read("cli/package.json");
|
|
29117
29457
|
const pools = [server.dependencies, server.devDependencies, cli.dependencies, cli.devDependencies];
|
|
29118
29458
|
const out = {};
|
|
@@ -29126,19 +29466,19 @@ function depVersions(repo) {
|
|
|
29126
29466
|
async function pack(argv, ctx) {
|
|
29127
29467
|
let repo;
|
|
29128
29468
|
try {
|
|
29129
|
-
repo = resolveLayout(distDir(),
|
|
29469
|
+
repo = resolveLayout(distDir(), existsSync8).root;
|
|
29130
29470
|
} catch (e) {
|
|
29131
29471
|
ctx.stderr(`${e.message}
|
|
29132
29472
|
`);
|
|
29133
29473
|
return 1;
|
|
29134
29474
|
}
|
|
29135
|
-
if (!
|
|
29475
|
+
if (!existsSync8(join12(repo, "server/prisma/schema.prisma"))) {
|
|
29136
29476
|
ctx.stderr("pack: hanya bisa dijalankan dari checkout repo hanoman\n");
|
|
29137
29477
|
return 1;
|
|
29138
29478
|
}
|
|
29139
29479
|
const outIdx = argv.indexOf("--out");
|
|
29140
|
-
const out = outIdx === -1 ?
|
|
29141
|
-
const version3 = JSON.parse(
|
|
29480
|
+
const out = outIdx === -1 ? join12(repo, "dist-npm") : join12(repo, argv[outIdx + 1] ?? "dist-npm");
|
|
29481
|
+
const version3 = JSON.parse(readFileSync8(join12(repo, "package.json"), "utf8")).version;
|
|
29142
29482
|
if (!version3) {
|
|
29143
29483
|
ctx.stderr("pack: root package.json tanpa field version\n");
|
|
29144
29484
|
return 1;
|
|
@@ -29152,20 +29492,20 @@ async function pack(argv, ctx) {
|
|
|
29152
29492
|
return 1;
|
|
29153
29493
|
}
|
|
29154
29494
|
rmSync(out, { recursive: true, force: true });
|
|
29155
|
-
mkdirSync2(
|
|
29495
|
+
mkdirSync2(join12(out, "bin"), { recursive: true });
|
|
29156
29496
|
for (const item of copyPlan(repo)) {
|
|
29157
|
-
if (!
|
|
29497
|
+
if (!existsSync8(item.from)) {
|
|
29158
29498
|
ctx.stderr(`pack: artefak hilang \u2014 ${item.from} (sudah \`pnpm build\`?)
|
|
29159
29499
|
`);
|
|
29160
29500
|
return 1;
|
|
29161
29501
|
}
|
|
29162
|
-
const dest =
|
|
29163
|
-
mkdirSync2(
|
|
29502
|
+
const dest = join12(out, item.to);
|
|
29503
|
+
mkdirSync2(dirname6(dest), { recursive: true });
|
|
29164
29504
|
cpSync(item.from, dest, item.dir ? { recursive: true } : {});
|
|
29165
29505
|
}
|
|
29166
|
-
writeFileSync2(
|
|
29167
|
-
writeFileSync2(
|
|
29168
|
-
const missing = REQUIRED_ARTIFACTS.filter((a) => !
|
|
29506
|
+
writeFileSync2(join12(out, "bin/hanoman.mjs"), BIN_SHIM);
|
|
29507
|
+
writeFileSync2(join12(out, "package.json"), JSON.stringify(packageJsonFor(version3, deps), null, 2) + "\n");
|
|
29508
|
+
const missing = REQUIRED_ARTIFACTS.filter((a) => !existsSync8(join12(out, a)));
|
|
29169
29509
|
if (missing.length) {
|
|
29170
29510
|
ctx.stderr(`pack: artefak wajib hilang: ${missing.join(", ")}
|
|
29171
29511
|
`);
|
|
@@ -29190,13 +29530,13 @@ var verify_packed_exports = {};
|
|
|
29190
29530
|
__export(verify_packed_exports, {
|
|
29191
29531
|
default: () => verifyPacked
|
|
29192
29532
|
});
|
|
29193
|
-
import { readFileSync as
|
|
29194
|
-
import { join as
|
|
29533
|
+
import { readFileSync as readFileSync9 } from "node:fs";
|
|
29534
|
+
import { join as join13 } from "node:path";
|
|
29195
29535
|
function verifyPacked(_argv, ctx) {
|
|
29196
|
-
const path =
|
|
29536
|
+
const path = join13(process.cwd(), "package.json");
|
|
29197
29537
|
let pkg;
|
|
29198
29538
|
try {
|
|
29199
|
-
pkg = JSON.parse(
|
|
29539
|
+
pkg = JSON.parse(readFileSync9(path, "utf8"));
|
|
29200
29540
|
} catch {
|
|
29201
29541
|
ctx.stderr(`verify: tak bisa membaca ${path}
|
|
29202
29542
|
`);
|