hanoman 0.9.35 → 0.9.37
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 +68 -12
- package/dist/server.js +255 -102
- package/docs/agent-integration.md +4 -0
- package/package.json +1 -1
- package/web/assets/{DalangHanomanScreen-BVu8tGjd.js → DalangHanomanScreen-JE8gkztH.js} +1 -1
- package/web/assets/{DocPreviewModal-DwhXR__7.js → DocPreviewModal-B23vI_It.js} +1 -1
- package/web/assets/{DocsWorkspace-poV6NPLq.js → DocsWorkspace-CbV27H6A.js} +1 -1
- package/web/assets/{IdeScreen-BpGoKqok.js → IdeScreen-BY7sm97W.js} +1 -1
- package/web/assets/{LeadScreen-Bqj27JHC.js → LeadScreen-BFwI29zS.js} +1 -1
- package/web/assets/{ReviewScreen-ykVVM8ir.js → ReviewScreen-pM6zzGZl.js} +1 -1
- package/web/assets/{SchedulerScreen-26uRd--J.js → SchedulerScreen-BIhqn3X1.js} +1 -1
- package/web/assets/{SettingsScreen-D7qZqj-w.js → SettingsScreen-C_TW3mbs.js} +1 -1
- package/web/assets/{TeamScreen-NC9C8iL8.js → TeamScreen-RT926lDf.js} +1 -1
- package/web/assets/TerminalScreen-fpC5a2jS.js +2 -0
- package/web/assets/{TriageScreen-DzKT-O0A.js → TriageScreen-Zp1bdRnl.js} +1 -1
- package/web/assets/{VpsScreen-bVd5YC2y.js → VpsScreen-Jnb8C1o2.js} +2 -2
- package/web/assets/{fields-Cqp-sr6L.js → fields-B_3dIGcG.js} +1 -1
- package/web/assets/{index-BjNlrKWq.js → index-CbX7iwxN.js} +204 -204
- package/web/assets/{live-COTGt6Jw.js → live-CNp86nGW.js} +1 -1
- package/web/assets/{sched-lead-shared-Xe8lxNc_.js → sched-lead-shared-BUcJMfNH.js} +1 -1
- package/web/assets/{settings-rebase-Cp2i2t6-.js → settings-rebase-CYr7W_rB.js} +1 -1
- package/web/index.html +1 -1
- package/web/assets/TerminalScreen-Do49p9t6.js +0 -2
package/dist/server.js
CHANGED
|
@@ -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
|
};
|
|
@@ -8105,7 +8115,13 @@ var init_dto = __esm({
|
|
|
8105
8115
|
agent: zAgent.optional(),
|
|
8106
8116
|
model: external_exports.string().optional(),
|
|
8107
8117
|
effort: external_exports.string().optional(),
|
|
8108
|
-
force: external_exports.boolean().optional()
|
|
8118
|
+
force: external_exports.boolean().optional(),
|
|
8119
|
+
// ADR-0232 · opsional: `worktree:true` → sesi lahir di `.worktrees/<id>` pada branch baru
|
|
8120
|
+
// `term/<id>` dari `branchFrom` (kosong → HEAD repo), alih-alih langsung di repoDir. Tanpa
|
|
8121
|
+
// keduanya body-nya byte-identik dengan sebelumnya. `branchFrom` tanpa `worktree` ditolak di
|
|
8122
|
+
// route — ia tak berarti apa-apa di repoDir dan diam-diam mengabaikannya menyesatkan.
|
|
8123
|
+
worktree: external_exports.boolean().optional(),
|
|
8124
|
+
branchFrom: external_exports.string().min(1).max(255).optional()
|
|
8109
8125
|
}),
|
|
8110
8126
|
// SPEC-252 · ADR-0061 — model & effort per SESI: override opsional saat Start; kosong → global.
|
|
8111
8127
|
// SPEC-332 · ADR-0073 — mode goal per SESI: `goal` undefined → ikut Setting.goal.enabled,
|
|
@@ -13228,6 +13244,8 @@ var init_sessions = __esm({
|
|
|
13228
13244
|
} })
|
|
13229
13245
|
},
|
|
13230
13246
|
prdPath: str("flow `breakdown`: jalur PRD yang dipecah. WAJIB untuk alur itu."),
|
|
13247
|
+
worktree: bool("Terminal agen biasa (hanya `project`, tanpa `flow`/`shell`): true = lahir di worktree terpisah pada branch baru `term/<id>`, bukan langsung di repo project. Kosong = di repo project."),
|
|
13248
|
+
branchFrom: str("Bersama `worktree: true`: branch/ref asal worktree (lokal atau origin). Kosong = HEAD repo."),
|
|
13231
13249
|
force: bool("Lewati gerbang dependency. Pakai HANYA sesudah melihat daftar pemblokirnya.")
|
|
13232
13250
|
},
|
|
13233
13251
|
allOf: [
|
|
@@ -13257,7 +13275,8 @@ var init_sessions = __esm({
|
|
|
13257
13275
|
if (flow2 === "breakdown") return { method: "POST", path: "/terminal/sessions", body: { project, flow: flow2, prdPath: String(a.prdPath) } };
|
|
13258
13276
|
if (flow2 === "reverse" || flow2 === "scaffold") return { method: "POST", path: "/terminal/sessions", body: { project, flow: flow2 } };
|
|
13259
13277
|
const body = { project };
|
|
13260
|
-
for (const k of ["agent", "model", "effort"]) if (s(a[k]) !== void 0) body[k] = s(a[k]);
|
|
13278
|
+
for (const k of ["agent", "model", "effort", "branchFrom"]) if (s(a[k]) !== void 0) body[k] = s(a[k]);
|
|
13279
|
+
if (typeof a.worktree === "boolean") body.worktree = a.worktree;
|
|
13261
13280
|
return { method: "POST", path: "/terminal/sessions", body };
|
|
13262
13281
|
},
|
|
13263
13282
|
shape: (raw) => raw
|
|
@@ -16766,15 +16785,25 @@ function parseHookEvent(body) {
|
|
|
16766
16785
|
}
|
|
16767
16786
|
const turn = zTurnEnd.safeParse(body);
|
|
16768
16787
|
if (turn.success && !turn.data.stop_hook_active) {
|
|
16788
|
+
if (turn.data.background_tasks?.some((t) => t.status === "running")) return null;
|
|
16789
|
+
const message = clip3(turn.data.last_assistant_message, ASK_MESSAGE_MAX);
|
|
16769
16790
|
return {
|
|
16770
16791
|
source: "turn-end",
|
|
16771
|
-
askId: turn.data.turn_id
|
|
16792
|
+
askId: turn.data.turn_id ?? `stop:${turn.data.prompt_id ?? ""}:${fnv1a(message)}`,
|
|
16772
16793
|
questions: [],
|
|
16773
|
-
message
|
|
16794
|
+
message
|
|
16774
16795
|
};
|
|
16775
16796
|
}
|
|
16776
16797
|
return null;
|
|
16777
16798
|
}
|
|
16799
|
+
function fnv1a(s2) {
|
|
16800
|
+
let h2 = 2166136261;
|
|
16801
|
+
for (let i = 0; i < s2.length; i++) {
|
|
16802
|
+
h2 ^= s2.charCodeAt(i);
|
|
16803
|
+
h2 = Math.imul(h2, 16777619);
|
|
16804
|
+
}
|
|
16805
|
+
return (h2 >>> 0).toString(16);
|
|
16806
|
+
}
|
|
16778
16807
|
var ASK_QUESTION_MAX, ASK_MESSAGE_MAX, clip3, ASK_MAX_QUESTIONS, ASK_MAX_OPTIONS, zOption, zQuestion, zAskTool, zTurnEnd;
|
|
16779
16808
|
var init_session_ask = __esm({
|
|
16780
16809
|
"../shared/src/session-ask.ts"() {
|
|
@@ -16803,7 +16832,11 @@ var init_session_ask = __esm({
|
|
|
16803
16832
|
});
|
|
16804
16833
|
zTurnEnd = external_exports.object({
|
|
16805
16834
|
hook_event_name: external_exports.literal("Stop"),
|
|
16806
|
-
turn_id
|
|
16835
|
+
// ADR-0231 · codex mengirim `turn_id`; Stop claude (sesi bertanya lewat teks) tidak — ia membawa
|
|
16836
|
+
// `prompt_id` dan `background_tasks`.
|
|
16837
|
+
turn_id: external_exports.string().min(1).optional(),
|
|
16838
|
+
prompt_id: external_exports.string().optional(),
|
|
16839
|
+
background_tasks: external_exports.array(external_exports.object({ status: external_exports.string().optional() }).passthrough()).optional(),
|
|
16807
16840
|
last_assistant_message: external_exports.string().optional(),
|
|
16808
16841
|
// Codex menyalakan bendera ini saat Stop dipicu oleh hook Stop lain. Melayani giliran yang
|
|
16809
16842
|
// dibangkitkan gate mode goal (ADR-0074) berarti lead menjawab dirinya sendiri.
|
|
@@ -17359,29 +17392,25 @@ function orchestratorClause(plan, o = {}) {
|
|
|
17359
17392
|
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";
|
|
17360
17393
|
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).";
|
|
17361
17394
|
const retry = antigravity2 ? " (invoke_subagent BARU dengan nama definisi fase yang sama)" : codex2 ? "" : " (pemanggilan tool Agent BARU dengan `subagent_type` yang sama)";
|
|
17362
|
-
const askEscalation = codex2 || antigravity2 ? "tanyakan di terminal ini lalu tunggu jawaban" :
|
|
17363
|
-
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" :
|
|
17395
|
+
const askEscalation = codex2 || antigravity2 ? "tanyakan di terminal ini lalu tunggu jawaban" : ASK_ESCALATION_TOOL;
|
|
17396
|
+
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;
|
|
17364
17397
|
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." : "";
|
|
17365
17398
|
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." : "";
|
|
17366
17399
|
const runtimeLabel = (entry2) => antigravity2 ? `tier native ${entry2.model} \xB7 effort native unknown` : `${entry2.model} \xB7 ${entry2.effort}`;
|
|
17367
17400
|
const phaseList = plan.phases.map((p3, i) => `${i + 1}. ${p3.phase} \u2192 \`${p3.agentName}\` \xB7 ${runtimeLabel(p3)}`).join("\n");
|
|
17368
|
-
const
|
|
17369
|
-
const list2 = reviewer ? `${phaseList}
|
|
17370
|
-
Reviewer Execute \u2192 \`${reviewer.agentName}\` \xB7 ${runtimeLabel(reviewer)} (bukan fase \u2014 hanya dipanggil di langkah R)` : phaseList;
|
|
17401
|
+
const review = plan.phases.find((p3) => p3.phase === REVIEWER_CELL);
|
|
17371
17402
|
const hasExecute = plan.phases.some((p3) => p3.phase === "Execute");
|
|
17372
|
-
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.";
|
|
17373
|
-
const reviewStep =
|
|
17374
|
-
Tujuan: <objective backlog>
|
|
17375
|
-
Base SHA: $HANOMAN_BASE_SHA
|
|
17403
|
+
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.";
|
|
17404
|
+
const reviewStep = review ? `R. Fase Review: sesudah \`Execute done\` tercatat, panggil agen fasenya seperti langkah 1 dengan baris serah-terima tambahan:
|
|
17376
17405
|
Artefak: <path PERSIS dokumen spec & berkas plan> (qa yang melewati Spec & Plan: dokumen audit)
|
|
17377
17406
|
Laporan Execute: <tabel AC \u2192 bukti dari laporannya>
|
|
17378
17407
|
Putaran rework: <r>/2
|
|
17379
17408
|
|
|
17380
|
-
\`Verdict: lulus\` \u2192 langkah 2 (tulis \`
|
|
17409
|
+
\`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\`.` : "";
|
|
17381
17410
|
return [
|
|
17382
17411
|
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.",
|
|
17383
17412
|
`Fase berurutan:
|
|
17384
|
-
${
|
|
17413
|
+
${phaseList}`,
|
|
17385
17414
|
"Untuk SETIAP fase, berurutan:",
|
|
17386
17415
|
`1. Panggil subagent fasenya lewat ${call}, tugasnya berupa blok serah-terima berbentuk tetap:
|
|
17387
17416
|
Urutan: <n>/<total> \xB7 <Nama Fase>
|
|
@@ -17393,14 +17422,14 @@ Lampiran: <path INDEX.md lampiran, atau ->
|
|
|
17393
17422
|
Percobaan: <k>/2
|
|
17394
17423
|
|
|
17395
17424
|
${artefactRule} ${describeRule}`,
|
|
17396
|
-
'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.' + (
|
|
17425
|
+
'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)." : ""),
|
|
17397
17426
|
`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.`,
|
|
17398
17427
|
`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}`,
|
|
17399
17428
|
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.' : "",
|
|
17400
17429
|
reviewStep,
|
|
17401
17430
|
handoff,
|
|
17402
17431
|
"DILARANG mengerjakan isi fase sendiri \u2014 termasuk saat subagent gagal. Menulis `skipped` untuk fase yang dilewati bukan mengerjakannya.",
|
|
17403
|
-
|
|
17432
|
+
"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.'
|
|
17404
17433
|
].filter(Boolean).join("\n\n");
|
|
17405
17434
|
}
|
|
17406
17435
|
function startPrompt(flow2, spec, branchTo, autonomy, verifyScope, method, attachments, plan) {
|
|
@@ -17438,13 +17467,15 @@ function continuePrompt(flow2, spec, branchTo, autonomy, verifyScope, method, at
|
|
|
17438
17467
|
const m = resolveMethod(method);
|
|
17439
17468
|
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.`;
|
|
17440
17469
|
const push = `Setelah selesai: commit, lalu \`git push origin HEAD:refs/heads/${branchTo}\`. Worktree ini detached HEAD \u2014 itu memang disengaja.`;
|
|
17470
|
+
const hasReview = plan ? plan.phases.some((p3) => p3.phase === REVIEWER_CELL) : PIPELINES[flow2].includes(REVIEWER_CELL);
|
|
17441
17471
|
if (plan) {
|
|
17442
17472
|
return [
|
|
17443
17473
|
head,
|
|
17444
|
-
`JANGAN mengulang fase awal \u2014 spec & plan sudah ada di ${m.planDir}/**. Lanjutkan HANYA fase Execute lewat subagent fasenya
|
|
17474
|
+
`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."),
|
|
17445
17475
|
// S3 · berkas fase tak pernah dikosongkan: baris `Execute done` run lama masih ada dan akan
|
|
17446
17476
|
// memenuhi gerbang penutup sebelum agen Execute sesi ini bekerja sama sekali.
|
|
17447
|
-
|
|
17477
|
+
// ADR-0230 · sama untuk `Review done` lama.
|
|
17478
|
+
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.",
|
|
17448
17479
|
orchestratorClause(plan),
|
|
17449
17480
|
autonomyClause(autonomy),
|
|
17450
17481
|
orchestratorAttachmentClause(attachments),
|
|
@@ -17454,13 +17485,13 @@ function continuePrompt(flow2, spec, branchTo, autonomy, verifyScope, method, at
|
|
|
17454
17485
|
}
|
|
17455
17486
|
return [
|
|
17456
17487
|
head,
|
|
17457
|
-
`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
|
|
17488
|
+
`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 : ""),
|
|
17458
17489
|
autonomyClause(autonomy),
|
|
17459
17490
|
scopeClause(flow2, verifyScope),
|
|
17460
17491
|
codeStyleClause(flow2),
|
|
17461
17492
|
methodClause(m),
|
|
17462
17493
|
attachmentClause(attachments),
|
|
17463
|
-
skillInstruction(flow2, ["Execute"], m),
|
|
17494
|
+
skillInstruction(flow2, hasReview ? ["Execute", REVIEWER_CELL] : ["Execute"], m),
|
|
17464
17495
|
push,
|
|
17465
17496
|
specContext(spec)
|
|
17466
17497
|
].filter(Boolean).join("\n\n");
|
|
@@ -17633,7 +17664,7 @@ Stack: ${project.stack || "\u2014"}`,
|
|
|
17633
17664
|
${cron.prompt}`
|
|
17634
17665
|
].join("\n\n");
|
|
17635
17666
|
}
|
|
17636
|
-
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;
|
|
17667
|
+
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;
|
|
17637
17668
|
var init_prompt = __esm({
|
|
17638
17669
|
"../runner/src/prompt.ts"() {
|
|
17639
17670
|
"use strict";
|
|
@@ -17646,6 +17677,8 @@ var init_prompt = __esm({
|
|
|
17646
17677
|
WORK_PHASES = ["Execute", "Goal", "Kerjakan"];
|
|
17647
17678
|
DECIDER = "hanoman-lead bila aktif untuk project ini, selain itu manusia";
|
|
17648
17679
|
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.`;
|
|
17680
|
+
ASK_ESCALATION_TOOL = "tanyakan lewat AskUserQuestion";
|
|
17681
|
+
ASK_DECISIONS_TOOL = "lewat AskUserQuestion \u2014 tool itu memuat paling banyak 4 pertanyaan per panggilan, jadi pecah sisanya ke panggilan berikutnya sampai semuanya terjawab";
|
|
17649
17682
|
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)";
|
|
17650
17683
|
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.`;
|
|
17651
17684
|
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.`;
|
|
@@ -17657,8 +17690,10 @@ Setiap kali sebuah fase selesai (atau kamu putuskan dilewati), append satu baris
|
|
|
17657
17690
|
if (!phases2.includes("Plan") || !phases2.includes("Execute")) return base3;
|
|
17658
17691
|
return base3 + `
|
|
17659
17692
|
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 \`- [ ]\`.
|
|
17660
|
-
${PLAN_SHAPE}
|
|
17693
|
+
${PLAN_SHAPE}` + (phases2.includes(REVIEWER_CELL) ? `
|
|
17694
|
+
${SELF_REVIEW_CLAUSE}` : "");
|
|
17661
17695
|
};
|
|
17696
|
+
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`.";
|
|
17662
17697
|
skillInstruction = (flow2, phases2, method) => {
|
|
17663
17698
|
const lines2 = phases2.map((p3) => {
|
|
17664
17699
|
const skills2 = phaseSkillsFor(flow2, p3, method);
|
|
@@ -17969,7 +18004,7 @@ var init_settings2 = __esm({
|
|
|
17969
18004
|
'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))})'
|
|
17970
18005
|
].join(";");
|
|
17971
18006
|
busySnapshotCommand = (quotedSubFile) => `node -e '${BUSY_SNAPSHOT_SCRIPT}' ${quotedSubFile} >/dev/null 2>&1`;
|
|
17972
|
-
guardSettings = (decisionFile, goal, eventHook, subagentStatusLine) => {
|
|
18007
|
+
guardSettings = (decisionFile, goal, eventHook, subagentStatusLine, askText) => {
|
|
17973
18008
|
const hooks2 = {};
|
|
17974
18009
|
if (decisionFile) {
|
|
17975
18010
|
const f = `'${decisionFile.split("'").join("'\\''")}'`;
|
|
@@ -17997,6 +18032,8 @@ var init_settings2 = __esm({
|
|
|
17997
18032
|
hooks2.UserPromptSubmit = [{ hooks: [{ type: "command", command: `: > ${f}; : > ${sub}` }] }];
|
|
17998
18033
|
}
|
|
17999
18034
|
}
|
|
18035
|
+
if (eventHook && askText)
|
|
18036
|
+
(hooks2.Stop ??= []).push({ hooks: [{ type: "command", command: EVENT_HOOK_COMMAND }] });
|
|
18000
18037
|
if (goal) (hooks2.Stop ??= []).push({ hooks: [{ type: "prompt", prompt: goal }] });
|
|
18001
18038
|
return {
|
|
18002
18039
|
hooks: hooks2,
|
|
@@ -18025,7 +18062,7 @@ function defaultGoalCondition({ flow: flow2, specId, branchTo, spec }) {
|
|
|
18025
18062
|
const phases2 = PIPELINES[flow2];
|
|
18026
18063
|
const planGate = phases2.includes("Plan") && phases2.includes("Execute");
|
|
18027
18064
|
const clauses = [
|
|
18028
|
-
`1. output \`cat "$HANOMAN_PHASE_FILE"\` yang memuat satu baris untuk SETIAP fase ${phases2.join(" \u2192 ")}, masing-masing berakhiran \`done\` atau \`skipped
|
|
18065
|
+
`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("") + ";"
|
|
18029
18066
|
];
|
|
18030
18067
|
if (planGate) {
|
|
18031
18068
|
const dirs = PLAN_DIRS.map((d) => `${d}/`).join(" ");
|
|
@@ -18098,7 +18135,8 @@ function codexGoalScript(o) {
|
|
|
18098
18135
|
];
|
|
18099
18136
|
for (const p3 of phases2) {
|
|
18100
18137
|
lines2.push(
|
|
18101
|
-
|
|
18138
|
+
// ADR-0230 · fase `UNSKIPPABLE_PHASES` (Review) hanya lolos dengan `done`.
|
|
18139
|
+
`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"`
|
|
18102
18140
|
);
|
|
18103
18141
|
}
|
|
18104
18142
|
if (planGate) {
|
|
@@ -18175,7 +18213,7 @@ function agentFlags(o) {
|
|
|
18175
18213
|
...o.effort ? ["--effort", o.effort] : [],
|
|
18176
18214
|
"--dangerously-skip-permissions",
|
|
18177
18215
|
"--settings",
|
|
18178
|
-
JSON.stringify(guardSettings(o.decisionFile, o.goal, o.eventHook, o.subagentStatusLine))
|
|
18216
|
+
JSON.stringify(guardSettings(o.decisionFile, o.goal, o.eventHook, o.subagentStatusLine, o.askText))
|
|
18179
18217
|
];
|
|
18180
18218
|
}
|
|
18181
18219
|
var init_agent_cli = __esm({
|
|
@@ -18449,7 +18487,7 @@ function agentDelegationClause(defs, runtime = "claude") {
|
|
|
18449
18487
|
if (defs.every((def2) => def2.kind === "phase")) return "";
|
|
18450
18488
|
const codex2 = runtime === "codex";
|
|
18451
18489
|
const antigravity2 = runtime === "antigravity";
|
|
18452
|
-
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" :
|
|
18490
|
+
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;
|
|
18453
18491
|
return [
|
|
18454
18492
|
"",
|
|
18455
18493
|
"",
|
|
@@ -18458,7 +18496,7 @@ function agentDelegationClause(defs, runtime = "claude") {
|
|
|
18458
18496
|
""
|
|
18459
18497
|
].join("\n");
|
|
18460
18498
|
}
|
|
18461
|
-
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;
|
|
18499
|
+
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;
|
|
18462
18500
|
var init_custom_agents = __esm({
|
|
18463
18501
|
"../runner/src/custom-agents.ts"() {
|
|
18464
18502
|
"use strict";
|
|
@@ -18466,6 +18504,7 @@ var init_custom_agents = __esm({
|
|
|
18466
18504
|
init_code_style();
|
|
18467
18505
|
init_prompt();
|
|
18468
18506
|
init_agent_readonly();
|
|
18507
|
+
ASK_RELAY_TOOL = "ajukan semuanya lewat AskUserQuestion (pecah per 4 pertanyaan), lalu teruskan jawabannya lewat SendMessage ke agent ID yang sama";
|
|
18469
18508
|
PHASE_CONTEXT_HEADER = "=== KONTEKS ===";
|
|
18470
18509
|
liveMentions = (def2, roster) => {
|
|
18471
18510
|
if (def2.workspacePolicy === "read-only") return [];
|
|
@@ -18594,6 +18633,35 @@ var init_custom_agents = __esm({
|
|
|
18594
18633
|
}
|
|
18595
18634
|
});
|
|
18596
18635
|
|
|
18636
|
+
// ../runner/src/ask-via.ts
|
|
18637
|
+
function textAsk(s2) {
|
|
18638
|
+
let out4 = s2;
|
|
18639
|
+
for (const [tool, text2] of SWAPS) out4 = out4.split(tool).join(text2);
|
|
18640
|
+
return out4;
|
|
18641
|
+
}
|
|
18642
|
+
var NO_TOOL, TEXT_ASK_ROUTE, SWAPS;
|
|
18643
|
+
var init_ask_via = __esm({
|
|
18644
|
+
"../runner/src/ask-via.ts"() {
|
|
18645
|
+
"use strict";
|
|
18646
|
+
init_prompt();
|
|
18647
|
+
init_custom_agents();
|
|
18648
|
+
NO_TOOL = "JANGAN memakai AskUserQuestion (juga bila sebuah skill menyuruhnya)";
|
|
18649
|
+
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.`;
|
|
18650
|
+
SWAPS = [
|
|
18651
|
+
[ASK_ROUTE, TEXT_ASK_ROUTE],
|
|
18652
|
+
[
|
|
18653
|
+
ASK_DECISIONS_TOOL,
|
|
18654
|
+
`di terminal ini sekaligus dalam satu pesan (${NO_TOOL}), tiap pertanyaan bernomor dan diakhiri \`?\` beserta opsi, rekomendasi dan alasannya, lalu berhenti dan tunggu jawaban`
|
|
18655
|
+
],
|
|
18656
|
+
[
|
|
18657
|
+
ASK_RELAY_TOOL,
|
|
18658
|
+
`ajukan semuanya di terminal ini (${NO_TOOL}; bernomor, tiap pertanyaan diakhiri \`?\`), lalu teruskan jawabannya lewat SendMessage ke agent ID yang sama`
|
|
18659
|
+
],
|
|
18660
|
+
[ASK_ESCALATION_TOOL, `tanyakan di terminal ini (${NO_TOOL}) lalu berhenti dan tunggu jawaban`]
|
|
18661
|
+
];
|
|
18662
|
+
}
|
|
18663
|
+
});
|
|
18664
|
+
|
|
18597
18665
|
// ../runner/src/runtime-profile.ts
|
|
18598
18666
|
function resolveHardening(env) {
|
|
18599
18667
|
if (env.HANOMAN_HARDENING === "1") return true;
|
|
@@ -18853,7 +18921,7 @@ function phaseAgentInstructions(entry2, index, plan, ctx) {
|
|
|
18853
18921
|
const guide = PROJECT_FLOWS.has(flow2) ? projectGuide(flow2, phase, ctx) : backlogGuide(flow2, phase, ctx);
|
|
18854
18922
|
const executeMode = plan.executeMode ?? "inline";
|
|
18855
18923
|
const skills2 = phaseSkillsFor(flow2, phase, method, plan.runtime, executeMode);
|
|
18856
|
-
const skipSkillFinalReview = phase === "Execute" && plan.runtime === "claude" && executeMode === "subagent" &&
|
|
18924
|
+
const skipSkillFinalReview = phase === "Execute" && plan.runtime === "claude" && executeMode === "subagent" && plan.phases.some((p3) => p3.phase === REVIEWER_CELL) && skills2.includes("superpowers:subagent-driven-development");
|
|
18857
18925
|
const work = WORK_PHASES.includes(phase);
|
|
18858
18926
|
const verifies = work || phase === "Verifikasi";
|
|
18859
18927
|
return [
|
|
@@ -18862,7 +18930,7 @@ function phaseAgentInstructions(entry2, index, plan, ctx) {
|
|
|
18862
18930
|
DOC_WRITING_PHASES.has(phase) ? `=== STANDAR DOCS ===
|
|
18863
18931
|
${REVERSE_STANDARD}` : "",
|
|
18864
18932
|
skills2.length ? `Skills ${method.label} WAJIB untuk fase ini \u2014 muat & ikuti dengan mekanisme yang tersedia di agenmu: ` + skills2.join(", ") : "",
|
|
18865
|
-
skipSkillFinalReview ? "LEWATI final whole-branch review milik skill subagent-driven-development: review akhir dipegang
|
|
18933
|
+
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." : "",
|
|
18866
18934
|
verifies ? scopeClause(flow2, ctx.verifyScope) : "",
|
|
18867
18935
|
work ? codeStyleClause(flow2) : "",
|
|
18868
18936
|
methodClause(method),
|
|
@@ -18877,40 +18945,29 @@ ${REVERSE_STANDARD}` : "",
|
|
|
18877
18945
|
].filter(Boolean).join("\n\n");
|
|
18878
18946
|
}
|
|
18879
18947
|
function buildPhaseAgents(plan, ctx) {
|
|
18880
|
-
|
|
18881
|
-
|
|
18882
|
-
|
|
18883
|
-
|
|
18884
|
-
|
|
18885
|
-
|
|
18886
|
-
|
|
18887
|
-
|
|
18888
|
-
|
|
18889
|
-
|
|
18890
|
-
|
|
18891
|
-
|
|
18892
|
-
|
|
18893
|
-
|
|
18894
|
-
|
|
18895
|
-
|
|
18896
|
-
|
|
18897
|
-
|
|
18898
|
-
kind: "phase",
|
|
18899
|
-
phase: r.phase,
|
|
18900
|
-
name: r.agentName,
|
|
18901
|
-
description: `Reviewer independen hasil fase Execute flow ${plan.flow} hanoman \u2014 hanya dipanggil orchestrator sesi ini, sesudah Execute melapor selesai.`,
|
|
18902
|
-
instructions: reviewerInstructions(plan, ctx),
|
|
18903
|
-
context: ctx.context,
|
|
18904
|
-
tools: null,
|
|
18905
|
-
model: r.model,
|
|
18906
|
-
effort: r.effort,
|
|
18907
|
-
mentions: []
|
|
18908
|
-
}];
|
|
18948
|
+
return plan.phases.map((entry2, index) => {
|
|
18949
|
+
const review = entry2.phase === REVIEWER_CELL;
|
|
18950
|
+
return {
|
|
18951
|
+
kind: "phase",
|
|
18952
|
+
phase: entry2.phase,
|
|
18953
|
+
name: entry2.agentName,
|
|
18954
|
+
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.`,
|
|
18955
|
+
instructions: review ? reviewerInstructions(plan, ctx) : phaseAgentInstructions(entry2, index, plan, ctx),
|
|
18956
|
+
// T2 · konteks bersama dibawa TERPISAH (lihat `phasePromptOf`): claude merujuknya lewat satu
|
|
18957
|
+
// berkas di temp dir sesi, codex tetap inline.
|
|
18958
|
+
context: ctx.context,
|
|
18959
|
+
tools: null,
|
|
18960
|
+
model: entry2.model,
|
|
18961
|
+
effort: entry2.effort,
|
|
18962
|
+
mentions: [],
|
|
18963
|
+
...review ? {} : { executeMode: plan.executeMode ?? "inline" }
|
|
18964
|
+
};
|
|
18965
|
+
});
|
|
18909
18966
|
}
|
|
18910
18967
|
function reviewerInstructions(plan, ctx) {
|
|
18911
18968
|
const m = ctx.method;
|
|
18912
18969
|
return [
|
|
18913
|
-
`Kamu reviewer independen hasil fase Execute flow ${plan.flow} hanoman. Kamu dipanggil orchestrator sesudah
|
|
18970
|
+
`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.`,
|
|
18914
18971
|
"Prosedur:",
|
|
18915
18972
|
[
|
|
18916
18973
|
`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.`,
|
|
@@ -20899,6 +20956,10 @@ var init_antigravity_agent_config = __esm({
|
|
|
20899
20956
|
var src_exports = {};
|
|
20900
20957
|
__export(src_exports, {
|
|
20901
20958
|
ANTIGRAVITY_ENV_KEYS: () => ANTIGRAVITY_ENV_KEYS,
|
|
20959
|
+
ASK_DECISIONS_TOOL: () => ASK_DECISIONS_TOOL,
|
|
20960
|
+
ASK_ESCALATION_TOOL: () => ASK_ESCALATION_TOOL,
|
|
20961
|
+
ASK_RELAY_TOOL: () => ASK_RELAY_TOOL,
|
|
20962
|
+
ASK_ROUTE: () => ASK_ROUTE,
|
|
20902
20963
|
AUTONOMY_CLAUSE: () => AUTONOMY_CLAUSE,
|
|
20903
20964
|
CODEX_NATIVE_AGENTS_MIN_CLIENT: () => CODEX_NATIVE_AGENTS_MIN_CLIENT,
|
|
20904
20965
|
CODE_STYLE_CLAUSE: () => CODE_STYLE_CLAUSE,
|
|
@@ -20921,8 +20982,10 @@ __export(src_exports, {
|
|
|
20921
20982
|
REVERSE_PHASE_GUIDE: () => REVERSE_PHASE_GUIDE,
|
|
20922
20983
|
REVERSE_STANDARD: () => REVERSE_STANDARD,
|
|
20923
20984
|
SCAFFOLD_PHASE_GUIDE: () => SCAFFOLD_PHASE_GUIDE,
|
|
20985
|
+
SELF_REVIEW_CLAUSE: () => SELF_REVIEW_CLAUSE,
|
|
20924
20986
|
SUBAGENT_STATUSLINE_SCRIPT: () => SUBAGENT_STATUSLINE_SCRIPT,
|
|
20925
20987
|
SkillError: () => SkillError,
|
|
20988
|
+
TEXT_ASK_ROUTE: () => TEXT_ASK_ROUTE,
|
|
20926
20989
|
WORK_PHASES: () => WORK_PHASES,
|
|
20927
20990
|
agentContractOf: () => agentContractOf,
|
|
20928
20991
|
agentDefinitionHash: () => agentDefinitionHash,
|
|
@@ -21023,6 +21086,7 @@ __export(src_exports, {
|
|
|
21023
21086
|
startProjectPrompt: () => startProjectPrompt,
|
|
21024
21087
|
startPrompt: () => startPrompt,
|
|
21025
21088
|
startScaffoldPrompt: () => startScaffoldPrompt,
|
|
21089
|
+
textAsk: () => textAsk,
|
|
21026
21090
|
tomlBasicString: () => tomlBasicString,
|
|
21027
21091
|
validateAgentEvalManifest: () => validateAgentEvalManifest,
|
|
21028
21092
|
verifyScopeClause: () => verifyScopeClause,
|
|
@@ -21046,6 +21110,7 @@ var init_src2 = __esm({
|
|
|
21046
21110
|
init_codex_settings();
|
|
21047
21111
|
init_agent_cli();
|
|
21048
21112
|
init_custom_agents();
|
|
21113
|
+
init_ask_via();
|
|
21049
21114
|
init_agent_definition();
|
|
21050
21115
|
init_phase_agents();
|
|
21051
21116
|
init_agent_readonly();
|
|
@@ -21344,6 +21409,7 @@ function stageFor(phases2) {
|
|
|
21344
21409
|
if (WORK_PHASES.includes(p3.name) && p3.state === "active")
|
|
21345
21410
|
best = Math.max(best, STAGES.indexOf("executing"));
|
|
21346
21411
|
if (p3.state !== "done" && p3.state !== "skipped") continue;
|
|
21412
|
+
if (p3.state === "skipped" && UNSKIPPABLE_PHASES.has(p3.name)) continue;
|
|
21347
21413
|
const s2 = REACHED[p3.name];
|
|
21348
21414
|
if (s2) best = Math.max(best, STAGES.indexOf(s2));
|
|
21349
21415
|
}
|
|
@@ -21458,8 +21524,11 @@ var init_session_phases = __esm({
|
|
|
21458
21524
|
Audit: "objective",
|
|
21459
21525
|
Spec: "spec-ready",
|
|
21460
21526
|
Plan: "planned",
|
|
21527
|
+
// ADR-0230 · flow feature & qa ditutup fase Review resmi: Execute selesai baru `executing`, Review
|
|
21528
|
+
// yang mencapai `done`. `Review` unik lintas PIPELINES dan bukan fase kerja (`WORK_PHASES`).
|
|
21461
21529
|
Laporan: "done",
|
|
21462
|
-
Execute: "
|
|
21530
|
+
Execute: "executing",
|
|
21531
|
+
Review: "done",
|
|
21463
21532
|
// SPEC-407 · ADR-0089 · flow goal (Goal → Verifikasi): fase kerja mencapai `executing`, fase
|
|
21464
21533
|
// verifikasi yang mencapai `done`. Kedua nama unik lintas PIPELINES — peta ini berkunci nama.
|
|
21465
21534
|
Goal: "executing",
|
|
@@ -21489,7 +21558,7 @@ var init_session_phases = __esm({
|
|
|
21489
21558
|
if (PLAN_DIRS.some((d) => rel.startsWith(`${d}/`) && !rel.slice(d.length + 1).includes("/"))) return false;
|
|
21490
21559
|
return re.test(rel.slice(rel.lastIndexOf("/") + 1).toLowerCase());
|
|
21491
21560
|
});
|
|
21492
|
-
phasesComplete = (phases2) => phases2.length > 0 && phases2.every((p3) => p3.state === "done" || p3.state === "skipped");
|
|
21561
|
+
phasesComplete = (phases2) => phases2.length > 0 && phases2.every((p3) => p3.state === "done" || p3.state === "skipped" && !UNSKIPPABLE_PHASES.has(p3.name));
|
|
21493
21562
|
}
|
|
21494
21563
|
});
|
|
21495
21564
|
|
|
@@ -48973,8 +49042,13 @@ function createSession(projectId, cwd, opts2 = {}) {
|
|
|
48973
49042
|
}
|
|
48974
49043
|
const agentForDefs = opts2.agent ?? "claude";
|
|
48975
49044
|
const sessionEffort = agentForDefs === "codex" && opts2.model && opts2.effort ? coerceCodexEffort(opts2.model, opts2.effort) : opts2.effort;
|
|
48976
|
-
const
|
|
48977
|
-
const
|
|
49045
|
+
const askText = !opts2.command && agentForDefs === "claude" && opts2.askVia === "text";
|
|
49046
|
+
const asked = (s2) => askText ? textAsk(s2) : s2;
|
|
49047
|
+
const requestedPhaseDefs = opts2.command ? [] : (opts2.phaseAgents ?? []).map((d) => askText ? { ...d, instructions: textAsk(d.instructions) } : d);
|
|
49048
|
+
const bornPrompt = (orch) => {
|
|
49049
|
+
const p3 = orch ? opts2.prompt : opts2.legacyPrompt ?? opts2.prompt;
|
|
49050
|
+
return p3 === void 0 ? p3 : asked(p3);
|
|
49051
|
+
};
|
|
48978
49052
|
const selectionContext = {
|
|
48979
49053
|
projectId,
|
|
48980
49054
|
runtime: agentForDefs,
|
|
@@ -49060,7 +49134,7 @@ function createSession(projectId, cwd, opts2 = {}) {
|
|
|
49060
49134
|
return [error instanceof Error ? error.message : String(error)];
|
|
49061
49135
|
}
|
|
49062
49136
|
agentsFile = file;
|
|
49063
|
-
rosterBlock = agentDelegationClause(customDefs, "claude");
|
|
49137
|
+
rosterBlock = asked(agentDelegationClause(customDefs, "claude"));
|
|
49064
49138
|
liveAgentDefs = defs;
|
|
49065
49139
|
renderedDefs = defs;
|
|
49066
49140
|
return [];
|
|
@@ -49166,7 +49240,8 @@ function createSession(projectId, cwd, opts2 = {}) {
|
|
|
49166
49240
|
// SPEC-909 · ADR-0146 · sesi ber-`opts.command` tak pernah sampai ke sini (cabang shell
|
|
49167
49241
|
// mentah di atas), jadi hook event hanya pernah terpasang di sesi agen.
|
|
49168
49242
|
eventHook: true,
|
|
49169
|
-
subagentStatusLine: statusLineCommand
|
|
49243
|
+
subagentStatusLine: statusLineCommand,
|
|
49244
|
+
askText
|
|
49170
49245
|
}).map(sq).join(" ");
|
|
49171
49246
|
const agentsArg = agentsFile ? `--agents "$(cat ${sq(agentsFile)})"` : "";
|
|
49172
49247
|
const nativeAgentArgs = agent === "codex" ? codexAgentArgs.map(sq).join(" ") : "";
|
|
@@ -58206,6 +58281,22 @@ function statesFor(raw) {
|
|
|
58206
58281
|
if (key.startsWith(prefix)) orchestration[key] = state;
|
|
58207
58282
|
}
|
|
58208
58283
|
}
|
|
58284
|
+
const rawOrchestration = isRecord(object2.orchestration) ? object2.orchestration : {};
|
|
58285
|
+
for (const flow2 of ORCHESTRATION_FLOWS) {
|
|
58286
|
+
const rawFlow = isRecord(rawOrchestration[flow2]) ? rawOrchestration[flow2] : {};
|
|
58287
|
+
for (const runtime of ["claude", "codex"]) {
|
|
58288
|
+
const rawRuntime = isRecord(rawFlow[runtime]) ? rawFlow[runtime] : {};
|
|
58289
|
+
for (const phase of FLOW_PHASES[flow2]) {
|
|
58290
|
+
const rawCell = rawRuntime[phase];
|
|
58291
|
+
if (!isRecord(rawCell)) continue;
|
|
58292
|
+
for (const field of ["model", "effort"]) {
|
|
58293
|
+
const key = `${flow2}.${runtime}.${phase}.${field}`;
|
|
58294
|
+
if (!(key in marker.data.orchestration) && rawCell[field] !== void 0 && rawCell[field] !== null)
|
|
58295
|
+
orchestration[key] = "user";
|
|
58296
|
+
}
|
|
58297
|
+
}
|
|
58298
|
+
}
|
|
58299
|
+
}
|
|
58209
58300
|
const rawMarker = isRecord(object2.builtinRuntimeDefaults) ? object2.builtinRuntimeDefaults : {};
|
|
58210
58301
|
return {
|
|
58211
58302
|
claude: marker.data.claude,
|
|
@@ -59428,7 +59519,7 @@ var init_flow = __esm({
|
|
|
59428
59519
|
});
|
|
59429
59520
|
|
|
59430
59521
|
// src/services/lead/pane.ts
|
|
59431
|
-
function
|
|
59522
|
+
function readTurn(message) {
|
|
59432
59523
|
const body = message.trim();
|
|
59433
59524
|
if (!body) return { asking: false, reason: "giliran codex berakhir tanpa pesan" };
|
|
59434
59525
|
if (CODEX_FINISHED.some((re) => re.test(body)))
|
|
@@ -60163,7 +60254,7 @@ async function runChain(ask, s2, deps) {
|
|
|
60163
60254
|
const stop = (reason, failed = false) => ({ acted, done: false, failed, reason, at, flowId, step });
|
|
60164
60255
|
const asked = ask.source === "ask-tool";
|
|
60165
60256
|
if (ask.source === "turn-end") {
|
|
60166
|
-
const read2 =
|
|
60257
|
+
const read2 = readTurn(ask.message);
|
|
60167
60258
|
if (!read2.asking) return stop(read2.reason);
|
|
60168
60259
|
}
|
|
60169
60260
|
const steps = ask.source === "ask-tool" ? ask.questions : [null];
|
|
@@ -66234,6 +66325,28 @@ var init_project_checkout = __esm({
|
|
|
66234
66325
|
}
|
|
66235
66326
|
});
|
|
66236
66327
|
|
|
66328
|
+
// src/services/lead/ask-via.ts
|
|
66329
|
+
function leadDecides(cfg, optIn, projectId) {
|
|
66330
|
+
return optIn.includes(projectId) && leadActive(cfg, projectId);
|
|
66331
|
+
}
|
|
66332
|
+
async function askViaFor(projectId, agent, deps = prodDeps2) {
|
|
66333
|
+
if ((agent ?? "claude") !== "claude") return void 0;
|
|
66334
|
+
try {
|
|
66335
|
+
const [cfg, optIn] = await Promise.all([deps.cfg(), deps.optIn()]);
|
|
66336
|
+
return leadDecides(cfg, optIn, projectId) ? "text" : "tool";
|
|
66337
|
+
} catch {
|
|
66338
|
+
return "tool";
|
|
66339
|
+
}
|
|
66340
|
+
}
|
|
66341
|
+
var prodDeps2;
|
|
66342
|
+
var init_ask_via2 = __esm({
|
|
66343
|
+
"src/services/lead/ask-via.ts"() {
|
|
66344
|
+
"use strict";
|
|
66345
|
+
init_config5();
|
|
66346
|
+
prodDeps2 = { cfg: getLead, optIn: leadProjects };
|
|
66347
|
+
}
|
|
66348
|
+
});
|
|
66349
|
+
|
|
66237
66350
|
// src/services/session-launch.ts
|
|
66238
66351
|
function resumeState(repoDir, worktree, branchTo, headSha) {
|
|
66239
66352
|
if (realGit.worktreeAlive(worktree)) return { worktreeKept: true };
|
|
@@ -66351,7 +66464,7 @@ async function startSpecSession(spec, opts2) {
|
|
|
66351
66464
|
const resumeCtx = resume ? buildResumeCtx(repoDir, id2, opts2.flow, resume.worktreeKept) : void 0;
|
|
66352
66465
|
let plan = fullPlan;
|
|
66353
66466
|
if (fullPlan && isContinue && !isGoalFlow) {
|
|
66354
|
-
const phases2 = fullPlan.phases.filter((p3) => p3.phase === "Execute");
|
|
66467
|
+
const phases2 = fullPlan.phases.filter((p3) => p3.phase === "Execute" || p3.phase === REVIEWER_CELL);
|
|
66355
66468
|
plan = phases2.length ? { ...fullPlan, phases: phases2 } : null;
|
|
66356
66469
|
}
|
|
66357
66470
|
const buildPrompt = (p3) => {
|
|
@@ -66381,6 +66494,7 @@ async function startSpecSession(spec, opts2) {
|
|
|
66381
66494
|
...resumeCtx ? { resume: resumeCtx } : {}
|
|
66382
66495
|
}) : [];
|
|
66383
66496
|
const scopeEnv = { HANOMAN_BASE_SHA: baseSha, HANOMAN_VERIFY_SCOPE: verifyScope };
|
|
66497
|
+
const askVia = await askViaFor(spec.projectId, agent);
|
|
66384
66498
|
const s2 = createSession(spec.projectId, worktree, {
|
|
66385
66499
|
specId: spec.id,
|
|
66386
66500
|
flow: opts2.flow,
|
|
@@ -66388,13 +66502,14 @@ async function startSpecSession(spec, opts2) {
|
|
|
66388
66502
|
effort: effort2,
|
|
66389
66503
|
goal,
|
|
66390
66504
|
agent,
|
|
66505
|
+
askVia,
|
|
66391
66506
|
phaseFile: phaseFilePath(repoDir, id2),
|
|
66392
66507
|
decisionFile: decisionFilePath(repoDir, id2),
|
|
66393
66508
|
attachmentsDir: attachments.items.length ? attachments.dir : void 0,
|
|
66394
66509
|
prompt,
|
|
66395
66510
|
legacyPrompt,
|
|
66396
66511
|
phaseAgents,
|
|
66397
|
-
// S3 · SPEC-172 · berkas fase continue masih memuat `Execute done` run lama; fase yang DIKERJAKAN
|
|
66512
|
+
// S3 · SPEC-172 · berkas fase continue masih memuat `Execute done` (ADR-0230 · dan `Review done`) run lama; fase yang DIKERJAKAN
|
|
66398
66513
|
// ULANG sesi ini tak boleh dihitung `doneAtBirth`, supaya ⚠ bukti tetap bisa menyala.
|
|
66399
66514
|
...isContinue && plan ? { rerunPhases: plan.phases.map((p3) => p3.phase) } : {},
|
|
66400
66515
|
env: scopeEnv
|
|
@@ -66425,6 +66540,7 @@ var init_session_launch = __esm({
|
|
|
66425
66540
|
init_remote_session();
|
|
66426
66541
|
init_registry();
|
|
66427
66542
|
init_event_log();
|
|
66543
|
+
init_ask_via2();
|
|
66428
66544
|
init_pty();
|
|
66429
66545
|
LaunchError = class extends Error {
|
|
66430
66546
|
// SPEC-447 · `blockers` hanya terisi untuk kind "blocked"; route memetakannya ke body 409.
|
|
@@ -78180,6 +78296,8 @@ init_src2();
|
|
|
78180
78296
|
init_session_phases();
|
|
78181
78297
|
init_spec_review2();
|
|
78182
78298
|
import { existsSync as existsSync18 } from "node:fs";
|
|
78299
|
+
import { execFileSync as execFileSync9 } from "node:child_process";
|
|
78300
|
+
import { randomUUID as randomUUID13 } from "node:crypto";
|
|
78183
78301
|
init_integrate();
|
|
78184
78302
|
init_settings3();
|
|
78185
78303
|
init_codex_trust();
|
|
@@ -79257,6 +79375,7 @@ async function refuseSelfDecision(input) {
|
|
|
79257
79375
|
// src/routes/terminal.ts
|
|
79258
79376
|
init_tui_dialog();
|
|
79259
79377
|
init_runtime();
|
|
79378
|
+
init_ask_via2();
|
|
79260
79379
|
var ATTACHMENT_MIME = /* @__PURE__ */ new Set(["image/png", "image/jpeg", "image/webp"]);
|
|
79261
79380
|
var DIALOG_ANSWER_ERROR = {
|
|
79262
79381
|
stale: "layar dialog sudah berubah \u2014 muat ulang pertanyaannya",
|
|
@@ -79378,12 +79497,14 @@ async function terminal_default(app3, opts2) {
|
|
|
79378
79497
|
const brief = { id: project.id, name: project.name, desc: project.desc, stack: project.stack };
|
|
79379
79498
|
const plan = sessionPhasePlan(await getSetting(), "reverse", agent2, { model: model2, effort: effort3 });
|
|
79380
79499
|
const legacyPrompt = startProjectPrompt("reverse", brief, "reverse-docs") + resumeNote(reused);
|
|
79500
|
+
const askVia = await askViaFor(project.id, agent2);
|
|
79381
79501
|
const s3 = createSession(project.id, wt, {
|
|
79382
79502
|
id: id2,
|
|
79383
79503
|
flow: "reverse",
|
|
79384
79504
|
model: model2,
|
|
79385
79505
|
effort: effort3,
|
|
79386
79506
|
agent: agent2,
|
|
79507
|
+
askVia,
|
|
79387
79508
|
phaseFile: phaseFilePath(repoDir, id2),
|
|
79388
79509
|
decisionFile: decisionFilePath(repoDir, id2),
|
|
79389
79510
|
prompt: plan ? startProjectPrompt("reverse", brief, "reverse-docs", plan) + resumeNote(reused) : legacyPrompt,
|
|
@@ -79416,12 +79537,14 @@ async function terminal_default(app3, opts2) {
|
|
|
79416
79537
|
const brief = { id: project.id, name: project.name, desc: project.desc, stack: project.stack };
|
|
79417
79538
|
const plan = sessionPhasePlan(await getSetting(), "scaffold", agent2, { model: model2, effort: effort3 });
|
|
79418
79539
|
const legacyPrompt = startScaffoldPrompt(brief, "scaffold-docs") + resumeNote(reused);
|
|
79540
|
+
const askVia = await askViaFor(project.id, agent2);
|
|
79419
79541
|
const s3 = createSession(project.id, wt, {
|
|
79420
79542
|
id: id2,
|
|
79421
79543
|
flow: "scaffold",
|
|
79422
79544
|
model: model2,
|
|
79423
79545
|
effort: effort3,
|
|
79424
79546
|
agent: agent2,
|
|
79547
|
+
askVia,
|
|
79425
79548
|
phaseFile: phaseFilePath(repoDir, id2),
|
|
79426
79549
|
decisionFile: decisionFilePath(repoDir, id2),
|
|
79427
79550
|
prompt: plan ? startScaffoldPrompt(brief, "scaffold-docs", plan) + resumeNote(reused) : legacyPrompt,
|
|
@@ -79458,6 +79581,7 @@ async function terminal_default(app3, opts2) {
|
|
|
79458
79581
|
const audit = auditDoc ? { id: fromAudit, path: auditDoc.path, content: auditDoc.content } : void 0;
|
|
79459
79582
|
const plan = sessionPhasePlan(await getSetting(), "prd", agent2, { model: model2, effort: effort3 });
|
|
79460
79583
|
const legacyPrompt = startPrdPrompt(project_, brief, `prd/${slug2}`, audit) + resumeNote(reused);
|
|
79584
|
+
const askVia = await askViaFor(project.id, agent2);
|
|
79461
79585
|
const s3 = createSession(project.id, wt, {
|
|
79462
79586
|
id: id2,
|
|
79463
79587
|
flow: "prd",
|
|
@@ -79465,6 +79589,7 @@ async function terminal_default(app3, opts2) {
|
|
|
79465
79589
|
model: model2,
|
|
79466
79590
|
effort: effort3,
|
|
79467
79591
|
agent: agent2,
|
|
79592
|
+
askVia,
|
|
79468
79593
|
phaseFile: phaseFilePath(repoDir, id2),
|
|
79469
79594
|
decisionFile: decisionFilePath(repoDir, id2),
|
|
79470
79595
|
prompt: plan ? startPrdPrompt(project_, brief, `prd/${slug2}`, audit, plan) + resumeNote(reused) : legacyPrompt,
|
|
@@ -79506,6 +79631,7 @@ async function terminal_default(app3, opts2) {
|
|
|
79506
79631
|
const prd = { title, path: prdPath, content };
|
|
79507
79632
|
const plan = sessionPhasePlan(await getSetting(), "breakdown", agent2, { model: model2, effort: effort3 });
|
|
79508
79633
|
const legacyPrompt = startBreakdownPrompt(project_, prd, `breakdown/${slug2}`) + resumeNote(reused);
|
|
79634
|
+
const askVia = await askViaFor(project.id, agent2);
|
|
79509
79635
|
const s3 = createSession(project.id, wt, {
|
|
79510
79636
|
id: id2,
|
|
79511
79637
|
flow: "breakdown",
|
|
@@ -79513,6 +79639,7 @@ async function terminal_default(app3, opts2) {
|
|
|
79513
79639
|
model: model2,
|
|
79514
79640
|
effort: effort3,
|
|
79515
79641
|
agent: agent2,
|
|
79642
|
+
askVia,
|
|
79516
79643
|
phaseFile: phaseFilePath(repoDir, id2),
|
|
79517
79644
|
decisionFile: decisionFilePath(repoDir, id2),
|
|
79518
79645
|
prompt: plan ? startBreakdownPrompt(project_, prd, `breakdown/${slug2}`, plan) + resumeNote(reused) : legacyPrompt,
|
|
@@ -79531,6 +79658,26 @@ async function terminal_default(app3, opts2) {
|
|
|
79531
79658
|
}
|
|
79532
79659
|
const { agent, model, effort: effort2 } = await terminalAgentDefaults(parsed.data);
|
|
79533
79660
|
if (agent === "codex") ensureCodexTrust(repoDir);
|
|
79661
|
+
if (parsed.data.worktree) {
|
|
79662
|
+
const id2 = `term-${randomUUID13().slice(0, 8)}`;
|
|
79663
|
+
const branch = `term/${id2.slice("term-".length)}`;
|
|
79664
|
+
const from = parsed.data.branchFrom ?? "HEAD";
|
|
79665
|
+
const result = await withSessionAdmission({ id: id2, exempt: false, force: parsed.data.force }, async () => {
|
|
79666
|
+
const wt = `${repoDir}/.worktrees/${id2}`;
|
|
79667
|
+
try {
|
|
79668
|
+
realGit.addWorktree(repoDir, wt, from);
|
|
79669
|
+
execFileSync9("git", ["switch", "-q", "-c", branch], { cwd: wt, stdio: "pipe" });
|
|
79670
|
+
} catch (e) {
|
|
79671
|
+
if (ownsWorktree(repoDir, wt)) realGit.removeWorktree(repoDir, wt);
|
|
79672
|
+
return { code: 422, body: { error: `gagal membuat worktree dari "${from}": ${e.message}` } };
|
|
79673
|
+
}
|
|
79674
|
+
const s3 = createSession(project.id, wt, { id: id2, agent, model, effort: effort2, branch });
|
|
79675
|
+
return { code: 201, body: { id: s3.id } };
|
|
79676
|
+
}, (pane) => ({ code: 201, body: { id: pane.id } }));
|
|
79677
|
+
return reply.code(result.code).send(result.body);
|
|
79678
|
+
}
|
|
79679
|
+
if (parsed.data.branchFrom)
|
|
79680
|
+
return reply.code(400).send({ error: "branchFrom hanya berlaku bersama worktree:true" });
|
|
79534
79681
|
const s2 = await createOperatorSession(
|
|
79535
79682
|
project.id,
|
|
79536
79683
|
repoDir,
|
|
@@ -80570,7 +80717,7 @@ async function listVpsWithScore() {
|
|
|
80570
80717
|
// src/services/vps-key.ts
|
|
80571
80718
|
init_src2();
|
|
80572
80719
|
init_config2();
|
|
80573
|
-
import { execFileSync as
|
|
80720
|
+
import { execFileSync as execFileSync10 } from "node:child_process";
|
|
80574
80721
|
import { chmodSync as chmodSync9, copyFileSync, existsSync as existsSync21, mkdirSync as mkdirSync18, readFileSync as readFileSync24, unlinkSync as unlinkSync5 } from "node:fs";
|
|
80575
80722
|
import { homedir as homedir11 } from "node:os";
|
|
80576
80723
|
import { join as join44 } from "node:path";
|
|
@@ -80596,7 +80743,7 @@ function ensureHanomanKey() {
|
|
|
80596
80743
|
if (!existsSync21(privPath)) adoptLegacyKey(dir2);
|
|
80597
80744
|
if (!existsSync21(privPath)) {
|
|
80598
80745
|
mkdirSync18(dir2, { recursive: true, mode: 448 });
|
|
80599
|
-
|
|
80746
|
+
execFileSync10(
|
|
80600
80747
|
"ssh-keygen",
|
|
80601
80748
|
["-t", "ed25519", "-N", "", "-C", "hanoman", "-f", privPath],
|
|
80602
80749
|
{ stdio: ["ignore", "ignore", "pipe"] }
|
|
@@ -80998,7 +81145,7 @@ async function antigravity(app3) {
|
|
|
80998
81145
|
// src/services/model-catalog.ts
|
|
80999
81146
|
init_src2();
|
|
81000
81147
|
init_src();
|
|
81001
|
-
import { randomUUID as
|
|
81148
|
+
import { randomUUID as randomUUID14 } from "node:crypto";
|
|
81002
81149
|
import { readFile as readFile8, writeFile as writeFile6, rename as rename5, mkdir as mkdir9, rm as rm9 } from "node:fs/promises";
|
|
81003
81150
|
import { dirname as dirname18, join as join46 } from "node:path";
|
|
81004
81151
|
|
|
@@ -81309,7 +81456,7 @@ function createModelCatalogService(deps) {
|
|
|
81309
81456
|
async function writeModelCatalogCache(file, catalog, current = () => true) {
|
|
81310
81457
|
const sanitized = parseCachedCatalog(catalog);
|
|
81311
81458
|
await mkdir9(dirname18(file), { recursive: true });
|
|
81312
|
-
const temp = `${file}.${process.pid}.${
|
|
81459
|
+
const temp = `${file}.${process.pid}.${randomUUID14()}.tmp`;
|
|
81313
81460
|
try {
|
|
81314
81461
|
await writeFile6(temp, JSON.stringify(sanitized), { mode: 384, flag: "wx" });
|
|
81315
81462
|
if (current()) await rename5(temp, file);
|
|
@@ -87000,8 +87147,9 @@ init_settings3();
|
|
|
87000
87147
|
init_codex_trust();
|
|
87001
87148
|
init_qa_attachment_transfer();
|
|
87002
87149
|
init_uploads();
|
|
87150
|
+
init_ask_via2();
|
|
87003
87151
|
import { createHash as createHash21 } from "node:crypto";
|
|
87004
|
-
import { execFileSync as
|
|
87152
|
+
import { execFileSync as execFileSync11 } from "node:child_process";
|
|
87005
87153
|
import { join as join50 } from "node:path";
|
|
87006
87154
|
var QaSessionError = class extends Error {
|
|
87007
87155
|
constructor(code, message, needsBind = false) {
|
|
@@ -87036,7 +87184,7 @@ async function startQaFindingSession(d, fid) {
|
|
|
87036
87184
|
if (!reused) {
|
|
87037
87185
|
const base3 = realGit.revParse(repoDir, branch) ? branch : "HEAD";
|
|
87038
87186
|
realGit.addWorktree(repoDir, wt, base3);
|
|
87039
|
-
|
|
87187
|
+
execFileSync11("git", ["checkout", "-B", branch], { cwd: wt, encoding: "utf8" });
|
|
87040
87188
|
}
|
|
87041
87189
|
} catch (e) {
|
|
87042
87190
|
throw new QaSessionError(422, `Gagal membuat worktree QA: ${e.message}`);
|
|
@@ -87072,6 +87220,7 @@ ${files2.join("\n")}` : "",
|
|
|
87072
87220
|
CODE_STYLE_CLAUSE,
|
|
87073
87221
|
reused ? RESUMED_WORKTREE_NOTE : ""
|
|
87074
87222
|
].filter(Boolean).join("\n\n");
|
|
87223
|
+
const askVia = await askViaFor(d.projectId, agent);
|
|
87075
87224
|
const s2 = createSession(d.projectId, wt, {
|
|
87076
87225
|
id: id2,
|
|
87077
87226
|
branch,
|
|
@@ -87079,6 +87228,7 @@ ${files2.join("\n")}` : "",
|
|
|
87079
87228
|
model,
|
|
87080
87229
|
effort: effort2,
|
|
87081
87230
|
prompt,
|
|
87231
|
+
askVia,
|
|
87082
87232
|
env: { HANOMAN_BASE_SHA: baseSha, HANOMAN_VERIFY_SCOPE: verifyScope },
|
|
87083
87233
|
attachmentsDir: files2.length ? sessionUploadDir(id2) : void 0
|
|
87084
87234
|
});
|
|
@@ -89640,7 +89790,7 @@ init_event_log();
|
|
|
89640
89790
|
|
|
89641
89791
|
// src/services/remote-access-request.ts
|
|
89642
89792
|
init_src();
|
|
89643
|
-
import { randomUUID as
|
|
89793
|
+
import { randomUUID as randomUUID15 } from "node:crypto";
|
|
89644
89794
|
var REQUEST_TIER_LABEL = { lihat: "Lihat", kerja: "Kerja", tulis: "Tulis" };
|
|
89645
89795
|
var entries3 = [];
|
|
89646
89796
|
var accepted = [];
|
|
@@ -89664,7 +89814,7 @@ function createAccessRequest(input, now = Date.now()) {
|
|
|
89664
89814
|
return { ok: false, reason: "rate-limited", retryAfterMs: accepted[0] + ACCESS_REQUEST_WINDOW_MS - now };
|
|
89665
89815
|
accepted.push(now);
|
|
89666
89816
|
const entry2 = {
|
|
89667
|
-
id:
|
|
89817
|
+
id: randomUUID15(),
|
|
89668
89818
|
tier: input.tier,
|
|
89669
89819
|
state: "pending",
|
|
89670
89820
|
requestedAt: now,
|
|
@@ -90581,6 +90731,7 @@ init_settings3();
|
|
|
90581
90731
|
init_codex_trust();
|
|
90582
90732
|
init_pty();
|
|
90583
90733
|
init_session_launch_gate();
|
|
90734
|
+
init_ask_via2();
|
|
90584
90735
|
var cronSessionId = (cronId) => `cron-${cronId.toLowerCase().replace(/[^a-z0-9_-]/g, "_")}`;
|
|
90585
90736
|
async function liveCronSession(cronId) {
|
|
90586
90737
|
const s2 = await getSessionAsync(cronSessionId(cronId));
|
|
@@ -90601,11 +90752,13 @@ async function startCronSession(cron) {
|
|
|
90601
90752
|
if (agent === "codex") ensureCodexTrust(repoDir);
|
|
90602
90753
|
const wt = `${repoDir}/.worktrees/${id2}`;
|
|
90603
90754
|
if (!realGit.worktreeAlive(wt)) realGit.addWorktree(repoDir, wt, "HEAD");
|
|
90755
|
+
const askVia = await askViaFor(cron.projectId, agent);
|
|
90604
90756
|
const s2 = createSession(cron.projectId, wt, {
|
|
90605
90757
|
id: id2,
|
|
90606
90758
|
agent,
|
|
90607
90759
|
model,
|
|
90608
90760
|
effort: effort2,
|
|
90761
|
+
askVia,
|
|
90609
90762
|
prompt: cronPrompt(
|
|
90610
90763
|
{ id: project.id, name: project.name, desc: project.desc, stack: project.stack },
|
|
90611
90764
|
{ name: cron.name, prompt: cron.prompt }
|
|
@@ -90726,7 +90879,7 @@ async function tick4(now, deps, end2 = prodEnd) {
|
|
|
90726
90879
|
console.error("scheduler drain:", e);
|
|
90727
90880
|
}
|
|
90728
90881
|
}
|
|
90729
|
-
var
|
|
90882
|
+
var prodDeps3 = {
|
|
90730
90883
|
liveCount: async () => (await listSessionsAsync()).filter((s2) => !s2.exited).length,
|
|
90731
90884
|
isLive: async (specId) => {
|
|
90732
90885
|
const s2 = await getSessionAsync(sessionIdForSpec(specId));
|
|
@@ -90760,7 +90913,7 @@ var prodDeps2 = {
|
|
|
90760
90913
|
};
|
|
90761
90914
|
var TICK_MS3 = 1e4;
|
|
90762
90915
|
var timer7;
|
|
90763
|
-
function startScheduler(deps =
|
|
90916
|
+
function startScheduler(deps = prodDeps3) {
|
|
90764
90917
|
if (timer7) return;
|
|
90765
90918
|
timer7 = setInterval(() => void tick4(Date.now(), deps), TICK_MS3);
|
|
90766
90919
|
timer7.unref();
|
|
@@ -90797,7 +90950,7 @@ init_db();
|
|
|
90797
90950
|
init_session_launch();
|
|
90798
90951
|
init_session_admission2();
|
|
90799
90952
|
init_notifications2();
|
|
90800
|
-
var
|
|
90953
|
+
var prodDeps4 = {
|
|
90801
90954
|
// ADR-0170 · mengamandemen ADR-0169 keputusan #4: `bypassCapacity` DICABUT. Auto-resume kini
|
|
90802
90955
|
// tunduk cap/beban host seperti "Lanjutkan" manual — mesin 8 GB operator sudah dua kali kernel
|
|
90803
90956
|
// panic akibat batch sesi paralel tepat SAAT boot (memori mac-mini-8gb-panic-agen-paralel),
|
|
@@ -90806,7 +90959,7 @@ var prodDeps3 = {
|
|
|
90806
90959
|
recordFail: recordFailure,
|
|
90807
90960
|
recordDeferred: recordFailure
|
|
90808
90961
|
};
|
|
90809
|
-
async function resumeReconciledSessions(cutoff, deps =
|
|
90962
|
+
async function resumeReconciledSessions(cutoff, deps = prodDeps4) {
|
|
90810
90963
|
const report = { resumed: [], failed: [], deferred: [] };
|
|
90811
90964
|
const specIds = await reconciledSpecIdsSince(cutoff);
|
|
90812
90965
|
if (!specIds.length) return report;
|
|
@@ -90849,7 +91002,7 @@ init_tap();
|
|
|
90849
91002
|
init_src();
|
|
90850
91003
|
init_db();
|
|
90851
91004
|
init_actor();
|
|
90852
|
-
import { randomUUID as
|
|
91005
|
+
import { randomUUID as randomUUID16 } from "node:crypto";
|
|
90853
91006
|
function skipped(def2, row) {
|
|
90854
91007
|
if (!def2.skipWhen || !row) return false;
|
|
90855
91008
|
return row[def2.skipWhen.field] === def2.skipWhen.equals;
|
|
@@ -90915,7 +91068,7 @@ async function emitWebhook(i) {
|
|
|
90915
91068
|
const targets = matchingEndpoints(type, projectId);
|
|
90916
91069
|
if (!targets.length) return;
|
|
90917
91070
|
const name2 = projectId ? (await prisma.project.findUnique({ where: { id: projectId }, select: { name: true } }))?.name ?? null : null;
|
|
90918
|
-
const env = buildEnvelope(i, name2, (/* @__PURE__ */ new Date()).toISOString(), `evt_${
|
|
91071
|
+
const env = buildEnvelope(i, name2, (/* @__PURE__ */ new Date()).toISOString(), `evt_${randomUUID16().replace(/-/g, "")}`);
|
|
90919
91072
|
if (!env) return;
|
|
90920
91073
|
await enqueueEnvelope(env, targets);
|
|
90921
91074
|
} catch (e) {
|