hanoman 0.5.0 → 0.6.0
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 +2 -0
- package/dist/build-info.json +3 -3
- package/dist/cli.js +213 -27
- package/dist/server.js +529 -155
- package/package.json +1 -1
- package/web/assets/{ChangelogScreen-CqVppy70.js → ChangelogScreen-DVMpzy2Y.js} +1 -1
- package/web/assets/{DalangHanomanScreen-DRFC8ZdR.js → DalangHanomanScreen-aY89PmaJ.js} +1 -1
- package/web/assets/{DocPreviewModal-Di28IHju.js → DocPreviewModal-BTwj2rmX.js} +1 -1
- package/web/assets/{DocsWorkspace-DY0x50eq.js → DocsWorkspace-CgM5rgcr.js} +1 -1
- package/web/assets/{IdeScreen-BpSi7o5r.js → IdeScreen-B7oDlNQ0.js} +1 -1
- package/web/assets/{LeadScreen-BRzdha5a.js → LeadScreen-BzNU_kBC.js} +1 -1
- package/web/assets/{ReviewScreen-D2SwZTqF.js → ReviewScreen-Dk0Zy4jJ.js} +1 -1
- package/web/assets/{SchedulerScreen-w6hID1yX.js → SchedulerScreen-CxYqEqnw.js} +1 -1
- package/web/assets/SettingsScreen-D1Fop_V6.js +62 -0
- package/web/assets/{TeamScreen-D0W-oNAi.js → TeamScreen-DwtrDuZG.js} +1 -1
- package/web/assets/TerminalScreen-CViC7rot.js +9 -0
- package/web/assets/{TriageScreen-CmVGUNpA.js → TriageScreen-DjCXx0F4.js} +1 -1
- package/web/assets/{VpsScreen-BKoJ_dAB.js → VpsScreen-C2WoJQ_j.js} +1 -1
- package/web/assets/{diff-view-B_pIZnWa.js → diff-view-Bep86yt6.js} +1 -1
- package/web/assets/index-Bd9gXx1g.js +923 -0
- package/web/assets/{live-DJzk8BTb.js → live-BlNZnTbo.js} +1 -1
- package/web/index.html +1 -1
- package/web/assets/SettingsScreen-DC4OFYQ-.js +0 -62
- package/web/assets/TerminalScreen-B2keWEDd.js +0 -9
- package/web/assets/index-C_-gADIr.js +0 -923
package/dist/server.js
CHANGED
|
@@ -4793,6 +4793,214 @@ var init_logs = __esm({
|
|
|
4793
4793
|
}
|
|
4794
4794
|
});
|
|
4795
4795
|
|
|
4796
|
+
// ../shared/src/orchestration.ts
|
|
4797
|
+
function phaseAgentName(phase) {
|
|
4798
|
+
return PHASE_AGENT_PREFIX + phase.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
4799
|
+
}
|
|
4800
|
+
var ORCHESTRATION_FLOWS, FLOW_PHASES, PHASE_AGENT_PREFIX, isPhaseAgentName, PHASE_EVIDENCE_GRACE_MS;
|
|
4801
|
+
var init_orchestration = __esm({
|
|
4802
|
+
"../shared/src/orchestration.ts"() {
|
|
4803
|
+
"use strict";
|
|
4804
|
+
ORCHESTRATION_FLOWS = [
|
|
4805
|
+
"feature",
|
|
4806
|
+
"qa",
|
|
4807
|
+
"scaffold",
|
|
4808
|
+
"reverse",
|
|
4809
|
+
"prd",
|
|
4810
|
+
"audit",
|
|
4811
|
+
"breakdown",
|
|
4812
|
+
"goal",
|
|
4813
|
+
"no_effort"
|
|
4814
|
+
];
|
|
4815
|
+
FLOW_PHASES = {
|
|
4816
|
+
feature: ["Brainstorm", "Objective", "Spec", "Plan", "Execute"],
|
|
4817
|
+
qa: ["Audit", "Spec", "Plan", "Execute"],
|
|
4818
|
+
scaffold: ["Brainstorm", "Objective", "Doc index"],
|
|
4819
|
+
reverse: ["Scan", "Docs teknis", "Wawancara", "Konvensi & index", "Serah terima"],
|
|
4820
|
+
prd: ["Brainstorm", "PRD"],
|
|
4821
|
+
audit: ["Audit", "Laporan"],
|
|
4822
|
+
breakdown: ["Analisis", "Breakdown"],
|
|
4823
|
+
// SPEC-337 · ADR-0075 · audit lintas project: fase & stage-map identik audit-only, scope-nya
|
|
4824
|
+
// yang berbeda (project utama + tetangga ProjectLink).
|
|
4825
|
+
// SPEC-407 · ADR-0089 · backlog goal: tak ada fase perencanaan sama sekali. `Goal` = kerjakan,
|
|
4826
|
+
// `Verifikasi` = buktikan. Kedua nama unik lintas daftar ini — syarat peta REACHED di server,
|
|
4827
|
+
// yang berkunci nama fase saja.
|
|
4828
|
+
goal: ["Goal", "Verifikasi"],
|
|
4829
|
+
// SPEC-825 · ADR-0123 · task remeh: SATU fase. Nama `Kerjakan` unik lintas daftar ini — syarat
|
|
4830
|
+
// peta REACHED server, yang berkunci nama fase saja.
|
|
4831
|
+
no_effort: ["Kerjakan"]
|
|
4832
|
+
};
|
|
4833
|
+
PHASE_AGENT_PREFIX = "hanoman-fase-";
|
|
4834
|
+
isPhaseAgentName = (name2) => name2.startsWith(PHASE_AGENT_PREFIX);
|
|
4835
|
+
PHASE_EVIDENCE_GRACE_MS = 6e4;
|
|
4836
|
+
}
|
|
4837
|
+
});
|
|
4838
|
+
|
|
4839
|
+
// ../shared/src/runtime-defaults.ts
|
|
4840
|
+
var RUNTIME_DEFAULTS_VERSION, zRuntimeDefaultState, zBuiltinRuntimeDefaults, BUILTIN_CLAUDE_RUNTIME_DEFAULTS, BUILTIN_CODEX_RUNTIME_DEFAULTS, LEGACY_CLAUDE_RUNTIME_DEFAULTS, LEGACY_CODEX_RUNTIME_DEFAULTS, LEGACY_ORCHESTRATION_FLOW_DEFAULT, cell, flow, BUILTIN_ORCHESTRATION_DEFAULTS, seededFlows, BUILTIN_RUNTIME_DEFAULTS;
|
|
4841
|
+
var init_runtime_defaults = __esm({
|
|
4842
|
+
"../shared/src/runtime-defaults.ts"() {
|
|
4843
|
+
"use strict";
|
|
4844
|
+
init_orchestration();
|
|
4845
|
+
init_zod();
|
|
4846
|
+
RUNTIME_DEFAULTS_VERSION = "2026-09-17-v1";
|
|
4847
|
+
zRuntimeDefaultState = external_exports.enum(["seeded", "user"]);
|
|
4848
|
+
zBuiltinRuntimeDefaults = external_exports.object({
|
|
4849
|
+
version: external_exports.string().default(RUNTIME_DEFAULTS_VERSION),
|
|
4850
|
+
claude: external_exports.object({
|
|
4851
|
+
model: zRuntimeDefaultState.default("seeded"),
|
|
4852
|
+
effort: zRuntimeDefaultState.default("seeded")
|
|
4853
|
+
}).default({}),
|
|
4854
|
+
codex: external_exports.object({
|
|
4855
|
+
model: zRuntimeDefaultState.default("seeded"),
|
|
4856
|
+
effort: zRuntimeDefaultState.default("seeded")
|
|
4857
|
+
}).default({}),
|
|
4858
|
+
orchestration: external_exports.record(external_exports.string(), zRuntimeDefaultState).default({})
|
|
4859
|
+
});
|
|
4860
|
+
BUILTIN_CLAUDE_RUNTIME_DEFAULTS = {
|
|
4861
|
+
model: "claude-sonnet-5",
|
|
4862
|
+
effort: "medium"
|
|
4863
|
+
};
|
|
4864
|
+
BUILTIN_CODEX_RUNTIME_DEFAULTS = {
|
|
4865
|
+
model: "gpt-5.6-terra",
|
|
4866
|
+
effort: "medium"
|
|
4867
|
+
};
|
|
4868
|
+
LEGACY_CLAUDE_RUNTIME_DEFAULTS = {
|
|
4869
|
+
model: "claude-opus-5",
|
|
4870
|
+
effort: "xhigh"
|
|
4871
|
+
};
|
|
4872
|
+
LEGACY_CODEX_RUNTIME_DEFAULTS = {
|
|
4873
|
+
model: "gpt-5.6-sol",
|
|
4874
|
+
effort: "xhigh"
|
|
4875
|
+
};
|
|
4876
|
+
LEGACY_ORCHESTRATION_FLOW_DEFAULT = {
|
|
4877
|
+
enabled: true,
|
|
4878
|
+
claude: {},
|
|
4879
|
+
codex: {}
|
|
4880
|
+
};
|
|
4881
|
+
cell = (model, effort2) => ({ model, effort: effort2 });
|
|
4882
|
+
flow = (claude, codex2, enabled = true) => ({ enabled, claude, codex: codex2 });
|
|
4883
|
+
BUILTIN_ORCHESTRATION_DEFAULTS = {
|
|
4884
|
+
feature: flow(
|
|
4885
|
+
{
|
|
4886
|
+
Brainstorm: cell("claude-sonnet-5", "medium"),
|
|
4887
|
+
Objective: cell("claude-sonnet-5", "medium"),
|
|
4888
|
+
Spec: cell("claude-opus-5", "medium"),
|
|
4889
|
+
Plan: cell("claude-sonnet-5", "medium"),
|
|
4890
|
+
Execute: cell("claude-sonnet-5", "medium")
|
|
4891
|
+
},
|
|
4892
|
+
{
|
|
4893
|
+
Brainstorm: cell("gpt-5.6-terra", "medium"),
|
|
4894
|
+
Objective: cell("gpt-5.6-terra", "medium"),
|
|
4895
|
+
Spec: cell("gpt-5.6-sol", "medium"),
|
|
4896
|
+
Plan: cell("gpt-5.6-terra", "medium"),
|
|
4897
|
+
Execute: cell("gpt-5.6-terra", "medium")
|
|
4898
|
+
}
|
|
4899
|
+
),
|
|
4900
|
+
qa: flow(
|
|
4901
|
+
{
|
|
4902
|
+
Audit: cell("claude-sonnet-5", "medium"),
|
|
4903
|
+
Spec: cell("claude-opus-5", "medium"),
|
|
4904
|
+
Plan: cell("claude-sonnet-5", "medium"),
|
|
4905
|
+
Execute: cell("claude-sonnet-5", "medium")
|
|
4906
|
+
},
|
|
4907
|
+
{
|
|
4908
|
+
Audit: cell("gpt-5.6-terra", "medium"),
|
|
4909
|
+
Spec: cell("gpt-5.6-sol", "medium"),
|
|
4910
|
+
Plan: cell("gpt-5.6-terra", "medium"),
|
|
4911
|
+
Execute: cell("gpt-5.6-terra", "medium")
|
|
4912
|
+
}
|
|
4913
|
+
),
|
|
4914
|
+
scaffold: flow(
|
|
4915
|
+
{
|
|
4916
|
+
Brainstorm: cell("claude-sonnet-5", "medium"),
|
|
4917
|
+
Objective: cell("claude-sonnet-5", "medium"),
|
|
4918
|
+
"Doc index": cell("claude-opus-5", "medium")
|
|
4919
|
+
},
|
|
4920
|
+
{
|
|
4921
|
+
Brainstorm: cell("gpt-5.6-terra", "medium"),
|
|
4922
|
+
Objective: cell("gpt-5.6-terra", "medium"),
|
|
4923
|
+
"Doc index": cell("gpt-5.6-sol", "medium")
|
|
4924
|
+
}
|
|
4925
|
+
),
|
|
4926
|
+
reverse: flow(
|
|
4927
|
+
{
|
|
4928
|
+
Scan: cell("claude-sonnet-5", "medium"),
|
|
4929
|
+
"Docs teknis": cell("claude-sonnet-5", "medium"),
|
|
4930
|
+
Wawancara: cell("claude-sonnet-5", "medium"),
|
|
4931
|
+
"Konvensi & index": cell("claude-sonnet-5", "medium"),
|
|
4932
|
+
"Serah terima": cell("claude-sonnet-5", "medium")
|
|
4933
|
+
},
|
|
4934
|
+
{
|
|
4935
|
+
Scan: cell("gpt-5.6-terra", "medium"),
|
|
4936
|
+
"Docs teknis": cell("gpt-5.6-terra", "medium"),
|
|
4937
|
+
Wawancara: cell("gpt-5.6-terra", "medium"),
|
|
4938
|
+
"Konvensi & index": cell("gpt-5.6-terra", "medium"),
|
|
4939
|
+
"Serah terima": cell("gpt-5.6-terra", "medium")
|
|
4940
|
+
}
|
|
4941
|
+
),
|
|
4942
|
+
prd: flow(
|
|
4943
|
+
{
|
|
4944
|
+
Brainstorm: cell("claude-sonnet-5", "medium"),
|
|
4945
|
+
PRD: cell("claude-opus-5", "medium")
|
|
4946
|
+
},
|
|
4947
|
+
{
|
|
4948
|
+
Brainstorm: cell("gpt-5.6-terra", "medium"),
|
|
4949
|
+
PRD: cell("gpt-5.6-sol", "medium")
|
|
4950
|
+
}
|
|
4951
|
+
),
|
|
4952
|
+
audit: flow(
|
|
4953
|
+
{
|
|
4954
|
+
Audit: cell("claude-sonnet-5", "medium"),
|
|
4955
|
+
Laporan: cell("claude-sonnet-5", "medium")
|
|
4956
|
+
},
|
|
4957
|
+
{
|
|
4958
|
+
Audit: cell("gpt-5.6-terra", "medium"),
|
|
4959
|
+
Laporan: cell("gpt-5.6-terra", "medium")
|
|
4960
|
+
}
|
|
4961
|
+
),
|
|
4962
|
+
breakdown: flow(
|
|
4963
|
+
{
|
|
4964
|
+
Analisis: cell("claude-opus-5", "medium"),
|
|
4965
|
+
Breakdown: cell("claude-opus-5", "medium")
|
|
4966
|
+
},
|
|
4967
|
+
{
|
|
4968
|
+
Analisis: cell("gpt-5.6-sol", "medium"),
|
|
4969
|
+
Breakdown: cell("gpt-5.6-sol", "medium")
|
|
4970
|
+
}
|
|
4971
|
+
),
|
|
4972
|
+
goal: flow(
|
|
4973
|
+
{
|
|
4974
|
+
Goal: cell("claude-sonnet-5", "medium"),
|
|
4975
|
+
Verifikasi: cell("claude-sonnet-5", "medium")
|
|
4976
|
+
},
|
|
4977
|
+
{
|
|
4978
|
+
Goal: cell("gpt-5.6-terra", "medium"),
|
|
4979
|
+
Verifikasi: cell("gpt-5.6-terra", "medium")
|
|
4980
|
+
}
|
|
4981
|
+
),
|
|
4982
|
+
no_effort: flow(
|
|
4983
|
+
{ Kerjakan: cell("claude-haiku-4-5", "low") },
|
|
4984
|
+
{ Kerjakan: cell("gpt-5.6-terra", "low") },
|
|
4985
|
+
false
|
|
4986
|
+
)
|
|
4987
|
+
};
|
|
4988
|
+
seededFlows = Object.fromEntries(ORCHESTRATION_FLOWS.flatMap((flow2) => [
|
|
4989
|
+
[`${flow2}.enabled`, "seeded"],
|
|
4990
|
+
...["claude", "codex"].flatMap((runtime) => FLOW_PHASES[flow2].flatMap((phase) => [
|
|
4991
|
+
[`${flow2}.${runtime}.${phase}.model`, "seeded"],
|
|
4992
|
+
[`${flow2}.${runtime}.${phase}.effort`, "seeded"]
|
|
4993
|
+
]))
|
|
4994
|
+
]));
|
|
4995
|
+
BUILTIN_RUNTIME_DEFAULTS = {
|
|
4996
|
+
version: RUNTIME_DEFAULTS_VERSION,
|
|
4997
|
+
claude: { model: "seeded", effort: "seeded" },
|
|
4998
|
+
codex: { model: "seeded", effort: "seeded" },
|
|
4999
|
+
orchestration: seededFlows
|
|
5000
|
+
};
|
|
5001
|
+
}
|
|
5002
|
+
});
|
|
5003
|
+
|
|
4796
5004
|
// ../shared/src/entities.ts
|
|
4797
5005
|
function replaceModelCatalog(claude, codex2) {
|
|
4798
5006
|
MODELS = claude;
|
|
@@ -4826,7 +5034,7 @@ function cmpVersion(a, b) {
|
|
|
4826
5034
|
}
|
|
4827
5035
|
return 0;
|
|
4828
5036
|
}
|
|
4829
|
-
var zProject, zBriefPayload, zQaPayload, zGoalPayload, zSpecBlocker, zSourceChange, zManualDone, zSpec, NOTIFY_SOUNDS, MODELS, EFFORTS, 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, CHANGELOG_ENGINE_DEFAULTS, zLeadEngine, zLead, LEAD_DEFAULTS, zPortalChat, PORTAL_CHAT_DEFAULTS, zPhaseCell, zFlowOrchestration, zOrchestration, ORCHESTRATION_DEFAULTS, zSetting, zNotification, zDocFile, zDeviceTokenView;
|
|
5037
|
+
var zProject, zBriefPayload, zQaPayload, zGoalPayload, zSpecBlocker, zSourceChange, zManualDone, zSpec, NOTIFY_SOUNDS, MODELS, EFFORTS, 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, CHANGELOG_ENGINE_DEFAULTS, zLeadEngine, zLead, LEAD_DEFAULTS, zPortalChat, PORTAL_CHAT_DEFAULTS, zPhaseCell, zPhaseOverride, zPhaseOverrides, zFlowOrchestration, zOrchestration, ORCHESTRATION_DEFAULTS, zSetting, zNotification, zDocFile, zDeviceTokenView;
|
|
4830
5038
|
var init_entities = __esm({
|
|
4831
5039
|
"../shared/src/entities.ts"() {
|
|
4832
5040
|
"use strict";
|
|
@@ -4838,6 +5046,7 @@ var init_entities = __esm({
|
|
|
4838
5046
|
init_method_catalog();
|
|
4839
5047
|
init_relay();
|
|
4840
5048
|
init_logs();
|
|
5049
|
+
init_runtime_defaults();
|
|
4841
5050
|
zProject = external_exports.object({
|
|
4842
5051
|
id: external_exports.string(),
|
|
4843
5052
|
name: external_exports.string(),
|
|
@@ -4971,8 +5180,8 @@ var init_entities = __esm({
|
|
|
4971
5180
|
"gpt-5.3-codex-spark": "gpt-5.5"
|
|
4972
5181
|
};
|
|
4973
5182
|
zCodex = external_exports.object({
|
|
4974
|
-
model: external_exports.string().default("gpt-5.6-
|
|
4975
|
-
effort: external_exports.string().default("
|
|
5183
|
+
model: external_exports.string().default("gpt-5.6-terra"),
|
|
5184
|
+
effort: external_exports.string().default("medium")
|
|
4976
5185
|
});
|
|
4977
5186
|
CODEX_DEFAULTS = zCodex.parse({});
|
|
4978
5187
|
zSourceCommon = { enabled: external_exports.boolean().default(false) };
|
|
@@ -5063,6 +5272,11 @@ var init_entities = __esm({
|
|
|
5063
5272
|
model: external_exports.string().nullable().default(null),
|
|
5064
5273
|
effort: external_exports.string().nullable().default(null)
|
|
5065
5274
|
});
|
|
5275
|
+
zPhaseOverride = external_exports.object({
|
|
5276
|
+
model: external_exports.string().optional(),
|
|
5277
|
+
effort: external_exports.string().optional()
|
|
5278
|
+
});
|
|
5279
|
+
zPhaseOverrides = external_exports.record(external_exports.string(), zPhaseOverride);
|
|
5066
5280
|
zFlowOrchestration = external_exports.object({
|
|
5067
5281
|
enabled: external_exports.boolean().default(true),
|
|
5068
5282
|
claude: external_exports.record(external_exports.string(), zPhaseCell).default({}),
|
|
@@ -5079,10 +5293,10 @@ var init_entities = __esm({
|
|
|
5079
5293
|
goal: zFlowOrchestration.default({}),
|
|
5080
5294
|
no_effort: zFlowOrchestration.default({})
|
|
5081
5295
|
});
|
|
5082
|
-
ORCHESTRATION_DEFAULTS = zOrchestration.parse(
|
|
5296
|
+
ORCHESTRATION_DEFAULTS = zOrchestration.parse(BUILTIN_ORCHESTRATION_DEFAULTS);
|
|
5083
5297
|
zSetting = external_exports.object({
|
|
5084
|
-
model: external_exports.string().default("claude-
|
|
5085
|
-
effort: external_exports.string().default("
|
|
5298
|
+
model: external_exports.string().default("claude-sonnet-5"),
|
|
5299
|
+
effort: external_exports.string().default("medium"),
|
|
5086
5300
|
autoDefault: external_exports.boolean(),
|
|
5087
5301
|
autoScaffold: external_exports.boolean(),
|
|
5088
5302
|
notifyFail: external_exports.boolean(),
|
|
@@ -5143,7 +5357,10 @@ var init_entities = __esm({
|
|
|
5143
5357
|
builtinAgents: external_exports.record(external_exports.string(), external_exports.string()).default({}),
|
|
5144
5358
|
// SPEC-950 · marker safety policy lokal. Terpisah dari fingerprint konten agar policy sekali
|
|
5145
5359
|
// jalan tidak membuat seed memperlakukan konfigurasi operator sebagai bawaan.
|
|
5146
|
-
builtinAgentPolicies: external_exports.record(external_exports.string(), external_exports.string()).default({})
|
|
5360
|
+
builtinAgentPolicies: external_exports.record(external_exports.string(), external_exports.string()).default({}),
|
|
5361
|
+
// Marker lokal per bagian: `seeded` boleh menerima rekomendasi baru saat update, `user` harus
|
|
5362
|
+
// dipertahankan. Setting tidak ikut sync, sehingga keputusan operator tetap milik mesin ini.
|
|
5363
|
+
builtinRuntimeDefaults: zBuiltinRuntimeDefaults.default(BUILTIN_RUNTIME_DEFAULTS)
|
|
5147
5364
|
});
|
|
5148
5365
|
zNotification = external_exports.object({
|
|
5149
5366
|
id: external_exports.string(),
|
|
@@ -5177,38 +5394,6 @@ var init_entities = __esm({
|
|
|
5177
5394
|
}
|
|
5178
5395
|
});
|
|
5179
5396
|
|
|
5180
|
-
// ../shared/src/orchestration.ts
|
|
5181
|
-
function phaseAgentName(phase) {
|
|
5182
|
-
return PHASE_AGENT_PREFIX + phase.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
5183
|
-
}
|
|
5184
|
-
var FLOW_PHASES, PHASE_AGENT_PREFIX, isPhaseAgentName, PHASE_EVIDENCE_GRACE_MS;
|
|
5185
|
-
var init_orchestration = __esm({
|
|
5186
|
-
"../shared/src/orchestration.ts"() {
|
|
5187
|
-
"use strict";
|
|
5188
|
-
FLOW_PHASES = {
|
|
5189
|
-
feature: ["Brainstorm", "Objective", "Spec", "Plan", "Execute"],
|
|
5190
|
-
qa: ["Audit", "Spec", "Plan", "Execute"],
|
|
5191
|
-
scaffold: ["Brainstorm", "Objective", "Doc index"],
|
|
5192
|
-
reverse: ["Scan", "Docs teknis", "Wawancara", "Konvensi & index", "Serah terima"],
|
|
5193
|
-
prd: ["Brainstorm", "PRD"],
|
|
5194
|
-
audit: ["Audit", "Laporan"],
|
|
5195
|
-
breakdown: ["Analisis", "Breakdown"],
|
|
5196
|
-
// SPEC-337 · ADR-0075 · audit lintas project: fase & stage-map identik audit-only, scope-nya
|
|
5197
|
-
// yang berbeda (project utama + tetangga ProjectLink).
|
|
5198
|
-
// SPEC-407 · ADR-0089 · backlog goal: tak ada fase perencanaan sama sekali. `Goal` = kerjakan,
|
|
5199
|
-
// `Verifikasi` = buktikan. Kedua nama unik lintas daftar ini — syarat peta REACHED di server,
|
|
5200
|
-
// yang berkunci nama fase saja.
|
|
5201
|
-
goal: ["Goal", "Verifikasi"],
|
|
5202
|
-
// SPEC-825 · ADR-0123 · task remeh: SATU fase. Nama `Kerjakan` unik lintas daftar ini — syarat
|
|
5203
|
-
// peta REACHED server, yang berkunci nama fase saja.
|
|
5204
|
-
no_effort: ["Kerjakan"]
|
|
5205
|
-
};
|
|
5206
|
-
PHASE_AGENT_PREFIX = "hanoman-fase-";
|
|
5207
|
-
isPhaseAgentName = (name2) => name2.startsWith(PHASE_AGENT_PREFIX);
|
|
5208
|
-
PHASE_EVIDENCE_GRACE_MS = 6e4;
|
|
5209
|
-
}
|
|
5210
|
-
});
|
|
5211
|
-
|
|
5212
5397
|
// ../shared/src/orchestration-plan.ts
|
|
5213
5398
|
function codexNativeAgentsSupported(version) {
|
|
5214
5399
|
const parsed = version ? /(\d+)\.(\d+)\.(\d+)/.exec(version)?.[0] : null;
|
|
@@ -5223,13 +5408,14 @@ function resolvePhasePlan(input) {
|
|
|
5223
5408
|
flow: input.flow,
|
|
5224
5409
|
runtime: input.runtime,
|
|
5225
5410
|
phases: FLOW_PHASES[input.flow].map((phase) => {
|
|
5226
|
-
const
|
|
5227
|
-
const
|
|
5411
|
+
const cell2 = cells[phase];
|
|
5412
|
+
const override = input.phaseOverrides?.[phase];
|
|
5413
|
+
const model = override?.model ?? cell2?.model ?? input.orchestrator.model;
|
|
5228
5414
|
return {
|
|
5229
5415
|
phase,
|
|
5230
5416
|
agentName: phaseAgentName(phase),
|
|
5231
5417
|
model,
|
|
5232
|
-
effort: coerce3(model,
|
|
5418
|
+
effort: coerce3(model, override?.effort ?? cell2?.effort ?? input.orchestrator.effort)
|
|
5233
5419
|
};
|
|
5234
5420
|
})
|
|
5235
5421
|
};
|
|
@@ -6910,7 +7096,7 @@ var init_dto = __esm({
|
|
|
6910
7096
|
}).default({ inFlight: 0, queued: 0, capacity: 1 })
|
|
6911
7097
|
});
|
|
6912
7098
|
zFlow = external_exports.enum(["feature", "qa", "scaffold", "reverse", "prd", "audit", "breakdown", "goal", "no_effort"]);
|
|
6913
|
-
isGoalShapedFlow = (
|
|
7099
|
+
isGoalShapedFlow = (flow2) => flow2 === "goal" || flow2 === "no_effort";
|
|
6914
7100
|
zPrdBrief = external_exports.object({
|
|
6915
7101
|
title: external_exports.string().min(1),
|
|
6916
7102
|
context: external_exports.string(),
|
|
@@ -7026,6 +7212,9 @@ var init_dto = __esm({
|
|
|
7026
7212
|
flow: zFlow,
|
|
7027
7213
|
model: external_exports.string().optional(),
|
|
7028
7214
|
effort: external_exports.string().optional(),
|
|
7215
|
+
// Override model/effort subagent hanya berlaku untuk sesi ini; kosong berarti memakai
|
|
7216
|
+
// rekomendasi bawaan atau matriks Settings pada fase tersebut.
|
|
7217
|
+
phaseOverrides: zPhaseOverrides.optional(),
|
|
7029
7218
|
goal: external_exports.boolean().optional(),
|
|
7030
7219
|
goalCondition: external_exports.string().max(4e3).optional(),
|
|
7031
7220
|
agent: zAgent.optional(),
|
|
@@ -11244,9 +11433,9 @@ var init_sessions = __esm({
|
|
|
11244
11433
|
}
|
|
11245
11434
|
const project = String(a.project);
|
|
11246
11435
|
if (a.shell === true) return { method: "POST", path: "/terminal/sessions", body: { project, shell: true } };
|
|
11247
|
-
const
|
|
11248
|
-
if (
|
|
11249
|
-
if (
|
|
11436
|
+
const flow2 = s(a.flow);
|
|
11437
|
+
if (flow2 === "breakdown") return { method: "POST", path: "/terminal/sessions", body: { project, flow: flow2, prdPath: String(a.prdPath) } };
|
|
11438
|
+
if (flow2 === "reverse" || flow2 === "scaffold") return { method: "POST", path: "/terminal/sessions", body: { project, flow: flow2 } };
|
|
11250
11439
|
const body = { project };
|
|
11251
11440
|
for (const k of ["agent", "model", "effort"]) if (s(a[k]) !== void 0) body[k] = s(a[k]);
|
|
11252
11441
|
return { method: "POST", path: "/terminal/sessions", body };
|
|
@@ -12563,6 +12752,7 @@ var init_src = __esm({
|
|
|
12563
12752
|
init_pending();
|
|
12564
12753
|
init_team();
|
|
12565
12754
|
init_model_catalog();
|
|
12755
|
+
init_runtime_defaults();
|
|
12566
12756
|
}
|
|
12567
12757
|
});
|
|
12568
12758
|
|
|
@@ -12797,10 +12987,10 @@ var init_goal_spec = __esm({
|
|
|
12797
12987
|
function guideLine(guide, phase) {
|
|
12798
12988
|
return guide.split("\n").find((line) => line.startsWith(`- ${phase}:`)) ?? "";
|
|
12799
12989
|
}
|
|
12800
|
-
function phaseSkillsFor(
|
|
12990
|
+
function phaseSkillsFor(flow2, phase, method) {
|
|
12801
12991
|
const own = method.phaseSkills[phase] ?? [];
|
|
12802
|
-
const phases = PIPELINES[
|
|
12803
|
-
return writesCode(
|
|
12992
|
+
const phases = PIPELINES[flow2];
|
|
12993
|
+
return writesCode(flow2) && phase === phases[phases.length - 1] ? [.../* @__PURE__ */ new Set([...own, ...method.exitSkills])] : [...own];
|
|
12804
12994
|
}
|
|
12805
12995
|
function orchestratorClause(plan, o = {}) {
|
|
12806
12996
|
const codex2 = plan.runtime === "codex";
|
|
@@ -12833,15 +13023,15 @@ ${describeRule}`,
|
|
|
12833
13023
|
'Pekerjaan ini BELUM selesai sampai SEMUA fase di daftar di atas punya baris `done` atau `skipped` di $HANOMAN_PHASE_FILE \u2014 JANGAN commit/push final atau menyatakan tuntas sebelum itu. Periksa dengan `cat "$HANOMAN_PHASE_FILE"` sebelum commit terakhir.'
|
|
12834
13024
|
].filter(Boolean).join("\n\n");
|
|
12835
13025
|
}
|
|
12836
|
-
function startPrompt(
|
|
13026
|
+
function startPrompt(flow2, spec, branchTo, autonomy, verifyScope, method, attachments, plan) {
|
|
12837
13027
|
const m = resolveMethod(method);
|
|
12838
|
-
const head = `hanoman ${
|
|
13028
|
+
const head = `hanoman ${flow2}. Ikuti internal/docs sebagai Source of Truth; perbarui docs yang tersentuh dan link-nya di index, dalam commit yang sama.`;
|
|
12839
13029
|
const push = `Setelah fase terakhir: commit, lalu \`git push origin HEAD:refs/heads/${branchTo}\`. Worktree ini detached HEAD \u2014 itu memang disengaja.`;
|
|
12840
13030
|
if (plan) {
|
|
12841
13031
|
return [
|
|
12842
13032
|
head,
|
|
12843
|
-
orchestratorClause(plan, { fastPath:
|
|
12844
|
-
auditContinuationForOrchestrator(
|
|
13033
|
+
orchestratorClause(plan, { fastPath: flow2 === "qa" }),
|
|
13034
|
+
auditContinuationForOrchestrator(flow2, spec),
|
|
12845
13035
|
autonomyClause(autonomy),
|
|
12846
13036
|
attachmentClause(attachments),
|
|
12847
13037
|
push,
|
|
@@ -12850,23 +13040,23 @@ function startPrompt(flow, spec, branchTo, autonomy, verifyScope, method, attach
|
|
|
12850
13040
|
}
|
|
12851
13041
|
return [
|
|
12852
13042
|
head,
|
|
12853
|
-
phaseInstruction(PIPELINES[
|
|
12854
|
-
auditDecisionInstruction(
|
|
12855
|
-
auditContinuationInstruction(
|
|
12856
|
-
auditOnlyInstruction(
|
|
13043
|
+
phaseInstruction(PIPELINES[flow2], m),
|
|
13044
|
+
auditDecisionInstruction(flow2),
|
|
13045
|
+
auditContinuationInstruction(flow2, spec),
|
|
13046
|
+
auditOnlyInstruction(flow2),
|
|
12857
13047
|
autonomyClause(autonomy),
|
|
12858
|
-
scopeClause(
|
|
12859
|
-
codeStyleClause(
|
|
13048
|
+
scopeClause(flow2, verifyScope),
|
|
13049
|
+
codeStyleClause(flow2),
|
|
12860
13050
|
methodClause(m),
|
|
12861
13051
|
attachmentClause(attachments),
|
|
12862
|
-
skillInstruction(
|
|
13052
|
+
skillInstruction(flow2, PIPELINES[flow2], m),
|
|
12863
13053
|
push,
|
|
12864
13054
|
specContext(spec)
|
|
12865
13055
|
].filter(Boolean).join("\n\n");
|
|
12866
13056
|
}
|
|
12867
|
-
function continuePrompt(
|
|
13057
|
+
function continuePrompt(flow2, spec, branchTo, autonomy, verifyScope, method, attachments, plan) {
|
|
12868
13058
|
const m = resolveMethod(method);
|
|
12869
|
-
const head = `hanoman ${
|
|
13059
|
+
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.`;
|
|
12870
13060
|
const push = `Setelah selesai: commit, lalu \`git push origin HEAD:refs/heads/${branchTo}\`. Worktree ini detached HEAD \u2014 itu memang disengaja.`;
|
|
12871
13061
|
if (plan) {
|
|
12872
13062
|
return [
|
|
@@ -12883,26 +13073,26 @@ function continuePrompt(flow, spec, branchTo, autonomy, verifyScope, method, att
|
|
|
12883
13073
|
head,
|
|
12884
13074
|
`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.`,
|
|
12885
13075
|
autonomyClause(autonomy),
|
|
12886
|
-
scopeClause(
|
|
12887
|
-
codeStyleClause(
|
|
13076
|
+
scopeClause(flow2, verifyScope),
|
|
13077
|
+
codeStyleClause(flow2),
|
|
12888
13078
|
methodClause(m),
|
|
12889
13079
|
attachmentClause(attachments),
|
|
12890
|
-
skillInstruction(
|
|
13080
|
+
skillInstruction(flow2, ["Execute"], m),
|
|
12891
13081
|
push,
|
|
12892
13082
|
specContext(spec)
|
|
12893
13083
|
].filter(Boolean).join("\n\n");
|
|
12894
13084
|
}
|
|
12895
|
-
function resumePrompt(
|
|
13085
|
+
function resumePrompt(flow2, spec, branchTo, resume, autonomy, verifyScope, method, attachments, plan) {
|
|
12896
13086
|
const m = resolveMethod(method);
|
|
12897
13087
|
const auditDecided = resume.recorded.some((line) => line.startsWith("Audit "));
|
|
12898
|
-
const head = `hanoman ${
|
|
12899
|
-
const resumed = resumeClause(resume, branchTo, m.planDir, PIPELINES[
|
|
13088
|
+
const head = `hanoman ${flow2} \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.`;
|
|
13089
|
+
const resumed = resumeClause(resume, branchTo, m.planDir, PIPELINES[flow2].includes("Plan"));
|
|
12900
13090
|
const push = `Setelah fase terakhir: commit, lalu \`git push origin HEAD:refs/heads/${branchTo}\`. Worktree ini detached HEAD \u2014 itu memang disengaja.`;
|
|
12901
13091
|
if (plan) {
|
|
12902
13092
|
return [
|
|
12903
13093
|
head,
|
|
12904
13094
|
resumed,
|
|
12905
|
-
orchestratorClause(plan, { fastPath:
|
|
13095
|
+
orchestratorClause(plan, { fastPath: flow2 === "qa" && !auditDecided }),
|
|
12906
13096
|
autonomyClause(autonomy),
|
|
12907
13097
|
attachmentClause(attachments),
|
|
12908
13098
|
push,
|
|
@@ -12912,21 +13102,21 @@ function resumePrompt(flow, spec, branchTo, resume, autonomy, verifyScope, metho
|
|
|
12912
13102
|
return [
|
|
12913
13103
|
head,
|
|
12914
13104
|
resumed,
|
|
12915
|
-
phaseInstruction(PIPELINES[
|
|
12916
|
-
auditDecided ? "" : auditDecisionInstruction(
|
|
13105
|
+
phaseInstruction(PIPELINES[flow2], m),
|
|
13106
|
+
auditDecided ? "" : auditDecisionInstruction(flow2),
|
|
12917
13107
|
autonomyClause(autonomy),
|
|
12918
|
-
scopeClause(
|
|
12919
|
-
codeStyleClause(
|
|
13108
|
+
scopeClause(flow2, verifyScope),
|
|
13109
|
+
codeStyleClause(flow2),
|
|
12920
13110
|
methodClause(m),
|
|
12921
13111
|
attachmentClause(attachments),
|
|
12922
|
-
skillInstruction(
|
|
13112
|
+
skillInstruction(flow2, PIPELINES[flow2], m),
|
|
12923
13113
|
push,
|
|
12924
13114
|
specContext(spec)
|
|
12925
13115
|
].filter(Boolean).join("\n\n");
|
|
12926
13116
|
}
|
|
12927
|
-
function startGoalPrompt(
|
|
13117
|
+
function startGoalPrompt(flow2, spec, branchTo, opts = {}) {
|
|
12928
13118
|
const m = resolveMethod(opts.method);
|
|
12929
|
-
const noEffort =
|
|
13119
|
+
const noEffort = flow2 === "no_effort";
|
|
12930
13120
|
const head = noEffort ? "hanoman no-effort \u2014 sesi ini mengerjakan SATU pekerjaan remeh lalu berhenti. TIDAK ada fase Brainstorm, Objective, Spec, Plan, maupun fase pembuktian terpisah: jangan menulis design doc, jangan menulis plan berkotak, jangan memecah pekerjaan ini jadi backlog baru, dan jangan menambah fase sendiri. Langsung kerjakan, buktikan seperlunya di fase yang sama, lalu berhenti. Tetap ikuti internal/docs sebagai Source of Truth; perbarui docs yang tersentuh dan link-nya di index, dalam commit yang sama." : "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.";
|
|
12931
13121
|
const resumed = opts.resume ? resumeClause(opts.resume, branchTo, m.planDir, false) : "";
|
|
12932
13122
|
const push = `Setelah fase terakhir: commit, lalu \`git push origin HEAD:refs/heads/${branchTo}\`. Worktree ini detached HEAD \u2014 itu memang disengaja.`;
|
|
@@ -12946,31 +13136,31 @@ function startGoalPrompt(flow, spec, branchTo, opts = {}) {
|
|
|
12946
13136
|
head,
|
|
12947
13137
|
resumed,
|
|
12948
13138
|
goalDetail(spec),
|
|
12949
|
-
phaseInstruction(PIPELINES[
|
|
13139
|
+
phaseInstruction(PIPELINES[flow2], m),
|
|
12950
13140
|
noEffort ? "" : "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.",
|
|
12951
13141
|
autonomyClause(opts.autonomy),
|
|
12952
|
-
scopeClause(
|
|
12953
|
-
codeStyleClause(
|
|
13142
|
+
scopeClause(flow2, opts.verifyScope),
|
|
13143
|
+
codeStyleClause(flow2),
|
|
12954
13144
|
methodClause(m),
|
|
12955
13145
|
attachmentClause(opts.attachments),
|
|
12956
|
-
skillInstruction(
|
|
13146
|
+
skillInstruction(flow2, PIPELINES[flow2], m),
|
|
12957
13147
|
push,
|
|
12958
13148
|
goalBlock(spec)
|
|
12959
13149
|
].filter(Boolean).join("\n\n");
|
|
12960
13150
|
}
|
|
12961
|
-
function startProjectPrompt(
|
|
13151
|
+
function startProjectPrompt(flow2, project, branchTo, plan) {
|
|
12962
13152
|
const push = `Setiap fase selesai: commit hasilnya, lalu \`git push origin HEAD:refs/heads/${branchTo}\` \u2014 push per fase, supaya pekerjaan tak hilang bila worktree lenyap. Bila remote origin tidak ada, lewati push dan catat itu di laporan akhir \u2014 jangan gagal diam-diam. Worktree ini detached HEAD \u2014 memang disengaja. Manusia yang me-review dan merge branch ${branchTo}.`;
|
|
12963
13153
|
if (plan) {
|
|
12964
13154
|
return [
|
|
12965
|
-
`hanoman ${
|
|
13155
|
+
`hanoman ${flow2}. Susun Source of Truth repo ini dari kodenya di internal/docs/** lewat subagent fase; STANDAR DOCS ada di definisi agen fase penulis docs.`,
|
|
12966
13156
|
orchestratorClause(plan),
|
|
12967
13157
|
push,
|
|
12968
13158
|
projectContext(project)
|
|
12969
13159
|
].join("\n\n");
|
|
12970
13160
|
}
|
|
12971
13161
|
return [
|
|
12972
|
-
`hanoman ${
|
|
12973
|
-
phaseInstruction(PIPELINES[
|
|
13162
|
+
`hanoman ${flow2}. Susun Source of Truth repo ini dari kodenya di internal/docs/**, mengikuti STANDAR DOCS di bagian bawah prompt ini.`,
|
|
13163
|
+
phaseInstruction(PIPELINES[flow2], PROJECT_METHOD),
|
|
12974
13164
|
REVERSE_PHASE_GUIDE,
|
|
12975
13165
|
push,
|
|
12976
13166
|
projectContext(project),
|
|
@@ -13081,15 +13271,15 @@ Setiap kali sebuah fase selesai (atau kamu putuskan dilewati), append satu baris
|
|
|
13081
13271
|
return base2 + `
|
|
13082
13272
|
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 \`- [ ]\`.`;
|
|
13083
13273
|
};
|
|
13084
|
-
skillInstruction = (
|
|
13274
|
+
skillInstruction = (flow2, phases, method) => {
|
|
13085
13275
|
const lines2 = phases.map((p3) => {
|
|
13086
|
-
const skills = phaseSkillsFor(
|
|
13276
|
+
const skills = phaseSkillsFor(flow2, p3, method);
|
|
13087
13277
|
return skills.length ? `- ${p3}: ${skills.join(", ")}` : "";
|
|
13088
13278
|
}).filter(Boolean);
|
|
13089
13279
|
return lines2.length ? `Skills ${method.label} WAJIB: sebelum mengerjakan fase di bawah, muat & ikuti skill-nya dengan mekanisme yang tersedia di agenmu \u2014 bila skill relevan tersedia, pakai.
|
|
13090
13280
|
${lines2.join("\n")}` : "";
|
|
13091
13281
|
};
|
|
13092
|
-
auditDecisionInstruction = (
|
|
13282
|
+
auditDecisionInstruction = (flow2) => flow2 !== "qa" ? "" : 'Keputusan pasca-Audit (qa): bila temuan berconfidence tinggi dan perbaikannya bisa dikerjakan langsung (diff kecil, akar masalah jelas), LEWATI Spec dan Plan \u2014 tandai keduanya `skipped` (`echo "Spec skipped" >> "$HANOMAN_PHASE_FILE"` lalu `echo "Plan skipped" >> "$HANOMAN_PHASE_FILE"`) dan langsung ke Execute; dokumen audit menjadi doc-of-record perbaikan itu. Bila temuan luas, berisiko, atau ambigu, jalankan Spec \u2192 Plan \u2192 Execute penuh. Keputusan ini milikmu berdasarkan hasil Audit, bukan default \u2014 jangan bayar perencanaan yang tak perlu untuk perbaikan sepele.';
|
|
13093
13283
|
ESCALATION_CONTRACT = [
|
|
13094
13284
|
"REKOMENDASI ESKALASI (wajib, terbaca mesin). Di bagian akhir dokumen audit, tulis bagian",
|
|
13095
13285
|
"`## Rekomendasi eskalasi` berisi penjelasan singkat untuk manusia, LALU tepat SATU blok ```json",
|
|
@@ -13112,28 +13302,28 @@ ${lines2.join("\n")}` : "";
|
|
|
13112
13302
|
"",
|
|
13113
13303
|
"`alternatives` boleh array kosong. Jangan menulis blok json lain di dokumen itu."
|
|
13114
13304
|
].join("\n");
|
|
13115
|
-
auditOnlyInstruction = (
|
|
13116
|
-
auditContinuationInstruction = (
|
|
13117
|
-
if (
|
|
13305
|
+
auditOnlyInstruction = (flow2) => flow2 !== "audit" ? "" : "Ini audit-only: investigasi SAJA, JANGAN menulis perbaikan kode apa pun. Fase Audit (systematic-debugging): telusuri akar masalah / log / jawaban dan nilai apakah issue terdefinisi dengan baik. Fase Laporan: tulis DOKUMEN AUDIT ke Source of Truth `internal/docs/research/audit-<spec-id>-<slug>.md` (ikuti konvensi audit yang ada), tautkan di `internal/docs/README.md`, memuat: keluhan/pertanyaan, temuan (dengan bukti/log), apakah issue terdefinisi baik, dan rekomendasi tindak lanjut. Commit dokumen itu lalu push. Tak ada kode fitur.\n\n" + ESCALATION_CONTRACT;
|
|
13306
|
+
auditContinuationInstruction = (flow2, spec) => {
|
|
13307
|
+
if (flow2 !== "qa" && flow2 !== "feature") return "";
|
|
13118
13308
|
const fromAudit = spec.payload && typeof spec.payload === "object" ? spec.payload.fromAudit : void 0;
|
|
13119
13309
|
if (typeof fromAudit !== "string" || !fromAudit) return "";
|
|
13120
13310
|
const doc = `internal/docs/research/audit-${fromAudit.toLowerCase()}-*.md`;
|
|
13121
|
-
if (
|
|
13311
|
+
if (flow2 === "feature")
|
|
13122
13312
|
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.`;
|
|
13123
13313
|
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.`;
|
|
13124
13314
|
};
|
|
13125
|
-
auditContinuationForOrchestrator = (
|
|
13126
|
-
if (
|
|
13315
|
+
auditContinuationForOrchestrator = (flow2, spec) => {
|
|
13316
|
+
if (flow2 !== "qa" && flow2 !== "feature") return "";
|
|
13127
13317
|
const fromAudit = spec.payload && typeof spec.payload === "object" ? spec.payload.fromAudit : void 0;
|
|
13128
13318
|
if (typeof fromAudit !== "string" || !fromAudit) return "";
|
|
13129
13319
|
const doc = `internal/docs/research/audit-${fromAudit.toLowerCase()}-*.md`;
|
|
13130
|
-
if (
|
|
13320
|
+
if (flow2 === "feature")
|
|
13131
13321
|
return `Backlog brief ini LANJUTAN dari audit ${fromAudit}. Worktree ini lahir dari branch audit itu, jadi dokumen audit sudah ada di ${doc}. Saat memanggil agen fase Brainstorm, cantumkan path itu di baris \`Artefak fase sebelumnya:\` blok serah-terima \u2014 JANGAN membacanya sendiri untuk merancang fitur ini. Saat memanggil agen fase Objective, baris itu biasanya sudah membawa path artefak Brainstorm (dokumen spec yang ditulis fase itu); tambahkan path dokumen audit di samping path itu, bukan menggantikannya. Temuannya sudah terbukti, tapi bentuk solusinya belum; itu tetap dikerjakan agen fasenya masing-masing, bukan olehmu.`;
|
|
13132
13322
|
return `Backlog qa ini LANJUTAN dari audit ${fromAudit}. Temuannya sudah terbukti di ${doc} \u2014 JANGAN mendelegasikan ulang fase Audit. Sebelum fase lain: jalankan persis \`echo "Audit skipped" >> "$HANOMAN_PHASE_FILE"\`, verifikasi dengan \`tail -1 "$HANOMAN_PHASE_FILE"\` bahwa barisnya benar tertulis (gerbang yang sama seperti langkah 2), lalu cantumkan path dokumen audit itu di baris \`Artefak fase sebelumnya:\` saat memanggil agen fase Spec. Keputusan routing di sini menggantikan langkah 5 di atas \u2014 JANGAN menunggu frasa \`Rekomendasi fase: jalur-cepat\` dari agen Audit karena Audit tidak dijalankan pada kelanjutan ini. Kamu diizinkan mengambil SATU keputusan ROUTING dari isi dokumen audit itu SAJA, dibaca langsung dari kriterianya: temuan berconfidence tinggi dan perbaikan langsung berdiff kecil \u2192 tandai \`Spec skipped\` lalu \`Plan skipped\` (gerbang yang sama) lalu panggil agen fase Execute; selebihnya panggil Spec \u2192 Plan \u2192 Execute penuh lewat agen fasenya masing-masing. Kamu TIDAK menginvestigasi ulang maupun merancang perbaikannya sendiri \u2014 itu tetap pekerjaan agen fase.`;
|
|
13133
13323
|
};
|
|
13134
|
-
writesCode = (
|
|
13135
|
-
scopeClause = (
|
|
13136
|
-
codeStyleClause = (
|
|
13324
|
+
writesCode = (flow2) => PIPELINES[flow2].some((p3) => WORK_PHASES.includes(p3));
|
|
13325
|
+
scopeClause = (flow2, scope) => scope && writesCode(flow2) ? verifyScopeClause(scope) : "";
|
|
13326
|
+
codeStyleClause = (flow2) => writesCode(flow2) ? CODE_STYLE_CLAUSE : "";
|
|
13137
13327
|
methodClause = (method) => method.extraClause ?? "";
|
|
13138
13328
|
attachmentClause = (ctx) => {
|
|
13139
13329
|
if (!ctx || ctx.items.length === 0) return "";
|
|
@@ -13410,7 +13600,7 @@ var init_settings2 = __esm({
|
|
|
13410
13600
|
});
|
|
13411
13601
|
|
|
13412
13602
|
// ../runner/src/goal.ts
|
|
13413
|
-
function goalFlowCondition(
|
|
13603
|
+
function goalFlowCondition(flow2, specId, branchTo, spec) {
|
|
13414
13604
|
const g = readGoalPayload(spec?.payload);
|
|
13415
13605
|
const goal = g?.goal || (spec?.objective ?? "").trim() || "(goal tak tercatat di backlog item)";
|
|
13416
13606
|
const bukti = g?.done || goal;
|
|
@@ -13418,14 +13608,14 @@ function goalFlowCondition(flow, specId, branchTo, spec) {
|
|
|
13418
13608
|
`Sesi goal hanoman ${specId}. GOAL: ${goal}`,
|
|
13419
13609
|
"Sesi ini hanya boleh berhenti bila transkrip TERBARU memuat bukti langsung semua hal berikut:",
|
|
13420
13610
|
`1. goal tercapai \u2014 ${bukti};`,
|
|
13421
|
-
`2. output \`cat "$HANOMAN_PHASE_FILE"\` yang memuat satu baris untuk SETIAP fase ${PIPELINES[
|
|
13611
|
+
`2. output \`cat "$HANOMAN_PHASE_FILE"\` yang memuat satu baris untuk SETIAP fase ${PIPELINES[flow2].join(" \u2192 ")}, masing-masing berakhiran \`done\` atau \`skipped\`;`,
|
|
13422
13612
|
`3. output \`git push origin HEAD:refs/heads/${branchTo}\` yang SUKSES sesudah commit terakhir.`,
|
|
13423
13613
|
"Bila salah satu bukti tak ada di transkrip terbaru, kondisi BELUM terpenuhi: jalankan perintah verifikasinya, tuntaskan yang masih kurang, lalu lanjutkan \u2014 jangan berhenti."
|
|
13424
13614
|
].join("\n");
|
|
13425
13615
|
}
|
|
13426
|
-
function defaultGoalCondition({ flow, specId, branchTo, spec }) {
|
|
13427
|
-
if (isGoalShapedFlow(
|
|
13428
|
-
const phases = PIPELINES[
|
|
13616
|
+
function defaultGoalCondition({ flow: flow2, specId, branchTo, spec }) {
|
|
13617
|
+
if (isGoalShapedFlow(flow2)) return goalFlowCondition(flow2, specId, branchTo, spec);
|
|
13618
|
+
const phases = PIPELINES[flow2];
|
|
13429
13619
|
const planGate = phases.includes("Plan") && phases.includes("Execute");
|
|
13430
13620
|
const clauses = [
|
|
13431
13621
|
`1. output \`cat "$HANOMAN_PHASE_FILE"\` yang memuat satu baris untuk SETIAP fase ${phases.join(" \u2192 ")}, masing-masing berakhiran \`done\` atau \`skipped\`;`
|
|
@@ -13440,7 +13630,7 @@ function defaultGoalCondition({ flow, specId, branchTo, spec }) {
|
|
|
13440
13630
|
`${planGate ? 3 : 2}. output \`git push origin HEAD:refs/heads/${branchTo}\` yang SUKSES sesudah commit terakhir.`
|
|
13441
13631
|
);
|
|
13442
13632
|
return [
|
|
13443
|
-
`Sesi backlog hanoman ${specId} (flow ${
|
|
13633
|
+
`Sesi backlog hanoman ${specId} (flow ${flow2}) hanya boleh berhenti bila transkrip TERBARU memuat bukti langsung semua hal berikut:`,
|
|
13444
13634
|
...clauses,
|
|
13445
13635
|
`Bila salah satu bukti tak ada di transkrip terbaru, kondisi BELUM terpenuhi: jalankan perintah verifikasinya, tuntaskan yang masih kurang, lalu lanjutkan \u2014 jangan berhenti.`
|
|
13446
13636
|
].join("\n");
|
|
@@ -14044,7 +14234,7 @@ function fromAuditOf(payload) {
|
|
|
14044
14234
|
const value = payload.fromAudit;
|
|
14045
14235
|
return typeof value === "string" && value ? value : void 0;
|
|
14046
14236
|
}
|
|
14047
|
-
function backlogGuide(
|
|
14237
|
+
function backlogGuide(flow2, phase, ctx) {
|
|
14048
14238
|
const m = ctx.method;
|
|
14049
14239
|
switch (phase) {
|
|
14050
14240
|
case "Brainstorm":
|
|
@@ -14052,13 +14242,13 @@ function backlogGuide(flow, phase, ctx) {
|
|
|
14052
14242
|
case "Objective":
|
|
14053
14243
|
return "- Objective: baca dokumen spec dari fase Brainstorm (path-nya di serah-terima), lalu tambahkan bagian `## Objective` berisi SATU objective terukur beserta kriteria suksesnya.";
|
|
14054
14244
|
case "Spec":
|
|
14055
|
-
return
|
|
14245
|
+
return flow2 === "qa" ? `- Spec: tulis dokumen spec perbaikan di \`${m.specDir}/\` dari dokumen audit fase Audit (path-nya di serah-terima): akar masalah, bentuk perbaikan, dan acceptance criteria gaya EARS.` + (ctx.fromAudit ? ` Backlog ini LANJUTAN audit ${ctx.fromAudit} \u2014 fase Audit sengaja DILEWATI orchestrator, jadi baca dokumennya di \`internal/docs/research/audit-${ctx.fromAudit.toLowerCase()}-*.md\` (path juga ada di serah-terima) sebagai temuan; jangan menginvestigasi ulang dari nol.` : "") : "- Spec: lengkapi dokumen spec yang sama \u2014 arsitektur, komponen, kontrak data/API, penanganan galat, dan acceptance criteria gaya EARS. Perbarui docs Source of Truth yang tersentuh.";
|
|
14056
14246
|
case "Plan":
|
|
14057
14247
|
return `- Plan: tulis plan implementasi berkotak \`- [ ]\` di \`${m.planDir}/\` untuk backlog ini dari dokumen spec-nya (path di serah-terima).`;
|
|
14058
14248
|
case "Execute":
|
|
14059
14249
|
return `- Execute: kerjakan plan di \`${m.planDir}/**\` untuk backlog ini. Execute BELUM selesai selama plan masih punya task \`- [ ]\`: kerjakan SEMUA task sampai tiap kotak jadi \`- [x]\` sebelum melapor \`Status: selesai\`. hanoman menahan backlog di \`executing\`, bukan \`done\`, selama masih ada \`- [ ]\`.`;
|
|
14060
14250
|
case "Audit":
|
|
14061
|
-
return
|
|
14251
|
+
return flow2 === "audit" ? "- Audit: ini audit-only \u2014 investigasi SAJA, JANGAN menulis perbaikan kode apa pun. Telusuri akar masalah / log / jawaban dan nilai apakah issue terdefinisi dengan baik. Laporkan temuan beserta buktinya; dokumennya ditulis fase Laporan." : "- Audit: telusuri akar masalah dengan bukti (reproduksi, log, kode) dan tulis dokumen audit ke `internal/docs/research/audit-<spec-id>-<slug>.md`. Lalu putuskan jalurnya dari hasil Audit, bukan default: bila temuan berconfidence tinggi dan perbaikannya bisa dikerjakan langsung (diff kecil, akar masalah jelas), tulis `Rekomendasi fase: jalur-cepat` beserta alasannya \u2014 orchestrator akan melewati Spec & Plan dan dokumen audit menjadi doc-of-record perbaikan itu. Bila temuan luas, berisiko, atau ambigu, tulis `Rekomendasi fase: penuh`.";
|
|
14062
14252
|
case "Laporan":
|
|
14063
14253
|
return "- Laporan: tulis DOKUMEN AUDIT ke Source of Truth `internal/docs/research/audit-<spec-id>-<slug>.md` (ikuti konvensi audit yang ada), tautkan di `internal/docs/README.md`, memuat: keluhan/pertanyaan, temuan (dengan bukti/log), apakah issue terdefinisi baik, dan rekomendasi tindak lanjut. Commit dokumen itu. Tak ada kode fitur.\n\n" + ESCALATION_CONTRACT;
|
|
14064
14254
|
case "Goal":
|
|
@@ -14071,27 +14261,27 @@ function backlogGuide(flow, phase, ctx) {
|
|
|
14071
14261
|
return "";
|
|
14072
14262
|
}
|
|
14073
14263
|
}
|
|
14074
|
-
function projectGuide(
|
|
14075
|
-
if (
|
|
14076
|
-
if (
|
|
14077
|
-
const slug = ctx.prd?.slug ??
|
|
14078
|
-
const lines2 =
|
|
14264
|
+
function projectGuide(flow2, phase, ctx) {
|
|
14265
|
+
if (flow2 === "reverse") return guideLine(REVERSE_PHASE_GUIDE, phase);
|
|
14266
|
+
if (flow2 === "scaffold") return guideLine(SCAFFOLD_PHASE_GUIDE, phase);
|
|
14267
|
+
const slug = ctx.prd?.slug ?? flow2;
|
|
14268
|
+
const lines2 = flow2 === "prd" ? prdPhaseLines(slug) : breakdownPhaseLines(slug, ctx.prd?.title ?? slug);
|
|
14079
14269
|
return lines2[phase] ?? "";
|
|
14080
14270
|
}
|
|
14081
14271
|
function phaseAgentInstructions(entry, index, plan, ctx) {
|
|
14082
|
-
const { flow, method } = ctx;
|
|
14272
|
+
const { flow: flow2, method } = ctx;
|
|
14083
14273
|
const phase = entry.phase;
|
|
14084
|
-
const guide = PROJECT_FLOWS.has(
|
|
14085
|
-
const skills = phaseSkillsFor(
|
|
14274
|
+
const guide = PROJECT_FLOWS.has(flow2) ? projectGuide(flow2, phase, ctx) : backlogGuide(flow2, phase, ctx);
|
|
14275
|
+
const skills = phaseSkillsFor(flow2, phase, method);
|
|
14086
14276
|
const work = WORK_PHASES.includes(phase);
|
|
14087
14277
|
return [
|
|
14088
|
-
`Kamu agen fase "${phase}" (fase ${index + 1}/${plan.phases.length}) flow ${
|
|
14278
|
+
`Kamu agen fase "${phase}" (fase ${index + 1}/${plan.phases.length}) flow ${flow2} hanoman. Ikuti internal/docs sebagai Source of Truth; perbarui docs yang tersentuh dan link-nya di index, dalam commit yang sama.`,
|
|
14089
14279
|
guide,
|
|
14090
14280
|
DOC_WRITING_PHASES.has(phase) ? `=== STANDAR DOCS ===
|
|
14091
14281
|
${REVERSE_STANDARD}` : "",
|
|
14092
14282
|
skills.length ? `Skills ${method.label} WAJIB untuk fase ini \u2014 muat & ikuti dengan mekanisme yang tersedia di agenmu: ` + skills.join(", ") : "",
|
|
14093
|
-
work ? scopeClause(
|
|
14094
|
-
work ? codeStyleClause(
|
|
14283
|
+
work ? scopeClause(flow2, ctx.verifyScope) : "",
|
|
14284
|
+
work ? codeStyleClause(flow2) : "",
|
|
14095
14285
|
methodClause(method),
|
|
14096
14286
|
ATTACHMENT_NOTE,
|
|
14097
14287
|
PHASE_AGENT_AUTONOMY,
|
|
@@ -14933,10 +15123,10 @@ function recorded(file) {
|
|
|
14933
15123
|
}
|
|
14934
15124
|
return out4;
|
|
14935
15125
|
}
|
|
14936
|
-
function readPhases(file,
|
|
15126
|
+
function readPhases(file, flow2) {
|
|
14937
15127
|
const seen2 = recorded(file);
|
|
14938
15128
|
let activeTaken = false;
|
|
14939
|
-
return PIPELINES[
|
|
15129
|
+
return PIPELINES[flow2].map((name2) => {
|
|
14940
15130
|
const state = seen2.get(name2);
|
|
14941
15131
|
if (state) return { name: name2, state };
|
|
14942
15132
|
if (activeTaken) return { name: name2, state: "pending" };
|
|
@@ -15991,7 +16181,7 @@ function parsePanes(out4) {
|
|
|
15991
16181
|
n2,
|
|
15992
16182
|
projectId,
|
|
15993
16183
|
specId,
|
|
15994
|
-
|
|
16184
|
+
flow2,
|
|
15995
16185
|
phaseFile,
|
|
15996
16186
|
cwd,
|
|
15997
16187
|
dead,
|
|
@@ -16017,7 +16207,7 @@ function parsePanes(out4) {
|
|
|
16017
16207
|
id: n2.slice(PREFIX.length),
|
|
16018
16208
|
projectId: projectId ?? "",
|
|
16019
16209
|
specId: specId || void 0,
|
|
16020
|
-
flow:
|
|
16210
|
+
flow: flow2 || void 0,
|
|
16021
16211
|
phaseFile: phaseFile || void 0,
|
|
16022
16212
|
cwd: cwd ?? "",
|
|
16023
16213
|
exited,
|
|
@@ -16821,7 +17011,7 @@ exit 1
|
|
|
16821
17011
|
id: id2,
|
|
16822
17012
|
projectId,
|
|
16823
17013
|
specId,
|
|
16824
|
-
flow,
|
|
17014
|
+
flow: flow2,
|
|
16825
17015
|
cwd,
|
|
16826
17016
|
exited,
|
|
16827
17017
|
code,
|
|
@@ -16837,7 +17027,7 @@ exit 1
|
|
|
16837
17027
|
id: id2,
|
|
16838
17028
|
projectId,
|
|
16839
17029
|
specId,
|
|
16840
|
-
flow,
|
|
17030
|
+
flow: flow2,
|
|
16841
17031
|
cwd,
|
|
16842
17032
|
exited,
|
|
16843
17033
|
branch,
|
|
@@ -17654,7 +17844,7 @@ var init_settings3 = __esm({
|
|
|
17654
17844
|
"use strict";
|
|
17655
17845
|
init_db();
|
|
17656
17846
|
init_src();
|
|
17657
|
-
STEP = { model: "claude-
|
|
17847
|
+
STEP = { model: "claude-sonnet-5", effort: "medium" };
|
|
17658
17848
|
DEFAULT_SETTING = {
|
|
17659
17849
|
...STEP,
|
|
17660
17850
|
autoDefault: true,
|
|
@@ -17698,8 +17888,10 @@ var init_settings3 = __esm({
|
|
|
17698
17888
|
// SPEC-1215 · ADR-0166
|
|
17699
17889
|
builtinAgents: {},
|
|
17700
17890
|
// SPEC-881 · ADR-0136 · sidik jari seed (lokal, tak disync)
|
|
17701
|
-
builtinAgentPolicies: {}
|
|
17891
|
+
builtinAgentPolicies: {},
|
|
17702
17892
|
// SPEC-950 · marker safety policy sekali-jalan (lokal)
|
|
17893
|
+
builtinRuntimeDefaults: BUILTIN_RUNTIME_DEFAULTS
|
|
17894
|
+
// seed rekomendasi model/fase; user edit dipertahankan
|
|
17703
17895
|
};
|
|
17704
17896
|
RETIRED_MODELS = { "claude-opus-4-8": "claude-opus-5" };
|
|
17705
17897
|
}
|
|
@@ -18671,6 +18863,172 @@ var require_src = __commonJS({
|
|
|
18671
18863
|
}
|
|
18672
18864
|
});
|
|
18673
18865
|
|
|
18866
|
+
// src/services/runtime-defaults.ts
|
|
18867
|
+
function inferLegacyStates(raw) {
|
|
18868
|
+
const object = isRecord(raw) ? raw : {};
|
|
18869
|
+
const has = (key) => Object.prototype.hasOwnProperty.call(object, key);
|
|
18870
|
+
const rawCodex = object.codex;
|
|
18871
|
+
const rawOrchestration = isRecord(object.orchestration) ? object.orchestration : {};
|
|
18872
|
+
const orchestration = seededFlowStates();
|
|
18873
|
+
for (const flow2 of ORCHESTRATION_FLOWS) {
|
|
18874
|
+
const rawFlow = rawOrchestration[flow2];
|
|
18875
|
+
if (!has("orchestration") || rawFlow === void 0) continue;
|
|
18876
|
+
if (!legacyFlow(rawFlow)) {
|
|
18877
|
+
const flowObject = isRecord(rawFlow) ? rawFlow : {};
|
|
18878
|
+
if (Object.prototype.hasOwnProperty.call(flowObject, "enabled") && flowObject.enabled !== true)
|
|
18879
|
+
orchestration[`${flow2}.enabled`] = "user";
|
|
18880
|
+
for (const runtime of ["claude", "codex"]) {
|
|
18881
|
+
const rawRuntime = isRecord(flowObject[runtime]) ? flowObject[runtime] : {};
|
|
18882
|
+
for (const phase of FLOW_PHASES[flow2]) {
|
|
18883
|
+
const rawCell = rawRuntime[phase];
|
|
18884
|
+
if (!isRecord(rawCell)) continue;
|
|
18885
|
+
for (const field of ["model", "effort"]) {
|
|
18886
|
+
if (Object.prototype.hasOwnProperty.call(rawCell, field))
|
|
18887
|
+
orchestration[`${flow2}.${runtime}.${phase}.${field}`] = "user";
|
|
18888
|
+
}
|
|
18889
|
+
}
|
|
18890
|
+
}
|
|
18891
|
+
}
|
|
18892
|
+
}
|
|
18893
|
+
const claudeModel = !has("model") || object.model === LEGACY_CLAUDE_RUNTIME_DEFAULTS.model ? "seeded" : "user";
|
|
18894
|
+
const claudeEffort = !has("effort") || object.effort === LEGACY_CLAUDE_RUNTIME_DEFAULTS.effort ? "seeded" : "user";
|
|
18895
|
+
const rawCodexObject = isRecord(rawCodex) ? rawCodex : {};
|
|
18896
|
+
const codexModel2 = !has("codex") || !Object.prototype.hasOwnProperty.call(rawCodexObject, "model") || rawCodexObject.model === LEGACY_CODEX_RUNTIME_DEFAULTS.model ? "seeded" : "user";
|
|
18897
|
+
const codexEffort = !has("codex") || !Object.prototype.hasOwnProperty.call(rawCodexObject, "effort") || rawCodexObject.effort === LEGACY_CODEX_RUNTIME_DEFAULTS.effort ? "seeded" : "user";
|
|
18898
|
+
return {
|
|
18899
|
+
claude: { model: claudeModel, effort: claudeEffort },
|
|
18900
|
+
codex: { model: codexModel2, effort: codexEffort },
|
|
18901
|
+
orchestration
|
|
18902
|
+
};
|
|
18903
|
+
}
|
|
18904
|
+
function statesFor(raw, setting) {
|
|
18905
|
+
const object = isRecord(raw) ? raw : {};
|
|
18906
|
+
const marker = zBuiltinRuntimeDefaults.safeParse(object.builtinRuntimeDefaults);
|
|
18907
|
+
if (marker.success) {
|
|
18908
|
+
const orchestration = seededFlowStates();
|
|
18909
|
+
for (const flow2 of ORCHESTRATION_FLOWS) {
|
|
18910
|
+
const prefix = `${flow2}.`;
|
|
18911
|
+
for (const [key, state] of Object.entries(marker.data.orchestration)) {
|
|
18912
|
+
if (key.startsWith(prefix)) orchestration[key] = state;
|
|
18913
|
+
}
|
|
18914
|
+
}
|
|
18915
|
+
return { claude: marker.data.claude, codex: marker.data.codex, orchestration };
|
|
18916
|
+
}
|
|
18917
|
+
return inferLegacyStates(raw);
|
|
18918
|
+
}
|
|
18919
|
+
function applyRuntimeDefaults(raw) {
|
|
18920
|
+
const isFresh = raw === void 0 || raw === null;
|
|
18921
|
+
const parsed = isFresh ? zSetting.safeParse({ autoDefault: true, autoScaffold: true, notifyFail: true }) : zSetting.safeParse(raw);
|
|
18922
|
+
if (!parsed.success) return null;
|
|
18923
|
+
const states = statesFor(raw, parsed.data);
|
|
18924
|
+
const orchestration = { ...parsed.data.orchestration };
|
|
18925
|
+
for (const flow2 of ORCHESTRATION_FLOWS) {
|
|
18926
|
+
const builtIn = BUILTIN_ORCHESTRATION_DEFAULTS[flow2];
|
|
18927
|
+
const existing = parsed.data.orchestration[flow2];
|
|
18928
|
+
const nextFlow = {
|
|
18929
|
+
...existing,
|
|
18930
|
+
enabled: states.orchestration[`${flow2}.enabled`] !== "user" ? builtIn.enabled : existing.enabled,
|
|
18931
|
+
claude: { ...existing.claude },
|
|
18932
|
+
codex: { ...existing.codex }
|
|
18933
|
+
};
|
|
18934
|
+
for (const runtime of ["claude", "codex"]) {
|
|
18935
|
+
for (const phase of FLOW_PHASES[flow2]) {
|
|
18936
|
+
const existingCell = nextFlow[runtime][phase] ?? { model: null, effort: null };
|
|
18937
|
+
const builtInCell = builtIn[runtime][phase];
|
|
18938
|
+
nextFlow[runtime][phase] = {
|
|
18939
|
+
model: states.orchestration[`${flow2}.${runtime}.${phase}.model`] !== "user" ? builtInCell.model : existingCell.model,
|
|
18940
|
+
effort: states.orchestration[`${flow2}.${runtime}.${phase}.effort`] !== "user" ? builtInCell.effort : existingCell.effort
|
|
18941
|
+
};
|
|
18942
|
+
}
|
|
18943
|
+
}
|
|
18944
|
+
orchestration[flow2] = nextFlow;
|
|
18945
|
+
}
|
|
18946
|
+
const data = zSetting.parse({
|
|
18947
|
+
...parsed.data,
|
|
18948
|
+
model: states.claude.model === "seeded" ? BUILTIN_CLAUDE_RUNTIME_DEFAULTS.model : parsed.data.model,
|
|
18949
|
+
effort: states.claude.effort === "seeded" ? BUILTIN_CLAUDE_RUNTIME_DEFAULTS.effort : parsed.data.effort,
|
|
18950
|
+
codex: {
|
|
18951
|
+
model: states.codex.model === "seeded" ? BUILTIN_CODEX_RUNTIME_DEFAULTS.model : parsed.data.codex.model,
|
|
18952
|
+
effort: states.codex.effort === "seeded" ? BUILTIN_CODEX_RUNTIME_DEFAULTS.effort : parsed.data.codex.effort
|
|
18953
|
+
},
|
|
18954
|
+
orchestration,
|
|
18955
|
+
builtinRuntimeDefaults: markerFrom(states)
|
|
18956
|
+
});
|
|
18957
|
+
return { data, changed: isFresh || !same(raw, data) };
|
|
18958
|
+
}
|
|
18959
|
+
async function seedRuntimeDefaults() {
|
|
18960
|
+
try {
|
|
18961
|
+
const raw = (await prisma.setting.findUnique({ where: { id: 1 } }))?.data;
|
|
18962
|
+
const result = applyRuntimeDefaults(raw);
|
|
18963
|
+
if (!result?.changed) return;
|
|
18964
|
+
await prisma.setting.upsert({
|
|
18965
|
+
where: { id: 1 },
|
|
18966
|
+
update: { data: result.data },
|
|
18967
|
+
create: { id: 1, data: result.data }
|
|
18968
|
+
});
|
|
18969
|
+
} catch {
|
|
18970
|
+
}
|
|
18971
|
+
}
|
|
18972
|
+
function markRuntimeDefaultsUserEdited(before2, next) {
|
|
18973
|
+
const parsed = zBuiltinRuntimeDefaults.safeParse(before2.builtinRuntimeDefaults);
|
|
18974
|
+
const current = parsed.success ? parsed.data : {
|
|
18975
|
+
...BUILTIN_RUNTIME_DEFAULTS,
|
|
18976
|
+
claude: { ...BUILTIN_RUNTIME_DEFAULTS.claude },
|
|
18977
|
+
codex: { ...BUILTIN_RUNTIME_DEFAULTS.codex },
|
|
18978
|
+
orchestration: { ...BUILTIN_RUNTIME_DEFAULTS.orchestration }
|
|
18979
|
+
};
|
|
18980
|
+
const orchestration = { ...seededFlowStates(), ...current.orchestration };
|
|
18981
|
+
if (before2.model !== next.model) current.claude.model = "user";
|
|
18982
|
+
if (before2.effort !== next.effort) current.claude.effort = "user";
|
|
18983
|
+
if (before2.codex.model !== next.codex.model) current.codex.model = "user";
|
|
18984
|
+
if (before2.codex.effort !== next.codex.effort) current.codex.effort = "user";
|
|
18985
|
+
for (const flow2 of ORCHESTRATION_FLOWS) {
|
|
18986
|
+
if (before2.orchestration[flow2].enabled !== next.orchestration[flow2].enabled)
|
|
18987
|
+
orchestration[`${flow2}.enabled`] = "user";
|
|
18988
|
+
for (const runtime of ["claude", "codex"]) {
|
|
18989
|
+
for (const phase of FLOW_PHASES[flow2]) {
|
|
18990
|
+
for (const field of ["model", "effort"]) {
|
|
18991
|
+
if (before2.orchestration[flow2][runtime][phase]?.[field] !== next.orchestration[flow2][runtime][phase]?.[field])
|
|
18992
|
+
orchestration[`${flow2}.${runtime}.${phase}.${field}`] = "user";
|
|
18993
|
+
}
|
|
18994
|
+
}
|
|
18995
|
+
}
|
|
18996
|
+
}
|
|
18997
|
+
return {
|
|
18998
|
+
version: RUNTIME_DEFAULTS_VERSION,
|
|
18999
|
+
claude: { ...current.claude },
|
|
19000
|
+
codex: { ...current.codex },
|
|
19001
|
+
orchestration
|
|
19002
|
+
};
|
|
19003
|
+
}
|
|
19004
|
+
var isRecord, stable, same, seededFlowStates, markerFrom, legacyFlow;
|
|
19005
|
+
var init_runtime_defaults2 = __esm({
|
|
19006
|
+
"src/services/runtime-defaults.ts"() {
|
|
19007
|
+
"use strict";
|
|
19008
|
+
init_src();
|
|
19009
|
+
init_db();
|
|
19010
|
+
isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
19011
|
+
stable = (value) => {
|
|
19012
|
+
if (Array.isArray(value)) return value.map(stable);
|
|
19013
|
+
if (!isRecord(value)) return value;
|
|
19014
|
+
return Object.fromEntries(Object.keys(value).sort().map((key) => [key, stable(value[key])]));
|
|
19015
|
+
};
|
|
19016
|
+
same = (a, b) => JSON.stringify(stable(a)) === JSON.stringify(stable(b));
|
|
19017
|
+
seededFlowStates = () => Object.fromEntries(Object.keys(BUILTIN_RUNTIME_DEFAULTS.orchestration).map((key) => [key, "seeded"]));
|
|
19018
|
+
markerFrom = (states) => ({
|
|
19019
|
+
version: RUNTIME_DEFAULTS_VERSION,
|
|
19020
|
+
claude: states.claude,
|
|
19021
|
+
codex: states.codex,
|
|
19022
|
+
orchestration: states.orchestration
|
|
19023
|
+
});
|
|
19024
|
+
legacyFlow = (value) => {
|
|
19025
|
+
if (!isRecord(value)) return false;
|
|
19026
|
+
const parsed = zFlowOrchestration.safeParse(value);
|
|
19027
|
+
return parsed.success && same(parsed.data, LEGACY_ORCHESTRATION_FLOW_DEFAULT);
|
|
19028
|
+
};
|
|
19029
|
+
}
|
|
19030
|
+
});
|
|
19031
|
+
|
|
18674
19032
|
// src/services/agent-token.ts
|
|
18675
19033
|
import { randomBytes as randomBytes2, createHash as createHash2, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
|
|
18676
19034
|
function toAgentTokenView(t) {
|
|
@@ -25404,6 +25762,7 @@ async function refreshCustomAgentRuntimeSupport(probe = defaultCodexSupportProbe
|
|
|
25404
25762
|
return refresh;
|
|
25405
25763
|
}
|
|
25406
25764
|
async function installCustomAgents() {
|
|
25765
|
+
await seedRuntimeDefaults();
|
|
25407
25766
|
await seedBuiltinAgents();
|
|
25408
25767
|
await loadCustomAgents();
|
|
25409
25768
|
await refreshCustomAgentRuntimeSupport();
|
|
@@ -25426,6 +25785,7 @@ var init_custom_agents2 = __esm({
|
|
|
25426
25785
|
init_pty();
|
|
25427
25786
|
init_agent_tool_catalog();
|
|
25428
25787
|
init_builtin_agents2();
|
|
25788
|
+
init_runtime_defaults2();
|
|
25429
25789
|
init_codex_version();
|
|
25430
25790
|
cache4 = [];
|
|
25431
25791
|
codexNativeSupport = { version: null, ok: false };
|
|
@@ -35529,10 +35889,10 @@ var _Tokenizer = class {
|
|
|
35529
35889
|
});
|
|
35530
35890
|
}
|
|
35531
35891
|
for (const row of rows) {
|
|
35532
|
-
item.rows.push(splitCells(row, item.header.length).map((
|
|
35892
|
+
item.rows.push(splitCells(row, item.header.length).map((cell2) => {
|
|
35533
35893
|
return {
|
|
35534
|
-
text:
|
|
35535
|
-
tokens: this.lexer.inline(
|
|
35894
|
+
text: cell2,
|
|
35895
|
+
tokens: this.lexer.inline(cell2)
|
|
35536
35896
|
};
|
|
35537
35897
|
}));
|
|
35538
35898
|
}
|
|
@@ -36528,19 +36888,19 @@ var _Parser = class __Parser {
|
|
|
36528
36888
|
case "table": {
|
|
36529
36889
|
const tableToken = token;
|
|
36530
36890
|
let header2 = "";
|
|
36531
|
-
let
|
|
36891
|
+
let cell2 = "";
|
|
36532
36892
|
for (let j = 0; j < tableToken.header.length; j++) {
|
|
36533
|
-
|
|
36893
|
+
cell2 += this.renderer.tablecell(this.parseInline(tableToken.header[j].tokens), { header: true, align: tableToken.align[j] });
|
|
36534
36894
|
}
|
|
36535
|
-
header2 += this.renderer.tablerow(
|
|
36895
|
+
header2 += this.renderer.tablerow(cell2);
|
|
36536
36896
|
let body = "";
|
|
36537
36897
|
for (let j = 0; j < tableToken.rows.length; j++) {
|
|
36538
36898
|
const row = tableToken.rows[j];
|
|
36539
|
-
|
|
36899
|
+
cell2 = "";
|
|
36540
36900
|
for (let k = 0; k < row.length; k++) {
|
|
36541
|
-
|
|
36901
|
+
cell2 += this.renderer.tablecell(this.parseInline(row[k].tokens), { header: false, align: tableToken.align[k] });
|
|
36542
36902
|
}
|
|
36543
|
-
body += this.renderer.tablerow(
|
|
36903
|
+
body += this.renderer.tablerow(cell2);
|
|
36544
36904
|
}
|
|
36545
36905
|
out4 += this.renderer.table(header2, body);
|
|
36546
36906
|
continue;
|
|
@@ -36751,12 +37111,12 @@ var Marked = class {
|
|
|
36751
37111
|
switch (token.type) {
|
|
36752
37112
|
case "table": {
|
|
36753
37113
|
const tableToken = token;
|
|
36754
|
-
for (const
|
|
36755
|
-
values = values.concat(this.walkTokens(
|
|
37114
|
+
for (const cell2 of tableToken.header) {
|
|
37115
|
+
values = values.concat(this.walkTokens(cell2.tokens, callback));
|
|
36756
37116
|
}
|
|
36757
37117
|
for (const row of tableToken.rows) {
|
|
36758
|
-
for (const
|
|
36759
|
-
values = values.concat(this.walkTokens(
|
|
37118
|
+
for (const cell2 of row) {
|
|
37119
|
+
values = values.concat(this.walkTokens(cell2.tokens, callback));
|
|
36760
37120
|
}
|
|
36761
37121
|
}
|
|
36762
37122
|
break;
|
|
@@ -37909,6 +38269,7 @@ async function notifications_default(app3) {
|
|
|
37909
38269
|
init_src();
|
|
37910
38270
|
init_db();
|
|
37911
38271
|
init_settings3();
|
|
38272
|
+
init_runtime_defaults2();
|
|
37912
38273
|
init_bootstrap();
|
|
37913
38274
|
init_config4();
|
|
37914
38275
|
async function settings_default(app3) {
|
|
@@ -37917,8 +38278,18 @@ async function settings_default(app3) {
|
|
|
37917
38278
|
const parsed = zSetting.safeParse(req.body);
|
|
37918
38279
|
if (!parsed.success) return reply.code(400).send({ error: parsed.error.flatten() });
|
|
37919
38280
|
const before2 = await getSetting();
|
|
37920
|
-
const
|
|
38281
|
+
const input = req.body && typeof req.body === "object" && !Array.isArray(req.body) ? req.body : {};
|
|
38282
|
+
const has = (key) => Object.prototype.hasOwnProperty.call(input, key);
|
|
38283
|
+
const runtimePreserved = {
|
|
37921
38284
|
...parsed.data,
|
|
38285
|
+
model: has("model") ? parsed.data.model : before2.model,
|
|
38286
|
+
effort: has("effort") ? parsed.data.effort : before2.effort,
|
|
38287
|
+
codex: has("codex") ? parsed.data.codex : before2.codex,
|
|
38288
|
+
orchestration: has("orchestration") ? parsed.data.orchestration : before2.orchestration
|
|
38289
|
+
};
|
|
38290
|
+
const data = {
|
|
38291
|
+
...runtimePreserved,
|
|
38292
|
+
builtinRuntimeDefaults: markRuntimeDefaultsUserEdited(before2, runtimePreserved),
|
|
37922
38293
|
remoteControl: before2.remoteControl,
|
|
37923
38294
|
logShipping: before2.logShipping,
|
|
37924
38295
|
logRetention: before2.logRetention
|
|
@@ -38549,8 +38920,8 @@ init_pty();
|
|
|
38549
38920
|
init_session_phases();
|
|
38550
38921
|
init_notifications2();
|
|
38551
38922
|
init_stage_machine();
|
|
38552
|
-
async function advanceStage(specId, repoDir, sessionId2,
|
|
38553
|
-
const next = stageForRun(readPhases(phaseFilePath(repoDir, sessionId2),
|
|
38923
|
+
async function advanceStage(specId, repoDir, sessionId2, flow2, worktree) {
|
|
38924
|
+
const next = stageForRun(readPhases(phaseFilePath(repoDir, sessionId2), flow2), worktree, specId);
|
|
38554
38925
|
if (!next) return;
|
|
38555
38926
|
const spec = await prisma.spec.findUnique({ where: { id: specId }, select: { stage: true, title: true, projectId: true } });
|
|
38556
38927
|
if (!spec || STAGES.indexOf(next) <= STAGES.indexOf(spec.stage)) return;
|
|
@@ -39524,12 +39895,13 @@ init_pty();
|
|
|
39524
39895
|
// src/services/orchestration.ts
|
|
39525
39896
|
init_src();
|
|
39526
39897
|
init_pty();
|
|
39527
|
-
function sessionPhasePlan(setting,
|
|
39898
|
+
function sessionPhasePlan(setting, flow2, agent, orchestrator, phaseOverrides) {
|
|
39528
39899
|
return resolvePhasePlan({
|
|
39529
|
-
flow,
|
|
39900
|
+
flow: flow2,
|
|
39530
39901
|
runtime: agent,
|
|
39531
39902
|
orchestration: setting.orchestration,
|
|
39532
39903
|
orchestrator,
|
|
39904
|
+
phaseOverrides,
|
|
39533
39905
|
nativeAgents: nativeAgentsAvailable(agent)
|
|
39534
39906
|
});
|
|
39535
39907
|
}
|
|
@@ -39551,8 +39923,8 @@ function resumeState(repoDir, worktree, branchTo, headSha) {
|
|
|
39551
39923
|
const base2 = realGit.revParse(repoDir, `origin/${branchTo}`) ?? realGit.revParse(repoDir, branchTo) ?? (headSha ? realGit.revParse(repoDir, headSha) : null);
|
|
39552
39924
|
return base2 ? { worktreeKept: false, base: base2 } : null;
|
|
39553
39925
|
}
|
|
39554
|
-
function buildResumeCtx(repoDir, id2,
|
|
39555
|
-
const phases = readPhases(phaseFilePath(repoDir, id2),
|
|
39926
|
+
function buildResumeCtx(repoDir, id2, flow2, worktreeKept) {
|
|
39927
|
+
const phases = readPhases(phaseFilePath(repoDir, id2), flow2);
|
|
39556
39928
|
return {
|
|
39557
39929
|
recorded: phases.filter((p3) => p3.state === "done" || p3.state === "skipped").map((p3) => `${p3.name} ${p3.state}`),
|
|
39558
39930
|
next: phases.find((p3) => p3.state === "active")?.name,
|
|
@@ -39629,7 +40001,7 @@ async function startSpecSession(spec, opts) {
|
|
|
39629
40001
|
payload: spec.payload ?? void 0
|
|
39630
40002
|
};
|
|
39631
40003
|
const resumeCtx = resume ? buildResumeCtx(repoDir, id2, opts.flow, resume.worktreeKept) : void 0;
|
|
39632
|
-
const fullPlan = sessionPhasePlan(setting, opts.flow, agent, { model, effort: effort2 });
|
|
40004
|
+
const fullPlan = sessionPhasePlan(setting, opts.flow, agent, { model, effort: effort2 }, opts.phaseOverrides);
|
|
39633
40005
|
let plan = fullPlan;
|
|
39634
40006
|
if (fullPlan && isContinue && !isGoalFlow) {
|
|
39635
40007
|
const phases = fullPlan.phases.filter((p3) => p3.phase === "Execute");
|
|
@@ -41254,7 +41626,7 @@ var notifTitle = (kind, question, answer, confidence) => {
|
|
|
41254
41626
|
async function decide(req, deps = prodDecideDeps) {
|
|
41255
41627
|
const cfg = await getLead();
|
|
41256
41628
|
if (!leadActive(cfg, req.projectId)) return null;
|
|
41257
|
-
const
|
|
41629
|
+
const flow2 = req.flowId ? await joinFlow(req.flowId) : await openFlow({
|
|
41258
41630
|
projectId: req.projectId,
|
|
41259
41631
|
specId: req.specId,
|
|
41260
41632
|
sessionId: req.sessionId,
|
|
@@ -41262,7 +41634,7 @@ async function decide(req, deps = prodDecideDeps) {
|
|
|
41262
41634
|
title: req.question,
|
|
41263
41635
|
ttlMin: cfg.flowTtlMin
|
|
41264
41636
|
});
|
|
41265
|
-
const step =
|
|
41637
|
+
const step = flow2.steps + 1;
|
|
41266
41638
|
const project = await prisma.project.findUnique({ where: { id: req.projectId }, select: { name: true } });
|
|
41267
41639
|
const spec = req.specId ? await prisma.spec.findUnique({
|
|
41268
41640
|
where: { id: req.specId },
|
|
@@ -41274,7 +41646,7 @@ async function decide(req, deps = prodDecideDeps) {
|
|
|
41274
41646
|
orderBy: { createdAt: "desc" },
|
|
41275
41647
|
take: 10
|
|
41276
41648
|
});
|
|
41277
|
-
const chainRows = req.flowId ? await prisma.leadDecision.findMany({ where: { flowId:
|
|
41649
|
+
const chainRows = req.flowId ? await prisma.leadDecision.findMany({ where: { flowId: flow2.id }, orderBy: { createdAt: "asc" }, take: 10 }) : [];
|
|
41278
41650
|
const options2 = req.options ?? [];
|
|
41279
41651
|
const bounds = normalizeSelect(req.select ?? { mode: "single", min: 0, max: null }, options2.length);
|
|
41280
41652
|
const ctx = {
|
|
@@ -41319,15 +41691,15 @@ async function decide(req, deps = prodDecideDeps) {
|
|
|
41319
41691
|
});
|
|
41320
41692
|
} catch (e) {
|
|
41321
41693
|
if (e instanceof LeadBusyError) {
|
|
41322
|
-
if (!req.flowId) await closeFlow(
|
|
41694
|
+
if (!req.flowId) await closeFlow(flow2.id, "kedaluwarsa").catch(() => null);
|
|
41323
41695
|
throw e;
|
|
41324
41696
|
}
|
|
41325
|
-
return closeAfter(await fail(req, deps, `lead tak menghasilkan keputusan: ${e.message}`,
|
|
41697
|
+
return closeAfter(await fail(req, deps, `lead tak menghasilkan keputusan: ${e.message}`, flow2.id, step), flow2.id, req.chain);
|
|
41326
41698
|
} finally {
|
|
41327
41699
|
if (req.sessionId) clearQueued(req.sessionId);
|
|
41328
41700
|
}
|
|
41329
41701
|
const verdict = parseLeadVerdict(raw);
|
|
41330
|
-
if (!verdict) return closeAfter(await fail(req, deps, "keluaran lead tak memuat blok json keputusan yang sah",
|
|
41702
|
+
if (!verdict) return closeAfter(await fail(req, deps, "keluaran lead tak memuat blok json keputusan yang sah", flow2.id, step), flow2.id, req.chain);
|
|
41331
41703
|
const refs2 = keepExistingRefs(verdict.refs, repoDir);
|
|
41332
41704
|
const allowed = leadActionAllowed(verdict.action);
|
|
41333
41705
|
const kind = allowed ? req.kind : "refusal";
|
|
@@ -41385,12 +41757,12 @@ ${notes.join("\n\n")}` : "";
|
|
|
41385
41757
|
choiceIndex: choice?.index ?? null,
|
|
41386
41758
|
choices,
|
|
41387
41759
|
select: bounds,
|
|
41388
|
-
flowId:
|
|
41760
|
+
flowId: flow2.id,
|
|
41389
41761
|
step,
|
|
41390
41762
|
options: options2,
|
|
41391
41763
|
missing
|
|
41392
41764
|
});
|
|
41393
|
-
await closeAfter(row,
|
|
41765
|
+
await closeAfter(row, flow2.id, req.chain);
|
|
41394
41766
|
if (weighty) {
|
|
41395
41767
|
await deps.notify(
|
|
41396
41768
|
row.id,
|
|
@@ -41953,6 +42325,8 @@ async function terminal_default(app3, opts) {
|
|
|
41953
42325
|
// SPEC-376 · ADR-0080
|
|
41954
42326
|
method: parsed.data.method,
|
|
41955
42327
|
// SPEC-734 · ADR-0113
|
|
42328
|
+
phaseOverrides: parsed.data.phaseOverrides,
|
|
42329
|
+
// ADR-0164 · override subagent per sesi
|
|
41956
42330
|
force: parsed.data.force
|
|
41957
42331
|
// SPEC-447 · ADR-0093
|
|
41958
42332
|
});
|
|
@@ -50166,7 +50540,7 @@ var reconcileProdDeps = {
|
|
|
50166
50540
|
const s2 = getSession(sessionId2);
|
|
50167
50541
|
return s2 ? { exited: s2.exited, flow: s2.flow, phaseFile: s2.phaseFile, cwd: s2.cwd } : void 0;
|
|
50168
50542
|
},
|
|
50169
|
-
deriveStage: (phaseFile,
|
|
50543
|
+
deriveStage: (phaseFile, flow2, cwd, specId) => stageForRun(readPhases(phaseFile, flow2), cwd, specId),
|
|
50170
50544
|
headSha: (wt) => {
|
|
50171
50545
|
try {
|
|
50172
50546
|
return realGit.headSha(wt);
|