hanoman 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -3
- package/dist/build-info.json +3 -3
- package/dist/cli.js +1275 -1105
- package/dist/server.js +195 -65
- package/package.json +8 -9
- package/web/assets/{index-a6SFYnK5.js → index-CeJYUp36.js} +1551 -1551
- package/web/index.html +1 -1
package/dist/server.js
CHANGED
|
@@ -4151,7 +4151,7 @@ var init_enums = __esm({
|
|
|
4151
4151
|
"use strict";
|
|
4152
4152
|
init_zod();
|
|
4153
4153
|
zStage = external_exports.enum(["brainstorming", "objective", "spec-ready", "planned", "executing", "done"]);
|
|
4154
|
-
zSpecSource = external_exports.enum(["brief", "qa", "audit", "cross-audit", "help"]);
|
|
4154
|
+
zSpecSource = external_exports.enum(["brief", "qa", "audit", "cross-audit", "help", "goal"]);
|
|
4155
4155
|
zDocStatus = external_exports.enum(["ok", "drift", "broken"]);
|
|
4156
4156
|
zPriority = external_exports.enum(["tinggi", "sedang", "rendah"]);
|
|
4157
4157
|
zProjectKind = external_exports.enum(["from-scratch", "existing"]);
|
|
@@ -4184,7 +4184,7 @@ function cmpVersion(a, b) {
|
|
|
4184
4184
|
}
|
|
4185
4185
|
return 0;
|
|
4186
4186
|
}
|
|
4187
|
-
var zProject, zBriefPayload, zQaPayload, zSpec, NOTIFY_SOUNDS, E_5_6, E_LUNA, E_BASE, CODEX_MODELS, RETIRED_CODEX_MODELS, zCodex, CODEX_DEFAULTS, zSourceCommon, zScheduler, SCHEDULER_DEFAULTS, zGoal, GOAL_DEFAULTS, zConflict, CONFLICT_DEFAULTS, zSetting, zNotification, zDocFile, zDeviceTokenView;
|
|
4187
|
+
var zProject, zBriefPayload, zQaPayload, zGoalPayload, zSpec, NOTIFY_SOUNDS, E_5_6, E_LUNA, E_BASE, CODEX_MODELS, RETIRED_CODEX_MODELS, zCodex, CODEX_DEFAULTS, zSourceCommon, zScheduler, SCHEDULER_DEFAULTS, zGoal, GOAL_DEFAULTS, zConflict, CONFLICT_DEFAULTS, zSetting, zNotification, zDocFile, zDeviceTokenView;
|
|
4188
4188
|
var init_entities = __esm({
|
|
4189
4189
|
"../shared/src/entities.ts"() {
|
|
4190
4190
|
"use strict";
|
|
@@ -4223,6 +4223,12 @@ var init_entities = __esm({
|
|
|
4223
4223
|
// SPEC-244 · qa dinaikkan dari audit → sinyal skip fase Audit (ADR-0059)
|
|
4224
4224
|
fromErrorGroup: external_exports.string().optional()
|
|
4225
4225
|
});
|
|
4226
|
+
zGoalPayload = external_exports.object({
|
|
4227
|
+
goal: external_exports.string(),
|
|
4228
|
+
done: external_exports.string(),
|
|
4229
|
+
constraints: external_exports.string(),
|
|
4230
|
+
priority: zPriority
|
|
4231
|
+
});
|
|
4226
4232
|
zSpec = external_exports.object({
|
|
4227
4233
|
id: external_exports.string(),
|
|
4228
4234
|
projectId: external_exports.string(),
|
|
@@ -4232,7 +4238,8 @@ var init_entities = __esm({
|
|
|
4232
4238
|
priority: zPriority,
|
|
4233
4239
|
author: external_exports.string(),
|
|
4234
4240
|
objective: external_exports.string(),
|
|
4235
|
-
payload: external_exports.union([zBriefPayload, zQaPayload]).nullable(),
|
|
4241
|
+
payload: external_exports.union([zBriefPayload, zQaPayload, zGoalPayload]).nullable(),
|
|
4242
|
+
// SPEC-407 · +goal
|
|
4236
4243
|
branchFrom: external_exports.string().nullable(),
|
|
4237
4244
|
// SPEC-143 · null = default project (main)
|
|
4238
4245
|
baseSha: external_exports.string().nullable()
|
|
@@ -4446,9 +4453,9 @@ var init_agent = __esm({
|
|
|
4446
4453
|
|
|
4447
4454
|
// ../shared/src/dto.ts
|
|
4448
4455
|
function flowForSource(source) {
|
|
4449
|
-
return source === "qa" ? "qa" : source === "audit" ? "audit" : source === "cross-audit" ? "cross-audit" : "feature";
|
|
4456
|
+
return source === "qa" ? "qa" : source === "audit" ? "audit" : source === "cross-audit" ? "cross-audit" : source === "goal" ? "goal" : "feature";
|
|
4450
4457
|
}
|
|
4451
|
-
var zIssueDeviceToken, zSessionResult, zSessionHistory, zCreateProject, zProjectId, zRenameProject, zCreateLink, zUpdateProject, zCreateSpec, zPatchSpec, zIntegrate, zSessionSummary, zProjectView, zSchedulerQueueItem, zSchedulerSourceView, zSchedulerSessionView, zSchedulerState, zFlow, zPrdBrief, zPrdDoc, zBreakdownItem, zBreakdownDoc, zBatchCreateSpec, zEscalationTarget, zEscalationPrefill, zAuditEscalation, zAuditEscalationView, zTerminalSession, zDocFileContent, zDocIndexCat, zDocIndex, HOST_RE, USER_RE, zCreateVps, zPatchVps, zLogin, zSignup, zChangePassword, zVpsCheck, zMarkNa, zMarkNaBulk, zAttest, zRemediate, zStackFrame, zSymbolicatedFrame, zSourceMapUpload, zIngestPayload, zErrorGroupView, zErrorEventView, zErrorGroupDetail, zIngestKeyView, zTicketView, zTicketAttachmentView, zTicketDetail, zTicketEditInput, zHelpInfo, zPublicTicketStatus;
|
|
4458
|
+
var zIssueDeviceToken, zSessionResult, zSessionHistory, zCreateProject, zProjectId, zRenameProject, zCreateLink, zUpdateProject, zCreateSpec, zPatchSpec, zIntegrate, zSessionSummary, zProjectView, zSchedulerQueueItem, zSchedulerSourceView, zSchedulerSessionView, zSchedulerState, zFlow, zPrdBrief, zPrdDoc, zBreakdownItem, zBreakdownDoc, zBatchCreateSpec, zEscalationTarget, zEscalationPrefill, zAuditEscalation, zAuditEscalationView, zTerminalSession, zDocFileContent, zDocIndexCat, zDocIndex, HOST_RE, USER_RE, zCreateVps, zPatchVps, zLogin, zSignup, zChangePassword, zVpsCheck, zMarkNa, zMarkNaBulk, zAttest, zRemediate, UPDATE_RESTART_EXIT, zUpdateApplyBody, zStackFrame, zSymbolicatedFrame, zSourceMapUpload, zIngestPayload, zErrorGroupView, zErrorEventView, zErrorGroupDetail, zIngestKeyView, zTicketView, zTicketAttachmentView, zTicketDetail, zTicketEditInput, zHelpInfo, zPublicTicketStatus;
|
|
4452
4459
|
var init_dto = __esm({
|
|
4453
4460
|
"../shared/src/dto.ts"() {
|
|
4454
4461
|
"use strict";
|
|
@@ -4517,11 +4524,12 @@ var init_dto = __esm({
|
|
|
4517
4524
|
source: zSpecSource,
|
|
4518
4525
|
title: external_exports.string().min(1),
|
|
4519
4526
|
priority: zPriority,
|
|
4520
|
-
payload: external_exports.union([zBriefPayload, zQaPayload]),
|
|
4527
|
+
payload: external_exports.union([zBriefPayload, zQaPayload, zGoalPayload]),
|
|
4521
4528
|
branchFrom: external_exports.string().min(1).optional()
|
|
4522
4529
|
}).superRefine((o, ctx) => {
|
|
4523
|
-
const
|
|
4524
|
-
|
|
4530
|
+
const shape = "severity" in o.payload ? "qa" : "goal" in o.payload ? "goal" : "brief";
|
|
4531
|
+
const want = o.source === "qa" ? "qa" : o.source === "goal" ? "goal" : "brief";
|
|
4532
|
+
if (shape !== want)
|
|
4525
4533
|
ctx.addIssue({ code: external_exports.ZodIssueCode.custom, path: ["payload"], message: "bentuk payload tak cocok dengan source" });
|
|
4526
4534
|
});
|
|
4527
4535
|
zPatchSpec = external_exports.object({
|
|
@@ -4531,7 +4539,8 @@ var init_dto = __esm({
|
|
|
4531
4539
|
// SPEC-186 · edit konten selagi item belum dimulai. Ditolak server bila sudah mulai.
|
|
4532
4540
|
title: external_exports.string().min(1).optional(),
|
|
4533
4541
|
priority: zPriority.optional(),
|
|
4534
|
-
payload: external_exports.union([zBriefPayload, zQaPayload]).optional()
|
|
4542
|
+
payload: external_exports.union([zBriefPayload, zQaPayload, zGoalPayload]).optional()
|
|
4543
|
+
// SPEC-407 · +goal
|
|
4535
4544
|
});
|
|
4536
4545
|
zIntegrate = external_exports.object({
|
|
4537
4546
|
op: external_exports.enum(["merge", "rebase"]),
|
|
@@ -4596,7 +4605,7 @@ var init_dto = __esm({
|
|
|
4596
4605
|
queue: external_exports.array(zSchedulerQueueItem),
|
|
4597
4606
|
sessions: external_exports.array(zSchedulerSessionView)
|
|
4598
4607
|
});
|
|
4599
|
-
zFlow = external_exports.enum(["feature", "qa", "scaffold", "reverse", "prd", "audit", "breakdown", "cross-audit"]);
|
|
4608
|
+
zFlow = external_exports.enum(["feature", "qa", "scaffold", "reverse", "prd", "audit", "breakdown", "cross-audit", "goal"]);
|
|
4600
4609
|
zPrdBrief = external_exports.object({
|
|
4601
4610
|
title: external_exports.string().min(1),
|
|
4602
4611
|
context: external_exports.string(),
|
|
@@ -4742,6 +4751,8 @@ var init_dto = __esm({
|
|
|
4742
4751
|
});
|
|
4743
4752
|
zAttest = external_exports.object({ note: external_exports.string().max(500).optional() });
|
|
4744
4753
|
zRemediate = external_exports.object({ items: external_exports.array(external_exports.string()).min(1).max(64) });
|
|
4754
|
+
UPDATE_RESTART_EXIT = 75;
|
|
4755
|
+
zUpdateApplyBody = external_exports.object({ confirm: external_exports.boolean().optional() });
|
|
4745
4756
|
zStackFrame = external_exports.object({
|
|
4746
4757
|
function: external_exports.string().max(500).optional(),
|
|
4747
4758
|
filename: external_exports.string().max(2e3).optional(),
|
|
@@ -5520,6 +5531,22 @@ var init_verify_scope = __esm({
|
|
|
5520
5531
|
}
|
|
5521
5532
|
});
|
|
5522
5533
|
|
|
5534
|
+
// ../runner/src/goal-spec.ts
|
|
5535
|
+
function readGoalPayload(payload) {
|
|
5536
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload)) return null;
|
|
5537
|
+
const p = payload;
|
|
5538
|
+
const goal = str(p.goal);
|
|
5539
|
+
if (!goal) return null;
|
|
5540
|
+
return { goal, done: str(p.done), constraints: str(p.constraints) };
|
|
5541
|
+
}
|
|
5542
|
+
var str;
|
|
5543
|
+
var init_goal_spec = __esm({
|
|
5544
|
+
"../runner/src/goal-spec.ts"() {
|
|
5545
|
+
"use strict";
|
|
5546
|
+
str = (v) => typeof v === "string" ? v.trim() : "";
|
|
5547
|
+
}
|
|
5548
|
+
});
|
|
5549
|
+
|
|
5523
5550
|
// ../runner/src/prompt.ts
|
|
5524
5551
|
function startPrompt(flow, spec, branchTo, autonomy, verifyScope) {
|
|
5525
5552
|
const detail = spec.payload ? `
|
|
@@ -5560,7 +5587,7 @@ Detail: ${JSON.stringify(spec.payload)}` : "";
|
|
|
5560
5587
|
const auditDecided = resume.recorded.some((line) => line.startsWith("Audit "));
|
|
5561
5588
|
return [
|
|
5562
5589
|
`hanoman ${flow} \u2014 MELANJUTKAN sesi backlog yang sudah berjalan. Ikuti internal/docs sebagai Source of Truth; perbarui docs yang tersentuh dan link-nya di index, dalam commit yang sama.`,
|
|
5563
|
-
resumeClause(resume, branchTo),
|
|
5590
|
+
resumeClause(resume, branchTo, PIPELINES[flow].includes("Plan")),
|
|
5564
5591
|
phaseInstruction(PIPELINES[flow]),
|
|
5565
5592
|
auditDecided ? "" : auditDecisionInstruction(flow),
|
|
5566
5593
|
autonomyClause(autonomy),
|
|
@@ -5572,6 +5599,27 @@ Judul: ${spec.title}
|
|
|
5572
5599
|
Objective: ${spec.objective}${detail}`
|
|
5573
5600
|
].filter(Boolean).join("\n\n");
|
|
5574
5601
|
}
|
|
5602
|
+
function startGoalPrompt(spec, branchTo, opts = {}) {
|
|
5603
|
+
const g = readGoalPayload(spec.payload);
|
|
5604
|
+
const detail = [
|
|
5605
|
+
`Goal: ${g?.goal ?? spec.objective}`,
|
|
5606
|
+
g?.done ? `Selesai bila: ${g.done}` : "",
|
|
5607
|
+
g?.constraints ? `Batasan: ${g.constraints}` : ""
|
|
5608
|
+
].filter(Boolean).join("\n");
|
|
5609
|
+
return [
|
|
5610
|
+
"hanoman goal \u2014 sesi ini mengejar SATU goal sampai tercapai. TIDAK ada fase Brainstorm, Objective, Spec, maupun Plan: jangan menulis design doc, jangan menulis plan berkotak, jangan memecah pekerjaan ini jadi backlog baru. Langsung kerjakan goal-nya. Tetap ikuti internal/docs sebagai Source of Truth; perbarui docs yang tersentuh dan link-nya di index, dalam commit yang sama.",
|
|
5611
|
+
opts.resume ? resumeClause(opts.resume, branchTo, false) : "",
|
|
5612
|
+
detail,
|
|
5613
|
+
phaseInstruction(PIPELINES.goal),
|
|
5614
|
+
"Fase Verifikasi bukan formalitas: jalankan perintah yang membuktikan goal-nya tercapai (test/typecheck/benchmark/perintah yang relevan) dan baca outputnya. Klaim tanpa output bukan bukti.",
|
|
5615
|
+
autonomyClause(opts.autonomy),
|
|
5616
|
+
scopeClause("goal", opts.verifyScope),
|
|
5617
|
+
skillInstruction(PIPELINES.goal),
|
|
5618
|
+
`Setelah fase terakhir: commit, lalu \`git push origin HEAD:refs/heads/${branchTo}\`. Worktree ini detached HEAD \u2014 itu memang disengaja.`,
|
|
5619
|
+
`Backlog item ${spec.id} \xB7 sumber ${spec.source} \xB7 prioritas ${spec.priority}
|
|
5620
|
+
Judul: ${spec.title}`
|
|
5621
|
+
].filter(Boolean).join("\n\n");
|
|
5622
|
+
}
|
|
5575
5623
|
function startProjectPrompt(flow, project, branchTo) {
|
|
5576
5624
|
return [
|
|
5577
5625
|
`hanoman ${flow}. Susun Source of Truth repo ini dari kodenya di internal/docs/**, mengikuti STANDAR DOCS di bagian bawah prompt ini.`,
|
|
@@ -5676,12 +5724,13 @@ Judul: ${spec.title}
|
|
|
5676
5724
|
Objective: ${spec.objective}${detail}`
|
|
5677
5725
|
].filter(Boolean).join("\n\n");
|
|
5678
5726
|
}
|
|
5679
|
-
var PIPELINES, AUTONOMY_CLAUSE, AUTONOMY_CLAUSE_FULL, autonomyClause, phaseInstruction, PHASE_SKILLS, skillInstruction, auditDecisionInstruction, ESCALATION_CONTRACT, auditOnlyInstruction, auditContinuationInstruction, scopeClause, resumeClause, RESUMED_WORKTREE_NOTE, REVERSE_PHASE_GUIDE, SCAFFOLD_PHASE_GUIDE, projectLine, crossAuditLogGuide, CROSS_AUDIT_FOCUS;
|
|
5727
|
+
var PIPELINES, AUTONOMY_CLAUSE, AUTONOMY_CLAUSE_FULL, autonomyClause, phaseInstruction, PHASE_SKILLS, skillInstruction, auditDecisionInstruction, ESCALATION_CONTRACT, auditOnlyInstruction, auditContinuationInstruction, writesCode, scopeClause, resumeClause, RESUMED_WORKTREE_NOTE, REVERSE_PHASE_GUIDE, SCAFFOLD_PHASE_GUIDE, projectLine, crossAuditLogGuide, CROSS_AUDIT_FOCUS;
|
|
5680
5728
|
var init_prompt = __esm({
|
|
5681
5729
|
"../runner/src/prompt.ts"() {
|
|
5682
5730
|
"use strict";
|
|
5683
5731
|
init_reverse_standard();
|
|
5684
5732
|
init_verify_scope();
|
|
5733
|
+
init_goal_spec();
|
|
5685
5734
|
PIPELINES = {
|
|
5686
5735
|
feature: ["Brainstorm", "Objective", "Spec", "Plan", "Execute"],
|
|
5687
5736
|
qa: ["Audit", "Spec", "Plan", "Execute"],
|
|
@@ -5692,7 +5741,11 @@ var init_prompt = __esm({
|
|
|
5692
5741
|
breakdown: ["Analisis", "Breakdown"],
|
|
5693
5742
|
// SPEC-337 · ADR-0075 · audit lintas project: fase & stage-map identik audit-only, scope-nya
|
|
5694
5743
|
// yang berbeda (project utama + tetangga ProjectLink).
|
|
5695
|
-
"cross-audit": ["Audit", "Laporan"]
|
|
5744
|
+
"cross-audit": ["Audit", "Laporan"],
|
|
5745
|
+
// SPEC-407 · ADR-0089 · backlog goal: tak ada fase perencanaan sama sekali. `Goal` = kerjakan,
|
|
5746
|
+
// `Verifikasi` = buktikan. Kedua nama unik lintas PIPELINES — syarat peta REACHED di server,
|
|
5747
|
+
// yang berkunci nama fase saja.
|
|
5748
|
+
goal: ["Goal", "Verifikasi"]
|
|
5696
5749
|
};
|
|
5697
5750
|
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 saat butuh keputusan manusia sejati (percabangan yang mengubah bentuk kerja: data model, kontrak API, scope); saat itu tanyakan di terminal ini dan tunggu jawabannya. Selain itu, terus lanjut.';
|
|
5698
5751
|
AUTONOMY_CLAUSE_FULL = "Kamu berjalan TANPA pengawas \u2014 tak ada manusia yang menonton terminal ini untuk menjawab. Putuskan sendiri di SETIAP percabangan (termasuk yang mengubah bentuk kerja: data model, kontrak API, scope) berdasarkan Source of Truth dan penilaian terbaikmu; JANGAN berhenti bertanya. Tembus seluruh pipeline sampai stage `done`, lalu commit & push. Jangan menunggu review/persetujuan siapa pun \u2014 catat asumsi & keputusan penting di pesan commit agar bisa di-review pasca-fakta. Merge ke branch utama tetap dilakukan manusia, bukan kamu.";
|
|
@@ -5712,7 +5765,10 @@ Execute BELUM selesai selama plan (\`docs/superpowers/plans/**\`) masih punya ta
|
|
|
5712
5765
|
"superpowers:executing-plans",
|
|
5713
5766
|
"superpowers:test-driven-development",
|
|
5714
5767
|
"superpowers:verification-before-completion"
|
|
5715
|
-
]
|
|
5768
|
+
],
|
|
5769
|
+
// SPEC-407 · fase `Goal` sengaja TANPA skill: seluruh inti flow ini adalah membebaskan sesi
|
|
5770
|
+
// dari proses kaku. Yang tetap dijaga cuma pintu keluarnya.
|
|
5771
|
+
Verifikasi: ["superpowers:verification-before-completion"]
|
|
5716
5772
|
};
|
|
5717
5773
|
skillInstruction = (phases) => {
|
|
5718
5774
|
const lines2 = phases.filter((p) => PHASE_SKILLS[p]).map((p) => `- ${p}: ${PHASE_SKILLS[p].join(", ")}`);
|
|
@@ -5752,17 +5808,19 @@ ${lines2.join("\n")}` : "";
|
|
|
5752
5808
|
return `Backlog brief ini LANJUTAN dari audit ${fromAudit}. Worktree ini lahir dari branch audit itu, jadi dokumen audit sudah ada di ${doc}. BACA dokumen itu lebih dulu dan pakai sebagai bahan fase Brainstorm & Objective \u2014 temuannya sudah terbukti, jangan menginvestigasi ulang dari nol. Semua fase tetap dijalankan: dokumen audit memuat TEMUAN, bukan bentuk solusi, jadi perancangan fitur tetap pekerjaanmu.`;
|
|
5753
5809
|
return `Backlog qa ini LANJUTAN dari audit ${fromAudit}. Worktree ini lahir dari branch audit itu, jadi dokumen audit sudah ada di ${doc}. JANGAN mengulang investigasi fase Audit dari nol \u2014 baca dokumen audit itu sebagai temuan, tandai fase Audit dilewati (\`echo "Audit skipped" >> "$HANOMAN_PHASE_FILE"\`), lalu ambil keputusan pasca-Audit: perbaikan jelas & kecil \u2192 langsung Execute (tandai \`Spec skipped\` dan \`Plan skipped\` bila sesuai); selain itu Spec \u2192 Plan \u2192 Execute penuh.`;
|
|
5754
5810
|
};
|
|
5755
|
-
|
|
5756
|
-
|
|
5811
|
+
writesCode = (flow) => PIPELINES[flow].includes("Execute") || PIPELINES[flow].includes("Goal");
|
|
5812
|
+
scopeClause = (flow, scope) => scope && writesCode(flow) ? verifyScopeClause(scope) : "";
|
|
5813
|
+
resumeClause = (r, branchTo, hasPlan = true) => {
|
|
5757
5814
|
const fase = r.recorded.length ? `Fase yang SUDAH tercatat di $HANOMAN_PHASE_FILE: ${r.recorded.join(" \xB7 ")}. JANGAN mengulang fase itu dan JANGAN menulis ulang barisnya.` : "Belum ada fase yang tercatat di $HANOMAN_PHASE_FILE \u2014 worktree ini sendiri yang jadi alasan melanjutkan.";
|
|
5758
|
-
const lanjut = r.next ? `Lanjutkan dari fase: ${r.next}.` : "Semua fase sudah tercatat. Periksa apakah plan di `docs/superpowers/plans/**` masih menyisakan task `- [ ]` dan selesaikan sisanya; bila sudah bersih, tinggal commit & push.";
|
|
5815
|
+
const lanjut = r.next ? `Lanjutkan dari fase: ${r.next}.` : hasPlan ? "Semua fase sudah tercatat. Periksa apakah plan di `docs/superpowers/plans/**` masih menyisakan task `- [ ]` dan selesaikan sisanya; bila sudah bersih, tinggal commit & push." : "Semua fase sudah tercatat. Buktikan sekali lagi goal-nya benar-benar tercapai, lalu commit & push.";
|
|
5759
5816
|
const worktree = r.worktreeKept ? "Worktree ini adalah worktree sesi sebelumnya apa adanya \u2014 termasuk perubahan yang belum di-commit." : `Worktree ini DIBANGUN ULANG dari tip branch sesi \`${branchTo}\`: commit sesi sebelumnya ada, tetapi perubahan yang belum sempat di-commit TIDAK ada.`;
|
|
5817
|
+
const baca = hasPlan ? "Sebelum menulis apa pun: baca `git log --oneline` dan `git status`, lalu plan di `docs/superpowers/plans/**` untuk backlog item ini (`- [x]` sudah selesai, `- [ ]` belum). Jangan menulis ulang yang sudah ada." : "Sebelum menulis apa pun: baca `git log --oneline` dan `git status` untuk melihat apa yang sudah dikerjakan. Jangan menulis ulang yang sudah ada.";
|
|
5760
5818
|
return [
|
|
5761
5819
|
"Sesi ini MELANJUTKAN pekerjaan sesi sebelumnya untuk backlog item yang sama \u2014 bukan memulai dari nol.",
|
|
5762
5820
|
fase,
|
|
5763
5821
|
lanjut,
|
|
5764
5822
|
worktree,
|
|
5765
|
-
|
|
5823
|
+
baca
|
|
5766
5824
|
].join(" ");
|
|
5767
5825
|
};
|
|
5768
5826
|
RESUMED_WORKTREE_NOTE = "Catatan: worktree ini BUKAN kosong \u2014 ia berisi pekerjaan sesi sebelumnya untuk tugas yang sama (sesi itu berhenti sebelum selesai). Baca `git log --oneline` dan `git status` lebih dulu, lalu lanjutkan dari sana alih-alih menulis ulang semuanya dari awal.";
|
|
@@ -5930,7 +5988,21 @@ var init_settings = __esm({
|
|
|
5930
5988
|
});
|
|
5931
5989
|
|
|
5932
5990
|
// ../runner/src/goal.ts
|
|
5933
|
-
function
|
|
5991
|
+
function goalFlowCondition(specId, branchTo, spec) {
|
|
5992
|
+
const g = readGoalPayload(spec?.payload);
|
|
5993
|
+
const goal = g?.goal || (spec?.objective ?? "").trim() || "(goal tak tercatat di backlog item)";
|
|
5994
|
+
const bukti = g?.done || goal;
|
|
5995
|
+
return [
|
|
5996
|
+
`Sesi goal hanoman ${specId}. GOAL: ${goal}`,
|
|
5997
|
+
"Sesi ini hanya boleh berhenti bila transkrip TERBARU memuat bukti langsung semua hal berikut:",
|
|
5998
|
+
`1. goal tercapai \u2014 ${bukti};`,
|
|
5999
|
+
`2. output \`cat "$HANOMAN_PHASE_FILE"\` yang memuat satu baris untuk SETIAP fase ${PIPELINES.goal.join(" \u2192 ")}, masing-masing berakhiran \`done\` atau \`skipped\`;`,
|
|
6000
|
+
`3. output \`git push origin HEAD:refs/heads/${branchTo}\` yang SUKSES sesudah commit terakhir.`,
|
|
6001
|
+
"Bila salah satu bukti tak ada di transkrip terbaru, kondisi BELUM terpenuhi: jalankan perintah verifikasinya, tuntaskan yang masih kurang, lalu lanjutkan \u2014 jangan berhenti."
|
|
6002
|
+
].join("\n");
|
|
6003
|
+
}
|
|
6004
|
+
function defaultGoalCondition({ flow, specId, branchTo, spec }) {
|
|
6005
|
+
if (flow === "goal") return goalFlowCondition(specId, branchTo, spec);
|
|
5934
6006
|
const phases = PIPELINES[flow];
|
|
5935
6007
|
const planGate = phases.includes("Plan") && phases.includes("Execute");
|
|
5936
6008
|
const clauses = [
|
|
@@ -5964,6 +6036,7 @@ var init_goal = __esm({
|
|
|
5964
6036
|
"../runner/src/goal.ts"() {
|
|
5965
6037
|
"use strict";
|
|
5966
6038
|
init_prompt();
|
|
6039
|
+
init_goal_spec();
|
|
5967
6040
|
GOAL_MAX = 4e3;
|
|
5968
6041
|
goalOneLine = (cond) => cond.replace(/\s+/g, " ").trim();
|
|
5969
6042
|
GOAL_CHUNK = 500;
|
|
@@ -6128,6 +6201,7 @@ var init_src2 = __esm({
|
|
|
6128
6201
|
init_git();
|
|
6129
6202
|
init_settings();
|
|
6130
6203
|
init_goal();
|
|
6204
|
+
init_goal_spec();
|
|
6131
6205
|
init_codex_settings();
|
|
6132
6206
|
init_agent_cli();
|
|
6133
6207
|
init_verify_scope();
|
|
@@ -6199,7 +6273,8 @@ function readPhases(file, flow) {
|
|
|
6199
6273
|
function stageFor(phases) {
|
|
6200
6274
|
let best = -1;
|
|
6201
6275
|
for (const p of phases) {
|
|
6202
|
-
if (p.name === "Execute"
|
|
6276
|
+
if ((p.name === "Execute" || p.name === "Goal") && p.state === "active")
|
|
6277
|
+
best = Math.max(best, STAGES.indexOf("executing"));
|
|
6203
6278
|
if (p.state !== "done" && p.state !== "skipped") continue;
|
|
6204
6279
|
const s = REACHED[p.name];
|
|
6205
6280
|
if (s) best = Math.max(best, STAGES.indexOf(s));
|
|
@@ -6244,7 +6319,11 @@ var init_session_phases = __esm({
|
|
|
6244
6319
|
Spec: "spec-ready",
|
|
6245
6320
|
Plan: "planned",
|
|
6246
6321
|
Laporan: "done",
|
|
6247
|
-
Execute: "done"
|
|
6322
|
+
Execute: "done",
|
|
6323
|
+
// SPEC-407 · ADR-0089 · flow goal (Goal → Verifikasi): fase kerja mencapai `executing`, fase
|
|
6324
|
+
// verifikasi yang mencapai `done`. Kedua nama unik lintas PIPELINES — peta ini berkunci nama.
|
|
6325
|
+
Goal: "executing",
|
|
6326
|
+
Verifikasi: "done"
|
|
6248
6327
|
};
|
|
6249
6328
|
}
|
|
6250
6329
|
});
|
|
@@ -12269,7 +12348,7 @@ var require_parseParams = __commonJS({
|
|
|
12269
12348
|
var STATE_VALUE = 1;
|
|
12270
12349
|
var STATE_CHARSET = 2;
|
|
12271
12350
|
var STATE_LANG = 3;
|
|
12272
|
-
function parseParams(
|
|
12351
|
+
function parseParams(str2) {
|
|
12273
12352
|
const res = [];
|
|
12274
12353
|
let state = STATE_KEY;
|
|
12275
12354
|
let charset = "";
|
|
@@ -12277,9 +12356,9 @@ var require_parseParams = __commonJS({
|
|
|
12277
12356
|
let escaping = false;
|
|
12278
12357
|
let p = 0;
|
|
12279
12358
|
let tmp = "";
|
|
12280
|
-
const len =
|
|
12359
|
+
const len = str2.length;
|
|
12281
12360
|
for (var i = 0; i < len; ++i) {
|
|
12282
|
-
const char =
|
|
12361
|
+
const char = str2[i];
|
|
12283
12362
|
if (char === "\\" && inquote) {
|
|
12284
12363
|
if (escaping) {
|
|
12285
12364
|
escaping = false;
|
|
@@ -12292,7 +12371,7 @@ var require_parseParams = __commonJS({
|
|
|
12292
12371
|
if (inquote) {
|
|
12293
12372
|
inquote = false;
|
|
12294
12373
|
state = STATE_KEY;
|
|
12295
|
-
while (i + 1 < len &&
|
|
12374
|
+
while (i + 1 < len && str2[i + 1] !== ";") {
|
|
12296
12375
|
++i;
|
|
12297
12376
|
}
|
|
12298
12377
|
} else {
|
|
@@ -12811,29 +12890,29 @@ var require_Decoder = __commonJS({
|
|
|
12811
12890
|
function Decoder() {
|
|
12812
12891
|
this.buffer = void 0;
|
|
12813
12892
|
}
|
|
12814
|
-
Decoder.prototype.write = function(
|
|
12815
|
-
|
|
12893
|
+
Decoder.prototype.write = function(str2) {
|
|
12894
|
+
str2 = str2.replace(RE_PLUS, " ");
|
|
12816
12895
|
let res = "";
|
|
12817
12896
|
let i = 0;
|
|
12818
12897
|
let p = 0;
|
|
12819
|
-
const len =
|
|
12898
|
+
const len = str2.length;
|
|
12820
12899
|
for (; i < len; ++i) {
|
|
12821
12900
|
if (this.buffer !== void 0) {
|
|
12822
|
-
if (!HEX[
|
|
12901
|
+
if (!HEX[str2.charCodeAt(i)]) {
|
|
12823
12902
|
res += "%" + this.buffer;
|
|
12824
12903
|
this.buffer = void 0;
|
|
12825
12904
|
--i;
|
|
12826
12905
|
} else {
|
|
12827
|
-
this.buffer +=
|
|
12906
|
+
this.buffer += str2[i];
|
|
12828
12907
|
++p;
|
|
12829
12908
|
if (this.buffer.length === 2) {
|
|
12830
12909
|
res += String.fromCharCode(parseInt(this.buffer, 16));
|
|
12831
12910
|
this.buffer = void 0;
|
|
12832
12911
|
}
|
|
12833
12912
|
}
|
|
12834
|
-
} else if (
|
|
12913
|
+
} else if (str2[i] === "%") {
|
|
12835
12914
|
if (i > p) {
|
|
12836
|
-
res +=
|
|
12915
|
+
res += str2.substring(p, i);
|
|
12837
12916
|
p = i;
|
|
12838
12917
|
}
|
|
12839
12918
|
this.buffer = "";
|
|
@@ -12841,7 +12920,7 @@ var require_Decoder = __commonJS({
|
|
|
12841
12920
|
}
|
|
12842
12921
|
}
|
|
12843
12922
|
if (p < len && this.buffer === void 0) {
|
|
12844
|
-
res +=
|
|
12923
|
+
res += str2.substring(p);
|
|
12845
12924
|
}
|
|
12846
12925
|
return res;
|
|
12847
12926
|
};
|
|
@@ -13505,9 +13584,9 @@ var require_generateId = __commonJS({
|
|
|
13505
13584
|
}
|
|
13506
13585
|
module.exports.generateId = function generateIdFn() {
|
|
13507
13586
|
let num = 0;
|
|
13508
|
-
let
|
|
13587
|
+
let str2 = seed();
|
|
13509
13588
|
return function generateId() {
|
|
13510
|
-
return num === 255 ? (
|
|
13589
|
+
return num === 255 ? (str2 = seed()) + HEX[num = 0] : str2 + HEX[++num];
|
|
13511
13590
|
};
|
|
13512
13591
|
}();
|
|
13513
13592
|
}
|
|
@@ -15450,10 +15529,10 @@ function cleanUrl(href) {
|
|
|
15450
15529
|
}
|
|
15451
15530
|
var noopTest = { exec: () => null };
|
|
15452
15531
|
function splitCells(tableRow, count) {
|
|
15453
|
-
const row = tableRow.replace(/\|/g, (match, offset,
|
|
15532
|
+
const row = tableRow.replace(/\|/g, (match, offset, str2) => {
|
|
15454
15533
|
let escaped = false;
|
|
15455
15534
|
let curr = offset;
|
|
15456
|
-
while (--curr >= 0 &&
|
|
15535
|
+
while (--curr >= 0 && str2[curr] === "\\")
|
|
15457
15536
|
escaped = !escaped;
|
|
15458
15537
|
if (escaped) {
|
|
15459
15538
|
return "|";
|
|
@@ -15481,14 +15560,14 @@ function splitCells(tableRow, count) {
|
|
|
15481
15560
|
}
|
|
15482
15561
|
return cells;
|
|
15483
15562
|
}
|
|
15484
|
-
function rtrim(
|
|
15485
|
-
const l =
|
|
15563
|
+
function rtrim(str2, c, invert) {
|
|
15564
|
+
const l = str2.length;
|
|
15486
15565
|
if (l === 0) {
|
|
15487
15566
|
return "";
|
|
15488
15567
|
}
|
|
15489
15568
|
let suffLen = 0;
|
|
15490
15569
|
while (suffLen < l) {
|
|
15491
|
-
const currChar =
|
|
15570
|
+
const currChar = str2.charAt(l - suffLen - 1);
|
|
15492
15571
|
if (currChar === c && !invert) {
|
|
15493
15572
|
suffLen++;
|
|
15494
15573
|
} else if (currChar !== c && invert) {
|
|
@@ -15497,19 +15576,19 @@ function rtrim(str, c, invert) {
|
|
|
15497
15576
|
break;
|
|
15498
15577
|
}
|
|
15499
15578
|
}
|
|
15500
|
-
return
|
|
15579
|
+
return str2.slice(0, l - suffLen);
|
|
15501
15580
|
}
|
|
15502
|
-
function findClosingBracket(
|
|
15503
|
-
if (
|
|
15581
|
+
function findClosingBracket(str2, b) {
|
|
15582
|
+
if (str2.indexOf(b[1]) === -1) {
|
|
15504
15583
|
return -1;
|
|
15505
15584
|
}
|
|
15506
15585
|
let level = 0;
|
|
15507
|
-
for (let i = 0; i <
|
|
15508
|
-
if (
|
|
15586
|
+
for (let i = 0; i < str2.length; i++) {
|
|
15587
|
+
if (str2[i] === "\\") {
|
|
15509
15588
|
i++;
|
|
15510
|
-
} else if (
|
|
15589
|
+
} else if (str2[i] === b[0]) {
|
|
15511
15590
|
level++;
|
|
15512
|
-
} else if (
|
|
15591
|
+
} else if (str2[i] === b[1]) {
|
|
15513
15592
|
level--;
|
|
15514
15593
|
if (level < 0) {
|
|
15515
15594
|
return i;
|
|
@@ -17839,6 +17918,13 @@ async function liveSpecs(filter = {}) {
|
|
|
17839
17918
|
// src/routes/specs.ts
|
|
17840
17919
|
var branchUnknown = async (repoDir, branch) => !(await branchFromCandidates(repoDir)).includes(branch);
|
|
17841
17920
|
function deriveSpecFields(source, payload, manualPriority) {
|
|
17921
|
+
if (source === "goal") {
|
|
17922
|
+
const pick = (v) => typeof v === "string" ? v.trim() : "";
|
|
17923
|
+
return {
|
|
17924
|
+
priority: manualPriority,
|
|
17925
|
+
objective: pick(payload?.goal) || pick(payload?.done) || "\u2014 goal belum diisi."
|
|
17926
|
+
};
|
|
17927
|
+
}
|
|
17842
17928
|
const isQa = source === "qa";
|
|
17843
17929
|
const priority = isQa && payload && "severity" in payload ? payload.severity === "minor" ? "sedang" : "tinggi" : manualPriority;
|
|
17844
17930
|
const objective = isQa && payload && "actual" in payload ? payload.actual || payload.steps || "\u2014 audit untuk menelusuri akar masalah." : payload && "outcome" in payload ? payload.outcome || payload.context || "\u2014 brainstorm untuk memperjelas objective." : "";
|
|
@@ -17878,7 +17964,7 @@ async function specs_default(app2) {
|
|
|
17878
17964
|
source: b.source,
|
|
17879
17965
|
stage: "brainstorming",
|
|
17880
17966
|
priority,
|
|
17881
|
-
author: isQa ? `QA \xB7 ${author}` : b.source === "audit" ? `Audit \xB7 ${author}` : b.source === "cross-audit" ? `Audit lintas \xB7 ${author}` : author,
|
|
17967
|
+
author: isQa ? `QA \xB7 ${author}` : b.source === "audit" ? `Audit \xB7 ${author}` : b.source === "cross-audit" ? `Audit lintas \xB7 ${author}` : b.source === "goal" ? `Goal \xB7 ${author}` : author,
|
|
17882
17968
|
objective,
|
|
17883
17969
|
payload: b.payload,
|
|
17884
17970
|
branchFrom: b.branchFrom ?? null
|
|
@@ -19299,6 +19385,14 @@ function resumeState(repoDir, worktree, branchTo, headSha) {
|
|
|
19299
19385
|
const base = realGit.revParse(repoDir, `origin/${branchTo}`) ?? realGit.revParse(repoDir, branchTo) ?? (headSha ? realGit.revParse(repoDir, headSha) : null);
|
|
19300
19386
|
return base ? { worktreeKept: false, base } : null;
|
|
19301
19387
|
}
|
|
19388
|
+
function buildResumeCtx(repoDir, id, flow, worktreeKept) {
|
|
19389
|
+
const phases = readPhases(phaseFilePath(repoDir, id), flow);
|
|
19390
|
+
return {
|
|
19391
|
+
recorded: phases.filter((p) => p.state === "done" || p.state === "skipped").map((p) => `${p.name} ${p.state}`),
|
|
19392
|
+
next: phases.find((p) => p.state === "active")?.name,
|
|
19393
|
+
worktreeKept
|
|
19394
|
+
};
|
|
19395
|
+
}
|
|
19302
19396
|
async function startSpecSession(spec, opts) {
|
|
19303
19397
|
const repoDir = await resolveRepoDir(spec.projectId);
|
|
19304
19398
|
if (!repoDir) throw new LaunchError(`project "${spec.projectId}" belum di-bind ke checkout lokal`, "needs-bind");
|
|
@@ -19315,11 +19409,14 @@ async function startSpecSession(spec, opts) {
|
|
|
19315
19409
|
const worktree = `${repoDir}/.worktrees/${id}`;
|
|
19316
19410
|
const branchTo = `hanoman/${id}`;
|
|
19317
19411
|
const resume = !isContinue && spec.baseSha ? resumeState(repoDir, worktree, branchTo, spec.headSha) : null;
|
|
19318
|
-
const
|
|
19319
|
-
|
|
19320
|
-
opts.
|
|
19321
|
-
|
|
19322
|
-
|
|
19412
|
+
const isGoalFlow = opts.flow === "goal";
|
|
19413
|
+
const goalArgs = {
|
|
19414
|
+
flow: opts.flow,
|
|
19415
|
+
specId: spec.id,
|
|
19416
|
+
branchTo,
|
|
19417
|
+
spec: { payload: spec.payload ?? void 0, objective: spec.objective }
|
|
19418
|
+
};
|
|
19419
|
+
const goal = isGoalFlow || (opts.goal ?? setting.goal.enabled) ? resolveGoalCondition(goalArgs, opts.goalCondition, isGoalFlow ? null : setting.goal.condition) : void 0;
|
|
19323
19420
|
const verifyScope = opts.verifyScope ?? setting.verifyScope;
|
|
19324
19421
|
if (agent === "codex") ensureCodexTrust(repoDir);
|
|
19325
19422
|
let baseSha;
|
|
@@ -19342,17 +19439,18 @@ async function startSpecSession(spec, opts) {
|
|
|
19342
19439
|
objective: spec.objective,
|
|
19343
19440
|
payload: spec.payload ?? void 0
|
|
19344
19441
|
};
|
|
19442
|
+
const resumeCtx = resume ? buildResumeCtx(repoDir, id, opts.flow, resume.worktreeKept) : void 0;
|
|
19345
19443
|
let prompt;
|
|
19346
|
-
if (
|
|
19444
|
+
if (isGoalFlow) {
|
|
19445
|
+
prompt = startGoalPrompt(brief, branchTo, {
|
|
19446
|
+
autonomy: opts.autonomy,
|
|
19447
|
+
verifyScope,
|
|
19448
|
+
resume: resumeCtx
|
|
19449
|
+
});
|
|
19450
|
+
} else if (isContinue) {
|
|
19347
19451
|
prompt = continuePrompt(opts.flow, brief, branchTo, opts.autonomy, verifyScope);
|
|
19348
|
-
} else if (
|
|
19349
|
-
|
|
19350
|
-
const ctx = {
|
|
19351
|
-
recorded: phases.filter((p) => p.state === "done" || p.state === "skipped").map((p) => `${p.name} ${p.state}`),
|
|
19352
|
-
next: phases.find((p) => p.state === "active")?.name,
|
|
19353
|
-
worktreeKept: resume.worktreeKept
|
|
19354
|
-
};
|
|
19355
|
-
prompt = resumePrompt(opts.flow, brief, branchTo, ctx, opts.autonomy, verifyScope);
|
|
19452
|
+
} else if (resumeCtx) {
|
|
19453
|
+
prompt = resumePrompt(opts.flow, brief, branchTo, resumeCtx, opts.autonomy, verifyScope);
|
|
19356
19454
|
} else {
|
|
19357
19455
|
prompt = startPrompt(opts.flow, brief, branchTo, opts.autonomy, verifyScope);
|
|
19358
19456
|
}
|
|
@@ -20681,6 +20779,9 @@ async function codex(app2) {
|
|
|
20681
20779
|
app2.get("/codex/version", async () => codexVersionInfo());
|
|
20682
20780
|
}
|
|
20683
20781
|
|
|
20782
|
+
// src/routes/update.ts
|
|
20783
|
+
init_src();
|
|
20784
|
+
|
|
20684
20785
|
// src/services/update.ts
|
|
20685
20786
|
init_src();
|
|
20686
20787
|
init_config2();
|
|
@@ -20695,7 +20796,11 @@ function composeUpdate(x) {
|
|
|
20695
20796
|
latestVersion: x.latestVersion,
|
|
20696
20797
|
registry: { status: x.registryStatus, checkedAt: x.checkedAt },
|
|
20697
20798
|
updateAvailable: available,
|
|
20698
|
-
command: available ? UPDATE_COMMAND : ""
|
|
20799
|
+
command: available ? UPDATE_COMMAND : "",
|
|
20800
|
+
// Diwariskan apa adanya. Ia fakta tentang cara proses ini dilahirkan, bukan kesimpulan
|
|
20801
|
+
// tentang ada-tidaknya update — menurunkannya dari `available` akan menyembunyikan
|
|
20802
|
+
// instalasi tak-tersupervisi tepat saat tombolnya paling ingin ditekan.
|
|
20803
|
+
canApply: x.canApply
|
|
20699
20804
|
};
|
|
20700
20805
|
}
|
|
20701
20806
|
var RESULT_TTL_MS = 15e3;
|
|
@@ -20716,6 +20821,15 @@ function runningVersion() {
|
|
|
20716
20821
|
}
|
|
20717
20822
|
return "0.0.0";
|
|
20718
20823
|
}
|
|
20824
|
+
function supervised() {
|
|
20825
|
+
const v = process.env.HANOMAN_SUPERVISOR;
|
|
20826
|
+
return v === "1" || v === "true";
|
|
20827
|
+
}
|
|
20828
|
+
var exiter = null;
|
|
20829
|
+
function requestRestartForUpdate() {
|
|
20830
|
+
const delay = effectiveInt("HANOMAN_UPDATE_RESTART_DELAY_MS") ?? 250;
|
|
20831
|
+
setTimeout(() => (exiter ?? ((c) => process.exit(c)))(UPDATE_RESTART_EXIT), delay);
|
|
20832
|
+
}
|
|
20719
20833
|
async function maybeFetch() {
|
|
20720
20834
|
if (!effectiveBool("HANOMAN_UPDATE_FETCH")) return;
|
|
20721
20835
|
if (lastFetchAt && Date.now() - lastFetchAt < FETCH_TTL_MS) return;
|
|
@@ -20748,15 +20862,30 @@ async function getUpdateStatus() {
|
|
|
20748
20862
|
currentVersion: runningVersion(),
|
|
20749
20863
|
latestVersion: lastLatest,
|
|
20750
20864
|
registryStatus: lastStatus,
|
|
20751
|
-
checkedAt: lastFetchAt ? new Date(lastFetchAt).toISOString() : null
|
|
20865
|
+
checkedAt: lastFetchAt ? new Date(lastFetchAt).toISOString() : null,
|
|
20866
|
+
canApply: supervised()
|
|
20752
20867
|
});
|
|
20753
20868
|
cached = { at: Date.now(), value };
|
|
20754
20869
|
return value;
|
|
20755
20870
|
}
|
|
20756
20871
|
|
|
20757
20872
|
// src/routes/update.ts
|
|
20873
|
+
init_pty();
|
|
20758
20874
|
async function update(app2) {
|
|
20759
20875
|
app2.get("/update", async () => getUpdateStatus());
|
|
20876
|
+
app2.post("/update/apply", async (req, reply) => {
|
|
20877
|
+
const parsed = zUpdateApplyBody.safeParse(req.body ?? {});
|
|
20878
|
+
if (!parsed.success) return reply.code(400).send({ error: "bad-body" });
|
|
20879
|
+
const u = await getUpdateStatus();
|
|
20880
|
+
if (!u.canApply) return reply.code(409).send({ error: "unsupervised" });
|
|
20881
|
+
if (!u.updateAvailable) return reply.code(409).send({ error: "up-to-date", current: u.currentVersion });
|
|
20882
|
+
const liveSessions = listSessions().filter((s) => !s.exited).length;
|
|
20883
|
+
const from = u.currentVersion;
|
|
20884
|
+
const to = u.latestVersion;
|
|
20885
|
+
if (!parsed.data.confirm) return reply.code(409).send({ error: "confirm-required", liveSessions, from, to });
|
|
20886
|
+
requestRestartForUpdate();
|
|
20887
|
+
return reply.code(202).send({ accepted: true, from, to, liveSessions });
|
|
20888
|
+
});
|
|
20760
20889
|
}
|
|
20761
20890
|
|
|
20762
20891
|
// src/services/events.ts
|
|
@@ -23197,7 +23326,8 @@ function capabilityForRoute(method, path) {
|
|
|
23197
23326
|
const seg = path.replace(/^\/api\/?/, "").replace(/\/+$/, "").split("/").filter(Boolean);
|
|
23198
23327
|
const top = seg[0] ?? "";
|
|
23199
23328
|
if (top === "auth" || top === "agent-tokens" || top === "device-tokens" || top === "sync") return "COOKIE_ONLY";
|
|
23200
|
-
if (top === "limits" || top === "update" || top === "events" || top === "fs" || top === "health")
|
|
23329
|
+
if (top === "limits" || top === "update" || top === "events" || top === "fs" || top === "health")
|
|
23330
|
+
return read ? "GLOBAL_READ" : "COOKIE_ONLY";
|
|
23201
23331
|
if (top === "scheduler") return rw("settings");
|
|
23202
23332
|
if (top === "settings" || top === "config") return rw("settings");
|
|
23203
23333
|
if (top === "specs") return rw("backlog");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hanoman",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Orchestrator + dashboard workflow docs-driven untuk sesi Claude Code / Codex",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
"hanoman": "bin/hanoman.mjs"
|
|
12
12
|
},
|
|
13
13
|
"scripts": {
|
|
14
|
-
"postinstall": "prisma generate --schema prisma/schema.prisma || true"
|
|
14
|
+
"postinstall": "prisma generate --schema prisma/schema.prisma || true",
|
|
15
|
+
"prepublishOnly": "node dist/cli.js __verify"
|
|
15
16
|
},
|
|
16
17
|
"engines": {
|
|
17
18
|
"node": ">=20"
|
|
@@ -25,17 +26,15 @@
|
|
|
25
26
|
"LICENSE"
|
|
26
27
|
],
|
|
27
28
|
"dependencies": {
|
|
28
|
-
"
|
|
29
|
+
"fastify": "^4.28.0",
|
|
29
30
|
"@fastify/static": "^7.0.0",
|
|
30
31
|
"@fastify/websocket": "^10.0.1",
|
|
31
|
-
"@
|
|
32
|
-
"
|
|
32
|
+
"@fastify/cookie": "^9.4.0",
|
|
33
|
+
"@prisma/client": "^6.19.0",
|
|
33
34
|
"node-pty": "^1.1.0",
|
|
34
35
|
"pdfkit": "^0.19.1",
|
|
36
|
+
"prisma": "^6.19.0",
|
|
35
37
|
"pg": "^8.13.1"
|
|
36
38
|
},
|
|
37
|
-
"license": "MIT"
|
|
38
|
-
"devDependencies": {
|
|
39
|
-
"prisma": "^6.19.3"
|
|
40
|
-
}
|
|
39
|
+
"license": "MIT"
|
|
41
40
|
}
|