hanoman 0.9.34 → 0.9.36
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 +79 -13
- package/dist/server.js +235 -94
- package/package.json +1 -1
- package/web/assets/{DalangHanomanScreen-BwBpu2_P.js → DalangHanomanScreen-NmpJIcg6.js} +1 -1
- package/web/assets/{DocPreviewModal-z4u5bA7e.js → DocPreviewModal-DK597e3s.js} +1 -1
- package/web/assets/{DocsWorkspace-CtD3uuCo.js → DocsWorkspace-BQX-HlzW.js} +1 -1
- package/web/assets/{IdeScreen-D-jOfQ5p.js → IdeScreen-LeUPaFsS.js} +1 -1
- package/web/assets/{LeadScreen-BzauaH1t.js → LeadScreen-BVCKv46y.js} +1 -1
- package/web/assets/{ReviewScreen-CMhrSnaH.js → ReviewScreen-C6NcJChq.js} +1 -1
- package/web/assets/{SchedulerScreen-h9C8CMSA.js → SchedulerScreen-2AH0R3TJ.js} +1 -1
- package/web/assets/{SettingsScreen-DrV1eN2q.js → SettingsScreen-B4SVzh9m.js} +3 -3
- package/web/assets/{TeamScreen-DQ7DBfil.js → TeamScreen-6XEfuZUm.js} +1 -1
- package/web/assets/{TerminalScreen-BecrzSkO.js → TerminalScreen-DubD6vT-.js} +1 -1
- package/web/assets/{TriageScreen-jtTZsaK5.js → TriageScreen-BYJxyCar.js} +1 -1
- package/web/assets/{VpsScreen-v5UmXGHF.js → VpsScreen-Df37dgKx.js} +1 -1
- package/web/assets/{fields-B0XXQmkb.js → fields-C94HI0V8.js} +1 -1
- package/web/assets/{index-kLq09yz-.js → index-BeFSh2Ba.js} +207 -207
- package/web/assets/{live-wjfa6DIz.js → live-5ezoV9Fs.js} +1 -1
- package/web/assets/{sched-lead-shared-BfF2ZYfo.js → sched-lead-shared-BpZu6N2A.js} +1 -1
- package/web/assets/{settings-rebase-BMeQSp64.js → settings-rebase-DaTGgcuO.js} +1 -1
- package/web/index.html +1 -1
package/dist/server.js
CHANGED
|
@@ -4159,7 +4159,7 @@ var init_enums = __esm({
|
|
|
4159
4159
|
zSeverity = external_exports.enum(["critical", "major", "minor"]);
|
|
4160
4160
|
zTicketCategory = external_exports.enum(["bug", "fitur", "pertanyaan", "lainnya"]);
|
|
4161
4161
|
zTicketStatus = external_exports.enum(["new", "accepted", "rejected"]);
|
|
4162
|
-
VERIFY_SCOPES = ["changed", "full"];
|
|
4162
|
+
VERIFY_SCOPES = ["changed", "full", "none"];
|
|
4163
4163
|
zVerifyScope = external_exports.enum(VERIFY_SCOPES);
|
|
4164
4164
|
}
|
|
4165
4165
|
});
|
|
@@ -4299,6 +4299,8 @@ var init_method_catalog = __esm({
|
|
|
4299
4299
|
"superpowers:test-driven-development",
|
|
4300
4300
|
VERIFICATION_GATE
|
|
4301
4301
|
],
|
|
4302
|
+
// ADR-0230 · fase Review resmi: audit spec & plan vs diff + gerbang verifikasi.
|
|
4303
|
+
Review: ["superpowers:requesting-code-review", VERIFICATION_GATE],
|
|
4302
4304
|
// SPEC-407 · fase `Goal` sengaja TANPA skill: seluruh inti flow itu membebaskan sesi dari
|
|
4303
4305
|
// proses kaku. Yang tetap dijaga cuma pintu keluarnya.
|
|
4304
4306
|
Verifikasi: [VERIFICATION_GATE]
|
|
@@ -4342,6 +4344,8 @@ var init_method_catalog = __esm({
|
|
|
4342
4344
|
"mattpocock-skills:tdd",
|
|
4343
4345
|
"mattpocock-skills:code-review"
|
|
4344
4346
|
],
|
|
4347
|
+
// ADR-0230 · fase Review resmi: audit spec & plan vs diff + gerbang verifikasi.
|
|
4348
|
+
Review: ["mattpocock-skills:code-review", VERIFICATION_GATE],
|
|
4345
4349
|
Verifikasi: [VERIFICATION_GATE]
|
|
4346
4350
|
},
|
|
4347
4351
|
exitSkills: [VERIFICATION_GATE],
|
|
@@ -4382,6 +4386,8 @@ var init_method_catalog = __esm({
|
|
|
4382
4386
|
"agent-skills:test-driven-development",
|
|
4383
4387
|
"agent-skills:code-review-and-quality"
|
|
4384
4388
|
],
|
|
4389
|
+
// ADR-0230 · fase Review resmi: audit spec & plan vs diff + gerbang verifikasi.
|
|
4390
|
+
Review: ["agent-skills:code-review-and-quality", VERIFICATION_GATE],
|
|
4385
4391
|
Verifikasi: [VERIFICATION_GATE]
|
|
4386
4392
|
},
|
|
4387
4393
|
exitSkills: [VERIFICATION_GATE],
|
|
@@ -5168,7 +5174,7 @@ var init_logs = __esm({
|
|
|
5168
5174
|
function phaseAgentName(phase) {
|
|
5169
5175
|
return PHASE_AGENT_PREFIX + phase.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
5170
5176
|
}
|
|
5171
|
-
var ORCHESTRATION_FLOWS, FLOW_PHASES, PHASE_AGENT_PREFIX, isPhaseAgentName, PHASE_EVIDENCE_GRACE_MS, EXECUTE_MODE_FLOWS, REVIEWER_CELL, REVIEWER_FLOWS, REVIEWER_DEFAULTS;
|
|
5177
|
+
var ORCHESTRATION_FLOWS, FLOW_PHASES, PHASE_AGENT_PREFIX, isPhaseAgentName, PHASE_EVIDENCE_GRACE_MS, EXECUTE_MODE_FLOWS, REVIEWER_CELL, REVIEWER_FLOWS, REVIEWER_DEFAULTS, UNSKIPPABLE_PHASES;
|
|
5172
5178
|
var init_orchestration = __esm({
|
|
5173
5179
|
"../shared/src/orchestration.ts"() {
|
|
5174
5180
|
"use strict";
|
|
@@ -5184,8 +5190,9 @@ var init_orchestration = __esm({
|
|
|
5184
5190
|
"no_effort"
|
|
5185
5191
|
];
|
|
5186
5192
|
FLOW_PHASES = {
|
|
5187
|
-
|
|
5188
|
-
|
|
5193
|
+
// ADR-0230 · `Review` = fase resmi sesudah Execute (dulu langkah R di dalam Execute, ADR-0170 #4).
|
|
5194
|
+
feature: ["Brainstorm", "Objective", "Spec", "Plan", "Execute", "Review"],
|
|
5195
|
+
qa: ["Audit", "Spec", "Plan", "Execute", "Review"],
|
|
5189
5196
|
scaffold: ["Brainstorm", "Objective", "Doc index"],
|
|
5190
5197
|
reverse: ["Scan", "Docs teknis", "Wawancara", "Konvensi & index", "Serah terima"],
|
|
5191
5198
|
prd: ["Brainstorm", "PRD"],
|
|
@@ -5208,12 +5215,15 @@ var init_orchestration = __esm({
|
|
|
5208
5215
|
ORCHESTRATION_FLOWS.filter((f) => FLOW_PHASES[f].some((p3) => p3 === "Execute" || p3 === "Goal"))
|
|
5209
5216
|
);
|
|
5210
5217
|
REVIEWER_CELL = "Review";
|
|
5211
|
-
REVIEWER_FLOWS =
|
|
5218
|
+
REVIEWER_FLOWS = new Set(
|
|
5219
|
+
ORCHESTRATION_FLOWS.filter((f) => FLOW_PHASES[f].includes(REVIEWER_CELL))
|
|
5220
|
+
);
|
|
5212
5221
|
REVIEWER_DEFAULTS = {
|
|
5213
5222
|
claude: { model: "opus", effort: "high" },
|
|
5214
5223
|
codex: { model: "gpt-5.6-sol", effort: "high" },
|
|
5215
5224
|
antigravity: { model: "inherit", effort: null }
|
|
5216
5225
|
};
|
|
5226
|
+
UNSKIPPABLE_PHASES = /* @__PURE__ */ new Set([REVIEWER_CELL]);
|
|
5217
5227
|
}
|
|
5218
5228
|
});
|
|
5219
5229
|
|
|
@@ -5224,7 +5234,7 @@ var init_runtime_defaults = __esm({
|
|
|
5224
5234
|
"use strict";
|
|
5225
5235
|
init_orchestration();
|
|
5226
5236
|
init_zod();
|
|
5227
|
-
RUNTIME_DEFAULTS_VERSION = "2026-
|
|
5237
|
+
RUNTIME_DEFAULTS_VERSION = "2026-10-25-v1";
|
|
5228
5238
|
zRuntimeDefaultState = external_exports.enum(["seeded", "user"]);
|
|
5229
5239
|
zBuiltinRuntimeDefaults = external_exports.object({
|
|
5230
5240
|
version: external_exports.string().default(RUNTIME_DEFAULTS_VERSION),
|
|
@@ -5281,14 +5291,16 @@ var init_runtime_defaults = __esm({
|
|
|
5281
5291
|
Objective: cell("sonnet", "medium"),
|
|
5282
5292
|
Spec: cell("opus", "high"),
|
|
5283
5293
|
Plan: cell("opus", "high"),
|
|
5284
|
-
Execute: cell("sonnet", "high")
|
|
5294
|
+
Execute: cell("sonnet", "high"),
|
|
5295
|
+
Review: cell("opus", "high")
|
|
5285
5296
|
},
|
|
5286
5297
|
{
|
|
5287
5298
|
Brainstorm: cell("gpt-5.6-terra", "medium"),
|
|
5288
5299
|
Objective: cell("gpt-5.6-terra", "medium"),
|
|
5289
5300
|
Spec: cell("gpt-5.6-sol", "high"),
|
|
5290
5301
|
Plan: cell("gpt-5.6-sol", "high"),
|
|
5291
|
-
Execute: cell("gpt-5.6-terra", "high")
|
|
5302
|
+
Execute: cell("gpt-5.6-terra", "high"),
|
|
5303
|
+
Review: cell("gpt-5.6-sol", "high")
|
|
5292
5304
|
}
|
|
5293
5305
|
),
|
|
5294
5306
|
qa: flow(
|
|
@@ -5296,13 +5308,15 @@ var init_runtime_defaults = __esm({
|
|
|
5296
5308
|
Audit: cell("opus", "high"),
|
|
5297
5309
|
Spec: cell("opus", "high"),
|
|
5298
5310
|
Plan: cell("sonnet", "high"),
|
|
5299
|
-
Execute: cell("sonnet", "high")
|
|
5311
|
+
Execute: cell("sonnet", "high"),
|
|
5312
|
+
Review: cell("opus", "high")
|
|
5300
5313
|
},
|
|
5301
5314
|
{
|
|
5302
5315
|
Audit: cell("gpt-5.6-sol", "high"),
|
|
5303
5316
|
Spec: cell("gpt-5.6-sol", "high"),
|
|
5304
5317
|
Plan: cell("gpt-5.6-terra", "high"),
|
|
5305
|
-
Execute: cell("gpt-5.6-terra", "high")
|
|
5318
|
+
Execute: cell("gpt-5.6-terra", "high"),
|
|
5319
|
+
Review: cell("gpt-5.6-sol", "high")
|
|
5306
5320
|
}
|
|
5307
5321
|
),
|
|
5308
5322
|
scaffold: flow(
|
|
@@ -5856,20 +5870,16 @@ function resolvePhasePlan(input) {
|
|
|
5856
5870
|
const model = input.runtime === "claude" && picked === CLAUDE_DEFAULT_ALIAS ? CLAUDE_SUBAGENT_INHERIT : picked;
|
|
5857
5871
|
return { model, effort: coerce3(model, override?.effort ?? cell4?.effort ?? fallback3.effort ?? "medium") };
|
|
5858
5872
|
};
|
|
5859
|
-
const reviewer = REVIEWER_FLOWS.has(input.flow) ? {
|
|
5860
|
-
agentName: phaseAgentName(REVIEWER_CELL),
|
|
5861
|
-
phase: "Execute",
|
|
5862
|
-
...resolve25(REVIEWER_CELL, REVIEWER_DEFAULTS[input.runtime])
|
|
5863
|
-
} : void 0;
|
|
5864
5873
|
return {
|
|
5865
5874
|
flow: input.flow,
|
|
5866
5875
|
runtime: input.runtime,
|
|
5876
|
+
// ADR-0170 P2 · ADR-0230 · fase Review TIDAK mewarisi orchestrator: default-nya konstanta peran,
|
|
5877
|
+
// sel/override `Review` menimpanya.
|
|
5867
5878
|
phases: FLOW_PHASES[input.flow].map((phase) => ({
|
|
5868
5879
|
phase,
|
|
5869
5880
|
agentName: phaseAgentName(phase),
|
|
5870
|
-
...resolve25(phase, input.orchestrator)
|
|
5881
|
+
...resolve25(phase, phase === REVIEWER_CELL ? REVIEWER_DEFAULTS[input.runtime] : input.orchestrator)
|
|
5871
5882
|
})),
|
|
5872
|
-
...reviewer ? { reviewer } : {},
|
|
5873
5883
|
// Amandemen ADR-0170 P2 · cara Execute mengerjakan plan; hanya dipakai sesi claude.
|
|
5874
5884
|
executeMode: cfg?.executeMode ?? "inline"
|
|
5875
5885
|
};
|
|
@@ -13215,7 +13225,7 @@ var init_sessions = __esm({
|
|
|
13215
13225
|
effort: str("Effort. Kosong = default global."),
|
|
13216
13226
|
goal: bool("Mode goal per-sesi. Kosong = ikut setelan global."),
|
|
13217
13227
|
goalCondition: str("Kondisi selesai mode goal (maks 4000 karakter)."),
|
|
13218
|
-
verifyScope: enumStr(["changed", "full"], "Scope verifikasi. Kosong = ikut setelan global."),
|
|
13228
|
+
verifyScope: enumStr(["changed", "full", "none"], "Scope verifikasi: changed = hanya yang berubah, full = seluruh project, none = jangan jalankan test. Kosong = ikut setelan global."),
|
|
13219
13229
|
method: str("Metode workflow. Id tak dikenal jatuh ke default, bukan ditolak."),
|
|
13220
13230
|
phaseOverrides: {
|
|
13221
13231
|
type: "object",
|
|
@@ -16766,15 +16776,25 @@ function parseHookEvent(body) {
|
|
|
16766
16776
|
}
|
|
16767
16777
|
const turn = zTurnEnd.safeParse(body);
|
|
16768
16778
|
if (turn.success && !turn.data.stop_hook_active) {
|
|
16779
|
+
if (turn.data.background_tasks?.some((t) => t.status === "running")) return null;
|
|
16780
|
+
const message = clip3(turn.data.last_assistant_message, ASK_MESSAGE_MAX);
|
|
16769
16781
|
return {
|
|
16770
16782
|
source: "turn-end",
|
|
16771
|
-
askId: turn.data.turn_id
|
|
16783
|
+
askId: turn.data.turn_id ?? `stop:${turn.data.prompt_id ?? ""}:${fnv1a(message)}`,
|
|
16772
16784
|
questions: [],
|
|
16773
|
-
message
|
|
16785
|
+
message
|
|
16774
16786
|
};
|
|
16775
16787
|
}
|
|
16776
16788
|
return null;
|
|
16777
16789
|
}
|
|
16790
|
+
function fnv1a(s2) {
|
|
16791
|
+
let h2 = 2166136261;
|
|
16792
|
+
for (let i = 0; i < s2.length; i++) {
|
|
16793
|
+
h2 ^= s2.charCodeAt(i);
|
|
16794
|
+
h2 = Math.imul(h2, 16777619);
|
|
16795
|
+
}
|
|
16796
|
+
return (h2 >>> 0).toString(16);
|
|
16797
|
+
}
|
|
16778
16798
|
var ASK_QUESTION_MAX, ASK_MESSAGE_MAX, clip3, ASK_MAX_QUESTIONS, ASK_MAX_OPTIONS, zOption, zQuestion, zAskTool, zTurnEnd;
|
|
16779
16799
|
var init_session_ask = __esm({
|
|
16780
16800
|
"../shared/src/session-ask.ts"() {
|
|
@@ -16803,7 +16823,11 @@ var init_session_ask = __esm({
|
|
|
16803
16823
|
});
|
|
16804
16824
|
zTurnEnd = external_exports.object({
|
|
16805
16825
|
hook_event_name: external_exports.literal("Stop"),
|
|
16806
|
-
turn_id
|
|
16826
|
+
// ADR-0231 · codex mengirim `turn_id`; Stop claude (sesi bertanya lewat teks) tidak — ia membawa
|
|
16827
|
+
// `prompt_id` dan `background_tasks`.
|
|
16828
|
+
turn_id: external_exports.string().min(1).optional(),
|
|
16829
|
+
prompt_id: external_exports.string().optional(),
|
|
16830
|
+
background_tasks: external_exports.array(external_exports.object({ status: external_exports.string().optional() }).passthrough()).optional(),
|
|
16807
16831
|
last_assistant_message: external_exports.string().optional(),
|
|
16808
16832
|
// Codex menyalakan bendera ini saat Stop dipicu oleh hook Stop lain. Melayani giliran yang
|
|
16809
16833
|
// dibangkitkan gate mode goal (ADR-0074) berarti lead menjawab dirinya sendiri.
|
|
@@ -17243,7 +17267,7 @@ dengan folder implementasi nyata repo ini (hasil fase Scan):
|
|
|
17243
17267
|
});
|
|
17244
17268
|
|
|
17245
17269
|
// ../runner/src/verify-scope.ts
|
|
17246
|
-
var CHANGED, verifyScopeClause;
|
|
17270
|
+
var CHANGED, NONE, verifyScopeClause;
|
|
17247
17271
|
var init_verify_scope = __esm({
|
|
17248
17272
|
"../runner/src/verify-scope.ts"() {
|
|
17249
17273
|
"use strict";
|
|
@@ -17284,7 +17308,26 @@ var init_verify_scope = __esm({
|
|
|
17284
17308
|
"tipe/kontrak bersama, skema, atau berkas yang diimpor banyak modul), perluas scope seperlunya",
|
|
17285
17309
|
"dan katakan alasannya. Ini panduan biaya, bukan larangan."
|
|
17286
17310
|
].join("\n");
|
|
17287
|
-
|
|
17311
|
+
NONE = [
|
|
17312
|
+
"Scope verifikasi: TANPA menjalankan test. Operator memilih mode ini karena perangkatnya tak",
|
|
17313
|
+
"kuat menjalankan test \u2014 run sebelumnya membuat mesin tersendat.",
|
|
17314
|
+
"",
|
|
17315
|
+
"- JANGAN menjalankan test apa pun: `pnpm test`, `vitest` (termasuk `--changed`/`related`),",
|
|
17316
|
+
" `jest`, `pytest`, `go test`, Playwright/e2e, maupun skrip yang memanggilnya. Aturan ini",
|
|
17317
|
+
' MENIMPA instruksi skill/metode (mis. TDD "jalankan test, lihat merah lalu hijau"), instruksi',
|
|
17318
|
+
" fase Verifikasi/review, dan Definition of Done repo target.",
|
|
17319
|
+
"- Menulis atau memperbarui berkas test tetap boleh \u2014 hanya jangan menjalankannya.",
|
|
17320
|
+
"- JANGAN build, lint seluruh repo, boot server + curl, atau smoke end-to-end.",
|
|
17321
|
+
"- Typecheck: paling banyak SEKALI di akhir, hanya untuk paket yang tersentuh",
|
|
17322
|
+
" (mis. `pnpm --filter ./server typecheck`). JANGAN `pnpm -r typecheck`.",
|
|
17323
|
+
'- Verifikasi dengan MEMBACA: telusuri diff-mu (`git diff "$HANOMAN_BASE_SHA"...HEAD`,',
|
|
17324
|
+
" `git status --porcelain`), periksa pemanggil, tipe, dan cabang error dengan grep/baca berkas.",
|
|
17325
|
+
"- Laporan: nyatakan terang bahwa test TIDAK dijalankan (scope verifikasi `none`) dan sebut berkas",
|
|
17326
|
+
" test yang perlu dijalankan manusia. Jangan pernah mengklaim test hijau.",
|
|
17327
|
+
"",
|
|
17328
|
+
"Menjalankan test adalah tugas MANUSIA sebelum merge, bukan tugas sesi."
|
|
17329
|
+
].join("\n");
|
|
17330
|
+
verifyScopeClause = (scope) => scope === "changed" ? CHANGED : scope === "none" ? NONE : "";
|
|
17288
17331
|
}
|
|
17289
17332
|
});
|
|
17290
17333
|
|
|
@@ -17340,29 +17383,25 @@ function orchestratorClause(plan, o = {}) {
|
|
|
17340
17383
|
const resume = antigravity2 ? "send_message ke conversation ID child yang sama" : codex2 ? "send_input ke agent id yang sama" : "SendMessage ke agent ID yang kamu catat";
|
|
17341
17384
|
const describeRule = antigravity2 ? "Cantumkan label `Fase <Nama Fase>` dalam tugas. Pilih nama definisi native fase, JANGAN membuat agen umum pengganti. Catat conversation ID hasil invoke_subagent; ID itu dipakai untuk SEMUA relay keputusan dan rework lewat send_message, bukan invoke_subagent baru. Gunakan tool native langsung, bukan shell atau CLI hanoman untuk menyimulasikan delegasi. Bila tool tidak tersedia, laporkan galat langkah 3; jangan membuat bridge atau mengeksekusi isi fase sendiri." : codex2 ? "Deskripsi/label pemanggilan diisi persis `Fase <Nama Fase>` \u2014 tanpa nomor urut, dan BUKAN baris pertama blok serah-terima di atas." : "Deskripsi pemanggilan (parameter `description`) diisi persis `Fase <Nama Fase>` \u2014 tanpa nomor urut, dan BUKAN baris pertama blok serah-terima di atas.\nJANGAN pernah memanggil tool Agent tanpa `subagent_type` atau dengan `general-purpose`: fase itu jatuh ke agen umum ber-model orchestrator dan model/effort fasenya hilang. Sebelum memanggil, periksa ulang bahwa `subagent_type` = nama agen fase itu; bila tool menolaknya, itu galat langkah 3 \u2014 bukan alasan beralih ke agen umum. Catat agent ID yang dikembalikan hasil pemanggilan: itulah satu-satunya pegangan untuk melanjutkan agen yang SAMA. Melanjutkan agen itu (relay jawaban langkah 4) HANYA lewat SendMessage \u2014 tool Agent tak punya parameter `to`, dan memanggilnya lagi melahirkan agen BARU tanpa konteks (duplikat).";
|
|
17342
17385
|
const retry = antigravity2 ? " (invoke_subagent BARU dengan nama definisi fase yang sama)" : codex2 ? "" : " (pemanggilan tool Agent BARU dengan `subagent_type` yang sama)";
|
|
17343
|
-
const askEscalation = codex2 || antigravity2 ? "tanyakan di terminal ini lalu tunggu jawaban" :
|
|
17344
|
-
const askDecisions = antigravity2 ? "di terminal ini sekaligus dalam satu pesan, tiap pertanyaan bernomor dan diakhiri `?` beserta opsi, rekomendasi dan alasannya, lalu tunggu jawaban" : codex2 ? "di terminal ini sekaligus dalam satu pesan, tiap pertanyaan bernomor dan diakhiri `?` beserta opsinya, lalu tunggu jawaban" :
|
|
17386
|
+
const askEscalation = codex2 || antigravity2 ? "tanyakan di terminal ini lalu tunggu jawaban" : ASK_ESCALATION_TOOL;
|
|
17387
|
+
const askDecisions = antigravity2 ? "di terminal ini sekaligus dalam satu pesan, tiap pertanyaan bernomor dan diakhiri `?` beserta opsi, rekomendasi dan alasannya, lalu tunggu jawaban" : codex2 ? "di terminal ini sekaligus dalam satu pesan, tiap pertanyaan bernomor dan diakhiri `?` beserta opsinya, lalu tunggu jawaban" : ASK_DECISIONS_TOOL;
|
|
17345
17388
|
const turnTaking = plan.flow === "reverse" || plan.flow === "scaffold" || plan.flow === "prd" ? " Fase yang bergiliran dengan manusia (Wawancara, Brainstorm prd/scaffold) melapor satu topik per putaran \u2014 relay tiap putaran dengan cara yang sama, bawa konteks & opsi dari laporannya, dan biarkan jawaban bebas." : "";
|
|
17346
17389
|
const handoff = plan.phases.some((p3) => p3.phase === "Serah terima") ? "Sesudah fase Serah terima tercatat, tampilkan bagian `Ringkasan serah terima:` dari laporannya APA ADANYA ke manusia di terminal ini (teks biasa \u2014 informasi, bukan pertanyaan) sebelum menutup pekerjaan." : "";
|
|
17347
17390
|
const runtimeLabel = (entry2) => antigravity2 ? `tier native ${entry2.model} \xB7 effort native unknown` : `${entry2.model} \xB7 ${entry2.effort}`;
|
|
17348
17391
|
const phaseList = plan.phases.map((p3, i) => `${i + 1}. ${p3.phase} \u2192 \`${p3.agentName}\` \xB7 ${runtimeLabel(p3)}`).join("\n");
|
|
17349
|
-
const
|
|
17350
|
-
const list2 = reviewer ? `${phaseList}
|
|
17351
|
-
Reviewer Execute \u2192 \`${reviewer.agentName}\` \xB7 ${runtimeLabel(reviewer)} (bukan fase \u2014 hanya dipanggil di langkah R)` : phaseList;
|
|
17392
|
+
const review = plan.phases.find((p3) => p3.phase === REVIEWER_CELL);
|
|
17352
17393
|
const hasExecute = plan.phases.some((p3) => p3.phase === "Execute");
|
|
17353
|
-
const artefactRule = "Baris `Artefak fase sebelumnya:` diisi path PERSIS yang dilaporkan fase sebelumnya di `Artefak:` laporannya" + (hasExecute ? " \u2014 untuk Execute: dokumen spec DAN berkas plan yang dilaporkan fase Plan" : "") + ", bukan pola glob.";
|
|
17354
|
-
const reviewStep =
|
|
17355
|
-
Tujuan: <objective backlog>
|
|
17356
|
-
Base SHA: $HANOMAN_BASE_SHA
|
|
17394
|
+
const artefactRule = "Baris `Artefak fase sebelumnya:` diisi path PERSIS yang dilaporkan fase sebelumnya di `Artefak:` laporannya" + (hasExecute ? " \u2014 untuk Execute: dokumen spec DAN berkas plan yang dilaporkan fase Plan" : "") + (review ? "; untuk Review: dokumen spec & berkas plan yang SAMA dengan Execute" : "") + ", bukan pola glob.";
|
|
17395
|
+
const reviewStep = review ? `R. Fase Review: sesudah \`Execute done\` tercatat, panggil agen fasenya seperti langkah 1 dengan baris serah-terima tambahan:
|
|
17357
17396
|
Artefak: <path PERSIS dokumen spec & berkas plan> (qa yang melewati Spec & Plan: dokumen audit)
|
|
17358
17397
|
Laporan Execute: <tabel AC \u2192 bukti dari laporannya>
|
|
17359
17398
|
Putaran rework: <r>/2
|
|
17360
17399
|
|
|
17361
|
-
\`Verdict: lulus\` \u2192 langkah 2 (tulis \`
|
|
17400
|
+
\`Verdict: lulus\` \u2192 langkah 2 (tulis \`Review done\`). \`Verdict: rework\` \u2192 lanjutkan agen Execute yang SAMA lewat ${resume} dengan \`Temuan wajib diperbaiki:\` reviewer apa adanya; sesudah ia melapor \`selesai\` lagi, lanjutkan reviewer yang SAMA lewat ${resume} dengan laporan barunya. Batasnya maks 2 putaran rework: masih \`rework\` sesudah putaran ke-2 \u2192 perlakukan temuan tersisa sebagai \`Keputusan terbuka\` langkah 4 (tanyakan, teruskan jawabannya ke agen Execute, lalu review lagi). Putaran rework bukan percobaan ulang langkah 3 dan tak menulis ulang \`Execute done\`; reviewer galat atau tanpa baris \`Verdict:\` \u2192 langkah 3 berlaku padanya, \`menunggu-keputusan\` \u2192 langkah 4. JANGAN memperbaiki temuan sendiri, JANGAN menulis \`Review done\` tanpa \`Verdict: lulus\`, dan Review tak pernah \`skipped\`.` : "";
|
|
17362
17401
|
return [
|
|
17363
17402
|
antigravity2 ? "Sesi ini ORCHESTRATOR. Setiap fase dikerjakan child native persisten miliknya dengan tier inherit|flash|pro, bukan slug model parent atau effort independen. Runtime asynchronous: protocol wait mewajibkan menunggu laporan child sebelum fase berikutnya, relay atau marker; ini bukan jaminan foreground runtime, model exact atau effort terkunci. Jangan gunakan CLI one-shot/bridge untuk sesi kerja child. Kamu TIDAK mengerjakan isi fase sendiri." : "Sesi ini ORCHESTRATOR. Setiap fase dikerjakan subagent fase miliknya dengan model & effort yang sudah terkunci di definisinya \u2014 kamu TIDAK mengerjakan isi fase sendiri.",
|
|
17364
17403
|
`Fase berurutan:
|
|
17365
|
-
${
|
|
17404
|
+
${phaseList}`,
|
|
17366
17405
|
"Untuk SETIAP fase, berurutan:",
|
|
17367
17406
|
`1. Panggil subagent fasenya lewat ${call}, tugasnya berupa blok serah-terima berbentuk tetap:
|
|
17368
17407
|
Urutan: <n>/<total> \xB7 <Nama Fase>
|
|
@@ -17374,14 +17413,14 @@ Lampiran: <path INDEX.md lampiran, atau ->
|
|
|
17374
17413
|
Percobaan: <k>/2
|
|
17375
17414
|
|
|
17376
17415
|
${artefactRule} ${describeRule}`,
|
|
17377
|
-
'2. Baca laporannya. `Status: selesai` DENGAN bukti \u2192 SEBELUM hal lain (memanggil fase berikutnya, commit, atau push): jalankan persis `echo "<Nama Fase> done" >> "$HANOMAN_PHASE_FILE"`, lalu verifikasi dengan `tail -1 "$HANOMAN_PHASE_FILE"` bahwa barisnya benar tertulis. Kamu satu-satunya penulis berkas itu.' + (
|
|
17416
|
+
'2. Baca laporannya. `Status: selesai` DENGAN bukti \u2192 SEBELUM hal lain (memanggil fase berikutnya, commit, atau push): jalankan persis `echo "<Nama Fase> done" >> "$HANOMAN_PHASE_FILE"`, lalu verifikasi dengan `tail -1 "$HANOMAN_PHASE_FILE"` bahwa barisnya benar tertulis. Kamu satu-satunya penulis berkas itu.' + (review ? " Khusus Review: marker hanya sesudah `Verdict: lulus` (langkah R)." : ""),
|
|
17378
17417
|
`3. \`Status: sebagian\`/\`terhalang\`, galat, atau laporan tanpa bukti \u2192 delegasikan ULANG SEKALI ke subagent fase yang sama${retry} dengan laporan gagalnya disertakan (\`Percobaan: 2/2\`). Gagal lagi \u2192 BERHENTI dan ${askEscalation} apa yang harus dilakukan. Aturan ini berlaku walau klausa otonomi di prompt ini menyuruhmu tak bertanya.`,
|
|
17379
17418
|
`4. \`Status: menunggu-keputusan\` atau \`Keputusan terbuka:\` yang bukan \`-\` \u2192 SEBELUM menulis marker fase atau memanggil fase berikutnya, ajukan SEMUA pertanyaannya ${askDecisions}, lalu LANJUTKAN subagent yang SAMA lewat ${resume} dengan seluruh jawabannya. Ulangi selama subagent masih melaporkan keputusan terbuka \u2014 tak ada batas jumlah pertanyaan maupun putaran, dan giliran relay ini bukan percobaan ulang. JANGAN pernah menjawab sendiri, termasuk di sesi scheduler: yang menjawab ${DECIDER} \u2014 hanoman yang merutekannya, kamu cukup bertanya.${turnTaking}`,
|
|
17380
17419
|
o.fastPath ? '5. `Rekomendasi fase: jalur-cepat` sesudah Audit \u2192 SEBELUM lanjut ke Execute: jalankan `echo "Spec skipped" >> "$HANOMAN_PHASE_FILE"` lalu `echo "Plan skipped" >> "$HANOMAN_PHASE_FILE"` (gerbang yang sama seperti langkah 2), lalu lanjut ke Execute. `penuh` \u2192 Spec \u2192 Plan \u2192 Execute.' : "",
|
|
17381
17420
|
reviewStep,
|
|
17382
17421
|
handoff,
|
|
17383
17422
|
"DILARANG mengerjakan isi fase sendiri \u2014 termasuk saat subagent gagal. Menulis `skipped` untuk fase yang dilewati bukan mengerjakannya.",
|
|
17384
|
-
|
|
17423
|
+
"Pekerjaan ini BELUM selesai sampai SEMUA fase di daftar di atas punya baris `done` atau `skipped` di $HANOMAN_PHASE_FILE" + (review ? " (Review wajib `done`)" : "") + ' \u2014 JANGAN commit/push final atau menyatakan tuntas sebelum itu. Periksa dengan `cat "$HANOMAN_PHASE_FILE"` sebelum commit terakhir.'
|
|
17385
17424
|
].filter(Boolean).join("\n\n");
|
|
17386
17425
|
}
|
|
17387
17426
|
function startPrompt(flow2, spec, branchTo, autonomy, verifyScope, method, attachments, plan) {
|
|
@@ -17419,13 +17458,15 @@ function continuePrompt(flow2, spec, branchTo, autonomy, verifyScope, method, at
|
|
|
17419
17458
|
const m = resolveMethod(method);
|
|
17420
17459
|
const head = `hanoman ${flow2} \u2014 MELANJUTKAN backlog item yang sebelumnya ditandai selesai padahal pekerjaannya belum tuntas. Ikuti internal/docs sebagai Source of Truth; perbarui docs yang tersentuh dan link-nya di index, dalam commit yang sama.`;
|
|
17421
17460
|
const push = `Setelah selesai: commit, lalu \`git push origin HEAD:refs/heads/${branchTo}\`. Worktree ini detached HEAD \u2014 itu memang disengaja.`;
|
|
17461
|
+
const hasReview = plan ? plan.phases.some((p3) => p3.phase === REVIEWER_CELL) : PIPELINES[flow2].includes(REVIEWER_CELL);
|
|
17422
17462
|
if (plan) {
|
|
17423
17463
|
return [
|
|
17424
17464
|
head,
|
|
17425
|
-
`JANGAN mengulang fase awal \u2014 spec & plan sudah ada di ${m.planDir}/**. Lanjutkan HANYA fase Execute lewat subagent fasenya
|
|
17465
|
+
`JANGAN mengulang fase awal \u2014 spec & plan sudah ada di ${m.planDir}/**. Lanjutkan HANYA fase ` + (hasReview ? "Execute lalu Review lewat subagent fasenya." : "Execute lewat subagent fasenya."),
|
|
17426
17466
|
// S3 · berkas fase tak pernah dikosongkan: baris `Execute done` run lama masih ada dan akan
|
|
17427
17467
|
// memenuhi gerbang penutup sebelum agen Execute sesi ini bekerja sama sekali.
|
|
17428
|
-
|
|
17468
|
+
// ADR-0230 · sama untuk `Review done` lama.
|
|
17469
|
+
hasReview ? "$HANOMAN_PHASE_FILE bisa masih memuat baris `Execute done` dan `Review done` LAMA dari sesi sebelumnya \u2014 keduanya TIDAK berlaku untuk sesi ini dan tidak memenuhi gerbang penutup. Sesudah agen fase Execute SESI INI melapor `Status: selesai`, tulis baris `Execute done` BARU; sesudah agen fase Review SESI INI melapor `Verdict: lulus`, tulis baris `Review done` BARU (verifikasi `tail -1` tiap kali); commit/push final baru sah sesudah kedua baris baru itu." : "$HANOMAN_PHASE_FILE masih memuat baris `Execute done` LAMA dari sesi sebelumnya \u2014 baris itu TIDAK berlaku untuk sesi ini dan tidak memenuhi gerbang penutup. Sesudah agen fase Execute SESI INI melapor `Status: selesai`, tulis baris `Execute done` BARU (verifikasi `tail -1`); commit/push final baru sah sesudah baris baru itu.",
|
|
17429
17470
|
orchestratorClause(plan),
|
|
17430
17471
|
autonomyClause(autonomy),
|
|
17431
17472
|
orchestratorAttachmentClause(attachments),
|
|
@@ -17435,13 +17476,13 @@ function continuePrompt(flow2, spec, branchTo, autonomy, verifyScope, method, at
|
|
|
17435
17476
|
}
|
|
17436
17477
|
return [
|
|
17437
17478
|
head,
|
|
17438
|
-
`JANGAN mengulang fase awal \u2014 spec & plan sudah ada. Lanjut di fase Execute: baca plan di ${m.planDir}/** untuk backlog item ini, periksa task yang sudah \`[x]\` dan selesaikan yang masih \`[ ]\`. Verifikasi nyata sebelum klaim selesai
|
|
17479
|
+
`JANGAN mengulang fase awal \u2014 spec & plan sudah ada. Lanjut di fase Execute: baca plan di ${m.planDir}/** untuk backlog item ini, periksa task yang sudah \`[x]\` dan selesaikan yang masih \`[ ]\`. Verifikasi nyata sebelum klaim selesai.` + (hasReview ? ' Sesudah itu jalankan fase Review, lalu tulis `echo "Review done" >> "$HANOMAN_PHASE_FILE"` BARU (baris `Review done` lama di berkas itu tak berlaku).\n' + SELF_REVIEW_CLAUSE : ""),
|
|
17439
17480
|
autonomyClause(autonomy),
|
|
17440
17481
|
scopeClause(flow2, verifyScope),
|
|
17441
17482
|
codeStyleClause(flow2),
|
|
17442
17483
|
methodClause(m),
|
|
17443
17484
|
attachmentClause(attachments),
|
|
17444
|
-
skillInstruction(flow2, ["Execute"], m),
|
|
17485
|
+
skillInstruction(flow2, hasReview ? ["Execute", REVIEWER_CELL] : ["Execute"], m),
|
|
17445
17486
|
push,
|
|
17446
17487
|
specContext(spec)
|
|
17447
17488
|
].filter(Boolean).join("\n\n");
|
|
@@ -17614,7 +17655,7 @@ Stack: ${project.stack || "\u2014"}`,
|
|
|
17614
17655
|
${cron.prompt}`
|
|
17615
17656
|
].join("\n\n");
|
|
17616
17657
|
}
|
|
17617
|
-
var PIPELINES, WORK_PHASES, DECIDER, ASK_ROUTE, AMBIGUOUS, AUTONOMY_CLAUSE, AUTONOMY_CLAUSE_FULL, autonomyClause, PLAN_SHAPE, phaseInstruction, skillInstruction, auditDecisionInstruction, ESCALATION_CONTRACT, auditOnlyInstruction, auditContinuationInstruction, auditContinuationForOrchestrator, writesCode, scopeClause, codeStyleClause, methodClause, attachmentClause, orchestratorAttachmentClause, PROJECT_METHOD, specContext, goalDetail, goalBlock, goalContext, projectContext, scaffoldContext, prdBriefBlock, prdAuditBlock, prdContext, breakdownContext, prdPhaseLines, breakdownPhaseLines, resumeClause, RESUMED_WORKTREE_NOTE, REVERSE_PHASE_GUIDE, SCAFFOLD_PHASE_GUIDE;
|
|
17658
|
+
var PIPELINES, WORK_PHASES, DECIDER, ASK_ROUTE, ASK_ESCALATION_TOOL, ASK_DECISIONS_TOOL, AMBIGUOUS, AUTONOMY_CLAUSE, AUTONOMY_CLAUSE_FULL, autonomyClause, PLAN_SHAPE, phaseInstruction, SELF_REVIEW_CLAUSE, skillInstruction, auditDecisionInstruction, ESCALATION_CONTRACT, auditOnlyInstruction, auditContinuationInstruction, auditContinuationForOrchestrator, writesCode, scopeClause, codeStyleClause, methodClause, attachmentClause, orchestratorAttachmentClause, PROJECT_METHOD, specContext, goalDetail, goalBlock, goalContext, projectContext, scaffoldContext, prdBriefBlock, prdAuditBlock, prdContext, breakdownContext, prdPhaseLines, breakdownPhaseLines, resumeClause, RESUMED_WORKTREE_NOTE, REVERSE_PHASE_GUIDE, SCAFFOLD_PHASE_GUIDE;
|
|
17618
17659
|
var init_prompt = __esm({
|
|
17619
17660
|
"../runner/src/prompt.ts"() {
|
|
17620
17661
|
"use strict";
|
|
@@ -17627,6 +17668,8 @@ var init_prompt = __esm({
|
|
|
17627
17668
|
WORK_PHASES = ["Execute", "Goal", "Kerjakan"];
|
|
17628
17669
|
DECIDER = "hanoman-lead bila aktif untuk project ini, selain itu manusia";
|
|
17629
17670
|
ASK_ROUTE = `ajukan lewat AskUserQuestion bila agenmu punya tool itu (paling banyak 4 pertanyaan per panggilan \u2014 pecah sisanya ke panggilan berikutnya); bila tidak, tanyakan di terminal ini sekaligus, tiap pertanyaan bernomor dan diakhiri \`?\` beserta opsinya, lalu tunggu jawabannya. Tak ada batas jumlah pertanyaan: selama masih ambigu dan akan mempengaruhi hasil, tanyakan. Yang menjawab ditentukan hanoman \u2014 ${DECIDER}; jangan menjawabnya sendiri.`;
|
|
17671
|
+
ASK_ESCALATION_TOOL = "tanyakan lewat AskUserQuestion";
|
|
17672
|
+
ASK_DECISIONS_TOOL = "lewat AskUserQuestion \u2014 tool itu memuat paling banyak 4 pertanyaan per panggilan, jadi pecah sisanya ke panggilan berikutnya sampai semuanya terjawab";
|
|
17630
17673
|
AMBIGUOUS = "hal yang masih ambigu dan akan mempengaruhi hasil (data model, kontrak API, scope, perilaku yang terlihat pengguna, atau asumsi yang terpaksa kamu ambil agar bisa lanjut)";
|
|
17631
17674
|
AUTONOMY_CLAUSE = `Jalankan seluruh pipeline sampai tuntas tanpa berhenti di batas antar-fase. Checkpoint "review"/"approval"/"need review" milik skill superpowers BUKAN titik berhenti di sini \u2014 lanjut saja ke fase berikutnya. Berhenti HANYA untuk ${AMBIGUOUS}: JANGAN memutuskannya sendiri, ${ASK_ROUTE} Selain itu, terus lanjut.`;
|
|
17632
17675
|
AUTONOMY_CLAUSE_FULL = `Kamu diluncurkan scheduler \u2014 mungkin tak ada manusia yang sedang menonton terminal ini. Tembus seluruh pipeline sampai stage \`done\`, lalu commit & push: checkpoint "review"/"approval" milik skill BUKAN titik berhenti dan jangan menunggu persetujuan siapa pun. Tetapi JANGAN memutuskan sendiri ${AMBIGUOUS}: ${ASK_ROUTE} Catat keputusan penting di pesan commit. Merge ke branch utama tetap dilakukan manusia, bukan kamu.`;
|
|
@@ -17638,8 +17681,10 @@ Setiap kali sebuah fase selesai (atau kamu putuskan dilewati), append satu baris
|
|
|
17638
17681
|
if (!phases2.includes("Plan") || !phases2.includes("Execute")) return base3;
|
|
17639
17682
|
return base3 + `
|
|
17640
17683
|
Execute BELUM selesai selama plan (\`${method.planDir}/**\`) masih punya task \`- [ ]\`: kerjakan SEMUA PR/task sampai tiap kotak jadi \`- [x]\` sebelum menulis \`Execute done\`. hanoman menahan backlog di \`executing\`, bukan \`done\`, selama masih ada \`- [ ]\`.
|
|
17641
|
-
${PLAN_SHAPE}
|
|
17684
|
+
${PLAN_SHAPE}` + (phases2.includes(REVIEWER_CELL) ? `
|
|
17685
|
+
${SELF_REVIEW_CLAUSE}` : "");
|
|
17642
17686
|
};
|
|
17687
|
+
SELF_REVIEW_CLAUSE = "Fase Review (sesudah `Execute done`): periksa ulang hasil Execute terhadap dokumen spec & plan backlog ini \u2014 baca seluruh perubahan sesi ini (diff dari commit awal worktree) dan jalankan test sesuai scope verifikasi. Tulis tabel `AC \u2192 putusan \u2192 bukti` (setiap acceptance criteria \u2192 perintah & hasil yang kamu baca, atau path:baris) lalu satu baris `Verdict: lulus` atau `Verdict: rework`. `rework` \u2192 perbaiki temuannya, lalu review ulang; maks 2 putaran rework, sisanya jadi keputusan terbuka. Tulis `Review done` HANYA sesudah `Verdict: lulus`; Review TIDAK PERNAH `skipped`.";
|
|
17643
17688
|
skillInstruction = (flow2, phases2, method) => {
|
|
17644
17689
|
const lines2 = phases2.map((p3) => {
|
|
17645
17690
|
const skills2 = phaseSkillsFor(flow2, p3, method);
|
|
@@ -17950,7 +17995,7 @@ var init_settings2 = __esm({
|
|
|
17950
17995
|
'process.stdin.on("data",c=>d+=c).on("end",()=>{let n=0;try{n=(JSON.parse(d).background_tasks||[]).filter(t=>t&&t.type==="subagent"&&t.status==="running").length}catch{}require("fs").writeFileSync(process.argv[1],"1\\n".repeat(n))})'
|
|
17951
17996
|
].join(";");
|
|
17952
17997
|
busySnapshotCommand = (quotedSubFile) => `node -e '${BUSY_SNAPSHOT_SCRIPT}' ${quotedSubFile} >/dev/null 2>&1`;
|
|
17953
|
-
guardSettings = (decisionFile, goal, eventHook, subagentStatusLine) => {
|
|
17998
|
+
guardSettings = (decisionFile, goal, eventHook, subagentStatusLine, askText) => {
|
|
17954
17999
|
const hooks2 = {};
|
|
17955
18000
|
if (decisionFile) {
|
|
17956
18001
|
const f = `'${decisionFile.split("'").join("'\\''")}'`;
|
|
@@ -17978,6 +18023,8 @@ var init_settings2 = __esm({
|
|
|
17978
18023
|
hooks2.UserPromptSubmit = [{ hooks: [{ type: "command", command: `: > ${f}; : > ${sub}` }] }];
|
|
17979
18024
|
}
|
|
17980
18025
|
}
|
|
18026
|
+
if (eventHook && askText)
|
|
18027
|
+
(hooks2.Stop ??= []).push({ hooks: [{ type: "command", command: EVENT_HOOK_COMMAND }] });
|
|
17981
18028
|
if (goal) (hooks2.Stop ??= []).push({ hooks: [{ type: "prompt", prompt: goal }] });
|
|
17982
18029
|
return {
|
|
17983
18030
|
hooks: hooks2,
|
|
@@ -18006,7 +18053,7 @@ function defaultGoalCondition({ flow: flow2, specId, branchTo, spec }) {
|
|
|
18006
18053
|
const phases2 = PIPELINES[flow2];
|
|
18007
18054
|
const planGate = phases2.includes("Plan") && phases2.includes("Execute");
|
|
18008
18055
|
const clauses = [
|
|
18009
|
-
`1. output \`cat "$HANOMAN_PHASE_FILE"\` yang memuat satu baris untuk SETIAP fase ${phases2.join(" \u2192 ")}, masing-masing berakhiran \`done\` atau \`skipped
|
|
18056
|
+
`1. output \`cat "$HANOMAN_PHASE_FILE"\` yang memuat satu baris untuk SETIAP fase ${phases2.join(" \u2192 ")}, masing-masing berakhiran \`done\` atau \`skipped\`` + phases2.filter((p3) => UNSKIPPABLE_PHASES.has(p3)).map((p3) => ` (\`${p3}\` wajib \`done\`)`).join("") + ";"
|
|
18010
18057
|
];
|
|
18011
18058
|
if (planGate) {
|
|
18012
18059
|
const dirs = PLAN_DIRS.map((d) => `${d}/`).join(" ");
|
|
@@ -18079,7 +18126,8 @@ function codexGoalScript(o) {
|
|
|
18079
18126
|
];
|
|
18080
18127
|
for (const p3 of phases2) {
|
|
18081
18128
|
lines2.push(
|
|
18082
|
-
|
|
18129
|
+
// ADR-0230 · fase `UNSKIPPABLE_PHASES` (Review) hanya lolos dengan `done`.
|
|
18130
|
+
`grep -qE ${shq(`^${p3} ${UNSKIPPABLE_PHASES.has(p3) ? "done" : "(done|skipped)"}[[:space:]]*$`)} "$PF" 2>/dev/null || missing="$missing\\n- fase ${p3} belum tercatat di \\$HANOMAN_PHASE_FILE"`
|
|
18083
18131
|
);
|
|
18084
18132
|
}
|
|
18085
18133
|
if (planGate) {
|
|
@@ -18156,7 +18204,7 @@ function agentFlags(o) {
|
|
|
18156
18204
|
...o.effort ? ["--effort", o.effort] : [],
|
|
18157
18205
|
"--dangerously-skip-permissions",
|
|
18158
18206
|
"--settings",
|
|
18159
|
-
JSON.stringify(guardSettings(o.decisionFile, o.goal, o.eventHook, o.subagentStatusLine))
|
|
18207
|
+
JSON.stringify(guardSettings(o.decisionFile, o.goal, o.eventHook, o.subagentStatusLine, o.askText))
|
|
18160
18208
|
];
|
|
18161
18209
|
}
|
|
18162
18210
|
var init_agent_cli = __esm({
|
|
@@ -18430,7 +18478,7 @@ function agentDelegationClause(defs, runtime = "claude") {
|
|
|
18430
18478
|
if (defs.every((def2) => def2.kind === "phase")) return "";
|
|
18431
18479
|
const codex2 = runtime === "codex";
|
|
18432
18480
|
const antigravity2 = runtime === "antigravity";
|
|
18433
|
-
const relay = antigravity2 ? "ajukan semuanya di terminal ini (bernomor, tiap pertanyaan diakhiri `?`), lalu teruskan jawabannya lewat send_message ke conversation ID child yang sama" : codex2 ? "ajukan semuanya di terminal ini (bernomor, tiap pertanyaan diakhiri `?`), lalu teruskan jawabannya lewat send_input ke agent id yang sama" :
|
|
18481
|
+
const relay = antigravity2 ? "ajukan semuanya di terminal ini (bernomor, tiap pertanyaan diakhiri `?`), lalu teruskan jawabannya lewat send_message ke conversation ID child yang sama" : codex2 ? "ajukan semuanya di terminal ini (bernomor, tiap pertanyaan diakhiri `?`), lalu teruskan jawabannya lewat send_input ke agent id yang sama" : ASK_RELAY_TOOL;
|
|
18434
18482
|
return [
|
|
18435
18483
|
"",
|
|
18436
18484
|
"",
|
|
@@ -18439,7 +18487,7 @@ function agentDelegationClause(defs, runtime = "claude") {
|
|
|
18439
18487
|
""
|
|
18440
18488
|
].join("\n");
|
|
18441
18489
|
}
|
|
18442
|
-
var PHASE_CONTEXT_HEADER, liveMentions, policyOf, READ_ONLY_DENIED_OPERATORS, READ_ONLY_DENIED_COMMANDS, deniedCommandsProse, readOnlyAllowlistLines, NO_FAKE_EXPERIMENT, policyLines, ownPolicyLines, workLimitClause, STATUS_LINE, handoffClause, contractReference, READ_ONLY_TOOLS;
|
|
18490
|
+
var ASK_RELAY_TOOL, PHASE_CONTEXT_HEADER, liveMentions, policyOf, READ_ONLY_DENIED_OPERATORS, READ_ONLY_DENIED_COMMANDS, deniedCommandsProse, readOnlyAllowlistLines, NO_FAKE_EXPERIMENT, policyLines, ownPolicyLines, workLimitClause, STATUS_LINE, handoffClause, contractReference, READ_ONLY_TOOLS;
|
|
18443
18491
|
var init_custom_agents = __esm({
|
|
18444
18492
|
"../runner/src/custom-agents.ts"() {
|
|
18445
18493
|
"use strict";
|
|
@@ -18447,6 +18495,7 @@ var init_custom_agents = __esm({
|
|
|
18447
18495
|
init_code_style();
|
|
18448
18496
|
init_prompt();
|
|
18449
18497
|
init_agent_readonly();
|
|
18498
|
+
ASK_RELAY_TOOL = "ajukan semuanya lewat AskUserQuestion (pecah per 4 pertanyaan), lalu teruskan jawabannya lewat SendMessage ke agent ID yang sama";
|
|
18450
18499
|
PHASE_CONTEXT_HEADER = "=== KONTEKS ===";
|
|
18451
18500
|
liveMentions = (def2, roster) => {
|
|
18452
18501
|
if (def2.workspacePolicy === "read-only") return [];
|
|
@@ -18575,6 +18624,35 @@ var init_custom_agents = __esm({
|
|
|
18575
18624
|
}
|
|
18576
18625
|
});
|
|
18577
18626
|
|
|
18627
|
+
// ../runner/src/ask-via.ts
|
|
18628
|
+
function textAsk(s2) {
|
|
18629
|
+
let out4 = s2;
|
|
18630
|
+
for (const [tool, text2] of SWAPS) out4 = out4.split(tool).join(text2);
|
|
18631
|
+
return out4;
|
|
18632
|
+
}
|
|
18633
|
+
var NO_TOOL, TEXT_ASK_ROUTE, SWAPS;
|
|
18634
|
+
var init_ask_via = __esm({
|
|
18635
|
+
"../runner/src/ask-via.ts"() {
|
|
18636
|
+
"use strict";
|
|
18637
|
+
init_prompt();
|
|
18638
|
+
init_custom_agents();
|
|
18639
|
+
NO_TOOL = "JANGAN memakai AskUserQuestion (juga bila sebuah skill menyuruhnya)";
|
|
18640
|
+
TEXT_ASK_ROUTE = `${NO_TOOL}: tanyakan di terminal ini sekaligus dalam satu pesan, tiap pertanyaan bernomor dan diakhiri \`?\` beserta opsi, rekomendasi dan alasannya, lalu berhenti dan tunggu jawabannya. Tak ada batas jumlah pertanyaan: selama masih ambigu dan akan mempengaruhi hasil, tanyakan. Yang menjawab ditentukan hanoman \u2014 ${DECIDER}; jangan menjawabnya sendiri.`;
|
|
18641
|
+
SWAPS = [
|
|
18642
|
+
[ASK_ROUTE, TEXT_ASK_ROUTE],
|
|
18643
|
+
[
|
|
18644
|
+
ASK_DECISIONS_TOOL,
|
|
18645
|
+
`di terminal ini sekaligus dalam satu pesan (${NO_TOOL}), tiap pertanyaan bernomor dan diakhiri \`?\` beserta opsi, rekomendasi dan alasannya, lalu berhenti dan tunggu jawaban`
|
|
18646
|
+
],
|
|
18647
|
+
[
|
|
18648
|
+
ASK_RELAY_TOOL,
|
|
18649
|
+
`ajukan semuanya di terminal ini (${NO_TOOL}; bernomor, tiap pertanyaan diakhiri \`?\`), lalu teruskan jawabannya lewat SendMessage ke agent ID yang sama`
|
|
18650
|
+
],
|
|
18651
|
+
[ASK_ESCALATION_TOOL, `tanyakan di terminal ini (${NO_TOOL}) lalu berhenti dan tunggu jawaban`]
|
|
18652
|
+
];
|
|
18653
|
+
}
|
|
18654
|
+
});
|
|
18655
|
+
|
|
18578
18656
|
// ../runner/src/runtime-profile.ts
|
|
18579
18657
|
function resolveHardening(env) {
|
|
18580
18658
|
if (env.HANOMAN_HARDENING === "1") return true;
|
|
@@ -18834,7 +18912,7 @@ function phaseAgentInstructions(entry2, index, plan, ctx) {
|
|
|
18834
18912
|
const guide = PROJECT_FLOWS.has(flow2) ? projectGuide(flow2, phase, ctx) : backlogGuide(flow2, phase, ctx);
|
|
18835
18913
|
const executeMode = plan.executeMode ?? "inline";
|
|
18836
18914
|
const skills2 = phaseSkillsFor(flow2, phase, method, plan.runtime, executeMode);
|
|
18837
|
-
const skipSkillFinalReview = phase === "Execute" && plan.runtime === "claude" && executeMode === "subagent" &&
|
|
18915
|
+
const skipSkillFinalReview = phase === "Execute" && plan.runtime === "claude" && executeMode === "subagent" && plan.phases.some((p3) => p3.phase === REVIEWER_CELL) && skills2.includes("superpowers:subagent-driven-development");
|
|
18838
18916
|
const work = WORK_PHASES.includes(phase);
|
|
18839
18917
|
const verifies = work || phase === "Verifikasi";
|
|
18840
18918
|
return [
|
|
@@ -18843,7 +18921,7 @@ function phaseAgentInstructions(entry2, index, plan, ctx) {
|
|
|
18843
18921
|
DOC_WRITING_PHASES.has(phase) ? `=== STANDAR DOCS ===
|
|
18844
18922
|
${REVERSE_STANDARD}` : "",
|
|
18845
18923
|
skills2.length ? `Skills ${method.label} WAJIB untuk fase ini \u2014 muat & ikuti dengan mekanisme yang tersedia di agenmu: ` + skills2.join(", ") : "",
|
|
18846
|
-
skipSkillFinalReview ? "LEWATI final whole-branch review milik skill subagent-driven-development: review akhir dipegang
|
|
18924
|
+
skipSkillFinalReview ? "LEWATI final whole-branch review milik skill subagent-driven-development: review akhir dipegang fase Review (`hanoman-fase-review`) yang dipanggil orchestrator sesudah fase ini. Review per task tetap jalan." : "",
|
|
18847
18925
|
verifies ? scopeClause(flow2, ctx.verifyScope) : "",
|
|
18848
18926
|
work ? codeStyleClause(flow2) : "",
|
|
18849
18927
|
methodClause(method),
|
|
@@ -18858,40 +18936,29 @@ ${REVERSE_STANDARD}` : "",
|
|
|
18858
18936
|
].filter(Boolean).join("\n\n");
|
|
18859
18937
|
}
|
|
18860
18938
|
function buildPhaseAgents(plan, ctx) {
|
|
18861
|
-
|
|
18862
|
-
|
|
18863
|
-
|
|
18864
|
-
|
|
18865
|
-
|
|
18866
|
-
|
|
18867
|
-
|
|
18868
|
-
|
|
18869
|
-
|
|
18870
|
-
|
|
18871
|
-
|
|
18872
|
-
|
|
18873
|
-
|
|
18874
|
-
|
|
18875
|
-
|
|
18876
|
-
|
|
18877
|
-
|
|
18878
|
-
|
|
18879
|
-
kind: "phase",
|
|
18880
|
-
phase: r.phase,
|
|
18881
|
-
name: r.agentName,
|
|
18882
|
-
description: `Reviewer independen hasil fase Execute flow ${plan.flow} hanoman \u2014 hanya dipanggil orchestrator sesi ini, sesudah Execute melapor selesai.`,
|
|
18883
|
-
instructions: reviewerInstructions(plan, ctx),
|
|
18884
|
-
context: ctx.context,
|
|
18885
|
-
tools: null,
|
|
18886
|
-
model: r.model,
|
|
18887
|
-
effort: r.effort,
|
|
18888
|
-
mentions: []
|
|
18889
|
-
}];
|
|
18939
|
+
return plan.phases.map((entry2, index) => {
|
|
18940
|
+
const review = entry2.phase === REVIEWER_CELL;
|
|
18941
|
+
return {
|
|
18942
|
+
kind: "phase",
|
|
18943
|
+
phase: entry2.phase,
|
|
18944
|
+
name: entry2.agentName,
|
|
18945
|
+
description: review ? `Reviewer independen hasil fase Execute flow ${plan.flow} hanoman (fase Review) \u2014 hanya dipanggil orchestrator sesi ini, sesudah Execute ditutup.` : `Fase ${entry2.phase} flow ${plan.flow} hanoman \u2014 hanya dipanggil orchestrator sesi ini.`,
|
|
18946
|
+
instructions: review ? reviewerInstructions(plan, ctx) : phaseAgentInstructions(entry2, index, plan, ctx),
|
|
18947
|
+
// T2 · konteks bersama dibawa TERPISAH (lihat `phasePromptOf`): claude merujuknya lewat satu
|
|
18948
|
+
// berkas di temp dir sesi, codex tetap inline.
|
|
18949
|
+
context: ctx.context,
|
|
18950
|
+
tools: null,
|
|
18951
|
+
model: entry2.model,
|
|
18952
|
+
effort: entry2.effort,
|
|
18953
|
+
mentions: [],
|
|
18954
|
+
...review ? {} : { executeMode: plan.executeMode ?? "inline" }
|
|
18955
|
+
};
|
|
18956
|
+
});
|
|
18890
18957
|
}
|
|
18891
18958
|
function reviewerInstructions(plan, ctx) {
|
|
18892
18959
|
const m = ctx.method;
|
|
18893
18960
|
return [
|
|
18894
|
-
`Kamu reviewer independen hasil fase Execute flow ${plan.flow} hanoman. Kamu dipanggil orchestrator sesudah
|
|
18961
|
+
`Kamu agen fase Review \u2014 reviewer independen hasil fase Execute flow ${plan.flow} hanoman. Kamu dipanggil orchestrator sesudah fase Execute ditutup, dan fase Review baru ditutup bila kamu memberi \`Verdict: lulus\`. Kamu pengadu janji: yang kamu nilai bukan bagus-tidaknya kode, melainkan apakah yang DIMINTA benar-benar ada dan TERBUKTI pada keadaan akhir worktree ini.`,
|
|
18895
18962
|
"Prosedur:",
|
|
18896
18963
|
[
|
|
18897
18964
|
`1. Baca dokumen spec & plan dari baris \`Artefak:\` serah-terima (qa jalur-cepat: dokumen audit adalah doc-of-record; bila path tak ada, cari berkas ber-spec-id di \`${m.specDir}/\` & \`${m.planDir}/\`). Plan yang menyimpang dari spec adalah temuan.`,
|
|
@@ -20880,6 +20947,10 @@ var init_antigravity_agent_config = __esm({
|
|
|
20880
20947
|
var src_exports = {};
|
|
20881
20948
|
__export(src_exports, {
|
|
20882
20949
|
ANTIGRAVITY_ENV_KEYS: () => ANTIGRAVITY_ENV_KEYS,
|
|
20950
|
+
ASK_DECISIONS_TOOL: () => ASK_DECISIONS_TOOL,
|
|
20951
|
+
ASK_ESCALATION_TOOL: () => ASK_ESCALATION_TOOL,
|
|
20952
|
+
ASK_RELAY_TOOL: () => ASK_RELAY_TOOL,
|
|
20953
|
+
ASK_ROUTE: () => ASK_ROUTE,
|
|
20883
20954
|
AUTONOMY_CLAUSE: () => AUTONOMY_CLAUSE,
|
|
20884
20955
|
CODEX_NATIVE_AGENTS_MIN_CLIENT: () => CODEX_NATIVE_AGENTS_MIN_CLIENT,
|
|
20885
20956
|
CODE_STYLE_CLAUSE: () => CODE_STYLE_CLAUSE,
|
|
@@ -20902,8 +20973,10 @@ __export(src_exports, {
|
|
|
20902
20973
|
REVERSE_PHASE_GUIDE: () => REVERSE_PHASE_GUIDE,
|
|
20903
20974
|
REVERSE_STANDARD: () => REVERSE_STANDARD,
|
|
20904
20975
|
SCAFFOLD_PHASE_GUIDE: () => SCAFFOLD_PHASE_GUIDE,
|
|
20976
|
+
SELF_REVIEW_CLAUSE: () => SELF_REVIEW_CLAUSE,
|
|
20905
20977
|
SUBAGENT_STATUSLINE_SCRIPT: () => SUBAGENT_STATUSLINE_SCRIPT,
|
|
20906
20978
|
SkillError: () => SkillError,
|
|
20979
|
+
TEXT_ASK_ROUTE: () => TEXT_ASK_ROUTE,
|
|
20907
20980
|
WORK_PHASES: () => WORK_PHASES,
|
|
20908
20981
|
agentContractOf: () => agentContractOf,
|
|
20909
20982
|
agentDefinitionHash: () => agentDefinitionHash,
|
|
@@ -21004,6 +21077,7 @@ __export(src_exports, {
|
|
|
21004
21077
|
startProjectPrompt: () => startProjectPrompt,
|
|
21005
21078
|
startPrompt: () => startPrompt,
|
|
21006
21079
|
startScaffoldPrompt: () => startScaffoldPrompt,
|
|
21080
|
+
textAsk: () => textAsk,
|
|
21007
21081
|
tomlBasicString: () => tomlBasicString,
|
|
21008
21082
|
validateAgentEvalManifest: () => validateAgentEvalManifest,
|
|
21009
21083
|
verifyScopeClause: () => verifyScopeClause,
|
|
@@ -21027,6 +21101,7 @@ var init_src2 = __esm({
|
|
|
21027
21101
|
init_codex_settings();
|
|
21028
21102
|
init_agent_cli();
|
|
21029
21103
|
init_custom_agents();
|
|
21104
|
+
init_ask_via();
|
|
21030
21105
|
init_agent_definition();
|
|
21031
21106
|
init_phase_agents();
|
|
21032
21107
|
init_agent_readonly();
|
|
@@ -21325,6 +21400,7 @@ function stageFor(phases2) {
|
|
|
21325
21400
|
if (WORK_PHASES.includes(p3.name) && p3.state === "active")
|
|
21326
21401
|
best = Math.max(best, STAGES.indexOf("executing"));
|
|
21327
21402
|
if (p3.state !== "done" && p3.state !== "skipped") continue;
|
|
21403
|
+
if (p3.state === "skipped" && UNSKIPPABLE_PHASES.has(p3.name)) continue;
|
|
21328
21404
|
const s2 = REACHED[p3.name];
|
|
21329
21405
|
if (s2) best = Math.max(best, STAGES.indexOf(s2));
|
|
21330
21406
|
}
|
|
@@ -21439,8 +21515,11 @@ var init_session_phases = __esm({
|
|
|
21439
21515
|
Audit: "objective",
|
|
21440
21516
|
Spec: "spec-ready",
|
|
21441
21517
|
Plan: "planned",
|
|
21518
|
+
// ADR-0230 · flow feature & qa ditutup fase Review resmi: Execute selesai baru `executing`, Review
|
|
21519
|
+
// yang mencapai `done`. `Review` unik lintas PIPELINES dan bukan fase kerja (`WORK_PHASES`).
|
|
21442
21520
|
Laporan: "done",
|
|
21443
|
-
Execute: "
|
|
21521
|
+
Execute: "executing",
|
|
21522
|
+
Review: "done",
|
|
21444
21523
|
// SPEC-407 · ADR-0089 · flow goal (Goal → Verifikasi): fase kerja mencapai `executing`, fase
|
|
21445
21524
|
// verifikasi yang mencapai `done`. Kedua nama unik lintas PIPELINES — peta ini berkunci nama.
|
|
21446
21525
|
Goal: "executing",
|
|
@@ -21470,7 +21549,7 @@ var init_session_phases = __esm({
|
|
|
21470
21549
|
if (PLAN_DIRS.some((d) => rel.startsWith(`${d}/`) && !rel.slice(d.length + 1).includes("/"))) return false;
|
|
21471
21550
|
return re.test(rel.slice(rel.lastIndexOf("/") + 1).toLowerCase());
|
|
21472
21551
|
});
|
|
21473
|
-
phasesComplete = (phases2) => phases2.length > 0 && phases2.every((p3) => p3.state === "done" || p3.state === "skipped");
|
|
21552
|
+
phasesComplete = (phases2) => phases2.length > 0 && phases2.every((p3) => p3.state === "done" || p3.state === "skipped" && !UNSKIPPABLE_PHASES.has(p3.name));
|
|
21474
21553
|
}
|
|
21475
21554
|
});
|
|
21476
21555
|
|
|
@@ -48954,8 +49033,13 @@ function createSession(projectId, cwd, opts2 = {}) {
|
|
|
48954
49033
|
}
|
|
48955
49034
|
const agentForDefs = opts2.agent ?? "claude";
|
|
48956
49035
|
const sessionEffort = agentForDefs === "codex" && opts2.model && opts2.effort ? coerceCodexEffort(opts2.model, opts2.effort) : opts2.effort;
|
|
48957
|
-
const
|
|
48958
|
-
const
|
|
49036
|
+
const askText = !opts2.command && agentForDefs === "claude" && opts2.askVia === "text";
|
|
49037
|
+
const asked = (s2) => askText ? textAsk(s2) : s2;
|
|
49038
|
+
const requestedPhaseDefs = opts2.command ? [] : (opts2.phaseAgents ?? []).map((d) => askText ? { ...d, instructions: textAsk(d.instructions) } : d);
|
|
49039
|
+
const bornPrompt = (orch) => {
|
|
49040
|
+
const p3 = orch ? opts2.prompt : opts2.legacyPrompt ?? opts2.prompt;
|
|
49041
|
+
return p3 === void 0 ? p3 : asked(p3);
|
|
49042
|
+
};
|
|
48959
49043
|
const selectionContext = {
|
|
48960
49044
|
projectId,
|
|
48961
49045
|
runtime: agentForDefs,
|
|
@@ -49041,7 +49125,7 @@ function createSession(projectId, cwd, opts2 = {}) {
|
|
|
49041
49125
|
return [error instanceof Error ? error.message : String(error)];
|
|
49042
49126
|
}
|
|
49043
49127
|
agentsFile = file;
|
|
49044
|
-
rosterBlock = agentDelegationClause(customDefs, "claude");
|
|
49128
|
+
rosterBlock = asked(agentDelegationClause(customDefs, "claude"));
|
|
49045
49129
|
liveAgentDefs = defs;
|
|
49046
49130
|
renderedDefs = defs;
|
|
49047
49131
|
return [];
|
|
@@ -49147,7 +49231,8 @@ function createSession(projectId, cwd, opts2 = {}) {
|
|
|
49147
49231
|
// SPEC-909 · ADR-0146 · sesi ber-`opts.command` tak pernah sampai ke sini (cabang shell
|
|
49148
49232
|
// mentah di atas), jadi hook event hanya pernah terpasang di sesi agen.
|
|
49149
49233
|
eventHook: true,
|
|
49150
|
-
subagentStatusLine: statusLineCommand
|
|
49234
|
+
subagentStatusLine: statusLineCommand,
|
|
49235
|
+
askText
|
|
49151
49236
|
}).map(sq).join(" ");
|
|
49152
49237
|
const agentsArg = agentsFile ? `--agents "$(cat ${sq(agentsFile)})"` : "";
|
|
49153
49238
|
const nativeAgentArgs = agent === "codex" ? codexAgentArgs.map(sq).join(" ") : "";
|
|
@@ -58187,6 +58272,22 @@ function statesFor(raw) {
|
|
|
58187
58272
|
if (key.startsWith(prefix)) orchestration[key] = state;
|
|
58188
58273
|
}
|
|
58189
58274
|
}
|
|
58275
|
+
const rawOrchestration = isRecord(object2.orchestration) ? object2.orchestration : {};
|
|
58276
|
+
for (const flow2 of ORCHESTRATION_FLOWS) {
|
|
58277
|
+
const rawFlow = isRecord(rawOrchestration[flow2]) ? rawOrchestration[flow2] : {};
|
|
58278
|
+
for (const runtime of ["claude", "codex"]) {
|
|
58279
|
+
const rawRuntime = isRecord(rawFlow[runtime]) ? rawFlow[runtime] : {};
|
|
58280
|
+
for (const phase of FLOW_PHASES[flow2]) {
|
|
58281
|
+
const rawCell = rawRuntime[phase];
|
|
58282
|
+
if (!isRecord(rawCell)) continue;
|
|
58283
|
+
for (const field of ["model", "effort"]) {
|
|
58284
|
+
const key = `${flow2}.${runtime}.${phase}.${field}`;
|
|
58285
|
+
if (!(key in marker.data.orchestration) && rawCell[field] !== void 0 && rawCell[field] !== null)
|
|
58286
|
+
orchestration[key] = "user";
|
|
58287
|
+
}
|
|
58288
|
+
}
|
|
58289
|
+
}
|
|
58290
|
+
}
|
|
58190
58291
|
const rawMarker = isRecord(object2.builtinRuntimeDefaults) ? object2.builtinRuntimeDefaults : {};
|
|
58191
58292
|
return {
|
|
58192
58293
|
claude: marker.data.claude,
|
|
@@ -59409,7 +59510,7 @@ var init_flow = __esm({
|
|
|
59409
59510
|
});
|
|
59410
59511
|
|
|
59411
59512
|
// src/services/lead/pane.ts
|
|
59412
|
-
function
|
|
59513
|
+
function readTurn(message) {
|
|
59413
59514
|
const body = message.trim();
|
|
59414
59515
|
if (!body) return { asking: false, reason: "giliran codex berakhir tanpa pesan" };
|
|
59415
59516
|
if (CODEX_FINISHED.some((re) => re.test(body)))
|
|
@@ -60144,7 +60245,7 @@ async function runChain(ask, s2, deps) {
|
|
|
60144
60245
|
const stop = (reason, failed = false) => ({ acted, done: false, failed, reason, at, flowId, step });
|
|
60145
60246
|
const asked = ask.source === "ask-tool";
|
|
60146
60247
|
if (ask.source === "turn-end") {
|
|
60147
|
-
const read2 =
|
|
60248
|
+
const read2 = readTurn(ask.message);
|
|
60148
60249
|
if (!read2.asking) return stop(read2.reason);
|
|
60149
60250
|
}
|
|
60150
60251
|
const steps = ask.source === "ask-tool" ? ask.questions : [null];
|
|
@@ -66215,6 +66316,28 @@ var init_project_checkout = __esm({
|
|
|
66215
66316
|
}
|
|
66216
66317
|
});
|
|
66217
66318
|
|
|
66319
|
+
// src/services/lead/ask-via.ts
|
|
66320
|
+
function leadDecides(cfg, optIn, projectId) {
|
|
66321
|
+
return optIn.includes(projectId) && leadActive(cfg, projectId);
|
|
66322
|
+
}
|
|
66323
|
+
async function askViaFor(projectId, agent, deps = prodDeps2) {
|
|
66324
|
+
if ((agent ?? "claude") !== "claude") return void 0;
|
|
66325
|
+
try {
|
|
66326
|
+
const [cfg, optIn] = await Promise.all([deps.cfg(), deps.optIn()]);
|
|
66327
|
+
return leadDecides(cfg, optIn, projectId) ? "text" : "tool";
|
|
66328
|
+
} catch {
|
|
66329
|
+
return "tool";
|
|
66330
|
+
}
|
|
66331
|
+
}
|
|
66332
|
+
var prodDeps2;
|
|
66333
|
+
var init_ask_via2 = __esm({
|
|
66334
|
+
"src/services/lead/ask-via.ts"() {
|
|
66335
|
+
"use strict";
|
|
66336
|
+
init_config5();
|
|
66337
|
+
prodDeps2 = { cfg: getLead, optIn: leadProjects };
|
|
66338
|
+
}
|
|
66339
|
+
});
|
|
66340
|
+
|
|
66218
66341
|
// src/services/session-launch.ts
|
|
66219
66342
|
function resumeState(repoDir, worktree, branchTo, headSha) {
|
|
66220
66343
|
if (realGit.worktreeAlive(worktree)) return { worktreeKept: true };
|
|
@@ -66332,7 +66455,7 @@ async function startSpecSession(spec, opts2) {
|
|
|
66332
66455
|
const resumeCtx = resume ? buildResumeCtx(repoDir, id2, opts2.flow, resume.worktreeKept) : void 0;
|
|
66333
66456
|
let plan = fullPlan;
|
|
66334
66457
|
if (fullPlan && isContinue && !isGoalFlow) {
|
|
66335
|
-
const phases2 = fullPlan.phases.filter((p3) => p3.phase === "Execute");
|
|
66458
|
+
const phases2 = fullPlan.phases.filter((p3) => p3.phase === "Execute" || p3.phase === REVIEWER_CELL);
|
|
66336
66459
|
plan = phases2.length ? { ...fullPlan, phases: phases2 } : null;
|
|
66337
66460
|
}
|
|
66338
66461
|
const buildPrompt = (p3) => {
|
|
@@ -66362,6 +66485,7 @@ async function startSpecSession(spec, opts2) {
|
|
|
66362
66485
|
...resumeCtx ? { resume: resumeCtx } : {}
|
|
66363
66486
|
}) : [];
|
|
66364
66487
|
const scopeEnv = { HANOMAN_BASE_SHA: baseSha, HANOMAN_VERIFY_SCOPE: verifyScope };
|
|
66488
|
+
const askVia = await askViaFor(spec.projectId, agent);
|
|
66365
66489
|
const s2 = createSession(spec.projectId, worktree, {
|
|
66366
66490
|
specId: spec.id,
|
|
66367
66491
|
flow: opts2.flow,
|
|
@@ -66369,13 +66493,14 @@ async function startSpecSession(spec, opts2) {
|
|
|
66369
66493
|
effort: effort2,
|
|
66370
66494
|
goal,
|
|
66371
66495
|
agent,
|
|
66496
|
+
askVia,
|
|
66372
66497
|
phaseFile: phaseFilePath(repoDir, id2),
|
|
66373
66498
|
decisionFile: decisionFilePath(repoDir, id2),
|
|
66374
66499
|
attachmentsDir: attachments.items.length ? attachments.dir : void 0,
|
|
66375
66500
|
prompt,
|
|
66376
66501
|
legacyPrompt,
|
|
66377
66502
|
phaseAgents,
|
|
66378
|
-
// S3 · SPEC-172 · berkas fase continue masih memuat `Execute done` run lama; fase yang DIKERJAKAN
|
|
66503
|
+
// S3 · SPEC-172 · berkas fase continue masih memuat `Execute done` (ADR-0230 · dan `Review done`) run lama; fase yang DIKERJAKAN
|
|
66379
66504
|
// ULANG sesi ini tak boleh dihitung `doneAtBirth`, supaya ⚠ bukti tetap bisa menyala.
|
|
66380
66505
|
...isContinue && plan ? { rerunPhases: plan.phases.map((p3) => p3.phase) } : {},
|
|
66381
66506
|
env: scopeEnv
|
|
@@ -66406,6 +66531,7 @@ var init_session_launch = __esm({
|
|
|
66406
66531
|
init_remote_session();
|
|
66407
66532
|
init_registry();
|
|
66408
66533
|
init_event_log();
|
|
66534
|
+
init_ask_via2();
|
|
66409
66535
|
init_pty();
|
|
66410
66536
|
LaunchError = class extends Error {
|
|
66411
66537
|
// SPEC-447 · `blockers` hanya terisi untuk kind "blocked"; route memetakannya ke body 409.
|
|
@@ -79238,6 +79364,7 @@ async function refuseSelfDecision(input) {
|
|
|
79238
79364
|
// src/routes/terminal.ts
|
|
79239
79365
|
init_tui_dialog();
|
|
79240
79366
|
init_runtime();
|
|
79367
|
+
init_ask_via2();
|
|
79241
79368
|
var ATTACHMENT_MIME = /* @__PURE__ */ new Set(["image/png", "image/jpeg", "image/webp"]);
|
|
79242
79369
|
var DIALOG_ANSWER_ERROR = {
|
|
79243
79370
|
stale: "layar dialog sudah berubah \u2014 muat ulang pertanyaannya",
|
|
@@ -79359,12 +79486,14 @@ async function terminal_default(app3, opts2) {
|
|
|
79359
79486
|
const brief = { id: project.id, name: project.name, desc: project.desc, stack: project.stack };
|
|
79360
79487
|
const plan = sessionPhasePlan(await getSetting(), "reverse", agent2, { model: model2, effort: effort3 });
|
|
79361
79488
|
const legacyPrompt = startProjectPrompt("reverse", brief, "reverse-docs") + resumeNote(reused);
|
|
79489
|
+
const askVia = await askViaFor(project.id, agent2);
|
|
79362
79490
|
const s3 = createSession(project.id, wt, {
|
|
79363
79491
|
id: id2,
|
|
79364
79492
|
flow: "reverse",
|
|
79365
79493
|
model: model2,
|
|
79366
79494
|
effort: effort3,
|
|
79367
79495
|
agent: agent2,
|
|
79496
|
+
askVia,
|
|
79368
79497
|
phaseFile: phaseFilePath(repoDir, id2),
|
|
79369
79498
|
decisionFile: decisionFilePath(repoDir, id2),
|
|
79370
79499
|
prompt: plan ? startProjectPrompt("reverse", brief, "reverse-docs", plan) + resumeNote(reused) : legacyPrompt,
|
|
@@ -79397,12 +79526,14 @@ async function terminal_default(app3, opts2) {
|
|
|
79397
79526
|
const brief = { id: project.id, name: project.name, desc: project.desc, stack: project.stack };
|
|
79398
79527
|
const plan = sessionPhasePlan(await getSetting(), "scaffold", agent2, { model: model2, effort: effort3 });
|
|
79399
79528
|
const legacyPrompt = startScaffoldPrompt(brief, "scaffold-docs") + resumeNote(reused);
|
|
79529
|
+
const askVia = await askViaFor(project.id, agent2);
|
|
79400
79530
|
const s3 = createSession(project.id, wt, {
|
|
79401
79531
|
id: id2,
|
|
79402
79532
|
flow: "scaffold",
|
|
79403
79533
|
model: model2,
|
|
79404
79534
|
effort: effort3,
|
|
79405
79535
|
agent: agent2,
|
|
79536
|
+
askVia,
|
|
79406
79537
|
phaseFile: phaseFilePath(repoDir, id2),
|
|
79407
79538
|
decisionFile: decisionFilePath(repoDir, id2),
|
|
79408
79539
|
prompt: plan ? startScaffoldPrompt(brief, "scaffold-docs", plan) + resumeNote(reused) : legacyPrompt,
|
|
@@ -79439,6 +79570,7 @@ async function terminal_default(app3, opts2) {
|
|
|
79439
79570
|
const audit = auditDoc ? { id: fromAudit, path: auditDoc.path, content: auditDoc.content } : void 0;
|
|
79440
79571
|
const plan = sessionPhasePlan(await getSetting(), "prd", agent2, { model: model2, effort: effort3 });
|
|
79441
79572
|
const legacyPrompt = startPrdPrompt(project_, brief, `prd/${slug2}`, audit) + resumeNote(reused);
|
|
79573
|
+
const askVia = await askViaFor(project.id, agent2);
|
|
79442
79574
|
const s3 = createSession(project.id, wt, {
|
|
79443
79575
|
id: id2,
|
|
79444
79576
|
flow: "prd",
|
|
@@ -79446,6 +79578,7 @@ async function terminal_default(app3, opts2) {
|
|
|
79446
79578
|
model: model2,
|
|
79447
79579
|
effort: effort3,
|
|
79448
79580
|
agent: agent2,
|
|
79581
|
+
askVia,
|
|
79449
79582
|
phaseFile: phaseFilePath(repoDir, id2),
|
|
79450
79583
|
decisionFile: decisionFilePath(repoDir, id2),
|
|
79451
79584
|
prompt: plan ? startPrdPrompt(project_, brief, `prd/${slug2}`, audit, plan) + resumeNote(reused) : legacyPrompt,
|
|
@@ -79487,6 +79620,7 @@ async function terminal_default(app3, opts2) {
|
|
|
79487
79620
|
const prd = { title, path: prdPath, content };
|
|
79488
79621
|
const plan = sessionPhasePlan(await getSetting(), "breakdown", agent2, { model: model2, effort: effort3 });
|
|
79489
79622
|
const legacyPrompt = startBreakdownPrompt(project_, prd, `breakdown/${slug2}`) + resumeNote(reused);
|
|
79623
|
+
const askVia = await askViaFor(project.id, agent2);
|
|
79490
79624
|
const s3 = createSession(project.id, wt, {
|
|
79491
79625
|
id: id2,
|
|
79492
79626
|
flow: "breakdown",
|
|
@@ -79494,6 +79628,7 @@ async function terminal_default(app3, opts2) {
|
|
|
79494
79628
|
model: model2,
|
|
79495
79629
|
effort: effort3,
|
|
79496
79630
|
agent: agent2,
|
|
79631
|
+
askVia,
|
|
79497
79632
|
phaseFile: phaseFilePath(repoDir, id2),
|
|
79498
79633
|
decisionFile: decisionFilePath(repoDir, id2),
|
|
79499
79634
|
prompt: plan ? startBreakdownPrompt(project_, prd, `breakdown/${slug2}`, plan) + resumeNote(reused) : legacyPrompt,
|
|
@@ -86981,6 +87116,7 @@ init_settings3();
|
|
|
86981
87116
|
init_codex_trust();
|
|
86982
87117
|
init_qa_attachment_transfer();
|
|
86983
87118
|
init_uploads();
|
|
87119
|
+
init_ask_via2();
|
|
86984
87120
|
import { createHash as createHash21 } from "node:crypto";
|
|
86985
87121
|
import { execFileSync as execFileSync10 } from "node:child_process";
|
|
86986
87122
|
import { join as join50 } from "node:path";
|
|
@@ -87053,6 +87189,7 @@ ${files2.join("\n")}` : "",
|
|
|
87053
87189
|
CODE_STYLE_CLAUSE,
|
|
87054
87190
|
reused ? RESUMED_WORKTREE_NOTE : ""
|
|
87055
87191
|
].filter(Boolean).join("\n\n");
|
|
87192
|
+
const askVia = await askViaFor(d.projectId, agent);
|
|
87056
87193
|
const s2 = createSession(d.projectId, wt, {
|
|
87057
87194
|
id: id2,
|
|
87058
87195
|
branch,
|
|
@@ -87060,6 +87197,7 @@ ${files2.join("\n")}` : "",
|
|
|
87060
87197
|
model,
|
|
87061
87198
|
effort: effort2,
|
|
87062
87199
|
prompt,
|
|
87200
|
+
askVia,
|
|
87063
87201
|
env: { HANOMAN_BASE_SHA: baseSha, HANOMAN_VERIFY_SCOPE: verifyScope },
|
|
87064
87202
|
attachmentsDir: files2.length ? sessionUploadDir(id2) : void 0
|
|
87065
87203
|
});
|
|
@@ -90562,6 +90700,7 @@ init_settings3();
|
|
|
90562
90700
|
init_codex_trust();
|
|
90563
90701
|
init_pty();
|
|
90564
90702
|
init_session_launch_gate();
|
|
90703
|
+
init_ask_via2();
|
|
90565
90704
|
var cronSessionId = (cronId) => `cron-${cronId.toLowerCase().replace(/[^a-z0-9_-]/g, "_")}`;
|
|
90566
90705
|
async function liveCronSession(cronId) {
|
|
90567
90706
|
const s2 = await getSessionAsync(cronSessionId(cronId));
|
|
@@ -90582,11 +90721,13 @@ async function startCronSession(cron) {
|
|
|
90582
90721
|
if (agent === "codex") ensureCodexTrust(repoDir);
|
|
90583
90722
|
const wt = `${repoDir}/.worktrees/${id2}`;
|
|
90584
90723
|
if (!realGit.worktreeAlive(wt)) realGit.addWorktree(repoDir, wt, "HEAD");
|
|
90724
|
+
const askVia = await askViaFor(cron.projectId, agent);
|
|
90585
90725
|
const s2 = createSession(cron.projectId, wt, {
|
|
90586
90726
|
id: id2,
|
|
90587
90727
|
agent,
|
|
90588
90728
|
model,
|
|
90589
90729
|
effort: effort2,
|
|
90730
|
+
askVia,
|
|
90590
90731
|
prompt: cronPrompt(
|
|
90591
90732
|
{ id: project.id, name: project.name, desc: project.desc, stack: project.stack },
|
|
90592
90733
|
{ name: cron.name, prompt: cron.prompt }
|
|
@@ -90707,7 +90848,7 @@ async function tick4(now, deps, end2 = prodEnd) {
|
|
|
90707
90848
|
console.error("scheduler drain:", e);
|
|
90708
90849
|
}
|
|
90709
90850
|
}
|
|
90710
|
-
var
|
|
90851
|
+
var prodDeps3 = {
|
|
90711
90852
|
liveCount: async () => (await listSessionsAsync()).filter((s2) => !s2.exited).length,
|
|
90712
90853
|
isLive: async (specId) => {
|
|
90713
90854
|
const s2 = await getSessionAsync(sessionIdForSpec(specId));
|
|
@@ -90741,7 +90882,7 @@ var prodDeps2 = {
|
|
|
90741
90882
|
};
|
|
90742
90883
|
var TICK_MS3 = 1e4;
|
|
90743
90884
|
var timer7;
|
|
90744
|
-
function startScheduler(deps =
|
|
90885
|
+
function startScheduler(deps = prodDeps3) {
|
|
90745
90886
|
if (timer7) return;
|
|
90746
90887
|
timer7 = setInterval(() => void tick4(Date.now(), deps), TICK_MS3);
|
|
90747
90888
|
timer7.unref();
|
|
@@ -90778,7 +90919,7 @@ init_db();
|
|
|
90778
90919
|
init_session_launch();
|
|
90779
90920
|
init_session_admission2();
|
|
90780
90921
|
init_notifications2();
|
|
90781
|
-
var
|
|
90922
|
+
var prodDeps4 = {
|
|
90782
90923
|
// ADR-0170 · mengamandemen ADR-0169 keputusan #4: `bypassCapacity` DICABUT. Auto-resume kini
|
|
90783
90924
|
// tunduk cap/beban host seperti "Lanjutkan" manual — mesin 8 GB operator sudah dua kali kernel
|
|
90784
90925
|
// panic akibat batch sesi paralel tepat SAAT boot (memori mac-mini-8gb-panic-agen-paralel),
|
|
@@ -90787,7 +90928,7 @@ var prodDeps3 = {
|
|
|
90787
90928
|
recordFail: recordFailure,
|
|
90788
90929
|
recordDeferred: recordFailure
|
|
90789
90930
|
};
|
|
90790
|
-
async function resumeReconciledSessions(cutoff, deps =
|
|
90931
|
+
async function resumeReconciledSessions(cutoff, deps = prodDeps4) {
|
|
90791
90932
|
const report = { resumed: [], failed: [], deferred: [] };
|
|
90792
90933
|
const specIds = await reconciledSpecIdsSince(cutoff);
|
|
90793
90934
|
if (!specIds.length) return report;
|